2
2
* vim: ts=4 sw=4 et tw=0 wm=0
4
4
* libavoid - Fast, Incremental, Object-avoiding Line Router
5
* Copyright (C) 2004-2006 Michael Wybrow <mjwybrow@users.sourceforge.net>
6
* Copyright (C) 2004-2009 Monash University
7
8
* --------------------------------------------------------------------
8
9
* Much of the code in this module is based on code published with
18
19
* modify it under the terms of the GNU Lesser General Public
19
20
* License as published by the Free Software Foundation; either
20
21
* version 2.1 of the License, or (at your option) any later version.
22
* See the file LICENSE.LGPL distributed with the library.
24
* Licensees holding a valid commercial license may use this file in
25
* accordance with the commercial license agreement provided with the
22
28
* This library is distributed in the hope that it will be useful,
23
29
* but WITHOUT ANY WARRANTY; without even the implied warranty of
24
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25
* Lesser General Public License for more details.
27
* You should have received a copy of the GNU Lesser General Public
28
* License along with this library; if not, write to the Free Software
29
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
32
* Author(s): Michael Wybrow <mjwybrow@users.sourceforge.net>
33
38
#include "libavoid/graph.h"
34
39
#include "libavoid/geometry.h"
35
#include "libavoid/polyutil.h"
40
#include "libavoid/assertions.h"
47
Point::Point(const double xv, const double yv)
54
bool Point::operator==(const Point& rhs) const
56
if ((x == rhs.x) && (y == rhs.y))
64
bool Point::operator!=(const Point& rhs) const
66
if ((x != rhs.x) || (y != rhs.y))
74
46
// Returns true iff the point c lies on the closed segment ab.
47
// To be used when the points are known to be collinear.
76
49
// Based on the code of 'Between'.
78
static const bool inBetween(const Point& a, const Point& b, const Point& c)
51
bool inBetween(const Point& a, const Point& b, const Point& c)
80
53
// We only call this when we know the points are collinear,
81
54
// otherwise we should be checking this here.
82
assert(vecDir(a, b, c) == 0);
55
COLA_ASSERT(vecDir(a, b, c, 0.0001) == 0);
57
if ((fabs(a.x - b.x) > 1) && (a.x != b.x))
87
60
return (((a.x < c.x) && (c.x < b.x)) ||
71
// Returns true iff the point c lies on the closed segment ab.
73
bool pointOnLine(const Point& a, const Point& b, const Point& c,
74
const double tolerance)
76
return (vecDir(a, b, c, tolerance) == 0) && inBetween(a, b, c);
98
80
// Returns true if the segment cd intersects the segment ab, blocking
106
88
int ab_c = vecDir(a, b, c);
107
if ((ab_c == 0) && inBetween(a, b, c))
112
94
int ab_d = vecDir(a, b, d);
113
if ((ab_d == 0) && inBetween(a, b, d))
118
100
// It's ok for either of the points a or b to be on the line cd,
116
// Returns true if the segment e1-e2 intersects the shape boundary
117
// segment s1-s2, blocking visibility.
119
bool segmentShapeIntersect(const Point& e1, const Point& e2, const Point& s1,
120
const Point& s2, bool& seenIntersectionAtEndpoint)
122
if (segmentIntersect(e1, e2, s1, s2))
124
// Basic intersection of segments.
127
else if ( (((s2 == e1) || pointOnLine(s1, s2, e1)) &&
128
(vecDir(s1, s2, e2) != 0))
130
(((s2 == e2) || pointOnLine(s1, s2, e2)) &&
131
(vecDir(s1, s2, e1) != 0)) )
133
// Segments intersect at the endpoint of one of the segments. We
134
// allow this once, but the second one blocks visibility. Otherwise
135
// shapes butted up against each other could have visibility through
137
if (seenIntersectionAtEndpoint)
141
seenIntersectionAtEndpoint = true;
134
147
// Returns true iff the point p in a valid region that can contain
135
148
// shortest paths. a0, a1, a2 are ordered vertices of a shape.
205
218
int s12p = vecDir(c1, c2, p);
206
219
int s23p = vecDir(c2, c3, p);
210
// Case of p being somewhere on c1-c2.
215
// Case of p being somewhere on c2-c3.
221
if ((s12p == 1) && (s23p == 1))
223
if ((s12p >= 0) && (s23p >= 0))
227
229
else if (s123 == -1)
229
if ((s12p == -1) && (s23p == -1))
231
if ((s12p <= 0) && (s23p <= 0))
235
// Case of c3 being somewhere on c1-c2.
238
// c1-c2-c3 are collinear, so just return vecDir from c1-c2
240
// Returns the distance between points a and b.
243
// Returns the Euclidean distance between points a and b.
245
double euclideanDist(const Point& a, const Point& b)
247
double xdiff = a.x - b.x;
248
double ydiff = a.y - b.y;
250
return sqrt((xdiff * xdiff) + (ydiff * ydiff));
253
// Returns the Manhattan distance between points a and b.
255
double manhattanDist(const Point& a, const Point& b)
257
return fabs(a.x - b.x) + fabs(a.y - b.y);
261
// Returns the Euclidean distance between points a and b.
242
263
double dist(const Point& a, const Point& b)
250
271
// Returns the total length of all line segments in the polygon
251
double totalLength(const Polygn& poly)
272
double totalLength(const Polygon& poly)
254
for (int i = 0; i < poly.pn-1; ++i) {
255
l += dist(poly.ps[i], poly.ps[i+1]);
275
for (size_t i = 1; i < poly.size(); ++i)
277
l += dist(poly.ps[i-1], poly.ps[i]);
277
299
// This is a fast version that only works for convex shapes. The
278
300
// other version (inPolyGen) is more general.
280
bool inPoly(const Polygn& poly, const Point& q)
302
bool inPoly(const Polygon& poly, const Point& q, bool countBorder)
284
for (int i = 0; i < n; i++)
304
size_t n = poly.size();
305
const std::vector<Point>& P = poly.ps;
306
bool onBorder = false;
307
for (size_t i = 0; i < n; i++)
286
309
// point index; i1 = i-1 mod n
287
int prev = (i + n - 1) % n;
288
if (vecDir(P[prev], P[i], q) == -1)
310
size_t prev = (i + n - 1) % n;
311
int dir = vecDir(P[prev], P[i], q);
317
// Record if point was on a boundary.
318
onBorder |= (dir == 0);
320
if (!countBorder && onBorder)
300
331
// Based on the code of 'InPoly'.
302
bool inPolyGen(const Polygn& argpoly, const Point& q)
333
bool inPolyGen(const PolygonInterface& argpoly, const Point& q)
304
335
// Numbers of right and left edge/ray crossings.
308
339
// Copy the argument polygon
309
Polygn poly = copyPoly(argpoly);
340
Polygon poly = argpoly;
341
std::vector<Point>& P = poly.ps;
342
size_t n = poly.size();
313
344
// Shift so that q is the origin. This is done for pedogical clarity.
314
for (int i = 0; i < n; ++i)
345
for (size_t i = 0; i < n; ++i)
316
347
P[i].x = P[i].x - q.x;
317
348
P[i].y = P[i].y - q.y;
320
351
// For each edge e=(i-1,i), see if crosses ray.
321
for (int i = 0; i < n; ++i)
352
for (size_t i = 0; i < n; ++i)
323
354
// First see if q=(0,0) is a vertex.
324
355
if ((P[i].x == 0) && (P[i].y == 0))
326
357
// We count a vertex as inside.
331
361
// point index; i1 = i-1 mod n
332
int i1 = ( i + n - 1 ) % n;
362
size_t i1 = ( i + n - 1 ) % n;
334
364
// if e "straddles" the x-axis...
335
365
// The commented-out statement is logically equivalent to the one
400
429
int segmentIntersectPoint(const Point& a1, const Point& a2,
401
430
const Point& b1, const Point& b2, double *x, double *y)
404
double Ax,Bx,Cx,Ay,By,Cy,d,e,f,num,offset;
432
double Ax,Bx,Cx,Ay,By,Cy,d,e,f,num;
405
433
double x1lo,x1hi,y1lo,y1hi;
407
435
Ax = a2.x - a1.x;
489
offset = SAME_SIGNS(num,f) ? f/2 : -f/2;
491
*x = a1.x + (num+offset) / f;
494
offset = SAME_SIGNS(num,f) ? f/2 : -f/2;
496
*y = a1.y + (num+offset) / f;
516
*x = a1.x + (num) / f;
520
*y = a1.y + (num) / f;
526
// Line Segment Intersection
527
// Original code by Franklin Antonio
529
int rayIntersectPoint(const Point& a1, const Point& a2,
530
const Point& b1, const Point& b2, double *x, double *y)
532
double Ax,Bx,Cx,Ay,By,Cy,d,f,num;
546
// compute intersection coordinates:
548
if (f == 0) return PARALLEL;
553
*x = a1.x + (num) / f;
557
*y = a1.y + (num) / f;
498
559
return DO_INTERSECT;