Code

1) snap midpoints of line segments (both as source and as target)
authordvlierop2 <dvlierop2@users.sourceforge.net>
Sun, 14 Dec 2008 20:49:00 +0000 (20:49 +0000)
committerdvlierop2 <dvlierop2@users.sourceforge.net>
Sun, 14 Dec 2008 20:49:00 +0000 (20:49 +0000)
2) snap intersections within a single shape (as source; as target was already implemented)

22 files changed:
src/attributes-test.h
src/attributes.cpp
src/attributes.h
src/display/canvas-axonomgrid.cpp
src/display/canvas-axonomgrid.h
src/display/canvas-grid.cpp
src/display/canvas-grid.h
src/guide-snapper.cpp
src/guide-snapper.h
src/line-snapper.cpp
src/line-snapper.h
src/object-snapper.cpp
src/object-snapper.h
src/snap-preferences.h
src/snap.h
src/snapped-curve.cpp
src/snapper.cpp
src/snapper.h
src/sp-namedview.cpp
src/sp-shape.cpp
src/ui/dialog/document-properties.cpp
src/ui/dialog/document-properties.h

index bffc2779802334d2c825523dc6780693c6947f08..af1ed8a11dc41ba4f9ebbb0e8bda65942b18841b 100644 (file)
@@ -352,6 +352,7 @@ struct {char const *attr; bool supported;} const all_attrs[] = {
     {"inkscape:snap-guide", true},
     {"inkscape:snap-center", true},
     {"inkscape:snap-smooth-nodes", true},
+    {"inkscape:snap-midpoints", true},
     {"inkscape:snap-intersection-grid-guide", true},
     {"inkscape:snap-intersection-paths", true},
     {"inkscape:pageopacity", true},
index 149d177f5e2b1db1fb3df273b7a942132a8539c1..1ee33ef832468e8680eb06adb4c988a4c8fcf8c5 100644 (file)
@@ -92,6 +92,7 @@ static SPStyleProp const props[] = {
     {SP_ATTR_INKSCAPE_SNAP_GUIDE, "inkscape:snap-guide"},
     {SP_ATTR_INKSCAPE_SNAP_CENTER, "inkscape:snap-center"},
     {SP_ATTR_INKSCAPE_SNAP_SMOOTH_NODES, "inkscape:snap-smooth-nodes"},
+    {SP_ATTR_INKSCAPE_SNAP_MIDPOINTS, "inkscape:snap-midpoints"},
     {SP_ATTR_INKSCAPE_SNAP_INTERS_GRIDGUIDE, "inkscape:snap-intersection-grid-guide"},
     {SP_ATTR_INKSCAPE_SNAP_INTERS_PATHS, "inkscape:snap-intersection-paths"},
     {SP_ATTR_INKSCAPE_OBJECT_PATHS, "inkscape:object-paths"},
index f8925f47ccca86ced39dcd6b79be90e68d51a53e..68e6135dbd2084aae24b71fb56f1babed465fca3 100644 (file)
@@ -92,6 +92,7 @@ enum SPAttributeEnum {
     SP_ATTR_INKSCAPE_SNAP_GUIDE,
     SP_ATTR_INKSCAPE_SNAP_CENTER,
     SP_ATTR_INKSCAPE_SNAP_SMOOTH_NODES,
+    SP_ATTR_INKSCAPE_SNAP_MIDPOINTS,
     SP_ATTR_INKSCAPE_SNAP_INTERS_GRIDGUIDE,
     SP_ATTR_INKSCAPE_SNAP_INTERS_PATHS,
     SP_ATTR_INKSCAPE_OBJECT_PATHS,
index a636d8268eed30ddecea77c336e39abd818ba499..4b45eae339680baf17fd9c0ed72d872ca0971313 100644 (file)
@@ -19,7 +19,7 @@
 
 #include "sp-canvas-util.h"
 #include "canvas-axonomgrid.h"
-#include "util/mathfns.h" 
+#include "util/mathfns.h"
 #include "2geom/geom.h"
 #include "display-forward.h"
 #include <libnr/nr-pixops.h>
@@ -402,12 +402,12 @@ _wr.setUpdating (true);
 
     Inkscape::UI::Widget::RegisteredColorPicker *_rcp_gcol = Gtk::manage(
         new Inkscape::UI::Widget::RegisteredColorPicker(
-            _("Grid line _color:"), _("Grid line color"), _("Color of grid lines"), 
+            _("Grid line _color:"), _("Grid line color"), _("Color of grid lines"),
             "color", "opacity", _wr, repr, doc));
 
     Inkscape::UI::Widget::RegisteredColorPicker *_rcp_gmcol = Gtk::manage(
         new Inkscape::UI::Widget::RegisteredColorPicker(
-            _("Ma_jor grid line color:"), _("Major grid line color"), 
+            _("Ma_jor grid line color:"), _("Major grid line color"),
             _("Color of the major (highlighted) grid lines"),
             "empcolor", "empopacity", _wr, repr, doc));
 
@@ -656,7 +656,7 @@ CanvasAxonomGrid::Render (SPCanvasBuf *buf)
     }
 }
 
-CanvasAxonomGridSnapper::CanvasAxonomGridSnapper(CanvasAxonomGrid *grid, SnapManager const *sm, Geom::Coord const d) : LineSnapper(sm, d)
+CanvasAxonomGridSnapper::CanvasAxonomGridSnapper(CanvasAxonomGrid *grid, SnapManager *sm, Geom::Coord const d) : LineSnapper(sm, d)
 {
     this->grid = grid;
 }
@@ -685,64 +685,64 @@ CanvasAxonomGridSnapper::_getSnapLines(Geom::Point const &p) const
     // - 2 vertical grid lines, one left and one right from the point
     // - 2 angled z grid lines, one above and one below the point
     // - 2 angled x grid lines, one above and one below the point
-    
+
     // Calculate the x coordinate of the vertical grid lines
     Geom::Coord x_max = Inkscape::Util::round_to_upper_multiple_plus(p[Geom::X], scaled_spacing_h, grid->origin[Geom::X]);
     Geom::Coord x_min = Inkscape::Util::round_to_lower_multiple_plus(p[Geom::X], scaled_spacing_h, grid->origin[Geom::X]);
-    
+
     // Calculate the y coordinate of the intersection of the angled grid lines with the y-axis
-    double y_proj_along_z = p[Geom::Y] - grid->tan_angle[Z]*(p[Geom::X] - grid->origin[Geom::X]);  
-    double y_proj_along_x = p[Geom::Y] + grid->tan_angle[X]*(p[Geom::X] - grid->origin[Geom::X]);    
+    double y_proj_along_z = p[Geom::Y] - grid->tan_angle[Z]*(p[Geom::X] - grid->origin[Geom::X]);
+    double y_proj_along_x = p[Geom::Y] + grid->tan_angle[X]*(p[Geom::X] - grid->origin[Geom::X]);
     double y_proj_along_z_max = Inkscape::Util::round_to_upper_multiple_plus(y_proj_along_z, scaled_spacing_v, grid->origin[Geom::Y]);
-    double y_proj_along_z_min = Inkscape::Util::round_to_lower_multiple_plus(y_proj_along_z, scaled_spacing_v, grid->origin[Geom::Y]);    
+    double y_proj_along_z_min = Inkscape::Util::round_to_lower_multiple_plus(y_proj_along_z, scaled_spacing_v, grid->origin[Geom::Y]);
     double y_proj_along_x_max = Inkscape::Util::round_to_upper_multiple_plus(y_proj_along_x, scaled_spacing_v, grid->origin[Geom::Y]);
     double y_proj_along_x_min = Inkscape::Util::round_to_lower_multiple_plus(y_proj_along_x, scaled_spacing_v, grid->origin[Geom::Y]);
-    
+
     // Calculate the normal for the angled grid lines
     Geom::Point norm_x = Geom::rot90(Geom::Point(1, -grid->tan_angle[X]));
     Geom::Point norm_z = Geom::rot90(Geom::Point(1, grid->tan_angle[Z]));
-    
+
     // The four angled grid lines form a parallellogram, enclosing the point
     // One of the two vertical grid lines divides this parallellogram in two triangles
-    // We will now try to find out in which half (i.e. triangle) our point is, and return 
-    // only the three grid lines defining that triangle 
-    
-    // The vertical grid line is at the intersection of two angled grid lines. 
+    // We will now try to find out in which half (i.e. triangle) our point is, and return
+    // only the three grid lines defining that triangle
+
+    // The vertical grid line is at the intersection of two angled grid lines.
     // Now go find that intersection!
     Geom::Point result;
     Geom::IntersectorKind is = Geom::line_intersection(norm_x, norm_x[Geom::Y]*y_proj_along_x_max,
                                            norm_z, norm_z[Geom::Y]*y_proj_along_z_max,
                                            result);
-                         
-    // Determine which half of the parallellogram to use 
+
+    // Determine which half of the parallellogram to use
     bool use_left_half = true;
     bool use_right_half = true;
-    
+
     if (is == Geom::intersects) {
         use_left_half = (p[Geom::X] - grid->origin[Geom::X]) < result[Geom::X];
-        use_right_half = !use_left_half; 
+        use_right_half = !use_left_half;
     }
-    
+
     //std::cout << "intersection at " << result << " leads to use_left_half = " << use_left_half << " and use_right_half = " << use_right_half << std::endl;
-       
+
     // Return the three grid lines which define the triangle that encloses our point
     // If we didn't find an intersection above, all 6 grid lines will be returned
     if (use_left_half) {
         s.push_back(std::make_pair(norm_z, Geom::Point(grid->origin[Geom::X], y_proj_along_z_max)));
         s.push_back(std::make_pair(norm_x, Geom::Point(grid->origin[Geom::X], y_proj_along_x_min)));
-        s.push_back(std::make_pair(component_vectors[Geom::X], Geom::Point(x_max, 0)));            
+        s.push_back(std::make_pair(component_vectors[Geom::X], Geom::Point(x_max, 0)));
     }
-    
+
     if (use_right_half) {
         s.push_back(std::make_pair(norm_z, Geom::Point(grid->origin[Geom::X], y_proj_along_z_min)));
         s.push_back(std::make_pair(norm_x, Geom::Point(grid->origin[Geom::X], y_proj_along_x_max)));
-        s.push_back(std::make_pair(component_vectors[Geom::X], Geom::Point(x_min, 0)));        
-    } 
-    
+        s.push_back(std::make_pair(component_vectors[Geom::X], Geom::Point(x_min, 0)));
+    }
+
     return s;
 }
 
-void CanvasAxonomGridSnapper::_addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, Geom::Point const normal_to_line, Geom::Point const point_on_line) const 
+void CanvasAxonomGridSnapper::_addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, Geom::Point const normal_to_line, Geom::Point const point_on_line) const
 {
     SnappedLine dummy = SnappedLine(snapped_point, snapped_distance, getSnapperTolerance(), getSnapperAlwaysSnap(), normal_to_line, point_on_line);
     sc.grid_lines.push_back(dummy);
index 1d255d798a49396c2a2d14838b69f1a9e796e53c..0654a942947ae9e22efde24028a4eb03fbd35d71 100644 (file)
@@ -36,7 +36,7 @@ public:
 
     void Update (Geom::Matrix const &affine, unsigned int flags);
     void Render (SPCanvasBuf *buf);
-    
+
     void readRepr();
     void onReprAttrChanged (Inkscape::XML::Node * repr, const gchar *key, const gchar *oldval, const gchar *newval, bool is_interactive);
 
@@ -44,15 +44,15 @@ public:
     double angle_deg[3];  /**< Angle of each axis (note that angle[2] == 0) */
     double angle_rad[3];  /**< Angle of each axis (note that angle[2] == 0) */
     double tan_angle[3];  /**< tan(angle[.]) */
-    
+
     bool scaled;          /**< Whether the grid is in scaled mode */
-    
+
     Geom::Point ow;         /**< Transformed origin by the affine for the zoom */
     double lyw;           /**< Transformed length y by the affine for the zoom */
     double lxw_x;
     double lxw_z;
     double spacing_ylines;
-                          
+
     Geom::Point sw;          /**< the scaling factors of the affine transform */
 
 protected:
@@ -61,7 +61,7 @@ protected:
 private:
     CanvasAxonomGrid(const CanvasAxonomGrid&);
     CanvasAxonomGrid& operator=(const CanvasAxonomGrid&);
-    
+
     void updateWidgets();
 };
 
@@ -70,20 +70,20 @@ private:
 class CanvasAxonomGridSnapper : public LineSnapper
 {
 public:
-    CanvasAxonomGridSnapper(CanvasAxonomGrid *grid, SnapManager const *sm, Geom::Coord const d);
+    CanvasAxonomGridSnapper(CanvasAxonomGrid *grid, SnapManager *sm, Geom::Coord const d);
 
-private:    
+private:
     LineList _getSnapLines(Geom::Point const &p) const;
     void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, Geom::Point const normal_to_line, const Geom::Point point_on_line) const;
 
     CanvasAxonomGrid *grid;
-}; 
+};
 
 
 }; //namespace Inkscape
 
 
 
-#endif    
+#endif
 
 
index 8505426d3cb7822fc68bf9fb1c27190de8c23436..b03bfca9e0e2385e3cbb694ca8b31744e23d1da0 100644 (file)
@@ -14,7 +14,7 @@
 #define INKSCAPE_CANVAS_GRID_C
 
 #include "sp-canvas-util.h"
-#include "util/mathfns.h" 
+#include "util/mathfns.h"
 #include "display-forward.h"
 #include <libnr/nr-pixops.h>
 #include "desktop-handles.h"
@@ -357,13 +357,13 @@ CanvasGrid::on_repr_attr_changed(Inkscape::XML::Node *repr, gchar const *key, gc
     ((CanvasGrid*) data)->onReprAttrChanged(repr, key, oldval, newval, is_interactive);
 }
 
-bool CanvasGrid::isEnabled() 
-{ 
+bool CanvasGrid::isEnabled()
+{
     if (snapper == NULL) {
        return false;
-    } 
-    
-    return snapper->getEnabled();    
+    }
+
+    return snapper->getEnabled();
 }
 
 // ##########################################################
@@ -619,7 +619,7 @@ CanvasXYGrid::readRepr()
     if ( (value = repr->attribute("visible")) ) {
         visible = (strcmp(value,"false") != 0 && strcmp(value, "0") != 0);
     }
-    
+
     if ( (value = repr->attribute("enabled")) ) {
         g_assert(snapper != NULL);
         snapper->setEnabled(strcmp(value,"false") != 0 && strcmp(value, "0") != 0);
@@ -665,15 +665,15 @@ CanvasXYGrid::newSpecificWidget()
 
     Inkscape::UI::Widget::RegisteredColorPicker *_rcp_gcol = Gtk::manage(
         new Inkscape::UI::Widget::RegisteredColorPicker(
-            _("Grid line _color:"), _("Grid line color"), _("Color of grid lines"), 
+            _("Grid line _color:"), _("Grid line color"), _("Color of grid lines"),
             "color", "opacity", _wr, repr, doc));
 
     Inkscape::UI::Widget::RegisteredColorPicker *_rcp_gmcol = Gtk::manage(
         new Inkscape::UI::Widget::RegisteredColorPicker(
-            _("Ma_jor grid line color:"), _("Major grid line color"), 
-            _("Color of the major (highlighted) grid lines"), "empcolor", "empopacity", 
+            _("Ma_jor grid line color:"), _("Major grid line color"),
+            _("Color of the major (highlighted) grid lines"), "empcolor", "empopacity",
             _wr, repr, doc));
-    
+
     Inkscape::UI::Widget::RegisteredSuffixedInteger *_rsi = Gtk::manage( new Inkscape::UI::Widget::RegisteredSuffixedInteger(
             _("_Major grid line every:"), "", _("lines"), "empspacing", _wr, repr, doc) );
 
@@ -948,7 +948,7 @@ CanvasXYGrid::Render (SPCanvasBuf *buf)
     }
 }
 
-CanvasXYGridSnapper::CanvasXYGridSnapper(CanvasXYGrid *grid, SnapManager const *sm, Geom::Coord const d) : LineSnapper(sm, d)
+CanvasXYGridSnapper::CanvasXYGridSnapper(CanvasXYGrid *grid, SnapManager *sm, Geom::Coord const d) : LineSnapper(sm, d)
 {
     this->grid = grid;
 }
@@ -973,13 +973,13 @@ CanvasXYGridSnapper::_getSnapLines(Geom::Point const &p) const
             scaled_spacing /= SP_ACTIVE_DESKTOP->current_zoom();
         }
 
-        Geom::Coord rounded;        
+        Geom::Coord rounded;
         Geom::Point point_on_line;
-        
+
         rounded = Inkscape::Util::round_to_upper_multiple_plus(p[i], scaled_spacing, grid->origin[i]);
         point_on_line = i ? Geom::Point(0, rounded) : Geom::Point(rounded, 0);
         s.push_back(std::make_pair(component_vectors[i], point_on_line));
-        
+
         rounded = Inkscape::Util::round_to_lower_multiple_plus(p[i], scaled_spacing, grid->origin[i]);
         point_on_line = i ? Geom::Point(0, rounded) : Geom::Point(rounded, 0);
         s.push_back(std::make_pair(component_vectors[i], point_on_line));
@@ -988,7 +988,7 @@ CanvasXYGridSnapper::_getSnapLines(Geom::Point const &p) const
     return s;
 }
 
-void CanvasXYGridSnapper::_addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, Geom::Point const normal_to_line, Geom::Point const point_on_line) const 
+void CanvasXYGridSnapper::_addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, Geom::Point const normal_to_line, Geom::Point const point_on_line) const
 {
     SnappedLine dummy = SnappedLine(snapped_point, snapped_distance, getSnapperTolerance(), getSnapperAlwaysSnap(), normal_to_line, point_on_line);
     sc.grid_lines.push_back(dummy);
index f50537065be93802d641cd39b1c12763fbcafae0..e4bd0141461cf6e4158d89e405c50f35a5631beb 100644 (file)
@@ -90,9 +90,9 @@ public:
     guint32 color;        /**< Color for normal lines */
     guint32 empcolor;     /**< Color for emphasis lines */
     gint empspacing;      /**< Spacing between emphasis lines */
-    
+
     SPUnit const* gridunit;
-    
+
     Inkscape::XML::Node * repr;
     SPDocument *doc;
 
@@ -158,7 +158,7 @@ private:
 class CanvasXYGridSnapper : public LineSnapper
 {
 public:
-    CanvasXYGridSnapper(CanvasXYGrid *grid, SnapManager const *sm, Geom::Coord const d);
+    CanvasXYGridSnapper(CanvasXYGrid *grid, SnapManager *sm, Geom::Coord const d);
     bool ThisSnapperMightSnap() const;
 
 private:
index d9c57f8293914e53e0b0cb7ec818216b0b954568..be2e84170aff18ce4fbc4241f760c4bd6979d575 100644 (file)
@@ -17,7 +17,7 @@
 #include "sp-namedview.h"
 #include "sp-guide.h"
 
-Inkscape::GuideSnapper::GuideSnapper(SnapManager const *sm, Geom::Coord const d) : LineSnapper(sm, d)
+Inkscape::GuideSnapper::GuideSnapper(SnapManager *sm, Geom::Coord const d) : LineSnapper(sm, d)
 {
 
 }
@@ -32,7 +32,7 @@ Inkscape::GuideSnapper::LineList Inkscape::GuideSnapper::_getSnapLines(Geom::Poi
 
     for (GSList const *l = _snapmanager->getNamedView()->guides; l != NULL; l = l->next) {
         SPGuide const *g = SP_GUIDE(l->data);
-        s.push_back(std::make_pair(g->normal_to_line, g->point_on_line)); 
+        s.push_back(std::make_pair(g->normal_to_line, g->point_on_line));
     }
 
     return s;
index a7798c72ff3877c143c1406e47af93a6032adec5..f36d03499605ed7b0c3ce75ca2e3e085dd3e9a3b 100644 (file)
@@ -10,7 +10,7 @@
  *   Frank Felfe <innerspace@iname.com>
  *   Carl Hetherington <inkscape@carlh.net>
  *
- * Copyright (C) 1999-2002 Authors 
+ * Copyright (C) 1999-2002 Authors
  *
  * Released under GNU GPL, read the file 'COPYING' for more information
  */
@@ -28,11 +28,11 @@ namespace Inkscape
 class GuideSnapper : public LineSnapper
 {
 public:
-    GuideSnapper(SnapManager const *sm, Geom::Coord const d);    
+    GuideSnapper(SnapManager *sm, Geom::Coord const d);
     bool ThisSnapperMightSnap() const;
 
 private:
-    LineList _getSnapLines(Geom::Point const &p) const;    
+    LineList _getSnapLines(Geom::Point const &p) const;
     void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, Geom::Point const normal_to_line, Geom::Point const point_on_line) const;
 };
 
index f2d2f2ff624b0b46099fd802e324cf5cdd579a91..bfcda3f79dfba34402853eccf5afeed1e580fd10 100644 (file)
@@ -5,7 +5,7 @@
  * Authors:
  *   Diederik van Lierop <mail@diedenrezi.nl>
  *   And others...
- * 
+ *
  * Copyright (C) 1999-2008 Authors
  *
  * Released under GNU GPL, read the file 'COPYING' for more information
@@ -19,7 +19,7 @@
 #include <gtk/gtk.h>
 #include "snap.h"
 
-Inkscape::LineSnapper::LineSnapper(SnapManager const *sm, Geom::Coord const d) : Snapper(sm, d)
+Inkscape::LineSnapper::LineSnapper(SnapManager *sm, Geom::Coord const d) : Snapper(sm, d)
 {
 }
 
@@ -33,8 +33,8 @@ void Inkscape::LineSnapper::freeSnap(SnappedConstraints &sc,
 {
        if (_snap_enabled == false || _snapmanager->snapprefs.getSnapFrom(t) == false) {
         return;
-    }   
-    
+    }
+
     /* Get the lines that we will try to snap to */
     const LineList lines = _getSnapLines(p);
 
@@ -45,16 +45,16 @@ void Inkscape::LineSnapper::freeSnap(SnappedConstraints &sc,
         Geom::Point const p2 = p1 + Geom::rot90(i->first); // 2nd point at guide/grid line
         // std::cout << "  line through " << i->second << " with normal " << i->first;
         g_assert(i->first != Geom::Point(0,0)); // we cannot project on an linesegment of zero length
-        
+
         Geom::Point const p_proj = project_on_linesegment(p, p1, p2);
         Geom::Coord const dist = Geom::L2(p_proj - p);
         //Store any line that's within snapping range
         if (dist < getSnapperTolerance()) {
             _addSnappedLine(sc, p_proj, dist, i->first, i->second);
-            // std::cout << " -> distance = " << dist; 
-        }     
+            // std::cout << " -> distance = " << dist;
+        }
         // std::cout << std::endl;
-    }    
+    }
 }
 
 void Inkscape::LineSnapper::constrainedSnap(SnappedConstraints &sc,
@@ -69,7 +69,7 @@ void Inkscape::LineSnapper::constrainedSnap(SnappedConstraints &sc,
     if (_snap_enabled == false || _snapmanager->snapprefs.getSnapFrom(t) == false) {
         return;
     }
-    
+
     /* Get the lines that we will try to snap to */
     const LineList lines = _getSnapLines(p);
 
@@ -77,19 +77,19 @@ void Inkscape::LineSnapper::constrainedSnap(SnappedConstraints &sc,
         if (Geom::L2(c.getDirection()) > 0) { // Can't do a constrained snap without a constraint
             /* Normal to the line we're trying to snap along */
             Geom::Point const n(Geom::rot90(Geom::unit_vector(c.getDirection())));
-    
+
             Geom::Point const point_on_line = c.hasPoint() ? c.getPoint() : p;
-    
+
             /* Constant term of the line we're trying to snap along */
             Geom::Coord const q0 = dot(n, point_on_line);
             /* Constant term of the grid or guide line */
-            Geom::Coord const q1 = dot(i->first, i->second);        
-    
+            Geom::Coord const q1 = dot(i->first, i->second);
+
             /* Try to intersect this line with the target line */
             Geom::Point t_2geom(NR_HUGE, NR_HUGE);
             Geom::IntersectorKind const k = Geom::line_intersection(n, q0, i->first, q1, t_2geom);
             Geom::Point t(t_2geom);
-    
+
             if (k == Geom::intersects) {
                 const Geom::Coord dist = L2(t - p);
                 if (dist < getSnapperTolerance()) {
@@ -98,8 +98,8 @@ void Inkscape::LineSnapper::constrainedSnap(SnappedConstraints &sc,
                     // to look for additional intersections; just return the snapped point
                     // and forget about the line
                     sc.points.push_back(SnappedPoint(t, Inkscape::SNAPTARGET_UNDEFINED, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true));
-                    // The type of the snap target is yet undefined, as we cannot tell whether 
-                    // we're snapping to grid or the guide lines; must be set by on a higher level   
+                    // The type of the snap target is yet undefined, as we cannot tell whether
+                    // we're snapping to grid or the guide lines; must be set by on a higher level
                 }
             }
         }
index 529db1caaeb833700e6b0cb8da7ac2c916794753..91e8ca596d8e2d2188d0b36c795c603eb19fad0b 100644 (file)
@@ -8,7 +8,7 @@
  *    Authors:
  *      Carl Hetherington <inkscape@carlh.net>
  *             Diederik van Lierop <mail@diedenrezi.nl>
- * 
+ *
  *       Copyright (C) 1999-2008 Authors
  *
  *    Released under GNU GPL, read the file 'COPYING' for more information.
@@ -22,7 +22,7 @@ namespace Inkscape
 class LineSnapper : public Snapper
 {
 public:
-  LineSnapper(SnapManager const *sm, Geom::Coord const d);
+  LineSnapper(SnapManager *sm, Geom::Coord const d);
 
   void freeSnap(SnappedConstraints &sc,
                    Inkscape::SnapPreferences::PointType const &t,
@@ -31,7 +31,7 @@ public:
                    Geom::OptRect const &bbox_to_snap,
                    std::vector<SPItem const *> const *it,
                    std::vector<Geom::Point> *unselected_nodes) const;
-  
+
   void constrainedSnap(SnappedConstraints &sc,
                           Inkscape::SnapPreferences::PointType const &t,
                           Geom::Point const &p,
@@ -41,7 +41,7 @@ public:
                           std::vector<SPItem const *> const *it) const;
 
 protected:
-  typedef std::list<std::pair<Geom::Point, Geom::Point> > LineList; 
+  typedef std::list<std::pair<Geom::Point, Geom::Point> > LineList;
   //first point is a vector normal to the line
   //second point is a point on the line
 
@@ -51,7 +51,7 @@ private:
    *  \return List of lines that we should try snapping to.
    */
   virtual LineList _getSnapLines(Geom::Point const &p) const = 0;
-  
+
   virtual void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, Geom::Point const normal_to_line, Geom::Point const point_on_line) const = 0;
 };
 
index 06f24c47fa1129d28623bfbedea13f6710a82116..922c35bcbe545689f53e1de49a075dd009ea797f 100644 (file)
 
 Inkscape::SnapCandidate::SnapCandidate(SPItem* item, bool clip_or_mask, Geom::Matrix additional_affine)
     : item(item), clip_or_mask(clip_or_mask), additional_affine(additional_affine)
-{    
+{
 }
 
 Inkscape::SnapCandidate::~SnapCandidate()
-{    
+{
 }
 
-Inkscape::ObjectSnapper::ObjectSnapper(SnapManager const *sm, Geom::Coord const d)
+Inkscape::ObjectSnapper::ObjectSnapper(SnapManager *sm, Geom::Coord const d)
     : Snapper(sm, d), _snap_to_itemnode(true), _snap_to_itempath(true),
       _snap_to_bboxnode(true), _snap_to_bboxpath(true), _snap_to_page_border(false),
       _strict_snapping(true)
@@ -84,18 +84,18 @@ void Inkscape::ObjectSnapper::_findCandidates(SPObject* parent,
 {
     bool const c1 = (snap_dim == TRANSL_SNAP_XY) && ThisSnapperMightSnap();
     bool const c2 = (snap_dim != TRANSL_SNAP_XY) && GuidesMightSnap();
-    
+
     if (!(c1 || c2)) {
-        return;        
+        return;
     }
-    
+
     if (first_point) {
         _candidates->clear();
     }
-    
+
     Geom::Rect bbox_to_snap_incl = bbox_to_snap; // _incl means: will include the snapper tolerance
     bbox_to_snap_incl.expandBy(getSnapperTolerance()); // see?
-    
+
     for (SPObject* o = sp_object_first_child(parent); o != NULL; o = SP_OBJECT_NEXT(o)) {
         g_assert(_snapmanager->getDesktop() != NULL);
         if (SP_IS_ITEM(o) && !SP_ITEM(o)->isLocked() && !(_snapmanager->getDesktop()->itemIsHidden(SP_ITEM(o)) && !clip_or_mask)) {
@@ -109,32 +109,32 @@ void Inkscape::ObjectSnapper::_findCandidates(SPObject* parent,
                     i++;
                 }
             }
-            
+
             if (it == NULL || i == it->end()) {
-                SPItem *item = SP_ITEM(o); 
+                SPItem *item = SP_ITEM(o);
                 Geom::Matrix transform = Geom::identity();
                 if (item) {
                     SPObject *obj = NULL;
                     if (clip_or_mask) { // If the current item is a clipping path or a mask
                         // then store the transformation of the clipped path or mask itself
-                        // but also take into account the additional affine of the object 
+                        // but also take into account the additional affine of the object
                         // being clipped / masked
                         transform = to_2geom(item->transform) * additional_affine;
-                    } else { // cannot clip or mask more than once                     
+                    } else { // cannot clip or mask more than once
                         // The current item is not a clipping path or a mask, but might
                         // still be the subject of clipping or masking itself ; if so, then
                         // we should also consider that path or mask for snapping to
                         obj = SP_OBJECT(item->clip_ref->getObject());
                         if (obj) {
                             _findCandidates(obj, it, false, bbox_to_snap, snap_dim, true, item->transform);
-                        } 
+                        }
                         obj = SP_OBJECT(item->mask_ref->getObject());
                         if (obj) {
                             _findCandidates(obj, it, false, bbox_to_snap, snap_dim, true, item->transform);
                         }
                     }
-                }            
-                
+                }
+
                 if (SP_IS_GROUP(o)) {
                     _findCandidates(o, it, false, bbox_to_snap, snap_dim, false, Geom::identity());
                 } else {
@@ -142,7 +142,7 @@ void Inkscape::ObjectSnapper::_findCandidates(SPObject* parent,
                     if (clip_or_mask) {
                         // Oh oh, this will get ugly. We cannot use sp_item_i2d_affine directly because we need to
                         // insert an additional transformation in document coordinates (code copied from sp_item_i2d_affine)
-                        sp_item_invoke_bbox(item, 
+                        sp_item_invoke_bbox(item,
                             bbox_of_item,
                             sp_item_i2doc_affine(item) * matrix_to_desktop(additional_affine, item),
                             true);
@@ -150,11 +150,11 @@ void Inkscape::ObjectSnapper::_findCandidates(SPObject* parent,
                         sp_item_invoke_bbox(item, bbox_of_item, sp_item_i2d_affine(item), true);
                     }
                     if (bbox_of_item) {
-                        // See if the item is within range                                    
+                        // See if the item is within range
                         if (bbox_to_snap_incl.intersects(*bbox_of_item)) {
                             // This item is within snapping range, so record it as a candidate
                             _candidates->push_back(SnapCandidate(item, clip_or_mask, additional_affine));
-                        }                        
+                        }
                     }
                 }
             }
@@ -171,27 +171,27 @@ void Inkscape::ObjectSnapper::_collectNodes(Inkscape::SnapPreferences::PointType
     // first point and store the collection for later use. This significantly improves the performance
     if (first_point) {
         _points_to_snap_to->clear();
-        
+
          // Determine the type of bounding box we should snap to
         SPItem::BBoxType bbox_type = SPItem::GEOMETRIC_BBOX;
-        
+
         bool p_is_a_node = t & Inkscape::SnapPreferences::SNAPPOINT_NODE;
         bool p_is_a_bbox = t & Inkscape::SnapPreferences::SNAPPOINT_BBOX;
         bool p_is_a_guide = t & Inkscape::SnapPreferences::SNAPPOINT_GUIDE;
-        
+
         // A point considered for snapping should be either a node, a bbox corner or a guide. Pick only ONE!
-        g_assert(!((p_is_a_node && p_is_a_bbox) || (p_is_a_bbox && p_is_a_guide) || (p_is_a_node && p_is_a_guide)));        
-        
+        g_assert(!((p_is_a_node && p_is_a_bbox) || (p_is_a_bbox && p_is_a_guide) || (p_is_a_node && p_is_a_guide)));
+
         if (_snap_to_bboxnode) {
             Inkscape::Preferences *prefs = Inkscape::Preferences::get();
             bool prefs_bbox = prefs->getBool("/tools/bounding_box");
-            bbox_type = !prefs_bbox ? 
+            bbox_type = !prefs_bbox ?
                 SPItem::APPROXIMATE_BBOX : SPItem::GEOMETRIC_BBOX;
         }
-        
+
         // Consider the page border for snapping
         if (_snap_to_page_border) {
-            _getBorderNodes(_points_to_snap_to);            
+            _getBorderNodes(_points_to_snap_to);
         }
 
         for (std::vector<SnapCandidate>::const_iterator i = _candidates->begin(); i != _candidates->end(); i++) {
@@ -205,7 +205,35 @@ void Inkscape::ObjectSnapper::_collectNodes(Inkscape::SnapPreferences::PointType
             //Collect all nodes so we can snap to them
             if (_snap_to_itemnode) {
                 if (!(_strict_snapping && !p_is_a_node) || p_is_a_guide) {
+                    // Note: there are two ways in which intersections are considered:
+                    // Method 1: Intersections are calculated for each shape individually, for both the
+                    //           snap source and snap target (see sp_shape_snappoints)
+                    // Method 2: Intersections are calculated for each curve or line that we've snapped to, i.e. only for
+                    //           the target (see the intersect() method in the SnappedCurve and SnappedLine classes)
+                    // Some differences:
+                    // - Method 1 doesn't find intersections within a set of multiple objects
+                    // - Method 2 only works for targets
+                    // When considering intersections as snap targets:
+                    // - Method 1 only works when snapping to nodes, whereas
+                    // - Method 2 only works when snapping to paths
+                    // - There will be performance differences too!
+                    // If both methods are being used simultaneously, then this might lead to duplicate targets!
+
+                    // Well, here we will be looking for snap TARGETS. Both methods can therefore be used.
+                    // When snapping to paths, we will get a collection of snapped lines and snapped curves. findBestSnap() will
+                    // go hunting for intersections (but only when asked to in the prefs of course). In that case we can just
+                    // temporarily block the intersections in sp_item_snappoints, we don't need duplicates. If we're not snapping to
+                    // paths though but only to item nodes then we should still look for the intersections in sp_item_snappoints()
+                    bool old_pref = _snapmanager->snapprefs.getSnapIntersectionCS();
+                    if (_snap_to_itempath) {
+                        _snapmanager->snapprefs.setSnapIntersectionCS(false);
+                    }
+
                     sp_item_snappoints(root_item, SnapPointsIter(*_points_to_snap_to), &_snapmanager->snapprefs);
+
+                    if (_snap_to_itempath) {
+                        _snapmanager->snapprefs.setSnapIntersectionCS(old_pref);
+                    }
                 }
             }
 
@@ -214,7 +242,7 @@ void Inkscape::ObjectSnapper::_collectNodes(Inkscape::SnapPreferences::PointType
                 if (!(_strict_snapping && !p_is_a_bbox) || p_is_a_guide) {
                     // Discard the bbox of a clipped path / mask, because we don't want to snap to both the bbox
                     // of the item AND the bbox of the clipping path at the same time
-                    if (!(*i).clip_or_mask) {  
+                    if (!(*i).clip_or_mask) {
                         Geom::OptRect b = sp_item_bbox_desktop(root_item, bbox_type);
                         if (b) {
                             for ( unsigned k = 0 ; k < 4 ; k++ ) {
@@ -235,18 +263,18 @@ void Inkscape::ObjectSnapper::_snapNodes(SnappedConstraints &sc,
                                          std::vector<Geom::Point> *unselected_nodes) const
 {
     // Iterate through all nodes, find out which one is the closest to p, and snap to it!
-    
+
     _collectNodes(t, first_point);
-    
+
     if (unselected_nodes != NULL) {
         _points_to_snap_to->insert(_points_to_snap_to->end(), unselected_nodes->begin(), unselected_nodes->end());
-    }   
-    
+    }
+
     SnappedPoint s;
     bool success = false;
-    
+
     for (std::vector<Geom::Point>::const_iterator k = _points_to_snap_to->begin(); k != _points_to_snap_to->end(); k++) {
-        Geom::Coord dist = Geom::L2(*k - p);        
+        Geom::Coord dist = Geom::L2(*k - p);
         if (dist < getSnapperTolerance() && dist < s.getSnapDistance()) {
             s = SnappedPoint(*k, SNAPTARGET_NODE, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
             success = true;
@@ -254,7 +282,7 @@ void Inkscape::ObjectSnapper::_snapNodes(SnappedConstraints &sc,
     }
 
     if (success) {
-        sc.points.push_back(s);    
+        sc.points.push_back(s);
     }
 }
 
@@ -265,16 +293,16 @@ void Inkscape::ObjectSnapper::_snapTranslatingGuideToNodes(SnappedConstraints &s
 {
     // Iterate through all nodes, find out which one is the closest to this guide, and snap to it!
     _collectNodes(t, true);
-    
+
     SnappedPoint s;
     bool success = false;
-    
+
     Geom::Coord tol = getSnapperTolerance();
-    
+
     for (std::vector<Geom::Point>::const_iterator k = _points_to_snap_to->begin(); k != _points_to_snap_to->end(); k++) {
         // Project each node (*k) on the guide line (running through point p)
         Geom::Point p_proj = project_on_linesegment(*k, p, p + Geom::rot90(guide_normal));
-        Geom::Coord dist = Geom::L2(*k - p_proj); // distance from node to the guide         
+        Geom::Coord dist = Geom::L2(*k - p_proj); // distance from node to the guide
         Geom::Coord dist2 = Geom::L2(p - p_proj); // distance from projection of node on the guide, to the mouse location
         if ((dist < tol && dist2 < tol) || (getSnapperAlwaysSnap() && dist < s.getSnapDistance())) {
             s = SnappedPoint(*k, SNAPTARGET_NODE, dist, tol, getSnapperAlwaysSnap(), true);
@@ -283,7 +311,7 @@ void Inkscape::ObjectSnapper::_snapTranslatingGuideToNodes(SnappedConstraints &s
     }
 
     if (success) {
-        sc.points.push_back(s); 
+        sc.points.push_back(s);
     }
 }
 
@@ -300,19 +328,19 @@ void Inkscape::ObjectSnapper::_collectPaths(Inkscape::SnapPreferences::PointType
     // first point and store the collection for later use. This significantly improves the performance
     if (first_point) {
         _clear_paths();
-        
+
         // Determine the type of bounding box we should snap to
         SPItem::BBoxType bbox_type = SPItem::GEOMETRIC_BBOX;
-        
+
         bool p_is_a_node = t & Inkscape::SnapPreferences::SNAPPOINT_NODE;
-        
+
         if (_snap_to_bboxpath) {
             Inkscape::Preferences *prefs = Inkscape::Preferences::get();
             int prefs_bbox = prefs->getBool("/tools/bounding_box", 0);
-            bbox_type = !prefs_bbox ? 
+            bbox_type = !prefs_bbox ?
                 SPItem::APPROXIMATE_BBOX : SPItem::GEOMETRIC_BBOX;
         }
-        
+
         // Consider the page border for snapping
         if (_snap_to_page_border) {
             Geom::PathVector *border_path = _getBorderPathv();
@@ -320,7 +348,7 @@ void Inkscape::ObjectSnapper::_collectPaths(Inkscape::SnapPreferences::PointType
                 _paths_to_snap_to->push_back(border_path);
             }
         }
-        
+
         for (std::vector<SnapCandidate>::const_iterator i = _candidates->begin(); i != _candidates->end(); i++) {
 
             /* Transform the requested snap point to this item's coordinates */
@@ -335,7 +363,7 @@ void Inkscape::ObjectSnapper::_collectPaths(Inkscape::SnapPreferences::PointType
                 i2doc = sp_item_i2doc_affine((*i).item);
                 root_item = (*i).item;
             }
-            
+
             //Build a list of all paths considered for snapping to
 
             //Add the item's path to snap to
@@ -361,10 +389,10 @@ void Inkscape::ObjectSnapper::_collectPaths(Inkscape::SnapPreferences::PointType
                     }
 
                     if (!very_lenghty_prose && !very_complex_path) {
-                        SPCurve *curve = curve_for_item(root_item); 
+                        SPCurve *curve = curve_for_item(root_item);
                         if (curve) {
                             // We will get our own copy of the path, which must be freed at some point
-                            Geom::PathVector *borderpathv = pathvector_for_curve(root_item, curve, true, true, Geom::identity(), (*i).additional_affine); 
+                            Geom::PathVector *borderpathv = pathvector_for_curve(root_item, curve, true, true, Geom::identity(), (*i).additional_affine);
                             _paths_to_snap_to->push_back(borderpathv); // Perhaps for speed, get a reference to the Geom::pathvector, and store the transformation besides it.
                             curve->unref();
                         }
@@ -377,12 +405,12 @@ void Inkscape::ObjectSnapper::_collectPaths(Inkscape::SnapPreferences::PointType
                 if (!(_strict_snapping && p_is_a_node)) {
                     // Discard the bbox of a clipped path / mask, because we don't want to snap to both the bbox
                     // of the item AND the bbox of the clipping path at the same time
-                    if (!(*i).clip_or_mask) { 
-                       Geom::OptRect rect;
-                       sp_item_invoke_bbox(root_item, rect, i2doc, TRUE, bbox_type);
+                    if (!(*i).clip_or_mask) {
+                        Geom::OptRect rect;
+                        sp_item_invoke_bbox(root_item, rect, i2doc, TRUE, bbox_type);
                         if (rect) {
-                               Geom::PathVector *path = _getPathvFromRect(*rect);
-                               _paths_to_snap_to->push_back(path);
+                            Geom::PathVector *path = _getPathvFromRect(*rect);
+                            _paths_to_snap_to->push_back(path);
                         }
                     }
                 }
@@ -390,7 +418,7 @@ void Inkscape::ObjectSnapper::_collectPaths(Inkscape::SnapPreferences::PointType
         }
     }
 }
-    
+
 void Inkscape::ObjectSnapper::_snapPaths(SnappedConstraints &sc,
                                      Inkscape::SnapPreferences::PointType const &t,
                                      Geom::Point const &p,
@@ -400,23 +428,23 @@ void Inkscape::ObjectSnapper::_snapPaths(SnappedConstraints &sc,
 {
     _collectPaths(t, first_point);
     // Now we can finally do the real snapping, using the paths collected above
-    
-    g_assert(_snapmanager->getDesktop() != NULL);    
+
+    g_assert(_snapmanager->getDesktop() != NULL);
     Geom::Point const p_doc = _snapmanager->getDesktop()->dt2doc(p);
-    
+
     bool const node_tool_active = _snap_to_itempath && selected_path != NULL;
-    
+
     if (first_point) {
         /* findCandidates() is used for snapping to both paths and nodes. It ignores the path that is
-         * currently being edited, because that path requires special care: when snapping to nodes 
+         * currently being edited, because that path requires special care: when snapping to nodes
          * only the unselected nodes of that path should be considered, and these will be passed on separately.
          * This path must not be ignored however when snapping to the paths, so we add it here
-         * manually when applicable. 
-         * 
+         * manually when applicable.
+         *
          * Note that this path must be the last in line!
-         * */        
-        if (node_tool_active) {        
-            SPCurve *curve = curve_for_item(SP_ITEM(selected_path)); 
+         * */
+        if (node_tool_active) {
+            SPCurve *curve = curve_for_item(SP_ITEM(selected_path));
             if (curve) {
                 Geom::PathVector *pathv = pathvector_for_curve(SP_ITEM(selected_path), curve, true, true, Geom::identity(), Geom::identity()); // We will get our own copy of the path, which must be freed at some point
                 _paths_to_snap_to->push_back(pathv);
@@ -424,77 +452,77 @@ void Inkscape::ObjectSnapper::_snapPaths(SnappedConstraints &sc,
             }
         }
     }
-    
+
     for (std::vector<Geom::PathVector*>::const_iterator it_p = _paths_to_snap_to->begin(); it_p != _paths_to_snap_to->end(); it_p++) {
-        bool const being_edited = (node_tool_active && (*it_p) == _paths_to_snap_to->back());            
+        bool const being_edited = (node_tool_active && (*it_p) == _paths_to_snap_to->back());
         //if true then this pathvector it_pv is currently being edited in the node tool
-        
+
         // char * svgd = sp_svg_write_path(**it_p);
-        // std::cout << "Dumping the pathvector: " << svgd << std::endl;        
-        
+        // std::cout << "Dumping the pathvector: " << svgd << std::endl;
+
         for(Geom::PathVector::iterator it_pv = (*it_p)->begin(); it_pv != (*it_p)->end(); ++it_pv) {
             // Find a nearest point for each curve within this path
             // n curves will return n time values with 0 <= t <= 1
             std::vector<double> anp = (*it_pv).nearestPointPerCurve(p_doc);
-            
+
             std::vector<double>::const_iterator np = anp.begin();
             unsigned int index = 0;
             for (; np != anp.end(); np++, index++) {
                 Geom::Curve const *curve = &((*it_pv).at_index(index));
                 Geom::Point const sp_doc = curve->pointAt(*np);
-               
+
                 bool c1 = true;
-                bool c2 = true;                                
+                bool c2 = true;
                 if (being_edited) {
                     /* If the path is being edited, then we should only snap though to stationary pieces of the path
-                     * and not to the pieces that are being dragged around. This way we avoid 
+                     * and not to the pieces that are being dragged around. This way we avoid
                      * self-snapping. For this we check whether the nodes at both ends of the current
-                     * piece are unselected; if they are then this piece must be stationary 
-                     */                    
+                     * piece are unselected; if they are then this piece must be stationary
+                     */
                     g_assert(unselected_nodes != NULL);
-                    Geom::Point start_pt = _snapmanager->getDesktop()->doc2dt(curve->pointAt(0)); 
-                    Geom::Point end_pt = _snapmanager->getDesktop()->doc2dt(curve->pointAt(1));                                    
-                    c1 = isUnselectedNode(start_pt, unselected_nodes); 
-                    c2 = isUnselectedNode(end_pt, unselected_nodes);  
+                    Geom::Point start_pt = _snapmanager->getDesktop()->doc2dt(curve->pointAt(0));
+                    Geom::Point end_pt = _snapmanager->getDesktop()->doc2dt(curve->pointAt(1));
+                    c1 = isUnselectedNode(start_pt, unselected_nodes);
+                    c2 = isUnselectedNode(end_pt, unselected_nodes);
                     /* Unfortunately, this might yield false positives for coincident nodes. Inkscape might therefore mistakenly
                      * snap to path segments that are not stationary. There are at least two possible ways to overcome this:
                      * - Linking the individual nodes of the SPPath we have here, to the nodes of the NodePath::SubPath class as being
                      *   used in sp_nodepath_selected_nodes_move. This class has a member variable called "selected". For this the nodes
                      *   should be in the exact same order for both classes, so we can index them
                      * - Replacing the SPPath being used here by the the NodePath::SubPath class; but how?
-                     */ 
+                     */
                 }
-                
-                Geom::Point const sp_dt = _snapmanager->getDesktop()->doc2dt(sp_doc);                
+
+                Geom::Point const sp_dt = _snapmanager->getDesktop()->doc2dt(sp_doc);
                 if (!being_edited || (c1 && c2)) {
                     Geom::Coord const dist = Geom::distance(sp_doc, p_doc);
                     if (dist < getSnapperTolerance()) {
-                        sc.curves.push_back(Inkscape::SnappedCurve(from_2geom(sp_dt), dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, curve));   
+                        sc.curves.push_back(Inkscape::SnappedCurve(from_2geom(sp_dt), dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, curve));
                     }
                 }
-            }        
-        } // End of: for (Geom::PathVector::iterator ....)        
-    }    
+            }
+        } // End of: for (Geom::PathVector::iterator ....)
+    }
 }
 
-/* Returns true if point is coincident with one of the unselected nodes */ 
+/* Returns true if point is coincident with one of the unselected nodes */
 bool Inkscape::ObjectSnapper::isUnselectedNode(Geom::Point const &point, std::vector<Geom::Point> const *unselected_nodes) const
 {
     if (unselected_nodes == NULL) {
         return false;
     }
-    
+
     if (unselected_nodes->size() == 0) {
         return false;
     }
-    
+
     for (std::vector<Geom::Point>::const_iterator i = unselected_nodes->begin(); i != unselected_nodes->end(); i++) {
         if (Geom::L2(point - *i) < 1e-4) {
             return true;
-        }   
-    }  
-    
-    return false;    
+        }
+    }
+
+    return false;
 }
 
 void Inkscape::ObjectSnapper::_snapPathsConstrained(SnappedConstraints &sc,
@@ -503,52 +531,52 @@ void Inkscape::ObjectSnapper::_snapPathsConstrained(SnappedConstraints &sc,
                                      bool const &first_point,
                                      ConstraintLine const &c) const
 {
-    
+
     _collectPaths(t, first_point);
-    
+
     // Now we can finally do the real snapping, using the paths collected above
-    
+
     g_assert(_snapmanager->getDesktop() != NULL);
-    Geom::Point const p_doc = _snapmanager->getDesktop()->dt2doc(p);    
-    
+    Geom::Point const p_doc = _snapmanager->getDesktop()->dt2doc(p);
+
     Geom::Point direction_vector = c.getDirection();
     if (!is_zero(direction_vector)) {
         direction_vector = Geom::unit_vector(direction_vector);
     }
-    
+
     Geom::Point const p1_on_cl = c.hasPoint() ? c.getPoint() : p;
     Geom::Point const p2_on_cl = p1_on_cl + direction_vector;
-    
-    // The intersection point of the constraint line with any path, 
+
+    // The intersection point of the constraint line with any path,
     // must lie within two points on the constraintline: p_min_on_cl and p_max_on_cl
     // The distance between those points is twice the snapping tolerance
     Geom::Point const p_proj_on_cl = project_on_linesegment(p, p1_on_cl, p2_on_cl);
-    Geom::Point const p_min_on_cl = _snapmanager->getDesktop()->dt2doc(p_proj_on_cl - getSnapperTolerance() * direction_vector);    
+    Geom::Point const p_min_on_cl = _snapmanager->getDesktop()->dt2doc(p_proj_on_cl - getSnapperTolerance() * direction_vector);
     Geom::Point const p_max_on_cl = _snapmanager->getDesktop()->dt2doc(p_proj_on_cl + getSnapperTolerance() * direction_vector);
-    
+
     Geom::Path cl;
-    std::vector<Geom::Path> clv;    
+    std::vector<Geom::Path> clv;
     cl.start(p_min_on_cl);
     cl.appendNew<Geom::LineSegment>(p_max_on_cl);
     clv.push_back(cl);
-    
+
     for (std::vector<Geom::PathVector*>::const_iterator k = _paths_to_snap_to->begin(); k != _paths_to_snap_to->end(); k++) {
-        if (*k) {                        
+        if (*k) {
             Geom::CrossingSet cs = Geom::crossings(clv, *(*k));
             if (cs.size() > 0) {
                 // We need only the first element of cs, because cl is only a single straight linesegment
                 // This first element contains a vector filled with crossings of cl with *k
-                for (std::vector<Geom::Crossing>::const_iterator m = cs[0].begin(); m != cs[0].end(); m++) {                    
+                for (std::vector<Geom::Crossing>::const_iterator m = cs[0].begin(); m != cs[0].end(); m++) {
                     if ((*m).ta >= 0 && (*m).ta <= 1 ) {
                         // Reconstruct the point of intersection
                         Geom::Point p_inters = p_min_on_cl + ((*m).ta) * (p_max_on_cl - p_min_on_cl);
                         // When it's within snapping range, then return it
-                        // (within snapping range == between p_min_on_cl and p_max_on_cl == 0 < ta < 1)                        
+                        // (within snapping range == between p_min_on_cl and p_max_on_cl == 0 < ta < 1)
                         Geom::Coord dist = Geom::L2(_snapmanager->getDesktop()->dt2doc(p_proj_on_cl) - p_inters);
                         SnappedPoint s(_snapmanager->getDesktop()->doc2dt(p_inters), SNAPTARGET_PATH, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
                         sc.points.push_back(s);
-                    }  
-                } 
+                    }
+                }
             }
         }
     }
@@ -563,7 +591,7 @@ void Inkscape::ObjectSnapper::freeSnap(SnappedConstraints &sc,
                                             std::vector<SPItem const *> const *it,
                                             std::vector<Geom::Point> *unselected_nodes) const
 {
-       if (_snap_enabled == false || _snapmanager->snapprefs.getSnapFrom(t) == false ) {
+    if (_snap_enabled == false || _snapmanager->snapprefs.getSnapFrom(t) == false ) {
         return;
     }
 
@@ -572,29 +600,29 @@ void Inkscape::ObjectSnapper::freeSnap(SnappedConstraints &sc,
         Geom::Rect const local_bbox_to_snap = bbox_to_snap ? *bbox_to_snap : Geom::Rect(p, p);
         _findCandidates(sp_document_root(_snapmanager->getDocument()), it, first_point, local_bbox_to_snap, TRANSL_SNAP_XY, false, Geom::identity());
     }
-    
+
     if (_snap_to_itemnode || _snap_to_bboxnode || _snap_to_page_border) {
         _snapNodes(sc, t, p, first_point, unselected_nodes);
     }
-    
+
     if (_snap_to_itempath || _snap_to_bboxpath || _snap_to_page_border) {
         unsigned n = (unselected_nodes == NULL) ? 0 : unselected_nodes->size();
         if (n > 0) {
-            /* While editing a path in the node tool, findCandidates must ignore that path because 
+            /* While editing a path in the node tool, findCandidates must ignore that path because
              * of the node snapping requirements (i.e. only unselected nodes must be snapable).
              * That path must not be ignored however when snapping to the paths, so we add it here
              * manually when applicable
-             */            
+             */
             SPPath *path = NULL;
             if (it != NULL) {
                 g_assert(SP_IS_PATH(*it->begin()));
                 g_assert(it->size() == 1);
                 path = SP_PATH(*it->begin());
             }
-            _snapPaths(sc, t, p, first_point, unselected_nodes, path);                
+            _snapPaths(sc, t, p, first_point, unselected_nodes, path);
         } else {
-            _snapPaths(sc, t, p, first_point, NULL, NULL);   
-        }        
+            _snapPaths(sc, t, p, first_point, NULL, NULL);
+        }
     }
 }
 
@@ -615,15 +643,15 @@ void Inkscape::ObjectSnapper::constrainedSnap( SnappedConstraints &sc,
         Geom::Rect const local_bbox_to_snap = bbox_to_snap ? *bbox_to_snap : Geom::Rect(p, p);
         _findCandidates(sp_document_root(_snapmanager->getDocument()), it, first_point, local_bbox_to_snap, TRANSL_SNAP_XY, false, Geom::identity());
     }
-    
+
     // A constrained snap, is a snap in only one degree of freedom (specified by the constraint line).
     // This is usefull for example when scaling an object while maintaining a fixed aspect ratio. It's
     // nodes are only allowed to move in one direction (i.e. in one degree of freedom).
-    
+
     // When snapping to objects, we either snap to their nodes or their paths. It is however very
     // unlikely that any node will be exactly at the constrained line, so for a constrained snap
     // to objects we will only consider the object's paths. Beside, the nodes will be at these paths,
-    // so we will more or less snap to them anyhow.   
+    // so we will more or less snap to them anyhow.
 
     if (_snap_to_itempath || _snap_to_bboxpath || _snap_to_page_border) {
         _snapPathsConstrained(sc, t, p, first_point, c);
@@ -639,7 +667,7 @@ void Inkscape::ObjectSnapper::guideSnap(SnappedConstraints &sc,
     /* Get a list of all the SPItems that we will try to snap to */
     std::vector<SPItem*> cand;
     std::vector<SPItem const *> const it; //just an empty list
-    
+
     DimensionToSnap snap_dim;
     if (guide_normal == to_2geom(component_vectors[Geom::Y])) {
         snap_dim = GUIDE_TRANSL_SNAP_Y;
@@ -648,20 +676,20 @@ void Inkscape::ObjectSnapper::guideSnap(SnappedConstraints &sc,
     } else {
         snap_dim = ANGLED_GUIDE_TRANSL_SNAP;
     }
-    
-    // We don't support ANGLED_GUIDE_ROT_SNAP yet. 
-    
+
+    // We don't support ANGLED_GUIDE_ROT_SNAP yet.
+
     // It would be cool to allow the user to rotate a guide by dragging it, instead of
-    // only translating it. (For example when CTRL is pressed). We will need an UI part 
-    // for that first; and some important usability choices need to be made: 
+    // only translating it. (For example when CTRL is pressed). We will need an UI part
+    // for that first; and some important usability choices need to be made:
     // E.g. which point should be used for pivoting? A previously snapped point,
     // or a transformation center (which can be moved after clicking for the
     // second time on an object; but should this point then be constrained to the
     // line, or can it be located anywhere?)
-    
+
     _findCandidates(sp_document_root(_snapmanager->getDocument()), &it, true, Geom::Rect(p, p), snap_dim, false, Geom::identity());
     _snapTranslatingGuideToNodes(sc, Inkscape::SnapPreferences::SNAPPOINT_GUIDE, p, guide_normal);
-    // _snapRotatingGuideToNodes has not been implemented yet. 
+    // _snapRotatingGuideToNodes has not been implemented yet.
 }
 
 /**
@@ -679,7 +707,7 @@ bool Inkscape::ObjectSnapper::GuidesMightSnap() const
     return (_snap_enabled && _snapmanager->snapprefs.getSnapModeGuide() && snap_to_something);
 }
 
-void Inkscape::ObjectSnapper::_clear_paths() const 
+void Inkscape::ObjectSnapper::_clear_paths() const
 {
     for (std::vector<Geom::PathVector*>::const_iterator k = _paths_to_snap_to->begin(); k != _paths_to_snap_to->end(); k++) {
         g_free(*k);
@@ -690,7 +718,7 @@ void Inkscape::ObjectSnapper::_clear_paths() const
 Geom::PathVector* Inkscape::ObjectSnapper::_getBorderPathv() const
 {
     Geom::Rect const border_rect = Geom::Rect(Geom::Point(0,0), Geom::Point(sp_document_width(_snapmanager->getDocument()),sp_document_height(_snapmanager->getDocument())));
-    return _getPathvFromRect(border_rect);        
+    return _getPathvFromRect(border_rect);
 }
 
 Geom::PathVector* Inkscape::ObjectSnapper::_getPathvFromRect(Geom::Rect const rect) const
@@ -701,7 +729,7 @@ Geom::PathVector* Inkscape::ObjectSnapper::_getPathvFromRect(Geom::Rect const re
         return dummy;
     } else {
         return NULL;
-    }     
+    }
 }
 
 void Inkscape::ObjectSnapper::_getBorderNodes(std::vector<Geom::Point> *points) const
index f235ae5661c6d491f63e07d496494e3221a8b227..9972677e0c301c1461b2960a2834c6f05380ca90 100644 (file)
@@ -9,7 +9,7 @@
  *   Carl Hetherington <inkscape@carlh.net>
  *   Diederik van Lierop <mail@diedenrezi.nl>
  *
- * Copyright (C) 2005 - 2008 Authors 
+ * Copyright (C) 2005 - 2008 Authors
  *
  * Released under GNU GPL, read the file 'COPYING' for more information
  */
@@ -26,31 +26,31 @@ namespace Inkscape
 {
 
 class SnapCandidate
-    
+
 {
 public:
     SnapCandidate(SPItem* item, bool clip_or_mask, Geom::Matrix _additional_affine);
     ~SnapCandidate();
-    
+
     SPItem* item;        // An item that is to be considered for snapping to
     bool clip_or_mask;    // If true, then item refers to a clipping path or a mask
-    
-    /* To find out the absolute position of a clipping path or mask, we not only need to know 
-     * the transformation of the clipping path or mask itself, but also the transformation of 
+
+    /* To find out the absolute position of a clipping path or mask, we not only need to know
+     * the transformation of the clipping path or mask itself, but also the transformation of
      * the object to which the clip or mask is being applied; that transformation is stored here
      */
-    Geom::Matrix additional_affine;  
+    Geom::Matrix additional_affine;
 };
 
 class ObjectSnapper : public Snapper
 {
 
 public:
-    ObjectSnapper(SnapManager const *sm, Geom::Coord const d);
+    ObjectSnapper(SnapManager *sm, Geom::Coord const d);
     ~ObjectSnapper();
 
       enum DimensionToSnap {
-          GUIDE_TRANSL_SNAP_X, // For snapping a vertical guide (normal in the X-direction) to objects, 
+          GUIDE_TRANSL_SNAP_X, // For snapping a vertical guide (normal in the X-direction) to objects,
           GUIDE_TRANSL_SNAP_Y, // For snapping a horizontal guide (normal in the Y-direction) to objects
           ANGLED_GUIDE_TRANSL_SNAP, // For snapping an angled guide, while translating it accross the desktop
           ANGLED_GUIDE_ROT_SNAP, // For snapping an angled guide, while rotating it around some pivot point
@@ -69,10 +69,10 @@ public:
       void guideSnap(SnappedConstraints &sc,
                    Geom::Point const &p,
                  Geom::Point const &guide_normal) const;
-  
+
       bool ThisSnapperMightSnap() const;
       bool GuidesMightSnap() const;
-  
+
       void freeSnap(SnappedConstraints &sc,
                       Inkscape::SnapPreferences::PointType const &t,
                       Geom::Point const &p,
@@ -84,17 +84,17 @@ public:
       void constrainedSnap(SnappedConstraints &sc,
                       Inkscape::SnapPreferences::PointType const &t,
                       Geom::Point const &p,
-                      bool const &first_point,                                                                   
+                      bool const &first_point,
                       Geom::OptRect const &bbox_to_snap,
                       ConstraintLine const &c,
                       std::vector<SPItem const *> const *it) const;
-  
+
 private:
     //store some lists of candidates, points and paths, so we don't have to rebuild them for each point we want to snap
-    std::vector<SnapCandidate> *_candidates; 
+    std::vector<SnapCandidate> *_candidates;
     std::vector<Geom::Point> *_points_to_snap_to;
     std::vector<Geom::PathVector*> *_paths_to_snap_to;
-    
+
     void _findCandidates(SPObject* parent,
                        std::vector<SPItem const *> const *it,
                        bool const &first_point,
@@ -102,55 +102,55 @@ private:
                        DimensionToSnap snap_dim,
                        bool const _clip_or_mask,
                        Geom::Matrix const additional_affine) const;
-  
+
     void _snapNodes(SnappedConstraints &sc,
                       Inkscape::SnapPreferences::PointType const &t,
                       Geom::Point const &p, // in desktop coordinates
                       bool const &first_point,
                       std::vector<Geom::Point> *unselected_nodes) const; // in desktop coordinates
-                      
+
     void _snapTranslatingGuideToNodes(SnappedConstraints &sc,
                      Inkscape::SnapPreferences::PointType const &t,
                      Geom::Point const &p,
                      Geom::Point const &guide_normal) const;
-                     
+
     void _collectNodes(Inkscape::SnapPreferences::PointType const &t,
                   bool const &first_point) const;
-  
+
     void _snapPaths(SnappedConstraints &sc,
-                      Inkscape::SnapPreferences::PointType const &t, 
+                      Inkscape::SnapPreferences::PointType const &t,
                       Geom::Point const &p,    // in desktop coordinates
                       bool const &first_point,
                       std::vector<Geom::Point> *unselected_nodes, // in desktop coordinates
                       SPPath const *selected_path) const;
-                      
+
     void _snapPathsConstrained(SnappedConstraints &sc,
                  Inkscape::SnapPreferences::PointType const &t,
                  Geom::Point const &p, // in desktop coordinates
                  bool const &first_point,
                  ConstraintLine const &c) const;
-  
+
     bool isUnselectedNode(Geom::Point const &point, std::vector<Geom::Point> const *unselected_nodes) const;
-  
-    void _collectPaths(Inkscape::SnapPreferences::PointType const &t, 
+
+    void _collectPaths(Inkscape::SnapPreferences::PointType const &t,
                   bool const &first_point) const;
-                  
+
     void _clear_paths() const;
     Geom::PathVector* _getBorderPathv() const;
     Geom::PathVector* _getPathvFromRect(Geom::Rect const rect) const;
     void _getBorderNodes(std::vector<Geom::Point> *points) const;
-  
+
     bool _snap_to_itemnode;
     bool _snap_to_itempath;
     bool _snap_to_bboxnode;
     bool _snap_to_bboxpath;
     bool _snap_to_page_border;
-  
-    //If enabled, then bbox corners will only snap to bboxes, 
+
+    //If enabled, then bbox corners will only snap to bboxes,
     //and nodes will only snap to nodes and paths. We will not
     //snap bbox corners to nodes, or nodes to bboxes.
     //(snapping to grids and guides is not affected by this)
-    bool _strict_snapping; 
+    bool _strict_snapping;
 };
 
 }
index d98cd7cef2c7e08f4ed682de0e646621616ad14c..a52e0cfd9a32d079ffee2f9f4a0846af3387d586 100644 (file)
@@ -20,7 +20,7 @@ class SnapPreferences
 {
 public:
        SnapPreferences();
-       
+
        /// Point types to snap.
     typedef int PointType;
     static const PointType SNAPPOINT_NODE;
@@ -39,31 +39,34 @@ public:
     void setSnapIntersectionGG(bool enabled) {_intersectionGG = enabled;}
     void setSnapIntersectionCS(bool enabled) {_intersectionCS = enabled;}
     void setSnapSmoothNodes(bool enabled) {_smoothNodes = enabled;}
+    void setSnapMidpoints(bool enabled) {_midpoints = enabled;}
     bool getSnapIntersectionGG() const {return _intersectionGG;}
-    bool getSnapIntersectionCS() const {return _intersectionCS;}    
+    bool getSnapIntersectionCS() const {return _intersectionCS;}
     bool getSnapSmoothNodes() const {return _smoothNodes;}
-    
+    bool getSnapMidpoints() const {return _midpoints;}
+
     void setIncludeItemCenter(bool enabled) {_include_item_center = enabled;}
     bool getIncludeItemCenter() const {return _include_item_center;}
-    
-    void setSnapEnabledGlobally(bool enabled) {_snap_enabled_globally = enabled;}        
-    bool getSnapEnabledGlobally() const {return _snap_enabled_globally;}    
-    
+
+    void setSnapEnabledGlobally(bool enabled) {_snap_enabled_globally = enabled;}
+    bool getSnapEnabledGlobally() const {return _snap_enabled_globally;}
+
     void setSnapPostponedGlobally(bool postponed) {_snap_postponed_globally = postponed;}
     bool getSnapPostponedGlobally() const {return _snap_postponed_globally;}
-    
+
     void setSnapFrom(PointType t, bool s);
     bool getSnapFrom(PointType t) const;
-       
+
 private:
     bool _include_item_center; //If true, snapping nodes will also snap the item's center
-    bool _intersectionGG;
-    bool _intersectionCS;
+    bool _intersectionGG; //Consider snapping to intersections of grid and guides
+    bool _intersectionCS; //Consider snapping to intersections of curves
     bool _smoothNodes;
+    bool _midpoints;
     bool _snap_enabled_globally; // Toggles ALL snapping
     bool _snap_postponed_globally; // Hold all snapping temporarily when the mouse is moving fast
     PointType _snap_from; ///< bitmap of point types that we will snap from
-        
+
 };
 
 }
index b8d9fdd25604680c25bba39e4d318624c2d14a72..14adf399facbb4e564653ee6a7f068beb55e776b 100644 (file)
@@ -48,44 +48,44 @@ public:
         STRETCH,
         SKEW
     };
-       
+
        SnapManager(SPNamedView const *v);
 
     typedef std::list<const Inkscape::Snapper*> SnapperList;
 
     bool someSnapperMightSnap() const;
-    
+
     void setup(SPDesktop const *desktop, bool snapindicator = true, SPItem const *item_to_ignore = NULL, std::vector<Geom::Point> *unselected_nodes = NULL);
     void setup(SPDesktop const *desktop, bool snapindicator, std::vector<SPItem const *> &items_to_ignore, std::vector<Geom::Point> *unselected_nodes = NULL);
 
-    // freeSnapReturnByRef() is preferred over freeSnap(), because it only returns a 
-    // point if snapping has occured (by overwriting p); otherwise p is untouched    
+    // freeSnapReturnByRef() is preferred over freeSnap(), because it only returns a
+    // point if snapping has occured (by overwriting p); otherwise p is untouched
     void freeSnapReturnByRef(Inkscape::SnapPreferences::PointType point_type,
                       Geom::Point &p,
                       bool first_point = true,
                       Geom::OptRect const &bbox_to_snap = Geom::OptRect()) const;
-    
+
     Inkscape::SnappedPoint freeSnap(Inkscape::SnapPreferences::PointType point_type,
                                     Geom::Point const &p,
                                     bool first_point = true,
                                     Geom::OptRect const &bbox_to_snap = Geom::OptRect() ) const;
-    
+
     Geom::Point multipleOfGridPitch(Geom::Point const &t) const;
-    
-    // constrainedSnapReturnByRef() is preferred over constrainedSnap(), because it only returns a 
+
+    // constrainedSnapReturnByRef() is preferred over constrainedSnap(), because it only returns a
     // point, by overwriting p, if snapping has occured; otherwise p is untouched
     void constrainedSnapReturnByRef(Inkscape::SnapPreferences::PointType point_type,
                              Geom::Point &p,
                              Inkscape::Snapper::ConstraintLine const &constraint,
                              bool first_point = true,
                              Geom::OptRect const &bbox_to_snap = Geom::OptRect()) const;
-    
+
     Inkscape::SnappedPoint constrainedSnap(Inkscape::SnapPreferences::PointType point_type,
                                            Geom::Point const &p,
                                            Inkscape::Snapper::ConstraintLine const &constraint,
                                            bool first_point = true,
                                            Geom::OptRect const &bbox_to_snap = Geom::OptRect()) const;
-                                           
+
     void guideSnap(Geom::Point &p, Geom::Point const &guide_normal) const;
 
     Inkscape::SnappedPoint freeSnapTranslation(Inkscape::SnapPreferences::PointType point_type,
@@ -126,28 +126,28 @@ public:
                                                Geom::Point const &s, // s[0] = skew factor, s[1] = scale factor
                                                Geom::Point const &o,
                                                Geom::Dim2 d) const;
-    
+
     Inkscape::GuideSnapper guide;      ///< guide snapper
     Inkscape::ObjectSnapper object;    ///< snapper to other objects
     Inkscape::SnapPreferences snapprefs;
 
     SnapperList getSnappers() const;
     SnapperList getGridSnappers() const;
-    
+
     SPDesktop const *getDesktop() const {return _desktop;}
     SPNamedView const *getNamedView() const {return _named_view;}
     SPDocument *getDocument() const;
-    
+
 protected:
     SPNamedView const *_named_view;
 
 private:
-       std::vector<SPItem const *> *_items_to_ignore;
+    std::vector<SPItem const *> *_items_to_ignore;
     SPItem const *_item_to_ignore;
     SPDesktop const *_desktop;
     bool _snapindicator;
-    std::vector<Geom::Point> *_unselected_nodes;                                    
-    
+    std::vector<Geom::Point> *_unselected_nodes;
+
     Inkscape::SnappedPoint _snapTransformed(Inkscape::SnapPreferences::PointType type,
                                             std::vector<Geom::Point> const &points,
                                             Geom::Point const &pointer,
@@ -158,16 +158,16 @@ private:
                                             Geom::Point const &origin,
                                             Geom::Dim2 dim,
                                             bool uniform) const;
-    
-    Geom::Point _transformPoint(Geom::Point const &p, 
-                                                               Transformation const transformation_type, 
-                                                               Geom::Point const &transformation, 
-                                                               Geom::Point const &origin, 
-                                                               Geom::Dim2 const dim, 
-                                                               bool const uniform) const;
-   
-    void _displaySnapsource(Inkscape::SnapPreferences::PointType point_type, Geom::Point const &p) const; 
-    
+
+    Geom::Point _transformPoint(Geom::Point const &p,
+                                            Transformation const transformation_type,
+                                            Geom::Point const &transformation,
+                                            Geom::Point const &origin,
+                                            Geom::Dim2 const dim,
+                                            bool const uniform) const;
+
+    void _displaySnapsource(Inkscape::SnapPreferences::PointType point_type, Geom::Point const &p) const;
+
     Inkscape::SnappedPoint findBestSnap(Geom::Point const &p, SnappedConstraints &sc, bool constrained) const;
 };
 
index 7b65c5c655b0751f46d64a77008b000ed6d62b10..fa2d561cd2e161c299e8f5e9935a6af39d275124 100644 (file)
@@ -63,7 +63,7 @@ Inkscape::SnappedPoint Inkscape::SnappedCurve::intersect(SnappedCurve const &cur
         // There might be multiple intersections: find the closest
         Geom::Coord best_dist = NR_HUGE;
         Geom::Point best_p = Geom::Point(NR_HUGE, NR_HUGE);
-        for (std::vector<Geom::Crossing>::const_iterator i = cs.begin(); i != cs.end(); i++) {
+        for (Geom::Crossings::const_iterator i = cs.begin(); i != cs.end(); i++) {
             Geom::Point p_ix = this->_curve->pointAt((*i).ta);
             Geom::Coord dist = Geom::distance(p_ix, p);
             if (dist < best_dist) {
index 3dd58737ee015678243bed32d672ed84c2e09c31..492e4ca4d019b4da14ac7a72094b470f78fa4504 100644 (file)
@@ -19,8 +19,8 @@
  *  \param nv Named view.
  *  \param d Snap tolerance.
  */
-Inkscape::Snapper::Snapper(SnapManager const *sm, Geom::Coord const t) : 
-       _snapmanager(sm), 
+Inkscape::Snapper::Snapper(SnapManager *sm, Geom::Coord const t) :
+       _snapmanager(sm),
        _snap_enabled(true),
        _snapper_tolerance(std::max(t, 1.0))
 {
index 0c405fd2bfadced3d9108896a65f25f9bd177311..f6e1a086e8a18c301e645e435c57c673fe526328 100644 (file)
@@ -42,9 +42,9 @@ class Snapper
 {
 public:
        Snapper() {}
-       Snapper(SnapManager const *sm, ::Geom::Coord const t);
+       Snapper(SnapManager *sm, ::Geom::Coord const t);
        virtual ~Snapper() {}
-       
+
     void setSnapperTolerance(Geom::Coord t);
     Geom::Coord getSnapperTolerance() const; //returns the tolerance of the snapper in screen pixels (i.e. independent of zoom)
     bool getSnapperAlwaysSnap() const; //if true, then the snapper will always snap, regardless of its tolerance
@@ -83,10 +83,10 @@ public:
         Geom::Point getDirection() const {
             return _direction;
         }
-        
+
         void setPoint(Geom::Point const &p) {
             _point = p;
-            _has_point = true;        
+            _has_point = true;
         }
 
     private:
@@ -105,8 +105,8 @@ public:
                                  std::vector<SPItem const *> const */*it*/) const {};
 
 protected:
-       SnapManager const *_snapmanager;
-       
+       SnapManager *_snapmanager;
+
        bool _snap_enabled; ///< true if this snapper is enabled, otherwise false
 
 private:
index 2b7c8bbc44178eb30f82cc8be2b04a7aa3f55388..c46f30e0696ddca39e83e758b3b64b2b1d3349a2 100644 (file)
@@ -111,7 +111,7 @@ static void sp_namedview_init(SPNamedView *nv)
     nv->guides = NULL;
     nv->viewcount = 0;
     nv->grids = NULL;
-    
+
     nv->default_layer_id = 0;
 
     nv->connector_spacing = defaultConnSpacing;
@@ -248,6 +248,7 @@ static void sp_namedview_build(SPObject *object, SPDocument *document, Inkscape:
     sp_object_read_attr(object, "inkscape:snap-guide");
     sp_object_read_attr(object, "inkscape:snap-center");
     sp_object_read_attr(object, "inkscape:snap-smooth-nodes");
+    sp_object_read_attr(object, "inkscape:snap-midpoints");
     sp_object_read_attr(object, "inkscape:snap-intersection-grid-guide");
     sp_object_read_attr(object, "inkscape:snap-intersection-paths");
     sp_object_read_attr(object, "inkscape:object-paths");
@@ -469,7 +470,11 @@ static void sp_namedview_set(SPObject *object, unsigned int key, const gchar *va
     case SP_ATTR_INKSCAPE_SNAP_SMOOTH_NODES:
             nv->snap_manager.snapprefs.setSnapSmoothNodes(value ? sp_str_to_bool(value) : FALSE);
             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
-            break;           
+            break;
+    case SP_ATTR_INKSCAPE_SNAP_MIDPOINTS:
+            nv->snap_manager.snapprefs.setSnapMidpoints(value ? sp_str_to_bool(value) : FALSE);
+            object->requestModified(SP_OBJECT_MODIFIED_FLAG);
+            break;
     case SP_ATTR_INKSCAPE_SNAP_GUIDE:
             nv->snap_manager.snapprefs.setSnapModeGuide(value ? sp_str_to_bool(value) : FALSE);
             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
@@ -501,7 +506,7 @@ static void sp_namedview_set(SPObject *object, unsigned int key, const gchar *va
     case SP_ATTR_INKSCAPE_SNAP_PAGE:
             nv->snap_manager.object.setSnapToPageBorder(value ? sp_str_to_bool(value) : FALSE);
             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
-            break;    
+            break;
     case SP_ATTR_INKSCAPE_CURRENT_LAYER:
             nv->default_layer_id = value ? g_quark_from_string(value) : 0;
             object->requestModified(SP_OBJECT_MODIFIED_FLAG);
index d3f357e7688f51e1d6a025aa04eebe1d7738d0ed..7ee2af1ec97321eecde89ff6d8331847cebf773e 100644 (file)
@@ -23,6 +23,7 @@
 #include <2geom/rect.h>
 #include <2geom/transforms.h>
 #include <2geom/pathvector.h>
+#include <2geom/path-intersection.h>
 #include "helper/geom.h"
 #include "helper/geom-nodetype.h"
 
@@ -79,21 +80,21 @@ static SPLPEItemClass *parent_class;
 GType
 sp_shape_get_type (void)
 {
-       static GType type = 0;
-       if (!type) {
-               GTypeInfo info = {
-                       sizeof (SPShapeClass),
-                       NULL, NULL,
-                       (GClassInitFunc) sp_shape_class_init,
-                       NULL, NULL,
-                       sizeof (SPShape),
-                       16,
-                       (GInstanceInitFunc) sp_shape_init,
-                       NULL,   /* value_table */
-               };
-               type = g_type_register_static (SP_TYPE_LPE_ITEM, "SPShape", &info, (GTypeFlags)0);
-       }
-       return type;
+    static GType type = 0;
+    if (!type) {
+        GTypeInfo info = {
+            sizeof (SPShapeClass),
+            NULL, NULL,
+            (GClassInitFunc) sp_shape_class_init,
+            NULL, NULL,
+            sizeof (SPShape),
+            16,
+            (GInstanceInitFunc) sp_shape_init,
+            NULL,    /* value_table */
+        };
+        type = g_type_register_static (SP_TYPE_LPE_ITEM, "SPShape", &info, (GTypeFlags)0);
+    }
+    return type;
 }
 
 /**
@@ -112,17 +113,17 @@ sp_shape_class_init (SPShapeClass *klass)
 
     gobject_class->finalize = sp_shape_finalize;
 
-       sp_object_class->build = sp_shape_build;
-       sp_object_class->release = sp_shape_release;
+    sp_object_class->build = sp_shape_build;
+    sp_object_class->release = sp_shape_release;
     sp_object_class->set = sp_shape_set;
-       sp_object_class->update = sp_shape_update;
-       sp_object_class->modified = sp_shape_modified;
+    sp_object_class->update = sp_shape_update;
+    sp_object_class->modified = sp_shape_modified;
     sp_object_class->write = sp_shape_write;
 
-       item_class->bbox = sp_shape_bbox;
-       item_class->print = sp_shape_print;
-       item_class->show = sp_shape_show;
-       item_class->hide = sp_shape_hide;
+    item_class->bbox = sp_shape_bbox;
+    item_class->print = sp_shape_print;
+    item_class->show = sp_shape_show;
+    item_class->hide = sp_shape_hide;
     item_class->snappoints = sp_shape_snappoints;
     lpe_item_class->update_patheffect = NULL;
 
@@ -174,7 +175,7 @@ sp_shape_build (SPObject *object, SPDocument *document, Inkscape::XML::Node *rep
 
     for (int i = 0 ; i < SP_MARKER_LOC_QTY ; i++) {
         sp_shape_set_marker (object, i, object->style->marker[i].value);
-         }
+      }
 }
 
 /**
@@ -190,31 +191,31 @@ sp_shape_build (SPObject *object, SPDocument *document, Inkscape::XML::Node *rep
 static void
 sp_shape_release (SPObject *object)
 {
-       SPItem *item;
-       SPShape *shape;
-       SPItemView *v;
-       int i;
-
-       item = (SPItem *) object;
-       shape = (SPShape *) object;
-
-       for (i=SP_MARKER_LOC_START; i<SP_MARKER_LOC_QTY; i++) {
-         if (shape->marker[i]) {
-           for (v = item->display; v != NULL; v = v->next) {
-             sp_marker_hide ((SPMarker *) shape->marker[i], NR_ARENA_ITEM_GET_KEY (v->arenaitem) + i);
-           }
+    SPItem *item;
+    SPShape *shape;
+    SPItemView *v;
+    int i;
+
+    item = (SPItem *) object;
+    shape = (SPShape *) object;
+
+    for (i=SP_MARKER_LOC_START; i<SP_MARKER_LOC_QTY; i++) {
+      if (shape->marker[i]) {
+        for (v = item->display; v != NULL; v = v->next) {
+          sp_marker_hide ((SPMarker *) shape->marker[i], NR_ARENA_ITEM_GET_KEY (v->arenaitem) + i);
+        }
       shape->release_connect[i].disconnect();
       shape->modified_connect[i].disconnect();
-           shape->marker[i] = sp_object_hunref (shape->marker[i], object);
-         }
-       }
-       if (shape->curve) {
-               shape->curve = shape->curve->unref();
-       }
-    
-       if (((SPObjectClass *) parent_class)->release) {
-         ((SPObjectClass *) parent_class)->release (object);
-       }
+        shape->marker[i] = sp_object_hunref (shape->marker[i], object);
+      }
+    }
+    if (shape->curve) {
+        shape->curve = shape->curve->unref();
+    }
+
+    if (((SPObjectClass *) parent_class)->release) {
+      ((SPObjectClass *) parent_class)->release (object);
+    }
 }
 
 
@@ -237,9 +238,9 @@ sp_shape_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::No
     return repr;
 }
 
-/** 
+/**
  * Updates the shape when its attributes have changed.  Also establishes
- * marker objects to match the style settings.  
+ * marker objects to match the style settings.
  */
 static void
 sp_shape_update (SPObject *object, SPCtx *ctx, unsigned int flags)
@@ -258,7 +259,7 @@ sp_shape_update (SPObject *object, SPCtx *ctx, unsigned int flags)
      */
     for (int i = 0 ; i < SP_MARKER_LOC_QTY ; i++) {
         sp_shape_set_marker (object, i, object->style->marker[i].value);
-         }
+      }
 
     if (flags & (SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
         SPStyle *style;
@@ -463,17 +464,17 @@ sp_shape_update_marker_view (SPShape *shape, NRArenaItem *ai)
 static void
 sp_shape_modified (SPObject *object, unsigned int flags)
 {
-       SPShape *shape = SP_SHAPE (object);
+    SPShape *shape = SP_SHAPE (object);
 
-       if (((SPObjectClass *) (parent_class))->modified) {
-         (* ((SPObjectClass *) (parent_class))->modified) (object, flags);
-       }
+    if (((SPObjectClass *) (parent_class))->modified) {
+      (* ((SPObjectClass *) (parent_class))->modified) (object, flags);
+    }
 
-       if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) {
-               for (SPItemView *v = SP_ITEM (shape)->display; v != NULL; v = v->next) {
-                       nr_arena_shape_set_style (NR_ARENA_SHAPE (v->arenaitem), object->style);
-               }
-       }
+    if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) {
+        for (SPItemView *v = SP_ITEM (shape)->display; v != NULL; v = v->next) {
+            nr_arena_shape_set_style (NR_ARENA_SHAPE (v->arenaitem), object->style);
+        }
+    }
 }
 
 /**
@@ -493,7 +494,7 @@ static void sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &
             cbbox.y1 = (*geombbox)[1][1];
 
             if ((SPItem::BBoxType) flags != SPItem::GEOMETRIC_BBOX) {
-                
+
                 SPStyle* style=SP_OBJECT_STYLE (item);
                 if (!style->stroke.isNone()) {
                     double const scale = transform.descrim();
@@ -611,11 +612,11 @@ static void sp_shape_bbox(SPItem const *item, NRRect *bbox, Geom::Matrix const &
 void
 sp_shape_print (SPItem *item, SPPrintContext *ctx)
 {
-       NRRect pbox, dbox, bbox;
+    NRRect pbox, dbox, bbox;
 
-       SPShape *shape = SP_SHAPE(item);
+    SPShape *shape = SP_SHAPE(item);
 
-       if (!shape->curve) return;
+    if (!shape->curve) return;
 
         Inkscape::Preferences *prefs = Inkscape::Preferences::get();
         gint add_comments = prefs->getBool("/printing/debug/add-label-comments");
@@ -756,7 +757,7 @@ sp_shape_show (SPItem *item, NRArena *arena, unsigned int /*key*/, unsigned int
      */
     for (int i = 0 ; i < SP_MARKER_LOC_QTY ; i++) {
         sp_shape_set_marker (object, i, object->style->marker[i].value);
-         }
+      }
 
     if (sp_shape_has_markers (shape)) {
 
@@ -786,26 +787,26 @@ sp_shape_show (SPItem *item, NRArena *arena, unsigned int /*key*/, unsigned int
 static void
 sp_shape_hide (SPItem *item, unsigned int key)
 {
-       SPShape *shape;
-       SPItemView *v;
-       int i;
+    SPShape *shape;
+    SPItemView *v;
+    int i;
 
-       shape = (SPShape *) item;
+    shape = (SPShape *) item;
 
-       for (i=0; i<SP_MARKER_LOC_QTY; i++) {
-         if (shape->marker[i]) {
-           for (v = item->display; v != NULL; v = v->next) {
+    for (i=0; i<SP_MARKER_LOC_QTY; i++) {
+      if (shape->marker[i]) {
+        for (v = item->display; v != NULL; v = v->next) {
                 if (key == v->key) {
-             sp_marker_hide ((SPMarker *) shape->marker[i],
+          sp_marker_hide ((SPMarker *) shape->marker[i],
                                     NR_ARENA_ITEM_GET_KEY (v->arenaitem) + i);
                 }
-           }
-         }
-       }
+        }
+      }
+    }
 
-       if (((SPItemClass *) parent_class)->hide) {
-         ((SPItemClass *) parent_class)->hide (item, key);
-       }
+    if (((SPItemClass *) parent_class)->hide) {
+      ((SPItemClass *) parent_class)->hide (item, key);
+    }
 }
 
 /**
@@ -884,26 +885,26 @@ sp_shape_number_of_markers (SPShape *shape, int type)
 static void
 sp_shape_marker_release (SPObject *marker, SPShape *shape)
 {
-       SPItem *item;
-       int i;
-
-       item = (SPItem *) shape;
-
-       for (i = SP_MARKER_LOC_START; i < SP_MARKER_LOC_QTY; i++) {
-         if (marker == shape->marker[i]) {
-           SPItemView *v;
-           /* Hide marker */
-           for (v = item->display; v != NULL; v = v->next) {
-             sp_marker_hide ((SPMarker *) (shape->marker[i]), NR_ARENA_ITEM_GET_KEY (v->arenaitem) + i);
-             /* fixme: Do we need explicit remove here? (Lauris) */
-             /* nr_arena_item_set_mask (v->arenaitem, NULL); */
-           }
-           /* Detach marker */
+    SPItem *item;
+    int i;
+
+    item = (SPItem *) shape;
+
+    for (i = SP_MARKER_LOC_START; i < SP_MARKER_LOC_QTY; i++) {
+      if (marker == shape->marker[i]) {
+        SPItemView *v;
+        /* Hide marker */
+        for (v = item->display; v != NULL; v = v->next) {
+          sp_marker_hide ((SPMarker *) (shape->marker[i]), NR_ARENA_ITEM_GET_KEY (v->arenaitem) + i);
+          /* fixme: Do we need explicit remove here? (Lauris) */
+          /* nr_arena_item_set_mask (v->arenaitem, NULL); */
+        }
+        /* Detach marker */
       shape->release_connect[i].disconnect();
       shape->modified_connect[i].disconnect();
-           shape->marker[i] = sp_object_hunref (shape->marker[i], item);
-         }
-       }
+        shape->marker[i] = sp_object_hunref (shape->marker[i], item);
+      }
+    }
 }
 
 /**
@@ -912,12 +913,12 @@ sp_shape_marker_release (SPObject *marker, SPShape *shape)
 static void
 sp_shape_marker_modified (SPObject */*marker*/, guint /*flags*/, SPItem */*item*/)
 {
-       /* I think mask does update automagically */
-       /* g_warning ("Item %s mask %s modified", SP_OBJECT_ID (item), SP_OBJECT_ID (mask)); */
+    /* I think mask does update automagically */
+    /* g_warning ("Item %s mask %s modified", SP_OBJECT_ID (item), SP_OBJECT_ID (mask)); */
 }
 
 /**
- * Adds a new marker to shape object at the location indicated by key.  value 
+ * Adds a new marker to shape object at the location indicated by key.  value
  * must be a valid URI reference resolvable from the shape object (i.e., present
  * in the document <defs>).  If the shape object already has a marker
  * registered at the given position, it is removed first.  Then the
@@ -971,12 +972,12 @@ sp_shape_set_marker (SPObject *object, unsigned int key, const gchar *value)
 void
 sp_shape_set_shape (SPShape *shape)
 {
-       g_return_if_fail (shape != NULL);
-       g_return_if_fail (SP_IS_SHAPE (shape));
+    g_return_if_fail (shape != NULL);
+    g_return_if_fail (SP_IS_SHAPE (shape));
 
-       if (SP_SHAPE_CLASS (G_OBJECT_GET_CLASS (shape))->set_shape) {
-         SP_SHAPE_CLASS (G_OBJECT_GET_CLASS (shape))->set_shape (shape);
-       }
+    if (SP_SHAPE_CLASS (G_OBJECT_GET_CLASS (shape))->set_shape) {
+      SP_SHAPE_CLASS (G_OBJECT_GET_CLASS (shape))->set_shape (shape);
+    }
 }
 
 /**
@@ -988,16 +989,16 @@ sp_shape_set_shape (SPShape *shape)
 void
 sp_shape_set_curve (SPShape *shape, SPCurve *curve, unsigned int owner)
 {
-       if (shape->curve) {
-               shape->curve = shape->curve->unref();
-       }
-       if (curve) {
-               if (owner) {
-                       shape->curve = curve->ref();
-               } else {
-                       shape->curve = curve->copy();
-               }
-       }
+    if (shape->curve) {
+        shape->curve = shape->curve->unref();
+    }
+    if (curve) {
+        if (owner) {
+            shape->curve = curve->ref();
+        } else {
+            shape->curve = curve->copy();
+        }
+    }
         SP_OBJECT(shape)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
 }
 
@@ -1007,10 +1008,10 @@ sp_shape_set_curve (SPShape *shape, SPCurve *curve, unsigned int owner)
 SPCurve *
 sp_shape_get_curve (SPShape *shape)
 {
-       if (shape->curve) {
-               return shape->curve->copy();
-       }
-       return NULL;
+    if (shape->curve) {
+        return shape->curve->copy();
+    }
+    return NULL;
 }
 
 /**
@@ -1019,16 +1020,16 @@ sp_shape_get_curve (SPShape *shape)
 void
 sp_shape_set_curve_insync (SPShape *shape, SPCurve *curve, unsigned int owner)
 {
-       if (shape->curve) {
-               shape->curve = shape->curve->unref();
-       }
-       if (curve) {
-               if (owner) {
-                       shape->curve = curve->ref();
-               } else {
-                       shape->curve = curve->copy();
-               }
-       }
+    if (shape->curve) {
+        shape->curve = shape->curve->unref();
+    }
+    if (curve) {
+        if (owner) {
+            shape->curve = curve->ref();
+        } else {
+            shape->curve = curve->copy();
+        }
+    }
 }
 
 /**
@@ -1058,22 +1059,44 @@ static void sp_shape_snappoints(SPItem const *item, SnapPointsIter p, Inkscape::
         while (curve_it2 != path_it->end_closed())
         {
             /* Test whether to add the node between curve_it1 and curve_it2.
-             * Loop to end_closed (so always including closing segment), the last node to be added
-             * is the node between the closing segment and the segment before that one. Regardless
-             * of the path being closed. If the path is closed, the final point was already added by
+             * Loop to end_closed (so always including closing segment); the last node to be added
+             * is the node between the closing segment and the segment before that, regardless
+             * of the path being closed or not. If the path is closed, the final point was already added by
              * adding the initial point. */
 
             Geom::NodeType nodetype = Geom::get_nodetype(*curve_it1, *curve_it2);
 
-            // Depending on the snapping preferences, either add only cusp nodes, or add add both cusp and smooths nodes
+            // Depending on the snapping preferences, either add only cusp nodes, or add add both cusp and smooth nodes
             if (snapprefs->getSnapSmoothNodes() || nodetype == Geom::NODE_NONE || nodetype == Geom::NODE_CUSP) {
                 *p = from_2geom(curve_it1->finalPoint() * i2d);
             }
-            
+
+            // Consider midpoints of line segments for snapping
+            if (snapprefs->getSnapMidpoints()) {
+                if (Geom::LineSegment const* line_segment = dynamic_cast<Geom::LineSegment const*>(&(*curve_it1))) {
+                    *p = from_2geom(Geom::middle_point(*line_segment) * i2d);
+                }
+            }
+
             ++curve_it1;
             ++curve_it2;
         }
+
+        // Find the internal intersections of each path and consider these for snapping (using "Method 1" as desciribed in Inkscape::ObjectSnapper::_collectNodes())
+        if (snapprefs->getSnapIntersectionCS()) {
+            Geom::Crossings cs;
+            cs = self_crossings(*path_it);
+            if (cs.size() > 0) { // There might be multiple intersections...
+                for (Geom::Crossings::const_iterator i = cs.begin(); i != cs.end(); i++) {
+                    Geom::Point p_ix = (*path_it).pointAt((*i).ta);
+                    *p = from_2geom(p_ix * i2d);
+                }
+            }
+        }
     }
+
+
+
 }
 
 /*
index 1bbd201363963a1b59660d841388c166eb990961..713acc23e049592beb554f3a00abddac79a21eab 100644 (file)
@@ -119,6 +119,7 @@ DocumentProperties::DocumentProperties()
        //Applies to both nodes and guides, but not to bboxes, that's why its located here
       _rcbic( _("Rotation _center"), _("Consider the rotation center of an object when snapping"), "inkscape:snap-center", _wr),
       _rcbsm( _("_Smooth nodes"), _("Snap to smooth nodes too, instead of only snapping to cusp nodes"), "inkscape:snap-smooth-nodes", _wr),
+      _rcbmp( _("_Midpoints"), _("Snap midpoints of straight line segments"), "inkscape:snap-midpoints", _wr),
       _rcbsigg(_("_Grid with guides"), _("Snap to grid-guide intersections"), "inkscape:snap-intersection-grid-guide", _wr),
       _rcbsils(_("_Paths"), _("Snap to intersections of paths ('snap to paths' must be enabled, see the previous tab)"),
                 "inkscape:snap-intersection-paths", _wr),
@@ -368,7 +369,7 @@ DocumentProperties::build_snap_dtls()
     //Other options to locate here: e.g. visual snapping indicators on/off
 
     Gtk::Label *label_i= manage (new Gtk::Label);
-    label_i->set_markup (_("<b>Snapping to intersections of</b>"));
+    label_i->set_markup (_("<b>Snapping intersections of</b>"));
     Gtk::Label *label_m = manage (new Gtk::Label);
     label_m->set_markup (_("<b>Special points to consider</b>"));
 
@@ -380,7 +381,8 @@ DocumentProperties::build_snap_dtls()
         0,                  0,
         label_m,            0,
         0,                  &_rcbic,
-        0,                  &_rcbsm
+        0,                  &_rcbsm,
+        0,                  &_rcbmp
     };
 
     attach_all(_page_snap_dtls.table(), array, G_N_ELEMENTS(array));
@@ -774,6 +776,7 @@ DocumentProperties::update()
     _rcbsng.setActive (nv->snap_manager.snapprefs.getSnapModeGuide());
     _rcbic.setActive (nv->snap_manager.snapprefs.getIncludeItemCenter());
     _rcbsm.setActive (nv->snap_manager.snapprefs.getSnapSmoothNodes());
+    _rcbmp.setActive (nv->snap_manager.snapprefs.getSnapMidpoints());
     _rcbsigg.setActive (nv->snap_manager.snapprefs.getSnapIntersectionGG());
     _rcbsils.setActive (nv->snap_manager.snapprefs.getSnapIntersectionCS());
     _rcbsnop.setActive(nv->snap_manager.object.getSnapToItemPath());
index 2428ab24a826a4030409e2eae3fed7558b59932b..36a6c739b61ae929b9cf89e77766701a7df2ff7d 100644 (file)
@@ -112,7 +112,7 @@ protected:
     RegisteredCheckButton _rcbsnon, _rcbsnbbp, _rcbsnbbn, _rcbsnpb;
     ToleranceSlider       _rsu_sno, _rsu_sn, _rsu_gusn;
     //---------------------------------------------------------------
-    RegisteredCheckButton _rcbic, _rcbsm;
+    RegisteredCheckButton _rcbic, _rcbsm, _rcbmp;
     RegisteredCheckButton _rcbsigg, _rcbsils;
     //---------------------------------------------------------------
     Gtk::Menu   _menu;