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