00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "a2dprec.h"
00013
00014 #ifdef __BORLANDC__
00015 #pragma hdrstop
00016 #endif
00017
00018 #ifndef WX_PRECOMP
00019 #include "wx/wx.h"
00020 #endif
00021
00022 #include <float.h>
00023 #include "wx/artbase/afmatrix.h"
00024 #include "wx/general/gen.h"
00025 #include "wx/canvas/restrict.h"
00026 #include "wx/canvas/canobj.h"
00027 #include "wx/canvas/cancom.h"
00028 #include "wx/canvas/objlist.h"
00029 #include "wx/artbase/drawer2d.h"
00030
00031 static inline double sqr(double val) {return val*val;}
00032
00033 #if 0
00034
00035 static int CmprDbl(double *val1, double *val2)
00036 {
00037 if(*val1<*val2)
00038 return -1;
00039 else if(*val1>*val2)
00040 return 1;
00041 else
00042 return 0;
00043 }
00044 #endif
00045
00046 a2dPropertyIdUint32* a2dRestrictionEngine::PROPID_SnapSourceFeaturesMem;
00047 a2dPropertyIdUint32* a2dRestrictionEngine::PROPID_SnapSourceFeatures;
00048 a2dPropertyIdUint32* a2dRestrictionEngine::PROPID_SnapToFeatures;
00049 a2dPropertyIdDouble* a2dRestrictionEngine::PROPID_RotationAngle;
00050 a2dPropertyIdUint32* a2dRestrictionEngine::PROPID_RotationRationalNom;
00051 a2dPropertyIdUint32* a2dRestrictionEngine::PROPID_RotationRationalDen;
00052 a2dPropertyIdInt32* a2dRestrictionEngine::PROPID_SnapThresHold;
00053 a2dPropertyIdPoint2D*a2dRestrictionEngine::PROPID_PointToSnap;
00054 a2dPropertyIdPoint2D* a2dRestrictionEngine::PROPID_PointToRestrictTo;
00055 a2dPropertyIdBool* a2dRestrictionEngine::PROPID_SnapOnlyVisbleObjects;
00056 a2dPropertyIdBool* a2dRestrictionEngine::PROPID_Snap;
00057 a2dPropertyIdBool* a2dRestrictionEngine::PROPID_SnapGetSet;
00058 a2dPropertyIdBool* a2dRestrictionEngine::PROPID_AltDown;
00059 a2dPropertyIdBool* a2dRestrictionEngine::PROPID_ShiftDown;
00060
00061 INITIALIZE_PROPERTIES( a2dRestrictionEngine, a2dEvtHandler )
00062 {
00063 A2D_PROPID_GS( a2dPropertyIdBool, a2dRestrictionEngine, SnapGetSet, false, GetSnap, SetSnap );
00064 A2D_PROPID_GSI( a2dPropertyIdUint32, a2dRestrictionEngine, SnapSourceFeatures, 0 );
00065 A2D_PROPID_GSI( a2dPropertyIdUint32, a2dRestrictionEngine, SnapToFeatures, 0 );
00066 A2D_PROPID_GSI( a2dPropertyIdDouble, a2dRestrictionEngine, RotationAngle, 0 );
00067 A2D_PROPID_M( a2dPropertyIdUint32, a2dRestrictionEngine, RotationRationalNom, 0, m_rotationRationalNom );
00068 A2D_PROPID_M( a2dPropertyIdUint32, a2dRestrictionEngine, RotationRationalDen, 0, m_rotationRationalDen );
00069 A2D_PROPID_M( a2dPropertyIdInt32, a2dRestrictionEngine, SnapThresHold, 0, m_snapThresHold );
00070 A2D_PROPID_M( a2dPropertyIdPoint2D, a2dRestrictionEngine, PointToSnap, a2dPoint2D( 0, 0 ), m_pointToSnap );
00071 A2D_PROPID_M( a2dPropertyIdPoint2D, a2dRestrictionEngine, PointToRestrictTo, a2dPoint2D( 0, 0 ), m_pointToRestrictTo );
00072 A2D_PROPID_M( a2dPropertyIdBool, a2dRestrictionEngine, SnapOnlyVisbleObjects, false, m_snapOnlyVisbleObjects );
00073 A2D_PROPID_M( a2dPropertyIdBool, a2dRestrictionEngine, Snap, false, m_snap );
00074 A2D_PROPID_M( a2dPropertyIdBool, a2dRestrictionEngine, AltDown, false, m_altDown );
00075 A2D_PROPID_M( a2dPropertyIdBool, a2dRestrictionEngine, ShiftDown, false, m_shiftDown );
00076 A2D_PROPID_M( a2dPropertyIdUint32, a2dRestrictionEngine, SnapSourceFeaturesMem, 0, m_snapSourceFeatures );
00077 return true;
00078 }
00079
00080 A2D_BEGIN_EVENT_TABLE(a2dRestrictionEngine, a2dEvtHandler)
00081 A2D_EVT_ACTIVATE_VIEW( a2dRestrictionEngine::OnActivate )
00082 A2D_END_EVENT_TABLE()
00083
00084 double a2dRestrictionEngine::GetSnapThresHoldWorld() const
00085 {
00086 if ( m_view )
00087 {
00088 return m_view->GetDrawer2D()->DeviceToWorldXRel( m_snapThresHold );
00089 }
00090 return 0;
00091 }
00092
00093 void a2dRestrictionEngine::OnActivate( a2dViewEvent& viewevent )
00094 {
00095 a2dCanvasView* view = (a2dCanvasView*) viewevent.GetEventObject();
00096 bool activate = viewevent.GetActive();
00097
00098 if ( activate && view )
00099 {
00100 m_view = wxDynamicCast( view, a2dCanvasView );
00101 m_doc = m_view->GetCanvasDocument();
00102
00103 SetInternal();
00104
00105
00106 }
00107 }
00108
00109 void a2dRestrictionEngine::SetInternal()
00110 {
00111 m_docSnapDistX = m_snapDistX;
00112 m_docSnapDistY = m_snapDistY;
00113 m_docOriginX = m_originX;
00114 m_docOriginY = m_originY;
00115 if ( m_doc )
00116 {
00117 m_docSnapDistX /= m_doc->GetUnitsScale();
00118 m_docSnapDistY /= m_doc->GetUnitsScale();
00119 m_docOriginX /= m_doc->GetUnitsScale();
00120 m_docOriginY /= m_doc->GetUnitsScale();
00121 }
00122 }
00123
00124 a2dRestrictionEngine::a2dRestrictionEngine()
00125 : m_lineToSnap( 0, 0, 1, 1 )
00126 {
00127 a2dDocviewGlobals->GetEventDistributer()->Register( this );
00128
00129 m_snapDistX=1.0;
00130 m_snapDistY=1.0;
00131 m_originX=0.0;
00132 m_originY=0.0;
00133 m_rotationAngle = 10;
00134 m_rotationRationalNom=0x0000003f;
00135 m_rotationRationalDen=0x00000024;
00136 m_angleList=0;
00137 m_nAngleList=0;
00138
00139 m_snapThresHold = 6;
00140
00141 m_snapSourceFeatures = snapToBoundingBox | snapToObjectPos | snapToPinsUnconnected | snapToObjectVertexes;
00142
00143 m_snapToFeatures = snapToGridPos | snapToObjectPos | snapToPinsUnconnected | snapToObjectVertexes;
00144
00145
00146 m_snapToFeatures = snapToBoundingBox | snapToObjectPos | snapToPinsUnconnected | snapToObjectVertexes | snapToObjectSnapVPath;
00147
00148 m_snap = true;
00149 m_altDown = false;
00150 m_shiftDown = false;
00151 m_snapOnlyVisbleObjects = true;
00152
00153 m_doc = NULL;
00154 m_view = NULL;
00155
00156 SetInternal();
00157
00158 PROPID_SnapGetSet->SetPropertyToObject( this, true );
00159 bool val = PROPID_SnapGetSet->GetPropertyValue( this );
00160
00161
00162
00163 }
00164
00165 a2dRestrictionEngine::~a2dRestrictionEngine()
00166 {
00167 a2dDocviewGlobals->GetEventDistributer()->Unregister( this );
00168
00169 if(m_angleList)
00170 delete [] m_angleList;
00171 }
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194 static void SnapIfBetterPos(double val, double grid, double origin, double *best)
00195 {
00196 assert(grid);
00197 double
00198 newVal = floor((val-origin)/grid+0.5)*grid + origin,
00199 dist = newVal-val;
00200 if(fabs(dist)<fabs(*best))
00201 {
00202 *best = dist;
00203 }
00204 }
00205
00206
00207
00208
00209 static void SnapIfBetterSize(double oldVal, double newVal, double *best)
00210 {
00211 double
00212 dist = newVal-oldVal;
00213 if(fabs(dist)<fabs(*best))
00214 {
00215 *best = dist;
00216 }
00217 }
00218
00219
00220
00221 static double SnapGrid(double val, double grid)
00222 {
00223 assert(grid);
00224 return floor((val)/grid+0.5)*grid;
00225 }
00226
00227 void a2dRestrictionEngine::SetPointSnapResult( const a2dPoint2D& p )
00228 {
00229 m_snappedPoint = p;
00230 }
00231
00232 bool a2dRestrictionEngine::SetPointSnapResultIfCloser( const a2dPoint2D& p )
00233 {
00234 double dx = p.m_x - m_pointToSnap.m_x;
00235 double dy = p.m_y - m_pointToSnap.m_y;
00236 double snappedDx = m_snappedPoint.m_x - m_pointToSnap.m_x;
00237 double snappedDy = m_snappedPoint.m_y - m_pointToSnap.m_y;
00238
00239 if ( fabs(dx) < GetSnapThresHoldWorld() && fabs(dy) < GetSnapThresHoldWorld() )
00240 {
00241 if ( fabs(dx) < fabs( snappedDx ) && fabs(dy) < fabs( snappedDy ) )
00242 {
00243 m_snappedPoint = p;
00244 return true;
00245 }
00246 }
00247 return false;
00248 }
00249
00250 bool a2dRestrictionEngine::RestrictPoint(double& x, double& y, wxUint32 sourceRequired, bool ignoreEngine )
00251 {
00252 bool res = false;
00253 if ( !m_snap || m_altDown )
00254 return res;
00255
00256 if ( !ignoreEngine )
00257 sourceRequired = sourceRequired & m_snapToFeatures;
00258
00259 m_pointToSnap = a2dPoint2D( x, y );
00260
00261 SetPointSnapResult( a2dPoint2D( DBL_MAX, DBL_MAX ) );
00262
00263
00264 if ( sourceRequired & snapToPins ||
00265 sourceRequired & snapToPinsUnconnected ||
00266 sourceRequired & snapToObjectPos ||
00267 sourceRequired & snapToObjectVertexes
00268 )
00269 {
00270
00271
00272 a2dCanvasObjectList::iterator iter = m_parentObject->GetChildObjectList()->begin();
00273 while( iter != m_parentObject->GetChildObjectList()->end() )
00274 {
00275 a2dCanvasObjectList::value_type objchild = *iter;
00276 if ( !objchild->GetRelease() &&
00277 objchild->GetSnapTo() &&
00278 ( !m_snapOnlyVisbleObjects || objchild->GetVisible() ) &&
00279 ( !m_view || m_view->GetLayerRenderArray()[ objchild->GetLayer() ].DoRenderLayer()) )
00280 {
00281 if ( objchild->GetBbox().PointInBox( x, y, GetSnapThresHoldWorld() ) )
00282 {
00283 if ( objchild->RestrictToObject( this, sourceRequired ) )
00284 {
00285
00286
00287 x = m_snappedPoint.m_x;
00288 y = m_snappedPoint.m_y;
00289 res = true;
00290 }
00291 }
00292 }
00293 iter++;
00294 }
00295 if ( res )
00296 return res;
00297 }
00298
00299
00300 if ( sourceRequired & snapToPointAngleMod && !m_shiftDown )
00301 {
00302 double rad2deg = 180/wxPI;
00303 double dx = x - m_pointToRestrictTo.m_x;
00304 double dy = y - m_pointToRestrictTo.m_y;
00305 double radius = sqrt( dx*dx + dy*dy );
00306
00307 double ang;
00308 if (!dx && !dy)
00309 ang = 0;
00310 else
00311 ang = atan2( dy, dx );
00312
00313 double angn = AngleRestrict( ang );
00314
00315 dx = cos( angn ) * radius;
00316 dy = sin( angn ) * radius;
00317 x = m_pointToRestrictTo.m_x + dx;
00318 y = m_pointToRestrictTo.m_y + dy;
00319 return true;
00320 }
00321
00322 if ( sourceRequired & snapToPointAngleRational && !m_shiftDown )
00323 {
00324 double rad2deg = 180/wxPI;
00325 double dx = x - m_pointToRestrictTo.m_x;
00326 double dy = y - m_pointToRestrictTo.m_y;
00327 double radius = sqrt( dx*dx + dy*dy );
00328
00329 double ang;
00330 if (!dx && !dy)
00331 ang = 0;
00332 else
00333 ang = atan2( dy, dx );
00334
00335 ang = RationalRestrict( ang );
00336
00337 dx = cos( ang ) * radius;
00338 dy = sin( ang ) * radius;
00339 x = m_pointToRestrictTo.m_x + dx;
00340 y = m_pointToRestrictTo.m_y + dy;
00341 return true;
00342 }
00343
00344 if ( sourceRequired & snapToPointPos ||
00345 sourceRequired & snapToPointPosX ||
00346 sourceRequired & snapToPointPosY ||
00347 sourceRequired & snapToPointPosXorY ||
00348 sourceRequired & snapToPointPosXorYForce ||
00349 m_shiftDown
00350 )
00351 {
00352 if( sourceRequired & snapToPointPos )
00353 {
00354 if ( fabs( x - m_pointToRestrictTo.m_x ) < GetSnapThresHoldWorld() &&
00355 fabs( y - m_pointToRestrictTo.m_y ) < GetSnapThresHoldWorld()
00356 )
00357 {
00358 x = m_pointToRestrictTo.m_x;
00359 y = m_pointToRestrictTo.m_y;
00360 res = true;
00361 return res;
00362 }
00363 }
00364 if( sourceRequired & snapToPointPosX )
00365 {
00366 if ( fabs( x - m_pointToRestrictTo.m_x ) < GetSnapThresHoldWorld() )
00367 {
00368 x = m_pointToRestrictTo.m_x;
00369 res = true;
00370 return res;
00371 }
00372 }
00373 if( sourceRequired & snapToPointPosY )
00374 {
00375 if ( fabs( y - m_pointToRestrictTo.m_y ) < GetSnapThresHoldWorld() )
00376 {
00377 y = m_pointToRestrictTo.m_y;
00378 res = true;
00379 return res;
00380 }
00381 }
00382 if( sourceRequired & snapToPointPosXorYForce || m_shiftDown )
00383 {
00384 if ( fabs( x - m_pointToRestrictTo.m_x ) < fabs( y - m_pointToRestrictTo.m_y ) )
00385 {
00386 x = m_pointToRestrictTo.m_x;
00387 res = true;
00388 }
00389 else
00390 {
00391 y = m_pointToRestrictTo.m_y;
00392 res = true;
00393 }
00394 res = true;
00395 return res;
00396 }
00397 }
00398
00399
00400 if ( sourceRequired & snapToObjectSnapVPath )
00401 {
00402 double dx = DBL_MAX;
00403 double dy = DBL_MAX;
00404
00405
00406
00407 a2dCanvasObjectList::iterator iter = m_parentObject->GetChildObjectList()->begin();
00408 while( iter != m_parentObject->GetChildObjectList()->end() )
00409 {
00410 a2dCanvasObjectList::value_type objchild = *iter;
00411 if ( !objchild->GetRelease() &&
00412 objchild->GetSnapTo() &&
00413 ( !m_snapOnlyVisbleObjects || objchild->GetVisible() ) &&
00414 ( !m_view || m_view->GetLayerRenderArray()[ objchild->GetLayer() ].DoRenderLayer()) )
00415 {
00416 if ( objchild->GetBbox().PointInBox( x, y, GetSnapThresHoldWorld() ) )
00417 {
00418 a2dCanvasObjectList* vectorpaths = objchild->GetSnapVpath( sourceRequired );
00419 if ( vectorpaths != wxNullCanvasObjectList )
00420 {
00421 forEachIn( a2dCanvasObjectList, vectorpaths )
00422 {
00423 a2dVectorPath* obj = wxStaticCast( (*iter).Get(), a2dVectorPath );
00424 unsigned int i;
00425 for (i = 0; i < obj->GetSegments()->GetCount(); i++)
00426 {
00427 a2dVpathSegment& seg = obj->GetSegments()->Item(i);
00428 switch ( seg.GetType() )
00429 {
00430 case a2dPATHSEG_MOVETO:
00431 case a2dPATHSEG_LINETO:
00432 case a2dPATHSEG_LINETO_NOSTROKE:
00433 case a2dPATHSEG_CBCURVETO_NOSTROKE:
00434 case a2dPATHSEG_CBCURVETO:
00435 case a2dPATHSEG_QBCURVETO_NOSTROKE:
00436 case a2dPATHSEG_QBCURVETO:
00437 case a2dPATHSEG_ARCTO_NOSTROKE:
00438 case a2dPATHSEG_ARCTO:
00439 {
00440 if ( fabs( x - seg.m_x1 ) < GetSnapThresHoldWorld() &&
00441 fabs( y - seg.m_y1 ) < GetSnapThresHoldWorld()
00442 )
00443 {
00444
00445 if ( fabs( x - seg.m_x1 ) < fabs(dx) && fabs( y - seg.m_y1 ) < fabs(dy) )
00446 {
00447 dx = x - seg.m_x1;
00448 dy = y - seg.m_y1;
00449 x = seg.m_x1;
00450 y = seg.m_y1;
00451 res = true;
00452 }
00453 }
00454 }
00455 break;
00456 }
00457 }
00458 }
00459 delete vectorpaths;
00460 }
00461 }
00462 }
00463 iter++;
00464 }
00465 if ( res )
00466 return res;
00467 }
00468
00469 if ( sourceRequired & snapToGridPos )
00470 {
00471
00472 if( sourceRequired & snapToGridPosX && m_snapDistX)
00473 {
00474 x = floor((x-m_docOriginX)/m_docSnapDistX+0.5)*m_docSnapDistX + m_docOriginX;
00475 res = true;
00476 }
00477
00478 if( sourceRequired & snapToGridPosY && m_snapDistY)
00479 {
00480 y = floor((y-m_docOriginY)/m_docSnapDistY+0.5)*m_docSnapDistY + m_docOriginY;
00481 res = true;
00482 }
00483 return res;
00484 }
00485 return res;
00486 }
00487
00488 bool a2dRestrictionEngine::RestrictLine( a2dLine& line, wxUint32 sourceRequired, bool ignoreEngine )
00489 {
00490 return false;
00491 }
00492
00493 bool a2dRestrictionEngine::RestrictAngle( double *ang, wxUint32 sourceRequired, bool ignoreEngine)
00494 {
00495 if ( !ignoreEngine )
00496 sourceRequired = sourceRequired & m_snapToFeatures;
00497
00498 if ( sourceRequired & snapToPointAngleMod )
00499 {
00500 *ang = AngleRestrict( *ang );
00501 return true;
00502 }
00503
00504 if ( sourceRequired & snapToPointAngleRational )
00505 {
00506 *ang = RationalRestrict( *ang );
00507 return true;
00508 }
00509 return false;
00510 }
00511
00512 static int CmprDbl(const void *val1, const void *val2)
00513 {
00514 if(*(double*)val1 < *(double*)val2)
00515 return -1;
00516 else if(*(double*)val1 > *(double*)val2)
00517 return 1;
00518 else
00519 return 0;
00520 }
00521
00522 double a2dRestrictionEngine::AngleRestrict(double angle)
00523 {
00524 double
00525 angleSnapRad = m_rotationAngle/180*wxPI;
00526 return floor( angle/angleSnapRad+0.5 ) * angleSnapRad;
00527 }
00528
00529 void a2dRestrictionEngine::AngleRestrictVectorRot(double *vecx, double *vecy)
00530 {
00531 double
00532 angle = atan2( *vecy, *vecx ),
00533 len = sqrt( sqr( *vecx ) + sqr( *vecy ) );
00534 angle = AngleRestrict( angle );
00535 *vecx = cos( angle ) * len;
00536 *vecy = sin( angle ) * len;
00537 }
00538
00539 void a2dRestrictionEngine::AngleRestrictVectorSkew(double *vecx, double *vecy, double otherx, double othery)
00540 {
00541 double
00542 angleOld = atan2( *vecy, *vecx ),
00543 angleNew = AngleRestrict( angleOld ),
00544 angleOther = atan2( othery, otherx ),
00545 proj = *vecx * othery - *vecy * otherx;
00546
00547 if( fabs( angleNew-angleOther) < 1e-5 )
00548 {
00549
00550
00551
00552 double
00553 angleSnapRad = m_rotationAngle/180*wxPI,
00554 angleNew1 = angleNew - angleSnapRad,
00555 angleNew2 = angleNew + angleSnapRad;
00556 if( fabs( angleOld - angleNew1 ) < fabs( angleOld - angleNew2 ) )
00557 angleNew = angleNew1;
00558 else
00559 angleNew = angleNew2;
00560 }
00561
00562 double
00563 newx = cos( angleNew ),
00564 newy = sin( angleNew ),
00565 newpro = newx * othery - newy * otherx;
00566
00567 if( !newpro )
00568 return;
00569
00570 *vecx = newx * ( proj / newpro );
00571 *vecy = newy * ( proj / newpro );
00572 }
00573
00574 double a2dRestrictionEngine::RationalRestrict(double angle)
00575 {
00576
00577 int
00578 quad=0;
00579 bool
00580 mirr=false;
00581
00582 if(angle<0)
00583 angle+=2*wxPI;
00584
00585 if(angle>wxPI)
00586 {
00587 quad+=2;
00588 angle-=wxPI;
00589 }
00590 if(angle>wxPI/2)
00591 {
00592 quad+=1;
00593 angle-=wxPI/2;
00594 }
00595 if(angle>wxPI/4)
00596 {
00597 mirr=true;
00598 angle=wxPI/2-angle;
00599 }
00600
00601 if(!m_angleList)
00602 {
00603
00604 const int
00605 mAngles=31*30/2+1;
00606 int
00607 nAngles=0;
00608 double
00609 angles[mAngles];
00610
00611 angles[nAngles++]=0;
00612 int i;
00613 for( i=1; i<=31; i++)
00614 {
00615 if(m_rotationRationalNom&(1<<i))
00616 {
00617 for(int j=i; j<=31; j++)
00618 {
00619 if(m_rotationRationalDen&(j<<i))
00620 {
00621 assert(nAngles<mAngles);
00622 angles[nAngles++]=atan(double(i)/double(j));
00623 }
00624 }
00625 }
00626 }
00627
00628
00629 qsort(angles, nAngles, sizeof(*angles), CmprDbl);
00630
00631
00632 m_nAngleList=1;
00633 for(i=1; i<nAngles; i++)
00634 {
00635 if(angles[i]-angles[m_nAngleList-1]>1e-13)
00636 {
00637 angles[m_nAngleList++]=angles[i];
00638 }
00639 }
00640
00641
00642 m_angleList=new double[m_nAngleList];
00643 memcpy(m_angleList, angles, sizeof(*m_angleList)*m_nAngleList);
00644 }
00645
00646
00647 if(m_nAngleList<=1)
00648 {
00649 angle=0;
00650 }
00651 else
00652 {
00653 int
00654 low=0,
00655 high=m_nAngleList-1,
00656 mid;
00657
00658 while(high-low>1)
00659 {
00660 mid=(low+high)>>1;
00661 if(m_angleList[mid]<angle)
00662 low=mid;
00663 else
00664 high=mid;
00665 }
00666
00667
00668
00669 if(angle-m_angleList[low]<m_angleList[high]-angle)
00670 angle = m_angleList[low];
00671 else
00672 angle = m_angleList[high];
00673 }
00674
00675
00676 if(mirr)
00677 angle = wxPI/2 - angle;
00678 angle += quad*wxPI/2;
00679
00680 return angle;
00681 }
00682
00683 void a2dRestrictionEngine::RationalRestrictVector(double *vecx, double *vecy)
00684 {
00685 double
00686 angle=atan2(*vecy,*vecx),
00687 len=sqrt(sqr(*vecx)+sqr(*vecy));
00688 angle=RationalRestrict(angle);
00689 *vecx=cos(angle)*len;
00690 *vecy=sin(angle)*len;
00691 }
00692
00693 bool a2dRestrictionEngine::RestrictCanvasObjectAtVertexes( a2dCanvasObject* object, a2dPoint2D& point, double& dx, double& dy, wxUint32 sourceRequired, bool ignoreEngine )
00694 {
00695 bool res = false;
00696 dx = DBL_MAX;
00697 dy = DBL_MAX;
00698
00699 if ( !m_snap || m_altDown )
00700 return res;
00701
00702 if ( !ignoreEngine )
00703 sourceRequired = sourceRequired & m_snapToFeatures;
00704
00705
00706 if ( object->GetSnap() )
00707 {
00708 a2dCanvasObjectList* vectorpaths = object->GetSnapVpath( m_snapSourceFeatures );
00709 if ( vectorpaths != wxNullCanvasObjectList )
00710 {
00711 forEachIn( a2dCanvasObjectList, vectorpaths )
00712 {
00713 a2dVectorPath* obj = wxStaticCast( (*iter).Get(), a2dVectorPath );
00714 unsigned int i;
00715 for (i = 0; i < obj->GetSegments()->GetCount(); i++)
00716 {
00717 a2dVpathSegment& seg = obj->GetSegments()->Item(i);
00718 switch ( seg.GetType() )
00719 {
00720 case a2dPATHSEG_MOVETO:
00721 case a2dPATHSEG_LINETO:
00722 case a2dPATHSEG_LINETO_NOSTROKE:
00723 case a2dPATHSEG_CBCURVETO_NOSTROKE:
00724 case a2dPATHSEG_CBCURVETO:
00725 case a2dPATHSEG_QBCURVETO_NOSTROKE:
00726 case a2dPATHSEG_QBCURVETO:
00727 case a2dPATHSEG_ARCTO_NOSTROKE:
00728 case a2dPATHSEG_ARCTO:
00729 {
00730
00731 double x = seg.m_x1;
00732 double y = seg.m_y1;
00733 if ( RestrictPoint( x, y, sourceRequired, ignoreEngine ) )
00734 {
00735
00736 if ( fabs( x - seg.m_x1 ) < fabs(dx) && fabs( y - seg.m_y1 ) < fabs(dy) )
00737 {
00738 dx = x - seg.m_x1;
00739 dy = y - seg.m_y1;
00740 point = a2dPoint2D( seg.m_x1, seg.m_y1 );
00741 res = true;
00742 }
00743 }
00744 }
00745 break;
00746 }
00747 }
00748 }
00749 delete vectorpaths;
00750 }
00751 }
00752 return res;
00753 }
00754
00755 bool a2dRestrictionEngine::RestrictVertexes( a2dVertexArray* segments, a2dPoint2D& point, double& dx, double& dy, wxUint32 sourceRequired, bool ignoreEngine )
00756 {
00757 dx = DBL_MAX;
00758 dy = DBL_MAX;
00759
00760 bool res = false;
00761 int i=0;
00762 for (i=0; i< segments->size(); i++)
00763 {
00764 a2dLineSegmentPtr seg = segments->Item(i);
00765 double x = seg->m_x;
00766 double y = seg->m_y;
00767 if ( RestrictPoint( x, y, sourceRequired, ignoreEngine ) )
00768 {
00769
00770 if ( fabs( x - seg->m_x ) < dx && fabs( y - seg->m_y ) < dy )
00771 {
00772 dx = fabs( x - seg->m_x );
00773 dy = fabs( y - seg->m_y );
00774 point = a2dPoint2D( seg->m_x, seg->m_y );
00775 res = true;
00776 }
00777 }
00778 }
00779 return res;
00780 }
00781
00782 bool a2dRestrictionEngine::RestrictVertexes( a2dVertexList* lsegments, a2dPoint2D& point, double& dx, double& dy, wxUint32 sourceRequired, bool ignoreEngine )
00783 {
00784 dx = DBL_MAX;
00785 dy = DBL_MAX;
00786 bool res = false;
00787
00788 int i=0;
00789 for( a2dVertexList::iterator iter = lsegments->begin(); iter != lsegments->end(); ++iter, i++ )
00790 {
00791 a2dLineSegment* seg = *iter;
00792 double x = seg->m_x;
00793 double y = seg->m_y;
00794 if ( RestrictPoint( x, y, sourceRequired, ignoreEngine ) )
00795 {
00796
00797 if ( fabs( x - seg->m_x ) < dx && fabs( y - seg->m_y ) < dy )
00798 {
00799 dx = fabs( x - seg->m_x );
00800 dy = fabs( y - seg->m_y );
00801 point = a2dPoint2D( seg->m_x, seg->m_y );
00802 res = true;
00803 }
00804 }
00805 }
00806 return res;
00807 }
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819 a2dRestrictionEngineOld::a2dRestrictionEngineOld()
00820 {
00821 m_posModesX=posNone;
00822 m_posModesY=posNone;
00823 m_sizeModesX=sizeNone;
00824 m_sizeModesY=sizeNone;
00825 m_rotModes=rotNone;
00826 m_snapDistX=1;
00827 m_snapDistY=1;
00828 m_originX=0;
00829 m_originY=0;
00830 m_sizeX=1;
00831 m_sizeY=1;
00832 m_rotationAngle=2;
00833 m_rotationRationalNom=0x0000003f;
00834 m_rotationRationalDen=0x00000024;
00835 m_angleList=0;
00836 m_nAngleList=0;
00837 m_minSizeX=1;
00838 m_minSizeY=1;
00839 m_maxSizeX=DBL_MAX;
00840 m_maxSizeY=DBL_MAX;
00841 }
00842
00843 a2dRestrictionEngineOld::~a2dRestrictionEngineOld()
00844 {
00845 if(m_angleList)
00846 delete [] m_angleList;
00847 }
00848
00849
00850 static const double Eps=1e-10;
00851
00852 void a2dRestrictionEngineOld::RestrictAffine(a2dAffineMatrix *mNew, const a2dAffineMatrix *mOld, ESnapWhat snapWhat, SnapObjectInfo *info, double *w, double *h)
00853 {
00854
00855
00856
00857 if(!this)
00858 return;
00859
00860 double
00861 wfa = w ? fabs(*w) : 1,
00862 hfa = h ? fabs(*h) : 1,
00863 a00 = mNew->m_matrix[0][0],
00864 a01 = mNew->m_matrix[0][1],
00865 a10 = mNew->m_matrix[1][0],
00866 a11 = mNew->m_matrix[1][1],
00867 a20 = mNew->m_matrix[2][0],
00868 a21 = mNew->m_matrix[2][1];
00869
00870
00871
00872
00873 double
00874 fixX = 0.0,
00875 fixY = 0.0;
00876 bool
00877 hasFix=false,
00878 linearZero=false,
00879 shiftZero=false;
00880 if( mOld )
00881 {
00882 a2dAffineMatrix
00883 diff = *mNew-*mOld;
00884 double
00885 maxNew = mNew->GetMaximum(),
00886 maxOld = mOld->GetMaximum(),
00887 maxDiff = diff.GetMaximum(),
00888 detDiff = diff.GetDeterminant();
00889
00890 linearZero = maxDiff <= wxMax( maxNew, maxOld ) * Eps ;
00891
00892 shiftZero =
00893 fabs( diff.m_matrix[2][0] ) <= wxMax( fabs( mNew->m_matrix[2][0] ), fabs( mOld->m_matrix[2][0] ) ) * Eps &&
00894 fabs( diff.m_matrix[2][1] ) <= wxMax( fabs( mNew->m_matrix[2][1] ), fabs( mOld->m_matrix[2][1] ) ) * Eps ;
00895
00896 if( linearZero && shiftZero)
00897 {
00898
00899 return;
00900 }
00901 else if( shiftZero )
00902 {
00903
00904
00905 hasFix=true;
00906 }
00907 else if( linearZero )
00908 {
00909
00910 }
00911 else if( fabs( detDiff ) < sqr( maxDiff ) * Eps )
00912 {
00913
00914
00915 double
00916 det1 = diff.GetDeterminant1(),
00917 det2 = diff.GetDeterminant2(),
00918 max1 = diff.GetMaximum1(),
00919 max2 = diff.GetMaximum2();
00920 if( fabs( det1 ) <= max1 * Eps && fabs( det2 ) <= max2 * Eps )
00921 {
00922
00923
00924 hasFix=true;
00925
00926
00927 if( fabs( diff.m_matrix[0][0] ) + fabs( diff.m_matrix[1][0] ) > fabs( diff.m_matrix[0][1] ) + fabs( diff.m_matrix[1][1] ) )
00928 {
00929
00930
00931 if( fabs( diff.m_matrix[0][0] ) > fabs( diff.m_matrix[1][0] ) )
00932 {
00933 fixX = -diff.m_matrix[2][0] / diff.m_matrix[0][0];
00934 }
00935 else {
00936 fixY = -diff.m_matrix[2][0] / diff.m_matrix[1][0];
00937 }
00938 }
00939 else
00940 {
00941
00942
00943 if( fabs( diff.m_matrix[0][1] ) > fabs( diff.m_matrix[1][1] ) )
00944 {
00945 fixX = -diff.m_matrix[2][1] / diff.m_matrix[0][1];
00946 }
00947 else {
00948 fixY = -diff.m_matrix[2][1] / diff.m_matrix[1][1];
00949 }
00950 }
00951 }
00952
00953 }
00954 else
00955 {
00956
00957 fixX = - diff.GetDeterminant1()/detDiff;
00958 fixY = - diff.GetDeterminant2()/detDiff;
00959 hasFix=true;
00960 }
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977 }
00978
00979
00980
00981
00982
00983 if( hasFix )
00984 {
00985 a20 += a00 * fixX + a10 * fixY;
00986 a21 += a01 * fixX + a11 * fixY;
00987 }
00988
00989
00990
00991
00992 if((snapWhat & snapRot) && (m_rotModes & info->m_rotModes))
00993 {
00994 int
00995 modes=m_rotModes & info->m_rotModes;
00996
00997
00998 if(m_rotationAngle)
00999 {
01000 if(modes&rotVectorAngleX)
01001 {
01002
01003 AngleRestrictVectorRot(&a00, &a01);
01004 }
01005 if(modes&rotVectorAngleY)
01006 {
01007
01008 AngleRestrictVectorRot(&a10, &a11);
01009 }
01010 }
01011
01012
01013 if(m_rotationRationalNom && m_rotationRationalDen)
01014 {
01015 if(modes&rotVectorRationalX)
01016 {
01017
01018 RationalRestrictVector(&a00, &a01);
01019 }
01020 if(modes&rotVectorRationalY)
01021 {
01022
01023 RationalRestrictVector(&a10, &a11);
01024 }
01025 }
01026
01027
01028 if(modes&rotPureRotations)
01029 {
01030 double
01031 lenY=sqrt(sqr(a11)+sqr(a10)),
01032 lenX=sqrt(sqr(a01)+sqr(a00));
01033 if(lenX)
01034 {
01035 if(a00*a11-a01*a10>=0)
01036 {
01037
01038 a10=-a01*lenY/lenX;
01039 a11=a11*lenY/lenX;
01040 }
01041 else
01042 {
01043
01044 a10=a01*lenY/lenX;
01045 a11=-a00*lenY/lenX;
01046 }
01047 }
01048 }
01049 }
01050
01051
01052
01053
01054 if((snapWhat & snapSkew) && (m_rotModes & info->m_rotModes))
01055 {
01056 int
01057 modes=m_rotModes & info->m_rotModes;
01058
01059
01060 if(m_rotationAngle)
01061 {
01062 if(modes&rotVectorAngleX)
01063 {
01064
01065 AngleRestrictVectorSkew(&a00, &a01, a10, a11);
01066 }
01067 if(modes&rotVectorAngleY)
01068 {
01069
01070 AngleRestrictVectorSkew(&a10, &a11, a00, a01);
01071 }
01072 }
01073
01074
01075 if(modes&rotPureSlanting)
01076 {
01077
01078 if(a01)
01079 {
01080 double
01081 lenY=sqrt(sqr(a11)+sqr(a10));
01082 a11=lenY;
01083 a10=0;
01084 }
01085 }
01086 }
01087
01088
01089
01090
01091 if((snapWhat & snapSize) && (m_sizeModesX & info->m_sizeModesX))
01092 {
01093
01094
01095
01096 int
01097 modes = m_sizeModesX & info->m_sizeModesX;
01098 double
01099 oldLen=wfa*sqrt(sqr(a00)+sqr(a01)),
01100 newLen=oldLen;
01101
01102 if( (modes & sizeMin) && oldLen < m_minSizeX )
01103 {
01104 newLen=m_minSizeX;
01105 }
01106 else if( (modes & sizeMax) && oldLen > m_maxSizeX )
01107 {
01108 newLen=m_maxSizeX;
01109 }
01110 else if( m_sizeX )
01111 {
01112 double
01113 best = DBL_MAX;
01114
01115 if( modes & sizeLength )
01116 {
01117 SnapIfBetterSize( oldLen, SnapGrid( wfa * sqrt(sqr(a00)+sqr(a01) ), m_sizeX), &best );
01118 }
01119 if( modes & sizeProject )
01120 {
01121
01122
01123
01124 double
01125 otherLen = sqrt(sqr(a10)+sqr(a11));
01126 if(otherLen)
01127 {
01128 double
01129 prjc = wfa * (- a00*a11 + a01*a10) / otherLen;
01130 if( prjc )
01131 {
01132 double
01133 newLen = oldLen * SnapGrid( prjc, m_sizeX ) / prjc;
01134 SnapIfBetterSize( oldLen, newLen, &best );
01135 }
01136 }
01137 }
01138 if( modes & sizeMajor )
01139 {
01140 double
01141 major = wfa * wxMax(a00, a01);
01142 if(major)
01143 {
01144 double
01145 newLen = oldLen * SnapGrid( major, m_sizeX ) / major;
01146 SnapIfBetterSize( oldLen, newLen, &best );
01147 }
01148 }
01149 if( modes & sizeAxis )
01150 {
01151 double
01152 axis = wfa * a00;
01153 if(axis)
01154 {
01155 double
01156 newLen = oldLen * SnapGrid( axis, m_sizeX ) / axis;
01157 SnapIfBetterSize( oldLen, newLen, &best );
01158 }
01159 }
01160
01161 if( best != DBL_MAX )
01162 {
01163 newLen = oldLen + best;
01164 if( (modes & sizeMin) && newLen < m_minSizeX )
01165 newLen=m_minSizeX;
01166 else if( (modes & sizeMax) && newLen > m_maxSizeX )
01167 newLen=m_maxSizeX;
01168 }
01169 }
01170 if( newLen != oldLen )
01171 {
01172 if(oldLen) {
01173 if(w && (snapWhat & snapWH))
01174 {
01175 *w *= newLen/oldLen;
01176 }
01177 else
01178 {
01179 a00 *= newLen/oldLen;
01180 a01 *= newLen/oldLen;
01181 }
01182 }
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215 }
01216 }
01217
01218
01219
01220
01221 if(
01222 (snapWhat & snapSize) && (m_sizeModesY & info->m_sizeModesY) &&
01223
01224 !((snapWhat & snapWH) && w && h==w)
01225
01226 )
01227 {
01228
01229
01230
01231 int
01232 modes = m_sizeModesY & info->m_sizeModesY;
01233 double
01234 oldLen=hfa*sqrt(sqr(a10)+sqr(a11)),
01235 newLen=oldLen;
01236
01237 if( (modes & sizeMin) && oldLen < m_minSizeY )
01238 {
01239 newLen=m_minSizeY;
01240 }
01241 else if( (modes & sizeMax) && oldLen > m_maxSizeY )
01242 {
01243 newLen=m_maxSizeY;
01244 }
01245 else if( m_sizeY )
01246 {
01247 double
01248 best = DBL_MAX;
01249
01250 if( modes & sizeLength )
01251 {
01252 SnapIfBetterSize( oldLen, SnapGrid( hfa * sqrt(sqr(a10)+sqr(a11) ), m_sizeY), &best );
01253 }
01254 if( modes & sizeProject )
01255 {
01256
01257
01258
01259 double
01260 otherLen = sqrt(sqr(a00)+sqr(a01));
01261 if(otherLen)
01262 {
01263 double
01264 prjc = hfa * (- a10*a01 + a11*a00) / otherLen;
01265 if( prjc )
01266 {
01267 double
01268 newLen = oldLen * SnapGrid( prjc, m_sizeY ) / prjc;
01269 SnapIfBetterSize( oldLen, newLen, &best );
01270 }
01271 }
01272 }
01273 if( modes & sizeMajor )
01274 {
01275 double
01276 major = hfa * wxMax(a10, a11);
01277 if(major)
01278 {
01279 double
01280 newLen = oldLen * SnapGrid( major, m_sizeY ) / major;
01281 SnapIfBetterSize( oldLen, newLen, &best );
01282 }
01283 }
01284 if( modes & sizeAxis )
01285 {
01286 double
01287 axis = hfa * a11;
01288 if(axis)
01289 {
01290 double
01291 newLen = oldLen * SnapGrid( axis, m_sizeY ) / axis;
01292 SnapIfBetterSize( oldLen, newLen, &best );
01293 }
01294 }
01295
01296 if( best != DBL_MAX )
01297 {
01298 newLen = oldLen + best;
01299 if( (modes & sizeMin) && newLen < m_minSizeY )
01300 newLen=m_minSizeY;
01301 else if( (modes & sizeMax) && newLen > m_maxSizeY )
01302 newLen=m_maxSizeY;
01303 }
01304 }
01305 if( newLen != oldLen )
01306 {
01307 if(oldLen) {
01308 if(h && (snapWhat & snapWH))
01309 {
01310 *h *= newLen/oldLen;
01311 }
01312 else
01313 {
01314 a10 *= newLen/oldLen;
01315 a11 *= newLen/oldLen;
01316 }
01317 }
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350 }
01351 }
01352
01353
01354
01355
01356 if( hasFix )
01357 {
01358 a20 -= a00 * fixX + a10 * fixY;
01359 a21 -= a01 * fixX + a11 * fixY;
01360 }
01361
01362 mNew->m_matrix[0][0] = a00;
01363 mNew->m_matrix[0][1] = a01;
01364 mNew->m_matrix[1][0] = a10;
01365 mNew->m_matrix[1][1] = a11;
01366
01367
01368
01369
01370 {
01371 double
01372 wf = w ? *w : 1,
01373 hf = h ? *h : 1;
01374 a00*=wf;
01375 a01*=wf;
01376 a10*=hf;
01377 a11*=hf;
01378 }
01379
01380
01381
01382
01383 if((snapWhat & snapPosX) && (m_posModesX & info->m_posModesX) && m_docSnapDistX) {
01384 int
01385 modes=m_posModesX & info->m_posModesX;
01386 double
01387 bestShift=DBL_MAX;
01388 if(modes & posCenter)
01389 SnapIfBetterPos(a00*info->m_centerX + a10*info->m_centerY + a20, m_docSnapDistX, m_docOriginX, &bestShift);
01390 if(modes & posTopLeft)
01391 SnapIfBetterPos(a00*info->m_left + a10*info->m_top + a20, m_docSnapDistX, m_docOriginX, &bestShift);
01392 if(modes & posTop)
01393 SnapIfBetterPos(a00*info->m_centerX + a10*info->m_top + a20, m_docSnapDistX, m_docOriginX, &bestShift);
01394 if(modes & posTopRight)
01395 SnapIfBetterPos(a00*info->m_right + a10*info->m_top + a20, m_docSnapDistX, m_docOriginX, &bestShift);
01396 if(modes & posRight)
01397 SnapIfBetterPos(a00*info->m_right + a10*info->m_centerY + a20, m_docSnapDistX, m_docOriginX, &bestShift);
01398 if(modes & posBottomRight)
01399 SnapIfBetterPos(a00*info->m_right + a10*info->m_bottom + a20, m_docSnapDistX, m_docOriginX, &bestShift);
01400 if(modes & posBottom)
01401 SnapIfBetterPos(a00*info->m_centerX + a10*info->m_bottom + a20, m_docSnapDistX, m_docOriginX, &bestShift);
01402 if(modes & posBottomLeft)
01403 SnapIfBetterPos(a00*info->m_left + a10*info->m_bottom + a20, m_docSnapDistX, m_docOriginX, &bestShift);
01404 if(modes & posLeft)
01405 SnapIfBetterPos(a00*info->m_left + a10*info->m_centerY + a20, m_docSnapDistX, m_docOriginX, &bestShift);
01406 if((modes & posOther) && info->m_other)
01407 {
01408 forEachIn( a2dVertexList, info->m_other )
01409 {
01410 a2dPoint2D point = (*iter)->GetPoint();
01411 SnapIfBetterPos(a00*point.m_x + a10*point.m_y + a20, m_docSnapDistX, m_docOriginX, &bestShift);
01412 }
01413 }
01414 if(modes & pos6L) {
01415
01416 if(fabs(a00)<Eps*fabs(a01))
01417 {
01418 if(modes & posLineTop)
01419 SnapIfBetterPos(a00*info->m_centerX + a10*info->m_top + a20, m_docSnapDistX, m_docOriginX, &bestShift);
01420 if(modes & posLineHCenter)
01421 SnapIfBetterPos(a00*info->m_centerX + a10*info->m_centerY + a20, m_docSnapDistX, m_docOriginX, &bestShift);
01422 if(modes & posLineBottom)
01423 SnapIfBetterPos(a00*info->m_centerX + a10*info->m_bottom + a20, m_docSnapDistX, m_docOriginX, &bestShift);
01424 }
01425
01426 if(fabs(a10)<Eps*fabs(a11))
01427 {
01428 if(modes & posLineLeft)
01429 SnapIfBetterPos(a00*info->m_left + a10*info->m_centerY + a20, m_docSnapDistX, m_docOriginX, &bestShift);
01430 if(modes & posLineVCenter)
01431 SnapIfBetterPos(a00*info->m_centerX + a10*info->m_centerY + a20, m_docSnapDistX, m_docOriginX, &bestShift);
01432 if(modes & posLineRight)
01433 SnapIfBetterPos(a00*info->m_right + a10*info->m_centerY + a20, m_docSnapDistX, m_docOriginX, &bestShift);
01434 }
01435 }
01436 assert(fabs(bestShift)<=0.50001*m_docSnapDistX);
01437 a20+=bestShift;
01438 }
01439
01440
01441
01442
01443 if((snapWhat & snapPosY) && (m_posModesY & info->m_posModesY) && m_docSnapDistY) {
01444 int
01445 modes=m_posModesY & info->m_posModesY;
01446 double
01447 bestShift=DBL_MAX;
01448 if(modes & posCenter)
01449 SnapIfBetterPos(a01*info->m_centerX + a11*info->m_centerY + a21, m_docSnapDistY, m_docOriginY, &bestShift);
01450 if(modes & posTopLeft)
01451 SnapIfBetterPos(a01*info->m_left + a11*info->m_top + a21, m_docSnapDistY, m_docOriginY, &bestShift);
01452 if(modes & posTop)
01453 SnapIfBetterPos(a01*info->m_centerX + a11*info->m_top + a21, m_docSnapDistY, m_docOriginY, &bestShift);
01454 if(modes & posTopRight)
01455 SnapIfBetterPos(a01*info->m_right + a11*info->m_top + a21, m_docSnapDistY, m_docOriginY, &bestShift);
01456 if(modes & posRight)
01457 SnapIfBetterPos(a01*info->m_right + a11*info->m_centerY + a21, m_docSnapDistY, m_docOriginY, &bestShift);
01458 if(modes & posBottomRight)
01459 SnapIfBetterPos(a01*info->m_right + a11*info->m_bottom + a21, m_docSnapDistY, m_docOriginY, &bestShift);
01460 if(modes & posBottom)
01461 SnapIfBetterPos(a01*info->m_centerX + a11*info->m_bottom + a21, m_docSnapDistY, m_docOriginY, &bestShift);
01462 if(modes & posBottomLeft)
01463 SnapIfBetterPos(a01*info->m_left + a11*info->m_bottom + a21, m_docSnapDistY, m_docOriginY, &bestShift);
01464 if(modes & posLeft)
01465 SnapIfBetterPos(a01*info->m_left + a11*info->m_centerY + a21, m_docSnapDistY, m_docOriginY, &bestShift);
01466 if((modes & posOther) && info->m_other)
01467 {
01468 forEachIn( a2dVertexList, info->m_other )
01469 {
01470 a2dPoint2D point = (*iter)->GetPoint();
01471 SnapIfBetterPos(a01*point.m_x + a11*point.m_y + a21, m_docSnapDistY, m_docOriginY, &bestShift);
01472 }
01473 }
01474 if(modes & pos6L) {
01475
01476 if(fabs(a01)<Eps*fabs(a11))
01477 {
01478 if(modes & posLineTop)
01479 SnapIfBetterPos(a01*info->m_centerX + a11*info->m_top + a21, m_docSnapDistY, m_docOriginY, &bestShift);
01480 if(modes & posLineHCenter)
01481 SnapIfBetterPos(a01*info->m_centerX + a11*info->m_centerY + a21, m_docSnapDistY, m_docOriginY, &bestShift);
01482 if(modes & posLineBottom)
01483 SnapIfBetterPos(a01*info->m_centerX + a11*info->m_bottom + a21, m_docSnapDistY, m_docOriginY, &bestShift);
01484 }
01485
01486 if(fabs(a01)<Eps*fabs(a11))
01487 {
01488 if(modes & posLineLeft)
01489 SnapIfBetterPos(a01*info->m_left + a11*info->m_centerY + a21, m_docSnapDistY, m_docOriginY, &bestShift);
01490 if(modes & posLineVCenter)
01491 SnapIfBetterPos(a01*info->m_centerX + a11*info->m_centerY + a21, m_docSnapDistY, m_docOriginY, &bestShift);
01492 if(modes & posLineRight)
01493 SnapIfBetterPos(a01*info->m_right + a11*info->m_centerY + a21, m_docSnapDistY, m_docOriginY, &bestShift);
01494 }
01495 }
01496 assert(fabs(bestShift)<=0.50001*m_docSnapDistY);
01497 a21+=bestShift;
01498 }
01499
01500
01501
01502
01503 mNew->m_matrix[2][0] = a20;
01504 mNew->m_matrix[2][1] = a21;
01505
01506
01507 }
01508
01509 void a2dRestrictionEngineOld::RestrictEndpointAngle(double *angle, const a2dAffineMatrix& WXUNUSED(matrix), ESnapWhat snapWhat)
01510 {
01511 if( snapWhat & snapEndAngle )
01512 {
01513 double
01514 deg2rad=wxPI/180,
01515 rad2deg=180/wxPI;
01516 if( m_rotModes&rotEndpointAngle )
01517 {
01518 *angle=AngleRestrict( *angle * deg2rad ) * rad2deg;
01519 }
01520 else if(m_rotModes&rotEndpointRational)
01521 {
01522 *angle=RationalRestrict( *angle * deg2rad ) * rad2deg;
01523 }
01524 }
01525
01526 }
01527
01528 void a2dRestrictionEngineOld::RestrictPoint(double *x, double *y)
01529 {
01530
01531 if((m_posModesX & posSngl) && m_docSnapDistX)
01532 {
01533 *x = floor((*x-m_docOriginX) / m_docSnapDistX+0.5) * m_docSnapDistX + m_docOriginX;
01534 }
01535
01536 if((m_posModesY & posSngl) && m_docSnapDistY)
01537 {
01538 *y = floor((*y-m_docOriginY) / m_docSnapDistY+0.5) * m_docSnapDistY + m_docOriginY;
01539 }
01540 }
01541
01542 double a2dRestrictionEngineOld::AngleRestrict(double angle)
01543 {
01544 double
01545 angleSnapRad=m_rotationAngle/180*wxPI;
01546 return floor(angle/angleSnapRad+0.5)*angleSnapRad;
01547 }
01548
01549 void a2dRestrictionEngineOld::AngleRestrictVectorRot(double *vecx, double *vecy)
01550 {
01551 double
01552 angle = atan2( *vecy, *vecx ),
01553 len = sqrt( sqr( *vecx ) + sqr( *vecy ) );
01554 angle = AngleRestrict( angle );
01555 *vecx = cos( angle ) * len;
01556 *vecy = sin( angle ) * len;
01557 }
01558
01559 void a2dRestrictionEngineOld::AngleRestrictVectorSkew(double *vecx, double *vecy, double otherx, double othery) {
01560 double
01561 angleOld = atan2( *vecy, *vecx ),
01562 angleNew = AngleRestrict( angleOld ),
01563 angleOther = atan2( othery, otherx ),
01564 proj = *vecx * othery - *vecy * otherx;
01565
01566 if( fabs( angleNew-angleOther) < 1e-5 )
01567 {
01568
01569
01570
01571 double
01572 angleSnapRad = m_rotationAngle/180*wxPI,
01573 angleNew1 = angleNew - angleSnapRad,
01574 angleNew2 = angleNew + angleSnapRad;
01575 if( fabs( angleOld - angleNew1 ) < fabs( angleOld - angleNew2 ) )
01576 angleNew = angleNew1;
01577 else
01578 angleNew = angleNew2;
01579 }
01580
01581 double
01582 newx = cos( angleNew ),
01583 newy = sin( angleNew ),
01584 newpro = newx * othery - newy * otherx;
01585
01586 if( !newpro )
01587 return;
01588
01589 *vecx = newx * ( proj / newpro );
01590 *vecy = newy * ( proj / newpro );
01591 }
01592
01593 double a2dRestrictionEngineOld::RationalRestrict(double angle)
01594 {
01595
01596 int
01597 quad=0;
01598 bool
01599 mirr=false;
01600
01601 if(angle<0)
01602 angle+=2*wxPI;
01603
01604 if(angle>wxPI)
01605 {
01606 quad+=2;
01607 angle-=wxPI;
01608 }
01609 if(angle>wxPI/2)
01610 {
01611 quad+=1;
01612 angle-=wxPI/2;
01613 }
01614 if(angle>wxPI/4)
01615 {
01616 mirr=true;
01617 angle=wxPI/2-angle;
01618 }
01619
01620 if(!m_angleList)
01621 {
01622
01623 const int
01624 mAngles=31*30/2+1;
01625 int
01626 nAngles=0;
01627 double
01628 angles[mAngles];
01629
01630 angles[nAngles++]=0;
01631 int i;
01632 for( i=1; i<=31; i++)
01633 {
01634 if(m_rotationRationalNom&(1<<i))
01635 {
01636 for(int j=i; j<=31; j++)
01637 {
01638 if(m_rotationRationalDen&(j<<i))
01639 {
01640 assert(nAngles<mAngles);
01641 angles[nAngles++]=atan(double(i)/double(j));
01642 }
01643 }
01644 }
01645 }
01646
01647
01648 qsort(angles, nAngles, sizeof(*angles), CmprDbl);
01649
01650
01651 m_nAngleList=1;
01652 for(i=1; i<nAngles; i++)
01653 {
01654 if(angles[i]-angles[m_nAngleList-1]>1e-13)
01655 {
01656 angles[m_nAngleList++]=angles[i];
01657 }
01658 }
01659
01660
01661 m_angleList=new double[m_nAngleList];
01662 memcpy(m_angleList, angles, sizeof(*m_angleList)*m_nAngleList);
01663 }
01664
01665
01666 if(m_nAngleList<=1)
01667 {
01668 angle=0;
01669 }
01670 else
01671 {
01672 int
01673 low=0,
01674 high=m_nAngleList-1,
01675 mid;
01676
01677 while(high-low>1)
01678 {
01679 mid=(low+high)>>1;
01680 if(m_angleList[mid]<angle)
01681 low=mid;
01682 else
01683 high=mid;
01684 }
01685
01686
01687
01688 if(angle-m_angleList[low]<m_angleList[high]-angle)
01689 angle=m_angleList[low];
01690 else
01691 angle=m_angleList[high];
01692 }
01693
01694
01695 if(mirr)
01696 angle=wxPI/2-angle;
01697 angle+=quad*wxPI/2;
01698
01699 return angle;
01700 }
01701
01702 void a2dRestrictionEngineOld::RationalRestrictVector(double *vecx, double *vecy)
01703 {
01704 double
01705 angle=atan2(*vecy,*vecx),
01706 len=sqrt(sqr(*vecx)+sqr(*vecy));
01707 angle=RationalRestrict(angle);
01708 *vecx=cos(angle)*len;
01709 *vecy=sin(angle)*len;
01710 }