srb.c

Go to the documentation of this file.
00001 /**************************************************************************
00002 
00003 Rayburst Sampling Algorithm
00004 This code is used to cast rays inside a 3D volumetric dataset.
00005 
00006 Copyright (C) 2006 Computational Neurobiology and Imaging Center
00007 Mount Sinani School of Medicine, New York NY
00008 www.mssm.edu/cnic
00009 
00010 Software Development: Douglas Ehlenberger and Alfredo Rodriguez
00011 
00012 This program is free software; you can redistribute it and/or modify
00013 it under the terms of the GNU General Public License as published by
00014 the Free Software Foundation; either version 2 of the License, or
00015 (at your option) any later version.
00016 
00017 This program is distributed in the hope that it will be useful,
00018 but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020 GNU General Public License for more details.
00021 
00022 You should have received a copy of the GNU General Public License along
00023 with this program; if not, write to the Free Software Foundation, Inc.,
00024 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00025 
00026 Please send any questions or comments to douglas.ehlenberger@mssm.edu
00027 
00028 ***************************************************************************/
00029 
00030 #include "srb.h"
00031 
00032 
00033 #define _SRB_ARRAY_LENGTH( array )\
00034    ( sizeof( (array) ) / sizeof( (array)[ 0 ] ) )
00035 
00036 
00037 #define _SRB_MIN3( a, b, c )\
00038    ( ( a < b ) ? ( ( a < c ) ? 0 : 2 ) : ( ( b < c ) ? 1 : 2 ) )
00039 
00040 
00041 #define _SRB_DISTANCE_SQUARED( x1, y1, z1, x2, y2, z2 )\
00042    ( ( (x2) - (x1) ) * ( (x2) - (x1) ) +\
00043      ( (y2) - (y1) ) * ( (y2) - (y1) ) +\
00044      ( (z2) - (z1) ) * ( (z2) - (z1) )   )
00045 
00046 
00047 /* Helper macros to properly index vertex
00048    and triangle arrays. */
00049 
00050 #define _SRB_VERTEX( vertices, at )\
00051    ( (vertices) + ( 3 * (at) ) )
00052 
00053 #define _SRB_TRIANGLE( triangles, at )\
00054    ( (triangles) + ( 3 * (at) ) )
00055 
00056 
00057 /* Forward declarations. */
00058 
00059 struct _SRBVERTEX;
00060 typedef struct _SRBVERTEX SRBVERTEX;
00061 
00062 struct _SRBEDGE;
00063 typedef struct _SRBEDGE SRBEDGE;
00064 
00065 struct _SRBTRIANGLE;
00066 typedef struct _SRBTRIANGLE SRBTRIANGLE;
00067 
00068 
00069 struct _SRBVERTEX
00070    {
00071    double      x;
00072    double      y;
00073    double      z;
00074    int         index;
00075    SRBVERTEX  *next;
00076    };
00077 
00078 
00079 struct _SRBEDGE
00080    {
00081    SRBVERTEX    *V1;
00082    SRBVERTEX    *V2;
00083    SRBTRIANGLE  *T1;
00084    SRBTRIANGLE  *T2;
00085    SRBVERTEX    *M;
00086    SRBEDGE      *E1;
00087    SRBEDGE      *E2;
00088    SRBEDGE      *O;
00089    int           iteration;
00090    SRBEDGE      *next;
00091    };
00092 
00093 
00094 #define _SRB_EDGE_MIDPOINT( E, _x, _y, _z )\
00095    (_x) = ( (E)->V1->x + (E)->V2->x ) / 2.0;\
00096    (_y) = ( (E)->V1->y + (E)->V2->y ) / 2.0;\
00097    (_z) = ( (E)->V1->z + (E)->V2->z ) / 2.0
00098 
00099 
00100 #define _SRB_EDGE_FIND_CHILD( P, V1, V2, E )\
00101    ( (E) = _SRB_IS_EDGE( (P)->E1, (V1), (V2) ) ? (P)->E1 : (P)->E2 )
00102 
00103 
00104 /* NOTE: OK to use address since they are unique. */
00105 #define _SRB_IS_EDGE( E, _V1, _V2 )\
00106    ( ( (E)->V1 == (_V1) && (E)->V2 == (_V2) ) || ( (E)->V1 == (_V2) && (E)->V2 == (_V1) ) )
00107 
00108 
00109 struct _SRBTRIANGLE
00110    {
00111    SRBEDGE      *E1;
00112    SRBEDGE      *E2;
00113    SRBEDGE      *E3;
00114    SRBVERTEX    *V1;
00115    SRBVERTEX    *V2;
00116    SRBVERTEX    *V3;
00117    int           iteration;
00118    SRBTRIANGLE  *next;
00119    };
00120 
00121 
00122 #define _SRB_TRIANGLE_CENTER( T, _x, _y, _z )\
00123    (_x) = ( (T)->V1->x + (T)->V2->x + (T)->V3->x ) / 3.0;\
00124    (_y) = ( (T)->V1->y + (T)->V2->y + (T)->V3->y ) / 3.0;\
00125    (_z) = ( (T)->V1->z + (T)->V2->z + (T)->V3->z ) / 3.0
00126 
00127 
00128 typedef struct _SRBRAY
00129    {
00130    double  ox;
00131    double  oy;
00132    double  oz;
00133    double  dx;
00134    double  dy;
00135    double  dz;
00136    double  ex;
00137    double  ey;
00138    double  ez;
00139    }
00140    SRBRAY;
00141 
00142 
00143 typedef struct _SRBPYRAMID
00144    {
00145    double  ox;
00146    double  oy;
00147    double  oz;
00148    double  ax;
00149    double  ay;
00150    double  az;
00151    double  bx;
00152    double  by;
00153    double  bz;
00154    double  cx;
00155    double  cy;
00156    double  cz;
00157    double  volume;
00158    double  face_area;
00159    }
00160    SRBPYRAMID;
00161 
00162 
00163 typedef struct _SRB
00164    {
00165    SRBVERTEX    *vertices;
00166    SRBEDGE      *edges;
00167    SRBTRIANGLE  *triangles;
00168    int           iteration;
00169    SRBEDGE      *tail;
00170 
00171    /* Dummy headers. Avoid unnecessary allocation. */
00172    SRBVERTEX    _vertex;
00173    SRBEDGE      _edge;
00174    SRBTRIANGLE  _triangle;
00175    }
00176    SRB;
00177 
00178 
00179 static SRBVERTEX* _srb_vertex_new
00180    (
00181    SRB     *srb,
00182    double   x,
00183    double   y,
00184    double   z
00185    )
00186    {
00187    SRBVERTEX *V;
00188 
00189    if( NULL == ( V = malloc( sizeof( SRBVERTEX ) ) ) )
00190       return NULL;
00191 
00192    V->x = x;
00193    V->y = y;
00194    V->z = z;
00195 
00196    V->next = srb->vertices->next;
00197    srb->vertices->next = V;
00198 
00199    return V;
00200    }
00201 
00202 
00203 static SRBVERTEX* _srb_vertex_new_at
00204    (
00205    SRB     *srb,
00206    int      at,
00207    double   x,
00208    double   y,
00209    double   z
00210    )
00211    {
00212    SRBVERTEX  *V, *head;
00213    int         i;
00214 
00215 
00216    if( NULL == ( V = malloc( sizeof( SRBVERTEX ) ) ) )
00217       return NULL;
00218 
00219    V->x = x;
00220    V->y = y;
00221    V->z = z;
00222 
00223    head = srb->vertices;
00224    for( i = 0; i < at; ++i )
00225       head = head->next;
00226 
00227    V->next    = head->next;
00228    head->next = V;
00229 
00230    return V;
00231    }
00232 
00233 
00234 static SRBVERTEX* _srb_vertex_at( SRB *srb, int at )
00235    {
00236    SRBVERTEX  *V;
00237    int         i;
00238 
00239 
00240    V = srb->vertices->next;
00241 
00242    for( i = 0; i < at; ++i )
00243       V = V->next;
00244 
00245    return V;
00246    }
00247 
00248 
00249 static SRBEDGE* _srb_edge_new
00250    (
00251    SRB        *srb,
00252    SRBVERTEX  *V1,
00253    SRBVERTEX  *V2
00254    )
00255    {
00256    SRBEDGE *E;
00257 
00258    if( NULL == ( E = malloc( sizeof( SRBEDGE ) ) ) )
00259       return NULL;
00260 
00261    E->V1 = V1;
00262    E->V2 = V2;
00263    E->T1 = NULL;
00264    E->T2 = NULL;
00265    E->M  = NULL;
00266    E->E1 = NULL;
00267    E->E2 = NULL;
00268    E->O  = NULL;
00269 
00270    E->iteration = srb->iteration;
00271 
00272    E->next = srb->edges->next;
00273    srb->edges->next = E;
00274 
00275    return E;
00276    }
00277 
00278 
00279 static SRBEDGE* _srb_edge_new_at_tail( SRB *srb, SRBVERTEX *V1, SRBVERTEX *V2 )
00280    {
00281    SRBEDGE *E;
00282 
00283    if( NULL == ( E = _srb_edge_new( srb, V1, V2 ) ) )
00284       return NULL;
00285 
00286    /* Splice out from front. */
00287    srb->edges->next = E->next;
00288 
00289    if( NULL == srb->tail )
00290       {
00291       /* Splice back into front if first one. */
00292       E->next = srb->edges->next;
00293       srb->edges->next = E;
00294       }
00295    else
00296       {
00297       E->next = srb->tail->next;
00298       srb->tail->next = E;
00299       }
00300 
00301    srb->tail = E;
00302 
00303    return E;
00304    }
00305 
00306 
00307 static SRBEDGE* _srb_edge_find( SRB *srb, SRBVERTEX *V1, SRBVERTEX *V2 )
00308    {
00309    SRBEDGE *E = srb->edges->next;
00310 
00311    while( NULL != E )
00312       {
00313       if( _SRB_IS_EDGE( E, V1, V2 ) )
00314          return E;
00315 
00316       E = E->next;
00317       }
00318 
00319    return NULL;
00320    }
00321 
00322 
00323 static SRBEDGE* _srb_edge_new_unique( SRB *srb, SRBVERTEX *V1, SRBVERTEX *V2 )
00324    {
00325    SRBEDGE *E;
00326 
00327    if( NULL == ( E = _srb_edge_find( srb, V1, V2 ) ) )
00328       return _srb_edge_new( srb, V1, V2 );
00329    else
00330       return E;
00331    }
00332 
00333 
00334 static void _srb_edge_set_triangle( SRBEDGE *E, SRBTRIANGLE *T )
00335    {
00336    if( NULL == E->T1 )
00337       E->T1 = T;
00338    else if( NULL == E->T2 )
00339       E->T2 = T;
00340    }
00341 
00342 
00343 static SRBTRIANGLE* _srb_triangle_new
00344    (
00345    SRB        *srb,
00346    SRBEDGE    *E1,
00347    SRBEDGE    *E2,
00348    SRBEDGE    *E3,
00349    SRBVERTEX  *V1,
00350    SRBVERTEX  *V2,
00351    SRBVERTEX  *V3
00352    )
00353    {
00354    SRBTRIANGLE *T;
00355 
00356    if( NULL == ( T = malloc( sizeof( SRBTRIANGLE ) ) ) )
00357       return NULL;
00358 
00359    T->E1 = E1;
00360    T->E2 = E2;
00361    T->E3 = E3;
00362    T->V1 = V1;
00363    T->V2 = V2;
00364    T->V3 = V3;
00365 
00366    T->iteration = srb->iteration;
00367 
00368    T->next = srb->triangles->next;
00369    srb->triangles->next = T;
00370 
00371    return T;
00372    }
00373 
00374 
00375 static void _srb_init( SRB *srb, SRBPARAMS *params )
00376    {
00377    srb->_vertex.next   = NULL;
00378    srb->vertices       = &srb->_vertex;
00379    srb->_edge.next     = NULL;
00380    srb->edges          = &srb->_edge;
00381    srb->_triangle.next = NULL;
00382    srb->triangles      = &srb->_triangle;
00383 
00384    srb->iteration = 0;
00385 
00386    /* Convert the origin from voxel space to image space. */
00387    params->origin_x = params->origin_x / params->voxel_width;
00388    params->origin_y = params->origin_y / params->voxel_height;
00389    params->origin_z = params->origin_z / params->voxel_length;
00390    }
00391 
00392 
00393 static int _srb_init_2d
00394    (
00395    SRB        *srb,
00396    SRBPARAMS  *params,
00397    double     *vertices,
00398    int         vertex_count
00399    )
00400    {
00401    int         i, j;
00402    double     *v;
00403    SRBVERTEX  *V, *V1, *V2;
00404    SRBEDGE    *E1, *E2;
00405 
00406 
00407    _srb_init( srb, params );
00408    srb->tail = NULL;
00409 
00410    for( i = 0; i < vertex_count; ++i )
00411       {
00412       v = _SRB_VERTEX( vertices, i );
00413 
00414       if( NULL == _srb_vertex_new_at( srb, i, v[0], v[1], v[2] ) )
00415          return 0;
00416       }
00417 
00418    V = srb->vertices->next;
00419 
00420    while( NULL != V )
00421       {
00422       V1 = V;
00423       V2 = NULL != V->next ? V->next : srb->vertices->next;
00424 
00425       if( NULL == _srb_edge_new_at_tail( srb, V1, V2 ) )
00426          return 0;
00427 
00428       V = V->next;
00429       }
00430 
00431    /* Pair up opposite edges. */
00432 
00433    E1 = srb->edges->next;
00434 
00435    for( i = 0; i < vertex_count / 2; ++i )
00436       {
00437       E2 = E1;
00438 
00439       for( j = 0; j < vertex_count / 2; ++j )
00440          E2 = E2->next;
00441 
00442       E1->O = E2;
00443       E2->O = E1;
00444 
00445       E1 = E1->next;
00446       }
00447 
00448    return 1;
00449    }
00450 
00451 
00452 static int _srb_init_3d
00453    (
00454    SRB        *srb,
00455    SRBPARAMS  *params,
00456    double     *vertices,
00457    int         vertex_count,
00458    int        *triangles,
00459    int         triangle_count
00460    )
00461    {
00462    int           i;
00463    double       *v;
00464    int          *t;
00465    SRBVERTEX    *V1, *V2, *V3;
00466    SRBEDGE      *E1, *E2, *E3;
00467    SRBTRIANGLE  *T;
00468 
00469 
00470    _srb_init( srb, params );
00471 
00472    for( i = 0; i < vertex_count; ++i )
00473       {
00474       v = _SRB_VERTEX( vertices, i );
00475 
00476       if( NULL == _srb_vertex_new_at( srb, i, v[0], v[1], v[2] ) )
00477          return 0;
00478       }
00479 
00480    for( i = 0; i < triangle_count; ++i )
00481       {
00482       t = _SRB_VERTEX( triangles, i );
00483 
00484       V1 = _srb_vertex_at( srb, t[0] );
00485       V2 = _srb_vertex_at( srb, t[1] );
00486       V3 = _srb_vertex_at( srb, t[2] );
00487 
00488       if( NULL == ( E1 = _srb_edge_new_unique( srb, V1, V2 ) ) ||
00489           NULL == ( E2 = _srb_edge_new_unique( srb, V2, V3 ) ) ||
00490           NULL == ( E3 = _srb_edge_new_unique( srb, V3, V1 ) )    )
00491             return 0;
00492 
00493       if( NULL == ( T = _srb_triangle_new( srb, E1, E2, E3, V1, V2, V3 ) ) )
00494          return 0;
00495 
00496       _srb_edge_set_triangle( E1, T );
00497       _srb_edge_set_triangle( E2, T );
00498       _srb_edge_set_triangle( E3, T );
00499       }
00500 
00501    return 1;
00502    }
00503 
00504 
00505 static _srb_finalize( SRB *srb )
00506    {
00507    SRBVERTEX    *V;
00508    SRBEDGE      *E;
00509    SRBTRIANGLE  *T;
00510    void         *next;
00511 
00512 
00513    V = srb->vertices->next;
00514 
00515    while( NULL != V )
00516       {
00517       next = V->next;
00518       free( V );
00519       V = next;
00520       }
00521 
00522    E = srb->edges->next;
00523 
00524    while( NULL != E )
00525       {
00526       next = E->next;
00527       free( E );
00528       E = next;
00529       }
00530 
00531    T = srb->triangles->next;
00532 
00533    while( NULL != T )
00534       {
00535       next = T->next;
00536       free( T );
00537       T = next;
00538       }
00539    }
00540 
00541 
00542 static void _srb_set_midpoint_2d( SRBEDGE *E, SRBVERTEX *V, SRBPARAMS *params )
00543    {
00544    double  v1x, v1y, v1z, v2x, v2y, v2z;
00545    double  m;
00546 
00547 
00548    /* Find direction vectors. */
00549 
00550    v1x = E->V1->x - params->origin_x;
00551    v1y = E->V1->y - params->origin_y;
00552    v1z = E->V1->z - params->origin_z;
00553 
00554    v2x = E->V2->x - params->origin_x;
00555    v2y = E->V2->y - params->origin_y;
00556    v2z = E->V2->z - params->origin_z;
00557 
00558    /* Normalize them. */
00559 
00560    m = sqrt( v1x * v1x + v1y * v1y + v1z * v1z );
00561    v1x /= m;
00562    v1y /= m;
00563    v1z /= m;
00564 
00565    m = sqrt( v2x * v2x + v2y * v2y + v2z * v2z );
00566    v2x /= m;
00567    v2y /= m;
00568    v2z /= m;
00569 
00570    /* Just add the two vectors and we get the right direction. */
00571    V->x = v1x + v2x;
00572    V->y = v1y + v2y;
00573    V->z = v1z + v2z;
00574    }
00575 
00576 
00577 static int _srb_tesselate_2d( SRB *srb, SRBEDGE *E, SRBPARAMS *params )
00578    {
00579 /*  
00580                  
00581      () E->O->V1             () E->V2
00582       \                       \
00583        \                       \
00584         \                       \
00585          \  E->O->E1             \  E->E2
00586           \                       \
00587            \                       \
00588            () E->O->M     ()        () E->M
00589              \          origin       \  
00590               \                       \
00591                \                       \
00592                 \                       \  E->E1
00593                  \  E->O->E2             \
00594                   \                       \
00595                    \                       \
00596                    () E->O->V2             () E->V1
00597 */
00598 
00599    if( NULL == E->M )
00600       {
00601       if( NULL == ( E->M = _srb_vertex_new( srb, 0.0, 0.0, 0.0 ) ) )
00602          return 0;
00603 
00604       _srb_set_midpoint_2d( E, E->M, params );
00605 
00606       if( NULL == ( E->E1 = _srb_edge_new_at_tail( srb, E->V1, E->M ) ) )
00607          return 0;
00608 
00609       if( NULL == ( E->E2 = _srb_edge_new_at_tail( srb, E->M, E->V2 ) ) )
00610          return 0;
00611       }
00612 
00613    if( NULL != E->O->M )
00614       {
00615       /* NOTE: Pair up the edges so that on the next iteration a line
00616          drawn between their midpoints always passes through the origin. */
00617 
00618       E->E1->O    = E->O->E1;
00619       E->O->E1->O = E->E1;
00620 
00621       E->E2->O    = E->O->E2;
00622       E->O->E2->O = E->E2;
00623       }
00624 
00625    return 1;
00626    }
00627 
00628 
00629 static int _srb_tesselate_3d( SRB *srb, SRBTRIANGLE *T )
00630    {
00631    SRBEDGE      *E1, *E2, *E3, *E4, *E5, *E6, *E7, *E8, *E9;
00632    SRBTRIANGLE  *T1, *T2, *T3, *T4;
00633    double        x, y, z;
00634 
00635 /*                   T->V2
00636                       ()
00637                       /\
00638                      /  \
00639                     /    \
00640                  E5/  T2  \E4
00641                   /        \
00642                  /          \
00643        T->E2->M()-----E6-----()T->E1->M
00644                /\            /\
00645               /  \    T4    /  \
00646              /    \        /    \
00647           E8/  T3  \E7  E2/  T1  \E1
00648            /        \    /        \
00649           /          \  /          \
00650          /-----E9-----\/-----E3-----\
00651    T->V3()            ()            ()T->V1
00652                    T->E3->M
00653 */
00654          
00655    /* If necessary create up to 3 new midpoint vertices and up to
00656       6 new outside edges. */
00657    if( NULL == T->E1->M )
00658       {
00659       _SRB_EDGE_MIDPOINT( T->E1, x, y, z );
00660 
00661       if( NULL == ( T->E1->M = _srb_vertex_new( srb, x, y, z ) ) )
00662          return 0;
00663 
00664       if( NULL == ( T->E1->E1 = _srb_edge_new( srb, T->V1, T->E1->M ) ) )
00665          return 0;
00666 
00667       if( NULL == ( T->E1->E2 = _srb_edge_new( srb, T->E1->M, T->V2 ) ) )
00668          return 0;
00669 
00670       E1 = T->E1->E1;
00671       E4 = T->E1->E2;
00672       }
00673    else
00674       {
00675       _SRB_EDGE_FIND_CHILD( T->E1, T->V1, T->E1->M, E1 );
00676       _SRB_EDGE_FIND_CHILD( T->E1, T->E1->M, T->V2, E4 );
00677       }
00678 
00679    if( NULL == T->E2->M )
00680       {
00681       _SRB_EDGE_MIDPOINT( T->E2, x, y, z );
00682 
00683       if( NULL == ( T->E2->M = _srb_vertex_new( srb, x, y, z ) ) )
00684          return 0;
00685 
00686       if( NULL == ( T->E2->E1 = _srb_edge_new( srb, T->V2, T->E2->M ) ) )
00687          return 0;
00688 
00689       if( NULL == ( T->E2->E2 = _srb_edge_new( srb, T->E2->M, T->V3 ) ) )
00690          return 0;
00691 
00692       E5 = T->E2->E1;
00693       E8 = T->E2->E2;
00694       }
00695    else
00696       {
00697       _SRB_EDGE_FIND_CHILD( T->E2, T->V2, T->E2->M, E5 );
00698       _SRB_EDGE_FIND_CHILD( T->E2, T->E2->M, T->V3, E8 );
00699       }
00700 
00701    if( NULL == T->E3->M )
00702       {
00703       _SRB_EDGE_MIDPOINT( T->E3, x, y, z );
00704 
00705       if( NULL == ( T->E3->M = _srb_vertex_new( srb, x, y, z ) ) )
00706          return 0;
00707 
00708       if( NULL == ( T->E3->E1 = _srb_edge_new( srb, T->V3, T->E3->M ) ) )
00709          return 0;
00710 
00711       if( NULL == ( T->E3->E2 = _srb_edge_new( srb, T->E3->M, T->V1 ) ) )
00712          return 0;
00713 
00714       E9 = T->E3->E1;
00715       E3 = T->E3->E2;
00716       }
00717    else
00718       {
00719       _SRB_EDGE_FIND_CHILD( T->E3, T->V3, T->E3->M, E9 );
00720       _SRB_EDGE_FIND_CHILD( T->E3, T->E3->M, T->V1, E3 );
00721       }
00722 
00723    /* Always create 3 new edges for the middle triangle. */
00724    if( NULL == ( E6 = _srb_edge_new( srb, T->E1->M, T->E2->M ) ) )
00725       return 0;
00726 
00727    if( NULL == ( E7 = _srb_edge_new( srb, T->E2->M, T->E3->M ) ) )
00728       return 0;
00729 
00730    if( NULL == ( E2 = _srb_edge_new( srb, T->E3->M, T->E1->M ) ) )
00731       return 0;
00732 
00733    /* Create 4 new triangles from this original one. */
00734    if( NULL == ( T1 = _srb_triangle_new( srb, E1, E2, E3, T->V1, T->E1->M, T->E3->M ) ) )
00735       return 0;
00736 
00737    if( NULL == ( T2 = _srb_triangle_new( srb, E4, E5, E6, T->E1->M, T->V2, T->E2->M ) ) )
00738       return 0;
00739 
00740    if( NULL == ( T3 = _srb_triangle_new( srb, E7, E8, E9, T->E3->M, T->E2->M, T->V3 ) ) )
00741       return 0;
00742 
00743    if( NULL == ( T4 = _srb_triangle_new( srb, E6, E7, E2, T->E1->M, T->E2->M, T->E3->M ) ) )
00744       return 0;
00745 
00746    _srb_edge_set_triangle( E1, T1 );
00747    _srb_edge_set_triangle( E2, T1 );
00748    _srb_edge_set_triangle( E2, T4 );
00749    _srb_edge_set_triangle( E3, T1 );
00750 
00751    _srb_edge_set_triangle( E4, T2 );
00752    _srb_edge_set_triangle( E5, T2 );
00753    _srb_edge_set_triangle( E6, T2 );
00754    _srb_edge_set_triangle( E6, T4 );
00755 
00756    _srb_edge_set_triangle( E7, T3 );
00757    _srb_edge_set_triangle( E7, T4 );
00758    _srb_edge_set_triangle( E8, T3 );
00759    _srb_edge_set_triangle( E9, T3 );
00760 
00761    return 1;
00762    }
00763 
00764 
00765 static void _srb_mesh_delete( SRBMESH *mesh )
00766    {
00767    free( mesh->vertices );
00768    free( mesh->triangles );
00769    free( mesh );
00770    }
00771 
00772 
00773 static SRBMESH* _srb_mesh_new( int vertex_count, int triangle_count )
00774    {
00775    SRBMESH *mesh;
00776 
00777    if( NULL == ( mesh = malloc( sizeof( SRBMESH ) ) ) )
00778       return NULL;
00779 
00780    mesh->vertices  = malloc( sizeof( double ) * 3 * vertex_count );
00781    mesh->triangles = malloc( sizeof( int ) * 3 * triangle_count );
00782 
00783    if( NULL == mesh->vertices || NULL == mesh->triangles )
00784       {
00785       _srb_mesh_delete( mesh );
00786       return NULL;
00787       }
00788 
00789    mesh->vertex_count   = vertex_count;
00790    mesh->triangle_count = triangle_count;
00791 
00792    mesh->volume       = 0.0;
00793    mesh->surface_area = 0.0;
00794 
00795    return mesh;
00796    }
00797 
00798 
00799 static void _srb_fan_delete( SRBFAN *fan )
00800    {
00801    free( fan->vertices );
00802    free( fan );
00803    }
00804 
00805 
00806 static SRBFAN* _srb_fan_new( int vertex_count )
00807    {
00808    SRBFAN *fan;
00809 
00810    if( NULL == ( fan = malloc( sizeof( SRBFAN ) ) ) )
00811       return NULL;
00812 
00813    fan->vertices = malloc( sizeof( double ) * 3 * vertex_count );
00814 
00815    if( NULL == fan->vertices )
00816       {
00817       _srb_fan_delete( fan );
00818       return NULL;
00819       }
00820 
00821    fan->vertex_count = vertex_count;
00822 
00823    fan->diameter = 0.0;
00824    fan->area     = 0.0;
00825 
00826    return fan;
00827    }
00828 
00829 
00830 static void _srb_pyramid_face_area( SRBPYRAMID *triangle )
00831    {
00832    double nx, ny, nz;
00833    double oax, oay, oaz;
00834    double obx, oby, obz;
00835 
00836 
00837    /* Compute face vectors. */
00838    oax = triangle->ax - triangle->ox;
00839    oay = triangle->ay - triangle->oy;
00840    oaz = triangle->az - triangle->oz;
00841 
00842    obx = triangle->bx - triangle->ox;
00843    oby = triangle->by - triangle->oy;
00844    obz = triangle->bz - triangle->oz;
00845 
00846    /* Compute normal. */
00847    nx = oay * obz - oby * oaz;
00848    ny = oaz * obx - oax * obz;
00849    nz = oax * oby - obx * oay;
00850 
00851    /* Compute surface area. */
00852    triangle->face_area = 0.5 * sqrt( nx * nx + ny * ny + nz * nz );
00853    }
00854 
00855 
00856 static void _srb_pyramid_volume_and_surface_area( SRBPYRAMID *pyramid )
00857    {
00858    double  nx, ny, nz;
00859    double  acx, acy, acz;
00860    double  abx, aby, abz;
00861    double  aox, aoy, aoz;
00862 
00863 
00864    /* Compute base vectors. */
00865    acx = pyramid->cx - pyramid->ax;
00866    acy = pyramid->cy - pyramid->ay;
00867    acz = pyramid->cz - pyramid->az;
00868 
00869    abx = pyramid->bx - pyramid->ax;
00870    aby = pyramid->by - pyramid->ay;
00871    abz = pyramid->bz - pyramid->az;
00872 
00873    /* Compute normal. */
00874    nx = acy * abz - aby * acz;
00875    ny = abx * acz - acx * abz;
00876    nz = acx * aby - abx * acy;
00877 
00878    /* Compute 'a' to 'o' vector. */
00879    aox = pyramid->ox - pyramid->ax;
00880    aoy = pyramid->oy - pyramid->ay;
00881    aoz = pyramid->oz - pyramid->az;
00882 
00883    /* Compute surface area. */
00884    pyramid->face_area = 0.5 * sqrt( nx * nx + ny * ny + nz * nz );
00885 
00886    /* Compute volume. */
00887    pyramid->volume = ( 1.0 / 6.0 ) * ( aox * nx + aoy * ny + aoz * nz );
00888 
00889    /* If winding of the base triangle is known this test
00890       may be eliminated. */
00891    if( pyramid->volume < 0.0 )
00892       pyramid->volume = -pyramid->volume;
00893    }
00894 
00895 
00896 static SRBMESH* _srb_to_mesh( SRB *srb, SRBPARAMS *params )
00897    {
00898    SRBMESH      *mesh;
00899    SRBVERTEX    *V;
00900    SRBTRIANGLE  *T;
00901    int           vertex_count;
00902    int           triangle_count;
00903    double       *v;
00904    int          *t;
00905    int           i;
00906    SRBPYRAMID    P;
00907 
00908 
00909    vertex_count = 0;
00910    V            = srb->vertices->next;
00911 
00912    while( NULL != V )
00913       {
00914       /* Convert the point from image space to voxel space. */
00915       V->x = V->x * params->voxel_width;
00916       V->y = V->y * params->voxel_height;
00917       V->z = V->z * params->voxel_length;
00918 
00919       V->index = vertex_count++;
00920       V = V->next;
00921       }
00922 
00923    triangle_count = 0;
00924    T              = srb->triangles->next;
00925 
00926    while( NULL != T )
00927       {
00928       if( T->iteration == srb->iteration )
00929          ++triangle_count;
00930 
00931       T = T->next;
00932       }
00933 
00934    if( NULL == ( mesh = _srb_mesh_new( vertex_count, triangle_count ) ) )
00935       return NULL;
00936 
00937    V = srb->vertices->next;
00938 
00939    while( NULL != V )
00940       {
00941       v = _SRB_VERTEX( mesh->vertices, V->index );
00942 
00943       v[0] = V->x;
00944       v[1] = V->y;
00945       v[2] = V->z;
00946 
00947       V = V->next;
00948       }
00949 
00950    /* Convert the origin back to voxel space. */
00951    params->origin_x = params->origin_x * params->voxel_width;
00952    params->origin_y = params->origin_y * params->voxel_height;
00953    params->origin_z = params->origin_z * params->voxel_length;
00954 
00955    P.ox = params->origin_x;
00956    P.oy = params->origin_y;
00957    P.oz = params->origin_z;
00958 
00959    i = 0;
00960    T = srb->triangles->next;
00961 
00962    while( NULL != T )
00963       {
00964       if( T->iteration == srb->iteration )
00965          {
00966          t = _SRB_TRIANGLE( mesh->triangles, i );
00967          ++i;
00968 
00969          t[0] = T->V1->index;
00970          t[1] = T->V2->index;
00971          t[2] = T->V3->index;
00972 
00973          P.ax = T->V1->x;
00974          P.ay = T->V1->y;
00975          P.az = T->V1->z;
00976          P.bx = T->V2->x;
00977          P.by = T->V2->y;
00978          P.bz = T->V2->z;
00979          P.cx = T->V3->x;
00980          P.cy = T->V3->y;
00981          P.cz = T->V3->z;
00982 
00983          _srb_pyramid_volume_and_surface_area( &P );
00984 
00985          mesh->volume       += P.volume;
00986          mesh->surface_area += P.face_area;
00987          }
00988 
00989       T = T->next;
00990       }
00991 
00992    return mesh;
00993    }
00994 
00995 
00996 static SRBFAN* _srb_to_fan( SRB *srb, SRBPARAMS *params )
00997    {
00998    SRBFAN      *fan;
00999    SRBVERTEX   *V;
01000    SRBEDGE     *E;
01001    SRBVERTEX   *D1, *D2;
01002    int          vertex_count;
01003    double      *v;
01004    int          i;
01005    SRBPYRAMID   P;
01006    double       min_diameter;
01007    double       diameter;
01008 
01009 
01010    vertex_count = 0;
01011    V            = srb->vertices->next;
01012 
01013    while( NULL != V )
01014       {
01015       /* Convert the point from image space to voxel space. */
01016       V->x = V->x * params->voxel_width;
01017       V->y = V->y * params->voxel_height;
01018       V->z = V->z * params->voxel_length;
01019 
01020       ++vertex_count;
01021       V = V->next;
01022       }
01023 
01024    if( NULL == ( fan = _srb_fan_new( vertex_count ) ) )
01025       return NULL;
01026 
01027    /* Convert the origin back to voxel space. */
01028    params->origin_x = params->origin_x * params->voxel_width;
01029    params->origin_y = params->origin_y * params->voxel_height;
01030    params->origin_z = params->origin_z * params->voxel_length;
01031 
01032    /* NOTE: Need to go through the edges since they are in
01033       order if we want to generate a proper triangle fan. */
01034 
01035    i = 0;
01036    E = srb->edges->next;
01037 
01038    min_diameter = -1.0;
01039 
01040    while( NULL != E )
01041       {
01042       if( E->iteration == srb->iteration )
01043          {
01044          v = _SRB_VERTEX( fan->vertices, i );
01045 
01046          v[0] = E->V1->x;
01047          v[1] = E->V1->y;
01048          v[2] = E->V1->z;
01049 
01050          E->V1->index = i;
01051 
01052          /* NOTE: Using distance squared to avoid square root. */
01053          diameter = _SRB_DISTANCE_SQUARED(
01054                      E->V1->x,
01055                      E->V1->y,
01056                      E->V1->z,
01057                      E->O->V2->x,
01058                      E->O->V2->y,
01059                      E->O->V2->z
01060                      );
01061 
01062          if( min_diameter < 0.0 || diameter < min_diameter )
01063             {
01064             min_diameter = diameter;
01065 
01066             D1 = E->V1;
01067             D2 = E->O->V2;
01068             }
01069 
01070          ++i;
01071          }
01072 
01073       E = E->next;
01074       }
01075 
01076    fan->diameter = sqrt( min_diameter );
01077 
01078    P.ox = params->origin_x;
01079    P.oy = params->origin_y;
01080    P.oz = params->origin_z;
01081 
01082    E = srb->edges->next;
01083 
01084    while( NULL != E )
01085       {
01086       if( E->iteration == srb->iteration )
01087          {
01088          P.ax = E->V1->x;
01089          P.ay = E->V1->y;
01090          P.az = E->V1->z;
01091          P.bx = E->V2->x;
01092          P.by = E->V2->y;
01093          P.bz = E->V2->z;
01094 
01095          _srb_pyramid_face_area( &P );
01096 
01097          fan->area += P.face_area;
01098          }
01099 
01100       E = E->next;
01101       }
01102 
01103    return fan;
01104    }
01105 
01106 
01107 double _srb_interpolate_3d( SRBPARAMS *params, double x, double y, double z )
01108    {
01109    int     lox, loy, loz;
01110    double  i0, i1, i2, i3, i4, i5, i6, i7;
01111    double  i01, i23, i45, i67, i0123, i4567, value;
01112    int     imw, imh, iml, imwh;
01113 
01114 
01115    imw  = params->image_width;
01116    imh  = params->image_height;
01117    iml  = params->image_length;
01118    imwh = imw * imh;
01119 
01120    /* Check that point is inside image boundaries. */
01121    if( x < 0.0 || x > ( imw - 1 ) ||
01122        y < 0.0 || y > ( imh - 1 ) ||
01123        z < 0.0 || z > ( iml - 1 )   )
01124       return 0.0;
01125 
01126    /* Get point boundaries. */
01127    lox = ( int )x;
01128    loy = ( int )y;
01129    loz = ( int )z;
01130 
01131    /****************************************************************
01132    *  Get intensity at boundaries. Since these are integers there is
01133    *  not need to add 0.5 to find correct pixel domain.
01134    *             i1---i5     z
01135    *            /    /      /
01136    *          i0---i4 |     --x
01137    *           |   | i7    |
01138    *          i2--i6/      y
01139    *
01140    *****************************************************************/
01141    /* Get corner values. */
01142    i0 = ( double )params->image[ imwh * loz + imw * loy + lox ];
01143    i1 = ( double )params->image[ imwh * ( loz + 1 ) + imw * loy + lox ];
01144    i2 = ( double )params->image[ imwh * loz + imw * ( loy + 1 ) + lox ];
01145    i3 = ( double )params->image[ imwh * ( loz + 1 ) + imw * ( loy + 1 ) + lox ];
01146    i4 = ( double )params->image[ imwh * loz + imw * loy + ( lox + 1 ) ];
01147    i5 = ( double )params->image[ imwh * ( loz + 1 ) + imw * loy + ( lox + 1 ) ];
01148    i6 = ( double )params->image[ imwh * loz + imw * ( loy + 1 ) + ( lox + 1 ) ];
01149    i7 = ( double )params->image[ imwh * ( loz + 1 ) + imw * ( loy + 1 ) + ( lox + 1 ) ];
01150 
01151    /* Interpolate across z. */
01152    i01 = ( z - loz ) * ( i1 - i0 ) + i0;
01153    i23 = ( z - loz ) * ( i3 - i2 ) + i2;
01154    i45 = ( z - loz ) * ( i5 - i4 ) + i4;
01155    i67 = ( z - loz ) * ( i7 - i6 ) + i6;
01156 
01157    /* Interpolate across y. */
01158    i0123 = ( y - loy ) * ( i23 - i01 ) + i01;
01159    i4567 = ( y - loy ) * ( i67 - i45 ) + i45;
01160 
01161    /* Interpolate across x. */
01162    value = ( x - lox ) * ( i4567 - i0123 ) + i0123;
01163 
01164    /* Return that value. */
01165    return value;
01166    }
01167 
01168 
01169 double _srb_interpolate_2d( SRBPARAMS *params, double x, double y, double z, int dir )
01170    {
01171    int     lox, loy, loz;
01172    double  i0, i1, i2, i3, i4, i5, i6;
01173    double  i01, i23, i45, i02, i46, value;
01174    int     imw, imh, iml, imwh;
01175 
01176 
01177    imw  = params->image_width;
01178    imh  = params->image_height;
01179    iml  = params->image_length;
01180    imwh = imw * imh;
01181 
01182    /* Check that point is inside image boundaries. */
01183    if( x < 0.0 || x > ( imw - 1 ) ||
01184        y < 0.0 || y > ( imh - 1 ) ||
01185        z < 0.0 || z > ( iml - 1 )   )
01186       return 0.0;
01187 
01188    /* Get point boundaries. */
01189    lox = ( int )x;
01190    loy = ( int )y;
01191    loz = ( int )z;
01192 
01193    /****************************************************************
01194    *  Get intensity at boundaries. Since these are integers there is
01195    *  not need to add 0.5 to find correct pixel domain.
01196    *             i1---i5     z
01197    *            /    /      /
01198    *          i0---i4 |     --x
01199    *           |   | i7    |
01200    *          i2--i6/      y
01201    *
01202    *****************************************************************/
01203    switch( dir )
01204       {
01205       case 0:
01206          /* Get corner values. */
01207          i0 = ( double )params->image[ imwh * loz + imw * loy + lox ];
01208          i1 = ( double )params->image[ imwh * ( loz + 1 ) + imw * loy + lox ];
01209          i2 = ( double )params->image[ imwh * loz + imw * ( loy + 1 ) + lox ];
01210          i3 = ( double )params->image[ imwh * ( loz + 1 ) + imw * ( loy + 1 ) + lox ];
01211 
01212          /* Interpolate accross z. */
01213          i01 = ( z - loz ) * ( i1 - i0 ) + i0;
01214          i23 = ( z - loz ) * ( i3 - i2 ) + i2;
01215 
01216          /* Interpolate accross y. */
01217          value = ( y - loy ) * ( i23 - i01 ) + i01;
01218          break;
01219 
01220       case 1:
01221          /* Get corner values. */
01222          i0 = ( double )params->image[ imwh * loz + imw * loy + lox ];
01223          i1 = ( double )params->image[ imwh * ( loz + 1 ) + imw * loy + lox ];
01224          i4 = ( double )params->image[ imwh * loz + imw * loy + ( lox + 1 ) ];
01225          i5 = ( double )params->image[ imwh * ( loz + 1 ) + imw * loy + ( lox + 1 ) ];
01226 
01227          /* Interpolate accross z. */
01228          i01 = ( z - loz ) * ( i1 - i0 ) + i0;
01229          i45 = ( z - loz ) * ( i5 - i4 ) + i4;
01230 
01231          /* Interpolate across x. */
01232          value = ( x - lox ) * ( i45 - i01 ) + i01;
01233          break;
01234 
01235       case 2:
01236          /* Get corner values. */
01237          i0 = ( double )params->image[ imwh * loz + imw * loy + lox ];
01238          i2 = ( double )params->image[ imwh * loz + imw * ( loy + 1 ) + lox ];
01239          i4 = ( double )params->image[ imwh * loz + imw * loy + ( lox + 1 ) ];
01240          i6 = ( double )params->image[ imwh * loz + imw * ( loy + 1 ) + ( lox + 1 ) ];
01241 
01242          /* Interpolate accross y. */
01243          i02 = ( y - loy ) * ( i2 - i0 ) + i0;
01244          i46 = ( y - loy ) * ( i6 - i4 ) + i4;
01245 
01246          /* Interpolate accross x. */
01247          value = ( x - lox ) * ( i46 - i02 ) + i02;
01248          break;
01249       }
01250 
01251    /* Return that value. */
01252    return value;
01253    }
01254 
01255 
01256 void _srb_cast_ray( SRBRAY *ray, SRBPARAMS *params )
01257    {
01258    double  x, y, z, val;
01259    double  newx, newy, newz, newval;
01260    double  i, j, k, tx, ty, tz, tmin;
01261    int     which;
01262 
01263 
01264    /* Set current position of ray. */
01265    x = ray->ox;
01266    y = ray->oy;
01267    z = ray->oz;
01268 
01269    /* Compute first intensity using trilinear interpolation. */
01270    val = _srb_interpolate_3d( params, x, y, z );
01271 
01272    /* If intensity lower than threshold return origin as end. */
01273    if( val < params->threshold )
01274       {
01275       ray->ex = ray->ox;
01276       ray->ey = ray->oy;
01277       ray->ez = ray->oz;
01278 
01279       return;
01280       }
01281 
01282    while( 1 )
01283       {
01284       /* Get next face of exit. */
01285       i = ( ray->dx < 0.0 ) ? ceil( x - 1.0 ) : floor( x + 1.0 );
01286       j = ( ray->dy < 0.0 ) ? ceil( y - 1.0 ) : floor( y + 1.0 );
01287       k = ( ray->dz < 0.0 ) ? ceil( z - 1.0 ) : floor( z + 1.0 );
01288 
01289       /* Get time of intersection. */
01290       tx = ( i - x ) / ray->dx;
01291       ty = ( j - y ) / ray->dy;
01292       tz = ( k - z ) / ray->dz;
01293 
01294       which = _SRB_MIN3( tx, ty, tz );
01295 
01296       /* Interpolate at face. */
01297       switch( which )
01298          {
01299          case 0: tmin = tx; break;
01300          case 1: tmin = ty; break;
01301          case 2: tmin = tz; break;
01302          }
01303 
01304       newx = x + tmin * ray->dx;
01305       newy = y + tmin * ray->dy;
01306       newz = z + tmin * ray->dz;
01307 
01308       newval = _srb_interpolate_2d( params, newx, newy, newz, which );
01309 
01310       /* If intensity lower interpolate linearly and break. */
01311       if( newval < params->threshold )
01312          {
01313          ray->ex = ( params->threshold - val ) * ( newx - x ) / ( newval - val ) + x;
01314          ray->ey = ( params->threshold - val ) * ( newy - y ) / ( newval - val ) + y;
01315          ray->ez = ( params->threshold - val ) * ( newz - z ) / ( newval - val ) + z;
01316 
01317          return;
01318          }
01319 
01320       /* Advance position. */
01321       x   = newx;
01322       y   = newy;
01323       z   = newz;
01324       val = newval;
01325       }
01326    }
01327 
01328 
01329 static void _srb_initial_cast( SRB *srb, SRBPARAMS *params )
01330    {
01331    SRBVERTEX  *V;
01332    SRBRAY      R;
01333 
01334 
01335    R.ox = params->origin_x;
01336    R.oy = params->origin_y;
01337    R.oz = params->origin_z;
01338 
01339    V = srb->vertices->next;
01340 
01341    while( NULL != V )
01342       {
01343       /* First case is special case. The vertices
01344          position is the ray's direction. */
01345       R.dx = V->x;
01346       R.dy = V->y;
01347       R.dz = V->z;
01348 
01349       _srb_cast_ray( &R, params );
01350 
01351       V->x = R.ex;
01352       V->y = R.ey;
01353       V->z = R.ez;
01354 
01355       V = V->next;
01356       }
01357    }
01358 
01359 
01360 static int _srb_cast_2d( SRB *srb, SRBPARAMS *params )
01361    {
01362    SRBEDGE  *E;
01363    SRBRAY    R;
01364 
01365 
01366    ++(srb->iteration);
01367    srb->tail = NULL;
01368 
01369    /* First tesselate all the edges. */
01370 
01371    E = srb->edges->next;
01372 
01373    while( NULL != E )
01374       {
01375       if( E->iteration == srb->iteration - 1 )
01376          if( ! _srb_tesselate_2d( srb, E, params ) )
01377             return 0;
01378 
01379       E = E->next;
01380       }
01381 
01382    /* Now cast the midpoints. */
01383 
01384    R.ox = params->origin_x;
01385    R.oy = params->origin_y;
01386    R.oz = params->origin_z;
01387 
01388    E = srb->edges->next;
01389 
01390    while( NULL != E )
01391       {
01392       if( E->iteration == srb->iteration - 1 )
01393          {
01394          /* In 2D the midpoint is already a direction vector. */
01395          R.dx = E->M->x;
01396          R.dy = E->M->y;
01397          R.dz = E->M->z;
01398 
01399          _srb_cast_ray( &R, params );
01400 
01401          E->M->x = R.ex;
01402          E->M->y = R.ey;
01403          E->M->z = R.ez;
01404          }
01405 
01406       E = E->next;
01407       }
01408 
01409    return 1;
01410    }
01411 
01412 
01413 static int _srb_cast_3d( SRB *srb, SRBPARAMS *params )
01414    {
01415    SRBTRIANGLE  *T;
01416    SRBEDGE      *E;
01417    SRBRAY        R;
01418 
01419 
01420    ++(srb->iteration);
01421 
01422    /* First tesselate all the triangles. */
01423 
01424    T = srb->triangles->next;
01425 
01426    while( NULL != T )
01427       {
01428       if( T->iteration == srb->iteration - 1 )
01429          if( ! _srb_tesselate_3d( srb, T ) )
01430             return 0;
01431 
01432       T = T->next;
01433       }
01434 
01435    /* Now cast the midpoints. */
01436 
01437    R.ox = params->origin_x;
01438    R.oy = params->origin_y;
01439    R.oz = params->origin_z;
01440 
01441    E = srb->edges->next;
01442 
01443    while( NULL != E )
01444       {
01445       if( E->iteration == srb->iteration - 1 )
01446          {
01447          /* Convert the midpoint to a direction vector. */
01448          R.dx = E->M->x - R.ox;
01449          R.dy = E->M->y - R.oy;
01450          R.dz = E->M->z - R.oz;
01451 
01452          _srb_cast_ray( &R, params );
01453 
01454          E->M->x = R.ex;
01455          E->M->y = R.ey;
01456          E->M->z = R.ez;
01457          }
01458 
01459       E = E->next;
01460       }
01461 
01462    return 1;
01463    }
01464 
01465 
01466 static void _srb_tolerance_cast
01467    (
01468    SRB        *srb,
01469    SRBPARAMS  *params,
01470    double      x,
01471    double      y,
01472    double      z,
01473    double     *sum_dm,
01474    double     *sum_dc_minus_dm
01475    )
01476    {
01477    SRBRAY  R;
01478    double  dc, dm, dc_minus_dm;
01479 
01480 
01481    R.ox = params->origin_x;
01482    R.oy = params->origin_y;
01483    R.oz = params->origin_z;
01484 
01485    /* Distance to point. */
01486    dm = sqrt( _SRB_DISTANCE_SQUARED( R.ox, R.oy, R.oz, x, y, z ) );
01487 
01488    R.dx = x - R.ox;
01489    R.dy = y - R.oy;
01490    R.dz = z - R.oz;
01491 
01492    _srb_cast_ray( &R, params );
01493 
01494    /* Distance of the casted ray. */
01495    dc = sqrt( _SRB_DISTANCE_SQUARED( R.ox, R.oy, R.oz, R.ex, R.ey, R.ez ) );
01496 
01497    (*sum_dm) += dm;
01498 
01499    dc_minus_dm = dc - dm;
01500 
01501    if( dc_minus_dm < 0.0 )
01502       dc_minus_dm = -dc_minus_dm;
01503 
01504    (*sum_dc_minus_dm) += dc_minus_dm;
01505    }
01506 
01507 
01508 static int _srb_has_converged
01509    (
01510    SRB        *srb,
01511    SRBPARAMS  *params,
01512    double      sum_dm,
01513    double      sum_dc_minus_dm
01514    )
01515    {
01516    double f = ( sum_dc_minus_dm / sum_dm ) * 100.0;
01517 
01518    if( f < 0.0 )
01519       f = -f;
01520 
01521    return f <= params->fit_percent;
01522    }
01523 
01524 
01525 static int _srb_has_converged_3d( SRB *srb, SRBPARAMS *params )
01526    {
01527    SRBTRIANGLE  *T;
01528    double        x, y, z;
01529    double        sum_dm, sum_dc_minus_dm;
01530 
01531 
01532    sum_dm = sum_dc_minus_dm = 0.0;
01533 
01534    T = srb->triangles->next;
01535 
01536    while( NULL != T )
01537       {
01538       if( T->iteration == srb->iteration )
01539          {
01540          _SRB_TRIANGLE_CENTER( T, x, y, z );
01541          _srb_tolerance_cast( srb, params, x, y, z, &sum_dm, &sum_dc_minus_dm );
01542          }
01543 
01544       T = T->next;
01545       }
01546 
01547    return _srb_has_converged( srb, params, sum_dm, sum_dc_minus_dm );
01548    }
01549 
01550 
01551 static int _srb_has_converged_2d( SRB *srb, SRBPARAMS *params )
01552    {
01553    SRBEDGE  *E;
01554    double    x, y, z;
01555    double    sum_dm, sum_dc_minus_dm;
01556 
01557 
01558    sum_dm = sum_dc_minus_dm = 0.0;
01559 
01560    E = srb->edges->next;
01561 
01562    while( NULL != E )
01563       {
01564       if( E->iteration == srb->iteration )
01565          {
01566          _SRB_EDGE_MIDPOINT( E, x, y, z );
01567          _srb_tolerance_cast( srb, params, x, y, z, &sum_dm, &sum_dc_minus_dm );
01568          }
01569 
01570       E = E->next;
01571       }
01572 
01573    return _srb_has_converged( srb, params, sum_dm, sum_dc_minus_dm );
01574    }
01575 
01576 
01577 static double ____srb_octahedron_vertices[ 6 * 3 ] =
01578    { 
01579    1.0, 0.0, 0.0,
01580    0.0, 1.0, 0.0,
01581    -1.0, 0.0, 0.0,
01582    0.0, -1.0, 0.0,
01583    0.0, 0.0, 1.0,
01584    0.0, 0.0, -1.0
01585    };
01586 
01587 
01588 /* NOTE: These are vertex indices. */
01589 static int ____srb_octahedron_triangles[ 8 * 3 ] =
01590    { 
01591    0, 1, 4,
01592    1, 2, 4,
01593    2, 3, 4,
01594    3, 0, 4,
01595    1, 0, 5,
01596    2, 1, 5,
01597    3, 2, 5,
01598    0, 3, 5
01599    };
01600 
01601 
01602 SRBMESH* srb_run_3d( SRBPARAMS *params )
01603    {
01604    SRB       srb;
01605    SRBMESH  *mesh;
01606    int       i;
01607 
01608 
01609    if( ! _srb_init_3d(
01610             &srb,
01611             params,
01612             ____srb_octahedron_vertices,
01613             _SRB_ARRAY_LENGTH( ____srb_octahedron_vertices ) / 3,
01614             ____srb_octahedron_triangles,
01615             _SRB_ARRAY_LENGTH( ____srb_octahedron_triangles ) / 3
01616             ) )
01617       {
01618       _srb_finalize( &srb );
01619       return NULL;
01620       }
01621 
01622    _srb_initial_cast( &srb, params );
01623 
01624    for( i = 1; i <= params->max_iterations; ++i )
01625       {
01626       if( ! _srb_cast_3d( &srb, params ) )
01627          {
01628          _srb_finalize( &srb );
01629          return NULL;
01630          }
01631 
01632       if( _srb_has_converged_3d( &srb, params ) )
01633          break;
01634       }
01635 
01636    mesh = _srb_to_mesh( &srb, params );
01637    _srb_finalize( &srb );
01638 
01639    return mesh;
01640    }
01641 
01642 
01643 /* NOTE: Its critical that the vertices come in clockwise or
01644    counter-clockwise order! */
01645 static double ____srb_quadrilateral_vertices[ 4 * 3 ] =
01646    { 
01647    1.0, 0.0, 0.0,
01648    0.0, 1.0, 0.0,
01649    -1.0, 0.0, 0.0,
01650    0.0, -1.0, 0.0
01651    };
01652 
01653 
01654 SRBFAN* srb_run_2d( SRBPARAMS *params )
01655    {
01656    SRB      srb;
01657    SRBFAN  *fan;
01658    int      i;
01659 
01660 
01661    if( ! _srb_init_2d(
01662             &srb,
01663             params,
01664             ____srb_quadrilateral_vertices,
01665             _SRB_ARRAY_LENGTH( ____srb_quadrilateral_vertices ) / 3
01666             ) )
01667       {
01668       _srb_finalize( &srb );
01669       return NULL;
01670       }
01671 
01672    _srb_initial_cast( &srb, params );
01673 
01674    for( i = 1; i <= params->max_iterations; ++i )
01675       {
01676       if( ! _srb_cast_2d( &srb, params ) )
01677          {
01678          _srb_finalize( &srb );
01679          return NULL;
01680          }
01681 
01682       if( _srb_has_converged_2d( &srb, params ) )
01683          break;
01684       }
01685 
01686    fan = _srb_to_fan( &srb, params );
01687    _srb_finalize( &srb );
01688 
01689    return fan;
01690    }
01691 
01692 
01693 void srb_mesh_destroy( SRBMESH *mesh )
01694    {  _srb_mesh_delete( mesh );  }
01695 
01696 
01697 void srb_fan_destroy( SRBFAN *fan )
01698    {  _srb_fan_delete( fan );  }

Generated on Mon Jan 7 13:34:11 2008 for Rayburst Open-Source Code by  doxygen 1.4.7