Code

* Implement constrained snapping of knots
authordvlierop2 <dvlierop2@users.sourceforge.net>
Fri, 13 Mar 2009 20:15:31 +0000 (20:15 +0000)
committerdvlierop2 <dvlierop2@users.sourceforge.net>
Fri, 13 Mar 2009 20:15:31 +0000 (20:15 +0000)
* Implement snapping of the rectangle's radius handles
* Line snappers: set the snap target in the derived class instead of in findBestSnap()

13 files changed:
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/knot-holder-entity.cpp
src/knot-holder-entity.h
src/line-snapper.cpp
src/line-snapper.h
src/object-edit.cpp
src/snap.cpp
src/snapped-point.h

index ea5393d393f3b090229e5b20a07332b928120f25..9c6126b7c91a93aca0e525bbc784bc6b26b9403c 100644 (file)
@@ -757,12 +757,18 @@ CanvasAxonomGridSnapper::_getSnapLines(Geom::Point const &p) const
     return s;
 }
 
-void CanvasAxonomGridSnapper::_addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, SnapTargetType const &target, 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, SnapSourceType const &source, Geom::Point const normal_to_line, Geom::Point const point_on_line) const
 {
-    SnappedLine dummy = SnappedLine(snapped_point, snapped_distance, source, target, getSnapperTolerance(), getSnapperAlwaysSnap(), normal_to_line, point_on_line);
+    SnappedLine dummy = SnappedLine(snapped_point, snapped_distance, source, Inkscape::SNAPTARGET_GRID, getSnapperTolerance(), getSnapperAlwaysSnap(), normal_to_line, point_on_line);
     sc.grid_lines.push_back(dummy);
 }
 
+void CanvasAxonomGridSnapper::_addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source) const
+{
+       SnappedPoint dummy = SnappedPoint(snapped_point, source, Inkscape::SNAPTARGET_GRID, snapped_distance, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
+       sc.points.push_back(dummy);
+}
+
 bool CanvasAxonomGridSnapper::ThisSnapperMightSnap() const
 {
     return _snap_enabled && _snapmanager->snapprefs.getSnapToGrids() && _snapmanager->snapprefs.getSnapModeBBoxOrNodes();
index ecbd846a18e58549bea477ef4e165d9b8a7015fc..e36804d7c409d60b125fac8fc99fcc55e17c857b 100644 (file)
@@ -78,7 +78,8 @@ public:
 
 private:
     LineList _getSnapLines(Geom::Point const &p) const;
-    void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, SnapTargetType const &target, Geom::Point const normal_to_line, const Geom::Point point_on_line) const;
+    void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, Geom::Point const normal_to_line, const Geom::Point point_on_line) const;
+    void _addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source) const;
 
     CanvasAxonomGrid *grid;
 };
index 3e7295b90aea83cf2ac2b7656ead1d0495e667ca..c971382b464a3f4c237d96ffd790b83c64fe1e8e 100644 (file)
@@ -1003,12 +1003,18 @@ CanvasXYGridSnapper::_getSnapLines(Geom::Point const &p) const
     return s;
 }
 
-void CanvasXYGridSnapper::_addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance,  SnapSourceType const &source, SnapTargetType const &target, 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,  SnapSourceType const &source, Geom::Point const normal_to_line, Geom::Point const point_on_line) const
 {
-    SnappedLine dummy = SnappedLine(snapped_point, snapped_distance, source, target, getSnapperTolerance(), getSnapperAlwaysSnap(), normal_to_line, point_on_line);
+    SnappedLine dummy = SnappedLine(snapped_point, snapped_distance, source, Inkscape::SNAPTARGET_GRID, getSnapperTolerance(), getSnapperAlwaysSnap(), normal_to_line, point_on_line);
     sc.grid_lines.push_back(dummy);
 }
 
+void CanvasXYGridSnapper::_addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source) const
+{
+       SnappedPoint dummy = SnappedPoint(snapped_point, source, Inkscape::SNAPTARGET_GRID, snapped_distance, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
+       sc.points.push_back(dummy);
+}
+
 /**
  *  \return true if this Snapper will snap at least one kind of point.
  */
index 37e30fab0fcfcaff83cebbae166aa2015c535f27..750fef1b0ee7bf56b192bd39570a85801f735227 100644 (file)
@@ -166,7 +166,8 @@ public:
 
 private:
     LineList _getSnapLines(Geom::Point const &p) const;
-    void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance,  SnapSourceType const &source, SnapTargetType const &target, Geom::Point const normal_to_line, const Geom::Point point_on_line) const;
+    void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance,  SnapSourceType const &source, Geom::Point const normal_to_line, const Geom::Point point_on_line) const;
+    void _addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source) const;
     CanvasXYGrid *grid;
 };
 
index 989dec16b4662de1986aebd52a198c4a5c4b3fd9..7ee35255f85137ed00c1de4ec48b8b05375e950d 100644 (file)
@@ -70,12 +70,18 @@ bool Inkscape::GuideSnapper::ThisSnapperMightSnap() const
        return (_snap_enabled && _snapmanager->snapprefs.getSnapToGuides() && _snapmanager->getNamedView()->showguides);
 }
 
-void Inkscape::GuideSnapper::_addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, SnapTargetType const &target, Geom::Point const normal_to_line, Geom::Point const point_on_line) const
+void Inkscape::GuideSnapper::_addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, Geom::Point const normal_to_line, Geom::Point const point_on_line) const
 {
-    SnappedLine dummy = SnappedLine(snapped_point, snapped_distance, source, target, getSnapperTolerance(), getSnapperAlwaysSnap(), normal_to_line, point_on_line);
+    SnappedLine dummy = SnappedLine(snapped_point, snapped_distance, source, Inkscape::SNAPTARGET_GUIDE, getSnapperTolerance(), getSnapperAlwaysSnap(), normal_to_line, point_on_line);
     sc.guide_lines.push_back(dummy);
 }
 
+void Inkscape::GuideSnapper::_addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source) const
+{
+       SnappedPoint dummy = SnappedPoint(snapped_point, source, Inkscape::SNAPTARGET_GUIDE, snapped_distance, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
+       sc.points.push_back(dummy);
+}
+
 /*
   Local Variables:
   mode:c++
index 8b59194e8f2db39d9aea393ca9e93bf6a1a2611d..239e8b050ed69977f6d9880bf61d56ccb409519a 100644 (file)
@@ -36,7 +36,8 @@ public:
 
 private:
     LineList _getSnapLines(Geom::Point const &p) const;
-    void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance,  SnapSourceType const &source, SnapTargetType const &target, Geom::Point const normal_to_line, Geom::Point const point_on_line) const;
+    void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance,  SnapSourceType const &source, Geom::Point const normal_to_line, Geom::Point const point_on_line) const;
+    void _addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source) const;
 };
 
 }
index df58d356a1f20cbce3a9ba4064e02a39d5e6426d..4225dd9e3b19eb15292f8865bc967e527ce6db3a 100644 (file)
@@ -97,6 +97,18 @@ KnotHolderEntity::snap_knot_position(Geom::Point const &p)
     return s * i2d.inverse();
 }
 
+Geom::Point
+KnotHolderEntity::snap_knot_position_constrained(Geom::Point const &p, Inkscape::Snapper::ConstraintLine const &constraint)
+{
+    Geom::Matrix const i2d (sp_item_i2d_affine(item));
+    Geom::Point s = p * i2d;
+    Inkscape::Snapper::ConstraintLine transformed_constraint = Inkscape::Snapper::ConstraintLine(constraint.getPoint() * i2d, (constraint.getPoint() + constraint.getDirection()) * i2d - constraint.getPoint() * i2d);
+    SnapManager &m = desktop->namedview->snap_manager;
+    m.setup(desktop, true, item);
+    m.constrainedSnapReturnByRef(Inkscape::SnapPreferences::SNAPPOINT_NODE, s, Inkscape::SNAPSOURCE_HANDLE, transformed_constraint);
+    return s * i2d.inverse();
+}
+
 
 /* Pattern manipulation */
 
index 1f5ea8e2c98330a38e1a53848e45da5af4c91e1e..c8fd29ddf3dc15fc97e0c19b877eb5a93f30cfad 100644 (file)
@@ -1,9 +1,9 @@
 #ifndef SEEN_KNOT_HOLDER_ENTITY_H
 #define SEEN_KNOT_HOLDER_ENTITY_H
 
-/** \file 
- * KnotHolderEntity definition. 
- * 
+/** \file
+ * KnotHolderEntity definition.
+ *
  * Authors:
  *   Mitsuru Oka <oka326@parkcity.ne.jp>
  *   Maximilian Albert <maximilian.albert@gmail.com>
@@ -20,6 +20,7 @@
 #include <glib/gtypes.h>
 #include "knot.h"
 #include <2geom/forward.h>
+#include "snapper.h"
 
 struct SPItem;
 struct SPKnot;
@@ -36,7 +37,7 @@ class KnotHolderEntity {
 public:
     KnotHolderEntity() {}
     virtual ~KnotHolderEntity();
-    virtual void create(SPDesktop *desktop, SPItem *item, KnotHolder *parent, const gchar *tip = "", 
+    virtual void create(SPDesktop *desktop, SPItem *item, KnotHolder *parent, const gchar *tip = "",
                         SPKnotShapeType shape = SP_KNOT_SHAPE_DIAMOND,
                         SPKnotModeType mode = SP_KNOT_MODE_XOR,
                         guint32 color = 0xffffff00);
@@ -57,6 +58,7 @@ public:
 
 //private:
     Geom::Point snap_knot_position(Geom::Point const &p);
+    Geom::Point snap_knot_position_constrained(Geom::Point const &p, Inkscape::Snapper::ConstraintLine const &constraint);
 
     SPKnot *knot;
     SPItem *item;
index d751993dda940d8c9d84a4b560d36495470f1277..72a6cc33d54d5a7b1a2b784bbbf16732abd6e823 100644 (file)
@@ -51,8 +51,7 @@ void Inkscape::LineSnapper::freeSnap(SnappedConstraints &sc,
         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, source_type, Inkscape::SNAPTARGET_UNDEFINED, i->first, i->second);
-            // We don't know if we're snapping to grids or guides here; therefore the snap target type will be set in findBestSnap()
+            _addSnappedLine(sc, p_proj, dist, source_type, i->first, i->second);
             // std::cout << " -> distance = " << dist;
         }
         // std::cout << std::endl;
@@ -100,7 +99,7 @@ void Inkscape::LineSnapper::constrainedSnap(SnappedConstraints &sc,
                     // This snappoint is therefore fully constrained, so there's no need
                     // to look for additional intersections; just return the snapped point
                     // and forget about the line
-                    sc.points.push_back(SnappedPoint(t, source_type, Inkscape::SNAPTARGET_UNDEFINED, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true));
+                    _addSnappedPoint(sc, t, dist, source_type);
                 }
             }
         }
index 3a7ed6aae23b59331858b494b950e51bfc4531d9..4c971d23817500634e9e10cb98aa83c819058b1d 100644 (file)
@@ -54,7 +54,8 @@ private:
    */
   virtual LineList _getSnapLines(Geom::Point const &p) const = 0;
 
-  virtual void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, SnapTargetType const &target, Geom::Point const normal_to_line, Geom::Point const point_on_line) const = 0;
+  virtual void _addSnappedLine(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source, Geom::Point const normal_to_line, Geom::Point const point_on_line) const = 0;
+  virtual void _addSnappedPoint(SnappedConstraints &sc, Geom::Point const snapped_point, Geom::Coord const snapped_distance, SnapSourceType const &source) const = 0;
 };
 
 }
index a9cf202983efc0b39492c7fb80b4b02f11400b69..0719a59d319e2f2fc30cb7bd877356f5d66a19e5 100644 (file)
@@ -141,14 +141,15 @@ RectKnotHolderEntityRX::knot_set(Geom::Point const &p, Geom::Point const &/*orig
     //In general we cannot just snap this radius to an arbitrary point, as we have only a single
     //degree of freedom. For snapping to an arbitrary point we need two DOF. If we're going to snap
     //the radius then we should have a constrained snap. snap_knot_position() is unconstrained
+    Geom::Point const s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed), Geom::Point(-1, 0)));
 
     if (state & GDK_CONTROL_MASK) {
         gdouble temp = MIN(rect->height.computed, rect->width.computed) / 2.0;
-        rect->rx.computed = rect->ry.computed = CLAMP(rect->x.computed + rect->width.computed - p[Geom::X], 0.0, temp);
+        rect->rx.computed = rect->ry.computed = CLAMP(rect->x.computed + rect->width.computed - s[Geom::X], 0.0, temp);
         rect->rx._set = rect->ry._set = true;
 
     } else {
-        rect->rx.computed = CLAMP(rect->x.computed + rect->width.computed - p[Geom::X], 0.0, rect->width.computed / 2.0);
+        rect->rx.computed = CLAMP(rect->x.computed + rect->width.computed - s[Geom::X], 0.0, rect->width.computed / 2.0);
         rect->rx._set = true;
     }
 
@@ -190,18 +191,20 @@ RectKnotHolderEntityRY::knot_set(Geom::Point const &p, Geom::Point const &/*orig
     //In general we cannot just snap this radius to an arbitrary point, as we have only a single
     //degree of freedom. For snapping to an arbitrary point we need two DOF. If we're going to snap
     //the radius then we should have a constrained snap. snap_knot_position() is unconstrained
+    Geom::Point const s = snap_knot_position_constrained(p, Inkscape::Snapper::ConstraintLine(Geom::Point(rect->x.computed + rect->width.computed, rect->y.computed), Geom::Point(0, 1)));
 
-    if (state & GDK_CONTROL_MASK) {
+    if (state & GDK_CONTROL_MASK) { // When holding control then rx will be kept equal to ry,
+                                   // resulting in a perfect circle (and not an ellipse)
         gdouble temp = MIN(rect->height.computed, rect->width.computed) / 2.0;
-        rect->rx.computed = rect->ry.computed = CLAMP(p[Geom::Y] - rect->y.computed, 0.0, temp);
+        rect->rx.computed = rect->ry.computed = CLAMP(s[Geom::Y] - rect->y.computed, 0.0, temp);
         rect->ry._set = rect->rx._set = true;
     } else {
         if (!rect->rx._set || rect->rx.computed == 0) {
-            rect->ry.computed = CLAMP(p[Geom::Y] - rect->y.computed,
+            rect->ry.computed = CLAMP(s[Geom::Y] - rect->y.computed,
                                       0.0,
                                       MIN(rect->height.computed / 2.0, rect->width.computed / 2.0));
         } else {
-            rect->ry.computed = CLAMP(p[Geom::Y] - rect->y.computed,
+            rect->ry.computed = CLAMP(s[Geom::Y] - rect->y.computed,
                                       0.0,
                                       rect->height.computed / 2.0);
         }
index f6dceedba7e8fe6c46e759246c555445c5184f0c..130742483313d09eb4c2148ef98cdcf2a9708231 100644 (file)
@@ -814,14 +814,12 @@ Inkscape::SnappedPoint SnapManager::findBestSnap(Geom::Point const &p, Inkscape:
     // search for the closest snapped grid line
     Inkscape::SnappedLine closestGridLine;
     if (getClosestSL(sc.grid_lines, closestGridLine)) {
-        closestGridLine.setTarget(Inkscape::SNAPTARGET_GRID);
         sp_list.push_back(Inkscape::SnappedPoint(closestGridLine));
     }
 
     // search for the closest snapped guide line
     Inkscape::SnappedLine closestGuideLine;
     if (getClosestSL(sc.guide_lines, closestGuideLine)) {
-        closestGuideLine.setTarget(Inkscape::SNAPTARGET_GUIDE);
         sp_list.push_back(Inkscape::SnappedPoint(closestGuideLine));
     }
 
index c0209c09d24850a82ad178c03995be98f44d6894..4f27c3be09a9766e4569d372665ffb4608cb4314 100644 (file)
@@ -99,7 +99,7 @@ public:
     void getPoint(Geom::Point &p) const;
 
     /* This method however always returns a point, even if no snapping
-     * has occured; A check should be implemented in the calling code
+     * has occurred; A check should be implemented in the calling code
      * to check for snapping. Use this method only when really needed, e.g.
      * when the calling code is trying to snap multiple points and must
      * determine itself which point is most appropriate