summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 3f4648e)
raw | patch | inline | side by side (parent: 3f4648e)
author | dvlierop2 <dvlierop2@users.sourceforge.net> | |
Sun, 21 Sep 2008 20:18:04 +0000 (20:18 +0000) | ||
committer | dvlierop2 <dvlierop2@users.sourceforge.net> | |
Sun, 21 Sep 2008 20:18:04 +0000 (20:18 +0000) |
- fix snapping to page corners
diff --git a/src/gradient-drag.cpp b/src/gradient-drag.cpp
index 1caaf1d115466a19bce60abf51d61ceb9299c0a3..9432d4b5a004d777c3d111a1271a1b950c639f49 100644 (file)
--- a/src/gradient-drag.cpp
+++ b/src/gradient-drag.cpp
@@ -593,7 +593,7 @@ gr_knot_moved_handler(SPKnot *knot, NR::Point const *ppointer, guint state, gpoi
dist = fabs(p[NR::Y] - dragger->parent->hor_levels[i]);
if (dist < snap_dist) {
p[NR::Y] = dragger->parent->hor_levels[i];
- s = Inkscape::SnappedPoint(p, Inkscape::SNAPTARGET_GRADIENT, dist, snap_dist, false);
+ s = Inkscape::SnappedPoint(p, Inkscape::SNAPTARGET_GRADIENT, dist, snap_dist, false, false);
was_snapped = true;
sp_knot_moveto (knot, p);
}
@@ -602,7 +602,7 @@ gr_knot_moved_handler(SPKnot *knot, NR::Point const *ppointer, guint state, gpoi
dist = fabs(p[NR::X] - dragger->parent->vert_levels[i]);
if (dist < snap_dist) {
p[NR::X] = dragger->parent->vert_levels[i];
- s = Inkscape::SnappedPoint(p, Inkscape::SNAPTARGET_GRADIENT, dist, snap_dist, false);
+ s = Inkscape::SnappedPoint(p, Inkscape::SNAPTARGET_GRADIENT, dist, snap_dist, false, false);
was_snapped = true;
sp_knot_moveto (knot, p);
}
diff --git a/src/line-snapper.cpp b/src/line-snapper.cpp
index 5453c1cf27bc5d71140909251f71491785f9be70..b2934c2e39ad058e328ea40c5bee9d0e43aa4d91 100644 (file)
--- a/src/line-snapper.cpp
+++ b/src/line-snapper.cpp
// 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, Inkscape::SNAPTARGET_UNDEFINED, dist, getSnapperTolerance(), getSnapperAlwaysSnap()));
+ 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
}
diff --git a/src/object-snapper.cpp b/src/object-snapper.cpp
index 41866b41ca4c1cd0e076389e5c9704bddc3bd685..13fba80609a287a28d96c379d4437ef04caa49e2 100644 (file)
--- a/src/object-snapper.cpp
+++ b/src/object-snapper.cpp
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)) {
+ if (SP_IS_ITEM(o) && !SP_ITEM(o)->isLocked() && !(_snapmanager->getDesktop()->itemIsHidden(SP_ITEM(o)) && !clip_or_mask)) {
// Don't snap to locked items, and
// don't snap to hidden objects, unless they're a clipped path or a mask
/* See if this item is on the ignore list */
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);
if (dist < getSnapperTolerance() && dist < s.getDistance()) {
- s = SnappedPoint(*k, SNAPTARGET_NODE, dist, getSnapperTolerance(), getSnapperAlwaysSnap());
+ s = SnappedPoint(*k, SNAPTARGET_NODE, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
success = true;
}
}
@@ -278,7 +278,7 @@ void Inkscape::ObjectSnapper::_snapTranslatingGuideToNodes(SnappedConstraints &s
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.getDistance()) {
- s = SnappedPoint(*k, SNAPTARGET_NODE, dist, tol, getSnapperAlwaysSnap());
+ s = SnappedPoint(*k, SNAPTARGET_NODE, dist, tol, getSnapperAlwaysSnap(), true);
success = true;
}
}
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;
+ Geom::Curve const *curve = &((*it_pv).at_index(index));
+ Geom::Point const sp_doc = curve->pointAt(*np);
+
+ bool c1 = 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
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(), curve));
+ sc.curves.push_back(Inkscape::SnappedCurve(from_2geom(sp_dt), dist, getSnapperTolerance(), getSnapperAlwaysSnap(), false, curve));
}
}
}
// 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)
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());
+ SnappedPoint s(_snapmanager->getDesktop()->doc2dt(p_inters), SNAPTARGET_PATH, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true);
sc.points.push_back(s);
}
}
diff --git a/src/snap.cpp b/src/snap.cpp
index c4ed536e54d86ee7d11da1784326bec0e3e00f2b..394bc7f912bb6ba5b2ea524481806b1eaceee763 100644 (file)
--- a/src/snap.cpp
+++ b/src/snap.cpp
@@ -206,7 +206,7 @@ Inkscape::SnappedPoint SnapManager::freeSnap(Inkscape::Snapper::PointType point_
boost::optional<Geom::Rect> const &bbox_to_snap) const
{
if (!SomeSnapperMightSnap()) {
- return Inkscape::SnappedPoint(p, Inkscape::SNAPTARGET_UNDEFINED, NR_HUGE, 0, false);
+ return Inkscape::SnappedPoint(p, Inkscape::SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false);
}
std::vector<SPItem const *> *items_to_ignore;
@@ -328,7 +328,7 @@ Inkscape::SnappedPoint SnapManager::constrainedSnap(Inkscape::Snapper::PointType
boost::optional<Geom::Rect> const &bbox_to_snap) const
{
if (!SomeSnapperMightSnap()) {
- return Inkscape::SnappedPoint(p, Inkscape::SNAPTARGET_UNDEFINED, NR_HUGE, 0, false);
+ return Inkscape::SnappedPoint(p, Inkscape::SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false);
}
std::vector<SPItem const *> *items_to_ignore;
/* The current best metric for the best transformation; lower is better, NR_HUGE
** means that we haven't snapped anything.
*/
- Geom::Coord best_metric = NR_HUGE;
- Geom::Coord best_second_metric = NR_HUGE;
Geom::Point best_scale_metric(NR_HUGE, NR_HUGE);
Inkscape::SnappedPoint best_snapped_point;
g_assert(best_snapped_point.getAlwaysSnap() == false); // Check initialization of snapped point
}
Geom::Point result;
- Geom::Coord metric = NR_HUGE;
- Geom::Coord second_metric = NR_HUGE;
Geom::Point scale_metric(NR_HUGE, NR_HUGE);
if (snapped_point.getSnapped()) {
* distance is defined as the distance to the nearest line of the intersection,
* and not to the intersection itself!
*/
- metric = snapped_point.getDistance(); //used to be: metric = Geom::L2(result);
- second_metric = snapped_point.getSecondDistance();
+ // Only for translations, the relevant metric will be the real snapped distance,
+ // so we don't have to do anything special here
break;
case SCALE:
{
result[dim] = result[1-dim];
}
}
- metric = std::abs(result[dim] - transformation[dim]);
+ // Store the metric for this transformation as a virtual distance
+ snapped_point.setDistance(std::abs(result[dim] - transformation[dim]));
+ snapped_point.setSecondDistance(NR_HUGE);
break;
case SKEW:
result[0] = (snapped_point.getPoint()[dim] - (*i)[dim]) / ((*i)[1 - dim] - origin[1 - dim]); // skew factor
result[1] = transformation[1]; // scale factor
- metric = std::abs(result[0] - transformation[0]);
+ // Store the metric for this transformation as a virtual distance
+ snapped_point.setDistance(std::abs(result[0] - transformation[0]));
+ snapped_point.setSecondDistance(NR_HUGE);
break;
default:
g_assert_not_reached();
}
- /* Note it if it's the best so far */
+ // When scaling, we're considering the best transformation in each direction separately. We will have a metric in each
+ // direction, whereas for all other transformation we only a single one-dimensional metric. That's why we need to handle
+ // the scaling metric differently
if (transformation_type == SCALE) {
for (int index = 0; index < 2; index++) {
if (fabs(scale_metric[index]) < fabs(best_scale_metric[index])) {
best_scale_metric[0] = best_scale_metric[1];
}
}
- best_metric = std::min(best_scale_metric[0], best_scale_metric[1]);
- // std::cout << "P_orig = " << (*i) << " | scale_metric = " << scale_metric << " | distance = " << snapped_point.getDistance() << " | P_snap = " << snapped_point.getPoint() << std::endl;
- } else {
- bool const c1 = metric < best_metric;
- bool const c2 = metric == best_metric && snapped_point.getAtIntersection() == true && best_snapped_point.getAtIntersection() == false;
- bool const c3a = metric == best_metric && snapped_point.getAtIntersection() == true && best_snapped_point.getAtIntersection() == true;
- bool const c3b = second_metric < best_second_metric;
- bool const c4 = snapped_point.getAlwaysSnap() == true && best_snapped_point.getAlwaysSnap() == false;
- bool const c4n = snapped_point.getAlwaysSnap() == false && best_snapped_point.getAlwaysSnap() == true;
-
- if ((c1 || c2 || (c3a && c3b) || c4) && !c4n) {
+ } else { // For all transformations other than scaling
+ if (best_snapped_point.isOtherOneBetter(snapped_point)) {
best_transformation = result;
- best_metric = metric;
- best_second_metric = second_metric;
- best_snapped_point = snapped_point;
- // std::cout << "SEL ";
- } // else { std::cout << " ";}
- // std::cout << "P_orig = " << (*i) << " | metric = " << metric << " | distance = " << snapped_point.getDistance() << " | second metric = " << second_metric << " | P_snap = " << snapped_point.getPoint() << std::endl;
+ best_snapped_point = snapped_point;
+ }
}
}
j++;
}
+ Geom::Coord best_metric;
if (transformation_type == SCALE) {
// When scaling, don't ever exit with one of scaling components set to NR_HUGE
for (int index = 0; index < 2; index++) {
if (best_transformation[index] == NR_HUGE) {
if (uniform && best_transformation[1-index] < NR_HUGE) {
- best_transformation[index] = best_transformation[1-index];
+ best_transformation[index] = best_transformation[1-index];
} else {
- best_transformation[index] = transformation[index];
+ best_transformation[index] = transformation[index];
}
}
}
+ best_metric = std::min(best_scale_metric[0], best_scale_metric[1]);
+ } else { // For all transformations other than scaling
+ best_metric = best_snapped_point.getDistance();
}
best_snapped_point.setTransformation(best_transformation);
@@ -769,14 +762,16 @@ Inkscape::SnappedPoint SnapManager::constrainedSnapSkew(Inkscape::Snapper::Point
Inkscape::SnappedPoint SnapManager::findBestSnap(Geom::Point const &p, SnappedConstraints &sc, bool constrained) const
{
+
/*
std::cout << "Type and number of snapped constraints: " << std::endl;
std::cout << " Points : " << sc.points.size() << std::endl;
std::cout << " Lines : " << sc.lines.size() << std::endl;
std::cout << " Grid lines : " << sc.grid_lines.size()<< std::endl;
std::cout << " Guide lines : " << sc.guide_lines.size()<< std::endl;
+ std::cout << " Curves : " << sc.curves.size()<< std::endl;
*/
-
+
// Store all snappoints
std::list<Inkscape::SnappedPoint> sp_list;
@@ -793,11 +788,11 @@ Inkscape::SnappedPoint SnapManager::findBestSnap(Geom::Point const &p, SnappedCo
}
if (_intersectionCS) {
- // search for the closest snapped intersection of curves
- Inkscape::SnappedPoint closestCurvesIntersection;
- if (getClosestIntersectionCS(sc.curves, p, closestCurvesIntersection)) {
- sp_list.push_back(closestCurvesIntersection);
- }
+ // search for the closest snapped intersection of curves
+ Inkscape::SnappedPoint closestCurvesIntersection;
+ if (getClosestIntersectionCS(sc.curves, p, closestCurvesIntersection)) {
+ sp_list.push_back(closestCurvesIntersection);
+ }
}
// search for the closest snapped grid line
@@ -837,38 +832,29 @@ Inkscape::SnappedPoint SnapManager::findBestSnap(Geom::Point const &p, SnappedCo
// search for the closest snapped intersection of grid with guide lines
if (_intersectionGG) {
- Inkscape::SnappedPoint closestGridGuidePoint;
- if (getClosestIntersectionSL(sc.grid_lines, sc.guide_lines, closestGridGuidePoint)) {
- closestGridGuidePoint.setTarget(Inkscape::SNAPTARGET_GRID_GUIDE_INTERSECTION);
+ Inkscape::SnappedPoint closestGridGuidePoint;
+ if (getClosestIntersectionSL(sc.grid_lines, sc.guide_lines, closestGridGuidePoint)) {
+ closestGridGuidePoint.setTarget(Inkscape::SNAPTARGET_GRID_GUIDE_INTERSECTION);
sp_list.push_back(closestGridGuidePoint);
- }
+ }
}
}
// now let's see which snapped point gets a thumbs up
- Inkscape::SnappedPoint bestSnappedPoint = Inkscape::SnappedPoint(p, Inkscape::SNAPTARGET_UNDEFINED, NR_HUGE, 0, false);
+ Inkscape::SnappedPoint bestSnappedPoint = Inkscape::SnappedPoint(p, Inkscape::SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false);
+ // std::cout << "Finding the best snap..." << std::endl;
for (std::list<Inkscape::SnappedPoint>::const_iterator i = sp_list.begin(); i != sp_list.end(); i++) {
- // first find out if this snapped point is within snapping range
+ // first find out if this snapped point is within snapping range
+ // std::cout << "sp = " << from_2geom((*i).getPoint());
if ((*i).getDistance() <= (*i).getTolerance()) {
- // if it's the first point
- bool c1 = (i == sp_list.begin());
- // or, if it's closer
- bool c2 = (*i).getDistance() < bestSnappedPoint.getDistance();
- // or, if it's for a snapper with "always snap" turned on, and the previous wasn't
- bool c3 = (*i).getAlwaysSnap() && !bestSnappedPoint.getAlwaysSnap();
- // But in no case fall back from a snapper with "always snap" on to one with "always snap" off
- bool c3n = !(*i).getAlwaysSnap() && bestSnappedPoint.getAlwaysSnap();
- // or, if it's just as close then consider the second distance
- // (which is only relevant for points at an intersection)
- bool c4a = ((*i).getDistance() == bestSnappedPoint.getDistance());
- bool c4b = (*i).getSecondDistance() < bestSnappedPoint.getSecondDistance();
- // then prefer this point over the previous one
- if ((c1 || c2 || c3 || (c4a && c4b)) && !c3n) {
+ // if it's the first point, or if it is closer than the best snapped point so far
+ if (i == sp_list.begin() || bestSnappedPoint.isOtherOneBetter(*i)) {
+ // then prefer this point over the previous one
bestSnappedPoint = *i;
}
}
- }
-
+ // std::cout << std::endl;
+ }
// Update the snap indicator, if requested
if (_snapindicator) {
@@ -886,7 +872,7 @@ Inkscape::SnappedPoint SnapManager::findBestSnap(Geom::Point const &p, SnappedCo
void SnapManager::setup(SPDesktop const *desktop, bool snapindicator, SPItem const *item_to_ignore, std::vector<Geom::Point> *unselected_nodes)
{
g_assert(desktop != NULL);
- _item_to_ignore = item_to_ignore;
+ _item_to_ignore = item_to_ignore;
_items_to_ignore = NULL;
_desktop = desktop;
_snapindicator = snapindicator;
@@ -895,8 +881,8 @@ void SnapManager::setup(SPDesktop const *desktop, bool snapindicator, SPItem con
void SnapManager::setup(SPDesktop const *desktop, bool snapindicator, std::vector<SPItem const *> &items_to_ignore, std::vector<Geom::Point> *unselected_nodes)
{
- g_assert(desktop != NULL);
- _item_to_ignore = NULL;
+ g_assert(desktop != NULL);
+ _item_to_ignore = NULL;
_items_to_ignore = &items_to_ignore;
_desktop = desktop;
_snapindicator = snapindicator;
@@ -905,7 +891,7 @@ void SnapManager::setup(SPDesktop const *desktop, bool snapindicator, std::vecto
SPDocument *SnapManager::getDocument() const
{
- return _named_view->document;
+ return _named_view->document;
}
/*
diff --git a/src/snapped-curve.cpp b/src/snapped-curve.cpp
index dfed84531d807e3bb23736d4f6a5bf24333dedb1..3a6512e5e0522097316d175d864565ed23aa5119 100644 (file)
--- a/src/snapped-curve.cpp
+++ b/src/snapped-curve.cpp
-/**\r
- * \file src/snapped-curve.cpp\r
- * \brief SnappedCurve class.\r
- *\r
- * Authors:\r
- * Diederik van Lierop <mail@diedenrezi.nl>\r
- *\r
- * Released under GNU GPL, read the file 'COPYING' for more information.\r
- */\r
-\r
-#include "snapped-curve.h"\r
-#include "libnr/nr-values.h"\r
-#include <2geom/crossing.h>\r
-#include <2geom/path-intersection.h>\r
-#include <libnr/nr-convert2geom.h>\r
-\r
-// These two are needed for SP_ACTIVE_DESKTOP; this is a dirty hack\r
-#include "desktop.h"\r
-#include "inkscape.h"\r
-\r
-Inkscape::SnappedCurve::SnappedCurve(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, Geom::Coord const &snapped_tolerance, bool const &always_snap, Geom::Curve const *curve)\r
-{\r
- _distance = snapped_distance;\r
- _tolerance = snapped_tolerance;\r
- _always_snap = always_snap;\r
- _curve = curve;\r
- _second_distance = NR_HUGE;\r
- _second_tolerance = 0;\r
- _second_always_snap = false;\r
- _point = snapped_point;\r
- _at_intersection = false;\r
-}\r
-\r
-Inkscape::SnappedCurve::SnappedCurve() \r
-{\r
- _distance = NR_HUGE;\r
- _tolerance = 0;\r
- _always_snap = false;\r
- _curve = NULL;\r
- _second_distance = NR_HUGE;\r
- _second_tolerance = 0;\r
- _second_always_snap = false;\r
- _point = Geom::Point(0,0);\r
- _at_intersection = false;\r
-}\r
-\r
-Inkscape::SnappedCurve::~SnappedCurve()\r
-{\r
-}\r
-\r
-Inkscape::SnappedPoint Inkscape::SnappedCurve::intersect(SnappedCurve const &curve, Geom::Point const &p) const \r
-{\r
- // Calculate the intersections of two curves, which are both within snapping range, and\r
- // return only the closest intersection\r
- // The point of intersection should be considered for snapping, but might be outside the snapping range\r
- // PS: We need p (the location of the mouse pointer) for find out which intersection is the\r
- // closest, as there might be multiple intersections of two curves\r
- Geom::Crossings cs = crossings(*(this->_curve), *(curve._curve));\r
- \r
- if (cs.size() > 0) {\r
- // There might be multiple intersections: find the closest\r
- Geom::Coord best_dist = NR_HUGE;\r
- Geom::Point best_p = Geom::Point(NR_HUGE, NR_HUGE);\r
- for (std::vector<Geom::Crossing>::const_iterator i = cs.begin(); i != cs.end(); i++) {\r
- Geom::Point p_ix = this->_curve->pointAt((*i).ta);\r
- Geom::Coord dist = Geom::distance(p_ix, p);\r
- if (dist < best_dist) {\r
- best_dist = dist;\r
- best_p = p_ix;\r
- }\r
- }\r
- \r
- // Now we've found the closests intersection, return it as a SnappedPoint\r
- bool const use_this_as_primary = _distance < curve.getDistance();\r
- Inkscape::SnappedCurve const *primaryC = use_this_as_primary ? this : &curve;\r
- Inkscape::SnappedCurve const *secondaryC = use_this_as_primary ? &curve : this;\r
- // The intersection should in fact be returned in desktop coordinates, but for this\r
- // we need a desktop: this is a dirty hack\r
- SPDesktop const *desktop = SP_ACTIVE_DESKTOP;\r
- best_p = desktop->dt2doc(best_p);\r
- // TODO: Investigate whether it is possible to use document coordinates everywhere\r
- // in the snapper code. Only the mouse position should be in desktop coordinates, I guess.\r
- // All paths are already in document coords and we are certainly not going to change THAT.\r
- return SnappedPoint(from_2geom(best_p), Inkscape::SNAPTARGET_PATH_INTERSECTION, primaryC->getDistance(), primaryC->getTolerance(), primaryC->getAlwaysSnap(), true, \r
- secondaryC->getDistance(), secondaryC->getTolerance(), secondaryC->getAlwaysSnap());\r
- }\r
- \r
- // No intersection\r
- return SnappedPoint(Geom::Point(NR_HUGE, NR_HUGE), SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, NR_HUGE, 0, false);\r
-}\r
-\r
-// search for the closest snapped line\r
-bool getClosestCurve(std::list<Inkscape::SnappedCurve> const &list, Inkscape::SnappedCurve &result) \r
-{\r
- bool success = false;\r
- \r
- for (std::list<Inkscape::SnappedCurve>::const_iterator i = list.begin(); i != list.end(); i++) {\r
- if ((i == list.begin()) || (*i).getDistance() < result.getDistance()) {\r
- result = *i;\r
- success = true;\r
- } \r
- }\r
- \r
- return success; \r
-}\r
-\r
-// search for the closest intersection of two snapped curves, which are both member of the same collection\r
-bool getClosestIntersectionCS(std::list<Inkscape::SnappedCurve> const &list, Geom::Point const &p, Inkscape::SnappedPoint &result)\r
-{\r
- bool success = false;\r
- \r
- for (std::list<Inkscape::SnappedCurve>::const_iterator i = list.begin(); i != list.end(); i++) {\r
- std::list<Inkscape::SnappedCurve>::const_iterator j = i;\r
- j++;\r
- for (; j != list.end(); j++) {\r
- Inkscape::SnappedPoint sp = (*i).intersect(*j, p);\r
- if (sp.getAtIntersection()) {\r
- // if it's the first point\r
- bool const c1 = !success;\r
- // or, if it's closer \r
- bool const c2 = sp.getDistance() < result.getDistance();\r
- // or, if it's just then look at the other distance \r
- // (only relevant for snapped points which are at an intersection\r
- bool const c3 = (sp.getDistance() == result.getDistance()) && (sp.getSecondDistance() < result.getSecondDistance()); \r
- // then prefer this point over the previous one\r
- if (c1 || c2 || c3) { \r
- result = sp;\r
- success = true;\r
- }\r
- } \r
- }\r
- }\r
- \r
- return success; \r
-}\r
-/*\r
- Local Variables:\r
- mode:c++\r
- c-file-style:"stroustrup"\r
- c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
- indent-tabs-mode:nil\r
- fill-column:99\r
- End:\r
-*/\r
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :\r
+/**
+ * \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(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, Geom::Coord const &snapped_tolerance, bool const &always_snap, bool const &fully_constrained, 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;
+ _fully_constrained = fully_constrained;
+}
+
+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 = Geom::Point(0,0);
+ _at_intersection = false;
+ _fully_constrained = false;
+}
+
+Inkscape::SnappedCurve::~SnappedCurve()
+{
+}
+
+Inkscape::SnappedPoint Inkscape::SnappedCurve::intersect(SnappedCurve const &curve, Geom::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::Crossings cs = 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, true,
+ secondaryC->getDistance(), secondaryC->getTolerance(), secondaryC->getAlwaysSnap());
+ }
+
+ // No intersection
+ return SnappedPoint(Geom::Point(NR_HUGE, NR_HUGE), SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, 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, Geom::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
index e6e71e6481dc3f906f63378e7c2d9d1a62ad933e..814777b68953c2f97470e37fb1282552ea9d4190 100644 (file)
--- a/src/snapped-curve.h
+++ b/src/snapped-curve.h
{\r
public:\r
SnappedCurve();\r
- SnappedCurve(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, Geom::Coord const &snapped_tolerance, bool const &always_snap, Geom::Curve const *curve);\r
+ SnappedCurve(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, Geom::Coord const &snapped_tolerance, bool const &always_snap, bool const &fully_constrained, Geom::Curve const *curve);\r
~SnappedCurve();\r
Inkscape::SnappedPoint intersect(SnappedCurve const &curve, Geom::Point const &p) const; //intersect with another SnappedCurve\r
\r
diff --git a/src/snapped-line.cpp b/src/snapped-line.cpp
index f35c7a81ccf1566eb9106ee47bee178491b438f2..fc2d059dca4c82e81529344d8a22346b9f0f8056 100644 (file)
--- a/src/snapped-line.cpp
+++ b/src/snapped-line.cpp
@@ -67,12 +67,12 @@ Inkscape::SnappedPoint Inkscape::SnappedLineSegment::intersect(SnappedLineSegmen
bool const use_this_as_primary = c1 || c2;
Inkscape::SnappedLineSegment const *primarySLS = use_this_as_primary ? this : &line;
Inkscape::SnappedLineSegment const *secondarySLS = use_this_as_primary ? &line : this;
- return SnappedPoint(intersection, SNAPTARGET_PATH_INTERSECTION, primarySLS->getDistance(), primarySLS->getTolerance(), primarySLS->getAlwaysSnap(), true,
+ return SnappedPoint(intersection, SNAPTARGET_PATH_INTERSECTION, primarySLS->getDistance(), primarySLS->getTolerance(), primarySLS->getAlwaysSnap(), true, true,
secondarySLS->getDistance(), secondarySLS->getTolerance(), secondarySLS->getAlwaysSnap());
}
// No intersection
- return SnappedPoint(intersection, SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, NR_HUGE, 0, false);
+ return SnappedPoint(intersection, SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, false, NR_HUGE, 0, false);
};
@@ -142,14 +142,14 @@ Inkscape::SnappedPoint Inkscape::SnappedLine::intersect(SnappedLine const &line)
bool const use_this_as_primary = c1 || c2;
Inkscape::SnappedLine const *primarySL = use_this_as_primary ? this : &line;
Inkscape::SnappedLine const *secondarySL = use_this_as_primary ? &line : this;
- return SnappedPoint(intersection, Inkscape::SNAPTARGET_UNDEFINED, primarySL->getDistance(), primarySL->getTolerance(), primarySL->getAlwaysSnap(), true,
+ return SnappedPoint(intersection, Inkscape::SNAPTARGET_UNDEFINED, primarySL->getDistance(), primarySL->getTolerance(), primarySL->getAlwaysSnap(), true, true,
secondarySL->getDistance(), secondarySL->getTolerance(), secondarySL->getAlwaysSnap());
// 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
}
// No intersection
- return SnappedPoint(intersection, SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, NR_HUGE, 0, false);
+ return SnappedPoint(intersection, SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, false, NR_HUGE, 0, false);
}
// search for the closest snapped line segment
diff --git a/src/snapped-point.cpp b/src/snapped-point.cpp
index 3a3595a809c7021c4b987e44282c6e5514772bc0..4176d4a3d40bade1cce8e966deb78259f0c62c47 100644 (file)
--- a/src/snapped-point.cpp
+++ b/src/snapped-point.cpp
#include "snapped-point.h"
// overloaded constructor
-Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a)
+Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &fully_constrained)
: _point(p), _target(target), _distance(d), _tolerance(t), _always_snap(a)
{
_at_intersection = false;
+ _fully_constrained = fully_constrained;
_second_distance = NR_HUGE;
_second_tolerance = 0;
_second_always_snap = false;
_transformation = Geom::Point(1,1);
}
-Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &at_intersection, Geom::Coord const &d2, Geom::Coord const &t2, bool const &a2)
- : _point(p), _target(target), _at_intersection(at_intersection), _distance(d), _tolerance(t), _always_snap(a),
+Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &at_intersection, bool const &fully_constrained, Geom::Coord const &d2, Geom::Coord const &t2, bool const &a2)
+ : _point(p), _target(target), _at_intersection(at_intersection), _fully_constrained(fully_constrained), _distance(d), _tolerance(t), _always_snap(a),
_second_distance(d2), _second_tolerance(t2), _second_always_snap(a2)
{
_transformation = Geom::Point(1,1);
@@ -104,6 +105,27 @@ bool getClosestSP(std::list<Inkscape::SnappedPoint> &list, Inkscape::SnappedPoin
return success;
}
+bool Inkscape::SnappedPoint::isOtherOneBetter(Inkscape::SnappedPoint const &other_one) const
+{
+ // If it's closer
+ bool c2 = other_one.getDistance() < getDistance();
+ // or, if it's for a snapper with "always snap" turned on, and the previous wasn't
+ bool c3 = other_one.getAlwaysSnap() && !getAlwaysSnap();
+ // But in no case fall back from a snapper with "always snap" on to one with "always snap" off
+ bool c3n = !other_one.getAlwaysSnap() && getAlwaysSnap();
+ // or, if we have a fully constrained snappoint (e.g. to a node), while the previous one was only partly constrained (e.g. to a line)
+ bool c4 = other_one.getFullyConstrained() && !getFullyConstrained();
+ // But in no case fall back; (has less priority than c3n, so it is allowed to fall back when c3 is true, see below)
+ bool c4n = !other_one.getFullyConstrained() && getFullyConstrained();
+ // or, if it's just as close then consider the second distance
+ // (which is only relevant for points at an intersection)
+ bool c5a = (other_one.getDistance() == getDistance());
+ bool c5b = other_one.getSecondDistance() < getSecondDistance();
+
+ // std::cout << "c2 = " << c2 << " | c3 = " << c3 << " | c3n = " << c3n << " | c4 = " << c4 << " | c4n = " << c4n << " | c5a = " << c5a << " | c5b = " << c5b;
+ return (c2 || c3 || c4 || (c5a && c5b)) && !c3n && (!c4n || c3);
+}
+
/*
Local Variables:
mode:c++
diff --git a/src/snapped-point.h b/src/snapped-point.h
index 4999a2aaee16b2f121269a1e2c2395e856d7f097..575fd0e1cd3d6a650cba0974ab6bfabe92e3fc96 100644 (file)
--- a/src/snapped-point.h
+++ b/src/snapped-point.h
public:
SnappedPoint();
- SnappedPoint(Geom::Point const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &at_intersection, Geom::Coord const &d2, Geom::Coord const &t2, bool const &a2);
- SnappedPoint(Geom::Point const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a);
+ SnappedPoint(Geom::Point const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &at_intersection, bool const &fully_constrained, Geom::Coord const &d2, Geom::Coord const &t2, bool const &a2);
+ SnappedPoint(Geom::Point const &p, SnapTargetType const &target, Geom::Coord const &d, Geom::Coord const &t, bool const &a, bool const &fully_constrained);
~SnappedPoint();
Geom::Coord getDistance() const;
Geom::Coord getTolerance() const;
bool getAlwaysSnap() const;
Geom::Coord getSecondDistance() const;
+ void setSecondDistance(Geom::Coord const d) {_second_distance = d;}
Geom::Coord getSecondTolerance() const;
bool getSecondAlwaysSnap() const;
- /* This is the preferred method to find out which point we have snapped,
- * to because it only returns a point if snapping has actually occured
+ /* This is the preferred method to find out which point we have snapped
+ * to, because it only returns a point if snapping has actually occured
* (by overwriting p)
*/
void getPoint(Geom::Point &p) const;
Geom::Point getPoint() const {return _point;}
bool getAtIntersection() const {return _at_intersection;}
+ bool getFullyConstrained() const {return _fully_constrained;}
bool getSnapped() const {return _distance < NR_HUGE;}
Geom::Point getTransformation() const {return _transformation;}
void setTransformation(Geom::Point const t) {_transformation = t;}
void setTarget(SnapTargetType const target) {_target = target;}
SnapTargetType getTarget() {return _target;}
+ bool isOtherOneBetter(SnappedPoint const &other_one) const;
+
protected:
Geom::Point _point; // Location of the snapped point
SnapTargetType _target; // Describes to what we've snapped to
- bool _at_intersection; // If true, the snapped point is at an intersection
+ bool _at_intersection; // If true, the snapped point is at an intersection
+ bool _fully_constrained; // When snapping for example to a node, then the snap will be "fully constrained".
+ // When snapping to a line however, the snap is only partly constrained (i.e. only in one dimension)
/* Distance from original point to snapped point. If the snapped point is at
an intersection of e.g. two lines, then this is the distance to the closest