1 /**********************************************************************
2 *
3 * rttopo - topology library
4 * http://git.osgeo.org/gitea/rttopo/librttopo
5 *
6 * rttopo is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * rttopo is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with rttopo. If not, see <http://www.gnu.org/licenses/>.
18 *
19 **********************************************************************
20 *
21 * Copyright 2011 Nicklas Avén
22 * Copyright 2011 Nicklas Avén
23 *
24 **********************************************************************/
25
26
27
28 /**********************************************************************
29 *
30 * rttopo - topology library
31 * http://git.osgeo.org/gitea/rttopo/librttopo
32 * Copyright 2011 Nicklas Avén
33 *
34 * This is free software; you can redistribute and/or modify it under
35 * the terms of the GNU General Public Licence. See the COPYING file.
36 *
37 **********************************************************************/
38
39 #include "rttopo_config.h"
40 #include <string.h>
41 #include <stdlib.h>
42
43 #include "measures3d.h"
44 #include "rtgeom_log.h"
45
46
47 static inline int
get_3dvector_from_points(const RTCTX * ctx,RTPOINT3DZ * p1,RTPOINT3DZ * p2,VECTOR3D * v)48 get_3dvector_from_points(const RTCTX *ctx, RTPOINT3DZ *p1,RTPOINT3DZ *p2, VECTOR3D *v)
49 {
50 v->x=p2->x-p1->x;
51 v->y=p2->y-p1->y;
52 v->z=p2->z-p1->z;
53
54 return RT_TRUE;
55 }
56
57 static inline int
get_3dcross_product(const RTCTX * ctx,VECTOR3D * v1,VECTOR3D * v2,VECTOR3D * v)58 get_3dcross_product(const RTCTX *ctx, VECTOR3D *v1,VECTOR3D *v2, VECTOR3D *v)
59 {
60 v->x=(v1->y*v2->z)-(v1->z*v2->y);
61 v->y=(v1->z*v2->x)-(v1->x*v2->z);
62 v->z=(v1->x*v2->y)-(v1->y*v2->x);
63
64 return RT_TRUE;
65 }
66
67
68 /**
69 This function is used to create a vertical line used for cases where one if the
70 geometries lacks z-values. The vertical line crosses the 2d point that is closest
71 and the z-range is from maxz to minz in the geoemtrie that has z values.
72 */
73 static
create_v_line(const RTCTX * ctx,const RTGEOM * rtgeom,double x,double y,int srid)74 RTGEOM* create_v_line(const RTCTX *ctx, const RTGEOM *rtgeom,double x, double y, int srid)
75 {
76
77 RTPOINT *rtpoints[2];
78 RTGBOX gbox;
79 int rv = rtgeom_calculate_gbox(ctx, rtgeom, &gbox);
80
81 if ( rv == RT_FAILURE )
82 return NULL;
83
84 rtpoints[0] = rtpoint_make3dz(ctx, srid, x, y, gbox.zmin);
85 rtpoints[1] = rtpoint_make3dz(ctx, srid, x, y, gbox.zmax);
86
87 return (RTGEOM *)rtline_from_ptarray(ctx, srid, 2, rtpoints);
88 }
89
90 RTGEOM *
rtgeom_closest_line_3d(const RTCTX * ctx,const RTGEOM * rt1,const RTGEOM * rt2)91 rtgeom_closest_line_3d(const RTCTX *ctx, const RTGEOM *rt1, const RTGEOM *rt2)
92 {
93 return rt_dist3d_distanceline(ctx, rt1, rt2, rt1->srid, DIST_MIN);
94 }
95
96 RTGEOM *
rtgeom_furthest_line_3d(const RTCTX * ctx,RTGEOM * rt1,RTGEOM * rt2)97 rtgeom_furthest_line_3d(const RTCTX *ctx, RTGEOM *rt1, RTGEOM *rt2)
98 {
99 return rt_dist3d_distanceline(ctx, rt1, rt2, rt1->srid, DIST_MAX);
100 }
101
102 RTGEOM *
rtgeom_closest_point_3d(const RTCTX * ctx,const RTGEOM * rt1,const RTGEOM * rt2)103 rtgeom_closest_point_3d(const RTCTX *ctx, const RTGEOM *rt1, const RTGEOM *rt2)
104 {
105 return rt_dist3d_distancepoint(ctx, rt1, rt2, rt1->srid, DIST_MIN);
106 }
107
108
109 /**
110 Function initializing 3dshortestline and 3dlongestline calculations.
111 */
112 RTGEOM *
rt_dist3d_distanceline(const RTCTX * ctx,const RTGEOM * rt1,const RTGEOM * rt2,int srid,int mode)113 rt_dist3d_distanceline(const RTCTX *ctx, const RTGEOM *rt1, const RTGEOM *rt2, int srid, int mode)
114 {
115 RTDEBUG(ctx, 2, "rt_dist3d_distanceline is called");
116 double x1,x2,y1,y2, z1, z2, x, y;
117 double initdistance = ( mode == DIST_MIN ? FLT_MAX : -1.0);
118 DISTPTS3D thedl;
119 RTPOINT *rtpoints[2];
120 RTGEOM *result;
121
122 thedl.mode = mode;
123 thedl.distance = initdistance;
124 thedl.tolerance = 0.0;
125
126 /*Check if we really have 3D geoemtries*/
127 /*If not, send it to 2D-calculations which will give the same result*/
128 /*as an infinite z-value at one or two of the geometries*/
129 if(!rtgeom_has_z(ctx, rt1) || !rtgeom_has_z(ctx, rt2))
130 {
131
132 rtnotice(ctx, "One or both of the geometries is missing z-value. The unknown z-value will be regarded as \"any value\"");
133
134 if(!rtgeom_has_z(ctx, rt1) && !rtgeom_has_z(ctx, rt2))
135 return rt_dist2d_distanceline(ctx, rt1, rt2, srid, mode);
136
137 DISTPTS thedl2d;
138 thedl2d.mode = mode;
139 thedl2d.distance = initdistance;
140 thedl2d.tolerance = 0.0;
141 if (!rt_dist2d_comp(ctx, rt1,rt2,&thedl2d))
142 {
143 /*should never get here. all cases ought to be error handled earlier*/
144 rterror(ctx, "Some unspecified error.");
145 result = (RTGEOM *)rtcollection_construct_empty(ctx, RTCOLLECTIONTYPE, srid, 0, 0);
146 }
147 RTGEOM *vertical_line;
148 if(!rtgeom_has_z(ctx, rt1))
149 {
150 x=thedl2d.p1.x;
151 y=thedl2d.p1.y;
152
153 vertical_line = create_v_line(ctx, rt2,x,y,srid);
154 if (!rt_dist3d_recursive(ctx, vertical_line, rt2, &thedl))
155 {
156 /*should never get here. all cases ought to be error handled earlier*/
157 rtfree(ctx, vertical_line);
158 rterror(ctx, "Some unspecified error.");
159 result = (RTGEOM *)rtcollection_construct_empty(ctx, RTCOLLECTIONTYPE, srid, 0, 0);
160 }
161 rtfree(ctx, vertical_line);
162 }
163 if(!rtgeom_has_z(ctx, rt2))
164 {
165 x=thedl2d.p2.x;
166 y=thedl2d.p2.y;
167
168 vertical_line = create_v_line(ctx, rt1,x,y,srid);
169 if (!rt_dist3d_recursive(ctx, rt1, vertical_line, &thedl))
170 {
171 /*should never get here. all cases ought to be error handled earlier*/
172 rtfree(ctx, vertical_line);
173 rterror(ctx, "Some unspecified error.");
174 return (RTGEOM *)rtcollection_construct_empty(ctx, RTCOLLECTIONTYPE, srid, 0, 0);
175 }
176 rtfree(ctx, vertical_line);
177 }
178
179 }
180 else
181 {
182 if (!rt_dist3d_recursive(ctx, rt1, rt2, &thedl))
183 {
184 /*should never get here. all cases ought to be error handled earlier*/
185 rterror(ctx, "Some unspecified error.");
186 result = (RTGEOM *)rtcollection_construct_empty(ctx, RTCOLLECTIONTYPE, srid, 0, 0);
187 }
188 }
189 /*if thedl.distance is unchanged there where only empty geometries input*/
190 if (thedl.distance == initdistance)
191 {
192 RTDEBUG(ctx, 3, "didn't find geometries to measure between, returning null");
193 result = (RTGEOM *)rtcollection_construct_empty(ctx, RTCOLLECTIONTYPE, srid, 0, 0);
194 }
195 else
196 {
197 x1=thedl.p1.x;
198 y1=thedl.p1.y;
199 z1=thedl.p1.z;
200 x2=thedl.p2.x;
201 y2=thedl.p2.y;
202 z2=thedl.p2.z;
203
204 rtpoints[0] = rtpoint_make3dz(ctx, srid, x1, y1, z1);
205 rtpoints[1] = rtpoint_make3dz(ctx, srid, x2, y2, z2);
206
207 result = (RTGEOM *)rtline_from_ptarray(ctx, srid, 2, rtpoints);
208 }
209
210 return result;
211 }
212
213 /**
214 Function initializing 3dclosestpoint calculations.
215 */
216 RTGEOM *
rt_dist3d_distancepoint(const RTCTX * ctx,const RTGEOM * rt1,const RTGEOM * rt2,int srid,int mode)217 rt_dist3d_distancepoint(const RTCTX *ctx, const RTGEOM *rt1, const RTGEOM *rt2, int srid, int mode)
218 {
219
220 double x,y,z;
221 DISTPTS3D thedl;
222 double initdistance = FLT_MAX;
223 RTGEOM *result;
224
225 thedl.mode = mode;
226 thedl.distance= initdistance;
227 thedl.tolerance = 0;
228
229 RTDEBUG(ctx, 2, "rt_dist3d_distancepoint is called");
230
231 /*Check if we really have 3D geoemtries*/
232 /*If not, send it to 2D-calculations which will give the same result*/
233 /*as an infinite z-value at one or two of the geometries*/
234 if(!rtgeom_has_z(ctx, rt1) || !rtgeom_has_z(ctx, rt2))
235 {
236 rtnotice(ctx, "One or both of the geometries is missing z-value. The unknown z-value will be regarded as \"any value\"");
237
238 if(!rtgeom_has_z(ctx, rt1) && !rtgeom_has_z(ctx, rt2))
239 return rt_dist2d_distancepoint(ctx, rt1, rt2, srid, mode);
240
241
242 DISTPTS thedl2d;
243 thedl2d.mode = mode;
244 thedl2d.distance = initdistance;
245 thedl2d.tolerance = 0.0;
246 if (!rt_dist2d_comp(ctx, rt1,rt2,&thedl2d))
247 {
248 /*should never get here. all cases ought to be error handled earlier*/
249 rterror(ctx, "Some unspecified error.");
250 return (RTGEOM *)rtcollection_construct_empty(ctx, RTCOLLECTIONTYPE, srid, 0, 0);
251 }
252
253 RTGEOM *vertical_line;
254 if(!rtgeom_has_z(ctx, rt1))
255 {
256 x=thedl2d.p1.x;
257 y=thedl2d.p1.y;
258
259 vertical_line = create_v_line(ctx, rt2,x,y,srid);
260 if (!rt_dist3d_recursive(ctx, vertical_line, rt2, &thedl))
261 {
262 /*should never get here. all cases ought to be error handled earlier*/
263 rtfree(ctx, vertical_line);
264 rterror(ctx, "Some unspecified error.");
265 return (RTGEOM *)rtcollection_construct_empty(ctx, RTCOLLECTIONTYPE, srid, 0, 0);
266 }
267 rtfree(ctx, vertical_line);
268 }
269
270 if(!rtgeom_has_z(ctx, rt2))
271 {
272 x=thedl2d.p2.x;
273 y=thedl2d.p2.y;
274
275 vertical_line = create_v_line(ctx, rt1,x,y,srid);
276 if (!rt_dist3d_recursive(ctx, rt1, vertical_line, &thedl))
277 {
278 /*should never get here. all cases ought to be error handled earlier*/
279 rtfree(ctx, vertical_line);
280 rterror(ctx, "Some unspecified error.");
281 result = (RTGEOM *)rtcollection_construct_empty(ctx, RTCOLLECTIONTYPE, srid, 0, 0);
282 }
283 rtfree(ctx, vertical_line);
284 }
285
286 }
287 else
288 {
289 if (!rt_dist3d_recursive(ctx, rt1, rt2, &thedl))
290 {
291 /*should never get here. all cases ought to be error handled earlier*/
292 rterror(ctx, "Some unspecified error.");
293 result = (RTGEOM *)rtcollection_construct_empty(ctx, RTCOLLECTIONTYPE, srid, 0, 0);
294 }
295 }
296 if (thedl.distance == initdistance)
297 {
298 RTDEBUG(ctx, 3, "didn't find geometries to measure between, returning null");
299 result = (RTGEOM *)rtcollection_construct_empty(ctx, RTCOLLECTIONTYPE, srid, 0, 0);
300 }
301 else
302 {
303 x=thedl.p1.x;
304 y=thedl.p1.y;
305 z=thedl.p1.z;
306 result = (RTGEOM *)rtpoint_make3dz(ctx, srid, x, y, z);
307 }
308
309 return result;
310 }
311
312
313 /**
314 Function initializing 3d max distance calculation
315 */
316 double
rtgeom_maxdistance3d(const RTCTX * ctx,const RTGEOM * rt1,const RTGEOM * rt2)317 rtgeom_maxdistance3d(const RTCTX *ctx, const RTGEOM *rt1, const RTGEOM *rt2)
318 {
319 RTDEBUG(ctx, 2, "rtgeom_maxdistance3d is called");
320
321 return rtgeom_maxdistance3d_tolerance(ctx, rt1, rt2, 0.0 );
322 }
323
324 /**
325 Function handling 3d max distance calculations and dfullywithin calculations.
326 The difference is just the tolerance.
327 */
328 double
rtgeom_maxdistance3d_tolerance(const RTCTX * ctx,const RTGEOM * rt1,const RTGEOM * rt2,double tolerance)329 rtgeom_maxdistance3d_tolerance(const RTCTX *ctx, const RTGEOM *rt1, const RTGEOM *rt2, double tolerance)
330 {
331 if(!rtgeom_has_z(ctx, rt1) || !rtgeom_has_z(ctx, rt2))
332 {
333 rtnotice(ctx, "One or both of the geometries is missing z-value. The unknown z-value will be regarded as \"any value\"");
334 return rtgeom_maxdistance2d_tolerance(ctx, rt1, rt2, tolerance);
335 }
336 /*double thedist;*/
337 DISTPTS3D thedl;
338 RTDEBUG(ctx, 2, "rtgeom_maxdistance3d_tolerance is called");
339 thedl.mode = DIST_MAX;
340 thedl.distance= -1;
341 thedl.tolerance = tolerance;
342 if (rt_dist3d_recursive(ctx, rt1, rt2, &thedl))
343 {
344 return thedl.distance;
345 }
346 /*should never get here. all cases ought to be error handled earlier*/
347 rterror(ctx, "Some unspecified error.");
348 return -1;
349 }
350
351 /**
352 Function initializing 3d min distance calculation
353 */
354 double
rtgeom_mindistance3d(const RTCTX * ctx,const RTGEOM * rt1,const RTGEOM * rt2)355 rtgeom_mindistance3d(const RTCTX *ctx, const RTGEOM *rt1, const RTGEOM *rt2)
356 {
357 RTDEBUG(ctx, 2, "rtgeom_mindistance3d is called");
358 return rtgeom_mindistance3d_tolerance(ctx, rt1, rt2, 0.0 );
359 }
360
361 /**
362 Function handling 3d min distance calculations and dwithin calculations.
363 The difference is just the tolerance.
364 */
365 double
rtgeom_mindistance3d_tolerance(const RTCTX * ctx,const RTGEOM * rt1,const RTGEOM * rt2,double tolerance)366 rtgeom_mindistance3d_tolerance(const RTCTX *ctx, const RTGEOM *rt1, const RTGEOM *rt2, double tolerance)
367 {
368 if(!rtgeom_has_z(ctx, rt1) || !rtgeom_has_z(ctx, rt2))
369 {
370 rtnotice(ctx, "One or both of the geometries is missing z-value. The unknown z-value will be regarded as \"any value\"");
371
372 return rtgeom_mindistance2d_tolerance(ctx, rt1, rt2, tolerance);
373 }
374 DISTPTS3D thedl;
375 RTDEBUG(ctx, 2, "rtgeom_mindistance3d_tolerance is called");
376 thedl.mode = DIST_MIN;
377 thedl.distance= FLT_MAX;
378 thedl.tolerance = tolerance;
379 if (rt_dist3d_recursive(ctx, rt1, rt2, &thedl))
380 {
381 return thedl.distance;
382 }
383 /*should never get here. all cases ought to be error handled earlier*/
384 rterror(ctx, "Some unspecified error.");
385 return FLT_MAX;
386 }
387
388
389 /*------------------------------------------------------------------------------------------------------------
390 End of Initializing functions
391 --------------------------------------------------------------------------------------------------------------*/
392
393 /*------------------------------------------------------------------------------------------------------------
394 Preprocessing functions
395 Functions preparing geometries for distance-calculations
396 --------------------------------------------------------------------------------------------------------------*/
397
398
399 /**
400 This is a recursive function delivering every possible combination of subgeometries
401 */
rt_dist3d_recursive(const RTCTX * ctx,const RTGEOM * rtg1,const RTGEOM * rtg2,DISTPTS3D * dl)402 int rt_dist3d_recursive(const RTCTX *ctx, const RTGEOM *rtg1,const RTGEOM *rtg2, DISTPTS3D *dl)
403 {
404 int i, j;
405 int n1=1;
406 int n2=1;
407 RTGEOM *g1 = NULL;
408 RTGEOM *g2 = NULL;
409 RTCOLLECTION *c1 = NULL;
410 RTCOLLECTION *c2 = NULL;
411
412 RTDEBUGF(ctx, 2, "rt_dist3d_recursive is called with type1=%d, type2=%d", rtg1->type, rtg2->type);
413
414 if (rtgeom_is_collection(ctx, rtg1))
415 {
416 RTDEBUG(ctx, 3, "First geometry is collection");
417 c1 = rtgeom_as_rtcollection(ctx, rtg1);
418 n1 = c1->ngeoms;
419 }
420 if (rtgeom_is_collection(ctx, rtg2))
421 {
422 RTDEBUG(ctx, 3, "Second geometry is collection");
423 c2 = rtgeom_as_rtcollection(ctx, rtg2);
424 n2 = c2->ngeoms;
425 }
426
427 for ( i = 0; i < n1; i++ )
428 {
429
430 if (rtgeom_is_collection(ctx, rtg1))
431 {
432 g1 = c1->geoms[i];
433 }
434 else
435 {
436 g1 = (RTGEOM*)rtg1;
437 }
438
439 if (rtgeom_is_empty(ctx, g1)) return RT_TRUE;
440
441 if (rtgeom_is_collection(ctx, g1))
442 {
443 RTDEBUG(ctx, 3, "Found collection inside first geometry collection, recursing");
444 if (!rt_dist3d_recursive(ctx, g1, rtg2, dl)) return RT_FALSE;
445 continue;
446 }
447 for ( j = 0; j < n2; j++ )
448 {
449 if (rtgeom_is_collection(ctx, rtg2))
450 {
451 g2 = c2->geoms[j];
452 }
453 else
454 {
455 g2 = (RTGEOM*)rtg2;
456 }
457 if (rtgeom_is_collection(ctx, g2))
458 {
459 RTDEBUG(ctx, 3, "Found collection inside second geometry collection, recursing");
460 if (!rt_dist3d_recursive(ctx, g1, g2, dl)) return RT_FALSE;
461 continue;
462 }
463
464
465 /*If one of geometries is empty, return. True here only means continue searching. False would have stoped the process*/
466 if (rtgeom_is_empty(ctx, g1)||rtgeom_is_empty(ctx, g2)) return RT_TRUE;
467
468
469 if (!rt_dist3d_distribute_bruteforce(ctx, g1, g2, dl)) return RT_FALSE;
470 if (dl->distance<=dl->tolerance && dl->mode == DIST_MIN) return RT_TRUE; /*just a check if the answer is already given*/
471 }
472 }
473 return RT_TRUE;
474 }
475
476
477
478 /**
479
480 This function distributes the brute-force for 3D so far the only type, tasks depending on type
481 */
482 int
rt_dist3d_distribute_bruteforce(const RTCTX * ctx,const RTGEOM * rtg1,const RTGEOM * rtg2,DISTPTS3D * dl)483 rt_dist3d_distribute_bruteforce(const RTCTX *ctx, const RTGEOM *rtg1, const RTGEOM *rtg2, DISTPTS3D *dl)
484 {
485
486 int t1 = rtg1->type;
487 int t2 = rtg2->type;
488
489 RTDEBUGF(ctx, 2, "rt_dist3d_distribute_bruteforce is called with typ1=%d, type2=%d", rtg1->type, rtg2->type);
490
491 if ( t1 == RTPOINTTYPE )
492 {
493 if ( t2 == RTPOINTTYPE )
494 {
495 dl->twisted=1;
496 return rt_dist3d_point_point(ctx, (RTPOINT *)rtg1, (RTPOINT *)rtg2, dl);
497 }
498 else if ( t2 == RTLINETYPE )
499 {
500 dl->twisted=1;
501 return rt_dist3d_point_line(ctx, (RTPOINT *)rtg1, (RTLINE *)rtg2, dl);
502 }
503 else if ( t2 == RTPOLYGONTYPE )
504 {
505 dl->twisted=1;
506 return rt_dist3d_point_poly(ctx, (RTPOINT *)rtg1, (RTPOLY *)rtg2,dl);
507 }
508 else
509 {
510 rterror(ctx, "Unsupported geometry type: %s", rttype_name(ctx, t2));
511 return RT_FALSE;
512 }
513 }
514 else if ( t1 == RTLINETYPE )
515 {
516 if ( t2 == RTPOINTTYPE )
517 {
518 dl->twisted=(-1);
519 return rt_dist3d_point_line(ctx, (RTPOINT *)rtg2,(RTLINE *)rtg1,dl);
520 }
521 else if ( t2 == RTLINETYPE )
522 {
523 dl->twisted=1;
524 return rt_dist3d_line_line(ctx, (RTLINE *)rtg1,(RTLINE *)rtg2,dl);
525 }
526 else if ( t2 == RTPOLYGONTYPE )
527 {
528 dl->twisted=1;
529 return rt_dist3d_line_poly(ctx, (RTLINE *)rtg1,(RTPOLY *)rtg2,dl);
530 }
531 else
532 {
533 rterror(ctx, "Unsupported geometry type: %s", rttype_name(ctx, t2));
534 return RT_FALSE;
535 }
536 }
537 else if ( t1 == RTPOLYGONTYPE )
538 {
539 if ( t2 == RTPOLYGONTYPE )
540 {
541 dl->twisted=1;
542 return rt_dist3d_poly_poly(ctx, (RTPOLY *)rtg1, (RTPOLY *)rtg2,dl);
543 }
544 else if ( t2 == RTPOINTTYPE )
545 {
546 dl->twisted=-1;
547 return rt_dist3d_point_poly(ctx, (RTPOINT *)rtg2, (RTPOLY *)rtg1,dl);
548 }
549 else if ( t2 == RTLINETYPE )
550 {
551 dl->twisted=-1;
552 return rt_dist3d_line_poly(ctx, (RTLINE *)rtg2,(RTPOLY *)rtg1,dl);
553 }
554 else
555 {
556 rterror(ctx, "Unsupported geometry type: %s", rttype_name(ctx, t2));
557 return RT_FALSE;
558 }
559 }
560 else
561 {
562 rterror(ctx, "Unsupported geometry type: %s", rttype_name(ctx, t1));
563 return RT_FALSE;
564 }
565 /*You shouldn't being able to get here*/
566 rterror(ctx, "unspecified error in function rt_dist3d_distribute_bruteforce");
567 return RT_FALSE;
568 }
569
570
571
572 /*------------------------------------------------------------------------------------------------------------
573 End of Preprocessing functions
574 --------------------------------------------------------------------------------------------------------------*/
575
576
577 /*------------------------------------------------------------------------------------------------------------
578 Brute force functions
579 So far the only way to do 3D-calculations
580 --------------------------------------------------------------------------------------------------------------*/
581
582 /**
583
584 point to point calculation
585 */
586 int
rt_dist3d_point_point(const RTCTX * ctx,RTPOINT * point1,RTPOINT * point2,DISTPTS3D * dl)587 rt_dist3d_point_point(const RTCTX *ctx, RTPOINT *point1, RTPOINT *point2, DISTPTS3D *dl)
588 {
589 RTPOINT3DZ p1;
590 RTPOINT3DZ p2;
591 RTDEBUG(ctx, 2, "rt_dist3d_point_point is called");
592
593 rt_getPoint3dz_p(ctx, point1->point, 0, &p1);
594 rt_getPoint3dz_p(ctx, point2->point, 0, &p2);
595
596 return rt_dist3d_pt_pt(ctx, &p1, &p2,dl);
597 }
598 /**
599
600 point to line calculation
601 */
602 int
rt_dist3d_point_line(const RTCTX * ctx,RTPOINT * point,RTLINE * line,DISTPTS3D * dl)603 rt_dist3d_point_line(const RTCTX *ctx, RTPOINT *point, RTLINE *line, DISTPTS3D *dl)
604 {
605 RTPOINT3DZ p;
606 RTPOINTARRAY *pa = line->points;
607 RTDEBUG(ctx, 2, "rt_dist3d_point_line is called");
608
609 rt_getPoint3dz_p(ctx, point->point, 0, &p);
610 return rt_dist3d_pt_ptarray(ctx, &p, pa, dl);
611 }
612
613 /**
614
615 Computes point to polygon distance
616 For mindistance that means:
617 1)find the plane of the polygon
618 2)projecting the point to the plane of the polygon
619 3)finding if that projected point is inside the polygon, if so the distance is measured to that projected point
620 4) if not in polygon above, check the distance against the boundary of the polygon
621 for max distance it is artays point against boundary
622
623 */
624 int
rt_dist3d_point_poly(const RTCTX * ctx,RTPOINT * point,RTPOLY * poly,DISTPTS3D * dl)625 rt_dist3d_point_poly(const RTCTX *ctx, RTPOINT *point, RTPOLY *poly, DISTPTS3D *dl)
626 {
627 RTPOINT3DZ p, projp;/*projp is "point projected on plane"*/
628 PLANE3D plane;
629 RTDEBUG(ctx, 2, "rt_dist3d_point_poly is called");
630 rt_getPoint3dz_p(ctx, point->point, 0, &p);
631
632 /*If we are lookig for max distance, longestline or dfullywithin*/
633 if (dl->mode == DIST_MAX)
634 {
635 RTDEBUG(ctx, 3, "looking for maxdistance");
636 return rt_dist3d_pt_ptarray(ctx, &p, poly->rings[0], dl);
637 }
638
639 /*Find the plane of the polygon, the "holes" have to be on the same plane. so we only care about the boudary*/
640 if(!define_plane(ctx, poly->rings[0], &plane))
641 return RT_FALSE;
642
643 /*get our point projected on the plane of the polygon*/
644 project_point_on_plane(ctx, &p, &plane, &projp);
645
646 return rt_dist3d_pt_poly(ctx, &p, poly,&plane, &projp, dl);
647 }
648
649
650 /**
651
652 line to line calculation
653 */
654 int
rt_dist3d_line_line(const RTCTX * ctx,RTLINE * line1,RTLINE * line2,DISTPTS3D * dl)655 rt_dist3d_line_line(const RTCTX *ctx, RTLINE *line1, RTLINE *line2, DISTPTS3D *dl)
656 {
657 RTPOINTARRAY *pa1 = line1->points;
658 RTPOINTARRAY *pa2 = line2->points;
659 RTDEBUG(ctx, 2, "rt_dist3d_line_line is called");
660
661 return rt_dist3d_ptarray_ptarray(ctx, pa1, pa2, dl);
662 }
663
664 /**
665
666 line to polygon calculation
667 */
rt_dist3d_line_poly(const RTCTX * ctx,RTLINE * line,RTPOLY * poly,DISTPTS3D * dl)668 int rt_dist3d_line_poly(const RTCTX *ctx, RTLINE *line, RTPOLY *poly, DISTPTS3D *dl)
669 {
670 PLANE3D plane;
671 RTDEBUG(ctx, 2, "rt_dist3d_line_poly is called");
672
673 if (dl->mode == DIST_MAX)
674 {
675 return rt_dist3d_ptarray_ptarray(ctx, line->points, poly->rings[0], dl);
676 }
677
678 if(!define_plane(ctx, poly->rings[0], &plane))
679 return RT_FALSE;
680
681 return rt_dist3d_ptarray_poly(ctx, line->points, poly,&plane, dl);
682 }
683
684 /**
685
686 polygon to polygon calculation
687 */
rt_dist3d_poly_poly(const RTCTX * ctx,RTPOLY * poly1,RTPOLY * poly2,DISTPTS3D * dl)688 int rt_dist3d_poly_poly(const RTCTX *ctx, RTPOLY *poly1, RTPOLY *poly2, DISTPTS3D *dl)
689 {
690 PLANE3D plane;
691 RTDEBUG(ctx, 2, "rt_dist3d_poly_poly is called");
692 if (dl->mode == DIST_MAX)
693 {
694 return rt_dist3d_ptarray_ptarray(ctx, poly1->rings[0], poly2->rings[0], dl);
695 }
696
697 if(!define_plane(ctx, poly2->rings[0], &plane))
698 return RT_FALSE;
699
700 /*What we do here is to compare the bondary of one polygon with the other polygon
701 and then take the second boudary comparing with the first polygon*/
702 dl->twisted=1;
703 if(!rt_dist3d_ptarray_poly(ctx, poly1->rings[0], poly2,&plane, dl))
704 return RT_FALSE;
705 if(dl->distance==0.0) /*Just check if the answer already is given*/
706 return RT_TRUE;
707
708 if(!define_plane(ctx, poly1->rings[0], &plane))
709 return RT_FALSE;
710 dl->twisted=-1; /*because we swithc the order of geometries we swithch "twisted" to -1 which will give the right order of points in shortest line.*/
711 return rt_dist3d_ptarray_poly(ctx, poly2->rings[0], poly1,&plane, dl);
712 }
713
714 /**
715
716 * search all the segments of pointarray to see which one is closest to p
717 * Returns distance between point and pointarray
718 */
719 int
rt_dist3d_pt_ptarray(const RTCTX * ctx,RTPOINT3DZ * p,RTPOINTARRAY * pa,DISTPTS3D * dl)720 rt_dist3d_pt_ptarray(const RTCTX *ctx, RTPOINT3DZ *p, RTPOINTARRAY *pa,DISTPTS3D *dl)
721 {
722 int t;
723 RTPOINT3DZ start, end;
724 int twist = dl->twisted;
725
726 RTDEBUG(ctx, 2, "rt_dist3d_pt_ptarray is called");
727
728 rt_getPoint3dz_p(ctx, pa, 0, &start);
729
730 for (t=1; t<pa->npoints; t++)
731 {
732 dl->twisted=twist;
733 rt_getPoint3dz_p(ctx, pa, t, &end);
734 if (!rt_dist3d_pt_seg(ctx, p, &start, &end,dl)) return RT_FALSE;
735
736 if (dl->distance<=dl->tolerance && dl->mode == DIST_MIN) return RT_TRUE; /*just a check if the answer is already given*/
737 start = end;
738 }
739
740 return RT_TRUE;
741 }
742
743
744 /**
745
746 If searching for min distance, this one finds the closest point on segment A-B from p.
747 if searching for max distance it just sends p-A and p-B to pt-pt calculation
748 */
749 int
rt_dist3d_pt_seg(const RTCTX * ctx,RTPOINT3DZ * p,RTPOINT3DZ * A,RTPOINT3DZ * B,DISTPTS3D * dl)750 rt_dist3d_pt_seg(const RTCTX *ctx, RTPOINT3DZ *p, RTPOINT3DZ *A, RTPOINT3DZ *B, DISTPTS3D *dl)
751 {
752 RTPOINT3DZ c;
753 double r;
754 /*if start==end, then use pt distance */
755 if ( ( A->x == B->x) && (A->y == B->y) && (A->z == B->z) )
756 {
757 return rt_dist3d_pt_pt(ctx, p,A,dl);
758 }
759
760
761 r = ( (p->x-A->x) * (B->x-A->x) + (p->y-A->y) * (B->y-A->y) + ( p->z-A->z) * (B->z-A->z) )/( (B->x-A->x)*(B->x-A->x) +(B->y-A->y)*(B->y-A->y)+(B->z-A->z)*(B->z-A->z) );
762
763 /*This is for finding the 3Dmaxdistance.
764 the maxdistance have to be between two vertexes,
765 compared to mindistance which can be between
766 tvo vertexes vertex.*/
767 if (dl->mode == DIST_MAX)
768 {
769 if (r>=0.5)
770 {
771 return rt_dist3d_pt_pt(ctx, p,A,dl);
772 }
773 if (r<0.5)
774 {
775 return rt_dist3d_pt_pt(ctx, p,B,dl);
776 }
777 }
778
779 if (r<0) /*If the first vertex A is closest to the point p*/
780 {
781 return rt_dist3d_pt_pt(ctx, p,A,dl);
782 }
783 if (r>1) /*If the second vertex B is closest to the point p*/
784 {
785 return rt_dist3d_pt_pt(ctx, p,B,dl);
786 }
787
788 /*else if the point p is closer to some point between a and b
789 then we find that point and send it to rt_dist3d_pt_pt*/
790 c.x=A->x + r * (B->x-A->x);
791 c.y=A->y + r * (B->y-A->y);
792 c.z=A->z + r * (B->z-A->z);
793
794 return rt_dist3d_pt_pt(ctx, p,&c,dl);
795 }
796
797 double
distance3d_pt_pt(const RTCTX * ctx,const POINT3D * p1,const POINT3D * p2)798 distance3d_pt_pt(const RTCTX *ctx, const POINT3D *p1, const POINT3D *p2)
799 {
800 double dx = p2->x - p1->x;
801 double dy = p2->y - p1->y;
802 double dz = p2->z - p1->z;
803 return sqrt ( dx*dx + dy*dy + dz*dz);
804 }
805
806
807 /**
808
809 Compares incomming points and
810 stores the points closest to each other
811 or most far away from each other
812 depending on dl->mode (max or min)
813 */
814 int
rt_dist3d_pt_pt(const RTCTX * ctx,RTPOINT3DZ * thep1,RTPOINT3DZ * thep2,DISTPTS3D * dl)815 rt_dist3d_pt_pt(const RTCTX *ctx, RTPOINT3DZ *thep1, RTPOINT3DZ *thep2,DISTPTS3D *dl)
816 {
817 double dx = thep2->x - thep1->x;
818 double dy = thep2->y - thep1->y;
819 double dz = thep2->z - thep1->z;
820 double dist = sqrt ( dx*dx + dy*dy + dz*dz);
821 RTDEBUGF(ctx, 2, "rt_dist3d_pt_pt called (with points: p1.x=%f, p1.y=%f,p1.z=%f,p2.x=%f, p2.y=%f,p2.z=%f)",thep1->x,thep1->y,thep1->z,thep2->x,thep2->y,thep2->z );
822
823 if (((dl->distance - dist)*(dl->mode))>0) /*multiplication with mode to handle mindistance (mode=1) and maxdistance (mode = (-1)*/
824 {
825 dl->distance = dist;
826
827 if (dl->twisted>0) /*To get the points in right order. twisted is updated between 1 and (-1) every time the order is changed earlier in the chain*/
828 {
829 dl->p1 = *thep1;
830 dl->p2 = *thep2;
831 }
832 else
833 {
834 dl->p1 = *thep2;
835 dl->p2 = *thep1;
836 }
837 }
838 return RT_TRUE;
839 }
840
841
842 /**
843
844 Finds all combinationes of segments between two pointarrays
845 */
846 int
rt_dist3d_ptarray_ptarray(const RTCTX * ctx,RTPOINTARRAY * l1,RTPOINTARRAY * l2,DISTPTS3D * dl)847 rt_dist3d_ptarray_ptarray(const RTCTX *ctx, RTPOINTARRAY *l1, RTPOINTARRAY *l2,DISTPTS3D *dl)
848 {
849 int t,u;
850 RTPOINT3DZ start, end;
851 RTPOINT3DZ start2, end2;
852 int twist = dl->twisted;
853 RTDEBUGF(ctx, 2, "rt_dist3d_ptarray_ptarray called (points: %d-%d)",l1->npoints, l2->npoints);
854
855
856
857 if (dl->mode == DIST_MAX)/*If we are searching for maxdistance we go straight to point-point calculation since the maxdistance have to be between two vertexes*/
858 {
859 for (t=0; t<l1->npoints; t++) /*for each segment in L1 */
860 {
861 rt_getPoint3dz_p(ctx, l1, t, &start);
862 for (u=0; u<l2->npoints; u++) /*for each segment in L2 */
863 {
864 rt_getPoint3dz_p(ctx, l2, u, &start2);
865 rt_dist3d_pt_pt(ctx, &start,&start2,dl);
866 RTDEBUGF(ctx, 4, "maxdist_ptarray_ptarray; seg %i * seg %i, dist = %g\n",t,u,dl->distance);
867 RTDEBUGF(ctx, 3, " seg%d-seg%d dist: %f, mindist: %f",
868 t, u, dl->distance, dl->tolerance);
869 }
870 }
871 }
872 else
873 {
874 rt_getPoint3dz_p(ctx, l1, 0, &start);
875 for (t=1; t<l1->npoints; t++) /*for each segment in L1 */
876 {
877 rt_getPoint3dz_p(ctx, l1, t, &end);
878 rt_getPoint3dz_p(ctx, l2, 0, &start2);
879 for (u=1; u<l2->npoints; u++) /*for each segment in L2 */
880 {
881 rt_getPoint3dz_p(ctx, l2, u, &end2);
882 dl->twisted=twist;
883 rt_dist3d_seg_seg(ctx, &start, &end, &start2, &end2,dl);
884 RTDEBUGF(ctx, 4, "mindist_ptarray_ptarray; seg %i * seg %i, dist = %g\n",t,u,dl->distance);
885 RTDEBUGF(ctx, 3, " seg%d-seg%d dist: %f, mindist: %f",
886 t, u, dl->distance, dl->tolerance);
887 if (dl->distance<=dl->tolerance && dl->mode == DIST_MIN) return RT_TRUE; /*just a check if the answer is already given*/
888 start2 = end2;
889 }
890 start = end;
891 }
892 }
893 return RT_TRUE;
894 }
895
896 /**
897
898 Finds the two closest points on two linesegments
899 */
900 int
rt_dist3d_seg_seg(const RTCTX * ctx,RTPOINT3DZ * s1p1,RTPOINT3DZ * s1p2,RTPOINT3DZ * s2p1,RTPOINT3DZ * s2p2,DISTPTS3D * dl)901 rt_dist3d_seg_seg(const RTCTX *ctx, RTPOINT3DZ *s1p1, RTPOINT3DZ *s1p2, RTPOINT3DZ *s2p1, RTPOINT3DZ *s2p2, DISTPTS3D *dl)
902 {
903 VECTOR3D v1, v2, vl;
904 double s1k, s2k; /*two variables representing where on Line 1 (s1k) and where on Line 2 (s2k) a connecting line between the two lines is perpendicular to both lines*/
905 RTPOINT3DZ p1, p2;
906 double a, b, c, d, e, D;
907
908 /*s1p1 and s1p2 are the same point */
909 if ( ( s1p1->x == s1p2->x) && (s1p1->y == s1p2->y) && (s1p1->z == s1p2->z) )
910 {
911 return rt_dist3d_pt_seg(ctx, s1p1,s2p1,s2p2,dl);
912 }
913 /*s2p1 and s2p2 are the same point */
914 if ( ( s2p1->x == s2p2->x) && (s2p1->y == s2p2->y) && (s2p1->z == s2p2->z) )
915 {
916 dl->twisted= ((dl->twisted) * (-1));
917 return rt_dist3d_pt_seg(ctx, s2p1,s1p1,s1p2,dl);
918 }
919
920 /*
921 Here we use algorithm from softsurfer.com
922 that can be found here
923 http://softsurfer.com/Archive/algorithm_0106/algorithm_0106.htm
924 */
925
926 if (!get_3dvector_from_points(ctx, s1p1, s1p2, &v1))
927 return RT_FALSE;
928
929 if (!get_3dvector_from_points(ctx, s2p1, s2p2, &v2))
930 return RT_FALSE;
931
932 if (!get_3dvector_from_points(ctx, s2p1, s1p1, &vl))
933 return RT_FALSE;
934
935 a = DOT(v1,v1);
936 b = DOT(v1,v2);
937 c = DOT(v2,v2);
938 d = DOT(v1,vl);
939 e = DOT(v2,vl);
940 D = a*c - b*b;
941
942
943 if (D <0.000000001)
944 { /* the lines are almost parallel*/
945 s1k = 0.0; /*If the lines are paralell we try by using the startpoint of first segment. If that gives a projected point on the second line outside segment 2 it wil be found that s2k is >1 or <0.*/
946 if(b>c) /* use the largest denominator*/
947 {
948 s2k=d/b;
949 }
950 else
951 {
952 s2k =e/c;
953 }
954 }
955 else
956 {
957 s1k = (b*e - c*d) / D;
958 s2k = (a*e - b*d) / D;
959 }
960
961 /* Now we check if the projected closest point on the infinite lines is outside our segments. If so the combinations with start and end points will be tested*/
962 if(s1k<0.0||s1k>1.0||s2k<0.0||s2k>1.0)
963 {
964 if(s1k<0.0)
965 {
966
967 if (!rt_dist3d_pt_seg(ctx, s1p1, s2p1, s2p2, dl))
968 {
969 return RT_FALSE;
970 }
971 }
972 if(s1k>1.0)
973 {
974
975 if (!rt_dist3d_pt_seg(ctx, s1p2, s2p1, s2p2, dl))
976 {
977 return RT_FALSE;
978 }
979 }
980 if(s2k<0.0)
981 {
982 dl->twisted= ((dl->twisted) * (-1));
983 if (!rt_dist3d_pt_seg(ctx, s2p1, s1p1, s1p2, dl))
984 {
985 return RT_FALSE;
986 }
987 }
988 if(s2k>1.0)
989 {
990 dl->twisted= ((dl->twisted) * (-1));
991 if (!rt_dist3d_pt_seg(ctx, s2p2, s1p1, s1p2, dl))
992 {
993 return RT_FALSE;
994 }
995 }
996 }
997 else
998 {/*Find the closest point on the edges of both segments*/
999 p1.x=s1p1->x+s1k*(s1p2->x-s1p1->x);
1000 p1.y=s1p1->y+s1k*(s1p2->y-s1p1->y);
1001 p1.z=s1p1->z+s1k*(s1p2->z-s1p1->z);
1002
1003 p2.x=s2p1->x+s2k*(s2p2->x-s2p1->x);
1004 p2.y=s2p1->y+s2k*(s2p2->y-s2p1->y);
1005 p2.z=s2p1->z+s2k*(s2p2->z-s2p1->z);
1006
1007 if (!rt_dist3d_pt_pt(ctx, &p1,&p2,dl))/* Send the closest points to point-point calculation*/
1008 {
1009 return RT_FALSE;
1010 }
1011 }
1012 return RT_TRUE;
1013 }
1014
1015 /**
1016
1017 Checking if the point projected on the plane of the polygon actually is inside that polygon.
1018 If so the mindistance is between that projected point and our original point.
1019 If not we check from original point to the bounadary.
1020 If the projected point is inside a hole of the polygon we check the distance to the boudary of that hole.
1021 */
1022 int
rt_dist3d_pt_poly(const RTCTX * ctx,RTPOINT3DZ * p,RTPOLY * poly,PLANE3D * plane,RTPOINT3DZ * projp,DISTPTS3D * dl)1023 rt_dist3d_pt_poly(const RTCTX *ctx, RTPOINT3DZ *p, RTPOLY *poly, PLANE3D *plane,RTPOINT3DZ *projp, DISTPTS3D *dl)
1024 {
1025 int i;
1026
1027 RTDEBUG(ctx, 2, "rt_dist3d_point_poly called");
1028
1029
1030 if(pt_in_ring_3d(ctx, projp, poly->rings[0], plane))
1031 {
1032 for (i=1; i<poly->nrings; i++)
1033 {
1034 /* Inside a hole. Distance = pt -> ring */
1035 if ( pt_in_ring_3d(ctx, projp, poly->rings[i], plane ))
1036 {
1037 RTDEBUG(ctx, 3, " inside an hole");
1038 return rt_dist3d_pt_ptarray(ctx, p, poly->rings[i], dl);
1039 }
1040 }
1041
1042 return rt_dist3d_pt_pt(ctx, p,projp,dl);/* If the projected point is inside the polygon the shortest distance is between that point and the inputed point*/
1043 }
1044 else
1045 {
1046 return rt_dist3d_pt_ptarray(ctx, p, poly->rings[0], dl); /*If the projected point is outside the polygon we search for the closest distance against the boundarry instead*/
1047 }
1048
1049 return RT_TRUE;
1050
1051 }
1052
1053 /**
1054
1055 Computes pointarray to polygon distance
1056 */
rt_dist3d_ptarray_poly(const RTCTX * ctx,RTPOINTARRAY * pa,RTPOLY * poly,PLANE3D * plane,DISTPTS3D * dl)1057 int rt_dist3d_ptarray_poly(const RTCTX *ctx, RTPOINTARRAY *pa, RTPOLY *poly,PLANE3D *plane, DISTPTS3D *dl)
1058 {
1059
1060
1061 int i,j,k;
1062 double f, s1, s2;
1063 VECTOR3D projp1_projp2;
1064 RTPOINT3DZ p1, p2,projp1, projp2, intersectionp;
1065
1066 rt_getPoint3dz_p(ctx, pa, 0, &p1);
1067
1068 s1=project_point_on_plane(ctx, &p1, plane, &projp1); /*the sign of s1 tells us on which side of the plane the point is. */
1069 rt_dist3d_pt_poly(ctx, &p1, poly, plane,&projp1, dl);
1070
1071 for (i=1;i<pa->npoints;i++)
1072 {
1073 int intersects;
1074 rt_getPoint3dz_p(ctx, pa, i, &p2);
1075 s2=project_point_on_plane(ctx, &p2, plane, &projp2);
1076 rt_dist3d_pt_poly(ctx, &p2, poly, plane,&projp2, dl);
1077
1078 /*If s1and s2 has different signs that means they are on different sides of the plane of the polygon.
1079 That means that the edge between the points crosses the plane and might intersect with the polygon*/
1080 if((s1*s2)<=0)
1081 {
1082 f=fabs(s1)/(fabs(s1)+fabs(s2)); /*The size of s1 and s2 is the distance from the point to the plane.*/
1083 get_3dvector_from_points(ctx, &projp1, &projp2,&projp1_projp2);
1084
1085 /*get the point where the line segment crosses the plane*/
1086 intersectionp.x=projp1.x+f*projp1_projp2.x;
1087 intersectionp.y=projp1.y+f*projp1_projp2.y;
1088 intersectionp.z=projp1.z+f*projp1_projp2.z;
1089
1090 intersects = RT_TRUE; /*We set intersects to true until the opposite is proved*/
1091
1092 if(pt_in_ring_3d(ctx, &intersectionp, poly->rings[0], plane)) /*Inside outer ring*/
1093 {
1094 for (k=1;k<poly->nrings; k++)
1095 {
1096 /* Inside a hole, so no intersection with the polygon*/
1097 if ( pt_in_ring_3d(ctx, &intersectionp, poly->rings[k], plane ))
1098 {
1099 intersects=RT_FALSE;
1100 break;
1101 }
1102 }
1103 if(intersects)
1104 {
1105 dl->distance=0.0;
1106 dl->p1.x=intersectionp.x;
1107 dl->p1.y=intersectionp.y;
1108 dl->p1.z=intersectionp.z;
1109
1110 dl->p2.x=intersectionp.x;
1111 dl->p2.y=intersectionp.y;
1112 dl->p2.z=intersectionp.z;
1113 return RT_TRUE;
1114
1115 }
1116 }
1117 }
1118
1119 projp1=projp2;
1120 s1=s2;
1121 p1=p2;
1122 }
1123
1124 /*check or pointarray against boundary and inner boundaries of the polygon*/
1125 for (j=0;j<poly->nrings;j++)
1126 {
1127 rt_dist3d_ptarray_ptarray(ctx, pa, poly->rings[j], dl);
1128 }
1129
1130 return RT_TRUE;
1131 }
1132
1133
1134 /**
1135
1136 Here we define the plane of a polygon (boundary pointarray of a polygon)
1137 the plane is stored as a pont in plane (plane.pop) and a normal vector (plane.pv)
1138 */
1139 int
define_plane(const RTCTX * ctx,RTPOINTARRAY * pa,PLANE3D * pl)1140 define_plane(const RTCTX *ctx, RTPOINTARRAY *pa, PLANE3D *pl)
1141 {
1142 int i,j, numberofvectors, pointsinslice;
1143 RTPOINT3DZ p, p1, p2;
1144
1145 double sumx=0;
1146 double sumy=0;
1147 double sumz=0;
1148 double vl; /*vector length*/
1149
1150 VECTOR3D v1, v2, v;
1151
1152 if((pa->npoints-1)==3) /*Triangle is special case*/
1153 {
1154 pointsinslice=1;
1155 }
1156 else
1157 {
1158 pointsinslice=(int) floor((pa->npoints-1)/4); /*divide the pointarray into 4 slices*/
1159 }
1160
1161 /*find the avg point*/
1162 for (i=0;i<(pa->npoints-1);i++)
1163 {
1164 rt_getPoint3dz_p(ctx, pa, i, &p);
1165 sumx+=p.x;
1166 sumy+=p.y;
1167 sumz+=p.z;
1168 }
1169 pl->pop.x=(sumx/(pa->npoints-1));
1170 pl->pop.y=(sumy/(pa->npoints-1));
1171 pl->pop.z=(sumz/(pa->npoints-1));
1172
1173 sumx=0;
1174 sumy=0;
1175 sumz=0;
1176 numberofvectors= floor((pa->npoints-1)/pointsinslice); /*the number of vectors we try can be 3, 4 or 5*/
1177
1178 rt_getPoint3dz_p(ctx, pa, 0, &p1);
1179 for (j=pointsinslice;j<pa->npoints;j+=pointsinslice)
1180 {
1181 rt_getPoint3dz_p(ctx, pa, j, &p2);
1182
1183 if (!get_3dvector_from_points(ctx, &(pl->pop), &p1, &v1) || !get_3dvector_from_points(ctx, &(pl->pop), &p2, &v2))
1184 return RT_FALSE;
1185 /*perpendicular vector is cross product of v1 and v2*/
1186 if (!get_3dcross_product(ctx, &v1,&v2, &v))
1187 return RT_FALSE;
1188 vl=VECTORLENGTH(v);
1189 sumx+=(v.x/vl);
1190 sumy+=(v.y/vl);
1191 sumz+=(v.z/vl);
1192 p1=p2;
1193 }
1194 pl->pv.x=(sumx/numberofvectors);
1195 pl->pv.y=(sumy/numberofvectors);
1196 pl->pv.z=(sumz/numberofvectors);
1197
1198 return 1;
1199 }
1200
1201 /**
1202
1203 Finds a point on a plane from where the original point is perpendicular to the plane
1204 */
1205 double
project_point_on_plane(const RTCTX * ctx,RTPOINT3DZ * p,PLANE3D * pl,RTPOINT3DZ * p0)1206 project_point_on_plane(const RTCTX *ctx, RTPOINT3DZ *p, PLANE3D *pl, RTPOINT3DZ *p0)
1207 {
1208 /*In our plane definition we have a point on the plane and a normal vektor (pl.pv), perpendicular to the plane
1209 this vector will be paralell to the line between our inputted point above the plane and the point we are searching for on the plane.
1210 So, we already have a direction from p to find p0, but we don't know the distance.
1211 */
1212
1213 VECTOR3D v1;
1214 double f;
1215
1216 if (!get_3dvector_from_points(ctx, &(pl->pop), p, &v1))
1217 return RT_FALSE;
1218
1219 f=-(DOT(pl->pv,v1)/DOT(pl->pv,pl->pv));
1220
1221 p0->x=p->x+pl->pv.x*f;
1222 p0->y=p->y+pl->pv.y*f;
1223 p0->z=p->z+pl->pv.z*f;
1224
1225 return f;
1226 }
1227
1228
1229
1230
1231 /**
1232 * pt_in_ring_3d(ctx): crossing number test for a point in a polygon
1233 * input: p = a point,
1234 * pa = vertex points of a ring V[n+1] with V[n]=V[0]
1235 * plane=the plane that the vertex points are lying on
1236 * returns: 0 = outside, 1 = inside
1237 *
1238 * Our polygons have first and last point the same,
1239 *
1240 * The difference in 3D variant is that we exclude the dimension that faces the plane least.
1241 * That is the dimension with the highest number in pv
1242 */
1243 int
pt_in_ring_3d(const RTCTX * ctx,const RTPOINT3DZ * p,const RTPOINTARRAY * ring,PLANE3D * plane)1244 pt_in_ring_3d(const RTCTX *ctx, const RTPOINT3DZ *p, const RTPOINTARRAY *ring,PLANE3D *plane)
1245 {
1246
1247 int cn = 0; /* the crossing number counter */
1248 int i;
1249 RTPOINT3DZ v1, v2;
1250
1251 RTPOINT3DZ first, last;
1252
1253 rt_getPoint3dz_p(ctx, ring, 0, &first);
1254 rt_getPoint3dz_p(ctx, ring, ring->npoints-1, &last);
1255 if ( memcmp(&first, &last, sizeof(RTPOINT3DZ)) )
1256 {
1257 rterror(ctx, "pt_in_ring_3d: V[n] != V[0] (%g %g %g!= %g %g %g)",
1258 first.x, first.y, first.z, last.x, last.y, last.z);
1259 return RT_FALSE;
1260 }
1261
1262 RTDEBUGF(ctx, 2, "pt_in_ring_3d called with point: %g %g %g", p->x, p->y, p->z);
1263 /* printPA(ctx, ring); */
1264
1265 /* loop through all edges of the polygon */
1266 rt_getPoint3dz_p(ctx, ring, 0, &v1);
1267
1268
1269 if(fabs(plane->pv.z)>=fabs(plane->pv.x)&&fabs(plane->pv.z)>=fabs(plane->pv.y)) /*If the z vector of the normal vector to the plane is larger than x and y vector we project the ring to the xy-plane*/
1270 {
1271 for (i=0; i<ring->npoints-1; i++)
1272 {
1273 double vt;
1274 rt_getPoint3dz_p(ctx, ring, i+1, &v2);
1275
1276 /* edge from vertex i to vertex i+1 */
1277 if
1278 (
1279 /* an upward crossing */
1280 ((v1.y <= p->y) && (v2.y > p->y))
1281 /* a downward crossing */
1282 || ((v1.y > p->y) && (v2.y <= p->y))
1283 )
1284 {
1285
1286 vt = (double)(p->y - v1.y) / (v2.y - v1.y);
1287
1288 /* P.x <intersect */
1289 if (p->x < v1.x + vt * (v2.x - v1.x))
1290 {
1291 /* a valid crossing of y=p.y right of p.x */
1292 ++cn;
1293 }
1294 }
1295 v1 = v2;
1296 }
1297 }
1298 else if(fabs(plane->pv.y)>=fabs(plane->pv.x)&&fabs(plane->pv.y)>=fabs(plane->pv.z)) /*If the y vector of the normal vector to the plane is larger than x and z vector we project the ring to the xz-plane*/
1299 {
1300 for (i=0; i<ring->npoints-1; i++)
1301 {
1302 double vt;
1303 rt_getPoint3dz_p(ctx, ring, i+1, &v2);
1304
1305 /* edge from vertex i to vertex i+1 */
1306 if
1307 (
1308 /* an upward crossing */
1309 ((v1.z <= p->z) && (v2.z > p->z))
1310 /* a downward crossing */
1311 || ((v1.z > p->z) && (v2.z <= p->z))
1312 )
1313 {
1314
1315 vt = (double)(p->z - v1.z) / (v2.z - v1.z);
1316
1317 /* P.x <intersect */
1318 if (p->x < v1.x + vt * (v2.x - v1.x))
1319 {
1320 /* a valid crossing of y=p.y right of p.x */
1321 ++cn;
1322 }
1323 }
1324 v1 = v2;
1325 }
1326 }
1327 else /*Hopefully we only have the cases where x part of the normal vector is largest left*/
1328 {
1329 for (i=0; i<ring->npoints-1; i++)
1330 {
1331 double vt;
1332 rt_getPoint3dz_p(ctx, ring, i+1, &v2);
1333
1334 /* edge from vertex i to vertex i+1 */
1335 if
1336 (
1337 /* an upward crossing */
1338 ((v1.z <= p->z) && (v2.z > p->z))
1339 /* a downward crossing */
1340 || ((v1.z > p->z) && (v2.z <= p->z))
1341 )
1342 {
1343
1344 vt = (double)(p->z - v1.z) / (v2.z - v1.z);
1345
1346 /* P.x <intersect */
1347 if (p->y < v1.y + vt * (v2.y - v1.y))
1348 {
1349 /* a valid crossing of y=p.y right of p.x */
1350 ++cn;
1351 }
1352 }
1353 v1 = v2;
1354 }
1355 }
1356 RTDEBUGF(ctx, 3, "pt_in_ring_3d returning %d", cn&1);
1357
1358 return (cn&1); /* 0 if even (out), and 1 if odd (in) */
1359 }
1360
1361
1362
1363 /*------------------------------------------------------------------------------------------------------------
1364 End of Brute force functions
1365 --------------------------------------------------------------------------------------------------------------*/
1366
1367
1368
1369