home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: Graphics / Graphics.zip / povsrc31.zip / bsphere.c < prev    next >
C/C++ Source or Header  |  1999-10-20  |  14KB  |  652 lines

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