Code

Add 2 new object snapping modes: bbox to bbox, and nodes to bbox
authordvlierop2 <dvlierop2@users.sourceforge.net>
Wed, 25 Jul 2007 12:19:44 +0000 (12:19 +0000)
committerdvlierop2 <dvlierop2@users.sourceforge.net>
Wed, 25 Jul 2007 12:19:44 +0000 (12:19 +0000)
src/object-snapper.cpp

index a904bd93baa52505d016819338abeb3fb531cd31..88e143abaf9e3130b807386b694c37d526d4bfcc 100644 (file)
@@ -23,6 +23,7 @@
 #include "desktop.h"
 #include "inkscape.h"
 #include "splivarot.h"
+#include "prefs-utils.h"
 
 
 Inkscape::ObjectSnapper::ObjectSnapper(SPNamedView const *nv, NR::Coord const d)
@@ -78,6 +79,11 @@ void Inkscape::ObjectSnapper::_snapNodes(Inkscape::SnappedPoint &s,
     ** in SPDesktop rather than SPNamedView?
     */
     SPDesktop const *desktop = SP_ACTIVE_DESKTOP;
+    
+    // Determine the type of bounding box we should snap to
+    //TODO if (_snap_to_bbox) ???? -> will save some cpu time 
+       gchar const *prefs_bbox = prefs_get_string_attribute("tools.select", "bounding_box");
+       SPItem::BBoxType bbox_type = (prefs_bbox != NULL && strcmp(prefs_bbox, "geometric")==0)? SPItem::GEOMETRIC_BBOX : SPItem::APPROXIMATE_BBOX;        
 
     for (std::list<SPItem*>::const_iterator i = cand.begin(); i != cand.end(); i++) {
         
@@ -101,25 +107,35 @@ void Inkscape::ObjectSnapper::_snapNodes(Inkscape::SnappedPoint &s,
             curve = im->curve;
         }
             
+               std::list<NR::Point> points_to_snap_to;
+        
+        //Collect all nodes so we can snap to them
         if (curve) {
-
             int j = 0;
-
-            while (SP_CURVE_BPATH(curve)[j].code != NR_END) {
-        
+            while (SP_CURVE_BPATH(curve)[j].code != NR_END) {        
                 /* Get this node in desktop coordinates */
                 NArtBpath const &bp = SP_CURVE_BPATH(curve)[j];
-                NR::Point const n = desktop->doc2dt(bp.c(3) * i2doc);
-        
-                /* Try to snap to this node of the path */
-                NR::Coord const dist = NR::L2(n - p);
-                if (dist < getDistance() && dist < s.getDistance()) {
-                    s = SnappedPoint(n, dist);
-                }
-
+                points_to_snap_to.push_back(desktop->doc2dt(bp.c(3) * i2doc));
                 j++;
             }
         }
+        
+        //Collect the bounding box's corners so we can snap to them
+        NR::Maybe<NR::Rect> b = sp_item_bbox_desktop(root_item, bbox_type);
+        if (b) {
+               for ( unsigned k = 0 ; k < 4 ; k++ ) {
+                   points_to_snap_to.push_back(b->corner(k));
+               }
+        }        
+        
+        //Do the snapping, using all the nodes and corners collected above
+        for (std::list<NR::Point>::const_iterator k = points_to_snap_to.begin(); k != points_to_snap_to.end(); k++) {
+           /* Try to snap to this node of the path */
+            NR::Coord const dist = NR::L2(*k - p);
+            if (dist < getDistance() && dist < s.getDistance()) {
+                s = SnappedPoint(*k, dist);
+            }       
+        }
     }
 }
 
@@ -135,6 +151,11 @@ void Inkscape::ObjectSnapper::_snapPaths(Inkscape::SnappedPoint &s,
 
     NR::Point const p_doc = desktop->dt2doc(p);
     
+    // Determine the type of bounding box we should snap to
+    //TODO if (_snap_to_bbox) ???? -> will save some cpu time 
+       gchar const *prefs_bbox = prefs_get_string_attribute("tools.select", "bounding_box");
+       SPItem::BBoxType bbox_type = (prefs_bbox != NULL && strcmp(prefs_bbox, "geometric")==0)? SPItem::GEOMETRIC_BBOX : SPItem::APPROXIMATE_BBOX;        
+    
     for (std::list<SPItem*>::const_iterator i = cand.begin(); i != cand.end(); i++) {
 
         /* Transform the requested snap point to this item's coordinates */
@@ -149,29 +170,46 @@ void Inkscape::ObjectSnapper::_snapPaths(Inkscape::SnappedPoint &s,
             root_item = *i;
         }
         
-        NR::Point const p_it = p_doc * i2doc.inverse();
-
-        Path *livarot_path = Path_for_item(root_item, false, false);
-        if (!livarot_path)
-            continue;
-
-        livarot_path->ConvertWithBackData(0.01);
-
-        /* Look for the nearest position on this SPItem to our snap point */
-        NR::Maybe<Path::cut_position> const o = get_nearest_position_on_Path(livarot_path, p_it);
-        if (o && o->t >= 0 && o->t <= 1) {
-
-            /* Convert the nearest point back to desktop coordinates */
-            NR::Point const o_it = get_point_on_Path(livarot_path, o->piece, o->t);
-            NR::Point const o_dt = desktop->doc2dt(o_it * i2doc);
-
-            NR::Coord const dist = NR::L2(o_dt - p);
-            if (dist < getDistance() && dist < s.getDistance()) {
-                s = SnappedPoint(o_dt, dist);
-            }
-        }
-
-        delete livarot_path;
+        //Build a list of all paths considered for snapping to
+        std::list<Path*> paths_to_snap_to;
+        
+        //Add the item's path to snap to
+        paths_to_snap_to.push_back(Path_for_item(root_item, true, true));
+                
+        //Add the item's bounding box to snap to
+        //This will get ugly... rect -> curve -> bpath
+        NRRect rect;
+        sp_item_invoke_bbox(root_item, &rect, i2doc, TRUE, bbox_type);
+        NR::Maybe<NR::Rect> bbox = rect.upgrade();
+        SPCurve *curve = sp_curve_new_from_rect(bbox);
+        NArtBpath *bpath = SP_CURVE_BPATH(curve);
+        Path *path = bpath_to_Path(bpath);  
+        paths_to_snap_to.push_back(path);
+        delete curve;
+        delete bpath;
+        
+        //Now we can finally do the real snapping, using the paths collected above        
+        for (std::list<Path*>::const_iterator k = paths_to_snap_to.begin(); k != paths_to_snap_to.end(); k++) {
+               if (*k) {
+                   (*k)->ConvertWithBackData(0.01);
+               
+                       /* Look for the nearest position on this SPItem to our snap point */
+                       NR::Maybe<Path::cut_position> const o = get_nearest_position_on_Path(*k, p_doc);
+                       if (o && o->t >= 0 && o->t <= 1) {
+               
+                           /* Convert the nearest point back to desktop coordinates */
+                           NR::Point const o_it = get_point_on_Path(*k, o->piece, o->t);                           
+                           NR::Point const o_dt = desktop->doc2dt(o_it);
+                                       
+                           NR::Coord const dist = NR::L2(o_dt - p);
+                           if (dist < getDistance() && dist < s.getDistance()) {
+                               s = SnappedPoint(o_dt, dist);
+                           }
+                       }
+               
+                       delete *k;
+               }
+           }
     }
 }