1 //******************************************************************************
2 ///
3 /// @file core/bounding/boundingsphere.cpp
4 ///
5 /// Implementations related to bounding spheres (used by blob).
6 ///
7 /// @copyright
8 /// @parblock
9 ///
10 /// Persistence of Vision Ray Tracer ('POV-Ray') version 3.8.
11 /// Copyright 1991-2018 Persistence of Vision Raytracer Pty. Ltd.
12 ///
13 /// POV-Ray is free software: you can redistribute it and/or modify
14 /// it under the terms of the GNU Affero General Public License as
15 /// published by the Free Software Foundation, either version 3 of the
16 /// License, or (at your option) any later version.
17 ///
18 /// POV-Ray is distributed in the hope that it will be useful,
19 /// but WITHOUT ANY WARRANTY; without even the implied warranty of
20 /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 /// GNU Affero General Public License for more details.
22 ///
23 /// You should have received a copy of the GNU Affero General Public License
24 /// along with this program.  If not, see <http://www.gnu.org/licenses/>.
25 ///
26 /// ----------------------------------------------------------------------------
27 ///
28 /// POV-Ray is based on the popular DKB raytracer version 2.12.
29 /// DKBTrace was originally written by David K. Buck.
30 /// DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
31 ///
32 /// @endparblock
33 ///
34 //******************************************************************************
35 
36 // Unit header file must be the first file included within POV-Ray *.cpp files (pulls in config)
37 #include "core/bounding/boundingsphere.h"
38 
39 #include <algorithm>
40 
41 #include "core/coretypes.h"
42 
43 // this must be the last file included
44 #include "base/povdebug.h"
45 
46 namespace pov
47 {
48 
49 /*****************************************************************************
50 * Local preprocessor defines
51 ******************************************************************************/
52 
53 const int BRANCHING_FACTOR = 4;
54 
55 
56 /*****************************************************************************
57 * Static functions
58 ******************************************************************************/
59 
60 static void merge_spheres (Vector3d& C, DBL *r, const Vector3d& C1, DBL r1, const Vector3d& C2, DBL r2);
61 static void recompute_bound (BSPHERE_TREE *Node);
62 static int sort_and_split(BSPHERE_TREE **Root, BSPHERE_TREE ***Elements, int *nElem, int first, int last, int& maxelements);
63 
64 /*****************************************************************************
65 *
66 * FUNCTION
67 *
68 *   merge_spheres
69 *
70 * INPUT
71 *
72 *   C, r           - Center and radius^2 of new sphere
73 *   C1, r1, C2, r2 - Centers and radii^2 of spheres to merge
74 *
75 * OUTPUT
76 *
77 *   C, r
78 *
79 * RETURNS
80 *
81 * AUTHOR
82 *
83 *   Dieter Bayer
84 *
85 * DESCRIPTION
86 *
87 *   Calculate a sphere that encloses two given spheres.
88 *
89 * CHANGES
90 *
91 *   Jul 1994 : Creation.
92 *
93 *   Oct 1994 : Added test for enclosed spheres. Calculate optimal sphere. [DB]
94 *
95 ******************************************************************************/
96 
merge_spheres(Vector3d & C,DBL * r,const Vector3d & C1,DBL r1,const Vector3d & C2,DBL r2)97 static void merge_spheres(Vector3d& C, DBL *r, const Vector3d& C1, DBL r1, const Vector3d& C2, DBL r2)
98 {
99     DBL l, r1r, r2r, k1, k2;
100     Vector3d D;
101 
102     D = C1 - C2;
103 
104     l = D.length();
105 
106     /* Check if one sphere encloses the other. */
107 
108     r1r = sqrt(r1);
109     r2r = sqrt(r2);
110 
111     if (l + r1r <= r2r)
112     {
113         C = C2;
114 
115         *r = r2;
116 
117         return;
118     }
119 
120     if (l + r2r <= r1r)
121     {
122         C = C1;
123 
124         *r = r1;
125 
126         return;
127     }
128 
129     k1 = (1.0 + (r1r - r2r) / l) / 2.0;
130     k2 = (1.0 + (r2r - r1r) / l) / 2.0;
131 
132     C = k1 * C1 + k2 * C2;
133 
134     *r = Sqr((l + r1r + r2r) / 2.0);
135 }
136 
137 
138 
139 /*****************************************************************************
140 *
141 * FUNCTION
142 *
143 *   recompute_bound
144 *
145 * INPUT
146 *
147 *   Node - Pointer to node
148 *
149 * OUTPUT
150 *
151 *   Node
152 *
153 * RETURNS
154 *
155 * AUTHOR
156 *
157 *   Dieter Bayer
158 *
159 * DESCRIPTION
160 *
161 *   Recompute the bounding sphere of a given node in the bounding hierarchy,
162 *   i. e. find the bounding sphere that encloses the bounding spheres
163 *   of all nodes.
164 *
165 *   NOTE: The sphere found is probably not the tightest sphere possible!
166 *
167 * CHANGES
168 *
169 *   Jul 1994 : Creation.
170 *
171 *   Oct 1994 : Improved bounding sphere calculation. [DB]
172 *
173 ******************************************************************************/
174 
recompute_bound(BSPHERE_TREE * Node)175 static void recompute_bound(BSPHERE_TREE *Node)
176 {
177     short i;
178     DBL r2;
179     Vector3d C;
180 
181     C = Node->Node[0]->C;
182 
183     r2 = Node->Node[0]->r2;
184 
185     for (i = 1; i < Node->Entries; i++)
186     {
187         merge_spheres(C, &r2, C, r2, Node->Node[i]->C, Node->Node[i]->r2);
188     }
189 
190     Node->C = C;
191 
192     Node->r2 = r2;
193 }
194 
195 
196 
197 /*****************************************************************************
198 *
199 * FUNCTION
200 *
201 *   comp_elements
202 *
203 * INPUT
204 *
205 *   in_a, in_b - elements to compare
206 *
207 * OUTPUT
208 *
209 * RETURNS
210 *
211 *   int - result of comparison
212 *
213 * AUTHOR
214 *
215 *   Dieter Bayer
216 *
217 * DESCRIPTION
218 *
219 *   -
220 *
221 * CHANGES
222 *
223 *   Oct 1994 : Creation. (Derived from the bounding slab creation code)
224 *
225 ******************************************************************************/
226 
227 template<int Axis>
comp_elements(const void * in_a,const void * in_b)228 int CDECL comp_elements(const void *in_a, const void *in_b)
229 {
230     DBL am, bm;
231     typedef const BSPHERE_TREE *CONST_BSPHERE_TREE_PTR;
232 
233     am = (*reinterpret_cast<const CONST_BSPHERE_TREE_PTR *>(in_a))->C[Axis];
234     bm = (*reinterpret_cast<const CONST_BSPHERE_TREE_PTR *>(in_b))->C[Axis];
235 
236     if (am < bm - EPSILON)
237         return (-1);
238     else
239     {
240         if (am > bm + EPSILON)
241             return (1);
242         else
243             return (0);
244     }
245 }
246 
247 
248 
249 /*****************************************************************************
250 *
251 * FUNCTION
252 *
253 *   find_axis
254 *
255 * INPUT
256 *
257 * OUTPUT
258 *
259 * RETURNS
260 *
261 * AUTHOR
262 *
263 *   Dieter Bayer
264 *
265 * DESCRIPTION
266 *
267 *   -
268 *
269 * CHANGES
270 *
271 *   Oct 1994 : Creation. (Derived from the bounding slab creation code)
272 *
273 ******************************************************************************/
274 
find_axis(BSPHERE_TREE ** Elements,int first,int last)275 static int find_axis(BSPHERE_TREE **Elements, int first, int  last)
276 {
277     int which = X;
278     int i;
279     DBL e, d = - BOUND_HUGE;
280     Vector3d C, mins, maxs;
281 
282     mins = Vector3d(BOUND_HUGE);
283     maxs = Vector3d(-BOUND_HUGE);
284 
285     for (i = first; i < last; i++)
286     {
287         C = Elements[i]->C;
288 
289         mins[X] = min(mins[X], C[X]);
290         maxs[X] = max(maxs[X], C[X]);
291 
292         mins[Y] = min(mins[Y], C[Y]);
293         maxs[Y] = max(maxs[Y], C[Y]);
294 
295         mins[Z] = min(mins[Z], C[Z]);
296         maxs[Z] = max(maxs[Z], C[Z]);
297     }
298 
299     e = maxs[X] - mins[X];
300 
301     if (e > d)
302     {
303         d = e;  which = X;
304     }
305 
306     e = maxs[Y] - mins[Y];
307 
308     if (e > d)
309     {
310         d = e;  which = Y;
311     }
312 
313     e = maxs[Z] - mins[Z];
314 
315     if (e > d)
316     {
317         which = Z;
318     }
319 
320     return (which);
321 }
322 
323 
324 
325 /*****************************************************************************
326 *
327 * FUNCTION
328 *
329 *   build_area_table
330 *
331 * INPUT
332 *
333 * OUTPUT
334 *
335 * RETURNS
336 *
337 * AUTHOR
338 *
339 *   Dieter Bayer
340 *
341 * DESCRIPTION
342 *
343 *   Generates a table of bounding sphere surface areas.
344 *
345 * CHANGES
346 *
347 *   Oct 1994 : Creation. (Derived from the bounding slab creation code)
348 *
349 ******************************************************************************/
350 
build_area_table(BSPHERE_TREE ** Elements,int a,int b,DBL * areas)351 static void build_area_table(BSPHERE_TREE **Elements, int a, int  b, DBL *areas)
352 {
353     int i, imin, dir;
354     DBL r2;
355     Vector3d C;
356 
357     if (a < b)
358     {
359         imin = a;  dir = 1;
360     }
361     else
362     {
363         imin = b;  dir = -1;
364     }
365 
366     C = Elements[a]->C;
367 
368     r2 = Elements[a]->r2;
369 
370     for (i = a; i != (b + dir); i += dir)
371     {
372         merge_spheres(C, &r2, C, r2, Elements[i]->C, Elements[i]->r2);
373 
374         areas[i-imin] = r2;
375     }
376 }
377 
378 
379 
380 /*****************************************************************************
381 *
382 * FUNCTION
383 *
384 *   sort_and_split
385 *
386 * INPUT
387 *
388 * OUTPUT
389 *
390 * RETURNS
391 *
392 * AUTHOR
393 *
394 *   Dieter Bayer
395 *
396 * DESCRIPTION
397 *
398 *   -
399 *
400 * CHANGES
401 *
402 *   Oct 1994 : Creation. (Derived from the bounding slab creation code)
403 *
404 ******************************************************************************/
405 
sort_and_split(BSPHERE_TREE ** Root,BSPHERE_TREE *** Elements,int * nElem,int first,int last,int & maxelements)406 static int sort_and_split(BSPHERE_TREE **Root, BSPHERE_TREE ***Elements, int *nElem, int first, int last, int& maxelements)
407 {
408     int size, i, best_loc;
409     DBL *area_left, *area_right;
410     DBL best_index, new_index;
411     BSPHERE_TREE *cd;
412 
413     int Axis = find_axis(*Elements, first, last);
414 
415     size = last - first;
416 
417     if (size <= 0)
418     {
419         return (1);
420     }
421 
422     /*
423      * Actually, we could do this faster in several ways. We could use a
424      * logn algorithm to find the median along the given axis, and then a
425      * linear algorithm to partition along the axis. Oh well.
426      */
427 
428     switch(Axis)
429     {
430         case X:
431             QSORT(reinterpret_cast<void *>(*Elements + first), size, sizeof(BSPHERE_TREE *), comp_elements<X>);
432             break;
433         case Y:
434             QSORT(reinterpret_cast<void *>(*Elements + first), size, sizeof(BSPHERE_TREE *), comp_elements<Y>);
435             break;
436         case Z:
437             QSORT(reinterpret_cast<void *>(*Elements + first), size, sizeof(BSPHERE_TREE *), comp_elements<Z>);
438             break;
439     }
440 
441     /*
442      * area_left[] and area_right[] hold the surface areas of the bounding
443      * boxes to the left and right of any given point. E.g. area_left[i] holds
444      * the surface area of the bounding box containing Elements 0 through i and
445      * area_right[i] holds the surface area of the box containing Elements
446      * i through size-1.
447      */
448 
449     area_left  = new DBL[size];
450     area_right = new DBL[size];
451 
452     /* Precalculate the areas for speed. */
453 
454     build_area_table(*Elements, first, last - 1, area_left);
455     build_area_table(*Elements, last - 1, first, area_right);
456 
457     best_index = area_right[0] * (size - 3.0);
458 
459     best_loc = - 1;
460 
461     /*
462      * Find the most effective point to split. The best location will be
463      * the one that minimizes the function N1*A1 + N2*A2 where N1 and N2
464      * are the number of objects in the two groups and A1 and A2 are the
465      * surface areas of the bounding boxes of the two groups.
466      */
467 
468     for (i = 0; i < size - 1; i++)
469     {
470         new_index = (i + 1) * area_left[i] + (size - 1 - i) * area_right[i + 1];
471 
472         if (new_index < best_index)
473         {
474             best_index = new_index;
475             best_loc = i + first;
476         }
477     }
478 
479     delete[] area_left;
480     delete[] area_right;
481 
482     /*
483      * Stop splitting if the BRANCHING_FACTOR is reached or
484      * if splitting stops being effective.
485      */
486 
487     if ((size <= BRANCHING_FACTOR) || (best_loc < 0))
488     {
489         cd = reinterpret_cast<BSPHERE_TREE *>(POV_MALLOC(sizeof(BSPHERE_TREE), "blob bounding hierarchy"));
490 
491         cd->Entries = (short)size;
492 
493         cd->Node = reinterpret_cast<BSPHERE_TREE **>(POV_MALLOC(size*sizeof(BSPHERE_TREE *), "blob bounding hierarchy"));
494 
495         for (i = 0; i < size; i++)
496         {
497             cd->Node[i] = (*Elements)[first+i];
498         }
499 
500         recompute_bound(cd);
501 
502         *Root = cd;
503 
504         if (*nElem >= maxelements)
505         {
506             /* Prim array overrun, increase array by 50%. */
507 
508             maxelements = 1.5 * maxelements;
509 
510             /* For debugging only. */
511 
512 // TODO FIXME           Debug_Info("Reallocing elements to %d\n", maxelements);
513 
514             *Elements = reinterpret_cast<BSPHERE_TREE **>(POV_REALLOC(*Elements, maxelements * sizeof(BSPHERE_TREE *), "bounding slabs"));
515         }
516 
517         (*Elements)[*nElem] = cd;
518 
519         (*nElem)++;
520 
521         return (1);
522     }
523     else
524     {
525         sort_and_split(Root, Elements, nElem, first, best_loc + 1, maxelements);
526 
527         sort_and_split(Root, Elements, nElem, best_loc + 1, last, maxelements);
528 
529         return (0);
530     }
531 }
532 
533 
534 
535 /*****************************************************************************
536 *
537 * FUNCTION
538 *
539 *   Build_Bounding_Sphere_Hierarchy
540 *
541 * INPUT
542 *
543 *   nElem    - number of elements in Elements
544 *   Elements - array containing nElem elements
545 *
546 * OUTPUT
547 *
548 *   Root     - root node of the hierarchy
549 *
550 * RETURNS
551 *
552 * AUTHOR
553 *
554 *   Dieter Bayer
555 *
556 * DESCRIPTION
557 *
558 *   Create the bounding sphere hierarchy for a given set of elements.
559 *   One element consists of an element number (index into the array
560 *   of elements; e.g. blob components, triangles) and a bounding
561 *   sphere enclosing this element (center and squared radius).
562 *
563 * CHANGES
564 *
565 *   Oct 1994 : Creation. (Derived from the bounding slab creation code)
566 *
567 ******************************************************************************/
568 
Build_Bounding_Sphere_Hierarchy(BSPHERE_TREE ** Root,int nElem,BSPHERE_TREE *** Elements)569 void Build_Bounding_Sphere_Hierarchy(BSPHERE_TREE **Root, int nElem, BSPHERE_TREE ***Elements)
570 {
571     int low, high;
572 
573     // This is a resonable guess at the number of elements needed.
574     // This array will be reallocated as needed if it isn't.
575     int maxelements = 2 * nElem;
576 
577     // Do a sort on the elements, with the end result being
578     // a tree of objects sorted along the x, y, and z axes.
579 
580     if (nElem > 0)
581     {
582         low  = 0;
583         high = nElem;
584 
585         while (sort_and_split(Root, Elements, &nElem, low, high, maxelements) == 0)
586         {
587             low  = high;
588             high = nElem;
589         }
590     }
591 }
592 
593 
594 
595 /*****************************************************************************
596 *
597 * FUNCTION
598 *
599 *   Destroy_Bounding_Sphere_Hierarchy
600 *
601 * INPUT
602 *
603 *   Node - Pointer to current node
604 *
605 * OUTPUT
606 *
607 *   Node
608 *
609 * RETURNS
610 *
611 * AUTHOR
612 *
613 *   Dieter Bayer
614 *
615 * DESCRIPTION
616 *
617 *   Destroy bounding sphere hierarchy.
618 *
619 * CHANGES
620 *
621 *   Aug 1994 : Creation.
622 *
623 *   Dec 1994 : Fixed memory leakage. [DB]
624 *
625 ******************************************************************************/
626 
Destroy_Bounding_Sphere_Hierarchy(BSPHERE_TREE * Node)627 void Destroy_Bounding_Sphere_Hierarchy(BSPHERE_TREE *Node)
628 {
629     short i;
630 
631     if (Node != nullptr)
632     {
633         if (Node->Entries > 0)
634         {
635             /* This is a node. Free sub-nodes. */
636 
637             for (i = 0; i < Node->Entries; i++)
638             {
639                 Destroy_Bounding_Sphere_Hierarchy(Node->Node[i]);
640             }
641 
642             POV_FREE(Node->Node);
643         }
644 
645         POV_FREE(Node);
646     }
647 }
648 
649 }
650