summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDiederik van Lierop <mail@diedenrezi.nl>2008-08-08 22:28:49 +0000
committerdvlierop2 <dvlierop2@users.sourceforge.net>2008-08-08 22:28:49 +0000
commitef22647ff7f24ab39aac0020f01187587364dae0 (patch)
treeeac1d153a371f342562f63b8f05ed3329b7a2421 /src
parentfix marker behavior for moveto-only paths (diff)
downloadinkscape-ef22647ff7f24ab39aac0020f01187587364dae0.tar.gz
inkscape-ef22647ff7f24ab39aac0020f01187587364dae0.zip
Snap to intersections of any kind of path (were we previously only could snap to intersections of line-segments)
(bzr r6597)
Diffstat (limited to 'src')
-rw-r--r--src/attributes-test.h2
-rw-r--r--src/attributes.cpp2
-rw-r--r--src/attributes.h2
-rw-r--r--src/object-snapper.cpp33
-rw-r--r--src/snap.cpp19
-rw-r--r--src/snap.h6
-rw-r--r--src/snapped-curve.cpp146
-rw-r--r--src/snapped-curve.h55
-rw-r--r--src/snapper.h2
-rw-r--r--src/sp-namedview.cpp6
-rw-r--r--src/ui/dialog/document-properties.cpp6
11 files changed, 233 insertions, 46 deletions
diff --git a/src/attributes-test.h b/src/attributes-test.h
index c8287f769..25167e75b 100644
--- a/src/attributes-test.h
+++ b/src/attributes-test.h
@@ -353,7 +353,7 @@ struct {char const *attr; bool supported;} const all_attrs[] = {
{"inkscape:snap-guide", true},
{"inkscape:snap-center", true},
{"inkscape:snap-intersection-grid-guide", true},
- {"inkscape:snap-intersection-line-segments", true},
+ {"inkscape:snap-intersection-paths", true},
{"inkscape:pageopacity", true},
{"inkscape:pageshadow", true},
{"inkscape:transform-center-x", true},
diff --git a/src/attributes.cpp b/src/attributes.cpp
index c67144692..e64cedf36 100644
--- a/src/attributes.cpp
+++ b/src/attributes.cpp
@@ -93,7 +93,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_INTERS_GRIDGUIDE, "inkscape:snap-intersection-grid-guide"},
- {SP_ATTR_INKSCAPE_SNAP_INTERS_LINESEGM, "inkscape:snap-intersection-line-segments"},
+ {SP_ATTR_INKSCAPE_SNAP_INTERS_PATHS, "inkscape:snap-intersection-paths"},
{SP_ATTR_INKSCAPE_OBJECT_PATHS, "inkscape:object-paths"},
{SP_ATTR_INKSCAPE_OBJECT_NODES, "inkscape:object-nodes"},
{SP_ATTR_INKSCAPE_BBOX_PATHS, "inkscape:bbox-paths"},
diff --git a/src/attributes.h b/src/attributes.h
index c1c4dcadc..82fba18a9 100644
--- a/src/attributes.h
+++ b/src/attributes.h
@@ -93,7 +93,7 @@ enum SPAttributeEnum {
SP_ATTR_INKSCAPE_SNAP_GUIDE,
SP_ATTR_INKSCAPE_SNAP_CENTER,
SP_ATTR_INKSCAPE_SNAP_INTERS_GRIDGUIDE,
- SP_ATTR_INKSCAPE_SNAP_INTERS_LINESEGM,
+ SP_ATTR_INKSCAPE_SNAP_INTERS_PATHS,
SP_ATTR_INKSCAPE_OBJECT_PATHS,
SP_ATTR_INKSCAPE_OBJECT_NODES,
SP_ATTR_INKSCAPE_BBOX_PATHS,
diff --git a/src/object-snapper.cpp b/src/object-snapper.cpp
index 3bebc7b22..a3f7383db 100644
--- a/src/object-snapper.cpp
+++ b/src/object-snapper.cpp
@@ -416,6 +416,11 @@ void Inkscape::ObjectSnapper::_snapPaths(SnappedConstraints &sc,
/* FIXME: this seems like a hack. Perhaps Snappers should be
** in SPDesktop rather than SPNamedView?
*/
+ // TODO Diederik: shouldn't we just make all snapping code use document
+ // coordinates instead? Then we won't need a pointer to the desktop any longer
+ // At least we should define a clear boundary between those different coordinates,
+ // now this is not well defined
+
SPDesktop const *desktop = SP_ACTIVE_DESKTOP;
Geom::Point const p_doc = desktop->dt2doc(p);
@@ -441,10 +446,7 @@ 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());
-
//if true then this pathvector it_pv is currently being edited in the node tool
- SnappedPoint s;
- bool success = false;
// char * svgd = sp_svg_write_path(**it_p);
// std::cout << "Dumping the pathvector: " << svgd << std::endl;
@@ -486,31 +488,12 @@ void Inkscape::ObjectSnapper::_snapPaths(SnappedConstraints &sc,
NR::Coord const dist = Geom::distance(sp_doc, p_doc);
if (dist < getSnapperTolerance()) {
double t = MIN(*np, (*it_pv).size()); // make sure that t is within bounds;
- //Geom::Curve const & curve = (*it_pv).at_index(int(t));
- if(is_straight_curve((*it_pv).at_index(int(t)))) {
- // if we snap to a line segment, then return this line segment (leaves 1 DOF for snapping)
- sc.lines.push_back(Inkscape::SnappedLineSegment(sp_dt, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), start_pt, end_pt));
- } else {
- // for curves other than line segments, we'll return just the closest snapped point
- // (this is a fully constrained snap, no degrees of freedom left)
- if (dist < s.getDistance()) {
- // If this curve has multiple segments, then we will return only
- // a single snapped point
- s = SnappedPoint(sp_dt, SNAPTARGET_PATH, dist, getSnapperTolerance(), getSnapperAlwaysSnap());
- success = true;
- }
- }
+ Geom::Curve const *curve = &((*it_pv).at_index(int(t)));
+ sc.curves.push_back(Inkscape::SnappedCurve(from_2geom(sp_dt), dist, getSnapperTolerance(), getSnapperAlwaysSnap(), curve));
}
}
}
- } // End of: for (Geom::PathVector::iterator ....)
-
- // Return a snap point for each path in our collection.
- // (unless we've already snapped to a line segment, see above)
- if (success) {
- sc.points.push_back(s);
- }
-
+ } // End of: for (Geom::PathVector::iterator ....)
}
}
diff --git a/src/snap.cpp b/src/snap.cpp
index 9c9a69a98..778294711 100644
--- a/src/snap.cpp
+++ b/src/snap.cpp
@@ -23,6 +23,7 @@
#include "sp-namedview.h"
#include "snap.h"
#include "snapped-line.h"
+#include "snapped-curve.h"
#include <libnr/nr-point-fns.h>
#include <libnr/nr-scale-ops.h>
@@ -785,17 +786,17 @@ Inkscape::SnappedPoint SnapManager::findBestSnap(NR::Point const &p, SnappedCons
sp_list.push_back(closestPoint);
}
- // search for the closest snapped line segment
- Inkscape::SnappedLineSegment closestLineSegment;
- if (getClosestSLS(sc.lines, closestLineSegment)) {
- sp_list.push_back(Inkscape::SnappedPoint(closestLineSegment));
+ // search for the closest snapped curve
+ Inkscape::SnappedCurve closestCurve;
+ if (getClosestCurve(sc.curves, closestCurve)) {
+ sp_list.push_back(Inkscape::SnappedPoint(closestCurve));
}
- if (_intersectionLS) {
- // search for the closest snapped intersection of line segments
- Inkscape::SnappedPoint closestLineSegmentIntersection;
- if (getClosestIntersectionSLS(sc.lines, closestLineSegmentIntersection)) {
- sp_list.push_back(closestLineSegmentIntersection);
+ if (_intersectionCS) {
+ // search for the closest snapped intersection of curves
+ Inkscape::SnappedPoint closestCurvesIntersection;
+ if (getClosestIntersectionCS(sc.curves, p, closestCurvesIntersection)) {
+ sp_list.push_back(closestCurvesIntersection);
}
}
diff --git a/src/snap.h b/src/snap.h
index 981e91ecd..2ed786a63 100644
--- a/src/snap.h
+++ b/src/snap.h
@@ -127,9 +127,9 @@ public:
bool getSnapModeGuide() const;
void setSnapIntersectionGG(bool enabled) {_intersectionGG = enabled;}
- void setSnapIntersectionLS(bool enabled) {_intersectionLS = enabled;}
+ void setSnapIntersectionCS(bool enabled) {_intersectionCS = enabled;}
bool getSnapIntersectionGG() {return _intersectionGG;}
- bool getSnapIntersectionLS() {return _intersectionLS;}
+ bool getSnapIntersectionCS() {return _intersectionCS;}
void setIncludeItemCenter(bool enabled) {
_include_item_center = enabled;
@@ -167,7 +167,7 @@ private:
bool _include_item_center; //If true, snapping nodes will also snap the item's center
bool _intersectionGG;
- bool _intersectionLS;
+ bool _intersectionCS;
bool _snap_enabled_globally; //Toggles ALL snapping
std::vector<SPItem const *> *_items_to_ignore;
diff --git a/src/snapped-curve.cpp b/src/snapped-curve.cpp
new file mode 100644
index 000000000..c6b7edc8a
--- /dev/null
+++ b/src/snapped-curve.cpp
@@ -0,0 +1,146 @@
+/**
+ * \file src/snapped-curve.cpp
+ * \brief SnappedCurve class.
+ *
+ * Authors:
+ * Diederik van Lierop <mail@diedenrezi.nl>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information.
+ */
+
+#include "snapped-curve.h"
+#include "libnr/nr-values.h"
+#include <2geom/crossing.h>
+#include <2geom/path-intersection.h>
+#include <libnr/nr-convert2geom.h>
+
+// These two are needed for SP_ACTIVE_DESKTOP; this is a dirty hack
+#include "desktop.h"
+#include "inkscape.h"
+
+Inkscape::SnappedCurve::SnappedCurve(NR::Point const &snapped_point, NR::Coord const &snapped_distance, NR::Coord const &snapped_tolerance, bool const &always_snap, Geom::Curve const *curve)
+{
+ _distance = snapped_distance;
+ _tolerance = snapped_tolerance;
+ _always_snap = always_snap;
+ _curve = curve;
+ _second_distance = NR_HUGE;
+ _second_tolerance = 0;
+ _second_always_snap = false;
+ _point = snapped_point;
+ _at_intersection = false;
+}
+
+Inkscape::SnappedCurve::SnappedCurve()
+{
+ _distance = NR_HUGE;
+ _tolerance = 0;
+ _always_snap = false;
+ _curve = NULL;
+ _second_distance = NR_HUGE;
+ _second_tolerance = 0;
+ _second_always_snap = false;
+ _point = NR::Point(0,0);
+ _at_intersection = false;
+}
+
+Inkscape::SnappedCurve::~SnappedCurve()
+{
+}
+
+Inkscape::SnappedPoint Inkscape::SnappedCurve::intersect(SnappedCurve const &curve, NR::Point const &p) const
+{
+ // Calculate the intersections of two curves, which are both within snapping range, and
+ // return only the closest intersection
+ // The point of intersection should be considered for snapping, but might be outside the snapping range
+ // PS: We need p (the location of the mouse pointer) for find out which intersection is the
+ // closest, as there might be multiple intersections of two curves
+ Geom::SimpleCrosser xr;
+ Geom::Crossings cs = xr.crossings(*(this->_curve), *(curve._curve));
+
+ if (cs.size() > 0) {
+ // 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++) {
+ Geom::Point p_ix = this->_curve->pointAt((*i).ta);
+ Geom::Coord dist = Geom::distance(p_ix, p);
+ if (dist < best_dist) {
+ best_dist = dist;
+ best_p = p_ix;
+ }
+ }
+
+ // Now we've found the closests intersection, return it as a SnappedPoint
+ bool const use_this_as_primary = _distance < curve.getDistance();
+ Inkscape::SnappedCurve const *primaryC = use_this_as_primary ? this : &curve;
+ Inkscape::SnappedCurve const *secondaryC = use_this_as_primary ? &curve : this;
+ // The intersection should in fact be returned in desktop coordinates, but for this
+ // we need a desktop: this is a dirty hack
+ SPDesktop const *desktop = SP_ACTIVE_DESKTOP;
+ best_p = desktop->dt2doc(best_p);
+ // TODO: Investigate whether it is possible to use document coordinates everywhere
+ // in the snapper code. Only the mouse position should be in desktop coordinates, I guess.
+ // All paths are already in document coords and we are certainly not going to change THAT.
+ return SnappedPoint(from_2geom(best_p), Inkscape::SNAPTARGET_PATH_INTERSECTION, primaryC->getDistance(), primaryC->getTolerance(), primaryC->getAlwaysSnap(), true,
+ secondaryC->getDistance(), secondaryC->getTolerance(), secondaryC->getAlwaysSnap());
+ }
+
+ // No intersection
+ return SnappedPoint(NR::Point(NR_HUGE, NR_HUGE), SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, NR_HUGE, 0, false);
+}
+
+// search for the closest snapped line
+bool getClosestCurve(std::list<Inkscape::SnappedCurve> const &list, Inkscape::SnappedCurve &result)
+{
+ bool success = false;
+
+ for (std::list<Inkscape::SnappedCurve>::const_iterator i = list.begin(); i != list.end(); i++) {
+ if ((i == list.begin()) || (*i).getDistance() < result.getDistance()) {
+ result = *i;
+ success = true;
+ }
+ }
+
+ return success;
+}
+
+// search for the closest intersection of two snapped curves, which are both member of the same collection
+bool getClosestIntersectionCS(std::list<Inkscape::SnappedCurve> const &list, NR::Point const &p, Inkscape::SnappedPoint &result)
+{
+ bool success = false;
+
+ for (std::list<Inkscape::SnappedCurve>::const_iterator i = list.begin(); i != list.end(); i++) {
+ std::list<Inkscape::SnappedCurve>::const_iterator j = i;
+ j++;
+ for (; j != list.end(); j++) {
+ Inkscape::SnappedPoint sp = (*i).intersect(*j, p);
+ if (sp.getAtIntersection()) {
+ // if it's the first point
+ bool const c1 = !success;
+ // or, if it's closer
+ bool const c2 = sp.getDistance() < result.getDistance();
+ // or, if it's just then look at the other distance
+ // (only relevant for snapped points which are at an intersection
+ bool const c3 = (sp.getDistance() == result.getDistance()) && (sp.getSecondDistance() < result.getSecondDistance());
+ // then prefer this point over the previous one
+ if (c1 || c2 || c3) {
+ result = sp;
+ success = true;
+ }
+ }
+ }
+ }
+
+ return success;
+}
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/snapped-curve.h b/src/snapped-curve.h
new file mode 100644
index 000000000..28908c42f
--- /dev/null
+++ b/src/snapped-curve.h
@@ -0,0 +1,55 @@
+#ifndef SEEN_SNAPPEDCURVE_H
+#define SEEN_SNAPPEDCURVE_H
+
+/**
+ * \file src/snapped-curve.h
+ * \brief SnappedCurve class.
+ *
+ * Authors:
+ * Diederik van Lierop <mail@diedenrezi.nl>
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information.
+ */
+
+#include <vector>
+#include <list>
+#include "libnr/nr-coord.h"
+#include "libnr/nr-point.h"
+#include <libnr/nr-point-fns.h>
+#include "snapped-point.h"
+#include <2geom/forward.h>
+
+namespace Inkscape
+{
+
+/// Class describing the result of an attempt to snap to a curve.
+class SnappedCurve : public SnappedPoint
+{
+public:
+ SnappedCurve();
+ SnappedCurve(NR::Point const &snapped_point, NR::Coord const &snapped_distance, NR::Coord const &snapped_tolerance, bool const &always_snap, Geom::Curve const *curve);
+ ~SnappedCurve();
+ Inkscape::SnappedPoint intersect(SnappedCurve const &curve, NR::Point const &p) const; //intersect with another SnappedCurve
+
+private:
+ Geom::Curve const *_curve;
+};
+
+}
+
+bool getClosestCurve(std::list<Inkscape::SnappedCurve> const &list, Inkscape::SnappedCurve &result);
+bool getClosestIntersectionCS(std::list<Inkscape::SnappedCurve> const &list, NR::Point const &p, Inkscape::SnappedPoint &result);
+
+
+#endif /* !SEEN_SNAPPEDCURVE_H */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/snapper.h b/src/snapper.h
index cf2732b24..a63ea14c5 100644
--- a/src/snapper.h
+++ b/src/snapper.h
@@ -20,12 +20,14 @@
#include "snapped-point.h"
#include "snapped-line.h"
+#include "snapped-curve.h"
struct SnappedConstraints {
std::list<Inkscape::SnappedPoint> points;
std::list<Inkscape::SnappedLineSegment> lines;
std::list<Inkscape::SnappedLine> grid_lines;
std::list<Inkscape::SnappedLine> guide_lines;
+ std::list<Inkscape::SnappedCurve> curves;
};
struct SPNamedView;
diff --git a/src/sp-namedview.cpp b/src/sp-namedview.cpp
index 7caa9407c..7783c334d 100644
--- a/src/sp-namedview.cpp
+++ b/src/sp-namedview.cpp
@@ -252,7 +252,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-intersection-grid-guide");
- sp_object_read_attr(object, "inkscape:snap-intersection-line-segments");
+ sp_object_read_attr(object, "inkscape:snap-intersection-paths");
sp_object_read_attr(object, "inkscape:object-paths");
sp_object_read_attr(object, "inkscape:object-nodes");
sp_object_read_attr(object, "inkscape:bbox-paths");
@@ -481,8 +481,8 @@ static void sp_namedview_set(SPObject *object, unsigned int key, const gchar *va
nv->snap_manager.setSnapIntersectionGG(value ? sp_str_to_bool(value) : TRUE);
object->requestModified(SP_OBJECT_MODIFIED_FLAG);
break;
- case SP_ATTR_INKSCAPE_SNAP_INTERS_LINESEGM:
- nv->snap_manager.setSnapIntersectionLS(value ? sp_str_to_bool(value) : FALSE);
+ case SP_ATTR_INKSCAPE_SNAP_INTERS_PATHS:
+ nv->snap_manager.setSnapIntersectionCS(value ? sp_str_to_bool(value) : FALSE);
object->requestModified(SP_OBJECT_MODIFIED_FLAG);
break;
case SP_ATTR_INKSCAPE_OBJECT_PATHS:
diff --git a/src/ui/dialog/document-properties.cpp b/src/ui/dialog/document-properties.cpp
index 519f795db..a69e8858f 100644
--- a/src/ui/dialog/document-properties.cpp
+++ b/src/ui/dialog/document-properties.cpp
@@ -116,8 +116,8 @@ 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),
_rcbsigg(_("_Grid with guides"), _("Snap to grid-guide intersections"), "inkscape:snap-intersection-grid-guide", _wr),
- _rcbsils(_("_Line segments"), _("Snap to intersections of line segments ('snap to paths' must be enabled, see the previous tab)"),
- "inkscape:snap-intersection-line-segments", _wr),
+ _rcbsils(_("_Paths"), _("Snap to intersections of paths ('snap to paths' must be enabled, see the previous tab)"),
+ "inkscape:snap-intersection-paths", _wr),
//---------------------------------------------------------------
_grids_label_crea("", Gtk::ALIGN_LEFT),
//TRANSLATORS: In Grid|_New translate only the word _New. It ref to grid
@@ -495,7 +495,7 @@ DocumentProperties::update()
_rcbsng.setActive (nv->snap_manager.getSnapModeGuide());
_rcbic.setActive (nv->snap_manager.getIncludeItemCenter());
_rcbsigg.setActive (nv->snap_manager.getSnapIntersectionGG());
- _rcbsils.setActive (nv->snap_manager.getSnapIntersectionLS());
+ _rcbsils.setActive (nv->snap_manager.getSnapIntersectionCS());
_rcbsnop.setActive(nv->snap_manager.object.getSnapToItemPath());
_rcbsnon.setActive(nv->snap_manager.object.getSnapToItemNode());
_rcbsnbbp.setActive(nv->snap_manager.object.getSnapToBBoxPath());