nmg_mesh.c

Go to the documentation of this file.
00001 /*                      N M G _ M E S H . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1989-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** @addtogroup nmg */
00023 /*@{*/
00024 /** @file nmg_mesh.c
00025  *      Meshing routines for n-Manifold Geometry.
00026  *  This stuff is destined to be absorbed into nmg_fuse.c.
00027  *  "meshing" here refers to the sorting of faceuses around an edge
00028  *  as two edges sharing the same end points (vertex structs) are fused.
00029  *
00030  *  Authors -
00031  *      Lee A. Butler
00032  *      Michael John Muuss
00033  *
00034  *  Source -
00035  *      SECAD/VLD Computing Consortium, Bldg 394
00036  *      The U. S. Army Ballistic Research Laboratory
00037  *      Aberdeen Proving Ground, Maryland  21005-5066
00038  *
00039  */
00040 /*@}*/
00041 #ifndef lint
00042 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/nmg_mesh.c,v 14.10 2006/09/16 02:04:25 lbutler Exp $ (BRL)";
00043 #endif
00044 
00045 #include "common.h"
00046 
00047 
00048 #include <stdio.h>
00049 #include <math.h>
00050 #include "machine.h"
00051 #include "vmath.h"
00052 #include "nmg.h"
00053 #include "raytrace.h"
00054 
00055 
00056 /**
00057  *                      N M G _ I S _ A N G L E _ I N _ W E D G E
00058  *
00059  *  Determine if T lies within angle AB, such that A < T < B.
00060  *  The angle B is expected to be "more ccw" than A.
00061  *  Because of the wrap from 2pi to 0, B may have a smaller numeric value.
00062  *
00063  *  Returns -
00064  *      -2      t is equal to a
00065  *      -1      t is equal to b
00066  *       0      t is outside angle ab
00067  *       1      t is inside angle ab
00068  */
00069 int
00070 nmg_is_angle_in_wedge(double a, double b, double t)
00071 {
00072         /* XXX What tolerance to use here (in radians)? */
00073         if( NEAR_ZERO( a-t, 1.0e-8 ) )  return -2;
00074         if( NEAR_ZERO( b-t, 1.0e-8 ) )  return -1;
00075 
00076         /* If A==B, if T is not also equal, it's outside the wedge */
00077         if( NEAR_ZERO( a-b, 1.0e-8 ) )  return 0;
00078 
00079         if( b < a )  {
00080                 /* B angle has wrapped past zero, add on 2pi */
00081                 if( t <= b )  {
00082                         /* Range is A..0, 0..B, and 0<t<B; so T is in wedge */
00083                         return 1;
00084                 }
00085                 b += bn_twopi;
00086         }
00087         if( NEAR_ZERO( b-t, 1.0e-8 ) )  return -1;
00088 
00089         if( t < a )  return 0;
00090         if( t > b )  return 0;
00091         return 1;
00092 }
00093 
00094 /**
00095  *                      N M G _ P I C K _ B E S T _ E D G E _ G
00096  *
00097  *  Given two edgeuses with different edge geometry but
00098  *  running between the same two vertices,
00099  *  select the proper edge geometry to associate with.
00100  *
00101  *  Really, there are 3 geometries to be compared here:
00102  *  the vector between the two endpoints of this edge,
00103  *  and the two edge_g structures.
00104  *  Rather than always taking eu2 or eu1,
00105  *  select the one that best fits this one edge.
00106  *
00107  *  Consider fu1:
00108  *                       B
00109  *                       *
00110  *                      /|
00111  *                  eg2/ |
00112  *                    /  |
00113  *                  D/   |
00114  *                  *    |
00115  *                 /     |
00116  *              A *-*----* C
00117  *                  E eg1
00118  *
00119  *  At the start of a face/face intersection, eg1 runs from A to C,
00120  *  and eg2 runs ADB.  The line of intersection with the other face
00121  *  (fu2, not drawn) lies along eg1.
00122  *  Assume that edge AC needs to be broken at E,
00123  *  where E is just a little more than tol->dist away from A.
00124  *  Existing point D is found because it *is* within tol->dist of E,
00125  *  thanks to the cosine of angle BAC.
00126  *  So, edge AC is broken on vertex D, and the intersection list
00127  *  contains vertexuses A, E, and C.
00128  *
00129  *  Because D and E are the same point, fu1 has become a triangle with
00130  *  a little "spike" on the end.  If this is handled simply by re-homing
00131  *  edge AE to eg2, it may cause trouble, because eg1 now runs EC,
00132  *  but the geometry for eg1 runs AC.  If there are other vertices on
00133  *  edge eg1, the problem can not be resolved simply by recomputing the
00134  *  geometry of eg1.
00135  *  Since E (D) is within tolerance of eg1, it is not unreasonable
00136  *  just to leave eg1 alone.
00137  *
00138  *  The issue boils down to selecting whether the existing eg1 or eg2
00139  *  best represents the direction of the little stub edge AD (shared with AE).
00140  *  In this case, eg2 is the correct choice, as AD (and AE) lie on line AB.
00141  *
00142  *  It would be disasterous to force *all* of eg1 to use the edge geometry
00143  *  of eg2, as the two lines are very different.
00144  */
00145 struct edge_g_lseg *
00146 nmg_pick_best_edge_g(struct edgeuse *eu1, struct edgeuse *eu2, const struct bn_tol *tol)
00147 {
00148         NMG_CK_EDGEUSE(eu1);
00149         NMG_CK_EDGEUSE(eu2);
00150         BN_CK_TOL(tol);
00151 
00152         NMG_CK_EDGE_G_LSEG(eu1->g.lseg_p);
00153         NMG_CK_EDGE_G_LSEG(eu2->g.lseg_p);
00154         if( eu2->g.lseg_p != eu1->g.lseg_p )  {
00155                 vect_t          dir;
00156                 vect_t          dir_2;
00157                 vect_t          dir_1;
00158                 fastf_t         dot_2;
00159                 fastf_t         dot_1;
00160 
00161                 VSUB2( dir, eu1->vu_p->v_p->vg_p->coord, eu1->eumate_p->vu_p->v_p->vg_p->coord );
00162                 VUNITIZE(dir);
00163                 VMOVE( dir_2, eu2->g.lseg_p->e_dir );
00164                 VUNITIZE( dir_2 );
00165                 VMOVE( dir_1, eu1->g.lseg_p->e_dir );
00166                 VUNITIZE( dir_1 );
00167 
00168                 dot_2 = fabs(VDOT( dir, dir_2 ));
00169                 dot_1 = fabs(VDOT( dir, dir_1 ));
00170 
00171                 /* Dot product of 1 means colinear.  Take largest dot. */
00172                 if( dot_2 > dot_1 )  {
00173                         if (rt_g.NMG_debug & DEBUG_BASIC)  {
00174                                 bu_log("nmg_pick_best_edge_g() Make eu1 use geometry of eu2, s.d=%g, d.d=%g\n",
00175                                         acos(dot_2)*bn_radtodeg,
00176                                         acos(dot_1)*bn_radtodeg );
00177                         }
00178                         return eu2->g.lseg_p;
00179                 } else {
00180                         if (rt_g.NMG_debug & DEBUG_BASIC)  {
00181                                 bu_log("nmg_pick_best_edge_g() Make eu2 use geometry of eu1, s.d=%g, d.d=%g\n",
00182                                         acos(dot_2)*bn_radtodeg,
00183                                         acos(dot_1)*bn_radtodeg );
00184                         }
00185                         return eu1->g.lseg_p;
00186                 }
00187         }
00188         return eu1->g.lseg_p;   /* both the same */
00189 }
00190 
00191 /**
00192  *                      N M G _ R A D I A L _ J O I N _ E U
00193  *
00194  *      Make all the edgeuses around eu2's edge to refer to eu1's edge,
00195  *      taking care to organize them into the proper angular orientation,
00196  *      so that the attached faces are correctly arranged radially
00197  *      around the edge.
00198  *
00199  *      This depends on both edges being part of face loops,
00200  *      with vertex and face geometry already associated.
00201  *
00202  *  The two edgeuses being joined might well be from separate shells,
00203  *  so the issue of preserving (simple) faceuse orientation parity
00204  *  (SAME, OPPOSITE, OPPOSITE, SAME, ...)
00205  *  can't be used here -- that only applies to faceuses from the same shell.
00206  *
00207  *  Some of the edgeuses around both edges may be wires.
00208  *
00209  *      Call to nmg_check_radial at end has been deleted.
00210  *      Note that after two radial EU's have been joined
00211  *      a third cannot be joined to them without creating
00212  *      unclosed space that nmg_check_radial will find.
00213  */
00214 void
00215 nmg_radial_join_eu(struct edgeuse *eu1, struct edgeuse *eu2, const struct bn_tol *tol)
00216 {
00217 
00218         NMG_CK_EDGEUSE(eu1);
00219         NMG_CK_EDGEUSE(eu1->radial_p);
00220         NMG_CK_EDGEUSE(eu1->eumate_p);
00221         NMG_CK_EDGEUSE(eu2);
00222         NMG_CK_EDGEUSE(eu2->radial_p);
00223         NMG_CK_EDGEUSE(eu2->eumate_p);
00224         BN_CK_TOL(tol);
00225 
00226         if( eu1->e_p == eu2->e_p )  return;
00227 
00228         if( !NMG_ARE_EUS_ADJACENT(eu1, eu2) )
00229                 rt_bomb("nmg_radial_join_eu() edgeuses don't share vertices.\n");
00230 
00231         if( eu1->vu_p->v_p == eu1->eumate_p->vu_p->v_p )  rt_bomb("nmg_radial_join_eu(): 0 length edge (topology)\n");
00232 
00233         if( bn_pt3_pt3_equal( eu1->vu_p->v_p->vg_p->coord,
00234             eu1->eumate_p->vu_p->v_p->vg_p->coord, tol ) )
00235         {
00236                 bu_log( "vertices should have been fused:\n" );
00237                 bu_log( "\tvertex x%x ( %.12f %.12f %.12f )\n",
00238                         eu1->vu_p->v_p,
00239                         V3ARGS( eu1->vu_p->v_p->vg_p->coord ) );
00240                 bu_log( "\tvertex x%x ( %.12f %.12f %.12f )\n",
00241                         eu1->eumate_p->vu_p->v_p,
00242                         V3ARGS( eu1->eumate_p->vu_p->v_p->vg_p->coord ) );
00243                 rt_bomb("nmg_radial_join_eu(): 0 length edge (geometry)\n");
00244         }
00245 
00246 #if 1
00247 nmg_radial_join_eu_NEW(eu1, eu2, tol);
00248 return;
00249 #else
00250 
00251         /* Ensure faces are of same orientation, if both eu's have faces */
00252         fu1 = nmg_find_fu_of_eu(eu1);
00253         fu2 = nmg_find_fu_of_eu(eu2);
00254         if( fu1 && fu2 )  {
00255                 if( fu1->orientation != fu2->orientation ){
00256                         eu2 = eu2->eumate_p;
00257                         fu2 = nmg_find_fu_of_eu(eu2);
00258                         if( fu1->orientation != fu2->orientation )
00259                                 rt_bomb( "nmg_radial_join_eu(): Cannot find matching orientations for faceuses\n" );
00260                 }
00261         }
00262 
00263         /* XXX This angle-based algorithm can't handle snurb faces! */
00264         if( fu1 && fu1->f_p->g.magic_p && *fu1->f_p->g.magic_p == NMG_FACE_G_SNURB_MAGIC )  return;
00265         if( fu2 && fu2->f_p->g.magic_p && *fu2->f_p->g.magic_p == NMG_FACE_G_SNURB_MAGIC )  return;
00266 
00267         /*  Construct local coordinate system for this edge,
00268          *  so all angles can be measured relative to a common reference.
00269          */
00270         nmg_eu_2vecs_perp( xvec, yvec, zvec, original_eu1, tol );
00271 
00272         if (rt_g.NMG_debug & DEBUG_MESH_EU ) {
00273                 bu_log("nmg_radial_join_eu(eu1=x%x, eu2=x%x) e1=x%x, e2=x%x\n",
00274                         eu1, eu2,
00275                         eu1->e_p, eu2->e_p);
00276                 nmg_euprint("\tJoining", eu1);
00277                 nmg_euprint("\t     to", eu2);
00278                 bu_log( "Faces around eu1:\n" );
00279                 nmg_pr_fu_around_eu_vecs( eu1, xvec, yvec, zvec, tol );
00280                 bu_log( "Faces around eu2:\n" );
00281                 nmg_pr_fu_around_eu_vecs( eu2, xvec, yvec, zvec, tol );
00282         }
00283 
00284         best_eg = nmg_pick_best_edge_g( eu1, eu2, tol );
00285 
00286         for ( iteration1=0; eu2 && iteration1 < 10000; iteration1++ ) {
00287                 int     code = 0;
00288                 struct edgeuse  *first_eu1 = eu1;
00289                 int     wire_skip = 0;
00290                 /* Resume where we left off from last eu2 insertion */
00291 
00292                 /* find a place to insert eu2 around eu1's edge */
00293                 for ( iteration2=0; iteration2 < 10000; iteration2++ ) {
00294                         struct faceuse  *fur;
00295 
00296                         abs1 = abs2 = absr = -bn_twopi;
00297 
00298                         eur = eu1->radial_p;
00299                         NMG_CK_EDGEUSE(eur);
00300 
00301                         fu2 = nmg_find_fu_of_eu(eu2);
00302                         if( fu2 == (struct faceuse *)NULL )  {
00303                                 /* eu2 is a wire, it can go anywhere */
00304 bu_log("eu2=x%x is a wire, insert after eu1=x%x\n", eu2, eu1);
00305                                 goto insert;
00306                         }
00307                         fu1 = nmg_find_fu_of_eu(eu1);
00308                         if( fu1 == (struct faceuse *)NULL )  {
00309                                 /* eu1 is a wire, skip on to real face eu */
00310 bu_log("eu1=x%x is a wire, skipping on\n", eu1);
00311                                 wire_skip++;
00312                                 goto cont;
00313                         }
00314                         fur = nmg_find_fu_of_eu(eur);
00315                         while( fur == (struct faceuse *)NULL )  {
00316                                 /* eur is wire, advance eur */
00317 bu_log("eur=x%x is a wire, advancing to non-wire eur\n", eur);
00318                                 eur = eur->eumate_p->radial_p;
00319                                 wire_skip++;
00320                                 if( eur == eu1->eumate_p )  {
00321 bu_log("went all the way around\n");
00322                                         /* Went all the way around */
00323                                         goto insert;
00324                                 }
00325                                 fur = nmg_find_fu_of_eu(eur);
00326                         }
00327                         NMG_CK_FACEUSE(fu1);
00328                         NMG_CK_FACEUSE(fu2);
00329                         NMG_CK_FACEUSE(fur);
00330 
00331                         /*
00332                          *  Can't just check for shared fg here,
00333                          *  the angle changes by +/- 180 degrees,
00334                          *  depending on which side of the eu the loop is on
00335                          *  along this edge.
00336                          */
00337                         abs1 = nmg_measure_fu_angle( eu1, xvec, yvec, zvec );
00338                         abs2 = nmg_measure_fu_angle( eu2, xvec, yvec, zvec );
00339                         absr = nmg_measure_fu_angle( eur, xvec, yvec, zvec );
00340 
00341                         if (rt_g.NMG_debug & DEBUG_MESH_EU )  {
00342                                 bu_log("  abs1=%g, abs2=%g, absr=%g\n",
00343                                         abs1*bn_radtodeg,
00344                                         abs2*bn_radtodeg,
00345                                         absr*bn_radtodeg );
00346                         }
00347 
00348                         /* If abs1 == absr, warn about unfused faces, and skip. */
00349                         if( NEAR_ZERO( abs1-absr, 1.0e-8 ) )  {
00350                                 if( fu1->f_p->g.plane_p == fur->f_p->g.plane_p )  {
00351                                         /* abs1 == absr, faces are fused, don't insert here. */
00352                                         if (rt_g.NMG_debug & DEBUG_MESH_EU )  {
00353                                                 bu_log("fu1 and fur share face geometry x%x (flip1=%d, flip2=%d), skip\n",
00354                                                         fu1->f_p->g.plane_p, fu1->f_p->flip, fur->f_p->flip );
00355                                         }
00356                                         goto cont;
00357                                 }
00358 
00359                                 bu_log("nmg_radial_join_eu: WARNING 2 faces should have been fused, may be ambiguous.\n  abs1=%e, absr=%e, asb2=%e\n",
00360                                         abs1*bn_radtodeg, absr*bn_radtodeg, abs2*bn_radtodeg);
00361                                 bu_log("  fu1=x%x, f1=x%x, f1->flip=%d, fg1=x%x\n",
00362                                         fu1, fu1->f_p, fu1->f_p->flip, fu1->f_p->g.plane_p );
00363                                 bu_log("  fu2=x%x, f2=x%x, f2->flip=%d, fg2=x%x\n",
00364                                         fu2, fu2->f_p, fu2->f_p->flip, fu2->f_p->g.plane_p );
00365                                 bu_log("  fur=x%x, fr=x%x, fr->flip=%d, fgr=x%x\n",
00366                                         fur, fur->f_p, fur->f_p->flip, fur->f_p->g.plane_p );
00367                                 PLPRINT("  fu1", fu1->f_p->g.plane_p->N );
00368                                 PLPRINT("  fu2", fu2->f_p->g.plane_p->N );
00369                                 PLPRINT("  fur", fur->f_p->g.plane_p->N );
00370                                 {
00371                                         int debug = rt_g.NMG_debug;
00372 #if 0
00373                                         rt_g.NMG_debug |= DEBUG_MESH;
00374 #endif
00375                                         if( nmg_two_face_fuse(fu1->f_p, fur->f_p, tol) == 0 )
00376                                                 rt_bomb("faces didn't fuse?\n");
00377                                         rt_g.NMG_debug = debug;
00378                                 }
00379                                 bu_log("  nmg_radial_join_eu() skipping this eu\n");
00380                                 goto cont;
00381                         }
00382 
00383                         /*
00384                          *  If abs1 < abs2 < absr
00385                          *  (taking into account 360 wrap),
00386                          *  then insert face here.
00387                          *  Special handling if abs1==abs2 or abs2==absr.
00388                          */
00389                         code = nmg_is_angle_in_wedge( abs1, absr, abs2 );
00390                         if (rt_g.NMG_debug & DEBUG_MESH_EU )
00391                                 bu_log("    code=%d %s\n", code, (code!=0)?"INSERT_HERE":"skip");
00392                         if( code > 0 )  break;
00393                         if( code == -1 )  {
00394                                 /* absr == abs2 */
00395                                 break;
00396                         }
00397                         if( code <= -2 )  {
00398                                 /* abs1 == abs2 */
00399                                 break;
00400                         }
00401 
00402 cont:
00403 #if 0
00404                         if( iteration2 > 9997 )  rt_g.NMG_debug |= DEBUG_MESH_EU;
00405 #endif
00406                         /* If eu1 is only one pair of edgeuses, done */
00407                         if( eu1 == eur->eumate_p )  break;
00408                         eu1 = eur->eumate_p;
00409                         if( eu1 == first_eu1 )  {
00410                                 /* If all eu's were wires, here is fine */
00411                                 if( wire_skip >= iteration2 )  break;
00412                                 /* Nope, something bad happened */
00413                                 rt_bomb("nmg_radial_join_eu():  went full circle, no face insertion point.\n");
00414                                 break;
00415                         }
00416                 }
00417                 if(iteration2 >= 10000)  {
00418                         rt_bomb("nmg_radial_join_eu: infinite loop (2)\n");
00419                 }
00420 
00421                 /* find the next use of the edge eu2 is on.  If eu2 and it's
00422                  * mate are the last uses of the edge, there will be no next
00423                  * edgeuse to move. (Loop termination condition).
00424                  */
00425 insert:
00426                 nexteu = eu2->radial_p;
00427                 if (nexteu == eu2->eumate_p)
00428                         nexteu = (struct edgeuse *)NULL;
00429 
00430                 /* because faces are always created with counter-clockwise
00431                  * exterior loops and clockwise interior loops,
00432                  * radial edgeuses IN THE SAME SHELL will never point in
00433                  * the same direction or share the same vertex.  We thus make
00434                  * sure that eu2 is an edgeuse which might be radial to eu1
00435                  * XXX Need to look back for last eu IN THE SHELL OF eu2.
00436                  * XXX Even this isn't good enough, as we may be inserting
00437                  * XXX something new _after_ that last starting point.
00438                  */
00439                 eus = eu1;
00440                 while( nmg_find_s_of_eu(eus) != nmg_find_s_of_eu(eu2) )  {
00441                         eus = eus->eumate_p->radial_p;
00442                         if( eus == eu1 )  break;        /* full circle */
00443                 }
00444 
00445                 if (eu2->vu_p->v_p == eus->vu_p->v_p)
00446                         eu2 = eu2->eumate_p;
00447 
00448                 if (rt_g.NMG_debug & DEBUG_MESH_EU)  {
00449                         bu_log("  Inserting.  code=%d\n", code);
00450                         bu_log("joining eu1=x%x eu2=x%x with abs1=%g, absr=%g\n",
00451                                 eu1, eu2,
00452                                 abs1*bn_radtodeg, absr*bn_radtodeg);
00453                 }
00454 
00455                 /*
00456                  *  Make eu2 radial to eu1.
00457                  *  This should insert eu2 between eu1 and eu1->radial_p
00458                  *  (which may be less far around than eur, but thats OK).
00459                  *  This does NOT change the edge geometry pointer.
00460                  */
00461                 nmg_je(eu1, eu2);
00462 
00463                 if (rt_g.NMG_debug & DEBUG_MESH_EU)  {
00464                         bu_log("After nmg_je(), faces around original_eu1 are:\n");
00465                         nmg_pr_fu_around_eu_vecs( original_eu1, xvec, yvec, zvec, tol );
00466                 }
00467 
00468                 /* Proceed to the next source edgeuse */
00469                 eu2 = nexteu;
00470         }
00471         if( iteration1 >= 10000 )  rt_bomb("nmg_radial_join_eu:  infinite loop (1)\n");
00472 
00473         NMG_CK_EDGEUSE(original_eu1);
00474 
00475         /*
00476          *  Make another pass, ensuring that all edgeuses are using the
00477          *  "best_eg" line.
00478          */
00479         eu1 = original_eu1;
00480         for(;;)  {
00481                 if( eu1->g.lseg_p != best_eg )  {
00482                         nmg_use_edge_g( eu1, &best_eg->l.magic );
00483                 }
00484 
00485                 eu1 = eu1->eumate_p->radial_p;
00486                 if( eu1 == original_eu1 )  break;
00487         }
00488 
00489         if (rt_g.NMG_debug & DEBUG_MESH_EU)  bu_log("nmg_radial_join_eu: END\n");
00490 #endif
00491 }
00492 
00493 /**
00494  *                      N M G _ M E S H _ T W O _ F A C E S
00495  *
00496  *  Actuall do the work of meshing two faces.
00497  *  The two fu arguments may be the same, which causes the face to be
00498  *  meshed against itself.
00499  *
00500  *  The return is the number of edges meshed.
00501  */
00502 int
00503 nmg_mesh_two_faces(register struct faceuse *fu1, register struct faceuse *fu2, const struct bn_tol *tol)
00504 {
00505         struct loopuse  *lu1;
00506         struct loopuse  *lu2;
00507         struct edgeuse  *eu1;
00508         struct edgeuse  *eu2;
00509         struct vertex   *v1a, *v1b;
00510         struct edge     *e1;
00511         pointp_t        pt1, pt2;
00512         int             count = 0;
00513 
00514         NMG_CK_FACEUSE(fu1);
00515         NMG_CK_FACEUSE(fu2);
00516         BN_CK_TOL(tol);
00517 
00518         /* Visit all the loopuses in faceuse 1 */
00519         for (BU_LIST_FOR(lu1, loopuse, &fu1->lu_hd)) {
00520                 NMG_CK_LOOPUSE(lu1);
00521                 /* Ignore self-loops */
00522                 if (BU_LIST_FIRST_MAGIC(&lu1->down_hd) != NMG_EDGEUSE_MAGIC)
00523                         continue;
00524 
00525                 /* Visit all the edgeuses in loopuse1 */
00526                 for(BU_LIST_FOR(eu1, edgeuse, &lu1->down_hd)) {
00527                         NMG_CK_EDGEUSE(eu1);
00528 
00529                         v1a = eu1->vu_p->v_p;
00530                         v1b = eu1->eumate_p->vu_p->v_p;
00531                         NMG_CK_VERTEX(v1a);
00532                         NMG_CK_VERTEX(v1b);
00533                         e1 = eu1->e_p;
00534                         NMG_CK_EDGE(e1);
00535                         if (rt_g.NMG_debug & DEBUG_MESH)  {
00536                                 pt1 = v1a->vg_p->coord;
00537                                 pt2 = v1b->vg_p->coord;
00538                                 bu_log("ref_e=%8x v:%8x--%8x (%g, %g, %g)->(%g, %g, %g)\n",
00539                                         e1, v1a, v1b,
00540                                         V3ARGS(pt1), V3ARGS(pt2) );
00541                         }
00542 
00543                         /* Visit all the loopuses in faceuse2 */
00544                         for (BU_LIST_FOR(lu2, loopuse, &fu2->lu_hd)) {
00545                                 /* Ignore self-loops */
00546                                 if(BU_LIST_FIRST_MAGIC(&lu2->down_hd) != NMG_EDGEUSE_MAGIC)
00547                                         continue;
00548                                 /* Visit all the edgeuses in loopuse2 */
00549                                 for( BU_LIST_FOR(eu2, edgeuse, &lu2->down_hd) )  {
00550                                         NMG_CK_EDGEUSE(eu2);
00551                                         if (rt_g.NMG_debug & DEBUG_MESH) {
00552                                                 pt1 = eu2->vu_p->v_p->vg_p->coord;
00553                                                 pt2 = eu2->eumate_p->vu_p->v_p->vg_p->coord;
00554                                                 bu_log("\te:%8x v:%8x--%8x (%g, %g, %g)->(%g, %g, %g)\n",
00555                                                         eu2->e_p,
00556                                                         eu2->vu_p->v_p,
00557                                                         eu2->eumate_p->vu_p->v_p,
00558                                                         V3ARGS(pt1), V3ARGS(pt2) );
00559                                         }
00560 
00561                                         /* See if already shared */
00562                                         if( eu2->e_p == e1 ) continue;
00563                                         if( (eu2->vu_p->v_p == v1a &&
00564                                              eu2->eumate_p->vu_p->v_p == v1b) ||
00565                                             (eu2->eumate_p->vu_p->v_p == v1a &&
00566                                              eu2->vu_p->v_p == v1b) )  {
00567                                                 nmg_radial_join_eu(eu1, eu2, tol);
00568                                                 count++;
00569                                          }
00570                                 }
00571                         }
00572                 }
00573         }
00574         return count;
00575 }
00576 
00577 /**
00578  *                      N M G _ M E S H _ F A C E S
00579  *
00580  *  Scan through all the edges of fu1 and fu2, ensuring that all
00581  *  edges involving the same vertex pair are indeed shared.
00582  *  This means worrying about merging ("meshing") all the faces in the
00583  *  proper radial orientation around the edge.
00584  *  XXX probably should return(count);
00585  */
00586 void
00587 nmg_mesh_faces(struct faceuse *fu1, struct faceuse *fu2, const struct bn_tol *tol)
00588 {
00589         int     count = 0;
00590 
00591         NMG_CK_FACEUSE(fu1);
00592         NMG_CK_FACEUSE(fu2);
00593         BN_CK_TOL(tol);
00594 
00595         if (rt_g.NMG_debug & DEBUG_MESH_EU && rt_g.NMG_debug & DEBUG_PLOTEM) {
00596                 static int fnum=1;
00597                 nmg_pl_2fu( "Before_mesh%d.pl", fnum++, fu1, fu2, 1 );
00598         }
00599 
00600         if (rt_g.NMG_debug & DEBUG_MESH_EU)
00601                 bu_log("meshing self (fu1 %8x)\n", fu1);
00602         count += nmg_mesh_two_faces( fu1, fu1, tol );
00603 
00604         if (rt_g.NMG_debug & DEBUG_MESH_EU)
00605                 bu_log("meshing self (fu2 %8x)\n", fu2);
00606         count += nmg_mesh_two_faces( fu2, fu2, tol );
00607 
00608         if (rt_g.NMG_debug & DEBUG_MESH_EU)
00609                 bu_log("meshing to other (fu1:%8x fu2:%8x)\n", fu1, fu2);
00610         count += nmg_mesh_two_faces( fu1, fu2, tol );
00611 
00612         if (rt_g.NMG_debug & DEBUG_MESH_EU && rt_g.NMG_debug & DEBUG_PLOTEM) {
00613                 static int fno=1;
00614                 nmg_pl_2fu( "After_mesh%d.pl", fno++, fu1, fu2, 1 );
00615         }
00616 }
00617 
00618 /**
00619  *                      N M G _ M E S H _ F A C E _ S H E L L
00620  *
00621  *  The return is the number of edges meshed.
00622  */
00623 int
00624 nmg_mesh_face_shell(struct faceuse *fu1, struct shell *s, const struct bn_tol *tol)
00625 {
00626         register struct faceuse *fu2;
00627         int             count = 0;
00628 
00629         NMG_CK_FACEUSE(fu1);
00630         NMG_CK_SHELL(s);
00631         BN_CK_TOL(tol);
00632 
00633         count += nmg_mesh_two_faces( fu1, fu1, tol );
00634         for( BU_LIST_FOR( fu2, faceuse, &s->fu_hd ) )  {
00635                 NMG_CK_FACEUSE(fu2);
00636                 count += nmg_mesh_two_faces( fu2, fu2, tol );
00637                 count += nmg_mesh_two_faces( fu1, fu2, tol );
00638         }
00639         /* XXX What about wire edges in the shell? */
00640         return count;
00641 }
00642 
00643 /**
00644  *                      N M G _ M E S H _ S H E L L _ S H E L L
00645  *
00646  *  Mesh every edge in shell 1 with every edge in shell 2.
00647  *  The return is the number of edges meshed.
00648  *
00649  *  Does not use nmg_mesh_face_shell() to keep face/self meshing
00650  *  to the absolute minimum necessary.
00651  */
00652 int
00653 nmg_mesh_shell_shell(struct shell *s1, struct shell *s2, const struct bn_tol *tol)
00654 {
00655         struct faceuse  *fu1;
00656         struct faceuse  *fu2;
00657         int             count = 0;
00658 
00659         NMG_CK_SHELL(s1);
00660         NMG_CK_SHELL(s2);
00661         BN_CK_TOL(tol);
00662 
00663 nmg_region_v_unique( s1->r_p, tol );
00664 nmg_region_v_unique( s2->r_p, tol );
00665 
00666         /* First, mesh all faces of shell 2 with themselves */
00667         for( BU_LIST_FOR( fu2, faceuse, &s2->fu_hd ) )  {
00668                 NMG_CK_FACEUSE(fu2);
00669                 count += nmg_mesh_two_faces( fu2, fu2, tol );
00670         }
00671 
00672         /* Visit every face in shell 1 */
00673         for( BU_LIST_FOR( fu1, faceuse, &s1->fu_hd ) )  {
00674                 NMG_CK_FACEUSE(fu1);
00675 
00676                 /* First, mesh each face in shell 1 with itself */
00677                 count += nmg_mesh_two_faces( fu1, fu1, tol );
00678 
00679                 /* Visit every face in shell 2 */
00680                 for( BU_LIST_FOR( fu2, faceuse, &s2->fu_hd ) )  {
00681                         NMG_CK_FACEUSE(fu2);
00682                         count += nmg_mesh_two_faces( fu1, fu2, tol );
00683                 }
00684         }
00685 
00686         /* XXX What about wire edges in the shell? */
00687 
00688         /* Visit every wire loop in shell 1 */
00689 
00690         /* Visit every wire edge in shell 1 */
00691 
00692         return count;
00693 }
00694 
00695 /*
00696  * Local Variables:
00697  * mode: C
00698  * tab-width: 8
00699  * c-basic-offset: 4
00700  * indent-tabs-mode: t
00701  * End:
00702  * ex: shiftwidth=4 tabstop=8
00703  */

Generated on Mon Sep 18 01:24:53 2006 for BRL-CAD by  doxygen 1.4.6