wxArt2D
polyver.cpp
Go to the documentation of this file.
1 /*! \file artbase/src/polyver.cpp
2  \author Klaas Holwerda
3 
4  Copyright: 2000-2004 (c) Klaas Holwerda
5 
6  Licence: wxWidgets Licence
7 
8  RCS-ID: $Id: polyver.cpp,v 1.56 2009/09/30 18:38:57 titato Exp $
9 */
10 
11 #include "a2dprec.h"
12 
13 #ifdef __BORLANDC__
14 #pragma hdrstop
15 #endif
16 
17 #ifndef WX_PRECOMP
18 #include "wx/wx.h"
19 #endif
20 
21 
22 #include <float.h>
23 #include "wx/general/gen.h"
24 #include "wx/general/id.h"
25 #include "wx/artbase/polyver.h"
26 #include "wx/artbase/liner.h"
27 #include "wx/artbase/artglob.h"
28 
29 /*
30 IMPLEMENT_DYNAMIC_CLASS(a2dLineSegmentProperty,a2dNamedProperty)
31 
32 //----------------------------------------------------------------------------
33 // a2dLineSegmentProperty
34 //----------------------------------------------------------------------------
35 
36 a2dLineSegmentProperty::a2dLineSegmentProperty(): a2dNamedProperty()
37 {
38  m_segment = NULL;
39 }
40 
41 a2dLineSegmentProperty::a2dLineSegmentProperty( const a2dPropertyIdLineSegment &id, a2dLineSegment* segment )
42  : a2dNamedProperty( id )
43 {
44  m_segment = NULL;
45 }
46 
47 a2dLineSegmentProperty::~a2dLineSegmentProperty()
48 {
49 }
50 
51 a2dLineSegmentProperty::a2dLineSegmentProperty( const a2dLineSegmentProperty &other)
52  :a2dNamedProperty( other )
53 {
54  m_segment = other.m_segment;
55 }
56 
57 a2dNamedProperty *a2dLineSegmentProperty::Clone( a2dObject::CloneOptions options ) const
58 {
59  return new a2dLineSegmentProperty(*this);
60 };
61 
62 void a2dLineSegmentProperty::Assign( const a2dNamedProperty &other )
63 {
64  a2dLineSegmentProperty *propcast = wxStaticCast( &other, a2dLineSegmentProperty);
65  m_segment = propcast->m_segment;
66 }
67 
68 a2dLineSegmentProperty *a2dLineSegmentProperty::CreatePropertyFromString( const a2dPropertyIdLineSegment &id, const wxString &value )
69 {
70  return new a2dLineSegmentProperty( id, NULL );
71 }
72 
73 #if wxART2D_USE_CVGIO
74 void a2dLineSegmentProperty::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
75 {
76  wxASSERT(0);
77 }
78 
79 void a2dLineSegmentProperty::DoLoad( wxObject* parent, a2dIOHandlerXmlSerIn& parser, a2dXmlSer_flag xmlparts )
80 {
81  wxASSERT(0);
82 }
83 #endif //wxART2D_USE_CVGIO
84 */
85 
86 //----------------------------------------------------------------------------
87 // globals
88 //----------------------------------------------------------------------------
89 
91 ( a2dHit::hit_none, a2dHit::stroke1_none, a2dHit::stroke2_none, 0, 0 );
93 ( a2dHit::hit_fill, a2dHit::stroke1_none, a2dHit::stroke2_none, 0, 0 );
95 ( a2dHit::hit_stroke, a2dHit::stroke1_outside, a2dHit::stroke2_edgeother, 0, 0 );
97 ( a2dHit::hit_stroke, a2dHit::stroke1_inside, a2dHit::stroke2_edgeother, 0, 0 );
98 
99 
100 //! Calculate the square distance between a point and a line
101 /*! This returns DBL_MAX if the point is beyond the edges */
102 
103 double ClclDistSqrPntLine( const a2dPoint2D& p, const a2dPoint2D& p1, const a2dPoint2D& p2 )
104 {
105  double dx12 = double( p2.m_x ) - double( p1.m_x );
106  double dy12 = double( p2.m_y ) - double( p1.m_y );
107 
108  double dx1p = double( p.m_x ) - double( p1.m_x );
109  double dy1p = double( p.m_y ) - double( p1.m_y );
110 
111  // Calculate the square length
112  double length = dx12 * dx12 + dy12 * dy12;
113  // Calculate the projection * length
114  double projection = dx12 * dx1p + dy12 * dy1p;
115 
116  if( projection <= 0 || length == 0 )
117  {
118  // The point is beyond p1
119  return DBL_MAX;
120  }
121  else if( projection >= length )
122  {
123  // note projection and length can be compared, because both contain an extra
124  // length factor.
125  // The point is beyond p2
126  return DBL_MAX;
127  }
128  else
129  {
130  // The point is between p1 und p2
131 
132  // First check vertical and horizontal lines before doing sqrt and / operations
133  if( dx12 == 0 )
134  return dx1p * dx1p;
135  if( dy12 == 0 )
136  return dy1p * dy1p;
137 
138  // Note: we don't want the projection length, but the projection fraction
139  // between 0..1. As projection is the projection length * length, we must devide
140  // by length^2 here
141  projection /= length;
142  dx1p -= projection * dx12;
143  dy1p -= projection * dy12;
144  return dx1p * dx1p + dy1p * dy1p;
145  }
146 }
147 
148 A2DARTBASEDLLEXP bool InArc( double angle, double start, double end, bool clockwise )
149 {
150 
151  //if going counterclockwise from begin to end we pass trough middle => counterclockwise
152  //if going counterclockwise from begin to end we do NOT pass trough middle => clockwise
153 
154  //rotate such that start = zero
155  double mr, er;
156  mr = angle - start;
157  er = end - start;
158 
159  //make positive
160  if ( mr < 0 ) mr += 2.0 * M_PI;
161  if ( er < 0 ) er += 2.0 * M_PI;
162  if ( mr > 2.0 * M_PI ) mr -= 2.0 * M_PI;
163  if ( er > 2.0 * M_PI ) er -= 2.0 * M_PI;
164 
165  //middle gives direction
166  if ( mr < er )
167  {
168  if ( clockwise )
169  return false;
170  return true;
171  }
172  else
173  {
174  if ( clockwise )
175  return true;
176  return false;
177  }
178 }
179 
180 // ---------------------------------------------------------------------------
181 // spline drawing code
182 // ---------------------------------------------------------------------------
183 static void gds_quadratic_spline( a2dVertexList* org, double a1, double b1, double a2, double b2,
184  double a3, double b3, double a4, double b4, double aber );
185 static void gds_clear_stack();
186 static int gds_spline_pop( double* x1, double* y1, double* x2, double* y2, double* x3,
187  double* y3, double* x4, double* y4 );
188 static void gds_spline_push( double x1, double y1, double x2, double y2, double x3, double y3,
189  double x4, double y4 );
190 
191 //----------------------------------------------------------------------------
192 // polygon/line segments
193 //----------------------------------------------------------------------------
194 
195 //----------------------------------------------------------------------------
196 // a2dLineSegment
197 //----------------------------------------------------------------------------
198 
199 #ifdef CLASS_MEM_MANAGEMENT
200 a2dMemManager a2dLineSegment::sm_memManager( wxT( "a2dLineSegment memory manager" ) );
201 #endif //CLASS_MEM_MANAGEMENT
202 
203 a2dLineSegment::a2dLineSegment( double x, double y )
204 {
205  m_x = x;
206  m_y = y;
207  m_arc = false;
208  m_bin = false;
209  m_pntCnt = 1;
210  m_refcount = 0;
212 #if defined(_DEBUG) && defined (SMART_POINTER_DEBUG)
213  m_ownerlist = 0;
214 #endif
215 }
216 
218 {
219  m_x = point.m_x;
220  m_y = point.m_y;
221  m_arc = false;
222  m_bin = false;
223  m_pntCnt = 1;
224  m_refcount = 0;
226 #if defined(_DEBUG) && defined (SMART_POINTER_DEBUG)
227  m_ownerlist = 0;
228 #endif
229 }
230 
232 {
233  m_x = other.m_x;
234  m_y = other.m_y;
235  m_arc = other.m_arc;
236  m_bin = other.m_bin;
237  m_pntCnt = other.m_pntCnt;
238  m_refcount = 0;
239  m_segtype = other.m_segtype;
240 #if defined(_DEBUG) && defined (SMART_POINTER_DEBUG)
241  m_ownerlist = 0;
242 #endif
243 }
244 
245 a2dLineSegment::~a2dLineSegment()
246 {
247  wxASSERT_MSG( m_refcount == 0, wxT( "deleting a2dLineSegment while referenced" ) );
248 }
249 
251 {
252  a2dLineSegment* a = new a2dLineSegment( m_x, m_y );
253  return a;
254 }
255 
257 {
258  return sqrt( pow( prev.m_x - m_x, 2 ) + pow( prev.m_y - m_y, 2 ) );
259 }
260 
261 a2dBoundingBox a2dLineSegment::GetBbox( const a2dLineSegment& prev, const a2dAffineMatrix& WXUNUSED( lworld ) )
262 {
263  a2dBoundingBox bbox;
264  bbox.Expand( prev.m_x, prev.m_y );
265  bbox.Expand( m_x, m_y );
266  return bbox;
267 }
268 
269 #if defined(_DEBUG) && defined (SMART_POINTER_DEBUG)
270 
271 void a2dLineSegment::DumpOwners()
272 {
273  wxLogDebug( _T( "Owner list (%d) for (a2dLineSegment*)0x%p" ), m_refcount, this );
274  for( a2dLineSegmentPtr* crnt = m_ownerlist; crnt; crnt = crnt->m_next )
275  {
276  if( crnt->m_owner )
277  {
278  switch( crnt->m_ownertype )
279  {
281  wxLogDebug( _T( "SmrtPtr @ 0x%p in unknown %p" ), crnt, crnt->m_owner );
282  break;
284  wxLogDebug( _T( "SmrtPtr @ 0x%p in (%s*)0x%p offs=0x%x" ), crnt, ( ( wxObject* )crnt->m_owner )->GetClassInfo()->GetClassName(), crnt->m_owner, ( char* )crnt - ( char* )crnt->m_owner );
285  break;
287  wxLogDebug( _T( "SmrtPtr @ 0x%p in (wxSmrtPtrNode<a2dLineSegment>*)0x%p offs=0x%x" ), crnt, crnt->m_owner, ( char* )crnt - ( char* )crnt->m_owner );
288  break;
289  }
290  }
291  else
292  wxLogDebug( _T( "SmrtPtr @ 0x%p in unknown" ), crnt );
293  }
294 }
295 
296 #endif
297 
298 //----------------------------------------------------------------------------
299 // a2dArcSegment
300 //----------------------------------------------------------------------------
301 
302 a2dArcSegment::a2dArcSegment( double x1, double y1, double x2, double y2 )
303  : a2dLineSegment( x1, y1 )
304 {
305  m_arc = true;
306  m_x2 = x2;
307  m_y2 = y2;
308 }
309 
310 a2dArcSegment::a2dArcSegment( const a2dLineSegment& prev, double xc, double yc, double angle )
311  : a2dLineSegment( 0, 0 )
312 {
313  m_arc = true;
314 
315  double radius = sqrt( pow( prev.m_x - xc, 2 ) + pow( prev.m_y - yc, 2 ) );
316 
317  double endrad = atan2( prev.m_y - yc, prev.m_x - xc ) + wxDegToRad( angle );
318 
319  m_x = xc + radius * cos( endrad );
320  m_y = yc + radius * sin( endrad );
321 
322  double midrad = atan2( prev.m_y - yc, prev.m_x - xc ) + wxDegToRad( angle / 2.0 );
323 
324  m_x2 = xc + radius * cos( midrad );
325  m_y2 = yc + radius * sin( midrad );
326 }
327 
328 a2dArcSegment::a2dArcSegment( const a2dLineSegment& prev, double xc, double yc, double x1, double y1, double x2, double y2 )
329  : a2dLineSegment( x1, y1 )
330 {
331  m_arc = true;
332 
333  double radius = sqrt( pow( prev.m_x - xc, 2 ) + pow( prev.m_y - yc, 2 ) );
334 
335  double endrad = atan2( m_y - yc, m_x - xc );
336 
337  m_x = xc + radius * cos( endrad );
338  m_y = yc + radius * sin( endrad );
339 
340  double midrad = atan2( y2 - yc, x2 - xc );
341 
342  m_x2 = xc + radius * cos( midrad );
343  m_y2 = yc + radius * sin( midrad );
344 }
345 
347 {
348  m_x2 = other.m_x2;
349  m_y2 = other.m_y2;
350  m_arc = true;
351 }
352 
354 {}
355 
357 {
358  a2dArcSegment* a = new a2dArcSegment( m_x, m_y, m_x2, m_y2 );
359  return a;
360 }
361 
362 void a2dArcSegment::SetMidPoint( const a2dLineSegment& prev, double xm, double ym )
363 {
364  a2dPoint2D middleOrProj = a2dPoint2D( ( prev.m_x + m_x ) * 0.5, ( prev.m_y + m_y ) * 0.5 );
365  a2dLine line( prev.m_x, prev.m_y, m_x, m_y );
367  a2dLine* middleLine = line.CreatePerpendicularLineAt( middleOrProj );
368  middleOrProj = a2dPoint2D( xm, ym );
369  middleOrProj = middleLine->ProjectedPoint( middleOrProj );
370  delete middleLine;
371  m_x2 = middleOrProj.m_x;
372  m_y2 = middleOrProj.m_y;
373 }
374 
376 {
377  double len, radius, center_x, center_y, beginrad, midrad, endrad, phit;
378 
379  if ( CalcR( prev, radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
380  {
381  len = phit * radius;
382  }
383  else
384  len = sqrt( pow( prev.m_x - m_x, 2 ) + pow( prev.m_y - m_y, 2 ) );
385 
386  return len;
387 }
388 
389 void a2dArcSegment::CalcMidPoint( const a2dLineSegment& prev, double center_x, double center_y, double radius, bool clockwise )
390 {
391  double start = atan2( prev.m_y - center_y, prev.m_x - center_x );
392  double end = atan2( m_y - center_y, m_x - center_x );
393 
394  double b = ( prev.m_x - m_x );
395  double a = ( prev.m_y - m_y );
396  double l = sqrt( a * a + b * b );
397  a /= l; b /= l;
398 
399  m_x2 = center_x - radius * b;
400  m_y2 = center_y - radius * a;
401 
402  double mid = atan2( m_y2 - center_y, m_x2 - center_x );
403 
404  if ( InArc( mid, start, end, clockwise ) )
405  return;
406 
407  m_x2 = center_x + radius * b;
408  m_y2 = center_y + radius * a;
409 }
410 
411 bool a2dArcSegment::CalcR( const a2dLineSegment& prev, double& radius, double& center_x, double& center_y, double& beginrad, double& midrad, double& endrad, double& phit ) const
412 {
413  return ::CalcR( prev.m_x, prev.m_y, m_x2, m_y2, m_x, m_y,
414  radius, center_x, center_y, beginrad, midrad, endrad, phit );
415 }
416 
417 double a2dArcSegment::GetOx( const a2dLineSegment& prev ) const
418 {
419  double ax, ay, bx, by, cx, cy;
420  double ax2, ay2, bx2, by2, cx2, cy2;
421  double d;
422  bool straight = false;
423 
424  ax = prev.m_x; ay = prev.m_y; ax2 = pow( ax, 2 ); ay2 = pow( ay, 2 );
425  bx = m_x2; by = m_y2; bx2 = pow( bx, 2 ); by2 = pow( by, 2 );
426  cx = m_x; cy = m_y; cx2 = pow( cx, 2 ); cy2 = pow( cy, 2 );
427 
428  if ( ax == cx && ay == cy )
429  {
430  //assume the middle is exact 180 opposite.
431  return ( bx + ax ) / 2.0;
432  }
433  else
434  {
435  d = 2 * ( ay * cx + by * ax - by * cx - ay * bx - cy * ax + cy * bx );
436 
437  if ( fabs( d ) < a2dACCUR ) // (infinite radius)
438  {
439  d = a2dACCUR;
440  straight = true;
441  }
442 
443  return ( by * ax2 - cy * ax2 - by2 * ay + cy2 * ay + bx2 * cy + ay2 * by
444  + cx2 * ay - cy2 * by - cx2 * by - bx2 * ay + by2 * cy - ay2 * cy
445  ) / d;
446  }
447 }
448 
449 double a2dArcSegment::GetOy( const a2dLineSegment& prev ) const
450 {
451  double ax, ay, bx, by, cx, cy;
452  double ax2, ay2, bx2, by2, cx2, cy2;
453  double d;
454  bool straight = false;
455 
456  ax = prev.m_x; ay = prev.m_y; ax2 = pow( ax, 2 ); ay2 = pow( ay, 2 );
457  bx = m_x2; by = m_y2; bx2 = pow( bx, 2 ); by2 = pow( by, 2 );
458  cx = m_x; cy = m_y; cx2 = pow( cx, 2 ); cy2 = pow( cy, 2 );
459 
460  if ( ax == cx && ay == cy )
461  {
462  //assume the middle is exact 180 opposite.
463  return ( by + ay ) / 2.0;
464  }
465  else
466  {
467  d = 2 * ( ay * cx + by * ax - by * cx - ay * bx - cy * ax + cy * bx );
468 
469  if ( fabs( d ) < a2dACCUR ) // (infinite radius)
470  {
471  d = a2dACCUR;
472  straight = true;
473  }
474 
475  return ( ax2 * cx + ay2 * cx + bx2 * ax - bx2 * cx + by2 * ax - by2 * cx
476  - ax2 * bx - ay2 * bx - cx2 * ax + cx2 * bx - cy2 * ax + cy2 * bx
477  ) / d ;
478  }
479 }
480 
482 {
483  double ax, ay, bx, by, cx, cy;
484  double ax2, ay2, bx2, by2, cx2, cy2;
485  double d;
486  bool straight = false;
487 
488  ax = prev.m_x; ay = prev.m_y; ax2 = pow( ax, 2 ); ay2 = pow( ay, 2 );
489  bx = m_x2; by = m_y2; bx2 = pow( bx, 2 ); by2 = pow( by, 2 );
490  cx = m_x; cy = m_y; cx2 = pow( cx, 2 ); cy2 = pow( cy, 2 );
491 
492  if ( ax == cx && ay == cy )
493  {
494  //assume the middle is exact 180 opposite.
495  return a2dPoint2D( ( bx + ax ) / 2.0, ( by + ay ) / 2.0 );
496  }
497  else
498  {
499  d = 2 * ( ay * cx + by * ax - by * cx - ay * bx - cy * ax + cy * bx );
500 
501  if ( fabs( d ) < a2dACCUR ) // (infinite radius)
502  {
503  d = a2dACCUR;
504  straight = true;
505  }
506 
507  double x = ( by * ax2 - cy * ax2 - by2 * ay + cy2 * ay + bx2 * cy + ay2 * by
508  + cx2 * ay - cy2 * by - cx2 * by - bx2 * ay + by2 * cy - ay2 * cy
509  ) / d;
510 
511  double y = ( ax2 * cx + ay2 * cx + bx2 * ax - bx2 * cx + by2 * ax - by2 * cx
512  - ax2 * bx - ay2 * bx - cx2 * ax + cx2 * bx - cy2 * ax + cy2 * bx
513  ) / d ;
514  return a2dPoint2D( x, y );
515  }
516 }
517 
519 {
520  a2dBoundingBox bbox;
521  double radius, centerx, centery, start, mid, end, phit;
522 
523  if ( ! CalcR( prev, radius, centerx, centery, start, mid, end, phit ) )
524  {
525  bbox.Expand( prev.m_x, prev.m_y );
526  bbox.Expand( m_x, m_y );
527  return bbox;
528  }
529 
530  if ( !lworld.IsIdentity() )
531  {
532  double alphax = atan2( lworld.GetValue( 1, 0 ), lworld.GetValue( 0, 0 ) );
533  double alphay = atan2( lworld.GetValue( 1, 1 ), lworld.GetValue( 0, 1 ) );
534 
535  double x, y;
536 
537  //start point
538  lworld.TransformPoint( centerx + radius * cos ( start ), centery + radius * sin ( start ), x, y );
539  bbox.Expand( x, y );
540  //end point
541  lworld.TransformPoint( centerx + radius * cos ( end ), centery + radius * sin ( end ), x, y );
542  bbox.Expand( x, y );
543 
544  //outer points
545  if ( InArc( alphax, start, end, phit < 0 ) )
546  {
547  lworld.TransformPoint( centerx + radius * cos ( alphax ), centery + radius * sin ( alphax ), x, y );
548  bbox.Expand( x, y );
549  }
550  alphax += wxPI;
551  if ( InArc( alphax, start, end, phit < 0 ) )
552  {
553  lworld.TransformPoint( centerx + radius * cos ( alphax ), centery + radius * sin ( alphax ), x, y );
554  bbox.Expand( x, y );
555  }
556  alphax -= 2 * wxPI;
557  if ( InArc( alphax, start, end, phit < 0 ) )
558  {
559  lworld.TransformPoint( centerx + radius * cos ( alphax ), centery + radius * sin ( alphax ), x, y );
560  bbox.Expand( x, y );
561  }
562  if ( InArc( alphay, start, end, phit < 0 ) )
563  {
564  lworld.TransformPoint( centerx + radius * cos ( alphay ), centery + radius * sin ( alphay ), x, y );
565  bbox.Expand( x, y );
566  }
567  alphay += wxPI;
568  if ( InArc( alphay, start, end, phit < 0 ) )
569  {
570  lworld.TransformPoint( centerx + radius * cos ( alphay ), centery + radius * sin ( alphay ), x, y );
571  bbox.Expand( x, y );
572  }
573  alphay -= 2 * wxPI;
574  if ( InArc( alphay, start, end, phit < 0 ) )
575  {
576  lworld.TransformPoint( centerx + radius * cos ( alphay ), centery + radius * sin ( alphay ), x, y );
577  bbox.Expand( x, y );
578  }
579  }
580  else
581  {
582  //start point
583  bbox.Expand( centerx + radius * cos ( start ), centery + radius * sin ( start ) );
584  //end point
585  bbox.Expand( centerx + radius * cos ( end ), centery + radius * sin ( end ) );
586 
587  //outer points
588  if ( InArc( wxPI, start, end, phit < 0 ) )
589  bbox.Expand( centerx - radius, centery );
590  if ( InArc( 1.5 * wxPI, start, end, phit < 0 ) )
591  bbox.Expand( centerx, centery - radius );
592  if ( InArc( 0, start, end, phit < 0 ) )
593  bbox.Expand( centerx + radius, 0 );
594  if ( InArc( wxPI / 2, start, end, phit < 0 ) )
595  bbox.Expand( centerx, centery + radius );
596  }
597  return bbox;
598 }
599 
600 //----------------------------------------------------------------------------
601 // a2dVertexArray
602 //----------------------------------------------------------------------------
603 
605 {}
606 
608 {
609  *this = other;
610 }
611 
613 {
614  clear();
615  for( a2dVertexList::const_iterator iter = other.begin(); iter != other.end(); ++iter )
616  {
617  a2dLineSegmentPtr seg = ( *iter )->Clone();
618  push_back( seg );
619  }
620 }
621 
623 {}
624 
625 void a2dVertexArray::RemoveAt( size_t index )
626 {
627  size_t i = 0;
628  for( a2dVertexArray::iterator iter = begin(); iter != end(); ++iter )
629  {
630  if ( i == index )
631  {
632  erase( iter );
633  break;
634  }
635  i++;
636  }
637 }
638 
639 void a2dVertexArray::Insert( a2dLineSegment* segment, size_t index )
640 {
641  size_t i = 0;
642  for( a2dVertexArray::iterator iter = begin(); iter != end(); ++iter )
643  {
644  if ( i == index )
645  {
646  insert( iter, segment );
647  break;
648  }
649  i++;
650  }
651 }
652 
654 {
655  clear();
656  for( a2dVertexArray::const_iterator iter = other.begin(); iter != other.end(); ++iter )
657  {
658  a2dLineSegmentPtr seg = ( *iter )->Clone();
659  push_back( seg );
660  }
661 
662  return *this;
663 }
664 
666 {
667  clear();
668  for( a2dVertexList::const_iterator iter = other.begin(); iter != other.end(); ++iter )
669  {
670  a2dLineSegmentPtr seg = ( *iter )->Clone();
671  push_back( seg );
672  }
673  return *this;
674 }
675 
677 {
678  if ( index == 0 )
679  return Item( size() );
680  return Item( index - 1 );
681 }
682 
684 {
685  if ( index == size() )
686  return Item( 0 );
687  return Item( index + 1 );
688 }
689 
691 {
692  unsigned int i;
693  for ( i = 0; i < size(); i++ )
694  {
695  if ( Item( i )->GetArc() )
696  return true;
697  }
698  return false;
699 }
700 
702 {
703  double len = 0;
704  unsigned int i;
705  for ( i = 1; i < size(); i++ )
706  {
707  len = len + Item( i )->Length( *( Item( i - 1 ) ) );
708  }
709 
710  return len;
711 }
712 
713 
714 void a2dVertexArray::AddPoint( const a2dPoint2D& point, bool atEnd )
715 {
716  if ( atEnd )
717  push_back( new a2dLineSegment( point.m_x, point.m_y ) );
718  else
719  insert( begin(), new a2dLineSegment( point.m_x, point.m_y ) );
720 }
721 
722 void a2dVertexArray::AddPoint( double x, double y, bool atEnd )
723 {
724  if ( atEnd )
725  push_back( new a2dLineSegment( x, y ) );
726  else
727  insert( begin(), new a2dLineSegment( x, y ) );
728 }
729 
730 void a2dVertexArray::SetPointAdjustArcs( unsigned int n, double x, double y, bool polygon )
731 {
732  Item( n )->m_x = x;
733  Item( n )->m_y = y;
734 
735  if ( Item( n )->GetArc() )
736  {
737  a2dArcSegment* cseg = ( a2dArcSegment* ) Item( n ).Get();
738 
739  a2dLineSegmentPtr prev;
740  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
741  if ( polygon )
742  {
743  prev = Item( ( n - 1 ) % size() );
744 
745  if ( cseg->CalcR( *prev, radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
746  cseg->CalcMidPoint( *prev, center_x, center_y, radius, phit < 0 );
747  }
748  else
749  {
750  if ( n > 1 )
751  {
752  prev = Item( n - 1 );
753  if ( cseg->CalcR( *prev, radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
754  cseg->CalcMidPoint( *prev, center_x, center_y, radius, phit < 0 );
755  }
756  }
757  }
758 
759  a2dLineSegmentPtr next;
760  if ( polygon )
761  next = Item( ( n + 1 ) % size() );
762  else
763  {
764  if ( n < size() - 1 )
765  next = Item( n + 1 );
766  else
767  return;
768  }
769 
770  if ( next->GetArc() )
771  {
772  a2dArcSegment* cseg = ( a2dArcSegment* ) next->GetArc();
773 
774  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
775 
776  if ( cseg->CalcR( *( Item( n ) ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
777  cseg->CalcMidPoint( *( Item( n ) ), center_x, center_y, radius, phit < 0 );
778  }
779 }
780 
782 {
783  if ( size() < 3 )
784  return 0.0;
785 
786  double area = 0.0;
787 
788  a2dVertexArray* workOn = const_cast<a2dVertexArray*>( this );
789  double miny = workOn->Item( 0 )->m_y;
790  bool hasarcs = HasArcs();
791  if ( hasarcs )
792  {
793  workOn = new a2dVertexArray( *this );
794  workOn->ConvertToLines();
795  }
796 
797  a2dLineSegmentPtr seg;
798  unsigned int i;
799  for ( i = 0; i < size(); i++ )
800  {
801  seg = workOn->Item( i );
802  if ( seg->m_y < miny )
803  miny = seg->m_y;
804  }
805  if ( miny > 0 )
806  miny = 0;
807 
808  for ( int i = 0; i < workOn->size(); i++ )
809  {
810  double x = workOn->Item( i )->m_x;
811  double y = workOn->Item( i )->m_y - miny;
812  seg = Item( i + 1 != workOn->size() ? i + 1 : 0 );
813  area += ( seg->m_y - miny ) * x;
814  area -= seg->m_x * y;
815  }
816 
817  if ( hasarcs )
818  delete workOn;
819 
820  return fabs( area / 2.0 );
821 }
822 
824 {
825  if ( !cworld.IsIdentity() )
826  {
827  if ( !cworld.IsTranslate() )
828  ConvertToLines();
829 
830  unsigned int i;
831  for ( i = 0; i < size(); i++ )
832  {
833  a2dLineSegmentPtr seg = Item( i );
834  if ( seg->GetArc() )
835  {
836  a2dArcSegment* cseg = ( a2dArcSegment* ) seg.Get();
837  cworld.TransformPoint( cseg->m_x2, cseg->m_y2, cseg->m_x2, cseg->m_y2 );
838  }
839  cworld.TransformPoint( seg->m_x, seg->m_y, seg->m_x, seg->m_y );
840  }
841  }
842 }
843 
845 {
846  a2dBoundingBox bbox;
847 
848  double x, y;
849  lworld.TransformPoint( 0, 0, x, y );
850  if ( !size() )
851  bbox.Expand( x, y );
852  unsigned int i;
853  for ( i = 0; i < size(); i++ )
854  {
855  a2dLineSegmentPtr seg = Item( i );
856  if ( seg->GetArc() )
857  bbox.Expand( seg->GetBbox( *( Item( i ? i - 1 : 0 ) ), lworld ) );
858  else
859  {
860  lworld.TransformPoint( seg->m_x, seg->m_y, x, y );
861  bbox.Expand( x, y );
862  }
863  }
864  return bbox;
865 }
866 
867 void a2dVertexArray::ConvertToLines( double aberation )
868 {
869  double xw, yw;
870  a2dLineSegmentPtr segn;
871 
872  a2dVertexArray::iterator iterp = end();
873  a2dVertexArray::iterator iter = begin();
874  while ( iter != end() )
875  {
876  a2dLineSegment* seg = *iter;
877  if ( seg->GetArc() )
878  {
879  a2dArcSegment* cseg = ( a2dArcSegment* ) seg;
880 
881  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
882 
883  if ( cseg->CalcR( *( *iterp ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
884  {
885  double dphi;
886  unsigned int segments;
887  if ( aberation == 0 )
888  Aberration( radius / 200, phit, radius , dphi, segments );
889  //a2dGlobals->Aberration( phit, radius , dphi, segments );
890  else
891  Aberration( aberation, phit, radius , dphi, segments );
892 
893  double theta = beginrad;
894  unsigned int step;
895 
896  for ( step = 0; step < segments + 1; step++ )
897  {
898  xw = center_x + radius * cos ( theta );
899  yw = center_y + radius * sin ( theta );
900  segn = new a2dLineSegment( xw, yw );
901 
902  iter = insert( iter, segn );
903  iter++;
904  theta = theta + dphi;
905  }
906  }
907  else
908  {
909  segn = new a2dLineSegment( cseg->m_x, cseg->m_y );
910  iter = insert( iter, segn );
911  iter++;
912  }
913 
914  iter--; //last inserted segment
915  iterp = iter;
916  iter++;
917  iter = erase( iter );
918  }
919  else
920  {
921  iterp = iter;
922  iter++;
923  }
924  }
925 }
926 
927 a2dVpath* a2dVertexArray::ConvertToVpath( bool arc, bool closed )
928 {
929  a2dVpath* vpathsegments = new a2dVpath();
930 
931  double xw, yw;
932  unsigned int i;
933 
934  for ( i = 0; i < size(); i++ )
935  {
936  a2dLineSegmentPtr seg = Item( i );
937  if ( seg->GetArc() )
938  {
939  a2dArcSegment* cseg = ( a2dArcSegment* ) seg.Get();
940  if ( arc )
941  {
942  a2dVpathArcSegment* arcseg;
943  if ( i == 0 )
944  {
945  a2dVpathSegment* segn = new a2dVpathSegment( cseg->m_x, cseg->m_y, a2dPATHSEG_MOVETO );
946  vpathsegments->Add( segn );
947  arcseg = new a2dVpathArcSegment( cseg->m_x, cseg->m_y, cseg->m_x2, cseg->m_y2, a2dPATHSEG_ARCTO );
948  }
949  else if ( i == size() - 1 )
950  arcseg = new a2dVpathArcSegment( cseg->m_x, cseg->m_y, cseg->m_x2, cseg->m_y2, a2dPATHSEG_ARCTO, closed ? a2dPATHSEG_END_CLOSED : a2dPATHSEG_END_OPEN );
951  else
952  arcseg = new a2dVpathArcSegment( cseg->m_x, cseg->m_y, cseg->m_x2, cseg->m_y2, a2dPATHSEG_ARCTO );
953  vpathsegments->Add( arcseg );
954  }
955  else
956  {
957  // to line segments
958  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
959 
960  if ( cseg->CalcR( *( Item( i ? i - 1 : 0 ) ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
961  {
962  double dphi;
963  unsigned int segments;
964  Aberration( radius / 200, phit, radius , dphi, segments );
965  //a2dGlobals->Aberration( phit, radius , dphi, segments );
966 
967  double theta = beginrad;
968  unsigned int step;
969 
970  for ( step = 0; step < segments + 1; step++ )
971  {
972  xw = center_x + radius * cos ( theta );
973  yw = center_y + radius * sin ( theta );
974  a2dVpathSegment* lineseg = new a2dVpathSegment( xw, yw );
975  vpathsegments->Add( lineseg );
976  theta = theta + dphi;
977  }
978  }
979  else
980  {
981  a2dVpathSegment* segn = new a2dVpathSegment( cseg->m_x, cseg->m_y );
982  vpathsegments->Add( segn );
983  }
984  }
985  }
986  else
987  {
988  a2dVpathSegment* lineseg;
989  if ( i == 0 )
990  lineseg = new a2dVpathSegment( seg->m_x, seg->m_y , a2dPATHSEG_MOVETO );
991  else if ( i == size() - 1 )
992  lineseg = new a2dVpathSegment( seg->m_x, seg->m_y, a2dPATHSEG_LINETO, closed ? a2dPATHSEG_END_CLOSED : a2dPATHSEG_END_OPEN );
993  else
994  lineseg = new a2dVpathSegment( seg->m_x, seg->m_y, a2dPATHSEG_LINETO );
995  vpathsegments->Add( lineseg );
996  }
997  }
998  return vpathsegments;
999 }
1000 
1002 {
1003  a2dVertexArray* converted = new a2dVertexArray();
1004  a2dPoint2D _first;
1005  a2dPoint2D _middle;
1006  a2dPoint2D _end;
1007  a2dPoint2D offsetpointleft;
1008  a2dPoint2D offsetpointright;
1009 
1010  unsigned int insertAt = converted->size();
1011  a2dVertexArray::iterator insertHere = end();
1012  unsigned int segments = size();
1013 
1014  //create start of subpart
1015  a2dLineSegmentPtr seg = Item( 0 );
1016  if ( segments == 1 )
1017  {
1018  converted->push_back( new a2dLineSegment( seg->m_x - distance, seg->m_y ) );
1019  switch ( pathtype )
1020  {
1021  case a2dPATH_END_SQAURE:
1022  {
1023  //not defined
1024  }
1025  break;
1026  case a2dPATH_END_ROUND:
1027  {
1028  converted->push_back( new a2dArcSegment( seg->m_x + distance, seg->m_y, seg->m_x - distance, seg->m_y ) );
1029  }
1030  break;
1031  case a2dPATH_END_SQAURE_EXT:
1032  {
1033  //not defined
1034  }
1035  break;
1036  default:
1037  break;
1038  }
1039  return converted;
1040  }
1041  else
1042  {
1043  //first begin point
1044  _first = a2dPoint2D( seg->m_x, seg->m_y );
1045  a2dLineSegmentPtr segnext = Item( 1 );
1046  _middle = a2dPoint2D( segnext->m_x, segnext->m_y );
1047  a2dLine line1( _first, _middle );
1048  line1.CalculateLineParameters();
1049  offsetpointleft = _first;
1050  offsetpointright = _first;
1051  line1.Virtual_Point( offsetpointleft, distance );
1052  line1.Virtual_Point( offsetpointright, -distance );
1053 
1054  switch ( pathtype )
1055  {
1056  case a2dPATH_END_SQAURE:
1057  {
1058  converted->push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
1059  insertHere = converted->insert( insertHere, new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
1060  }
1061  break;
1062  case a2dPATH_END_ROUND:
1063  {
1064  a2dLine lineoffset( offsetpointright, offsetpointleft );
1065  lineoffset.CalculateLineParameters();
1066  a2dPoint2D offsetpointfirst;
1067 
1068  offsetpointfirst = _first;
1069  lineoffset.Virtual_Point( offsetpointfirst, distance );
1070  converted->push_back( new a2dArcSegment( offsetpointleft.m_x, offsetpointleft.m_y,
1071  offsetpointfirst.m_x, offsetpointfirst.m_y ) );
1072  insertHere = converted->insert( insertHere, new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
1073  break;
1074  }
1075  case a2dPATH_END_SQAURE_EXT:
1076  {
1077  a2dLine lineoffset( offsetpointright, offsetpointleft );
1078  lineoffset.CalculateLineParameters();
1079  lineoffset.Virtual_Point( offsetpointleft, distance );
1080  lineoffset.Virtual_Point( offsetpointright, distance );
1081 
1082  converted->push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
1083  insertHere = converted->insert( insertHere, new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
1084  break;
1085  }
1086  default:
1087  break;
1088  }
1089 
1090  }
1091 
1092  //in between start and end
1093  unsigned int i;
1094  for ( i = 1; i < segments - 1; i++ )
1095  {
1096  a2dLineSegmentPtr seg = Item( i - 1 );
1097  _first = a2dPoint2D( seg->m_x, seg->m_y );
1098  a2dLineSegmentPtr segnext = Item( i );
1099  _middle = a2dPoint2D( segnext->m_x, segnext->m_y );
1100  a2dLine line1( _first, _middle );
1101  a2dLineSegmentPtr segend = Item( i + 1 );
1102  _end = a2dPoint2D( segend->m_x, segend->m_y );
1103  a2dLine line2( _middle, _end );
1104  line1.CalculateLineParameters();
1105  line2.CalculateLineParameters();
1106 
1107  OUTPRODUCT _outproduct;
1108  _outproduct = line1.OutProduct( line2, 1e-9 );
1109 
1110  switch ( _outproduct )
1111  {
1112  // Line 2 lies on leftside of this line
1113  case R_IS_RIGHT :
1114  {
1115  line1.OffsetContour( line2, distance, offsetpointleft );
1116  line1.OffsetContour( line2, -distance, offsetpointright );
1117  }
1118  break;
1119  case R_IS_LEFT :
1120  {
1121  line1.OffsetContour( line2, distance, offsetpointleft );
1122  line1.OffsetContour( line2, -distance, offsetpointright );
1123  }
1124  break;
1125  // Line 2 lies on this line
1126  case R_IS_ON :
1127  {
1128  offsetpointleft = _middle;
1129  offsetpointright = _middle;
1130  line1.Virtual_Point( offsetpointleft, distance );
1131  line1.Virtual_Point( offsetpointright, -distance );
1132  }
1133  break;
1134  default:
1135  wxFAIL_MSG( wxT( "wrong line code" ) );
1136  break;
1137  }//end switch
1138 
1139  converted->push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
1140  insertHere = converted->insert( insertHere, new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
1141  }
1142 
1143  seg = Item( i - 1 ); //i = start+segments-1
1144 
1145  //first begin point
1146  _first = a2dPoint2D( seg->m_x, seg->m_y );
1147  a2dLineSegmentPtr segnext = Item( i );
1148  _end = a2dPoint2D( segnext->m_x, segnext->m_y );
1149  a2dLine line1( _first, _end );
1150  line1.CalculateLineParameters();
1151  offsetpointleft = _end;
1152  offsetpointright = _end;
1153  line1.Virtual_Point( offsetpointleft, distance );
1154  line1.Virtual_Point( offsetpointright, -distance );
1155 
1156  switch ( pathtype )
1157  {
1158  case a2dPATH_END_SQAURE:
1159  {
1160  converted->push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
1161  insertHere = converted->insert( insertHere, new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
1162  }
1163  break;
1164  case a2dPATH_END_ROUND:
1165  {
1166  a2dLine lineoffset( offsetpointleft, offsetpointright );
1167  lineoffset.CalculateLineParameters();
1168  a2dPoint2D offsetpointend;
1169 
1170  offsetpointend = _end;
1171  lineoffset.Virtual_Point( offsetpointend, distance );
1172  converted->push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
1173  converted->push_back( new a2dArcSegment( offsetpointright.m_x, offsetpointright.m_y,
1174  offsetpointend.m_x, offsetpointend.m_y ) );
1175  insertHere = converted->insert( insertHere, new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
1176  break;
1177  }
1178  case a2dPATH_END_SQAURE_EXT:
1179  {
1180  a2dLine lineoffset( offsetpointright, offsetpointleft );
1181  lineoffset.CalculateLineParameters();
1182  lineoffset.Virtual_Point( offsetpointleft, -distance );
1183  lineoffset.Virtual_Point( offsetpointright, -distance );
1184 
1185  converted->push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
1186  insertHere = converted->insert( insertHere, new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
1187  break;
1188  }
1189  default:
1190  break;
1191  }
1192 
1193  return converted;
1194 }
1195 
1197 {
1198  a2dVertexList h;
1199  unsigned int i;
1200  for ( i = 0; i < size(); i++ )
1201  {
1202  h.push_back( Item( i )->Clone() );
1203  }
1204 
1205  //TODO need an array version for speed
1206  h.ConvertIntoSplinedPolygon( Aber );
1207 
1208  unsigned int n = h.size();
1209  a2dVertexArray* spoints = new a2dVertexArray;
1210 
1211  a2dVertexList::iterator iter = h.begin();
1212  for ( i = 0; i < n; i++ )
1213  {
1214  spoints->push_back( ( *iter ) );
1215  iter = h.erase( iter );
1216  }
1217 
1218  return spoints;
1219 }
1220 
1222 {
1223  a2dVertexList h;
1224  unsigned int i;
1225  for ( i = 0; i < size(); i++ )
1226  {
1227  h.push_back( Item( i )->Clone() );
1228  }
1229 
1230  //TODO need an array version for speed
1231  h.ConvertIntoSplinedPolyline( Aber );
1232 
1233  unsigned int n = h.size();
1234  a2dVertexArray* spoints = new a2dVertexArray;
1235 
1236  a2dVertexList::iterator iter = h.begin();
1237  for ( i = 0; i < n; i++ )
1238  {
1239  spoints->push_back( ( *iter )->Clone() );
1240  iter = h.erase( iter );
1241  }
1242  return spoints;
1243 }
1244 
1245 
1246 /*! This function checks if a point is inside, outside or on the stroke of a polygon.
1247 This is done intersecting a vertical line through the test point with every edge of
1248 the polygon. Then the number of intersections above (y+) of the test point is counted
1249 +1 for left to right and -1 for right to left lines.
1250 There is an almost identical function for point list polygons. These functions should
1251 be kept identical except of the first two lines the handle lists or arrays.
1252 */
1253 
1254 a2dHit a2dVertexArray::HitTestPolygon( const a2dPoint2D& ptest, double margin )
1255 {
1256  wxASSERT( margin >= 0 );
1257 
1258  a2dPoint2D p1, p2, pm;
1259 
1260  double minDistSqrVertex = margin * margin;
1261  double minDistSqrStroke = margin * margin;
1262  bool vertexhit = false;
1263  int intersection_count = 0;
1264  a2dHit rslt;
1265 
1266  //iterate across points until we are sure that the given point is in or out
1267  unsigned int i;
1268  for ( i = 0; i < size(); i++ )
1269  {
1270  // Get the two points of edge #i
1271  p1 = Item( i )->GetPoint();
1272  if ( i == size() - 1 )
1273  p2 = Item( 0 )->GetPoint();
1274  else
1275  p2 = Item( i + 1 )->GetPoint();
1276 
1277  //--------------------------------------------------------------------
1278  // From here on, this function is identical to the hittest for
1279  // point array polygons. Keep these two identical !!
1280  //--------------------------------------------------------------------
1281 
1282  // check relative horizontal positions of line end points and point
1283  double xmin;
1284  double xmax;
1285  int direction;
1286  // Note: the case p1.m_x == p2.m_x is ignored during direction counting
1287  // See below.
1288  if( p1.m_x < p2.m_x )
1289  {
1290  xmin = p1.m_x;
1291  xmax = p2.m_x;
1292  direction = 1;
1293  }
1294  else
1295  {
1296  xmin = p2.m_x;
1297  xmax = p1.m_x;
1298  direction = -1;
1299  }
1300 
1301  if( ptest.m_x < xmin - margin || ptest.m_x > xmax + margin )
1302  continue;
1303 
1304  // check relative horizontal positions of line end points and point
1305  double ymin;
1306  double ymax;
1307  if( p1.m_y < p2.m_y )
1308  {
1309  ymin = p1.m_y;
1310  ymax = p2.m_y;
1311  }
1312  else
1313  {
1314  ymin = p2.m_y;
1315  ymax = p1.m_y;
1316  }
1317 
1318  // if ptest its y is beneath the minimum y of the segment, the ray does
1319  // intersect if x p1 and x p2 are on opposite sides.
1320  if( ptest.m_y < ymin - margin )
1321  {
1322  // The test point is definitely below the margin.
1323  // This cannot be a stroke hit
1324  // but the vertical line through ptest can intersect the edge
1325  if( ptest.m_x >= xmin && ptest.m_x < xmax && p1.m_x != p2.m_x )
1326  {
1327  intersection_count += direction;
1328  }
1329  }
1330  else if( ptest.m_y <= ymax + margin )
1331  {
1332  // The test point ptest is inside the margin extended bounding box+margin of the edge
1333  // This means we make vertex and stroke hit tests
1334  // and an intersection test between edge and the vertical line through ptest
1335 
1336  // Vertex hit test for point 1
1337  //
1338  // Note1: double ifs are MUCH slower than double calculations (at least on intel)
1339  // So it is faster calculating the distance square than doing a rectangle test
1340  //
1341  // Note2: vertex hits have higher priority than edge hits
1342  //
1343  // Note3: every vertex is once point1 and once point 2, so only one point needs
1344  // to be tested.
1345  //
1346  // Note4: Even if there is a stroke or vertex hit, serach is continued, because
1347  // there could be better hit. A stroke or vertex hit is rarely a random event,
1348  // so it doesn't make much sense to optimize this.
1349 
1350  double distSqr = ClclDistSqrPntPnt( ptest, p1 );
1351 
1352  if( distSqr < minDistSqrVertex )
1353  {
1354  minDistSqrVertex = distSqr;
1355  rslt.m_hit = a2dHit::hit_stroke;
1356  rslt.m_index = i;
1357  rslt.m_stroke2 = a2dHit::stroke2_vertex;
1358  vertexhit = true;
1359  }
1360 
1361  // Stroke center hit-test
1362  // This is done to allow hitting the stroke even if the stroke length
1363  // is leth than the hit margin. As vertex hits have priority, the stroke
1364  // coldn't be hit then. So the stroke center is treated as pseudo-vertex.
1365  pm = a2dPoint2D( 0.5 * ( p1.m_x + p2.m_x ), 0.5 * ( p1.m_y + p2.m_y ) );
1366  distSqr = ClclDistSqrPntPnt( ptest, pm );
1367  if( distSqr < minDistSqrVertex )
1368  {
1369  minDistSqrVertex = distSqr;
1370  rslt.m_hit = a2dHit::hit_stroke;
1371  rslt.m_index = i;
1372  if( p1.m_x == p2.m_x )
1373  rslt.m_stroke2 = a2dHit::stroke2_edgevert;
1374  else if( p1.m_y == p2.m_y )
1375  rslt.m_stroke2 = a2dHit::stroke2_edgehor;
1376  else
1377  rslt.m_stroke2 = a2dHit::stroke2_edgeother;
1378  vertexhit = true;
1379  }
1380 
1381  // Edge hit test
1382  // Note: The edge hittest is even done if a higher prioroity
1383  // vertex hit exists, and no edgehit can accur. This is done
1384  // because the distance of a vertex hit shall not be worse
1385  // then the distance from the closest edge, which is calculated
1386  // here.
1387  distSqr = ClclDistSqrPntLine( ptest, p1, p2 );
1388 
1389  if( distSqr < minDistSqrStroke )
1390  {
1391  minDistSqrStroke = distSqr;
1392  if( !vertexhit )
1393  {
1394  rslt.m_hit = a2dHit::hit_stroke;
1395  rslt.m_index = i;
1396  if( p1.m_x == p2.m_x )
1397  rslt.m_stroke2 = a2dHit::stroke2_edgevert;
1398  else if( p1.m_y == p2.m_y )
1399  rslt.m_stroke2 = a2dHit::stroke2_edgehor;
1400  else
1401  rslt.m_stroke2 = a2dHit::stroke2_edgeother;
1402  }
1403  }
1404 
1405  // Intersection test for inside/outside test
1406  // Vertical lines are ignored in the inside/outside test.
1407  // They are really not important for this.
1408  // You can define that on the vertical line you get the same result as
1409  // above or below the vertical line.
1410  // The right side of the ray is the side where inside outside is defined.
1411  // Lines starting/ending at the ray going to the right are seen, while lines
1412  // ending/starting on the ray coming from the left are not.
1413  if( ptest.m_x >= xmin && ptest.m_x < xmax && p1.m_x != p2.m_x )
1414  {
1415  if( p1.m_y == p2.m_y )
1416  {
1417  if( ptest.m_y <= p1.m_y )
1418  intersection_count += direction;
1419  }
1420  else
1421  {
1422  double y = ( ptest.m_x - p1.m_x ) * ( p2.m_y - p1.m_y ) / ( p2.m_x - p1.m_x ) + p1.m_y;
1423  if( ptest.m_y <= y )
1424  intersection_count += direction;
1425  }
1426  }
1427  }
1428  }
1429 
1430  if( rslt.m_hit == a2dHit::hit_stroke )
1431  {
1432  if( intersection_count )
1433  rslt.m_stroke1 = a2dHit::stroke1_inside;
1434  else
1435  rslt.m_stroke1 = a2dHit::stroke1_outside;
1436 
1437  if( vertexhit )
1438  rslt.m_distance = ( sqrt( wxMin( minDistSqrVertex, minDistSqrStroke ) ) / margin );
1439  else
1440  rslt.m_distance = ( sqrt( minDistSqrStroke ) / margin );
1441  }
1442  else
1443  {
1444  if( intersection_count )
1445  rslt.m_hit = a2dHit::hit_fill;
1446  else
1447  rslt.m_hit = a2dHit::hit_none;
1448  }
1449 
1450  return rslt;
1451 }
1452 
1453 a2dHit a2dVertexArray::HitTestPolyline( const a2dPoint2D& ptest, double margin )
1454 {
1455  wxASSERT( margin >= 0 );
1456 
1457  a2dPoint2D p1, p2, pm;
1458 
1459  double minDistSqrVertex = margin * margin;
1460  double minDistSqrStroke = margin * margin;
1461  bool vertexhit = false;
1462  bool lastpoint = false;
1463  a2dHit rslt;
1464 
1465  //iterate across points until we are sure that the given point is in or out
1466  unsigned int i;
1467  for ( i = 0; i < size(); i++ )
1468  {
1469  // Get the two points of edge #i
1470  p1 = Item( i )->GetPoint();
1471  if( i < size() - 1 )
1472  p2 = Item( i + 1 )->GetPoint();
1473  else
1474  lastpoint = true;
1475 
1476  //--------------------------------------------------------------------
1477  // From here on, this function is identical to the hittest for
1478  // point array polylines. Keep these two identical !!
1479  //--------------------------------------------------------------------
1480 
1481  // check relative horizontal positions of line end points and point
1482  double xmin;
1483  double xmax;
1484 
1485  if( p1.m_x < p2.m_x )
1486  {
1487  xmin = p1.m_x;
1488  xmax = p2.m_x;
1489  }
1490  else
1491  {
1492  xmin = p2.m_x;
1493  xmax = p1.m_x;
1494  }
1495 
1496  if( ptest.m_x < xmin - margin || ptest.m_x > xmax + margin )
1497  continue;
1498 
1499  // check relative horizontal positions of line end points and point
1500  double ymin;
1501  double ymax;
1502  if( p1.m_y < p2.m_y )
1503  {
1504  ymin = p1.m_y;
1505  ymax = p2.m_y;
1506  }
1507  else
1508  {
1509  ymin = p2.m_y;
1510  ymax = p1.m_y;
1511  }
1512 
1513  if( ptest.m_y < ymin - margin || ptest.m_y > ymax + margin )
1514  continue;
1515 
1516  // The test point ptest is inside the margin extended bounding box+margin of the edge
1517  // This means we make vertex and stroke hit tests
1518  // and an intersection test between edge and the vertical line through ptest
1519 
1520  // Vertex hit test for point 1
1521  //
1522  // Note1: double ifs are MUCH slower than double calculations (at least on intel)
1523  // So it is faster calculating the distance square than doing a rectangle test
1524  //
1525  // Note2: vertex hits have higher priority than edge hits
1526  //
1527  // Note3: every vertex is once point1 and once point 2, so only one point needs
1528  // to be tested.
1529  //
1530  // Note4: Even if there is a stroke or vertex hit, search is continued, because
1531  // there could be better hit. A stroke or vertex hit is rarely a random event,
1532  // so it doesn't make much sense to optimize this.
1533 
1534  double distSqr = ClclDistSqrPntPnt( ptest, p1 );
1535 
1536  if( distSqr < minDistSqrVertex )
1537  {
1538  minDistSqrVertex = distSqr;
1539  rslt.m_hit = a2dHit::hit_stroke;
1540  rslt.m_index = i;
1541  rslt.m_stroke2 = a2dHit::stroke2_vertex;
1542  vertexhit = true;
1543  }
1544 
1545  if( lastpoint )
1546  break;
1547 
1548  // Stroke center hit-test
1549  // This is done to allow hitting the stroke even if the stroke length
1550  // is less than the hit margin. As vertex hits have priority, the stroke
1551  // couldn't be hit then. So the stroke center is treated as pseudo-vertex.
1552  pm = a2dPoint2D( 0.5 * ( p1.m_x + p2.m_x ), 0.5 * ( p1.m_y + p2.m_y ) );
1553  distSqr = ClclDistSqrPntPnt( ptest, pm );
1554  if( distSqr < minDistSqrVertex )
1555  {
1556  minDistSqrVertex = distSqr;
1557  rslt.m_hit = a2dHit::hit_stroke;
1558  rslt.m_index = i;
1559  if( p1.m_x == p2.m_x )
1560  rslt.m_stroke2 = a2dHit::stroke2_edgevert;
1561  else if( p1.m_y == p2.m_y )
1562  rslt.m_stroke2 = a2dHit::stroke2_edgehor;
1563  else
1564  rslt.m_stroke2 = a2dHit::stroke2_edgeother;
1565  vertexhit = true;
1566  }
1567 
1568  // Edge hit test
1569  // Note: The edge hittest is even done if a higher prioroity
1570  // vertex hit exists, and no edgehit can accur. This is done
1571  // because the distance of a vertex hit shall not be worse
1572  // then the distance from the closest edge, which is calculated
1573  // here.
1574  distSqr = ClclDistSqrPntLine( ptest, p1, p2 );
1575 
1576  if( distSqr < minDistSqrStroke )
1577  {
1578  minDistSqrStroke = distSqr;
1579  if( !vertexhit )
1580  {
1581  rslt.m_hit = a2dHit::hit_stroke;
1582  rslt.m_index = i;
1583  if( p1.m_x == p2.m_x )
1584  rslt.m_stroke2 = a2dHit::stroke2_edgevert;
1585  else if( p1.m_y == p2.m_y )
1586  rslt.m_stroke2 = a2dHit::stroke2_edgehor;
1587  else
1588  rslt.m_stroke2 = a2dHit::stroke2_edgeother;
1589  }
1590  }
1591  }
1592 
1593  if( rslt.m_hit == a2dHit::hit_stroke )
1594  {
1595  rslt.m_stroke1 = a2dHit::stroke1_outside;
1596  if( vertexhit )
1597  rslt.m_distance = ( sqrt( wxMin( minDistSqrVertex, minDistSqrStroke ) ) / margin );
1598  else
1599  rslt.m_distance = ( sqrt( minDistSqrStroke ) / margin );
1600  }
1601 
1602  return rslt;
1603 }
1604 
1606 {
1607  bool did = false;
1608  a2dLineSegmentPtr segprev = NULL;
1609  a2dLineSegmentPtr seg = NULL;
1610  unsigned int i;
1611  for ( i = 0; i < size(); i++ )
1612  {
1613  seg = Item( i );
1614  if ( !seg->GetArc() && segprev && seg->GetPoint() == segprev->GetPoint() )
1615  {
1616  RemoveAt( i );
1617  i--;
1618  did = true;
1619  }
1620  else
1621  segprev = seg;
1622  }
1623  seg = Item( 0 );
1624  if ( polygon && !seg->GetArc() && segprev && seg->GetPoint() == segprev->GetPoint() )
1625  {
1626  RemoveAt( size() - 1 );
1627  did = true;
1628  }
1629  return did;
1630 }
1631 
1632 a2dVertexList* a2dVertexArray::GetRedundant( bool polygon, double smallest )
1633 
1634 {
1635  a2dVertexList* redunDant = new a2dVertexList();
1636  a2dLineSegmentPtr segprev = NULL;
1637  a2dLineSegmentPtr seg = NULL;
1638  unsigned int i;
1639  for ( i = 0; i < size(); i++ )
1640  {
1641  seg = Item( i );
1642  if ( !seg->GetArc() && segprev &&
1643  ( seg->GetPoint() == segprev->GetPoint() || ClclDistSqrPntPnt( seg->GetPoint(), segprev->GetPoint() ) <= smallest ) )
1644 
1645  {
1646  redunDant->push_back( seg->Clone() );
1647  }
1648  segprev = seg;
1649  }
1650  seg = Item( 0 );
1651  if ( polygon && !seg->GetArc() && segprev &&
1652  ( seg->GetPoint() == segprev->GetPoint() || ClclDistSqrPntPnt( seg->GetPoint(), segprev->GetPoint() ) <= smallest ) )
1653 
1654  redunDant->push_back( seg->Clone() );
1655 
1656  if ( redunDant->empty() )
1657  {
1658  delete redunDant;
1659  redunDant = NULL;
1660  }
1661  return redunDant;
1662 }
1663 
1664 
1665 //----------------------------------------------------------------------------
1666 // a2dVertexList
1667 //----------------------------------------------------------------------------
1668 
1669 a2dVertexList::a2dVertexList()
1670 {
1671  m_refcount = 0;
1672 }
1673 
1674 a2dVertexList::a2dVertexList( const a2dVertexList& other )
1675 {
1676  m_refcount = 0;
1677  *this = other;
1678 }
1679 
1680 a2dVertexList::a2dVertexList( const a2dVertexArray& other )
1681 {
1682  m_refcount = 0;
1683  clear();
1684  for( a2dVertexArray::const_iterator iter = other.begin(); iter != other.end(); ++iter )
1685  {
1686  a2dLineSegmentPtr seg = ( *iter )->Clone();
1687  push_back( seg );
1688  }
1689 }
1690 
1691 a2dVertexList::~a2dVertexList()
1692 {
1693  wxASSERT_MSG( m_refcount == 0, wxT( "deleting a2dLineSegment while referenced" ) );
1694  clear();
1695 }
1696 
1697 a2dVertexList& a2dVertexList::operator=( const a2dVertexList& other )
1698 {
1699  clear();
1700 
1701  for( a2dVertexList::const_iterator iter = other.begin(); iter != other.end(); ++iter )
1702  {
1703  a2dLineSegment* seg = ( *iter )->Clone();
1704  push_back( seg );
1705  }
1706 
1707  return *this;
1708 }
1709 
1710 a2dVertexList& a2dVertexList::operator=( const a2dVertexArray& other )
1711 {
1712  clear();
1713  for( a2dVertexArray::const_iterator iter = other.begin(); iter != other.end(); ++iter )
1714  {
1715  a2dLineSegment* seg = ( *iter )->Clone();
1716  push_back( seg );
1717  }
1718  return *this;
1719 }
1720 
1721 a2dVertexList::iterator a2dVertexList::GetPreviousAround( a2dVertexList::iterator iter )
1722 {
1723  if ( iter == begin() )
1724  return --end();
1725  return --iter;
1726 }
1727 
1728 a2dVertexList::iterator a2dVertexList::GetNextAround( a2dVertexList::iterator iter )
1729 {
1730  if ( iter == --end() )
1731  return begin();
1732  return ++iter;
1733 }
1734 
1735 a2dVertexList::const_iterator a2dVertexList::GetPreviousAround( a2dVertexList::const_iterator iter ) const
1736 {
1737  if ( iter == begin() )
1738  return --end();
1739  return --iter;
1740 }
1741 
1742 a2dVertexList::const_iterator a2dVertexList::GetNextAround( a2dVertexList::const_iterator iter ) const
1743 {
1744  if ( iter == --end() )
1745  return begin();
1746  return ++iter;
1747 }
1748 
1749 void a2dVertexList::MakeBegin( a2dVertexList::iterator iter )
1750 {
1751  a2dVertexList::iterator iterr = begin();
1752  while( iterr != iter )
1753  {
1754  a2dLineSegmentPtr seg = *iterr;
1755  ++iterr;
1756  pop_front();
1757  push_back( seg );
1758  }
1759 }
1760 
1762 {
1763  for( a2dVertexList::const_iterator iter = begin(); iter != end(); ++iter )
1764  {
1765  a2dLineSegment* seg = *iter;
1766  if ( seg->GetArc() )
1767  return true;
1768  }
1769  return false;
1770 }
1771 
1773 {
1774  double len = 0;
1775 
1776  a2dVertexList::iterator iterp = begin();
1777  a2dVertexList::iterator iter = iterp;
1778  iter++;
1779  while ( iter != end() )
1780  {
1781  len = len + ( *iter )->Length( *( *iterp ) );
1782  iterp = iter++;
1783  }
1784 
1785  return len;
1786 }
1787 
1789 {
1790  int i = 0;
1791  for( a2dVertexList::const_iterator iter = begin(); iter != end(); ++iter )
1792  {
1793  if( *iter == object )
1794  return i;
1795  i++;
1796  }
1797  return -1;
1798 }
1799 
1800 void a2dVertexList::Insert( unsigned int index, a2dLineSegmentPtr segin )
1801 {
1802  int i = 0;
1803  a2dVertexList::iterator iter;
1804  for( iter = begin(); iter != end(); ++iter )
1805  {
1806  if( i == index )
1807  {
1808  insert( iter, segin );
1809  break;
1810  }
1811  i++;
1812  }
1813  if( iter == end() && i == index )
1814  insert( iter, segin );
1815  wxASSERT_MSG( i <= size() , wxT( "index higher than list size" ) );
1816 }
1817 
1818 void a2dVertexList::AddPoint( const a2dPoint2D& point, bool atEnd )
1819 {
1820  if ( atEnd )
1821  push_back( new a2dLineSegment( point.m_x, point.m_y ) );
1822  else
1823  push_front( new a2dLineSegment( point.m_x, point.m_y ) );
1824 }
1825 
1826 void a2dVertexList::AddPoint( double x, double y, bool atEnd )
1827 {
1828  if ( atEnd )
1829  push_back( new a2dLineSegment( x, y ) );
1830  else
1831  push_front( new a2dLineSegment( x, y ) );
1832 }
1833 
1834 void a2dVertexList::SetPointAdjustArcs( a2dLineSegmentPtr segin, double x, double y, bool polygon )
1835 {
1836  a2dVertexList::iterator iter = begin();
1837  a2dVertexList::iterator prev = end();
1838  prev--;
1839  a2dLineSegment* seg;
1840  while ( iter != end() )
1841  {
1842  seg = *iter;
1843  if ( seg == segin )
1844  {
1845  seg->m_x = x;
1846  seg->m_y = y;
1847 
1848  if ( seg->GetArc() )
1849  {
1850  a2dArcSegment* cseg = ( a2dArcSegment* ) seg;
1851  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
1852  if ( prev != end() )
1853  {
1854  if ( cseg->CalcR( *( *prev ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
1855  cseg->CalcMidPoint( *( *prev ), center_x, center_y, radius, phit < 0 );
1856  }
1857  }
1858 
1859  a2dVertexList::iterator next = iter;
1860  next++;
1861  if ( next == end() && polygon )
1862  next = begin();
1863 
1864  if ( next != end() && ( *next )->GetArc() )
1865  {
1866  a2dArcSegment* cseg = ( a2dArcSegment* ) ( *next ).Get();
1867  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
1868 
1869  if ( cseg->CalcR( *( *iter ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
1870  cseg->CalcMidPoint( *( *iter ), center_x, center_y, radius, phit < 0 );
1871  }
1872  break;
1873  }
1874  prev = iter;
1875  iter++;
1876  }
1877 }
1878 
1879 void a2dVertexList::SetPointAdjustArcs( unsigned int n, double x, double y, bool polygon )
1880 {
1881  unsigned int i;
1882 
1883  a2dVertexList::iterator iter = begin();
1884  a2dVertexList::iterator prev = end();
1885  prev--;
1886  a2dLineSegment* seg;
1887  i = 0;
1888  while ( iter != end() )
1889  {
1890  seg = *iter;
1891  if ( i == n )
1892  {
1893  seg->m_x = x;
1894  seg->m_y = y;
1895 
1896  if ( seg->GetArc() )
1897  {
1898  a2dArcSegment* cseg = ( a2dArcSegment* ) seg;
1899  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
1900  if ( prev != end() )
1901  {
1902  if ( cseg->CalcR( *( *prev ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
1903  cseg->CalcMidPoint( *( *prev ), center_x, center_y, radius, phit < 0 );
1904  }
1905  }
1906 
1907  a2dVertexList::iterator next = iter;
1908  next++;
1909  if ( next == end() && polygon )
1910  next = begin();
1911 
1912  if ( next != end() && ( *next )->GetArc() )
1913  {
1914  a2dArcSegment* cseg = ( a2dArcSegment* ) ( *next ).Get();
1915  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
1916 
1917  if ( cseg->CalcR( *( *iter ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
1918  cseg->CalcMidPoint( *( *iter ), center_x, center_y, radius, phit < 0 );
1919  }
1920  break;
1921  }
1922  i++;
1923  prev = iter;
1924  iter++;
1925  }
1926 }
1927 
1929 {
1930  if ( !cworld.IsIdentity() )
1931  {
1932  if ( !cworld.IsTranslate() )
1933  ConvertToLines();
1934 
1935  for( a2dVertexList::iterator iter = begin(); iter != end(); ++iter )
1936  {
1937  a2dLineSegment* seg = *iter;
1938  if ( seg->GetArc() )
1939  {
1940  a2dArcSegment* cseg = ( a2dArcSegment* ) seg;
1941  cworld.TransformPoint( cseg->m_x2, cseg->m_y2, cseg->m_x2, cseg->m_y2 );
1942  }
1943  cworld.TransformPoint( seg->m_x, seg->m_y, seg->m_x, seg->m_y );
1944  }
1945  }
1946 }
1947 
1948 void a2dVertexList::ConvertToLines( double aberation )
1949 {
1950  double xw, yw;
1951  a2dLineSegment* segn;
1952 
1953  a2dVertexList::iterator iterp = end();
1954  a2dVertexList::iterator iter = begin();
1955  while ( iter != end() )
1956  {
1957  a2dLineSegment* seg = *iter;
1958  if ( seg->GetArc() )
1959  {
1960  a2dArcSegment* cseg = ( a2dArcSegment* ) seg;
1961 
1962  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
1963 
1964  if ( cseg->CalcR( *( *iterp ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
1965  {
1966  double dphi;
1967  unsigned int segments;
1968  if ( aberation == 0 )
1969  Aberration( radius / 200, phit, radius , dphi, segments );
1970  //a2dGlobals->Aberration( phit, radius , dphi, segments );
1971  else
1972  Aberration( aberation, phit, radius , dphi, segments );
1973 
1974  double theta = beginrad;
1975  unsigned int step;
1976 
1977  for ( step = 0; step < segments + 1; step++ )
1978  {
1979  xw = center_x + radius * cos ( theta );
1980  yw = center_y + radius * sin ( theta );
1981  segn = new a2dLineSegment( xw, yw );
1982 
1983  iter = insert( iter, segn );
1984  iter++;
1985  theta = theta + dphi;
1986  }
1987  }
1988  else
1989  {
1990  segn = new a2dLineSegment( cseg->m_x, cseg->m_y );
1991  iter = insert( iter, segn );
1992  iter++;
1993  }
1994 
1995  iter--; //last inserted segment
1996  iterp = iter;
1997  iter++;
1998  iter = erase( iter );
1999  }
2000  else
2001  {
2002  iterp = iter;
2003  iter++;
2004  }
2005  }
2006 }
2007 
2008 void a2dVertexList::ConvertToLines( double dphi, int minseg )
2009 {
2010  //convert dphi to radians first
2011  dphi = dphi * M_PI / 180.0;
2012 
2013  double xw, yw;
2014  a2dLineSegment* segn;
2015 
2016  a2dVertexList::iterator iterp = end();
2017  a2dVertexList::iterator iter = begin();
2018  while ( iter != end() )
2019  {
2020  a2dLineSegment* seg = *iter;
2021  if ( seg->GetArc() )
2022  {
2023  a2dArcSegment* cseg = ( a2dArcSegment* ) seg;
2024 
2025  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
2026  if ( cseg->CalcR( *( *iterp ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
2027  {
2028  unsigned int segments;
2029  segments = ( unsigned int ) ( ceil( phit / dphi ) < minseg ? minseg : ceil( phit / dphi ) );
2030 
2031  dphi = phit / ( segments );
2032  if ( midrad > endrad ) dphi = -dphi; //Clockwise
2033 
2034  double theta = beginrad;
2035  unsigned int step;
2036 
2037  for ( step = 0; step < segments + 1; step++ )
2038  {
2039  xw = center_x + radius * cos ( theta );
2040  yw = center_y + radius * sin ( theta );
2041  segn = new a2dLineSegment( xw, yw );
2042 
2043  iter = insert( iterp, segn );
2044  iter++;
2045  theta = theta + dphi;
2046  }
2047  }
2048  else
2049  {
2050  segn = new a2dLineSegment( cseg->m_x, cseg->m_y );
2051  iter = insert( iterp, segn );
2052  iter++;
2053  }
2054 
2055  iter--; //last inserted segment
2056  iterp = iter;
2057  iter++;
2058  iter = erase( iter );
2059  }
2060  else
2061  {
2062  iterp = iter;
2063  iter++;
2064  }
2065  }
2066 }
2067 
2068 a2dVpath* a2dVertexList::ConvertToVpath( bool arc, bool closed )
2069 {
2070  a2dVpath* vpathsegments = new a2dVpath();
2071 
2072  double xw, yw;
2073 
2074  a2dVertexList::iterator iterp = end();
2075  a2dVertexList::iterator iter = begin();
2076  while ( iter != end() )
2077  {
2078  a2dLineSegment* seg = *iter;
2079  if ( seg->GetArc() )
2080  {
2081  a2dArcSegment* cseg = ( a2dArcSegment* ) seg;
2082  if ( arc )
2083  {
2084  a2dVpathArcSegment* arcseg;
2085  a2dVertexList::iterator iternext = iter;
2086  iternext++;
2087  if ( iter == begin() )
2088  {
2089  a2dVpathSegment* segn = new a2dVpathSegment( cseg->m_x, cseg->m_y, a2dPATHSEG_MOVETO );
2090  vpathsegments->Add( segn );
2091  arcseg = new a2dVpathArcSegment( cseg->m_x, cseg->m_y, cseg->m_x2, cseg->m_y2, a2dPATHSEG_MOVETO );
2092  }
2093  else if ( iternext == end() )
2094  arcseg = new a2dVpathArcSegment( cseg->m_x, cseg->m_y, cseg->m_x2, cseg->m_y2, a2dPATHSEG_ARCTO, closed ? a2dPATHSEG_END_CLOSED : a2dPATHSEG_END_OPEN );
2095  else
2096  arcseg = new a2dVpathArcSegment( cseg->m_x, cseg->m_y, cseg->m_x2, cseg->m_y2, a2dPATHSEG_ARCTO );
2097  vpathsegments->Add( arcseg );
2098  }
2099  else
2100  {
2101  // to line segments
2102  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
2103 
2104  if ( cseg->CalcR( *( *iterp ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
2105  {
2106  double dphi;
2107  unsigned int segments;
2108  Aberration( radius / 200, phit, radius , dphi, segments );
2109  //a2dGlobals->Aberration( phit, radius , dphi, segments );
2110 
2111  double theta = beginrad;
2112  unsigned int step;
2113 
2114  for ( step = 0; step < segments + 1; step++ )
2115  {
2116  xw = center_x + radius * cos ( theta );
2117  yw = center_y + radius * sin ( theta );
2118  a2dVpathSegment* lineseg = new a2dVpathSegment( xw, yw );
2119  vpathsegments->Add( lineseg );
2120  theta = theta + dphi;
2121  }
2122  }
2123  else
2124  {
2125  a2dVpathSegment* segn = new a2dVpathSegment( cseg->m_x, cseg->m_y );
2126  vpathsegments->Add( segn );
2127  }
2128  }
2129  }
2130  else
2131  {
2132  a2dVpathSegment* lineseg;
2133  a2dVertexList::iterator iternext = iter;
2134  iternext++;
2135  if ( iter == begin() )
2136  lineseg = new a2dVpathSegment( seg->m_x, seg->m_y , a2dPATHSEG_MOVETO );
2137  else if ( iternext == end() )
2138  lineseg = new a2dVpathSegment( seg->m_x, seg->m_y, a2dPATHSEG_LINETO, closed ? a2dPATHSEG_END_CLOSED : a2dPATHSEG_END_OPEN );
2139  else
2140  lineseg = new a2dVpathSegment( seg->m_x, seg->m_y, a2dPATHSEG_LINETO );
2141  vpathsegments->Add( lineseg );
2142  }
2143 
2144  iterp = iter;
2145  iter++;
2146  }
2147  return vpathsegments;
2148 }
2149 
2150 
2152 {
2153  if ( size() < 3 )
2154  return 0.0;
2155 
2156  double area = 0.0;
2157 
2158  a2dVertexList* workOn = const_cast<a2dVertexList*>( this );
2159  double miny = ( *workOn->begin() )->m_y;
2160  bool hasarcs = HasArcs();
2161  if ( hasarcs )
2162  {
2163  workOn = new a2dVertexList( *this );
2164  workOn->ConvertToLines( 10, 3 );
2165  }
2166 
2167  a2dVertexList::const_iterator iter;
2168  for( iter = workOn->begin(); iter != workOn->end(); ++iter )
2169  {
2170  a2dLineSegment* seg = *iter;
2171  if ( seg->m_y < miny )
2172  miny = seg->m_y;
2173  }
2174  if ( miny > 0 )
2175  miny = 0;
2176 
2177  iter = workOn->begin();
2178  for ( int i = 0; i <= workOn->size(); i++ )
2179  {
2180  double x = ( *iter )->m_x;
2181  double y = ( *iter )->m_y - miny;
2182  iter = workOn->GetNextAround( iter );
2183  area += ( ( *iter )->m_y - miny ) * x;
2184  area -= ( *iter )->m_x * y;
2185  }
2186 
2187  if ( hasarcs )
2188  delete workOn;
2189 
2190  return fabs( area / 2.0 );
2191 }
2192 
2194 {
2195  return ( bool )( CalcArea() < 0.0 );
2196 }
2197 
2198 void a2dVertexList::InsertArc( a2dVertexList::iterator& iter, int n, double center_x, double center_y )
2199 {
2200  a2dPoint2D begin_p, middle_p;
2201  int middlepoint, i;
2202 
2203  middlepoint = n / 2;
2204 
2205 
2206  begin_p.m_x = ( *iter )->m_x;
2207  begin_p.m_y = ( *iter )->m_y; // begin point of ARC
2208 
2209  // leaf current intact, eventuallly next segment should become an arc.
2210  iter = GetNextAround( iter );
2211 
2212  //remove segmenet until end of arc segment
2213  for ( i = 1; i < middlepoint - 1; i++ ) // all points to middle point removed
2214  iter = erase( iter );
2215 
2216  middle_p.m_x = ( *iter )->m_x;
2217  middle_p.m_y = ( *iter )->m_y; // middle point of ARC
2218 
2219  for ( i = middlepoint; i < n; i++ ) // all points to end point removed
2220  iter = erase( iter );
2221 
2222  if ( ( *iter )->m_x == begin_p.m_x && ( *iter )->m_y == begin_p.m_y )
2223  {
2224  double dx = center_x - begin_p.m_x;
2225  double dy = center_y - begin_p.m_y;
2226  //a2dArcSegment* aseg = new a2dArcSegment( center_x + dx, center_y + dy, center_x - dx, center_y + dy );
2227  //insert( iter, aseg );
2228  //aseg = new a2dArcSegment( begin_p.m_x, begin_p.m_y, center_x + dx, center_y - dy );
2229  //insert( iter, aseg );
2230  a2dArcSegment* aseg = new a2dArcSegment( begin_p.m_x, begin_p.m_y, center_x + dx, center_y + dy );
2231  insert( iter, aseg );
2232  }
2233  else
2234  {
2235  a2dArcSegment* aseg = new a2dArcSegment( ( *iter )->m_x, ( *iter )->m_y, middle_p.m_x, middle_p.m_y );
2236  insert( iter, aseg );
2237  //remove end of arc segment, which is replaced by Arc segment to previous point.
2238  }
2239  iter = erase( iter );
2240 }
2241 
2242 bool a2dVertexList::CheckForOneCircle( a2dPoint2D& middle, double& radius )
2243 {
2244  a2dVertexList::iterator iter = begin();
2245  a2dLineSegment* seg = *iter;
2246  if ( size() == 1 && seg->GetArc() )
2247  {
2248  iter = GetPreviousAround( iter );
2249  double x = ( *iter )->m_x;
2250  double y = ( *iter )->m_y;
2251  a2dArcSegment* cseg = ( a2dArcSegment* ) seg;
2252  middle.m_x = cseg->GetOx( *seg );
2253  middle.m_y = cseg->GetOy( *seg );
2254  radius = sqrt( pow( x - middle.m_x, 2.0 ) + pow( y - middle.m_y, 2.0 ) );
2255 
2256  //now check if the end point is equal
2257  if ( x == seg->m_x && y == seg->m_y )
2258  return true;
2259  }
2260  /*
2261  if ( size() == 2 )
2262  {
2263  if ( seg->GetArc() )
2264  {
2265  GetPreviousAround( iter );
2266  if ( (*iter)->GetArc() )
2267  return false;
2268  double x = (*iter).m_x;
2269  double y = (*iter).m_y;
2270  a2dArcSegment * cseg = ( a2dArcSegment* ) seg;
2271  middle_p.m_x = cseg.GetOx( *iter );
2272  middle_p.m_y = cseg.GetOy( *iter );
2273  radius = sqrt(pow(x-aseg->GetOX(),2.0) + pow(y-aseg->GetOY(),2.0));
2274  return true;
2275  }
2276  else
2277  {
2278  GetPreviousAround( iter );
2279  if ( !(*iter)->GetArc() )
2280  return false;
2281  double x = (*iter).m_x;
2282  double y = (*iter).m_y;
2283  a2dArcSegment * cseg = ( a2dArcSegment* ) (*iter);
2284  middle_p.m_x = cseg.GetOx( begin() );
2285  middle_p.m_y = cseg.GetOy( begin() );
2286  radius = sqrt(pow(x-aseg->GetOX(),2.0) + pow(y-aseg->GetOY(),2.0));
2287  return true;
2288  }
2289  }
2290  */
2291  return false;
2292 }
2293 
2294 void a2dVertexList::ConvertPolygonToArc( double aber, double Rmin, double Rmax )
2295 {
2296  int n, minimum_points;
2297 
2298  a2dPoint2D center_p;
2299  minimum_points = 3; // alleen polygonen met meer dan 3 punten kunnen
2300  // geconverteerd worden
2301  a2dLineSegment* lsegn;
2302  if ( size() )
2303  {
2304  lsegn = new a2dLineSegment( front()->m_x, front()->m_y );
2305  push_back( lsegn );
2306  }
2307  else
2308  return;
2309 
2310  // redundant as a polyline, not polygon, else added point above is gone
2311  RemoveRedundant( false );
2312 
2313  if ( size() > minimum_points )
2314  {
2315 
2316  // Polygon wordt getest op ARC's, wordt er een ARC gevonden dan wordt het beginpunt naar
2317  // het eindpunt van de ARC gezet. Dit voorkomt dat een ARC niet herkent wordt wanneer
2318  // het beginpunt zich ergens op de ARC bevind.
2319  // In het geval dat alle punten voldoen aan een ARC (circel) vind de conversie direct plaats.
2320  // In alle andere gevallen wordt het testen op ARC's en het converteren gedaan door
2321  // G_Polyline::ConvertLine.
2322 
2323  a2dVertexList::iterator iter = begin();
2324  for ( int count = 0; count < size(); count++ )
2325  {
2326  n = TestArc( iter, aber, Rmin, Rmax, center_p );
2327 
2328  if ( n < size() && n > minimum_points )
2329  {
2330  for ( int t = 1; t < n; t++ ) iter++; // verschuiving beginpunt naar eindpunt ARC.
2331  //remove last clossing line
2332  pop_back();
2333  MakeBegin( iter );
2334  lsegn = new a2dLineSegment( ( *iter )->m_x, ( *iter )->m_y );
2335  push_back( lsegn );
2336 
2337  break;
2338  }
2339  else if ( n > minimum_points ) // alle punten van de polygon voldoen aan een ARC (circle)
2340  {
2341  iter = begin();
2342 
2343  double dx = center_p.m_x - ( *iter )->m_x;
2344  double dy = center_p.m_y - ( *iter )->m_y;
2345  a2dArcSegment* aseg = new a2dArcSegment( ( *iter )->m_x, ( *iter )->m_y, center_p.m_x + dx, center_p.m_y + dy );
2346  clear();
2347  push_back( aseg );
2348 
2349  //InsertArc( iter, n, center_p.m_x, center_p.m_y );
2350  return;
2351  }
2352 
2353  iter++;
2354  pop_back();
2355  MakeBegin( iter );
2356  lsegn = new a2dLineSegment( ( *iter )->m_x, ( *iter )->m_y );
2357  push_back( lsegn );
2358  }
2359 
2360  ConvertPolylineToArc( aber, Rmin, Rmax ); // De punten van de polyline die voldoen aan een circelboog
2361  } // worden geconverteerd naar een ARC.
2362 
2363  //in case the last found arc is also endpoint of the tested polyline, the extra added
2364  //segment above (to close the polygon), is replaced by an arc segment, and should stay.
2365  if ( !back()->GetArc() )
2366  pop_back();
2367 }
2368 
2369 void a2dVertexList::ConvertPolylineToArc( double aber, double Rmin, double Rmax )
2370 {
2371  int n, minimum_points;
2372 
2373  a2dPoint2D center_p; //center punt van een ARC
2374 
2375  minimum_points = 3;
2376 
2377  RemoveRedundant( false );
2378 
2379  a2dVertexList::iterator iter = begin();
2380  if ( size() > minimum_points ) // Alleen polylijnen met meer dan 3 punten kunnen
2381  {
2382  // worden geconverteerd naar ARC's
2383  iter++;
2384  iter++;
2385  iter++;
2386  while( iter != end() )
2387  {
2388  iter--;
2389  iter--;
2390  iter--;
2391  a2dLineSegment* seg = *iter;
2392  n = TestArc( iter, aber, Rmin, Rmax, center_p );
2393  if ( n > minimum_points )
2394  InsertArc( iter, n, center_p.m_x, center_p.m_y );
2395  else
2396  iter++;
2397 
2398  if ( iter != end() ) iter++; // Als het resterende aantal punten minder is dan 3
2399  if ( iter != end() ) iter++; // wordt het testen op ARC's gestopt.
2400  if ( iter != end() ) iter++;
2401  }
2402  }
2403 }
2404 
2405 #define KLEIN 1.0e-30
2406 #define GROOT 1.0e30
2407 #define PHI_MARGE 0.3 //must be lager than 0, 0.3 -> 30% (graden)
2408 #define SEG_MARGE 0.3 //must be lager than 0, 0.3 -> 30%
2409 
2410 int a2dVertexList::TestArc( a2dVertexList::iterator& iter, double aber, double Rmin, double Rmax , a2dPoint2D& center_p_old )
2411 {
2412  a2dPoint2D begin_p, middle_p, test_p, end_p, center_p ;
2413 
2414  a2dVertexList::iterator middle = iter;
2415  a2dVertexList::iterator test = iter;
2416  a2dVertexList::iterator endc = iter;
2417 
2418  double error1, error2, Radius, Radius_old;
2419  double x_between, y_between, dx, dy, x_prev, y_prev;
2420  double inp, phi, phi_old, phi_fac, a, b, lseg, lseg_old, seg_fac;
2421  double t_inp;
2422  lseg = 0;
2423  int i, j, ii, minimum_points;
2424 
2425  Radius = GROOT;
2426  error1 = GROOT;
2427  error2 = GROOT;
2428  phi = 0.0;
2429  lseg_old = 0.0;
2430  phi_old = 0.0;
2431 
2432  if ( aber < KLEIN ) // aber <= 0 ; test op "perfecte circelbogen"
2433  {
2434  phi_fac = 1 + PHI_MARGE; // hoek factor ; geeft aan hoeveel de segmenthoeken onderling mogen afwijken
2435  seg_fac = 1 + SEG_MARGE; // segment factor; geeft aan hoeveel de segmentlengtes onderling mogen afwijken
2436 
2437  if ( aber < 0.0 ) // aber < 0; zie punt 3 in de header
2438  aber = -aber;
2439  else // aber = 0; zie punt 2 in de header
2440  aber = GROOT;
2441  }
2442  else // aber > 0; zie punt 1 in de header
2443  {
2444  phi_fac = GROOT;
2445  seg_fac = GROOT;
2446  }
2447 
2448  minimum_points = 3;
2449 
2450  begin_p.m_x = ( *iter )->m_x;
2451  begin_p.m_y = ( *iter )->m_y; // Beginpunt
2452 
2453  for ( ii = 1; ii <= minimum_points; ii++ ) // Eindpunt wordt 3 posities opgeschoven en er wordt tevens
2454  {
2455  // getest of een van de punten niet behoord tot het type ARC
2456  if ( !( *endc )->GetArc() )
2457  endc++;
2458  else
2459  return ( 0 ); // Verlaat de functie indien een van de punten van het type ARC is.
2460  }
2461 
2462  middle++;
2463 
2464  i = minimum_points;
2465 
2466  do
2467  {
2468  i++;
2469  if ( i % 2 != 0 ) // Middelpunt schuift 1 punt op als aantal punten oneven is
2470  middle++;
2471 
2472  end_p.m_x = ( *endc )->m_x;
2473  end_p.m_y = ( *endc )->m_y; // End point
2474 
2475  middle_p.m_x = ( *middle )->m_x;
2476  middle_p.m_y = ( *middle )->m_y; // Middle point
2477 
2478  Radius_old = Radius;
2479  center_p_old = center_p;
2480 
2481  // Als het laatste punt gelijk is aan beginpunt dan niet opnieuw ARC berekenen
2482 
2483  if ( !( ( fabs( end_p.m_x - begin_p.m_x ) < a2dACCUR ) && ( fabs( end_p.m_y - begin_p.m_y ) < a2dACCUR ) ) )
2484  CalcR( begin_p.m_x, begin_p.m_y, middle_p.m_x, middle_p.m_y, end_p.m_x, end_p.m_y,
2485  Radius, center_p ); // Berekening radius en centerpunt
2486 
2487  test = iter;
2488 
2489  j = 1;
2490 
2491  test_p.m_x = ( *test )->m_x;
2492  test_p.m_y = ( *test )->m_y; // first test point
2493 
2494  while ( j < i ) // Alle punten liggende tussen begin en eindpunt worden getest
2495  {
2496  // of ze voldoen aan de berekende circelboog
2497  j++;
2498  x_prev = test_p.m_x; // Test point (1)
2499  y_prev = test_p.m_y;
2500 
2501  test++;
2502 
2503  test_p.m_x = ( *test )->m_x;
2504  test_p.m_y = ( *test )->m_y; // Test point (2)
2505 
2506  dx = center_p.m_x - test_p.m_x;
2507  dy = center_p.m_y - test_p.m_y;
2508 
2509  error1 = fabs( Radius - sqrt( pow( dx, 2 ) + pow( dy, 2 ) ) ); // Afwijking tussen berekende circelboog en testpunt
2510 
2511  x_between = ( test_p.m_x + x_prev ) / 2.0; // Berekening punt tussen twee testpunt 1 en testpunt 2,
2512  y_between = ( test_p.m_y + y_prev ) / 2.0; // dit is nodig voor berekening van de aberatie
2513 
2514  dx = center_p.m_x - x_between;
2515  dy = center_p.m_y - y_between;
2516 
2517  error2 = fabs( Radius - sqrt( pow( dx, 2 ) + pow( dy, 2 ) ) ); // Aberatie
2518 
2519  inp = ( center_p.m_x - x_prev ) * ( test_p.m_y - center_p.m_y ) - // a x b (vectoren)
2520  ( center_p.m_y - y_prev ) * ( test_p.m_x - center_p.m_x );
2521 
2522  a = sqrt( pow( ( center_p.m_x - x_prev ), 2 ) + pow( ( center_p.m_y - y_prev ), 2 ) );
2523  b = sqrt( pow( ( center_p.m_x - test_p.m_x ), 2 ) + pow( ( center_p.m_y - test_p.m_y ), 2 ) );
2524 
2525  phi_old = phi;
2526 
2527  t_inp = inp / ( a * b );
2528 
2529  if ( t_inp > 1.0 ) // t_inp mag niet groter worden dan 1 of kleiner dan -1
2530  t_inp = 1.0;
2531  else if ( t_inp < -1.0 )
2532  t_inp = -1.0;
2533 
2534  phi = 180.0 * asin( t_inp ) / M_PI; // Segment hoek
2535 
2536  lseg_old = lseg;
2537 
2538  lseg = sqrt( pow( ( test_p.m_x - x_prev ), 2 ) + pow( ( test_p.m_y - y_prev ), 2 ) ); // segment lengte
2539 
2540  if ( j == 2 )
2541  {
2542  phi_old = phi;
2543  lseg_old = lseg;
2544  }
2545 
2546  if ( error1 > aber || /* Afwijking punt groter dan aber */
2547  error2 > aber || /* Aberatie lijn groter dan aber */
2548  fabs( phi ) > fabs( phi_old )*phi_fac || /* Segment hoek groter vorige hoek */
2549  fabs( phi ) < fabs( phi_old ) / phi_fac || /* Segment hoek kleiner vorige hoek */
2550  phi * phi_old < 0.0 || /* Segment hoek tegengestelde richting van vorige hoek */
2551  lseg > lseg_old * seg_fac || /* Segment lengte groter vorige segment */
2552  lseg < lseg_old / seg_fac ) /* Segment lengte kleiner vorige segment */
2553  {
2554  if ( Radius_old > Rmin && Radius_old < Rmax ) // Als de nieuw gevonden circelboog niet
2555  // voldoet dan wordt getest of de vorige
2556  // radius binnen Rmin en Rmax ligt.
2557  return ( i - 1 ); // Return aantal gevonden punten -1
2558  // (laatste punt voldoet niet)
2559  else
2560  return ( 0 ); // Gevonden radius voldoet niet
2561  }
2562  }
2563  //een ARC segment is gevonden dat aan alle regels voldoet
2564  //indien mogelijk proberen we nog een punt verder te komen
2565  if ( ( *endc )->GetArc() ) // stop het huidige segment is een arc
2566  break;
2567 
2568  endc++; // probeer met het nieuwe eindpunt een nieuwe circelboog te berekenen.
2569  }
2570  while( endc != end() );
2571 
2572  if ( Radius > Rmin && Radius < Rmax ) // nieuw gevonden circelboog oke?
2573  {
2574  center_p_old = center_p;
2575  return ( i );
2576  }
2577  else
2578  return ( 0 ); // Gevonden radius voldoet niet
2579 }
2580 
2582 {
2583  a2dBoundingBox bbox;
2584 
2585  double x, y;
2586  lworld.TransformPoint( 0, 0, x, y );
2587  if ( !size() )
2588  bbox.Expand( x, y );
2589 
2590  a2dLineSegment* segprev = NULL;
2591  if ( size() )
2592  segprev = back();
2593  for( a2dVertexList::iterator iter = begin(); iter != end(); ++iter )
2594  {
2595  a2dLineSegment* seg = *iter;
2596  if ( seg->GetArc() && segprev )
2597  bbox.Expand( seg->GetBbox( *segprev, lworld ) );
2598  else
2599  {
2600  lworld.TransformPoint( seg->m_x, seg->m_y, x, y );
2601  bbox.Expand( x, y );
2602  }
2603  segprev = ( *iter );
2604  }
2605  return bbox;
2606 }
2607 
2608 a2dVertexList* a2dVertexList::ConvertToContour( double distance, a2dPATH_END_TYPE pathtype, bool asPolygon )
2609 {
2610  a2dVertexList* converted = new a2dVertexList();
2611  *converted = *this;
2612  converted->RemoveRedundant( asPolygon );
2613 
2614  converted->Contour( distance, pathtype, asPolygon );
2615  return converted;
2616 }
2617 
2618 void a2dVertexList::Contour( double distance, a2dPATH_END_TYPE pathtype, bool asPolygon )
2619 {
2620  bool rounded = true;
2621 
2622  a2dPoint2D _first;
2623  a2dPoint2D _middle;
2624  a2dPoint2D _end;
2625  a2dPoint2D offsetpointleft;
2626  a2dPoint2D offsetpointright;
2627 
2628  if ( asPolygon )
2629  push_front( new a2dLineSegment( back()->m_x, back()->m_y ) );
2630 
2631  unsigned int size = this->size();
2632  a2dVertexList::iterator iter = begin();
2633  a2dLineSegment* seg = *iter;
2634  a2dVertexList::iterator prev = iter;
2635 
2636  //create start of subpart
2637  if ( size == 1 )
2638  {
2639  a2dLineSegment* seg = *iter;
2640  push_back( new a2dLineSegment( seg->m_x - distance, seg->m_y ) );
2641  switch ( pathtype )
2642  {
2643  case a2dPATH_END_SQAURE:
2644  {
2645  //not defined
2646  }
2647  break;
2648  case a2dPATH_END_ROUND:
2649  {
2650  push_back( new a2dArcSegment( seg->m_x + distance, seg->m_y, seg->m_x - distance, seg->m_y ) );
2651  }
2652  break;
2653  case a2dPATH_END_SQAURE_EXT:
2654  {
2655  //not defined
2656  }
2657  break;
2658  default:
2659  break;
2660  }
2661  return;
2662  }
2663  // in three parts ( begin middle end ), by pushing back and front, both side of the contour are
2664  // constructed.
2665 
2666  //first begin point
2667  _first = a2dPoint2D( seg->m_x, seg->m_y );
2668  iter++;
2669  a2dLineSegment* segnext = *iter;
2670 
2671  _middle = a2dPoint2D( segnext->m_x, segnext->m_y );
2672  a2dLine line1( _first, _middle );
2673  line1.CalculateLineParameters();
2674  offsetpointleft = _first;
2675  offsetpointright = _first;
2676  line1.Virtual_Point( offsetpointleft, distance );
2677  line1.Virtual_Point( offsetpointright, -distance );
2678 
2679  switch ( pathtype )
2680  {
2681  case a2dPATH_END_SQAURE:
2682  {
2683  push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
2684  push_front( new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
2685  }
2686  break;
2687  case a2dPATH_END_ROUND:
2688  {
2689  a2dLine lineoffset( offsetpointright, offsetpointleft );
2690  lineoffset.CalculateLineParameters();
2691  a2dPoint2D offsetpointfirst;
2692 
2693  offsetpointfirst = _first;
2694  lineoffset.Virtual_Point( offsetpointfirst, distance );
2695  push_back( new a2dArcSegment( offsetpointleft.m_x, offsetpointleft.m_y,
2696  offsetpointfirst.m_x, offsetpointfirst.m_y ) );
2697  push_front( new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
2698  break;
2699  }
2700  case a2dPATH_END_SQAURE_EXT:
2701  {
2702  a2dLine lineoffset( offsetpointright, offsetpointleft );
2703  lineoffset.CalculateLineParameters();
2704  lineoffset.Virtual_Point( offsetpointleft, distance );
2705  lineoffset.Virtual_Point( offsetpointright, distance );
2706 
2707  push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
2708  push_front( new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
2709  break;
2710  }
2711  default:
2712  break;
2713  }
2714 
2715  size--;
2716  size--;
2717  while ( size )
2718  {
2719  a2dLineSegment* seg = *prev;
2720  _first = a2dPoint2D( seg->m_x, seg->m_y );
2721  a2dLineSegment* segnext = *iter;
2722  _middle = a2dPoint2D( segnext->m_x, segnext->m_y );
2723  a2dLine line1( _first, _middle );
2724  erase( prev );
2725  prev = iter;
2726  iter++;
2727  a2dLineSegment* segend = *iter;
2728  _end = a2dPoint2D( segend->m_x, segend->m_y );
2729  a2dLine line2( _middle, _end );
2730  line1.CalculateLineParameters();
2731  line2.CalculateLineParameters();
2732 
2733  OUTPRODUCT _outproduct;
2734  _outproduct = line1.OutProduct( line2, 1e-9 );
2735 
2736  switch ( _outproduct )
2737  {
2738  // Line 2 lies on leftside of this line
2739  case R_IS_RIGHT :
2740  {
2741  if ( !rounded )
2742  {
2743  line1.OffsetContour( line2, distance, offsetpointleft );
2744  line1.OffsetContour( line2, -distance, offsetpointright );
2745  push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
2746  push_front( new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
2747  }
2748  else
2749  {
2750  OffsetContour_rounded( line1, line2, distance, false );
2751  line1.OffsetContour( line2, -distance, offsetpointright );
2752  push_front( new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
2753  }
2754  }
2755  break;
2756  case R_IS_LEFT :
2757  {
2758  if ( !rounded )
2759  {
2760  line1.OffsetContour( line2, distance, offsetpointleft );
2761  line1.OffsetContour( line2, -distance, offsetpointright );
2762  push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
2763  push_front( new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
2764  }
2765  else
2766  {
2767  line1.OffsetContour( line2, distance, offsetpointleft );
2768  push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
2769  OffsetContour_rounded( line1, line2, -distance, true );
2770  }
2771  }
2772  break;
2773  // Line 2 lies on this line
2774  case R_IS_ON :
2775  {
2776  offsetpointleft = _middle;
2777  offsetpointright = _middle;
2778  line1.Virtual_Point( offsetpointleft, distance );
2779  line1.Virtual_Point( offsetpointright, -distance );
2780  push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
2781  push_front( new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
2782  }
2783  break;
2784  default:
2785  wxFAIL_MSG( wxT( "wrong line code" ) );
2786  break;
2787  }//end switch
2788 
2789  size--;
2790  }
2791 
2792  seg = *prev;
2793 
2794  //first begin point
2795  _first = a2dPoint2D( seg->m_x, seg->m_y );
2796  segnext = *iter;
2797  _end = a2dPoint2D( segnext->m_x, segnext->m_y );
2798  a2dLine line2( _first, _end );
2799  line2.CalculateLineParameters();
2800  offsetpointleft = _end;
2801  offsetpointright = _end;
2802  line2.Virtual_Point( offsetpointleft, distance );
2803  line2.Virtual_Point( offsetpointright, -distance );
2804 
2805  prev = erase( prev );
2806  prev = erase( prev );
2807 
2808  switch ( pathtype )
2809  {
2810  case a2dPATH_END_SQAURE:
2811  {
2812  push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
2813  push_front( new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
2814  }
2815  break;
2816  case a2dPATH_END_ROUND:
2817  {
2818  a2dLine lineoffset( offsetpointleft, offsetpointright );
2819  lineoffset.CalculateLineParameters();
2820  a2dPoint2D offsetpointend;
2821 
2822  offsetpointend = _end;
2823  lineoffset.Virtual_Point( offsetpointend, distance );
2824  push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
2825  push_back( new a2dArcSegment( offsetpointright.m_x, offsetpointright.m_y,
2826  offsetpointend.m_x, offsetpointend.m_y ) );
2827  push_front( new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
2828  break;
2829  }
2830  case a2dPATH_END_SQAURE_EXT:
2831  {
2832  a2dLine lineoffset( offsetpointright, offsetpointleft );
2833  lineoffset.CalculateLineParameters();
2834  lineoffset.Virtual_Point( offsetpointleft, -distance );
2835  lineoffset.Virtual_Point( offsetpointright, -distance );
2836 
2837  push_back( new a2dLineSegment( offsetpointleft.m_x, offsetpointleft.m_y ) );
2838  push_front( new a2dLineSegment( offsetpointright.m_x, offsetpointright.m_y ) );
2839  break;
2840  }
2841  default:
2842  break;
2843  }
2844 }
2845 
2847 {
2848  a2dVertexList* h = new a2dVertexList();
2849 
2850  *h = *this;
2851 
2852  //TODO need an array version for speed
2853  h->ConvertIntoSplinedPolygon( Aber );
2854 
2855  return h;
2856 }
2857 
2859 {
2860  a2dVertexList* h = new a2dVertexList();
2861 
2862  *h = *this;
2863 
2864  h->ConvertIntoSplinedPolyline( Aber );
2865 
2866  return h;
2867 }
2868 
2870 {
2871  //! circle segments are converted to lines first.
2872  ConvertToLines();
2873 
2874  a2dLineSegment* point;
2875  double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
2876  double x1, y1, x2, y2;
2877 
2878  if ( size() < 2 )
2879  return;
2880 
2881  a2dVertexList::iterator iter = --end();
2882  x1 = ( *iter )->m_x;
2883  y1 = ( *iter )->m_y;
2884 
2885  iter = begin();
2886  x2 = ( *iter )->m_x;
2887  y2 = ( *iter )->m_y;
2888 
2889  point = new a2dLineSegment( x2, y2 );
2890  push_back( point );
2891 
2892  cx1 = ( x1 + x2 ) / 2.0;
2893  cy1 = ( y1 + y2 ) / 2.0;
2894  cx2 = ( cx1 + x2 ) / 2.0;
2895  cy2 = ( cy1 + y2 ) / 2.0;
2896 
2897  iter = erase( iter );
2898  iter = begin();
2899  x1 = ( *iter )->m_x;
2900  y1 = ( *iter )->m_y;
2901  point = new a2dLineSegment( x1, y1 );
2902  push_back( point );
2903 
2904  unsigned int i = 1;
2905  unsigned int count = size();
2906  while ( i < count )
2907  {
2908  x1 = x2;
2909  y1 = y2;
2910  x2 = ( *iter )->m_x;
2911  y2 = ( *iter )->m_y;
2912  cx4 = ( x1 + x2 ) / 2.0;
2913  cy4 = ( y1 + y2 ) / 2.0;
2914  cx3 = ( x1 + cx4 ) / 2.0;
2915  cy3 = ( y1 + cy4 ) / 2.0;
2916 
2917  gds_quadratic_spline( this, cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4, Aber );
2918 
2919  cx1 = cx4;
2920  cy1 = cy4;
2921  cx2 = ( cx1 + x2 ) / 2.0;
2922  cy2 = ( cy1 + y2 ) / 2.0;
2923  iter = erase( iter );
2924  iter = begin();
2925  i++;
2926  }
2927 
2928  iter = begin();
2929  erase( iter );
2930 }
2931 
2932 void a2dVertexList::ConvertIntoSplinedPolyline( double Aber )
2933 {
2934  double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
2935  double x1, y1, x2, y2;
2936 
2937 
2938  if ( size() < 2 )
2939  return;
2940 
2941  a2dVertexList::iterator iter = begin();
2942 
2943  x1 = ( *iter )->m_x;
2944  y1 = ( *iter )->m_y;
2945 
2946  iter = erase( iter );
2947  iter = begin();
2948  x2 = ( *iter )->m_x;
2949  y2 = ( *iter )->m_y;
2950  cx1 = ( x1 + x2 ) / 2.0;
2951  cy1 = ( y1 + y2 ) / 2.0;
2952  cx2 = ( cx1 + x2 ) / 2.0;
2953  cy2 = ( cy1 + y2 ) / 2.0;
2954 
2955  a2dLineSegment* point = new a2dLineSegment( x1, y1 );
2956  push_back( point );
2957 
2958  iter = erase( iter );
2959 
2960  unsigned int i = 1;
2961  unsigned int count = size();
2962  while ( i < count )
2963  {
2964  x1 = x2;
2965  y1 = y2;
2966  x2 = ( *iter )->m_x;
2967  y2 = ( *iter )->m_y;
2968  cx4 = ( x1 + x2 ) / 2.0;
2969  cy4 = ( y1 + y2 ) / 2.0;
2970  cx3 = ( x1 + cx4 ) / 2.0;
2971  cy3 = ( y1 + cy4 ) / 2.0;
2972 
2973  gds_quadratic_spline( this, cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4, Aber );
2974 
2975  cx1 = cx4;
2976  cy1 = cy4;
2977  cx2 = ( cx1 + x2 ) / 2.0;
2978  cy2 = ( cy1 + y2 ) / 2.0;
2979  iter = erase( iter );
2980  i++;
2981  }
2982 
2983  point = new a2dLineSegment( cx1, cy1 );
2984  push_back( point );
2985 
2986  point = new a2dLineSegment( x2, y2 );
2987  push_back( point );
2988 }
2989 
2991 {
2992  bool did = false;
2993  a2dLineSegment* segprev = NULL;
2994  a2dLineSegment* seg = NULL;
2995  a2dVertexList::iterator iter = begin();
2996  while( iter != end() )
2997  {
2998  seg = *iter;
2999  if ( !seg->GetArc() && segprev && seg->GetPoint() == segprev->GetPoint() )
3000  {
3001  iter = erase( iter );
3002  did = true;
3003  }
3004  else
3005  {
3006  segprev = seg;
3007  iter++;
3008  }
3009  }
3010  iter = begin();
3011  seg = *iter;
3012  if ( polygon && !seg->GetArc() && segprev && seg->GetPoint() == segprev->GetPoint() )
3013  {
3014  iter = erase( iter );
3015  did = true;
3016  }
3017  return did;
3018 }
3019 
3020 a2dVertexList* a2dVertexList::GetRedundant( bool polygon, double smallest )
3021 {
3022  smallest = smallest * smallest;
3023  a2dVertexList* redunDant = new a2dVertexList();
3024  a2dLineSegment* segprev = NULL;
3025  a2dLineSegmentPtr seg;
3026  a2dVertexList::iterator iter = begin();
3027  while( iter != end() )
3028  {
3029  seg = *iter;
3030  if ( !seg->GetArc() && segprev &&
3031  ( seg->GetPoint() == segprev->GetPoint() || ClclDistSqrPntPnt( seg->GetPoint(), segprev->GetPoint() ) <= smallest ) )
3032  redunDant->push_back( seg->Clone() );
3033  segprev = seg;
3034  iter++;
3035  }
3036  iter = begin();
3037  seg = *iter;
3038  if ( polygon && !seg->GetArc() && segprev &&
3039  ( seg->GetPoint() == segprev->GetPoint() || ClclDistSqrPntPnt( seg->GetPoint(), segprev->GetPoint() ) <= smallest ) )
3040  redunDant->push_back( seg->Clone() );
3041 
3042  if ( redunDant->empty() )
3043  {
3044  delete redunDant;
3045  redunDant = NULL;
3046  }
3047  return redunDant;
3048 }
3049 
3050 a2dHit a2dVertexList::HitTestPolygon( const a2dPoint2D& ptest, double margin )
3051 {
3052  wxASSERT( margin >= 0 );
3053 
3054  a2dPoint2D p1, p2, pm;
3055 
3056  double minDistSqrVertex = margin * margin;
3057  double minDistSqrStroke = margin * margin;
3058  bool vertexhit = false;
3059  int intersection_count = 0;
3060  a2dHit rslt;
3061 
3062  int i = 0;
3063  for( a2dVertexList::iterator iter = begin(); iter != end(); ++iter, i++ )
3064  {
3065  a2dLineSegment* seg = *iter;
3066  p1 = seg->GetPoint();
3067  if ( iter == --end() )
3068  {
3069  p2 = front()->GetPoint();
3070  }
3071  else
3072  {
3073  iter++;
3074  p2 = ( *iter )->GetPoint();
3075  iter--;
3076  }
3077 
3078  //--------------------------------------------------------------------
3079  // From here on, this function is identical to the hittest for
3080  // point array polygons. Keep these two identical !!
3081  //--------------------------------------------------------------------
3082 
3083  // check relative horizontal positions of line end points and point
3084  double xmin;
3085  double xmax;
3086  int direction;
3087  // Note: the case p1.m_x == p2.m_x is ignored during direction counting
3088  // See below.
3089  if( p1.m_x < p2.m_x )
3090  {
3091  xmin = p1.m_x;
3092  xmax = p2.m_x;
3093  direction = 1;
3094  }
3095  else
3096  {
3097  xmin = p2.m_x;
3098  xmax = p1.m_x;
3099  direction = -1;
3100  }
3101 
3102  if( ptest.m_x < xmin - margin || ptest.m_x > xmax + margin )
3103  continue;
3104 
3105  // check relative horizontal positions of line end points and point
3106  double ymin;
3107  double ymax;
3108  if( p1.m_y < p2.m_y )
3109  {
3110  ymin = p1.m_y;
3111  ymax = p2.m_y;
3112  }
3113  else
3114  {
3115  ymin = p2.m_y;
3116  ymax = p1.m_y;
3117  }
3118 
3119  // if ptest its y is beneath the minimum y of the segment, the ray does
3120  // intersect if x p1 and x p2 are on opposite sides.
3121  if( ptest.m_y < ymin - margin )
3122  {
3123  // The test point is definitely below the margin.
3124  // This cannot be a stroke hit
3125  // but the vertical line through ptest can intersect the edge
3126  if( ptest.m_x >= xmin && ptest.m_x < xmax && p1.m_x != p2.m_x )
3127  {
3128  intersection_count += direction;
3129  }
3130  }
3131  else if( ptest.m_y <= ymax + margin )
3132  {
3133  // The test point ptest is inside the margin extended bounding box+margin of the edge
3134  // This means we make vertex and stroke hit tests
3135  // and an intersection test between edge and the vertical line through ptest
3136 
3137  // Vertex hit test for point 1
3138  //
3139  // Note1: double ifs are MUCH slower than double calculations (at least on intel)
3140  // So it is faster calculating the distance square than doing a rectangle test
3141  //
3142  // Note2: vertex hits have higher priority than edge hits
3143  //
3144  // Note3: every vertex is once point1 and once point 2, so only one point needs
3145  // to be tested.
3146  //
3147  // Note4: Even if there is a stroke or vertex hit, serach is continued, because
3148  // there could be better hit. A stroke or vertex hit is rarely a random event,
3149  // so it doesn't make much sense to optimize this.
3150 
3151  double distSqr = ClclDistSqrPntPnt( ptest, p1 );
3152 
3153  if( distSqr < minDistSqrVertex )
3154  {
3155  minDistSqrVertex = distSqr;
3156  rslt.m_hit = a2dHit::hit_stroke;
3157  rslt.m_index = i;
3158  rslt.m_stroke2 = a2dHit::stroke2_vertex;
3159  vertexhit = true;
3160  }
3161 
3162  // Stroke center hit-test
3163  // This is done to allow hitting the stroke even if the stroke length
3164  // is leth than the hit margin. As vertex hits have priority, the stroke
3165  // coldn't be hit then. So the stroke center is treated as pseudo-vertex.
3166  pm = a2dPoint2D( 0.5 * ( p1.m_x + p2.m_x ), 0.5 * ( p1.m_y + p2.m_y ) );
3167  distSqr = ClclDistSqrPntPnt( ptest, pm );
3168  if( distSqr < minDistSqrVertex )
3169  {
3170  minDistSqrVertex = distSqr;
3171  rslt.m_hit = a2dHit::hit_stroke;
3172  rslt.m_index = i;
3173  if( p1.m_x == p2.m_x )
3174  rslt.m_stroke2 = a2dHit::stroke2_edgevert;
3175  else if( p1.m_y == p2.m_y )
3176  rslt.m_stroke2 = a2dHit::stroke2_edgehor;
3177  else
3178  rslt.m_stroke2 = a2dHit::stroke2_edgeother;
3179  vertexhit = true;
3180  }
3181 
3182  // Edge hit test
3183  // Note: The edge hittest is even done if a higher prioroity
3184  // vertex hit exists, and no edgehit can accur. This is done
3185  // because the distance of a vertex hit shall not be worse
3186  // then the distance from the closest edge, which is calculated
3187  // here.
3188  distSqr = ClclDistSqrPntLine( ptest, p1, p2 );
3189 
3190  if( distSqr < minDistSqrStroke )
3191  {
3192  minDistSqrStroke = distSqr;
3193  if( !vertexhit )
3194  {
3195  rslt.m_hit = a2dHit::hit_stroke;
3196  rslt.m_index = i;
3197  if( p1.m_x == p2.m_x )
3198  rslt.m_stroke2 = a2dHit::stroke2_edgevert;
3199  else if( p1.m_y == p2.m_y )
3200  rslt.m_stroke2 = a2dHit::stroke2_edgehor;
3201  else
3202  rslt.m_stroke2 = a2dHit::stroke2_edgeother;
3203  }
3204  }
3205 
3206  // Intersection test for inside/outside test
3207  // Vertical lines are ignored in the inside/outside test.
3208  // They are really not important for this.
3209  // You can define that on the vertical line you get the same result as
3210  // above or below the vertical line.
3211  if( ptest.m_x >= xmin && ptest.m_x < xmax && p1.m_x != p2.m_x )
3212  {
3213  if( p1.m_y == p2.m_y )
3214  {
3215  if( ptest.m_y <= p1.m_y )
3216  intersection_count += direction;
3217  }
3218  else
3219  {
3220  double y = ( ptest.m_x - p1.m_x ) * ( p2.m_y - p1.m_y ) / ( p2.m_x - p1.m_x ) + p1.m_y;
3221  if( ptest.m_y <= y )
3222  intersection_count += direction;
3223  }
3224  }
3225  }
3226  }
3227 
3228  if( rslt.m_hit == a2dHit::hit_stroke )
3229  {
3230  if( intersection_count )
3231  rslt.m_stroke1 = a2dHit::stroke1_inside;
3232  else
3233  rslt.m_stroke1 = a2dHit::stroke1_outside;
3234 
3235  if( vertexhit )
3236  rslt.m_distance = ( sqrt( wxMin( minDistSqrVertex, minDistSqrStroke ) ) / margin );
3237  else
3238  rslt.m_distance = ( sqrt( minDistSqrStroke ) / margin );
3239  }
3240  else
3241  {
3242  if( intersection_count )
3243  rslt.m_hit = a2dHit::hit_fill;
3244  else
3245  rslt.m_hit = a2dHit::hit_none;
3246  }
3247 
3248  return rslt;
3249 }
3250 
3251 a2dHit a2dVertexList::HitTestPolyline( const a2dPoint2D& ptest, double margin )
3252 {
3253  wxASSERT( margin >= 0 );
3254 
3255  a2dPoint2D p1, p2, pm;
3256 
3257  double minDistSqrVertex = margin * margin;
3258  double minDistSqrStroke = margin * margin;
3259  bool vertexhit = false;
3260  bool lastpoint = false;
3261  a2dHit rslt;
3262 
3263  int i = 0;
3264  for( a2dVertexList::iterator iter = begin(); iter != end(); ++iter, i++ )
3265  {
3266  a2dLineSegment* seg = *iter;
3267  p1 = seg->GetPoint();
3268 
3269  if( iter != --end() )
3270  {
3271  iter++;
3272  p2 = ( *iter )->GetPoint();
3273  iter--;
3274  }
3275  else
3276  lastpoint = true;
3277 
3278  //--------------------------------------------------------------------
3279  // From here on, this function is identical to the hittest for
3280  // point array polylines. Keep these two identical !!
3281  //--------------------------------------------------------------------
3282 
3283  // check relative horizontal positions of line end points and point
3284  double xmin;
3285  double xmax;
3286 
3287  if( p1.m_x < p2.m_x )
3288  {
3289  xmin = p1.m_x;
3290  xmax = p2.m_x;
3291  }
3292  else
3293  {
3294  xmin = p2.m_x;
3295  xmax = p1.m_x;
3296  }
3297 
3298  if( ptest.m_x < xmin - margin || ptest.m_x > xmax + margin )
3299  continue;
3300 
3301  // check relative horizontal positions of line end points and point
3302  double ymin;
3303  double ymax;
3304  if( p1.m_y < p2.m_y )
3305  {
3306  ymin = p1.m_y;
3307  ymax = p2.m_y;
3308  }
3309  else
3310  {
3311  ymin = p2.m_y;
3312  ymax = p1.m_y;
3313  }
3314 
3315  if( ptest.m_y < ymin - margin || ptest.m_y > ymax + margin )
3316  continue;
3317 
3318  // The test point ptest is inside the margin extended bounding box+margin of the edge
3319  // This means we make vertex and stroke hit tests
3320  // and an intersection test between edge and the vertical line through ptest
3321 
3322  // Vertex hit test for point 1
3323  //
3324  // Note1: double ifs are MUCH slower than double calculations (at least on intel)
3325  // So it is faster calculating the distance square than doing a rectangle test
3326  //
3327  // Note2: vertex hits have higher priority than edge hits
3328  //
3329  // Note3: every vertex is once point1 and once point 2, so only one point needs
3330  // to be tested.
3331  //
3332  // Note4: Even if there is a stroke or vertex hit, search is continued, because
3333  // there could be better hit. A stroke or vertex hit is rarely a random event,
3334  // so it doesn't make much sense to optimize this.
3335 
3336  double distSqr = ClclDistSqrPntPnt( ptest, p1 );
3337 
3338  if( distSqr < minDistSqrVertex )
3339  {
3340  minDistSqrVertex = distSqr;
3341  rslt.m_hit = a2dHit::hit_stroke;
3342  rslt.m_index = i;
3343  rslt.m_stroke2 = a2dHit::stroke2_vertex;
3344  vertexhit = true;
3345  }
3346 
3347  if( lastpoint )
3348  break;
3349 
3350  // Stroke center hit-test
3351  // This is done to allow hitting the stroke even if the stroke length
3352  // is less than the hit margin. As vertex hits have priority, the stroke
3353  // coldn't be hit then. So the stroke center is treated as pseudo-vertex.
3354  pm = a2dPoint2D( 0.5 * ( p1.m_x + p2.m_x ), 0.5 * ( p1.m_y + p2.m_y ) );
3355  distSqr = ClclDistSqrPntPnt( ptest, pm );
3356  if( distSqr < minDistSqrVertex )
3357  {
3358  minDistSqrVertex = distSqr;
3359  rslt.m_hit = a2dHit::hit_stroke;
3360  rslt.m_index = i;
3361  if( p1.m_x == p2.m_x )
3362  rslt.m_stroke2 = a2dHit::stroke2_edgevert;
3363  else if( p1.m_y == p2.m_y )
3364  rslt.m_stroke2 = a2dHit::stroke2_edgehor;
3365  else
3366  rslt.m_stroke2 = a2dHit::stroke2_edgeother;
3367  vertexhit = true;
3368  }
3369 
3370  // Edge hit test
3371  // Note: The edge hittest is even done if a higher prioroity
3372  // vertex hit exists, and no edgehit can accur. This is done
3373  // because the distance of a vertex hit shall not be worse
3374  // then the distance from the closest edge, which is calculated
3375  // here.
3376  distSqr = ClclDistSqrPntLine( ptest, p1, p2 );
3377 
3378  if( distSqr < minDistSqrStroke )
3379  {
3380  minDistSqrStroke = distSqr;
3381  if( !vertexhit )
3382  {
3383  rslt.m_hit = a2dHit::hit_stroke;
3384  rslt.m_index = i;
3385  if( p1.m_x == p2.m_x )
3386  rslt.m_stroke2 = a2dHit::stroke2_edgevert;
3387  else if( p1.m_y == p2.m_y )
3388  rslt.m_stroke2 = a2dHit::stroke2_edgehor;
3389  else
3390  rslt.m_stroke2 = a2dHit::stroke2_edgeother;
3391  }
3392  }
3393  }
3394 
3395  if( rslt.m_hit == a2dHit::hit_stroke )
3396  {
3397  rslt.m_stroke1 = a2dHit::stroke1_outside;
3398  if( vertexhit )
3399  rslt.m_distance = ( sqrt( wxMin( minDistSqrVertex, minDistSqrStroke ) ) / margin );
3400  else
3401  rslt.m_distance = ( sqrt( minDistSqrStroke ) / margin );
3402  }
3403 
3404  return rslt;
3405 }
3406 
3407 void a2dVertexList::CreateArc( const a2dPoint2D& center, const a2dPoint2D& begin, const a2dPoint2D& end, double radius, bool clock, double aber, bool addAtFront )
3408 {
3409  double phi, dphi, dx, dy;
3410  int Segments;
3411  int i;
3412  double ang1, ang2, phit;
3413 
3414  dx = begin.m_x - center.m_x;
3415  dy = begin.m_y - center.m_y;
3416  ang1 = atan2( dy, dx );
3417  if ( ang1 < 0 ) ang1 += 2.0 * M_PI;
3418  dx = end.m_x - center.m_x;
3419  dy = end.m_y - center.m_y;
3420  ang2 = atan2( dy, dx );
3421  if ( ang2 < 0 ) ang2 += 2.0 * M_PI;
3422 
3423  if ( clock )
3424  {
3425  //clockwise
3426  if ( ang2 > ang1 )
3427  phit = 2.0 * M_PI - ang2 + ang1;
3428  else
3429  phit = ang1 - ang2;
3430  }
3431  else
3432  {
3433  //counter_clockwise
3434  if ( ang1 > ang2 )
3435  phit = -( 2.0 * M_PI - ang1 + ang2 );
3436  else
3437  phit = -( ang2 - ang1 );
3438  }
3439 
3440  //what is the delta phi to get an accurancy of aber
3441  dphi = 2 * acos( ( radius - aber ) / radius );
3442 
3443  //set the number of segments
3444  if ( phit > 0 )
3445  Segments = ( int )ceil( phit / dphi );
3446  else
3447  Segments = ( int )ceil( -phit / dphi );
3448 
3449  if ( Segments <= 1 )
3450  Segments = 1;
3451  if ( Segments > 6 )
3452  Segments = 6;
3453 
3454  dphi = phit / ( Segments );
3455 
3456  dx = begin.m_x - center.m_x;
3457  dy = begin.m_y - center.m_y;
3458  phi = atan2( dy, dx );
3459 
3460  //phi -= dphi;
3461  for ( i = 0; i <= Segments; i++ )
3462  {
3463  if ( addAtFront )
3464  push_front( new a2dLineSegment( center.m_x + radius * cos( phi ), center.m_y + radius * sin( phi ) ) );
3465  else
3466  push_back( new a2dLineSegment( center.m_x + radius * cos( phi ), center.m_y + radius * sin( phi ) ) );
3467  phi -= dphi;
3468  }
3469 }
3470 
3471 void a2dVertexList::CreateArc( const a2dPoint2D& center, const a2dLine& incoming, const a2dPoint2D& end, double radius, double aber, bool addAtFront )
3472 {
3473  double distance = 0;
3474  if ( incoming.PointOnLine( center, distance, a2dACCUR ) == R_RIGHT_SIDE )
3475  CreateArc( center, incoming.GetEndPoint(), end, radius, true, aber, addAtFront );
3476  else
3477  CreateArc( center, incoming.GetEndPoint(), end, radius, false, aber, addAtFront );
3478 }
3479 
3480 void a2dVertexList::OffsetContour_rounded( const a2dLine& currentline, const a2dLine& nextline, double factor, bool addAtFront )
3481 {
3482  a2dPoint2D offs_begin;
3483  a2dPoint2D offs_end;
3484  a2dPoint2D medial_axes_point;
3485  a2dPoint2D offs_bgn_next;
3486  a2dPoint2D offs_end_next;
3487 
3488  // make a node from this point
3489  offs_end = currentline.GetEndPoint();
3490  offs_begin = currentline.GetBeginPoint();
3491  currentline.Virtual_Point( offs_begin, factor );
3492  currentline.Virtual_Point( offs_end, factor );
3493  a2dLine offs_currentline( offs_begin, offs_end );
3494 
3495  offs_bgn_next = nextline.GetBeginPoint();
3496  offs_end_next = nextline.GetEndPoint();
3497  nextline.Virtual_Point( offs_bgn_next, factor );
3498  nextline.Virtual_Point( offs_end_next, factor );
3499 
3500  a2dLine offs_nextline( offs_bgn_next, offs_end_next );
3501 
3502  offs_currentline.CalculateLineParameters();
3503  offs_nextline.CalculateLineParameters();
3504  offs_currentline.Intersect( offs_nextline, medial_axes_point );
3505 
3506  double result_offs = sqrt( pow( currentline.GetEndPoint().m_x - medial_axes_point.m_x, 2 ) +
3507  pow( currentline.GetEndPoint().m_y - medial_axes_point.m_y, 2 ) );
3508 
3509  double roundFactor = a2dGlobals->GetRoundFactor();
3510  if ( result_offs < fabs( roundFactor * factor ) )
3511  {
3512  if ( addAtFront )
3513  push_front( new a2dLineSegment( medial_axes_point ) );
3514  else
3515  push_back( new a2dLineSegment( medial_axes_point ) );
3516  }
3517  else
3518  {
3519  //let us create a circle
3520  CreateArc( currentline.GetEndPoint(), offs_currentline, offs_nextline.GetBeginPoint(), fabs( factor ),
3521  a2dGlobals->GetAberArcToPoly(), addAtFront );
3522  }
3523 }
3524 
3525 //----------------------------------------------------------------------------
3526 // vector path segments
3527 //----------------------------------------------------------------------------
3528 const int VPATHSPLINE_STEP = 20;
3529 
3530 
3532 {
3533  m_type = type;
3534  m_close = close;
3535  m_x1 = x;
3536  m_y1 = y;
3537  m_refcount = 0;
3538 }
3539 
3541 {
3542  m_type = other.m_type;
3543  m_close = other.m_close;
3544  m_x1 = other.m_x1;
3545  m_y1 = other.m_y1;
3546  m_refcount = 0;
3547 }
3548 
3550 {
3551  wxASSERT_MSG( m_refcount == 0, wxT( "deleting a2dVpathSegment while referenced" ) );
3552 }
3553 
3555 {
3557  return a;
3558 }
3559 
3561 {
3562  return sqrt( pow( prev->m_x1 - m_x1, 2 ) + pow( prev->m_y1 - m_y1, 2 ) );
3563 }
3564 
3565 
3566 a2dVpathQBCurveSegment::a2dVpathQBCurveSegment( double x1, double y1, double x2, double y2, a2dPATHSEG type, a2dPATHSEG_END close )
3567  : a2dVpathSegment( x1, y1 )
3568 {
3569  m_type = type;
3570  wxASSERT_MSG( a2dPATHSEG_QBCURVETO == m_type || a2dPATHSEG_QBCURVETO_NOSTROKE == m_type , wxT( "wrong type" ) );
3571 
3572  m_close = close;
3573 
3574  m_x2 = x2;
3575  m_y2 = y2;
3576 }
3577 
3579  : a2dVpathSegment( x1, y1 )
3580 {
3581  m_type = type;
3582  wxASSERT_MSG( a2dPATHSEG_QBCURVETO == m_type || a2dPATHSEG_QBCURVETO_NOSTROKE == m_type , wxT( "wrong type" ) );
3583  m_close = close;
3584 
3585  switch ( prev->GetType() )
3586  {
3587  case a2dPATHSEG_QBCURVETO:
3589  {
3590  a2dVpathQBCurveSegment* cseg = ( a2dVpathQBCurveSegment* ) prev.Get();
3591  m_x2 = prev->m_x1 + ( cseg->m_x1 - cseg->m_x2 );
3592  m_y2 = prev->m_y1 + ( cseg->m_y1 - cseg->m_y2 );
3593  break;
3594  }
3595  default:
3596  {
3597  m_x2 = prev->m_x1;
3598  m_y2 = prev->m_y1;
3599  }
3600  }
3601 }
3602 
3603 
3604 
3606 {
3607  m_x2 = other.m_x2;
3608  m_y2 = other.m_y2;
3609 }
3610 
3612 {}
3613 
3615 {
3617  return a;
3618 }
3619 
3621 {
3622  int step;
3623  double t = 0;
3624  double len = 0;
3625  double xwl = prev->m_x1;
3626  double ywl = prev->m_y1;
3627  double xt, yt;
3628 
3629  for ( step = 1; step <= VPATHSPLINE_STEP; step++ )
3630  {
3631  PositionAt( prev, t, xt, yt );
3632  len = len + sqrt( pow( xwl - xt, 2 ) + pow( ywl - yt, 2 ) );
3633  t = t + 1 / ( double )VPATHSPLINE_STEP;
3634  xwl = xt;
3635  ywl = yt;
3636 
3637  }
3638  return len;
3639 }
3640 
3641 void a2dVpathQBCurveSegment::PositionAt( a2dVpathSegmentPtr prev, double t, double& xt, double& yt )
3642 {
3643  xt = prev->m_x1 * pow( 1 - t, 2 ) + m_x2 * ( 1 - t ) * t * 2 + m_x1 * pow( t, 2 );
3644  yt = prev->m_y1 * pow( 1 - t, 2 ) + m_y2 * ( 1 - t ) * t * 2 + m_y1 * pow( t, 2 );
3645 }
3646 
3647 a2dVpathCBCurveSegment::a2dVpathCBCurveSegment( double x1, double y1, double x2, double y2, double x3, double y3, a2dPATHSEG type, a2dPATHSEG_END close )
3648  : a2dVpathSegment( x1, y1 )
3649 {
3650  m_type = type;
3651  wxASSERT_MSG( ( a2dPATHSEG_CBCURVETO == m_type || a2dPATHSEG_CBCURVETO_NOSTROKE == m_type ) , wxT( "wrong type" ) );
3652 
3653  m_close = close;
3654 
3655  m_x2 = x2;
3656  m_y2 = y2;
3657 
3658  m_x3 = x3;
3659  m_y3 = y3;
3660 }
3661 
3662 a2dVpathCBCurveSegment::a2dVpathCBCurveSegment( a2dVpathSegmentPtr prev, double x1, double y1, double x3, double y3, a2dPATHSEG type, a2dPATHSEG_END close )
3663  : a2dVpathSegment( x1, y1 )
3664 {
3665  m_type = type;
3666  wxASSERT_MSG( ( a2dPATHSEG_CBCURVETO == m_type || a2dPATHSEG_CBCURVETO_NOSTROKE == m_type ) , wxT( "wrong type" ) );
3667 
3668  m_close = close;
3669 
3670  switch ( prev->GetType() )
3671  {
3672  case a2dPATHSEG_CBCURVETO:
3674  {
3675  a2dVpathCBCurveSegment* cseg = ( a2dVpathCBCurveSegment* ) prev.Get();
3676  m_x2 = prev->m_x1 + ( cseg->m_x1 - cseg->m_x3 );
3677  m_y2 = prev->m_y1 + ( cseg->m_y1 - cseg->m_y3 );
3678  break;
3679  }
3680  default:
3681  {
3682  m_x2 = prev->m_x1;
3683  m_y2 = prev->m_y1;
3684  }
3685  }
3686 
3687  m_x3 = x3;
3688  m_y3 = y3;
3689 }
3690 
3692 {
3693  m_x2 = other.m_x2;
3694  m_y2 = other.m_y2;
3695 
3696  m_x3 = other.m_x3;
3697  m_y3 = other.m_y3;
3698 
3699 }
3700 
3702 {}
3703 
3705 {
3707  return a;
3708 }
3709 
3711 {
3712  int step;
3713  double t = 0;
3714  double len = 0;
3715  double xwl = prev->m_x1;
3716  double ywl = prev->m_y1;
3717  double xt, yt;
3718 
3719  for ( step = 1; step <= VPATHSPLINE_STEP; step++ )
3720  {
3721  PositionAt( prev, t, xt, yt );
3722  len = len + sqrt( pow( xwl - xt, 2 ) + pow( ywl - yt, 2 ) );
3723  t = t + 1 / ( double )VPATHSPLINE_STEP;
3724  xwl = xt;
3725  ywl = yt;
3726 
3727  }
3728  return len;
3729 }
3730 
3731 void a2dVpathCBCurveSegment::PositionAt( a2dVpathSegmentPtr prev, double t, double& xt, double& yt )
3732 {
3733  xt = prev->m_x1 * pow( 1 - t, 3 ) + m_x2 * pow( 1 - t, 2 ) * t * 3 + m_x3 * ( 1 - t ) * t * t * 3 + m_x1 * pow( t, 3 );
3734  yt = prev->m_y1 * pow( 1 - t, 3 ) + m_y2 * pow( 1 - t, 2 ) * t * 3 + m_y3 * ( 1 - t ) * t * t * 3 + m_y1 * pow( t, 3 );
3735 }
3736 
3737 a2dVpathArcSegment::a2dVpathArcSegment( double x1, double y1, double x2, double y2, a2dPATHSEG type, a2dPATHSEG_END close )
3738  : a2dVpathSegment( x1, y1 )
3739 {
3740  m_type = type;
3741  wxASSERT_MSG( a2dPATHSEG_ARCTO == m_type || a2dPATHSEG_ARCTO_NOSTROKE == m_type , wxT( "wrong type" ) );
3742 
3743  m_close = close;
3744 
3745  m_x2 = x2;
3746  m_y2 = y2;
3747 }
3748 
3749 a2dVpathArcSegment::a2dVpathArcSegment( a2dVpathSegmentPtr prev, double xc, double yc, double angle, a2dPATHSEG type, a2dPATHSEG_END close )
3750  : a2dVpathSegment( 0, 0 )
3751 {
3752  m_type = type;
3753  wxASSERT_MSG( a2dPATHSEG_ARCTO == m_type || a2dPATHSEG_ARCTO_NOSTROKE == m_type , wxT( "wrong type" ) );
3754 
3755  m_close = close;
3756 
3757  double radius = sqrt( pow( prev->m_x1 - xc, 2 ) + pow( prev->m_y1 - yc, 2 ) );
3758 
3759  double endrad = atan2( prev->m_y1 - yc, prev->m_x1 - xc ) + wxDegToRad( angle );
3760 
3761  m_x1 = xc + radius * cos( endrad );
3762  m_y1 = yc + radius * sin( endrad );
3763 
3764  double midrad = atan2( prev->m_y1 - yc, prev->m_x1 - xc ) + wxDegToRad( angle / 2.0 );
3765 
3766  m_x2 = xc + radius * cos( midrad );
3767  m_y2 = yc + radius * sin( midrad );
3768 }
3769 
3770 a2dVpathArcSegment::a2dVpathArcSegment( a2dVpathSegmentPtr prev, double xc, double yc, double x1, double y1, double x2, double y2, a2dPATHSEG type, a2dPATHSEG_END close )
3771  : a2dVpathSegment( x1, y1 )
3772 {
3773  m_type = type;
3774  wxASSERT_MSG( a2dPATHSEG_ARCTO == m_type || a2dPATHSEG_ARCTO_NOSTROKE == m_type , wxT( "wrong type" ) );
3775 
3776  m_close = close;
3777 
3778  double radius = sqrt( pow( prev->m_x1 - xc, 2 ) + pow( prev->m_y1 - yc, 2 ) );
3779 
3780  double endrad = atan2( m_y1 - yc, m_x1 - xc );
3781 
3782  m_x1 = xc + radius * cos( endrad );
3783  m_y1 = yc + radius * sin( endrad );
3784 
3785  double midrad = atan2( y2 - yc, x2 - xc );
3786 
3787  m_x2 = xc + radius * cos( midrad );
3788  m_y2 = yc + radius * sin( midrad );
3789 }
3790 
3792 {
3793  m_x2 = other.m_x2;
3794  m_y2 = other.m_y2;
3795 }
3796 
3798 {}
3799 
3801 {
3803  return a;
3804 }
3805 
3807 {
3808  double len, radius, center_x, center_y, beginrad, midrad, endrad, phit;
3809 
3810  if ( CalcR( prev, radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
3811  {
3812  len = fabs( phit * radius );
3813  }
3814  else
3815  len = sqrt( pow( prev->m_x1 - m_x1, 2 ) + pow( prev->m_y1 - m_y1, 2 ) );
3816 
3817  return len;
3818 }
3819 
3820 bool a2dVpathArcSegment::CalcR( a2dVpathSegmentPtr prev, double& radius, double& center_x, double& center_y, double& beginrad, double& midrad, double& endrad, double& phit )
3821 {
3822  return ::CalcR( prev->m_x1, prev->m_y1, m_x2, m_y2, m_x1, m_y1,
3823  radius, center_x, center_y, beginrad, midrad, endrad, phit );
3824 }
3825 
3826 
3827 //----------------------------------------------------------------------------
3828 // a2dVpath
3829 //----------------------------------------------------------------------------
3830 
3831 a2dVpath::a2dVpath()
3832 {}
3833 
3834 a2dVpath::a2dVpath( a2dVertexArray& vertexArray, bool moveToFirst, bool closeLast )
3835 {
3836  Add( vertexArray, moveToFirst, closeLast );
3837 }
3838 
3839 a2dVpath::a2dVpath( a2dVertexList& vertexList, bool moveToFirst, bool closeLast )
3840 {
3841  Add( vertexList, moveToFirst, closeLast );
3842 }
3843 
3845 {}
3846 
3848 {
3849  clear();
3850  unsigned int i;
3851  for ( i = 0; i < other.size(); i++ )
3852  {
3853  a2dVpathSegment* seg = other.Item( i )->Clone();
3854  Add( seg );
3855  }
3856 
3857  return *this;
3858 }
3859 
3860 void a2dVpath::Add( a2dVertexArray& vertexArray, bool moveToFirst, bool closeLast )
3861 {
3862  unsigned int i;
3863  for ( i = 0; i < vertexArray.size(); i++ )
3864  {
3865  a2dLineSegmentPtr seg = vertexArray.Item( i );
3867  if ( i == vertexArray.size() - 1 && closeLast )
3868  close = a2dPATHSEG_END_CLOSED;
3869  if ( seg->GetArc() )
3870  {
3871  a2dArcSegment* cseg = ( a2dArcSegment* ) seg.Get();
3872  a2dVpathArcSegment* segn = new a2dVpathArcSegment( cseg->m_x, cseg->m_y, cseg->m_x2, cseg->m_y2, ( moveToFirst && i == 0 ) ? a2dPATHSEG_MOVETO : a2dPATHSEG_ARCTO, close );
3873  push_back( segn );
3874  }
3875  else
3876  {
3877  a2dVpathSegment* segn = new a2dVpathSegment( seg->m_x, seg->m_y, ( moveToFirst && i == 0 ) ? a2dPATHSEG_MOVETO : a2dPATHSEG_LINETO, close );
3878  push_back( segn );
3879  }
3880  }
3881 }
3882 
3883 void a2dVpath::Add( a2dVertexList& vertexList, bool moveToFirst, bool closeLast )
3884 {
3885  for( a2dVertexList::iterator iter = vertexList.begin(); iter != vertexList.end(); ++iter )
3886  {
3887  a2dLineSegment* seg = *iter;
3889  if ( *iter == vertexList.back() && closeLast )
3890  close = a2dPATHSEG_END_CLOSED;
3891  if ( seg->GetArc() )
3892  {
3893  a2dArcSegment* cseg = ( a2dArcSegment* ) seg;
3894  a2dVpathArcSegment* segn = new a2dVpathArcSegment( cseg->m_x, cseg->m_y, cseg->m_x2, cseg->m_y2, ( moveToFirst && iter == vertexList.begin() ) ? a2dPATHSEG_MOVETO : a2dPATHSEG_ARCTO, close );
3895  push_back( segn );
3896  }
3897  else
3898  {
3899  a2dVpathSegment* segn = new a2dVpathSegment( seg->m_x, seg->m_y, ( moveToFirst && iter == vertexList.begin() ) ? a2dPATHSEG_MOVETO : a2dPATHSEG_LINETO, close );
3900  push_back( segn );
3901  }
3902  }
3903 }
3904 
3905 void a2dVpath::MoveTo( double x, double y )
3906 {
3908  Add( seg );
3909 }
3910 
3911 void a2dVpath::LineTo( double x, double y, bool withStroke )
3912 {
3914  a2dVpathSegment* seg = new a2dVpathSegment( x, y, cmd );
3915  Add( seg );
3916 }
3917 
3918 void a2dVpath::QBCurveTo( double x1, double y1, double x2, double y2, bool withStroke )
3919 {
3921  a2dVpathQBCurveSegment* seg =
3922  new a2dVpathQBCurveSegment( x1, y1, x2, y2, cmd );
3923  Add( seg );
3924 }
3925 
3926 void a2dVpath::QBCurveTo( double x1, double y1, bool withStroke )
3927 {
3930  back().Get(), x1, y1, cmd );
3931  Add( seg );
3932 }
3933 
3934 void a2dVpath::CBCurveTo( double x1, double y1, double x2, double y2, double x3, double y3, bool withStroke )
3935 {
3938  x1, y1, x2, y2, x3, y3, cmd );
3939  Add( seg );
3940 }
3941 
3942 void a2dVpath::CBCurveTo( double x1, double y1, double x3, double y3, bool withStroke )
3943 {
3946  back().Get(), x1, y1, x3, y3, cmd );
3947  Add( seg );
3948 }
3949 
3950 void a2dVpath::ArcTo( double x1, double y1, double x2, double y2, bool withStroke )
3951 {
3954  x1, y1, x2, y2, cmd );
3955  Add( seg );
3956 }
3957 
3958 void a2dVpath::ArcTo( double xc, double yc, double angle, bool withStroke )
3959 {
3962  back().Get(), xc, yc, angle, cmd );
3963  Add( seg );
3964 }
3965 
3966 void a2dVpath::ArcTo( double xc, double yc, double x1, double y1, double x2, double y2, bool withStroke )
3967 {
3970  back().Get(), xc, yc, x1, y1, x2, y2, cmd );
3971  Add( seg );
3972 }
3973 
3974 void a2dVpath::Close( bool withStroke )
3975 {
3976  if ( !size() )
3977  {
3978  return;
3979  }
3980  back()->SetClose( withStroke ? a2dPATHSEG_END_CLOSED : a2dPATHSEG_END_CLOSED_NOSTROKE );
3981 }
3982 
3983 
3985 {
3986  double len = 0;
3987  unsigned int i;
3988  for ( i = 1; i < size(); i++ )
3989  {
3990  len = len + Item( i )->Length( Item( i - 1 ) );
3991  }
3992 
3993  return len;
3994 }
3995 
3996 void a2dVpath::RemoveAt( size_t index )
3997 {
3998  size_t i = 0;
3999  for( a2dVpath::iterator iter = begin(); iter != end(); ++iter )
4000  {
4001  if ( i == index )
4002  {
4003  erase( iter );
4004  break;
4005  }
4006  i++;
4007  }
4008 }
4009 
4010 void a2dVpath::Insert( a2dVpathSegment* segment, size_t index )
4011 {
4012  size_t i = 0;
4013  for( a2dVpath::iterator iter = begin(); iter != end(); ++iter )
4014  {
4015  if ( i == index )
4016  {
4017  insert( iter, segment );
4018  break;
4019  }
4020  i++;
4021  }
4022 }
4023 
4024 
4025 bool a2dVpath::IsPolygon( bool allowArc )
4026 {
4027  if ( size() && Item( size() - 1 )->GetClose() != a2dPATHSEG_END_CLOSED ) //last segment oke?
4028  return false;
4029  unsigned int i;
4030  for ( i = 0; i < size(); i++ )
4031  {
4032  a2dVpathSegmentPtr seg = Item( i );
4033  switch ( seg->GetType() )
4034  {
4035  case a2dPATHSEG_MOVETO:
4036  if ( i != 0 )
4037  return false;
4038  case a2dPATHSEG_LINETO:
4039  case a2dPATHSEG_ARCTO:
4040  if ( !allowArc )
4041  return false;
4042  break;
4043  default:
4044  return false;
4045  }
4046  }
4047  return true;
4048 }
4049 
4050 bool a2dVpath::IsPolyline( bool allowArc )
4051 {
4052  if ( size() && Item( size() - 1 )->GetClose() != a2dPATHSEG_END_OPEN ) //last segment oke?
4053  return false;
4054  unsigned int i;
4055  for ( i = 0; i < size(); i++ )
4056  {
4057  a2dVpathSegmentPtr seg = Item( i );
4058  switch ( seg->GetType() )
4059  {
4060  case a2dPATHSEG_MOVETO:
4061  if ( i != 0 )
4062  return false;
4063  case a2dPATHSEG_LINETO:
4064  case a2dPATHSEG_ARCTO:
4065  if ( !allowArc )
4066  return false;
4067  break;
4068  default:
4069  return false;
4070  }
4071  }
4072  return true;
4073 }
4074 
4076 {
4077  if ( !cworld.IsIdentity() )
4078  {
4079  if ( !cworld.IsTranslate() )
4080  ConvertToLines();
4081 
4082  unsigned int i;
4083  for ( i = 0; i < size(); i++ )
4084  {
4085  a2dVpathSegmentPtr seg = Item( i );
4086  switch ( seg->GetType() )
4087  {
4089  case a2dPATHSEG_CBCURVETO:
4090  {
4091  a2dVpathCBCurveSegment* cseg = ( a2dVpathCBCurveSegment* ) seg.Get();
4092  cworld.TransformPoint( cseg->m_x2, cseg->m_y2, cseg->m_x2, cseg->m_y2 );
4093  cworld.TransformPoint( cseg->m_x3, cseg->m_y3, cseg->m_x3, cseg->m_y3 );
4094  }
4095  break;
4096 
4098  case a2dPATHSEG_QBCURVETO:
4099  {
4100  a2dVpathQBCurveSegment* cseg = ( a2dVpathQBCurveSegment* ) seg.Get();
4101  cworld.TransformPoint( cseg->m_x2, cseg->m_y2, cseg->m_x2, cseg->m_y2 );
4102  }
4103  break;
4104 
4106  case a2dPATHSEG_ARCTO:
4107  {
4108  a2dVpathArcSegment* cseg = ( a2dVpathArcSegment* ) seg.Get();
4109  cworld.TransformPoint( cseg->m_x2, cseg->m_y2, cseg->m_x2, cseg->m_y2 );
4110  }
4111  break;
4112  default:
4113  break;
4114  }
4115 
4116  cworld.TransformPoint( seg->m_x1, seg->m_y1, seg->m_x1, seg->m_y1 );
4117  }
4118  }
4119 }
4120 
4122 {
4123  a2dBoundingBox bbox;
4124  double x, y;
4125  unsigned int i;
4126  for ( i = 0; i < size(); i++ )
4127  {
4128  a2dVpathSegmentPtr seg = Item( i );
4129  switch ( seg->GetType() )
4130  {
4131  case a2dPATHSEG_CBCURVETO:
4133  {
4134  a2dVpathCBCurveSegment* cseg = ( a2dVpathCBCurveSegment* ) seg.Get();
4135  lworld.TransformPoint( cseg->m_x2, cseg->m_y2, x, y );
4136  bbox.Expand( x, y );
4137  lworld.TransformPoint( cseg->m_x3, cseg->m_y3, x, y );
4138  bbox.Expand( x, y );
4139  }
4140  break;
4141 
4142  case a2dPATHSEG_QBCURVETO:
4144  {
4145  a2dVpathQBCurveSegment* cseg = ( a2dVpathQBCurveSegment* ) seg.Get();
4146  lworld.TransformPoint( cseg->m_x2, cseg->m_y2, x, y );
4147  bbox.Expand( x, y );
4148  }
4149  break;
4150 
4151  case a2dPATHSEG_ARCTO:
4153  {
4154  a2dVpathArcSegment* cseg = ( a2dVpathArcSegment* ) seg.Get();
4155 
4156  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
4157 
4158  //TODO soemthing to get the actual boundingbox of the arc
4159  if ( cseg->CalcR( Item( i ? i - 1 : 0 ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
4160  {
4161  lworld.TransformPoint( center_x + radius , center_y + radius, x, y );
4162  bbox.Expand( x, y );
4163  lworld.TransformPoint( center_x + radius , center_y - radius, x, y );
4164  bbox.Expand( x, y );
4165  lworld.TransformPoint( center_x - radius , center_y + radius, x, y );
4166  bbox.Expand( x, y );
4167  lworld.TransformPoint( center_x - radius , center_y - radius, x, y );
4168  bbox.Expand( x, y );
4169  }
4170 
4171  lworld.TransformPoint( cseg->m_x2, cseg->m_y2, x, y );
4172  bbox.Expand( x, y );
4173  }
4174  break;
4175  default:
4176  break;
4177  }
4178  lworld.TransformPoint( Item( i )->m_x1, Item( i )->m_y1, x, y );
4179  bbox.Expand( x, y );
4180  }
4181  return bbox;
4182 }
4183 
4185 {
4186  double xw, yw;
4187  bool nostroke = false;
4188  unsigned int i;
4189  a2dVpathSegment* segn;
4190  double tstep = 1 / ( double ) VPATHSPLINE_STEP;
4191 
4192  for ( i = 0; i < size(); i++ )
4193  {
4194  a2dVpathSegmentPtr seg = Item( i );
4195  switch ( seg->GetType() )
4196  {
4198  nostroke = true;
4199  case a2dPATHSEG_CBCURVETO:
4200  {
4201  double xw, yw;
4202 
4203  double xwl = Item( i ? i - 1 : 0 )->m_x1;
4204  double ywl = Item( i ? i - 1 : 0 )->m_y1;
4205  a2dVpathCBCurveSegment* cseg = ( a2dVpathCBCurveSegment* ) seg.Get();
4206 
4207  int step;
4208  double t = 0;
4209  for ( step = 0; step <= VPATHSPLINE_STEP; step++ )
4210  {
4211  xw = xwl * pow( 1 - t, 3 ) + cseg->m_x2 * pow( 1 - t, 2 ) * t * 3 + cseg->m_x3 * ( 1 - t ) * t * t * 3 + cseg->m_x1 * pow( t, 3 );
4212  yw = ywl * pow( 1 - t, 3 ) + cseg->m_y2 * pow( 1 - t, 2 ) * t * 3 + cseg->m_y3 * ( 1 - t ) * t * t * 3 + cseg->m_y1 * pow( t, 3 );
4213  if ( !nostroke )
4214  segn = new a2dVpathSegment( xw, yw, a2dPATHSEG_LINETO );
4215  else
4216  segn = new a2dVpathSegment( xw, yw, a2dPATHSEG_LINETO_NOSTROKE );
4217 
4218  if ( step == VPATHSPLINE_STEP )
4219  segn->m_close = seg->m_close;
4220 
4221  Insert( segn, i++ );
4222  t = t + tstep;
4223  }
4224  RemoveAt( i-- );
4225  }
4226  break;
4227 
4229  nostroke = true;
4230  case a2dPATHSEG_QBCURVETO:
4231  {
4232  double xw, yw;
4233 
4234  double xwl = Item( i ? i - 1 : 0 )->m_x1;
4235  double ywl = Item( i ? i - 1 : 0 )->m_y1;
4236  a2dVpathQBCurveSegment* cseg = ( a2dVpathQBCurveSegment* ) seg.Get();
4237 
4238  int step;
4239  double t = 0;
4240  for ( step = 0; step <= VPATHSPLINE_STEP; step++ )
4241  {
4242  xw = xwl * pow( 1 - t, 2 ) + cseg->m_x2 * ( 1 - t ) * t * 2 + cseg->m_x1 * pow( t, 2 );
4243  yw = ywl * pow( 1 - t, 2 ) + cseg->m_y2 * ( 1 - t ) * t * 2 + cseg->m_y1 * pow( t, 2 );
4244  if ( !nostroke )
4245  segn = new a2dVpathSegment( xw, yw, a2dPATHSEG_LINETO );
4246  else
4247  segn = new a2dVpathSegment( xw, yw, a2dPATHSEG_LINETO_NOSTROKE );
4248 
4249  if ( step == VPATHSPLINE_STEP )
4250  segn->m_close = seg->m_close;
4251 
4252  Insert( segn, i++ );
4253  t = t + tstep;
4254  }
4255  RemoveAt( i-- );
4256  }
4257  break;
4258 
4260  nostroke = true;
4261  case a2dPATHSEG_ARCTO:
4262  {
4263  a2dVpathArcSegment* cseg = ( a2dVpathArcSegment* ) seg.Get();
4264 
4265  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
4266 
4267  if ( cseg->CalcR( Item( i ? i - 1 : 0 ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
4268  {
4269  double dphi;
4270  unsigned int segments;
4271  Aberration( radius / 200, phit, radius , dphi, segments );
4272  //a2dGlobals->Aberration( phit, radius , dphi, segments );
4273 
4274  double theta = beginrad;
4275  unsigned int step;
4276 
4277  for ( step = 0; step < segments + 1; step++ )
4278  {
4279  xw = center_x + radius * cos ( theta );
4280  yw = center_y + radius * sin ( theta );
4281  if ( !nostroke )
4282  segn = new a2dVpathSegment( xw, yw, a2dPATHSEG_LINETO );
4283  else
4284  segn = new a2dVpathSegment( xw, yw, a2dPATHSEG_LINETO_NOSTROKE );
4285 
4286  if ( step == segments )
4287  segn->m_close = seg->m_close;
4288 
4289  Insert( segn, i++ );
4290  theta = theta + dphi;
4291  }
4292  }
4293  else
4294  {
4295  if ( !nostroke )
4296  segn = new a2dVpathSegment( cseg->m_x1, cseg->m_y1, a2dPATHSEG_LINETO );
4297  else
4298  segn = new a2dVpathSegment( cseg->m_x1, cseg->m_y1, a2dPATHSEG_LINETO_NOSTROKE );
4299 
4300  segn->m_close = seg->m_close;
4301  Insert( segn, i++ );
4302  }
4303  RemoveAt( i-- );
4304  }
4305  break;
4306  default:
4307  break;
4308  }
4309  nostroke = false;
4310  }
4311 }
4312 
4314 {
4315  double xw, yw;
4316  bool nostroke = false;
4317  unsigned int i;
4318  double tstep = 1 / ( double ) VPATHSPLINE_STEP;
4319  a2dVertexList* result = NULL;
4320 
4321  for ( i = 0; i < size(); i++ )
4322  {
4323  a2dVpathSegmentPtr seg = Item( i );
4324  switch ( seg->GetType() )
4325  {
4326  case a2dPATHSEG_MOVETO:
4327  {
4328  result = new a2dVertexList();
4329  addTo.push_back( result );
4330 
4331  result->push_back( new a2dLineSegment( seg->m_x1, seg->m_y1 ) );
4332  break;
4333  }
4335  nostroke = true;
4336  case a2dPATHSEG_LINETO:
4337  {
4338  result->push_back( new a2dLineSegment( seg->m_x1, seg->m_y1 ) );
4339  }
4340  break;
4342  nostroke = true;
4343  case a2dPATHSEG_CBCURVETO:
4344  {
4345  double xw, yw;
4346 
4347  double xwl = Item( i ? i - 1 : 0 )->m_x1;
4348  double ywl = Item( i ? i - 1 : 0 )->m_y1;
4349  a2dVpathCBCurveSegment* cseg = ( a2dVpathCBCurveSegment* ) seg.Get();
4350 
4351  int step;
4352  double t = 0;
4353  for ( step = 0; step <= VPATHSPLINE_STEP; step++ )
4354  {
4355  xw = xwl * pow( 1 - t, 3 ) + cseg->m_x2 * pow( 1 - t, 2 ) * t * 3 + cseg->m_x3 * ( 1 - t ) * t * t * 3 + cseg->m_x1 * pow( t, 3 );
4356  yw = ywl * pow( 1 - t, 3 ) + cseg->m_y2 * pow( 1 - t, 2 ) * t * 3 + cseg->m_y3 * ( 1 - t ) * t * t * 3 + cseg->m_y1 * pow( t, 3 );
4357  result->push_back( new a2dLineSegment( xw, yw ) );
4358  t = t + tstep;
4359  }
4360  }
4361  break;
4362 
4364  nostroke = true;
4365  case a2dPATHSEG_QBCURVETO:
4366  {
4367  double xw, yw;
4368 
4369  double xwl = Item( i ? i - 1 : 0 )->m_x1;
4370  double ywl = Item( i ? i - 1 : 0 )->m_y1;
4371  a2dVpathQBCurveSegment* cseg = ( a2dVpathQBCurveSegment* ) seg.Get();
4372 
4373  int step;
4374  double t = 0;
4375  for ( step = 0; step <= VPATHSPLINE_STEP; step++ )
4376  {
4377  xw = xwl * pow( 1 - t, 2 ) + cseg->m_x2 * ( 1 - t ) * t * 2 + cseg->m_x1 * pow( t, 2 );
4378  yw = ywl * pow( 1 - t, 2 ) + cseg->m_y2 * ( 1 - t ) * t * 2 + cseg->m_y1 * pow( t, 2 );
4379  result->push_back( new a2dLineSegment( xw, yw ) );
4380  t = t + tstep;
4381  }
4382  }
4383  break;
4384 
4386  nostroke = true;
4387  case a2dPATHSEG_ARCTO:
4388  {
4389  a2dVpathArcSegment* cseg = ( a2dVpathArcSegment* ) seg.Get();
4390 
4391  if ( arc )
4392  {
4393  double radius, center_x, center_y, beginrad, midrad, endrad, phit;
4394 
4395  if ( cseg->CalcR( Item( i ? i - 1 : 0 ), radius, center_x, center_y, beginrad, midrad, endrad, phit ) )
4396  {
4397  double dphi;
4398  unsigned int segments;
4399  Aberration( radius / 200, phit, radius , dphi, segments );
4400  //a2dGlobals->Aberration( phit, radius , dphi, segments );
4401 
4402  double theta = beginrad;
4403  unsigned int step;
4404 
4405  for ( step = 0; step < segments + 1; step++ )
4406  {
4407  xw = center_x + radius * cos ( theta );
4408  yw = center_y + radius * sin ( theta );
4409  result->push_back( new a2dLineSegment( xw, yw ) );
4410  theta = theta + dphi;
4411  }
4412  }
4413  else
4414  {
4415  result->push_back( new a2dLineSegment( cseg->m_x1, cseg->m_y1 ) );
4416  }
4417  }
4418  else
4419  result->push_back( new a2dArcSegment( cseg->m_x1, cseg->m_y1, cseg->m_x2, cseg->m_y2 ) );
4420  }
4421  break;
4422  default:
4423  break;
4424  }
4425  nostroke = false;
4426  }
4427 }
4428 
4429 void a2dVpath::Contour( double distance, a2dPATH_END_TYPE pathtype )
4430 {
4431  ConvertToLines();
4432 
4433  a2dVpath totalconverted;
4434  bool move = false;
4435 
4436  if ( distance )
4437  {
4438  unsigned int i = 0;
4439  int subpartstart = 0;
4440  int subpartLength = 0;
4441  while ( i < size() )
4442  {
4443  a2dVpathSegmentPtr seg = Item( i );
4444  switch ( seg->GetType() )
4445  {
4446  case a2dPATHSEG_MOVETO:
4447  {
4448  if ( i == 0 ) // the first should always be Move
4449  subpartLength++;
4450  else
4451  move = true;
4452  break;
4453  }
4454  case a2dPATHSEG_LINETO:
4456  subpartLength++;
4457  break;
4458  default:
4459  break;
4460  }
4461 
4462  if ( move )
4463  {
4464  //we have found one subpart, process it
4465  SingleContour( totalconverted, subpartstart, subpartLength, distance, pathtype );
4466  move = false;
4467  subpartLength = 1;
4468  subpartstart = i;
4469  }
4470  i++;
4471  }
4472 
4473  if ( subpartLength )
4474  {
4475  //we have found one subpart, process it
4476  SingleContour( totalconverted, subpartstart, subpartLength, distance, pathtype );
4477  }
4478 
4479  *this = totalconverted;
4480  }
4481 }
4482 
4483 void a2dVpath::SingleContour( a2dVpath& converted, unsigned int start, unsigned int segments, double distance, a2dPATH_END_TYPE pathtype )
4484 {
4485  //bool rounded = true;
4486  a2dPoint2D _first;
4487  a2dPoint2D _middle;
4488  a2dPoint2D _end;
4489  a2dPoint2D offsetpointleft;
4490  a2dPoint2D offsetpointright;
4491 
4492  unsigned int insertAt = converted.size();
4493 
4494  //create start of subpart
4495  a2dVpathSegmentPtr seg = Item( start );
4496  if ( segments == 1 )
4497  {
4498  converted.Add( new a2dVpathSegment( seg->m_x1 - distance, seg->m_y1 , a2dPATHSEG_MOVETO, seg->GetClose() ) );
4499  switch ( pathtype )
4500  {
4501  case a2dPATH_END_SQAURE:
4502  {
4503  //not defined
4504  }
4505  break;
4506  case a2dPATH_END_ROUND:
4507  {
4508  a2dVpathSegment* segn = new a2dVpathArcSegment( seg->m_x1 + distance, seg->m_y1,
4509  seg->m_x1 - distance, seg->m_y1, a2dPATHSEG_ARCTO, a2dPATHSEG_END_OPEN );
4510 
4511  converted.Add( segn );
4512  }
4513  break;
4514  case a2dPATH_END_SQAURE_EXT:
4515  {
4516  //not defined
4517  }
4518  break;
4519  default:
4520  break;
4521  }
4522  return;
4523  }
4524  else
4525  {
4526  //first begin point
4527  _first = a2dPoint2D( seg->m_x1, seg->m_y1 );
4528  a2dVpathSegmentPtr segnext = Item( start + 1 );
4529  _middle = a2dPoint2D( segnext->m_x1, segnext->m_y1 );
4530  a2dLine line1( _first, _middle );
4531  line1.CalculateLineParameters();
4532  offsetpointleft = _first;
4533  offsetpointright = _first;
4534  line1.Virtual_Point( offsetpointleft, distance );
4535  line1.Virtual_Point( offsetpointright, -distance );
4536 
4537  switch ( pathtype )
4538  {
4539  case a2dPATH_END_SQAURE:
4540  {
4541  converted.Add( new a2dVpathSegment( offsetpointleft.m_x, offsetpointleft.m_y, a2dPATHSEG_LINETO, a2dPATHSEG_END_OPEN ) );
4542  converted.Insert( new a2dVpathSegment( offsetpointright.m_x, offsetpointright.m_y, a2dPATHSEG_LINETO, a2dPATHSEG_END_OPEN ), insertAt );
4543  }
4544  break;
4545  case a2dPATH_END_ROUND:
4546  {
4547  a2dLine lineoffset( offsetpointright, offsetpointleft );
4548  lineoffset.CalculateLineParameters();
4549  a2dPoint2D offsetpointfirst;
4550 
4551  offsetpointfirst = _first;
4552  lineoffset.Virtual_Point( offsetpointfirst, distance );
4553  converted.Add( new a2dVpathArcSegment( offsetpointleft.m_x, offsetpointleft.m_y,
4554  offsetpointfirst.m_x, offsetpointfirst.m_y,
4556  converted.Insert( new a2dVpathSegment( offsetpointright.m_x, offsetpointright.m_y, a2dPATHSEG_LINETO, a2dPATHSEG_END_OPEN ), insertAt );
4557  break;
4558  }
4559  case a2dPATH_END_SQAURE_EXT:
4560  {
4561  a2dLine lineoffset( offsetpointright, offsetpointleft );
4562  lineoffset.CalculateLineParameters();
4563  lineoffset.Virtual_Point( offsetpointleft, distance );
4564  lineoffset.Virtual_Point( offsetpointright, distance );
4565 
4566  converted.Add( new a2dVpathSegment( offsetpointleft.m_x, offsetpointleft.m_y, a2dPATHSEG_LINETO, a2dPATHSEG_END_OPEN ) );
4567  converted.Insert( new a2dVpathSegment( offsetpointright.m_x, offsetpointright.m_y, a2dPATHSEG_LINETO, a2dPATHSEG_END_OPEN ), insertAt );
4568  break;
4569  }
4570  default:
4571  break;
4572  }
4573 
4574  }
4575 
4576  //in between start and end
4577  unsigned int i;
4578  for ( i = start + 1; i < start + segments - 1; i++ )
4579  {
4580  a2dVpathSegmentPtr seg = Item( i - 1 );
4581  _first = a2dPoint2D( seg->m_x1, seg->m_y1 );
4582  a2dVpathSegmentPtr segnext = Item( i );
4583  _middle = a2dPoint2D( segnext->m_x1, segnext->m_y1 );
4584  a2dLine line1( _first, _middle );
4585  a2dVpathSegmentPtr segend = Item( i + 1 );
4586  _end = a2dPoint2D( segend->m_x1, segend->m_y1 );
4587  a2dLine line2( _middle, _end );
4588  line1.CalculateLineParameters();
4589  line2.CalculateLineParameters();
4590 
4591  OUTPRODUCT _outproduct;
4592  _outproduct = line1.OutProduct( line2, 1e-9 );
4593 
4594  switch ( _outproduct )
4595  {
4596  // Line 2 lies on leftside of this line
4597  case R_IS_RIGHT :
4598  {
4599  line1.OffsetContour( line2, distance, offsetpointleft );
4600  line1.OffsetContour( line2, -distance, offsetpointright );
4601  }
4602  break;
4603  case R_IS_LEFT :
4604  {
4605  line1.OffsetContour( line2, distance, offsetpointleft );
4606  line1.OffsetContour( line2, -distance, offsetpointright );
4607  }
4608  break;
4609  // Line 2 lies on this line
4610  case R_IS_ON :
4611  {
4612  offsetpointleft = _middle;
4613  offsetpointright = _middle;
4614  line1.Virtual_Point( offsetpointleft, distance );
4615  line1.Virtual_Point( offsetpointright, -distance );
4616  }
4617  break;
4618  default:
4619  wxFAIL_MSG( wxT( "wrong line code" ) );
4620  break;
4621  }//end switch
4622 
4623  converted.Add( new a2dVpathSegment( offsetpointleft.m_x, offsetpointleft.m_y, a2dPATHSEG_LINETO, a2dPATHSEG_END_OPEN ) );
4624  converted.Insert( new a2dVpathSegment( offsetpointright.m_x, offsetpointright.m_y, a2dPATHSEG_LINETO, a2dPATHSEG_END_OPEN ), insertAt );
4625  }
4626 
4627  seg = Item( i - 1 );
4628  a2dVpathSegmentPtr segnext = Item( i );
4629 
4630  if ( segnext->GetClose() == a2dPATHSEG_END_CLOSED )
4631  {
4632  _first = a2dPoint2D( seg->m_x1, seg->m_y1 );
4633  _middle = a2dPoint2D( segnext->m_x1, segnext->m_y1 );
4634  a2dLine line1( _first, _middle );
4635  a2dVpathSegmentPtr segend = Item( i - segments + 1 );
4636  _end = a2dPoint2D( segend->m_x1, segend->m_y1 );
4637  a2dLine line2( _middle, _end );
4638  line1.CalculateLineParameters();
4639  line2.CalculateLineParameters();
4640 
4641  OUTPRODUCT _outproduct;
4642  _outproduct = line1.OutProduct( line2, 1e-9 );
4643 
4644  switch ( _outproduct )
4645  {
4646  // Line 2 lies on leftside of this line
4647  case R_IS_RIGHT :
4648  {
4649  line1.OffsetContour( line2, distance, offsetpointleft );
4650  line1.OffsetContour( line2, -distance, offsetpointright );
4651  }
4652  break;
4653  case R_IS_LEFT :
4654  {
4655  line1.OffsetContour( line2, distance, offsetpointleft );
4656  line1.OffsetContour( line2, -distance, offsetpointright );
4657  }
4658  break;
4659  // Line 2 lies on this line
4660  case R_IS_ON :
4661  {
4662  offsetpointleft = _middle;
4663  offsetpointright = _middle;
4664  line1.Virtual_Point( offsetpointleft, distance );
4665  line1.Virtual_Point( offsetpointright, -distance );
4666  }
4667  break;
4668  default:
4669  wxFAIL_MSG( wxT( "wrong line code" ) );
4670  break;
4671  }//end switch
4672 
4673  converted.Add( new a2dVpathSegment( offsetpointleft.m_x, offsetpointleft.m_y, a2dPATHSEG_LINETO, a2dPATHSEG_END_OPEN ) );
4674  converted.Insert( new a2dVpathSegment( offsetpointright.m_x, offsetpointright.m_y, a2dPATHSEG_LINETO, a2dPATHSEG_END_OPEN ), insertAt );
4675 
4676  seg = Item( i );
4677  segnext = Item( i - segments + 1 );
4678  }
4679 
4680 
4681  //if ( seg.GetClose() == a2dPATHSEG_END_OPEN || a2dPATHSEG_END_CLOSED_NOSTROKE )
4682  {
4683  //first begin point
4684  _first = a2dPoint2D( seg->m_x1, seg->m_y1 );
4685  _end = a2dPoint2D( segnext->m_x1, segnext->m_y1 );
4686  a2dLine line1( _first, _end );
4687  line1.CalculateLineParameters();
4688  offsetpointleft = _end;
4689  offsetpointright = _end;
4690  line1.Virtual_Point( offsetpointleft, distance );
4691  line1.Virtual_Point( offsetpointright, -distance );
4692 
4693  switch ( pathtype )
4694  {
4695  case a2dPATH_END_SQAURE:
4696  {
4697  converted.Add( new a2dVpathSegment( offsetpointleft.m_x, offsetpointleft.m_y, a2dPATHSEG_LINETO, a2dPATHSEG_END_CLOSED ) );
4698  converted.Insert( new a2dVpathSegment( offsetpointright.m_x, offsetpointright.m_y, a2dPATHSEG_MOVETO, a2dPATHSEG_END_OPEN ), insertAt );
4699  }
4700  break;
4701  case a2dPATH_END_ROUND:
4702  {
4703  a2dLine lineoffset( offsetpointleft, offsetpointright );
4704  lineoffset.CalculateLineParameters();
4705  a2dPoint2D offsetpointend;
4706 
4707  offsetpointend = _end;
4708  lineoffset.Virtual_Point( offsetpointend, distance );
4709  converted.Add( new a2dVpathSegment( offsetpointleft.m_x, offsetpointleft.m_y, a2dPATHSEG_LINETO, a2dPATHSEG_END_OPEN ) );
4710  converted.Add( new a2dVpathArcSegment( offsetpointright.m_x, offsetpointright.m_y,
4711  offsetpointend.m_x, offsetpointend.m_y,
4713  converted.Insert( new a2dVpathSegment( offsetpointright.m_x, offsetpointright.m_y, a2dPATHSEG_MOVETO, a2dPATHSEG_END_OPEN ), insertAt );
4714  break;
4715  }
4716  case a2dPATH_END_SQAURE_EXT:
4717  {
4718  a2dLine lineoffset( offsetpointright, offsetpointleft );
4719  lineoffset.CalculateLineParameters();
4720  lineoffset.Virtual_Point( offsetpointleft, -distance );
4721  lineoffset.Virtual_Point( offsetpointright, -distance );
4722 
4723  converted.Add( new a2dVpathSegment( offsetpointleft.m_x, offsetpointleft.m_y, a2dPATHSEG_LINETO, a2dPATHSEG_END_CLOSED ) );
4724  converted.Insert( new a2dVpathSegment( offsetpointright.m_x, offsetpointright.m_y, a2dPATHSEG_MOVETO, a2dPATHSEG_END_OPEN ), insertAt );
4725  break;
4726  }
4727  default:
4728  break;
4729  }
4730  }
4731 }
4732 
4733 /********************* CURVES FOR SPLINES *****************************
4734 
4735  The following spline drawing routine is from
4736 
4737  "An Algorithm for High-Speed Curve Generation"
4738  by George Merrill Chaikin,
4739  Computer Graphics and Image Processing, 3, Academic Press,
4740  1974, 346-349.
4741 
4742  and
4743 
4744  "On Chaikin's Algorithm" by R. F. Riesenfeld,
4745  Computer Graphics and Image Processing, 4, Academic Press,
4746  1975, 304-310.
4747 
4748 ***********************************************************************/
4749 
4750 #define half(z1, z2) ((z1+z2)/2.0)
4751 
4752 /* iterative version */
4753 
4754 static void gds_quadratic_spline( a2dVertexList* org, double a1, double b1, double a2, double b2, double a3, double b3, double a4,
4755  double b4, double Aber )
4756 {
4757  register double xmid, ymid;
4758  double x1, y1, x2, y2, x3, y3, x4, y4;
4759  a2dLineSegment* point;
4760 
4761  gds_clear_stack();
4762  gds_spline_push( a1, b1, a2, b2, a3, b3, a4, b4 );
4763 
4764  while ( gds_spline_pop( &x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4 ) )
4765  {
4766  xmid = half( x2, x3 );
4767  ymid = half( y2, y3 );
4768  if ( fabs( x1 - xmid ) < Aber && fabs( y1 - ymid ) < Aber &&
4769  fabs( xmid - x4 ) < Aber && fabs( ymid - y4 ) < Aber )
4770  {
4771  point = new a2dLineSegment( x1, y1 );
4772  org->push_back( point );
4773  point = new a2dLineSegment( xmid, ymid );
4774  org->push_back( point );
4775  }
4776  else
4777  {
4778  gds_spline_push( xmid, ymid, half( xmid, x3 ), half( ymid, y3 ),
4779  half( x3, x4 ), half( y3, y4 ), x4, y4 );
4780  gds_spline_push( x1, y1, half( x1, x2 ), half( y1, y2 ),
4781  half( x2, xmid ), half( y2, ymid ), xmid, ymid );
4782  }
4783  }
4784 }
4785 
4786 bool CalcR( double begin_x, double begin_y, double middle_x, double middle_y, double end_x, double end_y,
4787  double& radius, a2dPoint2D& center_p )
4788 {
4789  double center_x, center_y, beginrad, midrad, endrad, phit;
4790  bool ret = CalcR( begin_x, begin_y, middle_x, middle_y, end_x, end_y,
4791  radius, center_x, center_y, beginrad, midrad, endrad, phit );
4792  center_p.m_x = center_x;
4793  center_p.m_y = center_y;
4794  return ret;
4795 }
4796 
4797 bool CalcR( double begin_x, double begin_y, double middle_x, double middle_y, double end_x, double end_y,
4798  double& radius, double& center_x, double& center_y, double& beginrad, double& midrad, double& endrad, double& phit )
4799 {
4800  double ax, ay, bx, by, cx, cy;
4801  double ax2, ay2, bx2, by2, cx2, cy2;
4802  double d;
4803  bool straight = false;
4804 
4805  ax = begin_x; ay = begin_y; ax2 = pow( ax, 2 ); ay2 = pow( ay, 2 );
4806  bx = middle_x; by = middle_y; bx2 = pow( bx, 2 ); by2 = pow( by, 2 );
4807  cx = end_x; cy = end_y; cx2 = pow( cx, 2 ); cy2 = pow( cy, 2 );
4808 
4809  if ( fabs( ax - cx ) < a2dACCUR && fabs( ay - cy ) < a2dACCUR )
4810  {
4811  //assume the middle is exact 180 opposite.
4812  center_x = ( bx + ax ) / 2.0;
4813  center_y = ( by + ay ) / 2.0;
4814  radius = sqrt( pow( bx - ax, 2 ) + pow( by - ay, 2 ) ) / 2.0;
4815  }
4816  else
4817  {
4818  d = 2 * ( ay * cx + by * ax - by * cx - ay * bx - cy * ax + cy * bx );
4819 
4820  if ( fabs( d ) < a2dACCUR ) // (infinite radius)
4821  {
4822  d = a2dACCUR;
4823  straight = true;
4824  }
4825 
4826  center_x = ( by * ax2 - cy * ax2 - by2 * ay + cy2 * ay + bx2 * cy + ay2 * by
4827  + cx2 * ay - cy2 * by - cx2 * by - bx2 * ay + by2 * cy - ay2 * cy
4828  ) / d;
4829 
4830  center_y = ( ax2 * cx + ay2 * cx + bx2 * ax - bx2 * cx + by2 * ax - by2 * cx
4831  - ax2 * bx - ay2 * bx - cx2 * ax + cx2 * bx - cy2 * ax + cy2 * bx
4832  ) / d ;
4833 
4834  radius = sqrt( pow( ax - center_x, 2 ) + pow( ay - center_y, 2 ) );
4835  }
4836 
4837  if ( radius )
4838  {
4839  //beginrad between PI and -PI, assume counterclockwise, make endrad > beginrad.
4840  beginrad = atan2( begin_y - center_y, begin_x - center_x );
4841  midrad = atan2( middle_y - center_y, middle_x - center_x );
4842  endrad = atan2( end_y - center_y, end_x - center_x );
4843 
4844  double mr, er;
4845 
4846  //if going counterclockwise from begin to end we pass trough middle => counterclockwise
4847  //if going counterclockwise from begin to end we do NOT pass trough middle => clockwise
4848 
4849  //rotate such that beginrad = zero
4850  mr = midrad - beginrad;
4851  er = endrad - beginrad;
4852 
4853  //make positive
4854  if ( mr <= 0 ) mr += 2.0 * M_PI;
4855  if ( er <= 0 ) er += 2.0 * M_PI;
4856  if ( mr >= 2.0 * M_PI ) mr -= 2.0 * M_PI;
4857  if ( er >= 2.0 * M_PI ) er -= 2.0 * M_PI;
4858 
4859  bool counterclock;
4860 
4861  //middle gives direction
4862  if ( mr < er )
4863  {
4864  phit = er; //counterclockwise
4865  counterclock = true;
4866  }
4867  else
4868  {
4869  phit = -( 2.0 * M_PI - er ); //Clockwise
4870  counterclock = false;
4871  }
4872  }
4873  else
4874  {
4875  beginrad = 0;
4876  midrad = 0;
4877  endrad = 0;
4878  }
4879 
4880  return !straight;
4881 }
4882 
4883 /* utilities used by spline drawing routines */
4884 
4885 // splining stack.
4887 {
4888  double x1, y1, x2, y2, x3, y3, x4, y4;
4889 }
4890 Stack;
4891 
4892 #define SPLINE_STACK_DEPTH 20
4893 static Stack gds_spline_stack[SPLINE_STACK_DEPTH];
4894 static Stack* gds_stack_top;
4895 static int gds_stack_count;
4896 
4897 static void gds_clear_stack()
4898 {
4899  gds_stack_top = gds_spline_stack;
4900  gds_stack_count = 0;
4901 }
4902 
4903 static void gds_spline_push( double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4 )
4904 {
4905  gds_stack_top->x1 = x1;
4906  gds_stack_top->y1 = y1;
4907  gds_stack_top->x2 = x2;
4908  gds_stack_top->y2 = y2;
4909  gds_stack_top->x3 = x3;
4910  gds_stack_top->y3 = y3;
4911  gds_stack_top->x4 = x4;
4912  gds_stack_top->y4 = y4;
4913  gds_stack_top++;
4914  gds_stack_count++;
4915 }
4916 
4917 static int gds_spline_pop( double* x1, double* y1, double* x2, double* y2,
4918  double* x3, double* y3, double* x4, double* y4 )
4919 {
4920  if ( gds_stack_count == 0 )
4921  return ( 0 );
4922  gds_stack_top--;
4923  gds_stack_count--;
4924  *x1 = gds_stack_top->x1;
4925  *y1 = gds_stack_top->y1;
4926  *x2 = gds_stack_top->x2;
4927  *y2 = gds_stack_top->y2;
4928  *x3 = gds_stack_top->x3;
4929  *y3 = gds_stack_top->y3;
4930  *x4 = gds_stack_top->x4;
4931  *y4 = gds_stack_top->y4;
4932  return ( 1 );
4933 }
~a2dVpath()
destructor
Definition: polyver.cpp:3844
wxPoint2DDouble a2dPoint2D
this to define if coordinate numbers are integer or doubles
Definition: artglob.h:47
virtual double Length(a2dVpathSegmentPtr prev)
calculate length
Definition: polyver.cpp:3806
bool IsPolygon(bool allowArc=true)
test if closed polygon ( a2dPATHSEG_MOVETO, a2dPATHSEG_LINETO, a2dPATHSEG_ARCTO ) ...
Definition: polyver.cpp:4025
virtual a2dVpathSegment * Clone()
create exact copy
Definition: polyver.cpp:3800
a2dPATH_END_TYPE
defines the way a polyline with a contour width is ended.
Definition: polyver.h:31
unsigned int m_index
For edge/vertex hits the index of the edge / vertex.
Definition: polyver.h:89
Quadratic Bezier curve.
Definition: polyver.h:984
virtual double Length(const a2dLineSegment &prev)
calculate length
Definition: polyver.cpp:256
virtual a2dVpathSegment * Clone()
create exact copy
Definition: polyver.cpp:3704
void ConvertToLines()
Convert complex segments to line segments.
Definition: polyver.cpp:4184
double Length() const
calculate length of path
Definition: polyver.cpp:701
void InsertArc(a2dVertexList::iterator &iter, int n, double center_x, double center_y)
Definition: polyver.cpp:2198
a2dVpath * ConvertToVpath(bool arc, bool closed=false)
return converted vector Vpath, arc segments stay intact if arc is true
Definition: polyver.cpp:2068
bool m_arc
arc segment
Definition: polyver.h:241
Simple Memory manager for some objects which often create and destroy to replace OS-system calls...
Definition: a2dmemmgr.h:20
double m_x2
control point
Definition: polyver.h:1025
#define a2dACCUR
accuracy used to have some limit to calculation like hittesting
Definition: artglob.h:41
fundamental classes used by all other modules.
void ConvertToLines(double aberation=0)
Convert complex segments to line segments.
Definition: polyver.cpp:1948
double CalcArea() const
Definition: polyver.cpp:781
~a2dVpathArcSegment()
destructor
Definition: polyver.cpp:3797
double Length()
calculate length of path, assuming continues path.
Definition: polyver.cpp:3984
Cubic Bezier curve.
Definition: polyver.h:1045
a2dVertexArray()
constructor
Definition: polyver.cpp:604
void Transform(const a2dAffineMatrix &world)
transform all segments with given matrix
Definition: polyver.cpp:4075
a2dLineSegment(double x=0, double y=0)
constructor
Definition: polyver.cpp:203
static a2dHit stock_nohit
Stock object for no hit.
Definition: polyver.h:135
a2dHit HitTestPolyline(const a2dPoint2D &ptest, double margin)
extensive hittesting on vertex list seen as polyline.
Definition: polyver.cpp:1453
static a2dHit stock_strokeinside
Stock object for an inner stroke hit on objects without vertices/edges (like circles) ...
Definition: polyver.h:141
void CBCurveTo(double x1, double y1, double x2, double y2, double x3, double y3, bool withStroke=true)
add a quadratic bezier segment to the path
Definition: polyver.cpp:3934
double wxDegToRad(double deg)
conversion from degrees to radians
Definition: artglob.cpp:30
bool RemoveRedundant(bool polygon)
line segments ( not arcs ) with same point are removed
Definition: polyver.cpp:1605
a2dBoundingBox GetBbox(const a2dAffineMatrix &lworld=a2dIDENTITY_MATRIX)
return a boundingbox of a transformed vertexarray
Definition: polyver.cpp:2581
void Transform(const a2dAffineMatrix &world)
transform all segments with given matrix
Definition: polyver.cpp:823
a2dVertexArray * Contour(double distance, a2dPATH_END_TYPE pathtype)
create a contour around polygon/polyline
Definition: polyver.cpp:1001
double m_y2
control point
Definition: polyver.h:1027
double m_y3
control point 2
Definition: polyver.h:1100
Arc Segment.
Definition: polyver.h:1112
bool IsIdentity(void) const
Is the matrix the identity matrix?
Definition: afmatrix.h:147
double m_x3
control point 2
Definition: polyver.h:1098
double m_x2
x2 x of arc midpoint
Definition: polyver.h:471
a2dPoint2D GetEndPoint() const
Get the endpoint from a a2dLine.
Definition: liner.cpp:446
double ClclDistSqrPntPnt(const a2dPoint2D &a, const a2dPoint2D &b)
Calculate the square distance between two points.
Definition: polyver.h:1394
a2dVpathSegment(double x, double y, a2dPATHSEG type=a2dPATHSEG_LINETO, a2dPATHSEG_END close=a2dPATHSEG_END_OPEN)
constructor
Definition: polyver.cpp:3531
double GetValue(int col, int row) const
get the value in the matrix at col,row
Definition: afmatrix.cpp:106
a2dPoint2D GetOrigin(const a2dLineSegment &prev) const
Get origin of arc.
Definition: polyver.cpp:481
a2dVpath & operator=(const a2dVpath &other)
operator =
Definition: polyver.cpp:3847
a2dGlobal * a2dGlobals
global a2dCanvasGlobal to have easy access to global settings
Definition: artglob.cpp:34
void Close(bool withStroke=true)
Closing the path as a filled area.
Definition: polyver.cpp:3974
double ClclDistSqrPntLine(const a2dPoint2D &p, const a2dPoint2D &p1, const a2dPoint2D &p2)
Calculate the square distance between a point and a line.
Definition: polyver.cpp:103
virtual double Length(a2dSmrtPtr< a2dVpathSegment > prev)
calculate length
Definition: polyver.cpp:3560
void ArcTo(double x1, double y1, double x2, double y2, bool withStroke=true)
add an arc segment to the path
Definition: polyver.cpp:3950
a2dVertexList * ConvertSplinedPolyline(double Aber) const
Spline conversion for polyline.
Definition: polyver.cpp:2858
float m_distance
For margin hits, the distance from the stroke center in fractions of the margin.
Definition: polyver.h:93
Arc Segment in a2dVertexList.
Definition: polyver.h:371
a2dLine * CreatePerpendicularLineAt(const a2dPoint2D &a_point) const
create a line through a_point and which is pperpendicular to this
Definition: liner.cpp:333
vertex array of line and arc segments.
Definition: polyver.h:494
a2dPATHSEG_END m_close
is the path closing here or not
Definition: polyver.h:931
double m_y2
control point 1
Definition: polyver.h:1095
R_PointStatus PointOnLine(const a2dPoint2D &a_Point, double &Distance, double Marge) const
For an infinite a2dLine.
Definition: liner.cpp:614
not specific or part of outer contour
Definition: polyver.h:148
void ConvertPolylineToArc(double aber, double Rmin, double Rmax)
Definition: polyver.cpp:2369
void OffsetContour_rounded(const a2dLine &currentline, const a2dLine &nextline, double factor, bool addAtFront)
create a contour segements at a distance, using two segment
Definition: polyver.cpp:3480
a2dPATHSEG m_type
easy way to test type of segment
Definition: polyver.h:928
vertex list of line and arc segments.
Definition: polyver.h:600
void TransformPoint(double x, double y, double &tx, double &ty) const
Transform a point.
Definition: afmatrix.cpp:559
Id based property system with its base a2dPropertyId.
a2dBoundingBox GetBbox(const a2dAffineMatrix &lworld=a2dIDENTITY_MATRIX)
return a boundingbox of a transformed vertexarray
Definition: polyver.cpp:844
virtual double Length(const a2dLineSegment &prev)
calculate length
Definition: polyver.cpp:375
general vertexlist and array and vector path functions and classes.
a2dVertexList * ConvertSplinedPolygon(double Aber) const
Spline conversion for polygon.
Definition: polyver.cpp:2846
void Transform(const a2dAffineMatrix &world)
transform all segments with given matrix
Definition: polyver.cpp:1928
~a2dVpathCBCurveSegment()
destructor
Definition: polyver.cpp:3701
a2dVertexArray * ConvertSplinedPolyline(double Aber) const
Spline conversion for polyline.
Definition: polyver.cpp:1221
a2dPATHSEG
how do we move to the point of the segment
Definition: polyver.h:846
~a2dVpathQBCurveSegment()
destructor
Definition: polyver.cpp:3611
a2dVpath * ConvertToVpath(bool arc, bool closed=false)
return converted vector Vpath, arc segments stay intact if arc is true
Definition: polyver.cpp:927
OUTPRODUCT OutProduct(const a2dLine &two, double accur) const
outproduct of two wxLines
Definition: liner.cpp:795
classes for initializing the artbase modules, and set paths to be used for fonts etc.
bool HasArcs() const
return true if there are a2dArcSegment segments.
Definition: polyver.cpp:1761
bool CalcR(const a2dLineSegment &prev, double &radius, double &center_x, double &center_y, double &beginrad, double &midrad, double &endrad, double &phit) const
Calculation of center for the Arc.
Definition: polyver.cpp:411
double m_y2
second control point
Definition: polyver.h:1188
void Expand(const a2dPoint2D &, const a2dPoint2D &)
expand boundingbox width two points
Definition: bbox.cpp:155
void Virtual_Point(a2dPoint2D &a_point, double distance) const
calculate point Perpendicula at distance from the line, through given point
Definition: liner.cpp:304
bool m_bin
Marker for walking over the segments.
Definition: polyver.h:238
void SetPointAdjustArcs(unsigned int n, double x, double y, bool polygon)
sets a point of a segment and adjusts arc it midpoints.
Definition: polyver.cpp:730
void AddPoint(const a2dPoint2D &point, bool atEnd=true)
add point to end or begin
Definition: polyver.cpp:1818
a2dBoundingBox GetBbox(const a2dLineSegment &prev, const a2dAffineMatrix &lworld=a2dIDENTITY_MATRIX) const
Get bounding box of arc.
Definition: polyver.cpp:518
bool IsTranslate(void) const
Is the matrix only a translation?
Definition: afmatrix.h:359
void Insert(unsigned int index, a2dLineSegmentPtr segin)
insert before segment with index given
Definition: polyver.cpp:1800
The point is in the fill area.
Definition: polyver.h:56
Normal straight line segment in a2dVpath.
Definition: polyver.h:878
a2dSegType m_segtype
type of segment
Definition: polyver.h:247
a2dVpathQBCurveSegment(double x1, double y1, double x2, double y2, a2dPATHSEG type=a2dPATHSEG_QBCURVETO, a2dPATHSEG_END close=a2dPATHSEG_END_OPEN)
constructor
Definition: polyver.cpp:3566
a2dVertexList::iterator GetPreviousAround(a2dVertexList::iterator iter)
get the previous segment as a polygon ( –end() is no previous )
Definition: polyver.cpp:1721
Normal straight line segment in a2dVertexList and a2dVertexArray.
Definition: polyver.h:163
int TestArc(a2dVertexList::iterator &iter, double aber, double Rmin, double Rmax, a2dPoint2D &center_p_old)
a row of point (minimum 4 ) will be tested to see if its an arc.
Definition: polyver.cpp:2410
bool CalcR(a2dVpathSegmentPtr prev, double &radius, double &center_x, double &center_y, double &beginrad, double &midrad, double &endrad, double &phit)
Calculation of center for the Arc.
Definition: polyver.cpp:3820
a2dVertexArray * ConvertSplinedPolygon(double Aber) const
Spline conversion for polygon.
Definition: polyver.cpp:1196
void CalculateLineParameters()
Calculate the parameters if invalid.
Definition: liner.cpp:355
a2dVpathArcSegment(double x1, double y1, double x2, double y2, a2dPATHSEG type=a2dPATHSEG_ARCTO, a2dPATHSEG_END close=a2dPATHSEG_END_OPEN)
create arc segment
Definition: polyver.cpp:3737
a2dVertexList * GetRedundant(bool polygon, double smallest=0)
line segments ( not arcs ) with same point are returned
Definition: polyver.cpp:1632
void Add(a2dVpathSegment *seg)
add a segment
Definition: polyver.h:1240
a2dVertexArray & operator=(const a2dVertexArray &other)
operator =
Definition: polyver.cpp:653
a2dVertexList::iterator GetNextAround(a2dVertexList::iterator iter)
get the next segment as a polygon ( begin() is no next )
Definition: polyver.cpp:1728
a2dHit HitTestPolyline(const a2dPoint2D &ptest, double margin)
extensive hittesting on vertex list seen as polyline.
Definition: polyver.cpp:3251
virtual double Length(a2dVpathSegmentPtr prev)
calculate length
Definition: polyver.cpp:3710
static double GetRoundFactor()
Definition: artglob.h:124
void QBCurveTo(double x1, double y1, double x2, double y2, bool withStroke=true)
add a quadratic bezier segment to the path
Definition: polyver.cpp:3918
virtual double Length(a2dVpathSegmentPtr prev)
calculate length
Definition: polyver.cpp:3620
double m_x2
control point 1
Definition: polyver.h:1093
bool RemoveRedundant(bool polygon)
line segments ( not arcs ) with same point are removed
Definition: polyver.cpp:2990
A 2x3 affine matrix class for 2D transformations.
Definition: afmatrix.h:53
void PositionAt(a2dVpathSegmentPtr prev, double t, double &xt, double &yt)
calculate position at t, used for length
Definition: polyver.cpp:3731
a2dVertexList * ConvertToContour(double distance, a2dPATH_END_TYPE pathtype, bool asPolygon=false)
create a contour around polygon/polyline
Definition: polyver.cpp:2608
double GetOy(const a2dLineSegment &prev) const
Get origin Y of arc.
Definition: polyver.cpp:449
virtual a2dVpathSegment * Clone()
create exact copy
Definition: polyver.cpp:3614
virtual ~a2dVpathSegment()
destructor
Definition: polyver.cpp:3549
double m_y2
y2 y of arc midpoint
Definition: polyver.h:473
int IndexOf(a2dLineSegment *object) const
Find the index of a specific object.
Definition: polyver.cpp:1788
void ConvertIntoSplinedPolygon(double Aber)
Definition: polyver.cpp:2869
virtual a2dLineSegment * Clone()
create exact copy
Definition: polyver.cpp:250
double GetOx(const a2dLineSegment &prev) const
Get origin X of arc.
Definition: polyver.cpp:417
double m_x
x endpoint of line
Definition: polyver.h:232
struct for how a single object on one layer was hit
Definition: polyver.h:38
~a2dVertexArray()
destructor
Definition: polyver.cpp:622
~a2dArcSegment()
destructor
Definition: polyver.cpp:353
a2dPoint2D ProjectedPoint(const a2dPoint2D &p) const
return point after projecting p to this line.
Definition: liner.cpp:639
double m_y
y endpoint of line
Definition: polyver.h:235
void Aberration(double aber, double angle, double radius, double &dphi, unsigned int &segments)
calculate number of segments in an arc such that a certain accuracy is maintained ...
Definition: artglob.cpp:67
Line calculations.
Definition: liner.h:36
static a2dHit stock_strokeoutside
Stock object for an outer stroke hit on objects without vertices/edges (like circles) ...
Definition: polyver.h:139
a2dHit HitTestPolygon(const a2dPoint2D &ptest, double margin)
extensive hittesting on vertex list seen as polygon.
Definition: polyver.cpp:1254
double CalcArea() const
Definition: polyver.cpp:2151
double m_y1
y endpoint of line
Definition: polyver.h:922
bool InArc(double angle, double start, double end, bool clockwise)
Definition: polyver.cpp:148
void MoveTo(double x, double y)
add a MoveTo command to the path
Definition: polyver.cpp:3905
virtual a2dLineSegment * Clone()
create exact copy
Definition: polyver.cpp:356
bool HasArcs() const
return true if there are a2dArcSegment segments.
Definition: polyver.cpp:690
void SetPointAdjustArcs(unsigned int n, double x, double y, bool polygon)
sets a point of a segment and adjusts arc it midpoints.
Definition: polyver.cpp:1879
a2dVertexList * GetRedundant(bool polygon, double smallest=0)
line segments ( not arcs ) with same point are returned
Definition: polyver.cpp:3020
a2dPoint2D GetBeginPoint() const
Get the beginpoint from a a2dLine.
Definition: liner.cpp:437
a2dVpathCBCurveSegment(double x1, double y1, double x2, double y2, double x3, double y3, a2dPATHSEG type=a2dPATHSEG_CBCURVETO, a2dPATHSEG_END close=a2dPATHSEG_END_OPEN)
constructor
Definition: polyver.cpp:3647
void AddPoint(const a2dPoint2D &point, bool atEnd=true)
add point to end or begin
Definition: polyver.cpp:714
void LineTo(double x, double y, bool withStroke=true)
add a LineTo command to the path
Definition: polyver.cpp:3911
a2dHit HitTestPolygon(const a2dPoint2D &ptest, double margin)
extensive hittesting on vertex list seen as polygon.
Definition: polyver.cpp:3050
bool IsPolyline(bool allowArc=true)
test if polyline ( a2dPATHSEG_MOVETO, a2dPATHSEG_LINETO, a2dPATHSEG_ARCTO )
Definition: polyver.cpp:4050
a2dPATHSEG_END
end of a segment type
Definition: polyver.h:863
The a2dBoundingBox class stores one a2dBoundingBox of a a2dCanvasObject.
Definition: bbox.h:39
a2dBoundingBox GetBbox(const a2dAffineMatrix &lworld=a2dIDENTITY_MATRIX)
return a boundingbox of a transformed a2dVpath
Definition: polyver.cpp:4121
void OffsetContour(const a2dLine &nextline, double factor, a2dPoint2D &offsetpoint) const
Calculate point for a contour at a given distance.
Definition: liner.cpp:765
void Contour(double distance, a2dPATH_END_TYPE pathtype)
create an offset contour at distance
Definition: polyver.cpp:4429
virtual a2dVpathSegment * Clone()
create exact copy
Definition: polyver.cpp:3554
The object is not hit. This should not happen, because the parent should include hit childs...
Definition: polyver.h:52
static a2dHit stock_fill
Stock object for a fill hit.
Definition: polyver.h:137
double Length()
calculate length of path
Definition: polyver.cpp:1772
void PositionAt(a2dVpathSegmentPtr prev, double t, double &xt, double &yt)
calculate position at t, used for length
Definition: polyver.cpp:3641
double m_x1
x endpoint of line
Definition: polyver.h:919
void ConvertToPolygon(a2dListOfa2dVertexList &addTo, bool arc=true)
Definition: polyver.cpp:4313
bool CalcR(double begin_x, double begin_y, double middle_x, double middle_y, double end_x, double end_y, double &radius, a2dPoint2D &center_p)
Calculation of center for the Arc.
Definition: polyver.cpp:4786
static double GetAberArcToPoly()
conversion from arc into lines in database units
Definition: artglob.h:167
The point is on the stroke or stroke margin.
Definition: polyver.h:54
Vector Path.
Definition: polyver.h:1211
void ConvertToLines(double aberation=0)
Convert complex segments to line segments.
Definition: polyver.cpp:867
double m_x2
second control point
Definition: polyver.h:1186
void MakeBegin(a2dVertexList::iterator iter)
make the segmenet where iter point to the beginning of the list and shift the rest ...
Definition: polyver.cpp:1749
bool DirectionIsClockWise()
Definition: polyver.cpp:2193
void CreateArc(const a2dPoint2D &center, const a2dPoint2D &begin, const a2dPoint2D &end, double radius, bool clock, double aber, bool addAtFront)
create an arc and add it to the graph
Definition: polyver.cpp:3407
basic 2 point line class for intersection and contouring routines.
a2dLineSegmentPtr GetPreviousAround(wxUint32 index) const
get the previous segment as a polygon ( GetLast() is no previous )
Definition: polyver.cpp:676
a2dLineSegmentPtr GetNextAround(wxUint32 index) const
get the next segment as a polygon ( GetFirst() is no next )
Definition: polyver.cpp:683
const double wxPI
defines PI
Definition: artglob.cpp:28
void SetMidPoint(const a2dLineSegment &prev, double xm, double ym)
set middle point of arc segment
Definition: polyver.cpp:362
void Contour(double distance, a2dPATH_END_TYPE pathtype, bool asPolygon=false)
create a contour around polygon/polyline
Definition: polyver.cpp:2618
a2dArcSegment(double x1=0, double y1=0, double x2=0, double y2=0)
create arc segment
Definition: polyver.cpp:302
int Intersect(a2dLine &line, a2dPoint2D &bp, a2dPoint2D &ep, double Marge) const
Intersects two wxLines.
Definition: liner.cpp:451
void CalcMidPoint(const a2dLineSegment &prev, double center_x, double center_y, double radius, bool clockwise)
calculate new mid point bsed on prev segment radius and center.
Definition: polyver.cpp:389
polyver.cpp Source File -- Sun Oct 12 2014 17:04:23 -- Sun Oct 12 2014 -- 1.8.5 -- wxArt2D -- . -- Main Page Reference Documentation