1 /* GTS - Library for the manipulation of triangulated surfaces
2 * Copyright (C) 1999 Stéphane Popinet
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
23 static void bbox_init (GtsBBox
* bbox
)
31 * Returns: the #GtsBBoxClass.
33 GtsBBoxClass
* gts_bbox_class (void)
35 static GtsBBoxClass
* klass
= NULL
;
38 GtsObjectClassInfo bbox_info
= {
41 sizeof (GtsBBoxClass
),
42 (GtsObjectClassInitFunc
) NULL
,
43 (GtsObjectInitFunc
) bbox_init
,
47 klass
= gts_object_class_new (gts_object_class (), &bbox_info
);
56 * @bounded: the object to be bounded.
57 * @x1: x-coordinate of the lower left corner.
58 * @y1: y-coordinate of the lower left corner.
59 * @z1: z-coordinate of the lower left corner.
60 * @x2: x-coordinate of the upper right corner.
61 * @y2: y-coordinate of the upper right corner.
62 * @z2: z-coordinate of the upper right corner.
64 * Sets fields of @bbox.
66 void gts_bbox_set (GtsBBox
* bbox
,
68 gdouble x1
, gdouble y1
, gdouble z1
,
69 gdouble x2
, gdouble y2
, gdouble z2
)
71 g_return_if_fail (bbox
!= NULL
);
72 g_return_if_fail (x2
>= x1
&& y2
>= y1
&& z2
>= z1
);
74 bbox
->x1
= x1
; bbox
->y1
= y1
; bbox
->z1
= z1
;
75 bbox
->x2
= x2
; bbox
->y2
= y2
; bbox
->z2
= z2
;
76 bbox
->bounded
= bounded
;
81 * @klass: a #GtsBBoxClass.
82 * @bounded: the object to be bounded.
83 * @x1: x-coordinate of the lower left corner.
84 * @y1: y-coordinate of the lower left corner.
85 * @z1: z-coordinate of the lower left corner.
86 * @x2: x-coordinate of the upper right corner.
87 * @y2: y-coordinate of the upper right corner.
88 * @z2: z-coordinate of the upper right corner.
90 * Returns: a new #GtsBBox.
92 GtsBBox
* gts_bbox_new (GtsBBoxClass
* klass
,
94 gdouble x1
, gdouble y1
, gdouble z1
,
95 gdouble x2
, gdouble y2
, gdouble z2
)
99 g_return_val_if_fail (klass
!= NULL
, NULL
);
101 bbox
= GTS_BBOX (gts_object_new (GTS_OBJECT_CLASS (klass
)));
102 gts_bbox_set (bbox
, bounded
, x1
, y1
, z1
, x2
, y2
, z2
);
108 * @klass: a #GtsBBoxClass.
109 * @t: a #GtsTriangle.
111 * Returns: a new #GtsBBox bounding box of @t.
113 GtsBBox
* gts_bbox_triangle (GtsBBoxClass
* klass
,
119 g_return_val_if_fail (t
!= NULL
, NULL
);
120 g_return_val_if_fail (klass
!= NULL
, NULL
);
122 p
= GTS_POINT (GTS_SEGMENT (t
->e1
)->v1
);
123 bbox
= gts_bbox_new (klass
, t
, p
->x
, p
->y
, p
->z
, p
->x
, p
->y
, p
->z
);
125 p
= GTS_POINT (GTS_SEGMENT (t
->e1
)->v2
);
126 if (p
->x
> bbox
->x2
) bbox
->x2
= p
->x
;
127 if (p
->x
< bbox
->x1
) bbox
->x1
= p
->x
;
128 if (p
->y
> bbox
->y2
) bbox
->y2
= p
->y
;
129 if (p
->y
< bbox
->y1
) bbox
->y1
= p
->y
;
130 if (p
->z
> bbox
->z2
) bbox
->z2
= p
->z
;
131 if (p
->z
< bbox
->z1
) bbox
->z1
= p
->z
;
132 p
= GTS_POINT (gts_triangle_vertex (t
));
133 if (p
->x
> bbox
->x2
) bbox
->x2
= p
->x
;
134 if (p
->x
< bbox
->x1
) bbox
->x1
= p
->x
;
135 if (p
->y
> bbox
->y2
) bbox
->y2
= p
->y
;
136 if (p
->y
< bbox
->y1
) bbox
->y1
= p
->y
;
137 if (p
->z
> bbox
->z2
) bbox
->z2
= p
->z
;
138 if (p
->z
< bbox
->z1
) bbox
->z1
= p
->z
;
145 * @klass: a #GtsBBoxClass.
148 * Returns: a new #GtsBBox bounding box of @s.
150 GtsBBox
* gts_bbox_segment (GtsBBoxClass
* klass
, GtsSegment
* s
)
155 g_return_val_if_fail (s
!= NULL
, NULL
);
156 g_return_val_if_fail (klass
!= NULL
, NULL
);
158 bbox
= gts_bbox_new (klass
, s
, 0., 0., 0., 0., 0., 0.);
160 p1
= GTS_POINT (s
->v1
);
161 p2
= GTS_POINT (s
->v2
);
163 bbox
->x2
= p1
->x
; bbox
->x1
= p2
->x
;
166 bbox
->x1
= p1
->x
; bbox
->x2
= p2
->x
;
169 bbox
->y2
= p1
->y
; bbox
->y1
= p2
->y
;
172 bbox
->y1
= p1
->y
; bbox
->y2
= p2
->y
;
175 bbox
->z2
= p1
->z
; bbox
->z1
= p2
->z
;
178 bbox
->z1
= p1
->z
; bbox
->z2
= p2
->z
;
184 static void bbox_foreach_vertex (GtsPoint
* p
, GtsBBox
* bb
)
186 if (p
->x
< bb
->x1
) bb
->x1
= p
->x
;
187 if (p
->y
< bb
->y1
) bb
->y1
= p
->y
;
188 if (p
->z
< bb
->z1
) bb
->z1
= p
->z
;
189 if (p
->x
> bb
->x2
) bb
->x2
= p
->x
;
190 if (p
->y
> bb
->y2
) bb
->y2
= p
->y
;
191 if (p
->z
> bb
->z2
) bb
->z2
= p
->z
;
196 * @klass: a #GtsBBoxClass.
197 * @surface: a #GtsSurface.
199 * Returns: a new #GtsBBox bounding box of @surface.
201 GtsBBox
* gts_bbox_surface (GtsBBoxClass
* klass
, GtsSurface
* surface
)
205 g_return_val_if_fail (klass
!= NULL
, NULL
);
206 g_return_val_if_fail (surface
!= NULL
, NULL
);
208 bbox
= gts_bbox_new (klass
, surface
, 0., 0., 0., 0., 0., 0.);
209 bbox
->x1
= bbox
->y1
= bbox
->z1
= G_MAXDOUBLE
;
210 bbox
->x2
= bbox
->y2
= bbox
->z2
= -G_MAXDOUBLE
;
212 gts_surface_foreach_vertex (surface
, (GtsFunc
) bbox_foreach_vertex
, bbox
);
219 * @klass: a #GtsBBoxClass.
220 * @bboxes: a list of #GtsBBox.
222 * Returns: a new #GtsBBox bounding box of all the bounding boxes in
225 GtsBBox
* gts_bbox_bboxes (GtsBBoxClass
* klass
, GSList
* bboxes
)
230 g_return_val_if_fail (bboxes
!= NULL
, NULL
);
231 g_return_val_if_fail (klass
!= NULL
, NULL
);
234 bbox
= gts_bbox_new (klass
, bboxes
,
235 bb
->x1
, bb
->y1
, bb
->z1
, bb
->x2
, bb
->y2
, bb
->z2
);
236 bboxes
= bboxes
->next
;
239 if (bb
->x1
< bbox
->x1
) bbox
->x1
= bb
->x1
;
240 if (bb
->y1
< bbox
->y1
) bbox
->y1
= bb
->y1
;
241 if (bb
->z1
< bbox
->z1
) bbox
->z1
= bb
->z1
;
242 if (bb
->x2
> bbox
->x2
) bbox
->x2
= bb
->x2
;
243 if (bb
->y2
> bbox
->y2
) bbox
->y2
= bb
->y2
;
244 if (bb
->z2
> bbox
->z2
) bbox
->z2
= bb
->z2
;
245 bboxes
= bboxes
->next
;
253 * @klass: a #GtsBBoxClass.
254 * @points: a list of #GtsPoint.
256 * Returns: a new #GtsBBox bounding box of @points.
258 GtsBBox
* gts_bbox_points (GtsBBoxClass
* klass
, GSList
* points
)
268 bbox
= gts_bbox_new (klass
, points
, p
->x
, p
->y
, p
->z
, p
->x
, p
->y
, p
->z
);
275 else if (p
->x
< bbox
->x1
)
279 else if (p
->y
< bbox
->y1
)
283 else if (p
->z
< bbox
->z1
)
292 * gts_bboxes_are_overlapping:
296 * Returns: %TRUE if the bounding boxes @bb1 and @bb2 are overlapping
297 * (including just touching), %FALSE otherwise.
299 gboolean
gts_bboxes_are_overlapping (GtsBBox
* bb1
, GtsBBox
* bb2
)
303 if (bb1
->x1
> bb2
->x2
)
305 if (bb2
->x1
> bb1
->x2
)
307 if (bb1
->y1
> bb2
->y2
)
309 if (bb2
->y1
> bb1
->y2
)
311 if (bb1
->z1
> bb2
->z2
)
313 if (bb2
->z1
> bb1
->z2
)
318 #define bbox_volume(bb) (((bb)->x2 -\
326 * gts_bbox_diagonal2:
329 * Returns: the squared length of the diagonal of @bb.
331 gdouble
gts_bbox_diagonal2 (GtsBBox
* bb
)
335 g_return_val_if_fail (bb
!= NULL
, 0.);
341 return x
*x
+ y
*y
+ z
*z
;
347 * @fptr: a file pointer.
349 * Writes in file @fptr an OOGL (Geomview) description of @bb.
351 void gts_bbox_draw (GtsBBox
* bb
, FILE * fptr
)
353 g_return_if_fail (bb
!= NULL
);
355 fprintf (fptr
, "OFF 8 6 12\n");
356 fprintf (fptr
, "%g %g %g\n",
357 bb
->x1
, bb
->y1
, bb
->z1
);
358 fprintf (fptr
, "%g %g %g\n",
359 bb
->x2
, bb
->y1
, bb
->z1
);
360 fprintf (fptr
, "%g %g %g\n",
361 bb
->x2
, bb
->y2
, bb
->z1
);
362 fprintf (fptr
, "%g %g %g\n",
363 bb
->x1
, bb
->y2
, bb
->z1
);
364 fprintf (fptr
, "%g %g %g\n",
365 bb
->x1
, bb
->y1
, bb
->z2
);
366 fprintf (fptr
, "%g %g %g\n",
367 bb
->x2
, bb
->y1
, bb
->z2
);
368 fprintf (fptr
, "%g %g %g\n",
369 bb
->x2
, bb
->y2
, bb
->z2
);
370 fprintf (fptr
, "%g %g %g\n",
371 bb
->x1
, bb
->y2
, bb
->z2
);
381 #define MINMAX(x1, x2, xmin, xmax) { if (x1 < x2) { xmin = x1; xmax = x2; }\
382 else { xmin = x2; xmax = x1; } }
385 * gts_bbox_point_distance2:
388 * @min: a pointer on a gdouble.
389 * @max: a pointer on a gdouble.
391 * Sets @min and @max to lower and upper bounds for the square of the
392 * Euclidean distance between the object contained in @bb and @p. For these
393 * bounds to make any sense the bounding box must be "tight" i.e. each of the
394 * 6 faces of the box must at least be touched by one point of the bounded
397 void gts_bbox_point_distance2 (GtsBBox
* bb
, GtsPoint
* p
,
398 gdouble
* min
, gdouble
* max
)
400 gdouble x1
, y1
, z1
, x2
, y2
, z2
, x
, y
, z
;
401 gdouble dmin
, dmax
, xd1
, xd2
, yd1
, yd2
, zd1
, zd2
;
402 gdouble mx
, Mx
, my
, My
, mz
, Mz
;
404 g_return_if_fail (bb
!= NULL
);
405 g_return_if_fail (p
!= NULL
);
406 g_return_if_fail (min
!= NULL
);
407 g_return_if_fail (max
!= NULL
);
409 x1
= bb
->x1
; y1
= bb
->y1
; z1
= bb
->z1
;
410 x2
= bb
->x2
; y2
= bb
->y2
; z2
= bb
->z2
;
411 x
= p
->x
; y
= p
->y
; z
= p
->z
;
413 xd1
= (x1
- x
)*(x1
- x
);
414 xd2
= (x
- x2
)*(x
- x2
);
415 yd1
= (y1
- y
)*(y1
- y
);
416 yd2
= (y
- y2
)*(y
- y2
);
417 zd1
= (z1
- z
)*(z1
- z
);
418 zd2
= (z
- z2
)*(z
- z2
);
420 dmin
= x
< x1
? xd1
: x
> x2
? xd2
: 0.0;
421 dmin
+= y
< y1
? yd1
: y
> y2
? yd2
: 0.0;
422 dmin
+= z
< z1
? zd1
: z
> z2
? zd2
: 0.0;
424 MINMAX (xd1
, xd2
, mx
, Mx
);
425 MINMAX (yd1
, yd2
, my
, My
);
426 MINMAX (zd1
, zd2
, mz
, Mz
);
429 dmax
= MIN (dmax
, Mx
+ my
+ Mz
);
430 dmax
= MIN (dmax
, Mx
+ My
+ mz
);
437 * gts_bbox_is_stabbed:
441 * Returns: %TRUE if the ray starting at @p and ending at (+infty,
442 * @p->y, @p->z) intersects with @bb, %FALSE otherwise.
444 gboolean
gts_bbox_is_stabbed (GtsBBox
* bb
, GtsPoint
* p
)
446 g_return_val_if_fail (bb
!= NULL
, FALSE
);
447 g_return_val_if_fail (p
!= NULL
, FALSE
);
450 p
->y
< bb
->y1
|| p
->y
> bb
->y2
||
451 p
->z
< bb
->z1
|| p
->z
> bb
->z2
)
456 extern int triBoxOverlap (double boxcenter
[3],
457 double boxhalfsize
[3],
458 double triverts
[3][3]);
461 * gts_bbox_overlaps_triangle:
463 * @t: a #GtsTriangle.
465 * This is a wrapper around the fast overlap test of Tomas
466 * Akenine-Moller (http://www.cs.lth.se/home/Tomas_Akenine_Moller/).
468 * Returns: %TRUE if @bb overlaps with @t, %FALSE otherwise.
470 gboolean
gts_bbox_overlaps_triangle (GtsBBox
* bb
, GtsTriangle
* t
)
472 double bc
[3], bh
[3], tv
[3][3];
473 GtsPoint
* p1
, * p2
, * p3
;
475 g_return_val_if_fail (bb
!= NULL
, FALSE
);
476 g_return_val_if_fail (t
!= NULL
, FALSE
);
478 bc
[0] = (bb
->x2
+ bb
->x1
)/2.;
479 bh
[0] = (bb
->x2
- bb
->x1
)/2.;
480 bc
[1] = (bb
->y2
+ bb
->y1
)/2.;
481 bh
[1] = (bb
->y2
- bb
->y1
)/2.;
482 bc
[2] = (bb
->z2
+ bb
->z1
)/2.;
483 bh
[2] = (bb
->z2
- bb
->z1
)/2.;
484 p1
= GTS_POINT (GTS_SEGMENT (t
->e1
)->v1
);
485 p2
= GTS_POINT (GTS_SEGMENT (t
->e1
)->v2
);
486 p3
= GTS_POINT (gts_triangle_vertex (t
));
487 tv
[0][0] = p1
->x
; tv
[0][1] = p1
->y
; tv
[0][2] = p1
->z
;
488 tv
[1][0] = p2
->x
; tv
[1][1] = p2
->y
; tv
[1][2] = p2
->z
;
489 tv
[2][0] = p3
->x
; tv
[2][1] = p3
->y
; tv
[2][2] = p3
->z
;
491 return triBoxOverlap (bc
, bh
, tv
);
495 * gts_bbox_overlaps_segment:
499 * This functions uses gts_bbox_overlaps_triangle() with a degenerate
502 * Returns: %TRUE if @bb overlaps with @s, %FALSE otherwise.
504 gboolean
gts_bbox_overlaps_segment (GtsBBox
* bb
, GtsSegment
* s
)
506 double bc
[3], bh
[3], tv
[3][3];
507 GtsPoint
* p1
, * p2
, * p3
;
509 g_return_val_if_fail (bb
!= NULL
, FALSE
);
510 g_return_val_if_fail (s
!= NULL
, FALSE
);
512 bc
[0] = (bb
->x2
+ bb
->x1
)/2.;
513 bh
[0] = (bb
->x2
- bb
->x1
)/2.;
514 bc
[1] = (bb
->y2
+ bb
->y1
)/2.;
515 bh
[1] = (bb
->y2
- bb
->y1
)/2.;
516 bc
[2] = (bb
->z2
+ bb
->z1
)/2.;
517 bh
[2] = (bb
->z2
- bb
->z1
)/2.;
518 p1
= GTS_POINT (s
->v1
);
519 p2
= GTS_POINT (s
->v2
);
521 tv
[0][0] = p1
->x
; tv
[0][1] = p1
->y
; tv
[0][2] = p1
->z
;
522 tv
[1][0] = p2
->x
; tv
[1][1] = p2
->y
; tv
[1][2] = p2
->z
;
523 tv
[2][0] = p3
->x
; tv
[2][1] = p3
->y
; tv
[2][2] = p3
->z
;
525 return triBoxOverlap (bc
, bh
, tv
);
530 * @bboxes: a list of #GtsBBox.
532 * Builds a new hierarchy of bounding boxes for @bboxes. At each
533 * level, the GNode->data field contains a #GtsBBox bounding box of
534 * all the children. The tree is binary and is built by repeatedly
535 * cutting in two approximately equal halves the bounding boxes at
536 * each level until a leaf node (i.e. a bounding box given in @bboxes)
537 * is reached. In order to minimize the depth of the tree, the cutting
538 * direction is always chosen as perpendicular to the longest
539 * dimension of the bounding box.
541 * Returns: a new hierarchy of bounding boxes.
543 GNode
* gts_bb_tree_new (GSList
* bboxes
)
545 GSList
* i
, * positive
= NULL
, * negative
= NULL
;
548 guint dir
, np
= 0, nn
= 0;
552 g_return_val_if_fail (bboxes
!= NULL
, NULL
);
554 if (bboxes
->next
== NULL
) /* leaf node */
555 return g_node_new (bboxes
->data
);
557 bbox
= gts_bbox_bboxes (gts_bbox_class (), bboxes
);
558 node
= g_node_new (bbox
);
560 if (bbox
->x2
- bbox
->x1
> bbox
->y2
- bbox
->y1
) {
561 if (bbox
->z2
- bbox
->z1
> bbox
->x2
- bbox
->x1
)
566 else if (bbox
->z2
- bbox
->z1
> bbox
->y2
- bbox
->y1
)
571 p1
= (gdouble
*) &bbox
->x1
;
572 p2
= (gdouble
*) &bbox
->x2
;
573 cut
= (p1
[dir
] + p2
[dir
])/2.;
577 p1
= (gdouble
*) &bbox
->x1
;
578 p2
= (gdouble
*) &bbox
->x2
;
579 if ((p1
[dir
] + p2
[dir
])/2. > cut
) {
580 positive
= g_slist_prepend (positive
, bbox
);
584 negative
= g_slist_prepend (negative
, bbox
);
590 GSList
* last
= g_slist_nth (negative
, (nn
- 1)/2);
591 positive
= last
->next
;
594 else if (!negative
) {
595 GSList
* last
= g_slist_nth (positive
, (np
- 1)/2);
596 negative
= last
->next
;
599 g_node_prepend (node
, gts_bb_tree_new (positive
));
600 g_slist_free (positive
);
601 g_node_prepend (node
, gts_bb_tree_new (negative
));
602 g_slist_free (negative
);
607 static void prepend_triangle_bbox (GtsTriangle
* t
, GSList
** bboxes
)
609 *bboxes
= g_slist_prepend (*bboxes
,
610 gts_bbox_triangle (gts_bbox_class (), t
));
614 * gts_bb_tree_surface:
617 * Returns: a new hierarchy of bounding boxes bounding the faces of @s.
619 GNode
* gts_bb_tree_surface (GtsSurface
* s
)
621 GSList
* bboxes
= NULL
;
624 g_return_val_if_fail (s
!= NULL
, NULL
);
626 gts_surface_foreach_face (s
, (GtsFunc
) prepend_triangle_bbox
, &bboxes
);
627 tree
= gts_bb_tree_new (bboxes
);
628 g_slist_free (bboxes
);
634 * gts_bb_tree_stabbed:
635 * @tree: a bounding box tree.
638 * Returns: a list of bounding boxes, leaves of @tree which are
639 * stabbed by the ray defined by @p (see gts_bbox_is_stabbed()).
641 GSList
* gts_bb_tree_stabbed (GNode
* tree
, GtsPoint
* p
)
643 GSList
* list
= NULL
;
647 g_return_val_if_fail (tree
!= NULL
, NULL
);
648 g_return_val_if_fail (p
!= NULL
, NULL
);
651 if (!gts_bbox_is_stabbed (bb
, p
))
653 if (tree
->children
== NULL
) /* leaf node */
654 return g_slist_prepend (NULL
, bb
);
657 list
= g_slist_concat (list
, gts_bb_tree_stabbed (i
, p
));
664 * gts_bb_tree_overlap:
665 * @tree: a bounding box tree.
668 * Returns: a list of bounding boxes, leaves of @tree which overlap @bbox.
670 GSList
* gts_bb_tree_overlap (GNode
* tree
, GtsBBox
* bbox
)
672 GSList
* list
= NULL
;
676 g_return_val_if_fail (tree
!= NULL
, NULL
);
677 g_return_val_if_fail (bbox
!= NULL
, NULL
);
680 if (!gts_bboxes_are_overlapping (bbox
, bb
))
682 if (tree
->children
== NULL
) /* leaf node */
683 return g_slist_prepend (NULL
, bb
);
686 list
= g_slist_concat (list
, gts_bb_tree_overlap (i
, bbox
));
693 * gts_bb_tree_is_overlapping:
694 * @tree: a bounding box tree.
697 * Returns: %TRUE if any leaf of @tree overlaps @bbox, %FALSE otherwise.
699 gboolean
gts_bb_tree_is_overlapping (GNode
* tree
, GtsBBox
* bbox
)
704 g_return_val_if_fail (tree
!= NULL
, FALSE
);
705 g_return_val_if_fail (bbox
!= NULL
, FALSE
);
708 if (!gts_bboxes_are_overlapping (bbox
, bb
))
710 if (tree
->children
== NULL
) /* leaf node */
714 if (gts_bb_tree_is_overlapping (i
, bbox
))
722 * gts_bb_tree_traverse_overlapping:
723 * @tree1: a bounding box tree.
724 * @tree2: a bounding box tree.
725 * @func: a #GtsBBTreeTraverseFunc.
726 * @data: user data to be passed to @func.
728 * Calls @func for each overlapping pair of leaves of @tree1 and @tree2.
730 void gts_bb_tree_traverse_overlapping (GNode
* tree1
, GNode
* tree2
,
731 GtsBBTreeTraverseFunc func
,
734 GtsBBox
* bb1
, * bb2
;
736 g_return_if_fail (tree1
!= NULL
&& tree2
!= NULL
);
738 bb1
= tree1
->data
; bb2
= tree2
->data
;
739 if (!gts_bboxes_are_overlapping (bb1
, bb2
))
742 if (tree1
->children
== NULL
&& tree2
->children
== NULL
)
743 (*func
) (tree1
->data
, tree2
->data
, data
);
744 else if (tree2
->children
== NULL
||
745 (tree1
->children
!= NULL
&&
746 bbox_volume (bb1
) > bbox_volume (bb2
))) {
747 GNode
* i
= tree1
->children
;
749 gts_bb_tree_traverse_overlapping (i
, tree2
, func
, data
);
754 GNode
* i
= tree2
->children
;
756 gts_bb_tree_traverse_overlapping (tree1
, i
, func
, data
);
764 * @tree: a bounding box tree.
765 * @depth: a specified depth.
766 * @fptr: a file pointer.
768 * Write in @fptr an OOGL (Geomview) description of @tree for the
769 * depth specified by @depth.
771 void gts_bb_tree_draw (GNode
* tree
, guint depth
, FILE * fptr
)
775 g_return_if_fail (tree
!= NULL
);
776 g_return_if_fail (fptr
!= NULL
);
778 d
= g_node_depth (tree
);
781 fprintf (fptr
, "{ LIST");
784 gts_bbox_draw (tree
->data
, fptr
);
785 else if (d
< depth
) {
786 GNode
* i
= tree
->children
;
788 gts_bb_tree_draw (i
, depth
, fptr
);
794 fprintf (fptr
, "}\n");
797 static void bb_tree_free (GNode
* tree
, gboolean free_leaves
)
801 g_return_if_fail (tree
!= NULL
);
803 if (!free_leaves
&& tree
->children
== NULL
) /* leaf node */
806 gts_object_destroy (tree
->data
);
810 bb_tree_free (i
, free_leaves
);
816 * gts_bb_tree_destroy:
817 * @tree: a bounding box tree.
818 * @free_leaves: if %TRUE the bounding boxes given by the user are freed.
820 * Destroys all the bounding boxes created by @tree and destroys the
821 * tree itself. If @free_leaves is set to %TRUE, destroys boxes given
822 * by the user when creating the tree (i.e. leaves of the tree).
824 void gts_bb_tree_destroy (GNode
* tree
, gboolean free_leaves
)
826 g_return_if_fail (tree
!= NULL
);
828 bb_tree_free (tree
, free_leaves
);
829 g_node_destroy (tree
);
832 static gdouble
bb_tree_min_max (GNode
* tree
,
837 GNode
* tree1
, * tree2
;
838 gdouble min1
, max1
, min2
, max2
;
840 if (tree
->children
== NULL
) {
841 *list
= g_slist_prepend (*list
, tree
->data
);
844 tree1
= tree
->children
;
845 gts_bbox_point_distance2 (tree1
->data
, p
, &min1
, &max1
);
850 gts_bbox_point_distance2 (tree2
->data
, p
, &min2
, &max2
);
855 if (min1
<= min_max
) {
856 min_max
= bb_tree_min_max (tree1
, p
, min_max
, list
);
858 min_max
= bb_tree_min_max (tree2
, p
, min_max
, list
);
862 if (min2
<= min_max
) {
863 min_max
= bb_tree_min_max (tree2
, p
, min_max
, list
);
865 min_max
= bb_tree_min_max (tree1
, p
, min_max
, list
);
873 * gts_bb_tree_point_closest_bboxes:
874 * @tree: a bounding box tree.
877 * Returns: a list of #GtsBBox. One of the bounding boxes is assured to contain
878 * the object of @tree closest to @p.
880 GSList
* gts_bb_tree_point_closest_bboxes (GNode
* tree
,
883 gdouble min
, min_max
;
884 GSList
* list
= NULL
, * i
, * prev
= NULL
;
886 g_return_val_if_fail (tree
!= NULL
, NULL
);
887 g_return_val_if_fail (p
!= NULL
, NULL
);
889 gts_bbox_point_distance2 (tree
->data
, p
, &min
, &min_max
);
890 min_max
= bb_tree_min_max (tree
, p
, min_max
, &list
);
894 GSList
* next
= i
->next
;
897 gts_bbox_point_distance2 (i
->data
, p
, &min
, &max
);
915 * gts_bb_tree_point_distance:
916 * @tree: a bounding box tree.
918 * @distance: a #GtsBBoxDistFunc.
919 * @bbox: if not %NULL is set to the bounding box containing the closest
922 * Returns: the distance as evaluated by @distance between @p and the closest
925 gdouble
gts_bb_tree_point_distance (GNode
* tree
,
927 GtsBBoxDistFunc distance
,
931 gdouble dmin
= G_MAXDOUBLE
;
933 g_return_val_if_fail (tree
!= NULL
, dmin
);
934 g_return_val_if_fail (p
!= NULL
, dmin
);
935 g_return_val_if_fail (distance
!= NULL
, dmin
);
937 i
= list
= gts_bb_tree_point_closest_bboxes (tree
, p
);
939 gdouble d
= (*distance
) (p
, GTS_BBOX (i
->data
)->bounded
);
941 if (fabs (d
) < fabs (dmin
)) {
954 * gts_bb_tree_point_closest:
955 * @tree: a bounding box tree.
957 * @closest: a #GtsBBoxClosestFunc.
958 * @distance: if not %NULL is set to the distance between @p and the
961 * Returns: a new #GtsPoint, closest point to @p and belonging to an object of
964 GtsPoint
* gts_bb_tree_point_closest (GNode
* tree
,
966 GtsBBoxClosestFunc closest
,
970 gdouble dmin
= G_MAXDOUBLE
;
971 GtsPoint
* np
= NULL
;
973 g_return_val_if_fail (tree
!= NULL
, NULL
);
974 g_return_val_if_fail (p
!= NULL
, NULL
);
975 g_return_val_if_fail (closest
!= NULL
, NULL
);
977 i
= list
= gts_bb_tree_point_closest_bboxes (tree
, p
);
979 GtsPoint
* tp
= (*closest
) (p
, GTS_BBOX (i
->data
)->bounded
);
980 gdouble d
= gts_point_distance2 (tp
, p
);
984 gts_object_destroy (GTS_OBJECT (np
));
989 gts_object_destroy (GTS_OBJECT (tp
));
1001 * gts_bb_tree_triangle_distance:
1002 * @tree: a bounding box tree.
1003 * @t: a #GtsTriangle.
1004 * @distance: a #GtsBBoxDistFunc.
1005 * @delta: spatial scale of the sampling to be used.
1006 * @range: a #GtsRange to be filled with the results.
1008 * Given a triangle @t, points are sampled regularly on its surface
1009 * using @delta as increment. The distance from each of these points
1010 * to the closest object of @tree is computed using @distance and the
1011 * gts_bb_tree_point_distance() function. The fields of @range are
1012 * filled with the number of points sampled, the minimum, average and
1013 * maximum value and the standard deviation.
1015 void gts_bb_tree_triangle_distance (GNode
* tree
,
1017 GtsBBoxDistFunc distance
,
1021 GtsPoint
* p1
, * p2
, * p3
, * p
;
1022 GtsVector p1p2
, p1p3
;
1023 gdouble l1
, t1
, dt1
;
1026 g_return_if_fail (tree
!= NULL
);
1027 g_return_if_fail (t
!= NULL
);
1028 g_return_if_fail (distance
!= NULL
);
1029 g_return_if_fail (delta
> 0.);
1030 g_return_if_fail (range
!= NULL
);
1032 gts_triangle_vertices (t
,
1035 (GtsVertex
**) &p3
);
1037 gts_vector_init (p1p2
, p1
, p2
);
1038 gts_vector_init (p1p3
, p1
, p3
);
1039 gts_range_init (range
);
1040 p
= GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (gts_point_class ())));
1042 l1
= sqrt (gts_vector_scalar (p1p2
, p1p2
));
1044 dt1
= 1.0/(gdouble
) n1
;
1046 for (i
= 0; i
<= n1
; i
++, t1
+= dt1
) {
1047 gdouble t2
= 1. - t1
;
1048 gdouble x
= t2
*p1p3
[0];
1049 gdouble y
= t2
*p1p3
[1];
1050 gdouble z
= t2
*p1p3
[2];
1051 gdouble l2
= sqrt (x
*x
+ y
*y
+ z
*z
);
1052 guint j
, n2
= (guint
) (l2
/delta
+ 1);
1053 gdouble dt2
= t2
/(gdouble
) n2
;
1055 x
= t2
*p1
->x
+ t1
*p2
->x
;
1056 y
= t2
*p1
->y
+ t1
*p2
->y
;
1057 z
= t2
*p1
->z
+ t1
*p2
->z
;
1060 for (j
= 0; j
<= n2
; j
++, t2
+= dt2
) {
1061 p
->x
= x
+ t2
*p1p3
[0];
1062 p
->y
= y
+ t2
*p1p3
[1];
1063 p
->z
= z
+ t2
*p1p3
[2];
1065 gts_range_add_value (range
,
1066 gts_bb_tree_point_distance (tree
, p
, distance
, NULL
));
1070 gts_object_destroy (GTS_OBJECT (p
));
1071 gts_range_update (range
);
1075 * gts_bb_tree_segment_distance:
1076 * @tree: a bounding box tree.
1077 * @s: a #GtsSegment.
1078 * @distance: a #GtsBBoxDistFunc.
1079 * @delta: spatial scale of the sampling to be used.
1080 * @range: a #GtsRange to be filled with the results.
1082 * Given a segment @s, points are sampled regularly on its length
1083 * using @delta as increment. The distance from each of these points
1084 * to the closest object of @tree is computed using @distance and the
1085 * gts_bb_tree_point_distance() function. The fields of @range are
1086 * filled with the number of points sampled, the minimum, average and
1087 * maximum value and the standard deviation.
1089 void gts_bb_tree_segment_distance (GNode
* tree
,
1091 gdouble (*distance
) (GtsPoint
*,
1096 GtsPoint
* p1
, * p2
, * p
;
1101 g_return_if_fail (tree
!= NULL
);
1102 g_return_if_fail (s
!= NULL
);
1103 g_return_if_fail (distance
!= NULL
);
1104 g_return_if_fail (delta
> 0.);
1105 g_return_if_fail (range
!= NULL
);
1107 p1
= GTS_POINT (s
->v1
);
1108 p2
= GTS_POINT (s
->v2
);
1110 gts_vector_init (p1p2
, p1
, p2
);
1111 gts_range_init (range
);
1112 p
= GTS_POINT (gts_object_new (GTS_OBJECT_CLASS (gts_point_class())));
1114 l
= sqrt (gts_vector_scalar (p1p2
, p1p2
));
1115 n
= (guint
) (l
/delta
+ 1);
1116 dt
= 1.0/(gdouble
) n
;
1118 for (i
= 0; i
<= n
; i
++, t
+= dt
) {
1119 p
->x
= p1
->x
+ t
*p1p2
[0];
1120 p
->y
= p1
->y
+ t
*p1p2
[1];
1121 p
->z
= p1
->z
+ t
*p1p2
[2];
1123 gts_range_add_value (range
,
1124 gts_bb_tree_point_distance (tree
, p
, distance
, NULL
));
1127 gts_object_destroy (GTS_OBJECT (p
));
1128 gts_range_update (range
);
1131 static void surface_distance_foreach_triangle (GtsTriangle
* t
,
1134 gdouble
* delta
= data
[1];
1135 GtsRange
* range
= data
[2];
1136 gdouble
* total_area
= data
[3], area
;
1137 GtsRange range_triangle
;
1139 gts_bb_tree_triangle_distance (data
[0], t
, data
[4], *delta
, &range_triangle
);
1141 if (range_triangle
.min
< range
->min
)
1142 range
->min
= range_triangle
.min
;
1143 if (range_triangle
.max
> range
->max
)
1144 range
->max
= range_triangle
.max
;
1145 range
->n
+= range_triangle
.n
;
1147 area
= gts_triangle_area (t
);
1148 *total_area
+= area
;
1149 range
->sum
+= area
*range_triangle
.mean
;
1150 range
->sum2
+= area
*range_triangle
.mean
*range_triangle
.mean
;
1154 * gts_bb_tree_surface_distance:
1155 * @tree: a bounding box tree.
1156 * @s: a #GtsSurface.
1157 * @distance: a #GtsBBoxDistFunc.
1158 * @delta: a sampling increment defined as the percentage of the diagonal
1159 * of the root bounding box of @tree.
1160 * @range: a #GtsRange to be filled with the results.
1162 * Calls gts_bb_tree_triangle_distance() for each face of @s. The
1163 * fields of @range are filled with the minimum, maximum and average
1164 * distance. The average distance is defined as the sum of the average
1165 * distances for each triangle weighthed by their area and divided by
1166 * the total area of the surface. The standard deviation is defined
1167 * accordingly. The @n field of @range is filled with the number of
1168 * sampled points used.
1170 void gts_bb_tree_surface_distance (GNode
* tree
,
1172 GtsBBoxDistFunc distance
,
1177 gdouble total_area
= 0.;
1179 g_return_if_fail (tree
!= NULL
);
1180 g_return_if_fail (s
!= NULL
);
1181 g_return_if_fail (delta
> 0. && delta
< 1.);
1182 g_return_if_fail (range
!= NULL
);
1184 gts_range_init (range
);
1185 delta
*= sqrt (gts_bbox_diagonal2 (tree
->data
));
1189 data
[3] = &total_area
;
1192 gts_surface_foreach_face (s
,
1193 (GtsFunc
) surface_distance_foreach_triangle
,
1196 if (total_area
> 0.) {
1197 if (range
->sum2
- range
->sum
*range
->sum
/total_area
>= 0.)
1198 range
->stddev
= sqrt ((range
->sum2
- range
->sum
*range
->sum
/total_area
)
1202 range
->mean
= range
->sum
/total_area
;
1205 range
->min
= range
->max
= range
->mean
= range
->stddev
= 0.;
1208 static void surface_distance_foreach_boundary (GtsEdge
* e
,
1211 gdouble
* delta
= data
[1];
1212 GtsRange
* range
= data
[2];
1213 gdouble
* total_length
= data
[3], length
;
1214 GtsRange range_edge
;
1216 if (gts_edge_is_boundary (e
, NULL
)) {
1217 GtsSegment
* s
= GTS_SEGMENT (e
);
1219 gts_bb_tree_segment_distance (data
[0], s
, data
[4], *delta
, &range_edge
);
1221 if (range_edge
.min
< range
->min
)
1222 range
->min
= range_edge
.min
;
1223 if (range_edge
.max
> range
->max
)
1224 range
->max
= range_edge
.max
;
1225 range
->n
+= range_edge
.n
;
1227 length
= gts_point_distance (GTS_POINT (s
->v1
), GTS_POINT (s
->v2
));
1228 *total_length
+= length
;
1229 range
->sum
+= length
*range_edge
.mean
;
1230 range
->sum2
+= length
*range_edge
.mean
*range_edge
.mean
;
1235 * gts_bb_tree_surface_boundary_distance:
1236 * @tree: a bounding box tree.
1237 * @s: a #GtsSurface.
1238 * @distance: a #GtsBBoxDistFunc.
1239 * @delta: a sampling increment defined as the percentage of the diagonal
1240 * of the root bounding box of @tree.
1241 * @range: a #GtsRange to be filled with the results.
1243 * Calls gts_bb_tree_segment_distance() for each edge boundary of @s.
1244 * The fields of @range are filled with the minimum, maximum and
1245 * average distance. The average distance is defined as the sum of the
1246 * average distances for each boundary edge weighthed by their length
1247 * and divided by the total length of the boundaries. The standard
1248 * deviation is defined accordingly. The @n field of @range is filled
1249 * with the number of sampled points used.
1251 void gts_bb_tree_surface_boundary_distance (GNode
* tree
,
1253 gdouble (*distance
) (GtsPoint
*,
1259 gdouble total_length
= 0.;
1261 g_return_if_fail (tree
!= NULL
);
1262 g_return_if_fail (s
!= NULL
);
1263 g_return_if_fail (delta
> 0. && delta
< 1.);
1264 g_return_if_fail (range
!= NULL
);
1266 gts_range_init (range
);
1267 delta
*= sqrt (gts_bbox_diagonal2 (tree
->data
));
1271 data
[3] = &total_length
;
1274 gts_surface_foreach_edge (s
,
1275 (GtsFunc
) surface_distance_foreach_boundary
,
1278 if (total_length
> 0.) {
1279 if (range
->sum2
- range
->sum
*range
->sum
/total_length
>= 0.)
1280 range
->stddev
= sqrt ((range
->sum2
-
1281 range
->sum
*range
->sum
/total_length
)
1285 range
->mean
= range
->sum
/total_length
;
1288 range
->min
= range
->max
= range
->mean
= range
->stddev
= 0.;