1 | /* ptinpoly.c - point in polygon inside/outside code. |
---|
2 | |
---|
3 | by Eric Haines, 3D/Eye Inc, erich@eye.com |
---|
4 | |
---|
5 | This code contains the following algorithms: |
---|
6 | crossings - count the crossing made by a ray from the test point |
---|
7 | crossings-multiply - as above, but avoids a division; often a bit faster |
---|
8 | angle summation - sum the angle formed by point and vertex pairs |
---|
9 | weiler angle summation - sum the angles using quad movements |
---|
10 | half-plane testing - test triangle fan using half-space planes |
---|
11 | barycentric coordinates - test triangle fan w/barycentric coords |
---|
12 | spackman barycentric - preprocessed barycentric coordinates |
---|
13 | trapezoid testing - bin sorting algorithm |
---|
14 | grid testing - grid imposed on polygon |
---|
15 | exterior test - for convex polygons, check exterior of polygon |
---|
16 | inclusion test - for convex polygons, use binary search for edge. |
---|
17 | |
---|
18 | if a no preprocessing and nor extra storage is available use the |
---|
19 | Crossings test. |
---|
20 | if a little preprocessing and extra storage is available: |
---|
21 | - For general polygons |
---|
22 | * with few sides, use the half-plane or spackman test |
---|
23 | * with many sides use the crossings test |
---|
24 | - For convex polygons |
---|
25 | * with few sides, use the hybrid half-plane or spackman test |
---|
26 | * with many sides use the inclusion test |
---|
27 | if preprocessing and extra storage is available in abundance, use the |
---|
28 | Grid test, except for perhaps triangles. |
---|
29 | */ |
---|
30 | |
---|
31 | #include <stdio.h> |
---|
32 | #include <stdlib.h> |
---|
33 | #include <math.h> |
---|
34 | #include "ptinpoly.h" |
---|
35 | |
---|
36 | #define X 0 |
---|
37 | #define Y 1 |
---|
38 | |
---|
39 | #ifndef TRUE |
---|
40 | #define TRUE 1 |
---|
41 | #define FALSE 0 |
---|
42 | #endif |
---|
43 | |
---|
44 | #ifndef HUGE |
---|
45 | #define HUGE 1.797693134862315e+308 |
---|
46 | #endif |
---|
47 | |
---|
48 | #ifndef M_PI |
---|
49 | #define M_PI 3.14159265358979323846 |
---|
50 | #endif |
---|
51 | |
---|
52 | /* test if a & b are within epsilon. Favors cases where a < b */ |
---|
53 | #define Near(a,b,eps) ( ((b)-(eps)<(a)) && ((a)-(eps)<(b)) ) |
---|
54 | |
---|
55 | #define MALLOC_CHECK( a ) if ( !(a) ) { \ |
---|
56 | fprintf( stderr, "out of memory\n" ) ; \ |
---|
57 | exit(1) ; \ |
---|
58 | } |
---|
59 | |
---|
60 | |
---|
61 | /* ======= Crossings algorithm ============================================ */ |
---|
62 | |
---|
63 | /* Shoot a test ray along +X axis. The strategy, from MacMartin, is to |
---|
64 | * compare vertex Y values to the testing point's Y and quickly discard |
---|
65 | * edges which are entirely to one side of the test ray. |
---|
66 | * |
---|
67 | * Input 2D polygon _pgon_ with _numverts_ number of vertices and test point |
---|
68 | * _point_, returns 1 if inside, 0 if outside. WINDING and CONVEX can be |
---|
69 | * defined for this test. |
---|
70 | */ |
---|
71 | int CrossingsTest( pgon, numverts, point ) |
---|
72 | double pgon[][2] ; |
---|
73 | int numverts ; |
---|
74 | double point[2] ; |
---|
75 | { |
---|
76 | #ifdef WINDING |
---|
77 | register int crossings ; |
---|
78 | #endif |
---|
79 | register int j, yflag0, yflag1, inside_flag, xflag0 ; |
---|
80 | register double ty, tx, *vtx0, *vtx1 ; |
---|
81 | #ifdef CONVEX |
---|
82 | register int line_flag ; |
---|
83 | #endif |
---|
84 | |
---|
85 | tx = point[X] ; |
---|
86 | ty = point[Y] ; |
---|
87 | |
---|
88 | vtx0 = pgon[numverts-1] ; |
---|
89 | /* get test bit for above/below X axis */ |
---|
90 | yflag0 = ( vtx0[Y] >= ty ) ; |
---|
91 | vtx1 = pgon[0] ; |
---|
92 | |
---|
93 | #ifdef WINDING |
---|
94 | crossings = 0 ; |
---|
95 | #else |
---|
96 | inside_flag = 0 ; |
---|
97 | #endif |
---|
98 | #ifdef CONVEX |
---|
99 | line_flag = 0 ; |
---|
100 | #endif |
---|
101 | for ( j = numverts+1 ; --j ; ) { |
---|
102 | |
---|
103 | yflag1 = ( vtx1[Y] >= ty ) ; |
---|
104 | /* check if endpoints straddle (are on opposite sides) of X axis |
---|
105 | * (i.e. the Y's differ); if so, +X ray could intersect this edge. |
---|
106 | */ |
---|
107 | if ( yflag0 != yflag1 ) { |
---|
108 | xflag0 = ( vtx0[X] >= tx ) ; |
---|
109 | /* check if endpoints are on same side of the Y axis (i.e. X's |
---|
110 | * are the same); if so, it's easy to test if edge hits or misses. |
---|
111 | */ |
---|
112 | if ( xflag0 == ( vtx1[X] >= tx ) ) { |
---|
113 | |
---|
114 | /* if edge's X values both right of the point, must hit */ |
---|
115 | #ifdef WINDING |
---|
116 | if ( xflag0 ) crossings += ( yflag0 ? -1 : 1 ) ; |
---|
117 | #else |
---|
118 | if ( xflag0 ) inside_flag = !inside_flag ; |
---|
119 | #endif |
---|
120 | } else { |
---|
121 | /* compute intersection of pgon segment with +X ray, note |
---|
122 | * if >= point's X; if so, the ray hits it. |
---|
123 | */ |
---|
124 | if ( (vtx1[X] - (vtx1[Y]-ty)* |
---|
125 | ( vtx0[X]-vtx1[X])/(vtx0[Y]-vtx1[Y])) >= tx ) { |
---|
126 | #ifdef WINDING |
---|
127 | crossings += ( yflag0 ? -1 : 1 ) ; |
---|
128 | #else |
---|
129 | inside_flag = !inside_flag ; |
---|
130 | #endif |
---|
131 | } |
---|
132 | } |
---|
133 | #ifdef CONVEX |
---|
134 | /* if this is second edge hit, then done testing */ |
---|
135 | if ( line_flag ) goto Exit ; |
---|
136 | |
---|
137 | /* note that one edge has been hit by the ray's line */ |
---|
138 | line_flag = TRUE ; |
---|
139 | #endif |
---|
140 | } |
---|
141 | |
---|
142 | /* move to next pair of vertices, retaining info as possible */ |
---|
143 | yflag0 = yflag1 ; |
---|
144 | vtx0 = vtx1 ; |
---|
145 | vtx1 += 2 ; |
---|
146 | } |
---|
147 | #ifdef CONVEX |
---|
148 | Exit: ; |
---|
149 | #endif |
---|
150 | #ifdef WINDING |
---|
151 | /* test if crossings is not zero */ |
---|
152 | inside_flag = (crossings != 0) ; |
---|
153 | #endif |
---|
154 | |
---|
155 | return( inside_flag ) ; |
---|
156 | } |
---|
157 | |
---|
158 | /* ======= Angle summation algorithm ======================================= */ |
---|
159 | |
---|
160 | /* Sum angles made by (vtxN to test point to vtxN+1), check if in proper |
---|
161 | * range to be inside. VERY SLOW, included for tutorial reasons (i.e. |
---|
162 | * to show why one should never use this algorithm). |
---|
163 | * |
---|
164 | * Input 2D polygon _pgon_ with _numverts_ number of vertices and test point |
---|
165 | * _point_, returns 1 if inside, 0 if outside. |
---|
166 | */ |
---|
167 | int AngleTest( pgon, numverts, point ) |
---|
168 | double pgon[][2] ; |
---|
169 | int numverts ; |
---|
170 | double point[2] ; |
---|
171 | { |
---|
172 | register double *vtx0, *vtx1, angle, len, vec0[2], vec1[2], vec_dot ; |
---|
173 | register int j ; |
---|
174 | int inside_flag ; |
---|
175 | |
---|
176 | /* sum the angles and see if answer mod 2*PI > PI */ |
---|
177 | vtx0 = pgon[numverts-1] ; |
---|
178 | vec0[X] = vtx0[X] - point[X] ; |
---|
179 | vec0[Y] = vtx0[Y] - point[Y] ; |
---|
180 | len = sqrt( vec0[X] * vec0[X] + vec0[Y] * vec0[Y] ) ; |
---|
181 | if ( len <= 0.0 ) { |
---|
182 | /* point and vertex coincide */ |
---|
183 | return( 1 ) ; |
---|
184 | } |
---|
185 | vec0[X] /= len ; |
---|
186 | vec0[Y] /= len ; |
---|
187 | |
---|
188 | angle = 0.0 ; |
---|
189 | for ( j = 0 ; j < numverts ; j++ ) { |
---|
190 | vtx1 = pgon[j] ; |
---|
191 | vec1[X] = vtx1[X] - point[X] ; |
---|
192 | vec1[Y] = vtx1[Y] - point[Y] ; |
---|
193 | len = sqrt( vec1[X] * vec1[X] + vec1[Y] * vec1[Y] ) ; |
---|
194 | if ( len <= 0.0 ) { |
---|
195 | /* point and vertex coincide */ |
---|
196 | return( 1 ) ; |
---|
197 | } |
---|
198 | vec1[X] /= len ; |
---|
199 | vec1[Y] /= len ; |
---|
200 | |
---|
201 | /* check if vec1 is to "left" or "right" of vec0 */ |
---|
202 | vec_dot = vec0[X] * vec1[X] + vec0[Y] * vec1[Y] ; |
---|
203 | if ( vec_dot < -1.0 ) { |
---|
204 | /* point is on edge, so always add 180 degrees. always |
---|
205 | * adding is not necessarily the right answer for |
---|
206 | * concave polygons and subtractive triangles. |
---|
207 | */ |
---|
208 | angle += M_PI ; |
---|
209 | } else if ( vec_dot < 1.0 ) { |
---|
210 | if ( vec0[X] * vec1[Y] - vec1[X] * vec0[Y] >= 0.0 ) { |
---|
211 | /* add angle due to dot product of vectors */ |
---|
212 | angle += acos( vec_dot ) ; |
---|
213 | } else { |
---|
214 | /* subtract angle due to dot product of vectors */ |
---|
215 | angle -= acos( vec_dot ) ; |
---|
216 | } |
---|
217 | } /* if vec_dot >= 1.0, angle does not change */ |
---|
218 | |
---|
219 | /* get to next point */ |
---|
220 | vtx0 = vtx1 ; |
---|
221 | vec0[X] = vec1[X] ; |
---|
222 | vec0[Y] = vec1[Y] ; |
---|
223 | } |
---|
224 | /* test if between PI and 3*PI, 5*PI and 7*PI, etc */ |
---|
225 | inside_flag = fmod( fabs(angle) + M_PI, 4.0*M_PI ) > 2.0*M_PI ; |
---|
226 | |
---|
227 | return( inside_flag ) ; |
---|
228 | } |
---|
229 | |
---|
230 | /* ======= Weiler algorithm ============================================ */ |
---|
231 | |
---|
232 | /* Track quadrant movements using Weiler's algorithm (elsewhere in Graphics |
---|
233 | * Gems IV). Algorithm has been optimized for testing purposes, but the |
---|
234 | * crossings algorithm is still faster. Included to provide timings. |
---|
235 | * |
---|
236 | * Input 2D polygon _pgon_ with _numverts_ number of vertices and test point |
---|
237 | * _point_, returns 1 if inside, 0 if outside. WINDING can be defined for |
---|
238 | * this test. |
---|
239 | */ |
---|
240 | |
---|
241 | #define QUADRANT( vtx, x, y ) \ |
---|
242 | (((vtx)[X]>(x)) ? ( ((vtx)[Y]>(y)) ? 0:3 ) : ( ((vtx)[Y]>(y)) ? 1:2 )) |
---|
243 | |
---|
244 | #define X_INTERCEPT( v0, v1, y ) \ |
---|
245 | ( (((v1)[X]-(v0)[X])/((v1)[Y]-(v0)[Y])) * ((y)-(v0)[Y]) + (v0)[X] ) |
---|
246 | |
---|
247 | int WeilerTest( pgon, numverts, point ) |
---|
248 | double pgon[][2] ; |
---|
249 | int numverts ; |
---|
250 | double point[2] ; |
---|
251 | { |
---|
252 | register int angle, qd, next_qd, delta, j ; |
---|
253 | register double ty, tx, *vtx0, *vtx1 ; |
---|
254 | int inside_flag ; |
---|
255 | |
---|
256 | tx = point[X] ; |
---|
257 | ty = point[Y] ; |
---|
258 | |
---|
259 | vtx0 = pgon[numverts-1] ; |
---|
260 | qd = QUADRANT( vtx0, tx, ty ) ; |
---|
261 | angle = 0 ; |
---|
262 | |
---|
263 | vtx1 = pgon[0] ; |
---|
264 | |
---|
265 | for ( j = numverts+1 ; --j ; ) { |
---|
266 | /* calculate quadrant and delta from last quadrant */ |
---|
267 | next_qd = QUADRANT( vtx1, tx, ty ) ; |
---|
268 | delta = next_qd - qd ; |
---|
269 | |
---|
270 | /* adjust delta and add it to total angle sum */ |
---|
271 | switch ( delta ) { |
---|
272 | case 0: /* do nothing */ |
---|
273 | break ; |
---|
274 | case -1: |
---|
275 | case 3: |
---|
276 | angle-- ; |
---|
277 | qd = next_qd ; |
---|
278 | break ; |
---|
279 | |
---|
280 | case 1: |
---|
281 | case -3: |
---|
282 | angle++ ; |
---|
283 | qd = next_qd ; |
---|
284 | break ; |
---|
285 | |
---|
286 | case 2: |
---|
287 | case -2: |
---|
288 | if (X_INTERCEPT( vtx0, vtx1, ty ) > tx ) { |
---|
289 | angle -= delta ; |
---|
290 | } else { |
---|
291 | angle += delta ; |
---|
292 | } |
---|
293 | qd = next_qd ; |
---|
294 | break ; |
---|
295 | } |
---|
296 | |
---|
297 | /* increment for next step */ |
---|
298 | vtx0 = vtx1 ; |
---|
299 | vtx1 += 2 ; |
---|
300 | } |
---|
301 | |
---|
302 | #ifdef WINDING |
---|
303 | /* simple windings test: if angle != 0, then point is inside */ |
---|
304 | inside_flag = ( angle != 0 ) ; |
---|
305 | #else |
---|
306 | /* Jordan test: if angle is +-4, 12, 20, etc then point is inside */ |
---|
307 | inside_flag = ( (angle/4) & 0x1 ) ; |
---|
308 | #endif |
---|
309 | |
---|
310 | return (inside_flag) ; |
---|
311 | } |
---|
312 | |
---|
313 | #undef QUADRANT |
---|
314 | #undef Y_INTERCEPT |
---|
315 | |
---|
316 | /* ======= Triangle half-plane algorithm ================================== */ |
---|
317 | |
---|
318 | /* Split the polygon into a fan of triangles and for each triangle test if |
---|
319 | * the point is inside of the three half-planes formed by the triangle's edges. |
---|
320 | * |
---|
321 | * Call setup with 2D polygon _pgon_ with _numverts_ number of vertices, |
---|
322 | * which returns a pointer to a plane set array. |
---|
323 | * Call testing procedure with a pointer to this array, _numverts_, and |
---|
324 | * test point _point_, returns 1 if inside, 0 if outside. |
---|
325 | * Call cleanup with pointer to plane set array to free space. |
---|
326 | * |
---|
327 | * SORT and CONVEX can be defined for this test. |
---|
328 | */ |
---|
329 | |
---|
330 | /* split polygons along set of x axes - call preprocess once */ |
---|
331 | pPlaneSet PlaneSetup( pgon, numverts ) |
---|
332 | double pgon[][2] ; |
---|
333 | int numverts ; |
---|
334 | { |
---|
335 | int i, p1, p2 ; |
---|
336 | double tx, ty, vx0, vy0 ; |
---|
337 | pPlaneSet pps, pps_return ; |
---|
338 | #ifdef SORT |
---|
339 | double len[3], len_temp ; |
---|
340 | int j ; |
---|
341 | PlaneSet ps_temp ; |
---|
342 | #ifdef CONVEX |
---|
343 | pPlaneSet pps_new ; |
---|
344 | pSizePlanePair p_size_pair ; |
---|
345 | #endif |
---|
346 | #endif |
---|
347 | |
---|
348 | pps = pps_return = |
---|
349 | (pPlaneSet)malloc( 3 * (numverts-2) * sizeof( PlaneSet )) ; |
---|
350 | MALLOC_CHECK( pps ) ; |
---|
351 | #ifdef CONVEX |
---|
352 | #ifdef SORT |
---|
353 | p_size_pair = |
---|
354 | (pSizePlanePair)malloc( (numverts-2) * sizeof( SizePlanePair ) ) ; |
---|
355 | MALLOC_CHECK( p_size_pair ) ; |
---|
356 | #endif |
---|
357 | #endif |
---|
358 | |
---|
359 | vx0 = pgon[0][X] ; |
---|
360 | vy0 = pgon[0][Y] ; |
---|
361 | |
---|
362 | for ( p1 = 1, p2 = 2 ; p2 < numverts ; p1++, p2++ ) { |
---|
363 | pps->vx = vy0 - pgon[p1][Y] ; |
---|
364 | pps->vy = pgon[p1][X] - vx0 ; |
---|
365 | pps->c = pps->vx * vx0 + pps->vy * vy0 ; |
---|
366 | #ifdef SORT |
---|
367 | len[0] = pps->vx * pps->vx + pps->vy * pps->vy ; |
---|
368 | #ifdef CONVEX |
---|
369 | #ifdef HYBRID |
---|
370 | pps->ext_flag = ( p1 == 1 ) ; |
---|
371 | #endif |
---|
372 | /* Sort triangles by areas, so compute (twice) the area here */ |
---|
373 | p_size_pair[p1-1].pps = pps ; |
---|
374 | p_size_pair[p1-1].size = |
---|
375 | ( pgon[0][X] * pgon[p1][Y] ) + |
---|
376 | ( pgon[p1][X] * pgon[p2][Y] ) + |
---|
377 | ( pgon[p2][X] * pgon[0][Y] ) - |
---|
378 | ( pgon[p1][X] * pgon[0][Y] ) - |
---|
379 | ( pgon[p2][X] * pgon[p1][Y] ) - |
---|
380 | ( pgon[0][X] * pgon[p2][Y] ) ; |
---|
381 | #endif |
---|
382 | #endif |
---|
383 | pps++ ; |
---|
384 | pps->vx = pgon[p1][Y] - pgon[p2][Y] ; |
---|
385 | pps->vy = pgon[p2][X] - pgon[p1][X] ; |
---|
386 | pps->c = pps->vx * pgon[p1][X] + pps->vy * pgon[p1][Y] ; |
---|
387 | #ifdef SORT |
---|
388 | len[1] = pps->vx * pps->vx + pps->vy * pps->vy ; |
---|
389 | #endif |
---|
390 | #ifdef CONVEX |
---|
391 | #ifdef HYBRID |
---|
392 | pps->ext_flag = TRUE ; |
---|
393 | #endif |
---|
394 | #endif |
---|
395 | pps++ ; |
---|
396 | pps->vx = pgon[p2][Y] - vy0 ; |
---|
397 | pps->vy = vx0 - pgon[p2][X] ; |
---|
398 | pps->c = pps->vx * pgon[p2][X] + pps->vy * pgon[p2][Y] ; |
---|
399 | #ifdef SORT |
---|
400 | len[2] = pps->vx * pps->vx + pps->vy * pps->vy ; |
---|
401 | #endif |
---|
402 | #ifdef CONVEX |
---|
403 | #ifdef HYBRID |
---|
404 | pps->ext_flag = ( p2 == numverts-1 ) ; |
---|
405 | #endif |
---|
406 | #endif |
---|
407 | |
---|
408 | /* find an average point which must be inside of the triangle */ |
---|
409 | tx = ( vx0 + pgon[p1][X] + pgon[p2][X] ) / 3.0 ; |
---|
410 | ty = ( vy0 + pgon[p1][Y] + pgon[p2][Y] ) / 3.0 ; |
---|
411 | |
---|
412 | /* check sense and reverse if test point is not thought to be inside |
---|
413 | * first triangle |
---|
414 | */ |
---|
415 | if ( pps->vx * tx + pps->vy * ty >= pps->c ) { |
---|
416 | /* back up to start of plane set */ |
---|
417 | pps -= 2 ; |
---|
418 | /* point is thought to be outside, so reverse sense of edge |
---|
419 | * normals so that it is correctly considered inside. |
---|
420 | */ |
---|
421 | for ( i = 0 ; i < 3 ; i++ ) { |
---|
422 | pps->vx = -pps->vx ; |
---|
423 | pps->vy = -pps->vy ; |
---|
424 | pps->c = -pps->c ; |
---|
425 | pps++ ; |
---|
426 | } |
---|
427 | } else { |
---|
428 | pps++ ; |
---|
429 | } |
---|
430 | |
---|
431 | #ifdef SORT |
---|
432 | /* sort the planes based on the edge lengths */ |
---|
433 | pps -= 3 ; |
---|
434 | for ( i = 0 ; i < 2 ; i++ ) { |
---|
435 | for ( j = i+1 ; j < 3 ; j++ ) { |
---|
436 | if ( len[i] < len[j] ) { |
---|
437 | ps_temp = pps[i] ; |
---|
438 | pps[i] = pps[j] ; |
---|
439 | pps[j] = ps_temp ; |
---|
440 | len_temp = len[i] ; |
---|
441 | len[i] = len[j] ; |
---|
442 | len[j] = len_temp ; |
---|
443 | } |
---|
444 | } |
---|
445 | } |
---|
446 | pps += 3 ; |
---|
447 | #endif |
---|
448 | } |
---|
449 | |
---|
450 | #ifdef CONVEX |
---|
451 | #ifdef SORT |
---|
452 | /* sort the triangles based on their areas */ |
---|
453 | qsort( p_size_pair, numverts-2, |
---|
454 | sizeof( SizePlanePair ), CompareSizePlanePairs ) ; |
---|
455 | |
---|
456 | /* make the plane sets match the sorted order */ |
---|
457 | for ( i = 0, pps = pps_return |
---|
458 | ; i < numverts-2 |
---|
459 | ; i++ ) { |
---|
460 | |
---|
461 | pps_new = p_size_pair[i].pps ; |
---|
462 | for ( j = 0 ; j < 3 ; j++, pps++, pps_new++ ) { |
---|
463 | ps_temp = *pps ; |
---|
464 | *pps = *pps_new ; |
---|
465 | *pps_new = ps_temp ; |
---|
466 | } |
---|
467 | } |
---|
468 | free( p_size_pair ) ; |
---|
469 | #endif |
---|
470 | #endif |
---|
471 | |
---|
472 | return( pps_return ) ; |
---|
473 | } |
---|
474 | |
---|
475 | #ifdef CONVEX |
---|
476 | #ifdef SORT |
---|
477 | int CompareSizePlanePairs( p_sp0, p_sp1 ) |
---|
478 | pSizePlanePair p_sp0, p_sp1 ; |
---|
479 | { |
---|
480 | if ( p_sp0->size == p_sp1->size ) { |
---|
481 | return( 0 ) ; |
---|
482 | } else { |
---|
483 | return( p_sp0->size > p_sp1->size ? -1 : 1 ) ; |
---|
484 | } |
---|
485 | } |
---|
486 | #endif |
---|
487 | #endif |
---|
488 | |
---|
489 | |
---|
490 | /* check point for inside of three "planes" formed by triangle edges */ |
---|
491 | int PlaneTest( p_plane_set, numverts, point ) |
---|
492 | pPlaneSet p_plane_set ; |
---|
493 | int numverts ; |
---|
494 | double point[2] ; |
---|
495 | { |
---|
496 | register pPlaneSet ps ; |
---|
497 | register int p2 ; |
---|
498 | #ifndef CONVEX |
---|
499 | register int inside_flag ; |
---|
500 | #endif |
---|
501 | register double tx, ty ; |
---|
502 | |
---|
503 | tx = point[X] ; |
---|
504 | ty = point[Y] ; |
---|
505 | |
---|
506 | #ifndef CONVEX |
---|
507 | inside_flag = 0 ; |
---|
508 | #endif |
---|
509 | |
---|
510 | for ( ps = p_plane_set, p2 = numverts-1 ; --p2 ; ) { |
---|
511 | |
---|
512 | if ( ps->vx * tx + ps->vy * ty < ps->c ) { |
---|
513 | ps++ ; |
---|
514 | if ( ps->vx * tx + ps->vy * ty < ps->c ) { |
---|
515 | ps++ ; |
---|
516 | /* note: we make the third edge have a slightly different |
---|
517 | * equality condition, since this third edge is in fact |
---|
518 | * the next triangle's first edge. Not fool-proof, but |
---|
519 | * it doesn't hurt (better would be to keep track of the |
---|
520 | * triangle's area sign so we would know which kind of |
---|
521 | * triangle this is). Note that edge sorting nullifies |
---|
522 | * this special inequality, too. |
---|
523 | */ |
---|
524 | if ( ps->vx * tx + ps->vy * ty <= ps->c ) { |
---|
525 | /* point is inside polygon */ |
---|
526 | #ifdef CONVEX |
---|
527 | return( 1 ) ; |
---|
528 | #else |
---|
529 | inside_flag = !inside_flag ; |
---|
530 | #endif |
---|
531 | } |
---|
532 | #ifdef CONVEX |
---|
533 | #ifdef HYBRID |
---|
534 | /* check if outside exterior edge */ |
---|
535 | else if ( ps->ext_flag ) return( 0 ) ; |
---|
536 | #endif |
---|
537 | #endif |
---|
538 | ps++ ; |
---|
539 | } else { |
---|
540 | #ifdef CONVEX |
---|
541 | #ifdef HYBRID |
---|
542 | /* check if outside exterior edge */ |
---|
543 | if ( ps->ext_flag ) return( 0 ) ; |
---|
544 | #endif |
---|
545 | #endif |
---|
546 | /* get past last two plane tests */ |
---|
547 | ps += 2 ; |
---|
548 | } |
---|
549 | } else { |
---|
550 | #ifdef CONVEX |
---|
551 | #ifdef HYBRID |
---|
552 | /* check if outside exterior edge */ |
---|
553 | if ( ps->ext_flag ) return( 0 ) ; |
---|
554 | #endif |
---|
555 | #endif |
---|
556 | /* get past all three plane tests */ |
---|
557 | ps += 3 ; |
---|
558 | } |
---|
559 | } |
---|
560 | |
---|
561 | #ifdef CONVEX |
---|
562 | /* for convex, if we make it to here, all triangles were missed */ |
---|
563 | return( 0 ) ; |
---|
564 | #else |
---|
565 | return( inside_flag ) ; |
---|
566 | #endif |
---|
567 | } |
---|
568 | |
---|
569 | void PlaneCleanup( p_plane_set ) |
---|
570 | pPlaneSet p_plane_set ; |
---|
571 | { |
---|
572 | free( p_plane_set ) ; |
---|
573 | } |
---|
574 | |
---|
575 | /* ======= Barycentric algorithm ========================================== */ |
---|
576 | |
---|
577 | /* Split the polygon into a fan of triangles and for each triangle test if |
---|
578 | * the point has barycentric coordinates which are inside the triangle. |
---|
579 | * Similar to Badouel's code in Graphics Gems, with a little more efficient |
---|
580 | * coding. |
---|
581 | * |
---|
582 | * Input 2D polygon _pgon_ with _numverts_ number of vertices and test point |
---|
583 | * _point_, returns 1 if inside, 0 if outside. |
---|
584 | */ |
---|
585 | int BarycentricTest( pgon, numverts, point ) |
---|
586 | double pgon[][2] ; |
---|
587 | int numverts ; |
---|
588 | double point[2] ; |
---|
589 | { |
---|
590 | register double *pg1, *pg2, *pgend ; |
---|
591 | register double tx, ty, u0, u1, u2, v0, v1, vx0, vy0, alpha, beta, denom ; |
---|
592 | int inside_flag ; |
---|
593 | |
---|
594 | tx = point[X] ; |
---|
595 | ty = point[Y] ; |
---|
596 | vx0 = pgon[0][X] ; |
---|
597 | vy0 = pgon[0][Y] ; |
---|
598 | u0 = tx - vx0 ; |
---|
599 | v0 = ty - vy0 ; |
---|
600 | |
---|
601 | inside_flag = 0 ; |
---|
602 | pgend = pgon[numverts-1] ; |
---|
603 | for ( pg1 = pgon[1], pg2 = pgon[2] ; pg1 != pgend ; pg1+=2, pg2+=2 ) { |
---|
604 | |
---|
605 | u1 = pg1[X] - vx0 ; |
---|
606 | if ( u1 == 0.0 ) { |
---|
607 | |
---|
608 | /* 0 and 1 vertices have same X value */ |
---|
609 | |
---|
610 | /* zero area test - can be removed for convex testing */ |
---|
611 | u2 = pg2[X] - vx0 ; |
---|
612 | if ( ( u2 == 0.0 ) || |
---|
613 | |
---|
614 | /* compute beta and check bounds */ |
---|
615 | /* we use "<= 0.0" so that points on the shared interior |
---|
616 | * edge will (generally) be inside only one polygon. |
---|
617 | */ |
---|
618 | ( ( beta = u0 / u2 ) <= 0.0 ) || |
---|
619 | ( beta > 1.0 ) || |
---|
620 | |
---|
621 | /* zero area test - remove for convex testing */ |
---|
622 | ( ( v1 = pg1[Y] - vy0 ) == 0.0 ) || |
---|
623 | |
---|
624 | /* compute alpha and check bounds */ |
---|
625 | ( ( alpha = ( v0 - beta * |
---|
626 | ( pg2[Y] - vy0 ) ) / v1 ) < 0.0 ) ) { |
---|
627 | |
---|
628 | /* whew! missed! */ |
---|
629 | goto NextTri ; |
---|
630 | } |
---|
631 | |
---|
632 | } else { |
---|
633 | /* 0 and 1 vertices have different X value */ |
---|
634 | |
---|
635 | /* compute denom and check for zero area triangle - check |
---|
636 | * is not needed for convex polygon testing |
---|
637 | */ |
---|
638 | u2 = pg2[X] - vx0 ; |
---|
639 | v1 = pg1[Y] - vy0 ; |
---|
640 | denom = ( pg2[Y] - vy0 ) * u1 - u2 * v1 ; |
---|
641 | if ( ( denom == 0.0 ) || |
---|
642 | |
---|
643 | /* compute beta and check bounds */ |
---|
644 | /* we use "<= 0.0" so that points on the shared interior |
---|
645 | * edge will (generally) be inside only one polygon. |
---|
646 | */ |
---|
647 | ( ( beta = ( v0 * u1 - u0 * v1 ) / denom ) <= 0.0 ) || |
---|
648 | ( beta > 1.0 ) || |
---|
649 | |
---|
650 | /* compute alpha & check bounds */ |
---|
651 | ( ( alpha = ( u0 - beta * u2 ) / u1 ) < 0.0 ) ) { |
---|
652 | |
---|
653 | /* whew! missed! */ |
---|
654 | goto NextTri ; |
---|
655 | } |
---|
656 | } |
---|
657 | |
---|
658 | /* check gamma */ |
---|
659 | if ( alpha + beta <= 1.0 ) { |
---|
660 | /* survived */ |
---|
661 | inside_flag = !inside_flag ; |
---|
662 | } |
---|
663 | |
---|
664 | NextTri: ; |
---|
665 | } |
---|
666 | return( inside_flag ) ; |
---|
667 | } |
---|
668 | |
---|
669 | /* ======= Barycentric precompute (Spackman) algorithm ===================== */ |
---|
670 | |
---|
671 | /* Split the polygon into a fan of triangles and for each triangle test if |
---|
672 | * the point has barycentric coordinates which are inside the triangle. |
---|
673 | * Use Spackman's normalization method to precompute various parameters. |
---|
674 | * |
---|
675 | * Call setup with 2D polygon _pgon_ with _numverts_ number of vertices, |
---|
676 | * which returns a pointer to the array of the parameters records and the |
---|
677 | * number of parameter records created. |
---|
678 | * Call testing procedure with the first vertex in the polygon _pgon[0]_, |
---|
679 | * a pointer to this array, the number of parameter records, and test point |
---|
680 | * _point_, returns 1 if inside, 0 if outside. |
---|
681 | * Call cleanup with pointer to parameter record array to free space. |
---|
682 | * |
---|
683 | * SORT can be defined for this test. |
---|
684 | * (CONVEX could be added: see PlaneSetup and PlaneTest for method) |
---|
685 | */ |
---|
686 | pSpackmanSet SpackmanSetup( pgon, numverts, p_numrec ) |
---|
687 | double pgon[][2] ; |
---|
688 | int numverts ; |
---|
689 | int *p_numrec ; |
---|
690 | { |
---|
691 | int p1, p2, degen ; |
---|
692 | double denom, u1, v1, *pv[3] ; |
---|
693 | pSpackmanSet pss, pss_return ; |
---|
694 | #ifdef SORT |
---|
695 | double u[2], v[2], len[2], *pv_temp ; |
---|
696 | #endif |
---|
697 | |
---|
698 | pss = pss_return = |
---|
699 | (pSpackmanSet)malloc( (numverts-2) * sizeof( SpackmanSet )) ; |
---|
700 | MALLOC_CHECK( pss ) ; |
---|
701 | |
---|
702 | degen = 0 ; |
---|
703 | |
---|
704 | for ( p1 = 1, p2 = 2 ; p2 < numverts ; p1++, p2++ ) { |
---|
705 | |
---|
706 | pv[0] = pgon[0] ; |
---|
707 | pv[1] = pgon[p1] ; |
---|
708 | pv[2] = pgon[p2] ; |
---|
709 | |
---|
710 | #ifdef SORT |
---|
711 | /* Note that sorting can cause a mismatch of alpha/beta inequality |
---|
712 | * tests. In other words, test points on an interior line between |
---|
713 | * test triangles will often then be wrong. |
---|
714 | */ |
---|
715 | u[0] = pv[1][X] - pv[0][X] ; |
---|
716 | u[1] = pv[2][X] - pv[0][X] ; |
---|
717 | v[0] = pv[1][Y] - pv[0][Y] ; |
---|
718 | v[1] = pv[2][Y] - pv[0][Y] ; |
---|
719 | len[0] = u[0] * u[0] + v[0] * v[0] ; |
---|
720 | len[1] = u[1] * u[1] + v[1] * v[1] ; |
---|
721 | |
---|
722 | /* compare two edges touching anchor point and put longest first */ |
---|
723 | /* we don't sort all three edges because the anchor point and |
---|
724 | * values computed from it gets used for all triangles in the fan. |
---|
725 | */ |
---|
726 | if ( len[0] < len[1] ) { |
---|
727 | pv_temp = pv[1] ; |
---|
728 | pv[1] = pv[2] ; |
---|
729 | pv[2] = pv_temp ; |
---|
730 | } |
---|
731 | #endif |
---|
732 | |
---|
733 | u1 = pv[1][X] - pv[0][X] ; |
---|
734 | pss->u2 = pv[2][X] - pv[0][X] ; |
---|
735 | v1 = pv[1][Y] - pv[0][Y] ; |
---|
736 | pss->v2 = pv[2][Y] - pv[0][Y] ; |
---|
737 | pss->u1_nonzero = !( u1 == 0.0 ) ; |
---|
738 | if ( pss->u1_nonzero ) { |
---|
739 | /* not zero, so compute inverse */ |
---|
740 | pss->inv_u1 = 1.0 / u1 ; |
---|
741 | denom = pss->v2 * u1 - pss->u2 * v1 ; |
---|
742 | if ( denom == 0.0 ) { |
---|
743 | /* degenerate triangle, ignore it */ |
---|
744 | degen++ ; |
---|
745 | goto Skip ; |
---|
746 | } else { |
---|
747 | pss->u1p = u1 / denom ; |
---|
748 | pss->v1p = v1 / denom ; |
---|
749 | } |
---|
750 | } else { |
---|
751 | if ( pss->u2 == 0.0 ) { |
---|
752 | /* degenerate triangle, ignore it */ |
---|
753 | degen++ ; |
---|
754 | goto Skip ; |
---|
755 | } else { |
---|
756 | /* not zero, so compute inverse */ |
---|
757 | pss->inv_u2 = 1.0 / pss->u2 ; |
---|
758 | if ( v1 == 0.0 ) { |
---|
759 | /* degenerate triangle, ignore it */ |
---|
760 | degen++ ; |
---|
761 | goto Skip ; |
---|
762 | } else { |
---|
763 | pss->inv_v1 = 1.0 / v1 ; |
---|
764 | } |
---|
765 | } |
---|
766 | } |
---|
767 | |
---|
768 | pss++ ; |
---|
769 | Skip: ; |
---|
770 | } |
---|
771 | |
---|
772 | /* number of Spackman records */ |
---|
773 | *p_numrec = numverts - degen - 2 ; |
---|
774 | if ( degen ) { |
---|
775 | pss = pss_return = |
---|
776 | (pSpackmanSet)realloc( pss_return, |
---|
777 | (numverts-2-degen) * sizeof( SpackmanSet )) ; |
---|
778 | } |
---|
779 | |
---|
780 | return( pss_return ) ; |
---|
781 | } |
---|
782 | |
---|
783 | /* barycentric, a la Gems I and Spackman's normalization precompute */ |
---|
784 | int SpackmanTest( anchor, p_spackman_set, numrec, point ) |
---|
785 | double anchor[2] ; |
---|
786 | pSpackmanSet p_spackman_set ; |
---|
787 | int numrec ; |
---|
788 | double point[2] ; |
---|
789 | { |
---|
790 | register pSpackmanSet pss ; |
---|
791 | register int inside_flag ; |
---|
792 | register int nr ; |
---|
793 | register double tx, ty, vx0, vy0, u0, v0, alpha, beta ; |
---|
794 | |
---|
795 | tx = point[X] ; |
---|
796 | ty = point[Y] ; |
---|
797 | /* note that we really need only the first vertex of the polygon, |
---|
798 | * so do not really need to keep the whole polygon around. |
---|
799 | */ |
---|
800 | vx0 = anchor[X] ; |
---|
801 | vy0 = anchor[Y] ; |
---|
802 | u0 = tx - vx0 ; |
---|
803 | v0 = ty - vy0 ; |
---|
804 | |
---|
805 | inside_flag = 0 ; |
---|
806 | |
---|
807 | for ( pss = p_spackman_set, nr = numrec+1 ; --nr ; pss++ ) { |
---|
808 | |
---|
809 | if ( pss->u1_nonzero ) { |
---|
810 | /* 0 and 2 vertices have different X value */ |
---|
811 | |
---|
812 | /* compute beta and check bounds */ |
---|
813 | /* we use "<= 0.0" so that points on the shared interior edge |
---|
814 | * will (generally) be inside only one polygon. |
---|
815 | */ |
---|
816 | beta = ( v0 * pss->u1p - u0 * pss->v1p ) ; |
---|
817 | if ( ( beta <= 0.0 ) || ( beta > 1.0 ) || |
---|
818 | |
---|
819 | /* compute alpha & check bounds */ |
---|
820 | ( ( alpha = ( u0 - beta * pss->u2 ) * pss->inv_u1 ) |
---|
821 | < 0.0 ) ) { |
---|
822 | |
---|
823 | /* whew! missed! */ |
---|
824 | goto NextTri ; |
---|
825 | } |
---|
826 | } else { |
---|
827 | /* 0 and 2 vertices have same X value */ |
---|
828 | |
---|
829 | /* compute beta and check bounds */ |
---|
830 | /* we use "<= 0.0" so that points on the shared interior edge |
---|
831 | * will (generally) be inside only one polygon. |
---|
832 | */ |
---|
833 | beta = u0 * pss->inv_u2 ; |
---|
834 | if ( ( beta <= 0.0 ) || ( beta >= 1.0 ) || |
---|
835 | |
---|
836 | /* compute alpha and check bounds */ |
---|
837 | ( ( alpha = ( v0 - beta * pss->v2 ) * pss->inv_v1 ) |
---|
838 | < 0.0 ) ) { |
---|
839 | |
---|
840 | /* whew! missed! */ |
---|
841 | goto NextTri ; |
---|
842 | } |
---|
843 | } |
---|
844 | |
---|
845 | /* check gamma */ |
---|
846 | if ( alpha + beta <= 1.0 ) { |
---|
847 | /* survived */ |
---|
848 | inside_flag = !inside_flag ; |
---|
849 | } |
---|
850 | |
---|
851 | NextTri: ; |
---|
852 | } |
---|
853 | |
---|
854 | return( inside_flag ) ; |
---|
855 | } |
---|
856 | |
---|
857 | void SpackmanCleanup( p_spackman_set ) |
---|
858 | pSpackmanSet p_spackman_set ; |
---|
859 | { |
---|
860 | free( p_spackman_set ) ; |
---|
861 | } |
---|
862 | |
---|
863 | /* ======= Trapezoid (bin) algorithm ======================================= */ |
---|
864 | |
---|
865 | /* Split polygons along set of y bins and sorts the edge fragments. Testing |
---|
866 | * is done against these fragments. |
---|
867 | * |
---|
868 | * Call setup with 2D polygon _pgon_ with _numverts_ number of vertices, the |
---|
869 | * number of bins desired _bins_, and a pointer to a trapezoid structure |
---|
870 | * _p_trap_set_. |
---|
871 | * Call testing procedure with 2D polygon _pgon_ with _numverts_ number of |
---|
872 | * vertices, _p_trap_set_ pointer to trapezoid structure, and test point |
---|
873 | * _point_, returns 1 if inside, 0 if outside. |
---|
874 | * Call cleanup with pointer to trapezoid structure to free space. |
---|
875 | */ |
---|
876 | void TrapezoidSetup( pgon, numverts, bins, p_trap_set ) |
---|
877 | double pgon[][2] ; |
---|
878 | int numverts ; |
---|
879 | int bins ; |
---|
880 | pTrapezoidSet p_trap_set ; |
---|
881 | { |
---|
882 | double *vtx0, *vtx1, *vtxa, *vtxb, slope ; |
---|
883 | int i, j, bin_tot[TOT_BINS], ba, bb, id, full_cross, count ; |
---|
884 | double fba, fbb, vx0, vx1, dy, vy0 ; |
---|
885 | |
---|
886 | p_trap_set->bins = bins ; |
---|
887 | p_trap_set->trapz = (pTrapezoid)malloc( p_trap_set->bins * |
---|
888 | sizeof(Trapezoid)); |
---|
889 | MALLOC_CHECK( p_trap_set->trapz ) ; |
---|
890 | |
---|
891 | p_trap_set->minx = |
---|
892 | p_trap_set->maxx = pgon[0][X] ; |
---|
893 | p_trap_set->miny = |
---|
894 | p_trap_set->maxy = pgon[0][Y] ; |
---|
895 | |
---|
896 | for ( i = 1 ; i < numverts ; i++ ) { |
---|
897 | if ( p_trap_set->minx > (vx0 = pgon[i][X]) ) { |
---|
898 | p_trap_set->minx = vx0 ; |
---|
899 | } else if ( p_trap_set->maxx < vx0 ) { |
---|
900 | p_trap_set->maxx = vx0 ; |
---|
901 | } |
---|
902 | |
---|
903 | if ( p_trap_set->miny > (vy0 = pgon[i][Y]) ) { |
---|
904 | p_trap_set->miny = vy0 ; |
---|
905 | } else if ( p_trap_set->maxy < vy0 ) { |
---|
906 | p_trap_set->maxy = vy0 ; |
---|
907 | } |
---|
908 | } |
---|
909 | |
---|
910 | /* add a little to the bounds to ensure everything falls inside area */ |
---|
911 | p_trap_set->miny -= EPSILON * (p_trap_set->maxy-p_trap_set->miny) ; |
---|
912 | p_trap_set->maxy += EPSILON * (p_trap_set->maxy-p_trap_set->miny) ; |
---|
913 | |
---|
914 | p_trap_set->ydelta = |
---|
915 | (p_trap_set->maxy-p_trap_set->miny) / (double)p_trap_set->bins ; |
---|
916 | p_trap_set->inv_ydelta = 1.0 / p_trap_set->ydelta ; |
---|
917 | |
---|
918 | /* find how many locations to allocate for each bin */ |
---|
919 | for ( i = 0 ; i < p_trap_set->bins ; i++ ) { |
---|
920 | bin_tot[i] = 0 ; |
---|
921 | } |
---|
922 | |
---|
923 | vtx0 = pgon[numverts-1] ; |
---|
924 | for ( i = 0 ; i < numverts ; i++ ) { |
---|
925 | vtx1 = pgon[i] ; |
---|
926 | |
---|
927 | /* skip if Y's identical (edge has no effect) */ |
---|
928 | if ( vtx0[Y] != vtx1[Y] ) { |
---|
929 | |
---|
930 | if ( vtx0[Y] < vtx1[Y] ) { |
---|
931 | vtxa = vtx0 ; |
---|
932 | vtxb = vtx1 ; |
---|
933 | } else { |
---|
934 | vtxa = vtx1 ; |
---|
935 | vtxb = vtx0 ; |
---|
936 | } |
---|
937 | ba = (int)(( vtxa[Y]-p_trap_set->miny ) * p_trap_set->inv_ydelta) ; |
---|
938 | fbb = ( vtxb[Y] - p_trap_set->miny ) * p_trap_set->inv_ydelta ; |
---|
939 | bb = (int)fbb ; |
---|
940 | /* if high vertex ends on a boundary, don't go into next boundary */ |
---|
941 | if ( fbb - (double)bb == 0.0 ) { |
---|
942 | bb-- ; |
---|
943 | } |
---|
944 | |
---|
945 | /* mark the bins with this edge */ |
---|
946 | for ( j = ba ; j <= bb ; j++ ) { |
---|
947 | bin_tot[j]++ ; |
---|
948 | } |
---|
949 | } |
---|
950 | |
---|
951 | vtx0 = vtx1 ; |
---|
952 | } |
---|
953 | |
---|
954 | /* allocate the bin contents and fill in some basics */ |
---|
955 | for ( i = 0 ; i < p_trap_set->bins ; i++ ) { |
---|
956 | p_trap_set->trapz[i].edge_set = |
---|
957 | (pEdge*)malloc( bin_tot[i] * sizeof(pEdge) ) ; |
---|
958 | MALLOC_CHECK( p_trap_set->trapz[i].edge_set ) ; |
---|
959 | for ( j = 0 ; j < bin_tot[i] ; j++ ) { |
---|
960 | p_trap_set->trapz[i].edge_set[j] = |
---|
961 | (pEdge)malloc( sizeof(Edge) ) ; |
---|
962 | MALLOC_CHECK( p_trap_set->trapz[i].edge_set[j] ) ; |
---|
963 | } |
---|
964 | |
---|
965 | /* start these off at some awful values; refined below */ |
---|
966 | p_trap_set->trapz[i].minx = p_trap_set->maxx ; |
---|
967 | p_trap_set->trapz[i].maxx = p_trap_set->minx ; |
---|
968 | p_trap_set->trapz[i].count = 0 ; |
---|
969 | } |
---|
970 | |
---|
971 | /* now go through list yet again, putting edges in bins */ |
---|
972 | vtx0 = pgon[numverts-1] ; |
---|
973 | id = numverts-1 ; |
---|
974 | for ( i = 0 ; i < numverts ; i++ ) { |
---|
975 | vtx1 = pgon[i] ; |
---|
976 | |
---|
977 | /* we can skip edge if Y's are equal */ |
---|
978 | if ( vtx0[Y] != vtx1[Y] ) { |
---|
979 | if ( vtx0[Y] < vtx1[Y] ) { |
---|
980 | vtxa = vtx0 ; |
---|
981 | vtxb = vtx1 ; |
---|
982 | } else { |
---|
983 | vtxa = vtx1 ; |
---|
984 | vtxb = vtx0 ; |
---|
985 | } |
---|
986 | fba = ( vtxa[Y] - p_trap_set->miny ) * p_trap_set->inv_ydelta ; |
---|
987 | ba = (int)fba ; |
---|
988 | fbb = ( vtxb[Y] - p_trap_set->miny ) * p_trap_set->inv_ydelta ; |
---|
989 | bb = (int)fbb ; |
---|
990 | /* if high vertex ends on a boundary, don't go into it */ |
---|
991 | if ( fbb == (double)bb ) { |
---|
992 | bb-- ; |
---|
993 | } |
---|
994 | |
---|
995 | vx0 = vtxa[X] ; |
---|
996 | dy = vtxa[Y] - vtxb[Y] ; |
---|
997 | slope = p_trap_set->ydelta * ( vtxa[X] - vtxb[X] ) / dy ; |
---|
998 | |
---|
999 | /* set vx1 in case loop is not entered */ |
---|
1000 | vx1 = vx0 ; |
---|
1001 | full_cross = 0 ; |
---|
1002 | |
---|
1003 | for ( j = ba ; j < bb ; j++, vx0 = vx1 ) { |
---|
1004 | /* could increment vx1, but for greater accuracy recompute it */ |
---|
1005 | vx1 = vtxa[X] + ( (double)(j+1) - fba ) * slope ; |
---|
1006 | |
---|
1007 | count = p_trap_set->trapz[j].count++ ; |
---|
1008 | p_trap_set->trapz[j].edge_set[count]->id = id ; |
---|
1009 | p_trap_set->trapz[j].edge_set[count]->full_cross = full_cross; |
---|
1010 | TrapBound( j, count, vx0, vx1, p_trap_set ) ; |
---|
1011 | full_cross = 1 ; |
---|
1012 | } |
---|
1013 | |
---|
1014 | /* at last bin - fill as above, but with vx1 = vtxb[X] */ |
---|
1015 | vx0 = vx1 ; |
---|
1016 | vx1 = vtxb[X] ; |
---|
1017 | count = p_trap_set->trapz[bb].count++ ; |
---|
1018 | p_trap_set->trapz[bb].edge_set[count]->id = id ; |
---|
1019 | /* the last bin is never a full crossing */ |
---|
1020 | p_trap_set->trapz[bb].edge_set[count]->full_cross = 0 ; |
---|
1021 | TrapBound( bb, count, vx0, vx1, p_trap_set ) ; |
---|
1022 | } |
---|
1023 | |
---|
1024 | vtx0 = vtx1 ; |
---|
1025 | id = i ; |
---|
1026 | } |
---|
1027 | |
---|
1028 | /* finally, sort the bins' contents by minx */ |
---|
1029 | for ( i = 0 ; i < p_trap_set->bins ; i++ ) { |
---|
1030 | qsort( p_trap_set->trapz[i].edge_set, p_trap_set->trapz[i].count, |
---|
1031 | sizeof(pEdge), CompareEdges ) ; |
---|
1032 | } |
---|
1033 | } |
---|
1034 | |
---|
1035 | void TrapBound( j, count, vx0, vx1, p_trap_set ) |
---|
1036 | int j, count ; |
---|
1037 | double vx0, vx1 ; |
---|
1038 | pTrapezoidSet p_trap_set ; |
---|
1039 | { |
---|
1040 | double xt ; |
---|
1041 | |
---|
1042 | if ( vx0 > vx1 ) { |
---|
1043 | xt = vx0 ; |
---|
1044 | vx0 = vx1 ; |
---|
1045 | vx1 = xt ; |
---|
1046 | } |
---|
1047 | |
---|
1048 | if ( p_trap_set->trapz[j].minx > vx0 ) { |
---|
1049 | p_trap_set->trapz[j].minx = vx0 ; |
---|
1050 | } |
---|
1051 | if ( p_trap_set->trapz[j].maxx < vx1 ) { |
---|
1052 | p_trap_set->trapz[j].maxx = vx1 ; |
---|
1053 | } |
---|
1054 | p_trap_set->trapz[j].edge_set[count]->minx = vx0 ; |
---|
1055 | p_trap_set->trapz[j].edge_set[count]->maxx = vx1 ; |
---|
1056 | } |
---|
1057 | |
---|
1058 | /* used by qsort to sort */ |
---|
1059 | int CompareEdges( u, v ) |
---|
1060 | pEdge *u, *v ; |
---|
1061 | { |
---|
1062 | if ( (*u)->minx == (*v)->minx ) { |
---|
1063 | return( 0 ) ; |
---|
1064 | } else { |
---|
1065 | return( (*u)->minx < (*v)->minx ? -1 : 1 ) ; |
---|
1066 | } |
---|
1067 | } |
---|
1068 | |
---|
1069 | int TrapezoidTest( pgon, numverts, p_trap_set, point ) |
---|
1070 | double pgon[][2] ; |
---|
1071 | int numverts ; |
---|
1072 | pTrapezoidSet p_trap_set ; |
---|
1073 | double point[2] ; |
---|
1074 | { |
---|
1075 | int j, b, count, id ; |
---|
1076 | double tx, ty, *vtx0, *vtx1 ; |
---|
1077 | pEdge *pp_bin ; |
---|
1078 | pTrapezoid p_trap ; |
---|
1079 | int inside_flag ; |
---|
1080 | |
---|
1081 | inside_flag = 0 ; |
---|
1082 | |
---|
1083 | /* first, is point inside bounding rectangle? */ |
---|
1084 | if ( ( ty = point[Y] ) < p_trap_set->miny || |
---|
1085 | ty >= p_trap_set->maxy || |
---|
1086 | ( tx = point[X] ) < p_trap_set->minx || |
---|
1087 | tx >= p_trap_set->maxx ) { |
---|
1088 | |
---|
1089 | /* outside of box */ |
---|
1090 | return( 0 ) ; |
---|
1091 | } |
---|
1092 | |
---|
1093 | /* what bin are we in? */ |
---|
1094 | b = ( ty - p_trap_set->miny ) * p_trap_set->inv_ydelta ; |
---|
1095 | |
---|
1096 | /* find if we're inside this bin's bounds */ |
---|
1097 | if ( tx < (p_trap = &p_trap_set->trapz[b])->minx || |
---|
1098 | tx > p_trap->maxx ) { |
---|
1099 | |
---|
1100 | /* outside of box */ |
---|
1101 | return( 0 ) ; |
---|
1102 | } |
---|
1103 | |
---|
1104 | /* now search bin for crossings */ |
---|
1105 | pp_bin = p_trap->edge_set ; |
---|
1106 | count = p_trap->count ; |
---|
1107 | for ( j = 0 ; j < count ; j++, pp_bin++ ) { |
---|
1108 | if ( tx < (*pp_bin)->minx ) { |
---|
1109 | |
---|
1110 | /* all remaining edges are to right of point, so test them */ |
---|
1111 | do { |
---|
1112 | if ( (*pp_bin)->full_cross ) { |
---|
1113 | inside_flag = !inside_flag ; |
---|
1114 | } else { |
---|
1115 | id = (*pp_bin)->id ; |
---|
1116 | if ( ( ty <= pgon[id][Y] ) != |
---|
1117 | ( ty <= pgon[(id+1)%numverts][Y] ) ) { |
---|
1118 | |
---|
1119 | /* point crosses edge in Y, so must cross */ |
---|
1120 | inside_flag = !inside_flag ; |
---|
1121 | } |
---|
1122 | } |
---|
1123 | pp_bin++ ; |
---|
1124 | } while ( ++j < count ) ; |
---|
1125 | goto Exit; |
---|
1126 | |
---|
1127 | } else if ( tx < (*pp_bin)->maxx ) { |
---|
1128 | /* edge is overlapping point in X, check it */ |
---|
1129 | id = (*pp_bin)->id ; |
---|
1130 | vtx0 = pgon[id] ; |
---|
1131 | vtx1 = pgon[(id+1)%numverts] ; |
---|
1132 | |
---|
1133 | if ( (*pp_bin)->full_cross || |
---|
1134 | ( ty <= vtx0[Y] ) != ( ty <= vtx1[Y] ) ) { |
---|
1135 | |
---|
1136 | /* edge crosses in Y, so have to do full crossings test */ |
---|
1137 | if ( (vtx0[X] - |
---|
1138 | (vtx0[Y] - ty )* |
---|
1139 | ( vtx1[X]-vtx0[X])/(vtx1[Y]-vtx0[Y])) >= tx ) { |
---|
1140 | inside_flag = !inside_flag ; |
---|
1141 | } |
---|
1142 | } |
---|
1143 | |
---|
1144 | } /* else edge is to left of point, ignore it */ |
---|
1145 | } |
---|
1146 | |
---|
1147 | Exit: |
---|
1148 | return( inside_flag ) ; |
---|
1149 | } |
---|
1150 | |
---|
1151 | void TrapezoidCleanup( p_trap_set ) |
---|
1152 | pTrapezoidSet p_trap_set ; |
---|
1153 | { |
---|
1154 | int i, j, count ; |
---|
1155 | |
---|
1156 | for ( i = 0 ; i < p_trap_set->bins ; i++ ) { |
---|
1157 | /* all of these should have bin sets, but check just in case */ |
---|
1158 | if ( p_trap_set->trapz[i].edge_set ) { |
---|
1159 | count = p_trap_set->trapz[i].count ; |
---|
1160 | for ( j = 0 ; j < count ; j++ ) { |
---|
1161 | if ( p_trap_set->trapz[i].edge_set[j] ) { |
---|
1162 | free( p_trap_set->trapz[i].edge_set[j] ) ; |
---|
1163 | } |
---|
1164 | } |
---|
1165 | free( p_trap_set->trapz[i].edge_set ) ; |
---|
1166 | } |
---|
1167 | } |
---|
1168 | free( p_trap_set->trapz ) ; |
---|
1169 | } |
---|
1170 | |
---|
1171 | /* ======= Grid algorithm ================================================= */ |
---|
1172 | |
---|
1173 | /* Impose a grid upon the polygon and test only the local edges against the |
---|
1174 | * point. |
---|
1175 | * |
---|
1176 | * Call setup with 2D polygon _pgon_ with _numverts_ number of vertices, |
---|
1177 | * grid resolution _resolution_ and a pointer to a grid structure _p_gs_. |
---|
1178 | * Call testing procedure with a pointer to this array and test point _point_, |
---|
1179 | * returns 1 if inside, 0 if outside. |
---|
1180 | * Call cleanup with pointer to grid structure to free space. |
---|
1181 | */ |
---|
1182 | |
---|
1183 | /* Strategy for setup: |
---|
1184 | * Get bounds of polygon, allocate grid. |
---|
1185 | * "Walk" each edge of the polygon and note which edges have been crossed |
---|
1186 | * and what cells are entered (points on a grid edge are always considered |
---|
1187 | * to be above that edge). Keep a record of the edges overlapping a cell. |
---|
1188 | * For cells with edges, determine if any cell border has no edges passing |
---|
1189 | * through it and so can be used for shooting a test ray. |
---|
1190 | * Keep track of the parity of the x (horizontal) grid cell borders for |
---|
1191 | * use in determining whether the grid corners are inside or outside. |
---|
1192 | */ |
---|
1193 | void GridSetup( pgon, numverts, resolution, p_gs ) |
---|
1194 | double pgon[][2] ; |
---|
1195 | int numverts ; |
---|
1196 | int resolution ; |
---|
1197 | pGridSet p_gs ; |
---|
1198 | { |
---|
1199 | double *vtx0, *vtx1, *vtxa, *vtxb, *p_gl ; |
---|
1200 | int i, j, gc_clear_flags ; |
---|
1201 | double vx0, vx1, vy0, vy1, gxdiff, gydiff, eps ; |
---|
1202 | pGridCell p_gc, p_ngc ; |
---|
1203 | double xdiff, ydiff, tmax, inv_x, inv_y, xdir, ydir, t_near, tx, ty ; |
---|
1204 | double tgcx, tgcy ; |
---|
1205 | int gcx, gcy, sign_x ; |
---|
1206 | int y_flag, io_state ; |
---|
1207 | |
---|
1208 | p_gs->xres = p_gs->yres = resolution ; |
---|
1209 | p_gs->tot_cells = p_gs->xres * p_gs->yres ; |
---|
1210 | p_gs->glx = (double *)malloc( (p_gs->xres+1) * sizeof(double)); |
---|
1211 | MALLOC_CHECK( p_gs->glx ) ; |
---|
1212 | p_gs->gly = (double *)malloc( (p_gs->yres+1) * sizeof(double)); |
---|
1213 | MALLOC_CHECK( p_gs->gly ) ; |
---|
1214 | p_gs->gc = (pGridCell)malloc( p_gs->tot_cells * sizeof(GridCell)); |
---|
1215 | MALLOC_CHECK( p_gs->gc ) ; |
---|
1216 | |
---|
1217 | p_gs->minx = |
---|
1218 | p_gs->maxx = pgon[0][X] ; |
---|
1219 | p_gs->miny = |
---|
1220 | p_gs->maxy = pgon[0][Y] ; |
---|
1221 | |
---|
1222 | /* find bounds of polygon */ |
---|
1223 | for ( i = 1 ; i < numverts ; i++ ) { |
---|
1224 | vx0 = pgon[i][X] ; |
---|
1225 | if ( p_gs->minx > vx0 ) { |
---|
1226 | p_gs->minx = vx0 ; |
---|
1227 | } else if ( p_gs->maxx < vx0 ) { |
---|
1228 | p_gs->maxx = vx0 ; |
---|
1229 | } |
---|
1230 | |
---|
1231 | vy0 = pgon[i][Y] ; |
---|
1232 | if ( p_gs->miny > vy0 ) { |
---|
1233 | p_gs->miny = vy0 ; |
---|
1234 | } else if ( p_gs->maxy < vy0 ) { |
---|
1235 | p_gs->maxy = vy0 ; |
---|
1236 | } |
---|
1237 | } |
---|
1238 | |
---|
1239 | /* add a little to the bounds to ensure everything falls inside area */ |
---|
1240 | gxdiff = p_gs->maxx - p_gs->minx ; |
---|
1241 | gydiff = p_gs->maxy - p_gs->miny ; |
---|
1242 | p_gs->minx -= EPSILON * gxdiff ; |
---|
1243 | p_gs->maxx += EPSILON * gxdiff ; |
---|
1244 | p_gs->miny -= EPSILON * gydiff ; |
---|
1245 | p_gs->maxy += EPSILON * gydiff ; |
---|
1246 | |
---|
1247 | /* avoid roundoff problems near corners by not getting too close to them */ |
---|
1248 | eps = 1e-9 * ( gxdiff + gydiff ) ; |
---|
1249 | |
---|
1250 | /* use the new bounds to compute cell widths */ |
---|
1251 | TryAgain: |
---|
1252 | p_gs->xdelta = |
---|
1253 | (p_gs->maxx-p_gs->minx) / (double)p_gs->xres ; |
---|
1254 | p_gs->inv_xdelta = 1.0 / p_gs->xdelta ; |
---|
1255 | |
---|
1256 | p_gs->ydelta = |
---|
1257 | (p_gs->maxy-p_gs->miny) / (double)p_gs->yres ; |
---|
1258 | p_gs->inv_ydelta = 1.0 / p_gs->ydelta ; |
---|
1259 | |
---|
1260 | for ( i = 0, p_gl = p_gs->glx ; i < p_gs->xres ; i++ ) { |
---|
1261 | *p_gl++ = p_gs->minx + i * p_gs->xdelta ; |
---|
1262 | } |
---|
1263 | /* make last grid corner precisely correct */ |
---|
1264 | *p_gl = p_gs->maxx ; |
---|
1265 | |
---|
1266 | for ( i = 0, p_gl = p_gs->gly ; i < p_gs->yres ; i++ ) { |
---|
1267 | *p_gl++ = p_gs->miny + i * p_gs->ydelta ; |
---|
1268 | } |
---|
1269 | *p_gl = p_gs->maxy ; |
---|
1270 | |
---|
1271 | for ( i = 0, p_gc = p_gs->gc ; i < p_gs->tot_cells ; i++, p_gc++ ) { |
---|
1272 | p_gc->tot_edges = 0 ; |
---|
1273 | p_gc->gc_flags = 0x0 ; |
---|
1274 | p_gc->gr = NULL ; |
---|
1275 | } |
---|
1276 | |
---|
1277 | /* loop through edges and insert into grid structure */ |
---|
1278 | vtx0 = pgon[numverts-1] ; |
---|
1279 | for ( i = 0 ; i < numverts ; i++ ) { |
---|
1280 | vtx1 = pgon[i] ; |
---|
1281 | |
---|
1282 | if ( vtx0[Y] < vtx1[Y] ) { |
---|
1283 | vtxa = vtx0 ; |
---|
1284 | vtxb = vtx1 ; |
---|
1285 | } else { |
---|
1286 | vtxa = vtx1 ; |
---|
1287 | vtxb = vtx0 ; |
---|
1288 | } |
---|
1289 | |
---|
1290 | /* Set x variable for the direction of the ray */ |
---|
1291 | xdiff = vtxb[X] - vtxa[X] ; |
---|
1292 | ydiff = vtxb[Y] - vtxa[Y] ; |
---|
1293 | tmax = sqrt( xdiff * xdiff + ydiff * ydiff ) ; |
---|
1294 | |
---|
1295 | /* if edge is of 0 length, ignore it (useless edge) */ |
---|
1296 | if ( tmax == 0.0 ) goto NextEdge ; |
---|
1297 | |
---|
1298 | xdir = xdiff / tmax ; |
---|
1299 | ydir = ydiff / tmax ; |
---|
1300 | |
---|
1301 | gcx = (int)(( vtxa[X] - p_gs->minx ) * p_gs->inv_xdelta) ; |
---|
1302 | gcy = (int)(( vtxa[Y] - p_gs->miny ) * p_gs->inv_ydelta) ; |
---|
1303 | |
---|
1304 | /* get information about slopes of edge, etc */ |
---|
1305 | if ( vtxa[X] == vtxb[X] ) { |
---|
1306 | sign_x = 0 ; |
---|
1307 | tx = HUGE ; |
---|
1308 | } else { |
---|
1309 | inv_x = tmax / xdiff ; |
---|
1310 | tx = p_gs->xdelta * (double)gcx + p_gs->minx - vtxa[X] ; |
---|
1311 | if ( vtxa[X] < vtxb[X] ) { |
---|
1312 | sign_x = 1 ; |
---|
1313 | tx += p_gs->xdelta ; |
---|
1314 | tgcx = p_gs->xdelta * inv_x ; |
---|
1315 | } else { |
---|
1316 | sign_x = -1 ; |
---|
1317 | tgcx = -p_gs->xdelta * inv_x ; |
---|
1318 | } |
---|
1319 | tx *= inv_x ; |
---|
1320 | } |
---|
1321 | |
---|
1322 | if ( vtxa[Y] == vtxb[Y] ) { |
---|
1323 | ty = HUGE ; |
---|
1324 | } else { |
---|
1325 | inv_y = tmax / ydiff ; |
---|
1326 | ty = (p_gs->ydelta * (double)(gcy+1) + p_gs->miny - vtxa[Y]) |
---|
1327 | * inv_y ; |
---|
1328 | tgcy = p_gs->ydelta * inv_y ; |
---|
1329 | } |
---|
1330 | |
---|
1331 | p_gc = &p_gs->gc[gcy*p_gs->xres+gcx] ; |
---|
1332 | |
---|
1333 | vx0 = vtxa[X] ; |
---|
1334 | vy0 = vtxa[Y] ; |
---|
1335 | |
---|
1336 | t_near = 0.0 ; |
---|
1337 | |
---|
1338 | do { |
---|
1339 | /* choose the next boundary, but don't move yet */ |
---|
1340 | if ( tx <= ty ) { |
---|
1341 | gcx += sign_x ; |
---|
1342 | |
---|
1343 | ty -= tx ; |
---|
1344 | t_near += tx ; |
---|
1345 | tx = tgcx ; |
---|
1346 | |
---|
1347 | /* note which edge is hit when leaving this cell */ |
---|
1348 | if ( t_near < tmax ) { |
---|
1349 | if ( sign_x > 0 ) { |
---|
1350 | p_gc->gc_flags |= GC_R_EDGE_HIT ; |
---|
1351 | vx1 = p_gs->glx[gcx] ; |
---|
1352 | } else { |
---|
1353 | p_gc->gc_flags |= GC_L_EDGE_HIT ; |
---|
1354 | vx1 = p_gs->glx[gcx+1] ; |
---|
1355 | } |
---|
1356 | |
---|
1357 | /* get new location */ |
---|
1358 | vy1 = t_near * ydir + vtxa[Y] ; |
---|
1359 | } else { |
---|
1360 | /* end of edge, so get exact value */ |
---|
1361 | vx1 = vtxb[X] ; |
---|
1362 | vy1 = vtxb[Y] ; |
---|
1363 | } |
---|
1364 | |
---|
1365 | y_flag = FALSE ; |
---|
1366 | |
---|
1367 | } else { |
---|
1368 | |
---|
1369 | gcy++ ; |
---|
1370 | |
---|
1371 | tx -= ty ; |
---|
1372 | t_near += ty ; |
---|
1373 | ty = tgcy ; |
---|
1374 | |
---|
1375 | /* note top edge is hit when leaving this cell */ |
---|
1376 | if ( t_near < tmax ) { |
---|
1377 | p_gc->gc_flags |= GC_T_EDGE_HIT ; |
---|
1378 | /* this toggles the parity bit */ |
---|
1379 | p_gc->gc_flags ^= GC_T_EDGE_PARITY ; |
---|
1380 | |
---|
1381 | /* get new location */ |
---|
1382 | vx1 = t_near * xdir + vtxa[X] ; |
---|
1383 | vy1 = p_gs->gly[gcy] ; |
---|
1384 | } else { |
---|
1385 | /* end of edge, so get exact value */ |
---|
1386 | vx1 = vtxb[X] ; |
---|
1387 | vy1 = vtxb[Y] ; |
---|
1388 | } |
---|
1389 | |
---|
1390 | y_flag = TRUE ; |
---|
1391 | } |
---|
1392 | |
---|
1393 | /* check for corner crossing, then mark the cell we're in */ |
---|
1394 | if ( !AddGridRecAlloc( p_gc, vx0, vy0, vx1, vy1, eps ) ) { |
---|
1395 | /* warning, danger - we have just crossed a corner. |
---|
1396 | * There are all kinds of topological messiness we could |
---|
1397 | * do to get around this case, but they're a headache. |
---|
1398 | * The simplest recovery is just to change the extents a bit |
---|
1399 | * and redo the meshing, so that hopefully no edges will |
---|
1400 | * perfectly cross a corner. Since it's a preprocess, we |
---|
1401 | * don't care too much about the time to do it. |
---|
1402 | */ |
---|
1403 | |
---|
1404 | /* clean out all grid records */ |
---|
1405 | for ( i = 0, p_gc = p_gs->gc |
---|
1406 | ; i < p_gs->tot_cells |
---|
1407 | ; i++, p_gc++ ) { |
---|
1408 | |
---|
1409 | if ( p_gc->gr ) { |
---|
1410 | free( p_gc->gr ) ; |
---|
1411 | } |
---|
1412 | } |
---|
1413 | |
---|
1414 | /* make the bounding box ever so slightly larger, hopefully |
---|
1415 | * changing the alignment of the corners. |
---|
1416 | */ |
---|
1417 | p_gs->minx -= EPSILON * gxdiff * 0.24 ; |
---|
1418 | p_gs->miny -= EPSILON * gydiff * 0.10 ; |
---|
1419 | |
---|
1420 | /* yes, it's the dreaded goto - run in fear for your lives! */ |
---|
1421 | goto TryAgain ; |
---|
1422 | } |
---|
1423 | |
---|
1424 | if ( t_near < tmax ) { |
---|
1425 | /* note how we're entering the next cell */ |
---|
1426 | /* TBD: could be done faster by incrementing index in the |
---|
1427 | * incrementing code, above */ |
---|
1428 | p_gc = &p_gs->gc[gcy*p_gs->xres+gcx] ; |
---|
1429 | |
---|
1430 | if ( y_flag ) { |
---|
1431 | p_gc->gc_flags |= GC_B_EDGE_HIT ; |
---|
1432 | /* this toggles the parity bit */ |
---|
1433 | p_gc->gc_flags ^= GC_B_EDGE_PARITY ; |
---|
1434 | } else { |
---|
1435 | p_gc->gc_flags |= |
---|
1436 | ( sign_x > 0 ) ? GC_L_EDGE_HIT : GC_R_EDGE_HIT ; |
---|
1437 | } |
---|
1438 | } |
---|
1439 | |
---|
1440 | vx0 = vx1 ; |
---|
1441 | vy0 = vy1 ; |
---|
1442 | } |
---|
1443 | /* have we gone further than the end of the edge? */ |
---|
1444 | while ( t_near < tmax ) ; |
---|
1445 | |
---|
1446 | NextEdge: |
---|
1447 | vtx0 = vtx1 ; |
---|
1448 | } |
---|
1449 | |
---|
1450 | /* the grid is all set up, now set up the inside/outside value of each |
---|
1451 | * corner. |
---|
1452 | */ |
---|
1453 | p_gc = p_gs->gc ; |
---|
1454 | p_ngc = &p_gs->gc[p_gs->xres] ; |
---|
1455 | |
---|
1456 | /* we know the bottom and top rows are all outside, so no flag is set */ |
---|
1457 | for ( i = 1; i < p_gs->yres ; i++ ) { |
---|
1458 | /* start outside */ |
---|
1459 | io_state = 0x0 ; |
---|
1460 | |
---|
1461 | for ( j = 0; j < p_gs->xres ; j++ ) { |
---|
1462 | |
---|
1463 | if ( io_state ) { |
---|
1464 | /* change cell left corners to inside */ |
---|
1465 | p_gc->gc_flags |= GC_TL_IN ; |
---|
1466 | p_ngc->gc_flags |= GC_BL_IN ; |
---|
1467 | } |
---|
1468 | |
---|
1469 | if ( p_gc->gc_flags & GC_T_EDGE_PARITY ) { |
---|
1470 | io_state = !io_state ; |
---|
1471 | } |
---|
1472 | |
---|
1473 | if ( io_state ) { |
---|
1474 | /* change cell right corners to inside */ |
---|
1475 | p_gc->gc_flags |= GC_TR_IN ; |
---|
1476 | p_ngc->gc_flags |= GC_BR_IN ; |
---|
1477 | } |
---|
1478 | |
---|
1479 | p_gc++ ; |
---|
1480 | p_ngc++ ; |
---|
1481 | } |
---|
1482 | } |
---|
1483 | |
---|
1484 | p_gc = p_gs->gc ; |
---|
1485 | for ( i = 0; i < p_gs->tot_cells ; i++ ) { |
---|
1486 | |
---|
1487 | /* reverse parity of edge clear (1==edge clear) */ |
---|
1488 | gc_clear_flags = p_gc->gc_flags ^ GC_ALL_EDGE_CLEAR ; |
---|
1489 | if ( gc_clear_flags & GC_L_EDGE_CLEAR ) { |
---|
1490 | p_gc->gc_flags |= GC_AIM_L ; |
---|
1491 | } else |
---|
1492 | if ( gc_clear_flags & GC_B_EDGE_CLEAR ) { |
---|
1493 | p_gc->gc_flags |= GC_AIM_B ; |
---|
1494 | } else |
---|
1495 | if ( gc_clear_flags & GC_R_EDGE_CLEAR ) { |
---|
1496 | p_gc->gc_flags |= GC_AIM_R ; |
---|
1497 | } else |
---|
1498 | if ( gc_clear_flags & GC_T_EDGE_CLEAR ) { |
---|
1499 | p_gc->gc_flags |= GC_AIM_T ; |
---|
1500 | } else { |
---|
1501 | /* all edges have something on them, do full test */ |
---|
1502 | p_gc->gc_flags |= GC_AIM_C ; |
---|
1503 | } |
---|
1504 | p_gc++ ; |
---|
1505 | } |
---|
1506 | } |
---|
1507 | |
---|
1508 | int AddGridRecAlloc( p_gc, xa, ya, xb, yb, eps ) |
---|
1509 | pGridCell p_gc ; |
---|
1510 | double xa,ya,xb,yb,eps ; |
---|
1511 | { |
---|
1512 | pGridRec p_gr ; |
---|
1513 | double slope, inv_slope ; |
---|
1514 | |
---|
1515 | if ( Near(ya, yb, eps) ) { |
---|
1516 | if ( Near(xa, xb, eps) ) { |
---|
1517 | /* edge is 0 length, so get rid of it */ |
---|
1518 | return( FALSE ) ; |
---|
1519 | } else { |
---|
1520 | /* horizontal line */ |
---|
1521 | slope = HUGE ; |
---|
1522 | inv_slope = 0.0 ; |
---|
1523 | } |
---|
1524 | } else { |
---|
1525 | if ( Near(xa, xb, eps) ) { |
---|
1526 | /* vertical line */ |
---|
1527 | slope = 0.0 ; |
---|
1528 | inv_slope = HUGE ; |
---|
1529 | } else { |
---|
1530 | slope = (xb-xa)/(yb-ya) ; |
---|
1531 | inv_slope = (yb-ya)/(xb-xa) ; |
---|
1532 | } |
---|
1533 | } |
---|
1534 | |
---|
1535 | p_gc->tot_edges++ ; |
---|
1536 | if ( p_gc->tot_edges <= 1 ) { |
---|
1537 | p_gc->gr = (pGridRec)malloc( sizeof(GridRec) ) ; |
---|
1538 | } else { |
---|
1539 | p_gc->gr = (pGridRec)realloc( p_gc->gr, |
---|
1540 | p_gc->tot_edges * sizeof(GridRec) ) ; |
---|
1541 | } |
---|
1542 | MALLOC_CHECK( p_gc->gr ) ; |
---|
1543 | p_gr = &p_gc->gr[p_gc->tot_edges-1] ; |
---|
1544 | |
---|
1545 | p_gr->slope = slope ; |
---|
1546 | p_gr->inv_slope = inv_slope ; |
---|
1547 | |
---|
1548 | p_gr->xa = xa ; |
---|
1549 | p_gr->ya = ya ; |
---|
1550 | if ( xa <= xb ) { |
---|
1551 | p_gr->minx = xa ; |
---|
1552 | p_gr->maxx = xb ; |
---|
1553 | } else { |
---|
1554 | p_gr->minx = xb ; |
---|
1555 | p_gr->maxx = xa ; |
---|
1556 | } |
---|
1557 | if ( ya <= yb ) { |
---|
1558 | p_gr->miny = ya ; |
---|
1559 | p_gr->maxy = yb ; |
---|
1560 | } else { |
---|
1561 | p_gr->miny = yb ; |
---|
1562 | p_gr->maxy = ya ; |
---|
1563 | } |
---|
1564 | |
---|
1565 | /* P2 - P1 */ |
---|
1566 | p_gr->ax = xb - xa ; |
---|
1567 | p_gr->ay = yb - ya ; |
---|
1568 | |
---|
1569 | return( TRUE ) ; |
---|
1570 | } |
---|
1571 | |
---|
1572 | /* Test point against grid and edges in the cell (if any). Algorithm: |
---|
1573 | * Check bounding box; if outside then return. |
---|
1574 | * Check cell point is inside; if simple inside or outside then return. |
---|
1575 | * Find which edge or corner is considered to be the best for testing and |
---|
1576 | * send a test ray towards it, counting the crossings. Add in the |
---|
1577 | * state of the edge or corner the ray went to and so determine the |
---|
1578 | * state of the point (inside or outside). |
---|
1579 | */ |
---|
1580 | int GridTest( p_gs, point ) |
---|
1581 | register pGridSet p_gs ; |
---|
1582 | double point[2] ; |
---|
1583 | { |
---|
1584 | int j, count, init_flag ; |
---|
1585 | pGridCell p_gc ; |
---|
1586 | pGridRec p_gr ; |
---|
1587 | double tx, ty, xcell, ycell, bx,by,cx,cy, cornerx, cornery ; |
---|
1588 | double alpha, beta, denom ; |
---|
1589 | unsigned short gc_flags ; |
---|
1590 | int inside_flag ; |
---|
1591 | |
---|
1592 | /* first, is point inside bounding rectangle? */ |
---|
1593 | if ( ( ty = point[Y] ) < p_gs->miny || |
---|
1594 | ty >= p_gs->maxy || |
---|
1595 | ( tx = point[X] ) < p_gs->minx || |
---|
1596 | tx >= p_gs->maxx ) { |
---|
1597 | |
---|
1598 | /* outside of box */ |
---|
1599 | inside_flag = FALSE ; |
---|
1600 | } else { |
---|
1601 | |
---|
1602 | /* what cell are we in? */ |
---|
1603 | ycell = ( ty - p_gs->miny ) * p_gs->inv_ydelta ; |
---|
1604 | xcell = ( tx - p_gs->minx ) * p_gs->inv_xdelta ; |
---|
1605 | p_gc = &p_gs->gc[((int)ycell)*p_gs->xres + (int)xcell] ; |
---|
1606 | |
---|
1607 | /* is cell simple? */ |
---|
1608 | count = p_gc->tot_edges ; |
---|
1609 | if ( count ) { |
---|
1610 | /* no, so find an edge which is free. */ |
---|
1611 | gc_flags = p_gc->gc_flags ; |
---|
1612 | p_gr = p_gc->gr ; |
---|
1613 | switch( gc_flags & GC_AIM ) { |
---|
1614 | case GC_AIM_L: |
---|
1615 | /* left edge is clear, shoot X- ray */ |
---|
1616 | /* note - this next statement requires that GC_BL_IN is 1 */ |
---|
1617 | inside_flag = gc_flags & GC_BL_IN ; |
---|
1618 | for ( j = count+1 ; --j ; p_gr++ ) { |
---|
1619 | /* test if y is between edges */ |
---|
1620 | if ( ty >= p_gr->miny && ty < p_gr->maxy ) { |
---|
1621 | if ( tx > p_gr->maxx ) { |
---|
1622 | inside_flag = !inside_flag ; |
---|
1623 | } else if ( tx > p_gr->minx ) { |
---|
1624 | /* full computation */ |
---|
1625 | if ( ( p_gr->xa - |
---|
1626 | ( p_gr->ya - ty ) * p_gr->slope ) < tx ) { |
---|
1627 | inside_flag = !inside_flag ; |
---|
1628 | } |
---|
1629 | } |
---|
1630 | } |
---|
1631 | } |
---|
1632 | break ; |
---|
1633 | |
---|
1634 | case GC_AIM_B: |
---|
1635 | /* bottom edge is clear, shoot Y+ ray */ |
---|
1636 | /* note - this next statement requires that GC_BL_IN is 1 */ |
---|
1637 | inside_flag = gc_flags & GC_BL_IN ; |
---|
1638 | for ( j = count+1 ; --j ; p_gr++ ) { |
---|
1639 | /* test if x is between edges */ |
---|
1640 | if ( tx >= p_gr->minx && tx < p_gr->maxx ) { |
---|
1641 | if ( ty > p_gr->maxy ) { |
---|
1642 | inside_flag = !inside_flag ; |
---|
1643 | } else if ( ty > p_gr->miny ) { |
---|
1644 | /* full computation */ |
---|
1645 | if ( ( p_gr->ya - ( p_gr->xa - tx ) * |
---|
1646 | p_gr->inv_slope ) < ty ) { |
---|
1647 | inside_flag = !inside_flag ; |
---|
1648 | } |
---|
1649 | } |
---|
1650 | } |
---|
1651 | } |
---|
1652 | break ; |
---|
1653 | |
---|
1654 | case GC_AIM_R: |
---|
1655 | /* right edge is clear, shoot X+ ray */ |
---|
1656 | inside_flag = (gc_flags & GC_TR_IN) ? 1 : 0 ; |
---|
1657 | |
---|
1658 | /* TBD: Note, we could have sorted the edges to be tested |
---|
1659 | * by miny or somesuch, and so be able to cut testing |
---|
1660 | * short when the list's miny > point.y . |
---|
1661 | */ |
---|
1662 | for ( j = count+1 ; --j ; p_gr++ ) { |
---|
1663 | /* test if y is between edges */ |
---|
1664 | if ( ty >= p_gr->miny && ty < p_gr->maxy ) { |
---|
1665 | if ( tx <= p_gr->minx ) { |
---|
1666 | inside_flag = !inside_flag ; |
---|
1667 | } else if ( tx <= p_gr->maxx ) { |
---|
1668 | /* full computation */ |
---|
1669 | if ( ( p_gr->xa - |
---|
1670 | ( p_gr->ya - ty ) * p_gr->slope ) >= tx ) { |
---|
1671 | inside_flag = !inside_flag ; |
---|
1672 | } |
---|
1673 | } |
---|
1674 | } |
---|
1675 | } |
---|
1676 | break ; |
---|
1677 | |
---|
1678 | case GC_AIM_T: |
---|
1679 | /* top edge is clear, shoot Y+ ray */ |
---|
1680 | inside_flag = (gc_flags & GC_TR_IN) ? 1 : 0 ; |
---|
1681 | for ( j = count+1 ; --j ; p_gr++ ) { |
---|
1682 | /* test if x is between edges */ |
---|
1683 | if ( tx >= p_gr->minx && tx < p_gr->maxx ) { |
---|
1684 | if ( ty <= p_gr->miny ) { |
---|
1685 | inside_flag = !inside_flag ; |
---|
1686 | } else if ( ty <= p_gr->maxy ) { |
---|
1687 | /* full computation */ |
---|
1688 | if ( ( p_gr->ya - ( p_gr->xa - tx ) * |
---|
1689 | p_gr->inv_slope ) >= ty ) { |
---|
1690 | inside_flag = !inside_flag ; |
---|
1691 | } |
---|
1692 | } |
---|
1693 | } |
---|
1694 | } |
---|
1695 | break ; |
---|
1696 | |
---|
1697 | case GC_AIM_C: |
---|
1698 | /* no edge is clear, bite the bullet and test |
---|
1699 | * against the bottom left corner. |
---|
1700 | * We use Franklin Antonio's algorithm (Graphics Gems III). |
---|
1701 | */ |
---|
1702 | /* TBD: Faster yet might be to test against the closest |
---|
1703 | * corner to the cell location, but our hope is that we |
---|
1704 | * rarely need to do this testing at all. |
---|
1705 | */ |
---|
1706 | inside_flag = ((gc_flags & GC_BL_IN) == GC_BL_IN) ; |
---|
1707 | init_flag = TRUE ; |
---|
1708 | |
---|
1709 | /* get lower left corner coordinate */ |
---|
1710 | cornerx = p_gs->glx[(int)xcell] ; |
---|
1711 | cornery = p_gs->gly[(int)ycell] ; |
---|
1712 | for ( j = count+1 ; --j ; p_gr++ ) { |
---|
1713 | |
---|
1714 | /* quick out test: if test point is |
---|
1715 | * less than minx & miny, edge cannot overlap. |
---|
1716 | */ |
---|
1717 | if ( tx >= p_gr->minx && ty >= p_gr->miny ) { |
---|
1718 | |
---|
1719 | /* quick test failed, now check if test point and |
---|
1720 | * corner are on different sides of edge. |
---|
1721 | */ |
---|
1722 | if ( init_flag ) { |
---|
1723 | /* Compute these at most once for test */ |
---|
1724 | /* P3 - P4 */ |
---|
1725 | bx = tx - cornerx ; |
---|
1726 | by = ty - cornery ; |
---|
1727 | init_flag = FALSE ; |
---|
1728 | } |
---|
1729 | denom = p_gr->ay * bx - p_gr->ax * by ; |
---|
1730 | if ( denom != 0.0 ) { |
---|
1731 | /* lines are not collinear, so continue */ |
---|
1732 | /* P1 - P3 */ |
---|
1733 | cx = p_gr->xa - tx ; |
---|
1734 | cy = p_gr->ya - ty ; |
---|
1735 | alpha = by * cx - bx * cy ; |
---|
1736 | if ( denom > 0.0 ) { |
---|
1737 | if ( alpha < 0.0 || alpha >= denom ) { |
---|
1738 | /* test edge not hit */ |
---|
1739 | goto NextEdge ; |
---|
1740 | } |
---|
1741 | beta = p_gr->ax * cy - p_gr->ay * cx ; |
---|
1742 | if ( beta < 0.0 || beta >= denom ) { |
---|
1743 | /* polygon edge not hit */ |
---|
1744 | goto NextEdge ; |
---|
1745 | } |
---|
1746 | } else { |
---|
1747 | if ( alpha > 0.0 || alpha <= denom ) { |
---|
1748 | /* test edge not hit */ |
---|
1749 | goto NextEdge ; |
---|
1750 | } |
---|
1751 | beta = p_gr->ax * cy - p_gr->ay * cx ; |
---|
1752 | if ( beta > 0.0 || beta <= denom ) { |
---|
1753 | /* polygon edge not hit */ |
---|
1754 | goto NextEdge ; |
---|
1755 | } |
---|
1756 | } |
---|
1757 | inside_flag = !inside_flag ; |
---|
1758 | } |
---|
1759 | |
---|
1760 | } |
---|
1761 | NextEdge: ; |
---|
1762 | } |
---|
1763 | break ; |
---|
1764 | } |
---|
1765 | } else { |
---|
1766 | /* simple cell, so if lower left corner is in, |
---|
1767 | * then cell is inside. |
---|
1768 | */ |
---|
1769 | inside_flag = p_gc->gc_flags & GC_BL_IN ; |
---|
1770 | } |
---|
1771 | } |
---|
1772 | |
---|
1773 | return( inside_flag ) ; |
---|
1774 | } |
---|
1775 | |
---|
1776 | void GridCleanup( p_gs ) |
---|
1777 | pGridSet p_gs ; |
---|
1778 | { |
---|
1779 | int i ; |
---|
1780 | pGridCell p_gc ; |
---|
1781 | |
---|
1782 | for ( i = 0, p_gc = p_gs->gc |
---|
1783 | ; i < p_gs->tot_cells |
---|
1784 | ; i++, p_gc++ ) { |
---|
1785 | |
---|
1786 | if ( p_gc->gr ) { |
---|
1787 | free( p_gc->gr ) ; |
---|
1788 | } |
---|
1789 | } |
---|
1790 | free( p_gs->glx ) ; |
---|
1791 | free( p_gs->gly ) ; |
---|
1792 | free( p_gs->gc ) ; |
---|
1793 | } |
---|
1794 | |
---|
1795 | /* ======= Exterior (convex only) algorithm =============================== */ |
---|
1796 | |
---|
1797 | /* Test the edges of the convex polygon against the point. If the point is |
---|
1798 | * outside any edge, the point is outside the polygon. |
---|
1799 | * |
---|
1800 | * Call setup with 2D polygon _pgon_ with _numverts_ number of vertices, |
---|
1801 | * which returns a pointer to a plane set array. |
---|
1802 | * Call testing procedure with a pointer to this array, _numverts_, and |
---|
1803 | * test point _point_, returns 1 if inside, 0 if outside. |
---|
1804 | * Call cleanup with pointer to plane set array to free space. |
---|
1805 | * |
---|
1806 | * RANDOM can be defined for this test. |
---|
1807 | * CONVEX must be defined for this test; it is not usable for general polygons. |
---|
1808 | */ |
---|
1809 | |
---|
1810 | #ifdef CONVEX |
---|
1811 | /* make exterior plane set */ |
---|
1812 | pPlaneSet ExteriorSetup( pgon, numverts ) |
---|
1813 | double pgon[][2] ; |
---|
1814 | int numverts ; |
---|
1815 | { |
---|
1816 | int p1, p2, flip_edge ; |
---|
1817 | pPlaneSet pps, pps_return ; |
---|
1818 | #ifdef RANDOM |
---|
1819 | int i, ind ; |
---|
1820 | PlaneSet ps_temp ; |
---|
1821 | #endif |
---|
1822 | |
---|
1823 | pps = pps_return = |
---|
1824 | (pPlaneSet)malloc( numverts * sizeof( PlaneSet )) ; |
---|
1825 | MALLOC_CHECK( pps ) ; |
---|
1826 | |
---|
1827 | /* take cross product of vertex to find handedness */ |
---|
1828 | flip_edge = (pgon[0][X] - pgon[1][X]) * (pgon[1][Y] - pgon[2][Y] ) > |
---|
1829 | (pgon[0][Y] - pgon[1][Y]) * (pgon[1][X] - pgon[2][X] ) ; |
---|
1830 | |
---|
1831 | /* Generate half-plane boundary equations now for faster testing later. |
---|
1832 | * vx & vy are the edge's normal, c is the offset from the origin. |
---|
1833 | */ |
---|
1834 | for ( p1 = numverts-1, p2 = 0 ; p2 < numverts ; p1 = p2, p2++, pps++ ) { |
---|
1835 | pps->vx = pgon[p1][Y] - pgon[p2][Y] ; |
---|
1836 | pps->vy = pgon[p2][X] - pgon[p1][X] ; |
---|
1837 | pps->c = pps->vx * pgon[p1][X] + pps->vy * pgon[p1][Y] ; |
---|
1838 | |
---|
1839 | /* check sense and reverse plane edge if need be */ |
---|
1840 | if ( flip_edge ) { |
---|
1841 | pps->vx = -pps->vx ; |
---|
1842 | pps->vy = -pps->vy ; |
---|
1843 | pps->c = -pps->c ; |
---|
1844 | } |
---|
1845 | } |
---|
1846 | |
---|
1847 | #ifdef RANDOM |
---|
1848 | /* Randomize the order of the edges to improve chance of early out */ |
---|
1849 | /* There are better orders, but the default order is the worst */ |
---|
1850 | for ( i = 0, pps = pps_return |
---|
1851 | ; i < numverts |
---|
1852 | ; i++ ) { |
---|
1853 | |
---|
1854 | ind = (int)(RAN01() * numverts ) ; |
---|
1855 | if ( ( ind < 0 ) || ( ind >= numverts ) ) { |
---|
1856 | fprintf( stderr, |
---|
1857 | "Yikes, the random number generator is returning values\n" ) ; |
---|
1858 | fprintf( stderr, |
---|
1859 | "outside the range [0.0,1.0), so please fix the code!\n" ) ; |
---|
1860 | ind = 0 ; |
---|
1861 | } |
---|
1862 | |
---|
1863 | /* swap edges */ |
---|
1864 | ps_temp = *pps ; |
---|
1865 | *pps = pps_return[ind] ; |
---|
1866 | pps_return[ind] = ps_temp ; |
---|
1867 | } |
---|
1868 | #endif |
---|
1869 | |
---|
1870 | return( pps_return ) ; |
---|
1871 | } |
---|
1872 | |
---|
1873 | /* Check point for outside of all planes */ |
---|
1874 | /* note that we don't need "pgon", since it's been processed into |
---|
1875 | * its corresponding PlaneSet. |
---|
1876 | */ |
---|
1877 | int ExteriorTest( p_ext_set, numverts, point ) |
---|
1878 | pPlaneSet p_ext_set ; |
---|
1879 | int numverts ; |
---|
1880 | double point[2] ; |
---|
1881 | { |
---|
1882 | register PlaneSet *pps ; |
---|
1883 | register int p0 ; |
---|
1884 | register double tx, ty ; |
---|
1885 | int inside_flag ; |
---|
1886 | |
---|
1887 | tx = point[X] ; |
---|
1888 | ty = point[Y] ; |
---|
1889 | |
---|
1890 | for ( p0 = numverts+1, pps = p_ext_set ; --p0 ; pps++ ) { |
---|
1891 | |
---|
1892 | /* test if the point is outside this edge */ |
---|
1893 | if ( pps->vx * tx + pps->vy * ty > pps->c ) { |
---|
1894 | return( 0 ) ; |
---|
1895 | } |
---|
1896 | } |
---|
1897 | /* if we make it to here, we were inside all edges */ |
---|
1898 | return( 1 ) ; |
---|
1899 | } |
---|
1900 | |
---|
1901 | void ExteriorCleanup( p_ext_set ) |
---|
1902 | pPlaneSet p_ext_set ; |
---|
1903 | { |
---|
1904 | free( p_ext_set ) ; |
---|
1905 | } |
---|
1906 | #endif |
---|
1907 | |
---|
1908 | /* ======= Inclusion (convex only) algorithm ============================== */ |
---|
1909 | |
---|
1910 | /* Create an efficiency structure (see Preparata) for the convex polygon which |
---|
1911 | * allows binary searching to find which edge to test the point against. This |
---|
1912 | * algorithm is O(log n). |
---|
1913 | * |
---|
1914 | * Call setup with 2D polygon _pgon_ with _numverts_ number of vertices, |
---|
1915 | * which returns a pointer to an inclusion anchor structure. |
---|
1916 | * Call testing procedure with a pointer to this structure and test point |
---|
1917 | * _point_, returns 1 if inside, 0 if outside. |
---|
1918 | * Call cleanup with pointer to inclusion anchor structure to free space. |
---|
1919 | * |
---|
1920 | * CONVEX must be defined for this test; it is not usable for general polygons. |
---|
1921 | */ |
---|
1922 | |
---|
1923 | #ifdef CONVEX |
---|
1924 | /* make inclusion wedge set */ |
---|
1925 | pInclusionAnchor InclusionSetup( pgon, numverts ) |
---|
1926 | double pgon[][2] ; |
---|
1927 | int numverts ; |
---|
1928 | { |
---|
1929 | int pc, p1, p2, flip_edge ; |
---|
1930 | double ax,ay, qx,qy, wx,wy, len ; |
---|
1931 | pInclusionAnchor pia ; |
---|
1932 | pInclusionSet pis ; |
---|
1933 | |
---|
1934 | /* double the first edge to avoid needing modulo during test search */ |
---|
1935 | pia = (pInclusionAnchor)malloc( sizeof( InclusionAnchor )) ; |
---|
1936 | MALLOC_CHECK( pia ) ; |
---|
1937 | pis = pia->pis = |
---|
1938 | (pInclusionSet)malloc( (numverts+1) * sizeof( InclusionSet )) ; |
---|
1939 | MALLOC_CHECK( pis ) ; |
---|
1940 | |
---|
1941 | pia->hi_start = numverts - 1 ; |
---|
1942 | |
---|
1943 | /* get average point to make wedges from */ |
---|
1944 | qx = qy = 0.0 ; |
---|
1945 | for ( p2 = 0 ; p2 < numverts ; p2++ ) { |
---|
1946 | qx += pgon[p2][X] ; |
---|
1947 | qy += pgon[p2][Y] ; |
---|
1948 | } |
---|
1949 | pia->qx = qx /= (double)numverts ; |
---|
1950 | pia->qy = qy /= (double)numverts ; |
---|
1951 | |
---|
1952 | /* take cross product of vertex to find handedness */ |
---|
1953 | pia->flip_edge = flip_edge = |
---|
1954 | (pgon[0][X] - pgon[1][X]) * (pgon[1][Y] - pgon[2][Y] ) > |
---|
1955 | (pgon[0][Y] - pgon[1][Y]) * (pgon[1][X] - pgon[2][X] ) ; |
---|
1956 | |
---|
1957 | |
---|
1958 | ax = pgon[0][X] - qx ; |
---|
1959 | ay = pgon[0][Y] - qy ; |
---|
1960 | len = sqrt( ax * ax + ay * ay ) ; |
---|
1961 | if ( len == 0.0 ) { |
---|
1962 | fprintf( stderr, "sorry, polygon for inclusion test is defective\n" ) ; |
---|
1963 | exit(1) ; |
---|
1964 | } |
---|
1965 | pia->ax = ax /= len ; |
---|
1966 | pia->ay = ay /= len ; |
---|
1967 | |
---|
1968 | /* loop through edges, and double last edge */ |
---|
1969 | for ( pc = p1 = 0, p2 = 1 |
---|
1970 | ; pc <= numverts |
---|
1971 | ; pc++, p1 = p2, p2 = (++p2)%numverts, pis++ ) { |
---|
1972 | |
---|
1973 | /* wedge border */ |
---|
1974 | wx = pgon[p1][X] - qx ; |
---|
1975 | wy = pgon[p1][Y] - qy ; |
---|
1976 | len = sqrt( wx * wx + wy * wy ) ; |
---|
1977 | wx /= len ; |
---|
1978 | wy /= len ; |
---|
1979 | |
---|
1980 | /* cosine of angle from anchor border to wedge border */ |
---|
1981 | pis->dot = ax * wx + ay * wy ; |
---|
1982 | /* sign from cross product */ |
---|
1983 | if ( ( ax * wy > ay * wx ) == flip_edge ) { |
---|
1984 | pis->dot = -2.0 - pis->dot ; |
---|
1985 | } |
---|
1986 | |
---|
1987 | /* edge */ |
---|
1988 | pis->ex = pgon[p1][Y] - pgon[p2][Y] ; |
---|
1989 | pis->ey = pgon[p2][X] - pgon[p1][X] ; |
---|
1990 | pis->ec = pis->ex * pgon[p1][X] + pis->ey * pgon[p1][Y] ; |
---|
1991 | |
---|
1992 | /* check sense and reverse plane eqns if need be */ |
---|
1993 | if ( flip_edge ) { |
---|
1994 | pis->ex = -pis->ex ; |
---|
1995 | pis->ey = -pis->ey ; |
---|
1996 | pis->ec = -pis->ec ; |
---|
1997 | } |
---|
1998 | } |
---|
1999 | /* set first angle a little > 1.0 and last < -3.0 just to be safe. */ |
---|
2000 | pia->pis[0].dot = -3.001 ; |
---|
2001 | pia->pis[numverts].dot = 1.001 ; |
---|
2002 | |
---|
2003 | return( pia ) ; |
---|
2004 | } |
---|
2005 | |
---|
2006 | /* Find wedge point is in by binary search, then test wedge */ |
---|
2007 | int InclusionTest( pia, point ) |
---|
2008 | pInclusionAnchor pia ; |
---|
2009 | double point[2] ; |
---|
2010 | { |
---|
2011 | register double tx, ty, len, dot ; |
---|
2012 | int inside_flag, lo, hi, ind ; |
---|
2013 | pInclusionSet pis ; |
---|
2014 | |
---|
2015 | tx = point[X] - pia->qx ; |
---|
2016 | ty = point[Y] - pia->qy ; |
---|
2017 | len = sqrt( tx * tx + ty * ty ) ; |
---|
2018 | /* check if point is exactly at anchor point (which is inside polygon) */ |
---|
2019 | if ( len == 0.0 ) return( 1 ) ; |
---|
2020 | tx /= len ; |
---|
2021 | ty /= len ; |
---|
2022 | |
---|
2023 | /* get dot product for searching */ |
---|
2024 | dot = pia->ax * tx + pia->ay * ty ; |
---|
2025 | if ( ( pia->ax * ty > pia->ay * tx ) == pia->flip_edge ) { |
---|
2026 | dot = -2.0 - dot ; |
---|
2027 | } |
---|
2028 | |
---|
2029 | /* binary search through angle list and find matching angle pair */ |
---|
2030 | lo = 0 ; |
---|
2031 | hi = pia->hi_start ; |
---|
2032 | while ( lo <= hi ) { |
---|
2033 | ind = (lo+hi)/ 2 ; |
---|
2034 | if ( dot < pia->pis[ind].dot ) { |
---|
2035 | hi = ind - 1 ; |
---|
2036 | } else if ( dot > pia->pis[ind+1].dot ) { |
---|
2037 | lo = ind + 1 ; |
---|
2038 | } else { |
---|
2039 | goto Foundit ; |
---|
2040 | } |
---|
2041 | } |
---|
2042 | /* should never reach here, but just in case... */ |
---|
2043 | fprintf( stderr, |
---|
2044 | "Hmmm, something weird happened - bad dot product %lg\n", dot); |
---|
2045 | |
---|
2046 | Foundit: |
---|
2047 | |
---|
2048 | /* test if the point is outside the wedge's exterior edge */ |
---|
2049 | pis = &pia->pis[ind] ; |
---|
2050 | inside_flag = ( pis->ex * point[X] + pis->ey * point[Y] <= pis->ec ) ; |
---|
2051 | |
---|
2052 | return( inside_flag ) ; |
---|
2053 | } |
---|
2054 | |
---|
2055 | void InclusionCleanup( p_inc_anchor ) |
---|
2056 | pInclusionAnchor p_inc_anchor ; |
---|
2057 | { |
---|
2058 | free( p_inc_anchor->pis ) ; |
---|
2059 | free( p_inc_anchor ) ; |
---|
2060 | } |
---|
2061 | #endif |
---|
2062 | |
---|
2063 | |
---|
2064 | /* ======= Crossings Multiply algorithm =================================== */ |
---|
2065 | |
---|
2066 | /* |
---|
2067 | * This version is usually somewhat faster than the original published in |
---|
2068 | * Graphics Gems IV; by turning the division for testing the X axis crossing |
---|
2069 | * into a tricky multiplication test this part of the test became faster, |
---|
2070 | * which had the additional effect of making the test for "both to left or |
---|
2071 | * both to right" a bit slower for triangles than simply computing the |
---|
2072 | * intersection each time. The main increase is in triangle testing speed, |
---|
2073 | * which was about 15% faster; all other polygon complexities were pretty much |
---|
2074 | * the same as before. On machines where division is very expensive (not the |
---|
2075 | * case on the HP 9000 series on which I tested) this test should be much |
---|
2076 | * faster overall than the old code. Your mileage may (in fact, will) vary, |
---|
2077 | * depending on the machine and the test data, but in general I believe this |
---|
2078 | * code is both shorter and faster. This test was inspired by unpublished |
---|
2079 | * Graphics Gems submitted by Joseph Samosky and Mark Haigh-Hutchinson. |
---|
2080 | * Related work by Samosky is in: |
---|
2081 | * |
---|
2082 | * Samosky, Joseph, "SectionView: A system for interactively specifying and |
---|
2083 | * visualizing sections through three-dimensional medical image data", |
---|
2084 | * M.S. Thesis, Department of Electrical Engineering and Computer Science, |
---|
2085 | * Massachusetts Institute of Technology, 1993. |
---|
2086 | * |
---|
2087 | */ |
---|
2088 | |
---|
2089 | /* Shoot a test ray along +X axis. The strategy is to compare vertex Y values |
---|
2090 | * to the testing point's Y and quickly discard edges which are entirely to one |
---|
2091 | * side of the test ray. Note that CONVEX and WINDING code can be added as |
---|
2092 | * for the CrossingsTest() code; it is left out here for clarity. |
---|
2093 | * |
---|
2094 | * Input 2D polygon _pgon_ with _numverts_ number of vertices and test point |
---|
2095 | * _point_, returns 1 if inside, 0 if outside. |
---|
2096 | */ |
---|
2097 | int CrossingsMultiplyTest( pgon, numverts, point ) |
---|
2098 | double pgon[][2] ; |
---|
2099 | int numverts ; |
---|
2100 | double point[2] ; |
---|
2101 | { |
---|
2102 | register int j, yflag0, yflag1, inside_flag ; |
---|
2103 | register double ty, tx, *vtx0, *vtx1 ; |
---|
2104 | |
---|
2105 | tx = point[X] ; |
---|
2106 | ty = point[Y] ; |
---|
2107 | |
---|
2108 | vtx0 = pgon[numverts-1] ; |
---|
2109 | /* get test bit for above/below X axis */ |
---|
2110 | yflag0 = ( vtx0[Y] >= ty ) ; |
---|
2111 | vtx1 = pgon[0] ; |
---|
2112 | |
---|
2113 | inside_flag = 0 ; |
---|
2114 | for ( j = numverts+1 ; --j ; ) { |
---|
2115 | |
---|
2116 | yflag1 = ( vtx1[Y] >= ty ) ; |
---|
2117 | /* Check if endpoints straddle (are on opposite sides) of X axis |
---|
2118 | * (i.e. the Y's differ); if so, +X ray could intersect this edge. |
---|
2119 | * The old test also checked whether the endpoints are both to the |
---|
2120 | * right or to the left of the test point. However, given the faster |
---|
2121 | * intersection point computation used below, this test was found to |
---|
2122 | * be a break-even proposition for most polygons and a loser for |
---|
2123 | * triangles (where 50% or more of the edges which survive this test |
---|
2124 | * will cross quadrants and so have to have the X intersection computed |
---|
2125 | * anyway). I credit Joseph Samosky with inspiring me to try dropping |
---|
2126 | * the "both left or both right" part of my code. |
---|
2127 | */ |
---|
2128 | if ( yflag0 != yflag1 ) { |
---|
2129 | /* Check intersection of pgon segment with +X ray. |
---|
2130 | * Note if >= point's X; if so, the ray hits it. |
---|
2131 | * The division operation is avoided for the ">=" test by checking |
---|
2132 | * the sign of the first vertex wrto the test point; idea inspired |
---|
2133 | * by Joseph Samosky's and Mark Haigh-Hutchinson's different |
---|
2134 | * polygon inclusion tests. |
---|
2135 | */ |
---|
2136 | if ( ((vtx1[Y]-ty) * (vtx0[X]-vtx1[X]) >= |
---|
2137 | (vtx1[X]-tx) * (vtx0[Y]-vtx1[Y])) == yflag1 ) { |
---|
2138 | inside_flag = !inside_flag ; |
---|
2139 | } |
---|
2140 | } |
---|
2141 | |
---|
2142 | /* Move to the next pair of vertices, retaining info as possible. */ |
---|
2143 | yflag0 = yflag1 ; |
---|
2144 | vtx0 = vtx1 ; |
---|
2145 | vtx1 += 2 ; |
---|
2146 | } |
---|
2147 | |
---|
2148 | return( inside_flag ) ; |
---|
2149 | } |
---|