home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / macraysh.sit / Code / Source / blob.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-25  |  17.8 KB  |  714 lines

  1. /*
  2.  * blob.c
  3.  *
  4.  * Copyright (C) 1990, 1991, Mark Podlipec, Craig E. Kolb
  5.  * All rights reserved.
  6.  *
  7.  * This software may be freely copied, modified, and redistributed
  8.  * provided that this copyright notice is preserved on all copies.
  9.  *
  10.  * You may not distribute this software, in whole or in part, as part of
  11.  * any commercial product without the express consent of the authors.
  12.  *
  13.  * There is no warranty or other guarantee of fitness of this software
  14.  * for any purpose.  It is provided solely "as is".
  15.  *
  16.  * $Id: blob.c,v 4.0 91/07/17 14:36:07 kolb Exp Locker: kolb $
  17.  *
  18.  * $Log:    blob.c,v $
  19.  * Revision 4.0  91/07/17  14:36:07  kolb
  20.  * Initial version.
  21.  * 
  22.  */
  23. #include "geom.h"
  24. #include "blob.h"
  25.  
  26. Methods *iBlobMethods = NULL;
  27. static char blobName[] = "blob";
  28.  
  29. unsigned long BlobTests, BlobHits;
  30.  
  31. /*
  32.  * Blob/Metaball Description
  33.  *
  34.  * In this implementation a Blob is made up of a threshold T, and a 
  35.  * group of 1 or more Metaballs.  Each metaball 'i'  is defined by 
  36.  * its position (xi,yi,zi), its radius ri, and its strength si.
  37.  * Around each Metaball is a density function di(Ri) defined by:
  38.  *
  39.  *         di(Ri) =  c4i * Ri^4  +  c2i * Ri^2  + c0i     0 <= Ri <= ri
  40.  *         di(Ri) =  0                                    ri < Ri 
  41.  *
  42.  * where
  43.  *       c4i  = si / (ri^4)
  44.  *       c2i  = -(2 * si) / (ri^2)
  45.  *       c0i  = si
  46.  *       Ri^2 is the distance from a point (x,y,z) to the center of
  47.  *            the Metaball - (xi,yi,zi).
  48.  *
  49.  * The density function looks sort of like a W (Float-u) with the 
  50.  * center hump crossing the d-axis at  si  and the two humps on the
  51.  * side being tangent to the R-axis at  -ri  and  +ri. Only the 
  52.  * range  [0,ri] is being used. 
  53.  * I chose this function so that derivative = 0  at the points  0 and +ri. 
  54.  * This keeps the surface smooth when the densities are added. I also 
  55.  * wanted no  Ri^3  and  Ri  terms, since the equations are easier to 
  56.  * solve without them. This led to the symmetry about the d-axis and
  57.  * the derivative being equal to zero at -ri as well.
  58.  *
  59.  * The surface of the Blob is defined by:
  60.  *
  61.  *
  62.  *                  N
  63.  *                 ---  
  64.  *      F(x,y,z) = \    di(Ri)  = T
  65.  *                 /
  66.  *                 ---
  67.  *                 i=0
  68.  *
  69.  * where
  70.  *
  71.  *     di(Ri)    is   given above
  72.  *     Ri^2      =    (x-xi)^2  +  (y-yi)^2  + (z-zi)^2
  73.  *      N        is   number of Metaballs in Blob
  74.  *      T        is   the threshold
  75.  *    (xi,yi,zi) is   the center of Metaball i
  76.  *
  77.  */
  78.  
  79. /*****************************************************************************
  80.  * Create & return reference to a metaball.
  81.  */
  82. Blob *
  83. BlobCreate(T, mlist, npoints)
  84. Float T;
  85. MetaList *mlist;
  86. int npoints;
  87. {
  88.     Blob *blob;
  89.     int i;
  90.     MetaList *cur;
  91.  
  92. /* 
  93.  * There has to be at least one metaball in the blob.
  94.  * Note: if there's only one metaball, the blob 
  95.  * will be a sphere.
  96.  */
  97.     if (npoints < 1)
  98.     {
  99.         RLerror(RL_WARN, "blob field not correct.\n",0,0,0);
  100.         return (Blob *)NULL;
  101.     }
  102.  
  103. /*  
  104.  * Initialize primitive and Geom structures
  105.  */
  106.     blob = (Blob *)Malloc(sizeof(Blob));
  107.     blob->T = T;
  108.     blob->list=(MetaVector *) Malloc( (unsigned)(npoints*sizeof(MetaVector)) );
  109.     blob->num = npoints;
  110.  
  111. /*
  112.  * Initialize Metaball list
  113.  */
  114.     for(i=0;i<npoints;i++)
  115.     {
  116.         cur = mlist;
  117.         if ( (cur->mvec.c0 < EPSILON) || (cur->mvec.rs < EPSILON) )
  118.         {
  119.             RLerror(RL_WARN,"Degenerate metaball in blob (sr).\n",0,0,0);
  120.             return (Blob *)NULL;
  121.         }
  122.         /* store radius squared */
  123.         blob->list[i].rs = cur->mvec.rs * cur->mvec.rs;
  124.         /* Calculate and store coefficients for each metaball */
  125.         blob->list[i].c0 = cur->mvec.c0;
  126.         blob->list[i].c2 = -(2.0 * cur->mvec.c0) / blob->list[i].rs;
  127.         blob->list[i].c4 = cur->mvec.c0 /
  128.                 (blob->list[i].rs * blob->list[i].rs);
  129.         blob->list[i].x = cur->mvec.x;
  130.         blob->list[i].y = cur->mvec.y;
  131.         blob->list[i].z = cur->mvec.z;
  132.         mlist = mlist->next;
  133.         Free((voidstar)cur);
  134.     }
  135.     /* 
  136.      * Allocate room for Intersection Structures and
  137.      * Allocate room for an array of pointers to point to
  138.      * the Intersection Structures.
  139.      */
  140.     blob->ilist = (MetaInt *)Malloc( 2 * blob->num * sizeof(MetaInt));
  141.     blob->iarr = (MetaInt **)Malloc( 2 * blob->num * sizeof(MetaInt *));
  142.     return blob;
  143. }
  144.  
  145. Methods *
  146. BlobMethods()
  147. {
  148.     if (iBlobMethods == (Methods *)NULL) {
  149.         iBlobMethods = MethodsCreate();
  150.         iBlobMethods->create = (GeomCreateFunc *)BlobCreate;
  151.         iBlobMethods->methods = BlobMethods;
  152.         iBlobMethods->name = BlobName;
  153.         iBlobMethods->intersect = BlobIntersect;
  154.         iBlobMethods->normal = BlobNormal;
  155.         iBlobMethods->bounds = BlobBounds;
  156.         iBlobMethods->stats = BlobStats;
  157.         iBlobMethods->checkbounds = TRUE;
  158.         iBlobMethods->closed = TRUE;
  159.     }
  160.     return iBlobMethods;
  161. }
  162.  
  163. /*****************************************************************************
  164.  * Function used by qsort() when sorting the Ray/Blob intersection list
  165.  */
  166. int
  167. MetaCompare(A,B)
  168. char *A,*B;
  169. {
  170.     MetaInt **AA,**BB;
  171.  
  172.     AA = (MetaInt **) A;
  173.     BB = (MetaInt **) B;
  174.     if (AA[0]->bound == BB[0]->bound) return(0);
  175.     if (AA[0]->bound <  BB[0]->bound) return(-1);
  176.     return(1);  /* AA[0]->bound is > BB[0]->bound */
  177. }
  178.  
  179. /*****************************************************************************
  180.  * Ray/metaball intersection test.
  181.  */
  182. int
  183. BlobIntersect(blob, ray, mindist, maxdist)
  184. Blob *blob;
  185. Ray *ray;
  186. Float mindist, *maxdist;
  187. {
  188.     double c[5], s[4];
  189.     Float dist;
  190.     MetaInt *ilist,**iarr;
  191.     register int i,j,inum;
  192.     extern void qsort();
  193.  
  194.     BlobTests++;
  195.  
  196.     ilist = blob->ilist;
  197.     iarr = blob->iarr;
  198.  
  199. /*
  200.  * The first step in calculating the Ray/Blob intersection is to 
  201.  * divide the Ray into intervals such that only a fixed set of 
  202.  * Metaballs contribute to the density function along that interval. 
  203.  * This is done by finding the set of intersections between the Ray 
  204.  * and each Metaball's Sphere/Region of influence, which has a 
  205.  * radius  ri  and is centered at (xi,yi,zi).
  206.  * Intersection information is kept track of in the MetaInt 
  207.  * structure and consists of:
  208.  *
  209.  *   type    indicates whether this intersection is the start(R_START)
  210.  *           of a Region or the end(R_END) of one. 
  211.  *   pnt     the Metaball of this intersection
  212.  *   bound   the distance from Ray origin to this intersection
  213.  *
  214.  * This list is then sorted by  bound  and used later to find the Ray/Blob 
  215.  * intersection.
  216.  */
  217.  
  218.     inum = 0;
  219.     for(i=0; i < blob->num; i++)
  220.     {
  221.         register Float xadj, yadj, zadj;
  222.         register Float b, t, rs;
  223.         register Float dmin,dmax;
  224.  
  225.         rs   = blob->list[i].rs;
  226.         xadj = blob->list[i].x - ray->pos.x;
  227.         yadj = blob->list[i].y - ray->pos.y;
  228.         zadj = blob->list[i].z - ray->pos.z;
  229.  
  230.     /*
  231.      * Ray/Sphere of Influence intersection
  232.      */
  233.         b = xadj * ray->dir.x + yadj * ray->dir.y + zadj * ray->dir.z;
  234.         t = b * b - xadj * xadj - yadj * yadj - zadj * zadj + rs;
  235.  
  236.     /* 
  237.      * don't except imaginary or single roots. A single root is a ray
  238.      * tangent to the Metaball's Sphere/Region. The Metaball's
  239.      * contribution to the overall density function at this point is
  240.      * zero anyway.
  241.      */
  242.         if (t > 0.0) /* we have two roots */
  243.         {
  244.             t = sqrt(t);
  245.             dmin = b - t;
  246.     /* 
  247.      * only interested in stuff in front of ray origin 
  248.      */
  249.             if (dmin < mindist) dmin = mindist;
  250.             dmax = b + t;
  251.             if (dmax > dmin) /* we have a valid Region */
  252.             {
  253.         /*
  254.              * Initialize min/start and max/end Intersections Structures
  255.              * for this Metaball
  256.              */
  257.                 ilist[inum].type = R_START;
  258.                 ilist[inum].pnt = i;
  259.                 ilist[inum].bound = dmin;
  260.                 for(j=0;j<5;j++) ilist[inum].c[j] = 0.0;
  261.                 iarr[inum] = &(ilist[inum]);
  262.                 inum++;
  263.  
  264.                 ilist[inum].type = R_END;
  265.                 ilist[inum].pnt = i;
  266.                 ilist[inum].bound = dmax;
  267.                 for(j=0;j<5;j++) ilist[inum].c[j] = 0.0;
  268.                 iarr[inum] = &(ilist[inum]);
  269.                 inum++;
  270.             } /* End of valid Region */
  271.         } /* End of two roots */
  272.     } /* End of loop through metaballs */
  273.  
  274.     /*
  275.      * If there are no Ray/Metaball intersections there will 
  276.      * not be a Ray/Blob intersection. Exit now.
  277.      */
  278.     if (inum == 0)
  279.     {
  280.         return FALSE;
  281.     }
  282.  
  283.  
  284.     /* 
  285.      * Sort Intersection list. No sense using qsort if there's only
  286.      * two intersections.
  287.      *
  288.      * Note: we actually aren't sorting the Intersection structures, but
  289.      * an array of pointers to the Intersection structures. 
  290.      * This is faster than sorting the Intersection structures themselves.
  291.      */
  292.     if (inum==2)
  293.     {
  294.         MetaInt *t;
  295.         if (ilist[0].bound > ilist[1].bound)
  296.         {
  297.             t = iarr[0];
  298.             iarr[0] = iarr[1];
  299.             iarr[1] = t;
  300.         }
  301.     }
  302.     else
  303.         qsort((void *)iarr, (size_t)inum, (size_t)sizeof(MetaInt *),(__cmp_func)MetaCompare);
  304.  
  305.  
  306. /*
  307. * Finding the Ray/Blob Intersection
  308. * The non-zero part of the density function for each Metaball is
  309. *   di(Ri) = c4i * Ri^4  +  c2i * Ri^2  +  c0i 
  310. *
  311. * To find find the Ray/Blob intersection for one metaball
  312. * substitute for distance   
  313. *
  314. *     Ri^2 = (x-xi)^2 + (y-yi)^2 + (z-zi)^2
  315. * and then substitute the Ray equations:
  316. *   
  317. *     x  = x0 + x1 * t
  318. *     y  = y0 + y1 * t
  319. *     z  = z0 + z1 * t
  320. *
  321. * to get a big mess :^). Actually, it's a Quartic in t and it's fully 
  322. * listed farther down. Here's a short version:
  323. *
  324. *   c[4] * t^4  +  c[3] * t^3  +  c[2] * t^2  +  c[1] * t  +  c[0]  =  T
  325. *
  326. * Don't forget that the Blob is defined by the density being equal to 
  327. * the threshold T.
  328. * To calculate the intersection of a Ray and two or more Metaballs, 
  329. * the coefficients are calculated for each Metaball and then added 
  330. * together. We can do this since we're working with polynomials.
  331. * The points of intersection are the roots of the resultant equation.
  332. *
  333. * The algorithm loops through the intersection list, calculating
  334. * the coefficients if an intersection is the start of a Region and 
  335. * adding them to all intersections in that region.
  336. * When it detects a valid interval, it calculates the 
  337. * roots from the starting intersection's coefficients and if any of 
  338. * the roots are in the interval, the smallest one is returned.
  339. *
  340. */
  341.  
  342.     {
  343.         register Float *tmpc;
  344.         MetaInt *strt,*tmp;
  345.         register int istrt,itmp;
  346.         register int num,exitflag,inside;
  347.  
  348.     /*
  349.      * Start the algorithm outside the first interval
  350.      */
  351.         inside = 0;
  352.         istrt = 0; 
  353.         strt = iarr[istrt];
  354.         if (strt->type != R_START)
  355.             RLerror(RL_WARN,"MetaInt sanity check FAILED!\n",0,0,0);
  356.  
  357.         /*
  358.          * Loop through intersection. If a root is found the code
  359.          * will return at that point.
  360.          */
  361.         while( istrt < inum )
  362.         {
  363.             /* 
  364.              * Check for multiple intersections  at the same point.
  365.              * This is also where the coefficients are calculated
  366.              * and spread throughout that Metaball's sphere of
  367.              * influence.
  368.              */
  369.             do
  370.             {
  371.                 /* find out which metaball */
  372.                 i = strt->pnt;
  373.                 /* only at starting boundaries do this */
  374.                 if (strt->type == R_START)
  375.                 {
  376.                     register MetaVector *ml;
  377.                     register Float a1,a0;
  378.                     register Float xd,yd,zd;
  379.                     register Float c4,c2,c0;
  380.  
  381.                     /* we're inside */
  382.                     inside++;
  383.  
  384.     /*  As promised, the full equations
  385.      *
  386.      *   c[4] = c4*a2*a2; 
  387.      *   c[3] = 4.0*c4*a1*a2;
  388.      *   c[2] = 4.0*c4*a1*a1 + 2.0*c4*a2*a0 + c2*a2;
  389.      *   c[1] = 4.0*c4*a1*a0 + 2.0*c2*a1;
  390.      *   c[0] = c4*a0*a0 + c2*a0 + c0;
  391.      *
  392.      * where
  393.      *        a2 = (x1*x1 + y1*y1 + z1*z1) = 1.0 because the ray 
  394.      *                                           is normalized
  395.      *        a1 = (xd*x1 + yd*y1 + zd*z1)
  396.      *        a0 = (xd*xd + yd*yd + zd*zd)
  397.      *        xd = (x0 - xi)
  398.      *        yd = (y0 - yi)
  399.      *        zd = (z0 - zi)
  400.      *        (xi,yi,zi) is center of Metaball
  401.      *        (x0,y0,z0) is Ray origin
  402.      *        (x1,y1,z1) is normalized Ray direction
  403.      *        c4,c2,c0   are the coefficients for the
  404.      *                       Metaball's density function
  405.      *
  406.      */
  407.  
  408.                     /*
  409.                      * Some compilers would recalculate
  410.                      * this each time its used.
  411.                      */
  412.                     ml = &(blob->list[i]);
  413.  
  414.                     xd = ray->pos.x - ml->x;
  415.                     yd = ray->pos.y - ml->y;
  416.                     zd = ray->pos.z - ml->z;
  417.                     a1 = (xd * ray->dir.x + yd * ray->dir.y
  418.                         + zd * ray->dir.z);
  419.                     a0 = (xd * xd + yd * yd + zd * zd);
  420.  
  421.                     c0 = ml->c0;
  422.                     c2 = ml->c2;
  423.                     c4 = ml->c4;
  424.  
  425.                     c[4] = c4;
  426.                     c[3] = 4.0*c4*a1;
  427.                     c[2] = 2.0*c4*(2.0*a1*a1 + a0) + c2;
  428.                     c[1] = 2.0*a1*(2.0*c4*a0 + c2);
  429.                     c[0] = c4*a0*a0 + c2*a0 + c0;
  430.  
  431.         /* 
  432.          * Since we've gone through the trouble of calculating the 
  433.          * coefficients, put them where they'll be used.
  434.          * Starting at the current intersection(It's also the start of
  435.          * a region), add the coefficients to each intersection until
  436.          * we reach the end of this region.
  437.          */
  438.                     itmp = istrt; 
  439.                     tmp = strt;
  440.                     while( (tmp->pnt != i) ||
  441.                            (tmp->type != R_END) )
  442.                     {
  443.                         tmpc = tmp->c;
  444.                         for(j=0;j<5;j++) {
  445.                             *tmpc += c[j];
  446.                             tmpc++ ;
  447.                         }
  448.                         itmp++; 
  449.                         tmp = iarr[itmp];
  450.                     }
  451.  
  452.                 } /* End of start of a Region */ 
  453.                 /* 
  454.                  * Since the intersection wasn't the start
  455.                  * of a region, it must the end of one.
  456.                  */
  457.                 else inside--;
  458.  
  459.         /*
  460.          * If we are inside a region(or regions) and the next
  461.          * intersection is not at the same place, then we have
  462.          * the start of an interval. Set the exitflag.
  463.          */
  464.                 if ((inside > 0)
  465.                     && (strt->bound != iarr[istrt+1]->bound) )
  466.                     exitflag = 1;
  467.                 else 
  468.                 /* move to next intersection */
  469.                 {
  470.                     istrt++; 
  471.                     strt = iarr[istrt];
  472.                     exitflag = 0;
  473.                 }
  474.         /* 
  475.          * Check to see if we're at the end. If so then exit with
  476.          * no intersection found.
  477.          */
  478.                 if (istrt >= inum)
  479.                 {
  480.                     return FALSE;
  481.                 }
  482.             } while(!exitflag);
  483.                 /* End of Search for valid interval */
  484.  
  485.         /*
  486.          * Find Roots along this interval
  487.          */
  488.  
  489.             /* get coefficients from Intersection structure */
  490.             tmpc = strt->c;
  491.             for(j=0;j<5;j++) c[j] = *tmpc++;
  492.  
  493.             /* Don't forget to put in threshold */
  494.             c[0] -= blob->T;
  495.  
  496.             /* Use Graphic Gem's Quartic Root Finder */
  497.             num = SolveQuartic(c,s);
  498.  
  499.         /*
  500.          * If there are roots, search for roots within the interval.
  501.          */
  502.             dist = 0.0;
  503.             if (num>0)
  504.             {
  505.                 for(j=0;j<num;j++)
  506.                 {
  507.         /* 
  508.          * Not sure if EPSILON is truly needed, but it might cause
  509.          * small cracks between intervals in some cases. In any case 
  510.          * I don't believe it hurts.
  511.          */
  512.                     if ((s[j] >= (strt->bound - EPSILON))
  513.                         && (s[j] <= (iarr[istrt+1]->bound +
  514.                             EPSILON) ) )
  515.                     {
  516.                         if (dist == 0.0)
  517.                         /* first valid root */
  518.                             dist = s[j];
  519.                         else if (s[j] < dist)
  520.                          /* else only if smaller */
  521.                             dist = s[j];
  522.                     }
  523.                 }
  524.                 /*
  525.                  * Found a valid root 
  526.                  */
  527.                 if (dist > mindist && dist < *maxdist)
  528.                 {
  529.                     *maxdist = dist;
  530.                     BlobHits++;
  531.                     return TRUE;
  532.                     /* Yeah! Return valid root */
  533.                 }
  534.             }
  535.  
  536.         /* 
  537.          * Move to next intersection
  538.          */
  539.             istrt++;
  540.             strt = iarr[istrt];
  541.  
  542.         } /* End of loop through Intersection List */
  543.     } /* End of Solving for Ray/Blob Intersection */
  544.  
  545.     /* 
  546.      * return negative
  547.      */
  548.     return FALSE;
  549. }
  550.  
  551.  
  552. /***********************************************
  553.  * Find the Normal of a Blob at a given point
  554.  *
  555.  * The normal of a surface at a point (x0,y0,z0) is the gradient of that
  556.  * surface at that point. The gradient is the vector 
  557.  *
  558.  *            Fx(x0,y0,z0) , Fy(x0,y0,z0) , Fz(x0,y0,z0)
  559.  *
  560.  * where Fx(),Fy(),Fz() are the partial dervitives of F() with respect
  561.  * to x,y and z respectively. Since the surface of a Blob is made up
  562.  * of the sum of one or more polynomials, the normal of a Blob at a point
  563.  * is the sum of the gradients of the individual polynomials at that point.
  564.  * The individual polynomials in this case are di(Ri) i = 0,...,num .
  565.  *
  566.  * To find the gradient of the contributing polynomials
  567.  * take di(Ri) and substitute U = Ri^2;
  568.  *
  569.  *      di(U)    = c4i * U^2  +  c2i * U  + c0i
  570.  *
  571.  *      dix(U)   = 2 * c4i * Ux * U  +  c2i * Ux
  572.  *
  573.  *        U      = (x-xi)^2 + (y-yi)^2 + (z-zi)^2 
  574.  *
  575.  *        Ux     = 2 * (x-xi) 
  576.  *
  577.  * Rearranging we get
  578.  *  
  579.  *    dix(x0,y0,z0) = 4 * c4i * xdi * disti + 2 * c2i * xdi
  580.  *    diy(x0,y0,z0) = 4 * c4i * ydi * disti + 2 * c2i * ydi
  581.  *    diz(x0,y0,z0) = 4 * c4i * zdi * disti + 2 * c2i * zdi
  582.  * 
  583.  * where
  584.  *         xdi       =   x0-xi
  585.  *         ydi       =   y0-yi
  586.  *         zdi       =   y0-yi
  587.  *        disti      =   xdi*xdi + ydi*ydi + zdi*zdi   
  588.  *       (xi,yi,zi)  is  the center of Metaball i
  589.  *       c4i,c2i,c0i are the coefficients of Metaball i's density function
  590.  */
  591. int
  592. BlobNormal(blob, pos, nrm, gnrm)
  593. Blob *blob;
  594. Vector *pos, *nrm, *gnrm;
  595. {
  596.     register int i;
  597.  
  598.     /*  
  599.      * Initialize normals to zero 
  600.      */
  601.     nrm->x = nrm->y = nrm->z = 0.0;
  602.     /*
  603.      * Loop through Metaballs. If the point is within a Metaball's
  604.      * Sphere of influence, calculate the gradient and add it to the
  605.      * normals
  606.      */
  607.     for(i=0;i < blob->num; i++)
  608.     {
  609.         register MetaVector *sl;
  610.         register Float dist,xd,yd,zd;
  611.  
  612.         sl = &(blob->list[i]);
  613.         xd = pos->x - sl->x;
  614.         yd = pos->y - sl->y;
  615.         zd = pos->z - sl->z;
  616.  
  617.         dist  = xd*xd + yd*yd + zd*zd;
  618.         if (dist <= sl->rs )
  619.         {
  620.             register Float temp;
  621.  
  622.             /* temp is negative so normal points out of blob */
  623.             temp = -2.0 * (2.0 * sl->c4 * dist  +  sl->c2);
  624.             nrm->x += xd * temp;
  625.             nrm->y += yd * temp;
  626.             nrm->z += zd * temp;
  627.  
  628.         }
  629.     }
  630.     (void)VecNormalize(nrm);
  631.     *gnrm = *nrm;
  632.     return FALSE;
  633. }
  634.  
  635.  
  636. /*****************************************************************************
  637.  * Calculate the extent of the Blob
  638.  */
  639. void
  640. BlobBounds(blob, bounds)
  641. Blob *blob;
  642. Float bounds[2][3];
  643. {
  644.     Float r;
  645.     Float minx,miny,minz,maxx,maxy,maxz;
  646.     int i;
  647.  
  648.     /*
  649.      * Loop through Metaballs to find the minimun and maximum in each
  650.      * direction.
  651.      */
  652.     for( i=0;  i< blob->num;  i++)
  653.     {
  654.         register Float d;
  655.  
  656.         r = sqrt(blob->list[i].rs);
  657.         if (i==0)
  658.         {
  659.             minx = blob->list[i].x - r;
  660.             miny = blob->list[i].y - r;
  661.             minz = blob->list[i].z - r;
  662.             maxx = blob->list[i].x + r;
  663.             maxy = blob->list[i].y + r;
  664.             maxz = blob->list[i].z + r;
  665.         }
  666.         else
  667.         {
  668.             d = blob->list[i].x - r; 
  669.             if (d<minx) minx = d;
  670.             d = blob->list[i].y - r; 
  671.             if (d<miny) miny = d;
  672.             d = blob->list[i].z - r; 
  673.             if (d<minz) minz = d;
  674.             d = blob->list[i].x + r; 
  675.             if (d>maxx) maxx = d;
  676.             d = blob->list[i].y + r; 
  677.             if (d>maxy) maxy = d;
  678.             d = blob->list[i].z + r; 
  679.             if (d>maxz) maxz = d;
  680.         }
  681.     }
  682.     bounds[LOW][X]  = minx;
  683.     bounds[HIGH][X] = maxx;
  684.     bounds[LOW][Y]  = miny;
  685.     bounds[HIGH][Y] = maxy;
  686.     bounds[LOW][Z]  = minz;
  687.     bounds[HIGH][Z] = maxz;
  688. }
  689.  
  690. char *
  691. BlobName()
  692. {
  693.     return blobName;
  694. }
  695.  
  696. void
  697. BlobStats(tests, hits)
  698. unsigned long *tests, *hits;
  699. {
  700.     *tests = BlobTests;
  701.     *hits = BlobHits;
  702. }
  703.  
  704. void
  705. BlobMethodRegister(meth)
  706. UserMethodType meth;
  707. {
  708.     if (iBlobMethods)
  709.         iBlobMethods->user = meth;
  710. }
  711.