home *** CD-ROM | disk | FTP | other *** search
/ Windows Graphics Programming / Feng_Yuan_Win32_GDI_DirectX.iso / Samples / Chapt_08 / LineCurve / LineCurve.cpp next >
Encoding:
C/C++ Source or Header  |  2000-05-20  |  33.2 KB  |  1,453 lines

  1. //-----------------------------------------------------------------------------------//
  2. //              Windows Graphics Programming: Win32 GDI and DirectDraw               //
  3. //                             ISBN  0-13-086985-6                                   //
  4. //                                                                                   //
  5. //  Written            by  Yuan, Feng                             www.fengyuan.com   //
  6. //  Copyright (c) 2000 by  Hewlett-Packard Company                www.hp.com         //
  7. //  Published          by  Prentice Hall PTR, Prentice-Hall, Inc. www.phptr.com      //
  8. //                                                                                   //
  9. //  FileName   : linecurve.cpp                                                         //
  10. //  Description: Line/curve demo program, Chapter 8                                  //
  11. //  Version    : 1.00.000, May 31, 2000                                              //
  12. //-----------------------------------------------------------------------------------//
  13.  
  14. #define STRICT
  15. #define _WIN32_WINNT 0x0500
  16. #define WIN32_LEAN_AND_MEAN
  17.  
  18. #include <windows.h>
  19. #include <assert.h>
  20. #include <tchar.h>
  21. #include <math.h>
  22. #include <stdio.h>
  23.  
  24. #include "..\..\include\win.h"
  25. #include "..\..\include\Canvas.h"
  26. #include "..\..\include\Status.h"
  27. #include "..\..\include\FrameWnd.h"
  28. #include "..\..\include\Affine.h"
  29. #include "..\..\include\Pen.h"
  30. #include "..\..\include\curve.h"
  31. #include "..\..\include\BezierCurve.h"
  32.  
  33. #include "Resource.h"
  34.  
  35.  
  36. class KMyCanvas : public KCanvas
  37. {
  38.     virtual void    OnDraw(HDC hDC, const RECT * rcPaint);
  39.     virtual LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  40.     virtual    BOOL    OnCommand(WPARAM wParam, LPARAM lParam);
  41.  
  42.     int        m_test;
  43.     int        m_lastx;
  44.     int        m_lasty;
  45.  
  46.     void SetTest(int test);
  47.  
  48.     void DrawCrossHair(HDC hDC, bool on);
  49.  
  50.     void TestDrawMode(HDC hDC);
  51.     void TestWidthCap(HDC hDC);
  52.     void TestDCPen(HDC hDC);
  53.     void TestPenStyle(HDC hDC);
  54.  
  55.     void TestCosmetic(HDC hDC);
  56.     void TestGeometricWidth(HDC hDC);
  57.     void TestGeometricStyle(HDC hDC);
  58.  
  59.     void TestLine1(HDC hDC);
  60.     void TestLine2(HDC hDC);
  61.     void TestBezier(HDC hDC);
  62.     void BezierDemo(HDC hDC);
  63.  
  64.     void DragBezier(HDC hDC, int x, bool on);
  65.     void TestBezierPen(HDC hDC);
  66.     void TestArc(HDC hDC);
  67.  
  68.     void ArcToBezier(HDC hDC);
  69.     void AngleArcToBezier(HDC hDC);
  70.  
  71.     void TestPath(HDC hDC);
  72.     void TestPathStyleCurve(HDC hDC);
  73.  
  74.     void TestMapPath(HDC hDC);
  75.  
  76.     POINT m_bezier[4];
  77.  
  78. public:
  79.  
  80.     KMyCanvas()
  81.     {
  82.         m_test  = -1;
  83.         m_lastx = -1;
  84.         m_lasty = -1;
  85.  
  86.         m_bezier[0].x =  30; m_bezier[0].y = 330;
  87.         m_bezier[1].x = 130; m_bezier[1].y =  30;
  88.         m_bezier[2].x = 430; m_bezier[2].y = 130;
  89.         m_bezier[3].x = 630; m_bezier[3].y = 430;
  90.     }
  91. };
  92.  
  93.  
  94. void KMyCanvas::SetTest(int test)
  95. {
  96.     m_test = test;
  97.  
  98.     HMENU hMain = GetMenu(GetParent(m_hWnd));
  99.  
  100.     TCHAR Temp[MAX_PATH];
  101.  
  102.     _tcscpy(Temp, _T("LineCurve - "));
  103.  
  104.     GetMenuString(hMain, m_test, Temp + _tcslen(Temp), 
  105.         sizeof(Temp)/sizeof(TCHAR) - _tcslen(Temp), MF_BYCOMMAND);
  106.  
  107.     SetWindowText(GetParent(m_hWnd), Temp);
  108. }
  109.  
  110.  
  111. BOOL KMyCanvas::OnCommand(WPARAM wParam, LPARAM lParam)
  112. {
  113.     switch ( LOWORD(wParam) )
  114.     {
  115.         case IDM_TEST_DRAWMODE:
  116.         case IDM_TEST_WIDTHCAP:
  117.         case IDM_TEST_DCPEN:
  118.         case IDM_TEST_PENSTYLE:
  119.         case IDM_TEST_COSMETIC:
  120.         case IDM_TEST_GEOMETRIC_WIDTH:
  121.         case IDM_TEST_GEOMETRIC_STYLE:
  122.         case IDM_TEST_LINE1:
  123.         case IDM_TEST_LINE2:
  124.         case IDM_TEST_BEZIER:
  125.         case IDM_TEST_BEZIERDEMO:
  126.         case IDM_TEST_BEZIERPEN:
  127.         case IDM_TEST_ARC:
  128.         case IDM_TEST_ARCBEZIER:
  129.         case IDM_TEST_ANGLEARCBEZIER:
  130.         case IDM_TEST_PATH:
  131.         case IDM_TEST_PATHSTYLECURVE:
  132.         case IDM_TEST_MAPPATH:
  133.             SetTest( LOWORD(wParam) );
  134.             InvalidateRect(m_hWnd, NULL, TRUE);
  135.             return TRUE;
  136.  
  137.         case IDM_FILE_EXIT:
  138.             DestroyWindow(GetParent(m_hWnd));
  139.             return TRUE;
  140.     }
  141.  
  142.     return FALSE;    // not processed
  143. }
  144.  
  145.  
  146. void KMyCanvas::DrawCrossHair(HDC hDC, bool on)
  147. {
  148.     if ( (m_lastx<0) || (m_lasty<0) )
  149.         return;
  150.  
  151.     if ( m_test == IDM_TEST_BEZIER )
  152.         DragBezier(hDC, m_lastx, on);
  153.     else
  154.     {
  155.         RECT rect;
  156.  
  157.         GetClientRect(m_hWnd, & rect);
  158.  
  159.         SetROP2(hDC, R2_XORPEN);
  160.         KPen pen(PS_DOT, 0, RGB(0, 0, 0xFF), hDC);
  161.  
  162.         Line(hDC, rect.left, m_lasty, rect.right, m_lasty);
  163.         Line(hDC, m_lastx, rect.top, m_lastx, rect.bottom);
  164.     }
  165. }
  166.  
  167.  
  168. LRESULT KMyCanvas::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  169. {
  170.     LRESULT lr;
  171.  
  172.     switch( uMsg )
  173.     {
  174.         case WM_CREATE:
  175.             m_hWnd = hWnd;
  176.             SetTest(IDM_TEST_DRAWMODE);
  177.             return 0;
  178.  
  179.         case WM_PAINT:
  180.             {
  181.                 PAINTSTRUCT ps; 
  182.  
  183. //                SetLastError(0);
  184. //                HRGN hrgnClip = CreateRectRgn(0,0,0,0);
  185. //                GetUpdateRgn(m_hWnd,hrgnClip,FALSE);
  186. //                HDC hdc = GetDCEx(m_hWnd,NULL,DCX_VALIDATE|DCX_INTERSECTUPDATE);
  187.  
  188.                 HDC hDC = BeginPaint(m_hWnd, &ps);
  189.  
  190.             //    DrawCrossHair(hDC);
  191.                 OnDraw(hDC, &ps.rcPaint);
  192.                 DrawCrossHair(hDC, true);
  193.  
  194.                 EndPaint(m_hWnd, &ps);
  195.             }
  196.             return 0;
  197.  
  198.         case WM_MOUSEMOVE:
  199.             {
  200.                 HDC hDC = GetDC(hWnd);
  201.  
  202.                 DrawCrossHair(hDC, false);
  203.                 m_lastx = LOWORD(lParam); m_lasty = HIWORD(lParam);
  204.                 DrawCrossHair(hDC, true);
  205.                 ReleaseDC(hWnd, hDC);
  206.                 
  207.                 TCHAR temp[32];
  208.                 wsprintf(temp, _T("(%d, %d)"), m_lastx, m_lasty);
  209.                 m_pStatus->SetText(0, temp);
  210.         
  211.             }
  212.             return 0;
  213.  
  214.         default:
  215.             lr = DefWindowProc(hWnd, uMsg, wParam, lParam);
  216.     }
  217.  
  218.     return lr;
  219. }
  220.  
  221.  
  222. const TCHAR * R2_Names[] = 
  223. {
  224.     "R2_BLACK",
  225.     "R2_NOTMERGEPEN",
  226.     "R2_MASKNOTPEN",
  227.     "R2_NOTCOPYPEN",
  228.     "R2_MASKPENNOT",
  229.     "R2_NOT",
  230.     "R2_XORPEN",
  231.     "R2_NOTMASKPEN",
  232.     "R2_MASKPEN",
  233.     "R2_NOTXORPEN",
  234.     "R2_NOP",
  235.     "R2_MERGENOTPEN",
  236.     "R2_COPYPEN",
  237.     "R2_MERGEPENNOT",
  238.     "R2_MERGEPEN",
  239.     "R2_WHITE"
  240. };
  241.  
  242.  
  243. void KMyCanvas::TestDrawMode(HDC hDC)
  244. {
  245.     for (int c=0; c<20; c++)
  246.     {
  247.         RECT rect = { c*20+40, 30, c*20+58, 400 };
  248.  
  249.         HBRUSH hBrush = CreateSolidBrush(PALETTEINDEX(c));
  250.  
  251.         FillRect(hDC, & rect, hBrush);
  252.  
  253.         DeleteObject(hBrush);
  254.     }
  255.  
  256.     KPen pen(PS_SOLID, 0, RGB(0xFF, 0, 0), hDC);
  257.  
  258.     for (int r=R2_BLACK; r<=R2_WHITE; r++)
  259.     {
  260.         SetROP2(hDC, r);
  261.  
  262.         for (int i=0; i<18; i++)
  263.         {
  264.             Label(hDC, 440, r*22+20, R2_Names[r-R2_BLACK]);
  265.  
  266.             Line(hDC, 30, r*22+20+i, 430, r*22+20+i);
  267.         }
  268.     }
  269.  
  270.  
  271. void ZoomPixel(HDC hDC, int x0, int y0, int x1, int y1)
  272. {
  273.     COLORREF c = GetPixel(hDC, x0, y0);
  274.  
  275.     HBRUSH hBrush = CreateSolidBrush(c);
  276.     SelectObject(hDC, hBrush);
  277.  
  278.     Rectangle(hDC, x1, y1, x1+11, y1+11);
  279.     SelectObject(hDC, GetStockObject(WHITE_BRUSH));
  280.     DeleteObject(hBrush);
  281. }
  282.  
  283.  
  284. void KMyCanvas::TestWidthCap(HDC hDC)
  285. {
  286.     char temp[6];
  287.  
  288.     KPen green(PS_SOLID, 0, RGB(0, 0xFF, 0));
  289.     
  290.     for (int i=0; i<12; i++)
  291.     {
  292.         KPen pen (PS_DOT, i, RGB(0, 0, 0xFF));
  293.  
  294.         int x0 = 40 + (i/2)*110;
  295.         int x1 = x0 + 64;
  296.         int y0 = 30 + (i & 1) * 200;
  297.         
  298.         // thick line
  299.         Line(hDC, x0, y0, x1, y0, pen.m_hPen);
  300.  
  301.         // Center line
  302.         Line(hDC, x0, y0, x1, y0, green.m_hPen);
  303.  
  304.         wsprintf(temp, "w=%d", i);
  305.         Label(hDC, 40+x0-5*12, 90 + y0 -5*12-17, temp);
  306.  
  307.         // copy zoomed line
  308.         for (int y=-5; y<6; y++)
  309.         for (int x=-5; x<3;  x++)
  310.             ZoomPixel(hDC, x0+x, y0+y, 40+x0+x*12, 90 + y0 + y*12);
  311.  
  312.         Line(hDC, x0, y0, x1, y0, pen.m_hPen);
  313.     }
  314. }
  315.  
  316.  
  317. void KMyCanvas::TestDCPen(HDC hDC)
  318. {
  319.     Label(hDC, 10, 0, _T("Use DC_PEN to simulate gradient fill"));
  320.  
  321.     SelectObject(hDC, GetStockObject(DC_PEN));
  322.  
  323.     for (int i=0; i<128; i++)
  324.     {
  325.         SetDCPenColor(hDC, RGB(i, 255-i, 128+i));
  326.  
  327.         Line(hDC, 40, i+40, 150, i+40);
  328.     }
  329.  
  330.     SelectObject(hDC, GetStockObject(BLACK_PEN));
  331.     
  332.     // Test DeleteObject on stock object
  333.     BOOL rslt = DeleteObject(GetStockObject(DC_PEN));
  334. }
  335.  
  336. const LPCTSTR mess_PenStyle [] =
  337. {
  338.     _T("PS_SOLID"),
  339.     _T("PS_DASH"),
  340.     _T("PS_DOT"),
  341.     _T("PS_DASHDOT"),
  342.     _T("PS_DASHDOTDOT"),
  343.     _T("PS_NULL"),
  344.     _T("PS_INSIDEFRAME"),
  345.     _T("PS_USERSTYLE"),
  346.     _T("PS_ALTERNATE")
  347. };
  348.  
  349.  
  350. void KMyCanvas::TestPenStyle(HDC hDC)
  351. {
  352.     // Pen style
  353.     for (int i = PS_SOLID; i<=PS_INSIDEFRAME; i++)
  354.     {
  355.         Label(hDC, 10, i*20+10, mess_PenStyle[i]);
  356.  
  357.         SetBkColor(hDC, RGB(0, 0xFF, 0));
  358.         SetBkMode(hDC, OPAQUE);
  359.  
  360.         {    
  361.             KPen Pen(i, 1, RGB(0x00, 0x00, 0xFF), hDC);
  362.         
  363.             Line(hDC, 150, i*20 + 17, 180, i*20 + 17);
  364.         }
  365.  
  366.         SetBkColor(hDC, RGB(0xFF, 0xFF, 0xFF));
  367.     
  368.         // copy to zoomed display
  369.         for (int x=150; x<180; x++)
  370.             ZoomPixel(hDC, x,                i*20 + 17,
  371.                            200 + (x-150)*12, i*20 + 12);
  372.     }
  373. }
  374.  
  375.  
  376. void KMyCanvas::TestCosmetic(HDC hDC)
  377. {
  378.     const LOGBRUSH logbrush = { BS_SOLID, RGB(0, 0, 0xFF), 0 };
  379.  
  380. //    SetMapMode(hDC, MM_ANISOTROPIC);
  381. //    SetViewportExtEx(hDC, 2, 2, NULL);
  382.  
  383.     for (int i = PS_SOLID; i<=PS_ALTERNATE; i++)
  384.     {
  385.         HPEN hPen;
  386.         const DWORD cycle[4] = { 4, 3, 2, 1 };
  387.         
  388.         if ( i==PS_USERSTYLE )
  389.             hPen = ExtCreatePen(PS_COSMETIC | i, 1, & logbrush, 4, cycle);
  390.         else
  391.             hPen = ExtCreatePen(PS_COSMETIC | i, 1, & logbrush, 0, NULL);
  392.         
  393.         Label(hDC, 10, i*20+10, mess_PenStyle[i]);
  394.  
  395.         if ( hPen )
  396.         {
  397.             SelectObject(hDC, hPen);
  398.             SetBkColor(hDC, RGB(0, 0xFF, 0));
  399.             SetBkMode(hDC, OPAQUE);
  400.         //    SetROP2(hDC, R2_XORPEN);
  401.  
  402.             // draw style line
  403.             Line(hDC, 150, i*20 + 17, 180, i*20 + 17);
  404.  
  405.             SetBkColor(hDC, RGB(0xFF, 0xFF, 0xFF));
  406.     
  407.             SelectObject(hDC, GetStockObject(BLACK_PEN));
  408.             DeleteObject(hPen);
  409.  
  410.             // copy to zoomed display
  411.             for (int x=150; x<180; x++)
  412.                 ZoomPixel(hDC, x,                i*20 + 17,
  413.                                200 + (x-150)*12, i*20 + 12);
  414.         }
  415.     }
  416. }
  417.  
  418. void KMyCanvas::TestGeometricWidth(HDC hDC)
  419. {
  420.     const LOGBRUSH logbrush = { BS_SOLID, RGB(0, 0xFF, 0), 0 };
  421.  
  422.     int save = SaveDC(hDC);
  423.  
  424.     HPEN hGreen = CreatePen(PS_SOLID, 0, RGB(0, 0xFF, 0));
  425.  
  426.     SetBkColor(hDC, RGB(0, 0xFF, 0));
  427.     SetBkMode(hDC, OPAQUE);
  428.  
  429.     // Geometric line width under transformation
  430.     
  431.         HPEN hPen = ExtCreatePen(PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_FLAT, 61, & logbrush, 0, NULL);
  432.         
  433.         KAffine affine;
  434.  
  435.         POINT p[6] = { 0, 0, 200, 0, -00, -30, 200, -30, 200, 30, 0, 30 };
  436.  
  437.         affine.Rotate(30, 0, 0);
  438.         affine.Translate(100, -200);
  439.  
  440.         SelectObject(hDC, hPen);
  441.         SetMapMode(hDC, MM_ANISOTROPIC);
  442.         SetViewportExtEx(hDC, 1, -1, NULL);
  443.  
  444.         SetGraphicsMode(hDC, GM_ADVANCED);
  445.  
  446.         SetWorldTransform(hDC, & affine.m_xm);
  447.  
  448.         LPtoDP(hDC, p, 6);
  449.  
  450.         Line(hDC, 0, 0, 200, 0);
  451.  
  452.         SelectObject(hDC, GetStockObject(BLACK_PEN));
  453.         DeleteObject(hPen);
  454.  
  455.         ModifyWorldTransform(hDC, NULL, MWT_IDENTITY);
  456.         SetGraphicsMode(hDC, GM_COMPATIBLE);
  457.  
  458.         SetBkColor(hDC, RGB(0xFF, 0xFF, 0xFF));
  459.         SetTextAlign(hDC, TA_LEFT);
  460.  
  461.         SetViewportExtEx(hDC, 1, 1, NULL);
  462.  
  463.         Line(hDC, p[0].x, p[0].y, 20, 200);
  464.         Label(hDC, 20, 200, "(x0,y0)");
  465.  
  466.         Line(hDC, p[1].x, p[1].y, 300, 80);
  467.         Label(hDC, 300, 80, "(x1,y1)");
  468.  
  469.         Line(hDC, p[5].x, p[5].y, 20, 120);
  470.         Label(hDC, 20, 120, "(x0-dx,y0+dy)");
  471.  
  472.         Line(hDC, p[4].x, p[4].y, 260, 40);
  473.         Label(hDC, 260, 40, "(x1-dx,y1+dy)");
  474.  
  475.         Line(hDC, p[3].x, p[3].y, 300, 160);
  476.         Label(hDC, 300, 160, "(x1+dx,y1-dy)");
  477.  
  478.         Line(hDC, p[2].x, p[2].y, 130, 250);
  479.         Label(hDC, 130, 250, "(x0+dx,y0-dy)");
  480.  
  481.         Label(hDC, 20, 20, "dx = pen_width * sin(°)/2");
  482.         Label(hDC, 20, 50, "dy = pen_width * cos(°)/2");
  483.     
  484.     DeleteObject(hGreen);
  485.  
  486.     RestoreDC(hDC, save);
  487. }
  488.  
  489.  
  490. class KGPen
  491. {
  492. public:
  493.     DWORD    m_cycle[4];
  494.     LOGBRUSH m_logbrush;
  495.     HPEN     m_hPen;
  496.  
  497.     KGPen()
  498.     {
  499.         m_cycle[0] = 20;
  500.         m_cycle[1] = 15;
  501.         m_cycle[2] = 10;
  502.         m_cycle[3] =  5;
  503.  
  504.         m_logbrush.lbStyle = BS_SOLID;
  505.         m_logbrush.lbColor = RGB(0, 0, 0xFF);
  506.         m_logbrush.lbHatch = 0;
  507.  
  508.         m_hPen = NULL;
  509.     }
  510.  
  511.     ~KGPen(void)
  512.     {
  513.         if ( m_hPen )
  514.             DeleteObject(m_hPen);
  515.     }
  516.  
  517.     void SetPen(int style, int width);
  518.  
  519.     void DrawLine(HDC hDC, const TCHAR * mess, int x0, int y0, int x1, int y1);
  520.     void DrawPolyLine(HDC hDC, int count, POINT * cord);
  521.     void DrawZ(HDC hDC, int endcap, int x, int y, COLORREF color, 
  522.                const TCHAR * desp, bool poly=false);
  523. };
  524.  
  525. void KGPen::SetPen(int style, int width)
  526. {
  527.     if ( m_hPen )
  528.         DeleteObject(m_hPen);
  529.  
  530.     if ( ( style & PS_STYLE_MASK ) == PS_USERSTYLE )
  531.         m_hPen = ExtCreatePen(PS_GEOMETRIC | style, width, & m_logbrush, 4, m_cycle);
  532.     else
  533.         m_hPen = ExtCreatePen(PS_GEOMETRIC | style, width, & m_logbrush, 0, NULL);
  534. }
  535.  
  536. void KGPen::DrawLine(HDC hDC, const TCHAR * mess, int x0, int y0, int x1, int y1)
  537. {
  538.     if ( mess )
  539.         Label(hDC, x0, y0-25, mess);
  540.  
  541.     if ( m_hPen )
  542.     {
  543.         SelectObject(hDC, m_hPen);
  544.         SetBkColor(hDC, RGB(0, 0xFF, 0));
  545.         SetBkMode(hDC, OPAQUE);
  546.  
  547.         // draw style line
  548.         Line(hDC, x0, y0, x1, y1);
  549.  
  550.         SetBkColor(hDC, RGB(0xFF, 0xFF, 0xFF));
  551.     
  552.         SelectObject(hDC, GetStockObject(BLACK_PEN));
  553.     }
  554. }
  555.  
  556. void KGPen::DrawPolyLine(HDC hDC, int count, POINT * cord)
  557. {
  558.     if ( m_hPen )
  559.     {
  560.         SelectObject(hDC, m_hPen);
  561.         SetBkColor(hDC, RGB(0, 0xFF, 0));
  562.         SetBkMode(hDC, OPAQUE);
  563.  
  564.         // draw style line
  565.         Polyline(hDC, cord, count); 
  566.  
  567.         SetBkColor(hDC, RGB(0xFF, 0xFF, 0xFF));
  568.     
  569.         SelectObject(hDC, GetStockObject(BLACK_PEN));
  570.     }
  571. }
  572.  
  573. void KGPen::DrawZ(HDC hDC, int endcap, int x, int y, COLORREF color, const TCHAR * desp, bool poly)
  574. {
  575.     SetPen(PS_SOLID | endcap, 25);
  576.  
  577.     if ( poly )
  578.     {
  579.         POINT p[4] = { x, y, x+100, y, x, y+50, x+100, y+50 };
  580.         
  581.         DrawPolyLine(hDC, 4, p);
  582.     }
  583.     else
  584.     {
  585.         DrawLine(hDC, NULL, x,     y,    x+100, y);
  586.  
  587.         m_logbrush.lbColor = color;
  588.         SetPen(PS_SOLID | endcap, 25);
  589.         DrawLine(hDC, NULL, x+100, y,    x   ,  y+50);
  590.  
  591.         m_logbrush.lbColor = RGB(0, 0, 0xFF);
  592.         SetPen(PS_SOLID | endcap, 25);
  593.         DrawLine(hDC, NULL, x    , y+50, x+100, y+50);
  594.     }
  595.  
  596.     SelectObject(hDC, GetStockObject(WHITE_PEN));
  597.     Line(hDC, x, y, x+100, y); LineTo(hDC, x, y+50); LineTo(hDC, x+100, y+50);
  598.  
  599.     while ( desp )
  600.     {
  601.         const TCHAR * p = _tcschr(desp, '\n');
  602.         int len;
  603.  
  604.         if ( p )
  605.             len = ((int) p - (int) desp)/sizeof(TCHAR);
  606.         else
  607.             len = _tcslen(desp);
  608.  
  609.         TextOut(hDC, x, y+70, desp, len);
  610.         y+= 20;
  611.  
  612.         if ( p )
  613.             desp = p + 1;
  614.         else
  615.             desp = NULL;
  616.     }
  617. }
  618.  
  619.  
  620. void KMyCanvas::TestGeometricStyle(HDC hDC)
  621. {
  622.     KGPen gpen;
  623.  
  624.     for (int i = PS_SOLID; i<=PS_ALTERNATE; i++)
  625.     {
  626.         Label(hDC, 10, i*20+30, mess_PenStyle[i]);
  627.  
  628.         int y = i*20 + 37;
  629.  
  630.         gpen.SetPen(i | PS_ENDCAP_FLAT, 3);
  631.         gpen.DrawLine(hDC, (i==PS_SOLID) ? "w=3, flat" : NULL,          150, y, 250, y);
  632.         
  633.         gpen.SetPen(i | PS_ENDCAP_FLAT, 7);
  634.         gpen.DrawLine(hDC, (i==PS_SOLID) ? "w=7, flat" : NULL,          270, y, 370, y);
  635.  
  636.         gpen.SetPen(i | PS_ENDCAP_SQUARE, 11);
  637.         gpen.DrawLine(hDC, (i==PS_SOLID) ? "w=11, square" : NULL,       390, y, 490, y);
  638.  
  639.         gpen.m_logbrush.lbStyle = BS_HATCHED;
  640.         gpen.m_logbrush.lbHatch = HS_DIAGCROSS;
  641.  
  642.         gpen.SetPen(i | PS_ENDCAP_ROUND, 15);
  643.         gpen.DrawLine(hDC, (i==PS_SOLID) ? "w=15, round, hatch" : NULL, 510, y, 610, y);
  644.  
  645.         gpen.m_logbrush.lbStyle = BS_SOLID;
  646.         gpen.m_logbrush.lbHatch = 0;
  647.     }
  648.  
  649.     gpen.DrawZ(hDC, PS_ENDCAP_FLAT,    50, 260, RGB(0xFF, 0x3F, 0x0F), _T("PS_ENDCAP_FLAT"));
  650.     gpen.DrawZ(hDC, PS_ENDCAP_SQUARE, 220, 260, RGB(0xFF, 0x3F, 0x0F), _T("PS_ENDCAP_SQUARE"));
  651.     gpen.DrawZ(hDC, PS_ENDCAP_ROUND,  390, 260, RGB(0xFF, 0x3F, 0x0F), _T("PS_ENDCAP_ROUND"));
  652.     
  653.     SetROP2(hDC, R2_XORPEN);
  654.     gpen.DrawZ(hDC, PS_ENDCAP_ROUND,  560, 260, RGB(0xFF, 0x3F, 0x0F), _T("PS_ENDCAP_ROUND\nR2_XORPEN"));
  655.  
  656.     SetROP2(hDC, R2_COPYPEN);
  657.  
  658. //    FLOAT f;
  659.  
  660. //    SetMiterLimit(hDC, 4.35, & f);
  661.  
  662.     gpen.DrawZ(hDC, PS_ENDCAP_FLAT   | PS_JOIN_BEVEL,  50, 400, RGB(0xFF, 0x3F, 0x0F), _T("PS_ENDCAP_FLAT\nPS_JOIN_BEVEL"), true);
  663.     gpen.DrawZ(hDC, PS_ENDCAP_SQUARE | PS_JOIN_MITER, 220, 400, RGB(0xFF, 0x3F, 0x0F), _T("PS_ENDCAP_SQUARE\nPS_JOIN_MITER"), true);
  664.     gpen.DrawZ(hDC, PS_ENDCAP_ROUND  | PS_JOIN_ROUND, 390, 400, RGB(0xFF, 0x3F, 0x0F), _T("PS_ENDCAP_ROUND\nPS_JOIN_ROUND"), true);
  665.     
  666.     SetROP2(hDC, R2_XORPEN);
  667.     gpen.DrawZ(hDC, PS_ENDCAP_ROUND  | PS_JOIN_ROUND, 560, 400, RGB(0xFF, 0x3F, 0x0F), _T("PS_ENDCAP_ROUND\nPS_JOIN_ROUND\nR2_XORPEN"), true);
  668. }
  669.  
  670.  
  671. void KMyCanvas::TestLine1(HDC hDC)
  672. {
  673.     const int    N      = 19;
  674.     const int    Radius = 200;
  675.     const double theta  = 3.1415926 * 2 / N;
  676.     
  677.     SelectObject(hDC, GetStockObject(DC_PEN));
  678.  
  679.     // simple line drawing
  680.     const COLORREF color[] = { 
  681.         RGB(0, 0, 0), RGB(255,0,0), RGB(0,255,0), RGB(0,0, 255),
  682.         RGB(255,255,0), RGB(0, 255, 255), RGB(255, 255, 0),
  683.         RGB(127, 255, 0), RGB(0, 127, 255), RGB(255, 0, 127)
  684.     };
  685.     
  686.     for (int p=0; p<N; p++)
  687.     for (int q=0; q<p; q++)
  688.     {
  689.         SetDCPenColor(hDC, color[min(p-q, N-p+q)]);
  690.  
  691.         Line(hDC, (int)(220 + Radius * sin(p * theta)), 
  692.                   (int)(220 + Radius * cos(p * theta)), 
  693.                   (int)(220 + Radius * sin(q * theta)), 
  694.                   (int)(220 + Radius * cos(q * theta)));
  695.     }
  696. }
  697.  
  698.  
  699. void Triangle(HDC hDC, int x0, int y0, int x1, int y1, int x2, int y2, bool extra=false)
  700. {
  701.     POINT corner[5] = { x0, y0, x1, y1, x2, y2, x0, y0, x1, y1 };
  702.  
  703.     if ( extra ) // extra segment to make nicer closing join
  704.         Polyline(hDC, corner, 5);
  705.     else
  706.         Polyline(hDC, corner, 4);
  707. }
  708.  
  709.  
  710. void CALLBACK LineDDAProc(int x, int y, LPARAM lpData)
  711. {
  712.     HDC hDC = (HDC) lpData;
  713.     POINT cur;
  714.  
  715.     GetCurrentPositionEx(hDC, & cur);
  716.  
  717.     if ( (cur.x & 31)== 0 ) // every 32th call
  718.         Triangle(hDC, x, y-16, x+20, y+18, x-20, y+18);
  719.  
  720.     cur.x ++;
  721.     MoveToEx(hDC, cur.x, cur.y, NULL);
  722. }
  723.  
  724.  
  725. void KMyCanvas::TestLine2(HDC hDC)
  726. {
  727.     LOGBRUSH logbrush = { BS_SOLID, RGB(0, 0, 0xFF), 0 };
  728.  
  729.     HPEN hPen = ExtCreatePen(PS_GEOMETRIC | PS_SOLID | 
  730.                     PS_ENDCAP_FLAT | PS_JOIN_MITER, 
  731.                     15, & logbrush, 0, NULL);
  732. //    SetROP2(hDC, R2_XORPEN);
  733.     
  734.     HGDIOBJ hOld = SelectObject(hDC, hPen);
  735.     
  736.     // drawing triangle using mutlple LineTo calls
  737.     SetViewportOrgEx(hDC, 100, 50, NULL);
  738.     Line(hDC, 0, 0, 50, 86); 
  739.     LineTo(hDC, -50, 86); LineTo(hDC, 0, 0);
  740.     
  741.     // using polyline
  742.     SetViewportOrgEx(hDC, 230, 50, NULL);
  743.     Triangle(hDC, 0, 0, 50, 86, -50, 86, false );
  744.  
  745.     // using polyline, extra segment
  746.     SetViewportOrgEx(hDC, 360, 50, NULL);
  747.     Triangle(hDC, 0, 0, 50, 86, -50, 86, true );
  748.  
  749.     // using LineDDA
  750.     SetViewportOrgEx(hDC, 490, 50, NULL);
  751.     SelectObject(hDC, hOld);
  752.     DeleteObject(hPen);
  753.  
  754.     hPen = ExtCreatePen(PS_GEOMETRIC | PS_DOT | PS_ENDCAP_ROUND, 
  755.                     3, & logbrush, 0, NULL);
  756.     SelectObject(hDC, hPen);
  757.  
  758.     LineDDA( 0,  0,   50, 86, LineDDAProc, (LPARAM) hDC); 
  759.     LineDDA( 50, 86, -50, 86, LineDDAProc, (LPARAM) hDC); 
  760.     LineDDA(-50, 86,   0,  0, LineDDAProc, (LPARAM) hDC);
  761.  
  762.     SetViewportOrgEx(hDC, 50, 150, NULL);
  763.     SelectObject(hDC, hOld);
  764.     DeleteObject(hPen);
  765.  
  766.     // PolyPolyline
  767.     hPen = ExtCreatePen(PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_ROUND, 
  768.                     5, & logbrush, 0, NULL);
  769.     SelectObject(hDC, hPen);
  770.     
  771.     POINT P[10] = { 0,  0, 100,  0, 100, 100, 0, 100,  0,  0,
  772.                   50, 50, 150, 50, 150, 150, 50,150, 50, 50 };
  773.     DWORD c[2] = { 5, 5 };
  774.     SetROP2(hDC, R2_XORPEN);
  775.     PolyPolyline(hDC, P, c, 2);
  776.  
  777.     SetViewportOrgEx(hDC, 0, 0, NULL);
  778.     SelectObject(hDC, hOld);
  779.     DeleteObject(hPen);
  780. }
  781.  
  782.  
  783. void KMyCanvas::TestBezier(HDC hDC)
  784. {
  785. }
  786.  
  787.  
  788. void KMyCanvas::DragBezier(HDC hDC, int x, bool on)
  789. {
  790.     SetROP2(hDC, R2_XORPEN);
  791.     SetBkMode(hDC, TRANSPARENT);
  792.  
  793.     LOGBRUSH logbrush = { BS_SOLID, RGB(0xFF, 0xFF, 0), 0 };
  794.  
  795.     m_bezier[0].x =  30; m_bezier[0].y = 330;
  796.     m_bezier[1].x = 130; m_bezier[1].y =  30;
  797.     m_bezier[2].x = 430; m_bezier[2].y = 130;
  798.     m_bezier[3].x = 630; m_bezier[3].y = 330;
  799.  
  800.     HPEN hPen, hOld;
  801.  
  802.     hPen = CreatePen(PS_DOT, 0, RGB(0xFF, 0, 0xFF));
  803.     hOld = (HPEN) SelectObject(hDC, hPen);
  804.     // Dotted line link control points
  805.     Polyline(hDC, m_bezier, 4);
  806.     SelectObject(hDC, hOld);
  807.     DeleteObject(hPen);
  808.  
  809.     hPen = ExtCreatePen(PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_ROUND, 3, & logbrush, 0, NULL);
  810.     hOld = (HPEN) SelectObject(hDC, hPen);
  811.  
  812.     // Solid thick Bezier curve
  813. //    PolyBezier(hDC, m_bezier, 4);
  814.     Bezier(hDC, 30, 330, 130, 30, 430, 130, 630, 330);
  815.     
  816.     SelectObject(hDC, hOld);
  817.     DeleteObject(hPen);
  818.  
  819.     double  t = (x%101) / 100.0;
  820.  
  821.     hPen = CreatePen(PS_DASH, 0, RGB(0, 0xFF, 0xFF));
  822.     hOld = (HPEN) SelectObject(hDC, hPen);
  823.  
  824.     POINT P12; P(P12, m_bezier[0], m_bezier[1], t);
  825.     POINT P23; P(P23, m_bezier[1], m_bezier[2], t);
  826.     POINT P34; P(P34, m_bezier[2], m_bezier[3], t);
  827.  
  828.     POINT P1223; P(P1223, P12, P23, t);
  829.     POINT P2334; P(P2334, P23, P34, t);
  830.     POINT P0;    P(P0   , P1223, P2334, t);
  831.     
  832.     // P(t) lines
  833.     Line(hDC, P12, P23);
  834.     Line(hDC, P23, P34);
  835.     Line(hDC, P1223, P2334);
  836.  
  837.     SelectObject(hDC, hOld);
  838.     DeleteObject(hPen);
  839.  
  840.     SetROP2(hDC, R2_COPYPEN);
  841.  
  842.     // labels
  843.     if ( on )
  844.         SetTextColor(hDC, 0);
  845.     else
  846.         SetTextColor(hDC, RGB(0xFF, 0xFF, 0xFF));
  847.  
  848.     Label(hDC, m_bezier[0].x,    m_bezier[0].y+10, "P1");
  849.     Label(hDC, m_bezier[1].x-20, m_bezier[1].y,    "P2");
  850.     Label(hDC, m_bezier[2].x+15, m_bezier[2].y,    "P3");
  851.     Label(hDC, m_bezier[3].x,    m_bezier[3].y+10, "P4");
  852.  
  853.     Label(hDC, P12.x-30, P12.y,    "P12");
  854.     Label(hDC, P23.x+10, P23.y-20, "P23");
  855.     Label(hDC, P34.x+30, P34.y+10, "P34");
  856.  
  857.     Label(hDC, P1223.x-20, P1223.y-20, "P1223");
  858.     Label(hDC, P2334.x-20, P2334.y-20, "P2334");
  859.  
  860.     Label(hDC, P0.x-20, P0.y-20, "P");
  861.  
  862.     TCHAR num[10];
  863.  
  864.     sprintf(num, "t=%8.5f    ", t);
  865.     Label(hDC, 250, 250, num);
  866. }
  867.  
  868.  
  869.  
  870. void KMyCanvas::BezierDemo(HDC hDC)
  871. {
  872.     KPen Red (PS_DOT, 0, RGB(0xFF, 0, 0));
  873.     KPen Blue(PS_SOLID, 3, RGB(0, 0, 0xFF));
  874.  
  875.     for (int z=0; z<=200; z+=40)
  876.     {
  877.         int x = 50, y = 240;
  878.  
  879.         POINT p[4] = { x, y, x+ 50, y-z, x+100, y-z, x+150, y }; x+= 160;
  880.         POINT q[4] = { x, y, x+ 50, y-z, x+100, y+z, x+150, y }; x+= 180;
  881.         
  882.         POINT r[4] = { x, y, x+170, y-z, x- 20, y-z, x+150, y }; x+= 200;
  883.         POINT s[4] = { x, y, x+170, y-z, x- 20, y+z, x+150, y }; x+= 180;
  884.         
  885.         POINT t[4] = { x+75, y, x,  y-z, x+150, y-z, x+75, y }; 
  886.  
  887.         Red.Select(hDC);
  888.         Polyline(hDC, p, 4);
  889.         Polyline(hDC, q, 4);
  890.         Polyline(hDC, r, 4);
  891.         Polyline(hDC, s, 4);
  892.         Polyline(hDC, t, 4);
  893.         Red.UnSelect();
  894.  
  895.         Blue.Select(hDC);
  896.         PolyBezier(hDC, p, 4);
  897.         PolyBezier(hDC, q, 4);
  898.         PolyBezier(hDC, r, 4);
  899.         PolyBezier(hDC, s, 4);
  900.         PolyBezier(hDC, t, 4);
  901.         Blue.UnSelect();
  902.  
  903.         if ( z==200 )
  904.         {
  905.             Label(hDC, p,   0, 10, -20, -10, +10, -10, -18,  10);
  906.             Label(hDC, q,   0, 10, -20, -10, +15, -10, -18, -25);
  907.             Label(hDC, r,   0, 10,  +5, -10, -20, -10, -18,  10);
  908.             Label(hDC, s,   0, 10, -20, -10, +15, -10, -18, -25);
  909.             Label(hDC, t, -20, 10,  +5, -10, -20, -10, + 5,  10);
  910.         }                
  911.     }
  912. }
  913.  
  914.  
  915. void KMyCanvas::TestBezierPen(HDC hDC)
  916. {
  917.     const POINT P[12] = 
  918.     {   50, 200, 100,  50, 150, 350, 200, 200,
  919.        150,  50, 100, 350,  50, 200,
  920.        125, 275, 175, 200, 125, 125,  75, 200, 125, 275
  921.     };
  922.     
  923.     const BYTE T[12] = 
  924.     {     PT_MOVETO, PT_BEZIERTO, PT_BEZIERTO, PT_BEZIERTO,
  925.         PT_BEZIERTO , PT_BEZIERTO, PT_BEZIERTO | PT_CLOSEFIGURE,
  926.         PT_MOVETO, PT_LINETO, PT_LINETO, PT_LINETO, PT_LINETO | PT_CLOSEFIGURE
  927.     };
  928.  
  929.     SetROP2(hDC, R2_XORPEN);
  930.  
  931.     LOGBRUSH logbrush = { BS_SOLID, RGB(0xFF, 0xFF, 0), 0 };
  932.  
  933.     HPEN hPen = ExtCreatePen(PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_FLAT | PS_JOIN_MITER, 15, & logbrush, 0, NULL);
  934.     SelectObject(hDC, hPen);
  935.  
  936.     PolyBezier(hDC, P, 7); // two Bezier curves
  937.     Polyline(hDC, P+7, 5); // diamond shape
  938.     
  939.     SetViewportOrgEx(hDC, 200, 0, NULL);
  940.     PolyDraw(hDC, P, T, 12);    // Bezier curves and diamon shape together
  941.     
  942.     SetViewportOrgEx(hDC, 0, 0, NULL);
  943.     SelectObject(hDC, GetStockObject(BLACK_PEN));
  944.     DeleteObject(hPen);
  945. }
  946.  
  947.  
  948. void KMyCanvas::TestArc(HDC hDC)
  949. {
  950. //    SetMapMode(hDC, MM_ANISOTROPIC);
  951. //    SetViewportExtEx(hDC, 1, -1, NULL);
  952.  
  953.     // 200 by 250
  954.     const int A =  80;
  955.     const int B = 100;
  956.     
  957.     POINT P[5] = { -A, -B, A, -B, A, B, -A, B, -A, -B };
  958.     POINT S    = {  A * 6/5, -B * 3/5 };
  959.     POINT E    = {  A * 6/5,  B * 3/5 };
  960.  
  961.     POINT PAA[5] = { -A, -A, A, -A, A, A, -A, A, -A, -A };
  962.     POINT SAA    = {  A * 6/5, -A * 3/5 };
  963.     POINT EAA    = {  A * 6/5,  A * 3/5 };
  964.  
  965.     // Arc counterclockwise
  966.     // ArcTo clockwise
  967.  
  968.     for (int i=0; i<3; i++)
  969.     {
  970.         if ( i==0 )
  971.         {
  972.             SetViewportOrgEx(hDC, 200, 300, 0);
  973.             SetArcDirection(hDC, AD_COUNTERCLOCKWISE);
  974.             Label(hDC, -65, P[0].y-40, "Arc, counterclockwise");
  975.         }
  976.         else
  977.         {
  978.             SetViewportOrgEx(hDC, 200 + i* A * 3, 300, 0);
  979.             SetArcDirection(hDC, AD_CLOCKWISE);
  980.  
  981.             if ( i==1)
  982.                 Label(hDC, -55, P[0].y-40, "ArcTo, clockwise");
  983.             else if (i==2)
  984.             {
  985.                 Label(hDC, -30, P[0].y-40, "AngleArc");
  986.                 memcpy(P, PAA, sizeof(P));
  987.                 S = SAA;
  988.                 E = EAA;
  989.             }
  990.         }
  991.     
  992.         HPEN hPen = CreatePen(PS_DOT, 0, RGB(0xFF, 0, 0));
  993.         HPEN hOld = (HPEN) SelectObject(hDC, hPen);
  994.  
  995.         // bounding rectangle, start/end lines
  996.         Polyline(hDC, P, 5);       Dot(hDC, P[0].x ,P[0].y); Dot(hDC, P[2].x ,P[2].y);
  997.         Line(hDC, 0, 0, S.x, S.y); Dot(hDC, S.x, S.y);
  998.         Line(hDC, 0, 0, E.x, E.y); Dot(hDC, E.x, E.y);
  999.  
  1000.         SelectObject(hDC, hOld);
  1001.         DeleteObject(hPen);
  1002.  
  1003.         hPen = CreatePen(PS_INSIDEFRAME, 3, RGB(0, 0, 0xFF));
  1004.         SelectObject(hDC, hPen);
  1005.  
  1006.     //    SetROP2(hDC, R2_XORPEN);
  1007.  
  1008.         // solid arc
  1009.         switch ( i )
  1010.         {
  1011.             case 0:
  1012.                 Arc(hDC, P[0].x, P[0].y, P[2].x, P[2].y, S.x, S.y, E.x, E.y);
  1013.                 break;
  1014.  
  1015.             case 1:
  1016.                 MoveToEx(hDC, P[0].x, (P[0].y+P[2].y)/2, NULL);
  1017.                 ArcTo(hDC, P[0].x, P[0].y, P[2].x, P[2].y, S.x, S.y, E.x, E.y);
  1018.                 break;
  1019.  
  1020.             case 2:
  1021.                 MoveToEx(hDC, P[0].x, (P[0].y+P[2].y)/2, NULL);
  1022.                 AngleArcTo(hDC, (P[0].x + P[2].y)/2, (P[0].x + P[2].y)/2,A, (float)26.56, (float)(360-26.56*2));
  1023.                 break;
  1024.         }
  1025.         
  1026.         SelectObject(hDC, hOld);
  1027.         DeleteObject(hPen);
  1028.     
  1029.         // labels
  1030.         Label(hDC, P[0].x, P[0].y-20,  "(Left, Top)");
  1031.         Label(hDC, P[2].x-100, P[2].y+5, "(Bottom, Right)");
  1032.  
  1033.         if ( i==2 )
  1034.         {
  1035.             Label(hDC, S.x-20, S.y-20, "eStartAngle");
  1036.             Label(hDC, E.x-20, E.y+5,  "eStartAngle + eSweepAngle");
  1037.         }
  1038.         else
  1039.         {
  1040.             Label(hDC, S.x-20, S.y-20, "(xStart, yStart)");
  1041.             Label(hDC, E.x-20, E.y+5,  "(xEnd, yEnd)");
  1042.         }
  1043.     }
  1044.  
  1045. //    SetViewportExtEx(hDC, 1, 1, NULL);
  1046.     SetViewportOrgEx(hDC, 0, 0, NULL);
  1047. }
  1048.  
  1049.  
  1050.  
  1051. void KMyCanvas::ArcToBezier(HDC hDC)
  1052. {
  1053.     SetMapMode(hDC, MM_ANISOTROPIC);
  1054.     SetViewportExtEx(hDC, 1, -1, NULL);
  1055.  
  1056.     SetViewportOrgEx(hDC, 50, 450, NULL);
  1057.  
  1058.     Line(hDC, 0, 0, 0, 420);
  1059.     Line(hDC, 0, 0, 420, 0);
  1060.  
  1061.     // Draw Bezier curves for m=0.0 to 1.0
  1062.     {
  1063.         KPen pen(PS_COSMETIC | PS_ALTERNATE, 1, RGB(0xFF, 0, 0), 0, NULL, hDC);
  1064.     
  1065.         for (int m=0; m<=400; m+=80)
  1066.         {
  1067.             POINT P[4] = { 0, 400, m, 400, 400, m, 400, 0 };
  1068.  
  1069.         //    Polyline(hDC, P, 4);
  1070.             PolyBezier(hDC, P, 4);
  1071.  
  1072.             double error, t;
  1073.             error = Error(m/400.0, t);
  1074.  
  1075.             TCHAR mess[128];
  1076.             
  1077.             sprintf(mess, _T("m=%3.1f, error(%5.3f) = %+8.5f%%"), m/400.0, t, error*100);
  1078.             Label(hDC, 20, 170- m/3, mess);
  1079.         }
  1080.     }
  1081.  
  1082.     double M = 4*(sqrt(2)-1)/3;
  1083.     
  1084.     int m = (int) (M*400);
  1085.     
  1086.     POINT Q[4] = { 0, 400, m, 400, 400, m, 400, 0 };
  1087.  
  1088.     {
  1089.         KPen blue(PS_COSMETIC | PS_ALTERNATE, 1, RGB(0, 0, 0xFF), 0, NULL, hDC);
  1090.  
  1091.         Polyline(hDC, Q, 4);
  1092.     }
  1093.  
  1094.     {
  1095.         KPen pen(PS_SOLID, 3, RGB(0, 0, 0xFF), hDC);
  1096.         PolyBezier(hDC, Q, 4);
  1097.  
  1098.         Label(hDC, Q[0].x+5,  Q[0].y+20, "(0,1)");
  1099.         Label(hDC, Q[1].x+5,  Q[1].y+20, "(m,1)");
  1100.         Label(hDC, Q[2].x+10, Q[2].y+ 5, "(1,m)");
  1101.         Label(hDC, Q[3].x+10, Q[3].y+20, "(1,0)");
  1102.     }
  1103.  
  1104.     double error, t;
  1105.     error = Error(M, t);
  1106.  
  1107.     TCHAR mess[128];
  1108.             
  1109.     sprintf(mess, _T("m=%8.6f, error(%5.3f) = %+8.6f%%"), M, t, error*100);
  1110.     Label(hDC, 20, -20, mess);
  1111.  
  1112.     // Test FullEllipse
  1113.     for (int i=0; i<100; i+=10)
  1114.         EllipseToBezier(hDC, 530-i, 280-i, 530+i, 320+i);
  1115.     
  1116.     SetViewportExtEx(hDC, 1, 1, NULL);
  1117.     SetViewportOrgEx(hDC, 0, 0, NULL);
  1118. }
  1119.  
  1120.  
  1121. void KMyCanvas::AngleArcToBezier(HDC hDC)
  1122. {
  1123.     SetMapMode(hDC, MM_ANISOTROPIC);
  1124.     SetViewportExtEx(hDC, 1, -1, NULL);
  1125.  
  1126.     SetViewportOrgEx(hDC, 400, 350, NULL);
  1127.  
  1128.     for (int angle=15; angle<=240; angle+=15)
  1129.     {
  1130.         TCHAR mess[32];
  1131.         double err;
  1132.  
  1133.         ::AngleArcToBezier(hDC, 0, 0, 50+angle*2/3, 50+angle*2/3, 0, angle*3.1415926/180, & err);
  1134.  
  1135.         sprintf(mess, "%d degree, error=%8.5f%%", angle, err*100);
  1136.         Label(hDC, -380, 350-angle, mess);
  1137.     }
  1138.  
  1139.     SetViewportExtEx(hDC, 1, 1, NULL);
  1140.     SetViewportOrgEx(hDC, 0, 0, NULL);
  1141. }
  1142.  
  1143.  
  1144. void KMyCanvas::TestPath(HDC hDC)
  1145. {
  1146.     SetViewportOrgEx(hDC, 150, 200, NULL);
  1147.  
  1148.     KPen wide(PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_FLAT | PS_JOIN_MITER, 17, RGB(0, 0, 0xFF), 0, NULL);
  1149. //    KPen wide(PS_SOLID, 0, RGB(0, 0, 0xFF));
  1150.     wide.Select(hDC);
  1151.  
  1152. //    KPen wide(PS_COSMETIC | PS_SOLID, 1, RGB(0, 0, 0xFF), 0, NULL);
  1153. //    wide.Select(hDC);
  1154.     
  1155.     // Path construction
  1156.     {
  1157.         BeginPath(hDC);
  1158.         
  1159.         MoveToEx(hDC, 0, 0, NULL);
  1160.         AngleArc(hDC, 0, 0, 150, 0, 135);
  1161.  
  1162.         POINT P[] = { -75, 20, -20, -75, 40, -40 };
  1163.         PolyBezierTo(hDC, P, 3);
  1164.         
  1165.         CloseFigure(hDC);
  1166.  
  1167.         EndPath(hDC);
  1168.     }
  1169.  
  1170. //    SetViewportOrgEx(hDC, 160, 200, NULL);
  1171.     
  1172. //    int n = SaveDC(hDC);
  1173. //    StrokePath(hDC);
  1174. //    RestoreDC(hDC, n);
  1175. //    SetViewportOrgEx(hDC, 150, 200, NULL);
  1176.  
  1177.     KPathData org;    org.GetPathData(hDC);
  1178.     
  1179.     FlattenPath(hDC);
  1180.     KPathData flt;  flt.GetPathData(hDC);
  1181.  
  1182.     WidenPath(hDC);
  1183.     KPathData wid;  wid.GetPathData(hDC);
  1184.  
  1185.     wide.UnSelect();
  1186.  
  1187.     //////////////////////////////////////////////
  1188.     // Draw original path data
  1189.     PolyDraw(hDC, org.m_pPoint, org.m_pFlag, org.m_nCount);
  1190.  
  1191.     // Display origin control points 
  1192.     SetViewportOrgEx(hDC, 450, 200, NULL);
  1193.     org.MarkPoints(hDC);
  1194.  
  1195.     //////////////////////////////////////////////
  1196.     // Display flatten lines
  1197.     SetViewportOrgEx(hDC, 150, 400, NULL);
  1198.     PolyDraw(hDC, flt.m_pPoint, flt.m_pFlag, flt.m_nCount);
  1199.     
  1200.  
  1201.     // Display flatten control
  1202.     SetViewportOrgEx(hDC, 450, 400, NULL);
  1203.     flt.MarkPoints(hDC);
  1204.  
  1205.     ///////////////////////////////////////////
  1206.     // Display flatten lines
  1207.     SetViewportOrgEx(hDC, 150, 600, NULL);
  1208.     PolyDraw(hDC, wid.m_pPoint, wid.m_pFlag, wid.m_nCount);
  1209.  
  1210.     // Display flatten control
  1211.     SetViewportOrgEx(hDC, 450, 600, NULL);
  1212.     wid.MarkPoints(hDC);
  1213.  
  1214.     SetViewportOrgEx(hDC, 750, 200, NULL);
  1215.  
  1216.     // Use WidenPath and Stroke path to show geometric line construction
  1217.     for (int i=0; i<3; i++)
  1218.     {
  1219.         const WideStyle[] = { PS_ENDCAP_SQUARE | PS_JOIN_MITER,
  1220.                               PS_ENDCAP_ROUND  | PS_JOIN_ROUND,
  1221.                               PS_ENDCAP_FLAT   | PS_JOIN_BEVEL
  1222.                             };
  1223.         const ThinStyle[] = { PS_ALTERNATE, PS_DOT, PS_SOLID };
  1224.         const Color    [] = { RGB(0xFF, 0, 0), RGB(0, 0, 0xFF), RGB(0,0,0) };
  1225.  
  1226.  
  1227.         {
  1228.             KPen wide(PS_GEOMETRIC | PS_SOLID | WideStyle[i], 70, RGB(0, 0, 0xFF), 0, NULL, hDC);
  1229.  
  1230.             BeginPath(hDC);
  1231.                 MoveToEx(hDC, 150, 0, NULL);
  1232.                 LineTo(hDC, 0, 0);
  1233.                 LineTo(hDC, 100, -100);
  1234.             EndPath(hDC);
  1235.             WidenPath(hDC);
  1236.         }
  1237.         
  1238.         if (i==2 )
  1239.         {
  1240.             KPathData pd; 
  1241.             pd.GetPathData(hDC);
  1242.             pd.MarkPoints(hDC, false);
  1243.         }
  1244.  
  1245.         {
  1246.             KPen thin(PS_COSMETIC | ThinStyle[i], 1, Color[i], 0, NULL, hDC);
  1247.             
  1248.             StrokePath(hDC);
  1249.         }
  1250.     }
  1251.  
  1252.     SetViewportOrgEx(hDC, 0, 0, NULL);
  1253.  
  1254. #ifdef TEST_INSIDEFRAME
  1255.  
  1256.     BeginPath(hDC);
  1257.  
  1258.     Ellipse(hDC, 0, 0, 100, 100);
  1259.  
  1260.     HPEN    hPen = CreatePen(PS_INSIDEFRAME, 21, RGB(0xFF, 0, 0));
  1261.     HGDIOBJ hOld = SelectObject(hDC, hPen);
  1262.     
  1263.     Ellipse(hDC, 0, 0, 100, 100);
  1264.  
  1265.     EndPath(hDC);
  1266.  
  1267.     SelectObject(hDC, hOld);
  1268.  
  1269.     StrokePath(hDC);
  1270.  
  1271.     DeleteObject(hPen);
  1272.  
  1273. #endif
  1274. }
  1275.  
  1276.  
  1277. void KMyCanvas::TestPathStyleCurve(HDC hDC)
  1278. {
  1279.     SetViewportOrgEx(hDC, 400, 300, NULL);
  1280.  
  1281.     for (int i=6; i<10; i++)
  1282.     {
  1283.         BeginPath(hDC);
  1284.         Ellipse(hDC, -50-i*25, -50-i*20, 50+i*25, 50+i*20);
  1285.         CloseFigure(hDC);
  1286.         EndPath(hDC);
  1287.  
  1288.         FlattenPath(hDC);
  1289.         KPathData flt;  
  1290.         flt.GetPathData(hDC);
  1291.  
  1292.         KDashes dash(hDC, i);
  1293.         KStyleCurve sc(& dash);
  1294.  
  1295.         sc.PolyDraw(flt.m_pPoint, flt.m_pFlag, flt.m_nCount);
  1296.     }
  1297.  
  1298.     SetViewportOrgEx(hDC, 0, 0, NULL);
  1299. }
  1300.  
  1301.  
  1302. void KMyCanvas::TestMapPath(HDC hDC)
  1303. {
  1304.     {
  1305.         KPen wide(PS_GEOMETRIC | PS_SOLID | PS_ENDCAP_FLAT | PS_JOIN_MITER, 15, 
  1306.                 RGB(0, 0, 0xFF), 0, NULL, hDC);
  1307.  
  1308.         BeginPath(hDC);
  1309.             Rectangle(hDC, 50, 50, 200, 500);
  1310.         EndPath(hDC);
  1311.  
  1312.         WidenPath(hDC);
  1313.     }
  1314.  
  1315.     KPathData pd;
  1316.     pd.GetPathData(hDC);
  1317.  
  1318.     StrokePath(hDC);
  1319.  
  1320.     KBiLinearMap bl;
  1321.     bl.SetWindow(50, 50, 150, 450);
  1322.     
  1323.     POINT Dest[] = { 200+9, 500, 200+9, 50, 500+9, 400, 450+9, 300 };
  1324.     bl.SetDestination(Dest);
  1325.  
  1326.     pd.MapPoints(bl);
  1327.  
  1328.     BeginPath(hDC);
  1329.         PolyDraw(hDC, pd.m_pPoint, pd.m_pFlag, pd.m_nCount);
  1330.     EndPath(hDC);
  1331.  
  1332.     SelectObject(hDC, GetStockObject(BLACK_BRUSH));
  1333.     FillPath(hDC);
  1334. }
  1335.  
  1336.  
  1337. void KMyCanvas::OnDraw(HDC hDC, const RECT * rcPaint)
  1338. {
  1339.     switch ( m_test )
  1340.     {
  1341.         case IDM_TEST_DRAWMODE:
  1342.             TestDrawMode(hDC);
  1343.             break;
  1344.  
  1345.         case IDM_TEST_WIDTHCAP:
  1346.             TestWidthCap(hDC);
  1347.             break;
  1348.  
  1349.         case IDM_TEST_DCPEN:
  1350.             TestDCPen(hDC);
  1351.             break;
  1352.  
  1353.         case IDM_TEST_PENSTYLE:
  1354.             TestPenStyle(hDC);
  1355.             break;
  1356.  
  1357.         case IDM_TEST_COSMETIC:
  1358.             TestCosmetic(hDC);
  1359.             break;
  1360.  
  1361.         case IDM_TEST_GEOMETRIC_WIDTH:
  1362.             TestGeometricWidth(hDC);
  1363.             break;
  1364.  
  1365.         case IDM_TEST_GEOMETRIC_STYLE:
  1366.             TestGeometricStyle(hDC);
  1367.             break;
  1368.  
  1369.         case IDM_TEST_LINE1:
  1370.             TestLine1(hDC);
  1371.             break;
  1372.  
  1373.         case IDM_TEST_LINE2:
  1374.             TestLine2(hDC);
  1375.             break;
  1376.  
  1377.         case IDM_TEST_BEZIER:
  1378.             TestBezier(hDC);
  1379.             break;
  1380.  
  1381.         case IDM_TEST_BEZIERDEMO:
  1382.             BezierDemo(hDC);
  1383.             break;
  1384.  
  1385.         case IDM_TEST_BEZIERPEN:
  1386.             TestBezierPen(hDC);
  1387.             break;
  1388.  
  1389.         case IDM_TEST_ARC:
  1390.             TestArc(hDC);
  1391.             break;
  1392.  
  1393.         case IDM_TEST_ARCBEZIER:
  1394.             ArcToBezier(hDC);
  1395.             break;
  1396.  
  1397.         case IDM_TEST_ANGLEARCBEZIER:
  1398.             AngleArcToBezier(hDC);
  1399.             break;
  1400.  
  1401.         case IDM_TEST_PATH:
  1402.             TestPath(hDC);
  1403.             break;
  1404.  
  1405.         case IDM_TEST_PATHSTYLECURVE:
  1406.             TestPathStyleCurve(hDC);
  1407.             break;
  1408.  
  1409.         case IDM_TEST_MAPPATH:
  1410.             TestMapPath(hDC);
  1411.     }
  1412. }
  1413.  
  1414. class KLogoFrame : public KFrame
  1415. {
  1416.     void GetWndClassEx(WNDCLASSEX & wc)
  1417.     {
  1418.         KFrame::GetWndClassEx(wc);
  1419.  
  1420.         wc.hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_LINE));
  1421.     }
  1422.  
  1423. public:
  1424.     KLogoFrame(HINSTANCE hInstance, const TBBUTTON * pButtons, int nCount,
  1425.         KToolbar * pToolbar, KCanvas * pCanvas, KStatusWindow * pStatus) :
  1426.             KFrame(hInstance, pButtons, nCount, pToolbar, pCanvas, pStatus)
  1427.     {
  1428.     }
  1429.  
  1430. };
  1431.  
  1432.  
  1433. int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int nShow)
  1434. {
  1435.     KMyCanvas     canvas;
  1436.     KStatusWindow status;
  1437.  
  1438.     KLogoFrame frame(hInst, NULL, 0, NULL, & canvas, & status);
  1439.  
  1440.     frame.CreateEx(0, _T("LineCurveDemo"), _T("LineCurve"),
  1441.         WS_OVERLAPPEDWINDOW,
  1442.         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 
  1443.         NULL, LoadMenu(hInst, MAKEINTRESOURCE(IDR_MAIN)), hInst);
  1444.  
  1445.     frame.ShowWindow(nShow);
  1446.     frame.UpdateWindow();
  1447.  
  1448.     frame.MessageLoop();
  1449.  
  1450.     return 0;
  1451. }
  1452.