67fec627a85670a71a093d3e70d43880c76785f7
1 /**
2 * \file src/snapped-line.cpp
3 * \brief SnappedLine class.
4 *
5 * Authors:
6 * Diederik van Lierop <mail@diedenrezi.nl>
7 *
8 * Released under GNU GPL, read the file 'COPYING' for more information.
9 */
11 #include "snapped-line.h"
12 #include <2geom/geom.h>
13 #include "libnr/nr-values.h"
15 Inkscape::SnappedLineSegment::SnappedLineSegment(NR::Point snapped_point, NR::Coord snapped_distance, NR::Point start_point_of_line, NR::Point end_point_of_line)
16 : _start_point_of_line(start_point_of_line), _end_point_of_line(end_point_of_line)
17 {
18 _distance = snapped_distance;
19 _point = snapped_point;
20 _at_intersection = false;
21 _second_distance = NR_HUGE;
22 }
24 Inkscape::SnappedLineSegment::SnappedLineSegment()
25 {
26 _start_point_of_line = NR::Point(0,0);
27 _end_point_of_line = NR::Point(0,0);
28 _distance = NR_HUGE;
29 _point = NR::Point(0,0);
30 _at_intersection = false;
31 _second_distance = NR_HUGE;
32 }
35 Inkscape::SnappedLineSegment::~SnappedLineSegment()
36 {
37 }
39 Inkscape::SnappedPoint Inkscape::SnappedLineSegment::intersect(SnappedLineSegment const &line) const
40 {
41 Geom::Point intersection_2geom(NR_HUGE, NR_HUGE);
42 NR::Coord distance = NR_HUGE;
43 NR::Coord second_distance = NR_HUGE;
45 Geom::IntersectorKind result = segment_intersect(_start_point_of_line.to_2geom(), _end_point_of_line.to_2geom(),
46 line._start_point_of_line.to_2geom(), line._end_point_of_line.to_2geom(),
47 intersection_2geom);
48 NR::Point intersection(intersection_2geom);
50 if (result == Geom::intersects) {
51 /* The relevant snapped distance is the distance to the closest snapped line, not the
52 distance to the intersection. See the comment in Inkscape::SnappedLine::intersect
53 */
54 distance = std::min(_distance, line.getDistance());
55 second_distance = std::max(_distance, line.getDistance());
56 }
57 return SnappedPoint(intersection, distance, result == Geom::intersects, second_distance);
58 };
62 Inkscape::SnappedLine::SnappedLine(NR::Point snapped_point, NR::Coord snapped_distance, NR::Point normal_to_line, NR::Point point_on_line)
63 : _normal_to_line(normal_to_line), _point_on_line(point_on_line)
64 {
65 _distance = snapped_distance;
66 _second_distance = NR_HUGE;
67 _point = snapped_point;
68 _at_intersection = false;
69 }
71 Inkscape::SnappedLine::SnappedLine()
72 {
73 _normal_to_line = NR::Point(0,0);
74 _point_on_line = NR::Point(0,0);
75 _distance = NR_HUGE;
76 _second_distance = NR_HUGE;
77 _point = NR::Point(0,0);
78 _at_intersection = false;
79 }
81 Inkscape::SnappedLine::~SnappedLine()
82 {
83 }
85 Inkscape::SnappedPoint Inkscape::SnappedLine::intersect(SnappedLine const &line) const
86 {
87 // Calculate the intersection of to lines, which are both within snapping range
88 // The point of intersection should be considered for snapping, but might be outside the snapping range
90 Geom::Point intersection_2geom(NR_HUGE, NR_HUGE);
91 NR::Coord distance = NR_HUGE;
92 NR::Coord second_distance = NR_HUGE;
94 Geom::IntersectorKind result = Geom::line_intersection(getNormal().to_2geom(), getConstTerm(),
95 line.getNormal().to_2geom(), line.getConstTerm(), intersection_2geom);
96 NR::Point intersection(intersection_2geom);
98 if (result == Geom::intersects) {
99 /* The relevant snapped distance is the distance to the closest snapped line, not the
100 distance to the intersection. For example, when a box is almost aligned with a grid
101 in both horizontal and vertical directions, the distance to the intersection of the
102 grid lines will always be larger then the distance to a grid line. We will be snapping
103 to the closest snapped point however, so if we ever want to snap to the intersection
104 then the distance to it should at least be equal to the other distance, not greater
105 than it, as that would rule the intersection out
106 */
107 distance = std::min(_distance, line.getDistance());
108 second_distance = std::max(_distance, line.getDistance());
109 }
111 return SnappedPoint(intersection, distance, result == Geom::intersects, second_distance);
112 }
114 // search for the closest snapped line segment
115 bool getClosestSLS(std::list<Inkscape::SnappedLineSegment> &list, Inkscape::SnappedLineSegment &result)
116 {
117 bool success = false;
119 for (std::list<Inkscape::SnappedLineSegment>::const_iterator i = list.begin(); i != list.end(); i++) {
120 if ((i == list.begin()) || (*i).getDistance() < result.getDistance()) {
121 result = *i;
122 success = true;
123 }
124 }
126 return success;
127 }
129 // search for the closest intersection of two snapped line segments, which are both member of the same collection
130 bool getClosestIntersectionSLS(std::list<Inkscape::SnappedLineSegment> &list, Inkscape::SnappedPoint &result)
131 {
132 bool success = false;
134 for (std::list<Inkscape::SnappedLineSegment>::const_iterator i = list.begin(); i != list.end(); i++) {
135 std::list<Inkscape::SnappedLineSegment>::const_iterator j = i;
136 j++;
137 for (; j != list.end(); j++) {
138 Inkscape::SnappedPoint sp = (*i).intersect(*j);
139 if (sp.getAtIntersection()) {
140 // if it's the first point
141 bool const c1 = !success;
142 // or, if it's closer
143 bool const c2 = sp.getDistance() < result.getDistance();
144 // or, if it's just then look at the other distance
145 // (only relevant for snapped points which are at an intersection
146 bool const c3 = (sp.getDistance() == result.getDistance()) && (sp.getSecondDistance() < result.getSecondDistance());
147 // then prefer this point over the previous one
148 if (c1 || c2 || c3) {
149 result = sp;
150 success = true;
151 }
152 }
153 }
154 }
156 return success;
157 }
159 // search for the closest snapped line
160 bool getClosestSL(std::list<Inkscape::SnappedLine> &list, Inkscape::SnappedLine &result)
161 {
162 bool success = false;
164 for (std::list<Inkscape::SnappedLine>::const_iterator i = list.begin(); i != list.end(); i++) {
165 if ((i == list.begin()) || (*i).getDistance() < result.getDistance()) {
166 result = *i;
167 success = true;
168 }
169 }
171 return success;
172 }
174 // search for the closest intersection of two snapped lines, which are both member of the same collection
175 bool getClosestIntersectionSL(std::list<Inkscape::SnappedLine> &list, Inkscape::SnappedPoint &result)
176 {
177 bool success = false;
179 for (std::list<Inkscape::SnappedLine>::const_iterator i = list.begin(); i != list.end(); i++) {
180 std::list<Inkscape::SnappedLine>::const_iterator j = i;
181 j++;
182 for (; j != list.end(); j++) {
183 Inkscape::SnappedPoint sp = (*i).intersect(*j);
184 if (sp.getAtIntersection()) {
185 // if it's the first point
186 bool const c1 = !success;
187 // or, if it's closer
188 bool const c2 = sp.getDistance() < result.getDistance();
189 // or, if it's just then look at the other distance
190 // (only relevant for snapped points which are at an intersection
191 bool const c3 = (sp.getDistance() == result.getDistance()) && (sp.getSecondDistance() < result.getSecondDistance());
192 // then prefer this point over the previous one
193 if (c1 || c2 || c3) {
194 result = sp;
195 success = true;
196 }
197 }
198 }
199 }
201 return success;
202 }
204 // search for the closest intersection of two snapped lines, which are in two different collections
205 bool getClosestIntersectionSL(std::list<Inkscape::SnappedLine> &list1, std::list<Inkscape::SnappedLine> &list2, Inkscape::SnappedPoint &result)
206 {
207 bool success = false;
209 for (std::list<Inkscape::SnappedLine>::const_iterator i = list1.begin(); i != list1.end(); i++) {
210 for (std::list<Inkscape::SnappedLine>::const_iterator j = list2.begin(); j != list2.end(); j++) {
211 Inkscape::SnappedPoint sp = (*i).intersect(*j);
212 if (sp.getAtIntersection()) {
213 // if it's the first point
214 bool const c1 = !success;
215 // or, if it's closer
216 bool const c2 = sp.getDistance() < result.getDistance();
217 // or, if it's just then look at the other distance
218 // (only relevant for snapped points which are at an intersection
219 bool const c3 = (sp.getDistance() == result.getDistance()) && (sp.getSecondDistance() < result.getSecondDistance());
220 // then prefer this point over the previous one
221 if (c1 || c2 || c3) {
222 result = sp;
223 success = true;
224 }
225 }
226 }
227 }
229 return success;
230 }
232 /*
233 Local Variables:
234 mode:c++
235 c-file-style:"stroustrup"
236 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
237 indent-tabs-mode:nil
238 fill-column:99
239 End:
240 */
241 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :