Code

Use new methods from 2geom's API
[inkscape.git] / src / snapped-curve.cpp
1 /**\r
2  *    \file src/snapped-curve.cpp\r
3  *    \brief SnappedCurve class.\r
4  *\r
5  *    Authors:\r
6  *      Diederik van Lierop <mail@diedenrezi.nl>\r
7  *\r
8  *    Released under GNU GPL, read the file 'COPYING' for more information.\r
9  */\r
10 \r
11 #include "snapped-curve.h"\r
12 #include "libnr/nr-values.h"\r
13 #include <2geom/crossing.h>\r
14 #include <2geom/path-intersection.h>\r
15 #include <libnr/nr-convert2geom.h>\r
16 \r
17 // These two are needed for SP_ACTIVE_DESKTOP; this is a dirty hack\r
18 #include "desktop.h"\r
19 #include "inkscape.h"\r
20 \r
21 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
22 {\r
23         _distance = snapped_distance;\r
24     _tolerance = snapped_tolerance;\r
25     _always_snap = always_snap;\r
26     _curve = curve;\r
27         _second_distance = NR_HUGE;\r
28     _second_tolerance = 0;\r
29     _second_always_snap = false;\r
30         _point = snapped_point;\r
31         _at_intersection = false;\r
32 }\r
33 \r
34 Inkscape::SnappedCurve::SnappedCurve() \r
35 {\r
36         _distance = NR_HUGE;\r
37     _tolerance = 0;\r
38     _always_snap = false;\r
39     _curve = NULL;\r
40         _second_distance = NR_HUGE;\r
41     _second_tolerance = 0;\r
42     _second_always_snap = false;\r
43         _point = Geom::Point(0,0);\r
44         _at_intersection = false;\r
45 }\r
46 \r
47 Inkscape::SnappedCurve::~SnappedCurve()\r
48 {\r
49 }\r
50 \r
51 Inkscape::SnappedPoint Inkscape::SnappedCurve::intersect(SnappedCurve const &curve, Geom::Point const &p) const \r
52 {\r
53     // Calculate the intersections of two curves, which are both within snapping range, and\r
54     // return only the closest intersection\r
55     // The point of intersection should be considered for snapping, but might be outside the snapping range\r
56     // PS: We need p (the location of the mouse pointer) for find out which intersection is the\r
57     // closest, as there might be multiple intersections of two curves\r
58     Geom::Crossings cs = crossings(*(this->_curve), *(curve._curve));\r
59      \r
60     if (cs.size() > 0) {\r
61         // There might be multiple intersections: find the closest\r
62         Geom::Coord best_dist = NR_HUGE;\r
63         Geom::Point best_p = Geom::Point(NR_HUGE, NR_HUGE);\r
64         for (std::vector<Geom::Crossing>::const_iterator i = cs.begin(); i != cs.end(); i++) {\r
65             Geom::Point p_ix = this->_curve->pointAt((*i).ta);\r
66             Geom::Coord dist = Geom::distance(p_ix, p);\r
67             if (dist < best_dist) {\r
68                 best_dist = dist;\r
69                 best_p = p_ix;\r
70             }\r
71         }\r
72         \r
73         // Now we've found the closests intersection, return it as a SnappedPoint\r
74         bool const use_this_as_primary = _distance < curve.getDistance();\r
75         Inkscape::SnappedCurve const *primaryC = use_this_as_primary ? this : &curve;\r
76         Inkscape::SnappedCurve const *secondaryC = use_this_as_primary ? &curve : this;\r
77         // The intersection should in fact be returned in desktop coordinates, but for this\r
78         // we need a desktop: this is a dirty hack\r
79         SPDesktop const *desktop = SP_ACTIVE_DESKTOP;\r
80         best_p = desktop->dt2doc(best_p);\r
81         // TODO: Investigate whether it is possible to use document coordinates everywhere\r
82         // in the snapper code. Only the mouse position should be in desktop coordinates, I guess.\r
83         // All paths are already in document coords and we are certainly not going to change THAT.\r
84         return SnappedPoint(from_2geom(best_p), Inkscape::SNAPTARGET_PATH_INTERSECTION, primaryC->getDistance(), primaryC->getTolerance(), primaryC->getAlwaysSnap(), true, \r
85                                           secondaryC->getDistance(), secondaryC->getTolerance(), secondaryC->getAlwaysSnap());\r
86     }\r
87     \r
88     // No intersection\r
89     return SnappedPoint(Geom::Point(NR_HUGE, NR_HUGE), SNAPTARGET_UNDEFINED, NR_HUGE, 0, false, false, NR_HUGE, 0, false);\r
90 }\r
91 \r
92 // search for the closest snapped line\r
93 bool getClosestCurve(std::list<Inkscape::SnappedCurve> const &list, Inkscape::SnappedCurve &result) \r
94 {\r
95     bool success = false;\r
96     \r
97     for (std::list<Inkscape::SnappedCurve>::const_iterator i = list.begin(); i != list.end(); i++) {\r
98         if ((i == list.begin()) || (*i).getDistance() < result.getDistance()) {\r
99             result = *i;\r
100             success = true;\r
101         }   \r
102     }\r
103     \r
104     return success; \r
105 }\r
106 \r
107 // search for the closest intersection of two snapped curves, which are both member of the same collection\r
108 bool getClosestIntersectionCS(std::list<Inkscape::SnappedCurve> const &list, Geom::Point const &p, Inkscape::SnappedPoint &result)\r
109 {\r
110     bool success = false;\r
111     \r
112     for (std::list<Inkscape::SnappedCurve>::const_iterator i = list.begin(); i != list.end(); i++) {\r
113         std::list<Inkscape::SnappedCurve>::const_iterator j = i;\r
114         j++;\r
115         for (; j != list.end(); j++) {\r
116             Inkscape::SnappedPoint sp = (*i).intersect(*j, p);\r
117             if (sp.getAtIntersection()) {\r
118                 // if it's the first point\r
119                 bool const c1 = !success;\r
120                 // or, if it's closer             \r
121                 bool const c2 = sp.getDistance() < result.getDistance();\r
122                 // or, if it's just then look at the other distance \r
123                 // (only relevant for snapped points which are at an intersection\r
124                 bool const c3 = (sp.getDistance() == result.getDistance()) && (sp.getSecondDistance() < result.getSecondDistance()); \r
125                 // then prefer this point over the previous one\r
126                 if (c1 || c2 || c3) {  \r
127                     result = sp;\r
128                     success = true;\r
129                 }\r
130             }               \r
131         }\r
132     }\r
133     \r
134     return success; \r
135 }\r
136 /*\r
137   Local Variables:\r
138   mode:c++\r
139   c-file-style:"stroustrup"\r
140   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))\r
141   indent-tabs-mode:nil\r
142   fill-column:99\r
143   End:\r
144 */\r
145 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :\r