Inkscape
Vector Graphics Editor
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages Concepts
geom.cpp
Go to the documentation of this file.
1
5#include <2geom/geom.h>
6#include <2geom/point.h>
7#include <algorithm>
8#include <optional>
9#include <2geom/rect.h>
10
11using std::swap;
12
13namespace Geom {
14
21
67line_intersection(Geom::Point const &n0, double const d0,
68 Geom::Point const &n1, double const d1,
70{
71 double denominator = dot(Geom::rot90(n0), n1);
72 double X = n1[Geom::Y] * d0 -
73 n0[Geom::Y] * d1;
74 /* X = (-d1, d0) dot (n0[Y], n1[Y]) */
75
76 if (denominator == 0) {
77 if ( X == 0 ) {
78 return coincident;
79 } else {
80 return parallel;
81 }
82 }
83
84 double Y = n0[Geom::X] * d1 -
85 n1[Geom::X] * d0;
86
87 result = Geom::Point(X, Y) / denominator;
88
89 return intersects;
90}
91
92
93
94/* ccw exists as a building block */
95int
97 const Geom::Point& p2)
98/* Determine which way a set of three points winds. */
99{
100 Geom::Point d1 = p1 - p0;
101 Geom::Point d2 = p2 - p0;
102 /* compare slopes but avoid division operation */
103 double c = dot(Geom::rot90(d1), d2);
104 if(c > 0)
105 return +1; // ccw - do these match def'n in header?
106 if(c < 0)
107 return -1; // cw
108
109 /* Colinear [or NaN]. Decide the order. */
110 if ( ( d1[0] * d2[0] < 0 ) ||
111 ( d1[1] * d2[1] < 0 ) ) {
112 return -1; // p2 < p0 < p1
113 } else if ( dot(d1,d1) < dot(d2,d2) ) {
114 return +1; // p0 <= p1 < p2
115 } else {
116 return 0; // p0 <= p2 <= p1
117 }
118}
119
127bool
129 Geom::Point const &p10, Geom::Point const &p11)
130{
131 if(p00 == p01) return false;
132 if(p10 == p11) return false;
133
134 return ((intersector_ccw(p00, p01, p10) * intersector_ccw(p00, p01, p11)) <= 0 );
135}
136
137
144bool
146 Geom::Point const &p10, Geom::Point const &p11)
147{
148 if(p00 == p01) return false;
149 if(p10 == p11) return false;
150
151 /* true iff ( (the p1 segment straddles the p0 infinite line)
152 * and (the p0 segment straddles the p1 infinite line) ). */
153 return (line_segment_intersectp(p00, p01, p10, p11) &&
154 line_segment_intersectp(p10, p11, p00, p01));
155}
156
165 Geom::Point const &p10, Geom::Point const &p11,
167{
168 if(line_segment_intersectp(p00, p01, p10, p11)) {
169 Geom::Point n0 = (p01 - p00).ccw();
170 double d0 = dot(n0,p00);
171
172 Geom::Point n1 = (p11 - p10).ccw();
173 double d1 = dot(n1,p10);
174 return line_intersection(n0, d0, n1, d1, result);
175 } else {
176 return no_intersection;
177 }
178}
179
180
189 Geom::Point const &p10, Geom::Point const &p11,
191{
192 if(segment_intersectp(p00, p01, p10, p11)) {
193 Geom::Point n0 = (p01 - p00).ccw();
194 double d0 = dot(n0,p00);
195
196 Geom::Point n1 = (p11 - p10).ccw();
197 double d1 = dot(n1,p10);
198 return line_intersection(n0, d0, n1, d1, result);
199 } else {
200 return no_intersection;
201 }
202}
203
212 Geom::Point const &p10, Geom::Point const &p11,
214{
215 Geom::Point n0 = (p01 - p00).ccw();
216 double d0 = dot(n0,p00);
217
218 Geom::Point n1 = (p11 - p10).ccw();
219 double d1 = dot(n1,p10);
220 return line_intersection(n0, d0, n1, d1, result);
221}
222
223// this is used to compare points for std::sort below
224static bool
225is_less(Point const &A, Point const &B)
226{
227 if (A[X] < B[X]) {
228 return true;
229 } else if (A[X] == B[X] && A[Y] < B[Y]) {
230 return true;
231 } else {
232 return false;
233 }
234}
235
236// TODO: this can doubtlessly be improved
237static void
238eliminate_duplicates_p(std::vector<Point> &pts)
239{
240 unsigned int size = pts.size();
241
242 if (size < 2)
243 return;
244
245 if (size == 2) {
246 if (pts[0] == pts[1]) {
247 pts.pop_back();
248 }
249 } else {
250 std::sort(pts.begin(), pts.end(), &is_less);
251 if (size == 3) {
252 if (pts[0] == pts[1]) {
253 pts.erase(pts.begin());
254 } else if (pts[1] == pts[2]) {
255 pts.pop_back();
256 }
257 } else {
258 // we have size == 4
259 if (pts[2] == pts[3]) {
260 pts.pop_back();
261 }
262 if (pts[0] == pts[1]) {
263 pts.erase(pts.begin());
264 }
265 }
266 }
267}
268
279std::vector<Geom::Point>
281 Geom::Point const &p0, Geom::Point const &p1)
282{
283 using namespace Geom;
284
285 std::vector<Point> results;
286
287 Point A(c0);
288 Point C(c1);
289
290 Point B(A[X], C[Y]);
291 Point D(C[X], A[Y]);
292
293 Point res;
294
295 if (line_segment_intersect(p0, p1, A, B, res) == intersects) {
296 results.push_back(res);
297 }
298 if (line_segment_intersect(p0, p1, B, C, res) == intersects) {
299 results.push_back(res);
300 }
301 if (line_segment_intersect(p0, p1, C, D, res) == intersects) {
302 results.push_back(res);
303 }
304 if (line_segment_intersect(p0, p1, D, A, res) == intersects) {
305 results.push_back(res);
306 }
307
308 eliminate_duplicates_p(results);
309
310 if (results.size() == 2) {
311 // sort the results so that the order is the same as that of p0 and p1
312 Point dir1 (results[1] - results[0]);
313 Point dir2 (p1 - p0);
314 if (dot(dir1, dir2) < 0) {
315 swap(results[0], results[1]);
316 }
317 }
318
319 return results;
320}
321
332std::optional<LineSegment>
335{
336 std::vector<Point> results;
337
338 results = rect_line_intersect(r.min(), r.max(), ls[0], ls[1]);
339 if(results.size() == 2) {
340 return LineSegment(results[0], results[1]);
341 }
342 return std::optional<LineSegment>();
343}
344
345std::optional<LineSegment>
347 Geom::Line l)
348{
349 return rect_line_intersect(r, l.segment(0, 1));
350}
351
366int centroid(std::vector<Geom::Point> const &p, Geom::Point& centroid, double &area) {
367 const unsigned n = p.size();
368 if (n < 3)
369 return 1;
370 Geom::Point centroid_tmp(0,0);
371 double atmp = 0;
372 for (unsigned i = n-1, j = 0; j < n; i = j, j++) {
373 const double ai = cross(p[j], p[i]);
374 atmp += ai;
375 centroid_tmp += (p[j] + p[i])*ai; // first moment.
376 }
377 area = atmp / 2;
378 if (atmp != 0) {
379 centroid = centroid_tmp / (3 * atmp);
380 return 0;
381 }
382 return 2;
383}
384
385}
386
387/*
388 Local Variables:
389 mode:c++
390 c-file-style:"stroustrup"
391 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
392 indent-tabs-mode:nil
393 fill-column:99
394 End:
395*/
396// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
Various geometrical calculations.
Cartesian point / 2D vector and related operations.
CPoint min() const
Get the corner of the rectangle with smallest coordinate values.
CPoint max() const
Get the corner of the rectangle with largest coordinate values.
Infinite line on a plane.
Definition line.h:53
LineSegment segment(Coord f, Coord t) const
Create a segment of this line.
Definition line.h:283
Two-dimensional point that doubles as a vector.
Definition point.h:66
Axis aligned, non-empty rectangle.
Definition rect.h:92
Css & result
double c[8][4]
BezierCurveN< 1 > LineSegment
Line segment.
@ Y
Definition coord.h:48
@ X
Definition coord.h:48
Various utility functions.
Definition affine.h:22
IntersectorKind line_intersection(Geom::Point const &n0, double const d0, Geom::Point const &n1, double const d1, Geom::Point &result)
Finds the intersection of the two (infinite) lines defined by the points p such that dot(n0,...
Definition geom.cpp:67
static void eliminate_duplicates_p(std::vector< Point > &pts)
Definition geom.cpp:238
int centroid(std::vector< Geom::Point > const &p, Geom::Point &centroid, double &area)
polyCentroid: Calculates the centroid (xCentroid, yCentroid) and area of a polygon,...
Definition geom.cpp:366
static double area(Geom::Point a, Geom::Point b, Geom::Point c)
std::optional< Geom::LineSegment > rect_line_intersect(Geom::Rect &r, Geom::LineSegment ls)
Determine whether & where an (infinite) line intersects a rectangle.
Definition geom.cpp:333
bool line_segment_intersectp(Geom::Point const &p00, Geom::Point const &p01, Geom::Point const &p10, Geom::Point const &p11)
Determine whether the line segment from p00 to p01 intersects the infinite line passing through p10 a...
Definition geom.cpp:128
IntersectorKind line_twopoint_intersect(Geom::Point const &p00, Geom::Point const &p01, Geom::Point const &p10, Geom::Point const &p11, Geom::Point &result)
Determine whether & where two line segments intersect.
Definition geom.cpp:211
IntersectorKind
Definition geom.cpp:15
@ parallel
Definition geom.cpp:17
@ no_intersection
Definition geom.cpp:19
@ coincident
Definition geom.cpp:18
@ intersects
Definition geom.cpp:16
bool segment_intersectp(Geom::Point const &p00, Geom::Point const &p01, Geom::Point const &p10, Geom::Point const &p11)
Determine whether two line segments intersect.
Definition geom.cpp:145
Piecewise< SBasis > cross(Piecewise< D2< SBasis > > const &a, Piecewise< D2< SBasis > > const &b)
static bool is_less(Point const &A, Point const &B)
Definition geom.cpp:225
int intersector_ccw(const Geom::Point &p0, const Geom::Point &p1, const Geom::Point &p2)
Definition geom.cpp:96
IntersectorKind line_segment_intersect(Geom::Point const &p00, Geom::Point const &p01, Geom::Point const &p10, Geom::Point const &p11, Geom::Point &result)
Determine whether & where a line segments intersects an (infinite) line.
Definition geom.cpp:164
T dot(D2< T > const &a, D2< T > const &b)
Definition d2.h:355
IntersectorKind segment_intersect(Geom::Point const &p00, Geom::Point const &p01, Geom::Point const &p10, Geom::Point const &p11, Geom::Point &result)
Determine whether & where two line segments intersect.
Definition geom.cpp:188
D2< T > rot90(D2< T > const &a)
Definition d2.h:397
int size
Axis-aligned rectangle.
unsigned n1