home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / contrib / src / canvas / polygon.cpp < prev   
C/C++ Source or Header  |  2000-11-24  |  44KB  |  1,454 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        polygon.cpp
  3. // Author:      Klaas Holwerda
  4. // Created:     XX/XX/XX
  5. // Copyright:   2000 (c) Klaas Holwerda
  6. // Licence:     wxWindows Licence
  7. /////////////////////////////////////////////////////////////////////////////
  8.  
  9. #ifdef __GNUG__
  10.     #pragma implementation "polygon.cpp"
  11. #endif
  12.  
  13. // For compilers that support precompilation, includes "wx/wx.h".
  14. #include "wx/wxprec.h"
  15.  
  16. #ifdef __BORLANDC__
  17.     #pragma hdrstop
  18. #endif
  19.  
  20. #include "wx/canvas/polygon.h"
  21. #include "wx/canvas/liner.h"
  22.  
  23. void ConvertSplinedPolygon(wxList* list, double Aber);
  24. void ConvertSplinedPolyline(wxList* list,double Aber);
  25. void ConvertSplinedPolygon(int& n, wxPoint2DDouble* points[], double Aber);
  26. static void GetLRO(const wxPoint2DDouble& P, const wxPoint2DDouble& p1, const wxPoint2DDouble& p2, int &LRO1, int &LRO2,const double marge);
  27.  
  28. //----------------------------------------------------------------------------
  29. // wxCanvasPolyline
  30. //----------------------------------------------------------------------------
  31.  
  32. wxCanvasPolyline::wxCanvasPolyline( int n,  wxPoint2DDouble points[])
  33.    : wxCanvasObject()
  34. {
  35.     m_n = n;
  36.     m_points = points;
  37.     m_pen = *wxBLACK_PEN;
  38.  
  39.     CalcBoundingBox();
  40. }
  41.  
  42. wxCanvasPolyline::~wxCanvasPolyline()
  43. {
  44.     delete m_points;
  45. }
  46.  
  47. void wxCanvasPolyline::SetPosXY( double x, double y)
  48. {
  49.     double xo=m_points[0].m_x;
  50.     double yo=m_points[0].m_y;
  51.     int i;
  52.     for (i=0; i < m_n;i++)
  53.     {
  54.         m_points[i].m_x += (x-xo);
  55.         m_points[i].m_y += (y-yo);
  56.     }
  57.     CalcBoundingBox();
  58. }
  59.  
  60. void wxCanvasPolyline::TransLate( double x, double y )
  61. {
  62.     int i;
  63.     for (i=0; i < m_n;i++)
  64.     {
  65.         m_points[i].m_x += x;
  66.         m_points[i].m_y += y;
  67.     }
  68.     CalcBoundingBox();
  69. }
  70.  
  71. void wxCanvasPolyline::CalcBoundingBox()
  72. {
  73.     m_bbox.SetValid(FALSE);
  74.  
  75.     int i;
  76.     for (i=0; i < m_n;i++)
  77.     {
  78.         m_bbox.Expand( m_points[i].m_x,m_points[i].m_y);
  79.     }
  80.  
  81.     //include the pen width also
  82.     m_bbox.EnLarge(m_pen.GetWidth());
  83. }
  84.  
  85. void wxCanvasPolyline::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
  86. {
  87.     if (!m_visible) return;
  88.  
  89.     int start_y = clip_y;
  90.     int end_y = clip_y+clip_height;
  91.  
  92.     int start_x = clip_x;
  93.     int end_x = clip_x+clip_width;
  94.  
  95. #if IMAGE_CANVAS
  96. #else
  97.     wxPoint *cpoints = new wxPoint[m_n];
  98.     int i;
  99.     for (i = 0; i < m_n; i++)
  100.     {
  101.         double x1;
  102.         double y1;
  103.         //transform to absolute
  104.         cworld->TransformPoint( m_points[i].m_x, m_points[i].m_y, x1, y1 );
  105.         //transform to device
  106.         cpoints[i].x = m_admin->LogicalToDeviceX(x1);
  107.         cpoints[i].y = m_admin->LogicalToDeviceY(y1);
  108.     }
  109.     wxDC *dc = m_admin->GetActive()->GetDC();
  110.     dc->SetClippingRegion(start_x,start_y,end_x-start_x,end_y-start_y);
  111.     int pw=m_pen.GetWidth();
  112.     m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
  113.     dc->SetPen(m_pen);
  114.     dc->DrawLines(m_n, cpoints, 0,0);
  115.     delete [] cpoints;
  116.     dc->SetPen(wxNullPen);
  117.     dc->DestroyClippingRegion();
  118.     m_pen.SetWidth(pw);
  119. #endif
  120. }
  121.  
  122. void wxCanvasPolyline::WriteSVG( wxTextOutputStream &stream )
  123. {
  124. }
  125.  
  126. wxCanvasObject* wxCanvasPolyline::IsHitWorld( double x, double y, double margin )
  127. {
  128.     if ((x >= m_bbox.GetMinX()-margin) &&
  129.         (x <= m_bbox.GetMaxX()+margin) &&
  130.         (y >= m_bbox.GetMinY()-margin) &&
  131.         (y <= m_bbox.GetMaxY()+margin)
  132.        )
  133.     {
  134.         wxPoint2DDouble P=wxPoint2DDouble(x,y);
  135.         if (PointOnPolyline(P,m_pen.GetWidth()/2+margin))
  136.             return this;
  137.         else
  138.             return (wxCanvasObject*) NULL;
  139.     }
  140.     return (wxCanvasObject*) NULL;
  141. }
  142.  
  143. bool wxCanvasPolyline::PointOnPolyline(const wxPoint2DDouble& P, double margin)
  144. {
  145.     bool    result = FALSE;
  146.     double  distance;
  147.     wxPoint2DDouble p1,p2;
  148.  
  149.     p2=m_points[0];
  150.     int i;
  151.     for (i = 0; i < m_n-1; i++)
  152.     {
  153.         p1=p2;
  154.         p2=m_points[i+1];
  155.         if (margin > sqrt(pow(p1.m_x-P.m_x,2)+pow(p1.m_y-P.m_y,2)))
  156.         {
  157.             result=TRUE;
  158.             break;
  159.         }
  160.         else if (!((p1.m_x == p2.m_x) && (p1.m_y == p2.m_y)))
  161.         {
  162.             wxLine line1(p1,p2);
  163.             if (line1.PointInLine(P,distance,margin) == R_IN_AREA)
  164.             {
  165.                 result=TRUE;
  166.                 break;
  167.             }
  168.         }
  169.     }
  170.  
  171.     return result;
  172. }
  173.  
  174. //----------------------------------------------------------------------------
  175. // wxCanvasPolygon
  176. //----------------------------------------------------------------------------
  177.  
  178. wxCanvasPolygon::wxCanvasPolygon( int n, wxPoint2DDouble points[],bool splined)
  179.    : wxCanvasObject()
  180. {
  181.     m_n = n;
  182.     m_points = points;
  183.     m_brush = *wxBLACK_BRUSH;
  184.     m_pen = *wxTRANSPARENT_PEN;
  185.     m_textfg=*wxBLACK;
  186.     m_textbg=*wxWHITE;
  187.     m_transp=FALSE;
  188.     m_gpen=*wxBLACK_PEN;
  189.     m_gdistance=0;
  190.     m_gradient=FALSE;
  191.     m_spline = splined;
  192.  
  193.     if (m_spline)
  194.     {
  195.         ConvertSplinedPolygon(m_n, &m_points, 10 );
  196.     }
  197.  
  198.     CalcBoundingBox();
  199. }
  200.  
  201. wxCanvasPolygon::~wxCanvasPolygon()
  202. {
  203.     delete m_points;
  204. }
  205.  
  206. void wxCanvasPolygon::SetPosXY( double x, double y)
  207. {
  208.     double xo=m_points[0].m_x;
  209.     double yo=m_points[0].m_y;
  210.     int i;
  211.     for (i=0; i < m_n;i++)
  212.     {
  213.         m_points[i].m_x += (x-xo);
  214.         m_points[i].m_y += (y-yo);
  215.     }
  216.     CalcBoundingBox();
  217. }
  218.  
  219. void wxCanvasPolygon::TransLate( double x, double y )
  220. {
  221.     int i;
  222.     for (i=0; i < m_n;i++)
  223.     {
  224.         m_points[i].m_x += x;
  225.         m_points[i].m_y += y;
  226.     }
  227.     CalcBoundingBox();
  228. }
  229.  
  230. void wxCanvasPolygon::CalcBoundingBox()
  231. {
  232.  
  233.     m_bbox.SetValid(FALSE);
  234.  
  235.     int i;
  236.     for (i=0; i < m_n;i++)
  237.     {
  238.         m_bbox.Expand( m_points[i].m_x,m_points[i].m_y);
  239.     }
  240.  
  241.     //include the pen width also
  242.     m_bbox.EnLarge(m_pen.GetWidth());
  243. }
  244.  
  245. void wxCanvasPolygon::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
  246. {
  247.     if (!m_visible) return;
  248.  
  249.     int start_y = clip_y;
  250.     int end_y = clip_y+clip_height;
  251.  
  252.     int start_x = clip_x;
  253.     int end_x = clip_x+clip_width;
  254.  
  255. #if IMAGE_CANVAS
  256. #else
  257.     //one extra for drawlines in some cases
  258.     wxPoint *cpoints = new wxPoint[m_n+1];
  259.     int i;
  260.     for (i = 0; i < m_n; i++)
  261.     {
  262.         double x1;
  263.         double y1;
  264.         cworld->TransformPoint( m_points[i].m_x, m_points[i].m_y, x1, y1 );
  265.         cpoints[i].x = m_admin->LogicalToDeviceX(x1);
  266.         cpoints[i].y = m_admin->LogicalToDeviceY(y1);
  267.     }
  268.     double x1;
  269.     double y1;
  270.     cworld->TransformPoint( m_points[0].m_x, m_points[0].m_y, x1, y1 );
  271.     cpoints[m_n].x = m_admin->LogicalToDeviceX(x1);
  272.     cpoints[m_n].y = m_admin->LogicalToDeviceY(y1);
  273.  
  274.     wxDC *dc = m_admin->GetActive()->GetDC();
  275.     dc->SetClippingRegion(start_x,start_y,end_x-start_x,end_y-start_y);
  276.     dc->SetBrush(m_brush);
  277.     int pw=m_pen.GetWidth();
  278.     m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
  279.     if ( m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE && m_transp)
  280.     {
  281.         //draw a transparent polygon
  282.         //leaf the pen not transparent, which i prefer
  283.         dc->SetPen( wxPen( *wxWHITE,m_admin->LogicalToDeviceXRel(pw), wxSOLID) );
  284.         dc->SetTextForeground(*wxBLACK);
  285.         dc->SetTextBackground(*wxWHITE);
  286.         dc->SetLogicalFunction(wxAND_INVERT);
  287.         // BLACK OUT the opaque pixels and leave the rest as is
  288.         dc->DrawPolygon(m_n, cpoints, 0,0,wxWINDING_RULE);
  289.         // Set background and foreground colors for fill pattern
  290.         //the previous blacked out pixels are now merged with the layer color
  291.         //while the non blacked out pixels stay as they are.
  292.         dc->SetTextForeground(*wxBLACK);
  293.         //now define what will be the color of the fillpattern parts that are not transparent
  294.         dc->SetTextBackground(m_textfg);
  295.         dc->SetLogicalFunction(wxOR);
  296.         //don't understand how but the outline is also depending on logicalfunction
  297.         dc->SetPen(m_pen);
  298.         dc->DrawPolygon(m_n, cpoints, 0,0,wxWINDING_RULE);
  299.     }
  300.     else if (m_gradient)
  301.     {
  302.         int pw2=m_gpen.GetWidth();
  303.         m_gpen.SetWidth(m_admin->LogicalToDeviceYRel(pw2));
  304.         FillPolygon(cworld,clip_x,clip_y,clip_width,clip_height );
  305.         if (m_pen.GetStyle() != wxTRANSPARENT)
  306.         {
  307.             dc->SetPen(m_pen);
  308.             dc->DrawLines(m_n+1, cpoints, 0,0);
  309.         }
  310.         m_gpen.SetWidth(pw2);
  311.     }
  312.     else
  313.     {
  314.         dc->SetPen(m_pen);
  315.         dc->DrawPolygon(m_n, cpoints, 0,0,wxWINDING_RULE);
  316.     }
  317.     delete [] cpoints;
  318.     dc->SetBrush(wxNullBrush);
  319.     dc->SetPen(wxNullPen);
  320.     dc->DestroyClippingRegion();
  321.     m_pen.SetWidth(pw);
  322. #endif
  323. }
  324.  
  325. void wxCanvasPolygon::WriteSVG( wxTextOutputStream &stream )
  326. {
  327. }
  328.  
  329. wxCanvasObject* wxCanvasPolygon::IsHitWorld( double x, double y, double margin )
  330. {
  331.     if ((x >= m_bbox.GetMinX()-margin) &&
  332.         (x <= m_bbox.GetMaxX()+margin) &&
  333.         (y >= m_bbox.GetMinY()-margin) &&
  334.         (y <= m_bbox.GetMaxY()+margin)
  335.        )
  336.     {
  337.         wxPoint2DDouble P=wxPoint2DDouble(x,y);
  338.         INOUTPOLY io=PointInPolygon(P, m_pen.GetWidth()/2+margin);
  339.         if (io == OUTSIDE_POLY)
  340.             return (wxCanvasObject*) NULL;
  341.         else
  342.             return this;
  343.     }
  344.     return (wxCanvasObject*) NULL;
  345. }
  346.  
  347. INOUTPOLY wxCanvasPolygon::PointInPolygon(const wxPoint2DDouble& P, double marge)
  348. {
  349.     int     R_tot = 0, L_tot = 0;
  350.     int     p1_LRO, p2_LRO;
  351.     double  px = P.m_x, py = P.m_y;
  352.     double  Y_intersect;
  353.     wxPoint2DDouble p1,p2;
  354.  
  355.     //iterate across points until we are sure that the given point is in or out
  356.     int i;
  357.     for (i = 0; i < m_n; i++)
  358.     {
  359.         p1 = m_points[i];
  360.         if (i == m_n-1)
  361.             p2 = m_points[0];
  362.         else
  363.             p2 = m_points[i+1];
  364.  
  365.         //more accurate
  366.         GetLRO(P,p1,p2,p1_LRO,p2_LRO,marge/10);
  367.         if (p1_LRO != p2_LRO)
  368.         {
  369.             int L = 0, R = 0;
  370.             if (p2_LRO == -1) { R = -p1_LRO; L = 1; }
  371.             if (p2_LRO == 0) if (p1_LRO == 1) R = -1; else L = -1;
  372.             if (p2_LRO == 1) { R = 1; L = p1_LRO; }
  373.  
  374.             // calculate intersection point with line for px
  375.             if (p1_LRO == 0)
  376.             {
  377.                 if ((p1.m_y < (py + marge)) && (p1.m_y > (py - marge)))
  378.                     return ON_POLY;
  379.                 else
  380.                     Y_intersect = p1.m_y;
  381.             }
  382.             else if (p2_LRO == 0)
  383.             {
  384.                 if ((p2.m_y < (py + marge)) && (p2.m_y > (py - marge)))
  385.                     return ON_POLY;
  386.                 else
  387.                     Y_intersect = p2.m_y;
  388.             }
  389.             else //both p2_LRO and p1_LRO not 0
  390.             {
  391.                 if ((p1.m_y > (py + marge)) && (p2.m_y > (py + marge)))
  392.                     Y_intersect = p1.m_y; //a save value to check later
  393.                 else if ((p1.m_y < (py- marge)) && (p2.m_y < (py - marge)))
  394.                     Y_intersect = p1.m_y; //a save value to check later
  395.                 else //need to calculate intersection
  396.                 {
  397.                     if (!((p1.m_x == p2.m_x) && (p1.m_y == p2.m_y)))
  398.                     {
  399.                         wxLine line1(p1,p2);
  400.                         line1.CalculateLineParameters();
  401.                         Y_intersect = line1.Calculate_Y(px);
  402.                     }
  403.                     else
  404.                          continue;
  405.                 }
  406.             }
  407.             if (Y_intersect > (py + marge))
  408.             {
  409.                 R_tot += R;
  410.                 L_tot += L;
  411.             }
  412.             else if ((Y_intersect <= (py + marge)) && (Y_intersect >= (py - marge)))
  413.             {
  414.                return ON_POLY;
  415.             }
  416.         }
  417.     }
  418.  
  419.     // geef het juiste resultaat terug
  420.     if (R_tot == 0)
  421.         if (L_tot == 0) return OUTSIDE_POLY;
  422.         else return ON_POLY;
  423.     else
  424.         if (L_tot == 0) return ON_POLY;
  425.         else return INSIDE_POLY;
  426. }
  427.  
  428. //----------------------------------------------------------------------------
  429. // wxCanvasPolylineL
  430. //----------------------------------------------------------------------------
  431.  
  432. wxCanvasPolylineL::wxCanvasPolylineL( wxList* points, bool spline )
  433.    : wxCanvasObject()
  434. {
  435.     m_lpoints = points;
  436.     m_pen = *wxBLACK_PEN;
  437.     m_spline=spline;
  438.     if (m_spline)
  439.         ConvertSplinedPolyline(m_lpoints, 10);
  440.     CalcBoundingBox();
  441. }
  442.  
  443. wxCanvasPolylineL::~wxCanvasPolylineL()
  444. {
  445.     m_lpoints->DeleteContents(TRUE);
  446.     delete m_lpoints;
  447. }
  448.  
  449. double wxCanvasPolylineL::GetPosX()
  450. {
  451.     wxNode *node = m_lpoints->GetFirst();
  452.     wxPoint2DDouble* point = (wxPoint2DDouble*)node->Data();
  453.     return point->m_x;
  454. }
  455.  
  456. double wxCanvasPolylineL::GetPosY()
  457. {
  458.     wxNode *node = m_lpoints->GetFirst();
  459.     wxPoint2DDouble* point = (wxPoint2DDouble*)node->Data();
  460.     return point->m_y;
  461. }
  462.  
  463. void wxCanvasPolylineL::SetPosXY( double x, double y )
  464. {
  465.     wxNode *node = m_lpoints->GetFirst();
  466.     wxPoint2DDouble* point = (wxPoint2DDouble*)node->Data();
  467.     double xo=point->m_x;
  468.     double yo=point->m_y;
  469.     while (node)
  470.     {
  471.         point = (wxPoint2DDouble*)node->Data();
  472.         point->m_x = point->m_x + x-xo;
  473.         point->m_y = point->m_y + y-yo;
  474.         node = node->GetNext();
  475.     }
  476.     CalcBoundingBox();
  477. }
  478.  
  479. void wxCanvasPolylineL::TransLate( double x, double y )
  480. {
  481.     wxNode *node = m_lpoints->GetFirst();
  482.     while (node)
  483.     {
  484.         wxPoint2DDouble* point = (wxPoint2DDouble*)node->Data();
  485.         point->m_x += x;
  486.         point->m_y += y;
  487.         node = node->GetNext();
  488.     }
  489.     CalcBoundingBox();
  490. }
  491.  
  492. void wxCanvasPolylineL::CalcBoundingBox()
  493. {
  494.     m_bbox.SetValid(FALSE);
  495.  
  496.     wxNode *node = m_lpoints->GetFirst();
  497.     while (node)
  498.     {
  499.         wxPoint2DDouble* point = (wxPoint2DDouble*)node->Data();
  500.         m_bbox.Expand( point->m_x,point->m_y);
  501.         node = node->GetNext();
  502.     }
  503.  
  504.     //include the pen width also
  505.     m_bbox.EnLarge(m_pen.GetWidth());
  506. }
  507.  
  508. void wxCanvasPolylineL::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
  509. {
  510.     if (!m_visible) return;
  511.  
  512.     int start_y = clip_y;
  513.     int end_y = clip_y+clip_height;
  514.  
  515.     int start_x = clip_x;
  516.     int end_x = clip_x+clip_width;
  517.  
  518. #if IMAGE_CANVAS
  519. #else
  520.     int n=m_lpoints->GetCount();
  521.     wxPoint *cpoints = new wxPoint[n];
  522.  
  523.     wxNode *node = m_lpoints->GetFirst();
  524.     int i=0;
  525.     while (node)
  526.     {
  527.         wxPoint2DDouble* point = (wxPoint2DDouble*)node->Data();
  528.         double x1;
  529.         double y1;
  530.         //transform to absolute
  531.         cworld->TransformPoint( point->m_x, point->m_y, x1, y1 );
  532.         //transform to device
  533.         cpoints[i].x = m_admin->LogicalToDeviceX(x1);
  534.         cpoints[i].y = m_admin->LogicalToDeviceY(y1);
  535.  
  536.         node = node->GetNext();
  537.         i++;
  538.     }
  539.  
  540.     wxDC *dc = m_admin->GetActive()->GetDC();
  541.     dc->SetClippingRegion(start_x,start_y,end_x-start_x,end_y-start_y);
  542.     int pw=m_pen.GetWidth();
  543.     m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
  544.     dc->SetPen(m_pen);
  545.     dc->DrawLines(n, cpoints, 0,0);
  546.     delete [] cpoints;
  547.     dc->SetPen(wxNullPen);
  548.     dc->DestroyClippingRegion();
  549.     m_pen.SetWidth(pw);
  550. #endif
  551. }
  552.  
  553. void wxCanvasPolylineL::WriteSVG( wxTextOutputStream &stream )
  554. {
  555. }
  556.  
  557. wxCanvasObject* wxCanvasPolylineL::IsHitWorld( double x, double y, double margin )
  558. {
  559.     if ((x >= m_bbox.GetMinX()-margin) &&
  560.         (x <= m_bbox.GetMaxX()+margin) &&
  561.         (y >= m_bbox.GetMinY()-margin) &&
  562.         (y <= m_bbox.GetMaxY()+margin)
  563.        )
  564.     {
  565.         wxPoint2DDouble P=wxPoint2DDouble(x,y);
  566.         if (PointOnPolyline(P,m_pen.GetWidth()/2+margin))
  567.             return this;
  568.         else
  569.             return (wxCanvasObject*) NULL;
  570.     }
  571.     return (wxCanvasObject*) NULL;
  572. }
  573.  
  574. bool wxCanvasPolylineL::PointOnPolyline(const wxPoint2DDouble& P, double margin)
  575. {
  576.     bool    result = FALSE;
  577.     double  distance;
  578.     wxPoint2DDouble p1,p2;
  579.  
  580.     wxNode *node = m_lpoints->GetFirst();
  581.     p2 = *(wxPoint2DDouble*)node->Data();
  582.     while (node && !result)
  583.     {
  584.         p1=p2;
  585.         node=node->GetNext();
  586.         if (!node) break;
  587.         p2 = *(wxPoint2DDouble*)node->Data();
  588.  
  589.         if (margin > sqrt(pow(p1.m_x-P.m_x,2)+pow(p1.m_y-P.m_y,2)))
  590.             result=TRUE;
  591.         else if (!((p1.m_x == p2.m_x) && (p1.m_y == p2.m_y)))
  592.         {
  593.             wxLine line1(p1,p2);
  594.             if (line1.PointInLine(P,distance,margin) == R_IN_AREA)
  595.             result=TRUE;
  596.         }
  597.     }
  598.  
  599.     return result;
  600. }
  601.  
  602. //----------------------------------------------------------------------------
  603. // wxCanvasPolygon
  604. //----------------------------------------------------------------------------
  605.  
  606. wxCanvasPolygonL::wxCanvasPolygonL( wxList* points, bool spline )
  607.    : wxCanvasObject()
  608. {
  609.     m_lpoints = points;
  610.     m_brush = *wxBLACK_BRUSH;
  611.     m_pen = *wxTRANSPARENT_PEN;
  612.     m_spline=spline;
  613.     m_textfg=*wxBLACK;
  614.     m_textbg=*wxWHITE;
  615.     m_transp=FALSE;
  616.  
  617.     if (m_spline)
  618.         ConvertSplinedPolyline(m_lpoints, 10);
  619.     CalcBoundingBox();
  620. }
  621.  
  622. wxCanvasPolygonL::~wxCanvasPolygonL()
  623. {
  624.     m_lpoints->DeleteContents(TRUE);
  625.     delete m_lpoints;
  626. }
  627.  
  628. double wxCanvasPolygonL::GetPosX()
  629. {
  630.     wxNode *node = m_lpoints->GetFirst();
  631.     wxPoint2DDouble* point = (wxPoint2DDouble*)node->Data();
  632.     return point->m_x;
  633. }
  634.  
  635. double wxCanvasPolygonL::GetPosY()
  636. {
  637.     wxNode *node = m_lpoints->GetFirst();
  638.     wxPoint2DDouble* point = (wxPoint2DDouble*)node->Data();
  639.     return point->m_y;
  640. }
  641.  
  642. void wxCanvasPolygonL::SetPosXY( double x, double y )
  643. {
  644.     wxNode *node = m_lpoints->GetFirst();
  645.     wxPoint2DDouble* point = (wxPoint2DDouble*)node->Data();
  646.     double xo=point->m_x;
  647.     double yo=point->m_y;
  648.     while (node)
  649.     {
  650.         point = (wxPoint2DDouble*)node->Data();
  651.         point->m_x = point->m_x + x-xo;
  652.         point->m_y = point->m_y + y-yo;
  653.         node = node->GetNext();
  654.     }
  655.     CalcBoundingBox();
  656. }
  657.  
  658. void wxCanvasPolygonL::TransLate( double x, double y )
  659. {
  660.     wxNode *node = m_lpoints->GetFirst();
  661.     while (node)
  662.     {
  663.         wxPoint2DDouble* point = (wxPoint2DDouble*)node->Data();
  664.         point->m_x += x;
  665.         point->m_y += y;
  666.         node = node->GetNext();
  667.     }
  668.     CalcBoundingBox();
  669. }
  670.  
  671. void wxCanvasPolygonL::CalcBoundingBox()
  672. {
  673.  
  674.     m_bbox.SetValid(FALSE);
  675.  
  676.     wxNode *node = m_lpoints->GetFirst();
  677.     while (node)
  678.     {
  679.         wxPoint2DDouble* point = (wxPoint2DDouble*)node->Data();
  680.         m_bbox.Expand( point->m_x,point->m_y);
  681.         node = node->GetNext();
  682.     }
  683.  
  684.     //include the pen width also
  685.     m_bbox.EnLarge(m_pen.GetWidth());
  686. }
  687.  
  688. void wxCanvasPolygonL::Render(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
  689. {
  690.     if (!m_visible) return;
  691.  
  692.     int start_y = clip_y;
  693.     int end_y = clip_y+clip_height;
  694.  
  695.     int start_x = clip_x;
  696.     int end_x = clip_x+clip_width;
  697.  
  698. #if IMAGE_CANVAS
  699. #else
  700.     int n=m_lpoints->GetCount();
  701.     wxPoint *cpoints = new wxPoint[n];
  702.  
  703.     wxNode *node = m_lpoints->GetFirst();
  704.     int i=0;
  705.     while (node)
  706.     {
  707.         wxPoint2DDouble* point = (wxPoint2DDouble*)node->Data();
  708.         double x1;
  709.         double y1;
  710.         //transform to absolute
  711.         cworld->TransformPoint( point->m_x, point->m_y, x1, y1 );
  712.         //transform to device
  713.         cpoints[i].x = m_admin->LogicalToDeviceX(x1);
  714.         cpoints[i].y = m_admin->LogicalToDeviceY(y1);
  715.  
  716.         node = node->GetNext();
  717.         i++;
  718.     }
  719.     wxDC *dc = m_admin->GetActive()->GetDC();
  720.     dc->SetClippingRegion(start_x,start_y,end_x-start_x,end_y-start_y);
  721.     dc->SetBrush(m_brush);
  722.     int pw=m_pen.GetWidth();
  723.     m_pen.SetWidth(m_admin->LogicalToDeviceXRel(pw));
  724.     if ( m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE && m_transp)
  725.     {
  726.         //draw a transparent polygon
  727.         //leaf the pen not transparent, which i prefer
  728.         dc->SetPen( wxPen( *wxWHITE,m_admin->LogicalToDeviceXRel(pw), wxSOLID) );
  729.         dc->SetTextForeground(*wxBLACK);
  730.         dc->SetTextBackground(*wxWHITE);
  731.         dc->SetLogicalFunction(wxAND_INVERT);
  732.         // BLACK OUT the opaque pixels and leave the rest as is
  733.         dc->DrawPolygon(n, cpoints, 0,0,wxWINDING_RULE);
  734.         // Set background and foreground colors for fill pattern
  735.         //the previous blacked out pixels are now merged with the layer color
  736.         //while the non blacked out pixels stay as they are.
  737.         dc->SetTextForeground(*wxBLACK);
  738.         //now define what will be the color of the fillpattern parts that are not transparent
  739.         dc->SetTextBackground(m_textfg);
  740.         dc->SetLogicalFunction(wxOR);
  741.         //don't understand how but the outline is also depending on logicalfunction
  742.         dc->SetPen(m_pen);
  743.         dc->DrawPolygon(n, cpoints, 0,0,wxWINDING_RULE);
  744.         dc->SetLogicalFunction(wxCOPY);
  745.     }
  746.     else
  747.     {
  748.         dc->SetPen(m_pen);
  749.         dc->SetTextForeground(m_textfg);
  750.         dc->SetTextBackground(m_textbg);
  751.         dc->DrawPolygon(n, cpoints, 0,0,wxWINDING_RULE);
  752.     }
  753.     delete [] cpoints;
  754.     dc->SetBrush(wxNullBrush);
  755.     dc->SetPen(wxNullPen);
  756.     dc->DestroyClippingRegion();
  757.     m_pen.SetWidth(pw);
  758. #endif
  759. }
  760.  
  761. void wxCanvasPolygonL::WriteSVG( wxTextOutputStream &stream )
  762. {
  763. }
  764.  
  765. static void GetLRO(const wxPoint2DDouble& P, const wxPoint2DDouble& p1, const wxPoint2DDouble& p2, int &LRO1, int &LRO2,const double marge)
  766. {
  767.     if (p1.m_x > (P.m_x + marge)) LRO1 = -1;        // beginnode is right of P
  768.     else
  769.         if (p1.m_x < (P.m_x - marge)) LRO1 = 1;     // beginnode is left of P
  770.         else LRO1 = 0;                              // beginnode is on vertical line through P
  771.  
  772.     if (p2.m_x > (P.m_x + marge)) LRO2 = -1;        // endnode is right of P
  773.     else
  774.         if (p2.m_x < (P.m_x - marge)) LRO2 = 1;     // endnode is left of P
  775.         else LRO2 = 0;                              // endnode is on vertical line through P
  776. }
  777.  
  778. wxCanvasObject* wxCanvasPolygonL::IsHitWorld( double x, double y, double margin )
  779. {
  780.     if ((x >= m_bbox.GetMinX()-margin) &&
  781.         (x <= m_bbox.GetMaxX()+margin) &&
  782.         (y >= m_bbox.GetMinY()-margin) &&
  783.         (y <= m_bbox.GetMaxY()+margin)
  784.        )
  785.     {
  786.         wxPoint2DDouble P=wxPoint2DDouble(x,y);
  787.         INOUTPOLY io=PointInPolygon(P,m_pen.GetWidth()/2 + margin);
  788.         if (io == OUTSIDE_POLY)
  789.             return (wxCanvasObject*) NULL;
  790.         else
  791.             return this;
  792.     }
  793.     return (wxCanvasObject*) NULL;
  794. }
  795.  
  796. INOUTPOLY wxCanvasPolygonL::PointInPolygon(const wxPoint2DDouble& P, double marge)
  797. {
  798.     int     R_tot = 0, L_tot = 0;
  799.     int     p1_LRO, p2_LRO;
  800.     double  px = P.m_x, py = P.m_y;
  801.     double  Y_intersect;
  802.     wxPoint2DDouble p1,p2;
  803.  
  804.     //iterate across points until we are sure that the given point is in or out
  805.     wxNode *node = m_lpoints->GetFirst();
  806.  
  807.     while (node)
  808.     {
  809.         p1 = *(wxPoint2DDouble*)node->Data();
  810.         if (m_lpoints->GetLast() == node)
  811.         {
  812.             p2 = *(wxPoint2DDouble*)m_lpoints->GetFirst();
  813.         }
  814.         else
  815.         {
  816.             p2 = *(wxPoint2DDouble*)node->GetNext()->Data();
  817.         }
  818.  
  819.         //more accurate
  820.         GetLRO(P,p1,p2,p1_LRO,p2_LRO,marge/10);
  821.         if (p1_LRO != p2_LRO)
  822.         {
  823.             int L = 0, R = 0;
  824.             if (p2_LRO == -1) { R = -p1_LRO; L = 1; }
  825.             if (p2_LRO == 0) if (p1_LRO == 1) R = -1; else L = -1;
  826.             if (p2_LRO == 1) { R = 1; L = p1_LRO; }
  827.  
  828.             // calculate intersection point with line for px
  829.             if (p1_LRO == 0)
  830.             {
  831.                 if ((p1.m_y < (py + marge)) && (p1.m_y > (py - marge)))
  832.                     return ON_POLY;
  833.                 else
  834.                     Y_intersect = p1.m_y;
  835.             }
  836.             else if (p2_LRO == 0)
  837.             {
  838.                 if ((p2.m_y < (py + marge)) && (p2.m_y > (py - marge)))
  839.                     return ON_POLY;
  840.                 else
  841.                     Y_intersect = p2.m_y;
  842.             }
  843.             else //both p2_LRO and p1_LRO not 0
  844.             {
  845.                 if ((p1.m_y > (py + marge)) && (p2.m_y > (py + marge)))
  846.                     Y_intersect = p1.m_y; //a save value to check later
  847.                 else if ((p1.m_y < (py- marge)) && (p2.m_y < (py - marge)))
  848.                     Y_intersect = p1.m_y; //a save value to check later
  849.                 else //need to calculate intersection
  850.                 {
  851.                     if (!((p1.m_x == p2.m_x) && (p1.m_y == p2.m_y)))
  852.                     {
  853.                         wxLine line1(p1,p2);
  854.                         line1.CalculateLineParameters();
  855.                         Y_intersect = line1.Calculate_Y(px);
  856.                     }
  857.                     else
  858.                          continue;
  859.                 }
  860.             }
  861.             if (Y_intersect > (py + marge))
  862.             {
  863.                 R_tot += R;
  864.                 L_tot += L;
  865.             }
  866.             else if ((Y_intersect <= (py + marge)) && (Y_intersect >= (py - marge)))
  867.             {
  868.                return ON_POLY;
  869.             }
  870.         }
  871.         node=node->Next();
  872.     }
  873.  
  874.     // geef het juiste resultaat terug
  875.     if (R_tot == 0)
  876.         if (L_tot == 0) return OUTSIDE_POLY;
  877.         else return ON_POLY;
  878.     else
  879.         if (L_tot == 0) return ON_POLY;
  880.         else return INSIDE_POLY;
  881. }
  882.  
  883. // ---------------------------------------------------------------------------
  884. // spline drawing code
  885. // ---------------------------------------------------------------------------
  886.  
  887. static void gds_quadratic_spline(wxList *org,double a1, double b1, double a2, double b2,
  888.                          double a3, double b3, double a4, double b4,double aber);
  889. static void gds_clear_stack();
  890. static int gds_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
  891.                   double *y3, double *x4, double *y4);
  892. static void gds_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
  893.                     double x4, double y4);
  894.  
  895. void ConvertSplinedPolygon(int& n, wxPoint2DDouble* points[], double Aber)
  896. {
  897.     wxList h;
  898.     int i;
  899.     for (i = 0; i < n; i++)
  900.     {
  901.         h.Append((wxObject*) new wxPoint2DDouble((*points)[i].m_x, (*points)[i].m_y));
  902.     }
  903.     delete *points;
  904.  
  905.     ConvertSplinedPolygon(&h, Aber);
  906.  
  907.     n=h.GetCount();
  908.     *points = new wxPoint2DDouble[n];
  909.     wxNode* node=h.GetFirst();
  910.     for (i = 0; i < n; i++)
  911.     {
  912.         wxNode* hh= node;
  913.         node = node->GetNext();
  914.         (*points)[i].m_x=((wxPoint2DDouble*) hh->GetData())->m_x;
  915.         (*points)[i].m_y=((wxPoint2DDouble*) hh->GetData())->m_y;
  916.         delete (wxPoint2DDouble*) hh->GetData();
  917.         h.DeleteNode(hh);
  918.     }
  919. }
  920.  
  921. void ConvertSplinedPolygon(wxList* list, double Aber)
  922. {
  923.     wxPoint2DDouble* point;
  924.     double           cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
  925.     double           x1, y1, x2, y2;
  926.  
  927.     if (list->GetCount() <2)
  928.         return;
  929.  
  930.     wxNode* iter=list->GetLast();
  931.     x1 = ((wxPoint2DDouble*)iter->Data())->m_x;
  932.     y1 = ((wxPoint2DDouble*)iter->Data())->m_y;
  933.  
  934.     iter=list->GetFirst();
  935.     x2 = ((wxPoint2DDouble*)iter->Data())->m_x;
  936.     y2 = ((wxPoint2DDouble*)iter->Data())->m_y;
  937.  
  938.     point = new wxPoint2DDouble(x2,y2);
  939.     list->Append((wxObject*)point);
  940.  
  941.     cx1 = (x1 + x2) / 2.0;
  942.     cy1 = (y1 + y2) / 2.0;
  943.     cx2 = (cx1 + x2) / 2.0;
  944.     cy2 = (cy1 + y2) / 2.0;
  945.  
  946.     delete (wxPoint2DDouble*) iter->Data();
  947.     delete iter;
  948.     iter=list->GetFirst();
  949.     x1 = ((wxPoint2DDouble*)iter->Data())->m_x;
  950.     y1 = ((wxPoint2DDouble*)iter->Data())->m_y;
  951.     point = new wxPoint2DDouble(x1,y1);
  952.     list->Append((wxObject*)point);
  953.  
  954.     int i=1;
  955.     int count=list->GetCount();
  956.     while (i < count)
  957.     {
  958.         x1 = x2;
  959.         y1 = y2;
  960.         x2 = ((wxPoint2DDouble*)iter->Data())->m_x;
  961.         y2 = ((wxPoint2DDouble*)iter->Data())->m_y;
  962.         cx4 = (x1 + x2) / 2.0;
  963.         cy4 = (y1 + y2) / 2.0;
  964.         cx3 = (x1 + cx4) / 2.0;
  965.         cy3 = (y1 + cy4) / 2.0;
  966.  
  967.         gds_quadratic_spline(list,cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4,Aber);
  968.  
  969.         cx1 = cx4;
  970.         cy1 = cy4;
  971.         cx2 = (cx1 + x2) / 2.0;
  972.         cy2 = (cy1 + y2) / 2.0;
  973.         delete (wxPoint2DDouble*)iter->Data();
  974.         delete iter;
  975.         iter=list->GetFirst();
  976.         i++;
  977.     }
  978.  
  979.     iter=list->GetFirst();
  980.     delete (wxPoint2DDouble*)iter->Data();
  981.     delete iter;
  982. }
  983.  
  984. void ConvertSplinedPolyline(wxList* list,double Aber)
  985. {
  986.     double           cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
  987.     double           x1, y1, x2, y2;
  988.  
  989.  
  990.     if (list->GetCount() <2)
  991.         return;
  992.  
  993.  
  994.  
  995.     wxNode* iter=list->GetFirst();
  996.  
  997.     x1 = ((wxPoint2DDouble*)iter->Data())->m_x;
  998.     y1 = ((wxPoint2DDouble*)iter->Data())->m_y;
  999.  
  1000.     delete (wxPoint2DDouble*)iter->Data();
  1001.     delete iter;
  1002.     iter=list->GetFirst();
  1003.     x2 = ((wxPoint2DDouble*)iter->Data())->m_x;
  1004.     y2 = ((wxPoint2DDouble*)iter->Data())->m_y;
  1005.     cx1 = (x1 + x2) / 2.0;
  1006.     cy1 = (y1 + y2) / 2.0;
  1007.     cx2 = (cx1 + x2) / 2.0;
  1008.     cy2 = (cy1 + y2) / 2.0;
  1009.  
  1010.     wxPoint2DDouble* point = new wxPoint2DDouble(x1,y1);
  1011.     list->Append((wxObject*)point);
  1012.  
  1013.     delete (wxPoint2DDouble*)iter->Data();
  1014.     delete iter;
  1015.     iter=list->GetFirst();
  1016.  
  1017.     int i=1;
  1018.     int count=list->GetCount();
  1019.     while (i < count)
  1020.     {
  1021.         x1 = x2;
  1022.         y1 = y2;
  1023.         x2 = ((wxPoint2DDouble*)iter->Data())->m_x;
  1024.         y2 = ((wxPoint2DDouble*)iter->Data())->m_y;
  1025.         cx4 = (x1 + x2) / 2.0;
  1026.         cy4 = (y1 + y2) / 2.0;
  1027.         cx3 = (x1 + cx4) / 2.0;
  1028.         cy3 = (y1 + cy4) / 2.0;
  1029.  
  1030.         gds_quadratic_spline(list,cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4,Aber);
  1031.  
  1032.         cx1 = cx4;
  1033.         cy1 = cy4;
  1034.         cx2 = (cx1 + x2) / 2.0;
  1035.         cy2 = (cy1 + y2) / 2.0;
  1036.         delete (wxPoint2DDouble*)iter->Data();
  1037.         delete iter;
  1038.         iter=list->GetFirst();
  1039.         i++;
  1040.     }
  1041.  
  1042.     point = new wxPoint2DDouble(cx1,cy1);
  1043.     list->Append((wxObject*)point);
  1044.  
  1045.     point = new wxPoint2DDouble(x2,y2);
  1046.     list->Append((wxObject*)point);
  1047. }
  1048.  
  1049. /********************* CURVES FOR SPLINES *****************************
  1050.  
  1051.   The following spline drawing routine is from
  1052.  
  1053.     "An Algorithm for High-Speed Curve Generation"
  1054.     by George Merrill Chaikin,
  1055.     Computer Graphics and Image Processing, 3, Academic Press,
  1056.     1974, 346-349.
  1057.  
  1058.       and
  1059.  
  1060.         "On Chaikin's Algorithm" by R. F. Riesenfeld,
  1061.         Computer Graphics and Image Processing, 4, Academic Press,
  1062.         1975, 304-310.
  1063.  
  1064. ***********************************************************************/
  1065.  
  1066. #define     half(z1, z2)    ((z1+z2)/2.0)
  1067. #define     THRESHOLD   5
  1068.  
  1069. /* iterative version */
  1070.  
  1071. void gds_quadratic_spline(wxList *org,double a1, double b1, double a2, double b2, double a3, double b3, double a4,
  1072.                          double b4,double Aber)
  1073. {
  1074.     register double  xmid, ymid;
  1075.     double           x1, y1, x2, y2, x3, y3, x4, y4;
  1076.     wxPoint2DDouble* point;
  1077.  
  1078.     gds_clear_stack();
  1079.     gds_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
  1080.  
  1081.     while (gds_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4))
  1082.     {
  1083.         xmid = half(x2, x3);
  1084.         ymid = half(y2, y3);
  1085.         if (fabs(x1 - xmid) < Aber && fabs(y1 - ymid) < Aber &&
  1086.             fabs(xmid - x4) < Aber && fabs(ymid - y4) < Aber)
  1087.         {
  1088.             point = new wxPoint2DDouble(x1,y1);
  1089.             org->Append((wxObject*)point);
  1090.             point = new wxPoint2DDouble(xmid,ymid);
  1091.             org->Append((wxObject*)point);
  1092.         } else {
  1093.             gds_spline_push(xmid, ymid, half(xmid, x3), half(ymid, y3),
  1094.                 half(x3, x4), half(y3, y4), x4, y4);
  1095.             gds_spline_push(x1, y1, half(x1, x2), half(y1, y2),
  1096.                 half(x2, xmid), half(y2, ymid), xmid, ymid);
  1097.         }
  1098.     }
  1099. }
  1100.  
  1101.  
  1102. /* utilities used by spline drawing routines */
  1103.  
  1104.  
  1105. typedef struct gds_spline_stack_struct {
  1106.     double           x1, y1, x2, y2, x3, y3, x4, y4;
  1107. }
  1108. Stack;
  1109.  
  1110. #define         SPLINE_STACK_DEPTH             20
  1111. static Stack    gds_spline_stack[SPLINE_STACK_DEPTH];
  1112. static Stack   *gds_stack_top;
  1113. static int      gds_stack_count;
  1114.  
  1115. static void gds_clear_stack()
  1116. {
  1117.     gds_stack_top = gds_spline_stack;
  1118.     gds_stack_count = 0;
  1119. }
  1120.  
  1121. static void gds_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
  1122. {
  1123.     gds_stack_top->x1 = x1;
  1124.     gds_stack_top->y1 = y1;
  1125.     gds_stack_top->x2 = x2;
  1126.     gds_stack_top->y2 = y2;
  1127.     gds_stack_top->x3 = x3;
  1128.     gds_stack_top->y3 = y3;
  1129.     gds_stack_top->x4 = x4;
  1130.     gds_stack_top->y4 = y4;
  1131.     gds_stack_top++;
  1132.     gds_stack_count++;
  1133. }
  1134.  
  1135. int gds_spline_pop(double *x1, double *y1, double *x2, double *y2,
  1136.                   double *x3, double *y3, double *x4, double *y4)
  1137. {
  1138.     if (gds_stack_count == 0)
  1139.         return (0);
  1140.     gds_stack_top--;
  1141.     gds_stack_count--;
  1142.     *x1 = gds_stack_top->x1;
  1143.     *y1 = gds_stack_top->y1;
  1144.     *x2 = gds_stack_top->x2;
  1145.     *y2 = gds_stack_top->y2;
  1146.     *x3 = gds_stack_top->x3;
  1147.     *y3 = gds_stack_top->y3;
  1148.     *x4 = gds_stack_top->x4;
  1149.     *y4 = gds_stack_top->y4;
  1150.     return (1);
  1151. }
  1152.  
  1153. void wxAET::CalculateLineParameters( const wxPoint2DDouble& p1 , const wxPoint2DDouble& p2 )
  1154. {
  1155.     double A = p2.m_y - p1.m_y; //A (y2-y1)
  1156.     if (A == 0)
  1157.     {
  1158.         m_horizontal=TRUE;
  1159.         m_BdivA=0;
  1160.         m_CdivA=0;
  1161.     }
  1162.     else
  1163.     {
  1164.         m_horizontal=FALSE;
  1165.         m_BdivA= (p1.m_x - p2.m_x)/A; //B (x1-x2)
  1166.         //normalize
  1167.         m_CdivA= ((p2.m_x*p1.m_y) - (p1.m_x*p2.m_y)) /A ;
  1168.     }
  1169. }
  1170.  
  1171. void wxAET::CalculateXs( double y )
  1172. {
  1173.     m_xs= -m_BdivA * y - m_CdivA;
  1174. }
  1175.  
  1176. //use by polygon filling
  1177. //moves the scanline up
  1178. //index is the index of the point where the search begins
  1179. //direction is +1 or -1 and indicates if the segment ascends or decends
  1180. bool wxCanvasPolygon::MoveUp( double horline, int& index, int direction)
  1181. {
  1182.     int walk = (index + direction + m_n) % m_n;
  1183.     while ( m_points[walk].m_y < horline )
  1184.     {
  1185.         if (m_points[walk].m_y < m_points[index].m_y )
  1186.             return FALSE;
  1187.         else
  1188.         {
  1189.             //modify index
  1190.             index=walk;
  1191.             walk = (index + direction + m_n) % m_n;
  1192.         }
  1193.     }
  1194.     return TRUE;
  1195. }
  1196.  
  1197. //a crictical point is a point between a decending and a ascending segment
  1198. //collect those points for filling later
  1199. void wxCanvasPolygon::DetectCriticalPoints()
  1200. {
  1201.     //candidate for critical point
  1202.     //true if Y is getting lower, unchanged i Y is unchanged
  1203.     //and if Y becomes higher and candidate was true: it is a critical point
  1204.     bool candidate = FALSE;
  1205.     int i,j;
  1206.  
  1207.     for ( i=0; i < m_n; i++)
  1208.     {
  1209.         //j next point
  1210.         j= (i+1) % m_n;
  1211.  
  1212.         //check if Y is smaller
  1213.         if (m_points[i].m_y > m_points[j].m_y)
  1214.             //we have a candidate
  1215.             candidate=TRUE;
  1216.         else if ( (m_points[i].m_y < m_points[j].m_y) && candidate)
  1217.         {   //this is a critical point put in list
  1218.             bool inserted=FALSE;
  1219.             wxNode *node = m_CRlist.GetFirst();
  1220.             while (node)
  1221.             {
  1222.                 //sorted on smallest Y value
  1223.                 int* ind=(int*) node->GetData();
  1224.                 if (m_points[*ind].m_y > m_points[i].m_y)
  1225.                 {
  1226.                     m_CRlist.Insert(node,(wxObject*) new int(i));
  1227.                     inserted = TRUE;
  1228.                     break;
  1229.                 }
  1230.                 node = node->GetNext();
  1231.             }
  1232.             if (!inserted)
  1233.                 m_CRlist.Append((wxObject*) new int(i));
  1234.             candidate = FALSE;
  1235.         }
  1236.     }
  1237.     if (candidate)
  1238.     {
  1239.         for ( i=0; i < m_n; i++)
  1240.         {
  1241.             //j next point
  1242.             j= (i+1) % m_n;
  1243.  
  1244.             //check if Y is smaller
  1245.             if (m_points[i].m_y > m_points[j].m_y)
  1246.                 //we have a candidate
  1247.                 candidate=TRUE;
  1248.             else if ( (m_points[i].m_y < m_points[j].m_y) && candidate)
  1249.             {   //this is a critical point put in list
  1250.                 bool inserted=FALSE;
  1251.                 wxNode *node = m_CRlist.GetFirst();
  1252.                 while (node)
  1253.                 {
  1254.                     //sorted on smallest Y value
  1255.                     int* ind=(int*) node->GetData();
  1256.                     if (m_points[*ind].m_y > m_points[i].m_y)
  1257.                     {
  1258.                         m_CRlist.Insert(node,(wxObject*) new int(i));
  1259.                         inserted = TRUE;
  1260.                         break;
  1261.                     }
  1262.                     node = node->GetNext();
  1263.                 }
  1264.                 if (!inserted)
  1265.                     m_CRlist.Append((wxObject*) new int(i));
  1266.                 candidate = FALSE;
  1267.             }
  1268.         }
  1269.     }
  1270. }
  1271.  
  1272.  
  1273. void wxCanvasPolygon::FillPolygon(wxTransformMatrix* cworld, int clip_x, int clip_y, int clip_width, int clip_height )
  1274. {
  1275. #if IMAGE_CANVAS
  1276. #else
  1277.     int index;
  1278.     //how much is on pixel in world coordinates
  1279.  
  1280.     double scalefactor;
  1281.     if (m_gdistance)
  1282.         scalefactor=m_gdistance;
  1283.     else
  1284.         //abs here needed if yaxis is going up (always scan in world coordinates UP)
  1285.         scalefactor=fabs(m_admin->DeviceToLogicalYRel(1)); //1 pixel height
  1286.  
  1287.     wxDC *dc = m_admin->GetActive()->GetDC();
  1288.     dc->SetClippingRegion( clip_x, clip_y, clip_width, clip_height );
  1289.     wxPen  gradientpen=m_gpen;
  1290.  
  1291.     int dred = m_textbg.Red()-m_textfg.Red();
  1292.     int dgreen = m_textbg.Green()-m_textfg.Green();
  1293.     int dblue = m_textbg.Blue()-m_textfg.Blue();
  1294.  
  1295.     //total number of lines to go from m_textbg to m_textfg
  1296.     //gives the following number of steps for the gradient color
  1297.     int stepcol = (int) (m_bbox.GetHeight()/scalefactor);
  1298.  
  1299.     DetectCriticalPoints();
  1300.  
  1301.     double min;
  1302.     double max;
  1303.     if (cworld->IsIdentity())
  1304.     {
  1305.         //TODO do something with clipping region (inverse transform?)
  1306.         //the next does not work, i don't know why
  1307.         //min = wxMin (m_admin->DeviceToLogicalY(clip_y),m_admin->DeviceToLogicalY(clip_y+clip_height));
  1308.         //max = wxMax (m_admin->DeviceToLogicalY(clip_y),m_admin->DeviceToLogicalY(clip_y+clip_height));
  1309.         min= m_bbox.GetMinY();
  1310.         max= m_bbox.GetMaxY();
  1311.     }
  1312.     else
  1313.     {
  1314.         min= m_bbox.GetMinY();
  1315.         max= m_bbox.GetMaxY();
  1316.     }
  1317.  
  1318.     int curcol = (int)( (min - m_bbox.GetMinY())/scalefactor );
  1319.  
  1320.     double i;
  1321.     for ( i = min; i < max; i+=scalefactor)
  1322.     {
  1323.         wxNode *node = m_AETlist.GetFirst();
  1324.         int count= m_AETlist.GetCount();
  1325.         while (count > 0)
  1326.         {
  1327.             wxAET* ele = ((wxAET*)node->GetData());
  1328.             index= ele->m_index;
  1329.             int direction = ele->m_direction;
  1330.             if (!MoveUp(i,index,direction))
  1331.             {
  1332.                 wxNode* h = node;
  1333.                 //remove this node
  1334.                 node = node->GetNext();
  1335.                 m_AETlist.DeleteNode(h);
  1336.             }
  1337.             else
  1338.             {
  1339.                 if (ele->m_index != index)
  1340.                 {
  1341.                    ele->m_index=index;
  1342.                    int h = (index + direction + m_n) % m_n;
  1343.                    ele->CalculateLineParameters(m_points[h],m_points[index]);
  1344.                 }
  1345.                 if (ele->m_horizontal)
  1346.                    ele->m_xs=m_points[index].m_x;
  1347.                 else
  1348.                    ele->CalculateXs(i);
  1349.                 node = node->GetNext();
  1350.             }
  1351.             count--;
  1352.         }
  1353.  
  1354.         node = m_CRlist.GetFirst();
  1355.         while (m_CRlist.GetCount() && m_points[*((int*)node->GetData())].m_y <=i )
  1356.         {
  1357.             int DI;
  1358.             for ( DI = -1; DI <=1 ; DI+=2)
  1359.             {
  1360.                 index=*((int*)node->GetData());
  1361.                 if (MoveUp(i,index,DI))
  1362.                 {
  1363.                     wxAET* ele = new wxAET();
  1364.                     ele->m_index=index;
  1365.                     ele->m_direction=DI;
  1366.                     int h = (index + DI + m_n) % m_n;
  1367.                     ele->CalculateLineParameters(m_points[h],m_points[index]);
  1368.                     if (ele->m_horizontal)
  1369.                         ele->m_xs=m_points[index].m_x;
  1370.                     else
  1371.                         ele->CalculateXs(i);
  1372.  
  1373.                     //insert in sorted order od m_xs
  1374.                     bool inserted=FALSE;
  1375.                     wxNode *node2 = m_AETlist.GetFirst();
  1376.                     while (node2)
  1377.                     {
  1378.                         //sorted on smallest xs value
  1379.                         if (ele->m_xs < ((wxAET*)node2->GetData())->m_xs)
  1380.                         {
  1381.                             m_AETlist.Insert(node2,(wxObject*) ele);
  1382.                             inserted = TRUE;
  1383.                             break;
  1384.                         }
  1385.                         node2 = node2->GetNext();
  1386.                     }
  1387.                     if (!inserted)
  1388.                         m_AETlist.Append((wxObject*)ele);
  1389.                 }
  1390.             }
  1391.  
  1392.             wxNode* h= node;
  1393.             node = node->GetNext();
  1394.             m_CRlist.DeleteNode(h);
  1395.         }
  1396.  
  1397.         curcol++;
  1398.         wxColour gradcol(m_textbg.Red()+dred*curcol/stepcol,
  1399.                          m_textbg.Green()+dgreen*curcol/stepcol,
  1400.                          m_textbg.Blue()+dblue*curcol/stepcol);
  1401.         gradientpen.SetColour(gradcol);
  1402.  
  1403.         //m_AETlist must be sorted in m_xs at this moment
  1404.         //now draw all the line parts on one horizontal scanline (Winding Rule)
  1405.         int out= 0;
  1406.         node = m_AETlist.GetFirst();
  1407.         while (node)
  1408.         {
  1409.             wxAET* ele = ((wxAET*)node->GetData());
  1410.             out+=ele->m_direction;
  1411.             if (out != 0)
  1412.             {
  1413.                 double x1=ele->m_xs;
  1414.                 node = node->GetNext();
  1415.                 ele = ((wxAET*)node->GetData());
  1416.                 double x2=ele->m_xs;
  1417.                 dc->SetPen( gradientpen );
  1418.                 double wx1,wy1,wx2,wy2;
  1419.                 cworld->TransformPoint( x1, i, wx1, wy1 );
  1420.                 cworld->TransformPoint( x2, i, wx2, wy2 );
  1421.                 int dx1,dy1,dx2,dy2;
  1422.                 dx1 = m_admin->LogicalToDeviceX( wx1 );
  1423.                 dy1 = m_admin->LogicalToDeviceY( wy1 );
  1424.                 dx2 = m_admin->LogicalToDeviceX( wx2 );
  1425.                 dy2 = m_admin->LogicalToDeviceY( wy2 );
  1426.  
  1427.                 //TODO KKK need real line clipping here since line can be rotated.
  1428.                 if (0 && cworld->IsIdentity())
  1429.                 {
  1430.                     if (dx1 < clip_x) dx1=clip_x;
  1431.                     if (dx2 > clip_x + clip_width) dx2=clip_x + clip_width;
  1432.                     if ((dy1 >  clip_y) && dy1 < clip_y + clip_height)
  1433.                         dc->DrawLine( dx1, dy1, dx2, dy2 );
  1434.                 }
  1435.                 else
  1436.                 {
  1437.                     dc->DrawLine( dx1, dy1, dx2, dy2 );
  1438.                 }
  1439.  
  1440.             }
  1441.             else
  1442.                 node = node->GetNext();
  1443.         }
  1444.     }
  1445.  
  1446.     dc->DestroyClippingRegion();
  1447. #endif
  1448. }
  1449.  
  1450.  
  1451.  
  1452.  
  1453.  
  1454.