00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "a2dprec.h"
00012
00013 #ifdef __BORLANDC__
00014 #pragma hdrstop
00015 #endif
00016
00017 #ifndef WX_PRECOMP
00018 #include "wx/wx.h"
00019 #endif
00020
00021 #include <wx/wfstream.h>
00022 #include <wx/module.h>
00023 #include <wx/clipbrd.h>
00024
00025 #include "wx/canvas/canobj.h"
00026 #include "wx/canvas/canprim.h"
00027 #include "wx/canvas/canglob.h"
00028 #include "wx/canvas/vpath.h"
00029 #include "wx/canvas/candoc.h"
00030 #include "wx/canvas/cancom.h"
00031 #include "wx/canvas/drawer.h"
00032 #include "wx/canvas/canvas.h"
00033 #include "wx/canvas/wire.h"
00034
00035 #if defined(__WXMSW__) && defined(__MEMDEBUG__)
00036 #include <wx/msw/msvcrt.h>
00037 #endif
00038
00039
00040 #define CIRCLE_STEPS 128
00041
00042 IMPLEMENT_CLASS(a2dWH, a2dCanvasObject)
00043 IMPLEMENT_CLASS(a2dWHCenter, a2dWH)
00044
00045 IMPLEMENT_DYNAMIC_CLASS(a2dOrigin, a2dCanvasObject)
00046 IMPLEMENT_DYNAMIC_CLASS(a2dPin, a2dHandle)
00047 IMPLEMENT_DYNAMIC_CLASS(a2dHandle, a2dCanvasObject)
00048 IMPLEMENT_DYNAMIC_CLASS(a2dArrow, a2dCanvasObject)
00049 IMPLEMENT_DYNAMIC_CLASS(a2dRectC, a2dCanvasObject)
00050 IMPLEMENT_DYNAMIC_CLASS(a2dRect, a2dWH)
00051 IMPLEMENT_DYNAMIC_CLASS(a2dCircle, a2dCanvasObject)
00052 IMPLEMENT_DYNAMIC_CLASS(a2dEllipse, a2dWHCenter)
00053 IMPLEMENT_DYNAMIC_CLASS(a2dEllipticArc, a2dWHCenter)
00054 IMPLEMENT_DYNAMIC_CLASS(a2dArc, a2dCanvasObject)
00055 IMPLEMENT_DYNAMIC_CLASS(a2dSLine, a2dCanvasObject)
00056 IMPLEMENT_DYNAMIC_CLASS(a2dScaledEndLine, a2dEndsLine)
00057 IMPLEMENT_DYNAMIC_CLASS(a2dEndsLine, a2dSLine)
00058 IMPLEMENT_DYNAMIC_CLASS(a2dEndsEllipticChord, a2dEllipticArc)
00059 IMPLEMENT_CLASS(a2dControl, a2dCanvasObject)
00060 IMPLEMENT_DYNAMIC_CLASS(a2dWires, a2dCanvasObject)
00061
00062
00063
00064
00065
00066 a2dOrigin::a2dOrigin()
00067 : a2dCanvasObject()
00068 {
00069 m_width = 10;
00070 m_height = 10;
00071 }
00072
00073 a2dOrigin::a2dOrigin( double w, double h )
00074 : a2dCanvasObject()
00075 {
00076 m_width = w;
00077 m_height = h;
00078 }
00079
00080 a2dOrigin::~a2dOrigin()
00081 {
00082 }
00083
00084 a2dOrigin::a2dOrigin( const a2dOrigin &other, CloneOptions options )
00085 :a2dCanvasObject( other, options )
00086 {
00087 m_width = other.m_width;
00088 m_height = other.m_height;
00089 }
00090
00091 a2dObject* a2dOrigin::Clone( CloneOptions options ) const
00092 {
00093 return new a2dOrigin( *this, options );
00094 };
00095
00096 a2dBoundingBox a2dOrigin::DoGetUnTransformedBbox( a2dBboxFlags WXUNUSED(flags) ) const
00097 {
00098 a2dBoundingBox bbox;
00099 bbox.Expand( -m_width, -m_height);
00100 bbox.Expand( m_width, m_height);
00101 return bbox;
00102 }
00103
00104 void a2dOrigin::DoRender( a2dIterC& ic, OVERLAP WXUNUSED(clipparent) )
00105 {
00106 int w = (int) m_width;
00107 int h = (int) m_height;
00108
00109 ic.GetDrawer2D()->DrawLine( -w, 0, w, 0);
00110 ic.GetDrawer2D()->DrawLine( 0, -h, 0, h);
00111 }
00112
00113 bool a2dOrigin::DoIsHitWorld( a2dIterC& WXUNUSED(ic), a2dHitEvent& hitEvent )
00114 {
00115 hitEvent.m_how.m_hit = a2dHit::hit_fill;
00116 return true;
00117 }
00118
00119 #if wxART2D_USE_CVGIO
00120 void a2dOrigin::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
00121 {
00122 a2dCanvasObject::DoSave( parent, out, xmlparts, towrite );
00123 if ( xmlparts == a2dXmlSer_attrib )
00124 {
00125 }
00126 else
00127 {
00128 }
00129 }
00130 #endif //wxART2D_USE_CVGIO
00131
00132
00133
00134
00135
00136
00137 a2dPropertyIdInt32* a2dHandle::PROPID_Width = NULL;
00138 a2dPropertyIdInt32* a2dHandle::PROPID_Height = NULL;
00139 a2dPropertyIdInt32* a2dHandle::PROPID_Radius = NULL;
00140
00141 INITIALIZE_PROPERTIES( a2dHandle, a2dCanvasObject )
00142 {
00143 PROPID_Width = new a2dPropertyIdInt32( wxT("Width"),
00144 a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdInt32::Mptr >( &a2dHandle::m_width) );
00145 AddPropertyId( PROPID_Width );
00146 PROPID_Height = new a2dPropertyIdInt32( wxT("Height"),
00147 a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdInt32::Mptr >( &a2dHandle::m_height) );
00148 AddPropertyId( PROPID_Height );
00149 PROPID_Radius = new a2dPropertyIdInt32( wxT("Radius"),
00150 a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdInt32::Mptr >( &a2dHandle::m_radius) );
00151 AddPropertyId( PROPID_Radius );
00152
00153 return true;
00154 }
00155
00156
00157 const long a2dHandle::sm_HandleNoHit = wxGenNewId();
00158 const long a2dHandle::sm_HandleHit = wxGenNewId();
00159
00160 A2D_BEGIN_EVENT_TABLE( a2dHandle, a2dCanvasObject )
00161 A2D_EVT_CANVASOBJECT_MOUSE_EVENT( a2dHandle::OnCanvasObjectMouseEvent )
00162 A2D_EVT_CANVASOBJECT_ENTER_EVENT( a2dHandle::OnEnterObject )
00163 A2D_EVT_CANVASOBJECT_LEAVE_EVENT( a2dHandle::OnLeaveObject )
00164 A2D_END_EVENT_TABLE()
00165
00166 a2dHandle::a2dHandle()
00167 : a2dCanvasObject()
00168 {
00169 m_parent = NULL;
00170 m_flags.m_prerenderaschild = false;
00171 m_width = a2dCanvasGlobals->GetHandle()->GetWidth();
00172 m_height = a2dCanvasGlobals->GetHandle()->GetWidth();
00173 m_radius = a2dCanvasGlobals->GetHandle()->GetRadius();
00174 m_mode = sm_HandleNoHit;
00175 }
00176
00177 a2dHandle::a2dHandle( a2dCanvasObject* parent, double xc, double yc, const wxString& name,
00178 int w, int h, double angle , int radius )
00179 : a2dCanvasObject()
00180 {
00181 m_name = name;
00182 m_parent = parent;
00183 m_flags.m_prerenderaschild = false;
00184
00185 Rotate(angle);
00186 m_lworld.Translate(xc, yc);
00187
00188 if ( w )
00189 m_width = w;
00190 else
00191 m_width = a2dCanvasGlobals->GetHandle()->GetWidth();
00192
00193 if ( h )
00194 m_height = h;
00195 else
00196 m_height = a2dCanvasGlobals->GetHandle()->GetHeight();
00197
00198 m_radius = radius;
00199 m_mode = sm_HandleNoHit;
00200
00201 SetPending(true);
00202 }
00203
00204 void a2dHandle::Set( double xc, double yc, int w, int h, double angle, int radius )
00205 {
00206 m_flags.m_prerenderaschild = false;
00207
00208 m_lworld.Identity();
00209 Rotate(angle);
00210 m_lworld.Translate(xc, yc);
00211
00212 m_width = w;
00213 m_height = h;
00214 m_radius = radius;
00215
00216 SetPending(true);
00217 }
00218
00219 void a2dHandle::Set2( double xc, double yc, const wxString& name )
00220 {
00221 m_flags.m_prerenderaschild = false;
00222
00223 m_lworld.Identity();
00224 m_lworld.Translate(xc, yc);
00225
00226 if ( !name.IsEmpty() )
00227 m_name = name;
00228
00229 SetPending(true);
00230 }
00231
00232 a2dHandle::~a2dHandle()
00233 {
00234 }
00235
00236 a2dHandle::a2dHandle( const a2dHandle &other, CloneOptions options )
00237 :a2dCanvasObject( other, options )
00238 {
00239 m_width = other.m_width;
00240 m_height = other.m_height;
00241 m_radius = other.m_radius;
00242 m_mode = other.m_mode;
00243 m_parent = other.m_parent;
00244 m_name = other.m_name;
00245
00246 }
00247
00248 void a2dHandle::SetParent( a2dCanvasObject* parent )
00249 {
00250 m_parent = parent;
00251 }
00252
00253 a2dObject* a2dHandle::Clone( CloneOptions options ) const
00254 {
00255 return new a2dHandle( *this, options );
00256 };
00257
00258 a2dBoundingBox a2dHandle::DoGetUnTransformedBbox( a2dBboxFlags WXUNUSED(flags) ) const
00259 {
00260 a2dBoundingBox bbox;
00261 bbox.Enlarge( 0 );
00262 return bbox;
00263 }
00264
00265 bool a2dHandle::DoUpdate( UpdateMode WXUNUSED(mode), const a2dBoundingBox& childbox, const a2dBoundingBox& clipbox, const a2dBoundingBox& propbox )
00266 {
00267 if ( !m_bbox.GetValid())
00268 {
00269 m_bbox=DoGetUnTransformedBbox();
00270 m_bbox.MapBbox(m_lworld);
00271 m_pixelExtend = (wxUint16) wxMax( m_pixelExtend, (int) wxMax( m_width/2, m_height/2) );
00272 assert( m_pixelExtend < 40 );
00273 return true;
00274 }
00275 return false;
00276 }
00277
00278 void a2dHandle::DoRender( a2dIterC& ic, OVERLAP WXUNUSED(clipparent) )
00279 {
00280 ic.GetDrawer2D()->OverRuleFixedStyle();
00281
00282 ic.GetDrawer2D()->SetDrawerFill( a2dCanvasGlobals->GetHandle()->GetFill() );
00283 ic.GetDrawer2D()->SetDrawerStroke( a2dCanvasGlobals->GetHandle()->GetStroke() );
00284
00285 double x1;
00286 double y1;
00287 ic.GetTransform().TransformPoint( 0, 0, x1, y1 );
00288 int dx = ic.GetDrawer2D()->WorldToDeviceX(x1);
00289 int dy = ic.GetDrawer2D()->WorldToDeviceY(y1);
00290 ic.GetDrawer2D()->PushIdentityTransform();
00291
00292 if ( m_mode == sm_HandleHit )
00293 {
00294 ic.GetDrawer2D()->SetDrawerFill( *a2dTRANSPARENT_FILL );
00295 ic.GetDrawer2D()->DrawLine( dx - m_width/2, dy, dx + m_width/2, dy);
00296 ic.GetDrawer2D()->DrawLine( dx, dy + m_height/2, dx, dy - m_height/2);
00297 }
00298 else if ( m_mode == sm_HandleNoHit )
00299 {
00300 ic.GetDrawer2D()->DrawCenterRoundedRectangle(dx, dy, m_width, m_height, m_radius);
00301 }
00302 else
00303 {
00304
00305 ic.GetDrawer2D()->DrawCircle(dx, dy, (int) hypot((double)m_width, (double)m_height) );
00306 }
00307 ic.GetDrawer2D()->PopTransform();
00308
00309 ic.GetDrawer2D()->ReStoreFixedStyle();
00310 }
00311
00312 bool a2dHandle::DoIsHitWorld( a2dIterC& ic, a2dHitEvent& hitEvent )
00313 {
00314
00315 double xh,yh;
00316 ic.GetTransform().TransformPoint(0,0,xh,yh);
00317
00318
00319
00320
00321
00322 double w = 0;
00323 double h = 0;
00324
00325 w = fabs(ic.GetDrawer2D()->DeviceToWorldXRel(m_width)) + ic.GetWorldStrokeExtend();
00326 h = fabs(ic.GetDrawer2D()->DeviceToWorldYRel(m_height)) + ic.GetWorldStrokeExtend();
00327
00328 hitEvent.m_how = HitTestRectangle( hitEvent.m_x, hitEvent.m_y, xh-w/2, yh-h/2, xh+w/2, yh+h/2, 0 );
00329
00330 return hitEvent.m_how.IsHit();
00331 }
00332
00333 #if wxART2D_USE_CVGIO
00334 void a2dHandle::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
00335 {
00336 a2dCanvasObject::DoSave( parent, out, xmlparts, towrite );
00337 if ( xmlparts == a2dXmlSer_attrib )
00338 {
00339 out.WriteAttribute( wxT("width"), m_width );
00340 out.WriteAttribute( wxT("height"), m_height );
00341 if (m_radius != 0.0)
00342 {
00343 out.WriteAttribute( wxT("radius"), m_radius );
00344 }
00345 }
00346 else
00347 {
00348 }
00349 }
00350 void a2dHandle::DoLoad( wxObject* parent, a2dIOHandlerXmlSerIn& parser, a2dXmlSer_flag xmlparts )
00351 {
00352 a2dCanvasObject::DoLoad( parent, parser, xmlparts );
00353 if ( xmlparts == a2dXmlSer_attrib )
00354 {
00355 m_width = parser.RequireAttributeValueInt( wxT("width") );
00356 m_height = parser.RequireAttributeValueInt( wxT("height") );
00357 m_radius = parser.GetAttributeValueInt( wxT("radius") );
00358 m_name = parser.GetAttributeValue( wxT("name"), m_name );
00359 }
00360 else
00361 {
00362 }
00363 }
00364 #endif //wxART2D_USE_CVGIO
00365
00366 bool a2dHandle::IsTemporary_DontSave() const
00367 {
00368
00369 return true;
00370 }
00371
00372 void a2dHandle::OnCanvasObjectMouseEvent( a2dCanvasObjectMouseEvent& event )
00373 {
00374 a2dIterC* ic = event.GetIterC();
00375
00376 static double xprev;
00377 static double yprev;
00378 static bool pushed = false;
00379
00380 double xw,yw;
00381 xw = event.GetX();
00382 yw = event.GetY();
00383
00384 a2dRestrictionEngine *restrictEngine = a2dCanvasGlobals->GetRestrictionEngine();
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396 if ( event.GetMouseEvent().LeftDown() )
00397 {
00398 ic->SetCorridorPath( true, this );
00399 xprev = xw;
00400 yprev = yw;
00401 SetMode( sm_HandleHit );
00402 ic->GetCanvasView()->PushCursor( a2dCanvasGlobals->GetCursor( a2dCURSOR_CROSS ) );
00403 pushed = true;
00404 a2dHandleMouseEvent handleEvent( ic, this, xw, yw, event.GetMouseEvent() );
00405 if ( m_parent )
00406 m_parent->ProcessEvent( handleEvent );
00407 }
00408 else if ( event.GetMouseEvent().Dragging() )
00409 {
00410 double x,y;
00411 x = xw - (xprev - GetPosX());
00412 y = yw - (yprev - GetPosY());
00413
00414 xprev = xw;
00415 yprev = yw;
00416 a2dHandleMouseEvent handleEvent( ic, this, xw, yw, event.GetMouseEvent() );
00417 if ( m_parent )
00418 m_parent->ProcessEvent( handleEvent );
00419 }
00420 else if ( event.GetMouseEvent().Moving() )
00421 {
00422 ic->GetCanvasView()->SetCursor( a2dCanvasGlobals->GetCursor( a2dCURSOR_EditVertex ) );
00423 }
00424 else if (event.GetMouseEvent().LeftUp() && ic->GetCanvasView()->GetCaptured() )
00425 {
00426 SetMode( sm_HandleNoHit );
00427 ic->SetCorridorPathToParent();
00428 if ( pushed )
00429 ic->GetCanvasView()->PopCursor();
00430 pushed = false;
00431 a2dHandleMouseEvent handleEvent( ic, this, xw, yw, event.GetMouseEvent() );
00432 if ( m_parent )
00433 m_parent->ProcessEvent( handleEvent );
00434 }
00435 else
00436 event.Skip();
00437 }
00438
00439 void a2dHandle::OnEnterObject(a2dCanvasObjectMouseEvent &event)
00440 {
00441 a2dIterC* ic = event.GetIterC();
00442 m_mode = sm_HandleHit;
00443 SetPending( true );
00444 ic->GetCanvasView()->PushCursor( a2dCanvasGlobals->GetCursor( a2dCURSOR_CROSS ) );
00445 }
00446
00447 void a2dHandle::OnLeaveObject(a2dCanvasObjectMouseEvent &event)
00448 {
00449 a2dIterC* ic = event.GetIterC();
00450 m_mode = sm_HandleNoHit;
00451 SetPending( true );
00452 ic->GetCanvasView()->PopCursor();
00453 }
00454
00455
00456
00457
00458 #define PINWIDTH 7
00459
00460 a2dPinClass *a2dPinClass::Any = NULL;
00461
00462 a2dPinClass *a2dPinClass::Standard = NULL;
00463
00464 a2dPinClass *a2dPinClass::Object = NULL;
00465 a2dPinClass *a2dPinClass::Wire = NULL;
00466
00467 a2dPinClass *a2dPinClass::Input = NULL;
00468 a2dPinClass *a2dPinClass::Output = NULL;
00469
00470 a2dPinClass *a2dPinClass::ObjectInput = NULL;
00471 a2dPinClass *a2dPinClass::ObjectOutput = NULL;
00472 a2dPinClass *a2dPinClass::WireInput = NULL;
00473 a2dPinClass *a2dPinClass::WireOutput = NULL;
00474
00475 std::list< a2dPinClass* > a2dPinClass::m_allPinClasses;
00476
00477 a2dPinClass::a2dPinClass( const wxString &name, wxUint32 flags )
00478 {
00479 m_name = name;
00480 m_flags = flags;
00481 m_tmplObject = NULL;
00482 m_connectionGenerator = NULL;
00483 }
00484
00485 a2dPinClass::~a2dPinClass()
00486 {
00487 }
00488
00489 void a2dPinClass::RemoveConnect( a2dPinClass* pinClass )
00490 {
00491 std::list< a2dPinClass* >::iterator iter = m_canConnectTo.begin();
00492 while( iter != m_canConnectTo.end() )
00493 {
00494 if ( (*iter) == pinClass )
00495 iter = m_canConnectTo.erase( iter );
00496 else
00497 iter++;
00498 }
00499 }
00500
00501 void a2dPinClass::InitializeStockPinClasses()
00502 {
00503 Standard = new a2dPinClass( wxT("standard") );
00504 Standard->AddConnect( a2dPinClass::Standard );
00505 Standard->SetConnectionGenerator( a2dCanvasGlobals->GetConnectionGenerator() );
00506
00507
00508 a2dWirePolylineL* wirestandard = new a2dWirePolylineL();
00509 wirestandard->SetStroke( a2dStroke(wxColour(255,0,0), 2,a2dSTROKE_SOLID));
00510 wirestandard->SetStartPinClass( a2dPinClass::Standard );
00511 wirestandard->SetEndPinClass( a2dPinClass::Standard );
00512 a2dPinClass::Standard->SetAngleLine( false );
00513 a2dPinClass::Standard->SetConnectObject( wirestandard );
00514 m_allPinClasses.push_back( Standard );
00515
00516 Any = new a2dPinClass( wxT("anyPinClass") );
00517 Any->AddConnect( a2dPinClass::Standard );
00518 Any->SetConnectionGenerator( a2dCanvasGlobals->GetConnectionGenerator() );
00519 m_allPinClasses.push_back( Any );
00520
00521 Wire = new a2dPinClass( wxT("wire"), PC_input | PC_output );
00522 Object = new a2dPinClass( wxT("object") );
00523 Wire->SetConnectionGenerator( a2dCanvasGlobals->GetConnectionGenerator() );
00524 Object->SetConnectionGenerator( a2dCanvasGlobals->GetConnectionGenerator() );
00525 Object->AddConnect( Wire );
00526 Object->AddConnect( Object );
00527 Wire->AddConnect( Object );
00528 Wire->AddConnect( Wire );
00529
00530
00531 a2dWirePolylineL* wireio = new a2dWirePolylineL();
00532 wireio->SetStroke( a2dStroke(wxColour(0,250,0), 2,a2dSTROKE_SOLID));
00533 wireio->SetStartPinClass( a2dPinClass::Wire );
00534 wireio->SetEndPinClass( a2dPinClass::Wire );
00535 a2dPinClass::Wire->SetAngleLine( false );
00536 a2dPinClass::Wire->SetConnectObject( wireio );
00537 m_allPinClasses.push_back( Object );
00538 m_allPinClasses.push_back( Wire );
00539
00540 Input = new a2dPinClass( wxT("input"), PC_input );
00541 Output = new a2dPinClass( wxT("output"), PC_output );
00542 Input->SetConnectionGenerator( a2dCanvasGlobals->GetConnectionGenerator() );
00543 Output->SetConnectionGenerator( a2dCanvasGlobals->GetConnectionGenerator() );
00544 Input->AddConnect( Output );
00545 Output->AddConnect( Input );
00546 m_allPinClasses.push_back( Input );
00547 m_allPinClasses.push_back( Output );
00548
00549 ObjectInput = new a2dPinClass( wxT("objectinput"), PC_input );
00550 ObjectOutput = new a2dPinClass( wxT("objectoutput"), PC_output );
00551 WireInput = new a2dPinClass( wxT("wireinput"), PC_input );
00552 WireOutput = new a2dPinClass( wxT("wireoutput"), PC_output );
00553
00554 ObjectInput->SetConnectionGenerator( a2dCanvasGlobals->GetConnectionGenerator() );
00555 ObjectOutput->SetConnectionGenerator( a2dCanvasGlobals->GetConnectionGenerator() );
00556 WireInput->SetConnectionGenerator( a2dCanvasGlobals->GetConnectionGenerator() );
00557 WireOutput->SetConnectionGenerator( a2dCanvasGlobals->GetConnectionGenerator() );
00558
00559 ObjectInput->AddConnect( WireOutput );
00560 ObjectInput->AddConnect( ObjectOutput );
00561 WireOutput->AddConnect( ObjectInput );
00562 ObjectOutput->AddConnect( WireInput );
00563 ObjectOutput->AddConnect( ObjectInput );
00564 WireInput->AddConnect( ObjectOutput );
00565
00566 WireInput->AddConnect( WireOutput );
00567 WireOutput->AddConnect( WireInput );
00568
00569 m_allPinClasses.push_back( ObjectInput );
00570 m_allPinClasses.push_back( ObjectOutput );
00571 m_allPinClasses.push_back( WireInput );
00572 m_allPinClasses.push_back( WireOutput );
00573 }
00574
00575 void a2dPinClass::DeleteStockPinClasses()
00576 {
00577 std::list< a2dPinClass* >::iterator iter;
00578
00579 for( iter = m_allPinClasses.begin(); iter != m_allPinClasses.end(); ++iter )
00580 delete (*iter);
00581 m_allPinClasses.clear();
00582 }
00583
00584 a2dPinClass* a2dPinClass::CanConnectTo( a2dPinClass *other, wxUint32 flags ) const
00585 {
00586 std::list< a2dPinClass* >::const_iterator iter;
00587
00588 for( iter = m_canConnectTo.begin(); iter != m_canConnectTo.end(); ++iter )
00589 {
00590 if ( ( other == NULL || (*iter) == other ) &&
00591 ( (flags & (*iter)->m_flags) > 0 )
00592 )
00593 return (*iter);
00594 }
00595 return false;
00596 }
00597
00598 a2dPinClass* a2dPinClass::CanConnectToAsWire( a2dPinClass *specific, wxUint32 flags ) const
00599 {
00600 std::list< a2dPinClass* >::const_iterator iter;
00601
00602 for( iter = m_canConnectTo.begin(); iter != m_canConnectTo.end(); ++iter )
00603 {
00604 if (
00605 ( specific ==NULL || (*iter) == specific ) &&
00606 ( (flags & (*iter)->m_flags) > 0 ) &&
00607 (*iter)->m_tmplObject
00608 )
00609 return (*iter);
00610 }
00611 return NULL;
00612 }
00613
00614 a2dPinClass* a2dPinClass::CanConnectToAsObject( a2dPinClass *specific, wxUint32 flags ) const
00615 {
00616 std::list< a2dPinClass* >::const_iterator iter;
00617
00618 for( iter = m_canConnectTo.begin(); iter != m_canConnectTo.end(); ++iter )
00619 {
00620 if (
00621 ( specific ==NULL || (*iter) == specific ) &&
00622 ( (flags & (*iter)->m_flags) > 0 ) &&
00623 ( (*iter)->m_tmplObject.Get() == NULL || a2dPinClass::Standard )
00624 )
00625 return (*iter);
00626 }
00627 return NULL;
00628 }
00629
00630 void a2dPinClass::SetConnectObject( a2dCanvasObject *tmplObject )
00631 {
00632 m_tmplObject = tmplObject;
00633 }
00634
00635 a2dCanvasObject* a2dPinClass::GetConnectObject() const
00636 {
00637 return m_tmplObject;
00638 }
00639
00640 a2dPinClass* a2dPinClass::GetClassByName( const wxString &name )
00641 {
00642 std::list< a2dPinClass* >::iterator iter;
00643
00644 for( iter = m_allPinClasses.begin(); iter != m_allPinClasses.end(); ++iter )
00645 {
00646 if ((*iter)->m_name == name)
00647 return (*iter);
00648 }
00649 return NULL;
00650 }
00651
00652 void a2dPinClass::SetPin( a2dPin* newpin )
00653 {
00654 m_defPin = newpin;
00655 }
00656
00657 a2dPin* a2dPinClass::GetPin()
00658 {
00659 if ( !m_defPin )
00660 {
00661 m_defPin = new a2dPin( NULL, wxT("templatePin"), this, 0, 0, 0, PINWIDTH, PINWIDTH );
00662 m_defPin->SetFill( *wxGREEN );
00663 m_defPin->SetStroke( wxColour( 66, 159, 235 ), 0 );
00664 }
00665 return m_defPin;
00666 }
00667
00668 void a2dPinClass::SetPinCannotConnect( a2dPin* newpin )
00669 {
00670 m_defCannotConnectPin = newpin;
00671 }
00672
00673 a2dPin* a2dPinClass::GetPinCannotConnect()
00674 {
00675 if ( !m_defCannotConnectPin )
00676 {
00677 m_defCannotConnectPin = new a2dPin( NULL, wxT("templatePin"), this, 0, 0, 0, PINWIDTH/2+1, PINWIDTH/2+1 );
00678 m_defCannotConnectPin->SetFill( wxColour( 255, 128, 128 ) );
00679 m_defCannotConnectPin->SetStroke( *wxRED, 0 );
00680 }
00681 return m_defCannotConnectPin;
00682 }
00683
00684 void a2dPinClass::SetPinCanConnect( a2dPin* newpin )
00685 {
00686 m_defCanConnectPin = newpin;
00687 }
00688
00689 a2dPin* a2dPinClass::GetPinCanConnect()
00690 {
00691 if ( !m_defCanConnectPin )
00692 {
00693 m_defCanConnectPin = new a2dPin( NULL, wxT("templatePin"), this, 0, 0, 0, 2*PINWIDTH+1, 2*PINWIDTH+1 );
00694 m_defCanConnectPin->SetFill( wxColour( 128, 255, 128 ) );
00695 m_defCanConnectPin->SetStroke( *wxGREEN, 0 );
00696 }
00697 return m_defCanConnectPin;
00698 }
00699
00700
00701
00702
00703
00704
00705 A2D_BEGIN_EVENT_TABLE( a2dPin, a2dHandle )
00706 A2D_EVT_CANVASOBJECT_ENTER_EVENT( a2dPin::OnEnterObject )
00707 A2D_EVT_CANVASOBJECT_LEAVE_EVENT( a2dPin::OnLeaveObject )
00708 A2D_END_EVENT_TABLE()
00709
00710 const a2dCanvasObject::a2dFeedbackId a2dPin::sm_feedbackStart;
00711 const a2dCanvasObject::a2dFeedbackId a2dPin::sm_feedbackGeneratePin;
00712 const a2dCanvasObject::a2dFeedbackId a2dPin::sm_feedbackEnd;
00713 const a2dCanvasObject::a2dFeedbackId a2dPin::sm_feedbackCanConnect;
00714
00715
00716 const long a2dPin::sm_PinUnConnected = wxGenNewId();
00717 const long a2dPin::sm_PinConnected = wxGenNewId();
00718 const long a2dPin::sm_PinCanConnect = wxGenNewId();
00719 const long a2dPin::sm_PinCannotConnect = wxGenNewId();
00720 const long a2dPin::sm_PinCanConnectToPinClass = wxGenNewId();
00721
00722
00723 a2dCanvasObject::a2dFeedbackIdPinMapping a2dPin::sm_feedbackOnPinmapConnect;
00724
00725 a2dPin::a2dPin()
00726 : a2dHandle( NULL, 0,0, wxT("dummy"), a2dPinClass::Standard->GetPin()->GetWidth(), a2dPinClass::Standard->GetPin()->GetHeight())
00727 {
00728 m_canvaspin = NULL;
00729 m_pinclass = a2dPinClass::Standard;
00730 m_flags.m_prerenderaschild = false;
00731 m_RenderConnected = false;
00732 m_clonebrother = 0;
00733 m_dynamicPin = false;
00734 m_temporaryPin = false;
00735 m_mode = sm_PinUnConnected;
00736 m_objectPin = true;
00737 }
00738
00739 a2dPin::a2dPin( a2dCanvasObject* parent, const wxString& name, a2dPinClass* pinclass, double xc, double yc,
00740 double angle , int w, int h, int WXUNUSED(radius) )
00741 : a2dHandle( parent, xc, yc, name, w, h, angle )
00742 {
00743 if ( !w )
00744 m_width = pinclass->GetPin()->GetWidth();
00745
00746 if ( !h )
00747 m_height = pinclass->GetPin()->GetHeight();
00748
00749 m_canvaspin = NULL;
00750 m_mode = sm_PinUnConnected;
00751 m_name = name;
00752 m_pinclass = pinclass;
00753 m_flags.m_prerenderaschild = false;
00754 m_RenderConnected = false;
00755 m_clonebrother = 0;
00756 m_dynamicPin = false;
00757 m_temporaryPin = false;
00758 m_internal = false;
00759 m_objectPin = true;
00760
00761 if ( m_parent )
00762 {
00763 m_parent->SetPending( true );
00764 m_parent->SetSpecificFlags( true, a2dCanvasOFlags::HasPins );
00765 }
00766 }
00767
00768
00769 void a2dPin::Set( double xc, double yc, double angle, const wxString& name, bool dynamic )
00770 {
00771 m_dynamicPin = dynamic;
00772 m_flags.m_prerenderaschild = false;
00773 m_lworld.Identity();
00774 Rotate(angle);
00775 m_lworld.Translate(xc, yc);
00776
00777 SetPending(true);
00778 if ( !name.IsEmpty() )
00779 m_name = name;
00780 }
00781
00782 a2dPin::~a2dPin()
00783 {
00784
00785 if ( m_canvaspin )
00786 m_canvaspin->ConnectTo( NULL );
00787 }
00788
00789 void a2dPin::ConnectTo( a2dPin* connectto )
00790 {
00791 #ifdef __WXDEBUG__
00792 if ( connectto )
00793 wxASSERT_MSG( m_canvaspin == 0 , _T("This pin is already connected to some other pin, not allowed.") );
00794 #endif
00795 m_canvaspin = connectto;
00796 m_mode = sm_PinConnected;
00797 }
00798
00799 void a2dPin::SetParent( a2dCanvasObject* parent )
00800 {
00801 m_parent = parent;
00802 if ( m_parent )
00803 {
00804 m_parent->SetPending( true );
00805 m_parent->SetSpecificFlags( true, a2dCanvasOFlags::HasPins );
00806 }
00807 }
00808
00809 void a2dPin::SetPending( bool pending )
00810 {
00811 a2dCanvasObject::SetPending( pending );
00812
00813
00814 }
00815
00816 a2dPoint2D a2dPin::GetAbsXY() const
00817 {
00818 a2dAffineMatrix tworld = m_parent->GetTransformMatrix();
00819 tworld *= m_lworld;
00820 return a2dPoint2D( tworld.GetValue(2,0), tworld.GetValue(2,1) );
00821 }
00822
00823 double a2dPin::GetAbsX() const
00824 {
00825 a2dAffineMatrix tworld = m_parent->GetTransformMatrix();
00826 tworld *= m_lworld;
00827 return tworld.GetValue(2,0);
00828 }
00829
00830 double a2dPin::GetAbsY() const
00831 {
00832 a2dAffineMatrix tworld = m_parent->GetTransformMatrix();
00833 tworld *= m_lworld;
00834 return tworld.GetValue(2,1);
00835 }
00836
00837 void a2dPin::SetAbsXY( double x, double y )
00838 {
00839 a2dAffineMatrix tworldInv = m_parent->GetTransformMatrix();
00840 tworldInv.Invert();
00841 double xt,yt;
00842 tworldInv.TransformPoint( x, y, xt, yt );
00843 SetPosXY( xt, yt );
00844
00845 assert( fabs( x - GetAbsX() ) < 1e-3 );
00846 assert( fabs( y - GetAbsY() ) < 1e-3 );
00847 }
00848
00849 void a2dPin::SetAbsXY( const a2dPoint2D & point )
00850 {
00851 SetAbsXY( point.m_x, point.m_y );
00852 }
00853
00854 double a2dPin::GetAbsAngle() const
00855 {
00856 a2dAffineMatrix tworld = m_parent->GetTransformMatrix();
00857 tworld *= m_lworld;
00858 return tworld.GetRotation();
00859 }
00860
00861 bool a2dPin::MayConnectTo( a2dPin* connectto )
00862 {
00863
00864
00865
00866 assert( (GetPinClass()->CanConnectTo( connectto->GetPinClass() ) != NULL) == (connectto->GetPinClass()->CanConnectTo( GetPinClass() ) != NULL) );
00867
00868
00869 if( m_canvaspin || connectto->m_canvaspin ) return false;
00870
00871
00872 return GetPinClass()->CanConnectTo( connectto->GetPinClass() ) != NULL;
00873 }
00874
00875 a2dPin* a2dPin::FindConnectablePin( a2dCanvasObject *root, double margin, bool autocreate )
00876 {
00877
00878
00879
00880 assert( root->Find( m_parent ) );
00881
00882
00883 a2dIterC ic;
00884 a2dIterCU icu( ic, root );
00885
00886 for( a2dCanvasObjectList::iterator iter = root->GetChildObjectList()->begin(); iter != root->GetChildObjectList()->end(); ++iter )
00887 {
00888 a2dCanvasObject *obj = *iter;
00889 if( !obj->CheckMask( a2dCanvasOFlags::HasPins ) ) continue;
00890 if( obj == m_parent ) continue;
00891
00892
00893 a2dPin *rslt = obj->CanConnectWith( ic, this, margin, autocreate );
00894
00895 if( rslt )
00896 return rslt;
00897 }
00898 return 0;
00899 }
00900
00901 void a2dPin::AutoConnect( a2dCanvasObject *root, double margin )
00902 {
00903
00904 wxASSERT( !PROPID_Original->GetPropertyValue( this ) );
00905
00906
00907 if( IsDislocated() || !ConnectedTo() )
00908 {
00909
00910
00911 a2dPin *save = ConnectedTo();
00912 ConnectTo( 0 );
00913 a2dPin *rslt = FindConnectablePin( root, margin, true );
00914 ConnectTo( save );
00915 if( rslt )
00916 {
00917
00918 GetCanvasDocument()->GetCanvasCommandProcessor()->Submit( new a2dCommand_ConnectPins( this, rslt ), true );
00919 }
00920 }
00921 }
00922
00923 bool a2dPin::IsDislocated() const
00924 {
00925 if( !ConnectedTo() )
00926 return false;
00927
00928 a2dPoint2D thispos = GetAbsXY();
00929 a2dPoint2D otherpos = ConnectedTo()->GetAbsXY();
00930
00931 return
00932 fabs( thispos.m_x - otherpos.m_x ) > a2dCanvasGlobals->GetCoordinateEpsilon() ||
00933 fabs( thispos.m_y - otherpos.m_y ) > a2dCanvasGlobals->GetCoordinateEpsilon();
00934 }
00935
00936 a2dPin::a2dPin(const a2dPin &other, CloneOptions options )
00937 :a2dHandle( other, options )
00938 {
00939
00940 m_name = other.m_name;
00941 m_pinclass = other.m_pinclass;
00942
00943 m_canvaspin = NULL;
00944 m_parent = other.m_parent;
00945 m_RenderConnected = other.m_RenderConnected;
00946 m_dynamicPin = other.m_dynamicPin;
00947 m_temporaryPin = other.m_temporaryPin;
00948 m_internal = other.m_internal;
00949 m_objectPin = other.m_objectPin;
00950
00951 if( options & clone_reconnectable )
00952 {
00953
00954
00955
00956
00957
00958
00959
00960
00961 wxASSERT( !other.m_clonebrother );
00962 const_cast<a2dPin&>(other).m_clonebrother = 0;
00963 m_clonebrother = 0;
00964 if( other.m_canvaspin )
00965 {
00966
00967 const_cast<a2dPin&>(other).m_clonebrother = this;
00968 m_clonebrother = &const_cast<a2dPin&>(other);
00969 }
00970 }
00971 else
00972 {
00973 m_clonebrother = 0;
00974 }
00975 }
00976
00977 a2dObject* a2dPin::Clone( CloneOptions options ) const
00978 {
00979 return new a2dPin( *this, options );
00980 };
00981
00982 a2dBoundingBox a2dPin::DoGetUnTransformedBbox( a2dBboxFlags WXUNUSED(flags) ) const
00983 {
00984 a2dBoundingBox bbox;
00985 bbox.Enlarge( 0 );
00986
00987 if( m_canvaspin )
00988 {
00989
00990
00991 if( IsDislocated() || m_RenderConnected )
00992 {
00993 bbox.Expand( 0, 0 );
00994
00995
00996
00997 }
00998 }
00999 else
01000 {
01001 bbox.Expand( 0, 0 );
01002
01003
01004
01005 }
01006
01007 return bbox;
01008 }
01009
01010 bool a2dPin::DoUpdate( UpdateMode WXUNUSED(mode), const a2dBoundingBox& childbox, const a2dBoundingBox& clipbox, const a2dBoundingBox& propbox )
01011 {
01012 if ( !m_bbox.GetValid())
01013 {
01014 m_bbox = DoGetUnTransformedBbox();
01015 m_bbox.MapBbox(m_lworld);
01016
01017 if( m_pinclass->HasAngleLine() )
01018 {
01019 m_pixelExtend = (wxUint16) wxMax( m_pixelExtend, (int) wxMax( m_width*3, m_height*3 ) );
01020 }
01021 else
01022 {
01023 m_pixelExtend = (wxUint16) wxMax( m_pixelExtend, (int) wxMax( m_width/2.0, m_height/2.0 ) );
01024 }
01025
01026 return true;
01027 }
01028 return false;
01029 }
01030
01031 void a2dPin::OnEnterObject(a2dCanvasObjectMouseEvent& WXUNUSED(event) )
01032 {
01033 }
01034
01035 void a2dPin::OnLeaveObject(a2dCanvasObjectMouseEvent& WXUNUSED(event) )
01036 {
01037 }
01038
01039 void a2dPin::EditFeedback( a2dIterC& ic, const a2dFeedbackId *id, a2dCanvasObject *currentEdit, int depth, a2dCanvasObjectFlagsMask flags, double x, double y )
01040 {
01041 a2dHandle::EditFeedback( ic, id, currentEdit, depth, flags, x, y );
01042
01043 if( id == &sm_feedbackStart )
01044 {
01045 a2dPin *pin = wxDynamicCast( currentEdit, a2dPin );
01046 if( !m_canvaspin && pin && m_flags.m_MouseInObject )
01047 {
01048 if( GetPinClass()->CanConnectTo( pin->GetPinClass() ) )
01049 {
01050 SetMode( sm_PinCanConnect );
01051 }
01052 else
01053 {
01054 SetMode( sm_PinCannotConnect );
01055 }
01056 }
01057 }
01058 else if( id == &sm_feedbackEnd )
01059 {
01060
01061
01062 if( !m_canvaspin )
01063 SetMode( sm_PinUnConnected );
01064 else
01065 SetMode( sm_PinConnected );
01066
01067
01068 if( IsTemporaryPin() )
01069 {
01070 wxASSERT_MSG( !ConnectedTo(), wxT("Temporary Pins are not to be connected, clone first because of Undo generation") );
01071 GetParent()->ReleaseChild( this );
01072 }
01073 }
01074 else if( id == &sm_feedbackCanConnect && GetBin() )
01075 {
01076 if( !m_canvaspin )
01077 {
01078 SetMode( sm_PinCanConnect );
01079 }
01080 }
01081 else if( id == &sm_feedbackOnPinmapConnect )
01082 {
01083 a2dFeedbackIdPinMapping* idOnPin = (a2dFeedbackIdPinMapping*) id;
01084
01085
01086 if ( !ConnectedTo() )
01087 {
01088 if ( idOnPin->GetTask() == a2d_ToConnectPinClassWire_ObjectPinClass_InOut && idOnPin->GetPinClass() == a2dPinClass::Any )
01089 SetMode( sm_PinCanConnectToPinClass );
01090 if ( idOnPin->GetTask() == a2d_ObjectPinClass_ToConnectPinClassWire_InOut &&
01091 GetPinClass() == GetPinClass()->GetConnectionGenerator()->GetPinClassForTask( idOnPin->GetPinClass(), idOnPin->GetTask(), m_parent )
01092 )
01093 SetMode( sm_PinCanConnectToPinClass );
01094 else if
01095 ( idOnPin->GetTask() == a2d_ToConnectPinClassWire_ObjectPinClass_InOut &&
01096 idOnPin->GetPinClass() == GetPinClass()->GetConnectionGenerator()->GetPinClassForTask( GetPinClass(), idOnPin->GetTask(), m_parent )
01097 )
01098 SetMode( sm_PinCanConnectToPinClass );
01099 }
01100 else
01101 {
01102 if( !m_canvaspin )
01103 SetMode( sm_PinUnConnected );
01104 else
01105 SetMode( sm_PinConnected );
01106 }
01107 }
01108 else if( id == &sm_feedbackGeneratePin )
01109 {
01110 if ( m_flags.m_MouseInObject )
01111 {
01112
01113
01114 a2dPin *wirePin = wxDynamicCast( currentEdit, a2dPin );
01115
01116
01117 if ( !ConnectedTo() &&
01118 ( !wirePin || GetPinClass()->CanConnectToAsWire( wirePin->GetPinClass() ) )
01119 )
01120 {
01121 SetMode( sm_PinCanConnectToPinClass );
01122 }
01123 else
01124 {
01125 if( !m_canvaspin )
01126 SetMode( sm_PinUnConnected );
01127 else
01128 SetMode( sm_PinConnected );
01129 }
01130 }
01131 else
01132 {
01133 if( IsTemporaryPin() && !ConnectedTo() )
01134 {
01135
01136 }
01137 }
01138 }
01139 }
01140
01141 void a2dPin::DrawHighLighted( a2dIterC& ic )
01142 {
01143 ic.GetDrawer2D()->SetDrawerStroke( a2dCanvasGlobals->GetHighLightStroke() );
01144 ic.GetDrawer2D()->SetDrawerFill( a2dCanvasGlobals->GetHighLightFill() );
01145
01146 double x1;
01147 double y1;
01148 ic.GetTransform().TransformPoint( 0, 0, x1, y1 );
01149 int dx = ic.GetDrawer2D()->WorldToDeviceX(x1);
01150 int dy = ic.GetDrawer2D()->WorldToDeviceY(y1);
01151
01152 ic.GetDrawer2D()->PushIdentityTransform();
01153 ic.GetDrawer2D()->DrawCenterRoundedRectangle(dx, dy, (int) (m_width * 1.1), (int) (m_height * 1.1), m_radius);
01154 ic.GetDrawer2D()->PopTransform();
01155 }
01156
01157 void a2dPin::DoRender( a2dIterC& ic, OVERLAP WXUNUSED(clipparent) )
01158 {
01159 double x1;
01160 double y1;
01161 ic.GetTransform().TransformPoint( 0, 0, x1, y1 );
01162 int dx = ic.GetDrawer2D()->WorldToDeviceX(x1);
01163 int dy = ic.GetDrawer2D()->WorldToDeviceY(y1);
01164
01165
01166 ic.GetDrawer2D()->PushIdentityTransform();
01167
01168 if ( m_flags.m_MouseInObject )
01169 {
01170 if ( !m_canvaspin )
01171 {
01172 if ( m_mode == sm_PinUnConnected )
01173 {
01174
01175 ic.GetDrawer2D()->SetDrawerFill( m_pinclass->GetPin()->GetFill() );
01176 ic.GetDrawer2D()->SetDrawerStroke( m_pinclass->GetPin()->GetStroke() );
01177 ic.GetDrawer2D()->DrawCenterRoundedRectangle(dx, dy, m_width, m_height, m_radius);
01178 if( m_pinclass->HasAngleLine() )
01179 {
01180 int x2,y2;
01181 double ang;
01182 ang = ic.GetTransform().GetRotation();
01183 x2 = Round( dx + m_pinclass->GetPin()->GetWidth()*3*cos(wxDegToRad(ang)) );
01184 y2 = Round( dy - m_pinclass->GetPin()->GetWidth()*3*sin(wxDegToRad(ang)) );
01185
01186 ic.GetDrawer2D()->DrawLine(dx,dy,x2,y2);
01187 }
01188 }
01189 else if ( m_mode == sm_PinCanConnect )
01190 {
01191 int w = m_pinclass->GetPinCanConnect()->GetWidth();
01192 int h = m_pinclass->GetPinCanConnect()->GetHeight();
01193 int r = m_pinclass->GetPinCanConnect()->GetRadius();
01194 ic.GetDrawer2D()->SetDrawerFill( m_pinclass->GetPinCanConnect()->GetFill() );
01195 ic.GetDrawer2D()->SetDrawerStroke( m_pinclass->GetPinCanConnect()->GetStroke() );
01196 ic.GetDrawer2D()->DrawCenterRoundedRectangle(dx, dy, w, h, r);
01197 }
01198 else if ( m_mode == sm_PinCannotConnect )
01199 {
01200 int w = m_pinclass->GetPinCannotConnect()->GetWidth();
01201 int h = m_pinclass->GetPinCannotConnect()->GetHeight();
01202 int r = m_pinclass->GetPinCanConnect()->GetRadius();
01203 ic.GetDrawer2D()->SetDrawerFill( m_pinclass->GetPinCannotConnect()->GetFill() );
01204 ic.GetDrawer2D()->SetDrawerStroke( m_pinclass->GetPinCannotConnect()->GetStroke() );
01205 ic.GetDrawer2D()->DrawCenterRoundedRectangle(dx, dy, w, h, r);
01206 }
01207 else if ( m_mode == sm_PinCanConnectToPinClass )
01208 {
01209
01210 int w = m_pinclass->GetPinCanConnect()->GetWidth();
01211 int h = m_pinclass->GetPinCanConnect()->GetHeight();
01212 int r = m_pinclass->GetPinCanConnect()->GetRadius();
01213 ic.GetDrawer2D()->SetDrawerFill( m_pinclass->GetPinCanConnect()->GetFill() );
01214 ic.GetDrawer2D()->SetDrawerStroke( m_pinclass->GetPinCanConnect()->GetStroke() );
01215 ic.GetDrawer2D()->DrawCenterRoundedRectangle(dx, dy, w, h, r);
01216 }
01217 }
01218 else
01219 {
01220
01221
01222 if( IsDislocated() || m_RenderConnected )
01223 {
01224 ic.GetDrawer2D()->SetDrawerFill( *a2dTRANSPARENT_FILL );
01225 ic.GetDrawer2D()->DrawLine( dx - m_width, dy + m_height, dx + m_width, dy - m_height);
01226 ic.GetDrawer2D()->DrawLine( dx - m_width, dy - m_height, dx + m_width, dy + m_height);
01227 }
01228 }
01229 }
01230 else
01231 {
01232 if ( !m_canvaspin )
01233 {
01234
01235 ic.GetDrawer2D()->SetDrawerFill( m_pinclass->GetPin()->GetFill() );
01236 ic.GetDrawer2D()->SetDrawerStroke( m_pinclass->GetPin()->GetStroke() );
01237 ic.GetDrawer2D()->DrawCenterRoundedRectangle(dx, dy, (int) (m_width), (int) (m_height), m_radius);
01238 if( m_pinclass->HasAngleLine() )
01239 {
01240 int x2,y2;
01241 double ang;
01242 ang = ic.GetTransform().GetRotation();
01243 x2 = Round( dx + m_pinclass->GetPin()->GetWidth()*3*cos(wxDegToRad(ang)) );
01244 y2 = Round( dy - m_pinclass->GetPin()->GetWidth()*3*sin(wxDegToRad(ang)) );
01245
01246 ic.GetDrawer2D()->DrawLine(dx,dy,x2,y2);
01247 }
01248 }
01249 }
01250 ic.GetDrawer2D()->PopTransform();
01251 }
01252
01253 void a2dPin::RestoreConnectionsAfterCloning( a2dCanvasCommandProcessor *cp )
01254 {
01255 if( m_clonebrother )
01256 {
01257 wxASSERT( m_clonebrother->m_clonebrother == this );
01258 wxASSERT( !m_canvaspin );
01259 wxASSERT( m_clonebrother->m_canvaspin );
01260
01261
01262
01263
01264
01265
01266 if( m_clonebrother->m_canvaspin->m_clonebrother )
01267 {
01268
01269 assert( m_clonebrother->m_canvaspin->m_canvaspin == m_clonebrother );
01270
01271
01272 assert( !m_clonebrother->m_canvaspin->m_clonebrother->m_canvaspin );
01273
01274
01275
01276 if( cp )
01277 {
01278 cp->Submit( new a2dCommand_ConnectPins( this, m_clonebrother->m_canvaspin->m_clonebrother ), true );
01279 }
01280 else
01281 {
01282
01283
01284
01285 this->ConnectTo( m_clonebrother->m_canvaspin->m_clonebrother );
01286 m_clonebrother->m_canvaspin->m_clonebrother->ConnectTo( this );
01287 }
01288
01289
01290 m_clonebrother->m_canvaspin->m_clonebrother->m_clonebrother = 0;
01291 m_clonebrother->m_canvaspin->m_clonebrother = 0;
01292 }
01293 m_clonebrother->m_clonebrother = 0;
01294 m_clonebrother = 0;
01295 }
01296 }
01297
01298 void a2dPin::ClearAllPinConnections( class a2dCanvasCommandProcessor *cp )
01299 {
01300 if( m_canvaspin )
01301 {
01302 if( cp )
01303 {
01304 cp->Submit( new a2dCommand_ConnectPins( this, 0 ), true );
01305 }
01306 else
01307 {
01308 wxASSERT( this == ConnectedTo()->ConnectedTo() );
01309 ConnectedTo()->ConnectTo( 0 );
01310 ConnectTo( 0 );
01311 }
01312 }
01313 }
01314
01315
01316 #if wxART2D_USE_CVGIO
01317 void a2dPin::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
01318 {
01319 a2dHandle::DoSave( parent, out, xmlparts, towrite);
01320 if ( xmlparts == a2dXmlSer_attrib )
01321 {
01322 out.WriteAttribute( wxT("pinclass"), m_pinclass->GetName() );
01323 if( m_canvaspin )
01324 {
01325 out.WriteAttribute( wxT("resolveid"), m_canvaspin->GetUniqueSerializationId() );
01326 wxASSERT_MSG( !m_temporaryPin, wxT("temporary pins should have bin deleted") );
01327 }
01328 out.WriteAttribute( wxT("RenderConnected"), m_RenderConnected, true );
01329 out.WriteAttribute( wxT("dynamicPin"), m_dynamicPin, true );
01330 out.WriteAttribute( wxT("internal"), m_internal, true );
01331 }
01332 else
01333 {
01334 }
01335 }
01336
01337 void a2dPin::DoLoad( wxObject* parent, a2dIOHandlerXmlSerIn& parser, a2dXmlSer_flag xmlparts )
01338 {
01339 m_parent = wxStaticCast( parent, a2dCanvasObject );
01340 m_parent->SetSpecificFlags( true, a2dCanvasOFlags::HasPins );
01341
01342 a2dHandle::DoLoad( parent, parser, xmlparts );
01343
01344 if ( xmlparts == a2dXmlSer_attrib )
01345 {
01346 wxString pinclass = parser.RequireAttributeValue( wxT("pinclass") );
01347 m_pinclass = a2dPinClass::GetClassByName( pinclass );
01348 if( !m_pinclass )
01349 {
01350 m_pinclass = a2dPinClass::Standard;
01351 wxString reference_name = GetName();
01352 a2dDocviewGlobals->ReportErrorF( a2dError_NoPinClass, _("a2dPin with name %s \n Pin class %s not found (replaced with Standard)"), reference_name.c_str(), pinclass.c_str() );
01353 }
01354 if ( parser.HasAttribute( wxT("resolveid") ) )
01355 {
01356 wxString resolveid = parser.GetAttributeValue( wxT("resolveid") );
01357 parser.ResolveOrAddLink( this, resolveid );
01358 }
01359
01360 m_RenderConnected = parser.GetAttributeValueBool( wxT("RenderConnected") );
01361 m_dynamicPin = parser.GetAttributeValueBool( wxT("dynamicPin") );
01362 m_internal = parser.GetAttributeValueBool( wxT("internal") );
01363 }
01364 else
01365 {
01366 }
01367 }
01368 #endif //wxART2D_USE_CVGIO
01369
01370 bool a2dPin::IsTemporary_DontSave() const
01371 {
01372
01373 return a2dCanvasObject::IsTemporary_DontSave();
01374 }
01375
01376 bool a2dPin::AlwaysWriteSerializationId() const
01377 {
01378 return true;
01379 }
01380
01381 bool a2dPin::LinkReference( a2dObject *other )
01382 {
01383 if(!other)
01384 return false;
01385
01386 a2dPin *canvaspin = wxDynamicCast( other, a2dPin );
01387
01388 if ( !canvaspin )
01389 {
01390 wxString reference_name = GetName();
01391 a2dDocviewGlobals->ReportErrorF( a2dError_LinkPin, _("a2dPin with name %s \n Linked to wrong object type"), reference_name.c_str() );
01392 if( m_canvaspin )
01393 {
01394 m_canvaspin->ConnectTo( 0 );
01395 m_canvaspin = 0;
01396 }
01397 return false;
01398 }
01399
01400 if( !m_canvaspin )
01401 {
01402 if( canvaspin->ConnectedTo() )
01403 {
01404 wxString reference_name = GetName();
01405 a2dDocviewGlobals->ReportErrorF( a2dError_LinkPin, _("a2dPin with name %s \n Reference is already connected"), reference_name.c_str() );
01406 canvaspin->ConnectedTo()->ConnectTo( 0 );
01407 canvaspin->ConnectTo( 0 );
01408 return false;
01409 }
01410 m_canvaspin = canvaspin;
01411 m_canvaspin->ConnectTo( this );
01412 return true;
01413 }
01414 else
01415 {
01416 if( m_canvaspin != canvaspin )
01417 {
01418 wxString reference_name = GetName();
01419 a2dDocviewGlobals->ReportErrorF( a2dError_LinkPin, _("a2dPin with name %s \n Reference is already connected"), reference_name.c_str() );
01420 m_canvaspin->ConnectTo( 0 );
01421 m_canvaspin = 0;
01422 return false;
01423 }
01424 return true;
01425 }
01426 }
01427
01428 #ifdef _DEBUG
01429
01430 void a2dPin::DoDump( int indent, wxString *line )
01431 {
01432 a2dHandle::DoDump( indent, line );
01433 *line += wxString::Format( _T(" name=%s"), GetName() );
01434 if( m_canvaspin )
01435 *line += wxString::Format(_T(" cp=%p"), m_canvaspin );
01436 if( m_clonebrother )
01437 *line += wxString::Format(_T(" cb=%p"), m_clonebrother );
01438 }
01439
01440 #endif
01441
01442
01443
01444
01445
01446 a2dArrow::a2dArrow( double xt, double yt, double l1, double l2, double b, bool spline )
01447 : a2dCanvasObject()
01448 {
01449 m_lworld.Translate(xt,yt);
01450 m_l1 = l1;
01451 m_l2 = l2;
01452 m_b = b;
01453 m_spline = spline;
01454 }
01455
01456 a2dArrow::a2dArrow()
01457 : a2dCanvasObject()
01458 {
01459 m_lworld.Translate(0,0);
01460 m_l1 = 40;
01461 m_l2 = 20;
01462 m_b = 10;
01463 m_spline = false;
01464 }
01465
01466 a2dArrow::~a2dArrow()
01467 {
01468 }
01469
01470 a2dArrow::a2dArrow( const a2dArrow &other, CloneOptions options )
01471 :a2dCanvasObject( other, options )
01472 {
01473 m_l1 = other.m_l1;
01474 m_l2 = other.m_l2;
01475 m_b = other.m_b;
01476 m_spline = other.m_spline;
01477 }
01478
01479 void a2dArrow::Set(double xt, double yt, double l1, double l2, double b, bool spline )
01480 {
01481 SetPosXY(xt,yt);
01482 m_l1 = l1;
01483 m_l2 = l2;
01484 m_b = b;
01485 m_spline = spline;
01486
01487 SetPending(true);
01488 }
01489
01490 void a2dArrow::Set( double l1, double l2, double b, bool spline )
01491 {
01492 m_l1 = l1;
01493 m_l2 = l2;
01494 m_b = b;
01495 m_spline = spline;
01496
01497 SetPending(true);
01498 }
01499
01500 a2dObject* a2dArrow::Clone( CloneOptions options ) const
01501 {
01502 a2dArrow* a = new a2dArrow( *this, options );
01503 return a;
01504 };
01505
01506 a2dVertexList* a2dArrow::GetAsPolygon()
01507 {
01508 a2dVertexList* pointlist = new a2dVertexList();
01509
01510 a2dCanvasObjectList* vectorpaths = GetAsCanvasVpaths();
01511 a2dVpath* segments = wxStaticCast( vectorpaths->front().Get(), a2dVectorPath ) ->GetSegments();
01512 segments->ConvertToLines();
01513 a2dLineSegment* point;
01514 unsigned int i;
01515 for (i=0; i < segments->GetCount();i++)
01516 {
01517 a2dVpathSegment& seg = segments->Item(i);
01518 point = new a2dLineSegment(seg.m_x1, seg.m_y1);
01519 pointlist->push_back(point);
01520 }
01521
01522 delete vectorpaths;
01523
01524 return pointlist;
01525 }
01526
01527 a2dCanvasObjectList* a2dArrow::GetAsCanvasVpaths( bool transform )
01528 {
01529 a2dAffineMatrix pworld;
01530 if ( transform )
01531 pworld = m_lworld;
01532
01533 a2dVpath* segments = new a2dVpath();
01534
01535 double x,y;
01536 pworld.TransformPoint( 0 , 0, x, y );
01537 a2dVpathSegment* seg = new a2dVpathSegment( x, y , a2dPATHSEG_MOVETO );
01538 segments->Add(seg);
01539 pworld.TransformPoint( m_l1, m_b/2, x, y );
01540 seg = new a2dVpathSegment( x, y , a2dPATHSEG_MOVETO );
01541 segments->Add(seg);
01542 pworld.TransformPoint( m_l2, 0, x, y );
01543 seg = new a2dVpathSegment( x, y , a2dPATHSEG_MOVETO );
01544 segments->Add(seg);
01545 pworld.TransformPoint( m_l1, -m_b/2, x, y );
01546 seg = new a2dVpathSegment( x, y , a2dPATHSEG_MOVETO );
01547 segments->Add(seg);
01548
01549 a2dVectorPath* canpath = new a2dVectorPath( segments );
01550 canpath->SetStroke( this->GetStroke() );
01551 canpath->SetFill( this->GetFill() );
01552 canpath->SetLayer( m_layer );
01553 canpath->SetContourWidth( GetContourWidth() );
01554 a2dCanvasObjectList* canpathlist = new a2dCanvasObjectList();
01555 canpathlist->push_back( canpath );
01556 return canpathlist;
01557 }
01558
01559 a2dBoundingBox a2dArrow::DoGetUnTransformedBbox( a2dBboxFlags WXUNUSED(flags) ) const
01560 {
01561 a2dBoundingBox bbox;
01562 bbox.Expand( 0 , - m_b/2);
01563 bbox.Expand( m_l1 , m_b/2);
01564 return bbox;
01565 }
01566
01567 void a2dArrow::DoRender( a2dIterC& ic, OVERLAP WXUNUSED(clipparent) )
01568 {
01569 a2dVertexArray* cpoints = new a2dVertexArray;
01570
01571 cpoints->push_back( new a2dLineSegment( 0, 0 ));
01572 cpoints->push_back( new a2dLineSegment( m_l1, m_b/2.0 ));
01573 cpoints->push_back( new a2dLineSegment( m_l2, 0 ));
01574 cpoints->push_back( new a2dLineSegment( m_l1, -m_b/2.0 ));
01575
01576 ic.GetDrawer2D()->DrawPolygon( cpoints, m_spline, wxWINDING_RULE);
01577
01578 cpoints->clear();
01579 delete cpoints;
01580 }
01581
01582 bool a2dArrow::DoIsHitWorld( a2dIterC& ic, a2dHitEvent& hitEvent )
01583 {
01584 a2dVertexArray points;
01585 points.push_back( new a2dLineSegment( 0, 0 ) );
01586 points.push_back( new a2dLineSegment( m_l1, m_b/2.0 ) );
01587 points.push_back( new a2dLineSegment( m_l2, 0 ) );
01588 points.push_back( new a2dLineSegment( m_l1, -m_b/2.0 ) );
01589
01590 a2dPoint2D P = a2dPoint2D(hitEvent.m_relx, hitEvent.m_rely);
01591 hitEvent.m_how = points.HitTestPolygon( P, ic.GetWorldStrokeExtend() + ic.GetTransformedHitMargin() );
01592
01593 return hitEvent.m_how.IsHit();
01594 }
01595
01596 #if wxART2D_USE_CVGIO
01597 void a2dArrow::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
01598 {
01599 a2dCanvasObject::DoSave( parent, out, xmlparts, towrite );
01600 if ( xmlparts == a2dXmlSer_attrib )
01601 {
01602 out.WriteAttribute( wxT("l1"), m_l1 );
01603 out.WriteAttribute( wxT("l2"), m_l2 );
01604 out.WriteAttribute( wxT("b"), m_b );
01605 out.WriteAttribute( wxT("spline"), m_spline );
01606 }
01607 else
01608 {
01609 }
01610 }
01611
01612 void a2dArrow::DoLoad( wxObject* parent, a2dIOHandlerXmlSerIn& parser, a2dXmlSer_flag xmlparts )
01613 {
01614 a2dCanvasObject::DoLoad( parent, parser, xmlparts );
01615 if ( xmlparts == a2dXmlSer_attrib )
01616 {
01617 m_l1 = parser.RequireAttributeValueDouble( wxT("l1") );
01618 m_l2 = parser.RequireAttributeValueDouble( wxT("l2") );
01619 m_b = parser.GetAttributeValueDouble( wxT("b") );
01620 m_spline = parser.GetAttributeValueBool( wxT("spline") );
01621 }
01622 else
01623 {
01624 }
01625 }
01626 #endif //wxART2D_USE_CVGIO
01627
01628
01629
01630
01631
01632 a2dPropertyIdDouble* a2dRectC::PROPID_Width = NULL;
01633 a2dPropertyIdDouble* a2dRectC::PROPID_Height = NULL;
01634 a2dPropertyIdDouble* a2dRectC::PROPID_Radius = NULL;
01635
01636 INITIALIZE_PROPERTIES( a2dRectC, a2dCanvasObject )
01637 {
01638 PROPID_Width = new a2dPropertyIdDouble( wxT("Width"),
01639 a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dRectC::m_width) );
01640 AddPropertyId( PROPID_Width );
01641 PROPID_Height = new a2dPropertyIdDouble( wxT("Height"),
01642 a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dRectC::m_height) );
01643 AddPropertyId( PROPID_Height );
01644 PROPID_Radius = new a2dPropertyIdDouble( wxT("Radius"),
01645 a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dRectC::m_radius) );
01646 AddPropertyId( PROPID_Radius );
01647
01648 return true;
01649 }
01650
01651
01652 a2dRectC::a2dRectC()
01653 : a2dCanvasObject()
01654 {
01655 m_width = 10;
01656 m_height = 10;
01657 m_radius = 0;
01658 }
01659
01660 a2dRectC::a2dRectC( double xc, double yc, double w, double h, double angle, double radius )
01661 : a2dCanvasObject()
01662 {
01663 Rotate(angle);
01664 m_lworld.Translate(xc, yc);
01665 m_width = w;
01666 m_height = h;
01667 m_radius = radius;
01668 }
01669
01670 a2dRectC::~a2dRectC()
01671 {
01672 }
01673
01674 a2dRectC::a2dRectC( const a2dRectC &other, CloneOptions options )
01675 :a2dCanvasObject( other, options )
01676 {
01677 m_width = other.m_width;
01678 m_height = other.m_height;
01679 m_radius = other.m_radius;
01680 }
01681
01682 void a2dRectC::Set(double xc, double yc, double w, double h, double angle , double radius)
01683 {
01684 SetRotation(angle);
01685 SetPosXY(xc,yc);
01686 m_width = w;
01687 m_height = h;
01688 m_radius = radius;
01689 SetPending(true);
01690 }
01691
01692
01693 a2dObject* a2dRectC::Clone( CloneOptions options ) const
01694 {
01695 return new a2dRectC( *this, options );
01696 };
01697
01698 a2dVertexList* a2dRectC::GetAsPolygon()
01699 {
01700 a2dVertexList* pointlist = new a2dVertexList();
01701
01702 a2dCanvasObjectList* vectorpaths = GetAsCanvasVpaths();
01703 a2dVpath* segments = wxStaticCast( vectorpaths->front().Get(), a2dVectorPath ) ->GetSegments();
01704 segments->ConvertToLines();
01705 a2dLineSegment* point;
01706 unsigned int i;
01707 for (i=0; i < segments->GetCount();i++)
01708 {
01709 a2dVpathSegment& seg = segments->Item(i);
01710 point = new a2dLineSegment(seg.m_x1, seg.m_y1);
01711 pointlist->push_back(point);
01712 }
01713
01714 delete vectorpaths;
01715 return pointlist;
01716 }
01717
01718 a2dCanvasObjectList* a2dRectC::GetAsCanvasVpaths( bool transform )
01719 {
01720 a2dAffineMatrix pworld;
01721 if ( transform )
01722 pworld = m_lworld;
01723
01724 a2dVpath* segments = new a2dVpath();
01725
01726 double w2 = fabs(m_width/2);
01727 double h2 = fabs(m_height/2);
01728
01729 if (m_radius && m_width && m_height)
01730 {
01731
01732 if ( m_radius < 0 )
01733 {
01734 double rx = -m_radius;
01735 if ( m_width < 0 )
01736 rx = -rx;
01737
01738 double ry = -m_radius;
01739 if ( m_height < 0 )
01740 ry = -ry;
01741
01742 a2dVpathSegment* seg = new a2dVpathSegment( rx, 0 , a2dPATHSEG_MOVETO );
01743 segments->push_back(seg);
01744
01745 seg = new a2dVpathArcSegment( *seg, rx, ry, 0.0, ry, 0.0, 0.0, a2dPATHSEG_ARCTO );
01746 segments->push_back(seg);
01747 seg = new a2dVpathSegment( 0, m_height - ry, a2dPATHSEG_LINETO );
01748 segments->push_back(seg);
01749
01750 seg = new a2dVpathArcSegment( *seg, rx, m_height - ry, rx, m_height, 0.0, m_height, a2dPATHSEG_ARCTO );
01751 segments->push_back(seg);
01752 seg = new a2dVpathSegment( m_width - rx, m_height, a2dPATHSEG_LINETO );
01753 segments->push_back(seg);
01754
01755 seg = new a2dVpathArcSegment( *seg, m_width - rx, m_height - ry, m_width, m_height - ry, m_width, m_height, a2dPATHSEG_ARCTO );
01756 segments->push_back(seg);
01757 seg = new a2dVpathSegment( m_width, ry, a2dPATHSEG_LINETO );
01758 segments->push_back(seg);
01759
01760 seg = new a2dVpathArcSegment( *seg, m_width - rx, ry, m_width - rx, 0.0, m_width, 0.0, a2dPATHSEG_ARCTO, a2dPATHSEG_END_CLOSED );
01761 segments->push_back(seg);
01762
01763 a2dAffineMatrix world;
01764 world.Translate( -w2, -h2 );
01765 world *= pworld;
01766 segments->Transform( world );
01767 }
01768 else
01769 {
01770 double rx = m_radius;
01771 if ( m_width < 0 )
01772 rx = -rx;
01773
01774 double ry = m_radius;
01775 if ( m_height < 0 )
01776 ry = -ry;
01777
01778 a2dVpathSegment* seg = new a2dVpathSegment( 0.0, -ry , a2dPATHSEG_MOVETO );
01779 segments->push_back(seg);
01780
01781 seg = new a2dVpathArcSegment( *seg, 0.0, 0.0, -rx, 0.0, -rx, -ry, a2dPATHSEG_ARCTO );
01782 segments->push_back(seg);
01783 seg = new a2dVpathSegment( -rx, m_height, a2dPATHSEG_LINETO );
01784 segments->push_back(seg);
01785
01786 seg = new a2dVpathArcSegment( *seg, 0.0, m_height, 0.0, m_height + ry, -rx, m_height + ry, a2dPATHSEG_ARCTO );
01787 segments->push_back(seg);
01788 seg = new a2dVpathSegment( m_width, m_height + ry, a2dPATHSEG_LINETO );
01789 segments->push_back(seg);
01790
01791 seg = new a2dVpathArcSegment( *seg, m_width, m_height, m_width + rx, m_height, m_width + rx, m_height + ry, a2dPATHSEG_ARCTO );
01792 segments->push_back(seg);
01793 seg = new a2dVpathSegment( m_width + rx, 0.0, a2dPATHSEG_LINETO );
01794 segments->push_back(seg);
01795
01796 seg = new a2dVpathArcSegment( *seg, m_width, 0.0, m_width, -ry, m_width + rx, -ry, a2dPATHSEG_ARCTO, a2dPATHSEG_END_CLOSED );
01797 segments->push_back(seg);
01798
01799 a2dAffineMatrix world;
01800 world.Translate( -w2, -h2 );
01801 world *= pworld;
01802 segments->Transform( world );
01803 }
01804 }
01805 else
01806 {
01807 double x,y;
01808 pworld.TransformPoint( -w2 , -h2, x, y );
01809 a2dVpathSegment* seg = new a2dVpathSegment( x, y , a2dPATHSEG_MOVETO );
01810 segments->push_back(seg);
01811 pworld.TransformPoint( -w2 , +h2, x, y );
01812 seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
01813 segments->push_back(seg);
01814 pworld.TransformPoint( +w2 , +h2, x, y );
01815 seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
01816 segments->push_back(seg);
01817 pworld.TransformPoint( +w2 , -h2, x, y );
01818 seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO, a2dPATHSEG_END_CLOSED );
01819 segments->push_back(seg);
01820 }
01821
01822 a2dVectorPath* canpath = new a2dVectorPath( segments );
01823 canpath->SetStroke( this->GetStroke() );
01824 canpath->SetFill( this->GetFill() );
01825 canpath->SetLayer( m_layer );
01826 canpath->SetContourWidth( GetContourWidth() );
01827 a2dCanvasObjectList* canpathlist = new a2dCanvasObjectList();
01828 canpathlist->push_back( canpath );
01829 return canpathlist;
01830 }
01831
01832
01833
01834 a2dBoundingBox a2dRectC::DoGetUnTransformedBbox( a2dBboxFlags WXUNUSED(flags) ) const
01835 {
01836 a2dBoundingBox bbox;
01837 bbox.Expand( - fabs(m_width/2) , - fabs(m_height/2));
01838 bbox.Expand( + fabs(m_width/2) , + fabs(m_height/2));
01839 if (m_radius > 0)
01840 bbox.Enlarge( m_radius );
01841 return bbox;
01842 }
01843
01844 void a2dRectC::DoRender( a2dIterC& ic, OVERLAP WXUNUSED(clipparent) )
01845 {
01846 if (m_radius<=0)
01847 {
01848 ic.GetDrawer2D()->DrawCenterRoundedRectangle( 0, 0, m_width, m_height, -m_radius);
01849 }
01850 else
01851 {
01852 ic.GetDrawer2D()->DrawCenterRoundedRectangle( 0, 0, m_width+2*m_radius, m_height+2*m_radius, m_radius);
01853 }
01854 }
01855
01856 bool a2dRectC::DoIsHitWorld( a2dIterC& ic, a2dHitEvent& hitEvent )
01857 {
01858 double margin = ic.GetTransformedHitMargin();
01859
01860 double xmax = fabs( m_width/2 );
01861 double ymax = fabs( m_height/2 );
01862 double xmin = -xmax;
01863 double ymin = -ymax;
01864
01865 if (m_radius > 0)
01866 {
01867 xmin -= m_radius;
01868 ymin -= m_radius;
01869 xmax += m_radius;
01870 ymax += m_radius;
01871 }
01872
01873 hitEvent.m_how = HitTestRectangle( hitEvent.m_relx, hitEvent.m_rely, xmin, ymin, xmax, ymax, ic.GetWorldStrokeExtend()+margin );
01874
01875 return hitEvent.m_how.IsHit();
01876 }
01877
01878 #if wxART2D_USE_CVGIO
01879 void a2dRectC::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
01880 {
01881 a2dCanvasObject::DoSave( parent, out, xmlparts, towrite );
01882 if ( xmlparts == a2dXmlSer_attrib )
01883 {
01884 out.WriteAttribute( wxT("width"), m_width );
01885 out.WriteAttribute( wxT("height"), m_height );
01886 if (m_radius != 0.0)
01887 {
01888 out.WriteAttribute( wxT("radius"), m_radius );
01889 }
01890 }
01891 else
01892 {
01893 }
01894 }
01895 #endif //wxART2D_USE_CVGIO
01896
01897
01898
01899
01900
01901
01902 a2dPropertyIdDouble* a2dWH::PROPID_Width = NULL;
01903 a2dPropertyIdDouble* a2dWH::PROPID_Height = NULL;
01904
01905 INITIALIZE_PROPERTIES( a2dWH, a2dCanvasObject )
01906 {
01907 PROPID_Width = new a2dPropertyIdDouble( wxT("Width"),
01908 a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dWH::m_width) );
01909 AddPropertyId( PROPID_Width );
01910 PROPID_Height = new a2dPropertyIdDouble( wxT("Height"),
01911 a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dWH::m_height) );
01912 AddPropertyId( PROPID_Height );
01913
01914 return true;
01915 }
01916
01917
01918
01919 A2D_BEGIN_EVENT_TABLE( a2dWH, a2dCanvasObject )
01920 A2D_EVT_CANVASHANDLE_MOUSE_EVENT( a2dWH::OnHandleEvent )
01921 A2D_EVT_CANVASOBJECT_RESIZE_EVENT( a2dWH::OnResizeObjectToChildBox )
01922 A2D_END_EVENT_TABLE()
01923
01924 a2dWH::a2dWH()
01925 : a2dCanvasObject()
01926 {
01927 m_width = 0;
01928 m_height = 0;
01929 }
01930
01931 a2dWH::a2dWH( double x, double y, double w, double h)
01932 : a2dCanvasObject()
01933 {
01934 m_lworld.Translate(x,y);
01935 m_width = w;
01936 m_height = h;
01937 }
01938
01939 a2dWH::a2dWH( const a2dWH& other, CloneOptions options )
01940 : a2dCanvasObject( other, options )
01941 {
01942 m_width = other.m_width;
01943 m_height = other.m_height;
01944 }
01945
01946 a2dWH::~a2dWH()
01947 {
01948 }
01949
01950 a2dCanvasObjectList* a2dWH::GetAsCanvasVpaths( bool transform )
01951 {
01952 a2dAffineMatrix pworld;
01953 if ( transform )
01954 pworld = m_lworld;
01955
01956 a2dVpath* segments = new a2dVpath();
01957 a2dVectorPath* canpath = new a2dVectorPath( segments );
01958 canpath->SetStroke( this->GetStroke() );
01959 canpath->SetFill( this->GetFill() );
01960 canpath->SetLayer( m_layer );
01961
01962 double x,y;
01963 pworld.TransformPoint( 0, 0, x, y );
01964 a2dVpathSegment* seg = new a2dVpathSegment( x, y , a2dPATHSEG_MOVETO );
01965 segments->push_back(seg);
01966 pworld.TransformPoint( 0 , m_height, x, y );
01967 seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
01968 segments->push_back(seg);
01969 pworld.TransformPoint( m_width , m_height, x, y );
01970 seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
01971 segments->push_back(seg);
01972 pworld.TransformPoint( m_width , 0, x, y );
01973 seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO, a2dPATHSEG_END_CLOSED );
01974 segments->push_back(seg);
01975
01976 a2dCanvasObjectList* canpathlist = new a2dCanvasObjectList();
01977 canpathlist->push_back( canpath );
01978 return canpathlist;
01979 }
01980
01981 bool a2dWH::RestrictToObject( a2dRestrictionEngine* engine, a2dSnapToWhatMask snapToWhat )
01982 {
01983
01984 if ( !m_flags.m_snap_to )
01985 return false;
01986
01987 bool res = false;
01988 if ( !res )
01989 res = a2dCanvasObject::RestrictToObject( engine, snapToWhat );
01990
01991 return res;
01992 }
01993
01994 a2dBoundingBox a2dWH::DoGetUnTransformedBbox( a2dBboxFlags WXUNUSED(flags) ) const
01995 {
01996 a2dBoundingBox bbox;
01997 bbox.Expand( 0, 0);
01998 bbox.Expand( m_width , m_height );
01999 return bbox;
02000 }
02001
02002 #if wxART2D_USE_CVGIO
02003
02004 void a2dWH::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
02005 {
02006 a2dCanvasObject::DoSave( parent, out, xmlparts, towrite );
02007 if ( xmlparts == a2dXmlSer_attrib )
02008 {
02009 out.WriteAttribute( wxT("width"), m_width );
02010 out.WriteAttribute( wxT("height"), m_height );
02011 }
02012 else
02013 {
02014 }
02015 }
02016
02017 void a2dWH::DoLoad( wxObject* parent, a2dIOHandlerXmlSerIn& parser, a2dXmlSer_flag xmlparts )
02018 {
02019 a2dCanvasObject::DoLoad( parent, parser, xmlparts );
02020 if ( xmlparts == a2dXmlSer_attrib )
02021 {
02022 m_width = parser.RequireAttributeValueDouble( wxT("width") );
02023 m_height = parser.RequireAttributeValueDouble( wxT("height") );
02024 }
02025 else
02026 {
02027 }
02028 }
02029 #endif //wxART2D_USE_CVGIO
02030
02031 bool a2dWH::DoIsHitWorld( a2dIterC& ic, a2dHitEvent& hitEvent )
02032 {
02033 double margin = ic.GetTransformedHitMargin();
02034
02035 double xmin = wxMin( 0 , m_width);
02036 double ymin = wxMin( 0 , m_height);
02037 double xmax = wxMax( 0 , m_width);
02038 double ymax = wxMax( 0 , m_height);
02039
02040 hitEvent.m_how = HitTestRectangle( hitEvent.m_relx, hitEvent.m_rely, xmin, ymin, xmax, ymax, ic.GetWorldStrokeExtend()+margin );
02041
02042 return hitEvent.m_how.IsHit();
02043 }
02044
02045 bool a2dWH::DoStartEdit( wxUint16 editmode, wxEditStyle editstyle )
02046 {
02047 PROPID_IncludeChildren->SetPropertyToObject( this, false );
02048 PROPID_Allowrotation->SetPropertyToObject( this, true );
02049 PROPID_Allowskew->SetPropertyToObject( this, true );
02050
02051 return a2dCanvasObject::DoStartEdit( editmode, editstyle );
02052 }
02053
02054 void a2dWH::OnHandleEvent(a2dHandleMouseEvent &event)
02055 {
02056 a2dIterC* ic = event.GetIterC();
02057
02058 if ( m_flags.m_editingCopy )
02059 {
02060 a2dRestrictionEngine *restrictEngine = a2dCanvasGlobals->GetRestrictionEngine();
02061
02062 a2dHandle* draghandle = event.GetCanvasHandle();
02063
02064 wxUint16 editmode = PROPID_Editmode->GetPropertyValue( this );
02065
02066 if ( editmode == 1 )
02067 {
02068 double xw,yw;
02069 xw = event.GetX();
02070 yw = event.GetY();
02071
02072 a2dAffineMatrix atWorld = ic->GetTransform();
02073 a2dAffineMatrix inverse = ic->GetInverseTransform();
02074
02075 double xwi;
02076 double ywi;
02077 inverse.TransformPoint( xw, yw, xwi, ywi );
02078
02079 a2dWH* original = wxStaticCast( PROPID_Original->GetPropertyValue( this ).Get(), a2dWH );
02080
02081 a2dBoundingBox untrans = GetUnTransformedBbox( a2dCANOBJ_BBOX_EDIT );
02082
02083 double xmin,ymin,xmax,ymax,w,h;
02084 xmin = untrans.GetMinX();
02085 ymin = untrans.GetMinY();
02086 xmax = untrans.GetMaxX();
02087 ymax = untrans.GetMaxY();
02088 w = untrans.GetWidth();
02089 h = untrans.GetHeight();
02090
02091 a2dAffineMatrix origworld = m_lworld;
02092 double x1,y1,x2,y2;
02093
02094 if ( event.GetMouseEvent().LeftDown() )
02095 {
02096 }
02097 else if (event.GetMouseEvent().LeftUp() )
02098 {
02099 m_root->GetCommandProcessor()->Submit( new a2dCommand_SetCanvasProperty( original, PROPID_TransformMatrix, m_lworld ) );
02100 }
02101 else if ( event.GetMouseEvent().Dragging() )
02102 {
02103 if (restrictEngine )
02104 restrictEngine->RestrictPoint( xw, yw );
02105 ic->GetInverseTransform().TransformPoint( xw, yw, xwi, ywi );
02106
02107 if ( draghandle->GetName() == wxT("handle1") )
02108 {
02109
02110 double dx,dy;
02111 dx = xwi-xmin;
02112 dy = ywi-ymin;
02113
02114 double sx;
02115 double sy;
02116 if ( w )
02117 sx = (w-dx/2)/w;
02118 else
02119 sx = 0;
02120 if ( h )
02121 sy = (h-dy/2)/h;
02122 else
02123 sy = 0;
02124
02125 origworld.TransformPoint( xmax,ymax, x2, y2 );
02126
02127
02128 SetTransformMatrix();
02129 Scale(sx,sy);
02130 Transform( origworld );
02131 m_lworld.TransformPoint( xmax, ymax, x1, y1 );
02132 Translate(x2-x1, y2-y1);
02133 }
02134 else if ( draghandle->GetName() == wxT("handle2") )
02135 {
02136
02137 double dx,dy;
02138 dx = xwi-xmin;
02139 dy = ywi-ymax;
02140
02141 double sx;
02142 double sy;
02143 if ( w )
02144 sx = (w-dx/2)/w;
02145 else
02146 sx = 0;
02147 if ( h )
02148 sy = (h+dy/2)/h;
02149 else
02150 sy = 0;
02151
02152 origworld.TransformPoint( xmax, ymin, x2, y2 );
02153
02154
02155 SetTransformMatrix();
02156 Scale(sx,sy);
02157 Transform( origworld );
02158 m_lworld.TransformPoint( xmax, ymin, x1, y1 );
02159 Translate(x2-x1, y2-y1);
02160 }
02161 else if ( draghandle->GetName() == wxT("handle3") )
02162 {
02163
02164 double dx,dy;
02165
02166 dx = xwi-xmax;
02167 dy = ywi-ymax;
02168
02169 double sx;
02170 double sy;
02171 if ( w )
02172 sx = (w+dx/2)/w;
02173 else
02174 sx = 0;
02175 if ( h )
02176 sy = (h+dy/2)/h;
02177 else
02178 sy = 0;
02179
02180 origworld.TransformPoint( xmin, ymin, x2, y2 );
02181
02182
02183 SetTransformMatrix();
02184 Scale(sx,sy);
02185 Transform( origworld );
02186 m_lworld.TransformPoint( xmin, ymin, x1, y1 );
02187 Translate(x2-x1, y2-y1);
02188 }
02189 else if ( draghandle->GetName() == wxT("handle4") )
02190 {
02191
02192 double dx,dy;
02193
02194 dx = xwi-xmax;
02195 dy = ywi-ymin;
02196
02197 double sx;
02198 double sy;
02199 if ( w )
02200 sx = (w+dx/2)/w;
02201 else
02202 sx = 0;
02203 if ( h )
02204 sy = (h-dy/2)/h;
02205 else
02206 sy = 0;
02207
02208 origworld.TransformPoint( xmin, ymax, x2, y2 );
02209
02210
02211 SetTransformMatrix();
02212 Scale(sx,sy);
02213 Transform( origworld );
02214 m_lworld.TransformPoint( xmin, ymax, x1, y1 );
02215 Translate(x2-x1, y2-y1);
02216 }
02217 else if ( draghandle->GetName() == wxT("rotate") )
02218 {
02219 double xr, yr;
02220 m_lworld.TransformPoint( xmin + w/2, ymin + h/2, xr, yr );
02221
02222
02223 double dx,dy;
02224
02225 dx = xw - xr;
02226 dy = yw - yr;
02227 double angn;
02228 if (!dx && !dy)
02229 angn=0;
02230 else
02231 angn= wxRadToDeg(atan2(dy,dx));
02232
02233 m_lworld = m_lworld.Rotate(angn-m_lworld.GetRotation(), xr, yr );
02234
02235
02236
02237
02238
02239 }
02240 else if ( draghandle->GetName() == wxT("skewx") )
02241 {
02242
02243 double dx,dy;
02244
02245 dx = xwi-(xmin + w*3/4);
02246 dy = ywi-(ymin + h/2);
02247
02248 origworld.TransformPoint( xmin + w/2, ymin + h/2, x2, y2 );
02249
02250
02251 SetTransformMatrix();
02252 SkewX( wxRadToDeg(atan2(dx,dy)) );
02253 Transform( origworld );
02254 m_lworld.TransformPoint( xmin + w/2, ymin + h/2, x1, y1 );
02255 Translate(x2-x1, y2-y1);
02256 }
02257 else if ( draghandle->GetName() == wxT("skewy") )
02258 {
02259
02260 double dx,dy;
02261
02262 dx = xwi-(xmin + w/2);
02263 dy = ywi-(ymin + h*3/4);
02264
02265 origworld.TransformPoint( xmin + w/2, ymin + h/2, x2, y2 );
02266
02267
02268 SetTransformMatrix();
02269 SkewY( wxRadToDeg(atan2(dy,dx)) );
02270 Transform( origworld );
02271 m_lworld.TransformPoint( xmin + w/2, ymin + h/2, x1, y1 );
02272 Translate(x2-x1, y2-y1);
02273 }
02274 else if ( draghandle->GetName() == wxT("handle12") )
02275 {
02276
02277 double dx;
02278
02279 dx = xwi-xmin;
02280
02281 double sx;
02282 if ( w )
02283 sx = (w-dx/2)/w;
02284 else
02285 sx = 0;
02286
02287 origworld.TransformPoint( xmax, ymax, x2, y2 );
02288
02289
02290 SetTransformMatrix();
02291 Scale( sx, 1 );
02292 Transform( origworld );
02293 m_lworld.TransformPoint( xmax, ymax, x1, y1 );
02294 Translate(x2-x1, y2-y1);
02295 }
02296 else if ( draghandle->GetName() == wxT("handle23") )
02297 {
02298
02299 double dy;
02300
02301 dy = ywi-ymax;
02302
02303 double sy;
02304 if ( h )
02305 sy = (h+dy/2)/h;
02306 else
02307 sy = 0;
02308
02309 origworld.TransformPoint( xmax, ymin, x2, y2 );
02310
02311
02312 SetTransformMatrix();
02313 Scale( 1, sy );
02314 Transform( origworld );
02315 m_lworld.TransformPoint( xmax, ymin, x1, y1 );
02316 Translate(x2-x1, y2-y1);
02317 }
02318 else if ( draghandle->GetName() == wxT("handle34") )
02319 {
02320
02321 double dx;
02322
02323 dx = xwi-xmax;
02324
02325 double sx;
02326 if ( w )
02327 sx = (w+dx/2)/w;
02328 else
02329 sx = 0;
02330
02331 origworld.TransformPoint( xmin, ymin, x2, y2 );
02332
02333
02334 SetTransformMatrix();
02335 Scale( sx, 1 );
02336 Transform( origworld );
02337 m_lworld.TransformPoint( xmin, ymin, x1, y1 );
02338 Translate(x2-x1, y2-y1);
02339 }
02340 else if ( draghandle->GetName() == wxT("handle41") )
02341 {
02342
02343 double dy;
02344
02345 dy = ywi - ymin;
02346
02347 double sy;
02348 if ( h )
02349 sy = (h-dy/2)/h;
02350 else
02351 sy = 0;
02352
02353 origworld.TransformPoint( xmin, ymax, x2, y2 );
02354
02355
02356 SetTransformMatrix();
02357 Scale( 1, sy );
02358 Transform( origworld );
02359 m_lworld.TransformPoint( xmin, ymax, x1, y1 );
02360 Translate(x2-x1, y2-y1);
02361 }
02362 else
02363 event.Skip();
02364 SetPending( true );
02365 }
02366 }
02367 else
02368 event.Skip();
02369 }
02370 else
02371 {
02372 event.Skip();
02373 }
02374 }
02375
02376 void a2dWH::OnResizeObjectToChildBox(a2dCanvasObjectEvent &event)
02377 {
02378 a2dBoundingBox box = event.GetBbox();
02379 SetPosXY( box.GetMinX(), box.GetMinY() );
02380 SetWidth( box.GetWidth() );
02381 SetHeight( -box.GetHeight() );
02382 SetPending( false );
02383 }
02384
02385 bool a2dWH::DoUpdate( UpdateMode mode, const a2dBoundingBox& childbox, const a2dBoundingBox& clipbox, const a2dBoundingBox& propbox )
02386 {
02387 bool calc = false;
02388 if ( !m_bbox.GetValid() )
02389 {
02390 calc = a2dCanvasObject::DoUpdate( mode, childbox, clipbox, propbox );
02391 }
02392 return calc;
02393 }
02394
02395
02396
02397
02398
02399 a2dPropertyIdDouble* a2dWHCenter::PROPID_Width = NULL;
02400 a2dPropertyIdDouble* a2dWHCenter::PROPID_Height = NULL;
02401
02402 INITIALIZE_PROPERTIES( a2dWHCenter, a2dWH )
02403 {
02404 PROPID_Width = new a2dPropertyIdDouble( wxT("Width"),
02405 a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dWHCenter::m_width) );
02406 AddPropertyId( PROPID_Width );
02407 PROPID_Height = new a2dPropertyIdDouble( wxT("Height"),
02408 a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dWHCenter::m_height) );
02409 AddPropertyId( PROPID_Height );
02410
02411 return true;
02412 }
02413
02414 A2D_BEGIN_EVENT_TABLE( a2dWHCenter, a2dWH )
02415 A2D_END_EVENT_TABLE()
02416
02417 a2dWHCenter::a2dWHCenter()
02418 : a2dWH()
02419 {
02420 }
02421
02422 a2dWHCenter::a2dWHCenter( double xc, double yc, double w, double h)
02423 : a2dWH( xc, yc, w, h )
02424 {
02425 }
02426
02427 a2dWHCenter::a2dWHCenter( const a2dWHCenter& other, CloneOptions options )
02428 : a2dWH( other, options )
02429 {
02430 }
02431
02432 a2dWHCenter::~a2dWHCenter()
02433 {
02434 }
02435
02436
02437
02438
02439
02440 a2dPropertyIdDouble* a2dRect::PROPID_Radius = NULL;
02441
02442 INITIALIZE_PROPERTIES( a2dRect, a2dWH )
02443 {
02444 PROPID_Radius = new a2dPropertyIdDouble( wxT("Radius"),
02445 a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dRect::m_radius) );
02446 AddPropertyId( PROPID_Radius );
02447
02448 return true;
02449 }
02450
02451 A2D_BEGIN_EVENT_TABLE( a2dRect, a2dWH )
02452 A2D_EVT_CANVASHANDLE_MOUSE_EVENT( a2dRect::OnHandleEvent )
02453 A2D_END_EVENT_TABLE()
02454
02455 a2dRect::a2dRect()
02456 : a2dWH()
02457 {
02458 m_radius = 0;
02459 m_contourwidth = 0;
02460 }
02461
02462 a2dRect::a2dRect( double x, double y, double w, double h , double radius, double contourwidth )
02463 : a2dWH( x, y, w, h )
02464 {
02465 m_radius = radius;
02466 m_contourwidth = contourwidth;
02467 }
02468
02469 a2dRect::a2dRect( const a2dPoint2D& p1, const a2dPoint2D& p2, double radius, double contourwidth )
02470 : a2dWH( p1.m_x, p1.m_y, p2.m_x - p1.m_x, p2.m_y - p1.m_y )
02471 {
02472 m_radius = radius;
02473 m_contourwidth = contourwidth;
02474 }
02475
02476 a2dRect::a2dRect( const a2dBoundingBox& bbox, double radius, double contourwidth )
02477 : a2dWH( bbox.GetMinX(), bbox.GetMinY(), bbox.GetWidth(), bbox.GetHeight() )
02478 {
02479 m_radius = radius;
02480 m_contourwidth = contourwidth;
02481 }
02482
02483 a2dRect::~a2dRect()
02484 {
02485 }
02486
02487 a2dRect::a2dRect( const a2dRect &other, CloneOptions options )
02488 :a2dWH( other, options )
02489 {
02490 m_radius = other.m_radius;
02491 m_contourwidth = other.m_contourwidth;
02492 }
02493
02494 a2dObject* a2dRect::Clone( CloneOptions options ) const
02495 {
02496 return new a2dRect( *this, options );
02497 };
02498
02499 a2dVertexList* a2dRect::GetAsPolygon()
02500 {
02501 a2dVertexList* pointlist = new a2dVertexList();
02502
02503 a2dCanvasObjectList* vectorpaths = GetAsCanvasVpaths();
02504 a2dVpath* segments = wxStaticCast( vectorpaths->front().Get(), a2dVectorPath ) ->GetSegments();
02505 segments->ConvertToLines();
02506 a2dLineSegment* point;
02507 unsigned int i;
02508 for (i=0; i < segments->GetCount();i++)
02509 {
02510 a2dVpathSegment& seg = segments->Item(i);
02511 point = new a2dLineSegment(seg.m_x1, seg.m_y1);
02512 pointlist->push_back(point);
02513 }
02514
02515 delete vectorpaths;
02516
02517 return pointlist;
02518 }
02519
02520 a2dCanvasObjectList* a2dRect::GetAsCanvasVpaths( bool transform )
02521 {
02522 a2dAffineMatrix pworld;
02523 if ( transform )
02524 pworld = m_lworld;
02525
02526 a2dVpath* segments = new a2dVpath();
02527 a2dVectorPath* canpath = new a2dVectorPath( segments );
02528 canpath->SetStroke( this->GetStroke() );
02529 canpath->SetFill( this->GetFill() );
02530 canpath->SetLayer( m_layer );
02531
02532 if (m_radius)
02533 {
02534
02535 if ( m_radius < 0 )
02536 {
02537 double rx = -m_radius;
02538 if ( m_width < 0 )
02539 rx = -rx;
02540
02541 double ry = -m_radius;
02542 if ( m_height < 0 )
02543 ry = -ry;
02544
02545 a2dVpathSegment* seg = new a2dVpathSegment( rx, 0 , a2dPATHSEG_MOVETO );
02546 segments->push_back(seg);
02547
02548 seg = new a2dVpathArcSegment( *seg, rx, ry, 0.0, ry, 0.0, 0.0, a2dPATHSEG_ARCTO );
02549 segments->push_back(seg);
02550 seg = new a2dVpathSegment( 0, m_height - ry, a2dPATHSEG_LINETO );
02551 segments->push_back(seg);
02552
02553 seg = new a2dVpathArcSegment( *seg, rx, m_height - ry, rx, m_height, 0.0, m_height, a2dPATHSEG_ARCTO );
02554 segments->push_back(seg);
02555 seg = new a2dVpathSegment( m_width - rx, m_height, a2dPATHSEG_LINETO );
02556 segments->push_back(seg);
02557
02558 seg = new a2dVpathArcSegment( *seg, m_width - rx, m_height - ry, m_width, m_height - ry, m_width, m_height, a2dPATHSEG_ARCTO );
02559 segments->push_back(seg);
02560 seg = new a2dVpathSegment( m_width, ry, a2dPATHSEG_LINETO );
02561 segments->push_back(seg);
02562
02563 seg = new a2dVpathArcSegment( *seg, m_width - rx, ry, m_width - rx, 0.0, m_width, 0.0, a2dPATHSEG_ARCTO, a2dPATHSEG_END_CLOSED );
02564 segments->push_back(seg);
02565
02566 segments->Transform( pworld );
02567 }
02568 else
02569 {
02570 double rx = m_radius;
02571 if ( m_width < 0 )
02572 rx = -rx;
02573
02574 double ry = m_radius;
02575 if ( m_height < 0 )
02576 ry = -ry;
02577
02578 a2dVpathSegment* seg = new a2dVpathSegment( 0.0, -ry , a2dPATHSEG_MOVETO );
02579 segments->push_back(seg);
02580
02581 seg = new a2dVpathArcSegment( *seg, 0.0, 0.0, -rx, 0.0, -rx, -ry, a2dPATHSEG_ARCTO );
02582 segments->push_back(seg);
02583 seg = new a2dVpathSegment( -rx, m_height, a2dPATHSEG_LINETO );
02584 segments->push_back(seg);
02585
02586 seg = new a2dVpathArcSegment( *seg, 0.0, m_height, 0.0, m_height + ry, -rx, m_height + ry, a2dPATHSEG_ARCTO );
02587 segments->push_back(seg);
02588 seg = new a2dVpathSegment( m_width, m_height + ry, a2dPATHSEG_LINETO );
02589 segments->push_back(seg);
02590
02591 seg = new a2dVpathArcSegment( *seg, m_width, m_height, m_width + rx, m_height, m_width + rx, m_height + ry, a2dPATHSEG_ARCTO );
02592 segments->push_back(seg);
02593 seg = new a2dVpathSegment( m_width + rx, 0.0, a2dPATHSEG_LINETO );
02594 segments->push_back(seg);
02595
02596 seg = new a2dVpathArcSegment( *seg, m_width, 0.0, m_width, -ry, m_width + rx, -ry, a2dPATHSEG_ARCTO, a2dPATHSEG_END_CLOSED );
02597 segments->push_back(seg);
02598
02599 segments->Transform( pworld );
02600 }
02601 canpath->SetContourWidth( GetContourWidth() );
02602 canpath->SetPathType( a2dPATH_END_SQAURE_EXT );
02603 }
02604 else
02605 {
02606 if ( GetContourWidth() )
02607 {
02608 double x,y;
02609 double w = GetContourWidth()/2.0;
02610 pworld.TransformPoint( -w, -w, x, y );
02611 a2dVpathSegment* seg = new a2dVpathSegment( x, y , a2dPATHSEG_MOVETO );
02612 segments->push_back(seg);
02613 pworld.TransformPoint( -w , m_height + w, x, y );
02614 seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
02615 segments->push_back(seg);
02616 pworld.TransformPoint( m_width + w , m_height + w, x, y );
02617 seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
02618 segments->push_back(seg);
02619 pworld.TransformPoint( m_width + w, -w, x, y );
02620 seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
02621 segments->push_back(seg);
02622 pworld.TransformPoint( -w , -w, x, y );
02623 seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
02624 segments->push_back(seg);
02625 pworld.TransformPoint( w, w, x, y );
02626 seg = new a2dVpathSegment( x, y, a2dPATHSEG_LINETO_NOSTROKE );
02627 segments->push_back(seg);
02628 pworld.TransformPoint( m_width - w, w, x, y );
02629 seg = new a2dVpathSegment( x, y, a2dPATHSEG_LINETO );
02630 segments->push_back(seg);
02631 pworld.TransformPoint( m_width - w, m_height - w, x, y );
02632 seg = new a2dVpathSegment( x, y, a2dPATHSEG_LINETO );
02633 segments->push_back(seg);
02634 pworld.TransformPoint( w, m_height - w, x, y );
02635 seg = new a2dVpathSegment( x, y, a2dPATHSEG_LINETO );
02636 segments->push_back(seg);
02637 pworld.TransformPoint( w, w, x, y );
02638 seg = new a2dVpathSegment( x, y, a2dPATHSEG_LINETO );
02639 segments->push_back(seg);
02640 pworld.TransformPoint( -w, -w, x, y );
02641 seg = new a2dVpathSegment( x, y, a2dPATHSEG_LINETO_NOSTROKE, a2dPATHSEG_END_CLOSED );
02642 segments->push_back(seg);
02643 }
02644 else
02645 {
02646 double x,y;
02647 pworld.TransformPoint( 0, 0, x, y );
02648 a2dVpathSegment* seg = new a2dVpathSegment( x, y , a2dPATHSEG_MOVETO );
02649 segments->push_back(seg);
02650 pworld.TransformPoint( 0 , m_height, x, y );
02651 seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
02652 segments->push_back(seg);
02653 pworld.TransformPoint( m_width , m_height, x, y );
02654 seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
02655 segments->push_back(seg);
02656 pworld.TransformPoint( m_width , 0, x, y );
02657 seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO, a2dPATHSEG_END_CLOSED );
02658 segments->push_back(seg);
02659 }
02660 }
02661
02662 a2dCanvasObjectList* canpathlist = new a2dCanvasObjectList();
02663 canpathlist->push_back( canpath );
02664 return canpathlist;
02665 }
02666
02667
02668 bool a2dRect::DoStartEdit( wxUint16 editmode, wxEditStyle editstyle )
02669 {
02670 if ( m_flags.m_editable )
02671 {
02672 if ( editmode == 1 )
02673 {
02674 m_flags.m_visiblechilds = true;
02675 m_flags.m_childrenOnSameLayer = true;
02676
02677
02678 double rx = m_radius;
02679 if ( ( m_radius < 0 && m_width < 0 ) || ( m_radius > 0 && m_width > 0 ) )
02680 rx = -rx;
02681
02682 a2dHandle* handle = new a2dHandle( this, rx, 0, wxT("__rounding__"),
02683 Round( a2dCanvasGlobals->GetHandle()->GetWidth()*1.5 ),
02684 Round( a2dCanvasGlobals->GetHandle()->GetHeight()*1.5 ) );
02685 handle->SetLayer( m_layer );
02686 Append(handle);
02687 handle->SetSpecificFlags( true, a2dCanvasOFlags::BIN2 );
02688
02689 double radius = m_radius;
02690 m_radius = 0;
02691 a2dBoundingBox untrans = GetUnTransformedBbox( a2dCANOBJ_BBOX_EDIT );
02692 double x,y,w,h;
02693 x = untrans.GetMinX();
02694 y = untrans.GetMinY();
02695 w = untrans.GetWidth();
02696 h = untrans.GetHeight();
02697 m_radius = radius;
02698
02699 a2dRect* around = new a2dRect( x, y, w, h );
02700 around->SetStroke( *wxRED, 0, a2dSTROKE_DOT_DASH );
02701 around->SetFill( *a2dTRANSPARENT_FILL );
02702 around->SetPreRenderAsChild( false );
02703 around->SetSpecificFlags( true, a2dCanvasOFlags::BIN2 );
02704 around->SetHitFlags( a2dCANOBJ_EVENT_NON );
02705 around->SetLayer( m_layer );
02706 Append( around );
02707
02708 Append( handle = new a2dHandle( this, x, y, wxT("handle1") ));
02709 handle->SetLayer( m_layer );
02710 Append( handle = new a2dHandle( this, x, y+h, wxT("handle2") ));
02711 handle->SetLayer( m_layer );
02712 Append( handle = new a2dHandle( this, x+w, y+h , wxT("handle3") ));
02713 handle->SetLayer( m_layer );
02714 Append( handle = new a2dHandle( this, x+w, y, wxT("handle4") ));
02715 handle->SetLayer( m_layer );
02716 Append( handle = new a2dHandle( this, x, y+h/2 , wxT("handle12") ));
02717 handle->SetLayer( m_layer );
02718 Append( handle = new a2dHandle( this, x+w/2, y+h, wxT("handle23") ));
02719 handle->SetLayer( m_layer );
02720 Append( handle = new a2dHandle( this, x+w, y+h/2 , wxT("handle34") ));
02721 handle->SetLayer( m_layer );
02722 Append( handle = new a2dHandle( this, x+w/2, y, wxT("handle41") ));
02723 handle->SetLayer( m_layer );
02724
02725
02726 {
02727 a2dSLine* rotline = new a2dSLine( x + w/2, y + h/2, x + w*3/4, y + h/2 );
02728 rotline->SetStroke( *wxRED, 0 );
02729 rotline->SetPreRenderAsChild( false );
02730 rotline->SetSpecificFlags( true, a2dCanvasOFlags::BIN2 );
02731 rotline->SetHitFlags( a2dCANOBJ_EVENT_NON );
02732 Append( rotline );
02733 rotline->SetLayer( m_layer );
02734
02735 Append( handle = new a2dHandle( this, x+w*3/4, y+h/2, wxT("rotate") ));
02736 handle->SetLayer( m_layer );
02737 }
02738
02739 {
02740 Append( handle = new a2dHandle( this, x+w*3/4, y+h, wxT("skewx") ));
02741 handle->SetLayer( m_layer );
02742 Append( handle = new a2dHandle( this, x+w, y+h*3/4, wxT("skewy") ));
02743 handle->SetLayer( m_layer );
02744 }
02745
02746 m_childobjects->SetSpecificFlags( false, a2dCanvasOFlags::PRERENDERASCHILD, wxT("a2dHandle") );
02747 m_childobjects->SetSpecificFlags( true, a2dCanvasOFlags::BIN2, wxT("a2dHandle") );
02748
02749
02750
02751 Update( updatemask_force );
02752
02753 SetPending( true );
02754 return true;
02755 }
02756 else
02757 {
02758 PROPID_IncludeChildren->SetPropertyToObject( this, false );
02759 PROPID_Allowrotation->SetPropertyToObject( this, true );
02760 PROPID_Allowskew->SetPropertyToObject( this, true );
02761
02762 return a2dWH::DoStartEdit( editmode, editstyle );
02763 }
02764 }
02765
02766 return false;
02767 }
02768
02769 void a2dRect::OnHandleEvent(a2dHandleMouseEvent &event)
02770 {
02771 a2dIterC* ic = event.GetIterC();
02772
02773 if ( m_flags.m_editingCopy )
02774 {
02775 a2dHandle* draghandle = event.GetCanvasHandle();
02776
02777 wxUint16 editmode = PROPID_Editmode->GetPropertyValue( this );
02778
02779 if ( editmode == 1 )
02780 {
02781 double xw,yw;
02782 xw = event.GetX();
02783 yw = event.GetY();
02784
02785 a2dAffineMatrix atWorld = ic->GetTransform();
02786 a2dAffineMatrix inverse = ic->GetInverseTransform();
02787
02788 double xwi;
02789 double ywi;
02790 inverse.TransformPoint( xw, yw, xwi, ywi );
02791
02792 a2dRect* original = wxStaticCast( PROPID_Original->GetPropertyValue( this ).Get(), a2dRect );
02793
02794 double radius = m_radius;
02795 m_radius = 0;
02796 a2dBoundingBox untrans = GetUnTransformedBbox( a2dCANOBJ_BBOX_EDIT );
02797
02798 double xmin,ymin,xmax,ymax,w,h;
02799 xmin = untrans.GetMinX();
02800 ymin = untrans.GetMinY();
02801 xmax = untrans.GetMaxX();
02802 ymax = untrans.GetMaxY();
02803 w = untrans.GetWidth();
02804 h = untrans.GetHeight();
02805 m_radius = radius;
02806
02807 if ( event.GetMouseEvent().LeftDown() )
02808 {
02809 }
02810 else if (event.GetMouseEvent().LeftUp() )
02811 {
02812 if ( draghandle->GetName() == wxT("__rounding__") )
02813 {
02814 original->SetRadius( m_radius );
02815 }
02816 else
02817 event.Skip();
02818 }
02819 else if ( event.GetMouseEvent().Dragging() )
02820 {
02821 if ( draghandle->GetName() == wxT("__rounding__") )
02822 {
02823
02824 if ( ( m_width < 0 && xwi < 0 ) || ( m_width > 0 && xwi > 0 ) )
02825 {
02826 if ( fabs( xwi ) < fabs(m_width/2) && fabs( xwi ) < fabs(m_height/2) )
02827 {
02828 m_radius = -fabs( xwi );
02829 draghandle->SetPosXY( xwi, 0 );
02830 SetPending( true );
02831 }
02832 }
02833 else
02834 {
02835 m_radius = fabs( xwi );
02836 draghandle->SetPosXY( xwi, 0 );
02837 SetPending( true );
02838 }
02839 }
02840 else
02841 event.Skip();
02842 SetPending( true );
02843 }
02844 }
02845 else
02846 {
02847 event.Skip();
02848 }
02849 }
02850 else
02851 {
02852 event.Skip();
02853 }
02854 }
02855
02856 a2dBoundingBox a2dRect::DoGetUnTransformedBbox( a2dBboxFlags flags ) const
02857 {
02858 a2dBoundingBox bbox;
02859 bbox.Expand( 0, 0);
02860 bbox.Expand( m_width , m_height );
02861
02862 if ( !(flags & a2dCANOBJ_BBOX_EDIT ) )
02863 {
02864 if (m_radius > 0)
02865 bbox.Enlarge( m_radius );
02866
02867 if (m_contourwidth > 0)
02868 bbox.Enlarge( m_contourwidth/2 );
02869 }
02870 return bbox;
02871 }
02872
02873 void a2dRect::DoRender( a2dIterC& ic, OVERLAP clipparent )
02874 {
02875 if ( m_contourwidth )
02876 {
02877 a2dCanvasObjectList* vectorpaths = GetAsCanvasVpaths( false );
02878
02879 forEachIn( a2dCanvasObjectList, vectorpaths )
02880 {
02881 a2dVectorPath* obj = wxStaticCast( (*iter).Get(), a2dVectorPath );
02882 obj->DoRender( ic, clipparent );
02883 }
02884 delete vectorpaths;
02885 }
02886 else
02887 {
02888 if (m_radius<=0)
02889 {
02890 if ( m_flags.m_editingCopy )
02891 ic.GetDrawer2D()->DrawRoundedRectangle( 0, 0, m_width, m_height, -m_radius);
02892 else
02893 ic.GetDrawer2D()->DrawRoundedRectangle( 0, 0, m_width, m_height, -m_radius);
02894 }
02895 else
02896 {
02897 ic.GetDrawer2D()->DrawRoundedRectangle( -m_radius, -m_radius, m_width+2*m_radius, m_height+2*m_radius, m_radius);
02898 }
02899 }
02900 }
02901
02902 #if wxART2D_USE_CVGIO
02903
02904 void a2dRect::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
02905 {
02906 a2dWH::DoSave( parent, out, xmlparts, towrite );
02907 if ( xmlparts == a2dXmlSer_attrib )
02908 {
02909 if (m_radius != 0.0)
02910 {
02911 out.WriteAttribute( wxT("radius"), m_radius );
02912 out.WriteAttribute( wxT("contourwidth"), m_contourwidth );
02913 }
02914 }
02915 else
02916 {
02917 }
02918 }
02919
02920 void a2dRect::DoLoad( wxObject* parent, a2dIOHandlerXmlSerIn& parser, a2dXmlSer_flag xmlparts )
02921 {
02922 a2dWH::DoLoad( parent, parser, xmlparts );
02923 if ( xmlparts == a2dXmlSer_attrib )
02924 {
02925 m_radius = parser.GetAttributeValueDouble( wxT("radius") );
02926 m_contourwidth = parser.GetAttributeValueDouble( wxT("contourwidth"), 0 );
02927 }
02928 else
02929 {
02930 }
02931 }
02932 #endif //wxART2D_USE_CVGIO
02933
02934 bool a2dRect::DoIsHitWorld( a2dIterC& ic, a2dHitEvent& hitEvent )
02935 {
02936 double margin = ic.GetTransformedHitMargin();
02937
02938 double xmin = wxMin( 0 , m_width);
02939 double ymin = wxMin( 0 , m_height);
02940 double xmax = wxMax( 0 , m_width);
02941 double ymax = wxMax( 0 , m_height);
02942
02943 if (m_radius > 0)
02944 {
02945 xmin -= m_radius;
02946 ymin -= m_radius;
02947 xmax += m_radius;
02948 ymax += m_radius;
02949 }
02950
02951 hitEvent.m_how = HitTestRectangle( hitEvent.m_relx, hitEvent.m_rely, xmin, ymin, xmax, ymax, ic.GetWorldStrokeExtend() + margin + m_contourwidth );
02952
02953 return hitEvent.m_how.IsHit();
02954 }
02955
02956 void a2dRect::EditFeedback( a2dIterC& ic, const a2dFeedbackId *id, a2dCanvasObject *currentEdit, int depth, a2dCanvasObjectFlagsMask flags, double x, double y )
02957 {
02958 a2dCanvasObject::EditFeedback( ic, id, currentEdit, depth, flags, x, y );
02959 }
02960
02961 bool a2dRect::GeneratePins( a2dPinClass* toConnectTo, a2dConnectTask task, double WXUNUSED(x), double WXUNUSED(y) )
02962 {
02963 a2dPinClass* toCreate;
02964 if ( GetGeneratePins() && (toCreate = toConnectTo->GetPinClassForTask( task, this )) )
02965 {
02966 m_flags.m_visiblechilds = true;
02967 a2dPin *newPin = NULL;
02968 if ( !HasPinNamed( wxT("pinc*"), true) )
02969 {
02970 newPin = AddPin( wxT("pinc"), m_width/2, m_height/2, a2dPin::temporaryObjectPin, toCreate );
02971 newPin->SetInternal( true );
02972 }
02973 if ( !HasPinNamed( wxT("pin1"), true) )
02974 AddPin( wxT("pin1"), 0, 0, a2dPin::temporaryObjectPin, toCreate );
02975 if ( !HasPinNamed( wxT("pin2"), true) )
02976 AddPin( wxT("pin2"), 0, m_height/2, a2dPin::temporaryObjectPin, toCreate );
02977 if ( !HasPinNamed( wxT("pin3"), true) )
02978 AddPin( wxT("pin3"), 0, m_height, a2dPin::temporaryObjectPin, toCreate );
02979 if ( !HasPinNamed( wxT("pin4"), true) )
02980 AddPin( wxT("pin4"), m_width/2, m_height , a2dPin::temporaryObjectPin, toCreate );
02981 if ( !HasPinNamed( wxT("pin5"), true) )
02982 AddPin( wxT("pin5"), m_width, m_height , a2dPin::temporaryObjectPin, toCreate );
02983 if ( !HasPinNamed( wxT("pin6"), true) )
02984 AddPin( wxT("pin6"), m_width, m_height/2 , a2dPin::temporaryObjectPin, toCreate );
02985 if ( !HasPinNamed( wxT("pin7"), true) )
02986 AddPin( wxT("pin7"), m_width, 0, a2dPin::temporaryObjectPin, toCreate );
02987 if ( !HasPinNamed( wxT("pin8"), true) )
02988 AddPin( wxT("pin8"), m_width/2, 0, a2dPin::temporaryObjectPin, toCreate );
02989
02990
02991
02992
02993
02994
02995
02996
02997
02998
02999
03000 wxASSERT( HasPins(true) );
03001 m_childobjects->SetSpecificFlags( false, a2dCanvasOFlags::PRERENDERASCHILD, wxT("a2dPin") );
03002 return true;
03003 }
03004 return false;
03005 }
03006
03007
03008
03009
03010
03011 a2dPropertyIdDouble* a2dCircle::PROPID_Radius = NULL;
03012
03013 INITIALIZE_PROPERTIES( a2dCircle, a2dCanvasObject )
03014 {
03015 PROPID_Radius = new a2dPropertyIdDouble( wxT("Radius"),
03016 a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dCircle::m_radius) );
03017 AddPropertyId( PROPID_Radius );
03018
03019 return true;
03020 }
03021
03022 a2dCircle::a2dCircle()
03023 : a2dCanvasObject()
03024 {
03025 m_radius = 0;
03026 m_contourwidth = 0;
03027 }
03028
03029 a2dCircle::a2dCircle( double x, double y, double radius, double width )
03030 : a2dCanvasObject()
03031 {
03032 m_lworld.Translate(x,y);
03033 m_radius = radius;
03034 m_contourwidth = width;
03035 }
03036
03037 a2dCircle::~a2dCircle()
03038 {
03039 }
03040
03041 a2dCircle::a2dCircle( const a2dCircle &other, CloneOptions options )
03042 :a2dCanvasObject( other, options )
03043 {
03044 m_radius = other.m_radius;
03045 m_contourwidth = other.m_contourwidth;
03046 }
03047
03048 a2dObject* a2dCircle::Clone( CloneOptions options ) const
03049 {
03050 return new a2dCircle( *this, options );
03051 }
03052
03053 a2dVertexList* a2dCircle::GetAsPolygon()
03054 {
03055 a2dVertexList* pointlist = new a2dVertexList();
03056
03057 a2dCanvasObjectList* vectorpaths = GetAsCanvasVpaths();
03058 a2dVpath* segments = wxStaticCast( vectorpaths->front().Get(), a2dVectorPath ) ->GetSegments();
03059 segments->ConvertToLines();
03060 a2dLineSegment* point;
03061 unsigned int i;
03062 for (i=0; i < segments->GetCount();i++)
03063 {
03064 a2dVpathSegment& seg = segments->Item(i);
03065 point = new a2dLineSegment(seg.m_x1, seg.m_y1);
03066 pointlist->push_back(point);
03067 }
03068
03069 delete vectorpaths;
03070
03071 return pointlist;
03072 }
03073
03074 a2dCanvasObjectList* a2dCircle::GetAsCanvasVpaths( bool transform )
03075 {
03076 a2dAffineMatrix pworld;
03077 if ( transform )
03078 pworld = m_lworld;
03079
03080 a2dVpath* segments = new a2dVpath();
03081
03082 if (m_contourwidth)
03083 {
03084 double w2 = m_contourwidth/2;
03085 a2dVpathSegment* seg = new a2dVpathSegment( 0, m_radius + w2, a2dPATHSEG_MOVETO );
03086 segments->push_back(seg);
03087 seg = new a2dVpathArcSegment( 0, -m_radius - w2, m_radius + w2, 0, a2dPATHSEG_ARCTO );
03088 segments->push_back(seg);
03089 seg = new a2dVpathArcSegment( 0, m_radius + w2, -m_radius - w2, 0, a2dPATHSEG_ARCTO );
03090 segments->push_back(seg);
03091
03092 seg = new a2dVpathSegment( 0, m_radius - w2, a2dPATHSEG_LINETO_NOSTROKE );
03093 segments->push_back(seg);
03094
03095 seg = new a2dVpathArcSegment( 0, -m_radius + w2, -m_radius + w2, 0, a2dPATHSEG_ARCTO );
03096 segments->push_back(seg);
03097 seg = new a2dVpathArcSegment( 0, m_radius - w2, m_radius - w2, 0, a2dPATHSEG_ARCTO );
03098 segments->push_back(seg);
03099
03100 seg = new a2dVpathSegment( 0, m_radius + w2, a2dPATHSEG_LINETO_NOSTROKE, a2dPATHSEG_END_CLOSED );
03101 segments->push_back(seg);
03102 }
03103 else
03104 {
03105 a2dVpathSegment* seg = new a2dVpathSegment( 0, m_radius, a2dPATHSEG_MOVETO );
03106 segments->push_back(seg);
03107 seg = new a2dVpathArcSegment( 0, -m_radius, m_radius, 0, a2dPATHSEG_ARCTO );
03108 segments->push_back(seg);
03109 seg = new a2dVpathArcSegment( 0, m_radius, -m_radius, 0, a2dPATHSEG_ARCTO, a2dPATHSEG_END_CLOSED );
03110 segments->push_back(seg);
03111 }
03112 segments->Transform( pworld );
03113
03114 a2dVectorPath* canpath = new a2dVectorPath( segments );
03115 canpath->SetStroke( this->GetStroke() );
03116 canpath->SetFill( this->GetFill() );
03117 canpath->SetLayer( m_layer );
03118
03119 a2dCanvasObjectList* canpathlist = new a2dCanvasObjectList();
03120 canpathlist->push_back( canpath );
03121 return canpathlist;
03122 }
03123
03124 a2dBoundingBox a2dCircle::DoGetUnTransformedBbox( a2dBboxFlags flags ) const
03125 {
03126 a2dBoundingBox bbox;
03127
03128 bbox.Expand( -m_radius, -m_radius );
03129 bbox.Expand( m_radius, m_radius );
03130
03131 if ( !(flags & a2dCANOBJ_BBOX_EDIT ) )
03132 {
03133 if (m_contourwidth > 0)
03134 bbox.Enlarge( m_contourwidth/2 );
03135 }
03136
03137 return bbox;
03138 }
03139
03140 bool a2dCircle::DoUpdate( UpdateMode mode, const a2dBoundingBox& childbox, const a2dBoundingBox& clipbox, const a2dBoundingBox& propbox )
03141 {
03142
03143
03144 if ( !m_bbox.GetValid())
03145 {
03146 double rad = m_radius + m_contourwidth/2;
03147
03148 double alphax = atan2( m_lworld.GetValue( 1, 0 ), m_lworld.GetValue( 0, 0 ) );
03149 double alphay = atan2( m_lworld.GetValue( 1, 1 ), m_lworld.GetValue( 0, 1 ) );
03150
03151 double x,y;
03152 m_lworld.TransformPoint( rad * cos (alphax), rad * sin (alphax), x, y );
03153 m_bbox.Expand( x, y );
03154 m_lworld.TransformPoint( rad * -cos (alphax ), rad * -sin (alphax), x, y );
03155 m_bbox.Expand( x, y );
03156
03157 m_lworld.TransformPoint( rad * cos (alphay), rad * sin (alphay), x, y );
03158 m_bbox.Expand( x, y );
03159 m_lworld.TransformPoint( rad * -cos (alphay), rad * -sin (alphay), x, y );
03160 m_bbox.Expand( x, y );
03161
03162 return true;
03163 }
03164
03165 return false;
03166 }
03167
03168 void a2dCircle::DoRender( a2dIterC& ic, OVERLAP clipparent )
03169 {
03170 if ( m_contourwidth )
03171 {
03172 a2dCanvasObjectList* vectorpaths = GetAsCanvasVpaths( false );
03173
03174 forEachIn( a2dCanvasObjectList, vectorpaths )
03175 {
03176 a2dVectorPath* obj = wxStaticCast( (*iter).Get(), a2dVectorPath );
03177 obj->DoRender( ic, clipparent );
03178 }
03179 delete vectorpaths;
03180 }
03181 else
03182 ic.GetDrawer2D()->DrawCircle( 0, 0, m_radius);
03183 }
03184
03185 #if wxART2D_USE_CVGIO
03186 void a2dCircle::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
03187 {
03188 a2dCanvasObject::DoSave( parent, out, xmlparts, towrite );
03189 if ( xmlparts == a2dXmlSer_attrib )
03190 {
03191 out.WriteAttribute( wxT("radius"), m_radius );
03192 out.WriteAttribute( wxT("contourwidth"), m_contourwidth );
03193 }
03194 else
03195 {
03196 }
03197 }
03198
03199 void a2dCircle::DoLoad( wxObject* parent, a2dIOHandlerXmlSerIn& parser, a2dXmlSer_flag xmlparts )
03200 {
03201 a2dCanvasObject::DoLoad( parent, parser, xmlparts );
03202 if ( xmlparts == a2dXmlSer_attrib )
03203 {
03204 m_radius = parser.RequireAttributeValueDouble( wxT("radius") );
03205 m_contourwidth = parser.GetAttributeValueDouble( wxT("contourwidth"), 0 );
03206 }
03207 else
03208 {
03209 }
03210 }
03211 #endif //wxART2D_USE_CVGIO
03212
03213 bool a2dCircle::DoIsHitWorld( a2dIterC& ic, a2dHitEvent& hitEvent )
03214 {
03215 double pw = ic.GetWorldStrokeExtend();
03216 double margin = ic.GetTransformedHitMargin();
03217 double r = sqrt((hitEvent.m_relx*hitEvent.m_relx)+(hitEvent.m_rely*hitEvent.m_rely));
03218
03219 if ( m_contourwidth )
03220 {
03221
03222 if (m_radius+pw+ m_contourwidth/2 +margin > r )
03223 {
03224
03225 if (m_radius - m_contourwidth/2 -pw - margin > r )
03226 {
03227 hitEvent.m_how = a2dHit::stock_nohit;
03228 return false;
03229 }
03230
03231
03232 if (m_radius + m_contourwidth/2 < r )
03233 hitEvent.m_how = a2dHit::stock_strokeoutside;
03234 else if (m_radius - m_contourwidth/2 < r )
03235 {
03236 if (m_radius + m_contourwidth/2 -pw - margin > r &&
03237 m_radius - m_contourwidth/2 +pw + margin < r
03238 )
03239 hitEvent.m_how = a2dHit::stock_fill;
03240 else
03241 hitEvent.m_how = a2dHit::stock_strokeinside;
03242 }
03243 else
03244 hitEvent.m_how = a2dHit::stock_strokeoutside;
03245
03246 return true;
03247 }
03248 else
03249 {
03250 hitEvent.m_how = a2dHit::stock_nohit;
03251 return false;
03252 }
03253 }
03254 else
03255 {
03256 if (m_radius+pw+margin > r)
03257 {
03258 if (m_radius-pw-margin > r)
03259 hitEvent.m_how = a2dHit::stock_fill;
03260 else if (m_radius > r)
03261 hitEvent.m_how = a2dHit::stock_strokeinside;
03262 else
03263 hitEvent.m_how = a2dHit::stock_strokeoutside;
03264 wxMouseEvent* mouse = wxDynamicCast( hitEvent.m_event, wxMouseEvent );
03265
03266
03267
03268
03269
03270
03271
03272
03273
03274 return true;
03275 }
03276 else
03277 {
03278
03279 hitEvent.m_how = a2dHit::stock_nohit;
03280 return false;
03281 }
03282 }
03283 }
03284
03285 bool a2dCircle::DoStartEdit( wxUint16 editmode, wxEditStyle editstyle )
03286 {
03287 if ( m_flags.m_editable )
03288 {
03289 PROPID_IncludeChildren->SetPropertyToObject( this, false );
03290 return a2dCanvasObject::DoStartEdit( editmode, editstyle );
03291 }
03292
03293 return false;
03294 }
03295
03296 bool a2dCircle::GeneratePins( a2dPinClass* toConnectTo, a2dConnectTask task, double WXUNUSED(x), double WXUNUSED(y) )
03297 {
03298 a2dPinClass* toCreate;
03299 if ( GetGeneratePins() && (toCreate = toConnectTo->GetPinClassForTask( task, this )) )
03300 {
03301 double radsrt2 = sqrt( wxSqr(m_radius/2) + wxSqr(m_radius/2) );
03302 m_flags.m_visiblechilds = true;
03303 a2dPin *newPin = NULL;
03304 if ( !HasPinNamed( wxT("pinc*"), true) )
03305 {
03306 newPin = AddPin( wxT("pinc"), 0, 0, a2dPin::temporaryObjectPin, toCreate );
03307 newPin->SetInternal( true );
03308 }
03309 if ( !HasPinNamed( wxT("pin1")) )
03310 AddPin( wxT("pin1"), 0, m_radius, a2dPin::temporaryObjectPin, toCreate );
03311 if ( !HasPinNamed( wxT("pin2")) )
03312 AddPin( wxT("pin2"), radsrt2, radsrt2, a2dPin::temporaryObjectPin, toCreate );
03313 if ( !HasPinNamed( wxT("pin3")) )
03314 AddPin( wxT("pin3"), m_radius, 0, a2dPin::temporaryObjectPin, toCreate );
03315 if ( !HasPinNamed( wxT("pin4")) )
03316 AddPin( wxT("pin4"), radsrt2, -radsrt2 , a2dPin::temporaryObjectPin, toCreate );
03317 if ( !HasPinNamed( wxT("pin5")) )
03318 AddPin( wxT("pin5"), 0, -m_radius , a2dPin::temporaryObjectPin, toCreate );
03319 if ( !HasPinNamed( wxT("pin6")) )
03320 AddPin( wxT("pin6"), -radsrt2, -radsrt2 , a2dPin::temporaryObjectPin, toCreate );
03321 if ( !HasPinNamed( wxT("pin7")) )
03322 AddPin( wxT("pin7"), -m_radius, 0, a2dPin::temporaryObjectPin, toCreate );
03323 if ( !HasPinNamed( wxT("pin8")) )
03324 AddPin( wxT("pin8"), -radsrt2, radsrt2, a2dPin::temporaryObjectPin, toCreate );
03325
03326 wxASSERT( HasPins(true) );
03327 m_childobjects->SetSpecificFlags( false, a2dCanvasOFlags::PRERENDERASCHILD, wxT("a2dPin") );
03328
03329 return true;
03330 }
03331 return false;
03332 }
03333
03334
03335
03336
03337
03338 a2dEllipse::a2dEllipse()
03339 : a2dWHCenter()
03340 {
03341 m_contourwidth = 0;
03342 }
03343
03344 a2dEllipse::a2dEllipse( double xc, double yc, double width, double height, double contourwidth )
03345 : a2dWHCenter( xc, yc, width, height )
03346 {
03347 m_contourwidth = contourwidth;
03348 }
03349
03350 a2dEllipse::~a2dEllipse()
03351 {
03352 }
03353
03354 a2dEllipse::a2dEllipse( const a2dEllipse &other, CloneOptions options )
03355 :a2dWHCenter( other, options )
03356 {
03357 m_contourwidth = other.m_contourwidth;
03358 }
03359
03360 a2dObject* a2dEllipse::Clone( CloneOptions options ) const
03361 {
03362 return new a2dEllipse( *this, options );
03363 };
03364
03365 a2dVertexList* a2dEllipse::GetAsPolygon()
03366 {
03367 a2dVertexList* pointlist = new a2dVertexList();
03368
03369 a2dCanvasObjectList* vectorpaths = GetAsCanvasVpaths();
03370 a2dVpath* segments = wxStaticCast( vectorpaths->front().Get(), a2dVectorPath ) ->GetSegments();
03371 segments->ConvertToLines();
03372 a2dLineSegment* point;
03373 unsigned int i;
03374 for (i=0; i < segments->GetCount();i++)
03375 {
03376 a2dVpathSegment& seg = segments->Item(i);
03377 point = new a2dLineSegment(seg.m_x1, seg.m_y1);
03378 pointlist->push_back(point);
03379 }
03380
03381 delete vectorpaths;
03382
03383 return pointlist;
03384 }
03385
03386 a2dCanvasObjectList* a2dEllipse::GetAsCanvasVpaths( bool transform )
03387 {
03388 a2dAffineMatrix pworld;
03389 if ( transform )
03390 pworld = m_lworld;
03391
03392
03393
03394 a2dVpath* segments = new a2dVpath();
03395
03396 double dphi = wxPI * 2.0 / CIRCLE_STEPS;
03397
03398 a2dVpathSegment* seg;
03399 double x,y;
03400 double theta;
03401 int i;
03402 for (i = 0; i < CIRCLE_STEPS; i++)
03403 {
03404 theta = i *dphi;
03405 pworld.TransformPoint( m_width/2 * cos (theta), -m_height/2 * sin (theta), x, y );
03406 if ( i == 0 )
03407 seg = new a2dVpathSegment( x, y , a2dPATHSEG_MOVETO );
03408 else if ( i == CIRCLE_STEPS - 1 )
03409 seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO, a2dPATHSEG_END_CLOSED );
03410 else
03411 seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
03412 segments->push_back(seg);
03413 }
03414
03415 a2dVectorPath* canpath = new a2dVectorPath( segments );
03416 canpath->SetStroke( this->GetStroke() );
03417 canpath->SetFill( this->GetFill() );
03418 canpath->SetLayer( m_layer );
03419 canpath->SetContourWidth( GetContourWidth() );
03420 canpath->SetPathType( a2dPATH_END_ROUND );
03421 a2dCanvasObjectList* canpathlist = new a2dCanvasObjectList();
03422 canpathlist->push_back( canpath );
03423 return canpathlist;
03424 }
03425
03426 a2dBoundingBox a2dEllipse::DoGetUnTransformedBbox( a2dBboxFlags flags ) const
03427 {
03428 a2dBoundingBox bbox;
03429
03430 bbox.Expand( -m_width/2, -m_height/2 );
03431 bbox.Expand( m_width/2, m_height/2 );
03432
03433 if ( !(flags & a2dCANOBJ_BBOX_EDIT ) )
03434 {
03435 if (m_contourwidth > 0)
03436 bbox.Enlarge( m_contourwidth/2 );
03437 }
03438
03439 return bbox;
03440 }
03441
03442 bool a2dEllipse::DoUpdate( UpdateMode mode, const a2dBoundingBox& childbox, const a2dBoundingBox& clipbox, const a2dBoundingBox& propbox )
03443 {
03444
03445
03446 if ( !m_bbox.GetValid())
03447 {
03448 double width = m_width + m_contourwidth/2;
03449 double height = m_height + m_contourwidth/2;
03450
03451 double alphax = atan2( m_lworld.GetValue( 1, 0 ) * height, m_lworld.GetValue( 0, 0 ) * width );
03452 double alphay = atan2( m_lworld.GetValue( 1, 1 ) * height, m_lworld.GetValue( 0, 1 ) * width );
03453
03454 double x,y;
03455 m_lworld.TransformPoint( width/2 * cos (alphax), height/2 * sin (alphax), x, y );
03456 m_bbox.Expand( x, y );
03457 m_lworld.TransformPoint( width/2 * -cos (alphax ), height/2 * -sin (alphax), x, y );
03458 m_bbox.Expand( x, y );
03459
03460 m_lworld.TransformPoint( width/2 * cos (alphay), height/2 * sin (alphay), x, y );
03461 m_bbox.Expand( x, y );
03462 m_lworld.TransformPoint( width/2 * -cos (alphay), height/2 * -sin (alphay), x, y );
03463 m_bbox.Expand( x, y );
03464
03465 return true;
03466 }
03467 return false;
03468 }
03469
03470 void a2dEllipse::DoRender( a2dIterC& ic, OVERLAP clipparent )
03471 {
03472 if ( GetContourWidth() )
03473 {
03474 a2dCanvasObjectList* vectorpaths = GetAsCanvasVpaths( false );
03475
03476 forEachIn( a2dCanvasObjectList, vectorpaths )
03477 {
03478 a2dVectorPath* obj = wxStaticCast( (*iter).Get(), a2dVectorPath );
03479 obj->DoRender( ic, clipparent );
03480 }
03481 delete vectorpaths;
03482 }
03483 else
03484 ic.GetDrawer2D()->DrawEllipse( 0, 0, m_width, m_height);
03485 }
03486
03487 #if wxART2D_USE_CVGIO
03488 void a2dEllipse::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
03489 {
03490 a2dWHCenter::DoSave( parent, out, xmlparts, towrite );
03491 if ( xmlparts == a2dXmlSer_attrib )
03492 {
03493 out.WriteAttribute( wxT("contourwidth"), m_contourwidth );
03494 }
03495 else
03496 {
03497 }
03498 }
03499
03500 void a2dEllipse::DoLoad( wxObject* parent, a2dIOHandlerXmlSerIn& parser, a2dXmlSer_flag xmlparts )
03501 {
03502 a2dWHCenter::DoLoad( parent, parser, xmlparts );
03503 if ( xmlparts == a2dXmlSer_attrib )
03504 {
03505 m_contourwidth = parser.GetAttributeValueDouble( wxT("contourwidth"), 0 );
03506 }
03507 else
03508 {
03509 }
03510 }
03511 #endif //wxART2D_USE_CVGIO
03512
03513 bool a2dEllipse::DoIsHitWorld( a2dIterC& ic, a2dHitEvent& hitEvent )
03514 {
03515 double xh = hitEvent.m_relx;
03516 double yh = hitEvent.m_rely;
03517
03518 double pw = ic.GetWorldStrokeExtend();
03519 double margin = ic.GetTransformedHitMargin();
03520
03521 double a = 0.5*m_width + pw + margin ;
03522 double b = 0.5*m_height + pw + margin;
03523 double c = wxSqr(xh/a) + wxSqr(yh/b);
03524 if ( 1 > c)
03525 {
03526 a = 0.5*m_width - pw - margin ;
03527 b = 0.5*m_height - pw - margin;
03528 c = wxSqr(xh/a) + wxSqr(yh/b);
03529
03530 if( 1 > c )
03531 {
03532 hitEvent.m_how = a2dHit::stock_fill;
03533 return true;
03534 }
03535
03536 a = 0.5*m_width;
03537 b = 0.5*m_height;
03538 c = wxSqr(xh/a) + wxSqr(yh/b);
03539
03540 if( 1 > c )
03541 {
03542 hitEvent.m_how = a2dHit::stock_strokeinside;
03543 return true;
03544 }
03545 else
03546 {
03547 hitEvent.m_how = a2dHit::stock_strokeoutside;
03548 return true;
03549 }
03550
03551 }
03552 else
03553 {
03554 hitEvent.m_how = a2dHit::stock_nohit;
03555 return false;
03556 }
03557 }
03558
03559 bool a2dEllipse::DoStartEdit( wxUint16 editmode, wxEditStyle editstyle )
03560 {
03561 if ( m_flags.m_editable )
03562 {
03563 PROPID_IncludeChildren->SetPropertyToObject( this, false );
03564 return a2dWHCenter::DoStartEdit( editmode, editstyle );
03565 }
03566
03567 return false;
03568 }
03569
03570 bool a2dEllipse::GeneratePins( a2dPinClass* toConnectTo, a2dConnectTask task, double WXUNUSED(x), double WXUNUSED(y) )
03571 {
03572 a2dPinClass* toCreate;
03573 if ( GetGeneratePins() && (toCreate = toConnectTo->GetPinClassForTask( task, this )) )
03574 {
03575 double rx2 = m_width/2 * cos( wxDegToRad( 45 ) );
03576 double ry2 = m_height/2 * sin( wxDegToRad( 45 ) );
03577
03578 m_flags.m_visiblechilds = true;
03579 a2dPin *newPin = NULL;
03580 if ( !HasPinNamed( wxT("pinc*"), true) )
03581 {
03582 newPin = AddPin( wxT("pinc"), 0, 0, a2dPin::temporaryObjectPin, toCreate );
03583 newPin->SetInternal( true );
03584 }
03585 if ( !HasPinNamed( wxT("pin1")) )
03586 AddPin( wxT("pin1"), 0, m_height/2, a2dPin::temporaryObjectPin, toCreate );
03587 if ( !HasPinNamed( wxT("pin2")) )
03588 AddPin( wxT("pin2"), rx2, ry2, a2dPin::temporaryObjectPin, toCreate );
03589 if ( !HasPinNamed( wxT("pin3")) )
03590 AddPin( wxT("pin3"), m_width/2, 0, a2dPin::temporaryObjectPin, toCreate );
03591 if ( !HasPinNamed( wxT("pin4")) )
03592 AddPin( wxT("pin4"), rx2, -ry2, a2dPin::temporaryObjectPin, toCreate );
03593 if ( !HasPinNamed( wxT("pin5")) )
03594 AddPin( wxT("pin5"), 0, -m_height/2, a2dPin::temporaryObjectPin, toCreate );
03595 if ( !HasPinNamed( wxT("pin6")) )
03596 AddPin( wxT("pin6"), -rx2, -ry2 , a2dPin::temporaryObjectPin, toCreate );
03597 if ( !HasPinNamed( wxT("pin7")) )
03598 AddPin( wxT("pin7"), -m_width/2, 0, a2dPin::temporaryObjectPin, toCreate );
03599 if ( !HasPinNamed( wxT("pin8")) )
03600 AddPin( wxT("pin8"), -rx2, ry2, a2dPin::temporaryObjectPin, toCreate );
03601
03602 wxASSERT( HasPins(true) );
03603 m_childobjects->SetSpecificFlags( false, a2dCanvasOFlags::PRERENDERASCHILD, wxT("a2dPin") );
03604
03605 return true;
03606 }
03607 return false;
03608 }
03609
03610
03611
03612
03613 a2dPropertyIdDouble* a2dEllipticArc::PROPID_StartAngle = NULL;
03614 a2dPropertyIdDouble* a2dEllipticArc::PROPID_EndAngle = NULL;
03615 a2dPropertyIdBool* a2dEllipticArc::PROPID_Chord = NULL;
03616
03617 INITIALIZE_PROPERTIES( a2dEllipticArc, a2dWHCenter )
03618 {
03619 PROPID_StartAngle = new a2dPropertyIdDouble( wxT("StartAngle"),
03620 a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dEllipticArc::m_start) );
03621 AddPropertyId( PROPID_StartAngle );
03622 PROPID_EndAngle = new a2dPropertyIdDouble( wxT("EndAngle"),
03623 a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dEllipticArc::m_end) );
03624 AddPropertyId( PROPID_EndAngle );
03625 PROPID_Chord = new a2dPropertyIdBool( wxT("Radius"),
03626 a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdBool::Mptr >( &a2dEllipticArc::m_chord) );
03627 AddPropertyId( PROPID_Chord );
03628
03629 return true;
03630 }
03631
03632 A2D_BEGIN_EVENT_TABLE( a2dEllipticArc, a2dWHCenter )
03633 A2D_EVT_CANVASHANDLE_MOUSE_EVENT( a2dEllipticArc::OnHandleEvent )
03634 A2D_EVT_CHAR( a2dEllipticArc::OnChar )
03635 A2D_END_EVENT_TABLE()
03636
03637 a2dEllipticArc::a2dEllipticArc()
03638 : a2dWHCenter()
03639 {
03640 m_start = 0;
03641 m_end = 0;
03642 m_chord = false;
03643 m_contourwidth = 0;
03644 }
03645
03646 a2dEllipticArc::a2dEllipticArc( double xc, double yc, double width, double height, double start, double end, bool chord, double contourwidth )
03647 : a2dWHCenter( xc, yc, width, height )
03648 {
03649 m_start = start;
03650 m_end = end;
03651 m_chord = chord;
03652 m_contourwidth = contourwidth;
03653 }
03654
03655 a2dEllipticArc::~a2dEllipticArc()
03656 {
03657 }
03658
03659 a2dEllipticArc::a2dEllipticArc( const a2dEllipticArc &other, CloneOptions options )
03660 :a2dWHCenter( other, options )
03661 {
03662 m_start = other.m_start;
03663 m_end = other.m_end;
03664 m_chord = other.m_chord;
03665 m_contourwidth = other.m_contourwidth;
03666 }
03667
03668 void a2dEllipticArc::SetChord( bool chord )
03669 {
03670 m_chord = chord;
03671 SetPending(true);
03672 }
03673
03674 a2dObject* a2dEllipticArc::Clone( CloneOptions options ) const
03675 {
03676 return new a2dEllipticArc( *this, options );
03677 };
03678
03679 a2dVertexList* a2dEllipticArc::GetAsPolygon()
03680 {
03681 a2dVertexList* pointlist = new a2dVertexList();
03682
03683 a2dCanvasObjectList* vectorpaths = GetAsCanvasVpaths();
03684 a2dVpath* segments = wxStaticCast( vectorpaths->front().Get(), a2dVectorPath ) ->GetSegments();
03685 segments->ConvertToLines();
03686 a2dLineSegment* point;
03687 unsigned int i;
03688 for (i=0; i < segments->GetCount();i++)
03689 {
03690 a2dVpathSegment& seg = segments->Item(i);
03691 point = new a2dLineSegment(seg.m_x1, seg.m_y1);
03692 pointlist->push_back(point);
03693 }
03694
03695 delete vectorpaths;
03696
03697 return pointlist;
03698 }
03699
03700 a2dCanvasObjectList* a2dEllipticArc::GetAsCanvasVpaths( bool transform )
03701 {
03702 a2dAffineMatrix pworld;
03703 if ( transform )
03704 pworld = m_lworld;
03705
03706
03707
03708 a2dVpath* segments = new a2dVpath();
03709
03710 double start,end;
03711
03712 start = wxDegToRad(m_start);
03713 end = wxDegToRad(m_end);
03714
03715 end = end-start;
03716 if (end <= 0) end += 2.0*wxPI;
03717
03718 if (start < 0) start += 2.0*wxPI;
03719
03720 end=end+start;
03721
03722 double dphi = wxPI * 2.0 / CIRCLE_STEPS;
03723 int steps = (int)((end-start)/dphi);
03724 if (steps == 0)
03725 steps = 1;
03726 dphi = (end-start)/steps;
03727
03728 a2dVpathSegment* seg;
03729
03730 double theta = start;
03731 int i;
03732 double x,y;
03733 for (i = 0; i < steps+1; i++)
03734 {
03735 pworld.TransformPoint( m_width/2 * cos (theta), m_height/2 * sin (theta), x, y );
03736 if ( i == 0 )
03737 seg = new a2dVpathSegment( x, y , a2dPATHSEG_MOVETO );
03738 else
03739 seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
03740 segments->push_back(seg);
03741 theta = theta + dphi;
03742 }
03743
03744 if (!m_chord)
03745 {
03746 pworld.TransformPoint( 0, 0, x, y );
03747 seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO, a2dPATHSEG_END_CLOSED );
03748 segments->push_back(seg);
03749 }
03750
03751 a2dVectorPath* canpath = new a2dVectorPath( segments );
03752 canpath->SetStroke( this->GetStroke() );
03753 canpath->SetFill( this->GetFill() );
03754 canpath->SetLayer( m_layer );
03755 canpath->SetContourWidth( GetContourWidth() );
03756 canpath->SetPathType( a2dPATH_END_ROUND );
03757 a2dCanvasObjectList* canpathlist = new a2dCanvasObjectList();
03758 canpathlist->push_back( canpath );
03759 return canpathlist;
03760 }
03761
03762 a2dBoundingBox a2dEllipticArc::DoGetUnTransformedBbox( a2dBboxFlags flags ) const
03763 {
03764 a2dBoundingBox bbox;
03765
03766 double start,end;
03767
03768 start = wxDegToRad(m_start);
03769 end = wxDegToRad(m_end);
03770
03771 if ( !m_chord )
03772 bbox.Expand( 0, 0 );
03773
03774 bbox.Expand( m_width/2 * cos (start), m_height/2 * sin (start) );
03775
03776 bbox.Expand( m_width/2 * cos (end), m_height/2 * sin (end) );
03777
03778
03779 if ( InArc( 0, start, end, false ) )
03780 bbox.Expand( m_width/2, 0 );
03781 if ( InArc( wxPI/2, start, end, false ) )
03782 bbox.Expand( 0, m_height/2 );
03783 if ( InArc( wxPI, start, end, false ) )
03784 bbox.Expand( -m_width/2, 0 );
03785 if ( InArc( 1.5*wxPI, start, end, false ) )
03786 bbox.Expand( 0, -m_height/2 );
03787
03788 if ( !(flags & a2dCANOBJ_BBOX_EDIT ) )
03789 {
03790 if (m_contourwidth > 0)
03791 bbox.Enlarge( m_contourwidth/2 );
03792 }
03793
03794 return bbox;
03795 }
03796
03797 bool a2dEllipticArc::DoUpdate( UpdateMode mode, const a2dBoundingBox& childbox, const a2dBoundingBox& clipbox, const a2dBoundingBox& propbox )
03798 {
03799
03800
03801 if ( !m_bbox.GetValid())
03802 {
03803 double width = m_width + m_contourwidth/2;
03804 double height = m_height + m_contourwidth/2;
03805
03806 double alphax = atan2( m_lworld.GetValue( 1, 0 ) * height, m_lworld.GetValue( 0, 0 ) * width );
03807 double alphay = atan2( m_lworld.GetValue( 1, 1 ) * height, m_lworld.GetValue( 0, 1 ) * width );
03808
03809 double x,y;
03810
03811 double start,end;
03812
03813 start = wxDegToRad(m_start);
03814 end = wxDegToRad(m_end);
03815
03816
03817
03818
03819
03820
03821
03822 m_lworld.TransformPoint( width/2 * cos (start), height/2 * sin (start), x, y );
03823 m_bbox.Expand( x, y );
03824
03825 m_lworld.TransformPoint( width/2 * cos (end), height/2 * sin (end), x, y );
03826 m_bbox.Expand( x, y );
03827
03828 if (!m_chord)
03829 {
03830 m_lworld.TransformPoint( 0, 0, x, y );
03831 m_bbox.Expand( x, y );
03832 }
03833
03834
03835 if ( InArc( alphax, start, end, false ) )
03836 {
03837 m_lworld.TransformPoint( width/2 * cos (alphax), height/2 * sin (alphax), x, y );
03838 m_bbox.Expand( x, y );
03839 }
03840 alphax += wxPI;
03841 if ( InArc( alphax, start, end, false ) )
03842 {
03843 m_lworld.TransformPoint( width/2 * cos (alphax), height/2 * sin (alphax), x, y );
03844 m_bbox.Expand( x, y );
03845 }
03846 alphax -= 2*wxPI;
03847 if ( InArc( alphax, start, end, false ) )
03848 {
03849 m_lworld.TransformPoint( width/2 * cos (alphax), height/2 * sin (alphax), x, y );
03850 m_bbox.Expand( x, y );
03851 }
03852 if ( InArc( alphay, start, end, false ) )
03853 {
03854 m_lworld.TransformPoint( width/2 * cos (alphay), height/2 * sin (alphay), x, y );
03855 m_bbox.Expand( x, y );
03856 }
03857 alphay += wxPI;
03858 if ( InArc( alphay, start, end, false ) )
03859 {
03860 m_lworld.TransformPoint( width/2 * cos (alphay), height/2 * sin (alphay), x, y );
03861 m_bbox.Expand( x, y );
03862 }
03863 alphay -= 2*wxPI;
03864 if ( InArc( alphay, start, end, false ) )
03865 {
03866 m_lworld.TransformPoint( width/2 * cos (alphay), height/2 * sin (alphay), x, y );
03867 m_bbox.Expand( x, y );
03868 }
03869
03870 return true;
03871 }
03872 return false;
03873 }
03874
03875 void a2dEllipticArc::DoRender( a2dIterC& ic, OVERLAP clipparent )
03876 {
03877 if ( GetContourWidth() )
03878 {
03879 if ( m_flags.m_editingCopy && m_chord)
03880 m_chord = false;
03881
03882 a2dCanvasObjectList* vectorpaths = GetAsCanvasVpaths( false );
03883
03884 if ( m_flags.m_editingCopy && m_chord)
03885 m_chord = true;
03886
03887 forEachIn( a2dCanvasObjectList, vectorpaths )
03888 {
03889 a2dVectorPath* obj = wxStaticCast( (*iter).Get(), a2dVectorPath );
03890 obj->DoRender( ic, clipparent );
03891 }
03892 delete vectorpaths;
03893 }
03894 else
03895 {
03896 if ( m_flags.m_editingCopy && m_chord)
03897 {
03898 m_chord = false;
03899 ic.GetDrawer2D()->DrawEllipticArc( 0, 0 ,m_width, m_height, m_start, m_end, m_chord );
03900 m_chord = true;
03901 }
03902 else
03903 ic.GetDrawer2D()->DrawEllipticArc( 0, 0 ,m_width, m_height, m_start, m_end, m_chord );
03904 }
03905 }
03906
03907 #if wxART2D_USE_CVGIO
03908 void a2dEllipticArc::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
03909 {
03910 a2dWHCenter::DoSave( parent, out, xmlparts, towrite );
03911 if ( xmlparts == a2dXmlSer_attrib )
03912 {
03913 out.WriteAttribute( wxT("start"), m_start );
03914 out.WriteAttribute( wxT("end"), m_end );
03915 out.WriteAttribute( wxT("chord"), m_chord );
03916 out.WriteAttribute( wxT("contourwidth"), m_contourwidth );
03917 }
03918 else
03919 {
03920 }
03921 }
03922
03923 void a2dEllipticArc::DoLoad( wxObject* parent, a2dIOHandlerXmlSerIn& parser, a2dXmlSer_flag xmlparts )
03924 {
03925 a2dWHCenter::DoLoad( parent, parser, xmlparts );
03926 if ( xmlparts == a2dXmlSer_attrib )
03927 {
03928 m_start = parser.GetAttributeValueDouble( wxT("start") );
03929 m_end = parser.GetAttributeValueDouble( wxT("end") );
03930 m_chord = parser.GetAttributeValueBool( wxT("chord") );
03931 m_contourwidth = parser.GetAttributeValueDouble( wxT("contourwidth"), 0 );
03932 }
03933 else
03934 {
03935 }
03936 }
03937 #endif //wxART2D_USE_CVGIO
03938
03939 bool a2dEllipticArc::DoIsHitWorld( a2dIterC& ic, a2dHitEvent& hitEvent )
03940 {
03941 double xh = hitEvent.m_relx;
03942 double yh = hitEvent.m_rely;
03943
03944 if ( m_height == 0 && m_width == 0 )
03945 {
03946 hitEvent.m_how = a2dHit::stock_nohit;
03947 return false;
03948 }
03949
03950 if ( m_height == 0 || m_width == 0 )
03951 {
03952 hitEvent.m_how = a2dHit::stock_nohit;
03953 return false;
03954 }
03955
03956 double pw = ic.GetWorldStrokeExtend();
03957 double margin = ic.GetTransformedHitMargin();
03958
03959 double a = m_width/2+pw+margin ;
03960 double b = m_height/2+pw+margin;
03961 double c = wxSqr(xh/a)+wxSqr(yh/b);
03962 if ( 1 > c)
03963 {
03964 double dx = xh;
03965 double dy = yh;
03966
03967 double start,end,angle;
03968
03969 start = wxDegToRad(m_start);
03970 end = wxDegToRad(m_end);
03971
03972 double rx,ry;
03973 double c = m_height/m_width;
03974
03975 rx = sqrt( dx*dx + (dy*dy)/(c*c));
03976 ry = rx*c;
03977
03978 if (dx*ry == 0 && dy*rx == 0)
03979 angle = 0;
03980 else
03981 angle = atan2(dy*rx, dx*ry);
03982
03983 angle = angle-start;
03984 end = end-start;
03985
03986 if (angle<=0) angle += 2.0*wxPI;
03987
03988 if (end<=0) end += 2.0*wxPI;
03989 if (start<0) start += 2.0*wxPI;
03990
03991
03992 angle = angle+start;
03993 end = end+start;
03994
03995 if ( angle > start && angle < end)
03996
03997 {
03998 hitEvent.m_how = a2dHit::stock_fill;
03999 return true;
04000 }
04001 }
04002
04003 hitEvent.m_how = a2dHit::stock_nohit;
04004 return false;
04005 }
04006
04007 bool a2dEllipticArc::DoStartEdit( wxUint16 editmode, wxEditStyle editstyle )
04008 {
04009 if ( m_flags.m_editable )
04010 {
04011 PROPID_IncludeChildren->SetPropertyToObject( this, false );
04012 if ( editmode == 1 )
04013 {
04014 double rx = m_width/2 ;
04015 double ry = m_height/2 ;
04016
04017 double xs, ys, xe, ye ;
04018 xs = rx * cos (wxDegToRad( m_start )) ;
04019 ys = ry * sin (wxDegToRad( m_start )) ;
04020 xe = rx * cos (wxDegToRad( m_end )) ;
04021 ye = ry * sin (wxDegToRad( m_end )) ;
04022
04023
04024 m_flags.m_visiblechilds = true;
04025 m_flags.m_childrenOnSameLayer = true;
04026
04027 a2dHandle* handle = NULL;
04028 Append( handle = new a2dHandle( this, xs*3/4, ys*3/4 , wxT("startangle") ));
04029 handle->SetLayer( m_layer );
04030 Append( handle = new a2dHandle( this, xe*3/4, ye*3/4 , wxT("endangle") ));
04031 handle->SetLayer( m_layer );
04032
04033 m_childobjects->SetSpecificFlags( false, a2dCanvasOFlags::PRERENDERASCHILD, wxT("a2dHandle") );
04034 m_childobjects->SetSpecificFlags( true, a2dCanvasOFlags::BIN2, wxT("a2dHandle") );
04035 }
04036 return a2dWHCenter::DoStartEdit( editmode, editstyle );
04037 }
04038
04039 return false;
04040 }
04041
04042 void a2dEllipticArc::OnChar(wxKeyEvent& event)
04043 {
04044 if ( m_flags.m_editingCopy )
04045 {
04046 switch(event.GetKeyCode())
04047 {
04048 case WXK_TAB:
04049 {
04050 wxUint16* editmode = PROPID_Editmode->GetPropertyValuePtr( this );
04051 if ( editmode )
04052 {
04053 (*editmode)++;
04054 if ( (*editmode) > 1) (*editmode) = 0;
04055 ReStartEdit( (*editmode) );
04056 }
04057 break;
04058 }
04059 default:
04060 event.Skip();
04061 }
04062 }
04063 else
04064 event.Skip();
04065 }
04066
04067 void a2dEllipticArc::OnHandleEvent(a2dHandleMouseEvent &event)
04068 {
04069 a2dIterC* ic = event.GetIterC();
04070
04071 if ( m_flags.m_editingCopy )
04072 {
04073 a2dRestrictionEngine *restrict = a2dCanvasGlobals->GetRestrictionEngine();
04074
04075 a2dHandle* draghandle = event.GetCanvasHandle();
04076
04077 double xw,yw;
04078 xw = event.GetX();
04079 yw = event.GetY();
04080
04081 a2dAffineMatrix atWorld = ic->GetTransform();
04082 a2dAffineMatrix inverse = ic->GetInverseTransform();
04083
04084 double xwi;
04085 double ywi;
04086 inverse.TransformPoint( xw, yw, xwi, ywi );
04087
04088 a2dEllipticArc* original = wxStaticCast( PROPID_Original->GetPropertyValue( this ).Get(), a2dEllipticArc );
04089
04090 if (event.GetMouseEvent().LeftUp() )
04091 {
04092 if ( draghandle->GetName() == wxT("startangle") )
04093 {
04094 m_root->GetCommandProcessor()->Submit(new a2dCommand_SetCanvasProperty( original, PROPID_StartAngle, m_start ) );
04095
04096 }
04097 else if ( draghandle->GetName() == wxT("endangle") )
04098 {
04099 m_root->GetCommandProcessor()->Submit(new a2dCommand_SetCanvasProperty( original, PROPID_EndAngle, m_end ) );
04100
04101 }
04102 else
04103 event.Skip();
04104 }
04105 else if ( event.GetMouseEvent().Dragging() )
04106 {
04107 double xs,ys,xe,ye,rx,ry;
04108
04109 if ( draghandle->GetName() == wxT("startangle") )
04110 {
04111
04112 double c;
04113 xs = xwi;
04114 ys = ywi;
04115
04116 c = m_height/m_width;
04117
04118 rx = sqrt( xs*xs + (ys*ys)/(c*c));
04119 ry = rx*c;
04120
04121 if (xs*ry == 0)
04122 {
04123 if (ys*rx > 0)
04124 m_start = 90;
04125 else
04126 m_start = 270;
04127 }
04128 else
04129 m_start = wxRadToDeg( atan2(ys*rx, xs*ry));
04130
04131 if(restrict)
04132 restrict->RestrictAngle( &m_start, a2dRestrictionEngine::snapToPointAngle );
04133
04134 xs = m_width/2 * cos( wxDegToRad(m_start) ) ;
04135 ys = m_height/2 * sin( wxDegToRad(m_start) ) ;
04136
04137 draghandle->SetPosXY( xs*3/4, ys*3/4 );
04138 SetPending( true );
04139 }
04140 else if ( draghandle->GetName() == wxT("endangle") )
04141 {
04142
04143 double c;
04144 xe = xwi;
04145 ye = ywi;
04146
04147 c = m_height/m_width;
04148
04149 rx = sqrt( xe*xe + (ye*ye)/(c*c));
04150 ry = rx*c;
04151
04152 if (xe*ry == 0)
04153 {
04154 if (ye*rx > 0)
04155 m_end = 90;
04156 else
04157 m_end = 270;
04158 }
04159 else
04160 m_end = wxRadToDeg( atan2(ye*rx, xe*ry ));
04161
04162 if(restrict)
04163 restrict->RestrictAngle( &m_end, a2dRestrictionEngine::snapToPointAngle );
04164
04165 xe = m_width/2 * cos( wxDegToRad(m_end) ) ;
04166 ye = m_height/2 * sin( wxDegToRad(m_end) ) ;
04167 draghandle->SetPosXY( xe*3/4, ye*3/4 );
04168 SetPending( true );
04169 }
04170 else
04171 event.Skip();
04172 }
04173 else
04174 event.Skip();
04175 }
04176 else
04177 {
04178 event.Skip();
04179 }
04180 }
04181
04182
04183
04184
04185
04186 a2dPropertyIdDouble* a2dArc::PROPID_X1 = NULL;
04187 a2dPropertyIdDouble* a2dArc::PROPID_X2 = NULL;
04188 a2dPropertyIdDouble* a2dArc::PROPID_Y1 = NULL;
04189 a2dPropertyIdDouble* a2dArc::PROPID_Y2 = NULL;
04190 a2dPropertyIdBool* a2dArc::PROPID_Chord = NULL;
04191 a2dPropertyIdDouble* a2dArc::PROPID_StartAngle = NULL;
04192 a2dPropertyIdDouble* a2dArc::PROPID_EndAngle = NULL;
04193
04194 INITIALIZE_PROPERTIES( a2dArc, a2dCanvasObject )
04195 {
04196 PROPID_X1 = new a2dPropertyIdDouble( wxT("X1"),
04197 a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dArc::m_x1) );
04198 AddPropertyId( PROPID_X1 );
04199 PROPID_X2 = new a2dPropertyIdDouble( wxT("X2"),
04200 a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dArc::m_x2) );
04201 AddPropertyId( PROPID_X2 );
04202 PROPID_Y1 = new a2dPropertyIdDouble( wxT("Y1"),
04203 a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dArc::m_y1) );
04204 AddPropertyId( PROPID_Y1 );
04205 PROPID_Y2 = new a2dPropertyIdDouble( wxT("Y2"),
04206 a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dArc::m_y2) );
04207 AddPropertyId( PROPID_Y2 );
04208 PROPID_StartAngle = new a2dPropertyIdDouble( wxT("StartAngle"),
04209 a2dPropertyId::flag_none, 0,
04210 a2dPropertyIdDouble::Get( &a2dArc::GetStartAngle ),
04211 a2dPropertyIdDouble::Set( &a2dArc::SetStartAngle ) );
04212 AddPropertyId( PROPID_StartAngle );
04213 PROPID_EndAngle = new a2dPropertyIdDouble( wxT("EndAngle"),
04214 a2dPropertyId::flag_none, 0,
04215 a2dPropertyIdDouble::Get( &a2dArc::GetEndAngle ),
04216 a2dPropertyIdDouble::Set( &a2dArc::SetEndAngle ) );
04217 AddPropertyId( PROPID_EndAngle );
04218 PROPID_Chord = new a2dPropertyIdBool( wxT("Chord"),
04219 a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdBool::Mptr >( &a2dArc::m_chord) );
04220 AddPropertyId( PROPID_Chord );
04221
04222 return true;
04223 }
04224
04225 A2D_BEGIN_EVENT_TABLE( a2dArc, a2dCanvasObject )
04226 A2D_EVT_CANVASHANDLE_MOUSE_EVENT( a2dArc::OnHandleEvent )
04227 A2D_EVT_CHAR( a2dArc::OnChar )
04228 A2D_END_EVENT_TABLE()
04229
04230 a2dArc::a2dArc()
04231 : a2dCanvasObject()
04232 {
04233 m_x1 = 0;
04234 m_x2 = 0;
04235 m_y1 = 0;
04236 m_y2 = 0;
04237 m_chord = false;
04238 m_contourwidth = 0;
04239 }
04240
04241 a2dArc::a2dArc( double xc, double yc, double radius, double start, double end, bool chord, double contourwidth )
04242 : a2dCanvasObject()
04243 {
04244 m_lworld.Translate(xc,yc);
04245
04246 m_x1 = radius * cos (wxDegToRad(start)) ;
04247 m_x2 = radius * cos (wxDegToRad(end)) ;
04248 m_y1 = radius * sin (wxDegToRad(start)) ;
04249 m_y2 = radius * sin (wxDegToRad(end)) ;
04250 m_chord = chord;
04251 m_contourwidth = contourwidth;
04252 }
04253
04254 a2dArc::a2dArc( double x1, double y1, double x2, double y2, double xc, double yc, bool chord, double contourwidth )
04255 : a2dCanvasObject()
04256 {
04257 m_lworld.Translate(xc,yc);
04258
04259 double dx = x1 - xc;
04260 double dy = y1 - yc;
04261 double radius = sqrt(dx*dx+dy*dy);
04262
04263 m_x1 = dx;
04264 m_y1 = dy;
04265
04266
04267 dx = x2 - xc;
04268 dy = y2 - yc;
04269 double end = atan2(dy,dx);
04270
04271 m_x2 = radius * cos (end) ;
04272 m_y2 = radius * sin (end) ;
04273 m_chord = chord;
04274 m_contourwidth = contourwidth;
04275 }
04276
04277 a2dArc::~a2dArc()
04278 {
04279 }
04280
04281 void a2dArc::SetRadius(double radius)
04282 {
04283
04284 double dx = m_x1;
04285 double dy = m_y1;
04286
04287 double start;
04288
04289 if (!dx && !dy)
04290 start = 0;
04291 else
04292 start = atan2(dy,dx);
04293
04294 m_x1 = radius * cos (start) ;
04295 m_y1 = radius * sin (start) ;
04296
04297 dx = m_x2;
04298 dy = m_y2;
04299
04300 double end;
04301
04302 if (!dx && !dy)
04303 end = 0;
04304 else
04305 end = atan2(dy,dx);
04306
04307 m_x2 = radius * cos (end) ;
04308 m_y2 = radius * sin (end) ;
04309 }
04310
04311 double a2dArc::GetRadius() const
04312 {
04313 return sqrt( m_x1*m_x1 + m_y1*m_y1 );
04314 }
04315
04316 void a2dArc::SetChord( bool chord )
04317 {
04318 m_chord = chord;
04319 SetPending(true);
04320 }
04321
04322 void a2dArc::Set( double xs, double ys, double xm, double ym, double xe, double ye )
04323 {
04324 double radius;
04325 double center_x, center_y;
04326 double beginrad, midrad, endrad, phit;
04327
04328 double ax,ay,bx,by,cx,cy;
04329 double ax2,ay2,bx2,by2,cx2,cy2;
04330 double d;
04331 bool straight = false;
04332
04333 ax=xs; ay=ys; ax2=pow(ax,2); ay2=pow(ay,2);
04334 bx=xm; by=ym; bx2=pow(bx,2); by2=pow(by,2);
04335 cx=xe; cy=ye; cx2=pow(cx,2); cy2=pow(cy,2);
04336
04337 if ( ax == cx && ay == cy )
04338 {
04339
04340 center_x = (bx + ax) / 2.0;
04341 center_y = (by + ay) / 2.0;
04342 radius = sqrt( pow( bx - ax, 2 ) + pow( by - ay, 2 ) )/2.0;
04343 }
04344 else
04345 {
04346 d=2*(ay*cx + by*ax - by*cx - ay*bx - cy*ax + cy*bx);
04347
04348 if (fabs(d) < a2dACCUR )
04349 {
04350 d = a2dACCUR;
04351 straight = true;
04352 }
04353
04354 center_x = ( by * ax2 - cy * ax2 - by2 * ay + cy2 * ay + bx2 * cy + ay2 * by
04355 + cx2 * ay - cy2 * by - cx2 * by - bx2 * ay + by2 * cy - ay2 * cy
04356 )/d;
04357
04358 center_y = ( ax2 * cx + ay2 * cx + bx2 * ax - bx2 * cx + by2 * ax - by2 * cx
04359 - ax2 * bx - ay2 * bx - cx2 * ax + cx2 * bx - cy2 * ax + cy2 * bx
04360 )/d ;
04361
04362 radius = sqrt(pow(ax-center_x,2) + pow(ay-center_y,2));
04363 }
04364
04365 if ( radius )
04366 {
04367
04368 beginrad = atan2(ys-center_y,xs-center_x);
04369 midrad = atan2(ym-center_y,xm-center_x);
04370 endrad = atan2(ye-center_y,xe-center_x);
04371
04372 double mr,er;
04373
04374
04375
04376
04377
04378 mr = midrad - beginrad;
04379 er = endrad - beginrad;
04380
04381
04382 if ( mr<=0 ) mr += 2.0*M_PI;
04383 if ( er<=0 ) er += 2.0*M_PI;
04384
04385 bool counterclock;
04386
04387
04388 if (mr < er)
04389 {
04390 phit = er;
04391 counterclock = true;
04392 }
04393 else
04394 {
04395 phit = -( 2.0*M_PI - er );
04396 counterclock = false;
04397 }
04398
04399 if ( counterclock )
04400 {
04401 m_x1 = xs-center_x;
04402 m_y1 = ys-center_y;
04403 m_x2 = xe-center_x;
04404 m_y2 = ye-center_y;
04405 }
04406 else
04407 {
04408 m_x2 = xs-center_x;
04409 m_y2 = ys-center_y;
04410 m_x1 = xe-center_x;
04411 m_y1 = ye-center_y;
04412 }
04413 }
04414 else
04415 {
04416
04417 wxASSERT( radius );
04418 }
04419
04420 m_lworld.Translate( center_x, center_y );
04421 }
04422
04423 a2dArc::a2dArc( const a2dArc &other, CloneOptions options )
04424 :a2dCanvasObject( other, options )
04425 {
04426 m_x1 = other.m_x1;
04427 m_y1 = other.m_y1;
04428 m_x2 = other.m_x2;
04429 m_y2 = other.m_y2;
04430 m_chord = other.m_chord;
04431 m_contourwidth = other.m_contourwidth;
04432 }
04433
04434 a2dObject* a2dArc::Clone( CloneOptions options ) const
04435 {
04436 return new a2dArc( *this, options );
04437 };
04438
04439 double a2dArc::GetStartAngle() const
04440 {
04441 double start;
04442 if (!m_x1 && !m_y1)
04443 start = 0;
04444 else
04445 start = atan2(m_y1,m_x1);
04446
04447 return start;
04448 }
04449
04450 double a2dArc::GetEndAngle() const
04451 {
04452 double end;
04453 if (!m_x2 && !m_y2)
04454 end = 0;
04455 else
04456 end = atan2(m_y2,m_x2);
04457
04458 return end;
04459 }
04460
04461 void a2dArc::SetStartAngle( double a )
04462 {
04463 double radius = GetRadius();
04464 m_x1 = radius * cos ( a ) ;
04465 m_y1 = radius * sin ( a ) ;
04466 }
04467
04468 void a2dArc::SetEndAngle( double a )
04469 {
04470 double radius = GetRadius();
04471 m_x2 = radius * cos ( a ) ;
04472 m_y2 = radius * sin ( a ) ;
04473 }
04474
04475 a2dPoint2D a2dArc::GetMidPoint() const
04476 {
04477 double dx = m_x1;
04478
04479 double dy = m_y1;
04480
04481 double start;
04482 double radius = sqrt(dx*dx+dy*dy);
04483
04484 if (!dx && !dy)
04485 start = 0;
04486 else
04487 start = atan2(dy, dx);
04488
04489 dx = m_x2;
04490 dy = m_y2;
04491
04492 double end;
04493
04494 if (!dx && !dy)
04495 end = 0;
04496 else
04497 end = atan2(dy,dx);
04498
04499 end = end-start;
04500 if (end<=0) end += 2.0*wxPI;
04501
04502 if (start<0) start += 2.0*wxPI;
04503
04504 end=end+start;
04505
04506 return a2dPoint2D( radius * cos( (end-start)/2 ), radius * sin( (end-start)/2 ) );
04507 }
04508
04509
04510 a2dVertexList* a2dArc::GetAsPolygon()
04511 {
04512 a2dVertexList* pointlist = new a2dVertexList();
04513
04514 a2dCanvasObjectList* vectorpaths = GetAsCanvasVpaths();
04515 a2dVpath* segments = wxStaticCast( vectorpaths->front().Get(), a2dVectorPath ) ->GetSegments();
04516 segments->ConvertToLines();
04517 a2dLineSegment* point;
04518 unsigned int i;
04519 for (i=0; i < segments->GetCount();i++)
04520 {
04521 a2dVpathSegment& seg = segments->Item(i);
04522 point = new a2dLineSegment(seg.m_x1, seg.m_y1);
04523 pointlist->push_back(point);
04524 }
04525
04526 delete vectorpaths;
04527
04528 return pointlist;
04529 }
04530
04531 a2dCanvasObjectList* a2dArc::GetAsCanvasVpaths( bool transform )
04532 {
04533 a2dAffineMatrix pworld;
04534 if ( transform )
04535 pworld = m_lworld;
04536
04537
04538
04539 a2dVpath* segments = new a2dVpath();
04540
04541 a2dVpathSegment* seg;
04542
04543 double dx = m_x1;
04544
04545 double dy = m_y1;
04546
04547 double start;
04548 double radius = sqrt(dx*dx+dy*dy);
04549
04550 if (!dx && !dy)
04551 start = 0;
04552 else
04553 start = atan2(dy, dx);
04554
04555 dx = m_x2;
04556 dy = m_y2;
04557
04558 double end;
04559
04560 if (!dx && !dy)
04561 end = 0;
04562 else
04563 end = atan2(dy,dx);
04564
04565 end = end-start;
04566 if (end<=0) end += 2.0*wxPI;
04567
04568 if (start<0) start += 2.0*wxPI;
04569
04570 end=end+start;
04571
04572 double dphi = wxPI * 2.0 / CIRCLE_STEPS;
04573 int steps = (int) ((end-start)/dphi);
04574 if (steps == 0)
04575 steps = 1;
04576 dphi = (end-start)/steps;
04577
04578 double theta = start;
04579 int i;
04580
04581
04582 double x,y;
04583
04584 for (i = 0; i < steps+1; i++)
04585 {
04586 pworld.TransformPoint( radius * cos (theta), radius * sin (theta), x, y );
04587 if ( i == 0 )
04588 seg = new a2dVpathSegment( x, y , a2dPATHSEG_MOVETO );
04589 else
04590 seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO );
04591 segments->push_back(seg);
04592 theta = theta + dphi;
04593 }
04594
04595
04596 if (!m_chord)
04597
04598 {
04599 pworld.TransformPoint( 0, 0, x, y );
04600
04601 seg = new a2dVpathSegment( x, y , a2dPATHSEG_LINETO, a2dPATHSEG_END_CLOSED );
04602 segments->push_back(seg);
04603 }
04604
04605 a2dVectorPath* canpath = new a2dVectorPath( segments );
04606 canpath->SetStroke( this->GetStroke() );
04607 canpath->SetFill( this->GetFill() );
04608 canpath->SetLayer( m_layer );
04609 canpath->SetContourWidth( GetContourWidth() );
04610 canpath->SetPathType( a2dPATH_END_ROUND );
04611 a2dCanvasObjectList* canpathlist = new a2dCanvasObjectList();
04612 canpathlist->push_back( canpath );
04613 return canpathlist;
04614 }
04615
04616 a2dBoundingBox a2dArc::DoGetUnTransformedBbox( a2dBboxFlags flags ) const
04617 {
04618 a2dBoundingBox bbox;
04619
04620 double dx = m_x1;
04621 double dy = m_y1;
04622
04623 double start;
04624 double end;
04625 double radius = sqrt(dx*dx+dy*dy);
04626
04627
04628 if ( m_x1 == m_x2 && m_y1 == m_y2 )
04629 {
04630 start = 0;
04631 end = 2.0 * wxPI;
04632 }
04633 else
04634 {
04635 if (!dx && !dy)
04636 start = 0;
04637 else
04638 start = atan2(dy, dx);
04639
04640 dx = m_x2;
04641 dy = m_y2;
04642
04643 if (!dx && !dy)
04644 end = 0;
04645 else
04646 end = atan2(dy,dx);
04647
04648 end = end-start;
04649 if (end<=0) end += 2.0*wxPI;
04650 end += start;
04651 }
04652
04653 if ( !m_chord )
04654 bbox.Expand( 0, 0 );
04655
04656 bbox.Expand( radius * cos (start), radius * sin (start) );
04657
04658 bbox.Expand( radius * cos (end), radius * sin (end) );
04659
04660
04661 if ( InArc( 0, start, end, false ) )
04662 bbox.Expand( radius, 0 );
04663 if ( InArc( wxPI/2, start, end, false ) )
04664 bbox.Expand( 0, radius );
04665 if ( InArc( wxPI, start, end, false ) )
04666 bbox.Expand( -radius, 0 );
04667 if ( InArc( 1.5*wxPI, start, end, false ) )
04668 bbox.Expand( 0, -radius );
04669
04670 if ( !(flags & a2dCANOBJ_BBOX_EDIT ) )
04671 {
04672 if (m_contourwidth > 0)
04673 bbox.Enlarge( m_contourwidth/2 );
04674 }
04675
04676 return bbox;
04677 }
04678
04679 bool a2dArc::DoUpdate( UpdateMode mode, const a2dBoundingBox& childbox, const a2dBoundingBox& clipbox, const a2dBoundingBox& propbox )
04680 {
04681
04682
04683
04684
04685 if ( !m_bbox.GetValid())
04686 {
04687 double x,y;
04688 double dx = m_x1;
04689 double dy = m_y1;
04690
04691 double start;
04692 double end;
04693 double radius = sqrt(dx*dx+dy*dy);
04694 radius += m_contourwidth/2;
04695
04696 if ( m_x1 == m_x2 && m_y1 == m_y2 )
04697 {
04698 start = 0;
04699 end = 2.0 * wxPI;
04700 }
04701 else
04702 {
04703 if (!dx && !dy)
04704 start = 0;
04705 else
04706 start = atan2(dy, dx);
04707
04708 dx = m_x2;
04709 dy = m_y2;
04710
04711 if (!dx && !dy)
04712 end = 0;
04713 else
04714 end = atan2(dy,dx);
04715 }
04716
04717 double alphax = atan2( m_lworld.GetValue( 1, 0 ), m_lworld.GetValue( 0, 0 ) );
04718 double alphay = atan2( m_lworld.GetValue( 1, 1 ), m_lworld.GetValue( 0, 1 ) );
04719
04720
04721 if ( end <= start ) end += 2.0*wxPI;
04722 if ( alphax <= start ) alphax += wxPI;
04723 if ( alphay <= start ) alphay += wxPI;
04724 if ( alphax >= end ) alphax -= wxPI;
04725 if ( alphay >= end ) alphay -= wxPI;
04726
04727
04728 m_lworld.TransformPoint( radius * cos (start), radius * sin (start), x, y );
04729 m_bbox.Expand( x, y );
04730
04731 m_lworld.TransformPoint( radius * cos (end), radius * sin (end), x, y );
04732 m_bbox.Expand( x, y );
04733
04734
04735 if ( InArc( alphax, start, end, false ) )
04736 {
04737 m_lworld.TransformPoint( radius * cos (alphax), radius * sin (alphax), x, y );
04738 m_bbox.Expand( x, y );
04739 }
04740 alphax += wxPI;
04741 if ( InArc( alphax, start, end, false ) )
04742 {
04743 m_lworld.TransformPoint( radius * cos (alphax), radius * sin (alphax), x, y );
04744 m_bbox.Expand( x, y );
04745 }
04746 alphax -= 2*wxPI;
04747 if ( InArc( alphax, start, end, false ) )
04748 {
04749 m_lworld.TransformPoint( radius * cos (alphax), radius * sin (alphax), x, y );
04750 m_bbox.Expand( x, y );
04751 }
04752 if ( InArc( alphay, start, end, false ) )
04753 {
04754 m_lworld.TransformPoint( radius * cos (alphay), radius * sin (alphay), x, y );
04755 m_bbox.Expand( x, y );
04756 }
04757 alphay += wxPI;
04758 if ( InArc( alphay, start, end, false ) )
04759 {
04760 m_lworld.TransformPoint( radius * cos (alphay), radius * sin (alphay), x, y );
04761 m_bbox.Expand( x, y );
04762 }
04763 alphay -= 2*wxPI;
04764 if ( InArc( alphay, start, end, false ) )
04765 {
04766 m_lworld.TransformPoint( radius * cos (alphay), radius * sin (alphay), x, y );
04767 m_bbox.Expand( x, y );
04768 }
04769
04770 return true;
04771 }
04772
04773 return false;
04774 }
04775
04776 void a2dArc::DoRender( a2dIterC& ic, OVERLAP clipparent )
04777 {
04778 if ( GetContourWidth() )
04779 {
04780 if ( m_flags.m_editingCopy && m_chord)
04781 m_chord = false;
04782
04783 a2dCanvasObjectList* vectorpaths = GetAsCanvasVpaths( false );
04784
04785 if ( m_flags.m_editingCopy && m_chord)
04786 m_chord = true;
04787
04788 forEachIn( a2dCanvasObjectList, vectorpaths )
04789 {
04790 a2dVectorPath* obj = wxStaticCast( (*iter).Get(), a2dVectorPath );
04791 obj->DoRender( ic, clipparent );
04792 }
04793 delete vectorpaths;
04794 }
04795 else if ( m_flags.m_editingCopy && m_chord)
04796 {
04797 m_chord = false;
04798 ic.GetDrawer2D()->DrawArc( m_x1, m_y1, m_x2, m_y2, 0, 0, m_chord );
04799 m_chord = true;
04800 }
04801 else
04802 ic.GetDrawer2D()->DrawArc( m_x1, m_y1, m_x2, m_y2, 0, 0, m_chord );
04803
04804 }
04805
04806 #if wxART2D_USE_CVGIO
04807 void a2dArc::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
04808 {
04809 a2dCanvasObject::DoSave( parent, out, xmlparts, towrite );
04810 if ( xmlparts == a2dXmlSer_attrib )
04811 {
04812 out.WriteAttribute( wxT("x1"), m_x1 );
04813 out.WriteAttribute( wxT("y1"), m_y1 );
04814 out.WriteAttribute( wxT("x2"), m_x2 );
04815 out.WriteAttribute( wxT("y2"), m_y2 );
04816 out.WriteAttribute( wxT("contourwidth"), m_contourwidth );
04817 }
04818 else
04819 {
04820 }
04821 }
04822
04823 void a2dArc::DoLoad( wxObject* parent, a2dIOHandlerXmlSerIn& parser, a2dXmlSer_flag xmlparts )
04824 {
04825 a2dCanvasObject::DoLoad( parent, parser, xmlparts );
04826 if ( xmlparts == a2dXmlSer_attrib )
04827 {
04828 m_x1 = parser.GetAttributeValueDouble( wxT("x1") );
04829 m_y1 = parser.GetAttributeValueDouble( wxT("y1") );
04830 m_x2 = parser.GetAttributeValueDouble( wxT("x2") );
04831 m_y2 = parser.GetAttributeValueDouble( wxT("y2") );
04832 m_contourwidth = parser.GetAttributeValueDouble( wxT("contourwidth"), 0 );
04833 }
04834 else
04835 {
04836 }
04837 }
04838 #endif //wxART2D_USE_CVGIO
04839
04840 bool a2dArc::DoIsHitWorld( a2dIterC& ic, a2dHitEvent& hitEvent )
04841 {
04842 double xh = hitEvent.m_relx;
04843 double yh = hitEvent.m_rely;
04844 double pw = ic.GetWorldStrokeExtend();
04845
04846 double dx = m_x1;
04847 double dy = m_y1;
04848 double radius = sqrt(dx*dx+dy*dy);
04849 double margin = ic.GetTransformedHitMargin();
04850
04851 if (radius+pw+margin > sqrt((xh*xh)+(yh*yh)))
04852 {
04853
04854 dx = xh;
04855 dy = yh;
04856
04857 double angle;
04858
04859 if (!dx && !dy)
04860 angle = 0;
04861 else
04862 angle = atan2(dy,dx);
04863
04864 dx = m_x1;
04865 dy = m_y1;
04866
04867 double start;
04868
04869 if (!dx && !dy)
04870 start = 0;
04871 else
04872 start = atan2(dy,dx);
04873
04874 dx = m_x2;
04875 dy = m_y2;
04876
04877 double end;
04878
04879 if (!dx && !dy)
04880 end = 0;
04881 else
04882 end = atan2(dy,dx);
04883
04884
04885 angle = angle-start;
04886 end = end-start;
04887
04888 if ( angle <= 0) angle += 2.0*wxPI;
04889 if ( end <=0 ) end += 2.0*wxPI;
04890 if ( angle >= 2.0*M_PI ) angle -= 2.0*M_PI;
04891 if ( end >= 2.0*M_PI ) end -= 2.0*M_PI;
04892
04893
04894 if ( angle < end )
04895 {
04896 if ( m_chord )
04897 {
04898 if ( radius < sqrt((xh*xh)+(yh*yh)) )
04899 hitEvent.m_how = a2dHit::stock_strokeoutside;
04900 else if ( radius > sqrt((xh*xh)+(yh*yh)) && radius-pw-margin < sqrt((xh*xh)+(yh*yh)) )
04901 hitEvent.m_how = a2dHit::stock_strokeinside;
04902 else
04903 {
04904 hitEvent.m_how = a2dHit::stock_nohit;
04905 return false;
04906 }
04907 }
04908 else
04909 {
04910 if ( radius < sqrt((xh*xh)+(yh*yh)) )
04911 hitEvent.m_how = a2dHit::stock_strokeoutside;
04912 if ( radius > sqrt((xh*xh)+(yh*yh)) && radius-pw-margin < sqrt((xh*xh)+(yh*yh)) )
04913 hitEvent.m_how = a2dHit::stock_strokeinside;
04914 else
04915 hitEvent.m_how = a2dHit::stock_fill;
04916 }
04917 return true;
04918 }
04919 hitEvent.m_how = a2dHit::stock_nohit;
04920 return false;
04921 }
04922 else
04923 {
04924 hitEvent.m_how = a2dHit::stock_nohit;
04925 return false;
04926 }
04927 }
04928
04929 bool a2dArc::DoStartEdit( wxUint16 editmode, wxEditStyle editstyle )
04930 {
04931 if ( m_flags.m_editable )
04932 {
04933 PROPID_IncludeChildren->SetPropertyToObject( this, false );
04934 if ( editmode == 1 )
04935 {
04936 m_flags.m_visiblechilds = true;
04937 m_flags.m_childrenOnSameLayer = true;
04938
04939 a2dHandle* handle = NULL;
04940 Append( handle = new a2dHandle( this, GetX1()*3/4, GetY1()*3/4, wxT("startangle") ));
04941 handle->SetLayer( m_layer );
04942 Append( handle = new a2dHandle( this, GetX2()*3/4, GetY2()*3/4, wxT("endangle") ));
04943 handle->SetLayer( m_layer );
04944
04945 m_childobjects->SetSpecificFlags( false, a2dCanvasOFlags::PRERENDERASCHILD, wxT("a2dHandle") );
04946 m_childobjects->SetSpecificFlags( true, a2dCanvasOFlags::BIN2, wxT("a2dHandle") );
04947 }
04948
04949 PROPID_Allowrotation->SetPropertyToObject( this, true );
04950 PROPID_Allowskew->SetPropertyToObject( this, true );
04951
04952 return a2dCanvasObject::DoStartEdit( editmode, editstyle );
04953 }
04954
04955 return false;
04956 }
04957
04958 void a2dArc::OnChar(wxKeyEvent& event)
04959 {
04960 if ( m_flags.m_editingCopy )
04961 {
04962 switch(event.GetKeyCode())
04963 {
04964 case WXK_TAB:
04965 {
04966 wxUint16* editmode = PROPID_Editmode->GetPropertyValuePtr( this );
04967 if ( editmode )
04968 {
04969 (*editmode)++;
04970 if ( (*editmode) > 1) (*editmode) = 0;
04971 ReStartEdit( (*editmode) );
04972 }
04973 break;
04974 }
04975 default:
04976 event.Skip();
04977 }
04978 }
04979 else
04980 event.Skip();
04981 }
04982
04983 void a2dArc::OnHandleEvent(a2dHandleMouseEvent &event)
04984 {
04985 a2dIterC* ic = event.GetIterC();
04986
04987 if ( m_flags.m_editingCopy )
04988 {
04989 a2dRestrictionEngine *restrictEngine = a2dCanvasGlobals->GetRestrictionEngine();
04990
04991 a2dHandle* draghandle = event.GetCanvasHandle();
04992
04993 double xw,yw;
04994 xw = event.GetX();
04995 yw = event.GetY();
04996
04997 a2dAffineMatrix atWorld = ic->GetTransform();
04998 a2dAffineMatrix inverse = ic->GetInverseTransform();
04999
05000 double xwi;
05001 double ywi;
05002 inverse.TransformPoint( xw, yw, xwi, ywi );
05003
05004 a2dArc* original = wxStaticCast( PROPID_Original->GetPropertyValue( this ).Get(), a2dArc );
05005
05006 if (event.GetMouseEvent().LeftUp() )
05007 {
05008 if ( draghandle->GetName() == wxT("startangle") )
05009 {
05010 double start = atan2( m_y1, m_x1 );
05011 m_root->GetCommandProcessor()->Submit(new a2dCommand_SetCanvasProperty( original, PROPID_StartAngle, start ) );
05012 }
05013 else if ( draghandle->GetName() == wxT("endangle") )
05014 {
05015 double end = atan2( m_y2, m_x2 );
05016 m_root->GetCommandProcessor()->Submit(new a2dCommand_SetCanvasProperty( original, PROPID_EndAngle, end ) );
05017 }
05018 else
05019 event.Skip();
05020 }
05021 else if ( event.GetMouseEvent().Dragging() )
05022 {
05023 if (restrictEngine )
05024 restrictEngine->RestrictPoint( xwi, ywi );
05025
05026 if ( draghandle->GetName() == wxT("startangle") )
05027 {
05028
05029 double dx,dy;
05030 dx = xwi;
05031 dy = ywi;
05032
05033 double end = atan2(dy,dx);
05034
05035 dx = GetX1();
05036 dy = GetY1();
05037
05038 double radius = sqrt(dx*dx+dy*dy);
05039 dx = radius * cos (end);
05040 dy = radius * sin (end);
05041
05042 SetX1( dx );
05043 SetY1( dy );
05044
05045 draghandle->SetPosXY( GetX1()*3/4, GetY1()*3/4 );
05046 SetPending( true );
05047 }
05048 else if ( draghandle->GetName() == wxT("endangle") )
05049 {
05050
05051 double dx,dy;
05052 dx = xwi;
05053 dy = ywi;
05054
05055 double end = atan2(dy,dx);
05056
05057 dx = GetX2();
05058 dy = GetY2();
05059
05060 double radius = sqrt(dx*dx+dy*dy);
05061 dx = radius * cos (end);
05062 dy = radius * sin (end);
05063 SetX2( dx );
05064 SetY2( dy );
05065
05066 draghandle->SetPosXY( GetX2()*3/4, GetY2()*3/4 );
05067 SetPending( true );
05068 }
05069 else
05070 event.Skip();
05071 }
05072 else
05073 event.Skip();
05074 }
05075 else
05076 {
05077 event.Skip();
05078 }
05079 }
05080
05081
05082
05083
05084 a2dPropertyIdDouble* a2dSLine::PROPID_X1 = NULL;
05085 a2dPropertyIdDouble* a2dSLine::PROPID_X2 = NULL;
05086 a2dPropertyIdDouble* a2dSLine::PROPID_Y1 = NULL;
05087 a2dPropertyIdDouble* a2dSLine::PROPID_Y2 = NULL;
05088
05089 INITIALIZE_PROPERTIES( a2dSLine, a2dCanvasObject )
05090 {
05091 PROPID_X1 = new a2dPropertyIdDouble( wxT("X1"),
05092 a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dSLine::m_x1) );
05093 AddPropertyId( PROPID_X1 );
05094 PROPID_X2 = new a2dPropertyIdDouble( wxT("X2"),
05095 a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dSLine::m_x2) );
05096 AddPropertyId( PROPID_X2 );
05097 PROPID_Y1 = new a2dPropertyIdDouble( wxT("Y1"),
05098 a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dSLine::m_y1) );
05099 AddPropertyId( PROPID_Y1 );
05100 PROPID_Y2 = new a2dPropertyIdDouble( wxT("Y2"),
05101 a2dPropertyId::flag_none, 0, static_cast < a2dPropertyIdDouble::Mptr >( &a2dSLine::m_y2) );
05102 AddPropertyId( PROPID_Y2 );
05103
05104 return true;
05105 }
05106
05107 A2D_BEGIN_EVENT_TABLE( a2dSLine, a2dCanvasObject )
05108 A2D_EVT_CANVASHANDLE_MOUSE_EVENT( a2dSLine::OnHandleEvent )
05109 A2D_EVT_CHAR( a2dSLine::OnChar )
05110 A2D_END_EVENT_TABLE()
05111
05112 a2dSLine::a2dSLine()
05113 : a2dCanvasObject()
05114 {
05115 m_x1 = 0;
05116 m_y1 = 0;
05117 m_x2 = 0;
05118 m_y2 = 0;
05119 m_contourwidth = 0;
05120 m_pathtype = a2dPATH_END_SQAURE;
05121 }
05122
05123 a2dSLine::a2dSLine( double x1, double y1, double x2, double y2, double contourwidth )
05124 : a2dCanvasObject()
05125 {
05126 m_x1 = x1;
05127 m_y1 = y1;
05128 m_x2 = x2;
05129 m_y2 = y2;
05130 m_contourwidth = contourwidth;
05131 m_pathtype = a2dPATH_END_SQAURE;
05132 }
05133
05134 a2dSLine::~a2dSLine()
05135 {
05136 }
05137
05138 a2dSLine::a2dSLine( const a2dSLine &other, CloneOptions options )
05139 :a2dCanvasObject( other, options )
05140 {
05141 m_x1 = other.m_x1;
05142 m_y1 = other.m_y1;
05143 m_x2 = other.m_x2;
05144 m_y2 = other.m_y2;
05145 m_contourwidth = other.m_contourwidth;
05146 m_pathtype = other.m_pathtype;
05147 }
05148
05149 a2dObject* a2dSLine::Clone( CloneOptions options ) const
05150 {
05151 return new a2dSLine( *this, options );
05152 };
05153
05154 double a2dSLine::GetPosX1( bool transform ) const
05155 {
05156 double x,y;
05157 if (transform)
05158 m_lworld.TransformPoint( m_x1, m_y1, x, y );
05159 else
05160 x = m_x1;
05161 return x;
05162 }
05163
05164 double a2dSLine::GetPosY1( bool transform ) const
05165 {
05166 double x,y;
05167 if (transform)
05168 m_lworld.TransformPoint( m_x1, m_y1, x, y );
05169 else
05170 y = m_y1;
05171 return y;
05172 }
05173
05174 double a2dSLine::GetPosX2( bool transform ) const
05175 {
05176 double x,y;
05177 if (transform)
05178 m_lworld.TransformPoint( m_x2, m_y2, x, y );
05179 else
05180 x = m_x2;
05181 return x;
05182 }
05183
05184 double a2dSLine::GetPosY2( bool transform ) const
05185 {
05186 double x,y;
05187 if (transform)
05188 m_lworld.TransformPoint( m_x2, m_y2, x, y );
05189 else
05190 y = m_y2;
05191 return y;
05192 }
05193
05194 bool a2dSLine::EliminateMatrix()
05195 {
05196 m_lworld.TransformPoint( m_x1, m_y1, m_x1, m_y1 );
05197 m_lworld.TransformPoint( m_x2, m_y2, m_x2, m_y2 );
05198
05199 return a2dCanvasObject::EliminateMatrix();
05200 }
05201
05202 double a2dSLine::GetLength() const
05203 {
05204 double x1,y1,x2,y2;
05205 m_lworld.TransformPoint( m_x1, m_y1, x1, y1 );
05206 m_lworld.TransformPoint( m_x2, m_y2, x2, y2 );
05207
05208 return sqrt( wxSqr(x2-x1) + wxSqr(y2-y1) );
05209 }
05210
05211 void a2dSLine::SetPosXY1( double x, double y, bool afterinversion)
05212 {
05213 if ( afterinversion )
05214 {
05215 a2dAffineMatrix inverse = m_lworld;
05216 inverse.Invert();
05217 inverse.TransformPoint( x, y, x, y );
05218 }
05219
05220 m_x1 = x;
05221 m_y1 = y;
05222
05223 SetPending(true);
05224 }
05225
05226 void a2dSLine::SetPosXY2( double x, double y, bool afterinversion)
05227 {
05228 if ( afterinversion )
05229 {
05230 a2dAffineMatrix inverse = m_lworld;
05231 inverse.Invert();
05232 inverse.TransformPoint( x, y, x, y );
05233 }
05234
05235 m_x2 = x;
05236 m_y2 = y;
05237
05238 SetPending(true);
05239 }
05240
05241 void a2dSLine::SetPosXY12( double x1, double y1, double x2, double y2, bool afterinversion)
05242 {
05243 if ( afterinversion )
05244 {
05245 a2dAffineMatrix inverse = m_lworld;
05246 inverse.Invert();
05247 inverse.TransformPoint( x1, y1, x1, y1 );
05248 inverse.TransformPoint( x2, y2, x2, y2 );
05249 }
05250
05251 m_x1 = x1;
05252 m_y1 = y1;
05253 m_x2 = x2;
05254 m_y2 = y2;
05255
05256 SetPending(true);
05257 }
05258
05259 a2dCanvasObjectList* a2dSLine::GetAsCanvasVpaths( bool transform )
05260 {
05261 a2dAffineMatrix pworld;
05262 if ( transform )
05263 pworld = m_lworld;
05264
05265 a2dVpath* segments = new a2dVpath();
05266
05267 a2dVpathSegment* seg;
05268
05269 seg = new a2dVpathSegment( m_x1, m_y1, a2dPATHSEG_MOVETO );
05270 segments->push_back(seg);
05271 seg = new a2dVpathSegment( m_x2, m_y2, a2dPATHSEG_LINETO, a2dPATHSEG_END_OPEN );
05272 segments->push_back(seg);
05273
05274 segments->Transform( pworld );
05275
05276 a2dVectorPath* canpath = new a2dVectorPath( segments );
05277 canpath->SetStroke( this->GetStroke() );
05278 canpath->SetFill( this->GetFill() );
05279 canpath->SetLayer( m_layer );
05280 canpath->SetContourWidth( GetContourWidth() );
05281 canpath->SetPathType( a2dPATH_END_ROUND );
05282 a2dCanvasObjectList* canpathlist = new a2dCanvasObjectList();
05283 canpathlist->push_back( canpath );
05284 return canpathlist;
05285 }
05286
05287 a2dBoundingBox a2dSLine::DoGetUnTransformedBbox( a2dBboxFlags flags ) const
05288 {
05289 a2dBoundingBox bbox;
05290 bbox.Expand( m_x1 , m_y1);
05291 bbox.Expand( m_x2 , m_y2);
05292
05293 if ( !(flags & a2dCANOBJ_BBOX_EDIT ) )
05294 {
05295 if (m_contourwidth > 0)
05296 bbox.Enlarge( m_contourwidth/2 );
05297 }
05298
05299 return bbox;
05300 }
05301
05302 void a2dSLine::DoRender( a2dIterC& ic, OVERLAP clipparent )
05303 {
05304 if ( GetContourWidth() )
05305 {
05306 a2dLine line1( m_x1, m_y1, m_x2, m_y2 );
05307 line1.CalculateLineParameters();
05308 double distance = m_contourwidth / 2.0;
05309 a2dPoint2D offsetpoint1left = a2dPoint2D( m_x1, m_y1 );
05310 a2dPoint2D offsetpoint1right = a2dPoint2D( m_x1, m_y1 );
05311 a2dPoint2D offsetpoint2left = a2dPoint2D( m_x2, m_y2 );
05312 a2dPoint2D offsetpoint2right = a2dPoint2D( m_x2, m_y2 );
05313 line1.Virtual_Point( offsetpoint1left, distance );
05314 line1.Virtual_Point( offsetpoint1right, -distance );
05315 line1.Virtual_Point( offsetpoint2left, distance );
05316 line1.Virtual_Point( offsetpoint2right, -distance );
05317
05318 a2dVertexArray contour;
05319 contour.AddPoint( offsetpoint1left );
05320 contour.AddPoint( offsetpoint2left );
05321 contour.AddPoint( offsetpoint2right );
05322 contour.AddPoint( offsetpoint1right );
05323
05324 ic.GetDrawer2D()->DrawPolygon( &contour );
05325 }
05326 else
05327 ic.GetDrawer2D()->DrawLine( m_x1, m_y1, m_x2, m_y2 );
05328 }
05329
05330 bool a2dSLine::RestrictToObject( a2dRestrictionEngine* engine, a2dSnapToWhatMask snapToWhat )
05331 {
05332
05333 if ( !m_flags.m_snap_to )
05334 return false;
05335
05336 bool res = false;
05337 if ( snapToWhat & a2dRestrictionEngine::snapToStart )
05338 {
05339 double x, y;
05340 m_lworld.TransformPoint( m_x1, m_y1, x, y );
05341
05342 res |= engine->SetPointSnapResultIfCloser( a2dPoint2D( x, y ) );
05343 }
05344 if ( snapToWhat & a2dRestrictionEngine::snapToEnd )
05345 {
05346 double x, y;
05347 m_lworld.TransformPoint( m_x2, m_y2, x, y );
05348
05349
05350 res |= engine->SetPointSnapResultIfCloser( a2dPoint2D( x, y ) );
05351 }
05352
05353 res |= a2dCanvasObject::RestrictToObject( engine, snapToWhat );
05354
05355 return res;
05356 }
05357
05358 #if wxART2D_USE_CVGIO
05359 void a2dSLine::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
05360 {
05361 a2dCanvasObject::DoSave( parent, out, xmlparts, towrite );
05362 if ( xmlparts == a2dXmlSer_attrib )
05363 {
05364 out.WriteAttribute( wxT("x1"), m_x1 );
05365 out.WriteAttribute( wxT("y1"), m_y1 );
05366 out.WriteAttribute( wxT("x2"), m_x2 );
05367 out.WriteAttribute( wxT("y2"), m_y2 );
05368 out.WriteAttribute( wxT("contourwidth"), m_contourwidth );
05369 }
05370 else
05371 {
05372 }
05373 }
05374
05375 void a2dSLine::DoLoad( wxObject* parent, a2dIOHandlerXmlSerIn& parser, a2dXmlSer_flag xmlparts )
05376 {
05377 a2dCanvasObject::DoLoad( parent, parser, xmlparts );
05378 if ( xmlparts == a2dXmlSer_attrib )
05379 {
05380 m_x1 = parser.GetAttributeValueDouble( wxT("x1") );
05381 m_y1 = parser.GetAttributeValueDouble( wxT("y1") );
05382 m_x2 = parser.GetAttributeValueDouble( wxT("x2") );
05383 m_y2 = parser.GetAttributeValueDouble( wxT("y2") );
05384 m_contourwidth = parser.GetAttributeValueDouble( wxT("contourwidth"), 0 );
05385 }
05386 else
05387 {
05388 }
05389 }
05390 #endif //wxART2D_USE_CVGIO
05391
05392 bool a2dSLine::DoIsHitWorld( a2dIterC& ic, a2dHitEvent& hitEvent )
05393 {
05394 if ( m_x1 == m_x2 && m_y1 == m_y2 )
05395 {
05396 return fabs(hitEvent.m_relx - m_x1) < ic.GetWorldStrokeExtend() + ic.GetTransformedHitMargin() &&
05397 fabs(hitEvent.m_rely - m_y1) < ic.GetWorldStrokeExtend() + ic.GetTransformedHitMargin();
05398 }
05399
05400 a2dLine line1(m_x1, m_y1, m_x2, m_y2);
05401 a2dPoint2D P = a2dPoint2D(hitEvent.m_relx, hitEvent.m_rely);
05402
05403 double distance;
05404 if (line1.PointInLine(P, distance, m_contourwidth/2.0 + ic.GetWorldStrokeExtend() + ic.GetTransformedHitMargin() ) == R_IN_AREA)
05405 {
05406 hitEvent.m_how = a2dHit::stock_strokeoutside;
05407 return true;
05408 }
05409 else
05410 {
05411 hitEvent.m_how = a2dHit::stock_nohit;
05412 return false;
05413 }
05414 }
05415
05416 bool a2dSLine::DoStartEdit( wxUint16 editmode, wxEditStyle editstyle )
05417 {
05418 if ( m_flags.m_editable )
05419 {
05420 if ( editmode == 1 )
05421 {
05422 m_flags.m_visiblechilds = true;
05423 m_flags.m_childrenOnSameLayer = true;
05424
05425 a2dHandle* handle = NULL;
05426 Append( handle = new a2dHandle( this, m_x1, m_y1 , wxT("__startpoint__") ));
05427 handle->SetLayer( m_layer );
05428 Append( handle = new a2dHandle( this, m_x2, m_y2 , wxT("__endpoint__") ));
05429 handle->SetLayer( m_layer );
05430
05431 m_childobjects->SetSpecificFlags( false, a2dCanvasOFlags::PRERENDERASCHILD, wxT("a2dHandle") );
05432 m_childobjects->SetSpecificFlags( true, a2dCanvasOFlags::BIN2, wxT("a2dHandle") );
05433
05434
05435
05436 Update( updatemask_force );
05437
05438 SetPending( true );
05439 return true;
05440 }
05441 else
05442 {
05443 PROPID_IncludeChildren->SetPropertyToObject( this, false );
05444 PROPID_Allowrotation->SetPropertyToObject( this, true );
05445 PROPID_Allowskew->SetPropertyToObject( this, true );
05446
05447 return a2dCanvasObject::DoStartEdit( editmode, editstyle );
05448 }
05449 }
05450
05451 return false;
05452 }
05453
05454 void a2dSLine::OnChar(wxKeyEvent& event)
05455 {
05456 if ( m_flags.m_editingCopy )
05457 {
05458 switch(event.GetKeyCode())
05459 {
05460 case WXK_TAB:
05461 {
05462 wxUint16* editmode = PROPID_Editmode->GetPropertyValuePtr( this );
05463 if ( editmode )
05464 {
05465 (*editmode)++;
05466 if ( (*editmode) > 1) (*editmode) = 0;
05467 ReStartEdit( (*editmode) );
05468 }
05469 break;
05470 }
05471 default:
05472 event.Skip();
05473 }
05474 }
05475 else
05476 event.Skip();
05477 }
05478
05479
05480 void a2dSLine::OnHandleEvent(a2dHandleMouseEvent &event)
05481 {
05482 if ( m_flags.m_editingCopy )
05483 {
05484 a2dRestrictionEngine *restrictEngine = a2dCanvasGlobals->GetRestrictionEngine();
05485
05486 a2dHandle* draghandle = event.GetCanvasHandle();
05487
05488
05489 double xw,yw;
05490 xw = event.GetX();
05491 yw = event.GetY();
05492
05493 double xwi;
05494 double ywi;
05495 a2dAffineMatrix inverse = m_lworld;
05496 inverse.Invert();
05497 inverse.TransformPoint( xw, yw, xwi, ywi );
05498
05499 a2dSLine* original = wxStaticCast( PROPID_Original->GetPropertyValue( this ).Get(), a2dSLine );
05500 a2dAffineMatrix origworld = m_lworld;
05501
05502 if (event.GetMouseEvent().LeftUp() )
05503 {
05504 if ( draghandle->GetName() == wxT("__startpoint__") )
05505 {
05506 m_root->GetCommandProcessor()->Submit(new a2dCommand_MoveSegment( original, m_x1, m_y1, 0, false ));
05507 draghandle->SetPosXY( m_x1, m_y1 );
05508 }
05509 else if ( draghandle->GetName() == wxT("__endpoint__") )
05510 {
05511 m_root->GetCommandProcessor()->Submit(new a2dCommand_MoveSegment( original, m_x2, m_y2, 1, false ));
05512 draghandle->SetPosXY( m_x2, m_y2 );
05513 }
05514 else
05515 event.Skip();
05516 }
05517 else if ( event.GetMouseEvent().Dragging() )
05518 {
05519 if ( draghandle->GetName() == wxT("__startpoint__") )
05520 {
05521
05522 if (restrictEngine )
05523 restrictEngine->RestrictPoint( xw, yw );
05524 SetPosXY1( xw, yw );
05525 draghandle->SetPosXY( m_x1, m_y1 );
05526 SetPending( true );
05527 }
05528 else if ( draghandle->GetName() == wxT("__endpoint__") )
05529 {
05530
05531 if (restrictEngine )
05532 restrictEngine->RestrictPoint( xw, yw );
05533 SetPosXY2( xw, yw );
05534 draghandle->SetPosXY( m_x2, m_y2 );
05535 SetPending( true );
05536 }
05537 else
05538 event.Skip();
05539 }
05540 else
05541 event.Skip();
05542 }
05543 else
05544 {
05545 event.Skip();
05546 }
05547 }
05548
05549
05550
05551
05552
05553 a2dEndsLine::a2dEndsLine()
05554 : a2dSLine()
05555 {
05556 m_xscale = m_yscale = 1;
05557 m_takeStyleToArrow = false;
05558 }
05559
05560 a2dEndsLine::a2dEndsLine( double x1, double y1, double x2, double y2, double contourwidth )
05561 : a2dSLine(x1,y1,x2,y2,contourwidth)
05562 {
05563 m_xscale = m_yscale = 1;
05564 m_takeStyleToArrow = false;
05565 }
05566
05567 a2dEndsLine::a2dEndsLine( const a2dSLine &other, CloneOptions options )
05568 :a2dSLine( other, options )
05569 {
05570 m_xscale = m_yscale = 1;
05571 m_takeStyleToArrow = false;
05572 }
05573
05574 a2dEndsLine::a2dEndsLine( const a2dEndsLine &other, CloneOptions options )
05575 :a2dSLine( other, options )
05576 {
05577 if ( options & clone_members)
05578 {
05579 if ( other.m_begin )
05580 m_begin = other.m_begin->TClone( options );
05581 if ( other.m_end )
05582 m_end = other.m_end->TClone( options );
05583 }
05584 else
05585 {
05586 m_begin = other.m_begin;
05587 m_end = other.m_end;
05588 }
05589
05590 m_xscale = other.m_xscale;
05591 m_yscale = other.m_yscale;
05592 m_takeStyleToArrow = other.m_takeStyleToArrow;
05593 #if defined(_DEBUG) && defined (SMART_POINTER_DEBUG)
05594
05595 CurrentSmartPointerOwner = this;
05596 #endif
05597 }
05598
05599 a2dObject* a2dEndsLine::Clone( CloneOptions options ) const
05600 {
05601 return new a2dEndsLine( *this, options );
05602 }
05603
05604 a2dEndsLine::~a2dEndsLine()
05605 {
05606 }
05607
05608 void a2dEndsLine::SetBegin(a2dCanvasObject* begin)
05609 {
05610 SetPending(true);
05611 m_begin = begin;
05612 if (m_begin && m_root )
05613 m_begin->SetCanvasDocument( m_root );
05614 }
05615
05616 void a2dEndsLine::SetEnd(a2dCanvasObject* end)
05617 {
05618 SetPending(true);
05619 m_end = end;
05620 if (m_end && m_root )
05621 m_end->SetCanvasDocument( m_root);
05622 }
05623
05624 a2dBoundingBox a2dEndsLine::DoGetUnTransformedBbox( a2dBboxFlags flags ) const
05625 {
05626 a2dBoundingBox bbox;
05627 bbox = a2dSLine::DoGetUnTransformedBbox( flags );
05628
05629 if (m_begin )
05630 {
05631 double dx, dy;
05632 dx = m_x2-m_x1;
05633 dy = m_y2-m_y1;
05634 double ang1;
05635 if (!dx && !dy)
05636 ang1 = 0;
05637 else
05638 ang1 = wxRadToDeg(atan2(dy, dx));
05639
05640 a2dAffineMatrix lworld;
05641
05642 lworld.Scale(m_xscale, m_yscale, 0, 0);
05643 lworld.Rotate(-ang1);
05644 lworld.Translate(m_x1, m_y1);
05645
05646 bbox.Expand( m_begin->GetMappedBbox( lworld) );
05647 }
05648
05649 if (m_end )
05650 {
05651 double dx, dy;
05652 dx = m_x2-m_x1;
05653 dy = m_y2-m_y1;
05654 double ang2;
05655 if (!dx && !dy)
05656 ang2 = 0;
05657 else
05658 ang2 = wxRadToDeg(atan2(-dy, -dx));
05659
05660 a2dAffineMatrix tworld;
05661
05662 tworld.Scale(m_xscale, m_yscale, 0, 0);
05663 tworld.Rotate(-ang2);
05664 tworld.Translate(m_x2, m_y2);
05665
05666 bbox.Expand( m_end->GetMappedBbox( tworld) );
05667 }
05668 return bbox;
05669 }
05670
05671 bool a2dEndsLine::DoUpdate( UpdateMode mode, const a2dBoundingBox& childbox, const a2dBoundingBox& clipbox, const a2dBoundingBox& propbox )
05672 {
05673 bool calc = false;
05674 if (m_begin )
05675 {
05676 if ( m_takeStyleToArrow )
05677 {
05678 m_begin->SetFill( GetFill() );
05679 m_begin->SetStroke( GetStroke() );
05680 }
05681 calc = m_begin->Update( mode );
05682 }
05683 if (m_end )
05684 {
05685 if ( m_takeStyleToArrow )
05686 {
05687 m_end->SetFill( GetFill() );
05688 m_end->SetStroke( GetStroke() );
05689 }
05690 calc = m_end->Update( mode ) || calc;
05691 }
05692 if ( !m_bbox.GetValid() || calc)
05693 {
05694 m_bbox.SetValid(false);
05695 m_bbox = DoGetUnTransformedBbox();
05696
05697 m_bbox.MapBbox(m_lworld);
05698 return true;
05699 }
05700 return calc;
05701 }
05702
05703 void a2dEndsLine::DoRender( a2dIterC& ic, OVERLAP clipparent )
05704 {
05705 a2dSLine::DoRender( ic, clipparent );
05706
05707 if (m_begin )
05708 {
05709 double dx, dy;
05710 dx = m_x2-m_x1;
05711 dy = m_y2-m_y1;
05712 double ang1;
05713 if (!dx && !dy)
05714 ang1 = 0;
05715 else
05716 ang1 = wxRadToDeg(atan2(dy, dx));
05717
05718 a2dAffineMatrix lworld;
05719
05720 lworld.Scale(m_xscale, m_yscale, 0, 0);
05721 lworld.Rotate(-ang1);
05722 lworld.Translate(m_x1, m_y1);
05723 a2dIterCU cu( ic, lworld );
05724
05725
05726
05727
05728
05729 bool old = m_begin->GetChildrenOnSameLayer();
05730 m_begin->SetChildrenOnSameLayer(true);
05731 m_begin->Render( ic, clipparent );
05732 m_begin->SetChildrenOnSameLayer(old);
05733 }
05734
05735 if (m_end )
05736 {
05737 double dx, dy;
05738 dx = m_x2-m_x1;
05739 dy = m_y2-m_y1;
05740 double ang2;
05741 if (!dx && !dy)
05742 ang2 = 0;
05743 else
05744 ang2 = wxRadToDeg(atan2(-dy, -dx));
05745
05746 a2dAffineMatrix tworld;
05747
05748 tworld.Scale(m_xscale, m_yscale, 0, 0);
05749 tworld.Rotate(-ang2);
05750 tworld.Translate(m_x2, m_y2);
05751
05752 a2dIterCU cu( ic, tworld );
05753
05754 bool old = m_end->GetChildrenOnSameLayer();
05755 m_end->SetChildrenOnSameLayer(true);
05756 m_end->Render( ic, clipparent );
05757 m_end->SetChildrenOnSameLayer(old);
05758 }
05759 }
05760
05761 #if wxART2D_USE_CVGIO
05762 void a2dEndsLine::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
05763 {
05764 a2dSLine::DoSave( parent, out, xmlparts, towrite );
05765 if ( xmlparts == a2dXmlSer_attrib )
05766 {
05767 if (m_begin || m_end )
05768 {
05769 out.WriteAttribute( wxT("xscale"), m_xscale );
05770 out.WriteAttribute( wxT("yscale"), m_yscale );
05771 if ( m_begin )
05772 out.WriteAttribute( wxT("begin"), m_begin->GetUniqueSerializationId() );
05773 if ( m_end )
05774 out.WriteAttribute( wxT("end"), m_end->GetUniqueSerializationId() );
05775 }
05776 }
05777 else
05778 {
05779 if ( (m_begin && !m_begin->GetCheck()) ||
05780 (m_end && !m_end->GetCheck())
05781 )
05782 {
05783
05784 a2dCanvasObjectPtr begin = m_begin;
05785 a2dCanvasObjectPtr end = m_end;
05786
05787 out.WriteStartElement( wxT("derived") );
05788
05789 if ( m_begin && !m_begin->GetCheck() )
05790 m_begin->Save( this, out, towrite);
05791 if (m_end && !m_end->GetCheck() )
05792 m_end->Save( this, out, towrite);
05793
05794 out.WriteEndElement();
05795 }
05796 }
05797 }
05798
05799 void a2dEndsLine::DoLoad( wxObject* parent, a2dIOHandlerXmlSerIn& parser, a2dXmlSer_flag xmlparts )
05800 {
05801 a2dSLine::DoLoad( parent, parser, xmlparts );
05802 if ( xmlparts == a2dXmlSer_attrib )
05803 {
05804 m_xscale = parser.GetAttributeValueDouble( wxT("xscale") );
05805 m_yscale = parser.GetAttributeValueDouble( wxT("yscale") );
05806
05807 wxString resolveKey;
05808 if ( parser.HasAttribute( wxT("begin") ) )
05809 {
05810 parser.ResolveOrAdd( (a2dSmrtPtr<class a2dObject>*) &m_begin, parser.GetAttributeValue( wxT("begin") ) );
05811 }
05812 if ( parser.HasAttribute( wxT("end") ) )
05813 {
05814 parser.ResolveOrAdd( (a2dSmrtPtr<class a2dObject>*) &m_end, parser.GetAttributeValue( wxT("end") ) );
05815 }
05816 }
05817 else
05818 {
05819 if ( parser.GetTagName() != wxT("derived") )
05820 return;
05821
05822 parser.Require( START_TAG, wxT("derived") );
05823 parser.Next();
05824
05825 DoLoadOneObject( this, parser, xmlparts );
05826 DoLoadOneObject( this, parser, xmlparts );
05827
05828 parser.Require( END_TAG, wxT("derived") );
05829 parser.Next();
05830 }
05831 }
05832 #endif //wxART2D_USE_CVGIO
05833
05834 void a2dEndsLine::DoWalker( wxObject* parent, a2dWalkerIOHandler& handler )
05835 {
05836 handler.WalkTask( parent, this, a2dWalker_a2dDerivedCanvasObjectStart );
05837 a2dCanvasObject::DoWalker( parent, handler );
05838 if (m_begin)
05839 m_begin->Walker( this, handler );
05840
05841 if (m_end)
05842 m_end->Walker( this, handler );
05843
05844 handler.WalkTask( parent, this, a2dWalker_a2dDerivedCanvasObjectStart );
05845 }
05846
05847 bool a2dEndsLine::DoIsHitWorld( a2dIterC& ic, a2dHitEvent& hitEvent )
05848 {
05849 bool h = a2dSLine::DoIsHitWorld( ic, hitEvent );
05850
05851 if (!h)
05852 {
05853 if (m_begin )
05854 {
05855 double dx, dy;
05856 dx = m_x2-m_x1;
05857 dy = m_y2-m_y1;
05858 double ang1;
05859 if (!dx && !dy)
05860 ang1 = 0;
05861 else
05862 ang1 = wxRadToDeg(atan2(dy, dx));
05863
05864 a2dAffineMatrix lworld;
05865
05866 lworld.Scale(m_xscale,m_yscale,0,0);
05867 lworld.Rotate(-ang1);
05868 lworld.Translate(m_x1,m_y1);
05869 a2dIterCU cu( ic, lworld );
05870 h = m_begin->IsHitWorld( ic, hitEvent ) != 0;
05871 }
05872
05873 if (!h && m_end )
05874 {
05875 double dx, dy;
05876 dx = m_x2-m_x1;
05877 dy = m_y2-m_y1;
05878 double ang2;
05879 if (!dx && !dy)
05880 ang2 = 0;
05881 else
05882 ang2 = wxRadToDeg(atan2(-dy, -dx));
05883
05884 a2dAffineMatrix tworld;
05885
05886 tworld.Scale(m_xscale, m_yscale, 0, 0);
05887 tworld.Rotate(-ang2);
05888 tworld.Translate(m_x2, m_y2);
05889 a2dIterCU cu( ic, tworld );
05890 h = m_end->IsHitWorld( ic, hitEvent ) != 0;
05891 }
05892 }
05893
05894 if (h)
05895 {
05896 hitEvent.m_how = a2dHit::stock_strokeoutside;
05897 return true;
05898 }
05899 hitEvent.m_how = a2dHit::stock_nohit;
05900 return false;
05901 }
05902
05903
05904
05905
05906 #define L1 2
05907 #define L2 1
05908 #define B 1
05909
05910 A2D_BEGIN_EVENT_TABLE( a2dScaledEndLine, a2dEndsLine )
05911 A2D_END_EVENT_TABLE()
05912
05913 a2dScaledEndLine::a2dScaledEndLine()
05914 : a2dEndsLine()
05915 {
05916 m_xscale = m_yscale = 1;
05917 m_begin = new a2dArrow( 0,0, L1, L2, B);
05918 m_end = new a2dArrow( 0,0, L1, L2, B);
05919 }
05920
05921 a2dScaledEndLine::a2dScaledEndLine( double x1, double y1, double x2, double y2, double contourwidth )
05922 : a2dEndsLine(x1,y1,x2,y2,contourwidth)
05923 {
05924 m_begin = new a2dArrow( 0,0, L1, L2, B);
05925 m_end = new a2dArrow( 0,0, L1, L2, B);
05926
05927 m_xscale = m_yscale = 1;
05928 }
05929
05930 a2dScaledEndLine::a2dScaledEndLine( const a2dSLine &other, CloneOptions options )
05931 :a2dEndsLine( other, options )
05932 {
05933 m_xscale = m_yscale = 1;
05934 }
05935
05936 a2dScaledEndLine::a2dScaledEndLine( const a2dScaledEndLine &other, CloneOptions options )
05937 :a2dEndsLine( other, options )
05938 {
05939 }
05940
05941 a2dObject* a2dScaledEndLine::Clone( CloneOptions options ) const
05942 {
05943 return new a2dScaledEndLine( *this, options );
05944 }
05945
05946 a2dScaledEndLine::~a2dScaledEndLine()
05947 {
05948 }
05949
05950 void a2dScaledEndLine::SetBegin( double l1, double l2, double b, bool spline )
05951 {
05952 if ( m_begin && wxDynamicCast( m_begin.Get(), a2dArrow) )
05953 wxStaticCast( m_begin.Get(), a2dArrow)->Set( l1, l2, b, spline );
05954 SetPending(true);
05955 }
05956
05957 void a2dScaledEndLine::SetEnd( double l1, double l2, double b, bool spline )
05958 {
05959 if ( m_end && wxDynamicCast( m_end.Get(), a2dArrow) )
05960 wxStaticCast( m_end.Get(), a2dArrow)->Set( l1, l2, b, spline );
05961 SetPending(true);
05962 }
05963
05964 bool a2dScaledEndLine::DoUpdate( UpdateMode mode, const a2dBoundingBox& childbox, const a2dBoundingBox& clipbox, const a2dBoundingBox& propbox )
05965 {
05966 bool calc = false;
05967 if (m_begin )
05968 {
05969 if ( m_takeStyleToArrow )
05970 {
05971 m_begin->SetFill( GetFill() );
05972 m_begin->SetStroke( GetStroke() );
05973 }
05974 m_xscale = m_contourwidth;
05975 m_yscale = m_contourwidth;
05976 calc = m_begin->Update( mode );
05977 }
05978 if (m_end )
05979 {
05980 if ( m_takeStyleToArrow )
05981 {
05982 m_end->SetFill( GetFill() );
05983 m_end->SetStroke( GetStroke() );
05984 }
05985 m_xscale = m_contourwidth;
05986 m_yscale = m_contourwidth;
05987 calc = m_end->Update( mode ) || calc;
05988 }
05989 if ( !m_bbox.GetValid() || calc)
05990 {
05991 m_bbox.SetValid(false);
05992 m_bbox = DoGetUnTransformedBbox();
05993
05994 m_bbox.MapBbox(m_lworld);
05995 return true;
05996 }
05997 return calc;
05998 }
05999
06000 void a2dScaledEndLine::DoRender( a2dIterC& ic, OVERLAP clipparent )
06001 {
06002 if ( m_contourwidth )
06003 {
06004 a2dLine line1( m_x1, m_y1, m_x2, m_y2 );
06005 line1.CalculateLineParameters();
06006 double distance = m_contourwidth / 2.0;
06007 if ( distance == 0 )
06008 distance = 1;
06009
06010 a2dPoint2D layBackBegin( m_x1, m_y1 );
06011 a2dPoint2D layBackEnd( m_x2, m_y2 );
06012
06013
06014 if ( m_begin && wxDynamicCast( m_begin.Get(), a2dArrow) )
06015 {
06016 a2dArrow* arrow1 = wxStaticCast( m_begin.Get(), a2dArrow);
06017 double baseD2B = arrow1->GetBase()/2.0;
06018 double l1B = arrow1->GetL1();
06019 double layBackB = l1B * distance / baseD2B;
06020 layBackBegin = line1.DistancePoint( layBackB, true );
06021 }
06022 if ( m_end && wxDynamicCast( m_end.Get(), a2dArrow) )
06023 {
06024 a2dArrow* arrow2 = wxStaticCast( m_end.Get(), a2dArrow);
06025 double baseD2E = arrow2->GetBase()/2.0;
06026 double l1E = arrow2->GetL1();
06027 double layBackE = l1E * distance / baseD2E;
06028 layBackEnd = line1.DistancePoint( -layBackE, false );
06029 }
06030
06031 a2dPoint2D offsetpoint1left = layBackBegin;
06032 a2dPoint2D offsetpoint1right = layBackBegin;
06033 a2dPoint2D offsetpoint2left = layBackEnd;
06034 a2dPoint2D offsetpoint2right = layBackEnd;
06035
06036 line1.Virtual_Point( offsetpoint1left, distance );
06037 line1.Virtual_Point( offsetpoint1right, -distance );
06038 line1.Virtual_Point( offsetpoint2left, distance );
06039 line1.Virtual_Point( offsetpoint2right, -distance );
06040
06041 a2dVertexArray contour;
06042 contour.AddPoint( offsetpoint1left );
06043 contour.AddPoint( offsetpoint2left );
06044 contour.AddPoint( offsetpoint2right );
06045 contour.AddPoint( offsetpoint1right );
06046
06047 ic.GetDrawer2D()->DrawPolygon( &contour );
06048
06049 if (m_begin )
06050 {
06051 double dx, dy;
06052 dx = m_x2-m_x1;
06053 dy = m_y2-m_y1;
06054 double ang1;
06055 if (!dx && !dy)
06056 ang1 = 0;
06057 else
06058 ang1 = wxRadToDeg(atan2(dy, dx));
06059
06060 a2dAffineMatrix lworld;
06061
06062 lworld.Scale(m_xscale, m_yscale, 0, 0);
06063 lworld.Rotate(-ang1);
06064 lworld.Translate(m_x1, m_y1);
06065 a2dIterCU cu( ic, lworld );
06066
06067
06068
06069
06070
06071 bool old = m_begin->GetChildrenOnSameLayer();
06072 m_begin->SetChildrenOnSameLayer(true);
06073 m_begin->Render( ic, clipparent );
06074 m_begin->SetChildrenOnSameLayer(old);
06075 }
06076
06077 if (m_end )
06078 {
06079 double dx, dy;
06080 dx = m_x2-m_x1;
06081 dy = m_y2-m_y1;
06082 double ang2;
06083 if (!dx && !dy)
06084 ang2 = 0;
06085 else
06086 ang2 = wxRadToDeg(atan2(-dy, -dx));
06087
06088 a2dAffineMatrix tworld;
06089
06090 tworld.Scale(m_xscale, m_yscale, 0, 0);
06091 tworld.Rotate(-ang2);
06092 tworld.Translate(m_x2, m_y2);
06093
06094 a2dIterCU cu( ic, tworld );
06095
06096 bool old = m_end->GetChildrenOnSameLayer();
06097 m_end->SetChildrenOnSameLayer(true);
06098 m_end->Render( ic, clipparent );
06099 m_end->SetChildrenOnSameLayer(old);
06100 }
06101 }
06102 else
06103 {
06104 ic.GetDrawer2D()->DrawLine( m_x1, m_y1, m_x2, m_y2 );
06105 }
06106
06107 }
06108
06109
06110
06111
06112
06113 a2dEndsEllipticChord::a2dEndsEllipticChord()
06114 : a2dEllipticArc()
06115 {
06116 m_xscale = m_yscale = 1;
06117 }
06118
06119 a2dEndsEllipticChord::a2dEndsEllipticChord( double xc, double yc, double width, double height, double start, double end )
06120 : a2dEllipticArc( xc, yc, width, height, start, end, true )
06121 {
06122 m_xscale = m_yscale = 1;
06123 }
06124
06125 a2dEndsEllipticChord::a2dEndsEllipticChord( const a2dEndsEllipticChord &other, CloneOptions options )
06126 :a2dEllipticArc( other, options )
06127 {
06128 if ( options & clone_members )
06129 {
06130 if ( other.m_beginobj )
06131 m_beginobj = other.m_beginobj->TClone( options );
06132 if ( other.m_endobj )
06133 m_endobj = other.m_endobj->TClone( options );
06134 }
06135 else
06136 {
06137 m_beginobj = other.m_beginobj;
06138 m_endobj = other.m_endobj;
06139 }
06140
06141 m_xscale = other.m_xscale;
06142 m_yscale = other.m_yscale;
06143 #if defined(_DEBUG) && defined (SMART_POINTER_DEBUG)
06144
06145 CurrentSmartPointerOwner = this;
06146 #endif
06147 }
06148
06149 a2dObject* a2dEndsEllipticChord::Clone( CloneOptions options ) const
06150 {
06151 return new a2dEndsEllipticChord( *this, options );
06152 };
06153
06154 a2dEndsEllipticChord::~a2dEndsEllipticChord()
06155 {
06156 }
06157
06158 void a2dEndsEllipticChord::SetBeginObj(a2dCanvasObject* begin)
06159 {
06160 SetPending(true);
06161 m_beginobj = begin;
06162 if (m_beginobj && m_root )
06163 m_beginobj->SetCanvasDocument( m_root );
06164 }
06165
06166 void a2dEndsEllipticChord::SetEndObj(a2dCanvasObject* end)
06167 {
06168 SetPending(true);
06169 m_endobj = end;
06170 if (m_endobj && m_root )
06171 m_endobj->SetCanvasDocument( m_root);
06172 }
06173
06174 a2dBoundingBox a2dEndsEllipticChord::DoGetUnTransformedBbox( a2dBboxFlags flags ) const
06175 {
06176 a2dBoundingBox bbox = a2dEllipticArc::DoGetUnTransformedBbox( flags );
06177
06178 if (m_beginobj )
06179 {
06180 bbox.Expand( m_beginobj->GetMappedBbox( GetBeginTransform() ) );
06181 }
06182
06183 if (m_endobj )
06184 {
06185 bbox.Expand( m_endobj->GetMappedBbox( GetEndTransform() ) );
06186 }
06187 return bbox;
06188 }
06189
06190 bool a2dEndsEllipticChord::DoUpdate( UpdateMode mode, const a2dBoundingBox& childbox, const a2dBoundingBox& clipbox, const a2dBoundingBox& propbox )
06191 {
06192 bool calc = false;
06193 if (m_beginobj )
06194 {
06195 calc = m_beginobj->Update( mode );
06196 }
06197 if (m_endobj )
06198 {
06199 calc = m_endobj->Update( mode ) || calc;
06200 }
06201 if ( !m_bbox.GetValid() || calc )
06202 {
06203 m_bbox.SetValid(false);
06204 m_bbox = DoGetUnTransformedBbox();
06205
06206 m_bbox.MapBbox(m_lworld);
06207 return true;
06208 }
06209 return calc;
06210 }
06211
06212 void a2dEndsEllipticChord::DoRender( a2dIterC& ic, OVERLAP clipparent )
06213 {
06214 a2dEllipticArc::DoRender( ic, clipparent );
06215
06216 if (m_beginobj )
06217 {
06218 a2dIterCU cu( ic, GetBeginTransform() );
06219
06220
06221
06222
06223
06224 bool old = m_beginobj->GetChildrenOnSameLayer();
06225 m_beginobj->SetChildrenOnSameLayer(true);
06226 m_beginobj->Render( ic, clipparent );
06227 m_beginobj->SetChildrenOnSameLayer(old);
06228 }
06229
06230 if (m_endobj )
06231 {
06232 a2dIterCU cu( ic, GetEndTransform() );
06233
06234 bool old = m_endobj->GetChildrenOnSameLayer();
06235 m_endobj->SetChildrenOnSameLayer(true);
06236 m_endobj->Render( ic, clipparent );
06237 m_endobj->SetChildrenOnSameLayer(old);
06238 }
06239 }
06240
06241 void a2dEndsEllipticChord::DoWalker( wxObject* parent, a2dWalkerIOHandler& handler )
06242 {
06243 handler.WalkTask( parent, this, a2dWalker_a2dDerivedCanvasObjectStart );
06244 a2dCanvasObject::DoWalker( parent, handler );
06245 if (m_beginobj)
06246 m_beginobj->Walker( this, handler );
06247
06248 if (m_endobj)
06249 m_endobj->Walker( this, handler );
06250
06251 handler.WalkTask( parent, this, a2dWalker_a2dDerivedCanvasObjectStart );
06252 }
06253
06254 #if wxART2D_USE_CVGIO
06255 void a2dEndsEllipticChord::DoSave( wxObject* parent, a2dIOHandlerXmlSerOut &out, a2dXmlSer_flag xmlparts , a2dObjectList* towrite )
06256 {
06257 a2dEllipticArc::DoSave( parent, out, xmlparts, towrite );
06258 if ( xmlparts == a2dXmlSer_attrib )
06259 {
06260 if (m_beginobj || m_endobj )
06261 {
06262 out.WriteAttribute( wxT("xscale"), m_xscale );
06263 out.WriteAttribute( wxT("yscale"), m_yscale );
06264 if ( m_beginobj )
06265 out.WriteAttribute( wxT("beginobj"), m_beginobj->GetUniqueSerializationId() );
06266 if ( m_endobj )
06267 out.WriteAttribute( wxT("endobj"), m_endobj->GetUniqueSerializationId() );
06268 }
06269 }
06270 else
06271 {
06272 if ( (m_beginobj && !m_beginobj->GetCheck()) ||
06273 (m_endobj && !m_endobj->GetCheck())
06274 )
06275 {
06276
06277 a2dCanvasObjectPtr begin = m_beginobj;
06278 a2dCanvasObjectPtr end = m_endobj;
06279
06280 out.WriteStartElement( wxT("derived") );
06281
06282 if ( m_beginobj && !m_beginobj->GetCheck() )
06283 m_beginobj->Save( this, out, towrite);
06284 if (m_endobj && !m_endobj->GetCheck() )
06285 m_endobj->Save( this, out, towrite);
06286
06287 out.WriteEndElement();
06288 }
06289 }
06290 }
06291
06292 void a2dEndsEllipticChord::DoLoad( wxObject* parent, a2dIOHandlerXmlSerIn& parser, a2dXmlSer_flag xmlparts )
06293 {
06294 a2dEllipticArc::DoLoad( parent, parser, xmlparts );
06295 if ( xmlparts == a2dXmlSer_attrib )
06296 {
06297 m_xscale = parser.GetAttributeValueDouble( wxT("xscale") );
06298 m_yscale = parser.GetAttributeValueDouble( wxT("yscale") );
06299 if ( parser.HasAttribute( wxT("beginobj") ) )
06300 {
06301 parser.ResolveOrAdd( (a2dSmrtPtr<class a2dObject>*) &m_beginobj, parser.GetAttributeValue( wxT("beginobj") ) );
06302 }
06303 if ( parser.HasAttribute( wxT("endobj") ) )
06304 {
06305 parser.ResolveOrAdd( (a2dSmrtPtr<class a2dObject>*) &m_endobj, parser.GetAttributeValue( wxT("endobj") ) );
06306 }
06307 }
06308 else
06309 {
06310 if ( parser.GetTagName() != wxT("derived") )
06311 return;
06312
06313 parser.Require( START_TAG, wxT("derived") );
06314 parser.Next();
06315
06316 DoLoadOneObject( this, parser, xmlparts );
06317 DoLoadOneObject( this, parser, xmlparts );
06318
06319 parser.Require( END_TAG, wxT("derived") );
06320 parser.Next();
06321 }
06322 }
06323 #endif //wxART2D_USE_CVGIO
06324
06325 bool a2dEndsEllipticChord::DoIsHitWorld( a2dIterC& ic, a2dHitEvent& hitEvent )
06326 {
06327 bool h = a2dEllipticArc::DoIsHitWorld( ic, hitEvent );
06328
06329 if (!h)
06330 {
06331 if (m_beginobj )
06332 {
06333 a2dIterCU cu( ic, GetBeginTransform() );
06334 h = m_beginobj->IsHitWorld( ic, hitEvent ) != 0;
06335 }
06336
06337 if (!h && m_endobj)
06338 {
06339 a2dIterCU cu( ic, GetEndTransform() );
06340 h = m_endobj->IsHitWorld( ic, hitEvent ) != 0;
06341 }
06342 }
06343
06344 if (h)
06345 {
06346 hitEvent.m_how = a2dHit::stock_strokeoutside;
06347 return true;
06348 }
06349 hitEvent.m_how = a2dHit::stock_nohit;
06350 return false;
06351 }
06352
06353 a2dAffineMatrix a2dEndsEllipticChord::GetBeginTransform() const
06354 {
06355 double ang1 = wxRadToDeg( atan2( sin ( wxDegToRad( m_start + 90 ) ) * m_height, cos ( wxDegToRad( m_start + 90 ) ) * m_width ) );
06356 double x1 = m_width/2 * cos( wxDegToRad( m_start ) );
06357 double y1 = m_height/2 * sin( wxDegToRad( m_start ) );
06358
06359 a2dAffineMatrix lworld;
06360
06361 lworld.Scale(m_xscale, m_yscale, 0, 0);
06362 lworld.Rotate(-ang1);
06363 lworld.Translate(x1, y1);
06364
06365 return lworld;
06366 }
06367
06368 a2dAffineMatrix a2dEndsEllipticChord::GetEndTransform() const
06369 {
06370 double ang2 = wxRadToDeg( atan2( sin ( wxDegToRad( m_end - 90 ) ) * m_height, cos ( wxDegToRad( m_end - 90 ) ) * m_width ) );
06371 double x2 = m_width/2 * cos( wxDegToRad( m_end ) );
06372 double y2 = m_height/2 * sin( wxDegToRad( m_end ) );
06373
06374 a2dAffineMatrix lworld;
06375
06376 lworld.Scale(m_xscale, m_yscale, 0, 0);
06377 lworld.Rotate(-ang2);
06378 lworld.Translate(x2, y2);
06379
06380 return lworld;
06381 }
06382
06383
06384
06385
06386
06387 a2dControl::a2dControl( double x, double y, double width, double height, wxWindow *control )
06388 : a2dRect( x, y, width, height )
06389 {
06390 m_control = control;
06391 m_control->Show( false );
06392 }
06393
06394 a2dControl::~a2dControl()
06395 {
06396
06397
06398
06399
06400 }
06401
06402 a2dControl::a2dControl( const a2dControl &other, CloneOptions options )
06403 :a2dRect( other, options )
06404 {
06405 m_control = other.m_control;
06406 int x,y ;
06407 other.m_control->GetPosition( &x, &y );
06408 m_control->Move(x,y);
06409
06410 SetPending(true);
06411 }
06412
06413 a2dObject* a2dControl::Clone( CloneOptions options ) const
06414 {
06415 return new a2dControl( *this, options );
06416 };
06417
06418 bool a2dControl::DoUpdate( UpdateMode mode, const a2dBoundingBox& childbox, const a2dBoundingBox& clipbox, const a2dBoundingBox& propbox )
06419 {
06420 if ( !m_bbox.GetValid() )
06421 {
06422 return a2dRect::DoUpdate( mode, childbox, clipbox, propbox );
06423 }
06424 return false;
06425 }
06426
06427 void a2dControl::DoRender( a2dIterC& ic, OVERLAP clipparent )
06428 {
06429 if ( ic.GetCanvasView()->GetDisplayWindow() && m_control->GetParent() != ic.GetCanvasView()->GetDisplayWindow() )
06430 return;
06431
06432 if ( m_flags.m_editingCopy )
06433 {
06434 int xd = ic.GetDrawer2D()->WorldToDeviceX( GetPosX() );
06435 int yd = ic.GetDrawer2D()->WorldToDeviceY( GetPosY() );
06436 m_control->Move(xd,yd);
06437 }
06438
06439 a2dRect::DoRender( ic, clipparent );
06440 }
06441
06442 bool a2dControl::DoIsHitWorld( a2dIterC& WXUNUSED(ic), a2dHitEvent& hitEvent )
06443 {
06444 hitEvent.m_how = a2dHit::stock_fill;
06445 return true;
06446 }
06447
06448 bool a2dControl::DoStartEdit( wxUint16 editmode, wxEditStyle editstyle )
06449 {
06450 if ( m_flags.m_editable )
06451 {
06452 if ( editmode == 1 )
06453 {
06454 m_flags.m_visiblechilds = true;
06455 m_flags.m_childrenOnSameLayer = true;
06456
06457 m_control->Show( true );
06458 return true;
06459 }
06460 else
06461 {
06462 PROPID_IncludeChildren->SetPropertyToObject( this, false );
06463 PROPID_Allowrotation->SetPropertyToObject( this, true );
06464 PROPID_Allowskew->SetPropertyToObject( this, true );
06465
06466 return a2dWH::DoStartEdit( editmode, editstyle );
06467 }
06468 }
06469
06470 return false;
06471 }
06472
06473 void a2dControl::DoEndEdit()
06474 {
06475 m_control->Show( false );
06476 SetPending(true);
06477 }
06478
06479
06480
06481
06482 a2dWires::a2dWires()
06483 {
06484 m_childobjects = new a2dCanvasObjectList();
06485 m_frozen = false;
06486 m_flags.m_draggable = false;
06487 }
06488
06489 a2dWires::a2dWires( a2dCanvasObject* toconnect, const wxString& pinname )
06490 :a2dCanvasObject()
06491 {
06492 m_flags.m_draggable = false;
06493 bool done = false;
06494
06495 m_childobjects = new a2dCanvasObjectList();
06496
06497 m_frozen = false;
06498
06499 for( a2dCanvasObjectList::iterator iter = toconnect->GetChildObjectList()->begin(); iter != toconnect->GetChildObjectList()->end(); ++iter )
06500 {
06501 a2dPin* pinc = wxDynamicCast( (*iter).Get(), a2dPin );
06502 if ( pinc )
06503 {
06504 if ( pinname == pinc->GetName() )
06505 {
06506 wxASSERT_MSG( pinc->ConnectedTo() == NULL , wxT("this pin is already connected") );
06507
06508 a2dPin* newpin = new a2dPin( this, wxT("pin1"), a2dPinClass::Standard, pinc->GetAbsX(), pinc->GetAbsY(), 180 - pinc->GetAbsAngle() );
06509 Append( newpin );
06510
06511 pinc->ConnectTo( newpin );
06512 newpin->ConnectTo( pinc );
06513 done = true;
06514 }
06515 }
06516 }
06517
06518 wxASSERT_MSG( done, wxT("no such pin to connect to") );
06519 }
06520
06521 a2dWires::a2dWires( a2dCanvasObject* toConnect, a2dPin* pinc )
06522 :a2dCanvasObject()
06523 {
06524 bool done = false;
06525 wxASSERT_MSG( pinc->GetParent() == toConnect, wxT("this pin has not connect object as parent") );
06526 wxASSERT_MSG( pinc->ConnectedTo() == NULL , wxT("this pin is already connected") );
06527
06528 for( a2dCanvasObjectList::iterator iter = toConnect->GetChildObjectList()->begin(); iter != toConnect->GetChildObjectList()->end(); ++iter )
06529 {
06530 a2dCanvasObject *obj = *iter;
06531 a2dPin* pinother = wxDynamicCast( obj, a2dPin );
06532 if ( pinother == pinc )
06533 {
06534 done=true;
06535 break;
06536 }
06537 }
06538
06539 wxASSERT_MSG( done, wxT("this pin is not in to connect object") );
06540
06541 m_flags.m_hasPins = true;
06542
06543 m_childobjects = new a2dCanvasObjectList();
06544
06545 m_frozen = false;
06546
06547 a2dPin* newpin = new a2dPin( this, wxT("pin1"), a2dPinClass::Standard, pinc->GetAbsX(), pinc->GetAbsY(), 180 - pinc->GetAbsAngle() );
06548 Append( newpin );
06549
06550 pinc->ConnectTo( newpin );
06551 newpin->ConnectTo( pinc );
06552 #if defined(_DEBUG) && defined (SMART_POINTER_DEBUG)
06553
06554 CurrentSmartPointerOwner = this;
06555 #endif
06556 }
06557
06558 a2dWires::~a2dWires()
06559 {
06560 }
06561
06562 a2dObject* a2dWires::Clone( CloneOptions WXUNUSED(options) ) const
06563 {
06564 a2dWires* a = new a2dWires();
06565
06566 return a;
06567 };
06568
06569 bool a2dWires::IsConnect() const
06570 {
06571 return true;
06572 }
06573
06574 bool a2dWires::ConnectWith( a2dCanvasObject* parent, a2dCanvasObject* toConnect, const wxString& pinname, double margin, bool WXUNUSED(undo) )
06575 {
06576 bool done=false;
06577
06578 for( a2dCanvasObjectList::iterator iter = m_childobjects->begin(); iter != m_childobjects->end(); ++iter )
06579 {
06580 a2dCanvasObject *obj = *iter;
06581 a2dPin* pinc = wxDynamicCast( obj, a2dPin );
06582 if ( pinc )
06583 {
06584 if (pinname.IsEmpty())
06585 {
06586
06587 for( a2dCanvasObjectList::iterator itero = toConnect->GetChildObjectList()->begin(); itero != toConnect->GetChildObjectList()->end(); ++itero )
06588 {
06589 a2dCanvasObject *obj = *itero;
06590 a2dPin* pinother = wxDynamicCast( obj, a2dPin );
06591 if ( pinother )
06592 {
06593 if ( fabs( pinother->GetAbsX() - pinc->GetAbsX() ) < margin &&
06594 fabs( pinother->GetAbsY() - pinc->GetAbsY() ) < margin )
06595 {
06596 ConnectPins( parent, pinc, pinother );
06597 done = true;
06598 }
06599 }
06600 }
06601 }
06602 else
06603 {
06604
06605 for( a2dCanvasObjectList::iterator itero = toConnect->GetChildObjectList()->begin(); itero != toConnect->GetChildObjectList()->end(); ++itero )
06606 {
06607 a2dCanvasObject *obj = *itero;
06608 a2dPin* pinother = wxDynamicCast( obj, a2dPin );
06609 if ( pinother && pinname == pinother->GetName())
06610 {
06611 if ( fabs( pinother->GetAbsX() - pinc->GetAbsX() ) < margin &&
06612 fabs( pinother->GetAbsY() - pinc->GetAbsY() ) < margin )
06613 {
06614 ConnectPins( parent, pinc, pinother );
06615 done = true;
06616 }
06617 }
06618 }
06619 }
06620 }
06621 }
06622
06623 if ( !done )
06624 {
06625 wxString nextpin = wxT("pin");
06626 nextpin << GetPinCount()+1;
06627
06628
06629 for( a2dCanvasObjectList::iterator itero = toConnect->GetChildObjectList()->begin(); itero != toConnect->GetChildObjectList()->end(); ++itero )
06630 {
06631 a2dCanvasObject *obj = *itero;
06632 a2dPin* pinother = wxDynamicCast( obj, a2dPin );
06633 if ( pinother )
06634 {
06635 if ( pinname == pinother->GetName() )
06636 {
06637 a2dPin* newpin = new a2dPin( this, nextpin, a2dPinClass::Standard, pinother->GetAbsX(), pinother->GetAbsY(), 180 - pinother->GetAbsAngle() );
06638 Append( newpin );
06639
06640 pinother->ConnectTo( newpin );
06641 newpin->ConnectTo( pinother );
06642 done=true;
06643 }
06644 }
06645 }
06646 }
06647
06648 SetPending(true);
06649
06650 return done;
06651 }
06652
06653 bool a2dWires::ConnectWith( a2dCanvasObject* WXUNUSED(parent), a2dPin* pin, double margin, bool WXUNUSED(undo) )
06654 {
06655 wxASSERT_MSG( pin->ConnectedTo() == 0, _("This pin is already connected to some other pin, not allowed.") );
06656
06657 if ( pin->GetParent() == this )
06658 return false;
06659
06660 bool done=false;
06661
06662 a2dCanvasObjectList::iterator iter;
06663
06664 for( iter = m_childobjects->begin(); iter != m_childobjects->end(); ++iter )
06665 {
06666 a2dCanvasObject *obj = *iter;
06667 a2dPin* pinc = wxDynamicCast( obj, a2dPin );
06668 if ( pinc && pinc == pin )
06669 {
06670 return true;
06671 }
06672 }
06673
06674
06675 for( iter = m_childobjects->begin(); iter != m_childobjects->end(); ++iter )
06676 {
06677 a2dCanvasObject *obj = *iter;
06678 a2dPin* pinc = wxDynamicCast( obj, a2dPin );
06679 if ( pinc )
06680 {
06681 if ( fabs( pinc->GetAbsX() - pin->GetAbsX() ) < margin &&
06682 fabs( pinc->GetAbsY() - pin->GetAbsY() ) < margin )
06683 {
06684 if ( !pinc->ConnectedTo() )
06685 {
06686 pin->ConnectTo( pinc );
06687 pinc->ConnectTo( pin );
06688 }
06689 done = true;
06690 }
06691 }
06692 }
06693
06694 if ( !done )
06695 {
06696 wxString nextpin = wxT("pin");
06697 nextpin << GetPinCount()+1;
06698
06699
06700 a2dPin* newpin = new a2dPin( this, nextpin, a2dPinClass::Standard, pin->GetAbsX(), pin->GetAbsY(), 180 - pin->GetAbsAngle() );
06701 Append( newpin );
06702
06703 pin->ConnectTo( newpin );
06704 newpin->ConnectTo( pin );
06705 }
06706
06707 SetPending(true);
06708
06709 return true;
06710 }
06711
06712 bool a2dWires::DoUpdate( UpdateMode mode, const a2dBoundingBox& childbox, const a2dBoundingBox& clipbox, const a2dBoundingBox& propbox )
06713 {
06714 for( a2dCanvasObjectList::iterator iter = m_childobjects->begin(); iter != m_childobjects->end(); ++iter )
06715 {
06716 a2dCanvasObject *obj = *iter;
06717 a2dPin* pinc = wxDynamicCast( obj, a2dPin );
06718 if ( pinc && pinc->ConnectedTo() )
06719 {
06720 pinc->Set( pinc->ConnectedTo()->GetAbsX(), pinc->ConnectedTo()->GetAbsY(), 180 - pinc->ConnectedTo()->GetAbsAngle() );
06721 }
06722 }
06723
06724
06725 if ( m_childobjects != wxNullCanvasObjectList && m_flags.m_visiblechilds)
06726 {
06727 for( a2dCanvasObjectList::iterator iter = m_childobjects->begin(); iter != m_childobjects->end(); ++iter )
06728 {
06729 a2dCanvasObject *obj = *iter;
06730 obj->Update( mode );
06731
06732
06733
06734 }
06735 }
06736
06737
06738
06739
06740
06741
06742
06743
06744
06745
06746
06747
06748
06749
06750
06751
06752
06753
06754
06755
06756
06757
06758
06759
06760
06761
06762
06763
06764
06765 return true;
06766 }
06767
06768 void a2dWires::DoRender( a2dIterC& ic, OVERLAP WXUNUSED(clipparent) )
06769 {
06770
06771 a2dAffineMatrix inverse = m_lworld;
06772 inverse.Invert();
06773
06774 a2dAffineMatrix untrans = ic.GetTransform();
06775 untrans *= inverse;
06776
06777
06778 a2dBoundingBox absarea = GetMappedBbox( untrans);
06779
06780 #ifdef CANVASDEBUG
06781
06782 a2dBoundingBox bbox = DoGetUnTransformedBbox( ic );
06783 a2dRect* tmp = new a2dRect( absarea.GetMinX() , absarea.GetMinY() , absarea.GetWidth() , absarea.GetHeight() );
06784 tmp->SetIgnoreSetpending();
06785 tmp->Own();
06786 tmp->SetCanvasDocument(m_root);
06787 tmp->Update( ic, true);
06788 tmp->SetFill( a2dTRANSPARENT_FILL );
06789 tmp->SetStroke( ic.GetDrawer2D()->GetDrawerStroke() );
06790 tmp->Render( cworld, _ON, layer, mask );
06791 tmp->Release();
06792 #endif
06793
06794 if ( ic.GetDrawer2D()->GetClippingBox().Intersect( absarea ) != _OUT )
06795 {
06796 for( a2dCanvasObjectList::iterator iter = m_childobjects->begin(); iter != m_childobjects->end(); ++iter )
06797 {
06798 a2dCanvasObject *obj = *iter;
06799 a2dPin* pinc = wxDynamicCast( obj, a2dPin );
06800
06801 if ( pinc )
06802 {
06803 double x = pinc->GetAbsX();
06804 double y = pinc->GetAbsY();
06805
06806 for( a2dCanvasObjectList::iterator itero = m_childobjects->begin(); itero != m_childobjects->end(); ++itero )
06807 {
06808 a2dCanvasObject *obj = *itero;
06809 a2dPin* pinother = wxDynamicCast( obj, a2dPin );
06810
06811 if ( pinother && pinother != pinc )
06812 {
06813 double x2 = pinother->GetAbsX();
06814 double y2 = pinother->GetAbsY();
06815
06816 ic.GetDrawer2D()->DrawLine(x,y,x2,y2);
06817 }
06818 }
06819 }
06820 }
06821 }
06822 }
06823
06824 void a2dWires::CreateWires()
06825 {
06826 for( a2dCanvasObjectList::iterator iter = m_childobjects->begin(); iter != m_childobjects->end(); ++iter )
06827 {
06828 a2dCanvasObject *obj = *iter;
06829 a2dPin* pinc = wxDynamicCast( obj, a2dPin );
06830 if ( pinc )
06831 {
06832 double x = pinc->GetPosX();
06833 double y = pinc->GetPosY();
06834
06835 for( a2dCanvasObjectList::iterator itero = m_childobjects->begin(); itero != m_childobjects->end(); ++itero )
06836 {
06837 a2dCanvasObject *obj = *itero;
06838 a2dPin* pinother = wxDynamicCast( obj, a2dPin );
06839 if ( pinother && pinother != pinc )
06840 {
06841 double x2 = pinother->GetPosX();
06842 double y2 = pinother->GetPosY();
06843
06844
06845
06846
06847 a2dSmrtPtr<a2dSLine> a = new a2dSLine(x,y,x2,y2);
06848 a->SetLayer( wxLAYER_DEFAULT );
06849
06850
06851 a->SetSpecificFlags( true, a2dCanvasOFlags::A);
06852 a->SetCanvasDocument(m_root);
06853 Append(a);
06854 }
06855 }
06856 }
06857 }
06858 }