00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042 #ifndef lint
00043 static const char RCSvol[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/g_vol.c,v 14.13 2006/09/16 02:04:25 lbutler Exp $ (BRL)";
00044 #endif
00045
00046 #include "common.h"
00047
00048 #include <stddef.h>
00049 #include <stdio.h>
00050 #include <ctype.h>
00051 #include <math.h>
00052 #include <string.h>
00053
00054 #include "machine.h"
00055 #include "vmath.h"
00056 #include "db.h"
00057 #include "nmg.h"
00058 #include "rtgeom.h"
00059 #include "raytrace.h"
00060 #include "./debug.h"
00061 #include "./fixpt.h"
00062
00063
00064
00065
00066
00067
00068
00069 struct rt_vol_specific {
00070 struct rt_vol_internal vol_i;
00071 vect_t vol_xnorm;
00072 vect_t vol_ynorm;
00073 vect_t vol_znorm;
00074 mat_t vol_mat;
00075 vect_t vol_origin;
00076 vect_t vol_large;
00077 };
00078 #define VOL_NULL ((struct rt_vol_specific *)0)
00079
00080 #define VOL_O(m) bu_offsetof(struct rt_vol_internal, m)
00081
00082 const struct bu_structparse rt_vol_parse[] = {
00083 #if CRAY && !__STDC__
00084 {"%s", RT_VOL_NAME_LEN, "file", 1, BU_STRUCTPARSE_FUNC_NULL },
00085 #else
00086 {"%s", RT_VOL_NAME_LEN, "file", bu_offsetofarray(struct rt_vol_internal, file), BU_STRUCTPARSE_FUNC_NULL },
00087 #endif
00088 {"%d", 1, "w", VOL_O(xdim), BU_STRUCTPARSE_FUNC_NULL },
00089 {"%d", 1, "n", VOL_O(ydim), BU_STRUCTPARSE_FUNC_NULL },
00090 {"%d", 1, "d", VOL_O(zdim), BU_STRUCTPARSE_FUNC_NULL },
00091 {"%d", 1, "lo", VOL_O(lo), BU_STRUCTPARSE_FUNC_NULL },
00092 {"%d", 1, "hi", VOL_O(hi), BU_STRUCTPARSE_FUNC_NULL },
00093 {"%f", ELEMENTS_PER_VECT, "size",bu_offsetofarray(struct rt_vol_internal, cellsize), BU_STRUCTPARSE_FUNC_NULL },
00094 {"%f", 16, "mat", bu_offsetofarray(struct rt_vol_internal,mat), BU_STRUCTPARSE_FUNC_NULL },
00095 {"", 0, (char *)0, 0, BU_STRUCTPARSE_FUNC_NULL }
00096 };
00097
00098 BU_EXTERN(void rt_vol_plate,(point_t a, point_t b, point_t c, point_t d,
00099 mat_t mat, struct bu_list *vhead, struct rt_vol_internal *vip));
00100
00101
00102
00103
00104
00105
00106
00107 #define NORM_ZPOS 3
00108 #define NORM_YPOS 2
00109 #define NORM_XPOS 1
00110 #define NORM_XNEG (-1)
00111 #define NORM_YNEG (-2)
00112 #define NORM_ZNEG (-3)
00113
00114
00115
00116
00117
00118
00119
00120 #define VOL_XWIDEN 2
00121 #define VOL_YWIDEN 2
00122 #define VOL_ZWIDEN 2
00123 #define VOL(_vip,_xx,_yy,_zz) (_vip)->map[ \
00124 (((_zz)+VOL_ZWIDEN) * ((_vip)->ydim + VOL_YWIDEN*2)+ \
00125 ((_yy)+VOL_YWIDEN))* ((_vip)->xdim + VOL_XWIDEN*2)+ \
00126 (_xx)+VOL_XWIDEN ]
00127
00128 #define OK(_vip,_v) ( (int)(_v) >= (_vip)->lo && (int)(_v) <= (_vip)->hi )
00129
00130 static int rt_vol_normtab[3] = { NORM_XPOS, NORM_YPOS, NORM_ZPOS };
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141 int
00142 rt_vol_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead)
00143 {
00144 register struct rt_vol_specific *volp =
00145 (struct rt_vol_specific *)stp->st_specific;
00146 vect_t invdir;
00147 double t0;
00148 double t1;
00149 double tmax;
00150 vect_t t;
00151 vect_t delta;
00152 int igrid[3];
00153 vect_t P;
00154 int inside;
00155 int in_axis;
00156 int out_axis;
00157 int j;
00158 struct xray ideal_ray;
00159
00160
00161 MAT4X3PNT( ideal_ray.r_pt, volp->vol_mat, rp->r_pt );
00162 MAT4X3VEC( ideal_ray.r_dir, volp->vol_mat, rp->r_dir );
00163 rp = &ideal_ray;
00164
00165
00166 if( !NEAR_ZERO( rp->r_dir[X], SQRT_SMALL_FASTF ) ) {
00167 invdir[X]=1.0/rp->r_dir[X];
00168 } else {
00169 invdir[X] = INFINITY;
00170 rp->r_dir[X] = 0.0;
00171 }
00172 if( !NEAR_ZERO( rp->r_dir[Y], SQRT_SMALL_FASTF ) ) {
00173 invdir[Y]=1.0/rp->r_dir[Y];
00174 } else {
00175 invdir[Y] = INFINITY;
00176 rp->r_dir[Y] = 0.0;
00177 }
00178 if( !NEAR_ZERO( rp->r_dir[Z], SQRT_SMALL_FASTF ) ) {
00179 invdir[Z]=1.0/rp->r_dir[Z];
00180 } else {
00181 invdir[Z] = INFINITY;
00182 rp->r_dir[Z] = 0.0;
00183 }
00184
00185
00186 VSETALL( P, 0 );
00187 if( ! rt_in_rpp(rp, invdir, P, volp->vol_large ) )
00188 return 0;
00189 VJOIN1( P, rp->r_pt, rp->r_min, rp->r_dir );
00190 if(RT_G_DEBUG&DEBUG_VOL)VPRINT("vol_large", volp->vol_large);
00191 if(RT_G_DEBUG&DEBUG_VOL)VPRINT("vol_origin", volp->vol_origin);
00192 if(RT_G_DEBUG&DEBUG_VOL)VPRINT("r_pt", rp->r_pt);
00193 if(RT_G_DEBUG&DEBUG_VOL)VPRINT("P", P);
00194 if(RT_G_DEBUG&DEBUG_VOL)VPRINT("cellsize", volp->vol_i.cellsize);
00195 t0 = rp->r_min;
00196 tmax = rp->r_max;
00197 if(RT_G_DEBUG&DEBUG_VOL)bu_log("[shoot: r_min=%g, r_max=%g]\n", rp->r_min, rp->r_max);
00198
00199
00200 igrid[X] = (P[X] - volp->vol_origin[X]) / volp->vol_i.cellsize[X];
00201 igrid[Y] = (P[Y] - volp->vol_origin[Y]) / volp->vol_i.cellsize[Y];
00202 igrid[Z] = (P[Z] - volp->vol_origin[Z]) / volp->vol_i.cellsize[Z];
00203 if( igrid[X] < 0 ) {
00204 igrid[X] = 0;
00205 } else if( igrid[X] >= volp->vol_i.xdim ) {
00206 igrid[X] = volp->vol_i.xdim-1;
00207 }
00208 if( igrid[Y] < 0 ) {
00209 igrid[Y] = 0;
00210 } else if( igrid[Y] >= volp->vol_i.ydim ) {
00211 igrid[Y] = volp->vol_i.ydim-1;
00212 }
00213 if( igrid[Z] < 0 ) {
00214 igrid[Z] = 0;
00215 } else if( igrid[Z] >= volp->vol_i.zdim ) {
00216 igrid[Z] = volp->vol_i.zdim-1;
00217 }
00218 if(RT_G_DEBUG&DEBUG_VOL)bu_log("igrid=(%d, %d, %d)\n", igrid[X], igrid[Y], igrid[Z]);
00219
00220
00221 if( rp->r_dir[X] == 0.0 ) {
00222 t[X] = INFINITY;
00223 delta[X] = 0;
00224 } else {
00225 j = igrid[X];
00226 if( rp->r_dir[X] < 0 ) j++;
00227 t[X] = (volp->vol_origin[X] + j*volp->vol_i.cellsize[X] -
00228 rp->r_pt[X]) * invdir[X];
00229 delta[X] = volp->vol_i.cellsize[X] * fabs(invdir[X]);
00230 }
00231
00232 if( rp->r_dir[Y] == 0.0 ) {
00233 t[Y] = INFINITY;
00234 delta[Y] = 0;
00235 } else {
00236 j = igrid[Y];
00237 if( rp->r_dir[Y] < 0 ) j++;
00238 t[Y] = (volp->vol_origin[Y] + j*volp->vol_i.cellsize[Y] -
00239 rp->r_pt[Y]) * invdir[Y];
00240 delta[Y] = volp->vol_i.cellsize[Y] * fabs(invdir[Y]);
00241 }
00242
00243 if( rp->r_dir[Z] == 0.0 ) {
00244 t[Z] = INFINITY;
00245 delta[Z] = 0;
00246 } else {
00247 j = igrid[Z];
00248 if( rp->r_dir[Z] < 0 ) j++;
00249 t[Z] = (volp->vol_origin[Z] + j*volp->vol_i.cellsize[Z] -
00250 rp->r_pt[Z]) * invdir[Z];
00251 delta[Z] = volp->vol_i.cellsize[Z] * fabs(invdir[Z]);
00252 }
00253
00254
00255 if(RT_G_DEBUG&DEBUG_VOL)bu_log("t[X] = %g, delta[X] = %g\n", t[X], delta[X] );
00256 if(RT_G_DEBUG&DEBUG_VOL)bu_log("t[Y] = %g, delta[Y] = %g\n", t[Y], delta[Y] );
00257 if(RT_G_DEBUG&DEBUG_VOL)bu_log("t[Z] = %g, delta[Z] = %g\n", t[Z], delta[Z] );
00258
00259
00260 if( t[X] >= t[Y] ) {
00261 in_axis = X;
00262 t0 = t[X];
00263 } else {
00264 in_axis = Y;
00265 t0 = t[Y];
00266 }
00267 if( t[Z] > t0 ) {
00268 in_axis = Z;
00269 t0 = t[Z];
00270 }
00271 if(RT_G_DEBUG&DEBUG_VOL)bu_log("Entry axis is %s, t0=%g\n", in_axis==X ? "X" : (in_axis==Y?"Y":"Z"), t0);
00272
00273
00274 t[X] += delta[X];
00275 t[Y] += delta[Y];
00276 t[Z] += delta[Z];
00277
00278
00279 if( t[X] < t0 ) {
00280 bu_log("*** advancing t[X]\n");
00281 t[X] += delta[X];
00282 }
00283 if( t[Y] < t0 ) {
00284 bu_log("*** advancing t[Y]\n");
00285 t[Y] += delta[Y];
00286 }
00287 if( t[Z] < t0 ) {
00288 bu_log("*** advancing t[Z]\n");
00289 t[Z] += delta[Z];
00290 }
00291 if(RT_G_DEBUG&DEBUG_VOL) VPRINT("Exit t[]", t);
00292
00293 inside = 0;
00294
00295 while( t0 < tmax ) {
00296 int val;
00297 struct seg *segp;
00298
00299
00300 if( t[X] < t[Y] ) {
00301 if( t[Z] < t[X] ) {
00302 out_axis = Z;
00303 t1 = t[Z];
00304 } else {
00305 out_axis = X;
00306 t1 = t[X];
00307 }
00308 } else {
00309 if( t[Z] < t[Y] ) {
00310 out_axis = Z;
00311 t1 = t[Z];
00312 } else {
00313 out_axis = Y;
00314 t1 = t[Y];
00315 }
00316 }
00317
00318
00319 val = VOL( &volp->vol_i, igrid[X], igrid[Y], igrid[Z] );
00320 if(RT_G_DEBUG&DEBUG_VOL)bu_log("igrid [%d %d %d] from %g to %g, val=%d\n",
00321 igrid[X], igrid[Y], igrid[Z],
00322 t0, t1, val );
00323 if(RT_G_DEBUG&DEBUG_VOL)bu_log("Exit axis is %s, t[]=(%g, %g, %g)\n",
00324 out_axis==X ? "X" : (out_axis==Y?"Y":"Z"),
00325 t[X], t[Y], t[Z] );
00326
00327 if( t1 <= t0 ) bu_log("ERROR vol t1=%g < t0=%g\n", t1, t0 );
00328 if( !inside ) {
00329 if( OK( &volp->vol_i, val ) ) {
00330
00331
00332 inside = 1;
00333
00334 RT_GET_SEG(segp, ap->a_resource);
00335 segp->seg_stp = stp;
00336 segp->seg_in.hit_dist = t0;
00337
00338
00339 if( rp->r_dir[in_axis] < 0 ) {
00340
00341 segp->seg_in.hit_surfno =
00342 rt_vol_normtab[in_axis];
00343 } else {
00344
00345 segp->seg_in.hit_surfno =
00346 (-rt_vol_normtab[in_axis]);
00347 }
00348 BU_LIST_INSERT( &(seghead->l), &(segp->l) );
00349 if(RT_G_DEBUG&DEBUG_VOL) bu_log("START t=%g, surfno=%d\n",
00350 t0, segp->seg_in.hit_surfno);
00351 } else {
00352
00353 }
00354 } else {
00355 if( OK( &volp->vol_i, val ) ) {
00356
00357 } else {
00358 register struct seg *tail;
00359
00360
00361 inside = 0;
00362
00363 tail = BU_LIST_LAST( seg, &(seghead->l) );
00364 tail->seg_out.hit_dist = t0;
00365
00366
00367 if( rp->r_dir[in_axis] < 0 ) {
00368
00369 tail->seg_out.hit_surfno =
00370 (-rt_vol_normtab[in_axis]);
00371 } else {
00372
00373 tail->seg_out.hit_surfno =
00374 rt_vol_normtab[in_axis];
00375 }
00376 if(RT_G_DEBUG&DEBUG_VOL) bu_log("END t=%g, surfno=%d\n",
00377 t0, tail->seg_out.hit_surfno );
00378 }
00379 }
00380
00381
00382 t0 = t1;
00383 in_axis = out_axis;
00384 t[out_axis] += delta[out_axis];
00385 if( rp->r_dir[out_axis] > 0 ) {
00386 igrid[out_axis]++;
00387 } else {
00388 igrid[out_axis]--;
00389 }
00390 }
00391
00392 if( inside ) {
00393 register struct seg *tail;
00394
00395
00396 tail = BU_LIST_LAST( seg, &(seghead->l) );
00397 tail->seg_out.hit_dist = tmax;
00398
00399
00400 if( rp->r_dir[in_axis] < 0 ) {
00401
00402 tail->seg_out.hit_surfno = (-rt_vol_normtab[in_axis]);
00403 } else {
00404
00405 tail->seg_out.hit_surfno = rt_vol_normtab[in_axis];
00406 }
00407 if(RT_G_DEBUG&DEBUG_VOL) bu_log("closed END t=%g, surfno=%d\n",
00408 tmax, tail->seg_out.hit_surfno );
00409 }
00410
00411 if( BU_LIST_IS_EMPTY( &(seghead->l) ) )
00412 return(0);
00413 return(2);
00414 }
00415
00416
00417
00418
00419
00420
00421
00422
00423 int
00424 rt_vol_import(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip)
00425 {
00426 union record *rp;
00427 register struct rt_vol_internal *vip;
00428 struct bu_vls str;
00429 FILE *fp;
00430 int nbytes;
00431 register int y;
00432 register int z;
00433 mat_t tmat;
00434 int ret;
00435
00436 BU_CK_EXTERNAL( ep );
00437 rp = (union record *)ep->ext_buf;
00438 if( rp->u_id != DBID_STRSOL ) {
00439 bu_log("rt_ebm_import: defective strsol record\n");
00440 return(-1);
00441 }
00442
00443 RT_CK_DB_INTERNAL( ip );
00444 ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
00445 ip->idb_type = ID_VOL;
00446 ip->idb_meth = &rt_functab[ID_VOL];
00447 ip->idb_ptr = bu_calloc(1, sizeof(struct rt_vol_internal), "rt_vol_internal");
00448 vip = (struct rt_vol_internal *)ip->idb_ptr;
00449 vip->magic = RT_VOL_INTERNAL_MAGIC;
00450
00451
00452 MAT_IDN( vip->mat );
00453 vip->lo = 0;
00454 vip->hi = 255;
00455
00456
00457 VSETALL( vip->cellsize, 1 );
00458
00459 bu_vls_init( &str );
00460 bu_vls_strcpy( &str, rp->ss.ss_args );
00461 if( bu_struct_parse( &str, rt_vol_parse, (char *)vip ) < 0 ) {
00462 bu_vls_free( &str );
00463 return -2;
00464 }
00465 bu_vls_free( &str );
00466
00467
00468 if( vip->file[0] == '\0' || vip->xdim < 1 ||
00469 vip->ydim < 1 || vip->zdim < 1 || vip->mat[15] <= 0.0 ||
00470 vip->lo < 0 || vip->hi > 255 ) {
00471 bu_struct_print("Unreasonable VOL parameters", rt_vol_parse,
00472 (char *)vip );
00473 return(-1);
00474 }
00475
00476
00477 bn_mat_mul( tmat, mat, vip->mat );
00478 MAT_COPY( vip->mat, tmat );
00479
00480
00481 nbytes = (vip->xdim+VOL_XWIDEN*2)*
00482 (vip->ydim+VOL_YWIDEN*2)*
00483 (vip->zdim+VOL_ZWIDEN*2);
00484 vip->map = (unsigned char *)bu_calloc( 1, nbytes, "vol_import bitmap" );
00485
00486 bu_semaphore_acquire( BU_SEM_SYSCALL );
00487 if( (fp = fopen(vip->file, "r")) == NULL ) {
00488 perror(vip->file);
00489 bu_semaphore_release( BU_SEM_SYSCALL );
00490 return(-1);
00491 }
00492 bu_semaphore_release( BU_SEM_SYSCALL );
00493
00494
00495 for( z=0; z < vip->zdim; z++ ) {
00496 for( y=0; y < vip->ydim; y++ ) {
00497 bu_semaphore_acquire( BU_SEM_SYSCALL );
00498 ret = fread( &VOL(vip, 0, y, z), vip->xdim, 1, fp );
00499 bu_semaphore_release( BU_SEM_SYSCALL );
00500 if( ret < 1 ) {
00501 bu_log("rt_vol_import(%s): Unable to read whole VOL, y=%d, z=%d\n",
00502 vip->file, y, z);
00503 bu_semaphore_acquire( BU_SEM_SYSCALL );
00504 fclose(fp);
00505 bu_semaphore_release( BU_SEM_SYSCALL );
00506 return -1;
00507 }
00508 }
00509 }
00510 bu_semaphore_acquire( BU_SEM_SYSCALL );
00511 fclose(fp);
00512 bu_semaphore_release( BU_SEM_SYSCALL );
00513 return( 0 );
00514 }
00515
00516
00517
00518
00519
00520
00521 int
00522 rt_vol_export(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
00523 {
00524 struct rt_vol_internal *vip;
00525 struct rt_vol_internal vol;
00526 union record *rec;
00527 struct bu_vls str;
00528
00529 RT_CK_DB_INTERNAL(ip);
00530 if( ip->idb_type != ID_VOL ) return(-1);
00531 vip = (struct rt_vol_internal *)ip->idb_ptr;
00532 RT_VOL_CK_MAGIC(vip);
00533 vol = *vip;
00534
00535
00536 vol.mat[15] /= local2mm;
00537
00538 BU_CK_EXTERNAL(ep);
00539 ep->ext_nbytes = sizeof(union record)*DB_SS_NGRAN;
00540 ep->ext_buf = (genptr_t)bu_calloc( 1, ep->ext_nbytes, "vol external");
00541 rec = (union record *)ep->ext_buf;
00542
00543 bu_vls_init( &str );
00544 bu_vls_struct_print( &str, rt_vol_parse, (char *)&vol );
00545
00546 rec->ss.ss_id = DBID_STRSOL;
00547 strncpy( rec->ss.ss_keyword, "vol", NAMESIZE-1 );
00548 strncpy( rec->ss.ss_args, bu_vls_addr(&str), DB_SS_LEN-1 );
00549 bu_vls_free( &str );
00550
00551 return(0);
00552 }
00553
00554
00555
00556
00557
00558
00559
00560
00561 int
00562 rt_vol_import5(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip)
00563 {
00564 register struct rt_vol_internal *vip;
00565 struct bu_vls str;
00566 FILE *fp;
00567 int nbytes;
00568 register int y;
00569 register int z;
00570 mat_t tmat;
00571 int ret;
00572
00573 BU_CK_EXTERNAL( ep );
00574
00575 RT_CK_DB_INTERNAL( ip );
00576 ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
00577 ip->idb_type = ID_VOL;
00578 ip->idb_meth = &rt_functab[ID_VOL];
00579 ip->idb_ptr = bu_calloc(1, sizeof(struct rt_vol_internal), "rt_vol_internal");
00580 vip = (struct rt_vol_internal *)ip->idb_ptr;
00581 vip->magic = RT_VOL_INTERNAL_MAGIC;
00582
00583
00584 MAT_IDN( vip->mat );
00585 vip->lo = 0;
00586 vip->hi = 255;
00587
00588
00589 VSETALL( vip->cellsize, 1 );
00590
00591 bu_vls_init( &str );
00592 bu_vls_strncpy( &str, ep->ext_buf, ep->ext_nbytes );
00593 if( bu_struct_parse( &str, rt_vol_parse, (char *)vip ) < 0 ) {
00594 bu_vls_free( &str );
00595 return -2;
00596 }
00597 bu_vls_free( &str );
00598
00599
00600 if( vip->file[0] == '\0' || vip->xdim < 1 ||
00601 vip->ydim < 1 || vip->zdim < 1 || vip->mat[15] <= 0.0 ||
00602 vip->lo < 0 || vip->hi > 255 ) {
00603 bu_struct_print("Unreasonable VOL parameters", rt_vol_parse,
00604 (char *)vip );
00605 return(-1);
00606 }
00607
00608
00609 bn_mat_mul( tmat, mat, vip->mat );
00610 MAT_COPY( vip->mat, tmat );
00611
00612
00613 nbytes = (vip->xdim+VOL_XWIDEN*2)*
00614 (vip->ydim+VOL_YWIDEN*2)*
00615 (vip->zdim+VOL_ZWIDEN*2);
00616 vip->map = (unsigned char *)bu_calloc( 1, nbytes, "vol_import bitmap" );
00617
00618 bu_semaphore_acquire( BU_SEM_SYSCALL );
00619 if( (fp = fopen(vip->file, "r")) == NULL ) {
00620 perror(vip->file);
00621 bu_semaphore_release( BU_SEM_SYSCALL );
00622 return(-1);
00623 }
00624 bu_semaphore_release( BU_SEM_SYSCALL );
00625
00626
00627 for( z=0; z < vip->zdim; z++ ) {
00628 for( y=0; y < vip->ydim; y++ ) {
00629 bu_semaphore_acquire( BU_SEM_SYSCALL );
00630 ret = fread( &VOL(vip, 0, y, z), vip->xdim, 1, fp );
00631 bu_semaphore_release( BU_SEM_SYSCALL );
00632 if( ret < 1 ) {
00633 bu_log("rt_vol_import(%s): Unable to read whole VOL, y=%d, z=%d\n",
00634 vip->file, y, z);
00635 bu_semaphore_acquire( BU_SEM_SYSCALL );
00636 fclose(fp);
00637 bu_semaphore_release( BU_SEM_SYSCALL );
00638 return -1;
00639 }
00640 }
00641 }
00642 bu_semaphore_acquire( BU_SEM_SYSCALL );
00643 fclose(fp);
00644 bu_semaphore_release( BU_SEM_SYSCALL );
00645 return( 0 );
00646 }
00647
00648
00649
00650
00651
00652
00653 int
00654 rt_vol_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
00655 {
00656 struct rt_vol_internal *vip;
00657 struct rt_vol_internal vol;
00658 struct bu_vls str;
00659
00660 RT_CK_DB_INTERNAL(ip);
00661 if( ip->idb_type != ID_VOL ) return(-1);
00662 vip = (struct rt_vol_internal *)ip->idb_ptr;
00663 RT_VOL_CK_MAGIC(vip);
00664 vol = *vip;
00665
00666
00667 vol.mat[15] /= local2mm;
00668
00669 BU_CK_EXTERNAL(ep);
00670
00671 bu_vls_init( &str );
00672 bu_vls_struct_print( &str, rt_vol_parse, (char *)&vol );
00673 ep->ext_nbytes = bu_vls_strlen( &str );
00674 ep->ext_buf = (genptr_t)bu_calloc( 1, ep->ext_nbytes, "vol external");
00675
00676 strcpy( ep->ext_buf, bu_vls_addr(&str) );
00677 bu_vls_free( &str );
00678
00679 return(0);
00680 }
00681
00682
00683
00684
00685
00686
00687
00688
00689 int
00690 rt_vol_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local)
00691 {
00692 register struct rt_vol_internal *vip =
00693 (struct rt_vol_internal *)ip->idb_ptr;
00694 register int i;
00695 struct bu_vls substr;
00696 vect_t local;
00697
00698 RT_VOL_CK_MAGIC(vip);
00699
00700 VSCALE( local, vip->cellsize, mm2local )
00701 bu_vls_strcat( str, "thresholded volumetric solid (VOL)\n\t");
00702
00703
00704
00705
00706 bu_vls_init( &substr );
00707 bu_vls_printf( &substr, " file=\"%s\" w=%d n=%d d=%d lo=%d hi=%d size=%g %g %g\n mat=",
00708 vip->file, vip->xdim, vip->ydim, vip->zdim, vip->lo, vip->hi,
00709 V3INTCLAMPARGS( local ) );
00710 bu_vls_vlscat( str, &substr );
00711 for( i=0 ; i<15 ; i++ )
00712 {
00713 bu_vls_trunc2( &substr, 0 );
00714 bu_vls_printf( &substr, "%g,", INTCLAMP(vip->mat[i]) );
00715 bu_vls_vlscat( str, &substr );
00716 }
00717 bu_vls_trunc2( &substr, 0 );
00718 bu_vls_printf( &substr, "%g\n", INTCLAMP(vip->mat[i]) );
00719 bu_vls_vlscat( str, &substr );
00720
00721 bu_vls_free( &substr );
00722
00723 return(0);
00724 }
00725
00726
00727
00728
00729
00730
00731 void
00732 rt_vol_ifree(struct rt_db_internal *ip)
00733 {
00734 register struct rt_vol_internal *vip;
00735
00736 RT_CK_DB_INTERNAL(ip);
00737 vip = (struct rt_vol_internal *)ip->idb_ptr;
00738 RT_VOL_CK_MAGIC(vip);
00739
00740 if( vip->map) bu_free( (char *)vip->map, "vol bitmap" );
00741
00742 vip->magic = 0;
00743 vip->map = (unsigned char *)0;
00744 bu_free( (char *)vip, "vol ifree" );
00745 ip->idb_ptr = GENPTR_NULL;
00746 }
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759 int
00760 rt_vol_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
00761 {
00762 struct rt_vol_internal *vip;
00763 register struct rt_vol_specific *volp;
00764 vect_t norm;
00765 vect_t radvec;
00766 vect_t diam;
00767 vect_t small1;
00768
00769
00770 vip = (struct rt_vol_internal *)ip->idb_ptr;
00771 RT_VOL_CK_MAGIC(vip);
00772
00773 BU_GETSTRUCT( volp, rt_vol_specific );
00774 volp->vol_i = *vip;
00775 vip->map = (unsigned char *)0;
00776
00777
00778 bn_mat_inv( volp->vol_mat, vip->mat );
00779
00780
00781 VSET( norm, 1, 0 , 0 );
00782 MAT3X3VEC( volp->vol_xnorm, vip->mat, norm );
00783 VSET( norm, 0, 1, 0 );
00784 MAT3X3VEC( volp->vol_ynorm, vip->mat, norm );
00785 VSET( norm, 0, 0, 1 );
00786 MAT3X3VEC( volp->vol_znorm, vip->mat, norm );
00787
00788 stp->st_specific = (genptr_t)volp;
00789
00790
00791 VSETALL( small1, 0 );
00792 VSET( volp->vol_large,
00793 volp->vol_i.xdim*vip->cellsize[0], volp->vol_i.ydim*vip->cellsize[1], volp->vol_i.zdim*vip->cellsize[2] );
00794 bn_rotate_bbox( stp->st_min, stp->st_max, vip->mat,
00795 small1, volp->vol_large );
00796
00797
00798 VSETALL( volp->vol_origin, 0 );
00799 VADD2( volp->vol_large, volp->vol_large, volp->vol_origin );
00800
00801 VSUB2( diam, stp->st_max, stp->st_min );
00802 VADD2SCALE( stp->st_center, stp->st_min, stp->st_max, 0.5 );
00803 VSCALE( radvec, diam, 0.5 );
00804 stp->st_aradius = stp->st_bradius = MAGNITUDE( radvec );
00805
00806 return(0);
00807 }
00808
00809
00810
00811
00812 void
00813 rt_vol_print(register const struct soltab *stp)
00814 {
00815 register const struct rt_vol_specific *volp =
00816 (struct rt_vol_specific *)stp->st_specific;
00817
00818 bu_log("vol file = %s\n", volp->vol_i.file );
00819 bu_log("dimensions = (%d, %d, %d)\n",
00820 volp->vol_i.xdim, volp->vol_i.ydim,
00821 volp->vol_i.zdim );
00822 VPRINT("model cellsize", volp->vol_i.cellsize);
00823 VPRINT("model grid origin", volp->vol_origin);
00824 }
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834 void
00835 rt_vol_norm(register struct hit *hitp, struct soltab *stp, register struct xray *rp)
00836 {
00837 register struct rt_vol_specific *volp =
00838 (struct rt_vol_specific *)stp->st_specific;
00839
00840 VJOIN1( hitp->hit_point, rp->r_pt, hitp->hit_dist, rp->r_dir );
00841
00842 switch( hitp->hit_surfno ) {
00843 case NORM_XPOS:
00844 VMOVE( hitp->hit_normal, volp->vol_xnorm );
00845 break;
00846 case NORM_XNEG:
00847 VREVERSE( hitp->hit_normal, volp->vol_xnorm );
00848 break;
00849
00850 case NORM_YPOS:
00851 VMOVE( hitp->hit_normal, volp->vol_ynorm );
00852 break;
00853 case NORM_YNEG:
00854 VREVERSE( hitp->hit_normal, volp->vol_ynorm );
00855 break;
00856
00857 case NORM_ZPOS:
00858 VMOVE( hitp->hit_normal, volp->vol_znorm );
00859 break;
00860 case NORM_ZNEG:
00861 VREVERSE( hitp->hit_normal, volp->vol_znorm );
00862 break;
00863
00864 default:
00865 bu_log("rt_vol_norm(%s): surfno=%d bad\n",
00866 stp->st_name, hitp->hit_surfno );
00867 VSETALL( hitp->hit_normal, 0 );
00868 break;
00869 }
00870 }
00871
00872
00873
00874
00875
00876
00877 void
00878 rt_vol_curve(register struct curvature *cvp, register struct hit *hitp, struct soltab *stp)
00879 {
00880
00881
00882
00883 bn_vec_ortho( cvp->crv_pdir, hitp->hit_normal );
00884 cvp->crv_c1 = cvp->crv_c2 = 0;
00885 }
00886
00887
00888
00889
00890
00891
00892
00893 void
00894 rt_vol_uv(struct application *ap, struct soltab *stp, register struct hit *hitp, register struct uvcoord *uvp)
00895 {
00896
00897
00898
00899
00900 }
00901
00902
00903
00904
00905 void
00906 rt_vol_free(struct soltab *stp)
00907 {
00908 register struct rt_vol_specific *volp =
00909 (struct rt_vol_specific *)stp->st_specific;
00910
00911 bu_free( (char *)volp->vol_i.map, "vol_map" );
00912 bu_free( (char *)volp, "rt_vol_specific" );
00913 }
00914
00915 int
00916 rt_vol_class(void)
00917 {
00918 return(0);
00919 }
00920
00921
00922
00923
00924 int
00925 rt_vol_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
00926 {
00927 register struct rt_vol_internal *vip;
00928 register short x,y,z;
00929 register short v1,v2;
00930 point_t a,b,c,d;
00931
00932 RT_CK_DB_INTERNAL(ip);
00933 vip = (struct rt_vol_internal *)ip->idb_ptr;
00934 RT_VOL_CK_MAGIC(vip);
00935
00936
00937
00938
00939
00940 for( z=-1; z<=vip->zdim; z++ ) {
00941 for( x=-1; x<=vip->xdim; x++ ) {
00942 for( y=-1; y<=vip->ydim; y++ ) {
00943 v1 = VOL(vip, x,y,z);
00944 v2 = VOL(vip, x+1,y,z);
00945 if( OK(vip, v1) == OK(vip, v2) ) continue;
00946
00947 VSET( a, x+0.5, y-0.5, z-0.5 );
00948 VSET( b, x+0.5, y-0.5, z+0.5 );
00949 for( ++y; y<=vip->ydim; y++ ) {
00950 v1 = VOL(vip, x,y,z);
00951 v2 = VOL(vip, x+1,y,z);
00952 if( OK(vip, v1) == OK(vip, v2) )
00953 break;
00954 }
00955
00956 VSET( c, x+0.5, y-0.5, z+0.5 );
00957 VSET( d, x+0.5, y-0.5, z-0.5 );
00958 rt_vol_plate( a,b,c,d, vip->mat, vhead, vip );
00959 }
00960 }
00961 }
00962
00963
00964
00965
00966 for( z=-1; z<=vip->zdim; z++ ) {
00967 for( y=-1; y<=vip->ydim; y++ ) {
00968 for( x=-1; x<=vip->xdim; x++ ) {
00969 v1 = VOL(vip, x,y,z);
00970 v2 = VOL(vip, x,y+1,z);
00971 if( OK(vip, v1) == OK(vip, v2) ) continue;
00972
00973 VSET( a, x-0.5, y+0.5, z-0.5 );
00974 VSET( b, x-0.5, y+0.5, z+0.5 );
00975 for( ++x; x<=vip->xdim; x++ ) {
00976 v1 = VOL(vip, x,y,z);
00977 v2 = VOL(vip, x,y+1,z);
00978 if( OK(vip, v1) == OK(vip, v2) )
00979 break;
00980 }
00981
00982 VSET( c, (x-0.5), (y+0.5), (z+0.5) );
00983 VSET( d, (x-0.5), (y+0.5), (z-0.5) );
00984 rt_vol_plate( a,b,c,d, vip->mat, vhead, vip );
00985 }
00986 }
00987 }
00988
00989
00990
00991
00992 for( x=-1; x<=vip->xdim; x++ ) {
00993 for( z=-1; z<=vip->zdim; z++ ) {
00994 for( y=-1; y<=vip->ydim; y++ ) {
00995 v1 = VOL(vip, x,y,z);
00996 v2 = VOL(vip, x,y,z+1);
00997 if( OK(vip, v1) == OK(vip, v2) ) continue;
00998
00999 VSET( a, (x-0.5), (y-0.5), (z+0.5) );
01000 VSET( b, (x+0.5), (y-0.5), (z+0.5) );
01001 for( ++y; y<=vip->ydim; y++ ) {
01002 v1 = VOL(vip, x,y,z);
01003 v2 = VOL(vip, x,y,z+1);
01004 if( OK(vip, v1) == OK(vip, v2) )
01005 break;
01006 }
01007
01008 VSET( c, (x+0.5), (y-0.5), (z+0.5) );
01009 VSET( d, (x-0.5), (y-0.5), (z+0.5) );
01010 rt_vol_plate( a,b,c,d, vip->mat, vhead, vip );
01011 }
01012 }
01013 }
01014 return(0);
01015 }
01016
01017
01018
01019
01020 void
01021 rt_vol_plate(fastf_t *a, fastf_t *b, fastf_t *c, fastf_t *d, register fastf_t *mat, register struct bu_list *vhead, register struct rt_vol_internal *vip)
01022 {
01023 LOCAL point_t s;
01024 LOCAL point_t arot, prot;
01025
01026 VELMUL( s, vip->cellsize, a );
01027 MAT4X3PNT( arot, mat, s );
01028 RT_ADD_VLIST( vhead, arot, BN_VLIST_LINE_MOVE );
01029
01030 VELMUL( s, vip->cellsize, b );
01031 MAT4X3PNT( prot, mat, s );
01032 RT_ADD_VLIST( vhead, prot, BN_VLIST_LINE_DRAW );
01033
01034 VELMUL( s, vip->cellsize, c );
01035 MAT4X3PNT( prot, mat, s );
01036 RT_ADD_VLIST( vhead, prot, BN_VLIST_LINE_DRAW );
01037
01038 VELMUL( s, vip->cellsize, d );
01039 MAT4X3PNT( prot, mat, s );
01040 RT_ADD_VLIST( vhead, prot, BN_VLIST_LINE_DRAW );
01041
01042 RT_ADD_VLIST( vhead, arot, BN_VLIST_LINE_DRAW );
01043 }
01044
01045
01046
01047
01048 int
01049 rt_vol_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
01050 {
01051 struct rt_vol_internal *vip;
01052 register int x,y,z;
01053 int i;
01054 struct shell *s;
01055 struct vertex *verts[4];
01056 struct faceuse *fu;
01057 struct model *m_tmp;
01058 struct nmgregion *r_tmp;
01059
01060 NMG_CK_MODEL( m );
01061 BN_CK_TOL( tol );
01062 RT_CK_TESS_TOL( ttol );
01063
01064 RT_CK_DB_INTERNAL(ip);
01065 vip = (struct rt_vol_internal *)ip->idb_ptr;
01066 RT_VOL_CK_MAGIC(vip);
01067
01068
01069 m_tmp = nmg_mm();
01070 r_tmp = nmg_mrsv( m_tmp );
01071 s = BU_LIST_FIRST(shell, &r_tmp->s_hd);
01072
01073 for( x=0 ; x<vip->xdim ; x++ )
01074 {
01075 for( y=0 ; y<vip->ydim ; y++ )
01076 {
01077 for( z=0 ; z<vip->zdim ; z++ )
01078 {
01079 point_t pt,pt1;
01080
01081
01082 if( !OK( vip , VOL( vip , x , y , z ) ) )
01083 continue;
01084
01085
01086
01087
01088 if( !OK( vip , VOL( vip , x , y , z+1 ) ) )
01089 {
01090 for( i=0 ; i<4 ; i++ )
01091 verts[i] = (struct vertex *)NULL;
01092
01093 fu = nmg_cface( s , verts , 4 );
01094
01095 VSET( pt , x+.5 , y-.5 , z+.5 );
01096 VELMUL( pt1 , vip->cellsize , pt );
01097 MAT4X3PNT( pt , vip->mat , pt1 );
01098 nmg_vertex_gv( verts[0] , pt );
01099 VSET( pt , x+.5 , y+.5 , z+.5 );
01100 VELMUL( pt1 , vip->cellsize , pt );
01101 MAT4X3PNT( pt , vip->mat , pt1 );
01102 nmg_vertex_gv( verts[1] , pt );
01103 VSET( pt , x-.5 , y+.5 , z+.5 );
01104 VELMUL( pt1 , vip->cellsize , pt );
01105 MAT4X3PNT( pt , vip->mat , pt1 );
01106 nmg_vertex_gv( verts[2] , pt );
01107 VSET( pt , x-.5 , y-.5 , z+.5 );
01108 VELMUL( pt1 , vip->cellsize , pt );
01109 MAT4X3PNT( pt , vip->mat , pt1 );
01110 nmg_vertex_gv( verts[3] , pt );
01111
01112 if( nmg_fu_planeeqn( fu , tol ) )
01113 goto fail;
01114 }
01115
01116
01117 if( !OK( vip , VOL( vip , x , y , z-1 ) ) )
01118 {
01119 for( i=0 ; i<4 ; i++ )
01120 verts[i] = (struct vertex *)NULL;
01121
01122 fu = nmg_cface( s , verts , 4 );
01123
01124 VSET( pt , x+.5 , y-.5 , z-.5 );
01125 VELMUL( pt1 , vip->cellsize , pt );
01126 MAT4X3PNT( pt , vip->mat , pt1 );
01127 nmg_vertex_gv( verts[3] , pt );
01128 VSET( pt , x+.5 , y+.5 , z-.5 );
01129 VELMUL( pt1 , vip->cellsize , pt );
01130 MAT4X3PNT( pt , vip->mat , pt1 );
01131 nmg_vertex_gv( verts[2] , pt );
01132 VSET( pt , x-.5 , y+.5 , z-.5 );
01133 VELMUL( pt1 , vip->cellsize , pt );
01134 MAT4X3PNT( pt , vip->mat , pt1 );
01135 nmg_vertex_gv( verts[1] , pt );
01136 VSET( pt , x-.5 , y-.5 , z-.5 );
01137 VELMUL( pt1 , vip->cellsize , pt );
01138 MAT4X3PNT( pt , vip->mat , pt1 );
01139 nmg_vertex_gv( verts[0] , pt );
01140
01141 if( nmg_fu_planeeqn( fu , tol ) )
01142 goto fail;
01143 }
01144
01145
01146 if( !OK( vip , VOL( vip , x , y+1 , z ) ) )
01147 {
01148 for( i=0 ; i<4 ; i++ )
01149 verts[i] = (struct vertex *)NULL;
01150
01151 fu = nmg_cface( s , verts , 4 );
01152
01153 VSET( pt , x+.5 , y+.5 , z+.5 );
01154 VELMUL( pt1 , vip->cellsize , pt );
01155 MAT4X3PNT( pt , vip->mat , pt1 );
01156 nmg_vertex_gv( verts[0] , pt );
01157 VSET( pt , x+.5 , y+.5 , z-.5 );
01158 VELMUL( pt1 , vip->cellsize , pt );
01159 MAT4X3PNT( pt , vip->mat , pt1 );
01160 nmg_vertex_gv( verts[1] , pt );
01161 VSET( pt , x-.5 , y+.5 , z-.5 );
01162 VELMUL( pt1 , vip->cellsize , pt );
01163 MAT4X3PNT( pt , vip->mat , pt1 );
01164 nmg_vertex_gv( verts[2] , pt );
01165 VSET( pt , x-.5 , y+.5 , z+.5 );
01166 VELMUL( pt1 , vip->cellsize , pt );
01167 MAT4X3PNT( pt , vip->mat , pt1 );
01168 nmg_vertex_gv( verts[3] , pt );
01169
01170 if( nmg_fu_planeeqn( fu , tol ) )
01171 goto fail;
01172 }
01173
01174
01175 if( !OK( vip , VOL( vip , x , y-1 , z ) ) )
01176 {
01177 for( i=0 ; i<4 ; i++ )
01178 verts[i] = (struct vertex *)NULL;
01179
01180 fu = nmg_cface( s , verts , 4 );
01181
01182 VSET( pt , x+.5 , y-.5 , z+.5 );
01183 VELMUL( pt1 , vip->cellsize , pt );
01184 MAT4X3PNT( pt , vip->mat , pt1 );
01185 nmg_vertex_gv( verts[3] , pt );
01186 VSET( pt , x+.5 , y-.5 , z-.5 );
01187 VELMUL( pt1 , vip->cellsize , pt );
01188 MAT4X3PNT( pt , vip->mat , pt1 );
01189 nmg_vertex_gv( verts[2] , pt );
01190 VSET( pt , x-.5 , y-.5 , z-.5 );
01191 VELMUL( pt1 , vip->cellsize , pt );
01192 MAT4X3PNT( pt , vip->mat , pt1 );
01193 nmg_vertex_gv( verts[1] , pt );
01194 VSET( pt , x-.5 , y-.5 , z+.5 );
01195 VELMUL( pt1 , vip->cellsize , pt );
01196 MAT4X3PNT( pt , vip->mat , pt1 );
01197 nmg_vertex_gv( verts[0] , pt );
01198
01199 if( nmg_fu_planeeqn( fu , tol ) )
01200 goto fail;
01201 }
01202
01203
01204 if( !OK( vip , VOL( vip , x+1 , y , z ) ) )
01205 {
01206 for( i=0 ; i<4 ; i++ )
01207 verts[i] = (struct vertex *)NULL;
01208
01209 fu = nmg_cface( s , verts , 4 );
01210
01211 VSET( pt , x+.5 , y-.5 , z-.5 );
01212 VELMUL( pt1 , vip->cellsize , pt );
01213 MAT4X3PNT( pt , vip->mat , pt1 );
01214 nmg_vertex_gv( verts[0] , pt );
01215 VSET( pt , x+.5 , y+.5 , z-.5 );
01216 VELMUL( pt1 , vip->cellsize , pt );
01217 MAT4X3PNT( pt , vip->mat , pt1 );
01218 nmg_vertex_gv( verts[1] , pt );
01219 VSET( pt , x+.5 , y+.5 , z+.5 );
01220 VELMUL( pt1 , vip->cellsize , pt );
01221 MAT4X3PNT( pt , vip->mat , pt1 );
01222 nmg_vertex_gv( verts[2] , pt );
01223 VSET( pt , x+.5 , y-.5 , z+.5 );
01224 VELMUL( pt1 , vip->cellsize , pt );
01225 MAT4X3PNT( pt , vip->mat , pt1 );
01226 nmg_vertex_gv( verts[3] , pt );
01227
01228 if( nmg_fu_planeeqn( fu , tol ) )
01229 goto fail;
01230 }
01231
01232
01233 if( !OK( vip , VOL( vip , x-1 , y , z ) ) )
01234 {
01235 for( i=0 ; i<4 ; i++ )
01236 verts[i] = (struct vertex *)NULL;
01237
01238 fu = nmg_cface( s , verts , 4 );
01239
01240 VSET( pt , x-.5 , y-.5 , z-.5 );
01241 VELMUL( pt1 , vip->cellsize , pt );
01242 MAT4X3PNT( pt , vip->mat , pt1 );
01243 nmg_vertex_gv( verts[3] , pt );
01244 VSET( pt , x-.5 , y+.5 , z-.5 );
01245 VELMUL( pt1 , vip->cellsize , pt );
01246 MAT4X3PNT( pt , vip->mat , pt1 );
01247 nmg_vertex_gv( verts[2] , pt );
01248 VSET( pt , x-.5 , y+.5 , z+.5 );
01249 VELMUL( pt1 , vip->cellsize , pt );
01250 MAT4X3PNT( pt , vip->mat , pt1 );
01251 nmg_vertex_gv( verts[1] , pt );
01252 VSET( pt , x-.5 , y-.5 , z+.5 );
01253 VELMUL( pt1 , vip->cellsize , pt );
01254 MAT4X3PNT( pt , vip->mat , pt1 );
01255 nmg_vertex_gv( verts[0] , pt );
01256
01257 if( nmg_fu_planeeqn( fu , tol ) )
01258 goto fail;
01259 }
01260 }
01261 }
01262 }
01263
01264 nmg_region_a( r_tmp , tol );
01265
01266
01267 nmg_model_fuse( m_tmp , tol );
01268
01269
01270 nmg_shell_coplanar_face_merge( s, tol, 1 );
01271
01272
01273 for( BU_LIST_FOR( fu , faceuse , &s->fu_hd ) )
01274 {
01275 struct loopuse *lu;
01276
01277 NMG_CK_FACEUSE( fu );
01278
01279 if( fu->orientation != OT_SAME )
01280 continue;
01281
01282 for( BU_LIST_FOR( lu , loopuse , &fu->lu_hd ) )
01283 (void)nmg_kill_snakes( lu );
01284 }
01285
01286 (void)nmg_unbreak_region_edges( (long *)(&s->l) );
01287
01288 (void)nmg_mark_edges_real( (long *)&s->l );
01289
01290 nmg_merge_models( m , m_tmp );
01291 *r = r_tmp;
01292
01293 return( 0 );
01294
01295 fail:
01296 nmg_km( m_tmp );
01297 *r = (struct nmgregion *)NULL;
01298
01299 return( -1 );
01300 }
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310