00001 /*! \file wx/canvas/restrict.h 00002 \brief snapping engine, for snapping while editing a drawing 00003 \author Michael Sögtrop 00004 \date Created 10/27/2003 00005 00006 Copyright: 2003-2004 (c) Michael Sögtrop 00007 00008 Licence: wxWidgets Licence 00009 00010 RCS-ID: $Id: restrict.h,v 1.22 2008/09/05 19:01:10 titato Exp $ 00011 */ 00012 00013 #ifndef __RESTRICT_H__ 00014 #define __RESTRICT_H__ 00015 00016 #ifndef WX_PRECOMP 00017 #include "wx/wx.h" 00018 #endif 00019 00020 #include "wx/general/smrtptr.h" 00021 #include "wx/general/gen.h" 00022 #include "wx/artbase/artglob.h" 00023 #include "wx/canvas/candefs.h" 00024 00025 //! mask for a2dSnapToWhat flags 00026 typedef wxUint32 a2dSnapToWhatMask; 00027 00028 //!Restriction engine for editing restrictions like snapping 00029 /*! 00030 The restriction engine is used by editing tools to restrict/snap editing 00031 of points, handles, pins, segments to the same things in other objects or 00032 to a grid on the whole drawing area. We call the object which need to be snapped the source, 00033 while the object to which we want to snap the targets. 00034 When the source is a single vertex, the is no extra feature to be set. 00035 But if the source is a a2dCanvasObject, one can specify which features in it can be snapped. 00036 For the targets, there or many more options, set by a2dSnapToWhat flags in m_snapToFeatures. 00037 00038 With rational snapping is meant snapping to angles whose tangent is a rational 00039 number with a small integer nominatior and denominator. The max 00040 nominator/denominator is the snapping parameter. For slanting angles, 00041 the absolute slanting angle (that is angle to the coordinate axis) is used, 00042 not the slanting angle relative to the rotated coordinate system. With 00043 rational snapping, you can solve many problems of slant and angle snapping, 00044 where you want to snap also to the horizontal and vertical grid. If we snap 00045 to angles with a small rational tan, the resulting points will also snap to 00046 a small fraction of the horiontal or vertical grid. 00047 00048 Each of these snapping modes may be enabled separately. 00049 00050 An example menu handler to enable/disable snapping: 00051 00052 \code 00053 void MyDrawFrm::OnDrawRasterSnap(wxCommandEvent &event) 00054 { 00055 if( event.IsChecked() ) 00056 { 00057 a2dRestrictionEngine 00058 *restrict=new a2dRestrictionEngine(); 00059 restrict->SetSnapGrid(20,20); 00060 restrict->SetRotationAngle(15); 00061 restrict->SetSnapToFeatures( snapToGridPos | 00062 snapToObjectPos | snapToPinsUnconnected | 00063 snapToObjectVertexes | snapToPointAngleMod ); 00064 00065 a2dCanvasGlobals->SetRestrictionEngine(restrict); 00066 } 00067 else 00068 { 00069 a2dCanvasGlobals->SetRestrictionEngine(0); 00070 } 00071 } 00072 \endcode 00073 00074 */ 00075 00076 class A2DCANVASDLLEXP a2dRestrictionEngine : public a2dEvtHandler 00077 { 00078 A2D_DECLARE_EVENT_TABLE() 00079 00080 public: 00081 //! Constructor 00082 a2dRestrictionEngine(); 00083 00084 //! Destructor 00085 ~a2dRestrictionEngine(); 00086 00087 //! Flags for defining to what should be snapped to. 00088 //! To the drawing/snapping grid, and inside other a2dCanvasObject's 00089 enum a2dSnapToWhat 00090 { 00091 snapToNone = 0x00000000, //!< no snap to modes specified 00092 snapToObjectPosX = 0x00000001, //!< perform x position snapping 00093 snapToObjectPosY = 0x00000002, //!< perform y position snapping 00094 00095 snapToObjectPos = snapToObjectPosX|snapToObjectPosY, 00096 00097 snapToStart = 0x00000100, //!< snap start point of line 00098 snapToEnd = 0x00000200, //!< snap end point of line 00099 snapToPins = 0x00000400, //!< snap to pins in other objects 00100 snapToPinsUnconnected 00101 = 0x00000800, //!< snap to pins in other objects when not connected 00102 snapToObjectIntersection 00103 = 0x00001000, //!< snap to intersections in other objects 00104 snapToObjectVertexes 00105 = 0x00002000, //!< snap to other objects its vertexes, which are decided in a2dCanvasObject::RestrictToObject() 00106 snapToObjectSegmentsMiddle 00107 = 0x00004000, //!< snap segments middle of other objects in a2dCanvasObject::RestrictToObject() 00108 snapToObjectSegments 00109 = 0x00008000, //!< snap segments of other objects in a2dCanvasObject::RestrictToObject() 00110 00111 snapToGridPosX = 0x00010000, //!< perform x grid snapping 00112 snapToGridPosY = 0x00020000, //!< perform y grid snapping 00113 snapToGridPos = snapToGridPosX|snapToGridPosY, 00114 00115 snapToPointPosX = 0x00040000, //!< perform x position snapping to a specific point 00116 snapToPointPosY = 0x00080000, //!< perform y position snapping to a specific point 00117 snapToPointPosXorY = 0x00100000, //!< perform snapping to X or Y of a specific point 00118 snapToPointPosXorYForce = 0x00200000, //!< perform alligning to X or Y of a specific point 00119 snapToPointPos = snapToPointPosX|snapToPointPosY, 00120 00121 snapToPointAngleMod = 0x00400000, //!< perform angle snapping to multiples of m_rotationAngle to a specific point 00122 snapToPointAngleRational = 0x00800000, //!< perform rational angle snapping to a specific point 00123 snapToPointAngle = snapToPointAngleMod|snapToPointAngleRational, 00124 00125 snapToBoundingBox = 0x01000000, //!< perform snapping to boundingbox of objects 00126 00127 snapToObjectSnapVPath = 0x02000000, //!< perform snapping to snapping vector path returned by a2dCanvasObject::GetSnapVpath() 00128 00129 snapToAll = 0xFFFFFFFF //! mask to allow all possible snapping modes. 00130 00131 }; 00132 00133 friend a2dSnapToWhat operator | (a2dSnapToWhat a, a2dSnapToWhat b) {return (a2dSnapToWhat) ((int)a|(int)b);} 00134 00135 //! Set snapping grid (only position) 00136 void SetSnapGrid( const a2dDoMu& x, const a2dDoMu& y) {m_snapDistX=x; m_snapDistY=y; SetInternal(); } 00137 00138 //! Get horizontal center snapping distance (zero if disabled) 00139 const a2dDoMu& GetSnapGridX() const {return m_snapDistX; } 00140 00141 //! Get vertical center snapping distance (zero if disabled) 00142 const a2dDoMu& GetSnapGridY() const {return m_snapDistY; } 00143 00144 //! Set snapping origin (position grid offest/shift) 00145 void SetSnapOrigin( const a2dDoMu& x, const a2dDoMu& y) {m_originX=x; m_originY=y; SetInternal(); } 00146 00147 void SetSnapOriginX( const a2dDoMu& x) { m_originX=x; SetInternal(); } 00148 void SetSnapOriginY( const a2dDoMu& y) { m_originY=y; SetInternal(); } 00149 00150 //! Get snapping origin X (position grid offset/shift) 00151 const a2dDoMu& GetSnapOriginX() const {return m_originX;} 00152 00153 //! Get snapping origin Y (position grid offset/shift) 00154 const a2dDoMu& GetSnapOriginY() const {return m_originY;} 00155 00156 //! Set rotation angle raster 00157 void SetRotationAngle(double a) {m_rotationAngle=a; } 00158 00159 //! Get rotation angle raster 00160 double GetRotationAngle() const { return m_rotationAngle; } 00161 00162 //! used to snap vertexes to a pin or point like snapping features in objects. 00163 int GetSnapThresHold() const { return m_snapThresHold; } 00164 00165 //! used to snap vertexes to a pin or point like snapping features in objects. 00166 void SetSnapThresHold( int thresHold ) { m_snapThresHold = thresHold; } 00167 00168 //! used to snap vertexes to a pin or point, for snapping features in objects. 00169 /*! 00170 Calculated from m_snapThresHold, taking into account the active a2dCanvasView. 00171 */ 00172 double GetSnapThresHoldWorld() const; 00173 00174 //! enable all snapping features or not 00175 void SetSnap(bool snap){ m_snap = snap; } 00176 00177 //! enable all snapping features or not 00178 bool GetSnap() const {return m_snap;} 00179 00180 //! enable all snapping features for object only for visible object. 00181 void SetSnapOnlyVisibleObjects( bool snapOnlyVisbleObjects ){ m_snapOnlyVisbleObjects = snapOnlyVisbleObjects; } 00182 00183 //! all snapping features for object only for visible object? 00184 bool GetSnapOnlyVisibleObjects() const { return m_snapOnlyVisbleObjects; } 00185 00186 //! Set rotation rational raster nominator/denominator mask 00187 /*! 00188 nomMask bitX / denMask bit Y present an angle in radians to which can be snapped. 00189 e.g. if bit 2 is set in nomMask, and bit 6 is set in denMask, we will have 1/5 snap to 2*PI/5 00190 00191 \param nomMask each bit set here presents a number (bit1 number 0 until bit32 number 31) 00192 \param denMask each bit set here presents a number (bit1 number 0 until bit32 number 31) 00193 */ 00194 void SetRotationRational(wxUint32 nomMask, wxUint32 denMask) { 00195 m_rotationRationalNom=nomMask; m_rotationRationalDen=denMask; } 00196 00197 //! set what snapping features or enabled for the source to snap to. 00198 //! see a2dSnapToWhat for snapping features. 00199 void SetSnapSourceFeatures( wxUint32 snapSourceFeatures ) { m_snapSourceFeatures = snapSourceFeatures; } 00200 00201 void SetSnapSourceFeature( a2dSnapToWhat snapSourceFeature, bool value = true ) 00202 { 00203 m_snapSourceFeatures = value? m_snapSourceFeatures | snapToPins : 00204 m_snapSourceFeatures & ( snapToAll ^ snapToPins ); 00205 } 00206 00207 //! set what snapping features or enabled for the source to snap to. 00208 //! see a2dSnapToWhat for snapping features. 00209 wxUint32 GetSnapSourceFeatures() const { return m_snapSourceFeatures; } 00210 00211 //! set what snapping features or enabled for the target to snap to. 00212 //! see a2dSnapToWhat for snapping features. 00213 void SetSnapToFeatures( wxUint32 snapToFeatures ) { m_snapToFeatures = snapToFeatures; } 00214 00215 void SetSnapToFeature( a2dSnapToWhat snapToFeature, bool value = true ) 00216 { 00217 m_snapToFeatures = value? m_snapToFeatures | snapToFeature : 00218 m_snapToFeatures & ( snapToAll ^ snapToFeature ); 00219 } 00220 00221 bool GetSnapToFeature( a2dSnapToWhat snapToFeature ) const 00222 { 00223 return (m_snapToFeatures & snapToFeature) > 0; 00224 } 00225 00226 //! set what snapping features or enabled for the target to snap to. 00227 //! see a2dSnapToWhat for snapping features. 00228 wxUint32 GetSnapToFeatures() const { return m_snapToFeatures; } 00229 00230 //! return the clossest vertex which can be snapped if any. 00231 /*! 00232 The source a2dCanvasObject is asked for its snapping features/vertexes via a2dCanvasObject::GetSnapVpath(), 00233 but only those ementioned in m_snapSourceFeatures. All the features returned will be tried to snap to neighbouring 00234 canvas objects, and eventually the grid. e.g. It calls for each vertex in the snapping path the function RestrictPoint(), 00235 and the clossest snapped point will be snapped to. 00236 00237 \param object object to be snapped to other snapping targets 00238 \param point if a point to snap is found, it is stored here. 00239 \param dx x distance from the returned point to the snapping point. 00240 \param dy y distance from the returned point to the snapping point. 00241 \param sourceRequired what the caller wants the snapping points in the object to restrict to. ( is ANDed with m_snapToFeatures ) 00242 \param ignoreEngine set to ignore engine its own snap modes. 00243 */ 00244 virtual bool RestrictCanvasObjectAtVertexes( a2dCanvasObject* object, a2dPoint2D& point, double& dx, double& dy, wxUint32 sourceRequired = snapToAll, bool ignoreEngine = false ); 00245 00246 //! return the clossest vertex which can be snapped if any. 00247 /*! 00248 \param segments segments to be snapped to other snapping targets 00249 \param point if a point to snap is found, it is stored here. 00250 \param dx x distance from the returned point to the snapping point. 00251 \param dy y distance from the returned point to the snapping point. 00252 \param sourceRequired what the caller wants the snapping points to restrict to. ( is ANDed with m_snapToFeatures ) 00253 \param ignoreEngine set to ignore engine its own snap modes. 00254 */ 00255 virtual bool RestrictVertexes( a2dVertexArray* segments, a2dPoint2D& point, double& dx, double& dy, wxUint32 sourceRequired = snapToAll, bool ignoreEngine = false ); 00256 00257 //! return the clossest vertex which can be snapped if any. 00258 /*! 00259 \param lsegments segments to be snapped to other snapping targets 00260 \param point if a point to snap is found, it is stored here. 00261 \param dx x distance from the returned point to the snapping point. 00262 \param dy y distance from the returned point to the snapping point. 00263 \param sourceRequired what the caller wants the snapping points to restrict to. ( is ANDed with m_snapToFeatures ) 00264 \param ignoreEngine set to ignore engine its own snap modes. 00265 */ 00266 virtual bool RestrictVertexes( a2dVertexList* lsegments, a2dPoint2D& point, double& dx, double& dy, wxUint32 sourceRequired = snapToAll, bool ignoreEngine = false ); 00267 00268 //! Restrict a single point of a line or polyline 00269 /*! 00270 \param x input x and output x after restriction 00271 \param y input y and output y after restriction 00272 \param sourceRequired what the caller wants the (x,y) to restrict to. ( is ANDed with m_snapToFeatures ) 00273 \param ignoreEngine set to ignore engine its own snap modes. 00274 00275 \return true if the point was restricted 00276 */ 00277 virtual bool RestrictPoint(double& x, double& y, wxUint32 sourceRequired = snapToAll, bool ignoreEngine = false ); 00278 00279 //! Restrict a single line 00280 /*! 00281 \param line the line to restrict 00282 \param sourceRequired what the caller wants the (x,y) to restrict to. ( is ANDed with m_snapToFeatures ) 00283 \param ignoreEngine set to ignore engine its own snap modes. 00284 00285 \return true if the point was restricted 00286 */ 00287 virtual bool RestrictLine( a2dLine& line, wxUint32 sourceRequired = snapToAll, bool ignoreEngine = false ); 00288 00289 //! Restrict angle 00290 /*! 00291 \param ang input angle and output angle after restriction 00292 \param sourceRequired what the caller wants the (x,y) to restrict to. ( is ANDed with m_snapToFeatures ) 00293 \param ignoreEngine set to ignore engine its own snap modes. 00294 00295 \return true if the point was restricted 00296 */ 00297 virtual bool RestrictAngle( double *ang, wxUint32 sourceRequired = snapToAll, bool ignoreEngine = false ); 00298 00299 //! sets the point for snapping to 00300 /*! 00301 In modes: 00302 - a2dSnapToWhat::snapToPointPos 00303 - a2dSnapToWhat::snapToPointPosX 00304 - a2dSnapToWhat::snapToPointPosY 00305 - a2dSnapToWhat::snapToPointPos 00306 - a2dSnapToWhat::snapToPointPosXorY 00307 */ 00308 void SetRestrictPoint( double xSnap, double ySnap ) { m_pointToRestrictTo = a2dPoint2D( xSnap, ySnap ); } 00309 00310 //! to ask engine for the restrict point 00311 /*! 00312 For snapping modes that restrict to X,Y of the restrict Point. 00313 */ 00314 const a2dPoint2D& GetRestrictPoint() const { return m_pointToRestrictTo; } 00315 00316 //! to ask engine for the point that needs to be snapped to a a2dCanvasObject 00317 /*! 00318 When engine is asked to snap a vertex/point, the result point to snap is set. 00319 This can be used by e.g. a2dCanvasObject::RestrictToObject() to snap to pins etc. 00320 */ 00321 a2dPoint2D GetPointToSnap() const { return m_pointToSnap; } 00322 00323 //! set the point that was snapped to a a2dCanvasObject vertex 00324 /*! 00325 When engine is asked to snap a vertex/point, the result point is set here. 00326 This is used e.g. a2dCanvasObject::RestrictToObject() to snap to pins etc. 00327 */ 00328 void SetPointSnapResult( const a2dPoint2D& p ); 00329 00330 //! set the point that was snapped to a a2dCanvasObject vertex 00331 /*! 00332 When engine is asked to snap a vertex/point, the result point is set here. 00333 But only of the new point is closer than the old one. 00334 This is used e.g. a2dCanvasObject::RestrictToObject() to snap to pins etc. 00335 */ 00336 bool SetPointSnapResultIfCloser( const a2dPoint2D& p ); 00337 00338 //! to ask engine for the line that needs to be snapped to a a2dCanvasObject 00339 /*! 00340 When engine is asked to snape a line, the line to snap is set. 00341 This can be used by e.g. a2dCanvasObject::RestrictToObject() to snap to othere lines, pins etc. 00342 */ 00343 a2dLine& GetLineToSnap() { return m_lineToSnap; } 00344 00345 //! parent object of objects that need to be snapped to 00346 /*! 00347 For snapping features where canvas objects are involved, this needs to be set to the 00348 parent object of the objects which can be snaped or can be snapped to. 00349 For example when needing to snap a vertex/point to the objects in a a2dcanvasView, 00350 set this parent object to the a2dcanvasView::GetShowObject(). 00351 00352 \remark when using the restriction engine, you much make sure this is set right each time. 00353 00354 \param obj: pointer to object to set as parent 00355 */ 00356 void SetParentSnapObjects(a2dCanvasObject* obj) { m_parentObject = obj; } 00357 00358 //! return pointer of the current parent object 00359 /*! 00360 \return: pointer to the current parent object. 00361 */ 00362 a2dCanvasObject* GetParentSnapObjects() const { return m_parentObject; } 00363 00364 00365 //! some snapping may depend on shift key being down 00366 void SetShiftKeyDown(bool shiftDown){ m_shiftDown = shiftDown;} 00367 00368 //! some snapping may depend on shift key being down 00369 bool GetShiftKeyDown() const { return m_shiftDown; } 00370 00371 //! some snapping may depend on alt key being down 00372 void SetAltKeyDown(bool altDown){ m_altDown = altDown;} 00373 00374 //! some snapping may depend on alt key being down 00375 bool GetAltKeyDown() const { return m_altDown; } 00376 00377 //! react on activation of a view, to set snap margin 00378 void OnActivate( a2dViewEvent& viewevent ); 00379 00380 private: 00381 //! Some stuff nedded by the ref counting base class 00382 virtual a2dObject* Clone( CloneOptions WXUNUSED(options) ) const { wxASSERT(0); return 0; } 00383 00384 #if wxART2D_USE_CVGIO 00385 virtual void DoSave( wxObject* WXUNUSED(parent), a2dIOHandlerXmlSerOut &WXUNUSED(out), a2dXmlSer_flag WXUNUSED(xmlparts), a2dObjectList* WXUNUSED(towrite) ) { wxASSERT(0); } 00386 virtual void DoLoad( wxObject* WXUNUSED(parent), a2dIOHandlerXmlSerIn& WXUNUSED(parser), a2dXmlSer_flag WXUNUSED(xmlparts) ) { wxASSERT(0); } 00387 #endif //wxART2D_USE_CVGIO 00388 00389 protected: 00390 00391 void SetInternal(); 00392 00393 //! Restrict an angle 00394 double AngleRestrict(double angle); 00395 //! Restrict the angle of a vector, keeping the vectors length 00396 void AngleRestrictVectorRot(double *vecx, double *vecy); 00397 //! Restrict the angle of a vector, keeping the vectors projection on the orthogonal of another vector 00398 void AngleRestrictVectorSkew(double *vecx, double *vecy, double otherx, double othery); 00399 00400 //! Rational restrict an angle 00401 double RationalRestrict(double angle); 00402 //! Rational restrict the angle of a vector 00403 void RationalRestrictVector(double *vecx, double *vecy); 00404 00405 //! set to the a2dSnapToWhat features enabled by the engine for the source object 00406 wxUint32 m_snapSourceFeatures; 00407 00408 //! set to the a2dSnapToWhat target features enabled by the engine and/or snap source object 00409 wxUint32 m_snapToFeatures; 00410 00411 a2dDoMu m_snapDistX; //!< horizontal position snapping grid distance 00412 a2dDoMu m_snapDistY; //!< vertical position snapping grid distance 00413 a2dDoMu m_originX; //!< horizontal grid snapping origin vs. coordinate origin 00414 a2dDoMu m_originY; //!< vertical grid snapping origins vs. coordinate origin 00415 double m_rotationAngle; //!< angle snapping angle in degrees 00416 wxUint32 m_rotationRationalNom; //!< bit map of possible nominators (bit1->0.. bit32->31) for rational angle snapping 00417 wxUint32 m_rotationRationalDen; //!< bit map of possible denominators (bit1->0.. bit32->31) for rational angle snapping 00418 double *m_angleList; //!< sorted list of allowed rational angles 00419 int m_nAngleList; //!< number of allowed rational angles 00420 00421 //! threshold in pixels towards the snapping point. 00422 int m_snapThresHold; 00423 00424 //! set to point that is currently being snapped. 00425 a2dPoint2D m_pointToSnap; 00426 00427 //! set to point that is snapped to m_pointToSnap 00428 a2dPoint2D m_snappedPoint; 00429 00430 a2dPoint2D m_pointToRestrictTo; 00431 00432 a2dLine m_lineToSnap; 00433 00434 bool m_snapOnlyVisbleObjects; //!< if true snapping modes for object is only on visible object. 00435 bool m_snap; //!< if true snapping modes are enabled, else non. 00436 bool m_altDown; //!< snapping modifier when alt key is pressed 00437 bool m_shiftDown; //!< snapping modifier when shift key is pressed 00438 00439 //! parent canvas object in a2dCanvasDocument on which snapping needs to be done. 00440 a2dCanvasObject* m_parentObject; 00441 00442 //! units of measurement taken from here, unless NULL 00443 a2dCanvasDocument* m_doc; 00444 00445 //! units of view taken from here, unless NULL 00446 a2dCanvasView* m_view; 00447 00448 double m_docSnapDistX; 00449 double m_docSnapDistY; 00450 double m_docOriginX; 00451 double m_docOriginY; 00452 00453 public: 00454 00455 static a2dPropertyIdUint32* PROPID_SnapSourceFeaturesMem; 00456 static a2dPropertyIdUint32* PROPID_SnapSourceFeatures; 00457 static a2dPropertyIdUint32* PROPID_SnapToFeatures; 00458 static a2dPropertyIdDouble* PROPID_RotationAngle; 00459 static a2dPropertyIdUint32* PROPID_RotationRationalNom; 00460 static a2dPropertyIdUint32* PROPID_RotationRationalDen; 00461 static a2dPropertyIdInt32* PROPID_SnapThresHold; 00462 static a2dPropertyIdPoint2D* PROPID_PointToSnap; 00463 static a2dPropertyIdPoint2D* PROPID_PointToRestrictTo; 00464 static a2dPropertyIdBool* PROPID_SnapOnlyVisbleObjects; 00465 static a2dPropertyIdBool* PROPID_Snap; 00466 static a2dPropertyIdBool* PROPID_SnapGetSet; 00467 static a2dPropertyIdBool* PROPID_AltDown; 00468 static a2dPropertyIdBool* PROPID_ShiftDown; 00469 00470 DECLARE_PROPERTIES() 00471 }; 00472 00473 //! Smart pointer type for restriction engine 00474 #if defined(WXART2D_USINGDLL) 00475 template class A2DCANVASDLLEXP a2dSmrtPtr<a2dRestrictionEngine>; 00476 #endif 00477 typedef a2dSmrtPtr<a2dRestrictionEngine> a2dRestrictionEnginePtr; 00478 00479 00480 00481 00482 00483 00484 00485 00486 00487 00488 //! DEPRECATED Restriction engine for editing restrictions like snapping 00489 /*! 00490 The restriction engine is used by editing tools to restrict editing 00491 of points and affine transformations. 00492 00493 - For affine transformations, the following restrictions are implemented 00494 00495 -# Snapping of position 00496 -# Snapping of the size 00497 -# Snapping of the rotation in frations of a full rotation or rational 00498 snapping. 00499 -# Snapping of the slanting angles in fractions of a full rotation or 00500 rational snapping 00501 -# Minimum and maximum size 00502 00503 With rational snapping i mean snapping to angles whose tangent is a rational 00504 number with a small integer nominatior and denominator. The max 00505 nominator/denominator is the snapping parameter. For slanting angles, 00506 the absolute slanting angle (that is angle to the coordinate axis) is used, 00507 not the slanting angle relative to the rotated coordinate system. With 00508 rational snapping, you can solve many problems of slant and angle snapping, 00509 where you want to snap also to the horizontal and vertical grid. If we snap 00510 to angles with a small rational tan, the resulting points will also snap to 00511 a small fraction of the horiontal or vertical grid. 00512 00513 - For position snapping of affine transformations, any of the 4 corner, 00514 4 midline or the center point can snap to a grid. Each point can be enabled 00515 separately. Snapping of the non-center points can also be enabled only 00516 in the case, that they are connected to a vertical or horizontal border line. 00517 00518 - For size snapping of affine transformations assume that the affine transformation 00519 transformes the origin and two unity length coordinate axis vectors to a different 00520 origin with different axis orientation and length. This way, the transformation 00521 consits of three vectors, the origin vector, the x-axis vector and the 00522 y-axis vector. The x-size can be one of the following: 00523 00524 -# the length of the transformed x-axis vector 00525 -# the projection of the transformed x-axis vector on a line perpendicular 00526 to the transformed y-axis 00527 -# the larger component of the x-axis vector 00528 -# the first (horizontal) component of the x-axis vector. 00529 00530 Each of these snapping modes may be enabled separately. 00531 00532 - Points and lines are simply snapped to a grid. 00533 00534 - An example menu handler to enable/disable snapping: 00535 00536 \code 00537 void MyDrawFrm::OnDrawRasterSnap(wxCommandEvent &event) 00538 { 00539 if( event.IsChecked() ) 00540 { 00541 a2dRestrictionEngineOld 00542 *restrict=new a2dRestrictionEngineOld(); 00543 restrict->SetSnapGrid(20,20); 00544 restrict->SetPosModes(a2dRestrictionEngineOld::pos3P|a2dRestrictionEngineOld::posSngl|a2dRestrictionEngineOld::posOther); 00545 restrict->SetSizeModes(a2dRestrictionEngineOld::sizeLength|a2dRestrictionEngineOld::sizeMin); 00546 restrict->SetRotationModes(a2dRestrictionEngineOld::rotAllAngle); 00547 restrict->SetRotationAngle(15); 00548 a2dCanvasGlobals->SetRestrictionEngine(restrict); 00549 } 00550 else 00551 { 00552 a2dCanvasGlobals->SetRestrictionEngine(0); 00553 } 00554 } 00555 \endcode 00556 00557 \todo Implement angle snapping for lines with length snapping or snapping of 00558 the endpoints to vertical or horizontal grodlines. 00559 */ 00560 00561 class A2DCANVASDLLEXP a2dRestrictionEngineOld : public a2dObject 00562 { 00563 public: 00564 //! Constructor 00565 a2dRestrictionEngineOld(); 00566 00567 //! Destructor 00568 ~a2dRestrictionEngineOld(); 00569 00570 //! Position snap modes/flags (once for x any y) 00571 enum EPositionSnapModes 00572 { 00573 posCenter = 0x00000001, //!< enable position snapping of object center to grid 00574 posTopLeft = 0x00000002, //!< enable position snapping of object top left to grid 00575 posTop = 0x00000004, //!< enable position snapping of object top to grid 00576 posTopRight = 0x00000008, //!< enable position snapping of object top right to grid 00577 posRight = 0x00000010, //!< enable position snapping of object right to grid 00578 posBottomRight = 0x00000020, //!< enable position snapping of object bottom right to grid 00579 posBottom = 0x00000040, //!< enable position snapping of object bottom to grid 00580 posBottomLeft = 0x00000080, //!< enable position snapping of object bottom left to grid 00581 posLeft = 0x00000100, //!< enable position snapping of object left to grid 00582 posLineTop = 0x00000200, //!< enable position snapping of object top line to grid, if x axis parallel to main axis 00583 posLineHCenter = 0x00000400, //!< enable position snapping of object h-center line to grid, if x axis parallel to main axis 00584 posLineBottom = 0x00000800, //!< enable position snapping of object bottom line to grid, if x axis parallel to main axis 00585 posLineLeft = 0x00001000, //!< enable position snapping of object left line to grid, if y axis parallel to main axis 00586 posLineVCenter = 0x00002000, //!< enable position snapping of object v-center line to grid, if y axis parallel to main axis 00587 posLineRight = 0x00004000, //!< enable position snapping of object right line to grid, if y axis parallel to main axis 00588 posOther = 0x00008000, //!< enable position snapping of object other points to grid (e.g. triangle corner) 00589 posSngl = 0x00010000, //!< enable restriction of single points (e.g. of polylines) 00590 00591 posEqual = 0x80000000, //!< used internally 00592 posNone = 0x00000000, //!< disable all posizion restriction modes 00593 00594 //! enable all 6 line snapping modes 00595 pos6L = posLineTop|posLineHCenter|posLineBottom|posLineLeft|posLineVCenter|posLineRight, 00596 //! enable center point snapping modes 00597 pos1P = posCenter, 00598 //! enable center + top left point snapping modes 00599 pos2P = posCenter|posTopLeft, 00600 //! enable center + top left + bottom right point snapping modes 00601 pos3P = posCenter|posTopLeft|posBottomRight, 00602 //! enable all center + 4 corner point snapping modes 00603 pos5P = posCenter|posTopLeft|posTopRight|posBottomRight|posBottomLeft, 00604 //! enable all 9 point snapping modes 00605 pos9P = posCenter|posTopLeft|posTop|posTopRight|posRight|posBottomRight|posBottom|posBottomLeft|posLeft, 00606 //! enable all position restriction modes, except other point modes 00607 posAny = pos9P|pos6L|posSngl, 00608 //! enable center point and all 6 line snapping modes 00609 pos1P6L = posCenter|pos6L, 00610 }; 00611 friend EPositionSnapModes operator | (EPositionSnapModes a, EPositionSnapModes b) {return (EPositionSnapModes) ((int)a|(int)b);} 00612 00613 //! Size snap modes/flags (once for x and y) 00614 enum ESizeSnapModes 00615 { 00616 sizeLength = 0x00000001, //!< enable size snapping of transformed axis vector length 00617 sizeProject = 0x00000002, //!< enable snapping of projection of transformed axis vector length to orthogonal of other axis vector 00618 sizeMajor = 0x00000004, //!< enable size snapping of transformed axis major component 00619 sizeAxis = 0x00000008, //!< enable size snapping of projection to untronsformed axis 00620 sizePos = 0x00000010, //!< snap size by snapping individual points 00621 sizeMin = 0x00000020, //!< enable minimum size restriction 00622 sizeMax = 0x00000040, //!< enable maximum size restriction 00623 sizeEqual = 0x80000000, //!< used internally 00624 sizeNone = 0x00000000, //!< disable all size restriction modes 00625 sizeAny = 0x0000007F //!< enable all size restriction modes 00626 }; 00627 friend ESizeSnapModes operator | (ESizeSnapModes a, ESizeSnapModes b) {return (ESizeSnapModes) ((int)a|(int)b);} 00628 00629 //! Rotation/Slanting snap modes/flags 00630 enum ERotationSnapModes 00631 { 00632 // affine rotation/skew snapping 00633 rotVectorAngleX = 0x00000001, //!< enable angle snapping for rotation of first coordinate vektor 00634 rotVectorRationalX = 0x00000002, //!< enable rational snapping for rotations of first coordinate vektor 00635 rotVectorAngleY = 0x00000004, //!< enable angle snapping for rotations of second coordinate vektor 00636 rotVectorRationalY = 0x00000008, //!< enable rational snapping for rotations of second coordinate vektor 00637 rotPureRotations = 0x00000010, //!< allow only pure rotations, no slanting 00638 rotPureSlanting = 0x00000020, //!< allow only pure one axis slanting 00639 00640 // endpoint angle snapping 00641 rotEndpointAngle = 0x00000040, //!< enable snapping of arc endpoint angles 00642 rotEndpointRational = 0x00000080, //!< enable snapping of arc endpoint angles (rational) 00643 rotEndpointUntrans = 0x00000100, //!< enable snapping of arc ednpoints in untransformed coordinate system 00644 00645 rotNone = 0x00000000, //!< disable all rotation restriction modes 00646 rotAllAngle = rotVectorAngleX|rotVectorAngleY|rotEndpointAngle, 00647 rotAllRational = rotVectorRationalX|rotVectorRationalY|rotEndpointRational, 00648 rotAll = 0x000001FF 00649 }; 00650 friend ERotationSnapModes operator | (ERotationSnapModes a, ERotationSnapModes b) {return (ERotationSnapModes) ((int)a|(int)b);} 00651 00652 //! Flags for what to touch during a restriction 00653 enum ESnapWhat 00654 { 00655 snapPosX = 0x00000001, //!< perform x position snapping 00656 snapPosY = 0x00000002, //!< perform y position snapping 00657 snapSizeX = 0x00000004, //!< perform x size snapping 00658 snapSizeY = 0x00000008, //!< perform y size snapping 00659 snapRot = 0x00000010, //!< perform rotation snapping 00660 snapSkew = 0x00000020, //!< perform skew snapping 00661 snapWH = 0x00000040, //!< during size snapping, change w/h rather than transform 00662 snapEndAngle = 0x00000080, //!< snap angle of endpoints or arcs 00663 snapStart = 0x00000100, //!< snap start point of line 00664 snapEnd = 0x00000200, //!< snap end point of line 00665 snapPointI = 0x80000000, //!< snap point i of polygon (ored with i, other flags are invalid) 00666 snapPos = snapPosX|snapPosY, 00667 snapSize = snapSizeX|snapSizeY, 00668 snapPosSize = snapPos|snapSize, 00669 snapSizeWH = snapSize|snapWH, 00670 }; 00671 friend ESnapWhat operator | (ESnapWhat a, ESnapWhat b) {return (ESnapWhat) ((int)a|(int)b);} 00672 00673 //! Structure to descripe snapping properties of an object 00674 struct SnapObjectInfo 00675 { 00676 double m_left; //!< minimum x coordinate (e.g. 0), transformed via affine transform and w 00677 double m_top; //!< minimum y coordinate (e.g. 0), transformed via affine transform and h 00678 double m_right; //!< maximum x coordinate (e.g. 1), transformed via affine transform and w 00679 double m_bottom; //!< maximum y coordinate (e.g. 1), transformed via affine transform and h 00680 double m_centerX; //!< center x coordinate (e.g. 0.5), transformed via affine transform and w 00681 double m_centerY; //!< center y coordinate (e.g. 0.5), transformed via affine transform and h 00682 EPositionSnapModes m_posModesX; //!< anded with m_posModesX of wxRetrictionEngine 00683 EPositionSnapModes m_posModesY; //!< anded with m_posModesY of wxRetrictionEngine 00684 ESizeSnapModes m_sizeModesX; //!< anded with m_sizeModesX of wxRetrictionEngine 00685 ESizeSnapModes m_sizeModesY; //!< anded with m_sizeModesY of wxRetrictionEngine 00686 ERotationSnapModes m_rotModes; //!< anded with m_rotModes of wxRetrictionEngine 00687 class a2dVertexList *m_other; //!< other snapping points (enabled by bits in m_posModesX/m_posModesY, NOT owned or deleted by this object) 00688 }; 00689 00690 //! Set position snap modes (ored EPositionSnapModes) 00691 void SetPosModes(EPositionSnapModes modeX, EPositionSnapModes modeY=posEqual) {m_posModesX = modeX; m_posModesY = modeY==posEqual ? modeX : modeY;} 00692 //! Get position snap modes (ored EPositionSnapModes) 00693 EPositionSnapModes GetPosModesX() {return m_posModesX;} 00694 EPositionSnapModes GetPosModesY() {return m_posModesY;} 00695 00696 //! Set size snap modes (ored ESizeSnapModes) 00697 void SetSizeModes(ESizeSnapModes modeX, ESizeSnapModes modeY=sizeEqual) {m_sizeModesX = modeX; m_sizeModesY = modeY==sizeEqual ? modeX : modeY;} 00698 //! Get size snap modes (ored ESizeSnapModes) 00699 ESizeSnapModes GetSizeModesX() {return m_sizeModesX;} 00700 ESizeSnapModes GetSizeModesY() {return m_sizeModesY;} 00701 00702 //! Set rotation/slanting snap modes (ored ERotationSnapModes) 00703 void SetRotationModes(ERotationSnapModes mode) {m_rotModes = mode;} 00704 //! Get rotation/slanting snap modes (ored ERotationSnapModes) 00705 ERotationSnapModes GetRotationModes() {return m_rotModes;} 00706 00707 //! Set snapping grid (position and size) 00708 void SetSnapGrid( double x, double y ) {m_snapDistX=x; m_snapDistY=y; m_sizeX=x, m_sizeY=y; } 00709 //! Set snapping grid (only position) 00710 void SetPosGrid( double x, double y ) {m_snapDistX=x; m_snapDistY=y;} 00711 //! Set snapping grid (only size) 00712 void SetSizeGrid(double x, double y) {m_sizeX=x; m_sizeY=y;} 00713 //! Set snapping origin (position grid offest/shift) 00714 void SetSnapOrigin(double x, double y) {m_originX=x; m_originY=y;} 00715 //! Set minimum size 00716 void SetMinSize(double x, double y) {m_minSizeX=x; m_minSizeY=y; } 00717 //! Set maximum size 00718 void SetMaxSize(double x, double y) {m_maxSizeX=x; m_maxSizeY=y; } 00719 //! Set rotation angle raster 00720 void SetRotationAngle(double a) {m_rotationAngle=a; } 00721 //! Set rotation rational raster nominator/denominator mask 00722 void SetRotationRational(wxUint32 nomMask, wxUint32 denMask) { 00723 m_rotationRationalNom=nomMask; m_rotationRationalDen=denMask; } 00724 00725 //! Restrict an affine transformation 00726 /*! \param mNew the edited tranformation matrix, that will be restricted 00727 * \param mOld the tranformation matrix as it was prior to editing 00728 * \param snapWhat enable various snapping options 00729 * \param info snapping info 00730 * \param w if (snapWhat & snapWH) the w parameter reflects the width, rather than the matrix 00731 * \param h if (snapWhat & snapWH) the h parameter reflects the height, rather than the matrix 00732 */ 00733 void RestrictAffine(a2dAffineMatrix *mNew, const a2dAffineMatrix *mOld, ESnapWhat snapWhat, SnapObjectInfo *info, double *w=0, double *h=0); 00734 00735 //! Restrict a starting /ending angle of e.g. an elliptic arc 00736 //! The angle is in degrees 00737 //! The matrix is required for e.g. untransformed snapping 00738 void RestrictEndpointAngle(double *angle, const a2dAffineMatrix &matrix, ESnapWhat snapWhat); 00739 00740 //! Restrict a single point of a line or polyline 00741 void RestrictPoint(double *x, double *y); 00742 00743 //! Get horizontal center snapping distance (zero if disabled) 00744 double GetCenterSnapX() {return (m_posModesX&posAny) ? m_snapDistX : 0;} 00745 //! Get vertical center snapping distance (zero if disabled) 00746 double GetCenterSnapY() {return (m_posModesY&posAny) ? m_snapDistY : 0;} 00747 00748 private: 00749 //! Some stuff nedded by the ref counting base class 00750 virtual a2dObject* Clone( CloneOptions WXUNUSED(options) ) const { wxASSERT(0); return 0; } 00751 00752 #if wxART2D_USE_CVGIO 00753 virtual void DoSave( wxObject* WXUNUSED(parent), a2dIOHandlerXmlSerOut &WXUNUSED(out), a2dXmlSer_flag WXUNUSED(xmlparts), a2dObjectList* WXUNUSED(towrite) ) { wxASSERT(0); } 00754 virtual void DoLoad( wxObject* WXUNUSED(parent), a2dIOHandlerXmlSerIn& WXUNUSED(parser), a2dXmlSer_flag WXUNUSED(xmlparts) ) { wxASSERT(0); } 00755 #endif //wxART2D_USE_CVGIO 00756 00757 protected: 00758 //! Restrict an angle 00759 double AngleRestrict(double angle); 00760 //! Restrict the angle of a vector, keeping the vectors length 00761 void AngleRestrictVectorRot(double *vecx, double *vecy); 00762 //! Restrict the angle of a vector, keeping the vectors projection on the orthogonal of another vector 00763 void AngleRestrictVectorSkew(double *vecx, double *vecy, double otherx, double othery); 00764 00765 //! Rational restrict an angle 00766 double RationalRestrict(double angle); 00767 //! Rational restrict the angle of a vector 00768 void RationalRestrictVector(double *vecx, double *vecy); 00769 00770 EPositionSnapModes m_posModesX; //!< ored EPositionSnapModes of enabled modes for x 00771 EPositionSnapModes m_posModesY; //!< ored EPositionSnapModes of enabled modes for y 00772 ESizeSnapModes m_sizeModesX; //!< ored ESizeSnapModes of enabled modes for x 00773 ESizeSnapModes m_sizeModesY; //!< ored ESizeSnapModes of enabled modes for y 00774 ERotationSnapModes m_rotModes; //!< ored ERotationSnapModes of enabled modes 00775 double m_snapDistX; //!< horizontal position snapping grid distance 00776 double m_snapDistY; //!< vertical position snapping grid distance 00777 double m_originX; //!< horizontal grid snapping origin vs. coordinate origin 00778 double m_originY; //!< vertical grid snapping origins vs. coordinate origin 00779 double m_sizeX; //!< horizontal size snapping grid distance 00780 double m_sizeY; //!< vertical size snapping grid distance 00781 double m_minSizeX; //!< minimal horiontal size 00782 double m_minSizeY; //!< minimal vertical size 00783 double m_maxSizeX; //!< maximal horiontal size 00784 double m_maxSizeY; //!< maximal vertical size 00785 double m_rotationAngle; //!< angle snapping angle in degrees 00786 wxUint32 m_rotationRationalNom; //!< bit map of possible nominators (0..31) for rational angle snapping 00787 wxUint32 m_rotationRationalDen; //!< bit map of possible denominators (0..31) for rational angle snapping 00788 double *m_angleList; //!< sorted list of allowed rational angles 00789 int m_nAngleList; //!< number of allowed rational angles 00790 00791 double m_docSnapDistX; 00792 double m_docSnapDistY; 00793 double m_docOriginX; 00794 double m_docOriginY; 00795 00796 }; 00797 00798 #endif // __RESTRICT_H__