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 #ifndef lint
00039 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/nmg_extrude.c,v 14.12 2006/09/16 02:04:25 lbutler Exp $ (ARL)";
00040 #endif
00041
00042 #include "common.h"
00043
00044
00045 #include <stdio.h>
00046 #include <math.h>
00047 #include <string.h>
00048 #include "machine.h"
00049 #include "vmath.h"
00050 #include "db.h"
00051 #include "nmg.h"
00052 #include "raytrace.h"
00053 #include "rtgeom.h"
00054 #include "./debug.h"
00055
00056
00057
00058
00059
00060
00061
00062 static int
00063 verts_in_nmg_loop(struct loopuse *lu)
00064 {
00065 int cnt;
00066 struct edgeuse *eu;
00067 struct vertex *v;
00068
00069
00070 cnt = 0;
00071 NMG_CK_LOOPUSE(lu);
00072 if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_EDGEUSE_MAGIC) {
00073 for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
00074 NMG_CK_EDGEUSE(eu);
00075 NMG_CK_EDGE(eu->e_p);
00076 NMG_CK_VERTEXUSE(eu->vu_p);
00077 NMG_CK_VERTEX(eu->vu_p->v_p);
00078 cnt++;
00079 }
00080 } else if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_VERTEXUSE_MAGIC) {
00081 v = BU_LIST_PNEXT(vertexuse, &lu->down_hd)->v_p;
00082 NMG_CK_VERTEX(v);
00083 cnt++;
00084 } else
00085 rt_bomb("verts_in_nmg_loop: bad loopuse\n");
00086 return(cnt);
00087 }
00088
00089
00090
00091
00092
00093
00094 static int
00095 verts_in_nmg_face(struct faceuse *fu)
00096 {
00097 int cnt;
00098 struct loopuse *lu;
00099
00100 cnt = 0;
00101 for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd))
00102 cnt += verts_in_nmg_loop(lu);
00103 return(cnt);
00104 }
00105
00106
00107
00108
00109
00110
00111 void
00112 nmg_translate_face(struct faceuse *fu, const fastf_t *Vec, const struct bn_tol *tol)
00113 {
00114 int cnt,
00115 cur,
00116 i,
00117 in_there;
00118 struct vertex **verts;
00119 struct edgeuse *eu;
00120 struct loopuse *lu;
00121 struct vertex *v;
00122 struct faceuse *fu_tmp;
00123 plane_t pl;
00124 struct bu_ptbl edge_g_tbl;
00125
00126 bu_ptbl_init( &edge_g_tbl , 64, " &edge_g_tbl ");
00127
00128 cur = 0;
00129 cnt = verts_in_nmg_face(fu);
00130 verts = (struct vertex **)
00131 bu_malloc(cnt * sizeof(struct vertex *), "verts");
00132 for (i = 0; i < cnt; i++)
00133 verts[i] = NULL;
00134
00135
00136 for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) {
00137 NMG_CK_LOOPUSE(lu);
00138 if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_EDGEUSE_MAGIC) {
00139 for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
00140 in_there = 0;
00141 for (i = 0; i < cur && !in_there; i++)
00142 if (verts[i] == eu->vu_p->v_p)
00143 in_there = 1;
00144 if (!in_there) {
00145 verts[cur++] = eu->vu_p->v_p;
00146 VADD2(eu->vu_p->v_p->vg_p->coord,
00147 eu->vu_p->v_p->vg_p->coord,
00148 Vec);
00149 }
00150 }
00151 } else if (BU_LIST_FIRST_MAGIC(&lu->down_hd)
00152 == NMG_VERTEXUSE_MAGIC) {
00153 v = BU_LIST_FIRST(vertexuse, &lu->down_hd)->v_p;
00154 NMG_CK_VERTEX(v);
00155 VADD2(v->vg_p->coord, v->vg_p->coord, Vec);
00156 } else
00157 rt_bomb("nmg_translate_face: bad loopuse\n");
00158 }
00159
00160 fu_tmp = fu;
00161 if( fu_tmp->orientation != OT_SAME )
00162 fu_tmp = fu_tmp->fumate_p;
00163
00164
00165 nmg_edge_g_tabulate( &edge_g_tbl , &fu->l.magic );
00166 for( i=0 ; i<BU_PTBL_END( &edge_g_tbl ) ; i++ )
00167 {
00168 long *ep;
00169 struct edge_g_lseg *eg;
00170
00171 ep = BU_PTBL_GET( &edge_g_tbl , i );
00172 switch( *ep )
00173 {
00174 case NMG_EDGE_G_LSEG_MAGIC:
00175 eg = (struct edge_g_lseg *)ep;
00176 NMG_CK_EDGE_G_LSEG( eg );
00177 VADD2( eg->e_pt , eg->e_pt , Vec );
00178 break;
00179 case NMG_EDGE_G_CNURB_MAGIC:
00180
00181 break;
00182 }
00183 }
00184
00185 bu_ptbl_free( &edge_g_tbl );
00186
00187 if(nmg_loop_plane_area( BU_LIST_FIRST( loopuse , &fu_tmp->lu_hd ) , pl ) < 0.0 )
00188 {
00189 rt_bomb( "nmg_translate_face: Cannot calculate plane equation for face\n" );
00190 }
00191 nmg_face_g( fu_tmp , pl );
00192 bu_free((char *)verts, "verts");
00193 }
00194
00195
00196
00197
00198
00199
00200
00201 int
00202 nmg_extrude_face(struct faceuse *fu, const fastf_t *Vec, const struct bn_tol *tol)
00203
00204
00205
00206 {
00207 fastf_t cosang;
00208 int nfaces;
00209 struct faceuse *fu2, *nmg_dup_face(struct faceuse *fu, struct shell *s), **outfaces;
00210 int face_count=2;
00211 struct loopuse *lu, *lu2;
00212 plane_t n;
00213
00214 #define MIKE_TOL 0.0001
00215
00216 NMG_CK_FACEUSE( fu );
00217 BN_CK_TOL( tol );
00218
00219
00220 fu2 = nmg_dup_face(fu, fu->s_p);
00221 nmg_reverse_face( fu2 );
00222 if( fu2->orientation != OT_OPPOSITE )
00223 fu2 = fu2->fumate_p;
00224
00225
00226 NMG_GET_FU_PLANE( n, fu );
00227 cosang = VDOT(Vec, n);
00228 if (NEAR_ZERO(cosang, MIKE_TOL))
00229 rt_bomb("extrude_nmg_face: extrusion cannot be parallel to face\n");
00230 if (cosang > 0.)
00231 nmg_translate_face(fu, Vec, tol);
00232 else if (cosang < 0.)
00233 nmg_translate_face(fu2->fumate_p, Vec, tol);
00234
00235 nfaces = verts_in_nmg_face( fu );
00236 outfaces = (struct faceuse **)bu_calloc( nfaces+2 , sizeof( struct faceuse *) ,
00237 "nmg_extrude_face: outfaces" );
00238
00239 outfaces[0] = fu;
00240 outfaces[1] = fu2->fumate_p;
00241
00242 for( BU_LIST_FOR2(lu , lu2 , loopuse , &fu->lu_hd , &fu2->lu_hd ) )
00243 {
00244 struct edgeuse *eu,*eu2;
00245
00246 NMG_CK_LOOPUSE( lu );
00247 NMG_CK_LOOPUSE( lu2 );
00248
00249 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
00250 continue;
00251 if( BU_LIST_FIRST_MAGIC( &lu2->down_hd ) != NMG_EDGEUSE_MAGIC )
00252 {
00253 bu_log( "nmg_extrude_face: Original face and dup face don't match up!!\n" );
00254 return( -1 );
00255 }
00256 for( BU_LIST_FOR2( eu , eu2 , edgeuse , &lu->down_hd , &lu2->down_hd ) )
00257 {
00258 struct vertex *vertlist[4];
00259
00260 NMG_CK_EDGEUSE( eu );
00261 NMG_CK_EDGEUSE( eu2 );
00262
00263 vertlist[0] = eu->vu_p->v_p;
00264 vertlist[1] = eu2->vu_p->v_p;
00265 vertlist[2] = eu2->eumate_p->vu_p->v_p;
00266 vertlist[3] = eu->eumate_p->vu_p->v_p;
00267 outfaces[face_count] = nmg_cface( fu->s_p , vertlist , 4 );
00268 if( nmg_calc_face_g( outfaces[face_count] ) )
00269 {
00270 bu_log( "nmg_extrude_face: failed to calculate plane eqn\n" );
00271 return( -1 );
00272 }
00273 face_count++;
00274 }
00275
00276 }
00277
00278 nmg_gluefaces( outfaces , face_count, tol );
00279
00280 bu_free( (char *)outfaces , "nmg_extrude_face: outfaces" );
00281
00282 return( 0 );
00283 }
00284
00285
00286
00287
00288
00289
00290 struct vertexuse *
00291 nmg_find_vertex_in_lu(const struct vertex *v, const struct loopuse *lu)
00292 {
00293 struct edgeuse *eu;
00294 struct vertexuse *ret_vu;
00295
00296 NMG_CK_VERTEX( v );
00297 NMG_CK_LOOPUSE( lu );
00298
00299 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) == NMG_VERTEXUSE_MAGIC )
00300 {
00301 struct vertexuse *vu;
00302
00303 vu = BU_LIST_FIRST( vertexuse , &lu->down_hd );
00304 NMG_CK_VERTEXUSE( vu );
00305
00306 if( vu->v_p == v )
00307 return( vu );
00308 else
00309 return( (struct vertexuse *)NULL );
00310 }
00311
00312 ret_vu = (struct vertexuse *)NULL;
00313 for( BU_LIST_FOR( eu , edgeuse , &lu->down_hd ) )
00314 {
00315 NMG_CK_EDGEUSE( eu );
00316
00317 if( eu->vu_p->v_p == v )
00318 {
00319 ret_vu = eu->vu_p;
00320 break;
00321 }
00322 }
00323
00324 return( ret_vu );
00325 }
00326
00327
00328
00329
00330
00331
00332
00333 static void
00334 nmg_start_new_loop(struct edgeuse *start_eu, struct loopuse *lu1, struct loopuse *lu2, struct bu_ptbl *loops)
00335 {
00336 struct bu_ptbl *new_lu_tab;
00337 struct loopuse *this_lu;
00338 struct loopuse *other_lu;
00339 struct edgeuse *eu;
00340 int edges=0;
00341 int done=0;
00342
00343 NMG_CK_EDGEUSE( start_eu );
00344 NMG_CK_LOOPUSE( lu1 );
00345 NMG_CK_LOOPUSE( lu2 );
00346
00347
00348 new_lu_tab = (struct bu_ptbl *)bu_malloc( sizeof( struct bu_ptbl ) , "nmg_start_new_loop: new_lu_tab" );
00349 bu_ptbl_init( new_lu_tab , 64, " new_lu_tab ");
00350
00351
00352 bu_ptbl_ins( loops , (long *)new_lu_tab );
00353
00354
00355
00356
00357
00358 this_lu = lu1;
00359 other_lu = lu2;
00360 eu = start_eu;
00361 while( !done )
00362 {
00363 struct edgeuse *next_eu;
00364 struct vertexuse *vu2;
00365
00366 next_eu = BU_LIST_PNEXT_CIRC( edgeuse , &eu->l );
00367
00368
00369 if( edges )
00370 {
00371
00372 if( (eu->vu_p->v_p == start_eu->vu_p->v_p ) )
00373 {
00374
00375 done = 1;
00376 break;
00377 }
00378
00379
00380 vu2 = nmg_find_vertex_in_lu( eu->vu_p->v_p , other_lu );
00381 if( vu2 )
00382 {
00383
00384 struct edgeuse *eu2;
00385 struct loopuse *lu_tmp;
00386 int loop_started=0;
00387 int i;
00388
00389 eu2 = vu2->up.eu_p;
00390
00391
00392 for( i=0 ; i<BU_PTBL_END( loops ) ; i++ )
00393 {
00394 struct bu_ptbl *loop_tab;
00395 struct edgeuse *loop_start_eu;
00396
00397 loop_tab = (struct bu_ptbl *)BU_PTBL_GET( loops , i );
00398 loop_start_eu = (struct edgeuse *)BU_PTBL_GET( loop_tab , 0 );
00399 if( loop_start_eu == eu )
00400 {
00401 loop_started = 1;
00402 break;
00403 }
00404 }
00405
00406
00407
00408
00409 if( !loop_started )
00410 nmg_start_new_loop( eu , this_lu , other_lu , loops );
00411
00412
00413 eu = eu2;
00414 next_eu = BU_LIST_PNEXT_CIRC( edgeuse , &eu->l );
00415 lu_tmp = this_lu;
00416 this_lu = other_lu;
00417 other_lu = lu_tmp;
00418 }
00419 }
00420
00421
00422 bu_ptbl_ins( new_lu_tab , (long *)eu );
00423
00424 edges++;
00425
00426
00427 eu = next_eu;
00428 }
00429
00430 }
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451 void
00452 nmg_fix_overlapping_loops(struct shell *s, const struct bn_tol *tol)
00453 {
00454 struct faceuse *fu;
00455 struct edgeuse *start_eu;
00456 struct bu_ptbl loops;
00457 int i;
00458
00459 NMG_CK_SHELL( s );
00460
00461 if( rt_g.NMG_debug & DEBUG_BASIC )
00462 bu_log( "nmg_fix_overlapping_loops: s = x%x\n" , s );
00463
00464
00465 nmg_split_loops_into_faces( &s->l.magic , tol );
00466
00467
00468
00469
00470
00471 bu_ptbl_init( &loops , 64, " &loops ");
00472
00473
00474 for( BU_LIST_FOR( fu , faceuse , &s->fu_hd ) )
00475 {
00476 struct loopuse *lu1,*lu2;
00477 struct edgeuse *eu1;
00478 struct edgeuse *eu;
00479 int inside=0;
00480 int outside=0;
00481
00482 NMG_CK_FACEUSE( fu );
00483
00484
00485 if( fu->orientation != OT_SAME )
00486 continue;
00487
00488
00489
00490
00491 lu1 = BU_LIST_FIRST( loopuse , &fu->lu_hd );
00492 NMG_CK_LOOPUSE( lu1 );
00493
00494 lu2 = BU_LIST_PNEXT( loopuse , &lu1->l );
00495
00496
00497 if( BU_LIST_IS_HEAD( lu2 , &fu->lu_hd ) )
00498 continue;
00499
00500 NMG_CK_LOOPUSE( lu2 );
00501
00502
00503
00504 if( BU_LIST_FIRST_MAGIC( &lu1->down_hd ) != NMG_EDGEUSE_MAGIC )
00505 continue;
00506
00507 if( BU_LIST_FIRST_MAGIC( &lu2->down_hd ) != NMG_EDGEUSE_MAGIC )
00508 continue;
00509
00510
00511 if( lu1->orientation == lu2->orientation )
00512 {
00513 bu_log( "nmg_fix_overlapping_loops: Cannot handle loops of same orientation\n" );
00514 nmg_pr_fu_briefly( fu , (char *)NULL );
00515 continue;
00516 }
00517
00518
00519
00520 if( lu1->orientation == OT_OPPOSITE && lu2->orientation == OT_SAME )
00521 {
00522 struct loopuse *lu_tmp;
00523
00524 lu_tmp = lu1;
00525 lu1 = lu2;
00526 lu2 = lu_tmp;
00527 }
00528 else if( lu2->orientation != OT_OPPOSITE || lu1->orientation != OT_SAME )
00529 {
00530 bu_log( "nmg_fix_overlapping_loops: bad loop orientations %s and %s\n",
00531 nmg_orientation( lu1->orientation ),
00532 nmg_orientation( lu2->orientation ) );
00533 continue;
00534 }
00535
00536
00537
00538
00539 for( BU_LIST_FOR( eu , edgeuse , &lu2->down_hd ) )
00540 {
00541 struct vertexuse *vu;
00542
00543 NMG_CK_EDGEUSE( eu );
00544
00545 vu = eu->vu_p;
00546
00547
00548 if( !nmg_find_vertex_in_lu( vu->v_p , lu1 ) )
00549 {
00550 int class;
00551
00552 class = nmg_classify_pt_loop( vu->v_p->vg_p->coord , lu1 , tol );
00553 if( class == NMG_CLASS_AoutB )
00554 outside++;
00555 else if( class == NMG_CLASS_AinB )
00556 inside++;
00557 }
00558 }
00559
00560
00561
00562
00563 if( !inside || !outside )
00564 continue;
00565
00566
00567
00568
00569 for( BU_LIST_FOR( eu1 , edgeuse , &lu1->down_hd ) )
00570 {
00571 vect_t v1;
00572 struct edgeuse *eu2;
00573
00574 VSUB2( v1 , eu1->eumate_p->vu_p->v_p->vg_p->coord , eu1->vu_p->v_p->vg_p->coord );
00575 for( BU_LIST_FOR( eu2 , edgeuse , &lu2->down_hd ) )
00576 {
00577 vect_t v2;
00578 fastf_t dist[2];
00579 struct vertex *v=(struct vertex *)NULL;
00580
00581 VSUB2( v2 , eu2->eumate_p->vu_p->v_p->vg_p->coord ,
00582 eu2->vu_p->v_p->vg_p->coord );
00583
00584 if( bn_isect_lseg3_lseg3( dist , eu1->vu_p->v_p->vg_p->coord , v1 ,
00585 eu2->vu_p->v_p->vg_p->coord , v2 , tol ) >= 0 )
00586 {
00587 struct edgeuse *new_eu;
00588
00589 if( dist[0]>0.0 && dist[0]<1.0 &&
00590 dist[1]>=0.0 && dist[1]<=1.0 )
00591 {
00592 point_t pt;
00593
00594 if( dist[1] == 0.0 )
00595 v = eu2->vu_p->v_p;
00596 else if( dist[1] == 1.0 )
00597 v = eu2->eumate_p->vu_p->v_p;
00598 else
00599 {
00600 VJOIN1( pt , eu1->vu_p->v_p->vg_p->coord , dist[0] , v1 );
00601 new_eu = nmg_esplit( v , eu1, 0 );
00602 v = new_eu->vu_p->v_p;
00603 if( !v->vg_p )
00604 nmg_vertex_gv( v , pt );
00605 }
00606
00607 VSUB2( v1 , eu1->eumate_p->vu_p->v_p->vg_p->coord ,
00608 eu1->vu_p->v_p->vg_p->coord );
00609 }
00610 if( dist[1]>0.0 && dist[1]<1.0 && dist[0]>=0.0 && dist[0]<=1.0 )
00611 {
00612 point_t pt;
00613
00614 if( dist[0] == 0.0 )
00615 v = eu1->vu_p->v_p;
00616 else if( dist[0] == 1.0 )
00617 v = eu2->eumate_p->vu_p->v_p;
00618 else
00619 {
00620 VJOIN1( pt , eu2->vu_p->v_p->vg_p->coord , dist[1] , v2 );
00621 new_eu = nmg_esplit( v , eu2, 0 );
00622 v = new_eu->vu_p->v_p;
00623 if( !v->vg_p )
00624 nmg_vertex_gv( v , pt );
00625 }
00626
00627 VSUB2( v2 , eu2->eumate_p->vu_p->v_p->vg_p->coord ,
00628 eu2->vu_p->v_p->vg_p->coord );
00629 }
00630 }
00631 }
00632 }
00633
00634
00635
00636
00637 start_eu = (struct edgeuse *)NULL;
00638 for( BU_LIST_FOR( eu1 , edgeuse , &lu1->down_hd ) )
00639 {
00640 struct vertex *v1,*v2;
00641 point_t mid_pt;
00642
00643
00644 if( !nmg_find_vertex_in_lu( eu1->vu_p->v_p , lu2 ) )
00645 continue;
00646
00647 v1 = eu1->vu_p->v_p;
00648 NMG_CK_VERTEX( v1 );
00649 v2 = eu1->eumate_p->vu_p->v_p;
00650 NMG_CK_VERTEX( v2 );
00651
00652
00653 VBLEND2( mid_pt , 0.5 , v1->vg_p->coord , 0.5 , v2->vg_p->coord )
00654
00655 if( nmg_classify_pt_loop( mid_pt , lu2 , tol ) == NMG_CLASS_AoutB )
00656 {
00657 start_eu = eu1;
00658 break;
00659 }
00660 }
00661
00662 if( !start_eu )
00663 {
00664 bu_log( "nmg_fix_overlapping_loops: cannot find start point for new loops\n" );
00665 bu_log( "lu1=x%x, lu2=x%x\n" , lu1 , lu2 );
00666 nmg_pr_fu_briefly( fu , (char *)NULL );
00667 continue;;
00668 }
00669
00670 bu_ptbl_reset( &loops );
00671
00672
00673
00674
00675 nmg_start_new_loop( start_eu , lu1 , lu2 , &loops );
00676
00677
00678 for( i=0 ; i<BU_PTBL_END( &loops ) ; i++ )
00679 {
00680 struct loopuse *new_lu;
00681 struct loopuse *new_lu_mate;
00682 struct bu_ptbl *loop_tab;
00683 int eu_no;
00684
00685
00686 loop_tab = (struct bu_ptbl *)BU_PTBL_GET( &loops , i );
00687
00688
00689 if( BU_PTBL_END( loop_tab ) )
00690 {
00691
00692 new_lu = nmg_mlv( &fu->l.magic , (struct vertex *)NULL , OT_SAME );
00693 new_lu_mate = new_lu->lumate_p;
00694
00695
00696 nmg_kvu( BU_LIST_FIRST( vertexuse , &new_lu->down_hd ) );
00697 nmg_kvu( BU_LIST_FIRST( vertexuse , &new_lu_mate->down_hd ) );
00698
00699
00700 for( eu_no=0 ; eu_no<BU_PTBL_END( loop_tab ) ; eu_no++ )
00701 {
00702 struct edgeuse *mv_eu;
00703
00704
00705 mv_eu = (struct edgeuse *)BU_PTBL_GET( loop_tab , eu_no );
00706 NMG_CK_EDGEUSE( mv_eu );
00707
00708
00709 BU_LIST_DEQUEUE( &mv_eu->l );
00710 BU_LIST_INSERT( &new_lu->down_hd , &mv_eu->l );
00711 mv_eu->up.lu_p = new_lu;
00712
00713
00714 BU_LIST_DEQUEUE( &mv_eu->eumate_p->l );
00715 BU_LIST_APPEND( &new_lu_mate->down_hd , &mv_eu->eumate_p->l );
00716 mv_eu->eumate_p->up.lu_p = new_lu_mate;
00717 }
00718
00719 bu_ptbl_free( loop_tab );
00720 bu_free( (char *)loop_tab , "nmg_fix_overlapping_loops: loop_tab" );
00721 }
00722 }
00723
00724
00725 lu1 = BU_LIST_FIRST( loopuse , &fu->lu_hd );
00726 while( BU_LIST_NOT_HEAD( lu1 , &fu->lu_hd ) )
00727 {
00728 struct loopuse *next_lu;
00729
00730 next_lu = BU_LIST_PNEXT( loopuse , &lu1->l );
00731
00732 if( BU_LIST_IS_EMPTY( &lu1->down_hd ) )
00733 {
00734 if( nmg_klu( lu1 ) )
00735 rt_bomb( "nmg_fix_overlapping_loops: Emptied faceuse!!\n" );
00736 }
00737 lu1 = next_lu;
00738 }
00739 }
00740 bu_ptbl_free( &loops );
00741
00742 if( rt_g.NMG_debug & DEBUG_BASIC )
00743 bu_log( "nmg_fix_overlapping_loops: done\n" );
00744 }
00745
00746
00747
00748
00749
00750
00751
00752 void
00753 nmg_break_crossed_loops(struct shell *is, const struct bn_tol *tol)
00754 {
00755 struct faceuse *fu;
00756
00757 NMG_CK_SHELL( is );
00758 BN_CK_TOL( tol );
00759
00760 for( BU_LIST_FOR( fu , faceuse , &is->fu_hd ) )
00761 {
00762 struct loopuse *lu;
00763
00764 NMG_CK_FACEUSE( fu );
00765
00766 if( fu->orientation != OT_SAME )
00767 continue;
00768
00769 for( BU_LIST_FOR( lu , loopuse , &fu->lu_hd ) )
00770 {
00771 struct edgeuse *eu1,*eu2;
00772 vect_t v1,v2;
00773
00774 NMG_CK_LOOPUSE( lu );
00775
00776 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
00777 continue;
00778
00779 for( BU_LIST_FOR( eu1 , edgeuse , &lu->down_hd ) )
00780 {
00781 VSUB2( v1 , eu1->eumate_p->vu_p->v_p->vg_p->coord ,
00782 eu1->vu_p->v_p->vg_p->coord );
00783
00784 eu2 = BU_LIST_PNEXT( edgeuse , eu1 );
00785 while( BU_LIST_NOT_HEAD( eu2 , &lu->down_hd ) )
00786 {
00787 fastf_t dist[2];
00788
00789 VSUB2( v2 , eu2->eumate_p->vu_p->v_p->vg_p->coord ,
00790 eu2->vu_p->v_p->vg_p->coord );
00791
00792 if( bn_isect_lseg3_lseg3( dist , eu1->vu_p->v_p->vg_p->coord , v1 ,
00793 eu2->vu_p->v_p->vg_p->coord , v2 , tol ) >= 0 )
00794 {
00795 point_t pt;
00796 struct edgeuse *new_eu;
00797 struct vertex *v=(struct vertex *)NULL;
00798
00799 if( dist[0]>0.0 && dist[0]<1.0 &&
00800 dist[1]>=0.0 && dist[1]<=1.0 )
00801 {
00802 if( dist[1] == 0.0 )
00803 v = eu2->vu_p->v_p;
00804 else if( dist[1] == 1.0 )
00805 v = eu2->eumate_p->vu_p->v_p;
00806 else
00807 {
00808 VJOIN1( pt , eu1->vu_p->v_p->vg_p->coord ,
00809 dist[0] , v1 );
00810 v = nmg_find_pt_in_shell( is , pt , tol );
00811 }
00812
00813 new_eu = nmg_esplit( v , eu1, 0 );
00814 v = new_eu->vu_p->v_p;
00815 if( !v->vg_p )
00816 nmg_vertex_gv( v , pt );
00817
00818 VSUB2( v1 , eu1->eumate_p->vu_p->v_p->vg_p->coord ,
00819 eu1->vu_p->v_p->vg_p->coord );
00820 }
00821 if( dist[1] > 0.0 && dist[1] < 1.0 &&
00822 dist[0]>=0.0 && dist[0]<=1.0 )
00823 {
00824 if( dist[0] == 0.0 )
00825 v = eu1->vu_p->v_p;
00826 else if( dist[0] == 1.0 )
00827 v = eu1->eumate_p->vu_p->v_p;
00828 else
00829 {
00830 VJOIN1( pt , eu2->vu_p->v_p->vg_p->coord , dist[1] , v2 );
00831 v = nmg_find_pt_in_shell( is , pt , tol );
00832 }
00833
00834 new_eu = nmg_esplit( v , eu2, 0 );
00835 v = new_eu->vu_p->v_p;
00836 if( !v->vg_p )
00837 nmg_vertex_gv( v , pt );
00838 }
00839 }
00840 eu2 = BU_LIST_PNEXT( edgeuse , eu2 );
00841 }
00842 }
00843 }
00844 }
00845 }
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857 struct shell *
00858 nmg_extrude_cleanup(struct shell *is, const int is_void, const struct bn_tol *tol)
00859 {
00860 struct model *m;
00861 struct nmgregion *new_r;
00862 struct faceuse *fu;
00863 struct loopuse *lu;
00864 struct vertexuse *vu;
00865 struct nmgregion *old_r;
00866 struct shell *s_tmp;
00867
00868 NMG_CK_SHELL( is );
00869 BN_CK_TOL( tol );
00870
00871 if( rt_g.NMG_debug & DEBUG_BASIC )
00872 bu_log( "nmg_extrude_cleanup( is=x%x )\n" , is );
00873
00874 m = nmg_find_model( &is->l.magic );
00875
00876
00877 nmg_isect_shell_self( is , tol );
00878
00879
00880 nmg_fix_overlapping_loops( is , tol );
00881
00882
00883 for( BU_LIST_FOR( fu , faceuse , &is->fu_hd ) )
00884 {
00885 if( fu->orientation != OT_SAME )
00886 continue;
00887
00888 lu = BU_LIST_LAST( loopuse , &fu->lu_hd );
00889 while( BU_LIST_NOT_HEAD( lu , &fu->lu_hd ) )
00890 {
00891 struct loopuse *new_lu;
00892 int orientation;
00893
00894
00895 while( (vu=(struct vertexuse *)nmg_loop_touches_self( lu ) ) != (struct vertexuse *)NULL )
00896 {
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906 orientation = lu->orientation;
00907 new_lu = nmg_split_lu_at_vu( lu , vu );
00908 new_lu->orientation = orientation;
00909 lu->orientation = orientation;
00910 new_lu->lumate_p->orientation = orientation;
00911 lu->lumate_p->orientation = orientation;
00912 }
00913
00914 lu = BU_LIST_PLAST( loopuse , &lu->l );
00915 }
00916 }
00917
00918 nmg_rebound( m , tol );
00919
00920
00921 old_r = is->r_p;
00922
00923
00924 new_r = nmg_mrsv( m );
00925
00926
00927 s_tmp = BU_LIST_FIRST( shell , &new_r->s_hd );
00928
00929
00930
00931
00932
00933
00934 (void)nmg_mv_shell_to_region( is , new_r );
00935
00936
00937 if( nmg_ks( s_tmp ) )
00938 rt_bomb( "nmg_extrude_shell: Nothing got moved to new region\n" );
00939
00940
00941 if( (nmg_decompose_shell( is , tol )) < 2 )
00942 {
00943
00944 if( nmg_bad_face_normals( is , tol ) )
00945 {
00946 (void)nmg_ks( is );
00947 is = (struct shell *)NULL;
00948 }
00949 else if( is_void != -1 && nmg_shell_is_void( is ) != is_void )
00950 {
00951 (void)nmg_ks( is );
00952 is = (struct shell *)NULL;
00953 }
00954 else
00955 (void)nmg_mv_shell_to_region( is , old_r );
00956
00957 nmg_kr( new_r );
00958 new_r = NULL;
00959 }
00960 else
00961 {
00962
00963 s_tmp = BU_LIST_FIRST( shell , &new_r->s_hd );
00964 while( BU_LIST_NOT_HEAD( s_tmp , &new_r->s_hd ) )
00965 {
00966 struct shell *next_s;
00967 int kill_it=0;
00968
00969 next_s = BU_LIST_PNEXT( shell , &s_tmp->l );
00970
00971 if( nmg_bad_face_normals( s_tmp , tol ) )
00972 kill_it = 1;
00973
00974 if( !kill_it )
00975 {
00976 if( is_void != -1 && nmg_shell_is_void( s_tmp ) != is_void )
00977 kill_it = 1;
00978 }
00979
00980 if( kill_it )
00981 {
00982
00983 if( nmg_ks( s_tmp ) )
00984 {
00985 nmg_kr( new_r );
00986 new_r = (struct nmgregion *)NULL;
00987 is = (struct shell *)NULL;
00988 break;
00989 }
00990 }
00991 s_tmp = next_s;
00992 }
00993 }
00994
00995 if( new_r )
00996 {
00997
00998 is = BU_LIST_FIRST( shell , &new_r->s_hd );
00999
01000 s_tmp = BU_LIST_PNEXT( shell , &is->l );
01001 while( BU_LIST_NOT_HEAD( s_tmp , &new_r->s_hd ) )
01002 {
01003 struct shell *next_s;
01004
01005 next_s = BU_LIST_PNEXT( shell , &s_tmp->l );
01006
01007 if( s_tmp == is )
01008 {
01009 s_tmp = next_s;
01010 continue;
01011 }
01012
01013 nmg_js( is , s_tmp , tol );
01014 s_tmp = next_s;
01015 }
01016
01017
01018 if( is )
01019 (void)nmg_mv_shell_to_region( is , old_r );
01020
01021
01022 if( BU_LIST_NON_EMPTY( &new_r->s_hd ) )
01023 bu_log( "nmg_extrude_cleanup: temporary nmgregion not empty!!\n" );
01024
01025 (void)nmg_kr( new_r );
01026 }
01027 return( is );
01028 }
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045 void
01046 nmg_hollow_shell(struct shell *s, const fastf_t thick, const int approximate, const struct bn_tol *tol)
01047 {
01048 struct nmgregion *new_r,*old_r;
01049 struct vertexuse *vu;
01050 struct edgeuse *eu;
01051 struct loopuse *lu;
01052 struct faceuse *fu;
01053 struct face_g_plane *fg_p;
01054 struct model *m;
01055 struct shell *is;
01056 struct shell *s_tmp;
01057 struct bu_ptbl shells;
01058 long *flags;
01059 long **copy_tbl;
01060 int shell_no;
01061 int is_void;
01062 int s_tmp_is_closed;
01063
01064 if( rt_g.NMG_debug & DEBUG_BASIC )
01065 bu_log( "nmg_extrude_shell( s=x%x , thick=%f)\n" , s , thick );
01066
01067 NMG_CK_SHELL( s );
01068 BN_CK_TOL( tol );
01069
01070 if( thick < 0.0 )
01071 {
01072 bu_log( "nmg_extrude_shell: thickness less than zero not allowed" );
01073 return;
01074 }
01075
01076 if( thick < tol->dist )
01077 {
01078 bu_log( "nmg_extrude_shell: thickness less than tolerance not allowed" );
01079 return;
01080 }
01081
01082 m = nmg_find_model( (long *)s );
01083
01084
01085 old_r = s->r_p;
01086 NMG_CK_REGION( old_r );
01087
01088
01089 new_r = nmg_mrsv( m );
01090 s_tmp = BU_LIST_FIRST( shell , &new_r->s_hd );
01091 (void)nmg_mv_shell_to_region( s , new_r );
01092
01093
01094 (void)nmg_decompose_shell( s , tol );
01095
01096
01097 (void)nmg_ks( s_tmp );
01098
01099
01100 nmg_region_a( new_r , tol );
01101
01102
01103 bu_ptbl_init( &shells , 64, " &shells ");
01104 for( BU_LIST_FOR( s_tmp , shell , &new_r->s_hd ) )
01105 bu_ptbl_ins( &shells , (long *)s_tmp );
01106
01107
01108 for( shell_no=0 ; shell_no<BU_PTBL_END( &shells ) ; shell_no ++ )
01109 {
01110 s_tmp = (struct shell *)BU_PTBL_GET( &shells , shell_no );
01111
01112
01113 is = nmg_dup_shell( s_tmp , ©_tbl, tol );
01114
01115
01116 flags = (long *)bu_calloc( m->maxindex , sizeof( long ) , "nmg_extrude_shell flags" );
01117
01118
01119 for( BU_LIST_FOR( fu , faceuse , &is->fu_hd ) )
01120 {
01121 NMG_CK_FACEUSE( fu );
01122 NMG_CK_FACE( fu->f_p );
01123 fg_p = fu->f_p->g.plane_p;
01124 NMG_CK_FACE_G_PLANE( fg_p );
01125
01126
01127 if( NMG_INDEX_TEST_AND_SET( flags , fg_p ) )
01128 {
01129 if( fu->f_p->flip )
01130 fg_p->N[3] += thick;
01131 else
01132 fg_p->N[3] -= thick;
01133 }
01134 }
01135
01136
01137 nmg_invert_shell( is , tol );
01138
01139 is_void = nmg_shell_is_void( is );
01140
01141
01142
01143
01144 for( BU_LIST_FOR( fu , faceuse , &s_tmp->fu_hd ) )
01145 {
01146 if( fu->orientation != OT_SAME )
01147 continue;
01148
01149 for( BU_LIST_FOR( lu , loopuse , &fu->lu_hd ) )
01150 {
01151 NMG_CK_LOOPUSE( lu );
01152 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) == NMG_VERTEXUSE_MAGIC )
01153 {
01154
01155
01156
01157 continue;
01158 }
01159 else
01160 {
01161 for( BU_LIST_FOR( eu , edgeuse , &lu->down_hd ) )
01162 {
01163 struct vertex *new_v;
01164
01165 NMG_CK_EDGEUSE( eu );
01166 vu = eu->vu_p;
01167 NMG_CK_VERTEXUSE( vu );
01168 new_v = NMG_INDEX_GETP( vertex , copy_tbl , vu->v_p );
01169 NMG_CK_VERTEX( new_v )
01170 if( NMG_INDEX_TEST_AND_SET( flags , new_v ) )
01171 {
01172
01173 if( nmg_in_vert( new_v , approximate , tol ) )
01174 rt_bomb( "Failed to get a new point from nmg_inside_vert\n" );
01175 }
01176 }
01177 }
01178 }
01179 }
01180
01181
01182 nmg_region_a( is->r_p , tol );
01183
01184 nmg_vmodel( m );
01185
01186 s_tmp_is_closed = !nmg_check_closed_shell( s_tmp , tol );
01187 if( s_tmp_is_closed )
01188 is = nmg_extrude_cleanup( is , is_void , tol );
01189
01190
01191 if( is )
01192 {
01193 if( s_tmp_is_closed )
01194 {
01195 if( nmg_check_closed_shell( is , tol ) )
01196 {
01197 bu_log( "nmg_extrude_shell: inside shell is not closed, calling nmg_close_shell\n" );
01198 nmg_close_shell( is, tol );
01199 }
01200
01201 nmg_shell_coplanar_face_merge( is , tol , 0 );
01202 nmg_simplify_shell( is );
01203
01204
01205 nmg_js( s_tmp , is , tol );
01206 }
01207 else
01208 {
01209 if( !nmg_check_closed_shell( is , tol ) )
01210 {
01211 bu_log( "nmg_extrude_shell: inside shell is closed, outer isn't!!\n" );
01212 nmg_shell_coplanar_face_merge( is , tol , 0 );
01213 nmg_simplify_shell( is );
01214 nmg_js( s_tmp , is , tol );
01215 }
01216 else
01217 {
01218
01219 nmg_open_shells_connect( s_tmp , is ,
01220 (const long **)copy_tbl , tol );
01221 }
01222 }
01223 }
01224
01225
01226 nmg_region_a( s_tmp->r_p , tol );
01227
01228
01229 bu_free( (char *)flags , "nmg_extrude_shell: flags" );
01230 bu_free( (char *)copy_tbl , "nmg_extrude_shell: copy_tbl" );
01231 }
01232
01233
01234 for( shell_no=0 ; shell_no<BU_PTBL_END( &shells ) ; shell_no++ )
01235 {
01236 struct shell *s2;
01237
01238 s2 = (struct shell *)BU_PTBL_GET( &shells , shell_no );
01239 if( s2 != s )
01240 nmg_js( s , s2 , tol );
01241 }
01242
01243 bu_ptbl_free( &shells );
01244
01245 (void)nmg_mv_shell_to_region( s , old_r );
01246 nmg_kr( new_r );
01247 }
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264 struct shell *
01265 nmg_extrude_shell(struct shell *s, const fastf_t dist, const int normal_ward, const int approximate, const struct bn_tol *tol)
01266 {
01267 fastf_t thick;
01268 int along_normal;
01269 struct model *m;
01270 struct nmgregion *new_r,*old_r;
01271 struct shell *s_tmp,*s2;
01272 struct bu_ptbl shells;
01273 struct bu_ptbl verts;
01274 int shell_no;
01275 int failed=0;
01276
01277 NMG_CK_SHELL( s );
01278 BN_CK_TOL( tol );
01279
01280 if( NEAR_ZERO( dist , tol->dist ) )
01281 {
01282 bu_log( "nmg_extrude_shell: Cannot extrude a distance less than tolerance distance\n" );
01283 return( s );
01284 }
01285
01286 along_normal = normal_ward;
01287 if( dist < 0.0 )
01288 {
01289 thick = (-dist);
01290 along_normal = (!normal_ward);
01291 }
01292 else
01293 thick = dist;
01294
01295 m = nmg_find_model( &s->l.magic );
01296 NMG_CK_MODEL( m );
01297
01298 old_r = s->r_p;
01299 NMG_CK_REGION( old_r );
01300
01301
01302 new_r = nmg_mrsv( m );
01303 s_tmp = BU_LIST_FIRST( shell , &new_r->s_hd );
01304 (void)nmg_mv_shell_to_region( s , new_r );
01305 (void)nmg_decompose_shell( s , tol );
01306
01307
01308 (void)nmg_ks( s_tmp );
01309
01310
01311 nmg_region_a( new_r , tol );
01312
01313
01314 bu_ptbl_init( &shells , 64, " &shells ");
01315 for( BU_LIST_FOR( s_tmp , shell , &new_r->s_hd ) )
01316 bu_ptbl_ins( &shells , (long *)s_tmp );
01317
01318 bu_ptbl_init( &verts , 64, " &verts ");
01319
01320
01321 for( shell_no=0 ; shell_no < BU_PTBL_END( &shells ) ; shell_no++ )
01322 {
01323 int vert_no;
01324 int is_void;
01325 long *flags;
01326 struct faceuse *fu;
01327
01328 s_tmp = (struct shell *)BU_PTBL_GET( &shells , shell_no );
01329 NMG_CK_SHELL( s_tmp );
01330
01331 is_void = nmg_shell_is_void( s_tmp );
01332
01333
01334 flags = (long *)bu_calloc( m->maxindex , sizeof( long ) , "nmg_extrude_shell flags" );
01335
01336
01337 for( BU_LIST_FOR( fu , faceuse , &s_tmp->fu_hd ) )
01338 {
01339 struct face_g_plane *fg_p;
01340
01341 NMG_CK_FACEUSE( fu );
01342 NMG_CK_FACE( fu->f_p );
01343 fg_p = fu->f_p->g.plane_p;
01344 NMG_CK_FACE_G_PLANE( fg_p );
01345
01346
01347 if( NMG_INDEX_TEST_AND_SET( flags , fg_p ) )
01348 {
01349 if( along_normal ^ fu->f_p->flip )
01350 fg_p->N[3] += thick;
01351 else
01352 fg_p->N[3] -= thick;
01353 }
01354 }
01355
01356 bu_free( (char *)flags , "nmg_extrude_shell flags" );
01357
01358
01359 nmg_vertex_tabulate( &verts , &s_tmp->l.magic );
01360
01361
01362 for( vert_no = 0 ; vert_no < BU_PTBL_END( &verts ) ; vert_no++ )
01363 {
01364 struct vertex *new_v;
01365
01366 new_v = (struct vertex *)BU_PTBL_GET( &verts , vert_no );
01367 NMG_CK_VERTEX( new_v );
01368
01369 if( nmg_in_vert( new_v , approximate , tol ) )
01370 {
01371 bu_log( "nmg_extrude_shell: Failed to calculate new vertex at v=x%x was ( %f %f %f )\n",
01372 new_v , V3ARGS( new_v->vg_p->coord ) );
01373 failed = 1;
01374 goto out;
01375 }
01376 }
01377
01378 bu_ptbl_free( &verts );
01379
01380 if( approximate )
01381 {
01382 for( BU_LIST_FOR( fu , faceuse , &s_tmp->fu_hd ) )
01383 {
01384 struct loopuse *lu;
01385 int got_plane=0;
01386
01387 if( fu->orientation != OT_SAME )
01388 continue;
01389
01390 for( BU_LIST_FOR( lu , loopuse , &fu->lu_hd ) )
01391 {
01392 fastf_t area;
01393 plane_t pl;
01394
01395 if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
01396 continue;
01397
01398 if( lu->orientation != OT_SAME )
01399 continue;
01400
01401 area = nmg_loop_plane_area( lu , pl );
01402
01403 if( area > 0.0 )
01404 {
01405 nmg_face_g( fu , pl );
01406 got_plane = 1;
01407 break;
01408 }
01409 }
01410 if( !got_plane )
01411 {
01412 bu_log( "nmg_extrude_shell: Cannot recalculate plane for face:\n" );
01413 nmg_pr_fu_briefly( fu , (char *)NULL );
01414 failed = 1;
01415 goto out;
01416 }
01417 }
01418 }
01419
01420
01421 nmg_region_a( s_tmp->r_p , tol );
01422
01423 (void)nmg_extrude_cleanup( s_tmp , is_void , tol );
01424 }
01425
01426 out:
01427 bu_ptbl_free( &shells );
01428
01429
01430 if( BU_LIST_NON_EMPTY( &new_r->s_hd ) )
01431 {
01432 s_tmp = BU_LIST_FIRST( shell , &new_r->s_hd );
01433 s2 = BU_LIST_PNEXT( shell , &s_tmp->l );
01434 while( BU_LIST_NOT_HEAD( s2 , &new_r->s_hd ) )
01435 {
01436 struct shell *next_s;
01437
01438 next_s = BU_LIST_PNEXT( shell , &s2->l );
01439 nmg_js( s_tmp , s2 , tol );
01440
01441 s2 = next_s;
01442 }
01443 }
01444 else
01445 s_tmp = (struct shell *)NULL;
01446
01447 if( s_tmp )
01448 (void)nmg_mv_shell_to_region( s_tmp , old_r );
01449
01450 nmg_kr( new_r );
01451
01452 if( failed )
01453 return( (struct shell *)NULL );
01454 else
01455 return( s_tmp );
01456 }
01457
01458
01459
01460
01461
01462
01463
01464
01465
01466