]>
git.saurik.com Git - wxWidgets.git/blob - contrib/src/canvas/polygon.cpp
1 /////////////////////////////////////////////////////////////////////////////
3 // Author: Klaas Holwerda
5 // Copyright: 2000 (c) Klaas Holwerda
6 // Licence: wxWindows Licence
7 /////////////////////////////////////////////////////////////////////////////
10 #pragma implementation "polygon.cpp"
13 // For compilers that support precompilation, includes "wx/wx.h".
14 #include "wx/wxprec.h"
20 #include "wx/canvas/polygon.h"
21 #include "wx/canvas/liner.h"
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
);
28 //----------------------------------------------------------------------------
30 //----------------------------------------------------------------------------
32 wxCanvasPolyline::wxCanvasPolyline( int n
, wxPoint2DDouble points
[])
42 wxCanvasPolyline::~wxCanvasPolyline()
47 void wxCanvasPolyline::SetPosXY( double x
, double y
)
49 double xo
=m_points
[0].m_x
;
50 double yo
=m_points
[0].m_y
;
52 for (i
=0; i
< m_n
;i
++)
54 m_points
[i
].m_x
+= (x
-xo
);
55 m_points
[i
].m_y
+= (y
-yo
);
60 void wxCanvasPolyline::TransLate( double x
, double y
)
63 for (i
=0; i
< m_n
;i
++)
71 void wxCanvasPolyline::CalcBoundingBox()
73 m_bbox
.SetValid(FALSE
);
76 for (i
=0; i
< m_n
;i
++)
78 m_bbox
.Expand( m_points
[i
].m_x
,m_points
[i
].m_y
);
81 //include the pen width also
82 m_bbox
.EnLarge(m_pen
.GetWidth());
85 void wxCanvasPolyline::Render(wxTransformMatrix
* cworld
, int clip_x
, int clip_y
, int clip_width
, int clip_height
)
87 if (!m_visible
) return;
90 int end_y
= clip_y
+clip_height
;
93 int end_x
= clip_x
+clip_width
;
97 wxPoint
*cpoints
= new wxPoint
[m_n
];
99 for (i
= 0; i
< m_n
; i
++)
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
);
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
));
114 dc
->DrawLines(m_n
, cpoints
, 0,0);
116 dc
->SetPen(wxNullPen
);
117 dc
->DestroyClippingRegion();
122 void wxCanvasPolyline::WriteSVG( wxTextOutputStream
&stream
)
126 wxCanvasObject
* wxCanvasPolyline::IsHitWorld( double x
, double y
, double margin
)
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
)
134 wxPoint2DDouble P
=wxPoint2DDouble(x
,y
);
135 if (PointOnPolyline(P
,m_pen
.GetWidth()/2+margin
))
138 return (wxCanvasObject
*) NULL
;
140 return (wxCanvasObject
*) NULL
;
143 bool wxCanvasPolyline::PointOnPolyline(const wxPoint2DDouble
& P
, double margin
)
147 wxPoint2DDouble p1
,p2
;
151 for (i
= 0; i
< m_n
-1; i
++)
155 if (margin
> sqrt(pow(p1
.m_x
-P
.m_x
,2)+pow(p1
.m_y
-P
.m_y
,2)))
160 else if (!((p1
.m_x
== p2
.m_x
) && (p1
.m_y
== p2
.m_y
)))
163 if (line1
.PointInLine(P
,distance
,margin
) == R_IN_AREA
)
174 //----------------------------------------------------------------------------
176 //----------------------------------------------------------------------------
178 wxCanvasPolygon::wxCanvasPolygon( int n
, wxPoint2DDouble points
[],bool splined
)
183 m_brush
= *wxBLACK_BRUSH
;
184 m_pen
= *wxTRANSPARENT_PEN
;
195 ConvertSplinedPolygon(m_n
, &m_points
, 10 );
201 wxCanvasPolygon::~wxCanvasPolygon()
206 void wxCanvasPolygon::SetPosXY( double x
, double y
)
208 double xo
=m_points
[0].m_x
;
209 double yo
=m_points
[0].m_y
;
211 for (i
=0; i
< m_n
;i
++)
213 m_points
[i
].m_x
+= (x
-xo
);
214 m_points
[i
].m_y
+= (y
-yo
);
219 void wxCanvasPolygon::TransLate( double x
, double y
)
222 for (i
=0; i
< m_n
;i
++)
224 m_points
[i
].m_x
+= x
;
225 m_points
[i
].m_y
+= y
;
230 void wxCanvasPolygon::CalcBoundingBox()
233 m_bbox
.SetValid(FALSE
);
236 for (i
=0; i
< m_n
;i
++)
238 m_bbox
.Expand( m_points
[i
].m_x
,m_points
[i
].m_y
);
241 //include the pen width also
242 m_bbox
.EnLarge(m_pen
.GetWidth());
245 void wxCanvasPolygon::Render(wxTransformMatrix
* cworld
, int clip_x
, int clip_y
, int clip_width
, int clip_height
)
247 if (!m_visible
) return;
249 int start_y
= clip_y
;
250 int end_y
= clip_y
+clip_height
;
252 int start_x
= clip_x
;
253 int end_x
= clip_x
+clip_width
;
257 //one extra for drawlines in some cases
258 wxPoint
*cpoints
= new wxPoint
[m_n
+1];
260 for (i
= 0; i
< m_n
; i
++)
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
);
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
);
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
)
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
298 dc
->DrawPolygon(m_n
, cpoints
, 0,0,wxWINDING_RULE
);
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
)
308 dc
->DrawLines(m_n
+1, cpoints
, 0,0);
310 m_gpen
.SetWidth(pw2
);
315 dc
->DrawPolygon(m_n
, cpoints
, 0,0,wxWINDING_RULE
);
318 dc
->SetBrush(wxNullBrush
);
319 dc
->SetPen(wxNullPen
);
320 dc
->DestroyClippingRegion();
325 void wxCanvasPolygon::WriteSVG( wxTextOutputStream
&stream
)
329 wxCanvasObject
* wxCanvasPolygon::IsHitWorld( double x
, double y
, double margin
)
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
)
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
;
344 return (wxCanvasObject
*) NULL
;
347 INOUTPOLY
wxCanvasPolygon::PointInPolygon(const wxPoint2DDouble
& P
, double marge
)
349 int R_tot
= 0, L_tot
= 0;
351 double px
= P
.m_x
, py
= P
.m_y
;
353 wxPoint2DDouble p1
,p2
;
355 //iterate across points until we are sure that the given point is in or out
357 for (i
= 0; i
< m_n
; i
++)
366 GetLRO(P
,p1
,p2
,p1_LRO
,p2_LRO
,marge
/10);
367 if (p1_LRO
!= p2_LRO
)
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
; }
374 // calculate intersection point with line for px
377 if ((p1
.m_y
< (py
+ marge
)) && (p1
.m_y
> (py
- marge
)))
380 Y_intersect
= p1
.m_y
;
382 else if (p2_LRO
== 0)
384 if ((p2
.m_y
< (py
+ marge
)) && (p2
.m_y
> (py
- marge
)))
387 Y_intersect
= p2
.m_y
;
389 else //both p2_LRO and p1_LRO not 0
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
397 if (!((p1
.m_x
== p2
.m_x
) && (p1
.m_y
== p2
.m_y
)))
400 line1
.CalculateLineParameters();
401 Y_intersect
= line1
.Calculate_Y(px
);
407 if (Y_intersect
> (py
+ marge
))
412 else if ((Y_intersect
<= (py
+ marge
)) && (Y_intersect
>= (py
- marge
)))
419 // geef het juiste resultaat terug
421 if (L_tot
== 0) return OUTSIDE_POLY
;
424 if (L_tot
== 0) return ON_POLY
;
425 else return INSIDE_POLY
;
428 //----------------------------------------------------------------------------
430 //----------------------------------------------------------------------------
432 wxCanvasPolylineL::wxCanvasPolylineL( wxList
* points
, bool spline
)
436 m_pen
= *wxBLACK_PEN
;
439 ConvertSplinedPolyline(m_lpoints
, 10);
443 wxCanvasPolylineL::~wxCanvasPolylineL()
445 m_lpoints
->DeleteContents(TRUE
);
449 double wxCanvasPolylineL::GetPosX()
451 wxNode
*node
= m_lpoints
->GetFirst();
452 wxPoint2DDouble
* point
= (wxPoint2DDouble
*)node
->Data();
456 double wxCanvasPolylineL::GetPosY()
458 wxNode
*node
= m_lpoints
->GetFirst();
459 wxPoint2DDouble
* point
= (wxPoint2DDouble
*)node
->Data();
463 void wxCanvasPolylineL::SetPosXY( double x
, double y
)
465 wxNode
*node
= m_lpoints
->GetFirst();
466 wxPoint2DDouble
* point
= (wxPoint2DDouble
*)node
->Data();
467 double xo
=point
->m_x
;
468 double yo
=point
->m_y
;
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();
479 void wxCanvasPolylineL::TransLate( double x
, double y
)
481 wxNode
*node
= m_lpoints
->GetFirst();
484 wxPoint2DDouble
* point
= (wxPoint2DDouble
*)node
->Data();
487 node
= node
->GetNext();
492 void wxCanvasPolylineL::CalcBoundingBox()
494 m_bbox
.SetValid(FALSE
);
496 wxNode
*node
= m_lpoints
->GetFirst();
499 wxPoint2DDouble
* point
= (wxPoint2DDouble
*)node
->Data();
500 m_bbox
.Expand( point
->m_x
,point
->m_y
);
501 node
= node
->GetNext();
504 //include the pen width also
505 m_bbox
.EnLarge(m_pen
.GetWidth());
508 void wxCanvasPolylineL::Render(wxTransformMatrix
* cworld
, int clip_x
, int clip_y
, int clip_width
, int clip_height
)
510 if (!m_visible
) return;
512 int start_y
= clip_y
;
513 int end_y
= clip_y
+clip_height
;
515 int start_x
= clip_x
;
516 int end_x
= clip_x
+clip_width
;
520 int n
=m_lpoints
->GetCount();
521 wxPoint
*cpoints
= new wxPoint
[n
];
523 wxNode
*node
= m_lpoints
->GetFirst();
527 wxPoint2DDouble
* point
= (wxPoint2DDouble
*)node
->Data();
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
);
536 node
= node
->GetNext();
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
));
545 dc
->DrawLines(n
, cpoints
, 0,0);
547 dc
->SetPen(wxNullPen
);
548 dc
->DestroyClippingRegion();
553 void wxCanvasPolylineL::WriteSVG( wxTextOutputStream
&stream
)
557 wxCanvasObject
* wxCanvasPolylineL::IsHitWorld( double x
, double y
, double margin
)
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
)
565 wxPoint2DDouble P
=wxPoint2DDouble(x
,y
);
566 if (PointOnPolyline(P
,m_pen
.GetWidth()/2+margin
))
569 return (wxCanvasObject
*) NULL
;
571 return (wxCanvasObject
*) NULL
;
574 bool wxCanvasPolylineL::PointOnPolyline(const wxPoint2DDouble
& P
, double margin
)
578 wxPoint2DDouble p1
,p2
;
580 wxNode
*node
= m_lpoints
->GetFirst();
581 p2
= *(wxPoint2DDouble
*)node
->Data();
582 while (node
&& !result
)
585 node
=node
->GetNext();
587 p2
= *(wxPoint2DDouble
*)node
->Data();
589 if (margin
> sqrt(pow(p1
.m_x
-P
.m_x
,2)+pow(p1
.m_y
-P
.m_y
,2)))
591 else if (!((p1
.m_x
== p2
.m_x
) && (p1
.m_y
== p2
.m_y
)))
594 if (line1
.PointInLine(P
,distance
,margin
) == R_IN_AREA
)
602 //----------------------------------------------------------------------------
604 //----------------------------------------------------------------------------
606 wxCanvasPolygonL::wxCanvasPolygonL( wxList
* points
, bool spline
)
610 m_brush
= *wxBLACK_BRUSH
;
611 m_pen
= *wxTRANSPARENT_PEN
;
618 ConvertSplinedPolyline(m_lpoints
, 10);
622 wxCanvasPolygonL::~wxCanvasPolygonL()
624 m_lpoints
->DeleteContents(TRUE
);
628 double wxCanvasPolygonL::GetPosX()
630 wxNode
*node
= m_lpoints
->GetFirst();
631 wxPoint2DDouble
* point
= (wxPoint2DDouble
*)node
->Data();
635 double wxCanvasPolygonL::GetPosY()
637 wxNode
*node
= m_lpoints
->GetFirst();
638 wxPoint2DDouble
* point
= (wxPoint2DDouble
*)node
->Data();
642 void wxCanvasPolygonL::SetPosXY( double x
, double y
)
644 wxNode
*node
= m_lpoints
->GetFirst();
645 wxPoint2DDouble
* point
= (wxPoint2DDouble
*)node
->Data();
646 double xo
=point
->m_x
;
647 double yo
=point
->m_y
;
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();
658 void wxCanvasPolygonL::TransLate( double x
, double y
)
660 wxNode
*node
= m_lpoints
->GetFirst();
663 wxPoint2DDouble
* point
= (wxPoint2DDouble
*)node
->Data();
666 node
= node
->GetNext();
671 void wxCanvasPolygonL::CalcBoundingBox()
674 m_bbox
.SetValid(FALSE
);
676 wxNode
*node
= m_lpoints
->GetFirst();
679 wxPoint2DDouble
* point
= (wxPoint2DDouble
*)node
->Data();
680 m_bbox
.Expand( point
->m_x
,point
->m_y
);
681 node
= node
->GetNext();
684 //include the pen width also
685 m_bbox
.EnLarge(m_pen
.GetWidth());
688 void wxCanvasPolygonL::Render(wxTransformMatrix
* cworld
, int clip_x
, int clip_y
, int clip_width
, int clip_height
)
690 if (!m_visible
) return;
692 int start_y
= clip_y
;
693 int end_y
= clip_y
+clip_height
;
695 int start_x
= clip_x
;
696 int end_x
= clip_x
+clip_width
;
700 int n
=m_lpoints
->GetCount();
701 wxPoint
*cpoints
= new wxPoint
[n
];
703 wxNode
*node
= m_lpoints
->GetFirst();
707 wxPoint2DDouble
* point
= (wxPoint2DDouble
*)node
->Data();
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
);
716 node
= node
->GetNext();
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
)
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
743 dc
->DrawPolygon(n
, cpoints
, 0,0,wxWINDING_RULE
);
744 dc
->SetLogicalFunction(wxCOPY
);
749 dc
->SetTextForeground(m_textfg
);
750 dc
->SetTextBackground(m_textbg
);
751 dc
->DrawPolygon(n
, cpoints
, 0,0,wxWINDING_RULE
);
754 dc
->SetBrush(wxNullBrush
);
755 dc
->SetPen(wxNullPen
);
756 dc
->DestroyClippingRegion();
761 void wxCanvasPolygonL::WriteSVG( wxTextOutputStream
&stream
)
765 static void GetLRO(const wxPoint2DDouble
& P
, const wxPoint2DDouble
& p1
, const wxPoint2DDouble
& p2
, int &LRO1
, int &LRO2
,const double marge
)
767 if (p1
.m_x
> (P
.m_x
+ marge
)) LRO1
= -1; // beginnode is right of P
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
772 if (p2
.m_x
> (P
.m_x
+ marge
)) LRO2
= -1; // endnode is right of P
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
778 wxCanvasObject
* wxCanvasPolygonL::IsHitWorld( double x
, double y
, double margin
)
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
)
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
;
793 return (wxCanvasObject
*) NULL
;
796 INOUTPOLY
wxCanvasPolygonL::PointInPolygon(const wxPoint2DDouble
& P
, double marge
)
798 int R_tot
= 0, L_tot
= 0;
800 double px
= P
.m_x
, py
= P
.m_y
;
802 wxPoint2DDouble p1
,p2
;
804 //iterate across points until we are sure that the given point is in or out
805 wxNode
*node
= m_lpoints
->GetFirst();
809 p1
= *(wxPoint2DDouble
*)node
->Data();
810 if (m_lpoints
->GetLast() == node
)
812 p2
= *(wxPoint2DDouble
*)m_lpoints
->GetFirst();
816 p2
= *(wxPoint2DDouble
*)node
->GetNext()->Data();
820 GetLRO(P
,p1
,p2
,p1_LRO
,p2_LRO
,marge
/10);
821 if (p1_LRO
!= p2_LRO
)
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
; }
828 // calculate intersection point with line for px
831 if ((p1
.m_y
< (py
+ marge
)) && (p1
.m_y
> (py
- marge
)))
834 Y_intersect
= p1
.m_y
;
836 else if (p2_LRO
== 0)
838 if ((p2
.m_y
< (py
+ marge
)) && (p2
.m_y
> (py
- marge
)))
841 Y_intersect
= p2
.m_y
;
843 else //both p2_LRO and p1_LRO not 0
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
851 if (!((p1
.m_x
== p2
.m_x
) && (p1
.m_y
== p2
.m_y
)))
854 line1
.CalculateLineParameters();
855 Y_intersect
= line1
.Calculate_Y(px
);
861 if (Y_intersect
> (py
+ marge
))
866 else if ((Y_intersect
<= (py
+ marge
)) && (Y_intersect
>= (py
- marge
)))
874 // geef het juiste resultaat terug
876 if (L_tot
== 0) return OUTSIDE_POLY
;
879 if (L_tot
== 0) return ON_POLY
;
880 else return INSIDE_POLY
;
883 // ---------------------------------------------------------------------------
884 // spline drawing code
885 // ---------------------------------------------------------------------------
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
);
895 void ConvertSplinedPolygon(int& n
, wxPoint2DDouble
* points
[], double Aber
)
899 for (i
= 0; i
< n
; i
++)
901 h
.Append((wxObject
*) new wxPoint2DDouble((*points
)[i
].m_x
, (*points
)[i
].m_y
));
905 ConvertSplinedPolygon(&h
, Aber
);
908 *points
= new wxPoint2DDouble
[n
];
909 wxNode
* node
=h
.GetFirst();
910 for (i
= 0; i
< n
; i
++)
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();
921 void ConvertSplinedPolygon(wxList
* list
, double Aber
)
923 wxPoint2DDouble
* point
;
924 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
925 double x1
, y1
, x2
, y2
;
927 if (list
->GetCount() <2)
930 wxNode
* iter
=list
->GetLast();
931 x1
= ((wxPoint2DDouble
*)iter
->Data())->m_x
;
932 y1
= ((wxPoint2DDouble
*)iter
->Data())->m_y
;
934 iter
=list
->GetFirst();
935 x2
= ((wxPoint2DDouble
*)iter
->Data())->m_x
;
936 y2
= ((wxPoint2DDouble
*)iter
->Data())->m_y
;
938 point
= new wxPoint2DDouble(x2
,y2
);
939 list
->Append((wxObject
*)point
);
941 cx1
= (x1
+ x2
) / 2.0;
942 cy1
= (y1
+ y2
) / 2.0;
943 cx2
= (cx1
+ x2
) / 2.0;
944 cy2
= (cy1
+ y2
) / 2.0;
946 delete (wxPoint2DDouble
*) iter
->Data();
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
);
955 int count
=list
->GetCount();
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;
967 gds_quadratic_spline(list
,cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
,Aber
);
971 cx2
= (cx1
+ x2
) / 2.0;
972 cy2
= (cy1
+ y2
) / 2.0;
973 delete (wxPoint2DDouble
*)iter
->Data();
975 iter
=list
->GetFirst();
979 iter
=list
->GetFirst();
980 delete (wxPoint2DDouble
*)iter
->Data();
984 void ConvertSplinedPolyline(wxList
* list
,double Aber
)
986 double cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
;
987 double x1
, y1
, x2
, y2
;
990 if (list
->GetCount() <2)
995 wxNode
* iter
=list
->GetFirst();
997 x1
= ((wxPoint2DDouble
*)iter
->Data())->m_x
;
998 y1
= ((wxPoint2DDouble
*)iter
->Data())->m_y
;
1000 delete (wxPoint2DDouble
*)iter
->Data();
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;
1010 wxPoint2DDouble
* point
= new wxPoint2DDouble(x1
,y1
);
1011 list
->Append((wxObject
*)point
);
1013 delete (wxPoint2DDouble
*)iter
->Data();
1015 iter
=list
->GetFirst();
1018 int count
=list
->GetCount();
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;
1030 gds_quadratic_spline(list
,cx1
, cy1
, cx2
, cy2
, cx3
, cy3
, cx4
, cy4
,Aber
);
1034 cx2
= (cx1
+ x2
) / 2.0;
1035 cy2
= (cy1
+ y2
) / 2.0;
1036 delete (wxPoint2DDouble
*)iter
->Data();
1038 iter
=list
->GetFirst();
1042 point
= new wxPoint2DDouble(cx1
,cy1
);
1043 list
->Append((wxObject
*)point
);
1045 point
= new wxPoint2DDouble(x2
,y2
);
1046 list
->Append((wxObject
*)point
);
1049 /********************* CURVES FOR SPLINES *****************************
1051 The following spline drawing routine is from
1053 "An Algorithm for High-Speed Curve Generation"
1054 by George Merrill Chaikin,
1055 Computer Graphics and Image Processing, 3, Academic Press,
1060 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1061 Computer Graphics and Image Processing, 4, Academic Press,
1064 ***********************************************************************/
1066 #define half(z1, z2) ((z1+z2)/2.0)
1069 /* iterative version */
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
)
1074 register double xmid
, ymid
;
1075 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
1076 wxPoint2DDouble
* point
;
1079 gds_spline_push(a1
, b1
, a2
, b2
, a3
, b3
, a4
, b4
);
1081 while (gds_spline_pop(&x1
, &y1
, &x2
, &y2
, &x3
, &y3
, &x4
, &y4
))
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
)
1088 point
= new wxPoint2DDouble(x1
,y1
);
1089 org
->Append((wxObject
*)point
);
1090 point
= new wxPoint2DDouble(xmid
,ymid
);
1091 org
->Append((wxObject
*)point
);
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
);
1102 /* utilities used by spline drawing routines */
1105 typedef struct gds_spline_stack_struct
{
1106 double x1
, y1
, x2
, y2
, x3
, y3
, x4
, y4
;
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
;
1115 static void gds_clear_stack()
1117 gds_stack_top
= gds_spline_stack
;
1118 gds_stack_count
= 0;
1121 static void gds_spline_push(double x1
, double y1
, double x2
, double y2
, double x3
, double y3
, double x4
, double y4
)
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
;
1135 int gds_spline_pop(double *x1
, double *y1
, double *x2
, double *y2
,
1136 double *x3
, double *y3
, double *x4
, double *y4
)
1138 if (gds_stack_count
== 0)
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
;
1153 void wxAET::CalculateLineParameters( const wxPoint2DDouble
& p1
, const wxPoint2DDouble
& p2
)
1155 double A
= p2
.m_y
- p1
.m_y
; //A (y2-y1)
1165 m_BdivA
= (p1
.m_x
- p2
.m_x
)/A
; //B (x1-x2)
1167 m_CdivA
= ((p2
.m_x
*p1
.m_y
) - (p1
.m_x
*p2
.m_y
)) /A
;
1171 void wxAET::CalculateXs( double y
)
1173 m_xs
= -m_BdivA
* y
- m_CdivA
;
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
)
1182 int walk
= (index
+ direction
+ m_n
) % m_n
;
1183 while ( m_points
[walk
].m_y
< horline
)
1185 if (m_points
[walk
].m_y
< m_points
[index
].m_y
)
1191 walk
= (index
+ direction
+ m_n
) % m_n
;
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()
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
;
1207 for ( i
=0; i
< m_n
; i
++)
1212 //check if Y is smaller
1213 if (m_points
[i
].m_y
> m_points
[j
].m_y
)
1214 //we have a candidate
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();
1222 //sorted on smallest Y value
1223 int* ind
=(int*) node
->GetData();
1224 if (m_points
[*ind
].m_y
> m_points
[i
].m_y
)
1226 m_CRlist
.Insert(node
,(wxObject
*) new int(i
));
1230 node
= node
->GetNext();
1233 m_CRlist
.Append((wxObject
*) new int(i
));
1239 for ( i
=0; i
< m_n
; i
++)
1244 //check if Y is smaller
1245 if (m_points
[i
].m_y
> m_points
[j
].m_y
)
1246 //we have a candidate
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();
1254 //sorted on smallest Y value
1255 int* ind
=(int*) node
->GetData();
1256 if (m_points
[*ind
].m_y
> m_points
[i
].m_y
)
1258 m_CRlist
.Insert(node
,(wxObject
*) new int(i
));
1262 node
= node
->GetNext();
1265 m_CRlist
.Append((wxObject
*) new int(i
));
1273 void wxCanvasPolygon::FillPolygon(wxTransformMatrix
* cworld
, int clip_x
, int clip_y
, int clip_width
, int clip_height
)
1278 //how much is on pixel in world coordinates
1282 scalefactor
=m_gdistance
;
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
1287 wxDC
*dc
= m_admin
->GetActive()->GetDC();
1288 dc
->SetClippingRegion( clip_x
, clip_y
, clip_width
, clip_height
);
1289 wxPen gradientpen
=m_gpen
;
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();
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
);
1299 DetectCriticalPoints();
1303 if (cworld
->IsIdentity())
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();
1314 min
= m_bbox
.GetMinY();
1315 max
= m_bbox
.GetMaxY();
1318 int curcol
= (int)( (min
- m_bbox
.GetMinY())/scalefactor
);
1321 for ( i
= min
; i
< max
; i
+=scalefactor
)
1323 wxNode
*node
= m_AETlist
.GetFirst();
1324 int count
= m_AETlist
.GetCount();
1327 wxAET
* ele
= ((wxAET
*)node
->GetData());
1328 index
= ele
->m_index
;
1329 int direction
= ele
->m_direction
;
1330 if (!MoveUp(i
,index
,direction
))
1334 node
= node
->GetNext();
1335 m_AETlist
.DeleteNode(h
);
1339 if (ele
->m_index
!= index
)
1342 int h
= (index
+ direction
+ m_n
) % m_n
;
1343 ele
->CalculateLineParameters(m_points
[h
],m_points
[index
]);
1345 if (ele
->m_horizontal
)
1346 ele
->m_xs
=m_points
[index
].m_x
;
1348 ele
->CalculateXs(i
);
1349 node
= node
->GetNext();
1354 node
= m_CRlist
.GetFirst();
1355 while (m_CRlist
.GetCount() && m_points
[*((int*)node
->GetData())].m_y
<=i
)
1358 for ( DI
= -1; DI
<=1 ; DI
+=2)
1360 index
=*((int*)node
->GetData());
1361 if (MoveUp(i
,index
,DI
))
1363 wxAET
* ele
= new wxAET();
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
;
1371 ele
->CalculateXs(i
);
1373 //insert in sorted order od m_xs
1374 bool inserted
=FALSE
;
1375 wxNode
*node2
= m_AETlist
.GetFirst();
1378 //sorted on smallest xs value
1379 if (ele
->m_xs
< ((wxAET
*)node2
->GetData())->m_xs
)
1381 m_AETlist
.Insert(node2
,(wxObject
*) ele
);
1385 node2
= node2
->GetNext();
1388 m_AETlist
.Append((wxObject
*)ele
);
1393 node
= node
->GetNext();
1394 m_CRlist
.DeleteNode(h
);
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
);
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)
1406 node
= m_AETlist
.GetFirst();
1409 wxAET
* ele
= ((wxAET
*)node
->GetData());
1410 out
+=ele
->m_direction
;
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
);
1427 //TODO KKK need real line clipping here since line can be rotated.
1428 if (0 && cworld
->IsIdentity())
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
);
1437 dc
->DrawLine( dx1
, dy1
, dx2
, dy2
);
1442 node
= node
->GetNext();
1446 dc
->DestroyClippingRegion();