blob: 4645f206e52ff14c20c04ec9601d20725339197b [file] [log] [blame]
Austin Schuh3333ec72022-12-29 16:21:06 -08001/* Copyright (C) 2013-2016, The Regents of The University of Michigan.
2All rights reserved.
3This software was developed in the APRIL Robotics Lab under the
4direction of Edwin Olson, ebolson@umich.edu. This software may be
5available under alternative licensing terms; contact the address above.
6Redistribution and use in source and binary forms, with or without
7modification, are permitted provided that the following conditions are met:
81. Redistributions of source code must retain the above copyright notice, this
9 list of conditions and the following disclaimer.
102. Redistributions in binary form must reproduce the above copyright notice,
11 this list of conditions and the following disclaimer in the documentation
12 and/or other materials provided with the distribution.
13THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23The views and conclusions contained in the software and documentation are those
24of the authors and should not be interpreted as representing official policies,
25either expressed or implied, of the Regents of The University of Michigan.
26*/
27
28#include <assert.h>
29#include <math.h>
30#include <stdio.h>
31#include <string.h>
32
33#include "g2d.h"
34#include "common/math_util.h"
35
36#ifdef _WIN32
37static inline long int random(void)
38{
39 return rand();
40}
41#endif
42
43double g2d_distance(const double a[2], const double b[2])
44{
45 return sqrtf(sq(a[0]-b[0]) + sq(a[1]-b[1]));
46}
47
48zarray_t *g2d_polygon_create_empty()
49{
50 return zarray_create(sizeof(double[2]));
51}
52
53void g2d_polygon_add(zarray_t *poly, double v[2])
54{
55 zarray_add(poly, v);
56}
57
58zarray_t *g2d_polygon_create_data(double v[][2], int sz)
59{
60 zarray_t *points = g2d_polygon_create_empty();
61
62 for (int i = 0; i < sz; i++)
63 g2d_polygon_add(points, v[i]);
64
65 return points;
66}
67
68zarray_t *g2d_polygon_create_zeros(int sz)
69{
70 zarray_t *points = zarray_create(sizeof(double[2]));
71
72 double z[2] = { 0, 0 };
73
74 for (int i = 0; i < sz; i++)
75 zarray_add(points, z);
76
77 return points;
78}
79
80void g2d_polygon_make_ccw(zarray_t *poly)
81{
82 // Step one: we want the points in counter-clockwise order.
83 // If the points are in clockwise order, we'll reverse them.
84 double total_theta = 0;
85 double last_theta = 0;
86
87 // Count the angle accumulated going around the polygon. If
88 // the sum is +2pi, it's CCW. Otherwise, we'll get -2pi.
89 int sz = zarray_size(poly);
90
91 for (int i = 0; i <= sz; i++) {
92 double p0[2], p1[2];
93 zarray_get(poly, i % sz, &p0);
94 zarray_get(poly, (i+1) % sz, &p1);
95
96 double this_theta = atan2(p1[1]-p0[1], p1[0]-p0[0]);
97
98 if (i > 0) {
99 double dtheta = mod2pi(this_theta-last_theta);
100 total_theta += dtheta;
101 }
102
103 last_theta = this_theta;
104 }
105
106 int ccw = (total_theta > 0);
107
108 // reverse order if necessary.
109 if (!ccw) {
110 for (int i = 0; i < sz / 2; i++) {
111 double a[2], b[2];
112
113 zarray_get(poly, i, a);
114 zarray_get(poly, sz-1-i, b);
115 zarray_set(poly, i, b, NULL);
116 zarray_set(poly, sz-1-i, a, NULL);
117 }
118 }
119}
120
121int g2d_polygon_contains_point_ref(const zarray_t *poly, double q[2])
122{
123 // use winding. If the point is inside the polygon, we'll wrap
124 // around it (accumulating 6.28 radians). If we're outside the
125 // polygon, we'll accumulate zero.
126 int psz = zarray_size(poly);
127
128 double acc_theta = 0;
129
130 double last_theta;
131
132 for (int i = 0; i <= psz; i++) {
133 double p[2];
134
135 zarray_get(poly, i % psz, &p);
136
137 double this_theta = atan2(q[1]-p[1], q[0]-p[0]);
138
139 if (i != 0)
140 acc_theta += mod2pi(this_theta - last_theta);
141
142 last_theta = this_theta;
143 }
144
145 return acc_theta > M_PI;
146}
147
148/*
149// sort by x coordinate, ascending
150static int g2d_convex_hull_sort(const void *_a, const void *_b)
151{
152 double *a = (double*) _a;
153 double *b = (double*) _b;
154
155 if (a[0] < b[0])
156 return -1;
157 if (a[0] == b[0])
158 return 0;
159 return 1;
160}
161*/
162
163/*
164zarray_t *g2d_convex_hull2(const zarray_t *points)
165{
166 zarray_t *hull = zarray_copy(points);
167
168 zarray_sort(hull, g2d_convex_hull_sort);
169
170 int hsz = zarray_size(hull);
171 int hout = 0;
172
173 for (int hin = 1; hin < hsz; hin++) {
174 double *p;
175 zarray_get_volatile(hull, i, &p);
176
177 // Everything to the right of hin is already convex. We now
178 // add one point, p, which begins "connected" by two
179 // (coincident) edges from the last right-most point to p.
180 double *last;
181 zarray_get_volatile(hull, hout, &last);
182
183 // We now remove points from the convex hull by moving
184 }
185
186 return hull;
187}
188*/
189
190// creates and returns a zarray(double[2]). The resulting polygon is
191// CCW and implicitly closed. Unnecessary colinear points are omitted.
192zarray_t *g2d_convex_hull(const zarray_t *points)
193{
194 zarray_t *hull = zarray_create(sizeof(double[2]));
195
196 // gift-wrap algorithm.
197
198 // step 1: find left most point.
199 int insz = zarray_size(points);
200
201 // must have at least 2 points. (XXX need 3?)
202 assert(insz >= 2);
203
204 double *pleft = NULL;
205 for (int i = 0; i < insz; i++) {
206 double *p;
207 zarray_get_volatile(points, i, &p);
208
209 if (pleft == NULL || p[0] < pleft[0])
210 pleft = p;
211 }
212
213 // cannot be NULL since there must be at least one point.
214 assert(pleft != NULL);
215
216 zarray_add(hull, pleft);
217
218 // step 2. gift wrap. Keep searching for points that make the
219 // smallest-angle left-hand turn. This implementation is carefully
220 // written to use only addition/subtraction/multiply. No division
221 // or sqrts. This guarantees exact results for integer-coordinate
222 // polygons (no rounding/precision problems).
223 double *p = pleft;
224
225 while (1) {
226 assert(p != NULL);
227
228 double *q = NULL;
229 double n0 = 0, n1 = 0; // the normal to the line (p, q) (not
230 // necessarily unit length).
231
232 // Search for the point q for which the line (p,q) is most "to
233 // the right of" the other points. (i.e., every time we find a
234 // point that is to the right of our current line, we change
235 // lines.)
236 for (int i = 0; i < insz; i++) {
237 double *thisq;
238 zarray_get_volatile(points, i, &thisq);
239
240 if (thisq == p)
241 continue;
242
243 // the first time we find another point, we initialize our
244 // value of q, forming the line (p,q)
245 if (q == NULL) {
246 q = thisq;
247 n0 = q[1] - p[1];
248 n1 = -q[0] + p[0];
249 } else {
250 // we already have a line (p,q). is point thisq RIGHT OF line (p, q)?
251 double e0 = thisq[0] - p[0], e1 = thisq[1] - p[1];
252 double dot = e0*n0 + e1*n1;
253
254 if (dot > 0) {
255 // it is. change our line.
256 q = thisq;
257 n0 = q[1] - p[1];
258 n1 = -q[0] + p[0];
259 }
260 }
261 }
262
263 // we must have elected *some* line, so long as there are at
264 // least 2 points in the polygon.
265 assert(q != NULL);
266
267 // loop completed?
268 if (q == pleft)
269 break;
270
271 int colinear = 0;
272
273 // is this new point colinear with the last two?
274 if (zarray_size(hull) > 1) {
275 double *o;
276 zarray_get_volatile(hull, zarray_size(hull) - 2, &o);
277
278 double e0 = o[0] - p[0];
279 double e1 = o[1] - p[1];
280
281 if (n0*e0 + n1*e1 == 0)
282 colinear = 1;
283 }
284
285 // if it is colinear, overwrite the last one.
286 if (colinear)
287 zarray_set(hull, zarray_size(hull)-1, q, NULL);
288 else
289 zarray_add(hull, q);
290
291 p = q;
292 }
293
294 return hull;
295}
296
297// Find point p on the boundary of poly that is closest to q.
298void g2d_polygon_closest_boundary_point(const zarray_t *poly, const double q[2], double *p)
299{
300 int psz = zarray_size(poly);
301 double min_dist = HUGE_VALF;
302
303 for (int i = 0; i < psz; i++) {
304 double *p0, *p1;
305
306 zarray_get_volatile(poly, i, &p0);
307 zarray_get_volatile(poly, (i+1) % psz, &p1);
308
309 g2d_line_segment_t seg;
310 g2d_line_segment_init_from_points(&seg, p0, p1);
311
312 double thisp[2];
313 g2d_line_segment_closest_point(&seg, q, thisp);
314
315 double dist = g2d_distance(q, thisp);
316 if (dist < min_dist) {
317 memcpy(p, thisp, sizeof(double[2]));
318 min_dist = dist;
319 }
320 }
321}
322
323int g2d_polygon_contains_point(const zarray_t *poly, double q[2])
324{
325 // use winding. If the point is inside the polygon, we'll wrap
326 // around it (accumulating 6.28 radians). If we're outside the
327 // polygon, we'll accumulate zero.
328 int psz = zarray_size(poly);
329 assert(psz > 0);
330
331 int last_quadrant;
332 int quad_acc = 0;
333
334 for (int i = 0; i <= psz; i++) {
335 double *p;
336
337 zarray_get_volatile(poly, i % psz, &p);
338
339 // p[0] < q[0] p[1] < q[1] quadrant
340 // 0 0 0
341 // 0 1 3
342 // 1 0 1
343 // 1 1 2
344
345 // p[1] < q[1] p[0] < q[0] quadrant
346 // 0 0 0
347 // 0 1 1
348 // 1 0 3
349 // 1 1 2
350
351 int quadrant;
352 if (p[0] < q[0])
353 quadrant = (p[1] < q[1]) ? 2 : 1;
354 else
355 quadrant = (p[1] < q[1]) ? 3 : 0;
356
357 if (i > 0) {
358 int dquadrant = quadrant - last_quadrant;
359
360 // encourage a jump table by mapping to small positive integers.
361 switch (dquadrant) {
362 case -3:
363 case 1:
364 quad_acc ++;
365 break;
366 case -1:
367 case 3:
368 quad_acc --;
369 break;
370 case 0:
371 break;
372 case -2:
373 case 2:
374 {
375 // get the previous point.
376 double *p0;
377 zarray_get_volatile(poly, i-1, &p0);
378
379 // Consider the points p0 and p (the points around the
380 //polygon that we are tracing) and the query point q.
381 //
382 // If we've moved diagonally across quadrants, we want
383 // to measure whether we have rotated +PI radians or
384 // -PI radians. We can test this by computing the dot
385 // product of vector (p0-q) with the vector
386 // perpendicular to vector (p-q)
387 double nx = p[1] - q[1];
388 double ny = -p[0] + q[0];
389
390 double dot = nx*(p0[0]-q[0]) + ny*(p0[1]-q[1]);
391 if (dot < 0)
392 quad_acc -= 2;
393 else
394 quad_acc += 2;
395
396 break;
397 }
398 }
399 }
400
401 last_quadrant = quadrant;
402 }
403
404 int v = (quad_acc >= 2) || (quad_acc <= -2);
405
406 #if 0
407 if (v != g2d_polygon_contains_point_ref(poly, q)) {
408 printf("FAILURE %d %d\n", v, quad_acc);
409 exit(-1);
410 }
411 #endif
412
413 return v;
414}
415
416void g2d_line_init_from_points(g2d_line_t *line, const double p0[2], const double p1[2])
417{
418 line->p[0] = p0[0];
419 line->p[1] = p0[1];
420 line->u[0] = p1[0]-p0[0];
421 line->u[1] = p1[1]-p0[1];
422 double mag = sqrtf(sq(line->u[0]) + sq(line->u[1]));
423
424 line->u[0] /= mag;
425 line->u[1] /= mag;
426}
427
428double g2d_line_get_coordinate(const g2d_line_t *line, const double q[2])
429{
430 return (q[0]-line->p[0])*line->u[0] + (q[1]-line->p[1])*line->u[1];
431}
432
433// Compute intersection of two line segments. If they intersect,
434// result is stored in p and 1 is returned. Otherwise, zero is
435// returned. p may be NULL.
436int g2d_line_intersect_line(const g2d_line_t *linea, const g2d_line_t *lineb, double *p)
437{
438 // this implementation is many times faster than the original,
439 // mostly due to avoiding a general-purpose LU decomposition in
440 // Matrix.inverse().
441 double m00, m01, m10, m11;
442 double i00, i01;
443 double b00, b10;
444
445 m00 = linea->u[0];
446 m01= -lineb->u[0];
447 m10 = linea->u[1];
448 m11= -lineb->u[1];
449
450 // determinant of m
451 double det = m00*m11-m01*m10;
452
453 // parallel lines?
454 if (fabs(det) < 0.00000001)
455 return 0;
456
457 // inverse of m
458 i00 = m11/det;
459 i01 = -m01/det;
460
461 b00 = lineb->p[0] - linea->p[0];
462 b10 = lineb->p[1] - linea->p[1];
463
464 double x00; //, x10;
465 x00 = i00*b00+i01*b10;
466
467 if (p != NULL) {
468 p[0] = linea->u[0]*x00 + linea->p[0];
469 p[1] = linea->u[1]*x00 + linea->p[1];
470 }
471
472 return 1;
473}
474
475
476void g2d_line_segment_init_from_points(g2d_line_segment_t *seg, const double p0[2], const double p1[2])
477{
478 g2d_line_init_from_points(&seg->line, p0, p1);
479 seg->p1[0] = p1[0];
480 seg->p1[1] = p1[1];
481}
482
483// Find the point p on segment seg that is closest to point q.
484void g2d_line_segment_closest_point(const g2d_line_segment_t *seg, const double *q, double *p)
485{
486 double a = g2d_line_get_coordinate(&seg->line, seg->line.p);
487 double b = g2d_line_get_coordinate(&seg->line, seg->p1);
488 double c = g2d_line_get_coordinate(&seg->line, q);
489
490 if (a < b)
491 c = dclamp(c, a, b);
492 else
493 c = dclamp(c, b, a);
494
495 p[0] = seg->line.p[0] + c * seg->line.u[0];
496 p[1] = seg->line.p[1] + c * seg->line.u[1];
497}
498
499// Compute intersection of two line segments. If they intersect,
500// result is stored in p and 1 is returned. Otherwise, zero is
501// returned. p may be NULL.
502int g2d_line_segment_intersect_segment(const g2d_line_segment_t *sega, const g2d_line_segment_t *segb, double *p)
503{
504 double tmp[2];
505
506 if (!g2d_line_intersect_line(&sega->line, &segb->line, tmp))
507 return 0;
508
509 double a = g2d_line_get_coordinate(&sega->line, sega->line.p);
510 double b = g2d_line_get_coordinate(&sega->line, sega->p1);
511 double c = g2d_line_get_coordinate(&sega->line, tmp);
512
513 // does intersection lie on the first line?
514 if ((c<a && c<b) || (c>a && c>b))
515 return 0;
516
517 a = g2d_line_get_coordinate(&segb->line, segb->line.p);
518 b = g2d_line_get_coordinate(&segb->line, segb->p1);
519 c = g2d_line_get_coordinate(&segb->line, tmp);
520
521 // does intersection lie on second line?
522 if ((c<a && c<b) || (c>a && c>b))
523 return 0;
524
525 if (p != NULL) {
526 p[0] = tmp[0];
527 p[1] = tmp[1];
528 }
529
530 return 1;
531}
532
533// Compute intersection of a line segment and a line. If they
534// intersect, result is stored in p and 1 is returned. Otherwise, zero
535// is returned. p may be NULL.
536int g2d_line_segment_intersect_line(const g2d_line_segment_t *seg, const g2d_line_t *line, double *p)
537{
538 double tmp[2];
539
540 if (!g2d_line_intersect_line(&seg->line, line, tmp))
541 return 0;
542
543 double a = g2d_line_get_coordinate(&seg->line, seg->line.p);
544 double b = g2d_line_get_coordinate(&seg->line, seg->p1);
545 double c = g2d_line_get_coordinate(&seg->line, tmp);
546
547 // does intersection lie on the first line?
548 if ((c<a && c<b) || (c>a && c>b))
549 return 0;
550
551 if (p != NULL) {
552 p[0] = tmp[0];
553 p[1] = tmp[1];
554 }
555
556 return 1;
557}
558
559// do the edges of polya and polyb collide? (Does NOT test for containment).
560int g2d_polygon_intersects_polygon(const zarray_t *polya, const zarray_t *polyb)
561{
562 // do any of the line segments collide? If so, the answer is no.
563
564 // dumb N^2 method.
565 for (int ia = 0; ia < zarray_size(polya); ia++) {
566 double pa0[2], pa1[2];
567 zarray_get(polya, ia, pa0);
568 zarray_get(polya, (ia+1)%zarray_size(polya), pa1);
569
570 g2d_line_segment_t sega;
571 g2d_line_segment_init_from_points(&sega, pa0, pa1);
572
573 for (int ib = 0; ib < zarray_size(polyb); ib++) {
574 double pb0[2], pb1[2];
575 zarray_get(polyb, ib, pb0);
576 zarray_get(polyb, (ib+1)%zarray_size(polyb), pb1);
577
578 g2d_line_segment_t segb;
579 g2d_line_segment_init_from_points(&segb, pb0, pb1);
580
581 if (g2d_line_segment_intersect_segment(&sega, &segb, NULL))
582 return 1;
583 }
584 }
585
586 return 0;
587}
588
589// does polya completely contain polyb?
590int g2d_polygon_contains_polygon(const zarray_t *polya, const zarray_t *polyb)
591{
592 // do any of the line segments collide? If so, the answer is no.
593 if (g2d_polygon_intersects_polygon(polya, polyb))
594 return 0;
595
596 // if none of the edges cross, then the polygon is either fully
597 // contained or fully outside.
598 double p[2];
599 zarray_get(polyb, 0, p);
600
601 return g2d_polygon_contains_point(polya, p);
602}
603
604// compute a point that is inside the polygon. (It may not be *far* inside though)
605void g2d_polygon_get_interior_point(const zarray_t *poly, double *p)
606{
607 // take the first three points, which form a triangle. Find the middle point
608 double a[2], b[2], c[2];
609
610 zarray_get(poly, 0, a);
611 zarray_get(poly, 1, b);
612 zarray_get(poly, 2, c);
613
614 p[0] = (a[0]+b[0]+c[0])/3;
615 p[1] = (a[1]+b[1]+c[1])/3;
616}
617
618int g2d_polygon_overlaps_polygon(const zarray_t *polya, const zarray_t *polyb)
619{
620 // do any of the line segments collide? If so, the answer is yes.
621 if (g2d_polygon_intersects_polygon(polya, polyb))
622 return 1;
623
624 // if none of the edges cross, then the polygon is either fully
625 // contained or fully outside.
626 double p[2];
627 g2d_polygon_get_interior_point(polyb, p);
628
629 if (g2d_polygon_contains_point(polya, p))
630 return 1;
631
632 g2d_polygon_get_interior_point(polya, p);
633
634 if (g2d_polygon_contains_point(polyb, p))
635 return 1;
636
637 return 0;
638}
639
640static int double_sort_up(const void *_a, const void *_b)
641{
642 double a = *((double*) _a);
643 double b = *((double*) _b);
644
645 if (a < b)
646 return -1;
647
648 if (a == b)
649 return 0;
650
651 return 1;
652}
653
654// Compute the crossings of the polygon along line y, storing them in
655// the array x. X must be allocated to be at least as long as
656// zarray_size(poly). X will be sorted, ready for
657// rasterization. Returns the number of intersections (and elements
658// written to x).
659/*
660 To rasterize, do something like this:
661
662 double res = 0.099;
663 for (double y = y0; y < y1; y += res) {
664 double xs[zarray_size(poly)];
665
666 int xsz = g2d_polygon_rasterize(poly, y, xs);
667 int xpos = 0;
668 int inout = 0; // start off "out"
669
670 for (double x = x0; x < x1; x += res) {
671 while (x > xs[xpos] && xpos < xsz) {
672 xpos++;
673 inout ^= 1;
674 }
675
676 if (inout)
677 printf("y");
678 else
679 printf(" ");
680 }
681 printf("\n");
682*/
683
684// returns the number of x intercepts
685int g2d_polygon_rasterize(const zarray_t *poly, double y, double *x)
686{
687 int sz = zarray_size(poly);
688
689 g2d_line_t line;
690 if (1) {
691 double p0[2] = { 0, y };
692 double p1[2] = { 1, y };
693
694 g2d_line_init_from_points(&line, p0, p1);
695 }
696
697 int xpos = 0;
698
699 for (int i = 0; i < sz; i++) {
700 g2d_line_segment_t seg;
701 double *p0, *p1;
702 zarray_get_volatile(poly, i, &p0);
703 zarray_get_volatile(poly, (i+1)%sz, &p1);
704
705 g2d_line_segment_init_from_points(&seg, p0, p1);
706
707 double q[2];
708 if (g2d_line_segment_intersect_line(&seg, &line, q))
709 x[xpos++] = q[0];
710 }
711
712 qsort(x, xpos, sizeof(double), double_sort_up);
713
714 return xpos;
715}
716
717/*
718 /---(1,5)
719 (-2,4)-/ |
720 \ |
721 \ (1,2)--(2,2)\
722 \ \
723 \ \
724 (0,0)------------------(4,0)
725*/
726#if 0
727
728#include "timeprofile.h"
729
730int main(int argc, char *argv[])
731{
732 timeprofile_t *tp = timeprofile_create();
733
734 zarray_t *polya = g2d_polygon_create_data((double[][2]) {
735 { 0, 0},
736 { 4, 0},
737 { 2, 2},
738 { 1, 2},
739 { 1, 5},
740 { -2,4} }, 6);
741
742 zarray_t *polyb = g2d_polygon_create_data((double[][2]) {
743 { .1, .1},
744 { .5, .1},
745 { .1, .5 } }, 3);
746
747 zarray_t *polyc = g2d_polygon_create_data((double[][2]) {
748 { 3, 0},
749 { 5, 0},
750 { 5, 1} }, 3);
751
752 zarray_t *polyd = g2d_polygon_create_data((double[][2]) {
753 { 5, 5},
754 { 6, 6},
755 { 5, 6} }, 3);
756
757/*
758 5 L---K
759 4 |I--J
760 3 |H-G
761 2 |E-F
762 1 |D--C
763 0 A---B
764 01234
765*/
766 zarray_t *polyE = g2d_polygon_create_data((double[][2]) {
767 {0,0}, {4,0}, {4, 1}, {1,1},
768 {1,2}, {3,2}, {3,3}, {1,3},
769 {1,4}, {4,4}, {4,5}, {0,5}}, 12);
770
771 srand(0);
772
773 timeprofile_stamp(tp, "begin");
774
775 if (1) {
776 int niters = 100000;
777
778 for (int i = 0; i < niters; i++) {
779 double q[2];
780 q[0] = 10.0f * random() / RAND_MAX - 2;
781 q[1] = 10.0f * random() / RAND_MAX - 2;
782
783 g2d_polygon_contains_point(polyE, q);
784 }
785
786 timeprofile_stamp(tp, "fast");
787
788 for (int i = 0; i < niters; i++) {
789 double q[2];
790 q[0] = 10.0f * random() / RAND_MAX - 2;
791 q[1] = 10.0f * random() / RAND_MAX - 2;
792
793 g2d_polygon_contains_point_ref(polyE, q);
794 }
795
796 timeprofile_stamp(tp, "slow");
797
798 for (int i = 0; i < niters; i++) {
799 double q[2];
800 q[0] = 10.0f * random() / RAND_MAX - 2;
801 q[1] = 10.0f * random() / RAND_MAX - 2;
802
803 int v0 = g2d_polygon_contains_point(polyE, q);
804 int v1 = g2d_polygon_contains_point_ref(polyE, q);
805 assert(v0 == v1);
806 }
807
808 timeprofile_stamp(tp, "both");
809 timeprofile_display(tp);
810 }
811
812 if (1) {
813 zarray_t *poly = polyE;
814
815 double res = 0.399;
816 for (double y = 5.2; y >= -.5; y -= res) {
817 double xs[zarray_size(poly)];
818
819 int xsz = g2d_polygon_rasterize(poly, y, xs);
820 int xpos = 0;
821 int inout = 0; // start off "out"
822 for (double x = -3; x < 6; x += res) {
823 while (x > xs[xpos] && xpos < xsz) {
824 xpos++;
825 inout ^= 1;
826 }
827
828 if (inout)
829 printf("y");
830 else
831 printf(" ");
832 }
833 printf("\n");
834
835 for (double x = -3; x < 6; x += res) {
836 double q[2] = {x, y};
837 if (g2d_polygon_contains_point(poly, q))
838 printf("X");
839 else
840 printf(" ");
841 }
842 printf("\n");
843 }
844 }
845
846
847
848/*
849// CW order
850double p[][2] = { { 0, 0},
851{ -2, 4},
852{1, 5},
853{1, 2},
854{2, 2},
855{4, 0} };
856*/
857
858 double q[2] = { 10, 10 };
859 printf("0==%d\n", g2d_polygon_contains_point(polya, q));
860
861 q[0] = 1; q[1] = 1;
862 printf("1==%d\n", g2d_polygon_contains_point(polya, q));
863
864 q[0] = 3; q[1] = .5;
865 printf("1==%d\n", g2d_polygon_contains_point(polya, q));
866
867 q[0] = 1.2; q[1] = 2.1;
868 printf("0==%d\n", g2d_polygon_contains_point(polya, q));
869
870 printf("0==%d\n", g2d_polygon_contains_polygon(polya, polyb));
871
872 printf("0==%d\n", g2d_polygon_contains_polygon(polya, polyc));
873
874 printf("0==%d\n", g2d_polygon_contains_polygon(polya, polyd));
875
876 ////////////////////////////////////////////////////////
877 // Test convex hull
878 if (1) {
879 zarray_t *hull = g2d_convex_hull(polyE);
880
881 for (int k = 0; k < zarray_size(hull); k++) {
882 double *h;
883 zarray_get_volatile(hull, k, &h);
884
885 printf("%15f, %15f\n", h[0], h[1]);
886 }
887 }
888
889 for (int i = 0; i < 100000; i++) {
890 zarray_t *points = zarray_create(sizeof(double[2]));
891
892 for (int j = 0; j < 100; j++) {
893 double q[2];
894 q[0] = 10.0f * random() / RAND_MAX - 2;
895 q[1] = 10.0f * random() / RAND_MAX - 2;
896
897 zarray_add(points, q);
898 }
899
900 zarray_t *hull = g2d_convex_hull(points);
901 for (int j = 0; j < zarray_size(points); j++) {
902 double *q;
903 zarray_get_volatile(points, j, &q);
904
905 int on_edge;
906
907 double p[2];
908 g2d_polygon_closest_boundary_point(hull, q, p);
909 if (g2d_distance(q, p) < .00001)
910 on_edge = 1;
911
912 assert(on_edge || g2d_polygon_contains_point(hull, q));
913 }
914
915 zarray_destroy(hull);
916 zarray_destroy(points);
917 }
918}
919#endif