Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
snapped-line.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
12#include "snapped-line.h"
13
14Inkscape::SnappedLineSegment::SnappedLineSegment(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &snapped_tolerance, bool const &always_snap, Geom::Point const &start_point_of_line, Geom::Point const &end_point_of_line)
15 : _start_point_of_line(start_point_of_line), _end_point_of_line(end_point_of_line)
16{
17 _point = snapped_point;
18 _source = source;
19 _source_num = source_num;
20 _target = target;
21 _distance = snapped_distance;
22 _tolerance = std::max(snapped_tolerance, 1.0);
23 _always_snap = always_snap;
24 _at_intersection = false;
27 _second_always_snap = false;
28}
29
31{
32 _source = SNAPSOURCE_UNDEFINED;
33 _source_num = -1;
34 _target = SNAPTARGET_UNDEFINED;
35 _distance = Geom::infinity();
36 _tolerance = 1;
37 _always_snap = false;
38 _at_intersection = false;
39 _second_distance = Geom::infinity();
40 _second_tolerance = 1;
41 _second_always_snap = false;
42}
43
44
46= default;
47
49{
50 Geom::OptCrossing inters = Geom::OptCrossing(); // empty by default
51 try
52 {
53 inters = Geom::intersection(getLineSegment(), line.getLineSegment());
54 }
56 {
57 // We're probably dealing with parallel lines, so they don't really cross
58 inters = Geom::OptCrossing();
59 }
60
61 if (inters) {
62 Geom::Point inters_pt = getLineSegment().pointAt((*inters).ta);
63 /* If a snapper has been told to "always snap", then this one should be preferred
64 * over the other, if that other one has not been told so. (The preferred snapper
65 * will be labeled "primary" below)
66 */
67 bool const c1 = this->getAlwaysSnap() && !line.getAlwaysSnap(); //do not use _tolerance directly!
68 /* If neither or both have been told to "always snap", then cast a vote based on
69 * the snapped distance. For this we should consider the distance to the snapped
70 * line, not the distance to the intersection.
71 * See the comment in Inkscape::SnappedLine::intersect
72 */
73 bool const c2 = _distance < line.getSnapDistance();
74 bool const use_this_as_primary = c1 || c2;
75 Inkscape::SnappedLineSegment const *primarySLS = use_this_as_primary ? this : &line;
76 Inkscape::SnappedLineSegment const *secondarySLS = use_this_as_primary ? &line : this;
77 Geom::Coord primaryDist = use_this_as_primary ? Geom::L2(inters_pt - this->getPoint()) : Geom::L2(inters_pt - line.getPoint());
78 Geom::Coord secondaryDist = use_this_as_primary ? Geom::L2(inters_pt - line.getPoint()) : Geom::L2(inters_pt - this->getPoint());
79 return SnappedPoint(inters_pt, SNAPSOURCE_UNDEFINED, primarySLS->getSourceNum(), SNAPTARGET_PATH_INTERSECTION, primaryDist, primarySLS->getTolerance(), primarySLS->getAlwaysSnap(), true, false, true,
80 secondaryDist, secondarySLS->getTolerance(), secondarySLS->getAlwaysSnap());
81 }
82
83 // No intersection
85};
86
87
88
89Inkscape::SnappedLine::SnappedLine(Geom::Point const &snapped_point, Geom::Coord const &snapped_distance, SnapSourceType const &source, long source_num, SnapTargetType const &target, Geom::Coord const &snapped_tolerance, bool const &always_snap, Geom::Point const &normal_to_line, Geom::Point const &point_on_line)
90 : _normal_to_line(normal_to_line), _point_on_line(point_on_line)
91{
92 _source = source;
93 _source_num = source_num;
94 _target = target;
95 _distance = snapped_distance;
96 _tolerance = std::max(snapped_tolerance, 1.0);
97 _always_snap = always_snap;
100 _second_always_snap = false;
101 _point = snapped_point;
102 _at_intersection = false;
103}
104
106{
107 _source = SNAPSOURCE_UNDEFINED;
108 _source_num = -1;
109 _target = SNAPTARGET_UNDEFINED;
110 _distance = Geom::infinity();
111 _tolerance = 1;
112 _always_snap = false;
113 _second_distance = Geom::infinity();
114 _second_tolerance = 1;
115 _second_always_snap = false;
116 _at_intersection = false;
117}
118
120= default;
121
123{
124 // Calculate the intersection of two lines, which are both within snapping range
125 // One could be a grid line, whereas the other could be a guide line
126 // The point of intersection should be considered for snapping, but might be outside the snapping range
127
128 Geom::OptCrossing inters = Geom::OptCrossing(); // empty by default
129 try
130 {
131 inters = Geom::intersection(getLine(), line.getLine());
132 }
133 catch (Geom::InfiniteSolutions &e)
134 {
135 // We're probably dealing with parallel lines, so they don't really cross
136 inters = Geom::OptCrossing();
137 }
138
139 if (inters) {
140 Geom::Point inters_pt = getLine().pointAt((*inters).ta);
141 /* If a snapper has been told to "always snap", then this one should be preferred
142 * over the other, if that other one has not been told so. (The preferred snapper
143 * will be labelled "primary" below)
144 */
145 bool const c1 = this->getAlwaysSnap() && !line.getAlwaysSnap();
146 /* If neither or both have been told to "always snap", then cast a vote based on
147 * the snapped distance. For this we should consider the distance to the snapped
148 * line or to the intersection
149 */
150 bool const c2 = _distance < line.getSnapDistance();
151 bool const use_this_as_primary = c1 || c2;
152 Inkscape::SnappedLine const *primarySL = use_this_as_primary ? this : &line;
153 Inkscape::SnappedLine const *secondarySL = use_this_as_primary ? &line : this;
154 Geom::Coord primaryDist = use_this_as_primary ? Geom::L2(inters_pt - this->getPoint()) : Geom::L2(inters_pt - line.getPoint());
155 Geom::Coord secondaryDist = use_this_as_primary ? Geom::L2(inters_pt - line.getPoint()) : Geom::L2(inters_pt - this->getPoint());
156 return SnappedPoint(inters_pt, Inkscape::SNAPSOURCE_UNDEFINED, primarySL->getSourceNum(), Inkscape::SNAPTARGET_UNDEFINED, primaryDist, primarySL->getTolerance(), primarySL->getAlwaysSnap(), true, false, true,
157 secondaryDist, secondarySL->getTolerance(), secondarySL->getAlwaysSnap());
158 // The type of the snap target is yet undefined, as we cannot tell whether
159 // we're snapping to grid or the guide lines; must be set by on a higher level
160 }
161
162 // No intersection
164}
165
166// search for the closest snapped line segment
167bool getClosestSLS(std::list<Inkscape::SnappedLineSegment> const &list, Inkscape::SnappedLineSegment &result)
168{
169 bool success = false;
170
171 for (std::list<Inkscape::SnappedLineSegment>::const_iterator i = list.begin(); i != list.end(); ++i) {
172 if ((i == list.begin()) || (*i).getSnapDistance() < result.getSnapDistance()) {
173 result = *i;
174 success = true;
175 }
176 }
177
178 return success;
179}
180
181// search for the closest intersection of two snapped line segments, which are both member of the same collection
182bool getClosestIntersectionSLS(std::list<Inkscape::SnappedLineSegment> const &list, Inkscape::SnappedPoint &result)
183{
184 bool success = false;
185
186 for (std::list<Inkscape::SnappedLineSegment>::const_iterator i = list.begin(); i != list.end(); ++i) {
187 std::list<Inkscape::SnappedLineSegment>::const_iterator j = i;
188 ++j;
189 for (; j != list.end(); ++j) {
190 Inkscape::SnappedPoint sp = (*i).intersect(*j);
191 if (sp.getAtIntersection()) {
192 // if it's the first point
193 bool const c1 = !success;
194 // or, if it's closer
195 bool const c2 = sp.getSnapDistance() < result.getSnapDistance();
196 // or, if it's just then look at the other distance
197 // (only relevant for snapped points which are at an intersection
198 bool const c3 = (sp.getSnapDistance() == result.getSnapDistance()) && (sp.getSecondSnapDistance() < result.getSecondSnapDistance());
199 // then prefer this point over the previous one
200 if (c1 || c2 || c3) {
201 result = sp;
202 success = true;
203 }
204 }
205 }
206 }
207
208 return success;
209}
210
211// search for the closest snapped line
212bool getClosestSL(std::list<Inkscape::SnappedLine> const &list, Inkscape::SnappedLine &result)
213{
214 bool success = false;
215
216 for (std::list<Inkscape::SnappedLine>::const_iterator i = list.begin(); i != list.end(); ++i) {
217 if ((i == list.begin()) || (*i).getSnapDistance() < result.getSnapDistance()) {
218 result = *i;
219 success = true;
220 }
221 }
222
223 return success;
224}
225
226// search for the closest intersection of two snapped lines, which are both member of the same collection
227bool getClosestIntersectionSL(std::list<Inkscape::SnappedLine> const &list, Inkscape::SnappedPoint &result)
228{
229 bool success = false;
230
231 for (std::list<Inkscape::SnappedLine>::const_iterator i = list.begin(); i != list.end(); ++i) {
232 std::list<Inkscape::SnappedLine>::const_iterator j = i;
233 ++j;
234 for (; j != list.end(); ++j) {
235 Inkscape::SnappedPoint sp = (*i).intersect(*j);
236 if (sp.getAtIntersection()) {
237 // if it's the first point
238 bool const c1 = !success;
239 // or, if it's closer
240 bool const c2 = sp.getSnapDistance() < result.getSnapDistance();
241 // or, if it's just then look at the other distance
242 // (only relevant for snapped points which are at an intersection
243 bool const c3 = (sp.getSnapDistance() == result.getSnapDistance()) && (sp.getSecondSnapDistance() < result.getSecondSnapDistance());
244 // then prefer this point over the previous one
245 if (c1 || c2 || c3) {
246 result = sp;
247 success = true;
248 }
249 }
250 }
251 }
252
253 return success;
254}
255
256// search for the closest intersection of two snapped lines, which are in two different collections
257bool getClosestIntersectionSL(std::list<Inkscape::SnappedLine> const &list1, std::list<Inkscape::SnappedLine> const &list2, Inkscape::SnappedPoint &result)
258{
259 bool success = false;
260
261 for (const auto & i : list1) {
262 for (const auto & j : list2) {
263 Inkscape::SnappedPoint sp = i.intersect(j);
264 if (sp.getAtIntersection()) {
265 // if it's the first point
266 bool const c1 = !success;
267 // or, if it's closer
268 bool const c2 = sp.getSnapDistance() < result.getSnapDistance();
269 // or, if it's just then look at the other distance
270 // (only relevant for snapped points which are at an intersection
271 bool const c3 = (sp.getSnapDistance() == result.getSnapDistance()) && (sp.getSecondSnapDistance() < result.getSecondSnapDistance());
272 // then prefer this point over the previous one
273 if (c1 || c2 || c3) {
274 result = sp;
275 success = true;
276 }
277 }
278 }
279 }
280
281 return success;
282}
283
284/*
285 Local Variables:
286 mode:c++
287 c-file-style:"stroustrup"
288 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
289 indent-tabs-mode:nil
290 fill-column:99
291 End:
292*/
293// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
Two-dimensional point that doubles as a vector.
Definition point.h:66
Class describing the result of an attempt to snap to a line segment.
Geom::LineSegment getLineSegment() const
Inkscape::SnappedPoint intersect(SnappedLineSegment const &line) const
Class describing the result of an attempt to snap to a line.
Geom::Line getLine() const
Inkscape::SnappedPoint intersect(SnappedLine const &line) const
Class describing the result of an attempt to snap.
Geom::Point getPoint() const
Geom::Coord getTolerance() const
bool getAlwaysSnap() const
Geom::Coord getSnapDistance() const
bool getAtIntersection() const
Geom::Coord getSecondSnapDistance() const
Geom::Coord _second_tolerance
Css & result
constexpr Coord infinity()
Get a value representing infinity.
Definition coord.h:88
double Coord
Floating point type used to store coordinates.
Definition coord.h:76
std::optional< Crossing > OptCrossing
Definition crossing.h:64
OptCrossing intersection(Ray const &r1, Line const &l2)
Definition line.h:545
SBasis L2(D2< SBasis > const &a, unsigned k)
Definition d2-sbasis.cpp:42
SnapSourceType
enumerations of snap source types and snap target types.
Definition snap-enums.h:18
@ SNAPSOURCE_UNDEFINED
Definition snap-enums.h:19
@ SNAPTARGET_UNDEFINED
Definition snap-enums.h:71
@ SNAPTARGET_PATH_INTERSECTION
Definition snap-enums.h:88
bool getClosestSLS(std::list< Inkscape::SnappedLineSegment > const &list, Inkscape::SnappedLineSegment &result)
bool getClosestSL(std::list< Inkscape::SnappedLine > const &list, Inkscape::SnappedLine &result)
bool getClosestIntersectionSLS(std::list< Inkscape::SnappedLineSegment > const &list, Inkscape::SnappedPoint &result)
bool getClosestIntersectionSL(std::list< Inkscape::SnappedLine > const &list, Inkscape::SnappedPoint &result)
SnappedLine class.