//--------------------------------------------------------------------------- #include <windows.h> #include <cstring> #include <cmath> #include <sstream> #pragma hdrstop #include "clipper.hpp" #include "cairo.h" #include "cairo-win32.h" #include "cairo_clipper.hpp" //--------------------------------------------------------------------------- int offsetVal; LRESULT CALLBACK WndProcedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); int CALLBACK wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { WCHAR* ClsName = L"CairoApp"; WCHAR* WndName = L"A Simple Cairo Clipper Demo"; offsetVal = 0; MSG Msg; HWND hWnd; WNDCLASSEX WndClsEx; // Create the application window WndClsEx.cbSize = sizeof(WNDCLASSEX); WndClsEx.style = CS_HREDRAW | CS_VREDRAW; WndClsEx.lpfnWndProc = WndProcedure; WndClsEx.cbClsExtra = 0; WndClsEx.cbWndExtra = 0; WndClsEx.hIcon = LoadIcon(NULL, IDI_APPLICATION); WndClsEx.hCursor = LoadCursor(NULL, IDC_ARROW); WndClsEx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); WndClsEx.lpszMenuName = NULL; WndClsEx.lpszClassName = ClsName; WndClsEx.hInstance = hInstance; WndClsEx.hIconSm = LoadIcon(NULL, IDI_APPLICATION); // Register the application RegisterClassEx(&WndClsEx); // Create the window object hWnd = CreateWindow(ClsName, WndName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, NULL, NULL, hInstance, NULL); if( !hWnd ) return 0; ShowWindow(hWnd, SW_SHOWNORMAL); UpdateWindow(hWnd); while( GetMessage(&Msg, NULL, 0, 0) ) { TranslateMessage(&Msg); DispatchMessage(&Msg); } return Msg.wParam; } //------------------------------------------------------------------------------ void OnPaint(HWND hWnd, HDC dc) { RECT rec; GetClientRect(hWnd, &rec); cairo_surface_t* surface = cairo_win32_surface_create(dc); cairo_t* cr = cairo_create(surface); cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING); cairo_set_line_width (cr, 2.0); //fill background with white ... cairo_rectangle(cr, 0, 0, rec.right, rec.bottom); cairo_set_source_rgba(cr, 1, 1, 1, 1); cairo_fill(cr); using namespace ClipperLib; const int scaling = 2; Clipper clpr; //clipper class Paths pg; //std::vector for polygon(s) storage //create a circular pattern, add the path to clipper and then draw it ... cairo_arc(cr, 170,110,70,0,2*3.1415926); cairo_close_path(cr); cairo::cairo_to_clipper(cr, pg, scaling); clpr.AddPaths(pg, ptSubject, true); cairo_set_source_rgba(cr, 0, 0, 1, 0.25); cairo_fill_preserve (cr); cairo_set_source_rgba(cr, 0, 0, 0, 0.5); cairo_stroke (cr); //draw a star and another circle, add them to clipper and draw ... cairo_move_to(cr, 60,110); cairo_line_to (cr, 240,70); cairo_line_to (cr, 110,210); cairo_line_to (cr, 140,25); cairo_line_to (cr, 230,200); cairo_close_path(cr); cairo_new_sub_path(cr); cairo_arc(cr, 190,50,20,0,2*3.1415926); cairo_close_path(cr); cairo::cairo_to_clipper(cr, pg, scaling); clpr.AddPaths(pg, ptClip, true); cairo_set_source_rgba(cr, 1, 0, 0, 0.25); cairo_fill_preserve (cr); cairo_set_source_rgba(cr, 0, 0, 0, 0.5); cairo_stroke (cr); clpr.Execute(ctIntersection, pg, pftNonZero, pftNonZero); //now do something fancy with the returned polygons ... OffsetPaths(pg, pg, offsetVal * std::pow((double)10,scaling), jtMiter, etClosed); //finally copy the clipped path back to the cairo context and draw it ... cairo::clipper_to_cairo(pg, cr, scaling); cairo_set_source_rgba(cr, 1, 1, 0, 1); cairo_fill_preserve (cr); cairo_set_source_rgba(cr, 0, 0, 0, 1); cairo_stroke (cr); cairo_text_extents_t extent; cairo_set_font_size(cr,11); std::stringstream ss; ss << "Polygon offset = " << offsetVal << ". (Adjust with arrow keys)"; std::string s = ss.str(); cairo_text_extents(cr, s.c_str(), &extent); cairo_move_to(cr, 10, rec.bottom - extent.height); cairo_show_text(cr, s.c_str()); cairo_destroy (cr); cairo_surface_destroy (surface); } //------------------------------------------------------------------------------ LRESULT CALLBACK WndProcedure(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC Handle; switch(Msg) { case WM_DESTROY: PostQuitMessage(WM_QUIT); return 0; case WM_PAINT: Handle = BeginPaint(hWnd, &ps); OnPaint(hWnd, Handle); EndPaint(hWnd, &ps); return 0; case WM_KEYDOWN: switch(wParam) { case VK_ESCAPE: PostQuitMessage(0); return 0; case VK_RIGHT: case VK_UP: if (offsetVal < 20) offsetVal++; InvalidateRect(hWnd, 0, false); return 0; case VK_LEFT: case VK_DOWN: if (offsetVal > -20) offsetVal--; InvalidateRect(hWnd, 0, false); return 0; default: return DefWindowProc(hWnd, Msg, wParam, lParam); } default: return DefWindowProc(hWnd, Msg, wParam, lParam); } } //---------------------------------------------------------------------------