wxArt2D
canprim.cpp
Go to the documentation of this file.
1 /*! \file canvas/src/canprim.cpp
2  \author Klaas Holwerda
3 
4  Copyright: 2000-2004 (c) Klaas Holwerda
5 
6  Licence: wxWidgets Licence
7 
8  RCS-ID: $Id: canprim.cpp,v 1.351 2009/07/24 16:35:01 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 #include <wx/wfstream.h>
22 #include <wx/module.h>
23 #include <wx/clipbrd.h>
24 
25 #include "wx/canvas/canobj.h"
26 #include "wx/canvas/canprim.h"
27 #include "wx/canvas/canglob.h"
28 #include "wx/canvas/vpath.h"
29 #include "wx/canvas/drawer.h"
30 #include "wx/canvas/drawing.h"
31 #include "wx/canvas/wire.h"
32 
33 #if defined(__WXMSW__) && defined(__MEMDEBUG__)
34 #include <wx/msw/msvcrt.h>
35 #endif
36 
37 
38 #define CIRCLE_STEPS 128
39 
40 IMPLEMENT_CLASS( a2dWH, a2dCanvasObject )
41 IMPLEMENT_CLASS( a2dWHCenter, a2dWH )
42 
43 IMPLEMENT_DYNAMIC_CLASS( a2dOrigin, a2dCanvasObject )
44 IMPLEMENT_DYNAMIC_CLASS( a2dArrow, a2dCanvasObject )
45 IMPLEMENT_DYNAMIC_CLASS( a2dRectC, a2dCanvasObject )
46 IMPLEMENT_DYNAMIC_CLASS( a2dRect, a2dWH )
47 IMPLEMENT_DYNAMIC_CLASS( a2dCircle, a2dCanvasObject )
48 IMPLEMENT_DYNAMIC_CLASS( a2dEllipse, a2dWHCenter )
49 IMPLEMENT_DYNAMIC_CLASS( a2dEllipticArc, a2dWHCenter )
50 IMPLEMENT_DYNAMIC_CLASS( a2dArc, a2dCanvasObject )
51 IMPLEMENT_DYNAMIC_CLASS( a2dSLine, a2dCanvasObject )
52 IMPLEMENT_DYNAMIC_CLASS( a2dScaledEndLine, a2dEndsLine )
53 IMPLEMENT_DYNAMIC_CLASS( a2dEndsLine, a2dSLine )
54 IMPLEMENT_DYNAMIC_CLASS( a2dEndsEllipticChord, a2dEllipticArc )
55 IMPLEMENT_CLASS( a2dControl, a2dCanvasObject )
56 IMPLEMENT_DYNAMIC_CLASS( a2dWires, a2dCanvasObject )
57 
58 //----------------------------------------------------------------------------
59 // a2dOrigin
60 //----------------------------------------------------------------------------
61 
62 a2dOrigin::a2dOrigin()
63  : a2dCanvasObject()
64 {
65  m_width = 10;
66  m_height = 10;
67 }
68 
69 a2dOrigin::a2dOrigin( double w, double h )
70  : a2dCanvasObject()
71 {
72  m_width = w;
73  m_height = h;
74 }
75 
76 a2dOrigin::~a2dOrigin()
77 {
78 }
79 
80 a2dOrigin::a2dOrigin( const a2dOrigin& other, CloneOptions options, a2dRefMap* refs )
81  : a2dCanvasObject( other, options, refs )
82 {
83  m_width = other.m_width;
84  m_height = other.m_height;
85 }
86 
88 {
89  return new a2dOrigin( *this, options, refs );
90 };
91 
92 a2dBoundingBox a2dOrigin::DoGetUnTransformedBbox( a2dBboxFlags WXUNUSED( flags ) ) const
93 {
94  a2dBoundingBox bbox;
95  bbox.Expand( -m_width, -m_height );
96  bbox.Expand( m_width, m_height );
97  return bbox;
98 }
99 
100 void a2dOrigin::DoRender( a2dIterC& ic, OVERLAP WXUNUSED( clipparent ) )
101 {
102  int w = ( int ) m_width;
103  int h = ( int ) m_height;
104 
105  ic.GetDrawer2D()->DrawLine( -w, 0, w, 0 );
106  ic.GetDrawer2D()->DrawLine( 0, -h, 0, h );
107 }
108 
109 bool a2dOrigin::DoIsHitWorld( a2dIterC& WXUNUSED( ic ), a2dHitEvent& hitEvent )
110 {
111  hitEvent.m_how.m_hit = a2dHit::hit_fill;
112  return true;
113 }
114 
115 #if wxART2D_USE_CVGIO
116 void a2dOrigin::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut& out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
117 {
118  a2dCanvasObject::DoSave( parent, out, xmlparts, towrite );
119  if ( xmlparts == a2dXmlSer_attrib )
120  {
121  }
122  else
123  {
124  }
125 }
126 #endif //wxART2D_USE_CVGIO
127 
128 //----------------------------------------------------------------------------
129 // a2dArrow
130 //----------------------------------------------------------------------------
131 
132 a2dArrow::a2dArrow( double xt, double yt, double l1, double l2, double b, bool spline )
133  : a2dCanvasObject()
134 {
135  m_lworld.Translate( xt, yt );
136  m_l1 = l1;
137  m_l2 = l2;
138  m_b = b;
139  m_spline = spline;
140 }
141 
143  : a2dCanvasObject()
144 {
145  m_lworld.Translate( 0, 0 );
146  m_l1 = 40;
147  m_l2 = 20;
148  m_b = 10;
149  m_spline = false;
150 }
151 
152 a2dArrow::~a2dArrow()
153 {
154 }
155 
156 a2dArrow::a2dArrow( const a2dArrow& other, CloneOptions options, a2dRefMap* refs )
157  : a2dCanvasObject( other, options, refs )
158 {
159  m_l1 = other.m_l1;
160  m_l2 = other.m_l2;
161  m_b = other.m_b;
162  m_spline = other.m_spline;
163 }
164 
165 void a2dArrow::Set( double xt, double yt, double l1, double l2, double b, bool spline )
166 {
167  SetPosXY( xt, yt );
168  m_l1 = l1;
169  m_l2 = l2;
170  m_b = b;
171  m_spline = spline;
172 
173  SetPending( true );
174 }
175 
176 void a2dArrow::Set( double l1, double l2, double b, bool spline )
177 {
178  m_l1 = l1;
179  m_l2 = l2;
180  m_b = b;
181  m_spline = spline;
182 
183  SetPending( true );
184 }
185 
187 {
188  a2dArrow* a = new a2dArrow( *this, options, refs );
189  return a;
190 };
191 
192 a2dVertexList* a2dArrow::GetAsVertexList( bool& returnIsPolygon ) const
193 {
194  returnIsPolygon = true;
195  returnIsPolygon = true;
196 
197  a2dVertexList* pointlist = new a2dVertexList();
198 
199  a2dCanvasObjectList* vectorpaths = GetAsCanvasVpaths();
200  a2dVpath* segments = wxStaticCast( vectorpaths->front().Get(), a2dVectorPath ) ->GetSegments();
201  segments->ConvertToLines();
202  a2dLineSegment* point;
203  unsigned int i;
204  for ( i = 0; i < segments->size(); i++ )
205  {
206  a2dVpathSegment* seg = segments->Item( i );
207  point = new a2dLineSegment( seg->m_x1, seg->m_y1 );
208  pointlist->push_back( point );
209  }
210 
211  delete vectorpaths;
212 
213  return pointlist;
214 }
215 
217 {
218  a2dAffineMatrix pworld;
219  if ( transform )
220  pworld = m_lworld;
221 
222  a2dVpath* segments = new a2dVpath();
223 
224  double x, y;
225  pworld.TransformPoint( 0 , 0, x, y );
227  segments->Add( seg );
228  pworld.TransformPoint( m_l1, m_b / 2, x, y );
229  seg = new a2dVpathSegment( x, y , a2dPATHSEG_MOVETO );
230  segments->Add( seg );
231  pworld.TransformPoint( m_l2, 0, x, y );
232  seg = new a2dVpathSegment( x, y , a2dPATHSEG_MOVETO );
233  segments->Add( seg );
234  pworld.TransformPoint( m_l1, -m_b / 2, x, y );
235  seg = new a2dVpathSegment( x, y , a2dPATHSEG_MOVETO );
236  segments->Add( seg );
237 
238  a2dVectorPath* canpath = new a2dVectorPath( segments );
239  canpath->SetStroke( this->GetStroke() );
240  canpath->SetFill( this->GetFill() );
241  canpath->SetLayer( m_layer );
242  canpath->SetContourWidth( GetContourWidth() );
243  a2dCanvasObjectList* canpathlist = new a2dCanvasObjectList();
244  canpathlist->push_back( canpath );
245  return canpathlist;
246 }
247 
248 a2dBoundingBox a2dArrow::DoGetUnTransformedBbox( a2dBboxFlags WXUNUSED( flags ) ) const
249 {
250  a2dBoundingBox bbox;
251  bbox.Expand( 0 , - m_b / 2 );
252  bbox.Expand( m_l1 , m_b / 2 );
253  return bbox;
254 }
255 
256 void a2dArrow::DoRender( a2dIterC& ic, OVERLAP WXUNUSED( clipparent ) )
257 {
258  a2dVertexArray* cpoints = new a2dVertexArray;
259 
260  cpoints->push_back( new a2dLineSegment( 0, 0 ) );
261  cpoints->push_back( new a2dLineSegment( m_l1, m_b / 2.0 ) );
262  cpoints->push_back( new a2dLineSegment( m_l2, 0 ) );
263  cpoints->push_back( new a2dLineSegment( m_l1, -m_b / 2.0 ) );
264 
265  ic.GetDrawer2D()->DrawPolygon( cpoints, m_spline, wxWINDING_RULE );
266 
267  cpoints->clear();
268  delete cpoints;
269 }
270 
272 {
273  a2dVertexArray points;
274  points.push_back( new a2dLineSegment( 0, 0 ) );
275  points.push_back( new a2dLineSegment( m_l1, m_b / 2.0 ) );
276  points.push_back( new a2dLineSegment( m_l2, 0 ) );
277  points.push_back( new a2dLineSegment( m_l1, -m_b / 2.0 ) );
278 
279  a2dPoint2D P = a2dPoint2D( hitEvent.m_relx, hitEvent.m_rely );
280  hitEvent.m_how = points.HitTestPolygon( P, ic.GetWorldStrokeExtend() + ic.GetTransformedHitMargin() );
281 
282  return hitEvent.m_how.IsHit();
283 }
284 
285 #if wxART2D_USE_CVGIO
286 void a2dArrow::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut& out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
287 {
288  a2dCanvasObject::DoSave( parent, out, xmlparts, towrite );
289  if ( xmlparts == a2dXmlSer_attrib )
290  {
291  out.WriteAttribute( wxT( "l1" ), m_l1 * out.GetScale() );
292  out.WriteAttribute( wxT( "l2" ), m_l2 * out.GetScale() );
293  out.WriteAttribute( wxT( "b" ), m_b * out.GetScale() );
294  out.WriteAttribute( wxT( "spline" ), m_spline );
295  }
296  else
297  {
298  }
299 }
300 
301 void a2dArrow::DoLoad( wxObject* parent, a2dIOHandlerXmlSerIn& parser, a2dXmlSer_flag xmlparts )
302 {
303  a2dCanvasObject::DoLoad( parent, parser, xmlparts );
304  if ( xmlparts == a2dXmlSer_attrib )
305  {
306  m_l1 = parser.RequireAttributeValueDouble( wxT( "l1" ) ) * parser.GetScale() ;
307  m_l2 = parser.RequireAttributeValueDouble( wxT( "l2" ) ) * parser.GetScale() ;
308  m_b = parser.GetAttributeValueDouble( wxT( "b" ) ) * parser.GetScale() ;
309  m_spline = parser.GetAttributeValueBool( wxT( "spline" ) );
310  }
311  else
312  {
313  }
314 }
315 #endif //wxART2D_USE_CVGIO
316 
317 //----------------------------------------------------------------------------
318 // a2dRectC
319 //----------------------------------------------------------------------------
320 
321 a2dPropertyIdDouble* a2dRectC::PROPID_Width = NULL;
322 a2dPropertyIdDouble* a2dRectC::PROPID_Height = NULL;
323 a2dPropertyIdDouble* a2dRectC::PROPID_Radius = NULL;
324 
325 INITIALIZE_PROPERTIES( a2dRectC, a2dCanvasObject )
326 {
327  PROPID_Width = new a2dPropertyIdDouble( wxT( "Width" ),
328  a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dRectC::m_width ) );
329  AddPropertyId( PROPID_Width );
330  PROPID_Height = new a2dPropertyIdDouble( wxT( "Height" ),
331  a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dRectC::m_height ) );
332  AddPropertyId( PROPID_Height );
333  PROPID_Radius = new a2dPropertyIdDouble( wxT( "Radius" ),
334  a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dRectC::m_radius ) );
335  AddPropertyId( PROPID_Radius );
336 
337  return true;
338 }
339 
340 
342  : a2dCanvasObject()
343 {
344  m_width = 10;
345  m_height = 10;
346  m_radius = 0;
347 }
348 
349 a2dRectC::a2dRectC( double xc, double yc, double w, double h, double angle, double radius )
350  : a2dCanvasObject()
351 {
352  Rotate( angle );
353  m_lworld.Translate( xc, yc );
354  m_width = w;
355  m_height = h;
356  m_radius = radius;
357 }
358 
360 {
361 }
362 
363 a2dRectC::a2dRectC( const a2dRectC& other, CloneOptions options, a2dRefMap* refs )
364  : a2dCanvasObject( other, options, refs )
365 {
366  m_width = other.m_width;
367  m_height = other.m_height;
368  m_radius = other.m_radius;
369 }
370 
371 void a2dRectC::Set( double xc, double yc, double w, double h, double angle , double radius )
372 {
373  SetRotation( angle );
374  SetPosXY( xc, yc );
375  m_width = w;
376  m_height = h;
377  m_radius = radius;
378  SetPending( true );
379 }
380 
381 
383 {
384  return new a2dRectC( *this, options, refs );
385 };
386 
387 a2dVertexList* a2dRectC::GetAsVertexList( bool& returnIsPolygon ) const
388 {
389  returnIsPolygon = true;
390  a2dVertexList* pointlist = new a2dVertexList();
391 
392  a2dCanvasObjectList* vectorpaths = GetAsCanvasVpaths();
393  a2dVpath* segments = wxStaticCast( vectorpaths->front().Get(), a2dVectorPath ) ->GetSegments();
394  segments->ConvertToLines();
395  a2dLineSegment* point;
396  unsigned int i;
397  for ( i = 0; i < segments->size(); i++ )
398  {
399  a2dVpathSegment* seg = segments->Item( i );
400  point = new a2dLineSegment( seg->m_x1, seg->m_y1 );
401  pointlist->push_back( point );
402  }
403 
404  delete vectorpaths;
405  return pointlist;
406 }
407 
409 {
410  a2dAffineMatrix pworld;
411  if ( transform )
412  pworld = m_lworld;
413 
414  a2dVpath* segments = new a2dVpath();
415 
416  double w2 = fabs( m_width / 2 );
417  double h2 = fabs( m_height / 2 );
418 
419  if ( m_radius && m_width && m_height )
420  {
421 
422  if ( m_radius < 0 )
423  {
424  double rx = -m_radius;
425  if ( m_width < 0 )
426  rx = -rx;
427 
428  double ry = -m_radius;
429  if ( m_height < 0 )
430  ry = -ry;
431 
432  a2dVpathSegment* seg = new a2dVpathSegment( rx, 0 , a2dPATHSEG_MOVETO );
433  segments->push_back( seg );
434 
435  seg = new a2dVpathArcSegment( seg, rx, ry, 0.0, ry, 0.0, 0.0, a2dPATHSEG_ARCTO );
436  segments->push_back( seg );
437  seg = new a2dVpathSegment( 0, m_height - ry, a2dPATHSEG_LINETO );
438  segments->push_back( seg );
439 
440  seg = new a2dVpathArcSegment( seg, rx, m_height - ry, rx, m_height, 0.0, m_height, a2dPATHSEG_ARCTO );
441  segments->push_back( seg );
443  segments->push_back( seg );
444 
445  seg = new a2dVpathArcSegment( seg, m_width - rx, m_height - ry, m_width, m_height - ry, m_width, m_height, a2dPATHSEG_ARCTO );
446  segments->push_back( seg );
447  seg = new a2dVpathSegment( m_width, ry, a2dPATHSEG_LINETO );
448  segments->push_back( seg );
449 
450  seg = new a2dVpathArcSegment( seg, m_width - rx, ry, m_width - rx, 0.0, m_width, 0.0, a2dPATHSEG_ARCTO, a2dPATHSEG_END_CLOSED );
451  segments->push_back( seg );
452 
453  a2dAffineMatrix world;
454  world.Translate( -w2, -h2 );
455  world *= pworld;
456  segments->Transform( world );
457  }
458  else
459  {
460  double rx = m_radius;
461  if ( m_width < 0 )
462  rx = -rx;
463 
464  double ry = m_radius;
465  if ( m_height < 0 )
466  ry = -ry;
467 
468  a2dVpathSegment* seg = new a2dVpathSegment( 0.0, -ry , a2dPATHSEG_MOVETO );
469  segments->push_back( seg );
470 
471  seg = new a2dVpathArcSegment( seg, 0.0, 0.0, -rx, 0.0, -rx, -ry, a2dPATHSEG_ARCTO );
472  segments->push_back( seg );
473  seg = new a2dVpathSegment( -rx, m_height, a2dPATHSEG_LINETO );
474  segments->push_back( seg );
475 
476  seg = new a2dVpathArcSegment( seg, 0.0, m_height, 0.0, m_height + ry, -rx, m_height + ry, a2dPATHSEG_ARCTO );
477  segments->push_back( seg );
479  segments->push_back( seg );
480 
481  seg = new a2dVpathArcSegment( seg, m_width, m_height, m_width + rx, m_height, m_width + rx, m_height + ry, a2dPATHSEG_ARCTO );
482  segments->push_back( seg );
483  seg = new a2dVpathSegment( m_width + rx, 0.0, a2dPATHSEG_LINETO );
484  segments->push_back( seg );
485 
486  seg = new a2dVpathArcSegment( seg, m_width, 0.0, m_width, -ry, m_width + rx, -ry, a2dPATHSEG_ARCTO, a2dPATHSEG_END_CLOSED );
487  segments->push_back( seg );
488 
489  a2dAffineMatrix world;
490  world.Translate( -w2, -h2 );
491  world *= pworld;
492  segments->Transform( world );
493  }
494  }
495  else
496  {
497  double x, y;
498  pworld.TransformPoint( -w2 , -h2, x, y );
500  segments->push_back( seg );
501  pworld.TransformPoint( -w2 , +h2, x, y );
502  seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
503  segments->push_back( seg );
504  pworld.TransformPoint( +w2 , +h2, x, y );
505  seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
506  segments->push_back( seg );
507  pworld.TransformPoint( +w2 , -h2, x, y );
509  segments->push_back( seg );
510  }
511 
512  a2dVectorPath* canpath = new a2dVectorPath( segments );
513  canpath->SetStroke( this->GetStroke() );
514  canpath->SetFill( this->GetFill() );
515  canpath->SetLayer( m_layer );
516  canpath->SetContourWidth( GetContourWidth() );
517  a2dCanvasObjectList* canpathlist = new a2dCanvasObjectList();
518  canpathlist->push_back( canpath );
519  return canpathlist;
520 }
521 
522 
523 
524 a2dBoundingBox a2dRectC::DoGetUnTransformedBbox( a2dBboxFlags WXUNUSED( flags ) ) const
525 {
526  a2dBoundingBox bbox;
527  bbox.Expand( - fabs( m_width / 2 ) , - fabs( m_height / 2 ) );
528  bbox.Expand( + fabs( m_width / 2 ) , + fabs( m_height / 2 ) );
529  if ( m_radius > 0 )
530  bbox.Enlarge( m_radius );
531  return bbox;
532 }
533 
534 void a2dRectC::DoRender( a2dIterC& ic, OVERLAP WXUNUSED( clipparent ) )
535 {
536  if ( m_radius <= 0 )
537  {
539  }
540  else
541  {
543  }
544 }
545 
547 {
548  double margin = ic.GetTransformedHitMargin();
549 
550  double xmax = fabs( m_width / 2 );
551  double ymax = fabs( m_height / 2 );
552  double xmin = -xmax;
553  double ymin = -ymax;
554 
555  if ( m_radius > 0 )
556  {
557  xmin -= m_radius;
558  ymin -= m_radius;
559  xmax += m_radius;
560  ymax += m_radius;
561  }
562 
563  hitEvent.m_how = HitTestRectangle( hitEvent.m_relx, hitEvent.m_rely, xmin, ymin, xmax, ymax, ic.GetWorldStrokeExtend() + margin );
564 
565  return hitEvent.m_how.IsHit();
566 }
567 
568 #if wxART2D_USE_CVGIO
569 void a2dRectC::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut& out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
570 {
571  a2dCanvasObject::DoSave( parent, out, xmlparts, towrite );
572  if ( xmlparts == a2dXmlSer_attrib )
573  {
574  out.WriteAttribute( wxT( "width" ), m_width * out.GetScale() );
575  out.WriteAttribute( wxT( "height" ), m_height * out.GetScale() );
576  if ( m_radius != 0.0 )
577  {
578  out.WriteAttribute( wxT( "radius" ), m_radius );
579  }
580  }
581  else
582  {
583  }
584 }
585 #endif //wxART2D_USE_CVGIO
586 
587 
588 //----------------------------------------------------------------------------
589 // a2dWH
590 //----------------------------------------------------------------------------
591 
594 
595 INITIALIZE_PROPERTIES( a2dWH, a2dCanvasObject )
596 {
597  PROPID_Width = new a2dPropertyIdDouble( wxT( "Width" ),
598  a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dWH::m_width ) );
599  AddPropertyId( PROPID_Width );
600  PROPID_Height = new a2dPropertyIdDouble( wxT( "Height" ),
601  a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dWH::m_height ) );
602  AddPropertyId( PROPID_Height );
603 
604  return true;
605 }
606 
607 
608 
609 BEGIN_EVENT_TABLE( a2dWH, a2dCanvasObject )
610  EVT_CANVASHANDLE_MOUSE_EVENT( a2dWH::OnHandleEvent )
611  EVT_CANVASOBJECT_RESIZE_EVENT( a2dWH::OnResizeObjectToChildBox )
612 END_EVENT_TABLE()
613 
615  : a2dCanvasObject()
616 {
617  m_width = 0;
618  m_height = 0;
619 }
620 
621 a2dWH::a2dWH( double x, double y, double w, double h )
622  : a2dCanvasObject()
623 {
624  m_lworld.Translate( x, y );
625  m_width = w;
626  m_height = h;
627 }
628 
629 a2dWH::a2dWH( const a2dWH& other, CloneOptions options, a2dRefMap* refs )
630  : a2dCanvasObject( other, options, refs )
631 {
632  m_width = other.m_width;
633  m_height = other.m_height;
634 }
635 
637 {
638 }
639 
641 {
642  a2dAffineMatrix pworld;
643  if ( transform )
644  pworld = m_lworld;
645 
646  a2dVpath* segments = new a2dVpath();
647  a2dVectorPath* canpath = new a2dVectorPath( segments );
648  canpath->SetStroke( this->GetStroke() );
649  canpath->SetFill( this->GetFill() );
650  canpath->SetLayer( m_layer );
651 
652  double x, y;
653  pworld.TransformPoint( 0, 0, x, y );
655  segments->push_back( seg );
656  pworld.TransformPoint( 0 , m_height, x, y );
657  seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
658  segments->push_back( seg );
659  pworld.TransformPoint( m_width , m_height, x, y );
660  seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
661  segments->push_back( seg );
662  pworld.TransformPoint( m_width , 0, x, y );
664  segments->push_back( seg );
665 
666  a2dCanvasObjectList* canpathlist = new a2dCanvasObjectList();
667  canpathlist->push_back( canpath );
668  return canpathlist;
669 }
670 
671 bool a2dWH::RestrictToObject( a2dIterC& ic, const a2dPoint2D& pointToSnapTo, a2dPoint2D& bestPointSofar, a2dSnapToWhatMask snapToWhat, double thresHoldWorld )
672 {
673  // object has disabled snap?
674  if ( !m_flags.m_snap_to )
675  return false;
676 
677  bool res = false;
678  if ( !res )
679  res = a2dCanvasObject::RestrictToObject( ic, pointToSnapTo, bestPointSofar, snapToWhat, thresHoldWorld );
680 
681  return res;
682 }
683 
684 a2dBoundingBox a2dWH::DoGetUnTransformedBbox( a2dBboxFlags WXUNUSED( flags ) ) const
685 {
686  a2dBoundingBox bbox;
687  bbox.Expand( 0, 0 );
688  bbox.Expand( m_width , m_height );
689  return bbox;
690 }
691 
692 #if wxART2D_USE_CVGIO
693 
694 void a2dWH::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut& out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
695 {
696  a2dCanvasObject::DoSave( parent, out, xmlparts, towrite );
697  if ( xmlparts == a2dXmlSer_attrib )
698  {
699  out.WriteAttribute( wxT( "width" ), m_width * out.GetScale() );
700  out.WriteAttribute( wxT( "height" ), m_height * out.GetScale() );
701  }
702  else
703  {
704  }
705 }
706 
707 void a2dWH::DoLoad( wxObject* parent, a2dIOHandlerXmlSerIn& parser, a2dXmlSer_flag xmlparts )
708 {
709  a2dCanvasObject::DoLoad( parent, parser, xmlparts );
710  if ( xmlparts == a2dXmlSer_attrib )
711  {
712  m_width = parser.RequireAttributeValueDouble( wxT( "width" ) ) * parser.GetScale();
713  m_height = parser.RequireAttributeValueDouble( wxT( "height" ) ) * parser.GetScale();
714  }
715  else
716  {
717  }
718 }
719 #endif //wxART2D_USE_CVGIO
720 
722 {
723  double margin = ic.GetTransformedHitMargin();
724 
725  double xmin = wxMin( 0 , m_width );
726  double ymin = wxMin( 0 , m_height );
727  double xmax = wxMax( 0 , m_width );
728  double ymax = wxMax( 0 , m_height );
729 
730  hitEvent.m_how = HitTestRectangle( hitEvent.m_relx, hitEvent.m_rely, xmin, ymin, xmax, ymax, ic.GetWorldStrokeExtend() + margin );
731 
732  return hitEvent.m_how.IsHit();
733 }
734 
735 bool a2dWH::DoStartEdit( wxUint16 editmode, wxEditStyle editstyle )
736 {
737  PROPID_IncludeChildren->SetPropertyToObject( this, false );
738  PROPID_Allowrotation->SetPropertyToObject( this, true );
739  PROPID_Allowskew->SetPropertyToObject( this, true );
740 
741  return a2dCanvasObject::DoStartEdit( editmode, editstyle );
742 }
743 
744 void a2dWH::OnHandleEvent( a2dHandleMouseEvent& event )
745 {
746  a2dIterC* ic = event.GetIterC();
747 
748  if ( m_flags.m_editingCopy )
749  {
750  a2dRestrictionEngine* restrictEngine = GetHabitat()->GetRestrictionEngine();
751 
752  a2dHandle* draghandle = event.GetCanvasHandle();
753 
754  wxUint16 editmode = PROPID_Editmode->GetPropertyValue( this );
755 
756  if ( editmode == 1 )
757  {
758  double xw, yw;
759  xw = event.GetX();
760  yw = event.GetY();
761 
762  a2dAffineMatrix atWorld = ic->GetTransform();
763  a2dAffineMatrix inverse = ic->GetInverseTransform();
764 
765  double xwi;
766  double ywi;
767  inverse.TransformPoint( xw, yw, xwi, ywi );
768 
769  a2dWH* original = wxStaticCast( PROPID_Original->GetPropertyValue( this ).Get(), a2dWH );
770 
772 
773  double xmin, ymin, xmax, ymax, w, h;
774  xmin = untrans.GetMinX();
775  ymin = untrans.GetMinY();
776  xmax = untrans.GetMaxX();
777  ymax = untrans.GetMaxY();
778  w = untrans.GetWidth();
779  h = untrans.GetHeight();
780 
781  a2dAffineMatrix origworld = m_lworld;
782  double x1, y1, x2, y2;
783 
784  if ( event.GetMouseEvent().LeftDown() )
785  {
786  }
787  else if ( event.GetMouseEvent().LeftUp() )
788  {
789  m_root->GetCommandProcessor()->Submit( new a2dCommand_SetCanvasProperty( original, PROPID_TransformMatrix, m_lworld ) );
790  }
791  else if ( event.GetMouseEvent().Dragging() )
792  {
793  if ( restrictEngine )
794  restrictEngine->RestrictPoint( xw, yw );
795  ic->GetInverseTransform().TransformPoint( xw, yw, xwi, ywi );
796 
797  if ( draghandle->GetName() == wxT( "handle1" ) )
798  {
799  //modify object
800  double dx, dy;
801  dx = xwi - xmin;
802  dy = ywi - ymin;
803 
804  double sx;
805  double sy;
806  if ( w )
807  sx = ( w - dx / 2 ) / w;
808  else
809  sx = 0;
810  if ( h )
811  sy = ( h - dy / 2 ) / h;
812  else
813  sy = 0;
814 
815  origworld.TransformPoint( xmax, ymax, x2, y2 );
816 
817  //reset matrix to identity
819  Scale( sx, sy );
820  Transform( origworld );
821  m_lworld.TransformPoint( xmax, ymax, x1, y1 );
822  Translate( x2 - x1, y2 - y1 );
823  }
824  else if ( draghandle->GetName() == wxT( "handle2" ) )
825  {
826  //modify object
827  double dx, dy;
828  dx = xwi - xmin;
829  dy = ywi - ymax;
830 
831  double sx;
832  double sy;
833  if ( w )
834  sx = ( w - dx / 2 ) / w;
835  else
836  sx = 0;
837  if ( h )
838  sy = ( h + dy / 2 ) / h;
839  else
840  sy = 0;
841 
842  origworld.TransformPoint( xmax, ymin, x2, y2 );
843 
844  //reset matrix to identity
846  Scale( sx, sy );
847  Transform( origworld );
848  m_lworld.TransformPoint( xmax, ymin, x1, y1 );
849  Translate( x2 - x1, y2 - y1 );
850  }
851  else if ( draghandle->GetName() == wxT( "handle3" ) )
852  {
853  //modify object
854  double dx, dy;
855 
856  dx = xwi - xmax;
857  dy = ywi - ymax;
858 
859  double sx;
860  double sy;
861  if ( w )
862  sx = ( w + dx / 2 ) / w;
863  else
864  sx = 0;
865  if ( h )
866  sy = ( h + dy / 2 ) / h;
867  else
868  sy = 0;
869 
870  origworld.TransformPoint( xmin, ymin, x2, y2 );
871 
872  //reset matrix to identity
874  Scale( sx, sy );
875  Transform( origworld );
876  m_lworld.TransformPoint( xmin, ymin, x1, y1 );
877  Translate( x2 - x1, y2 - y1 );
878  }
879  else if ( draghandle->GetName() == wxT( "handle4" ) )
880  {
881  //modify object
882  double dx, dy;
883 
884  dx = xwi - xmax;
885  dy = ywi - ymin;
886 
887  double sx;
888  double sy;
889  if ( w )
890  sx = ( w + dx / 2 ) / w;
891  else
892  sx = 0;
893  if ( h )
894  sy = ( h - dy / 2 ) / h;
895  else
896  sy = 0;
897 
898  origworld.TransformPoint( xmin, ymax, x2, y2 );
899 
900  //reset matrix to identity
902  Scale( sx, sy );
903  Transform( origworld );
904  m_lworld.TransformPoint( xmin, ymax, x1, y1 );
905  Translate( x2 - x1, y2 - y1 );
906  }
907  else if ( draghandle->GetName() == wxT( "rotate" ) )
908  {
909  double xr, yr;
910  m_lworld.TransformPoint( xmin + w / 2, ymin + h / 2, xr, yr );
911 
912  //modify object
913  double dx, dy;
914 
915  dx = xw - xr;
916  dy = yw - yr;
917  double angn;
918  if ( !dx && !dy )
919  angn = 0;
920  else
921  angn = wxRadToDeg( atan2( dy, dx ) );
922 
923  m_lworld = m_lworld.Rotate( angn - m_lworld.GetRotation(), xr, yr );
924 
925  //rotate.Translate( xr, yr);
926  //rotate.Rotate(wxRadToDeg(-ang));
927  //rotate.Translate( xr, yr);
928  //Transform(rotate);
929  }
930  else if ( draghandle->GetName() == wxT( "skewx" ) )
931  {
932  //modify object
933  double dx, dy;
934 
935  dx = xwi - ( xmin + w * 3 / 4 );
936  dy = ywi - ( ymin + h / 2 );
937 
938  origworld.TransformPoint( xmin + w / 2, ymin + h / 2, x2, y2 );
939 
940  //reset matrix to identity
942  SkewX( wxRadToDeg( atan2( dx, dy ) ) );
943  Transform( origworld );
944  m_lworld.TransformPoint( xmin + w / 2, ymin + h / 2, x1, y1 );
945  Translate( x2 - x1, y2 - y1 );
946  }
947  else if ( draghandle->GetName() == wxT( "skewy" ) )
948  {
949  //modify object
950  double dx, dy;
951 
952  dx = xwi - ( xmin + w / 2 );
953  dy = ywi - ( ymin + h * 3 / 4 );
954 
955  origworld.TransformPoint( xmin + w / 2, ymin + h / 2, x2, y2 );
956 
957  //reset matrix to identity
959  SkewY( wxRadToDeg( atan2( dy, dx ) ) );
960  Transform( origworld );
961  m_lworld.TransformPoint( xmin + w / 2, ymin + h / 2, x1, y1 );
962  Translate( x2 - x1, y2 - y1 );
963  }
964  else if ( draghandle->GetName() == wxT( "handle12" ) )
965  {
966  //modify object
967  double dx;
968 
969  dx = xwi - xmin;
970 
971  double sx;
972  if ( w )
973  sx = ( w - dx / 2 ) / w;
974  else
975  sx = 0;
976 
977  origworld.TransformPoint( xmax, ymax, x2, y2 );
978 
979  //reset matrix to identity
981  Scale( sx, 1 );
982  Transform( origworld );
983  m_lworld.TransformPoint( xmax, ymax, x1, y1 );
984  Translate( x2 - x1, y2 - y1 );
985  }
986  else if ( draghandle->GetName() == wxT( "handle23" ) )
987  {
988  //modify object
989  double dy;
990 
991  dy = ywi - ymax;
992 
993  double sy;
994  if ( h )
995  sy = ( h + dy / 2 ) / h;
996  else
997  sy = 0;
998 
999  origworld.TransformPoint( xmax, ymin, x2, y2 );
1000 
1001  //reset matrix to identity
1003  Scale( 1, sy );
1004  Transform( origworld );
1005  m_lworld.TransformPoint( xmax, ymin, x1, y1 );
1006  Translate( x2 - x1, y2 - y1 );
1007  }
1008  else if ( draghandle->GetName() == wxT( "handle34" ) )
1009  {
1010  //modify object
1011  double dx;
1012 
1013  dx = xwi - xmax;
1014 
1015  double sx;
1016  if ( w )
1017  sx = ( w + dx / 2 ) / w;
1018  else
1019  sx = 0;
1020 
1021  origworld.TransformPoint( xmin, ymin, x2, y2 );
1022 
1023  //reset matrix to identity
1025  Scale( sx, 1 );
1026  Transform( origworld );
1027  m_lworld.TransformPoint( xmin, ymin, x1, y1 );
1028  Translate( x2 - x1, y2 - y1 );
1029  }
1030  else if ( draghandle->GetName() == wxT( "handle41" ) )
1031  {
1032  //modify object
1033  double dy;
1034 
1035  dy = ywi - ymin;
1036 
1037  double sy;
1038  if ( h )
1039  sy = ( h - dy / 2 ) / h;
1040  else
1041  sy = 0;
1042 
1043  origworld.TransformPoint( xmin, ymax, x2, y2 );
1044 
1045  //reset matrix to identity
1047  Scale( 1, sy );
1048  Transform( origworld );
1049  m_lworld.TransformPoint( xmin, ymax, x1, y1 );
1050  Translate( x2 - x1, y2 - y1 );
1051  }
1052  else
1053  event.Skip();
1054  SetPending( true );
1055  }
1056  }
1057  else
1058  event.Skip();
1059  }
1060  else
1061  {
1062  event.Skip();
1063  }
1064 }
1065 
1066 void a2dWH::OnResizeObjectToChildBox( a2dCanvasObjectEvent& event )
1067 {
1068  a2dBoundingBox box = event.GetBbox();
1069  SetPosXY( box.GetMinX(), box.GetMinY() );
1070  SetWidth( box.GetWidth() );
1071  SetHeight( -box.GetHeight() );
1072  SetPending( false );
1073 }
1074 
1075 bool a2dWH::DoUpdate( UpdateMode mode, const a2dBoundingBox& childbox, const a2dBoundingBox& clipbox, const a2dBoundingBox& propbox )
1076 {
1077  bool calc = false;
1078  if ( !m_bbox.GetValid() )
1079  {
1080  calc = a2dCanvasObject::DoUpdate( mode, childbox, clipbox, propbox );
1081  }
1082  return calc;
1083 }
1084 
1085 //----------------------------------------------------------------------------
1086 // a2dWHCenter
1087 //----------------------------------------------------------------------------
1088 
1089 a2dPropertyIdDouble* a2dWHCenter::PROPID_Width = NULL;
1090 a2dPropertyIdDouble* a2dWHCenter::PROPID_Height = NULL;
1091 
1092 INITIALIZE_PROPERTIES( a2dWHCenter, a2dWH )
1093 {
1094  PROPID_Width = new a2dPropertyIdDouble( wxT( "Width" ),
1095  a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dWHCenter::m_width ) );
1096  AddPropertyId( PROPID_Width );
1097  PROPID_Height = new a2dPropertyIdDouble( wxT( "Height" ),
1098  a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dWHCenter::m_height ) );
1099  AddPropertyId( PROPID_Height );
1100 
1101  return true;
1102 }
1103 
1104 BEGIN_EVENT_TABLE( a2dWHCenter, a2dWH )
1105 END_EVENT_TABLE()
1106 
1108  : a2dWH()
1109 {
1110 }
1111 
1112 a2dWHCenter::a2dWHCenter( double xc, double yc, double w, double h )
1113  : a2dWH( xc, yc, w, h )
1114 {
1115 }
1116 
1118  : a2dWH( other, options, refs )
1119 {
1120 }
1121 
1123 {
1124 }
1125 
1126 //----------------------------------------------------------------------------
1127 // a2dRect
1128 //----------------------------------------------------------------------------
1129 
1130 a2dPropertyIdDouble* a2dRect::PROPID_Radius = NULL;
1131 
1132 INITIALIZE_PROPERTIES( a2dRect, a2dWH )
1133 {
1134  PROPID_Radius = new a2dPropertyIdDouble( wxT( "Radius" ),
1135  a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dRect::m_radius ) );
1136  AddPropertyId( PROPID_Radius );
1137 
1138  return true;
1139 }
1140 
1141 BEGIN_EVENT_TABLE( a2dRect, a2dWH )
1142  EVT_CANVASHANDLE_MOUSE_EVENT( a2dRect::OnHandleEvent )
1143 END_EVENT_TABLE()
1144 
1145 a2dRect::a2dRect()
1146  : a2dWH()
1147 {
1148  m_radius = 0;
1149  m_contourwidth = 0;
1150 }
1151 
1152 a2dRect::a2dRect( double x, double y, double w, double h , double radius, double contourwidth )
1153  : a2dWH( x, y, w, h )
1154 {
1155  m_radius = radius;
1156  m_contourwidth = contourwidth;
1157 }
1158 
1159 a2dRect::a2dRect( const a2dPoint2D& p1, const a2dPoint2D& p2, double radius, double contourwidth )
1160  : a2dWH( p1.m_x, p1.m_y, p2.m_x - p1.m_x, p2.m_y - p1.m_y )
1161 {
1162  m_radius = radius;
1163  m_contourwidth = contourwidth;
1164 }
1165 
1166 a2dRect::a2dRect( const a2dBoundingBox& bbox, double radius, double contourwidth )
1167  : a2dWH( bbox.GetMinX(), bbox.GetMinY(), bbox.GetWidth(), bbox.GetHeight() )
1168 {
1169  m_radius = radius;
1170  m_contourwidth = contourwidth;
1171 }
1172 
1173 a2dRect::~a2dRect()
1174 {
1175 }
1176 
1177 a2dRect::a2dRect( const a2dRect& other, CloneOptions options, a2dRefMap* refs )
1178  : a2dWH( other, options, refs )
1179 {
1180  m_radius = other.m_radius;
1182 }
1183 
1185 {
1186  return new a2dRect( *this, options, refs );
1187 };
1188 
1189 a2dVertexList* a2dRect::GetAsVertexList( bool& returnIsPolygon ) const
1190 {
1191  returnIsPolygon = true;
1192  a2dVertexList* pointlist = new a2dVertexList();
1193 
1194  a2dCanvasObjectList* vectorpaths = GetAsCanvasVpaths();
1195  a2dVpath* segments = wxStaticCast( vectorpaths->front().Get(), a2dVectorPath ) ->GetSegments();
1196  segments->ConvertToLines();
1197  a2dLineSegment* point;
1198  unsigned int i;
1199  for ( i = 0; i < segments->size(); i++ )
1200  {
1201  a2dVpathSegment* seg = segments->Item( i );
1202  point = new a2dLineSegment( seg->m_x1, seg->m_y1 );
1203  pointlist->push_back( point );
1204  }
1205 
1206  delete vectorpaths;
1207 
1208  return pointlist;
1209 }
1210 
1212 {
1213  a2dAffineMatrix pworld;
1214  if ( transform )
1215  pworld = m_lworld;
1216 
1217  a2dVpath* segments = new a2dVpath();
1218  a2dVectorPath* canpath = new a2dVectorPath( segments );
1219  canpath->SetStroke( this->GetStroke() );
1220  canpath->SetFill( this->GetFill() );
1221  canpath->SetLayer( m_layer );
1222 
1223  if ( m_radius )
1224  {
1225 
1226  if ( m_radius < 0 )
1227  {
1228  double rx = -m_radius;
1229  if ( m_width < 0 )
1230  rx = -rx;
1231 
1232  double ry = -m_radius;
1233  if ( m_height < 0 )
1234  ry = -ry;
1235 
1236  a2dVpathSegment* seg = new a2dVpathSegment( rx, 0 , a2dPATHSEG_MOVETO );
1237  segments->push_back( seg );
1238 
1239  seg = new a2dVpathArcSegment( seg, rx, ry, 0.0, ry, 0.0, 0.0, a2dPATHSEG_ARCTO );
1240  segments->push_back( seg );
1241  seg = new a2dVpathSegment( 0, m_height - ry, a2dPATHSEG_LINETO );
1242  segments->push_back( seg );
1243 
1244  seg = new a2dVpathArcSegment( seg, rx, m_height - ry, rx, m_height, 0.0, m_height, a2dPATHSEG_ARCTO );
1245  segments->push_back( seg );
1246  seg = new a2dVpathSegment( m_width - rx, m_height, a2dPATHSEG_LINETO );
1247  segments->push_back( seg );
1248 
1249  seg = new a2dVpathArcSegment( seg, m_width - rx, m_height - ry, m_width, m_height - ry, m_width, m_height, a2dPATHSEG_ARCTO );
1250  segments->push_back( seg );
1251  seg = new a2dVpathSegment( m_width, ry, a2dPATHSEG_LINETO );
1252  segments->push_back( seg );
1253 
1254  seg = new a2dVpathArcSegment( seg, m_width - rx, ry, m_width - rx, 0.0, m_width, 0.0, a2dPATHSEG_ARCTO, a2dPATHSEG_END_CLOSED );
1255  segments->push_back( seg );
1256 
1257  segments->Transform( pworld );
1258  }
1259  else
1260  {
1261  double rx = m_radius;
1262  if ( m_width < 0 )
1263  rx = -rx;
1264 
1265  double ry = m_radius;
1266  if ( m_height < 0 )
1267  ry = -ry;
1268 
1269  a2dVpathSegment* seg = new a2dVpathSegment( 0.0, -ry , a2dPATHSEG_MOVETO );
1270  segments->push_back( seg );
1271 
1272  seg = new a2dVpathArcSegment( seg, 0.0, 0.0, -rx, 0.0, -rx, -ry, a2dPATHSEG_ARCTO );
1273  segments->push_back( seg );
1274  seg = new a2dVpathSegment( -rx, m_height, a2dPATHSEG_LINETO );
1275  segments->push_back( seg );
1276 
1277  seg = new a2dVpathArcSegment( seg, 0.0, m_height, 0.0, m_height + ry, -rx, m_height + ry, a2dPATHSEG_ARCTO );
1278  segments->push_back( seg );
1279  seg = new a2dVpathSegment( m_width, m_height + ry, a2dPATHSEG_LINETO );
1280  segments->push_back( seg );
1281 
1282  seg = new a2dVpathArcSegment( seg, m_width, m_height, m_width + rx, m_height, m_width + rx, m_height + ry, a2dPATHSEG_ARCTO );
1283  segments->push_back( seg );
1284  seg = new a2dVpathSegment( m_width + rx, 0.0, a2dPATHSEG_LINETO );
1285  segments->push_back( seg );
1286 
1287  seg = new a2dVpathArcSegment( seg, m_width, 0.0, m_width, -ry, m_width + rx, -ry, a2dPATHSEG_ARCTO, a2dPATHSEG_END_CLOSED );
1288  segments->push_back( seg );
1289 
1290  segments->Transform( pworld );
1291  }
1292  canpath->SetContourWidth( GetContourWidth() );
1293  canpath->SetPathType( a2dPATH_END_SQAURE_EXT );
1294  }
1295  else
1296  {
1297  if ( GetContourWidth() )
1298  {
1299  double x, y;
1300  double w = GetContourWidth() / 2.0;
1301  pworld.TransformPoint( -w, -w, x, y );
1302  a2dVpathSegment* seg = new a2dVpathSegment( x, y , a2dPATHSEG_MOVETO );
1303  segments->push_back( seg );
1304  pworld.TransformPoint( -w , m_height + w, x, y );
1305  seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
1306  segments->push_back( seg );
1307  pworld.TransformPoint( m_width + w , m_height + w, x, y );
1308  seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
1309  segments->push_back( seg );
1310  pworld.TransformPoint( m_width + w, -w, x, y );
1311  seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
1312  segments->push_back( seg );
1313  pworld.TransformPoint( -w , -w, x, y );
1314  seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
1315  segments->push_back( seg );
1316  pworld.TransformPoint( w, w, x, y );
1317  seg = new a2dVpathSegment( x, y, a2dPATHSEG_LINETO_NOSTROKE );
1318  segments->push_back( seg );
1319  pworld.TransformPoint( m_width - w, w, x, y );
1320  seg = new a2dVpathSegment( x, y, a2dPATHSEG_LINETO );
1321  segments->push_back( seg );
1322  pworld.TransformPoint( m_width - w, m_height - w, x, y );
1323  seg = new a2dVpathSegment( x, y, a2dPATHSEG_LINETO );
1324  segments->push_back( seg );
1325  pworld.TransformPoint( w, m_height - w, x, y );
1326  seg = new a2dVpathSegment( x, y, a2dPATHSEG_LINETO );
1327  segments->push_back( seg );
1328  pworld.TransformPoint( w, w, x, y );
1329  seg = new a2dVpathSegment( x, y, a2dPATHSEG_LINETO );
1330  segments->push_back( seg );
1331  pworld.TransformPoint( -w, -w, x, y );
1333  segments->push_back( seg );
1334  }
1335  else
1336  {
1337  double x, y;
1338  pworld.TransformPoint( 0, 0, x, y );
1339  a2dVpathSegment* seg = new a2dVpathSegment( x, y , a2dPATHSEG_MOVETO );
1340  segments->push_back( seg );
1341  pworld.TransformPoint( 0 , m_height, x, y );
1342  seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
1343  segments->push_back( seg );
1344  pworld.TransformPoint( m_width , m_height, x, y );
1345  seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
1346  segments->push_back( seg );
1347  pworld.TransformPoint( m_width , 0, x, y );
1349  segments->push_back( seg );
1350  }
1351  }
1352 
1353  a2dCanvasObjectList* canpathlist = new a2dCanvasObjectList();
1354  canpathlist->push_back( canpath );
1355  return canpathlist;
1356 }
1357 
1358 
1359 bool a2dRect::DoStartEdit( wxUint16 editmode, wxEditStyle editstyle )
1360 {
1361  if ( m_flags.m_editable )
1362  {
1363  if ( editmode == 1 )
1364  {
1365  m_flags.m_visiblechilds = true;
1367 
1368  //add properties and handles as children in order to edit the object.
1369  double rx = m_radius;
1370  if ( ( m_radius < 0 && m_width < 0 ) || ( m_radius > 0 && m_width > 0 ) )
1371  rx = -rx;
1372 
1373  a2dHandle* handle = new a2dHandle( this, rx, 0, wxT( "__rounding__" ),
1374  Round( GetHabitat()->GetHandle()->GetWidth() * 1.5 ),
1375  Round( GetHabitat()->GetHandle()->GetHeight() * 1.5 ) );
1376  handle->SetLayer( m_layer );
1377  Append( handle );
1378  handle->SetSpecificFlags( true, a2dCanvasOFlags::BIN2 );
1379 
1380  double radius = m_radius;
1381  m_radius = 0;
1383  double x, y, w, h;
1384  x = untrans.GetMinX();
1385  y = untrans.GetMinY();
1386  w = untrans.GetWidth();
1387  h = untrans.GetHeight();
1388  m_radius = radius;
1389 
1390  a2dRect* around = new a2dRect( x, y, w, h );
1391  around->SetStroke( *wxRED, 0, a2dSTROKE_DOT_DASH );
1392  around->SetFill( *a2dTRANSPARENT_FILL );
1393  around->SetPreRenderAsChild( false );
1394  around->SetSpecificFlags( true, a2dCanvasOFlags::BIN2 );
1395  around->SetHitFlags( a2dCANOBJ_EVENT_NON );
1396  around->SetLayer( m_layer );
1397  Append( around );
1398 
1399  Append( handle = new a2dHandle( this, x, y, wxT( "handle1" ) ) );
1400  handle->SetLayer( m_layer );
1401  Append( handle = new a2dHandle( this, x, y + h, wxT( "handle2" ) ) );
1402  handle->SetLayer( m_layer );
1403  Append( handle = new a2dHandle( this, x + w, y + h , wxT( "handle3" ) ) );
1404  handle->SetLayer( m_layer );
1405  Append( handle = new a2dHandle( this, x + w, y, wxT( "handle4" ) ) );
1406  handle->SetLayer( m_layer );
1407  Append( handle = new a2dHandle( this, x, y + h / 2 , wxT( "handle12" ) ) );
1408  handle->SetLayer( m_layer );
1409  Append( handle = new a2dHandle( this, x + w / 2, y + h, wxT( "handle23" ) ) );
1410  handle->SetLayer( m_layer );
1411  Append( handle = new a2dHandle( this, x + w, y + h / 2 , wxT( "handle34" ) ) );
1412  handle->SetLayer( m_layer );
1413  Append( handle = new a2dHandle( this, x + w / 2, y, wxT( "handle41" ) ) );
1414  handle->SetLayer( m_layer );
1415 
1416  //if ( allowrotation )
1417  {
1418  a2dSLine* rotline = new a2dSLine( x + w / 2, y + h / 2, x + w * 3 / 4, y + h / 2 );
1419  rotline->SetStroke( *wxRED, 0 );
1420  rotline->SetPreRenderAsChild( false );
1421  rotline->SetSpecificFlags( true, a2dCanvasOFlags::BIN2 );
1422  rotline->SetHitFlags( a2dCANOBJ_EVENT_NON );
1423  Append( rotline );
1424  rotline->SetLayer( m_layer );
1425 
1426  Append( handle = new a2dHandle( this, x + w * 3 / 4, y + h / 2, wxT( "rotate" ) ) );
1427  handle->SetLayer( m_layer );
1428  }
1429  //if ( allowskew )
1430  {
1431  Append( handle = new a2dHandle( this, x + w * 3 / 4, y + h, wxT( "skewx" ) ) );
1432  handle->SetLayer( m_layer );
1433  Append( handle = new a2dHandle( this, x + w, y + h * 3 / 4, wxT( "skewy" ) ) );
1434  handle->SetLayer( m_layer );
1435  }
1436 
1437  m_childobjects->SetSpecificFlags( false, a2dCanvasOFlags::PRERENDERASCHILD, wxT( "a2dHandle" ) );
1438  m_childobjects->SetSpecificFlags( true, a2dCanvasOFlags::BIN2, wxT( "a2dHandle" ) );
1439 
1440  //calculate bbox's else mouse events may take place when first idle event is not yet
1441  //processed to do this calculation.
1443  //stil set it pending to do the redraw ( in place )
1444  SetPending( true );
1445  return true;
1446  }
1447  else
1448  {
1449  PROPID_IncludeChildren->SetPropertyToObject( this, false );
1450  PROPID_Allowrotation->SetPropertyToObject( this, true );
1451  PROPID_Allowskew->SetPropertyToObject( this, true );
1452 
1453  return a2dWH::DoStartEdit( editmode, editstyle );
1454  }
1455  }
1456 
1457  return false;
1458 }
1459 
1460 void a2dRect::OnHandleEvent( a2dHandleMouseEvent& event )
1461 {
1462  a2dIterC* ic = event.GetIterC();
1463 
1464  if ( m_flags.m_editingCopy )
1465  {
1466  a2dHandle* draghandle = event.GetCanvasHandle();
1467 
1468  wxUint16 editmode = PROPID_Editmode->GetPropertyValue( this );
1469 
1470  if ( editmode == 1 )
1471  {
1472  double xw, yw;
1473  xw = event.GetX();
1474  yw = event.GetY();
1475 
1476  a2dAffineMatrix atWorld = ic->GetTransform();
1477  a2dAffineMatrix inverse = ic->GetInverseTransform();
1478 
1479  double xwi;
1480  double ywi;
1481  inverse.TransformPoint( xw, yw, xwi, ywi );
1482 
1483  a2dRect* original = wxStaticCast( PROPID_Original->GetPropertyValue( this ).Get(), a2dRect );
1484 
1485  double radius = m_radius;
1486  m_radius = 0;
1488 
1489  double xmin, ymin, xmax, ymax, w, h;
1490  xmin = untrans.GetMinX();
1491  ymin = untrans.GetMinY();
1492  xmax = untrans.GetMaxX();
1493  ymax = untrans.GetMaxY();
1494  w = untrans.GetWidth();
1495  h = untrans.GetHeight();
1496  m_radius = radius;
1497 
1498  if ( event.GetMouseEvent().LeftDown() )
1499  {
1500  }
1501  else if ( event.GetMouseEvent().LeftUp() )
1502  {
1503  if ( draghandle->GetName() == wxT( "__rounding__" ) )
1504  {
1505  original->SetRadius( m_radius );
1506  }
1507  else
1508  event.Skip();
1509  }
1510  else if ( event.GetMouseEvent().Dragging() )
1511  {
1512  if ( draghandle->GetName() == wxT( "__rounding__" ) )
1513  {
1514  //assume outward
1515  if ( ( m_width < 0 && xwi < 0 ) || ( m_width > 0 && xwi > 0 ) )
1516  {
1517  //inward
1518  if ( fabs( xwi ) < fabs( m_width / 2 ) && fabs( xwi ) < fabs( m_height / 2 ) )
1519  {
1520  m_radius = -fabs( xwi );
1521  draghandle->SetPosXY( xwi, 0 );
1522  SetPending( true );
1523  }
1524  }
1525  else
1526  {
1527  m_radius = fabs( xwi );
1528  draghandle->SetPosXY( xwi, 0 );
1529  SetPending( true );
1530  }
1531  }
1532  else
1533  event.Skip();
1534  SetPending( true );
1535  }
1536  }
1537  else
1538  {
1539  event.Skip();
1540  }
1541  }
1542  else
1543  {
1544  event.Skip();
1545  }
1546 }
1547 
1549 {
1550  a2dBoundingBox bbox;
1551  bbox.Expand( 0, 0 );
1552  bbox.Expand( m_width , m_height );
1553 
1554  if ( !( flags & a2dCANOBJ_BBOX_EDIT ) )
1555  {
1556  if ( m_radius > 0 )
1557  bbox.Enlarge( m_radius );
1558 
1559  if ( m_contourwidth > 0 )
1560  bbox.Enlarge( m_contourwidth / 2 );
1561  }
1562  return bbox;
1563 }
1564 
1565 void a2dRect::DoRender( a2dIterC& ic, OVERLAP clipparent )
1566 {
1567  if ( m_contourwidth )
1568  {
1569  a2dCanvasObjectList* vectorpaths = GetAsCanvasVpaths( false );
1570 
1571  forEachIn( a2dCanvasObjectList, vectorpaths )
1572  {
1573  a2dVectorPath* obj = wxStaticCast( ( *iter ).Get(), a2dVectorPath );
1574  obj->DoRender( ic, clipparent );
1575  }
1576  delete vectorpaths;
1577  }
1578  else
1579  {
1580  if ( m_radius <= 0 )
1581  {
1582  if ( m_flags.m_editingCopy )
1584  else
1586  }
1587  else
1588  {
1590  }
1591  }
1592 }
1593 
1594 #if wxART2D_USE_CVGIO
1595 
1596 void a2dRect::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut& out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
1597 {
1598  a2dWH::DoSave( parent, out, xmlparts, towrite );
1599  if ( xmlparts == a2dXmlSer_attrib )
1600  {
1601  if ( m_radius != 0.0 )
1602  {
1603  out.WriteAttribute( wxT( "radius" ), m_radius * out.GetScale() );
1604  out.WriteAttribute( wxT( "contourwidth" ), m_contourwidth * out.GetScale() );
1605  }
1606  }
1607  else
1608  {
1609  }
1610 }
1611 
1612 void a2dRect::DoLoad( wxObject* parent, a2dIOHandlerXmlSerIn& parser, a2dXmlSer_flag xmlparts )
1613 {
1614  a2dWH::DoLoad( parent, parser, xmlparts );
1615  if ( xmlparts == a2dXmlSer_attrib )
1616  {
1617  m_radius = parser.GetAttributeValueDouble( wxT( "radius" ) );
1618  m_contourwidth = parser.GetAttributeValueDouble( wxT( "contourwidth" ), 0 );
1619  }
1620  else
1621  {
1622  }
1623 }
1624 #endif //wxART2D_USE_CVGIO
1625 
1627 {
1628  double margin = fabs( ic.GetTransformedHitMargin() );
1629 
1630  double xmin = wxMin( 0 , m_width );
1631  double ymin = wxMin( 0 , m_height );
1632  double xmax = wxMax( 0 , m_width );
1633  double ymax = wxMax( 0 , m_height );
1634 
1635  if ( m_radius > 0 )
1636  {
1637  xmin -= m_radius;
1638  ymin -= m_radius;
1639  xmax += m_radius;
1640  ymax += m_radius;
1641  }
1642 
1643  hitEvent.m_how = HitTestRectangle( hitEvent.m_relx, hitEvent.m_rely, xmin, ymin, xmax, ymax, ic.GetWorldStrokeExtend() + margin + m_contourwidth );
1644 
1645  return hitEvent.m_how.IsHit();
1646 }
1647 
1648 bool a2dRect::GeneratePins( a2dPinClass* toConnectTo, a2dConnectTask task, double WXUNUSED( x ), double WXUNUSED( y ), double WXUNUSED(margin) )
1649 {
1650  a2dPinClass* toCreate;
1651  if ( GetGeneratePins() && ( toCreate = toConnectTo->GetPinClassForTask( task, this ) ) )
1652  {
1653  m_flags.m_visiblechilds = true;
1654  a2dPin* newPin = NULL;
1655  if ( !HasPinNamed( wxT( "pinc*" ), true ) )
1656  {
1657  newPin = AddPin( wxT( "pinc" ), m_width / 2, m_height / 2, a2dPin::temporaryObjectPin, toCreate );
1658  newPin->SetInternal( true );
1659  }
1660  if ( !HasPinNamed( wxT( "pin1" ), true ) )
1661  AddPin( wxT( "pin1" ), 0, 0, a2dPin::temporaryObjectPin, toCreate );
1662  if ( !HasPinNamed( wxT( "pin2" ), true ) )
1663  AddPin( wxT( "pin2" ), 0, m_height / 2, a2dPin::temporaryObjectPin, toCreate );
1664  if ( !HasPinNamed( wxT( "pin3" ), true ) )
1665  AddPin( wxT( "pin3" ), 0, m_height, a2dPin::temporaryObjectPin, toCreate );
1666  if ( !HasPinNamed( wxT( "pin4" ), true ) )
1667  AddPin( wxT( "pin4" ), m_width / 2, m_height , a2dPin::temporaryObjectPin, toCreate );
1668  if ( !HasPinNamed( wxT( "pin5" ), true ) )
1669  AddPin( wxT( "pin5" ), m_width, m_height , a2dPin::temporaryObjectPin, toCreate );
1670  if ( !HasPinNamed( wxT( "pin6" ), true ) )
1671  AddPin( wxT( "pin6" ), m_width, m_height / 2 , a2dPin::temporaryObjectPin, toCreate );
1672  if ( !HasPinNamed( wxT( "pin7" ), true ) )
1673  AddPin( wxT( "pin7" ), m_width, 0, a2dPin::temporaryObjectPin, toCreate );
1674  if ( !HasPinNamed( wxT( "pin8" ), true ) )
1675  AddPin( wxT( "pin8" ), m_width / 2, 0, a2dPin::temporaryObjectPin, toCreate );
1676  /*
1677  Prepend( new a2dPin( this, wxT("pin1"), toCreate, 0, 0, -225 ));
1678  Prepend( new a2dPin( this, wxT("pin2"), toCreate, 0, m_height/2, 180 ));
1679  Prepend( new a2dPin( this, wxT("pin3"), toCreate, 0, m_height, -135 ));
1680  Prepend( new a2dPin( this, wxT("pin4"), toCreate, m_width/2, m_height, -90 ));
1681  Prepend( new a2dPin( this, wxT("pin5"), toCreate, m_width, m_height, -45 ));
1682  Prepend( new a2dPin( this, wxT("pin6"), toCreate, m_width, m_height/2, 0 ));
1683  Prepend( new a2dPin( this, wxT("pin7"), toCreate, m_width, 0, 45 ));
1684  Prepend( new a2dPin( this, wxT("pin8"), toCreate, m_width/2, 0, 90 ));
1685  */
1686 
1687  wxASSERT( HasPins( true ) );
1689  return true;
1690  }
1691  return false;
1692 }
1693 
1694 //----------------------------------------------------------------------------
1695 // a2dCircle
1696 //----------------------------------------------------------------------------
1697 
1698 a2dPropertyIdDouble* a2dCircle::PROPID_Radius = NULL;
1699 
1700 INITIALIZE_PROPERTIES( a2dCircle, a2dCanvasObject )
1701 {
1702  PROPID_Radius = new a2dPropertyIdDouble( wxT( "Radius" ),
1703  a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dCircle::m_radius ) );
1704  AddPropertyId( PROPID_Radius );
1705 
1706  return true;
1707 }
1708 
1709 a2dCircle::a2dCircle()
1710  : a2dCanvasObject()
1711 {
1712  m_radius = 0;
1713  m_contourwidth = 0;
1714 }
1715 
1716 a2dCircle::a2dCircle( double x, double y, double radius, double width )
1717  : a2dCanvasObject()
1718 {
1719  m_lworld.Translate( x, y );
1720  m_radius = radius;
1721  m_contourwidth = width;
1722 }
1723 
1725 {
1726 }
1727 
1728 a2dCircle::a2dCircle( const a2dCircle& other, CloneOptions options, a2dRefMap* refs )
1729  : a2dCanvasObject( other, options, refs )
1730 {
1731  m_radius = other.m_radius;
1733 }
1734 
1736 {
1737  return new a2dCircle( *this, options, refs );
1738 }
1739 
1740 a2dVertexList* a2dCircle::GetAsVertexList( bool& returnIsPolygon ) const
1741 {
1742  returnIsPolygon = true;
1743  a2dVertexList* pointlist = new a2dVertexList();
1744 
1745  a2dCanvasObjectList* vectorpaths = GetAsCanvasVpaths();
1746  a2dVpath* segments = wxStaticCast( vectorpaths->front().Get(), a2dVectorPath ) ->GetSegments();
1747  segments->ConvertToLines();
1748  a2dLineSegment* point;
1749  unsigned int i;
1750  for ( i = 0; i < segments->size(); i++ )
1751  {
1752  a2dVpathSegment* seg = segments->Item( i );
1753  point = new a2dLineSegment( seg->m_x1, seg->m_y1 );
1754  pointlist->push_back( point );
1755  }
1756 
1757  delete vectorpaths;
1758 
1759  return pointlist;
1760 }
1761 
1763 {
1764  a2dAffineMatrix pworld;
1765  if ( transform )
1766  pworld = m_lworld;
1767 
1768  a2dVpath* segments = new a2dVpath();
1769 
1770  if ( m_contourwidth )
1771  {
1772  double w2 = m_contourwidth / 2;
1774  segments->push_back( seg );
1775  seg = new a2dVpathArcSegment( 0, -m_radius - w2, m_radius + w2, 0, a2dPATHSEG_ARCTO );
1776  segments->push_back( seg );
1777  seg = new a2dVpathArcSegment( 0, m_radius + w2, -m_radius - w2, 0, a2dPATHSEG_ARCTO );
1778  segments->push_back( seg );
1779 
1780  seg = new a2dVpathSegment( 0, m_radius - w2, a2dPATHSEG_LINETO_NOSTROKE );
1781  segments->push_back( seg );
1782 
1783  seg = new a2dVpathArcSegment( 0, -m_radius + w2, -m_radius + w2, 0, a2dPATHSEG_ARCTO );
1784  segments->push_back( seg );
1785  seg = new a2dVpathArcSegment( 0, m_radius - w2, m_radius - w2, 0, a2dPATHSEG_ARCTO );
1786  segments->push_back( seg );
1787 
1789  segments->push_back( seg );
1790  }
1791  else
1792  {
1794  segments->push_back( seg );
1795  seg = new a2dVpathArcSegment( 0, -m_radius, m_radius, 0, a2dPATHSEG_ARCTO );
1796  segments->push_back( seg );
1798  segments->push_back( seg );
1799  }
1800  segments->Transform( pworld );
1801 
1802  a2dVectorPath* canpath = new a2dVectorPath( segments );
1803  canpath->SetStroke( this->GetStroke() );
1804  canpath->SetFill( this->GetFill() );
1805  canpath->SetLayer( m_layer );
1806  //canpath->SetContourWidth( GetContourWidth() );
1807  a2dCanvasObjectList* canpathlist = new a2dCanvasObjectList();
1808  canpathlist->push_back( canpath );
1809  return canpathlist;
1810 }
1811 
1813 {
1814  a2dBoundingBox bbox;
1815 
1816  bbox.Expand( -m_radius, -m_radius );
1817  bbox.Expand( m_radius, m_radius );
1818 
1819  if ( !( flags & a2dCANOBJ_BBOX_EDIT ) )
1820  {
1821  if ( m_contourwidth > 0 )
1822  bbox.Enlarge( m_contourwidth / 2 );
1823  }
1824 
1825  return bbox;
1826 }
1827 
1828 bool a2dCircle::DoUpdate( UpdateMode mode, const a2dBoundingBox& childbox, const a2dBoundingBox& clipbox, const a2dBoundingBox& propbox )
1829 {
1830  // Note: This calculates something different than the mapped untransformed
1831  // Bounding box. The box caclulated here might be smaller.
1832  if ( !m_bbox.GetValid() )
1833  {
1834  double rad = m_radius + m_contourwidth / 2;
1835 
1836  double alphax = atan2( m_lworld.GetValue( 1, 0 ), m_lworld.GetValue( 0, 0 ) );
1837  double alphay = atan2( m_lworld.GetValue( 1, 1 ), m_lworld.GetValue( 0, 1 ) );
1838 
1839  double x, y;
1840  m_lworld.TransformPoint( rad * cos ( alphax ), rad * sin ( alphax ), x, y );
1841  m_bbox.Expand( x, y );
1842  m_lworld.TransformPoint( rad * -cos ( alphax ), rad * -sin ( alphax ), x, y );
1843  m_bbox.Expand( x, y );
1844 
1845  m_lworld.TransformPoint( rad * cos ( alphay ), rad * sin ( alphay ), x, y );
1846  m_bbox.Expand( x, y );
1847  m_lworld.TransformPoint( rad * -cos ( alphay ), rad * -sin ( alphay ), x, y );
1848  m_bbox.Expand( x, y );
1849 
1850  return true;
1851  }
1852 
1853  return false;
1854 }
1855 
1856 void a2dCircle::DoRender( a2dIterC& ic, OVERLAP clipparent )
1857 {
1858  if ( m_contourwidth )
1859  {
1860  a2dCanvasObjectList* vectorpaths = GetAsCanvasVpaths( false );
1861 
1862  forEachIn( a2dCanvasObjectList, vectorpaths )
1863  {
1864  a2dVectorPath* obj = wxStaticCast( ( *iter ).Get(), a2dVectorPath );
1865  obj->DoRender( ic, clipparent );
1866  }
1867  delete vectorpaths;
1868  }
1869  else
1870  ic.GetDrawer2D()->DrawCircle( 0, 0, m_radius );
1871 }
1872 
1873 #if wxART2D_USE_CVGIO
1874 void a2dCircle::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut& out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
1875 {
1876  a2dCanvasObject::DoSave( parent, out, xmlparts, towrite );
1877  if ( xmlparts == a2dXmlSer_attrib )
1878  {
1879  out.WriteAttribute( wxT( "radius" ), m_radius * out.GetScale() );
1880  out.WriteAttribute( wxT( "contourwidth" ), m_contourwidth * out.GetScale() );
1881  }
1882  else
1883  {
1884  }
1885 }
1886 
1887 void a2dCircle::DoLoad( wxObject* parent, a2dIOHandlerXmlSerIn& parser, a2dXmlSer_flag xmlparts )
1888 {
1889  a2dCanvasObject::DoLoad( parent, parser, xmlparts );
1890  if ( xmlparts == a2dXmlSer_attrib )
1891  {
1892  m_radius = parser.RequireAttributeValueDouble( wxT( "radius" ) ) * parser.GetScale() ;
1893  m_contourwidth = parser.GetAttributeValueDouble( wxT( "contourwidth" ), 0 ) * parser.GetScale() ;
1894  }
1895  else
1896  {
1897  }
1898 }
1899 #endif //wxART2D_USE_CVGIO
1900 
1902 {
1903  double pw = ic.GetWorldStrokeExtend();
1904  double margin = ic.GetTransformedHitMargin();
1905  double r = sqrt( ( hitEvent.m_relx * hitEvent.m_relx ) + ( hitEvent.m_rely * hitEvent.m_rely ) );
1906 
1907  if ( m_contourwidth )
1908  {
1909  //donut hittest
1910  if ( m_radius + pw + m_contourwidth / 2 + margin > r )
1911  {
1912  //we are inside the donut its outer contour circle
1913  if ( m_radius - m_contourwidth / 2 - pw - margin > r )
1914  {
1915  hitEvent.m_how = a2dHit::stock_nohit;
1916  return false;
1917  }
1918  //we are outside the donut inner contour circle
1919 
1920  if ( m_radius + m_contourwidth / 2 < r )
1922  else if ( m_radius - m_contourwidth / 2 < r )
1923  {
1924  if ( m_radius + m_contourwidth / 2 - pw - margin > r &&
1925  m_radius - m_contourwidth / 2 + pw + margin < r
1926  )
1927  hitEvent.m_how = a2dHit::stock_fill;
1928  else
1929  hitEvent.m_how = a2dHit::stock_strokeinside;
1930  }
1931  else
1933 
1934  return true;
1935  }
1936  else
1937  {
1938  hitEvent.m_how = a2dHit::stock_nohit;
1939  return false;
1940  }
1941  }
1942  else
1943  {
1944  if ( m_radius + pw + margin > r )
1945  {
1946  if ( m_radius - pw - margin > r )
1947  hitEvent.m_how = a2dHit::stock_fill;
1948  else if ( m_radius > r )
1949  hitEvent.m_how = a2dHit::stock_strokeinside;
1950  else
1952  wxMouseEvent* mouse = wxDynamicCast( hitEvent.m_event, wxMouseEvent );
1953  /* KH debug
1954  if (mouse && mouse->LeftDown())
1955  {
1956  if ( m_flags.m_editingCopy )
1957  wxLogDebug(wxT(" inedit %p %s"), this, GetName() );
1958  else
1959  wxLogDebug(wxT(" in %p %s"), this, GetName() );
1960  }
1961  */
1962  return true;
1963  }
1964  else
1965  {
1966  // KH debug wxLogDebug(wxT(" out %p %s"), this, GetName() );
1967  hitEvent.m_how = a2dHit::stock_nohit;
1968  return false;
1969  }
1970  }
1971 }
1972 
1973 bool a2dCircle::DoStartEdit( wxUint16 editmode, wxEditStyle editstyle )
1974 {
1975  if ( m_flags.m_editable )
1976  {
1977  PROPID_IncludeChildren->SetPropertyToObject( this, false );
1978  return a2dCanvasObject::DoStartEdit( editmode, editstyle );
1979  }
1980 
1981  return false;
1982 }
1983 
1984 bool a2dCircle::GeneratePins( a2dPinClass* toConnectTo, a2dConnectTask task, double WXUNUSED( x ), double WXUNUSED( y ), double WXUNUSED(margin) )
1985 {
1986  a2dPinClass* toCreate;
1987  if ( GetGeneratePins() && ( toCreate = toConnectTo->GetPinClassForTask( task, this ) ) )
1988  {
1989  double radsrt2 = sqrt( wxSqr( m_radius / 2 ) + wxSqr( m_radius / 2 ) );
1990  m_flags.m_visiblechilds = true;
1991  a2dPin* newPin = NULL;
1992  if ( !HasPinNamed( wxT( "pinc*" ), true ) )
1993  {
1994  newPin = AddPin( wxT( "pinc" ), 0, 0, a2dPin::temporaryObjectPin, toCreate );
1995  newPin->SetInternal( true );
1996  }
1997  if ( !HasPinNamed( wxT( "pin1" ) ) )
1998  AddPin( wxT( "pin1" ), 0, m_radius, a2dPin::temporaryObjectPin, toCreate );
1999  if ( !HasPinNamed( wxT( "pin2" ) ) )
2000  AddPin( wxT( "pin2" ), radsrt2, radsrt2, a2dPin::temporaryObjectPin, toCreate );
2001  if ( !HasPinNamed( wxT( "pin3" ) ) )
2002  AddPin( wxT( "pin3" ), m_radius, 0, a2dPin::temporaryObjectPin, toCreate );
2003  if ( !HasPinNamed( wxT( "pin4" ) ) )
2004  AddPin( wxT( "pin4" ), radsrt2, -radsrt2 , a2dPin::temporaryObjectPin, toCreate );
2005  if ( !HasPinNamed( wxT( "pin5" ) ) )
2006  AddPin( wxT( "pin5" ), 0, -m_radius , a2dPin::temporaryObjectPin, toCreate );
2007  if ( !HasPinNamed( wxT( "pin6" ) ) )
2008  AddPin( wxT( "pin6" ), -radsrt2, -radsrt2 , a2dPin::temporaryObjectPin, toCreate );
2009  if ( !HasPinNamed( wxT( "pin7" ) ) )
2010  AddPin( wxT( "pin7" ), -m_radius, 0, a2dPin::temporaryObjectPin, toCreate );
2011  if ( !HasPinNamed( wxT( "pin8" ) ) )
2012  AddPin( wxT( "pin8" ), -radsrt2, radsrt2, a2dPin::temporaryObjectPin, toCreate );
2013 
2014  wxASSERT( HasPins( true ) );
2016 
2017  return true;
2018  }
2019  return false;
2020 }
2021 
2022 //----------------------------------------------------------------------------
2023 // a2dEllipse
2024 //----------------------------------------------------------------------------
2025 
2026 a2dEllipse::a2dEllipse()
2027  : a2dWHCenter()
2028 {
2029  m_contourwidth = 0;
2030 }
2031 
2032 a2dEllipse::a2dEllipse( double xc, double yc, double width, double height, double contourwidth )
2033  : a2dWHCenter( xc, yc, width, height )
2034 {
2035  m_contourwidth = contourwidth;
2036 }
2037 
2038 a2dEllipse::~a2dEllipse()
2039 {
2040 }
2041 
2042 a2dEllipse::a2dEllipse( const a2dEllipse& other, CloneOptions options, a2dRefMap* refs )
2043  : a2dWHCenter( other, options, refs )
2044 {
2045  m_contourwidth = other.m_contourwidth;
2046 }
2047 
2049 {
2050  return new a2dEllipse( *this, options, refs );
2051 };
2052 
2053 a2dVertexList* a2dEllipse::GetAsVertexList( bool& returnIsPolygon ) const
2054 {
2055  returnIsPolygon = true;
2056  a2dVertexList* pointlist = new a2dVertexList();
2057 
2058  a2dCanvasObjectList* vectorpaths = GetAsCanvasVpaths();
2059  a2dVpath* segments = wxStaticCast( vectorpaths->front().Get(), a2dVectorPath ) ->GetSegments();
2060  segments->ConvertToLines();
2061  a2dLineSegment* point;
2062  unsigned int i;
2063  for ( i = 0; i < segments->size(); i++ )
2064  {
2065  a2dVpathSegment* seg = segments->Item( i );
2066  point = new a2dLineSegment( seg->m_x1, seg->m_y1 );
2067  pointlist->push_back( point );
2068  }
2069 
2070  delete vectorpaths;
2071 
2072  return pointlist;
2073 }
2074 
2076 {
2077  a2dAffineMatrix pworld;
2078  if ( transform )
2079  pworld = m_lworld;
2080 
2081  //TODO how to approximate ellipse with spline
2082 
2083  a2dVpath* segments = new a2dVpath();
2084 
2085  double dphi = wxPI * 2.0 / CIRCLE_STEPS;
2086 
2087  a2dVpathSegment* seg;
2088  double x, y;
2089  double theta;
2090  int i;
2091  for ( i = 0; i < CIRCLE_STEPS; i++ )
2092  {
2093  theta = i * dphi;
2094  pworld.TransformPoint( m_width / 2 * cos ( theta ), -m_height / 2 * sin ( theta ), x, y );
2095  if ( i == 0 )
2096  seg = new a2dVpathSegment( x, y , a2dPATHSEG_MOVETO );
2097  else if ( i == CIRCLE_STEPS - 1 )
2099  else
2100  seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
2101  segments->push_back( seg );
2102  }
2103 
2104  a2dVectorPath* canpath = new a2dVectorPath( segments );
2105  canpath->SetStroke( this->GetStroke() );
2106  canpath->SetFill( this->GetFill() );
2107  canpath->SetLayer( m_layer );
2108  canpath->SetContourWidth( GetContourWidth() );
2109  canpath->SetPathType( a2dPATH_END_ROUND );
2110  a2dCanvasObjectList* canpathlist = new a2dCanvasObjectList();
2111  canpathlist->push_back( canpath );
2112  return canpathlist;
2113 }
2114 
2116 {
2117  a2dBoundingBox bbox;
2118 
2119  bbox.Expand( -m_width / 2, -m_height / 2 );
2120  bbox.Expand( m_width / 2, m_height / 2 );
2121 
2122  if ( !( flags & a2dCANOBJ_BBOX_EDIT ) )
2123  {
2124  if ( m_contourwidth > 0 )
2125  bbox.Enlarge( m_contourwidth / 2 );
2126  }
2127 
2128  return bbox;
2129 }
2130 
2131 bool a2dEllipse::DoUpdate( UpdateMode mode, const a2dBoundingBox& childbox, const a2dBoundingBox& clipbox, const a2dBoundingBox& propbox )
2132 {
2133  // Note: This calculates something different than the mapped untransformed
2134  // Bounding box. The box caclulated here might be smaller.
2135  if ( !m_bbox.GetValid() )
2136  {
2137  double width = m_width + m_contourwidth / 2;
2138  double height = m_height + m_contourwidth / 2;
2139 
2140  double alphax = atan2( m_lworld.GetValue( 1, 0 ) * height, m_lworld.GetValue( 0, 0 ) * width );
2141  double alphay = atan2( m_lworld.GetValue( 1, 1 ) * height, m_lworld.GetValue( 0, 1 ) * width );
2142 
2143  double x, y;
2144  m_lworld.TransformPoint( width / 2 * cos ( alphax ), height / 2 * sin ( alphax ), x, y );
2145  m_bbox.Expand( x, y );
2146  m_lworld.TransformPoint( width / 2 * -cos ( alphax ), height / 2 * -sin ( alphax ), x, y );
2147  m_bbox.Expand( x, y );
2148 
2149  m_lworld.TransformPoint( width / 2 * cos ( alphay ), height / 2 * sin ( alphay ), x, y );
2150  m_bbox.Expand( x, y );
2151  m_lworld.TransformPoint( width / 2 * -cos ( alphay ), height / 2 * -sin ( alphay ), x, y );
2152  m_bbox.Expand( x, y );
2153 
2154  return true;
2155  }
2156  return false;
2157 }
2158 
2159 void a2dEllipse::DoRender( a2dIterC& ic, OVERLAP clipparent )
2160 {
2161  if ( GetContourWidth() )
2162  {
2163  a2dCanvasObjectList* vectorpaths = GetAsCanvasVpaths( false );
2164 
2165  forEachIn( a2dCanvasObjectList, vectorpaths )
2166  {
2167  a2dVectorPath* obj = wxStaticCast( ( *iter ).Get(), a2dVectorPath );
2168  obj->DoRender( ic, clipparent );
2169  }
2170  delete vectorpaths;
2171  }
2172  else
2173  ic.GetDrawer2D()->DrawEllipse( 0, 0, m_width, m_height );
2174 }
2175 
2176 #if wxART2D_USE_CVGIO
2177 void a2dEllipse::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut& out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
2178 {
2179  a2dWHCenter::DoSave( parent, out, xmlparts, towrite );
2180  if ( xmlparts == a2dXmlSer_attrib )
2181  {
2182  out.WriteAttribute( wxT( "contourwidth" ), m_contourwidth * out.GetScale() );
2183  }
2184  else
2185  {
2186  }
2187 }
2188 
2189 void a2dEllipse::DoLoad( wxObject* parent, a2dIOHandlerXmlSerIn& parser, a2dXmlSer_flag xmlparts )
2190 {
2191  a2dWHCenter::DoLoad( parent, parser, xmlparts );
2192  if ( xmlparts == a2dXmlSer_attrib )
2193  {
2194  m_contourwidth = parser.GetAttributeValueDouble( wxT( "contourwidth" ), 0 ) * parser.GetScale() ;
2195  }
2196  else
2197  {
2198  }
2199 }
2200 #endif //wxART2D_USE_CVGIO
2201 
2203 {
2204  double xh = hitEvent.m_relx;
2205  double yh = hitEvent.m_rely;
2206 
2207  double pw = ic.GetWorldStrokeExtend();
2208  double margin = ic.GetTransformedHitMargin();
2209 
2210  double a = 0.5 * m_width + pw + margin ;
2211  double b = 0.5 * m_height + pw + margin;
2212  double c = wxSqr( xh / a ) + wxSqr( yh / b );
2213  if ( 1 > c )
2214  {
2215  a = 0.5 * m_width - pw - margin ;
2216  b = 0.5 * m_height - pw - margin;
2217  c = wxSqr( xh / a ) + wxSqr( yh / b );
2218 
2219  if( 1 > c )
2220  {
2221  hitEvent.m_how = a2dHit::stock_fill;
2222  return true;
2223  }
2224 
2225  a = 0.5 * m_width;
2226  b = 0.5 * m_height;
2227  c = wxSqr( xh / a ) + wxSqr( yh / b );
2228 
2229  if( 1 > c )
2230  {
2231  hitEvent.m_how = a2dHit::stock_strokeinside;
2232  return true;
2233  }
2234  else
2235  {
2237  return true;
2238  }
2239 
2240  }
2241  else
2242  {
2243  hitEvent.m_how = a2dHit::stock_nohit;
2244  return false;
2245  }
2246 }
2247 
2248 bool a2dEllipse::DoStartEdit( wxUint16 editmode, wxEditStyle editstyle )
2249 {
2250  if ( m_flags.m_editable )
2251  {
2252  PROPID_IncludeChildren->SetPropertyToObject( this, false );
2253  return a2dWHCenter::DoStartEdit( editmode, editstyle );
2254  }
2255 
2256  return false;
2257 }
2258 
2259 bool a2dEllipse::GeneratePins( a2dPinClass* toConnectTo, a2dConnectTask task, double WXUNUSED( x ), double WXUNUSED( y ), double WXUNUSED(margin) )
2260 {
2261  a2dPinClass* toCreate;
2262  if ( GetGeneratePins() && ( toCreate = toConnectTo->GetPinClassForTask( task, this ) ) )
2263  {
2264  double rx2 = m_width / 2 * cos( wxDegToRad( 45 ) );
2265  double ry2 = m_height / 2 * sin( wxDegToRad( 45 ) );
2266 
2267  m_flags.m_visiblechilds = true;
2268  a2dPin* newPin = NULL;
2269  if ( !HasPinNamed( wxT( "pinc*" ), true ) )
2270  {
2271  newPin = AddPin( wxT( "pinc" ), 0, 0, a2dPin::temporaryObjectPin, toCreate );
2272  newPin->SetInternal( true );
2273  }
2274  if ( !HasPinNamed( wxT( "pin1" ) ) )
2275  AddPin( wxT( "pin1" ), 0, m_height / 2, a2dPin::temporaryObjectPin, toCreate );
2276  if ( !HasPinNamed( wxT( "pin2" ) ) )
2277  AddPin( wxT( "pin2" ), rx2, ry2, a2dPin::temporaryObjectPin, toCreate );
2278  if ( !HasPinNamed( wxT( "pin3" ) ) )
2279  AddPin( wxT( "pin3" ), m_width / 2, 0, a2dPin::temporaryObjectPin, toCreate );
2280  if ( !HasPinNamed( wxT( "pin4" ) ) )
2281  AddPin( wxT( "pin4" ), rx2, -ry2, a2dPin::temporaryObjectPin, toCreate );
2282  if ( !HasPinNamed( wxT( "pin5" ) ) )
2283  AddPin( wxT( "pin5" ), 0, -m_height / 2, a2dPin::temporaryObjectPin, toCreate );
2284  if ( !HasPinNamed( wxT( "pin6" ) ) )
2285  AddPin( wxT( "pin6" ), -rx2, -ry2 , a2dPin::temporaryObjectPin, toCreate );
2286  if ( !HasPinNamed( wxT( "pin7" ) ) )
2287  AddPin( wxT( "pin7" ), -m_width / 2, 0, a2dPin::temporaryObjectPin, toCreate );
2288  if ( !HasPinNamed( wxT( "pin8" ) ) )
2289  AddPin( wxT( "pin8" ), -rx2, ry2, a2dPin::temporaryObjectPin, toCreate );
2290 
2291  wxASSERT( HasPins( true ) );
2293 
2294  return true;
2295  }
2296  return false;
2297 }
2298 
2299 //----------------------------------------------------------------------------
2300 // a2dEllipticArc
2301 //----------------------------------------------------------------------------
2302 a2dPropertyIdDouble* a2dEllipticArc::PROPID_StartAngle = NULL;
2303 a2dPropertyIdDouble* a2dEllipticArc::PROPID_EndAngle = NULL;
2304 a2dPropertyIdBool* a2dEllipticArc::PROPID_Chord = NULL;
2305 
2306 INITIALIZE_PROPERTIES( a2dEllipticArc, a2dWHCenter )
2307 {
2308  PROPID_StartAngle = new a2dPropertyIdDouble( wxT( "StartAngle" ),
2309  a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dEllipticArc::m_start ) );
2310  AddPropertyId( PROPID_StartAngle );
2311  PROPID_EndAngle = new a2dPropertyIdDouble( wxT( "EndAngle" ),
2312  a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dEllipticArc::m_end ) );
2313  AddPropertyId( PROPID_EndAngle );
2314  PROPID_Chord = new a2dPropertyIdBool( wxT( "Radius" ),
2315  a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdBool::Mptr >( &a2dEllipticArc::m_chord ) );
2316  AddPropertyId( PROPID_Chord );
2317 
2318  return true;
2319 }
2320 
2321 BEGIN_EVENT_TABLE( a2dEllipticArc, a2dWHCenter )
2323  EVT_CHAR( a2dEllipticArc::OnChar )
2324 END_EVENT_TABLE()
2325 
2327  : a2dWHCenter()
2328 {
2329  m_start = 0;
2330  m_end = 0;
2331  m_chord = false;
2332  m_contourwidth = 0;
2333 }
2334 
2335 a2dEllipticArc::a2dEllipticArc( double xc, double yc, double width, double height, double start, double end, bool chord, double contourwidth )
2336  : a2dWHCenter( xc, yc, width, height )
2337 {
2338  m_start = start;
2339  m_end = end;
2340  m_chord = chord;
2341  m_contourwidth = contourwidth;
2342 }
2343 
2345 {
2346 }
2347 
2349  : a2dWHCenter( other, options, refs )
2350 {
2351  m_start = other.m_start;
2352  m_end = other.m_end;
2353  m_chord = other.m_chord;
2355 }
2356 
2357 void a2dEllipticArc::SetChord( bool chord )
2358 {
2359  m_chord = chord;
2360  SetPending( true );
2361 }
2362 
2364 {
2365  return new a2dEllipticArc( *this, options, refs );
2366 };
2367 
2368 a2dVertexList* a2dEllipticArc::GetAsVertexList( bool& returnIsPolygon ) const
2369 {
2370  returnIsPolygon = true;
2371  a2dVertexList* pointlist = new a2dVertexList();
2372 
2373  a2dCanvasObjectList* vectorpaths = GetAsCanvasVpaths();
2374  a2dVpath* segments = wxStaticCast( vectorpaths->front().Get(), a2dVectorPath ) ->GetSegments();
2375  segments->ConvertToLines();
2376  a2dLineSegment* point;
2377  unsigned int i;
2378  for ( i = 0; i < segments->size(); i++ )
2379  {
2380  a2dVpathSegment* seg = segments->Item( i );
2381  point = new a2dLineSegment( seg->m_x1, seg->m_y1 );
2382  pointlist->push_back( point );
2383  }
2384 
2385  delete vectorpaths;
2386 
2387  return pointlist;
2388 }
2389 
2391 {
2392  a2dAffineMatrix pworld;
2393  if ( transform )
2394  pworld = m_lworld;
2395 
2396  //TODO how to approximate ellipse with spline
2397 
2398  a2dVpath* segments = new a2dVpath();
2399 
2400  double start, end;
2401 
2402  start = wxDegToRad( m_start );
2403  end = wxDegToRad( m_end );
2404 
2405  end = end - start;
2406  if ( end <= 0 ) end += 2.0 * wxPI;
2407 
2408  if ( start < 0 ) start += 2.0 * wxPI;
2409 
2410  end = end + start;
2411 
2412  double dphi = wxPI * 2.0 / CIRCLE_STEPS;
2413  int steps = ( int )( ( end - start ) / dphi );
2414  if ( steps == 0 )
2415  steps = 1;
2416  dphi = ( end - start ) / steps; //make it fit.
2417 
2418  a2dVpathSegment* seg;
2419 
2420  double theta = start;
2421  int i;
2422  double x, y;
2423  for ( i = 0; i < steps + 1; i++ )
2424  {
2425  pworld.TransformPoint( m_width / 2 * cos ( theta ), m_height / 2 * sin ( theta ), x, y );
2426  if ( i == 0 )
2427  seg = new a2dVpathSegment( x, y , a2dPATHSEG_MOVETO );
2428  else
2429  seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
2430  segments->push_back( seg );
2431  theta = theta + dphi;
2432  }
2433 
2434  if ( !m_chord )
2435  {
2436  pworld.TransformPoint( 0, 0, x, y );
2438  segments->push_back( seg );
2439  }
2440 
2441  a2dVectorPath* canpath = new a2dVectorPath( segments );
2442  canpath->SetStroke( this->GetStroke() );
2443  canpath->SetFill( this->GetFill() );
2444  canpath->SetLayer( m_layer );
2445  canpath->SetContourWidth( GetContourWidth() );
2446  canpath->SetPathType( a2dPATH_END_ROUND );
2447  a2dCanvasObjectList* canpathlist = new a2dCanvasObjectList();
2448  canpathlist->push_back( canpath );
2449  return canpathlist;
2450 }
2451 
2453 {
2454  a2dBoundingBox bbox;
2455 
2456  double start, end;
2457 
2458  start = wxDegToRad( m_start );
2459  end = wxDegToRad( m_end );
2460 
2461  if ( !m_chord )
2462  bbox.Expand( 0, 0 );
2463  //start point
2464  bbox.Expand( m_width / 2 * cos ( start ), m_height / 2 * sin ( start ) );
2465  //end point
2466  bbox.Expand( m_width / 2 * cos ( end ), m_height / 2 * sin ( end ) );
2467 
2468  //outer points
2469  if ( InArc( 0, start, end, false ) )
2470  bbox.Expand( m_width / 2, 0 );
2471  if ( InArc( wxPI / 2, start, end, false ) )
2472  bbox.Expand( 0, m_height / 2 );
2473  if ( InArc( wxPI, start, end, false ) )
2474  bbox.Expand( -m_width / 2, 0 );
2475  if ( InArc( 1.5 * wxPI, start, end, false ) )
2476  bbox.Expand( 0, -m_height / 2 );
2477 
2478  if ( !( flags & a2dCANOBJ_BBOX_EDIT ) )
2479  {
2480  if ( m_contourwidth > 0 )
2481  bbox.Enlarge( m_contourwidth / 2 );
2482  }
2483 
2484  return bbox;
2485 }
2486 
2487 bool a2dEllipticArc::DoUpdate( UpdateMode mode, const a2dBoundingBox& childbox, const a2dBoundingBox& clipbox, const a2dBoundingBox& propbox )
2488 {
2489  // Note: This calculates something different than the mapped untransformed
2490  // Bounding box. The box caclulated here might be smaller.
2491  if ( !m_bbox.GetValid() )
2492  {
2493  double width = m_width + m_contourwidth / 2;
2494  double height = m_height + m_contourwidth / 2;
2495 
2496  double alphax = atan2( m_lworld.GetValue( 1, 0 ) * height, m_lworld.GetValue( 0, 0 ) * width );
2497  double alphay = atan2( m_lworld.GetValue( 1, 1 ) * height, m_lworld.GetValue( 0, 1 ) * width );
2498 
2499  double x, y;
2500 
2501  double start, end;
2502 
2503  start = wxDegToRad( m_start );
2504  end = wxDegToRad( m_end );
2505 
2506  //wxLogDebug(wxT("start = %12.6lf"), start );
2507  //wxLogDebug(wxT("end = %12.6lf"), end);
2508  //wxLogDebug(wxT("alphax = %12.6lf"), alphax);
2509  //wxLogDebug(wxT("alphay = %12.6lf"), alphay);
2510 
2511  //start point
2512  m_lworld.TransformPoint( width / 2 * cos ( start ), height / 2 * sin ( start ), x, y );
2513  m_bbox.Expand( x, y );
2514  //end point
2515  m_lworld.TransformPoint( width / 2 * cos ( end ), height / 2 * sin ( end ), x, y );
2516  m_bbox.Expand( x, y );
2517 
2518  if ( !m_chord )
2519  {
2520  m_lworld.TransformPoint( 0, 0, x, y );
2521  m_bbox.Expand( x, y );
2522  }
2523 
2524  //outer points
2525  if ( InArc( alphax, start, end, false ) )
2526  {
2527  m_lworld.TransformPoint( width / 2 * cos ( alphax ), height / 2 * sin ( alphax ), x, y );
2528  m_bbox.Expand( x, y );
2529  }
2530  alphax += wxPI;
2531  if ( InArc( alphax, start, end, false ) )
2532  {
2533  m_lworld.TransformPoint( width / 2 * cos ( alphax ), height / 2 * sin ( alphax ), x, y );
2534  m_bbox.Expand( x, y );
2535  }
2536  alphax -= 2 * wxPI;
2537  if ( InArc( alphax, start, end, false ) )
2538  {
2539  m_lworld.TransformPoint( width / 2 * cos ( alphax ), height / 2 * sin ( alphax ), x, y );
2540  m_bbox.Expand( x, y );
2541  }
2542  if ( InArc( alphay, start, end, false ) )
2543  {
2544  m_lworld.TransformPoint( width / 2 * cos ( alphay ), height / 2 * sin ( alphay ), x, y );
2545  m_bbox.Expand( x, y );
2546  }
2547  alphay += wxPI;
2548  if ( InArc( alphay, start, end, false ) )
2549  {
2550  m_lworld.TransformPoint( width / 2 * cos ( alphay ), height / 2 * sin ( alphay ), x, y );
2551  m_bbox.Expand( x, y );
2552  }
2553  alphay -= 2 * wxPI;
2554  if ( InArc( alphay, start, end, false ) )
2555  {
2556  m_lworld.TransformPoint( width / 2 * cos ( alphay ), height / 2 * sin ( alphay ), x, y );
2557  m_bbox.Expand( x, y );
2558  }
2559 
2560  return true;
2561  }
2562  return false;
2563 }
2564 
2566 {
2567  if ( GetContourWidth() )
2568  {
2569  if ( m_flags.m_editingCopy && m_chord )
2570  m_chord = false;
2571 
2572  a2dCanvasObjectList* vectorpaths = GetAsCanvasVpaths( false );
2573 
2574  if ( m_flags.m_editingCopy && m_chord )
2575  m_chord = true;
2576 
2577  forEachIn( a2dCanvasObjectList, vectorpaths )
2578  {
2579  a2dVectorPath* obj = wxStaticCast( ( *iter ).Get(), a2dVectorPath );
2580  obj->DoRender( ic, clipparent );
2581  }
2582  delete vectorpaths;
2583  }
2584  else
2585  {
2586  if ( m_flags.m_editingCopy && m_chord )
2587  {
2588  m_chord = false;
2590  m_chord = true;
2591  }
2592  else
2594  }
2595 }
2596 
2597 #if wxART2D_USE_CVGIO
2598 void a2dEllipticArc::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut& out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
2599 {
2600  a2dWHCenter::DoSave( parent, out, xmlparts, towrite );
2601  if ( xmlparts == a2dXmlSer_attrib )
2602  {
2603  out.WriteAttribute( wxT( "start" ), m_start );
2604  out.WriteAttribute( wxT( "end" ), m_end );
2605  out.WriteAttribute( wxT( "chord" ), m_chord );
2606  out.WriteAttribute( wxT( "contourwidth" ), m_contourwidth * out.GetScale() );
2607  }
2608  else
2609  {
2610  }
2611 }
2612 
2613 void a2dEllipticArc::DoLoad( wxObject* parent, a2dIOHandlerXmlSerIn& parser, a2dXmlSer_flag xmlparts )
2614 {
2615  a2dWHCenter::DoLoad( parent, parser, xmlparts );
2616  if ( xmlparts == a2dXmlSer_attrib )
2617  {
2618  m_start = parser.GetAttributeValueDouble( wxT( "start" ) );
2619  m_end = parser.GetAttributeValueDouble( wxT( "end" ) );
2620  m_chord = parser.GetAttributeValueBool( wxT( "chord" ) );
2621  m_contourwidth = parser.GetAttributeValueDouble( wxT( "contourwidth" ), 0 ) * parser.GetScale() ;
2622  }
2623  else
2624  {
2625  }
2626 }
2627 #endif //wxART2D_USE_CVGIO
2628 
2630 {
2631  double xh = hitEvent.m_relx;
2632  double yh = hitEvent.m_rely;
2633 
2634  if ( m_height == 0 && m_width == 0 )
2635  {
2636  hitEvent.m_how = a2dHit::stock_nohit;
2637  return false;
2638  }
2639 
2640  if ( m_height == 0 || m_width == 0 )
2641  {
2642  hitEvent.m_how = a2dHit::stock_nohit;
2643  return false;
2644  }
2645 
2646  double pw = ic.GetWorldStrokeExtend();
2647  double margin = ic.GetTransformedHitMargin();
2648 
2649  double a = m_width / 2 + pw + margin ;
2650  double b = m_height / 2 + pw + margin;
2651  double c = wxSqr( xh / a ) + wxSqr( yh / b );
2652  if ( 1 > c )
2653  {
2654  double dx = xh;
2655  double dy = yh;
2656 
2657  double start, end, angle;
2658 
2659  start = wxDegToRad( m_start );
2660  end = wxDegToRad( m_end );
2661 
2662  double rx, ry;
2663  double c = m_height / m_width;
2664 
2665  rx = sqrt( dx * dx + ( dy * dy ) / ( c * c ) );
2666  ry = rx * c;
2667 
2668  if ( dx* ry == 0 && dy* rx == 0 )
2669  angle = 0;
2670  else
2671  angle = atan2( dy * rx, dx * ry );
2672 
2673  angle = angle - start;
2674  end = end - start;
2675 
2676  if ( angle <= 0 ) angle += 2.0 * wxPI;
2677 
2678  if ( end <= 0 ) end += 2.0 * wxPI;
2679  if ( start < 0 ) start += 2.0 * wxPI;
2680 
2681 
2682  angle = angle + start;
2683  end = end + start;
2684 
2685  if ( angle > start && angle < end )
2686 
2687  {
2688  hitEvent.m_how = a2dHit::stock_fill;
2689  return true;
2690  }
2691  }
2692 
2693  hitEvent.m_how = a2dHit::stock_nohit;
2694  return false;
2695 }
2696 
2697 bool a2dEllipticArc::DoStartEdit( wxUint16 editmode, wxEditStyle editstyle )
2698 {
2699  if ( m_flags.m_editable )
2700  {
2701  PROPID_IncludeChildren->SetPropertyToObject( this, false );
2702  if ( editmode == 1 )
2703  {
2704  double rx = m_width / 2 ;
2705  double ry = m_height / 2 ;
2706 
2707  double xs, ys, xe, ye ;
2708  xs = rx * cos ( wxDegToRad( m_start ) ) ;
2709  ys = ry * sin ( wxDegToRad( m_start ) ) ;
2710  xe = rx * cos ( wxDegToRad( m_end ) ) ;
2711  ye = ry * sin ( wxDegToRad( m_end ) ) ;
2712 
2713 
2714  m_flags.m_visiblechilds = true;
2716 
2717  a2dHandle* handle = NULL;
2718  Append( handle = new a2dHandle( this, xs * 3 / 4, ys * 3 / 4 , wxT( "startangle" ) ) );
2719  handle->SetLayer( m_layer );
2720  Append( handle = new a2dHandle( this, xe * 3 / 4, ye * 3 / 4 , wxT( "endangle" ) ) );
2721  handle->SetLayer( m_layer );
2722 
2723  m_childobjects->SetSpecificFlags( false, a2dCanvasOFlags::PRERENDERASCHILD, wxT( "a2dHandle" ) );
2724  m_childobjects->SetSpecificFlags( true, a2dCanvasOFlags::BIN2, wxT( "a2dHandle" ) );
2725  }
2726  return a2dWHCenter::DoStartEdit( editmode, editstyle );
2727  }
2728 
2729  return false;
2730 }
2731 
2732 void a2dEllipticArc::OnChar( wxKeyEvent& event )
2733 {
2734  if ( m_flags.m_editingCopy )
2735  {
2736  switch( event.GetKeyCode() )
2737  {
2738  case WXK_TAB:
2739  {
2740  wxUint16* editmode = PROPID_Editmode->GetPropertyValuePtr( this );
2741  if ( editmode )
2742  {
2743  ( *editmode )++;
2744  if ( ( *editmode ) > 1 ) ( *editmode ) = 0;
2745  ReStartEdit( ( *editmode ) );
2746  }
2747  break;
2748  }
2749  default:
2750  event.Skip();
2751  }
2752  }
2753  else
2754  event.Skip();
2755 }
2756 
2757 void a2dEllipticArc::OnHandleEvent( a2dHandleMouseEvent& event )
2758 {
2759  a2dIterC* ic = event.GetIterC();
2760 
2761  if ( m_flags.m_editingCopy )
2762  {
2763  a2dRestrictionEngine* restrict = GetHabitat()->GetRestrictionEngine();
2764 
2765  a2dHandle* draghandle = event.GetCanvasHandle();
2766 
2767  double xw, yw;
2768  xw = event.GetX();
2769  yw = event.GetY();
2770 
2771  a2dAffineMatrix atWorld = ic->GetTransform();
2772  a2dAffineMatrix inverse = ic->GetInverseTransform();
2773 
2774  double xwi;
2775  double ywi;
2776  inverse.TransformPoint( xw, yw, xwi, ywi );
2777 
2778  a2dEllipticArc* original = wxStaticCast( PROPID_Original->GetPropertyValue( this ).Get(), a2dEllipticArc );
2779 
2780  if ( event.GetMouseEvent().LeftUp() )
2781  {
2782  if ( draghandle->GetName() == wxT( "startangle" ) )
2783  {
2784  m_root->GetCommandProcessor()->Submit( new a2dCommand_SetCanvasProperty( original, PROPID_StartAngle, m_start ) );
2785  //original->SetStart( m_start );
2786  }
2787  else if ( draghandle->GetName() == wxT( "endangle" ) )
2788  {
2789  m_root->GetCommandProcessor()->Submit( new a2dCommand_SetCanvasProperty( original, PROPID_EndAngle, m_end ) );
2790  //original->SetEnd( m_end );
2791  }
2792  else
2793  event.Skip(); //maybe the base class handles
2794  }
2795  else if ( event.GetMouseEvent().Dragging() )
2796  {
2797  double xs, ys, xe, ye, rx, ry;
2798 
2799  if ( draghandle->GetName() == wxT( "startangle" ) )
2800  {
2801  //modify object
2802  double c;
2803  xs = xwi;
2804  ys = ywi;
2805 
2806  c = m_height / m_width;
2807 
2808  rx = sqrt( xs * xs + ( ys * ys ) / ( c * c ) );
2809  ry = rx * c;
2810 
2811  if ( xs* ry == 0 )
2812  {
2813  if ( ys * rx > 0 )
2814  m_start = 90;
2815  else
2816  m_start = 270;
2817  }
2818  else
2819  m_start = wxRadToDeg( atan2( ys * rx, xs * ry ) );
2820 
2821  if( restrict )
2822  restrict->RestrictAngle( &m_start, a2dRestrictionEngine::snapToPointAngle );
2823 
2824  xs = m_width / 2 * cos( wxDegToRad( m_start ) ) ;
2825  ys = m_height / 2 * sin( wxDegToRad( m_start ) ) ;
2826 
2827  draghandle->SetPosXY( xs * 3 / 4, ys * 3 / 4 );
2828  SetPending( true );
2829  }
2830  else if ( draghandle->GetName() == wxT( "endangle" ) )
2831  {
2832  //modify object
2833  double c;
2834  xe = xwi;
2835  ye = ywi;
2836 
2837  c = m_height / m_width;
2838 
2839  rx = sqrt( xe * xe + ( ye * ye ) / ( c * c ) );
2840  ry = rx * c;
2841 
2842  if ( xe* ry == 0 )
2843  {
2844  if ( ye * rx > 0 )
2845  m_end = 90;
2846  else
2847  m_end = 270;
2848  }
2849  else
2850  m_end = wxRadToDeg( atan2( ye * rx, xe * ry ) );
2851 
2852  if( restrict )
2853  restrict->RestrictAngle( &m_end, a2dRestrictionEngine::snapToPointAngle );
2854 
2855  xe = m_width / 2 * cos( wxDegToRad( m_end ) ) ;
2856  ye = m_height / 2 * sin( wxDegToRad( m_end ) ) ;
2857  draghandle->SetPosXY( xe * 3 / 4, ye * 3 / 4 );
2858  SetPending( true );
2859  }
2860  else
2861  event.Skip(); //maybe on the base class handles
2862  }
2863  else
2864  event.Skip(); //maybe on the base class handles
2865  }
2866  else
2867  {
2868  event.Skip();
2869  }
2870 }
2871 
2872 //----------------------------------------------------------------------------
2873 // a2dArc
2874 //----------------------------------------------------------------------------
2875 
2883 
2884 INITIALIZE_PROPERTIES( a2dArc, a2dCanvasObject )
2885 {
2886  PROPID_X1 = new a2dPropertyIdDouble( wxT( "X1" ),
2887  a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dArc::m_x1 ) );
2888  AddPropertyId( PROPID_X1 );
2889  PROPID_X2 = new a2dPropertyIdDouble( wxT( "X2" ),
2890  a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dArc::m_x2 ) );
2891  AddPropertyId( PROPID_X2 );
2892  PROPID_Y1 = new a2dPropertyIdDouble( wxT( "Y1" ),
2893  a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dArc::m_y1 ) );
2894  AddPropertyId( PROPID_Y1 );
2895  PROPID_Y2 = new a2dPropertyIdDouble( wxT( "Y2" ),
2896  a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dArc::m_y2 ) );
2897  AddPropertyId( PROPID_Y2 );
2898  PROPID_StartAngle = new a2dPropertyIdDouble( wxT( "StartAngle" ),
2900  a2dPropertyIdDouble::Get( &a2dArc::GetStartAngle ),
2901  a2dPropertyIdDouble::Set( &a2dArc::SetStartAngle ) );
2902  AddPropertyId( PROPID_StartAngle );
2903  PROPID_EndAngle = new a2dPropertyIdDouble( wxT( "EndAngle" ),
2905  a2dPropertyIdDouble::Get( &a2dArc::GetEndAngle ),
2906  a2dPropertyIdDouble::Set( &a2dArc::SetEndAngle ) );
2907  AddPropertyId( PROPID_EndAngle );
2908  PROPID_Chord = new a2dPropertyIdBool( wxT( "Chord" ),
2909  a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdBool::Mptr >( &a2dArc::m_chord ) );
2910  AddPropertyId( PROPID_Chord );
2911 
2912  return true;
2913 }
2914 
2915 BEGIN_EVENT_TABLE( a2dArc, a2dCanvasObject )
2916  EVT_CANVASHANDLE_MOUSE_EVENT( a2dArc::OnHandleEvent )
2917  EVT_CHAR( a2dArc::OnChar )
2918 END_EVENT_TABLE()
2919 
2921  : a2dCanvasObject()
2922 {
2923  m_x1 = 0;
2924  m_x2 = 0;
2925  m_y1 = 0;
2926  m_y2 = 0;
2927  m_chord = false;
2928  m_contourwidth = 0;
2929 }
2930 
2931 a2dArc::a2dArc( double xc, double yc, double radius, double start, double end, bool chord, double contourwidth )
2932  : a2dCanvasObject()
2933 {
2934  m_lworld.Translate( xc, yc );
2935 
2936  m_x1 = radius * cos ( wxDegToRad( start ) ) ;
2937  m_x2 = radius * cos ( wxDegToRad( end ) ) ;
2938  m_y1 = radius * sin ( wxDegToRad( start ) ) ;
2939  m_y2 = radius * sin ( wxDegToRad( end ) ) ;
2940  m_chord = chord;
2941  m_contourwidth = contourwidth;
2942 }
2943 
2944 a2dArc::a2dArc( double x1, double y1, double x2, double y2, double xc, double yc, bool chord, double contourwidth )
2945  : a2dCanvasObject()
2946 {
2947  m_lworld.Translate( xc, yc );
2948 
2949  double dx = x1 - xc;
2950  double dy = y1 - yc;
2951  double radius = sqrt( dx * dx + dy * dy );
2952 
2953  m_x1 = dx;
2954  m_y1 = dy;
2955 
2956  //adjust second point to have the same radius
2957  dx = x2 - xc;
2958  dy = y2 - yc;
2959  double end = atan2( dy, dx );
2960 
2961  m_x2 = radius * cos ( end ) ;
2962  m_y2 = radius * sin ( end ) ;
2963  m_chord = chord;
2964  m_contourwidth = contourwidth;
2965 }
2966 
2968 {
2969 }
2970 
2971 void a2dArc::SetRadius( double radius )
2972 {
2973  //adjust second point to have the same radius
2974  double dx = m_x1;
2975  double dy = m_y1;
2976 
2977  double start;
2978 
2979  if ( !dx && !dy )
2980  start = 0;
2981  else
2982  start = atan2( dy, dx );
2983 
2984  m_x1 = radius * cos ( start ) ;
2985  m_y1 = radius * sin ( start ) ;
2986 
2987  dx = m_x2;
2988  dy = m_y2;
2989 
2990  double end;
2991 
2992  if ( !dx && !dy )
2993  end = 0;
2994  else
2995  end = atan2( dy, dx );
2996 
2997  m_x2 = radius * cos ( end ) ;
2998  m_y2 = radius * sin ( end ) ;
2999 }
3000 
3001 double a2dArc::GetRadius() const
3002 {
3003  return sqrt( m_x1 * m_x1 + m_y1 * m_y1 );
3004 }
3005 
3006 void a2dArc::SetChord( bool chord )
3007 {
3008  m_chord = chord;
3009  SetPending( true );
3010 }
3011 
3012 void a2dArc::Set( double xs, double ys, double xm, double ym, double xe, double ye )
3013 {
3014  double radius;
3015  double center_x, center_y;
3016  double beginrad, midrad, endrad, phit;
3017 
3018  double ax, ay, bx, by, cx, cy;
3019  double ax2, ay2, bx2, by2, cx2, cy2;
3020  double d;
3021  bool straight = false;
3022 
3023  ax = xs; ay = ys; ax2 = pow( ax, 2 ); ay2 = pow( ay, 2 );
3024  bx = xm; by = ym; bx2 = pow( bx, 2 ); by2 = pow( by, 2 );
3025  cx = xe; cy = ye; cx2 = pow( cx, 2 ); cy2 = pow( cy, 2 );
3026 
3027  if ( ax == cx && ay == cy )
3028  {
3029  //assume the middle is exact 180 opposite.
3030  center_x = ( bx + ax ) / 2.0;
3031  center_y = ( by + ay ) / 2.0;
3032  radius = sqrt( pow( bx - ax, 2 ) + pow( by - ay, 2 ) ) / 2.0;
3033  }
3034  else
3035  {
3036  d = 2 * ( ay * cx + by * ax - by * cx - ay * bx - cy * ax + cy * bx );
3037 
3038  if ( fabs( d ) < a2dACCUR ) // (infinite radius)
3039  {
3040  d = a2dACCUR;
3041  straight = true;
3042  }
3043 
3044  center_x = ( by * ax2 - cy * ax2 - by2 * ay + cy2 * ay + bx2 * cy + ay2 * by
3045  + cx2 * ay - cy2 * by - cx2 * by - bx2 * ay + by2 * cy - ay2 * cy
3046  ) / d;
3047 
3048  center_y = ( ax2 * cx + ay2 * cx + bx2 * ax - bx2 * cx + by2 * ax - by2 * cx
3049  - ax2 * bx - ay2 * bx - cx2 * ax + cx2 * bx - cy2 * ax + cy2 * bx
3050  ) / d ;
3051 
3052  radius = sqrt( pow( ax - center_x, 2 ) + pow( ay - center_y, 2 ) );
3053  }
3054 
3055  if ( radius )
3056  {
3057  //beginrad between PI and -PI, assume counterclockwise, make endrad > beginrad.
3058  beginrad = atan2( ys - center_y, xs - center_x );
3059  midrad = atan2( ym - center_y, xm - center_x );
3060  endrad = atan2( ye - center_y, xe - center_x );
3061 
3062  double mr, er;
3063 
3064  //if going counterclockwise from begin to end we pass trough middle => counterclockwise
3065  //if going counterclockwise from begin to end we do NOT pass trough middle => clockwise
3066 
3067  //rotate such that beginrad = zero
3068  mr = midrad - beginrad;
3069  er = endrad - beginrad;
3070 
3071  //make positive
3072  if ( mr <= 0 ) mr += 2.0 * M_PI;
3073  if ( er <= 0 ) er += 2.0 * M_PI;
3074 
3075  bool counterclock;
3076 
3077  //middle gives direction
3078  if ( mr < er )
3079  {
3080  phit = er; //counterclockwise
3081  counterclock = true;
3082  }
3083  else
3084  {
3085  phit = -( 2.0 * M_PI - er ); //Clockwise
3086  counterclock = false;
3087  }
3088 
3089  if ( counterclock )
3090  {
3091  m_x1 = xs - center_x;
3092  m_y1 = ys - center_y;
3093  m_x2 = xe - center_x;
3094  m_y2 = ye - center_y;
3095  }
3096  else
3097  {
3098  m_x2 = xs - center_x;
3099  m_y2 = ys - center_y;
3100  m_x1 = xe - center_x;
3101  m_y1 = ye - center_y;
3102  }
3103  }
3104  else
3105  {
3106  //! todo what if this is the case.
3107  wxASSERT( radius );
3108  }
3109 
3110  m_lworld.Translate( center_x, center_y );
3111 }
3112 
3113 a2dArc::a2dArc( const a2dArc& other, CloneOptions options, a2dRefMap* refs )
3114  : a2dCanvasObject( other, options, refs )
3115 {
3116  m_x1 = other.m_x1;
3117  m_y1 = other.m_y1;
3118  m_x2 = other.m_x2;
3119  m_y2 = other.m_y2;
3120  m_chord = other.m_chord;
3122 }
3123 
3125 {
3126  return new a2dArc( *this, options, refs );
3127 };
3128 
3130 {
3131  double start;
3132  if ( !m_x1 && !m_y1 )
3133  start = 0;
3134  else
3135  start = atan2( m_y1, m_x1 );
3136 
3137  return start;
3138 }
3139 
3140 double a2dArc::GetEndAngle() const
3141 {
3142  double end;
3143  if ( !m_x2 && !m_y2 )
3144  end = 0;
3145  else
3146  end = atan2( m_y2, m_x2 );
3147 
3148  return end;
3149 }
3150 
3151 void a2dArc::SetStartAngle( double a )
3152 {
3153  double radius = GetRadius();
3154  m_x1 = radius * cos ( a ) ;
3155  m_y1 = radius * sin ( a ) ;
3156 }
3157 
3158 void a2dArc::SetEndAngle( double a )
3159 {
3160  double radius = GetRadius();
3161  m_x2 = radius * cos ( a ) ;
3162  m_y2 = radius * sin ( a ) ;
3163 }
3164 
3166 {
3167  double dx = m_x1;
3168 
3169  double dy = m_y1;
3170 
3171  double start;
3172  double radius = sqrt( dx * dx + dy * dy );
3173 
3174  if ( !dx && !dy )
3175  start = 0;
3176  else
3177  start = atan2( dy, dx );
3178 
3179  dx = m_x2;
3180  dy = m_y2;
3181 
3182  double end;
3183 
3184  if ( !dx && !dy )
3185  end = 0;
3186  else
3187  end = atan2( dy, dx );
3188 
3189  end = end - start;
3190  if ( end <= 0 ) end += 2.0 * wxPI;
3191 
3192  if ( start < 0 ) start += 2.0 * wxPI;
3193 
3194  end = end + start;
3195 
3196  return a2dPoint2D( radius * cos( ( end - start ) / 2 ), radius * sin( ( end - start ) / 2 ) );
3197 }
3198 
3199 
3200 a2dVertexList* a2dArc::GetAsVertexList( bool& returnIsPolygon ) const
3201 {
3202  returnIsPolygon = true;
3203  a2dVertexList* pointlist = new a2dVertexList();
3204 
3205  a2dCanvasObjectList* vectorpaths = GetAsCanvasVpaths();
3206  a2dVpath* segments = wxStaticCast( vectorpaths->front().Get(), a2dVectorPath ) ->GetSegments();
3207  segments->ConvertToLines();
3208  a2dLineSegment* point;
3209  unsigned int i;
3210  for ( i = 0; i < segments->size(); i++ )
3211  {
3212  a2dVpathSegment* seg = segments->Item( i );
3213  point = new a2dLineSegment( seg->m_x1, seg->m_y1 );
3214  pointlist->push_back( point );
3215  }
3216 
3217  delete vectorpaths;
3218 
3219  return pointlist;
3220 }
3221 
3223 {
3224  a2dAffineMatrix pworld;
3225  if ( transform )
3226  pworld = m_lworld;
3227 
3228  //TODO how to approximate ellipse with spline
3229 
3230  a2dVpath* segments = new a2dVpath();
3231 
3232  a2dVpathSegment* seg;
3233 
3234  double dx = m_x1;
3235 
3236  double dy = m_y1;
3237 
3238  double start;
3239  double radius = sqrt( dx * dx + dy * dy );
3240 
3241  if ( !dx && !dy )
3242  start = 0;
3243  else
3244  start = atan2( dy, dx );
3245 
3246  dx = m_x2;
3247  dy = m_y2;
3248 
3249  double end;
3250 
3251  if ( !dx && !dy )
3252  end = 0;
3253  else
3254  end = atan2( dy, dx );
3255 
3256  end = end - start;
3257  if ( end <= 0 ) end += 2.0 * wxPI;
3258 
3259  if ( start < 0 ) start += 2.0 * wxPI;
3260 
3261  end = end + start;
3262 
3263  double dphi = wxPI * 2.0 / CIRCLE_STEPS;
3264  int steps = ( int ) ( ( end - start ) / dphi );
3265  if ( steps == 0 )
3266  steps = 1;
3267  dphi = ( end - start ) / steps; //make it fit.
3268 
3269  double theta = start;
3270  int i;
3271 
3272 
3273  double x, y;
3274 
3275  for ( i = 0; i < steps + 1; i++ )
3276  {
3277  pworld.TransformPoint( radius * cos ( theta ), radius * sin ( theta ), x, y );
3278  if ( i == 0 )
3279  seg = new a2dVpathSegment( x, y , a2dPATHSEG_MOVETO );
3280  else
3281  seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
3282  segments->push_back( seg );
3283  theta = theta + dphi;
3284  }
3285 
3286 
3287  if ( !m_chord )
3288 
3289  {
3290  pworld.TransformPoint( 0, 0, x, y );
3291 
3293  segments->push_back( seg );
3294  }
3295 
3296  a2dVectorPath* canpath = new a2dVectorPath( segments );
3297  canpath->SetStroke( this->GetStroke() );
3298  canpath->SetFill( this->GetFill() );
3299  canpath->SetLayer( m_layer );
3300  canpath->SetContourWidth( GetContourWidth() );
3301  canpath->SetPathType( a2dPATH_END_ROUND );
3302  a2dCanvasObjectList* canpathlist = new a2dCanvasObjectList();
3303  canpathlist->push_back( canpath );
3304  return canpathlist;
3305 }
3306 
3308 {
3309  a2dBoundingBox bbox;
3310 
3311  double dx = m_x1;
3312  double dy = m_y1;
3313 
3314  double start;
3315  double end;
3316  double radius = sqrt( dx * dx + dy * dy );
3317 
3318 
3319  if ( m_x1 == m_x2 && m_y1 == m_y2 )
3320  {
3321  start = 0;
3322  end = 2.0 * wxPI;
3323  }
3324  else
3325  {
3326  if ( !dx && !dy )
3327  start = 0;
3328  else
3329  start = atan2( dy, dx );
3330 
3331  dx = m_x2;
3332  dy = m_y2;
3333 
3334  if ( !dx && !dy )
3335  end = 0;
3336  else
3337  end = atan2( dy, dx );
3338 
3339  end = end - start;
3340  if ( end <= 0 ) end += 2.0 * wxPI;
3341  end += start;
3342  }
3343 
3344  if ( !m_chord )
3345  bbox.Expand( 0, 0 );
3346  //start point
3347  bbox.Expand( radius * cos ( start ), radius * sin ( start ) );
3348  //end point
3349  bbox.Expand( radius * cos ( end ), radius * sin ( end ) );
3350 
3351  //outer points
3352  if ( InArc( 0, start, end, false ) )
3353  bbox.Expand( radius, 0 );
3354  if ( InArc( wxPI / 2, start, end, false ) )
3355  bbox.Expand( 0, radius );
3356  if ( InArc( wxPI, start, end, false ) )
3357  bbox.Expand( -radius, 0 );
3358  if ( InArc( 1.5 * wxPI, start, end, false ) )
3359  bbox.Expand( 0, -radius );
3360 
3361  if ( !( flags & a2dCANOBJ_BBOX_EDIT ) )
3362  {
3363  if ( m_contourwidth > 0 )
3364  bbox.Enlarge( m_contourwidth / 2 );
3365  }
3366 
3367  return bbox;
3368 }
3369 
3370 bool a2dArc::DoUpdate( UpdateMode mode, const a2dBoundingBox& childbox, const a2dBoundingBox& clipbox, const a2dBoundingBox& propbox )
3371 {
3372  //klion canvas\src\canprim.cpp(4221) : warning C4189: 'radius' : local variable is initialized but not referenced
3373 // double radius = sqrt(m_x1*m_x1+m_y1*m_y1);
3374  // Note: This calculates something different than the mapped untransformed
3375  // Bounding box. The box caclulated here might be smaller.
3376  if ( !m_bbox.GetValid() )
3377  {
3378  double x, y;
3379  double dx = m_x1;
3380  double dy = m_y1;
3381 
3382  double start;
3383  double end;
3384  double radius = sqrt( dx * dx + dy * dy );
3385  radius += m_contourwidth / 2;
3386 
3387  if ( m_x1 == m_x2 && m_y1 == m_y2 )
3388  {
3389  start = 0;
3390  end = 2.0 * wxPI;
3391  }
3392  else
3393  {
3394  if ( !dx && !dy )
3395  start = 0;
3396  else
3397  start = atan2( dy, dx );
3398 
3399  dx = m_x2;
3400  dy = m_y2;
3401 
3402  if ( !dx && !dy )
3403  end = 0;
3404  else
3405  end = atan2( dy, dx );
3406  }
3407 
3408  double alphax = atan2( m_lworld.GetValue( 1, 0 ), m_lworld.GetValue( 0, 0 ) );
3409  double alphay = atan2( m_lworld.GetValue( 1, 1 ), m_lworld.GetValue( 0, 1 ) );
3410 
3411  //since that is how the filled part is defined.
3412  if ( end <= start ) end += 2.0 * wxPI;
3413  if ( alphax <= start ) alphax += wxPI;
3414  if ( alphay <= start ) alphay += wxPI;
3415  if ( alphax >= end ) alphax -= wxPI;
3416  if ( alphay >= end ) alphay -= wxPI;
3417 
3418  //start point
3419  m_lworld.TransformPoint( radius * cos ( start ), radius * sin ( start ), x, y );
3420  m_bbox.Expand( x, y );
3421  //end point
3422  m_lworld.TransformPoint( radius * cos ( end ), radius * sin ( end ), x, y );
3423  m_bbox.Expand( x, y );
3424 
3425  //outer points
3426  if ( InArc( alphax, start, end, false ) )
3427  {
3428  m_lworld.TransformPoint( radius * cos ( alphax ), radius * sin ( alphax ), x, y );
3429  m_bbox.Expand( x, y );
3430  }
3431  alphax += wxPI;
3432  if ( InArc( alphax, start, end, false ) )
3433  {
3434  m_lworld.TransformPoint( radius * cos ( alphax ), radius * sin ( alphax ), x, y );
3435  m_bbox.Expand( x, y );
3436  }
3437  alphax -= 2 * wxPI;
3438  if ( InArc( alphax, start, end, false ) )
3439  {
3440  m_lworld.TransformPoint( radius * cos ( alphax ), radius * sin ( alphax ), x, y );
3441  m_bbox.Expand( x, y );
3442  }
3443  if ( InArc( alphay, start, end, false ) )
3444  {
3445  m_lworld.TransformPoint( radius * cos ( alphay ), radius * sin ( alphay ), x, y );
3446  m_bbox.Expand( x, y );
3447  }
3448  alphay += wxPI;
3449  if ( InArc( alphay, start, end, false ) )
3450  {
3451  m_lworld.TransformPoint( radius * cos ( alphay ), radius * sin ( alphay ), x, y );
3452  m_bbox.Expand( x, y );
3453  }
3454  alphay -= 2 * wxPI;
3455  if ( InArc( alphay, start, end, false ) )
3456  {
3457  m_lworld.TransformPoint( radius * cos ( alphay ), radius * sin ( alphay ), x, y );
3458  m_bbox.Expand( x, y );
3459  }
3460 
3461  return true;
3462  }
3463 
3464  return false;
3465 }
3466 
3467 void a2dArc::DoRender( a2dIterC& ic, OVERLAP clipparent )
3468 {
3469  if ( GetContourWidth() )
3470  {
3471  if ( m_flags.m_editingCopy && m_chord )
3472  m_chord = false;
3473 
3474  a2dCanvasObjectList* vectorpaths = GetAsCanvasVpaths( false );
3475 
3476  if ( m_flags.m_editingCopy && m_chord )
3477  m_chord = true;
3478 
3479  forEachIn( a2dCanvasObjectList, vectorpaths )
3480  {
3481  a2dVectorPath* obj = wxStaticCast( ( *iter ).Get(), a2dVectorPath );
3482  obj->DoRender( ic, clipparent );
3483  }
3484  delete vectorpaths;
3485  }
3486  else if ( m_flags.m_editingCopy && m_chord )
3487  {
3488  m_chord = false;
3489  ic.GetDrawer2D()->DrawArc( m_x1, m_y1, m_x2, m_y2, 0, 0, m_chord );
3490  m_chord = true;
3491  }
3492  else
3493  ic.GetDrawer2D()->DrawArc( m_x1, m_y1, m_x2, m_y2, 0, 0, m_chord );
3494 
3495 }
3496 
3497 #if wxART2D_USE_CVGIO
3498 void a2dArc::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut& out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
3499 {
3500  a2dCanvasObject::DoSave( parent, out, xmlparts, towrite );
3501  if ( xmlparts == a2dXmlSer_attrib )
3502  {
3503  out.WriteAttribute( wxT( "x1" ), m_x1 * out.GetScale() );
3504  out.WriteAttribute( wxT( "y1" ), m_y1 * out.GetScale() );
3505  out.WriteAttribute( wxT( "x2" ), m_x2 * out.GetScale() );
3506  out.WriteAttribute( wxT( "y2" ), m_y2 * out.GetScale() );
3507  out.WriteAttribute( wxT( "contourwidth" ), m_contourwidth * out.GetScale() );
3508  }
3509  else
3510  {
3511  }
3512 }
3513 
3514 void a2dArc::DoLoad( wxObject* parent, a2dIOHandlerXmlSerIn& parser, a2dXmlSer_flag xmlparts )
3515 {
3516  a2dCanvasObject::DoLoad( parent, parser, xmlparts );
3517  if ( xmlparts == a2dXmlSer_attrib )
3518  {
3519  m_x1 = parser.GetAttributeValueDouble( wxT( "x1" ) ) * parser.GetScale() ;
3520  m_y1 = parser.GetAttributeValueDouble( wxT( "y1" ) ) * parser.GetScale() ;
3521  m_x2 = parser.GetAttributeValueDouble( wxT( "x2" ) ) * parser.GetScale() ;
3522  m_y2 = parser.GetAttributeValueDouble( wxT( "y2" ) ) * parser.GetScale() ;
3523  m_contourwidth = parser.GetAttributeValueDouble( wxT( "contourwidth" ), 0 ) * parser.GetScale();
3524  }
3525  else
3526  {
3527  }
3528 }
3529 #endif //wxART2D_USE_CVGIO
3530 
3532 {
3533  double xh = hitEvent.m_relx;
3534  double yh = hitEvent.m_rely;
3535  double pw = ic.GetWorldStrokeExtend();
3536 
3537  double dx = m_x1;
3538  double dy = m_y1;
3539  double radius = sqrt( dx * dx + dy * dy );
3540  double margin = ic.GetTransformedHitMargin();
3541 
3542  if ( radius + pw + margin > sqrt( ( xh * xh ) + ( yh * yh ) ) )
3543  {
3544 
3545  dx = xh;
3546  dy = yh;
3547 
3548  double angle;
3549 
3550  if ( !dx && !dy )
3551  angle = 0;
3552  else
3553  angle = atan2( dy, dx );
3554 
3555  dx = m_x1;
3556  dy = m_y1;
3557 
3558  double start;
3559 
3560  if ( !dx && !dy )
3561  start = 0;
3562  else
3563  start = atan2( dy, dx );
3564 
3565  dx = m_x2;
3566  dy = m_y2;
3567 
3568  double end;
3569 
3570  if ( !dx && !dy )
3571  end = 0;
3572  else
3573  end = atan2( dy, dx );
3574 
3575  //rotate such that start = zero
3576  angle = angle - start;
3577  end = end - start;
3578 
3579  if ( angle <= 0 ) angle += 2.0 * wxPI;
3580  if ( end <= 0 ) end += 2.0 * wxPI;
3581  if ( angle >= 2.0 * M_PI ) angle -= 2.0 * M_PI;
3582  if ( end >= 2.0 * M_PI ) end -= 2.0 * M_PI;
3583 
3584  //middle gives direction
3585  if ( angle < end )
3586  {
3587  if ( m_chord )
3588  {
3589  if ( radius < sqrt( ( xh * xh ) + ( yh * yh ) ) )
3591  else if ( radius > sqrt( ( xh * xh ) + ( yh * yh ) ) && radius - pw - margin < sqrt( ( xh * xh ) + ( yh * yh ) ) )
3592  hitEvent.m_how = a2dHit::stock_strokeinside;
3593  else
3594  {
3595  hitEvent.m_how = a2dHit::stock_nohit;
3596  return false;
3597  }
3598  }
3599  else
3600  {
3601  if ( radius < sqrt( ( xh * xh ) + ( yh * yh ) ) )
3603  if ( radius > sqrt( ( xh * xh ) + ( yh * yh ) ) && radius - pw - margin < sqrt( ( xh * xh ) + ( yh * yh ) ) )
3604  hitEvent.m_how = a2dHit::stock_strokeinside;
3605  else
3606  hitEvent.m_how = a2dHit::stock_fill;
3607  }
3608  return true;
3609  }
3610  hitEvent.m_how = a2dHit::stock_nohit;
3611  return false;
3612  }
3613  else
3614  {
3615  hitEvent.m_how = a2dHit::stock_nohit;
3616  return false;
3617  }
3618 }
3619 
3620 bool a2dArc::DoStartEdit( wxUint16 editmode, wxEditStyle editstyle )
3621 {
3622  if ( m_flags.m_editable )
3623  {
3624  PROPID_IncludeChildren->SetPropertyToObject( this, false );
3625  if ( editmode == 1 )
3626  {
3627  m_flags.m_visiblechilds = true;
3629 
3630  a2dHandle* handle = NULL;
3631  Append( handle = new a2dHandle( this, GetX1() * 3 / 4, GetY1() * 3 / 4, wxT( "startangle" ) ) );
3632  handle->SetLayer( m_layer );
3633  Append( handle = new a2dHandle( this, GetX2() * 3 / 4, GetY2() * 3 / 4, wxT( "endangle" ) ) );
3634  handle->SetLayer( m_layer );
3635 
3636  m_childobjects->SetSpecificFlags( false, a2dCanvasOFlags::PRERENDERASCHILD, wxT( "a2dHandle" ) );
3637  m_childobjects->SetSpecificFlags( true, a2dCanvasOFlags::BIN2, wxT( "a2dHandle" ) );
3638  }
3639 
3640  PROPID_Allowrotation->SetPropertyToObject( this, true );
3641  PROPID_Allowskew->SetPropertyToObject( this, true );
3642 
3643  return a2dCanvasObject::DoStartEdit( editmode, editstyle );
3644  }
3645 
3646  return false;
3647 }
3648 
3649 void a2dArc::OnChar( wxKeyEvent& event )
3650 {
3651  if ( m_flags.m_editingCopy )
3652  {
3653  switch( event.GetKeyCode() )
3654  {
3655  case WXK_TAB:
3656  {
3657  wxUint16* editmode = PROPID_Editmode->GetPropertyValuePtr( this );
3658  if ( editmode )
3659  {
3660  ( *editmode )++;
3661  if ( ( *editmode ) > 1 ) ( *editmode ) = 0;
3662  ReStartEdit( ( *editmode ) );
3663  }
3664  break;
3665  }
3666  default:
3667  event.Skip();
3668  }
3669  }
3670  else
3671  event.Skip();
3672 }
3673 
3674 void a2dArc::OnHandleEvent( a2dHandleMouseEvent& event )
3675 {
3676  a2dIterC* ic = event.GetIterC();
3677 
3678  if ( m_flags.m_editingCopy )
3679  {
3680  a2dRestrictionEngine* restrictEngine = GetHabitat()->GetRestrictionEngine();
3681 
3682  a2dHandle* draghandle = event.GetCanvasHandle();
3683 
3684  double xw, yw;
3685  xw = event.GetX();
3686  yw = event.GetY();
3687 
3688  a2dAffineMatrix atWorld = ic->GetTransform();
3689  a2dAffineMatrix inverse = ic->GetInverseTransform();
3690 
3691  double xwi;
3692  double ywi;
3693  inverse.TransformPoint( xw, yw, xwi, ywi );
3694 
3695  a2dArc* original = wxStaticCast( PROPID_Original->GetPropertyValue( this ).Get(), a2dArc );
3696 
3697  if ( event.GetMouseEvent().LeftUp() )
3698  {
3699  if ( draghandle->GetName() == wxT( "startangle" ) )
3700  {
3701  double start = atan2( m_y1, m_x1 ); //angle
3703  }
3704  else if ( draghandle->GetName() == wxT( "endangle" ) )
3705  {
3706  double end = atan2( m_y2, m_x2 ); //angle
3708  }
3709  else
3710  event.Skip(); //maybe the base class handles
3711  }
3712  else if ( event.GetMouseEvent().Dragging() )
3713  {
3714  if ( restrictEngine )
3715  restrictEngine->RestrictPoint( xwi, ywi );
3716 
3717  if ( draghandle->GetName() == wxT( "startangle" ) )
3718  {
3719  //modify object
3720  double dx, dy;
3721  dx = xwi;
3722  dy = ywi;
3723 
3724  double end = atan2( dy, dx ); //angle
3725 
3726  dx = GetX1();
3727  dy = GetY1();
3728 
3729  double radius = sqrt( dx * dx + dy * dy );
3730  dx = radius * cos ( end );
3731  dy = radius * sin ( end );
3732 
3733  SetX1( dx );
3734  SetY1( dy );
3735 
3736  draghandle->SetPosXY( GetX1() * 3 / 4, GetY1() * 3 / 4 );
3737  SetPending( true );
3738  }
3739  else if ( draghandle->GetName() == wxT( "endangle" ) )
3740  {
3741  //modify object
3742  double dx, dy;
3743  dx = xwi;
3744  dy = ywi;
3745 
3746  double end = atan2( dy, dx ); //angle
3747 
3748  dx = GetX2();
3749  dy = GetY2();
3750 
3751  double radius = sqrt( dx * dx + dy * dy );
3752  dx = radius * cos ( end );
3753  dy = radius * sin ( end );
3754  SetX2( dx );
3755  SetY2( dy );
3756 
3757  draghandle->SetPosXY( GetX2() * 3 / 4, GetY2() * 3 / 4 );
3758  SetPending( true );
3759  }
3760  else
3761  event.Skip(); //maybe on the base class handles
3762  }
3763  else
3764  event.Skip(); //maybe on the base class handles
3765  }
3766  else
3767  {
3768  event.Skip();
3769  }
3770 }
3771 
3772 //----------------------------------------------------------------------------
3773 // a2dSLine
3774 //----------------------------------------------------------------------------
3775 a2dPropertyIdDouble* a2dSLine::PROPID_X1 = NULL;
3776 a2dPropertyIdDouble* a2dSLine::PROPID_X2 = NULL;
3777 a2dPropertyIdDouble* a2dSLine::PROPID_Y1 = NULL;
3778 a2dPropertyIdDouble* a2dSLine::PROPID_Y2 = NULL;
3779 
3780 INITIALIZE_PROPERTIES( a2dSLine, a2dCanvasObject )
3781 {
3782  PROPID_X1 = new a2dPropertyIdDouble( wxT( "X1" ),
3783  a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dSLine::m_x1 ) );
3784  AddPropertyId( PROPID_X1 );
3785  PROPID_X2 = new a2dPropertyIdDouble( wxT( "X2" ),
3786  a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dSLine::m_x2 ) );
3787  AddPropertyId( PROPID_X2 );
3788  PROPID_Y1 = new a2dPropertyIdDouble( wxT( "Y1" ),
3789  a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dSLine::m_y1 ) );
3790  AddPropertyId( PROPID_Y1 );
3791  PROPID_Y2 = new a2dPropertyIdDouble( wxT( "Y2" ),
3792  a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dSLine::m_y2 ) );
3793  AddPropertyId( PROPID_Y2 );
3794 
3795  return true;
3796 }
3797 
3798 BEGIN_EVENT_TABLE( a2dSLine, a2dCanvasObject )
3799  EVT_CANVASHANDLE_MOUSE_EVENT( a2dSLine::OnHandleEvent )
3800  EVT_CHAR( a2dSLine::OnChar )
3801 END_EVENT_TABLE()
3802 
3803 a2dSLine::a2dSLine()
3804  : a2dCanvasObject()
3805 {
3806  m_x1 = 0;
3807  m_y1 = 0;
3808  m_x2 = 0;
3809  m_y2 = 0;
3810  m_contourwidth = 0;
3811  m_pathtype = a2dPATH_END_SQAURE;
3812 }
3813 
3814 a2dSLine::a2dSLine( double x1, double y1, double x2, double y2, double contourwidth )
3815  : a2dCanvasObject()
3816 {
3817  m_x1 = x1;
3818  m_y1 = y1;
3819  m_x2 = x2;
3820  m_y2 = y2;
3821  m_contourwidth = contourwidth;
3822  m_pathtype = a2dPATH_END_SQAURE;
3823 }
3824 
3826 {
3827 }
3828 
3829 a2dSLine::a2dSLine( const a2dSLine& other, CloneOptions options, a2dRefMap* refs )
3830  : a2dCanvasObject( other, options, refs )
3831 {
3832  m_x1 = other.m_x1;
3833  m_y1 = other.m_y1;
3834  m_x2 = other.m_x2;
3835  m_y2 = other.m_y2;
3837  m_pathtype = other.m_pathtype;
3838 }
3839 
3841 {
3842  return new a2dSLine( *this, options, refs );
3843 };
3844 
3845 double a2dSLine::GetPosX1( bool transform ) const
3846 {
3847  double x, y;
3848  if ( transform )
3849  m_lworld.TransformPoint( m_x1, m_y1, x, y );
3850  else
3851  x = m_x1;
3852  return x;
3853 }
3854 
3855 double a2dSLine::GetPosY1( bool transform ) const
3856 {
3857  double x, y;
3858  if ( transform )
3859  m_lworld.TransformPoint( m_x1, m_y1, x, y );
3860  else
3861  y = m_y1;
3862  return y;
3863 }
3864 
3865 double a2dSLine::GetPosX2( bool transform ) const
3866 {
3867  double x, y;
3868  if ( transform )
3869  m_lworld.TransformPoint( m_x2, m_y2, x, y );
3870  else
3871  x = m_x2;
3872  return x;
3873 }
3874 
3875 double a2dSLine::GetPosY2( bool transform ) const
3876 {
3877  double x, y;
3878  if ( transform )
3879  m_lworld.TransformPoint( m_x2, m_y2, x, y );
3880  else
3881  y = m_y2;
3882  return y;
3883 }
3884 
3886 {
3889 
3891 }
3892 
3893 double a2dSLine::GetLength() const
3894 {
3895  double x1, y1, x2, y2;
3896  m_lworld.TransformPoint( m_x1, m_y1, x1, y1 );
3897  m_lworld.TransformPoint( m_x2, m_y2, x2, y2 );
3898 
3899  return sqrt( wxSqr( x2 - x1 ) + wxSqr( y2 - y1 ) );
3900 }
3901 
3902 void a2dSLine::SetPosXY1( double x, double y, bool afterinversion )
3903 {
3904  if ( afterinversion )
3905  {
3906  a2dAffineMatrix inverse = m_lworld;
3907  inverse.Invert();
3908  inverse.TransformPoint( x, y, x, y );
3909  }
3910 
3911  m_x1 = x;
3912  m_y1 = y;
3913 
3914  SetPending( true );
3915 }
3916 
3917 void a2dSLine::SetPosXY2( double x, double y, bool afterinversion )
3918 {
3919  if ( afterinversion )
3920  {
3921  a2dAffineMatrix inverse = m_lworld;
3922  inverse.Invert();
3923  inverse.TransformPoint( x, y, x, y );
3924  }
3925 
3926  m_x2 = x;
3927  m_y2 = y;
3928 
3929  SetPending( true );
3930 }
3931 
3932 void a2dSLine::SetPosXY12( double x1, double y1, double x2, double y2, bool afterinversion )
3933 {
3934  if ( afterinversion )
3935  {
3936  a2dAffineMatrix inverse = m_lworld;
3937  inverse.Invert();
3938  inverse.TransformPoint( x1, y1, x1, y1 );
3939  inverse.TransformPoint( x2, y2, x2, y2 );
3940  }
3941 
3942  m_x1 = x1;
3943  m_y1 = y1;
3944  m_x2 = x2;
3945  m_y2 = y2;
3946 
3947  SetPending( true );
3948 }
3949 
3951 {
3952  a2dAffineMatrix pworld;
3953  if ( transform )
3954  pworld = m_lworld;
3955 
3956  a2dVpath* segments = new a2dVpath();
3957 
3958  a2dVpathSegment* seg;
3959 
3960  seg = new a2dVpathSegment( m_x1, m_y1, a2dPATHSEG_MOVETO );
3961  segments->push_back( seg );
3963  segments->push_back( seg );
3964 
3965  segments->Transform( pworld );
3966 
3967  a2dVectorPath* canpath = new a2dVectorPath( segments );
3968  canpath->SetStroke( this->GetStroke() );
3969  canpath->SetFill( this->GetFill() );
3970  canpath->SetLayer( m_layer );
3971  canpath->SetContourWidth( GetContourWidth() );
3972  canpath->SetPathType( a2dPATH_END_ROUND );
3973  a2dCanvasObjectList* canpathlist = new a2dCanvasObjectList();
3974  canpathlist->push_back( canpath );
3975  return canpathlist;
3976 }
3977 
3979 {
3980  a2dBoundingBox bbox;
3981  bbox.Expand( m_x1 , m_y1 );
3982  bbox.Expand( m_x2 , m_y2 );
3983 
3984  if ( !( flags & a2dCANOBJ_BBOX_EDIT ) )
3985  {
3986  if ( m_contourwidth > 0 )
3987  bbox.Enlarge( m_contourwidth / 2 );
3988  }
3989 
3990  return bbox;
3991 }
3992 
3993 void a2dSLine::DoRender( a2dIterC& ic, OVERLAP clipparent )
3994 {
3995  if ( GetContourWidth() )
3996  {
3997  a2dLine line1( m_x1, m_y1, m_x2, m_y2 );
3998  line1.CalculateLineParameters();
3999  double distance = m_contourwidth / 2.0;
4000  a2dPoint2D offsetpoint1left = a2dPoint2D( m_x1, m_y1 );
4001  a2dPoint2D offsetpoint1right = a2dPoint2D( m_x1, m_y1 );
4002  a2dPoint2D offsetpoint2left = a2dPoint2D( m_x2, m_y2 );
4003  a2dPoint2D offsetpoint2right = a2dPoint2D( m_x2, m_y2 );
4004  line1.Virtual_Point( offsetpoint1left, distance );
4005  line1.Virtual_Point( offsetpoint1right, -distance );
4006  line1.Virtual_Point( offsetpoint2left, distance );
4007  line1.Virtual_Point( offsetpoint2right, -distance );
4008 
4009  a2dVertexArray contour;
4010  contour.AddPoint( offsetpoint1left );
4011  contour.AddPoint( offsetpoint2left );
4012  contour.AddPoint( offsetpoint2right );
4013  contour.AddPoint( offsetpoint1right );
4014 
4015  ic.GetDrawer2D()->DrawPolygon( &contour );
4016  }
4017  else
4018  ic.GetDrawer2D()->DrawLine( m_x1, m_y1, m_x2, m_y2 );
4019 }
4020 
4021 bool a2dSLine::RestrictToObject( a2dIterC& ic, const a2dPoint2D& pointToSnapTo, a2dPoint2D& bestPointSofar, a2dSnapToWhatMask snapToWhat, double thresHoldWorld )
4022 {
4023  // object has disabled snap?
4024  if ( !m_flags.m_snap_to )
4025  return false;
4026 
4027  bool res = false;
4028  if ( snapToWhat & a2dRestrictionEngine::snapToStart )
4029  {
4030  double x, y;
4031  m_lworld.TransformPoint( m_x1, m_y1, x, y );
4032 
4033  res |= SetPointIfCloser( pointToSnapTo, a2dPoint2D( x, y ), bestPointSofar, thresHoldWorld );
4034  }
4035  if ( snapToWhat & a2dRestrictionEngine::snapToEnd )
4036  {
4037  double x, y;
4038  m_lworld.TransformPoint( m_x2, m_y2, x, y );
4039 
4040  //if within the threshold, do snap to pin position.
4041  res |= SetPointIfCloser( pointToSnapTo, a2dPoint2D( x, y ), bestPointSofar, thresHoldWorld );
4042  }
4043 
4044  res |= a2dCanvasObject::RestrictToObject( ic, pointToSnapTo, bestPointSofar, snapToWhat, thresHoldWorld );
4045 
4046  return res;
4047 }
4048 
4049 #if wxART2D_USE_CVGIO
4050 void a2dSLine::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut& out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
4051 {
4052  a2dCanvasObject::DoSave( parent, out, xmlparts, towrite );
4053  if ( xmlparts == a2dXmlSer_attrib )
4054  {
4055  out.WriteAttribute( wxT( "x1" ), m_x1 * out.GetScale() );
4056  out.WriteAttribute( wxT( "y1" ), m_y1 * out.GetScale() );
4057  out.WriteAttribute( wxT( "x2" ), m_x2 * out.GetScale() );
4058  out.WriteAttribute( wxT( "y2" ), m_y2 * out.GetScale() );
4059  out.WriteAttribute( wxT( "contourwidth" ), m_contourwidth * out.GetScale() );
4060  }
4061  else
4062  {
4063  }
4064 }
4065 
4066 void a2dSLine::DoLoad( wxObject* parent, a2dIOHandlerXmlSerIn& parser, a2dXmlSer_flag xmlparts )
4067 {
4068  a2dCanvasObject::DoLoad( parent, parser, xmlparts );
4069  if ( xmlparts == a2dXmlSer_attrib )
4070  {
4071  m_x1 = parser.GetAttributeValueDouble( wxT( "x1" ) ) * parser.GetScale() ;
4072  m_y1 = parser.GetAttributeValueDouble( wxT( "y1" ) ) * parser.GetScale() ;
4073  m_x2 = parser.GetAttributeValueDouble( wxT( "x2" ) ) * parser.GetScale() ;
4074  m_y2 = parser.GetAttributeValueDouble( wxT( "y2" ) ) * parser.GetScale() ;
4075  m_contourwidth = parser.GetAttributeValueDouble( wxT( "contourwidth" ), 0 ) * parser.GetScale() ;
4076  }
4077  else
4078  {
4079  }
4080 }
4081 #endif //wxART2D_USE_CVGIO
4082 
4084 {
4085  if ( m_x1 == m_x2 && m_y1 == m_y2 )
4086  {
4087  return fabs( hitEvent.m_relx - m_x1 ) < ic.GetWorldStrokeExtend() + ic.GetTransformedHitMargin() &&
4088  fabs( hitEvent.m_rely - m_y1 ) < ic.GetWorldStrokeExtend() + ic.GetTransformedHitMargin();
4089  }
4090 
4091  a2dLine line1( m_x1, m_y1, m_x2, m_y2 );
4092  a2dPoint2D P = a2dPoint2D( hitEvent.m_relx, hitEvent.m_rely );
4093 
4094  double distance;
4095  if ( line1.PointInLine( P, distance, m_contourwidth / 2.0 + ic.GetWorldStrokeExtend() + ic.GetTransformedHitMargin() ) == R_IN_AREA )
4096  {
4098  return true;
4099  }
4100  else
4101  {
4102  hitEvent.m_how = a2dHit::stock_nohit;
4103  return false;
4104  }
4105 }
4106 
4107 bool a2dSLine::DoStartEdit( wxUint16 editmode, wxEditStyle editstyle )
4108 {
4109  if ( m_flags.m_editable )
4110  {
4111  if ( editmode == 1 )
4112  {
4113  m_flags.m_visiblechilds = true;
4115 
4116  a2dHandle* handle = NULL;
4117  Append( handle = new a2dHandle( this, m_x1, m_y1 , wxT( "__startpoint__" ) ) );
4118  handle->SetLayer( m_layer );
4119  Append( handle = new a2dHandle( this, m_x2, m_y2 , wxT( "__endpoint__" ) ) );
4120  handle->SetLayer( m_layer );
4121 
4122  m_childobjects->SetSpecificFlags( false, a2dCanvasOFlags::PRERENDERASCHILD, wxT( "a2dHandle" ) );
4123  m_childobjects->SetSpecificFlags( true, a2dCanvasOFlags::BIN2, wxT( "a2dHandle" ) );
4124 
4125  //calculate bbox's elase mouse events may take place when first idle event is not yet
4126  //processed to do this calculation.
4128  //stil set it pending to do the redraw ( in place )
4129  SetPending( true );
4130  return true;
4131  }
4132  else
4133  {
4134  PROPID_IncludeChildren->SetPropertyToObject( this, false );
4135  PROPID_Allowrotation->SetPropertyToObject( this, true );
4136  PROPID_Allowskew->SetPropertyToObject( this, true );
4137 
4138  return a2dCanvasObject::DoStartEdit( editmode, editstyle );
4139  }
4140  }
4141 
4142  return false;
4143 }
4144 
4145 void a2dSLine::OnChar( wxKeyEvent& event )
4146 {
4147  if ( m_flags.m_editingCopy )
4148  {
4149  switch( event.GetKeyCode() )
4150  {
4151  case WXK_TAB:
4152  {
4153  wxUint16* editmode = PROPID_Editmode->GetPropertyValuePtr( this );
4154  if ( editmode )
4155  {
4156  ( *editmode )++;
4157  if ( ( *editmode ) > 1 ) ( *editmode ) = 0;
4158  ReStartEdit( ( *editmode ) );
4159  }
4160  break;
4161  }
4162  default:
4163  event.Skip();
4164  }
4165  }
4166  else
4167  event.Skip();
4168 }
4169 
4170 
4171 void a2dSLine::OnHandleEvent( a2dHandleMouseEvent& event )
4172 {
4173  if ( m_flags.m_editingCopy )
4174  {
4175  a2dRestrictionEngine* restrictEngine = GetHabitat()->GetRestrictionEngine();
4176 
4177  a2dHandle* draghandle = event.GetCanvasHandle();
4178 
4179  //to world group coordinates to do hit test in world group coordinates
4180  double xw, yw;
4181  xw = event.GetX();
4182  yw = event.GetY();
4183 
4184  double xwi;
4185  double ywi;
4186  a2dAffineMatrix inverse = m_lworld;
4187  inverse.Invert();
4188  inverse.TransformPoint( xw, yw, xwi, ywi );
4189 
4190  a2dSLine* original = wxStaticCast( PROPID_Original->GetPropertyValue( this ).Get(), a2dSLine );
4191  a2dAffineMatrix origworld = m_lworld;
4192 
4193  if ( event.GetMouseEvent().LeftUp() )
4194  {
4195  if ( draghandle->GetName() == wxT( "__startpoint__" ) )
4196  {
4197  m_root->GetCommandProcessor()->Submit( new a2dCommand_MovePoint( original, m_x1, m_y1, true, false ) );
4198  draghandle->SetPosXY( m_x1, m_y1 );
4199  }
4200  else if ( draghandle->GetName() == wxT( "__endpoint__" ) )
4201  {
4202  m_root->GetCommandProcessor()->Submit( new a2dCommand_MovePoint( original, m_x2, m_y2, false, false ) );
4203  draghandle->SetPosXY( m_x2, m_y2 );
4204  }
4205  else
4206  event.Skip(); //maybe the base class handles
4207  }
4208  else if ( event.GetMouseEvent().Dragging() )
4209  {
4210  if ( draghandle->GetName() == wxT( "__startpoint__" ) )
4211  {
4212  //modify object
4213  if ( restrictEngine )
4214  restrictEngine->RestrictPoint( xw, yw );
4215  SetPosXY1( xw, yw );
4216  draghandle->SetPosXY( m_x1, m_y1 );
4217  SetPending( true );
4218  }
4219  else if ( draghandle->GetName() == wxT( "__endpoint__" ) )
4220  {
4221  //modify object
4222  if ( restrictEngine )
4223  restrictEngine->RestrictPoint( xw, yw );
4224  SetPosXY2( xw, yw );
4225  draghandle->SetPosXY( m_x2, m_y2 );
4226  SetPending( true );
4227  }
4228  else
4229  event.Skip(); //maybe on the base class handles
4230  }
4231  else
4232  event.Skip(); //maybe on the base class handles
4233  }
4234  else
4235  {
4236  event.Skip();
4237  }
4238 }
4239 
4240 //----------------------------------------------------------------------------
4241 // a2dEndsLine
4242 //----------------------------------------------------------------------------
4243 
4244 a2dEndsLine::a2dEndsLine()
4245  : a2dSLine()
4246 {
4247  m_xscale = m_yscale = 1;
4248  m_takeStyleToArrow = false;
4249 }
4250 
4251 a2dEndsLine::a2dEndsLine( double x1, double y1, double x2, double y2, double contourwidth )
4252  : a2dSLine( x1, y1, x2, y2, contourwidth )
4253 {
4254  m_xscale = m_yscale = 1;
4255  m_takeStyleToArrow = false;
4256 }
4257 
4258 a2dEndsLine::a2dEndsLine( const a2dSLine& other, CloneOptions options, a2dRefMap* refs )
4259  : a2dSLine( other, options, refs )
4260 {
4261  m_xscale = m_yscale = 1;
4262  m_takeStyleToArrow = false;
4263 }
4264 
4265 a2dEndsLine::a2dEndsLine( const a2dEndsLine& other, CloneOptions options, a2dRefMap* refs )
4266  : a2dSLine( other, options, refs )
4267 {
4268  if ( options & clone_members )
4269  {
4270  if ( other.m_begin )
4271  m_begin = other.m_begin->TClone( options );
4272  if ( other.m_end )
4273  m_end = other.m_end->TClone( options );
4274  }
4275  else
4276  {
4277  m_begin = other.m_begin;
4278  m_end = other.m_end;
4279  }
4280 
4281  m_xscale = other.m_xscale;
4282  m_yscale = other.m_yscale;
4284 #if defined(_DEBUG) && defined (SMART_POINTER_DEBUG)
4285  //klion: it is because the CurrentSmartPointerOwner can change in other. .. ->Clone( options )()
4286  CurrentSmartPointerOwner = this;
4287 #endif
4288 }
4289 
4291 {
4292  return new a2dEndsLine( *this, options, refs );
4293 }
4294 
4295 a2dEndsLine::~a2dEndsLine()
4296 {
4297 }
4298 
4300 {
4301  SetPending( true );
4302  m_begin = begin;
4303  if ( m_begin && m_root )
4304  m_begin->SetRoot( m_root );
4305 }
4306 
4308 {
4309  SetPending( true );
4310  m_end = end;
4311  if ( m_end && m_root )
4312  m_end->SetRoot( m_root );
4313 }
4314 
4316 {
4317  a2dBoundingBox bbox;
4318  bbox = a2dSLine::DoGetUnTransformedBbox( flags );
4319 
4320  if ( m_begin )
4321  {
4322  double dx, dy;
4323  dx = m_x2 - m_x1;
4324  dy = m_y2 - m_y1;
4325  double ang1;
4326  if ( !dx && !dy )
4327  ang1 = 0;
4328  else
4329  ang1 = wxRadToDeg( atan2( dy, dx ) );
4330 
4331  a2dAffineMatrix lworld;
4332  //clockwise rotation so minus
4333  lworld.Scale( m_xscale, m_yscale, 0, 0 );
4334  lworld.Rotate( -ang1 );
4335  lworld.Translate( m_x1, m_y1 );
4336 
4337  bbox.Expand( m_begin->GetMappedBbox( lworld ) );
4338  }
4339 
4340  if ( m_end )
4341  {
4342  double dx, dy;
4343  dx = m_x2 - m_x1;
4344  dy = m_y2 - m_y1;
4345  double ang2;
4346  if ( !dx && !dy )
4347  ang2 = 0;
4348  else
4349  ang2 = wxRadToDeg( atan2( -dy, -dx ) );
4350 
4351  a2dAffineMatrix tworld;
4352  //clockwise rotation so minus
4353  tworld.Scale( m_xscale, m_yscale, 0, 0 );
4354  tworld.Rotate( -ang2 );
4355  tworld.Translate( m_x2, m_y2 );
4356 
4357  bbox.Expand( m_end->GetMappedBbox( tworld ) );
4358  }
4359  return bbox;
4360 }
4361 
4362 bool a2dEndsLine::DoUpdate( UpdateMode mode, const a2dBoundingBox& childbox, const a2dBoundingBox& clipbox, const a2dBoundingBox& propbox )
4363 {
4364  bool calc = false;
4365  if ( m_begin )
4366  {
4367  if ( m_takeStyleToArrow )
4368  {
4369  m_begin->SetFill( GetFill() );
4370  m_begin->SetStroke( GetStroke() );
4371  }
4372  calc = m_begin->Update( mode );
4373  }
4374  if ( m_end )
4375  {
4376  if ( m_takeStyleToArrow )
4377  {
4378  m_end->SetFill( GetFill() );
4379  m_end->SetStroke( GetStroke() );
4380  }
4381  calc = m_end->Update( mode ) || calc;
4382  }
4383  if ( !m_bbox.GetValid() || calc )
4384  {
4385  m_bbox.SetValid( false );
4387 
4388  m_bbox.MapBbox( m_lworld );
4389  return true;
4390  }
4391  return calc;
4392 }
4393 
4394 void a2dEndsLine::DoRender( a2dIterC& ic, OVERLAP clipparent )
4395 {
4396  a2dSLine::DoRender( ic, clipparent );
4397 
4398  if ( m_begin )
4399  {
4400  double dx, dy;
4401  dx = m_x2 - m_x1;
4402  dy = m_y2 - m_y1;
4403  double ang1;
4404  if ( !dx && !dy )
4405  ang1 = 0;
4406  else
4407  ang1 = wxRadToDeg( atan2( dy, dx ) );
4408 
4409  a2dAffineMatrix lworld;
4410  //clockwise rotation so minus
4411  lworld.Scale( m_xscale, m_yscale, 0, 0 );
4412  lworld.Rotate( -ang1 );
4413  lworld.Translate( m_x1, m_y1 );
4414  a2dIterCU cu( ic, lworld );
4415 
4416  //The next switching of render layer is oke, imagine the begin and end objects
4417  //as normal child objects of the this line, in combination with the flag,
4418  //the effect is the same as starting a second layer iteration. Only this
4419  //one is optimized.
4420  bool old = m_begin->GetChildrenOnSameLayer();
4421  m_begin->SetChildrenOnSameLayer( true ); //
4422  m_begin->Render( ic, clipparent );
4423  m_begin->SetChildrenOnSameLayer( old ); //
4424  }
4425 
4426  if ( m_end )
4427  {
4428  double dx, dy;
4429  dx = m_x2 - m_x1;
4430  dy = m_y2 - m_y1;
4431  double ang2;
4432  if ( !dx && !dy )
4433  ang2 = 0;
4434  else
4435  ang2 = wxRadToDeg( atan2( -dy, -dx ) );
4436 
4437  a2dAffineMatrix tworld;
4438  //clockwise rotation so minus
4439  tworld.Scale( m_xscale, m_yscale, 0, 0 );
4440  tworld.Rotate( -ang2 );
4441  tworld.Translate( m_x2, m_y2 );
4442 
4443  a2dIterCU cu( ic, tworld );
4444 
4445  bool old = m_end->GetChildrenOnSameLayer();
4446  m_end->SetChildrenOnSameLayer( true );
4447  m_end->Render( ic, clipparent );
4448  m_end->SetChildrenOnSameLayer( old );
4449  }
4450 }
4451 
4452 #if wxART2D_USE_CVGIO
4453 void a2dEndsLine::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut& out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
4454 {
4455  a2dSLine::DoSave( parent, out, xmlparts, towrite );
4456  if ( xmlparts == a2dXmlSer_attrib )
4457  {
4458  if ( m_begin || m_end )
4459  {
4460  out.WriteAttribute( wxT( "xscale" ), m_xscale * out.GetScale() );
4461  out.WriteAttribute( wxT( "yscale" ), m_yscale * out.GetScale() );
4462  if ( m_begin )
4463  out.WriteAttribute( wxT( "begin" ), m_begin->GetUniqueSerializationId() );
4464  if ( m_end )
4465  out.WriteAttribute( wxT( "end" ), m_end->GetUniqueSerializationId() );
4466  }
4467  }
4468  else
4469  {
4470  if ( ( m_begin && !m_begin->GetCheck() ) ||
4471  ( m_end && !m_end->GetCheck() )
4472  )
4473  {
4474  //trick the system to have multiple refs on those objects, else we will not get an id attribute
4475  a2dCanvasObjectPtr begin = m_begin;
4476  a2dCanvasObjectPtr end = m_end;
4477 
4478  out.WriteStartElement( wxT( "derived" ) );
4479 
4480  if ( m_begin && !m_begin->GetCheck() )
4481  m_begin->Save( this, out, towrite );
4482  if ( m_end && !m_end->GetCheck() )
4483  m_end->Save( this, out, towrite );
4484 
4485  out.WriteEndElement();
4486  }
4487  }
4488 }
4489 
4490 void a2dEndsLine::DoLoad( wxObject* parent, a2dIOHandlerXmlSerIn& parser, a2dXmlSer_flag xmlparts )
4491 {
4492  a2dSLine::DoLoad( parent, parser, xmlparts );
4493  if ( xmlparts == a2dXmlSer_attrib )
4494  {
4495  m_xscale = parser.GetAttributeValueDouble( wxT( "xscale" ) ) * parser.GetScale() ;
4496  m_yscale = parser.GetAttributeValueDouble( wxT( "yscale" ) ) * parser.GetScale() ;
4497 
4498  wxString resolveKey;
4499  if ( parser.HasAttribute( wxT( "begin" ) ) )
4500  {
4501  parser.ResolveOrAdd( ( a2dSmrtPtr<class a2dObject>* ) &m_begin, parser.GetAttributeValue( wxT( "begin" ) ) );
4502  }
4503  if ( parser.HasAttribute( wxT( "end" ) ) )
4504  {
4505  parser.ResolveOrAdd( ( a2dSmrtPtr<class a2dObject>* ) &m_end, parser.GetAttributeValue( wxT( "end" ) ) );
4506  }
4507  }
4508  else
4509  {
4510  if ( parser.GetTagName() != wxT( "derived" ) )
4511  return;
4512 
4513  parser.Require( START_TAG, wxT( "derived" ) );
4514  parser.Next();
4515 
4516  m_begin = (a2dCanvasObject*) parser.LoadOneObject( this );
4517  m_end = (a2dCanvasObject*) parser.LoadOneObject( this );
4518 
4519  parser.Require( END_TAG, wxT( "derived" ) );
4520  parser.Next();
4521  }
4522 }
4523 #endif //wxART2D_USE_CVGIO
4524 
4525 void a2dEndsLine::DoWalker( wxObject* parent, a2dWalkerIOHandler& handler )
4526 {
4527  handler.WalkTask( parent, this, a2dWalker_a2dDerivedCanvasObjectStart );
4528  a2dCanvasObject::DoWalker( parent, handler );
4529  if ( m_begin )
4530  m_begin->Walker( this, handler );
4531 
4532  if ( m_end )
4533  m_end->Walker( this, handler );
4534 
4535  handler.WalkTask( parent, this, a2dWalker_a2dDerivedCanvasObjectStart );
4536 }
4537 
4539 {
4540  bool h = a2dSLine::DoIsHitWorld( ic, hitEvent );
4541 
4542  if ( !h )
4543  {
4544  if ( m_begin )
4545  {
4546  double dx, dy;
4547  dx = m_x2 - m_x1;
4548  dy = m_y2 - m_y1;
4549  double ang1;
4550  if ( !dx && !dy )
4551  ang1 = 0;
4552  else
4553  ang1 = wxRadToDeg( atan2( dy, dx ) );
4554 
4555  a2dAffineMatrix lworld;
4556  //clockwise rotation so minus
4557  lworld.Scale( m_xscale, m_yscale, 0, 0 );
4558  lworld.Rotate( -ang1 );
4559  lworld.Translate( m_x1, m_y1 );
4560  a2dIterCU cu( ic, lworld );
4561  h = m_begin->IsHitWorld( ic, hitEvent ) != 0;
4562  }
4563 
4564  if ( !h && m_end )
4565  {
4566  double dx, dy;
4567  dx = m_x2 - m_x1;
4568  dy = m_y2 - m_y1;
4569  double ang2;
4570  if ( !dx && !dy )
4571  ang2 = 0;
4572  else
4573  ang2 = wxRadToDeg( atan2( -dy, -dx ) );
4574 
4575  a2dAffineMatrix tworld;
4576  //clockwise rotation so minus
4577  tworld.Scale( m_xscale, m_yscale, 0, 0 );
4578  tworld.Rotate( -ang2 );
4579  tworld.Translate( m_x2, m_y2 );
4580  a2dIterCU cu( ic, tworld );
4581  h = m_end->IsHitWorld( ic, hitEvent ) != 0;
4582  }
4583  }
4584 
4585  if ( h )
4586  {
4588  return true;
4589  }
4590  hitEvent.m_how = a2dHit::stock_nohit;
4591  return false;
4592 }
4593 
4594 //----------------------------------------------------------------------------
4595 // a2dScaledEndLine
4596 //----------------------------------------------------------------------------
4597 #define L1 2
4598 #define L2 1
4599 #define B 1
4600 
4601 BEGIN_EVENT_TABLE( a2dScaledEndLine, a2dEndsLine )
4602 END_EVENT_TABLE()
4603 
4605  : a2dEndsLine()
4606 {
4607  m_xscale = m_yscale = 1;
4608  m_begin = new a2dArrow( 0, 0, L1, L2, B );
4609  m_end = new a2dArrow( 0, 0, L1, L2, B );
4610 }
4611 
4612 a2dScaledEndLine::a2dScaledEndLine( double x1, double y1, double x2, double y2, double contourwidth )
4613  : a2dEndsLine( x1, y1, x2, y2, contourwidth )
4614 {
4615  m_begin = new a2dArrow( 0, 0, L1, L2, B );
4616  m_end = new a2dArrow( 0, 0, L1, L2, B );
4617 
4618  m_xscale = m_yscale = 1;
4619 }
4620 
4621 a2dScaledEndLine::a2dScaledEndLine( const a2dSLine& other, CloneOptions options, a2dRefMap* refs )
4622  : a2dEndsLine( other, options, refs )
4623 {
4624  m_xscale = m_yscale = 1;
4625 }
4626 
4627 a2dScaledEndLine::a2dScaledEndLine( const a2dScaledEndLine& other, CloneOptions options, a2dRefMap* refs )
4628  : a2dEndsLine( other, options, refs )
4629 {
4630 }
4631 
4633 {
4634  return new a2dScaledEndLine( *this, options, refs );
4635 }
4636 
4638 {
4639 }
4640 
4641 void a2dScaledEndLine::SetBegin( double l1, double l2, double b, bool spline )
4642 {
4643  if ( m_begin && wxDynamicCast( m_begin.Get(), a2dArrow ) )
4644  wxStaticCast( m_begin.Get(), a2dArrow )->Set( l1, l2, b, spline );
4645  SetPending( true );
4646 }
4647 
4648 void a2dScaledEndLine::SetEnd( double l1, double l2, double b, bool spline )
4649 {
4650  if ( m_end && wxDynamicCast( m_end.Get(), a2dArrow ) )
4651  wxStaticCast( m_end.Get(), a2dArrow )->Set( l1, l2, b, spline );
4652  SetPending( true );
4653 }
4654 
4655 bool a2dScaledEndLine::DoUpdate( UpdateMode mode, const a2dBoundingBox& childbox, const a2dBoundingBox& clipbox, const a2dBoundingBox& propbox )
4656 {
4657  bool calc = false;
4658  if ( m_begin )
4659  {
4660  if ( m_takeStyleToArrow )
4661  {
4662  m_begin->SetFill( GetFill() );
4663  m_begin->SetStroke( GetStroke() );
4664  }
4667  calc = m_begin->Update( mode );
4668  }
4669  if ( m_end )
4670  {
4671  if ( m_takeStyleToArrow )
4672  {
4673  m_end->SetFill( GetFill() );
4674  m_end->SetStroke( GetStroke() );
4675  }
4678  calc = m_end->Update( mode ) || calc;
4679  }
4680  if ( !m_bbox.GetValid() || calc )
4681  {
4682  m_bbox.SetValid( false );
4684 
4685  m_bbox.MapBbox( m_lworld );
4686  return true;
4687  }
4688  return calc;
4689 }
4690 
4692 {
4693  if ( m_contourwidth )
4694  {
4695  a2dLine line1( m_x1, m_y1, m_x2, m_y2 );
4696  line1.CalculateLineParameters();
4697  double distance = m_contourwidth / 2.0;
4698  if ( distance == 0 )
4699  distance = 1;//line1.GetLength()/10;
4700 
4701  a2dPoint2D layBackBegin( m_x1, m_y1 );
4702  a2dPoint2D layBackEnd( m_x2, m_y2 );
4703 
4704  //for arrow or derived objects, make it such that the line does not pass the arrow.
4705  if ( m_begin && wxDynamicCast( m_begin.Get(), a2dArrow ) )
4706  {
4707  a2dArrow* arrow1 = wxStaticCast( m_begin.Get(), a2dArrow );
4708  double baseD2B = arrow1->GetBase() / 2.0;
4709  double l1B = arrow1->GetL1();
4710  double layBackB = l1B * distance / baseD2B;
4711  layBackBegin = line1.DistancePoint( layBackB, true );
4712  }
4713  if ( m_end && wxDynamicCast( m_end.Get(), a2dArrow ) )
4714  {
4715  a2dArrow* arrow2 = wxStaticCast( m_end.Get(), a2dArrow );
4716  double baseD2E = arrow2->GetBase() / 2.0;
4717  double l1E = arrow2->GetL1();
4718  double layBackE = l1E * distance / baseD2E;
4719  layBackEnd = line1.DistancePoint( -layBackE, false );
4720  }
4721 
4722  a2dPoint2D offsetpoint1left = layBackBegin;
4723  a2dPoint2D offsetpoint1right = layBackBegin;
4724  a2dPoint2D offsetpoint2left = layBackEnd;
4725  a2dPoint2D offsetpoint2right = layBackEnd;
4726 
4727  line1.Virtual_Point( offsetpoint1left, distance );
4728  line1.Virtual_Point( offsetpoint1right, -distance );
4729  line1.Virtual_Point( offsetpoint2left, distance );
4730  line1.Virtual_Point( offsetpoint2right, -distance );
4731 
4732  a2dVertexArray contour;
4733  contour.AddPoint( offsetpoint1left );
4734  contour.AddPoint( offsetpoint2left );
4735  contour.AddPoint( offsetpoint2right );
4736  contour.AddPoint( offsetpoint1right );
4737 
4738  ic.GetDrawer2D()->DrawPolygon( &contour );
4739 
4740  if ( m_begin )
4741  {
4742  double dx, dy;
4743  dx = m_x2 - m_x1;
4744  dy = m_y2 - m_y1;
4745  double ang1;
4746  if ( !dx && !dy )
4747  ang1 = 0;
4748  else
4749  ang1 = wxRadToDeg( atan2( dy, dx ) );
4750 
4751  a2dAffineMatrix lworld;
4752  //clockwise rotation so minus
4753  lworld.Scale( m_xscale, m_yscale, 0, 0 );
4754  lworld.Rotate( -ang1 );
4755  lworld.Translate( m_x1, m_y1 );
4756  a2dIterCU cu( ic, lworld );
4757 
4758  //The next switching of render layer is oke, imagine the begin and end objects
4759  //as normal child objects of the this line, in combination with the flag,
4760  //the effect is the same as starting a second layer iteration. Only this
4761  //one is optimized.
4762  bool old = m_begin->GetChildrenOnSameLayer();
4763  m_begin->SetChildrenOnSameLayer( true ); //
4764  m_begin->Render( ic, clipparent );
4765  m_begin->SetChildrenOnSameLayer( old ); //
4766  }
4767 
4768  if ( m_end )
4769  {
4770  double dx, dy;
4771  dx = m_x2 - m_x1;
4772  dy = m_y2 - m_y1;
4773  double ang2;
4774  if ( !dx && !dy )
4775  ang2 = 0;
4776  else
4777  ang2 = wxRadToDeg( atan2( -dy, -dx ) );
4778 
4779  a2dAffineMatrix tworld;
4780  //clockwise rotation so minus
4781  tworld.Scale( m_xscale, m_yscale, 0, 0 );
4782  tworld.Rotate( -ang2 );
4783  tworld.Translate( m_x2, m_y2 );
4784 
4785  a2dIterCU cu( ic, tworld );
4786 
4787  bool old = m_end->GetChildrenOnSameLayer();
4788  m_end->SetChildrenOnSameLayer( true );
4789  m_end->Render( ic, clipparent );
4790  m_end->SetChildrenOnSameLayer( old );
4791  }
4792  }
4793  else
4794  {
4795  ic.GetDrawer2D()->DrawLine( m_x1, m_y1, m_x2, m_y2 );
4796  }
4797 
4798 }
4799 
4800 //----------------------------------------------------------------------------
4801 // a2dEndsEllipticChord
4802 //----------------------------------------------------------------------------
4803 
4805  : a2dEllipticArc()
4806 {
4807  m_xscale = m_yscale = 1;
4808 }
4809 
4810 a2dEndsEllipticChord::a2dEndsEllipticChord( double xc, double yc, double width, double height, double start, double end )
4811  : a2dEllipticArc( xc, yc, width, height, start, end, true )
4812 {
4813  m_xscale = m_yscale = 1;
4814 }
4815 
4817  : a2dEllipticArc( other, options, refs )
4818 {
4819  if ( options & clone_members )
4820  {
4821  if ( other.m_beginobj )
4822  m_beginobj = other.m_beginobj->TClone( options );
4823  if ( other.m_endobj )
4824  m_endobj = other.m_endobj->TClone( options );
4825  }
4826  else
4827  {
4828  m_beginobj = other.m_beginobj;
4829  m_endobj = other.m_endobj;
4830  }
4831 
4832  m_xscale = other.m_xscale;
4833  m_yscale = other.m_yscale;
4834 #if defined(_DEBUG) && defined (SMART_POINTER_DEBUG)
4835  //klion: it is because the CurrentSmartPointerOwner can change in other. .. ->Clone( options )()
4836  CurrentSmartPointerOwner = this;
4837 #endif
4838 }
4839 
4841 {
4842  return new a2dEndsEllipticChord( *this, options, refs );
4843 };
4844 
4846 {
4847 }
4848 
4850 {
4851  SetPending( true );
4852  m_beginobj = begin;
4853  if ( m_beginobj && m_root )
4855 }
4856 
4858 {
4859  SetPending( true );
4860  m_endobj = end;
4861  if ( m_endobj && m_root )
4862  m_endobj->SetRoot( m_root );
4863 }
4864 
4866 {
4868 
4869  if ( m_beginobj )
4870  {
4872  }
4873 
4874  if ( m_endobj )
4875  {
4877  }
4878  return bbox;
4879 }
4880 
4881 bool a2dEndsEllipticChord::DoUpdate( UpdateMode mode, const a2dBoundingBox& childbox, const a2dBoundingBox& clipbox, const a2dBoundingBox& propbox )
4882 {
4883  bool calc = false;
4884  if ( m_beginobj )
4885  {
4886  calc = m_beginobj->Update( mode );
4887  }
4888  if ( m_endobj )
4889  {
4890  calc = m_endobj->Update( mode ) || calc;
4891  }
4892  if ( !m_bbox.GetValid() || calc )
4893  {
4894  m_bbox.SetValid( false );
4896 
4897  m_bbox.MapBbox( m_lworld );
4898  return true;
4899  }
4900  return calc;
4901 }
4902 
4904 {
4905  a2dEllipticArc::DoRender( ic, clipparent );
4906 
4907  if ( m_beginobj )
4908  {
4909  a2dIterCU cu( ic, GetBeginTransform() );
4910 
4911  //The next switching of render layer is oke, imagine the begin and end objects
4912  //as normal child objects of the this line, in combination with the flag,
4913  //the effect is the same as starting a second layer iteration. Only this
4914  //one is optimized.
4915  bool old = m_beginobj->GetChildrenOnSameLayer();
4916  m_beginobj->SetChildrenOnSameLayer( true ); //
4917  m_beginobj->Render( ic, clipparent );
4919  }
4920 
4921  if ( m_endobj )
4922  {
4923  a2dIterCU cu( ic, GetEndTransform() );
4924 
4925  bool old = m_endobj->GetChildrenOnSameLayer();
4927  m_endobj->Render( ic, clipparent );
4929  }
4930 }
4931 
4932 void a2dEndsEllipticChord::DoWalker( wxObject* parent, a2dWalkerIOHandler& handler )
4933 {
4934  handler.WalkTask( parent, this, a2dWalker_a2dDerivedCanvasObjectStart );
4935  a2dCanvasObject::DoWalker( parent, handler );
4936  if ( m_beginobj )
4937  m_beginobj->Walker( this, handler );
4938 
4939  if ( m_endobj )
4940  m_endobj->Walker( this, handler );
4941 
4942  handler.WalkTask( parent, this, a2dWalker_a2dDerivedCanvasObjectStart );
4943 }
4944 
4945 #if wxART2D_USE_CVGIO
4946 void a2dEndsEllipticChord::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut& out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
4947 {
4948  a2dEllipticArc::DoSave( parent, out, xmlparts, towrite );
4949  if ( xmlparts == a2dXmlSer_attrib )
4950  {
4951  if ( m_beginobj || m_endobj )
4952  {
4953  out.WriteAttribute( wxT( "xscale" ), m_xscale * out.GetScale() );
4954  out.WriteAttribute( wxT( "yscale" ), m_yscale * out.GetScale() );
4955  if ( m_beginobj )
4956  out.WriteAttribute( wxT( "beginobj" ), m_beginobj->GetUniqueSerializationId() );
4957  if ( m_endobj )
4958  out.WriteAttribute( wxT( "endobj" ), m_endobj->GetUniqueSerializationId() );
4959  }
4960  }
4961  else
4962  {
4963  if ( ( m_beginobj && !m_beginobj->GetCheck() ) ||
4964  ( m_endobj && !m_endobj->GetCheck() )
4965  )
4966  {
4967  //trick the system to have multiple refs on those objects, else we will not get an id attribute
4970 
4971  out.WriteStartElement( wxT( "derived" ) );
4972 
4973  if ( m_beginobj && !m_beginobj->GetCheck() )
4974  m_beginobj->Save( this, out, towrite );
4975  if ( m_endobj && !m_endobj->GetCheck() )
4976  m_endobj->Save( this, out, towrite );
4977 
4978  out.WriteEndElement();
4979  }
4980  }
4981 }
4982 
4983 void a2dEndsEllipticChord::DoLoad( wxObject* parent, a2dIOHandlerXmlSerIn& parser, a2dXmlSer_flag xmlparts )
4984 {
4985  a2dEllipticArc::DoLoad( parent, parser, xmlparts );
4986  if ( xmlparts == a2dXmlSer_attrib )
4987  {
4988  m_xscale = parser.GetAttributeValueDouble( wxT( "xscale" ) ) * parser.GetScale() ;
4989  m_yscale = parser.GetAttributeValueDouble( wxT( "yscale" ) ) * parser.GetScale() ;
4990  if ( parser.HasAttribute( wxT( "beginobj" ) ) )
4991  {
4992  parser.ResolveOrAdd( ( a2dSmrtPtr<class a2dObject>* ) &m_beginobj, parser.GetAttributeValue( wxT( "beginobj" ) ) );
4993  }
4994  if ( parser.HasAttribute( wxT( "endobj" ) ) )
4995  {
4996  parser.ResolveOrAdd( ( a2dSmrtPtr<class a2dObject>* ) &m_endobj, parser.GetAttributeValue( wxT( "endobj" ) ) );
4997  }
4998  }
4999  else
5000  {
5001  if ( parser.GetTagName() != wxT( "derived" ) )
5002  return;
5003 
5004  parser.Require( START_TAG, wxT( "derived" ) );
5005  parser.Next();
5006 
5007  m_beginobj = (a2dCanvasObject*) parser.LoadOneObject( this );
5008  m_endobj = (a2dCanvasObject*) parser.LoadOneObject( this );
5009 
5010  parser.Require( END_TAG, wxT( "derived" ) );
5011  parser.Next();
5012  }
5013 }
5014 #endif //wxART2D_USE_CVGIO
5015 
5017 {
5018  bool h = a2dEllipticArc::DoIsHitWorld( ic, hitEvent );
5019 
5020  if ( !h )
5021  {
5022  if ( m_beginobj )
5023  {
5024  a2dIterCU cu( ic, GetBeginTransform() );
5025  h = m_beginobj->IsHitWorld( ic, hitEvent ) != 0;
5026  }
5027 
5028  if ( !h && m_endobj )
5029  {
5030  a2dIterCU cu( ic, GetEndTransform() );
5031  h = m_endobj->IsHitWorld( ic, hitEvent ) != 0;
5032  }
5033  }
5034 
5035  if ( h )
5036  {
5038  return true;
5039  }
5040  hitEvent.m_how = a2dHit::stock_nohit;
5041  return false;
5042 }
5043 
5045 {
5046  double ang1 = wxRadToDeg( atan2( sin ( wxDegToRad( m_start + 90 ) ) * m_height, cos ( wxDegToRad( m_start + 90 ) ) * m_width ) );
5047  double x1 = m_width / 2 * cos( wxDegToRad( m_start ) );
5048  double y1 = m_height / 2 * sin( wxDegToRad( m_start ) );
5049 
5050  a2dAffineMatrix lworld;
5051  //clockwise rotation so minus
5052  lworld.Scale( m_xscale, m_yscale, 0, 0 );
5053  lworld.Rotate( -ang1 );
5054  lworld.Translate( x1, y1 );
5055 
5056  return lworld;
5057 }
5058 
5060 {
5061  double ang2 = wxRadToDeg( atan2( sin ( wxDegToRad( m_end - 90 ) ) * m_height, cos ( wxDegToRad( m_end - 90 ) ) * m_width ) );
5062  double x2 = m_width / 2 * cos( wxDegToRad( m_end ) );
5063  double y2 = m_height / 2 * sin( wxDegToRad( m_end ) );
5064 
5065  a2dAffineMatrix lworld;
5066  //clockwise rotation so minus
5067  lworld.Scale( m_xscale, m_yscale, 0, 0 );
5068  lworld.Rotate( -ang2 );
5069  lworld.Translate( x2, y2 );
5070 
5071  return lworld;
5072 }
5073 
5074 //----------------------------------------------------------------------------
5075 // a2dControl
5076 //----------------------------------------------------------------------------
5077 
5078 a2dControl::a2dControl( double x, double y, double width, double height, wxWindow* control )
5079  : a2dRect( x, y, width, height )
5080 {
5081  m_control = control;
5082  m_control->Show( false );
5083 }
5084 
5086 {
5087  //not here since the control is owned by the window in which it was created.
5088  //and that may be gone before the deletion of the object.
5089  //m_control->Close();
5090  //m_control->Destroy();
5091 }
5092 
5094  : a2dRect( other, options, refs )
5095 {
5096  m_control = other.m_control;
5097  int x, y ;
5098  other.m_control->GetPosition( &x, &y );
5099  m_control->Move( x, y );
5100 
5101  SetPending( true );
5102 }
5103 
5105 {
5106  return new a2dControl( *this, options, refs );
5107 };
5108 
5109 bool a2dControl::DoUpdate( UpdateMode mode, const a2dBoundingBox& childbox, const a2dBoundingBox& clipbox, const a2dBoundingBox& propbox )
5110 {
5111  if ( !m_bbox.GetValid() )
5112  {
5113  return a2dRect::DoUpdate( mode, childbox, clipbox, propbox );
5114  }
5115  return false;
5116 }
5117 
5118 void a2dControl::DoRender( a2dIterC& ic, OVERLAP clipparent )
5119 {
5120  if ( ic.GetDrawingPart()->GetDisplayWindow() && m_control->GetParent() != ic.GetDrawingPart()->GetDisplayWindow() ) //only one drawer which has the control on its display
5121  return;
5122 
5123  if ( m_flags.m_editingCopy )
5124  {
5125  int xd = ic.GetDrawer2D()->WorldToDeviceX( GetPosX() );
5126  int yd = ic.GetDrawer2D()->WorldToDeviceY( GetPosY() );
5127  m_control->Move( xd, yd );
5128  }
5129  //else
5130  a2dRect::DoRender( ic, clipparent );
5131 }
5132 
5133 bool a2dControl::DoIsHitWorld( a2dIterC& WXUNUSED( ic ), a2dHitEvent& hitEvent )
5134 {
5135  hitEvent.m_how = a2dHit::stock_fill;
5136  return true;
5137 }
5138 
5139 bool a2dControl::DoStartEdit( wxUint16 editmode, wxEditStyle editstyle )
5140 {
5141  if ( m_flags.m_editable )
5142  {
5143  if ( editmode == 1 )
5144  {
5145  m_flags.m_visiblechilds = true;
5147 
5148  m_control->Show( true );
5149  return true;
5150  }
5151  else
5152  {
5153  PROPID_IncludeChildren->SetPropertyToObject( this, false );
5154  PROPID_Allowrotation->SetPropertyToObject( this, true );
5155  PROPID_Allowskew->SetPropertyToObject( this, true );
5156 
5157  return a2dWH::DoStartEdit( editmode, editstyle );
5158  }
5159  }
5160 
5161  return false;
5162 }
5163 
5165 {
5166  m_control->Show( false );
5167  SetPending( true );
5168 }
5169 
5170 //----------------------------------------------------------------------------
5171 // a2dWires
5172 //----------------------------------------------------------------------------
5174 {
5176  m_frozen = false;
5177  m_flags.m_draggable = false;
5178 }
5179 
5180 a2dWires::a2dWires( a2dCanvasObject* toconnect, const wxString& pinname )
5181  : a2dCanvasObject()
5182 {
5183  m_flags.m_draggable = false;
5184  bool done = false;
5185 
5187 
5188  m_frozen = false;
5189 
5190  for( a2dCanvasObjectList::iterator iter = toconnect->GetChildObjectList()->begin(); iter != toconnect->GetChildObjectList()->end(); ++iter )
5191  {
5192  a2dPin* pinc = wxDynamicCast( ( *iter ).Get(), a2dPin );
5193  if ( pinc )
5194  {
5195  if ( pinname == pinc->GetName() )
5196  {
5197  a2dPin* newpin = new a2dPin( this, wxT( "pin1" ), a2dPinClass::Standard, pinc->GetAbsX(), pinc->GetAbsY(), 180 - pinc->GetAbsAngle() );
5198  Append( newpin );
5199 
5200  pinc->ConnectTo( newpin );
5201  done = true;
5202  }
5203  }
5204  }
5205 
5206  wxASSERT_MSG( done, wxT( "no such pin to connect to" ) );
5207 }
5208 
5210  : a2dCanvasObject()
5211 {
5212  bool done = false;
5213  wxASSERT_MSG( pinc->GetParent() == toConnect, wxT( "this pin has not connect object as parent" ) );
5214 
5215  for( a2dCanvasObjectList::iterator iter = toConnect->GetChildObjectList()->begin(); iter != toConnect->GetChildObjectList()->end(); ++iter )
5216  {
5217  a2dCanvasObject* obj = *iter;
5218  a2dPin* pinother = wxDynamicCast( obj, a2dPin );
5219  if ( pinother == pinc )
5220  {
5221  done = true;
5222  break;
5223  }
5224  }
5225 
5226  wxASSERT_MSG( done, wxT( "this pin is not in to connect object" ) );
5227 
5228  m_flags.m_hasPins = true;
5229 
5231 
5232  m_frozen = false;
5233 
5234  a2dPin* newpin = new a2dPin( this, wxT( "pin1" ), a2dPinClass::Standard, pinc->GetAbsX(), pinc->GetAbsY(), 180 - pinc->GetAbsAngle() );
5235  Append( newpin );
5236 
5237  pinc->ConnectTo( newpin );
5238 #if defined(_DEBUG) && defined (SMART_POINTER_DEBUG)
5239  //klion: it is because the CurrentSmartPointerOwner can change in new a2dPin()
5240  CurrentSmartPointerOwner = this;
5241 #endif
5242 }
5243 
5245 {
5246 }
5247 
5248 a2dObject* a2dWires::DoClone( CloneOptions WXUNUSED( options ), a2dRefMap* refs ) const
5249 {
5250  a2dWires* a = new a2dWires();
5251  //TODO
5252  return a;
5253 };
5254 
5256 {
5257  return true;
5258 }
5259 
5260 bool a2dWires::ConnectWith( a2dCanvasObject* parent, a2dCanvasObject* toConnect, const wxString& pinname, double margin, bool WXUNUSED( undo ) )
5261 {
5262  bool done = false;
5263 
5264  for( a2dCanvasObjectList::iterator iter = m_childobjects->begin(); iter != m_childobjects->end(); ++iter )
5265  {
5266  a2dCanvasObject* obj = *iter;
5267  a2dPin* pinc = wxDynamicCast( obj, a2dPin );
5268  if ( pinc )
5269  {
5270  if ( pinname.IsEmpty() )
5271  {
5272  //search pin at same position in object to connect
5273 
5274  for( a2dCanvasObjectList::iterator itero = toConnect->GetChildObjectList()->begin(); itero != toConnect->GetChildObjectList()->end(); ++itero )
5275  {
5276  a2dCanvasObject* obj = *itero;
5277  a2dPin* pinother = wxDynamicCast( obj, a2dPin );
5278  if ( pinother )
5279  {
5280  if ( fabs( pinother->GetAbsX() - pinc->GetAbsX() ) < margin &&
5281  fabs( pinother->GetAbsY() - pinc->GetAbsY() ) < margin )
5282  {
5283  ConnectPins( parent, pinc, pinother );
5284  done = true;
5285  }
5286  }
5287  }
5288  }
5289  else
5290  {
5291  //search pin with pinname in object to connect
5292  for( a2dCanvasObjectList::iterator itero = toConnect->GetChildObjectList()->begin(); itero != toConnect->GetChildObjectList()->end(); ++itero )
5293  {
5294  a2dCanvasObject* obj = *itero;
5295  a2dPin* pinother = wxDynamicCast( obj, a2dPin );
5296  if ( pinother && pinname == pinother->GetName() )
5297  {
5298  if ( fabs( pinother->GetAbsX() - pinc->GetAbsX() ) < margin &&
5299  fabs( pinother->GetAbsY() - pinc->GetAbsY() ) < margin )
5300  {
5301  ConnectPins( parent, pinc, pinother );
5302  done = true;
5303  }
5304  }
5305  }
5306  }
5307  }
5308  }
5309 
5310  if ( !done )
5311  {
5312  wxString nextpin = wxT( "pin" );
5313  nextpin << GetPinCount() + 1;
5314 
5315  //search pin with pinname in object to connect
5316  for( a2dCanvasObjectList::iterator itero = toConnect->GetChildObjectList()->begin(); itero != toConnect->GetChildObjectList()->end(); ++itero )
5317  {
5318  a2dCanvasObject* obj = *itero;
5319  a2dPin* pinother = wxDynamicCast( obj, a2dPin );
5320  if ( pinother )
5321  {
5322  if ( pinname == pinother->GetName() )
5323  {
5324  a2dPin* newpin = new a2dPin( this, nextpin, a2dPinClass::Standard, pinother->GetAbsX(), pinother->GetAbsY(), 180 - pinother->GetAbsAngle() );
5325  Append( newpin );
5326 
5327  pinother->ConnectTo( newpin );
5328  done = true;
5329  }
5330  }
5331  }
5332  }
5333 
5334  SetPending( true );
5335 
5336  return done;
5337 }
5338 
5339 bool a2dWires::ConnectWith( a2dCanvasObject* WXUNUSED( parent ), a2dPin* pin, double margin, bool WXUNUSED( undo ) )
5340 {
5341  if ( pin->GetParent() == this )
5342  return false;
5343 
5344  bool done = false;
5345 
5346  a2dCanvasObjectList::iterator iter;
5347  //if there the pin to connect is already in the wire, nothing to do.
5348  for( iter = m_childobjects->begin(); iter != m_childobjects->end(); ++iter )
5349  {
5350  a2dCanvasObject* obj = *iter;
5351  a2dPin* pinc = wxDynamicCast( obj, a2dPin );
5352  if ( pinc && pinc == pin )
5353  {
5354  return true;
5355  }
5356  }
5357 
5358  //if there is an un-connected pin at this position, use it.
5359  for( iter = m_childobjects->begin(); iter != m_childobjects->end(); ++iter )
5360  {
5361  a2dCanvasObject* obj = *iter;
5362  a2dPin* pinc = wxDynamicCast( obj, a2dPin );
5363  if ( pinc )
5364  {
5365  if ( fabs( pinc->GetAbsX() - pin->GetAbsX() ) < margin &&
5366  fabs( pinc->GetAbsY() - pin->GetAbsY() ) < margin )
5367  {
5368  if ( !pinc->IsConnectedTo( pin ) )
5369  {
5370  pin->ConnectTo( pinc );
5371  }
5372  done = true;
5373  }
5374  }
5375  }
5376 
5377  if ( !done )
5378  {
5379  wxString nextpin = wxT( "pin" );
5380  nextpin << GetPinCount() + 1;
5381 
5382 
5383  a2dPin* newpin = new a2dPin( this, nextpin, a2dPinClass::Standard, pin->GetAbsX(), pin->GetAbsY(), 180 - pin->GetAbsAngle() );
5384  Append( newpin );
5385 
5386  pin->ConnectTo( newpin );
5387  }
5388 
5389  SetPending( true );
5390 
5391  return true;
5392 }
5393 
5394 bool a2dWires::DoUpdate( UpdateMode mode, const a2dBoundingBox& childbox, const a2dBoundingBox& clipbox, const a2dBoundingBox& propbox )
5395 {
5396  for( a2dCanvasObjectList::iterator iter = m_childobjects->begin(); iter != m_childobjects->end(); ++iter )
5397  {
5398  a2dCanvasObject* obj = *iter;
5399  a2dPin* pinc = wxDynamicCast( obj, a2dPin );
5400  if ( pinc && pinc->IsConnectedTo() )
5401  {
5402  //todo
5403  //pinc->Set( pinc->ConnectedTo()->GetAbsX(), pinc->ConnectedTo()->GetAbsY(), 180 - pinc->ConnectedTo()->GetAbsAngle() );
5404  }
5405  }
5406 
5407 
5409  {
5410  for( a2dCanvasObjectList::iterator iter = m_childobjects->begin(); iter != m_childobjects->end(); ++iter )
5411  {
5412  a2dCanvasObject* obj = *iter;
5413  obj->Update( mode );
5414 
5415  //if calcchild has become true now, this means that down here the current child object did change and
5416  //therefore has recalculated its boundingbox
5417  }
5418  }
5419  /*
5420  //delete old wires
5421  node = GetChildObjectList()->GetFirst();
5422  while (node)
5423  {
5424  a2dCanvasObject *obj = node->GetData();
5425  if (obj->CheckMask(a2dCanvasOFlags::A))
5426  {
5427  obj->Release();
5428 
5429  a2dCanvasObjectList::compatibility_iterator nodeh=node;
5430  node = node->GetNext();
5431  GetChildObjectList()->DeleteNode(nodeh);
5432  }
5433  else
5434  node = node->GetNext();
5435  }
5436 
5437  //first create proper wires in group
5438  CreateWires();
5439  node = m_childobjects->GetFirst();
5440  while (node)
5441  {
5442  a2dCanvasObject *obj = node->GetData();
5443  obj->Update(force);
5444  node = node->GetNext();
5445  }
5446  */
5447 
5448  return true;
5449 }
5450 
5451 void a2dWires::DoRender( a2dIterC& ic, OVERLAP WXUNUSED( clipparent ) )
5452 {
5453 
5454  a2dAffineMatrix inverse = m_lworld;
5455  inverse.Invert();
5456 
5457  a2dAffineMatrix untrans = ic.GetTransform();
5458  untrans *= inverse;
5459 
5460  //the boundingbox is relative to the parent.
5461  a2dBoundingBox absarea = GetMappedBbox( untrans );
5462 
5463 #ifdef CANVASDEBUG
5464 
5466  a2dRect* tmp = new a2dRect( absarea.GetMinX() , absarea.GetMinY() , absarea.GetWidth() , absarea.GetHeight() );
5467  tmp->SetIgnoreSetpending();
5468  tmp->Own();
5469  tmp->SetRoot( m_root );
5470  tmp->Update( ic, true );
5471  tmp->SetFill( a2dTRANSPARENT_FILL );
5472  tmp->SetStroke( ic.GetDrawer2D()->GetDrawerStroke() );
5473  tmp->Render( cworld, _ON, layer, mask );
5474  tmp->Release();
5475 #endif
5476 
5477  if ( ic.GetDrawer2D()->GetClippingBox().Intersect( absarea ) != _OUT )
5478  {
5479  for( a2dCanvasObjectList::iterator iter = m_childobjects->begin(); iter != m_childobjects->end(); ++iter )
5480  {
5481  a2dCanvasObject* obj = *iter;
5482  a2dPin* pinc = wxDynamicCast( obj, a2dPin );
5483 
5484  if ( pinc )
5485  {
5486  double x = pinc->GetAbsX();
5487  double y = pinc->GetAbsY();
5488 
5489  for( a2dCanvasObjectList::iterator itero = m_childobjects->begin(); itero != m_childobjects->end(); ++itero )
5490  {
5491  a2dCanvasObject* obj = *itero;
5492  a2dPin* pinother = wxDynamicCast( obj, a2dPin );
5493 
5494  if ( pinother && pinother != pinc )
5495  {
5496  double x2 = pinother->GetAbsX();
5497  double y2 = pinother->GetAbsY();
5498 
5499  ic.GetDrawer2D()->DrawLine( x, y, x2, y2 );
5500  }
5501  }
5502  }
5503  }
5504  }
5505 }
5506 
5507 void a2dWires::CreateWires()
5508 {
5509  for( a2dCanvasObjectList::iterator iter = m_childobjects->begin(); iter != m_childobjects->end(); ++iter )
5510  {
5511  a2dCanvasObject* obj = *iter;
5512  a2dPin* pinc = wxDynamicCast( obj, a2dPin );
5513  if ( pinc )
5514  {
5515  double x = pinc->GetPosX();
5516  double y = pinc->GetPosY();
5517 
5518  for( a2dCanvasObjectList::iterator itero = m_childobjects->begin(); itero != m_childobjects->end(); ++itero )
5519  {
5520  a2dCanvasObject* obj = *itero;
5521  a2dPin* pinother = wxDynamicCast( obj, a2dPin );
5522  if ( pinother && pinother != pinc )
5523  {
5524  double x2 = pinother->GetPosX();
5525  double y2 = pinother->GetPosY();
5526 
5527  //direct maybe better?
5528  //ic.GetDrawer2D()->DrawLine(x,y,x2,y2);
5529 
5530  a2dSmrtPtr<a2dSLine> a = new a2dSLine( x, y, x2, y2 );
5531  a->SetLayer( wxLAYER_DEFAULT );
5532  //Slow
5533  //a->SetStroke(a2dStroke(wxColour(252,0,2 ),1.0,wxSOLID));
5534  a->SetSpecificFlags( true, a2dCanvasOFlags::A ); //to be able to delete them afterwords
5535  a->SetRoot( m_root );
5536  Append( a );
5537  }
5538  }
5539  }
5540  }
5541 }
void SetEnd(a2dCanvasObject *end)
set object to draw as end point
Definition: canprim.cpp:4307
~a2dControl()
destructor
Definition: canprim.cpp:5085
a2dHit m_how
return in which way the object was hit (stroke, fill, ...)
Definition: canobj.h:301
bool GeneratePins(a2dPinClass *toConnectTo, a2dConnectTask task, double x, double y, double margin=0)
create pins in derived objects.
Definition: canprim.cpp:2259
a2dCircle at x,y, and with radius
Definition: canprim.h:554
bool GetAttributeValueBool(const wxString &attrib, bool defaultv=false)
Returns the boolean value of an attribute.
Definition: genxmlpars.cpp:537
wxPoint2DDouble a2dPoint2D
this to define if coordinate numbers are integer or doubles
Definition: artglob.h:47
double m_relx
(world coordinates) hit point x relative to the canvas object its parent object(s) ...
Definition: canobj.h:289
double GetHeight() const
returns height of the boundingbox
Definition: bbox.cpp:334
virtual void Render(a2dIterC &ic, OVERLAP clipparent)
Render this object to the active a2dDrawingPart.
Definition: canobj.cpp:4712
double GetAbsY() const
get absolute Y position of the pin ( after applying the parent&#39;s matrix and its own matrix ) ...
Definition: canpin.cpp:966
bool SetSpecificFlags(bool setOrClear, a2dCanvasObjectFlagsMask which, const wxString &classname=wxT(""), a2dCanvasObjectFlagsMask whichobjects=a2dCanvasOFlags::ALL, const a2dBoundingBox &bbox=wxNonValidBbox, const a2dAffineMatrix &tworld=a2dIDENTITY_MATRIX)
set all given bit flags at once recursive for all objects in given boundingbox
Definition: objlist.cpp:519
all basic primitives derived from a2dCanvasObject
#define wxDynamicCast(obj, className)
Define wxDynamicCast so that it will give a compiler error for unrelated types.
Definition: gen.h:75
void SetRoot(a2dDrawing *root, bool recurse=true)
Sets this object to a a2dCanvasDocument.
Definition: canobj.cpp:5933
double GetPosX2(bool transform=true) const
Get (transformed) position of X2.
Definition: canprim.cpp:3865
virtual a2dObject * DoClone(CloneOptions options, a2dRefMap *refs) const
Clone this object and return a pointer to the new object.
Definition: canprim.cpp:4290
double m_y1
y of begin point
Definition: canprim.h:948
double GetContourWidth() const
get the Contour width of the shape
Definition: canprim.h:766
bool GetGeneratePins() const
get the GeneratePins flag
Definition: canobj.h:2289
a2dObject * LoadOneObject(wxObject *parent)
load one object from a CVG file.
double m_height
height in pixels
Definition: canprim.h:86
void DoRender(a2dIterC &ic, OVERLAP clipparent)
render derived object
Definition: vpath.cpp:616
used to move start or end point in line objects
Definition: drawing.h:2130
void DoWalker(wxObject *parent, a2dWalkerIOHandler &handler)
iterate over this object and its children
Definition: canprim.cpp:4932
bool HasAttribute(const wxString &attrib)
Does the current tag have this attribute?
Definition: genxmlpars.cpp:560
virtual void DrawArc(double x1, double y1, double x2, double y2, double xc, double yc, bool chord)
Draw Arc in world coordinates.
Definition: drawer2d.cpp:1957
void DoRender(a2dIterC &ic, OVERLAP clipparent)
render derived object
Definition: canprim.cpp:2565
bool m_chord
drawn as a chord ( no fill end no lines to center )
Definition: canprim.h:943
void SetEndAngle(double a)
Set the end angle (actually sets x2/y2)
Definition: canprim.cpp:3158
a2dHandle is used inside editing versions of a certain objects.
Definition: canpin.h:30
void ConvertToLines()
Convert complex segments to line segments.
Definition: polyver.cpp:4184
a2dCanvasObjectList * GetAsCanvasVpaths(bool transform=true) const
when implemented the object without its children, is converted to
Definition: canprim.cpp:2075
a2dWH
Definition: canprim.h:301
a2dConnectTask
flags for searching a connecting a2dpinClass, for the connecting task at hand.
Definition: connectgen.h:40
void SetRotation(double rotation)
Sets a rotation of this object.
Definition: canobj.cpp:2609
int WorldToDeviceY(double y) const
convert y from world to device coordinates
Definition: drawer2d.h:455
virtual void DoSave(wxObject *parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts, a2dObjectList *towrite)
write object specific CVGL data
Definition: canprim.cpp:2177
void Set(double xs, double ys, double xm, double ym, double xe, double ye)
set arc using begin, end and middle point.
Definition: canprim.cpp:3012
void SetStartAngle(double a)
Set the start angle (actually sets x1/y1)
Definition: canprim.cpp:3151
void DoLoad(wxObject *parent, a2dIOHandlerXmlSerIn &parser, a2dXmlSer_flag xmlparts)
load object specific CVG data
Definition: canprim.cpp:2189
a2dBoundingBox DoGetUnTransformedBbox(a2dBboxFlags flags=a2dCANOBJ_BBOX_NON) const
In derived object this should be overriden to calculate the boundingbox of the object without its chi...
Definition: canprim.cpp:248
void DoRender(a2dIterC &ic, OVERLAP clipparent)
render derived object
Definition: canprim.cpp:3993
#define a2dACCUR
accuracy used to have some limit to calculation like hittesting
Definition: artglob.h:41
virtual a2dObject * DoClone(CloneOptions options, a2dRefMap *refs) const
This is here so that this class cannot be used directly.
Definition: canprim.cpp:1184
void DoRender(a2dIterC &ic, OVERLAP clipparent)
render derived object
Definition: canprim.cpp:4691
bool m_frozen
are the wires frozen (means will not resize)
Definition: canprim.h:1520
virtual bool DoStartEdit(wxUint16 editmode, wxEditStyle editstyle)
only used for editable objects and under control of a editing tool.
Definition: canprim.cpp:1359
XMLeventType Next()
Walks to next element and returns event type.
Definition: genxmlpars.cpp:422
a2dCanvasObjectList * GetAsCanvasVpaths(bool transform=true) const
when implemented the object without its children, is converted to
Definition: canprim.cpp:1211
void SetRadius(double radius)
set corner radius of rectangle
Definition: canprim.h:491
virtual a2dVertexList * GetAsVertexList(bool &returnIsPolygon) const
convert to a polygon and return the vertexlist.
Definition: canprim.cpp:3200
bool ResolveOrAdd(a2dSmrtPtr< a2dObject > *storedHere, const wxString &id=wxT(""))
try to resolve the object that is in storedHere when it is a reference.
Definition: gen.cpp:4760
class to map references to objects stored in XML, in order to make the connection later on...
Definition: gen.h:3462
a2dPoint2D GetMidPoint() const
get point in between begin and end
Definition: canprim.cpp:3165
a2dDrawing * m_root
root group for rendering and accessing the canvas&#39;s also contains layer settings
Definition: canobj.h:2525
void SetPosXY12(double x1, double y1, double x2, double y2, bool afterinversion=true)
sets both positions of line
Definition: canprim.cpp:3932
void DoRender(a2dIterC &ic, OVERLAP clipparent)
render derived object
Definition: canprim.cpp:3467
void DoLoad(wxObject *parent, a2dIOHandlerXmlSerIn &parser, a2dXmlSer_flag xmlparts)
load object specific CVG data
Definition: canprim.cpp:2613
a2dBoundingBox DoGetUnTransformedBbox(a2dBboxFlags flags=a2dCANOBJ_BBOX_NON) const
In derived object this should be overriden to calculate the boundingbox of the object without its chi...
Definition: canprim.cpp:524
double m_radius
radius in case of rounded rectangle (negatif inwards positif outwards)
Definition: canprim.h:534
a2dPoint2D DistancePoint(double distance, bool begin) const
calculate point on line at distance from the begin or end of line
Definition: liner.cpp:315
a2dCanvasOFlags m_flags
holds flags for objects
Definition: canobj.h:2528
void DoLoad(wxObject *parent, a2dIOHandlerXmlSerIn &parser, a2dXmlSer_flag xmlparts)
load object specific CVG data
Definition: canprim.cpp:1612
void DoRender(a2dIterC &ic, OVERLAP clipparent)
render derived object
Definition: canprim.cpp:1565
virtual a2dVertexList * GetAsVertexList(bool &returnIsPolygon) const
convert to a polygon.
Definition: canprim.cpp:1189
const a2dAffineMatrix & GetInverseTransform() const
Inverse of GetTransform()
Definition: canobj.cpp:699
static const a2dCanvasObjectFlagsMask BIN2
Definition: candefs.h:193
void SetValid(bool)
Definition: bbox.cpp:364
a2dRectC()
constructor
Definition: canprim.cpp:341
a2dCanvasObjectList * GetAsCanvasVpaths(bool transform=true) const
when implemented the object without its children, is converted to
Definition: canprim.cpp:408
virtual a2dObject * DoClone(CloneOptions options, a2dRefMap *refs) const
Clone this object and return a pointer to the new object.
Definition: canprim.cpp:186
void Transform(const a2dAffineMatrix &world)
transform all segments with given matrix
Definition: polyver.cpp:4075
a2dPin is used in a2dCanvasObject to add pins to it.
Definition: canpin.h:233
This is a class/type description for a2dPin&#39;s.
Definition: canpin.h:628
static a2dHit stock_nohit
Stock object for no hit.
Definition: polyver.h:135
a2dBoundingBox DoGetUnTransformedBbox(a2dBboxFlags flags=a2dCANOBJ_BBOX_NON) const
In derived object this should be overriden to calculate the boundingbox of the object without its chi...
Definition: canprim.cpp:2452
Ref Counted base object.
Definition: gen.h:1045
void DoRender(a2dIterC &ic, OVERLAP clipparent)
render derived object
Definition: canprim.cpp:2159
static a2dHit stock_strokeinside
Stock object for an inner stroke hit on objects without vertices/edges (like circles) ...
Definition: polyver.h:141
bool DoIsHitWorld(a2dIterC &ic, a2dHitEvent &hitEvent)
Does hit test on the object (exclusif child objects)
Definition: canprim.cpp:546
void SetTransformMatrix(const a2dAffineMatrix &mat=a2dIDENTITY_MATRIX)
Returns the matrix used to position the object.
Definition: canobj.h:509
bool Rotate(double angle)
Rotate clockwise by the given number of degrees:
Definition: afmatrix.cpp:432
void Enlarge(const double Marge)
enlarge with the given amount
Definition: bbox.cpp:162
double m_x1
start x
Definition: canprim.h:1143
virtual bool DoStartEdit(wxUint16 editmode, wxEditStyle editstyle)
only used for editable objects and under control of a editing tool.
Definition: canprim.cpp:2697
basetype * GetPropertyValuePtr(a2dObject *obj) const
Get a pointer to the property value in obj.
Definition: id.inl:366
double wxDegToRad(double deg)
conversion from degrees to radians
Definition: artglob.cpp:30
double GetRadius() const
get radius of the Arc
Definition: canprim.cpp:3001
bool GeneratePins(a2dPinClass *toConnectTo, a2dConnectTask task, double x, double y, double margin=0)
create pins in derived objects.
Definition: canprim.cpp:1984
double GetContourWidth() const
get the Contour width of the shape
Definition: canprim.h:485
void DoRender(a2dIterC &ic, OVERLAP clipparent)
render derived object
Definition: canprim.cpp:5451
a2dWires()
constructor
Definition: canprim.cpp:5173
a2dEllipticArc()
constructor
Definition: canprim.cpp:2326
static a2dPropertyIdDouble * PROPID_StartAngle
property for class member
Definition: canprim.h:972
a2dBoundingBox DoGetUnTransformedBbox(a2dBboxFlags flags=a2dCANOBJ_BBOX_NON) const
In derived object this should be overriden to calculate the boundingbox of the object without its chi...
Definition: canprim.cpp:3307
a2dWHCenter()
default constructor
Definition: canprim.cpp:1107
bool IsHit() const
true if this is a hit
Definition: polyver.h:107
double m_contourwidth
if != 0 you get a donut
Definition: canprim.h:618
virtual bool Update(UpdateMode mode)
Update the state of the object according to its current position etc.
Definition: canobj.cpp:5149
a2dBoundingBox DoGetUnTransformedBbox(a2dBboxFlags flags=a2dCANOBJ_BBOX_NON) const
In derived object this should be overriden to calculate the boundingbox of the object without its chi...
Definition: canprim.cpp:4865
double GetY2() const
Get Y2 of arc being end point of arc.
Definition: canprim.h:872
void SetChord(bool chord)
if true draw as a chord ( no fill end no lines to center )
Definition: canprim.cpp:2357
Arc Segment.
Definition: polyver.h:1112
#define EVT_CANVASHANDLE_MOUSE_EVENT(func)
static event table macro for a2dHandle mouse event
Definition: canglob.h:318
double m_width
width in pixels
Definition: canprim.h:83
bool EliminateMatrix()
reduce matrix to identity without replacing object
Definition: canprim.cpp:3885
double GetBase()
return how broad the basis of the arrow is.
Definition: canprim.h:246
Input and output handler for the XmlSer format.
Definition: genxmlpars.h:819
virtual void DrawPolygon(a2dVertexArray *points, bool spline=false, wxPolygonFillMode fillStyle=wxODDEVEN_RULE)
Draw polygon in world coordinates using pointarray.
Definition: drawer2d.cpp:1889
UpdateMode
Various mode flags for Update.
Definition: canobj.h:1091
static a2dPropertyIdDouble * PROPID_EndAngle
property for class member
Definition: canprim.h:974
void SetChord(bool chord)
if true draw as a chord ( no fill end no lines to center )
Definition: canprim.cpp:3006
bool DoUpdate(UpdateMode mode, const a2dBoundingBox &childbox, const a2dBoundingBox &clipbox, const a2dBoundingBox &propbox)
Update derived Object specific things ( mainly boundingbox)
Definition: canprim.cpp:4362
double GetScale()
See GetScale()
Definition: genxmlpars.h:784
R_PointStatus PointInLine(const a2dPoint2D &a_Point, double &Distance, double Marge) const
For a non-infinite a2dLine.
Definition: liner.cpp:560
double GetValue(int col, int row) const
get the value in the matrix at col,row
Definition: afmatrix.cpp:106
~a2dWires()
destructor
Definition: canprim.cpp:5244
virtual void SetPending(bool pending)
set this object pending for update
Definition: canobj.cpp:2585
OVERLAP
Result of a a2dBoundingBox intersection or hittest.
Definition: bbox.h:24
bool m_visiblechilds
child objects are visible or not
Definition: candefs.h:292
bool DoUpdate(UpdateMode mode, const a2dBoundingBox &childbox, const a2dBoundingBox &clipbox, const a2dBoundingBox &propbox)
Update derived Object specific things ( mainly boundingbox)
Definition: canprim.cpp:2131
a2dCanvasObjectList * GetAsCanvasVpaths(bool transform=true) const
return the arrow converted to a vector path.
Definition: canprim.cpp:216
a2dPropertyIdTyped< bool, a2dBoolProperty > a2dPropertyIdBool
property of this type
Definition: id.h:655
a2dRectC is a centered rectangle
Definition: canprim.h:99
a2dPin * IsConnectedTo(a2dPin *pin=a2dAnyPin) const
Return the pin to which this pin is connected.
Definition: canpin.cpp:751
double m_y2
y of end point
Definition: canprim.h:954
void DoLoad(wxObject *parent, a2dIOHandlerXmlSerIn &parser, a2dXmlSer_flag xmlparts)
load object specific CVG data
Definition: canprim.cpp:4983
double m_contourwidth
if != 0 the line is contoured at distance m_contourwidth/2
Definition: canprim.h:1152
double m_l1
length from top of arrow to outside points in X
Definition: canprim.h:277
a2dArc()
constructor
Definition: canprim.cpp:2920
bool m_hasPins
true if this object does have a2dPin&#39;s as children
Definition: candefs.h:323
snap end point of line
Definition: restrict.h:110
The base class for all drawable objects in a a2dCanvasDocument.
double GetTransformedHitMargin()
transformed to object its coordinate system
Definition: canobj.cpp:616
bool DoIsHitWorld(a2dIterC &ic, a2dHitEvent &hitEvent)
Does hit test on the object (exclusif child objects)
Definition: canprim.cpp:5016
static a2dPropertyIdDouble * PROPID_Y2
property for class member
Definition: canprim.h:968
static a2dPropertyIdBool * PROPID_Chord
property for class member
Definition: canprim.h:970
~a2dEndsEllipticChord()
destructor
Definition: canprim.cpp:4845
virtual bool RestrictToObject(a2dIterC &ic, const a2dPoint2D &pointToSnapTo, a2dPoint2D &bestPointSofar, a2dSnapToWhatMask snapToWhat, double thresHoldWorld)
called from an a2dRestrictionEngine, to restrict vertexes, lines, object to this object.
Definition: canprim.cpp:671
double GetWidth() const
return width
Definition: canprim.h:337
void DoLoad(wxObject *parent, a2dIOHandlerXmlSerIn &parser, a2dXmlSer_flag xmlparts)
load object specific CVG data
Definition: canprim.cpp:1887
void DoRender(a2dIterC &ic, OVERLAP clipparent)
render derived object
Definition: canprim.cpp:100
bool DoUpdate(UpdateMode mode, const a2dBoundingBox &childbox, const a2dBoundingBox &clipbox, const a2dBoundingBox &propbox)
Update derived Object specific things ( mainly boundingbox)
Definition: canprim.cpp:5109
double m_xscale
scale begin and end object with this factor in X
Definition: canprim.h:1412
wxUint16 m_layer
layer of object, default wxLAYER_DEFAULT
Definition: canobj.h:2556
virtual void DoLoad(wxObject *parent, a2dIOHandlerXmlSerIn &parser, a2dXmlSer_flag xmlparts)
load object specific CVG data
Definition: canobj.cpp:5728
static a2dPropertyIdDouble * PROPID_X1
property for class member
Definition: canprim.h:962
void DoRender(a2dIterC &ic, OVERLAP clipparent)
render derived object
Definition: canprim.cpp:4903
void DoLoad(wxObject *parent, a2dIOHandlerXmlSerIn &parser, a2dXmlSer_flag xmlparts)
load object specific CVG data
Definition: canprim.cpp:4066
vertex array of line and arc segments.
Definition: polyver.h:494
bool m_spline
draw splined?
Definition: canprim.h:286
a2dCanvasObject is the base class for Canvas Objects.
Definition: canobj.h:371
virtual bool RestrictToObject(a2dIterC &ic, const a2dPoint2D &pointToSnapTo, a2dPoint2D &bestPointSofar, a2dSnapToWhatMask snapToWhat, double thresHoldWorld)
called from an a2dRestrictionEngine, to restrict vertexes, lines, object to this object.
Definition: canprim.cpp:4021
virtual void DoSave(wxObject *parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts, a2dObjectList *towrite)
write object specific CVGL data
Definition: canprim.cpp:4453
no special flags set
Definition: id.h:161
void DoLoad(wxObject *parent, a2dIOHandlerXmlSerIn &parser, a2dXmlSer_flag xmlparts)
load object specific CVG data
Definition: canprim.cpp:4490
void SetX1(double x1)
Set X1 of arc being begin point of arc.
Definition: canprim.h:882
double GetContourWidth() const
get the Contour width of the shape
Definition: canprim.h:924
A2DGENERALDLLEXP a2dWalkEvent a2dWalker_a2dDerivedCanvasObjectStart
id for a2dWalkEvent issued from within a2dWalkerIOHandler
bool SetPointIfCloser(const a2dPoint2D &pointToSnapTo, const a2dPoint2D &pointToSnap, a2dPoint2D &bestPointSofar, double thresHoldWorld)
Definition: canobj.cpp:4189
void SetWidth(double w)
set width of rectangle
Definition: canprim.h:328
void ReStartEdit(wxUint16 editmode)
to restart editing in a different mode
Definition: canobj.cpp:1693
virtual a2dVertexList * GetAsVertexList(bool &returnIsPolygon) const
convert to a polygon.
Definition: canprim.cpp:2053
a2dCanvasObjectList * GetChildObjectList()
get the list where the child objects are stored in.
Definition: canobj.cpp:2551
vertex list of line and arc segments.
Definition: polyver.h:600
void Set(double xc, double yc, double w, double h, double angle=0, double radius=0)
set all paramters for the centered rectangle
Definition: canprim.cpp:371
void TransformPoint(double x, double y, double &tx, double &ty) const
Transform a point.
Definition: afmatrix.cpp:559
virtual void DrawCenterRoundedRectangle(double xc, double yc, double width, double height, double radius, bool pixelsize=false)
Draw CenterRoundedRectangle in world coordinates.
Definition: drawer2d.cpp:2040
static const a2dCanvasObjectFlagsMask A
Definition: candefs.h:190
bool m_snap_to
snapping of other objects to this when in place
Definition: candefs.h:283
double GetRotation() const
return rotation
Definition: afmatrix.cpp:799
wxString GetName() const
get the name given to the handle.
Definition: canpin.h:56
bool DoUpdate(UpdateMode mode, const a2dBoundingBox &childbox, const a2dBoundingBox &clipbox, const a2dBoundingBox &propbox)
Update derived Object specific things ( mainly boundingbox)
Definition: canprim.cpp:3370
virtual bool DoStartEdit(wxUint16 editmode, wxEditStyle editstyle)
only used for editable objects and under control of a editing tool.
Definition: canprim.cpp:1973
return to contain edit bbox, suitable for editing matrix of object
Definition: canobj.h:666
virtual bool RestrictToObject(a2dIterC &ic, const a2dPoint2D &pointToSnapTo, a2dPoint2D &bestPointSofar, a2dSnapToWhatMask snapToWhat, double thresHoldWorld)
called from an a2dRestrictionEngine, to restrict vertexes, lines, object to this object.
Definition: canobj.cpp:4209
void WriteEndElement(bool newLine=true)
Writes correspondending end tag for the current start tag.
Definition: genxmlpars.cpp:862
a2dBoundingBox DoGetUnTransformedBbox(a2dBboxFlags flags=a2dCANOBJ_BBOX_NON) const
In derived object this should be overriden to calculate the boundingbox of the object without its chi...
Definition: canprim.cpp:92
a2dEndsEllipticChord()
constructor
Definition: canprim.cpp:4804
double m_yscale
scale begin and end object with this factor in Y
Definition: canprim.h:1257
vector path a2dVectorPath derived from a2dCanvasObject
a2dAffineMatrix m_lworld
used for positioning the object (x,y,ang,scale etc.)
Definition: canobj.h:2559
void SetEndObj(a2dCanvasObject *endob)
set object to draw as end point
Definition: canprim.cpp:4857
void SetInternal(bool internal)
set when pin is within the border of its parent
Definition: canpin.h:444
Io handler to iterate through a a2dDocument.
Definition: gen.h:3911
void SetHeight(double h)
set height of rectangle
Definition: canprim.h:334
double m_y1
start y
Definition: canprim.h:1145
wxMouseEvent & GetMouseEvent()
return the original mouse event that was redirected to the a2dHandle
Definition: canglob.h:290
virtual void DoSave(wxObject *parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts, a2dObjectList *towrite)
write object specific CVGL data
Definition: canprim.cpp:694
bool GetCheck() const
general flag use at will.
Definition: gen.h:1342
double GetEndAngle() const
Get the end angle (calculated form x2/y2)
Definition: canprim.cpp:3140
bool m_draggable
can be dragged
Definition: candefs.h:253
virtual void DoSave(wxObject *parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts, a2dObjectList *towrite)
write object specific CVGL data
Definition: canprim.cpp:2598
double m_contourwidth
if != 0 you get a contour around the rectangle ( donut like ).
Definition: canprim.h:794
void SetIgnoreSetpending(bool value=true)
set IgnoreSetpending flag
Definition: canobj.h:2299
void ConnectPins(a2dCanvasObject *parent, a2dPin *pinc, a2dPin *pinother, bool undo=false)
connect two pins which must be unconnected and at the same position
Definition: canobj.cpp:7037
a2dCanvasObjectList * wxNullCanvasObjectList
define a NON a2dCanvasObjectList
Definition: objlist.cpp:53
void DoRender(a2dIterC &ic, OVERLAP clipparent)
render derived object
Definition: canprim.cpp:256
used to change a property on objects
Definition: drawing.h:2244
see a2dCanvasObjectMouseEvent
Definition: canglob.h:161
void ConnectTo(a2dPin *connectto)
connect this pin to the given pin
Definition: canpin.cpp:918
bool GetValid() const
returns true if boundingbox is calculated properly and therefore its valid flag is set...
Definition: bbox.cpp:299
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
virtual a2dBoundingBox GetUnTransformedBbox(a2dBboxFlags flags=a2dCANOBJ_BBOX_CHILDREN) const
Get boundingbox without the affine matrix transform included.
Definition: canobj.cpp:5036
double GetMinX() const
get minimum X of the boundingbox
Definition: bbox.cpp:304
double GetLength() const
Returns length of line.
Definition: canprim.cpp:3893
virtual void DrawRoundedRectangle(double x, double y, double width, double height, double radius, bool pixelsize=false)
Draw RoundedRectangle in world coordinates.
Definition: drawer2d.cpp:2048
a2dOrigin stays at World Coordinate Zero (0,0) not matter what.
Definition: canprim.h:31
a2dCanvasObjectList * m_childobjects
holds child objects
Definition: canobj.h:2562
a2dCanvasObjectList * GetAsCanvasVpaths(bool transform=true) const
when implemented the object without its children, is converted to
Definition: canprim.cpp:2390
virtual a2dVertexList * GetAsVertexList(bool &returnIsPolygon) const
convert to a polygon.
Definition: canprim.cpp:1740
void DoLoad(wxObject *parent, a2dIOHandlerXmlSerIn &parser, a2dXmlSer_flag xmlparts)
load object specific CVG data
Definition: canprim.cpp:707
a2dControl captures a wxWindow inside
Definition: canprim.h:1427
~a2dWHCenter()
destructor
Definition: canprim.cpp:1122
void Transform(const a2dAffineMatrix &tworld)
transform the object using the given matrix
Definition: canobj.h:577
static a2dPropertyIdDouble * PROPID_Width
property to get m_width
Definition: canprim.h:374
void SetPosXY1(double x, double y, bool afterinversion=true)
sets position of first point
Definition: canprim.cpp:3902
#define forEachIn(listtype, list)
easy iteration for a2dlist
Definition: a2dlist.h:111
a2dBoundingBox DoGetUnTransformedBbox(a2dBboxFlags flags=a2dCANOBJ_BBOX_NON) const
In derived object this should be overriden to calculate the boundingbox of the object without its chi...
Definition: canprim.cpp:684
bool DoUpdate(UpdateMode mode, const a2dBoundingBox &childbox, const a2dBoundingBox &clipbox, const a2dBoundingBox &propbox)
Update derived Object specific things ( mainly boundingbox)
Definition: canprim.cpp:2487
virtual a2dObject * DoClone(CloneOptions options, a2dRefMap *refs) const
Clone this object and return a pointer to the new object.
Definition: canprim.cpp:4632
a2dEllipse centered at x,y.
Definition: canprim.h:635
a2dAffineMatrix GetEndTransform() const
Get the coordinate transform for the end object.
Definition: canprim.cpp:5059
void SetPropertyToObject(a2dObject *obj, const basetype &value, SetFlags setflags=set_none) const
Set the property in obj to value.
Definition: id.inl:238
void Walker(wxObject *parent, a2dWalkerIOHandler &handler)
This is used to recursively walk through an object tree.
Definition: gen.cpp:1473
double GetPosX() const
get x position from affine matrix
Definition: canobj.h:527
The point is in the fill area.
Definition: polyver.h:56
a2dCanvasObjectPtr m_beginobj
object drawn at begin point
Definition: canprim.h:1406
void SkewY(double angle)
Skew in Y.
Definition: canobj.cpp:2627
virtual a2dObject * DoClone(CloneOptions options, a2dRefMap *refs) const
Clone this object and return a pointer to the new object.
Definition: canprim.cpp:382
a2dDrawer2D * GetDrawer2D() const
get current a2dDrawer2D
Definition: canobj.cpp:636
Normal straight line segment in a2dVpath.
Definition: polyver.h:878
#define wxStaticCast(obj, className)
The wxWindows 2.4.2 wxStaticCast is buggy. It evaluates its argument twice.
Definition: gen.h:123
virtual a2dObject * DoClone(CloneOptions options, a2dRefMap *refs) const
Clone this object and return a pointer to the new object.
Definition: canprim.cpp:5248
bool m_editable
object can be edited
Definition: candefs.h:295
snap start point of line
Definition: restrict.h:109
bool DoIsHitWorld(a2dIterC &ic, a2dHitEvent &hitEvent)
Does hit test on the object (exclusif child objects)
Definition: canprim.cpp:3531
double wxRadToDeg(double rad)
conversion from radians to degrees
Definition: artglob.cpp:31
Normal straight line segment in a2dVertexList and a2dVertexArray.
Definition: polyver.h:163
double GetL1()
Returns the arrow length.
Definition: canprim.h:240
void SkewX(double angle)
Skew in X.
Definition: canobj.cpp:2621
void SetSpecificFlags(bool setOrClear, a2dCanvasObjectFlagsMask which)
set all bit flags in object that or true in mask to true or false
Definition: canobj.cpp:2645
a2dSLine
Definition: canprim.h:987
void SetContourWidth(double width)
Definition: vpath.h:155
~a2dCircle()
destructor
Definition: canprim.cpp:1724
Definition: bbox.h:27
bool DoIsHitWorld(a2dIterC &ic, a2dHitEvent &hitEvent)
Does hit test on the object (exclusif child objects)
Definition: canprim.cpp:5133
void CalculateLineParameters()
Calculate the parameters if invalid.
Definition: liner.cpp:355
virtual void DoSave(wxObject *parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts, a2dObjectList *towrite)
write object specific CVGL data
Definition: canobj.cpp:5569
void Translate(double x, double y)
relative translate the object to position x,y in world coordinates
Definition: canobj.h:569
virtual bool DoStartEdit(wxUint16 editmode, wxEditStyle editstyle)
only used for editable objects and under control of a editing tool.
Definition: canprim.cpp:2248
general event sent from a2dHandle to its parent a2dCanvasObject
Definition: canglob.h:273
void Add(a2dVpathSegment *seg)
add a segment
Definition: polyver.h:1240
a2dArrow()
constructor
Definition: canprim.cpp:142
Restriction engine for editing restrictions like snapping.
Definition: restrict.h:88
double m_l2
length from top of arrow to inside point in X
Definition: canprim.h:280
void SetBeginObj(a2dCanvasObject *begin)
set object to draw as begin point
Definition: canprim.cpp:4849
virtual a2dObject * DoClone(CloneOptions options, a2dRefMap *refs) const
Clone this object and return a pointer to the new object.
Definition: canprim.cpp:1735
bool m_childrenOnSameLayer
Definition: candefs.h:311
void DoRender(a2dIterC &ic, OVERLAP clipparent)
render derived object
Definition: canprim.cpp:1856
int WorldToDeviceX(double x) const
convert x from world to device coordinates
Definition: drawer2d.h:453
bool DoIsHitWorld(a2dIterC &ic, a2dHitEvent &hitEvent)
Does hit test on the object (exclusif child objects)
Definition: canprim.cpp:271
virtual void DoSave(wxObject *parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts, a2dObjectList *towrite)
write object specific CVGL data
Definition: canprim.cpp:4050
bool HasPins(bool realcheck=false)
are there a2dPin derived children
Definition: canobj.cpp:6414
virtual void DrawLine(double x1, double y1, double x2, double y2)
Draw line in world coordinates.
Definition: drawer2d.cpp:2167
Input and output handler for the XmlSer format.
Definition: genxmlpars.h:862
a2dPin * AddPin(const wxString name, double x, double y, wxUint32 a2dpinFlags, a2dPinClass *pinClass, bool undo=false)
add a a2dPin as child
Definition: canobj.cpp:6474
bool DoUpdate(UpdateMode mode, const a2dBoundingBox &childbox, const a2dBoundingBox &clipbox, const a2dBoundingBox &propbox)
Update derived Object specific things ( mainly boundingbox)
Definition: canprim.cpp:4881
double m_y2
end y
Definition: canprim.h:1149
virtual a2dObject * DoClone(CloneOptions options, a2dRefMap *refs) const
This is here so that this class cannot be used directly.
Definition: canprim.cpp:2363
void SetPathType(a2dPATH_END_TYPE pathtype)
Set when m_contourwidth != 0 what is the end of the lines should be.
Definition: vpath.h:169
void DoLoad(wxObject *parent, a2dIOHandlerXmlSerIn &parser, a2dXmlSer_flag xmlparts)
load object specific CVG data
Definition: canprim.cpp:301
double GetPosY2(bool transform=true) const
Get (transformed) position of Y2.
Definition: canprim.cpp:3875
a2dCanvasObjectPtr m_begin
object drawn at begin point
Definition: canprim.h:1248
Contains a2dDrawing Class to hold a drawing.
a2dArrow is used for having line begin and ends on specific objects.
Definition: canprim.h:198
wxUint32 a2dSnapToWhatMask
mask for a2dSnapToWhat flags
Definition: restrict.h:26
no hit will be reported
Definition: canobj.h:160
double m_xscale
scale begin and end object with this factor in X
Definition: canprim.h:1254
~a2dWH()
destructor
Definition: canprim.cpp:636
virtual bool Submit(a2dCommand *command, bool storeIt=true)
next to the base class submit, it sets a2DocumentCommandProcessor for a2dCommand
Definition: comevt.cpp:842
double GetX1() const
Get X1 of arc being begin point of arc.
Definition: canprim.h:866
virtual void DoSave(wxObject *parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts, a2dObjectList *towrite)
write object specific CVGL data
Definition: canprim.cpp:4946
a2dScaledEndLine
Definition: canprim.h:1277
virtual bool DoStartEdit(wxUint16 editmode, wxEditStyle editstyle)
only used for editable objects and under control of a editing tool.
Definition: canobj.cpp:1739
a2dCanvasObjectList * GetAsCanvasVpaths(bool transform=true) const
when implemented the object without its children, is converted to
Definition: canprim.cpp:1762
A 2x3 affine matrix class for 2D transformations.
Definition: afmatrix.h:53
a2dStroke GetDrawerStroke() const
get the current stroke
Definition: drawer2d.h:548
bool DoUpdate(UpdateMode mode, const a2dBoundingBox &childbox, const a2dBoundingBox &clipbox, const a2dBoundingBox &propbox)
Update derived Object specific things ( mainly boundingbox)
Definition: canprim.cpp:4655
a2dWH()
default constructor
Definition: canprim.cpp:614
double GetAttributeValueDouble(const wxString &attrib, double defaultv=0)
Returns the double value of an attribute.
Definition: genxmlpars.cpp:474
bool DoIsHitWorld(a2dIterC &ic, a2dHitEvent &hitEvent)
Does hit test on the object (exclusif child objects)
Definition: canprim.cpp:2202
int GetPinCount()
How many a2dPin derived children are there.
Definition: canobj.cpp:6455
virtual void DoWalker(wxObject *parent, a2dWalkerIOHandler &handler)
iterate over this object and its children
Definition: canprim.cpp:4525
double GetStartAngle() const
Get the start angle (calculated form x1/y1)
Definition: canprim.cpp:3129
double GetMaxX() const
get maximum X of the boundingbox
Definition: bbox.cpp:316
virtual a2dVertexList * GetAsVertexList(bool &returnIsPolygon) const
convert to a polygon.
Definition: canprim.cpp:2368
static a2dPropertyIdDouble * PROPID_X2
property for class member
Definition: canprim.h:964
double GetPosX1(bool transform=true) const
Get (transformed) position of X1.
Definition: canprim.cpp:3845
a2dPin * HasPinNamed(const wxString pinName, bool NotConnected=false)
are there a2dPin derived children which matches the given pin name?
Definition: canobj.cpp:6436
double GetPosY() const
get y position from affine matrix
Definition: canobj.h:530
bool DoIsHitWorld(a2dIterC &ic, a2dHitEvent &hitEvent)
Does hit test on the object (exclusif child objects)
Definition: canprim.cpp:721
double GetWorldStrokeExtend()
Definition: canobj.h:3403
wxWindow * m_control
control with a a2dCanvas as parent.
Definition: canprim.h:1462
void DoRender(a2dIterC &ic, OVERLAP clipparent)
render derived object
Definition: canprim.cpp:534
bool DoIsHitWorld(a2dIterC &ic, a2dHitEvent &hitEvent)
Does hit test on the object (exclusif child objects)
Definition: canprim.cpp:4538
virtual a2dObject * DoClone(CloneOptions options, a2dRefMap *refs) const
This is here so that this class cannot be used directly.
Definition: canprim.cpp:4840
double m_x1
x of begin point
Definition: canprim.h:946
virtual double GetContourWidth() const
get the Contour width of the shape
Definition: canobj.h:1411
while iterating a a2dCanvasDocument, this holds the context.
Definition: canobj.h:3212
double m_height
height of rectangle
Definition: canprim.h:174
virtual a2dObject * DoClone(CloneOptions options, a2dRefMap *refs) const
Clone this object and return a pointer to the new object.
Definition: canprim.cpp:3124
double GetContourWidth() const
get the Contour width of the shape
Definition: canprim.h:1108
virtual void DrawEllipticArc(double xc, double yc, double width, double height, double sa, double ea, bool chord)
Draw Elliptic Arc in world coordinates.
Definition: drawer2d.cpp:1998
~a2dSLine()
destructor
Definition: canprim.cpp:3825
double m_yscale
scale begin and end object with this factor in Y
Definition: canprim.h:1415
double wxSqr(double x)
good replacement for pow(x,2)
Definition: artglob.h:66
void Set(double xt, double yt, double l1, double l2, double b, bool spline=false)
Sets top, length, height and broad parameters.
Definition: canprim.cpp:165
virtual bool IsConnect() const
type of wire
Definition: canprim.cpp:5255
All updates of these modes force an update (e.g. update non-pending valid bounding boxes) ...
Definition: canobj.h:1107
virtual bool DoStartEdit(wxUint16 editmode, wxEditStyle editstyle)
only used for editable objects and under control of a editing tool.
Definition: canprim.cpp:4107
void MapBbox(const a2dAffineMatrix &matrix)
Definition: bbox.cpp:445
Definition: bbox.h:28
virtual a2dObject * DoClone(CloneOptions options, a2dRefMap *refs) const
This is here so that this class cannot be used directly.
Definition: canprim.cpp:2048
a2dCommandProcessor * GetCommandProcessor() const
Returns a pointer to the command processor associated with this document.
Definition: drawing.h:549
virtual a2dVertexList * GetAsVertexList(bool &returnIsPolygon) const
convert to a polygon.
Definition: canprim.cpp:387
a2dBoundingBox GetMappedBbox(a2dIterC &ic, bool withExtend=true)
first translate boundingbox with cworld and recalculate at new position
Definition: canobj.cpp:3256
a2dBoundingBox DoGetUnTransformedBbox(a2dBboxFlags flags=a2dCANOBJ_BBOX_NON) const
In derived object this should be overriden to calculate the boundingbox of the object without its chi...
Definition: canprim.cpp:4315
void SetStroke(const wxColour &strokecolor, double width=0, a2dStrokeStyle style=a2dSTROKE_SOLID)
Set a stroke for the object which will be used instead of the layer stroke.
Definition: canobj.cpp:2924
void SetChildrenOnSameLayer(bool samelayer)
if set children are rendered on the same layer as this object.
Definition: canobj.h:1429
Line calculations.
Definition: liner.h:36
a2dWires is used to generate wires to Connect other a2dCanvasObject&#39;s
Definition: canprim.h:1482
void Scale(double scalex, double scaley)
Scale in x and y ( &gt; zero)
Definition: canobj.cpp:2633
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
wxString GetName() const
get the name given to the pin.
Definition: canpin.h:322
wxString GetAttributeValue(const wxString &attrib, const wxString &defaultv=wxT(""))
Returns the value of an attribute.
Definition: genxmlpars.cpp:450
~a2dRectC()
destructor
Definition: canprim.cpp:359
a2dRestrictionEngine * GetRestrictionEngine()
Get restriction engine (grid snapping)
Definition: canglob.cpp:934
double m_start
start angle
Definition: canprim.h:788
bool DoUpdate(UpdateMode mode, const a2dBoundingBox &childbox, const a2dBoundingBox &clipbox, const a2dBoundingBox &propbox)
Update derived Object specific things ( mainly boundingbox)
Definition: canprim.cpp:1828
a2dOrigin()
constructor
Definition: canprim.cpp:62
double GetAbsAngle() const
get absolute angle of the pin ( after applying the parent its matrix and it own matrix ) ...
Definition: canpin.cpp:990
virtual a2dVertexList * GetAsVertexList(bool &returnIsPolygon) const
return the arrow converted to a polygon.
Definition: canprim.cpp:192
double m_y1
y endpoint of line
Definition: polyver.h:922
wire classes for connecting objects.
bool InArc(double angle, double start, double end, bool clockwise)
Definition: polyver.cpp:148
a2dCanvasObjectList * GetAsCanvasVpaths(bool transform=true) const
when implemented the object without its children, is converted to
Definition: canprim.cpp:3222
a2dEndsLine with begin and/or end object.
Definition: canprim.h:1174
double m_b
base of arrow
Definition: canprim.h:283
a2dCanvasObjectList * GetAsCanvasVpaths(bool transform=true) const
when implemented the object without its children, is converted to
Definition: canprim.cpp:640
double GetMaxY() const
get maximum Y of the boundingbox
Definition: bbox.cpp:322
double GetWidth() const
returns width of the boundingbox
Definition: bbox.cpp:328
An object of this class will update a a2dIterC with the required information.
Definition: canobj.h:3123
void SetY2(double y2)
Set Y2 of arc being end point of arc.
Definition: canprim.h:888
void Require(const XMLeventType &type, wxString name)
Forces a special tag.
Definition: genxmlpars.cpp:390
virtual void DoSave(wxObject *parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts, a2dObjectList *towrite)
write object specific CVGL data
Definition: canprim.cpp:569
bool DoIsHitWorld(a2dIterC &ic, a2dHitEvent &hitEvent)
Does hit test on the object (exclusif child objects)
Definition: canprim.cpp:1901
wxString GetTagName()
Returns name of the current XML tag.
Definition: genxmlpars.cpp:565
virtual a2dObject * DoClone(CloneOptions options, a2dRefMap *refs) const
Clone this object and return a pointer to the new object.
Definition: canprim.cpp:87
static a2dPinClass * Standard
Pins of this class can only connect to pins of the same class.
Definition: canpin.h:766
double m_width
width of rectangle
Definition: canprim.h:367
static a2dPropertyIdDouble * PROPID_Y1
property for class member
Definition: canprim.h:966
void DoRender(a2dIterC &ic, OVERLAP clipparent)
render derived object
Definition: canprim.cpp:5118
void AddPoint(const a2dPoint2D &point, bool atEnd=true)
add point to end or begin
Definition: polyver.cpp:714
void SetPosXY(double x, double y, bool restrict=false)
set position to x,y
Definition: canobj.cpp:1624
bool Scale(double scale)
Scale by scale (isotropic scaling i.e. the same in x and y):
Definition: afmatrix.cpp:270
bool Translate(double x, double y)
Translate by dx, dy:
Definition: afmatrix.cpp:420
a2dEndsEllipticChord with begin and/or end object.
Definition: canprim.h:1327
void SetBegin(double l1, double l2, double b, bool spline=false)
set begin shape factors if it is a2dArrow derived
Definition: canprim.cpp:4641
bool m_editingCopy
true if the object needs to be rendered in edit mode.
Definition: candefs.h:304
double m_radius
radius of circle
Definition: canprim.h:615
bool DoUpdate(UpdateMode mode, const a2dBoundingBox &childbox, const a2dBoundingBox &clipbox, const a2dBoundingBox &propbox)
Update derived Object specific things ( mainly boundingbox)
Definition: canprim.cpp:5394
a2dAffineMatrix GetBeginTransform() const
Get the coordinate transform for the begin object.
Definition: canprim.cpp:5044
virtual bool EliminateMatrix()
reduce matrix to identity
Definition: canobj.cpp:6191
if set, clone members (e.g. line end styles), otherwise ref-copy them
Definition: gen.h:1203
bool DoIsHitWorld(a2dIterC &ic, a2dHitEvent &hitEvent)
Does hit test on the object (exclusif child objects)
Definition: canprim.cpp:2629
bool DoIsHitWorld(a2dIterC &ic, a2dHitEvent &hitEvent)
Does hit test on the object (exclusif child objects)
Definition: canprim.cpp:4083
virtual void DoSave(wxObject *parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts, a2dObjectList *towrite)
write object specific CVGL data
Definition: canprim.cpp:1874
a2dRect
Definition: canprim.h:440
a2dCanvasObject * IsHitWorld(a2dIterC &ic, a2dHitEvent &hitEvent)
If the position (x,y) is within the object return this.
Definition: canobj.cpp:3415
void SetBegin(a2dCanvasObject *begin)
set object to draw as begin point
Definition: canprim.cpp:4299
virtual bool RestrictAngle(double *ang, wxUint32 sourceRequired=snapToAll, bool ignoreEngine=false)
Restrict angle.
Definition: restrict.cpp:485
The a2dBoundingBox class stores one a2dBoundingBox of a a2dCanvasObject.
Definition: bbox.h:39
bool GetChildrenOnSameLayer() const
are children rendered on the same layer as this object?
Definition: canobj.h:1432
bool Invert(void)
Invert matrix.
Definition: afmatrix.cpp:197
double GetX2() const
Get X2 of arc being end point of arc.
Definition: canprim.h:870
bool m_chord
drawn as a chord ( no fill end no lines to center )
Definition: canprim.h:785
virtual a2dObject * DoClone(CloneOptions options, a2dRefMap *refs) const
Clone this object and return a pointer to the new object.
Definition: canprim.cpp:3840
void Rotate(double rotation)
Rotates this object clockwise.
Definition: canobj.cpp:2615
void SetX2(double x2)
Set X2 of arc being end point of arc.
Definition: canprim.h:886
void DoRender(a2dIterC &ic, OVERLAP clipparent)
render derived object
Definition: canprim.cpp:4394
double m_x2
x of end point
Definition: canprim.h:951
virtual a2dBoundingBox DoGetUnTransformedBbox(a2dBboxFlags flags=a2dCANOBJ_BBOX_NON) const
In derived object this should be overriden to calculate the boundingbox of the object without its chi...
Definition: canobj.cpp:5031
static a2dHit stock_fill
Stock object for a fill hit.
Definition: polyver.h:137
~a2dEllipticArc()
destructor
Definition: canprim.cpp:2344
virtual bool WalkTask(wxObject *parent, wxObject *object, a2dWalkEvent event)
called from within a2dObject&#39;s and derived classes
Definition: gen.cpp:5265
double GetMinY() const
get minimum Y of the boundingbox
Definition: bbox.cpp:310
double m_height
height of rectangle
Definition: canprim.h:369
double m_contourwidth
if != 0 the line is contoured at distance m_contourwidth/2
Definition: canprim.h:957
a2dArc centered at x,y
Definition: canprim.h:823
bool DoIsHitWorld(a2dIterC &ic, a2dHitEvent &hitEvent)
Does hit test on the object (exclusif child objects)
Definition: canprim.cpp:1626
the a2dDrawingPart is a a2dView specially designed for displaying parts of a a2dDrawing. It uses a a2dDrawer2D to actually redraw things from the document, by giving that a2dDrawer2D as drawing context to the document, and telling the document to redraw a certain rectangular area. At that last is what this class is for. It optimizes the areas to be redrawn after object in the document were changed. To do that it combines redraw areas to a minimal set of redrawing areas. All the administration for this and the way things will be redrawn is from this view.
virtual void DoSave(wxObject *parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts, a2dObjectList *towrite)
write object specific CVGL data
Definition: canprim.cpp:3498
double m_x1
x endpoint of line
Definition: polyver.h:919
virtual void DrawEllipse(double x, double y, double width, double height)
Draw Ellipse in world coordinates.
Definition: drawer2d.cpp:2121
basetype GetPropertyValue(const a2dObject *obj) const
Get the property value in obj.
Definition: id.inl:325
a2dBoundingBox DoGetUnTransformedBbox(a2dBboxFlags flags=a2dCANOBJ_BBOX_NON) const
In derived object this should be overriden to calculate the boundingbox of the object without its chi...
Definition: canprim.cpp:1548
virtual void DoSave(wxObject *parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts, a2dObjectList *towrite)
write object specific CVGL data
Definition: canprim.cpp:1596
#define Round(x)
round to integer such that e.g 2.5 &lt; x &lt; 3.5 becomes 3
Definition: artglob.h:60
virtual void DrawCircle(double x, double y, double radius)
Draw Circle in world coordinates.
Definition: drawer2d.cpp:2116
virtual void Save(wxObject *parent, a2dIOHandlerXmlSerOut &out, a2dObjectList *towrite)
write all needed to an XML type of file called the CVG format
Definition: gen.cpp:1343
double GetY1() const
Get Y1 of arc being begin point of arc.
Definition: canprim.h:868
a2dCanvasObject for a Vector Path
Definition: vpath.h:55
virtual bool DoUpdate(UpdateMode mode, const a2dBoundingBox &childbox, const a2dBoundingBox &clipbox, const a2dBoundingBox &propbox)
Update derived Object specific things ( mainly boundingbox)
Definition: canobj.cpp:5098
virtual void DoSave(wxObject *parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts, a2dObjectList *towrite)
write object specific CVGL data
Definition: canprim.cpp:116
void DoLoad(wxObject *parent, a2dIOHandlerXmlSerIn &parser, a2dXmlSer_flag xmlparts)
load object specific CVG data
Definition: canprim.cpp:3514
a2dDrawingPart * GetDrawingPart() const
get current a2dDrawingPart
Definition: canobj.cpp:631
a2dCanvasObjectPtr m_endobj
object drawn at end point
Definition: canprim.h:1409
bool DoStartEdit(wxUint16 editmode, wxEditStyle editstyle)
only used for editable objects and under control of a editing tool.
Definition: canprim.cpp:735
This template class is for property ids with a known data type.
Definition: id.h:477
bool ConnectWith(a2dCanvasObject *parent, a2dCanvasObject *graph, const wxString &pinname, double margin=1, bool undo=false)
Do connect with another a2dCanvasObject by pinname.
Definition: canprim.cpp:5260
~a2dArc()
destructor
Definition: canprim.cpp:2967
double m_end
end angle
Definition: canprim.h:791
double GetScale()
See GetScale()
Definition: genxmlpars.h:545
double GetPosY1(bool transform=true) const
Get (transformed) position of Y1.
Definition: canprim.cpp:3855
a2dBoundingBox m_bbox
boundingbox in world coordinates
Definition: canobj.h:2539
Vector Path.
Definition: polyver.h:1211
double GetContourWidth() const
get the Contour width of the shape
Definition: canprim.h:668
double RequireAttributeValueDouble(const wxString &attrib)
Forces an attribute and returns its double value.
Definition: genxmlpars.cpp:487
double m_width
width of rectangle
Definition: canprim.h:172
bool DoUpdate(UpdateMode mode, const a2dBoundingBox &childbox, const a2dBoundingBox &clipbox, const a2dBoundingBox &propbox)
Update derived Object specific things ( mainly boundingbox)
Definition: canprim.cpp:1075
bool m_takeStyleToArrow
if set take style changes on line to the arrow objects
Definition: canprim.h:1260
virtual void DoSave(wxObject *parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts, a2dObjectList *towrite)
write object specific CVGL data
Definition: canprim.cpp:286
double GetAbsX() const
get absolute X position of the pin ( after applying the parent&#39;s matrix and its own matrix ) ...
Definition: canpin.cpp:959
bool GeneratePins(a2dPinClass *toConnectTo, a2dConnectTask task, double x, double y, double margin=0)
create pins in derived objects.
Definition: canprim.cpp:1648
void SetPosXY2(double x, double y, bool afterinversion=true)
sets position of second point
Definition: canprim.cpp:3917
void Append(a2dCanvasObject *obj)
append a a2dCanvasObject to the childobjects
Definition: canobj.cpp:6224
virtual void DoEndEdit()
only used for editable objects and under control of a editing tool.
Definition: canprim.cpp:5164
double GetHeight() const
return height
Definition: canprim.h:339
double m_contourwidth
if != 0 you get a contour around the rectangle ( donut like ).
Definition: canprim.h:537
a2dCanvasObject * GetParent() const
get parent object of the pin
Definition: canpin.h:295
const a2dAffineMatrix & GetTransform() const
Get the accumulated transform up to and including m_lworld of the current object. ...
Definition: canobj.cpp:663
virtual a2dObject * DoClone(CloneOptions options, a2dRefMap *refs) const
This is here so that this class cannot be used directly.
Definition: canprim.cpp:5104
a2dControl(double x, double y, double width, double height, wxWindow *control)
constructor
Definition: canprim.cpp:5078
a2dBoundingBox DoGetUnTransformedBbox(a2dBboxFlags flags=a2dCANOBJ_BBOX_NON) const
In derived object this should be overriden to calculate the boundingbox of the object without its chi...
Definition: canprim.cpp:3978
virtual void SetLayer(wxUint16 layer)
set layer index where this object is drawn upon.
Definition: canobj.cpp:5920
bool DoIsHitWorld(a2dIterC &ic, a2dHitEvent &hitEvent)
Does hit test on the object (exclusif child objects)
Definition: canprim.cpp:109
a2dPATH_END_TYPE m_pathtype
when m_contourwidth != 0 what is the end of the line looking like.
Definition: canprim.h:1155
static a2dPropertyIdDouble * PROPID_Height
property to get m_height
Definition: canprim.h:376
a2dCanvasObjectList * GetAsCanvasVpaths(bool transform=true) const
when implemented the object without its children, is converted to
Definition: canprim.cpp:3950
wxEvent * m_event
event to process in case of event processing call
Definition: canobj.h:309
list of a2dObject&#39;s
Definition: gen.h:3157
a2dWHCenter
Definition: canprim.h:392
a2dBoundingBox DoGetUnTransformedBbox(a2dBboxFlags flags=a2dCANOBJ_BBOX_NON) const
In derived object this should be overriden to calculate the boundingbox of the object without its chi...
Definition: canprim.cpp:1812
double m_rely
(world coordinates) hit point y relative to the canvas object its parent object(s) ...
Definition: canobj.h:291
#define EVT_CANVASOBJECT_RESIZE_EVENT(func)
static event table macro for a2dCanvasObject resize event
Definition: canglob.h:327
void SetY1(double y1)
Set Y1 of arc being begin point of arc.
Definition: canprim.h:884
CloneOptions
options for cloning
Definition: gen.h:1200
void SetHitFlags(a2dCanvasObjectHitFlags mask)
set hit flags
Definition: canobj.cpp:2670
double m_x2
end x
Definition: canprim.h:1147
void SetPreRenderAsChild(bool prerender)
If set, this object has a higher priority in rendering than other children objects.
Definition: canobj.h:1469
structure to give as parameter to member functions of a2dCanvasObject
Definition: canobj.h:252
virtual bool DoStartEdit(wxUint16 editmode, wxEditStyle editstyle)
only used for editable objects and under control of a editing tool.
Definition: canprim.cpp:5139
virtual bool RestrictPoint(double &x, double &y, wxUint32 sourceRequired=snapToAll, bool ignoreEngine=false)
Restrict a single point of a line or polyline.
Definition: restrict.cpp:227
void SetRadius(double radius)
set radius of the Arc
Definition: canprim.cpp:2971
const double wxPI
defines PI
Definition: artglob.cpp:28
wxInt64 GetUniqueSerializationId() const
return a unique id for this object
Definition: gen.cpp:1450
void SetFill(const a2dFill &fill)
Set a fill for the object which will be used instead of the layer fill.
Definition: canobj.cpp:2874
double m_radius
radius in case of rounded rectangle
Definition: canprim.h:176
virtual bool DoStartEdit(wxUint16 editmode, wxEditStyle editstyle)
only used for editable objects and under control of a editing tool.
Definition: canprim.cpp:3620
a2dEllipticArc centered at x,y
Definition: canprim.h:697
a2dPropertyIdTyped< double, a2dDoubleProperty > a2dPropertyIdDouble
property of this type
Definition: id.h:657
virtual void DoWalker(wxObject *parent, a2dWalkerIOHandler &handler)
iterate over this object and its children
Definition: canobj.cpp:5504
const a2dFill * a2dTRANSPARENT_FILL
global a2dFill stock object for TRANSPARENT filling
void SetEnd(double l1, double l2, double b, bool spline=false)
set end shape factors if it is a2dArrow derived
Definition: canprim.cpp:4648
static const a2dCanvasObjectFlagsMask PRERENDERASCHILD
Definition: candefs.h:198
general canvas module declarations and classes
void WriteStartElement(const wxString &name, bool newLine=true)
Writes start tag which has no attributes.
Definition: genxmlpars.cpp:738
wxEditStyle
Definition: canobj.h:109
a2dBoundingBox DoGetUnTransformedBbox(a2dBboxFlags flags=a2dCANOBJ_BBOX_NON) const
In derived object this should be overriden to calculate the boundingbox of the object without its chi...
Definition: canprim.cpp:2115
~a2dScaledEndLine()
destructor
Definition: canprim.cpp:4637
a2dCanvasObjectPtr m_end
object drawn at end point
Definition: canprim.h:1251
void GetClippingBox(double &x, double &y, double &w, double &h) const
what is the current clipping region in world coordinates
Definition: drawer2d.cpp:3006
canprim.cpp Source File -- Sun Oct 12 2014 17:04:14 -- Sun Oct 12 2014 -- 1.8.5 -- wxArt2D -- . -- Main Page Reference Documentation