nmg_mk.c

Go to the documentation of this file.
00001 /*                        N M G _ M K . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1994-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 /*@{*/
00025 /** @file nmg_mk.c
00026  *      Support routines for n-Manifold Geometry.
00027  *
00028  *      Naming convention
00029  *              nmg_m* routines "make" NMG structures.
00030  *              nmg_k* routines "kill" (delete) NMG structures.
00031  *
00032  *      in each of the above cases the letters or words following are an
00033  *      attempt at a mnemonic representation for what is manipulated
00034  *
00035  *      m       Model
00036  *      r       Region
00037  *      s       shell
00038  *      f       face
00039  *      fu      faceuse
00040  *      l       loop
00041  *      lu      loopuse
00042  *      e       edge
00043  *      eu      edgeuse
00044  *      v       vertex
00045  *      vu      vertexuse
00046  *
00047  *
00048  *      Rules:
00049  *
00050  * XXX - What does "overlap" mean? ctj
00051  *      edges of loops of the same face must not overlap
00052  *      the "magic" member of each struct is the first item.
00053  *
00054  *      All routines which create and destroy the NMG data structures
00055  *      are contained in this module.
00056  *
00057  *
00058  *  Authors -
00059  *      Lee A. Butler
00060  *      Michael John Muuss
00061  *
00062  *  Source -
00063  *      The U. S. Army Research Laboratory
00064  *      Aberdeen Proving Ground, Maryland  21005-5068  USA
00065  */
00066 /*@}*/
00067 
00068 #ifndef lint
00069 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/nmg_mk.c,v 14.15 2006/09/16 02:04:25 lbutler Exp $ (ARL)";
00070 #endif
00071 
00072 #include "common.h"
00073 
00074 #include <stddef.h>
00075 #include <stdio.h>
00076 #include <math.h>
00077 #include <string.h>
00078 
00079 #include "machine.h"
00080 #include "vmath.h"
00081 #include "nmg.h"
00082 #include "raytrace.h"
00083 #include "nurb.h"
00084 
00085 static struct vertexuse *nmg_mvu BU_ARGS( (struct vertex *v, long *upptr,
00086                                          struct model *m) );
00087 static struct vertexuse *nmg_mvvu BU_ARGS( (long *upptr, struct model *m) );
00088 
00089 
00090 /************************************************************************
00091  *                                                                      *
00092  *                      "Make" Routines                                 *
00093  *                                                                      *
00094  *  The subroutines create new topological entities and return a        *
00095  *  pointer to the new entity.                                          *
00096  *                                                                      *
00097  ************************************************************************/
00098 
00099 /*
00100  *  The nmg_m*() routines are used to create a topology-only object
00101  *  which at first has no geometry associated with it at all.
00102  *  A topology-only object can be used to answer questions like:
00103  *      is this vertex ON this shell?
00104  *      is this vertex ON this face?
00105  *      is this vertex ON this edge?
00106  *      Is this face ON this shell?
00107  * and many more.
00108  *
00109  *  After the topology has been built, most applications will proceed to
00110  *  associate geometry with the topology, primarily by supplying
00111  *  Cartesian coordinates for each struct vertex, and by supplying
00112  *  or computing face normals for the planar faces.  (Linear edge geometry
00113  *  is optional, as it is implicit from the vertex geometry).
00114  *
00115  *  Objects which have been fully populated with geometry can be used to
00116  *  answer questions about where things are located and how large they are.
00117  *
00118  * The abstract objects are:
00119  *      model, nmgregion, shell, face, loop, edge and vertex.
00120  * The uses of those objects are:
00121  *      faceuse, loopuse, edgeuse and vertexuse.
00122  * Geometry can optionally be associated with the abstract objects:
00123  *      face_g          (plane equation, bounding box)
00124  *      loop_g          (just a bounding box, for planar faces)
00125  *      edge_g          (to track edge subdivision heritage, for linear edges)
00126  *      vertex_g        (Cartesian coordinates)
00127  * The uses of those objects can optionally have attributes:
00128  *      nmgregion_a     (region bounding box)   [nmgregions have no uses]
00129  *      shell_a         (shell bounding box)    [shells have no uses]
00130  *      vertexuse_a     (special surface normal, for normal interpolation)
00131  *
00132  * Consider for example a simple cube.
00133  *
00134  * As a topology-only object, it would have the following structures:
00135  *
00136  *      1 model structure
00137  *              This is the handle which everything else hangs on.
00138  *              The model structure r_hd references 1 region structure.
00139  *      1 nmgregion structure.
00140  *              The region structure s_hd references 1 shell structure.
00141  *              Also, m_p references the model.
00142  *      1 shell structure.
00143  *              The shell structure fu_hd references 12 faceuse structures.
00144  *              One for each side of each of the 6 faces of the cube.
00145  *              Also, r_p references the nmgregion.
00146  *      12 faceuse structures.
00147  *              Each faceuse structure lu_hd references 1 loopuse structure.
00148  *              Also, 1 face structure and 1 faceuse structure (its mate),
00149  *              plus s_p references the shell.
00150  *      6 face structures.
00151  *              Each face structure fu_p references a random choice of 1 of
00152  *              the two parent faceuse structures sharing this face, and is
00153  *              in turn referenced by that faceuse and it's mate.
00154  *      12 loopuse structures
00155  *              Each loopuse structure down_hd references 4 edgeuse structures.
00156  *              Also, 1 loop structure, and 1 loopuse structure (its mate).
00157  *              The four edgeuse structures define the perimeter of the
00158  *              surface area that comprises this face.
00159  *              Because their orientation is OT_SAME, each loopuse "claims"
00160  *              all the surface area inside it for the face.
00161  *              (OT_OPPOSITE makes a hole, claiming surface area outside).
00162  *              Plus, "up" references the parent object (faceuse, here).
00163  *      6 loop structures
00164  *              Each loop structure references a random choice of 1 of it's
00165  *              parent loopuse structures and is in turn referenced by that
00166  *              loopuse and it's mate.
00167  *      48 edgeuse structures
00168  *              Each edgeuse structure references 1 vertexuse structure,
00169  *              1 edge structure, and 2 other edgeuse structures (it's mate
00170  *              and the next edgeuse radial to this edgeuse).
00171  *              (if this edge was NOT used in another face, then the
00172  *              radial pointer and mate pointer would point to the SAME
00173  *              edgeuse)
00174  *              To find all edgeuses around a given edge, follow radial to
00175  *              mate to radial to mate until you are back to the original
00176  *              edgeuse.
00177  *              Plus, "up" references the parent object (loopuse, here).
00178  *      12 edge structures
00179  *              Each edge structure references a random choice of one of
00180  *              it's parent edgeuse structures and is in turn referenced
00181  *              by that edgeuse, the mate of that edgeuse, the radial of
00182  *              that edgeuse and the mate of the radial. (In this simple
00183  *              case of the cube, there are 4 edgeuses per edge).
00184  *      48 vertexuse structures.
00185  *              Each vertexuse structure references one vertex structure
00186  *              and is in turn enroled as a member of the linked list
00187  *              headed by that vertex structure.
00188  *              Each vertexuse is cited by exactly one edgeuse.
00189  *              Also, "up" references the parent object (edgeuse, here).
00190  *      8 vertex structures
00191  *              Each vertex structure references 6 vertexuse structures
00192  *              via it's linked list. (In the case of the cube,
00193  *              there are three faces meeting at each vertex, and each of
00194  *              those faces has two faceuse structs of one loopuse each. Each
00195  *              loopuse will cite the vertex via one edgeuse, so 3*2 = 6).
00196  *
00197  * As well as each "use" pointing down to what it uses, the "use" points
00198  * up to the structure that uses it.  So working up from any abstract object
00199  * or it's use, the top of the tree (struct model) can be found.
00200  * Working down from the struct model, all elements of the object can be
00201  * visited.
00202  *
00203  * The object just described contains no geometry.  There is no way to tell
00204  * where in space the object lies or how big it is.
00205  *
00206  * To add geometry, the following structures are needed:
00207  *      8 vertex_g structures
00208  *              each vertex_g structure contains a point in space (point_t)
00209  *              and is referenced by 1 vertex structure.
00210  *      12 edge_g structures (completely optional)
00211  *              each edge_g structure contains the parametric definition of
00212  *              the line which contains the line segment which is the edge,
00213  *              given as a point in space and a direction vector.  It is
00214  *              referenced by 1 edge structure. (In general, it is referenced
00215  *              by all edges sharing that line).
00216  *              In a simple case the point would be the same as one of
00217  *              the vertex_g points and the direction would be the normalized
00218  *              (unit) vector of the difference between the two vertex_g points.
00219  *      6 loop_g structures
00220  *              Each loop_g structure contains a bounding box for the loop.
00221  *              It is referenced by 1 loop structure.
00222  *      6 face_g_plane structures
00223  *              Each face_g_plane structure contains a plane equation and
00224  *              a bounding box.  It is referenced by one face structure.
00225  *              The plane equation is calculated from the vertex_g data
00226  *              by nmg_fu_planeeqn().
00227  *              See h/vmath.h for the definition of a plane equation.
00228  *      1 shell_a structure
00229  *              Each shell_a structure contains the bounding box for the
00230  *              shell.  It is referenced by 1 shell structure.
00231  *      1 nmgregion_a structure
00232  *              Each nmgregion_a structure contains the bounding box for the
00233  *              region.  It is referenced by 1 region structure.
00234  *
00235  */
00236 
00237 /*
00238  *                      N M G _ M M
00239  *
00240  *      Make Model
00241  *      Create a new model.  The region list is empty.
00242  *      Creates a new model structure.  The model region structure list
00243  *      is empty.
00244  *
00245  *  Returns -
00246  *      (struct model *)
00247  *
00248  *  Method:
00249  *      Use NMG_BU_GETSTRUCT to allocate memory and then set all components.
00250  *      NMG_BU_GETSTRUCT is used instead of the standard GET_name because
00251  *      all of the GET_name macros expect a model pointer to get the
00252  *      maxindex from.  So here we use NMG_BU_GETSTRUCT so that we can
00253  *      set the maxindex and index by hand.
00254  *
00255  *  N.B.:
00256  *      "maxindex" is a misnomer.  It is the value of the NEXT index
00257  *      assigned.  This allows "ptab"s to be allocated easly using
00258  *      maxindex and the index value of the structures to be the actual
00259  *      index into the "ptab".
00260  */
00261 struct model *
00262 nmg_mm(void)
00263 {
00264         struct model *m;
00265 
00266         BU_GETSTRUCT( m, model );
00267 
00268         BU_LIST_INIT( &m->r_hd );
00269         m->index = 0;
00270         m->maxindex = 1;
00271         m->magic = NMG_MODEL_MAGIC;     /* Model Structure is GOOD */
00272 
00273         if (rt_g.NMG_debug & DEBUG_BASIC)  {
00274                 bu_log("nmg_mm() returns model x%x\n", m );
00275         }
00276 
00277         return(m);
00278 }
00279 
00280 /**
00281  *                      N M G _ M M R
00282  *
00283  *      Make Model and Region
00284  *      Create a new model, and an "empty" region to go with it.  Essentially
00285  *      this creates a minimal model system.
00286  *
00287  *  Returns -
00288  *      (struct model *)
00289  *
00290  *  Implicit Return -
00291  *      The new region is found with BU_LIST_FIRST( nmgregion, &m->r_hd );
00292  */
00293 struct model *
00294 nmg_mmr(void)
00295 {
00296         struct model *m;
00297         struct nmgregion *r;
00298 
00299         m = nmg_mm();
00300         GET_REGION(r, m);
00301 
00302         r->m_p = m;
00303 
00304         r->ra_p = (struct nmgregion_a *)NULL;
00305         BU_LIST_INIT( &r->s_hd );
00306         r->l.magic = NMG_REGION_MAGIC;  /* Region Structure is GOOD */
00307 
00308         BU_LIST_APPEND( &m->r_hd, &r->l );
00309 
00310         if (rt_g.NMG_debug & DEBUG_BASIC)  {
00311                 bu_log("nmg_mmr() returns model x%x with region x%x\n", m , r );
00312         }
00313 
00314         return(m);
00315 }
00316 
00317 /**
00318  *                      N M G _ M R S V
00319  *
00320  *      Make new region, shell, vertex in model as well as the
00321  *      required "uses".
00322  *      Create a new region in model consisting of a minimal shell.
00323  *
00324  *  Returns -
00325  *      (struct nmgregion *)
00326  *
00327  *  Implicit Returns -
00328  *      Region is also found with r=BU_LIST_FIRST( nmgregion, &m->r_hd );
00329  *      The new shell is found with s=BU_LIST_FIRST( shell, &r->s_hd );
00330  *      The new vertexuse is s->vu_p;
00331  */
00332 struct nmgregion *
00333 nmg_mrsv(struct model *m)
00334 {
00335         struct nmgregion *r;
00336 
00337         NMG_CK_MODEL(m);
00338 
00339         GET_REGION(r, m);
00340         r->m_p = m;
00341         r->ra_p = (struct nmgregion_a *) NULL;
00342 
00343         BU_LIST_INIT( &r->s_hd );
00344         r->l.magic = NMG_REGION_MAGIC;  /* Region struct is GOOD */
00345 
00346         (void)nmg_msv(r);
00347 
00348         /* new region goes at "head" of list of regions in model */
00349         BU_LIST_APPEND( &m->r_hd, &r->l );
00350 
00351         if (rt_g.NMG_debug & DEBUG_BASIC)  {
00352                 bu_log("nmg_mrsv(m=x%x) returns r=x%x\n" , m , r );
00353         }
00354 
00355         return(r);
00356 }
00357 
00358 /**
00359  *                      N M G _ M S V
00360  *
00361  *      Make Shell, Vertex Use, Vertex
00362  *      Create a new shell in a specified region.  The shell will consist
00363  *      of a single vertexuse and vertex (which are also created).
00364  *
00365  *  Returns -
00366  *      (struct shell *)
00367  *
00368  *  Implicit Returns -
00369  *      The new shell is also found with s=BU_LIST_FIRST( shell, &r->s_hd );
00370  *      The new vertexuse is s->vu_p;
00371  */
00372 struct shell *
00373 nmg_msv(struct nmgregion *r)
00374 {
00375         struct shell            *s;
00376         struct vertexuse        *vu;
00377 
00378         NMG_CK_REGION(r);
00379 
00380         /* set up shell */
00381         GET_SHELL(s, r->m_p);
00382 
00383         s->r_p = r;
00384         BU_LIST_APPEND( &r->s_hd, &s->l );
00385 
00386         s->sa_p = (struct shell_a *)NULL;
00387         BU_LIST_INIT( &s->fu_hd );
00388         BU_LIST_INIT( &s->lu_hd );
00389         BU_LIST_INIT( &s->eu_hd );
00390         s->vu_p = (struct vertexuse *) NULL;
00391         s->l.magic = NMG_SHELL_MAGIC;   /* Shell Struct is GOOD */
00392 
00393         vu = nmg_mvvu(&s->l.magic, r->m_p);
00394         s->vu_p = vu;
00395 
00396         if (rt_g.NMG_debug & DEBUG_BASIC)  {
00397                 bu_log("nmg_msv(r=x%x) returns s=x%x, vu=x%x\n" , r , s , s->vu_p );
00398         }
00399 
00400         return(s);
00401 }
00402 
00403 /**
00404  *                      N M G _ M F
00405  *
00406  *      Make Face from a wire loop.
00407  *      make a face from a pair of loopuses.  The loopuses must be direct
00408  *      children of a shell.  The new face will be a child of the same shell.
00409  *
00410  * Given a wire loop (by definition, a loop attached to a shell), create
00411  * a new face, faceuse (and mate) and move the wire loop from the shell
00412  * to the new faceuse (and mate).
00413  *
00414  *  Implicit Returns -
00415  *      The first faceuse is fu1=BU_LIST_FIRST( faceuse, &s->fu_hd );
00416  *      The second faceuse follows:  fu2=BU_LIST_NEXT( faceuse, &fu1->l.magic );
00417  */
00418 struct faceuse *
00419 nmg_mf(struct loopuse *lu1)
00420 {
00421         struct face *f;
00422         struct faceuse *fu1, *fu2;
00423         struct loopuse *lu2;
00424         struct shell    *s;
00425         struct model    *m;
00426 
00427         NMG_CK_LOOPUSE(lu1);
00428         if (*lu1->up.magic_p != NMG_SHELL_MAGIC) {
00429                 rt_bomb("nmg_mf() loop must be child of shell for making face\n");
00430         }
00431         lu2 = lu1->lumate_p;
00432         NMG_CK_LOOPUSE(lu2);
00433         if (lu2->up.magic_p != lu1->up.magic_p) {
00434                 rt_bomb("nmg_mf() loopuse mate does not have same parent\n");
00435         }
00436 
00437         s = lu1->up.s_p;
00438         NMG_CK_SHELL(s);
00439 
00440         m = nmg_find_model( &s->l.magic );
00441         GET_FACE(f, m);
00442         GET_FACEUSE(fu1, m);
00443         GET_FACEUSE(fu2, m);
00444 
00445         f->fu_p = fu1;
00446         f->g.plane_p = (struct face_g_plane *)NULL;
00447         f->flip = 0;
00448         BU_LIST_INIT(&f->l);
00449         f->l.magic = NMG_FACE_MAGIC;    /* Face struct is GOOD */
00450 
00451         BU_LIST_INIT(&fu1->lu_hd);
00452         BU_LIST_INIT(&fu2->lu_hd);
00453         fu1->s_p = fu2->s_p = s;
00454         fu1->fumate_p = fu2;
00455         fu2->fumate_p = fu1;
00456         fu1->orientation = fu2->orientation = OT_UNSPEC;
00457         fu1->f_p = fu2->f_p = f;
00458         fu1->l.magic =
00459             fu2->l.magic = NMG_FACEUSE_MAGIC; /* Faceuse structs are GOOD */
00460 
00461         /* move the loopuses from the shell to the faceuses */
00462         BU_LIST_DEQUEUE( &lu1->l );
00463         BU_LIST_DEQUEUE( &lu2->l );
00464         BU_LIST_APPEND( &fu1->lu_hd, &lu1->l );
00465         BU_LIST_APPEND( &fu2->lu_hd, &lu2->l );
00466 
00467         lu1->up.fu_p = fu1;
00468         lu1->orientation = OT_SAME;
00469         lu2->up.fu_p = fu2;
00470         lu2->orientation = OT_SAME;
00471 
00472         /* connect the faces to the parent shell:  head, fu1, fu2... */
00473         BU_LIST_APPEND( &s->fu_hd, &fu1->l );
00474         BU_LIST_APPEND( &fu1->l, &fu2->l );
00475 
00476         if (rt_g.NMG_debug & DEBUG_BASIC)  {
00477                 bu_log("nmg_mf(lu1=x%x) returns fu=x%x\n" , lu1 , fu1 );
00478         }
00479 
00480         return(fu1);
00481 }
00482 
00483 /**
00484  *                      N M G _ M L V
00485  *
00486  * XXX - vertex or vertexuse? or both? ctj
00487  *      Make a new loop (with specified orientation) and vertex,
00488  *      in a shell or face.
00489  *      If the vertex 'v' is NULL, the shell's lone vertex is used,
00490  *      or a new vertex is created.
00491  *
00492  *  "magic" must point to the magic number of a faceuse or shell.
00493  *
00494  *  If the shell has a lone vertex in it, that lone vertex *will*
00495  *  be used.  If a non-NULL 'v' is provided, the lone vertex and
00496  *  'v' will be fused together.  XXX Why is this good?
00497  *
00498  *  If a convenient shell does not exist, use s=nmg_msv() to make
00499  *  the shell and vertex, then call lu=nmg_mlv(s,s->vu_p->v_p,OT_SAME),
00500  *  followed by nmg_kvu(s->vu_p).
00501  *
00502  *  Implicit returns -
00503  *      The new vertexuse can be had by:
00504  *              BU_LIST_FIRST(vertexuse, &lu->down_hd);
00505  *
00506  *      In case the returned loopuse isn't retained, the new loopuse was
00507  *      inserted at the +head+ of the appropriate list, e.g.:
00508  *              lu = BU_LIST_FIRST(loopuse, &fu->lu_hd);
00509  *      or
00510  *              lu = BU_LIST_FIRST(loopuse, &s->lu_hd);
00511  *
00512  * N.B.  This function is made more complex than warrented by using
00513  * the "hack" of stealing a vertexuse structure from the shell if
00514  * at all possible.  A future enhancement to this function would be
00515  * to remove the vertexuse steal and have the caller pass in the
00516  * vertex from the shell followed by a call to nmg_kvu(s->vu_p).
00517  * The v==NULL convention is used only in nmg_mod.c.
00518  */
00519 struct loopuse *
00520 nmg_mlv(long int *magic, struct vertex *v, int orientation)
00521 {
00522         struct loop     *l;
00523         struct loopuse  *lu1, *lu2;
00524         struct vertexuse *vu1 = NULL;
00525         struct vertexuse *vu2;
00526         struct model    *m;
00527         /* XXX - why the new union? ctj */
00528         union {
00529                 struct shell *s;
00530                 struct faceuse *fu;
00531                 long *magic_p;
00532         } p;
00533 
00534         p.magic_p = magic;
00535 
00536         if (v) {
00537                 NMG_CK_VERTEX(v);
00538         }
00539 
00540         m = nmg_find_model( magic );
00541         GET_LOOP(l, m);
00542         GET_LOOPUSE(lu1, m);
00543         GET_LOOPUSE(lu2, m);
00544 
00545         l->lg_p = (struct loop_g *)NULL;
00546         l->lu_p = lu1;
00547         l->magic = NMG_LOOP_MAGIC;      /* Loop struct is GOOD */
00548 
00549         BU_LIST_INIT( &lu1->down_hd );
00550         BU_LIST_INIT( &lu2->down_hd );
00551         lu1->l_p = lu2->l_p = l;
00552         lu1->orientation = lu2->orientation = orientation;
00553 
00554         lu1->lumate_p = lu2;
00555         lu2->lumate_p = lu1;
00556 
00557         /* The only thing left to do to make the loopuses good is to */
00558         /* set the "up" pointer and "l.magic". */
00559         if (*p.magic_p == NMG_SHELL_MAGIC) {
00560                 struct shell    *s = p.s;
00561 
00562                 /* First, finish setting up the loopuses */
00563                 lu1->up.s_p = lu2->up.s_p = s;
00564 
00565                 lu1->l.magic = lu2->l.magic =
00566                     NMG_LOOPUSE_MAGIC;  /* Loopuse structs are GOOD */
00567 
00568                 BU_LIST_INSERT( &s->lu_hd, &lu1->l );
00569                 BU_LIST_INSERT( &lu1->l, &lu2->l );
00570 
00571                 /* Second, build the vertices */
00572                 /* This "if" degenerates to the "else" clause if no stealing */
00573                 if ( (vu1 = s->vu_p) ) {
00574                         /* Use shell's lone vertex */
00575                         s->vu_p = (struct vertexuse *)NULL;
00576                         vu1->up.lu_p = lu1;
00577                         if (v) nmg_movevu(vu1, v);
00578                 } else {
00579                         if (v) vu1 = nmg_mvu(v, &lu1->l.magic, m);
00580                         else vu1 = nmg_mvvu(&lu1->l.magic, m);
00581                 }
00582                 NMG_CK_VERTEXUSE(vu1);
00583                 RT_LIST_SET_DOWN_TO_VERT(&lu1->down_hd, vu1);
00584                 /* vu1->up.lu_p = lu1; done by nmg_mvu/nmg_mvvu */
00585 
00586                 vu2 = nmg_mvu(vu1->v_p, &lu2->l.magic, m);
00587                 NMG_CK_VERTEXUSE(vu2);
00588                 RT_LIST_SET_DOWN_TO_VERT(&lu2->down_hd, vu2);
00589                 /* vu2->up.lu_p = lu2; done by nmg_mvu() */
00590         } else if (*p.magic_p == NMG_FACEUSE_MAGIC) {
00591                 /* First, finish setting up the loopuses */
00592                 lu1->up.fu_p = p.fu;
00593                 lu2->up.fu_p = p.fu->fumate_p;
00594                 lu1->l.magic = lu2->l.magic =
00595                     NMG_LOOPUSE_MAGIC;  /* Loopuse structs are GOOD */
00596 
00597                 BU_LIST_INSERT( &p.fu->fumate_p->lu_hd, &lu2->l );
00598                 BU_LIST_INSERT( &p.fu->lu_hd, &lu1->l );
00599 
00600                 /* Second, build the vertices */
00601                 if (v) vu1 = nmg_mvu(v, &lu1->l.magic, m);
00602                 else vu1 = nmg_mvvu(&lu1->l.magic, m);
00603                 RT_LIST_SET_DOWN_TO_VERT(&lu1->down_hd, vu1);
00604                 /* vu1->up.lu_p = lu1; done by nmg_mvu/nmg_mvvu */
00605 
00606                 vu2 = nmg_mvu(vu1->v_p, &lu2->l.magic, m);
00607                 RT_LIST_SET_DOWN_TO_VERT(&lu2->down_hd, vu2);
00608                 /* vu2->up.lu_p = lu2; done by nmg_mvu() */
00609         } else {
00610                 rt_bomb("nmg_mlv() unknown parent for loopuse!\n");
00611         }
00612 
00613         if (rt_g.NMG_debug & DEBUG_BASIC)  {
00614                 bu_log("nmg_mlv(up=x%x, v=x%x, %s) returns lu=x%x on vu=x%x\n",
00615                         magic, v, nmg_orientation(orientation),
00616                         lu1, vu1 );
00617         }
00618         return(lu1);
00619 }
00620 
00621 /**                     N M G _ M V U
00622  *
00623  *      Make Vertexuse on existing vertex
00624  *
00625  *  This is a support routine for this module, and is not intended for
00626  *  general use, as it requires lots of cooperation from the caller.
00627  *  (Like setting the parent's down pointer appropriately).
00628  *
00629  *  This means that a vu is created but is not attached to the parent
00630  *  structure.  This is "bad" and requires the caller to fix.
00631  */
00632 static struct vertexuse *
00633 nmg_mvu(struct vertex *v, long int *upptr, struct model *m)
00634 
00635                                 /* pointer to parent struct */
00636 
00637 {
00638         struct vertexuse *vu;
00639 
00640         NMG_CK_VERTEX(v);
00641         NMG_CK_MODEL(m);
00642 
00643         if (*upptr != NMG_SHELL_MAGIC &&
00644             *upptr != NMG_LOOPUSE_MAGIC &&
00645             *upptr != NMG_EDGEUSE_MAGIC) {
00646                 bu_log("nmg_mvu() in %s at %d magic not shell, loop, or edge.  Was x%x (%s)\n",
00647                     __FILE__, __LINE__,
00648                     *upptr, bu_identify_magic(*upptr) );
00649                 rt_bomb("nmg_mvu() Cannot build vertexuse without parent\n");
00650         }
00651 
00652         GET_VERTEXUSE(vu, m);
00653 
00654         vu->v_p = v;
00655         vu->a.plane_p = (struct vertexuse_a_plane *)NULL;
00656         BU_LIST_APPEND( &v->vu_hd, &vu->l );
00657         vu->up.magic_p = upptr;
00658         vu->l.magic = NMG_VERTEXUSE_MAGIC;      /* Vertexuse struct is GOOD */
00659 
00660         if (rt_g.NMG_debug & DEBUG_BASIC)  {
00661                 bu_log("nmg_mvu(v=x%x, up=x%x) returns vu=x%x\n",
00662                         v, upptr, vu);
00663         }
00664         return(vu);
00665 }
00666 
00667 /**                     N M G _ M V V U
00668  *
00669  *      Make Vertex, Vertexuse
00670  *
00671  *  This is a support routine for this module, and is not intended for
00672  *  general use, as it requires lots of cooperation from the caller.
00673  *  (Like setting the parent's down pointer appropriately).
00674  *
00675  *  This means that a vu is created but is not attached to the parent
00676  *  structure.  This is "bad" and requires the caller to fix.
00677  */
00678 static struct vertexuse *
00679 nmg_mvvu(long int *upptr, struct model *m)
00680 {
00681         struct vertex   *v;
00682         struct vertexuse *ret_vu;
00683 
00684         NMG_CK_MODEL(m);
00685         GET_VERTEX(v, m);
00686         BU_LIST_INIT( &v->vu_hd );
00687         v->vg_p = (struct vertex_g *)NULL;
00688         v->magic = NMG_VERTEX_MAGIC;    /* Vertex struct is GOOD */
00689         ret_vu = nmg_mvu(v, upptr, m);
00690 
00691         if (rt_g.NMG_debug & DEBUG_BASIC)  {
00692                 bu_log("nmg_mvvu(upptr=x%x,m=x%x) returns vu=x%x\n" , upptr , m , ret_vu );
00693         }
00694 
00695         return( ret_vu );
00696 }
00697 
00698 
00699 /**
00700  *                      N M G _ M E
00701  *
00702  *      Make wire edge
00703  *      Make a new edge between a pair of vertices in a shell.
00704  *
00705  *      A new vertex will be made for any NULL vertex pointer parameters.
00706  *      If we need to make a new vertex and the shell still has its vertexuse
00707  *      we re-use that vertex rather than freeing and re-allocating.
00708  *
00709  *      If both vertices were specified, and the shell also had a
00710  *      vertexuse pointer, the vertexuse in the shell is killed.
00711  *      XXX Why?
00712  *
00713  *  Explicit Return -
00714  *      An edgeuse in shell "s" whose vertexuse refers to vertex v1.
00715  *      The edgeuse mate's vertexuse refers to vertex v2
00716  *
00717  *  Implicit Returns -
00718  *      1)  If the shell had a lone vertex in vu_p, it is destroyed,
00719  *      even if both vertices were specified.
00720  *      2)  The returned edgeuse is the first item on the shell's
00721  *      eu_hd list, followed immediately by the mate.
00722  */
00723 struct edgeuse *
00724 nmg_me(struct vertex *v1, struct vertex *v2, struct shell *s)
00725 {
00726         struct edge             *e;
00727         struct edgeuse          *eu1;
00728         struct edgeuse          *eu2;
00729         struct vertexuse        *vu;
00730         struct model            *m;
00731 
00732         if (v1) NMG_CK_VERTEX(v1);
00733         if (v2) NMG_CK_VERTEX(v2);
00734         NMG_CK_SHELL(s);
00735 
00736         m = nmg_find_model( &s->l.magic );
00737         GET_EDGE(e, m);
00738         GET_EDGEUSE(eu1, m);
00739         GET_EDGEUSE(eu2, m);
00740 
00741         BU_LIST_INIT( &eu1->l2 );
00742         BU_LIST_INIT( &eu2->l2 );
00743         eu1->l2.magic = eu2->l2.magic = NMG_EDGEUSE2_MAGIC;
00744 
00745         e->eu_p = eu1;
00746         /* e->is_real = XXX; */
00747         e->magic = NMG_EDGE_MAGIC;      /* Edge struct is GOOD */
00748 
00749         eu1->radial_p = eu1->eumate_p = eu2;
00750         eu2->radial_p = eu2->eumate_p = eu1;
00751 
00752         eu1->e_p = eu2->e_p = e;
00753         eu1->orientation = eu2->orientation = OT_NONE;
00754         /* XXX - why not OT_UNSPEC? ctj */
00755         eu1->vu_p = eu2->vu_p = (struct vertexuse *) NULL;
00756 
00757         eu1->l.magic = eu2->l.magic =
00758             NMG_EDGEUSE_MAGIC;  /* Edgeuse structs are GOOD */
00759         /* Not really, edgeuses require vertexuses, but we've got to */
00760         /* call nmg_mvvu() or nmg_mvu() before we can set vu_p so we */
00761         /* NULL out vu_p now. */
00762 
00763         /* link the edgeuses to the parent shell */
00764         eu1->up.s_p = eu2->up.s_p = s;
00765 
00766         if (v1)  {
00767                 eu1->vu_p = nmg_mvu(v1, &eu1->l.magic, m);
00768         } else if (s->vu_p)  {
00769                 /* This clause of the if statment dies when no vertex stealing */
00770                 /* steal the vertex from the shell */
00771                 vu = s->vu_p;
00772                 s->vu_p = (struct vertexuse *)NULL;
00773                 eu1->vu_p = vu;
00774                 vu->up.eu_p = eu1;
00775         } else {
00776                 eu1->vu_p = nmg_mvvu(&eu1->l.magic, m);
00777         }
00778 
00779         if (v2)  {
00780                 eu2->vu_p = nmg_mvu(v2, &eu2->l.magic, m);
00781         } else if (s->vu_p)  {
00782                 /* This clause of the if statment dies when no vertex stealing */
00783                 /* steal the vertex from the shell */
00784                 vu = s->vu_p;
00785                 s->vu_p = (struct vertexuse *)NULL;
00786                 eu2->vu_p = vu;
00787                 vu->up.eu_p = eu2;
00788         } else {
00789                 eu2->vu_p = nmg_mvvu(&eu2->l.magic, m);
00790         }
00791 
00792         /* This if statment dies when no vertex stealing */
00793         if( s->vu_p )  {
00794                 /* Ensure shell no longer has any stored vertexuse */
00795                 (void)nmg_kvu( s->vu_p );
00796                 s->vu_p = (struct vertexuse *)NULL;
00797         }
00798 
00799         /* shell's eu_head, eu1, eu2, ... */
00800         BU_LIST_APPEND( &s->eu_hd, &eu1->l );
00801         BU_LIST_APPEND( &eu1->l, &eu2->l );
00802 
00803         if (rt_g.NMG_debug & DEBUG_BASIC)  {
00804                 bu_log("nmg_me(v1=x%x, v2=x%x, s=x%x) returns eu=x%x\n" , v1 , v2 , s , eu1 );
00805         }
00806 
00807         return(eu1);
00808 }
00809 
00810 /**
00811  *                      N M G _ M E o n V U
00812  *
00813  *  Make an edge on vertexuse.
00814  *  The new edge runs from and to that vertex.
00815  *
00816  *  If the vertexuse was the shell's sole vertexuse, then the new edge
00817  *  is a wire edge in the shell's eu_hd list.
00818  *
00819  *  If the vertexuse was part of a loop-of-a-single-vertex, either
00820  *  as a loop in a face or as a wire-loop in the shell, the
00821  *  loop becomes a regular loop with one edge that runs from and to
00822  *  the original vertex.
00823  */
00824 struct edgeuse *
00825 nmg_meonvu(struct vertexuse *vu)
00826 {
00827         struct edge *e;
00828         struct edgeuse *eu1, *eu2;
00829         struct model    *m;
00830 
00831         NMG_CK_VERTEXUSE(vu);
00832 
00833         m = nmg_find_model( vu->up.magic_p );
00834         GET_EDGE(e, m);
00835         GET_EDGEUSE(eu1, m);
00836         GET_EDGEUSE(eu2, m);
00837 
00838         BU_LIST_INIT( &eu1->l2 );
00839         BU_LIST_INIT( &eu2->l2 );
00840         eu1->l2.magic = eu2->l2.magic = NMG_EDGEUSE2_MAGIC;
00841 
00842         e->eu_p = eu1;
00843         e->is_real = 0;
00844         e->magic = NMG_EDGE_MAGIC;
00845 
00846         eu1->radial_p = eu1->eumate_p = eu2;
00847         eu2->radial_p = eu2->eumate_p = eu1;
00848         eu1->e_p = eu2->e_p = e;
00849         eu1->orientation = eu2->orientation = OT_NONE;
00850         /* XXX Why not OT_UNSPEC? */
00851         eu1->vu_p = vu;
00852         /* vu->up needs to be set but we can't do that until we recover */
00853         /* the shell or loopuse from the up pointer. */
00854 
00855         eu2->vu_p = (struct vertexuse *) NULL;
00856 
00857         /* link edgeuses to parent */
00858         if (*vu->up.magic_p == NMG_SHELL_MAGIC) {
00859                 struct shell    *s;
00860 
00861                 s = eu2->up.s_p = eu1->up.s_p = vu->up.s_p;
00862                 eu1->l.magic = eu2->l.magic =
00863                     NMG_EDGEUSE_MAGIC;  /* Edgeuse structs are GOOD */
00864                 /* eu2 is fake good till it has a real vu */
00865 
00866                 vu->up.eu_p = eu1;      /* vu is good again */
00867 
00868                 if( s->vu_p != vu )
00869                         rt_bomb("nmg_meonvu() vetexuse parent shell disowns vertexuse!\n");
00870                 s->vu_p = (struct vertexuse *)NULL;     /* remove from shell */
00871 
00872                 eu2->vu_p = nmg_mvu(vu->v_p, &eu2->l.magic, m);
00873                 BU_LIST_APPEND( &s->eu_hd, &eu2->l );
00874                 BU_LIST_APPEND( &s->eu_hd, &eu1->l );
00875         } else if (*vu->up.magic_p == NMG_LOOPUSE_MAGIC) {
00876                 struct loopuse          *lu;
00877                 struct loopuse          *lumate;
00878                 struct vertexuse        *vumate;
00879 
00880                 lu = vu->up.lu_p;
00881                 NMG_CK_LOOPUSE(lu);
00882                 lumate = lu->lumate_p;
00883                 NMG_CK_LOOPUSE(lumate);
00884 
00885                 /* do a little consistency checking */
00886                 if( lu == lumate )  rt_bomb("nmg_meonvu() lu mate is lu\n");
00887                 if( BU_LIST_FIRST_MAGIC(&lumate->down_hd) != NMG_VERTEXUSE_MAGIC )
00888                         rt_bomb("nmg_meonvu() mate of vertex-loop is not vertex-loop!\n");
00889                 vumate = BU_LIST_FIRST(vertexuse, &lumate->down_hd);
00890                 NMG_CK_VERTEXUSE(vumate);
00891                 if( vu == vumate )  rt_bomb("nmg_meonvu() vu mate is vu\n");
00892                 NMG_CK_VERTEX(vu->v_p);
00893                 NMG_CK_VERTEX(vumate->v_p);
00894 
00895                 /* edgeuses point at vertexuses */
00896                 eu2->vu_p = vumate;
00897 
00898                 /* edgeuses point at parent loopuses */
00899                 eu1->up.lu_p = lu;
00900                 eu2->up.lu_p = lumate;
00901 
00902                 eu1->l.magic = eu2->l.magic =
00903                     NMG_EDGEUSE_MAGIC;  /* Edgeuse structs are GOOD */
00904 
00905                 /* Fix forw & back pointers after "abuse", above */
00906                 /*
00907                  * The down_hd can be a POINTER to a vertexuse or
00908                  * the head of a linked list.  In this case we are
00909                  * changing from a pointer to a linked list so we
00910                  * initialize the linked list head then add the loopuses
00911                  * to that list.
00912                  */
00913                 BU_LIST_INIT( &lu->down_hd );
00914                 BU_LIST_INIT( &lumate->down_hd );
00915                 /* Add edgeuses to loopuses linked lists */
00916                 BU_LIST_APPEND( &lumate->down_hd, &eu2->l );
00917                 BU_LIST_APPEND( &lu->down_hd, &eu1->l );
00918 
00919                 /* vertexuses point up at edgeuses */
00920                 vu->up.eu_p = eu1;
00921                 vumate->up.eu_p = eu2;
00922         } else {
00923                 rt_bomb("nmg_meonvu() cannot make edge, vertexuse not sole element of object\n");
00924         }
00925 
00926         if (rt_g.NMG_debug & DEBUG_BASIC)  {
00927                 bu_log("nmg_meonvu(vu=x%x) returns eu=x%x\n" , vu , eu1 );
00928         }
00929 
00930         return(eu1);
00931 }
00932 
00933 /**                     N M G _ M L
00934  *
00935  *      Make wire loop from wire edgeuse list
00936  *
00937  *      Passed a pointer to a shell.  The wire edgeuse child of the shell
00938  *      is taken as the head of a list of edge(use)s which will form
00939  *      the new loop.  The loop is created from the first N contiguous
00940  *      edges.  Thus the end of the new loop is
00941  *      delineated by the "next" edge(use)being:
00942  *
00943  *      A) the first object in the list (no other edgeuses in
00944  *              shell list)
00945  *      B) non-contiguous with the previous edge
00946  *
00947  *      A loop is created from this list of edges.  The edges must
00948  *      form a true circuit, or we dump core on your disk.  If we
00949  *      succeed, then the edgeuses are moved from the shell edgeuse list
00950  *      to the loop, and the two loopuses are inserted into the shell.
00951  */
00952 struct loopuse *
00953 nmg_ml(struct shell *s)
00954 {
00955         struct loop *l;
00956         struct loopuse *lu1, *lu2;
00957         struct edgeuse  *p1;
00958         struct edgeuse  *p2;
00959         struct edgeuse  *feu;
00960         struct model    *m;
00961 
00962         NMG_CK_SHELL(s);
00963         /* If loop on single vertex */
00964         if( BU_LIST_IS_EMPTY( &s->eu_hd ) && s->vu_p )  {
00965                 NMG_CK_VERTEXUSE(s->vu_p);
00966                 NMG_CK_VERTEX(s->vu_p->v_p);
00967                 lu1 = nmg_mlv(&s->l.magic, s->vu_p->v_p, OT_UNSPEC);
00968                 /* (void) nmg_kvu(s->vu_p); */
00969 
00970                 if (rt_g.NMG_debug & DEBUG_BASIC)  {
00971                         bu_log("nmg_ml(s=x%x) returns lu of single vertex=x%x\n" , s , lu1 );
00972                 }
00973 
00974                 return lu1;
00975         }
00976 
00977         m = nmg_find_model( &s->l.magic );
00978         GET_LOOP(l, m);
00979         GET_LOOPUSE(lu1, m);
00980         GET_LOOPUSE(lu2, m);
00981 
00982         l->lg_p = (struct loop_g *)NULL;
00983         l->lu_p = lu1;
00984         l->magic = NMG_LOOP_MAGIC;      /* loop struct is GOOD */
00985 
00986         BU_LIST_INIT( &lu1->down_hd );
00987         BU_LIST_INIT( &lu2->down_hd );
00988         lu1->l_p = lu2->l_p = l;
00989         lu1->orientation = lu2->orientation = OT_UNSPEC;
00990         lu1->lumate_p = lu2;
00991         lu2->lumate_p = lu1;
00992         lu1->up.s_p = lu2->up.s_p = s;
00993         lu1->l.magic = lu2->l.magic =
00994             NMG_LOOPUSE_MAGIC;  /* Loopuse structs are GOOD */
00995 
00996         /* Save the first edgeuse so we can tell if the loop closes */
00997         feu = BU_LIST_FIRST( edgeuse, &s->eu_hd );
00998         if (feu){
00999                 NMG_CK_EDGEUSE(feu);
01000                 NMG_CK_VERTEXUSE(feu->vu_p);
01001                 NMG_CK_VERTEX(feu->vu_p->v_p);
01002         }
01003 
01004         /* Safety catch in case eu_hd is empty */
01005         p2 = (struct edgeuse *)NULL;
01006         while( BU_LIST_NON_EMPTY( &s->eu_hd ) )  {
01007                 p1 = BU_LIST_FIRST( edgeuse, &s->eu_hd );
01008                 NMG_CK_EDGEUSE(p1);
01009                 p2 = p1->eumate_p;
01010                 NMG_CK_EDGEUSE(p2);
01011 
01012                 /* bogosity check */
01013                 if (p1->up.s_p != s || p2->up.s_p != s)
01014                         rt_bomb("nmg_ml() edgeuse mates don't have proper parent!\n");
01015 
01016                 /* dequeue the first edgeuse */
01017                 BU_LIST_DEQUEUE( &p1->l );
01018                 if( BU_LIST_IS_EMPTY( &s->eu_hd ) )  {
01019                         bu_log("nmg_ml() in %s at %d edgeuse mate not in this shell\n",
01020                             __FILE__, __LINE__);
01021                         rt_bomb("nmg_ml\n");
01022                 }
01023 
01024                 /* dequeue the edgeuse's mate */
01025                 BU_LIST_DEQUEUE( &p2->l );
01026 
01027                 /*  Insert the next new edgeuse(s) at tail of the loop's list
01028                  *  (ie, insert just before the head).
01029                  *  head, .....,p2, p1, (tail)
01030                  */
01031                 BU_LIST_INSERT( &lu1->down_hd, &p1->l );
01032                 BU_LIST_INSERT( &lu2->down_hd, &p2->l );
01033 
01034                 p1->up.lu_p = lu1;
01035                 p2->up.lu_p = lu2;
01036 
01037                 /* If p2's vertex does not match next one comming, quit */
01038                 if( BU_LIST_IS_EMPTY( &s->eu_hd ) )  break;
01039                 p1 = BU_LIST_FIRST( edgeuse, &s->eu_hd );
01040                 NMG_CK_EDGEUSE(p1);
01041                 NMG_CK_VERTEXUSE(p1->vu_p);
01042                 NMG_CK_VERTEX(p1->vu_p->v_p);
01043                 NMG_CK_VERTEXUSE(p2->vu_p);
01044                 NMG_CK_VERTEX(p2->vu_p->v_p);
01045                 if( p1->vu_p->v_p != p2->vu_p->v_p )  {
01046                         break;
01047                 }
01048         }
01049 
01050         if (p2) {
01051                 NMG_CK_EDGEUSE(p2);
01052                 NMG_CK_VERTEXUSE(p2->vu_p);
01053                 NMG_CK_VERTEX(p2->vu_p->v_p);
01054         }
01055         if( p2 && p2->vu_p->v_p != feu->vu_p->v_p) {
01056                 bu_log("nmg_ml() Edge(use)s do not form proper loop!\n");
01057                 nmg_pr_s(s, (char *)NULL);
01058                 bu_log("nmg_ml() Edge(use)s do not form proper loop!\n");
01059                 rt_bomb("nmg_ml\n");
01060         }
01061 
01062         /* Head, lu1, lu2, ... */
01063         BU_LIST_APPEND( &s->lu_hd, &lu2->l );
01064         BU_LIST_APPEND( &s->lu_hd, &lu1->l );
01065 
01066         if (rt_g.NMG_debug & DEBUG_BASIC)  {
01067                 bu_log("nmg_ml(s=x%x) returns lu=x%x\n" , s , lu1 );
01068         }
01069 
01070         return(lu1);
01071 }
01072 
01073 /************************************************************************
01074  *                                                                      *
01075  *                              "Kill" Routines                         *
01076  *                                                                      *
01077  *  These subroutines delete (kill) a topological entity,               *
01078  *  eliminating any related subordinate entities where appropriate.     *
01079  *                                                                      *
01080  *  If the superior entity becomes empty as a result of a "kill"        *
01081  *  operation, and that superior entity isn't allowed to *be* empty,    *
01082  *  then a TRUE (1) return code is given, indicating that the           *
01083  *  caller needs to immediately delete the superior entity before       *
01084  *  performing any other NMG operations.                                *
01085  *                                                                      *
01086  *  During this interval, the superior entity is in an "illegal"        *
01087  *  state that the verify routines (nmg_vshell, etc.) and subsequent    *
01088  *  NMG processing routines will not accept, so that code which fails   *
01089  *  to honor the return codes will "blow up" downstream.                *
01090  *  Unfortunately, in some cases the problem won't be detected for      *
01091  *  quite a while, but this is better than having subsequent code       *
01092  *  encountering entities that *look* valid, but shouldn't be.          *
01093  *                                                                      *
01094  ************************************************************************/
01095 
01096 /**                     N M G _ K V U
01097  *
01098  *      Kill vertexuse, and null out parent's vu_p.
01099  *
01100  *  This routine is not intented for general use by applications,
01101  *  because it requires cooperation on the part of the caller
01102  *  to properly dispose of or fix the now *quite* illegal parent.
01103  *  (Illegal because the parent's vu_p is NULL).
01104  *  It exists primarily as a support routine for "mopping up" after
01105  *  nmg_klu(), nmg_keu(), nmg_ks(), and nmg_mv_vu_between_shells().
01106  *
01107  *  It is also used in a particularly ugly way in
01108  *  nmg_cut_loop() and nmg_split_lu_at_vu()
01109  *  as part of their method for obtaining an "empty" loopuse/loop set.
01110  *
01111  *  It is worth noting that all these callers ignore the return code,
01112  *  because they *all* exist to intentionally empty out the parent, but
01113  *  the return code is provided anyway, in the name of [CTJ] symmetry.
01114  *
01115  *  Returns -
01116  *      0       If all is well in the parent
01117  *      1       If parent is empty, and is thus "illegal"
01118  */
01119 int
01120 nmg_kvu(register struct vertexuse *vu)
01121 {
01122         struct vertex   *v;
01123         int             ret = 0;
01124 
01125         NMG_CK_VERTEXUSE(vu);
01126 
01127         if (vu->a.magic_p)  {
01128                 NMG_CK_VERTEXUSE_A_EITHER(vu->a.magic_p);
01129                 switch(*vu->a.magic_p)  {
01130                 case NMG_VERTEXUSE_A_PLANE_MAGIC:
01131                         FREE_VERTEXUSE_A_PLANE(vu->a.plane_p);
01132                         break;
01133                 case NMG_VERTEXUSE_A_CNURB_MAGIC:
01134                         FREE_VERTEXUSE_A_CNURB(vu->a.cnurb_p);
01135                         break;
01136                 }
01137         }
01138 
01139         v = vu->v_p;
01140         NMG_CK_VERTEX(v);
01141 
01142         BU_LIST_DEQUEUE( &vu->l );
01143         if( BU_LIST_IS_EMPTY( &v->vu_hd ) )  {
01144                 /* last vertexuse on vertex */
01145                 if (v->vg_p) FREE_VERTEX_G(v->vg_p);
01146                 FREE_VERTEX(v);
01147         }
01148 
01149         /* erase existence of this vertexuse from parent */
01150         if (vu->up.magic_p != (long *)NULL) {
01151             if (*vu->up.magic_p == NMG_SHELL_MAGIC)  {
01152                 if (vu->up.s_p) {
01153                     vu->up.s_p->vu_p = (struct vertexuse *)NULL;
01154                     ret = nmg_shell_is_empty(vu->up.s_p);
01155                 }
01156             } else if (*vu->up.magic_p == NMG_LOOPUSE_MAGIC) {
01157                 if (vu->up.lu_p) {
01158                     /* Reset the hack */
01159                     BU_LIST_INIT( &vu->up.lu_p->down_hd );
01160                     ret = 1;
01161                 }
01162             } else if (*vu->up.magic_p == NMG_EDGEUSE_MAGIC)  {
01163                 if (vu->up.eu_p) {
01164                     vu->up.eu_p->vu_p = (struct vertexuse *)NULL;
01165                     ret = 1;
01166                 }
01167             } else
01168                 rt_bomb("nmg_kvu() killing vertexuse of unknown parent?\n");
01169         }
01170 
01171         FREE_VERTEXUSE(vu);
01172         if (rt_g.NMG_debug & DEBUG_BASIC)  {
01173                 bu_log("nmg_kvu(vu=x%x) ret=%d\n", vu, ret);
01174         }
01175         return ret;
01176 }
01177 
01178 
01179 /**
01180  *                      N M G _ K F G
01181  *
01182  *  Internal routine to release face geometry when no more faces use it.
01183  */
01184 static void
01185 nmg_kfg(long int *magic_p)
01186 {
01187         switch( *magic_p ) {
01188         case NMG_FACE_G_PLANE_MAGIC:
01189                 /* If face_g is not referred to by any other face, free it */
01190                 {
01191                         struct face_g_plane     *pp;
01192                         pp = (struct face_g_plane *)magic_p;
01193                         if( BU_LIST_NON_EMPTY( &(pp->f_hd) ) )  return;
01194                         FREE_FACE_G_PLANE(pp);
01195                 }
01196                 break;
01197         case NMG_FACE_G_SNURB_MAGIC:
01198                 /* If face_g is not referred to by any other face, free it */
01199                 {
01200                         struct face_g_snurb *sp;
01201                         sp = (struct face_g_snurb *)magic_p;
01202                         if( BU_LIST_NON_EMPTY( &(sp->f_hd) ) )  return;
01203                         bu_free( (char *)sp->u.knots, "nmg_kfg snurb u knots[]");
01204                         bu_free( (char *)sp->v.knots, "nmg_kfg snurb v knots[]");
01205                         bu_free( (char *)sp->ctl_points, "nmg_kfg snurb ctl_points[]");
01206                         FREE_FACE_G_SNURB(sp);
01207                 }
01208                 break;
01209         default:
01210                 rt_bomb("nmg_kfg() bad magic\n");
01211         }
01212 }
01213 
01214 /**                     N M G _ K F U
01215  *
01216  *      Kill Faceuse
01217  *
01218  *      delete a faceuse and its mate from the parent shell.
01219  *      Any children found are brutally murdered as well.
01220  *      The faceuses are dequeued from the parent shell's list here.
01221  *
01222  *  Returns -
01223  *      0       If all is well
01224  *      1       If parent shell is now empty, and is thus "illegal"
01225  */
01226 int
01227 nmg_kfu(struct faceuse *fu1)
01228 {
01229         struct faceuse *fu2;
01230         struct face     *f1;
01231         struct face     *f2;
01232         struct shell    *s;
01233         int             ret;
01234 
01235         NMG_CK_FACEUSE(fu1);
01236         fu2 = fu1->fumate_p;
01237         NMG_CK_FACEUSE(fu2);
01238         f1 = fu1->f_p;
01239         f2 = fu2->f_p;
01240         NMG_CK_FACE(f1);
01241         NMG_CK_FACE(f2);
01242         if( f1 != f2 )
01243                 rt_bomb("nmg_kfu() faceuse mates do not share face!\n");
01244         s = fu1->s_p;
01245         NMG_CK_SHELL(s);
01246 
01247         /* kill off the children (infanticide?)*/
01248         while( BU_LIST_NON_EMPTY( &fu1->lu_hd ) )  {
01249                 (void)nmg_klu( BU_LIST_FIRST( loopuse, &fu1->lu_hd ) );
01250         }
01251 
01252         /* Release the face geometry */
01253         if (f1->g.magic_p) {
01254                 /* Disassociate this face from face_g */
01255                 BU_LIST_DEQUEUE( &f1->l );
01256                 nmg_kfg( f1->g.magic_p );
01257         }
01258         FREE_FACE(f1);
01259         fu1->f_p = fu2->f_p = (struct face *)NULL;
01260 
01261         /* remove ourselves from the parent list */
01262         BU_LIST_DEQUEUE( &fu1->l );
01263         if( BU_LIST_IS_EMPTY( &s->fu_hd ) )
01264                 rt_bomb("nmg_kfu() faceuse mate not in parent shell?\n");
01265         BU_LIST_DEQUEUE( &fu2->l );
01266 
01267         FREE_FACEUSE(fu1);
01268         FREE_FACEUSE(fu2);
01269         ret = nmg_shell_is_empty(s);
01270         if (rt_g.NMG_debug & DEBUG_BASIC)  {
01271                 bu_log("nmg_kfu(fu1=x%x) fu2=x%x ret=%d\n", fu1, fu2, ret);
01272         }
01273         return ret;
01274 }
01275 
01276 /**                     N M G _ K L U
01277  *
01278  *      Kill loopuse, loopuse mate, and loop.
01279  *
01280  *      if the loop contains any edgeuses or vertexuses they are killed
01281  *      before the loop is deleted.
01282  *
01283  *      We support the concept of killing a loop with no children to
01284  *      support the routine "nmg_demote_lu"
01285  *
01286  *  Returns -
01287  *      0       If all is well
01288  *      1       If parent is empty, and is thus "illegal"
01289  */
01290 int
01291 nmg_klu(struct loopuse *lu1)
01292 {
01293         struct loopuse *lu2;
01294         long    magic1;
01295         int     ret = 0;
01296 
01297         NMG_CK_LOOPUSE(lu1);
01298         lu2 = lu1->lumate_p;
01299         NMG_CK_LOOPUSE(lu2);
01300 
01301         if (lu1->l_p != lu2->l_p)
01302                 rt_bomb("nmg_klu() loopmates do not share loop!\n");
01303 
01304         if (*lu1->up.magic_p != *lu2->up.magic_p)
01305                 rt_bomb("nmg_klu() loopuses do not have same type of parent!\n");
01306 
01307         /* deal with the children */
01308         magic1 = BU_LIST_FIRST_MAGIC( &lu1->down_hd );
01309         if( magic1 != BU_LIST_FIRST_MAGIC( &lu2->down_hd ) )
01310                 rt_bomb("nmg_klu() loopuses do not have same type of child!\n");
01311 
01312         if( magic1 == NMG_VERTEXUSE_MAGIC )  {
01313                 /* Follow the vertex-loop hack downward,
01314                  * nmg_kvu() will clean up */
01315                 (void)nmg_kvu( BU_LIST_FIRST(vertexuse, &lu1->down_hd) );
01316                 (void)nmg_kvu( BU_LIST_FIRST(vertexuse, &lu2->down_hd) );
01317         } else if ( magic1 == NMG_EDGEUSE_MAGIC) {
01318                 /* delete all edgeuse in the loopuse (&mate) */
01319                 while( BU_LIST_NON_EMPTY( &lu1->down_hd ) )  {
01320                         (void)nmg_keu(BU_LIST_FIRST(edgeuse, &lu1->down_hd) );
01321                 }
01322         } else if ( magic1 == BU_LIST_HEAD_MAGIC )  {
01323                 /* down_hd list is empty, no problem */
01324         } else {
01325                 bu_log("nmg_klu(x%x) magic=%s\n", lu1, bu_identify_magic(magic1) );
01326                 rt_bomb("nmg_klu: unknown type for loopuse child\n");
01327         }
01328 
01329         /* disconnect from parent's list */
01330         if (*lu1->up.magic_p == NMG_SHELL_MAGIC) {
01331                 BU_LIST_DEQUEUE( &lu1->l );
01332                 BU_LIST_DEQUEUE( &lu2->l );
01333                 ret = nmg_shell_is_empty( lu1->up.s_p );
01334         } else if (*lu1->up.magic_p == NMG_FACEUSE_MAGIC) {
01335                 BU_LIST_DEQUEUE( &lu1->l );
01336                 BU_LIST_DEQUEUE( &lu2->l );
01337                 ret = BU_LIST_IS_EMPTY( &lu1->up.fu_p->lu_hd );
01338         } else {
01339                 rt_bomb("nmg_klu() unknown parent for loopuse\n");
01340         }
01341 
01342         NMG_CK_LOOP(lu1->l_p);
01343         if (lu1->l_p->lg_p) {
01344                 NMG_CK_LOOP_G(lu1->l_p->lg_p);
01345                 FREE_LOOP_G(lu1->l_p->lg_p);
01346         }
01347         FREE_LOOP(lu1->l_p);
01348         FREE_LOOPUSE(lu1);
01349         FREE_LOOPUSE(lu2);
01350         if (rt_g.NMG_debug & DEBUG_BASIC)  {
01351                 bu_log("nmg_klu(lu1=x%x) lu2=x%x ret=%d\n", lu1, lu2, ret);
01352         }
01353         return ret;
01354 }
01355 
01356 /**
01357  *                      N M G _ K E G
01358  *
01359  *  Internal routine to kill an edge geometry structure (of either type),
01360  *  if all the edgeuses on it's list have vanished.
01361  *  Regardless, the edgeuse's geometry pointer is cleared.
01362  *
01363  *  This routine does only a single edgeuse.
01364  *  If the edgeuse mate has geometry to be killed, make a second call.
01365  *  Sometimes only one of the two needs to release the geometry.
01366  *
01367  *  Returns -
01368  *      0       If the old edge geometry (eu->g.magic_p) has other uses.
01369  *      1       If the old edge geometry has been destroyed. Caller beware!
01370  *
01371  *  NOT INTENDED FOR GENERAL USE!
01372  *  However, nmg_mod.c needs it for nmg_eusplit().  (Drat!)
01373  */
01374 /**static**/ int
01375 nmg_keg(struct edgeuse *eu)
01376 {
01377         NMG_CK_EDGEUSE(eu);
01378 
01379         if( !eu->g.magic_p )  return 0; /* ??? what to return here */
01380 
01381         switch( *eu->g.magic_p )  {
01382         case NMG_EDGE_G_LSEG_MAGIC:
01383                 {
01384                         struct edge_g_lseg      *lp;
01385                         lp = eu->g.lseg_p;
01386                         eu->g.magic_p = (long *)NULL;
01387                         if( BU_LIST_NON_EMPTY( &lp->eu_hd2 ) )  return 0;
01388                         FREE_EDGE_G_LSEG(lp);
01389                 }
01390                 break;
01391         case NMG_EDGE_G_CNURB_MAGIC:
01392                 {
01393                         struct edge_g_cnurb     *eg;
01394                         eg = eu->g.cnurb_p;
01395                         eu->g.magic_p = (long *)NULL;
01396                         if( BU_LIST_NON_EMPTY( &eg->eu_hd2 ) )  return 0;
01397                         if( eg->order != 0 )  {
01398                                 bu_free( (char *)eg->k.knots, "nmg_keg cnurb knots[]");
01399                                 bu_free( (char *)eg->ctl_points, "nmg_keg cnurb ctl_points[]");
01400                         }
01401                         FREE_EDGE_G_CNURB(eg);
01402                 }
01403                 break;
01404         }
01405         return 1;               /* edge geometry has been destroyed */
01406 }
01407 
01408 /*
01409  *                      N M G _ K E U
01410  *
01411  *      Delete an edgeuse & it's mate from a shell or loop.
01412  *
01413  *  Returns -
01414  *      0       If all is well
01415  *      1       If the parent now has no edgeuses, and is thus "illegal"
01416  *              and in need of being deleted.  (The lu / shell deletion
01417  *              can't be handled at this level, but must be done by the caller).
01418  */
01419 int
01420 nmg_keu(register struct edgeuse *eu1)
01421 {
01422         register struct edgeuse *eu2;
01423         struct edge             *e;
01424         int                     ret = 0;
01425 
01426         NMG_CK_EDGEUSE(eu1);
01427         e = eu1->e_p;
01428         NMG_CK_EDGE(e);
01429 
01430         eu2 = eu1->eumate_p;
01431         NMG_CK_EDGEUSE(eu2);
01432         NMG_CK_EDGE(eu2->e_p);
01433 
01434         if (e != eu2->e_p) {
01435                 rt_bomb("nmg_keu() edgeuse pair does not share edge\n");
01436         }
01437 
01438         /* unlink from radial linkages (if any) */
01439         if (eu1->radial_p != eu2) {
01440                 NMG_CK_EDGEUSE(eu1->radial_p);
01441                 NMG_CK_EDGEUSE(eu2->radial_p);
01442 
01443                 eu1->radial_p->radial_p = eu2->radial_p;
01444                 eu2->radial_p->radial_p = eu1->radial_p;
01445 
01446                 NMG_CK_EDGEUSE(eu1->radial_p);
01447                 NMG_CK_EDGEUSE(eu2->radial_p);
01448 
01449                 /* since there is a use of this edge left, make sure the edge
01450                  * structure points to a remaining edgeuse
01451                  */
01452                 if (e->eu_p == eu1 || e->eu_p == eu2)
01453                         e->eu_p = eu1->radial_p;
01454                 NMG_CK_EDGEUSE( e->eu_p );
01455         } else {
01456                 /* since these two edgeuses are the only use of this edge,
01457                  * we need to free the edge (since all uses are about
01458                  * to disappear).
01459                  */
01460                 FREE_EDGE(e);
01461                 e = (struct edge *)NULL;
01462                 eu1->e_p = e;   /* sanity */
01463                 eu2->e_p = e;
01464         }
01465 
01466         /* handle geometry, if any */
01467         if( eu1->g.magic_p )
01468         {
01469                 /* Dequeue edgeuse from geometry's list of users */
01470                 BU_LIST_DEQUEUE( &eu1->l2 );
01471 
01472                 /* Release the edgeuse's geometry pointer */
01473                 nmg_keg( eu1 );
01474         }
01475 
01476         if( eu2->g.magic_p )
01477         {
01478                 /* Dequeue edgeuse from geometry's list of users */
01479                 BU_LIST_DEQUEUE( &eu2->l2 );
01480 
01481                 /* Release the edgeuse's geometry pointer */
01482                 nmg_keg( eu2 );
01483         }
01484 
01485         /* remove the edgeuses from their parents */
01486         if (*eu1->up.magic_p == NMG_LOOPUSE_MAGIC) {
01487                 struct loopuse  *lu1, *lu2;
01488                 lu1 = eu1->up.lu_p;
01489                 lu2 = eu2->up.lu_p;
01490                 NMG_CK_LOOPUSE(lu1);
01491                 NMG_CK_LOOPUSE(lu2);
01492 
01493                 if( lu1 == lu2 )  rt_bomb("nmg_keu() edgeuses on same loopuse\n");
01494                 if (lu1->lumate_p != lu2 || lu1 != lu2->lumate_p ) {
01495                         bu_log("nmg_keu() lu1=x%x, mate=x%x\n", lu1, lu1->lumate_p);
01496                         bu_log("nmg_keu() lu2=x%x, mate=x%x\n", lu2, lu2->lumate_p);
01497                         rt_bomb("nmg_keu() edgeuse mates don't belong to loopuse mates\n");
01498                 }
01499 
01500                 /* remove the edgeuses from their parents */
01501                 BU_LIST_DEQUEUE( &eu1->l );
01502                 BU_LIST_DEQUEUE( &eu2->l );
01503 
01504                 /* If loopuse list is empty, caller needs to delete it. */
01505                 if( BU_LIST_IS_EMPTY( &lu1->down_hd ) )  ret = 1;
01506         } else if (*eu1->up.magic_p == NMG_SHELL_MAGIC) {
01507                 if (eu1->up.s_p != eu2->up.s_p) {
01508                         rt_bomb("nmg_keu() edguses don't share parent shell\n");
01509                 }
01510 
01511                 /* unlink edgeuses from the parent shell */
01512                 BU_LIST_DEQUEUE( &eu1->l );
01513                 BU_LIST_DEQUEUE( &eu2->l );
01514                 ret = nmg_shell_is_empty( eu1->up.s_p );
01515         } else {
01516                 rt_bomb("nmg_keu() bad up pointer\n");
01517         }
01518 
01519         /* kill the vertexuses associated with these edgeuses */
01520         if (eu1->vu_p) {
01521                 (void)nmg_kvu(eu1->vu_p);
01522         }
01523         if (eu2->vu_p) {
01524                 (void)nmg_kvu(eu2->vu_p);
01525         }
01526 
01527         FREE_EDGEUSE(eu1);
01528         FREE_EDGEUSE(eu2);
01529 
01530         if( e )
01531         {
01532                 NMG_CK_EDGE( e );
01533                 NMG_CK_EDGEUSE( e->eu_p );
01534         }
01535 
01536         if (rt_g.NMG_debug & DEBUG_BASIC)  {
01537                 bu_log("nmg_keu(eu1=x%x) eu2=x%x ret=%d\n", eu1, eu2, ret);
01538         }
01539         return ret;
01540 }
01541 
01542 /**                     N M G _ K S
01543  *
01544  *      Kill a shell and all children
01545  *
01546  *  Returns -
01547  *      0       If all is well
01548  *      1       If parent nmgregion is now empty.  While not "illegal",
01549  *              an empty region is probably worthy of note.
01550  */
01551 int
01552 nmg_ks(struct shell *s)
01553 {
01554         struct nmgregion        *r;
01555 
01556         NMG_CK_SHELL(s);
01557         r = s->r_p;
01558         NMG_CK_REGION(r);
01559 
01560         while( BU_LIST_NON_EMPTY( &s->fu_hd ) )
01561                 (void)nmg_kfu( BU_LIST_FIRST(faceuse, &s->fu_hd) );
01562         while( BU_LIST_NON_EMPTY( &s->lu_hd ) )
01563                 (void)nmg_klu( BU_LIST_FIRST(loopuse, &s->lu_hd) );
01564         while( BU_LIST_NON_EMPTY( &s->eu_hd ) )
01565                 (void)nmg_keu( BU_LIST_FIRST(edgeuse, &s->eu_hd) );
01566         if( s->vu_p )
01567                 nmg_kvu( s->vu_p );
01568 
01569         BU_LIST_DEQUEUE( &s->l );
01570 
01571         if (s->sa_p) {
01572                 FREE_SHELL_A(s->sa_p);
01573         }
01574 
01575         FREE_SHELL(s);
01576         if (rt_g.NMG_debug & DEBUG_BASIC)  {
01577                 bu_log("nmg_ks(s=x%x)\n", s);
01578         }
01579         if( BU_LIST_IS_EMPTY( &r->s_hd ) )  return 1;
01580         return 0;
01581 }
01582 
01583 /**                     N M G _ K R
01584  *
01585  *      Kill a region and all shells in it
01586  *
01587  *  Returns -
01588  *      0       If all is well
01589  *      1       If model is now empty.  While not "illegal",
01590  *              an empty model is probably worthy of note.
01591  */
01592 int
01593 nmg_kr(struct nmgregion *r)
01594 {
01595         struct model    *m;
01596 
01597         NMG_CK_REGION(r);
01598         m = r->m_p;
01599         NMG_CK_MODEL(m);
01600 
01601         while( BU_LIST_NON_EMPTY( &r->s_hd ) )
01602                 (void)nmg_ks( BU_LIST_FIRST( shell, &r->s_hd ) );
01603 
01604         BU_LIST_DEQUEUE( &r->l );
01605 
01606         if (r->ra_p) {
01607                 FREE_REGION_A(r->ra_p);
01608         }
01609         FREE_REGION(r);
01610         if (rt_g.NMG_debug & DEBUG_BASIC)  {
01611                 bu_log("nmg_kr(r=x%x)\n", r);
01612         }
01613 
01614         if( BU_LIST_IS_EMPTY( &m->r_hd ) ) {
01615                 m->maxindex = 1;        /* Reset when last region is killed */
01616                 return 1;
01617         }
01618         return 0;
01619 }
01620 
01621 /**                     N M G _ K M
01622  *
01623  *      Kill an entire model.  Nothing is left.
01624  */
01625 void
01626 nmg_km(struct model *m)
01627 {
01628         NMG_CK_MODEL(m);
01629 
01630         while( BU_LIST_NON_EMPTY( &m->r_hd ) )
01631                 (void)nmg_kr( BU_LIST_FIRST( nmgregion, &m->r_hd ) );
01632 
01633         FREE_MODEL(m);
01634         if (rt_g.NMG_debug & DEBUG_BASIC)  {
01635                 bu_log("nmg_km(m=x%x)\n", m);
01636         }
01637 }
01638 
01639 /************************************************************************
01640  *                                                                      *
01641  *                      "Geometry" and "Attribute" Routines             *
01642  *                                                                      *
01643  ************************************************************************/
01644 
01645 /**                     N M G _ V E R T E X _ G V
01646  *
01647  *      Associate point_t ("vector") coordinates with a vertex
01648  */
01649 void
01650 nmg_vertex_gv(struct vertex *v, const fastf_t *pt)
01651 {
01652         struct vertex_g *vg;
01653         struct model    *m;
01654 
01655         NMG_CK_VERTEX(v);
01656 
01657         if ( (vg = v->vg_p) ) {
01658                 NMG_CK_VERTEX_G(v->vg_p);
01659         }
01660         else {
01661                 m = nmg_find_model(
01662                         &BU_LIST_NEXT(vertexuse, &v->vu_hd)->l.magic );
01663                 GET_VERTEX_G(vg, m);
01664 
01665                 vg->magic = NMG_VERTEX_G_MAGIC;
01666                 v->vg_p = vg;
01667         }
01668         VMOVE( vg->coord, pt );
01669 
01670         if (rt_g.NMG_debug & DEBUG_BASIC)  {
01671                 bu_log("nmg_vertex_gv(v=x%x, pt=(%g %g %g))\n", v , V3ARGS( pt ));
01672         }
01673 }
01674 
01675 /**
01676  *                      N M G _ V E R T E X _ G
01677  *
01678  *      a version that can take x, y, z coords and doesn't need a point
01679  *      array.  Mostly useful for quick and dirty programs.
01680  */
01681 void
01682 nmg_vertex_g(register struct vertex *v, fastf_t x, fastf_t y, fastf_t z)
01683 {
01684         point_t pt;
01685 
01686         pt[0] = x;
01687         pt[1] = y;
01688         pt[2] = z;
01689 
01690         if (rt_g.NMG_debug & DEBUG_BASIC)  {
01691                 bu_log("nmg_vertex_g(v=x%x, pt=(%g %g %g))\n", v , x , y , z );
01692         }
01693 
01694         nmg_vertex_gv(v, pt);
01695 }
01696 
01697 /**                     N M G _ V E R T E X U S E _ N V
01698  *
01699  *      Assign a normal vector to a vertexuse
01700  */
01701 void
01702 nmg_vertexuse_nv(struct vertexuse *vu, const fastf_t *norm)
01703 {
01704         struct model *m;
01705 
01706         NMG_CK_VERTEXUSE( vu );
01707 
01708         if( !vu->a.magic_p )  {
01709                 struct vertexuse_a_plane *vua;
01710                 m = nmg_find_model( &vu->l.magic );
01711                 GET_VERTEXUSE_A_PLANE( vua , m );
01712                 vua->magic = NMG_VERTEXUSE_A_PLANE_MAGIC;
01713                 vu->a.plane_p = vua;
01714         }  else if( *vu->a.magic_p == NMG_VERTEXUSE_A_CNURB_MAGIC )  {
01715                 /* Assigning a normal vector to a cnurb vua is illegal */
01716                 rt_bomb("nmg_vertexuse_nv() Illegal assignment of normal vector to edge_g_cnurb vertexuse\n");
01717         }  else  {
01718                 NMG_CK_VERTEXUSE_A_PLANE( vu->a.plane_p );
01719         }
01720 
01721         VMOVE( vu->a.plane_p->N , norm );
01722 
01723         if (rt_g.NMG_debug & DEBUG_BASIC)  {
01724                 bu_log("nmg_vertexuse_nv(vu=x%x, norm=(%g %g %g))\n", vu , V3ARGS( norm ));
01725         }
01726 }
01727 
01728 /**
01729  *                      N M G _ V E R T E X U S E _ A _ C N U R B
01730  *
01731  *  Given a vertex with associated geometry in model space
01732  *  which lies on a face_g_snurb surface, it will have
01733  *  a corresponding set of (u,v) or (u,v,w) parameters on that surface.
01734  *  Build the association here.
01735  *
01736  *  Note that all vertexuses of a single vertex which are all used
01737  *  by the same face_g_snurb will have the same "param" value, but
01738  *  will have individual vertexuse_a_cnurb structures.
01739  */
01740 void
01741 nmg_vertexuse_a_cnurb(struct vertexuse *vu, const fastf_t *uvw)
01742 {
01743         struct vertexuse_a_cnurb        *vua;
01744         struct model    *m;
01745 
01746         NMG_CK_VERTEXUSE( vu );
01747 
01748         if( vu->a.magic_p )  rt_bomb("nmg_vertexuse_a_cnurb() vu has attribute already\n");
01749         NMG_CK_EDGEUSE( vu->up.eu_p );
01750         if( vu->up.eu_p->g.magic_p) NMG_CK_EDGE_G_CNURB( vu->up.eu_p->g.cnurb_p );
01751 
01752         m = nmg_find_model( &vu->l.magic );
01753         GET_VERTEXUSE_A_CNURB( vua , m );
01754         VMOVE( vua->param, uvw );
01755         vua->magic = NMG_VERTEXUSE_A_CNURB_MAGIC;
01756 
01757         vu->a.cnurb_p = vua;
01758 
01759         if (rt_g.NMG_debug & DEBUG_BASIC)  {
01760                 bu_log("nmg_vertexuse_a_cnurb(vu=x%x, param=(%g %g %g)) vua=x%x\n",
01761                         vu , V3ARGS( uvw ), vua);
01762         }
01763 }
01764 
01765 /**
01766  *                      N M G _ E D G E _ G
01767  *
01768  *      Compute the equation of the line formed by the endpoints of the edge.
01769  *
01770  *  XXX This isn't the best name.  nmg_edge_g_lseg() ?
01771  */
01772 void
01773 nmg_edge_g(struct edgeuse *eu)
01774 {
01775         struct model *m;
01776         struct edge_g_lseg *eg_p = (struct edge_g_lseg *)NULL;
01777         struct edge     *e;
01778         struct edgeuse  *eu2;
01779         pointp_t        pt;
01780         int             found_eg=0;
01781 
01782         NMG_CK_EDGEUSE(eu);
01783         e = eu->e_p;
01784         NMG_CK_EDGE(e);
01785         NMG_CK_VERTEXUSE(eu->vu_p);
01786         NMG_CK_VERTEX(eu->vu_p->v_p);
01787         NMG_CK_VERTEX_G(eu->vu_p->v_p->vg_p);
01788 
01789         NMG_CK_EDGEUSE(eu->eumate_p);
01790         NMG_CK_VERTEXUSE(eu->eumate_p->vu_p);
01791         NMG_CK_VERTEX(eu->eumate_p->vu_p->v_p);
01792         NMG_CK_VERTEX_G(eu->eumate_p->vu_p->v_p->vg_p);
01793 
01794         if(eu->vu_p->v_p == eu->eumate_p->vu_p->v_p )
01795                 rt_bomb("nmg_edge_g(): Warning - edge runs from+to same vertex, 0 len!\n");
01796 
01797         if ( (eg_p = eu->g.lseg_p) ) {
01798                 NMG_CK_EDGE_G_LSEG(eg_p);
01799                 rt_bomb("nmg_edge_g() geometry already assigned\n");
01800         }
01801 
01802         /* Search all other uses of this edge for an existing edge_g_lseg */
01803         eu2 = eu->eumate_p->radial_p;
01804         while( eu2 != eu )  {
01805                 if( eu2->g.magic_p && *eu2->g.magic_p == NMG_EDGE_G_LSEG_MAGIC )  {
01806                         eg_p = eu2->g.lseg_p;
01807                         found_eg = 1;
01808                         break;
01809                 }
01810                 eu2 = eu2->eumate_p->radial_p;
01811         }
01812 
01813         if( !eg_p )  {
01814                 /* Make new edge_g structure */
01815                 m = nmg_find_model(&eu->l.magic);
01816                 GET_EDGE_G_LSEG(eg_p, m);
01817                 BU_LIST_INIT( &eg_p->eu_hd2 );
01818                 eg_p->l.magic = NMG_EDGE_G_LSEG_MAGIC;
01819 
01820                 /* copy the point from the vertex of one of our edgeuses */
01821                 pt = eu->vu_p->v_p->vg_p->coord;
01822                 VMOVE(eg_p->e_pt, pt);
01823 
01824                 /* compute the direction from the endpoints of the edgeuse(s) */
01825                 pt = eu->eumate_p->vu_p->v_p->vg_p->coord;
01826                 VSUB2(eg_p->e_dir, eg_p->e_pt, pt);
01827 
01828                 /* If the edge vector is essentially 0 magnitude we're in trouble.
01829                  * Warn the user and create an arbitrary vector we can use.
01830                  */
01831                 if (VNEAR_ZERO(eg_p->e_dir, SMALL_FASTF)) {
01832                         pointp_t pt2 = eu->vu_p->v_p->vg_p->coord;
01833                         VPRINT("nmg_edge_g(): e_dir too small", eg_p->e_dir);
01834                         bu_log("nmg_edge_g(): (%g %g %g) -> (%g %g %g)",
01835                                         pt[X],  pt[Y],  pt[Z],
01836                                         pt2[X], pt2[Y], pt2[Z]);
01837 
01838                         VSET(eg_p->e_dir, 1.0, 0.0, 0.0);
01839                         VPRINT("nmg_edge_g(): Forcing e_dir to", eg_p->e_dir);
01840                         rt_bomb("nmg_edge_g():  0 length edge\n");
01841                 }
01842         }
01843 
01844         /* Dequeue edgeuses from their current list (should point to themselves), add to new list */
01845         BU_LIST_DEQUEUE( &eu->l2 );
01846         BU_LIST_DEQUEUE( &eu->eumate_p->l2 );
01847 
01848         /* Associate edgeuse with this geometry */
01849         BU_LIST_INSERT( &eg_p->eu_hd2, &eu->l2 );
01850         BU_LIST_INSERT( &eg_p->eu_hd2, &eu->eumate_p->l2 );
01851         eu->g.lseg_p = eg_p;
01852         eu->eumate_p->g.lseg_p = eg_p;
01853 
01854         if( !found_eg )
01855         {
01856                 /* No uses of this edge have geometry, get them all */
01857                 eu2 = eu->eumate_p->radial_p;
01858                 while( eu2 != eu )
01859                 {
01860                         eu2->g.lseg_p = eg_p;
01861                         BU_LIST_INSERT( &eg_p->eu_hd2, &eu2->l2 );
01862                         eu2->eumate_p->g.lseg_p = eg_p;
01863                         BU_LIST_INSERT( &eg_p->eu_hd2, &eu2->eumate_p->l2 );
01864 
01865                         eu2 = eu2->eumate_p->radial_p;
01866                 }
01867         }
01868 
01869         if (rt_g.NMG_debug & DEBUG_BASIC)  {
01870                 bu_log("nmg_edge_g(eu=x%x) eg=x%x\n", eu, eg_p );
01871         }
01872 }
01873 
01874 /**
01875  *                      N M G _ E D G E _ G _ C N U R B
01876  *
01877  *  For an edgeuse associated with a face_g_snurb surface,
01878  *  create a spline curve in the parameter space of the snurb
01879  *  which describes the path from the start vertex to the end vertex.
01880  *
01881  *  The parameters of the end points are taken from the vertexuse attributes
01882  *  at either end of the edgeuse.
01883  */
01884 void
01885 nmg_edge_g_cnurb(struct edgeuse *eu, int order, int n_knots, fastf_t *kv, int n_pts, int pt_type, fastf_t *points)
01886 {
01887         struct model    *m;
01888         struct edge_g_cnurb *eg;
01889         struct edge     *e;
01890         struct faceuse  *fu;
01891 
01892         NMG_CK_EDGEUSE(eu);
01893         e = eu->e_p;
01894         NMG_CK_EDGE(e);
01895         NMG_CK_VERTEXUSE(eu->vu_p);
01896         NMG_CK_VERTEX(eu->vu_p->v_p);
01897         NMG_CK_VERTEX_G(eu->vu_p->v_p->vg_p);
01898 
01899         NMG_CK_EDGEUSE(eu->eumate_p);
01900         NMG_CK_VERTEXUSE(eu->eumate_p->vu_p);
01901         NMG_CK_VERTEX(eu->eumate_p->vu_p->v_p);
01902         NMG_CK_VERTEX_G(eu->eumate_p->vu_p->v_p->vg_p);
01903 
01904 #if 0
01905         if(eu->vu_p->v_p == eu->eumate_p->vu_p->v_p )
01906                 rt_bomb("nmg_edge_g_cnurb(): edge runs from+to same vertex, 0 len!\n");
01907 #endif
01908 
01909         if (eu->g.cnurb_p) {
01910                 rt_bomb("nmg_edge_g_cnurb() geometry already assigned\n");
01911         }
01912         fu = nmg_find_fu_of_eu(eu);
01913         NMG_CK_FACEUSE(fu);
01914         NMG_CK_FACE_G_SNURB( fu->f_p->g.snurb_p );
01915 
01916         /* Make new edge_g structure */
01917         m = nmg_find_model(&eu->l.magic);
01918         GET_EDGE_G_CNURB(eg, m);
01919         BU_LIST_INIT( &eg->eu_hd2 );
01920 
01921         eg->order = order;
01922         if( n_knots > 0 && kv )  {
01923                 eg->k.k_size = n_knots;
01924                 eg->k.knots = kv;
01925         } else {
01926                 /* Give a default curve, no interior knots */
01927                 rt_nurb_kvknot( &eg->k, order, 0.0, 1.0, n_knots - (2 * order), (struct resource *)NULL );
01928         }
01929 
01930         if( n_pts < 2 )  rt_bomb("nmg_edge_g_cnurb() n_pts < 2\n");
01931         eg->c_size = n_pts;
01932         eg->pt_type = pt_type;
01933         if( points )  {
01934                 eg->ctl_points = points;
01935         } else {
01936                 int     ncoord = RT_NURB_EXTRACT_COORDS(pt_type);
01937 
01938                 eg->ctl_points = (fastf_t *)bu_calloc(
01939                         ncoord * n_pts,
01940                         sizeof(fastf_t),
01941                         "cnurb ctl_points[]" );
01942 
01943                 /*
01944                  * As a courtesy, set first and last point to
01945                  * the PARAMETER values of the edge's vertices.
01946                  */
01947                 NMG_CK_VERTEXUSE_A_CNURB( eu->vu_p->a.cnurb_p );
01948                 NMG_CK_VERTEXUSE_A_CNURB( eu->eumate_p->vu_p->a.cnurb_p );
01949                 switch( ncoord )  {
01950                 case 4:
01951                         eg->ctl_points[3] = 1;
01952                         eg->ctl_points[ (n_pts-1)*ncoord + 3] = 1;
01953                         /* fall through... */
01954                 case 3:
01955                         VMOVE( eg->ctl_points, eu->vu_p->a.cnurb_p->param );
01956                         VMOVE( &eg->ctl_points[ (n_pts-1)*ncoord ],
01957                                 eu->eumate_p->vu_p->a.cnurb_p->param );
01958                         break;
01959                 case 2:
01960                         V2MOVE( eg->ctl_points, eu->vu_p->a.cnurb_p->param );
01961                         V2MOVE( &eg->ctl_points[ (n_pts-1)*ncoord ],
01962                                 eu->eumate_p->vu_p->a.cnurb_p->param );
01963                         break;
01964                 default:
01965                         rt_bomb("nmg_edge_g_cnurb() bad ncoord?\n");
01966                 }
01967         }
01968 
01969         /* Dequeue edgeuses from their current list (should point to themselves), add to new list */
01970         BU_LIST_DEQUEUE( &eu->l2 );
01971         BU_LIST_DEQUEUE( &eu->eumate_p->l2 );
01972 
01973         /* Associate edgeuse with this geometry */
01974         BU_LIST_INSERT( &eg->eu_hd2, &eu->l2 );
01975         BU_LIST_INSERT( &eg->eu_hd2, &eu->eumate_p->l2 );
01976         eu->g.cnurb_p = eg;
01977         eu->eumate_p->g.cnurb_p = eg;
01978 
01979         eg->l.magic = NMG_EDGE_G_CNURB_MAGIC;
01980 
01981         if (rt_g.NMG_debug & DEBUG_BASIC)  {
01982                 bu_log("nmg_edge_g_cnurb(eu=x%x, order=%d, n_knots=%d, kv=x%x, n_pts=%d, pt_type=x%x, points=x%x) eg=x%x\n",
01983                         eu, order, n_knots, eg->k.knots,
01984                         n_pts, pt_type, eg->ctl_points, eg );
01985         }
01986 }
01987 
01988 /**
01989  *                      N M G _ E D G E _ G _ C N U R B _ P L I N E A R
01990  *
01991  *  For an edgeuse associated with a face_g_snurb surface,
01992  *  create a spline "curve" in the parameter space of the snurb
01993  *  which describes a STRAIGHT LINE in parameter space
01994  *  from the u,v parameters of the start vertex to the end vertex.
01995  *
01996  *  The parameters of the end points are found in the vertexuse attributes
01997  *  at either end of the edgeuse, which should have already been established.
01998  *
01999  *  This is a special case of nmg_edge_g_cnurb(), and should be used when
02000  *  the path through parameter space is known to be a line segment.
02001  *  This permits the savings of a lot of memory, both in core and on disk,
02002  *  by eliminating a knot vector (typ. 64 bytes or more) and a
02003  *  ctl_point[] array (typ. 16 bytes or more).
02004  *
02005  *  This special condition is indicated by order == 0.  See nmg.h for details.
02006  */
02007 void
02008 nmg_edge_g_cnurb_plinear(struct edgeuse *eu)
02009 {
02010         struct model    *m;
02011         struct edge_g_cnurb *eg;
02012         struct edge     *e;
02013         struct faceuse  *fu;
02014 
02015         NMG_CK_EDGEUSE(eu);
02016         e = eu->e_p;
02017         NMG_CK_EDGE(e);
02018         NMG_CK_VERTEXUSE(eu->vu_p);
02019         NMG_CK_VERTEX(eu->vu_p->v_p);
02020         NMG_CK_VERTEX_G(eu->vu_p->v_p->vg_p);
02021 
02022         NMG_CK_EDGEUSE(eu->eumate_p);
02023         NMG_CK_VERTEXUSE(eu->eumate_p->vu_p);
02024         NMG_CK_VERTEX(eu->eumate_p->vu_p->v_p);
02025         NMG_CK_VERTEX_G(eu->eumate_p->vu_p->v_p->vg_p);
02026 
02027         NMG_CK_VERTEXUSE_A_CNURB( eu->vu_p->a.cnurb_p );
02028         NMG_CK_VERTEXUSE_A_CNURB( eu->eumate_p->vu_p->a.cnurb_p );
02029 
02030 #if 0
02031         if(eu->vu_p->v_p == eu->eumate_p->vu_p->v_p )
02032                 rt_bomb("nmg_edge_g_cnurb_plinear(): edge runs from+to same vertex, 0 len!\n");
02033 #endif
02034 
02035         if (eu->g.cnurb_p) {
02036                 rt_bomb("nmg_edge_g_cnurb_plinear() geometry already assigned\n");
02037         }
02038         fu = nmg_find_fu_of_eu(eu);
02039         NMG_CK_FACEUSE(fu);
02040         NMG_CK_FACE_G_SNURB( fu->f_p->g.snurb_p );
02041 
02042         /* Make new edge_g structure */
02043         m = nmg_find_model(&eu->l.magic);
02044         GET_EDGE_G_CNURB(eg, m);
02045         BU_LIST_INIT( &eg->eu_hd2 );
02046 
02047         eg->order = 0;          /* SPECIAL FLAG */
02048 
02049         /* Dequeue edgeuses from their current list (should point to themselves), add to new list */
02050         BU_LIST_DEQUEUE( &eu->l2 );
02051         BU_LIST_DEQUEUE( &eu->eumate_p->l2 );
02052 
02053         /* Associate edgeuse with this geometry */
02054         BU_LIST_INSERT( &eg->eu_hd2, &eu->l2 );
02055         BU_LIST_INSERT( &eg->eu_hd2, &eu->eumate_p->l2 );
02056         eu->g.cnurb_p = eg;
02057         eu->eumate_p->g.cnurb_p = eg;
02058 
02059         eg->l.magic = NMG_EDGE_G_CNURB_MAGIC;
02060 
02061         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02062                 bu_log("nmg_edge_g_cnurb_plinear(eu=x%x) order=0, eg=x%x\n",
02063                         eu, eg );
02064         }
02065 }
02066 
02067 /**
02068  *                      N M G _ U S E _ E D G E _ G
02069  *
02070  *  Associate edgeuse 'eu' with the edge_g_X structure given as 'magic_p'.
02071  *  If the edgeuse is already associated with some geometry, release
02072  *  that first.  Note that, to start with, the two edgeuses may be
02073  *  using different original geometries.
02074  *
02075  *  Also do the edgeuse mate.
02076  *
02077  *  Returns -
02078  *      0       If the old edge geometry (eu->g.magic_p) has other uses.
02079  *      1       If the old edge geometry has been destroyed. Caller beware!
02080  */
02081 int
02082 nmg_use_edge_g(struct edgeuse *eu, long int *magic_p)
02083 {
02084         struct edge_g_lseg      *old;
02085         /* eg->eu_hd2 is a pun for eu_hd2 in either _lseg or _cnurb */
02086         struct edge_g_lseg      *eg = (struct edge_g_lseg *)magic_p;
02087         int                     ndead = 0;
02088 
02089         if( !magic_p )  return 0;       /* Don't use a null new geom */
02090 
02091         NMG_CK_EDGEUSE(eu);
02092         NMG_CK_EDGE_G_LSEG(eg);
02093         if( eu == eu->eumate_p )  rt_bomb("nmg_use_edge_g() eu == eumate_p!\n");
02094 
02095         old = eu->g.lseg_p;     /* This may be NULL.  For printing only. */
02096 
02097         /* Sanity check */
02098         if( old && eg )  {
02099 #if 0
02100                 vect_t          dir_src;
02101                 vect_t          dir_dest;
02102                 fastf_t         deg;
02103                 double          cos_ang;
02104 
02105                 VMOVE( dir_src, old->e_dir );
02106                 VUNITIZE( dir_src );
02107                 VMOVE( dir_dest, eg->e_dir );
02108                 VUNITIZE( dir_dest );
02109                 cos_ang = fabs(VDOT( dir_src, dir_dest ));
02110                 if( cos_ang > 1.0 )
02111                         cos_ang = 1.0;
02112                 deg = acos( cos_ang ) * bn_radtodeg;
02113                 if( fabs(deg) > 2 )  {
02114                         VPRINT( "dir_src ", dir_src );
02115                         VPRINT( "dir_dest", dir_dest );
02116                         bu_log("nmg_use_edge_g() NOTICE Angle between old=x%x & new=x%x lines was %g deg.\n",
02117                                 old, eg, deg );
02118                         rt_bomb("nmg_use_edge_g() angle between old & new lines is excessive\n");
02119                 }
02120 #endif
02121         }
02122 
02123         /* Handle edgeuse */
02124         if( eu->g.lseg_p != eg && eu->g.lseg_p )  {
02125 
02126                 NMG_CK_EDGE_G_LSEG(eu->g.lseg_p);
02127 
02128                 BU_LIST_DEQUEUE( &eu->l2 );
02129                 ndead += nmg_keg( eu );
02130                 eu->g.magic_p = (long *)NULL;
02131         }
02132         if( eu->g.lseg_p != eg )  {
02133                 BU_LIST_INSERT( &eg->eu_hd2, &(eu->l2) );
02134                 eu->g.magic_p = magic_p;
02135         }
02136 
02137         /* Handle edgeuse mate separately */
02138         if( eu->eumate_p->g.lseg_p != eg && eu->eumate_p->g.lseg_p )  {
02139                 struct edgeuse  *mate = eu->eumate_p;
02140 
02141                 NMG_CK_EDGEUSE(mate);
02142                 NMG_CK_EDGE_G_LSEG(mate->g.lseg_p);
02143 
02144                 BU_LIST_DEQUEUE( &mate->l2 );
02145                 ndead += nmg_keg( mate );
02146                 mate->g.magic_p = (long *)NULL;
02147         }
02148 
02149         if( eu->eumate_p->g.lseg_p != eg )  {
02150                 BU_LIST_INSERT( &eg->eu_hd2, &(eu->eumate_p->l2) );
02151                 eu->eumate_p->g.magic_p = magic_p;
02152         }
02153         if( eu->g.magic_p != eu->eumate_p->g.magic_p )  rt_bomb("nmg_use_edge_g() eu and mate not using same geometry?\n");
02154 
02155         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02156                 bu_log("nmg_use_edge_g(eu=x%x, magic_p=x%x) old_eg=x%x, ret=%d\n",
02157                         eu, magic_p, old, ndead);
02158         }
02159         return ndead;
02160 }
02161 
02162 /**                     N M G _ L O O P _ G
02163  *
02164  *      Build the bounding box for a loop
02165  *      The bounding box is guaranteed never to have zero thickness.
02166  * XXX This really isn't loop geometry, this is a loop attribute.
02167  * XXX This routine really should be called nmg_loop_bb(), unless
02168  * XXX it gets something more to do.
02169  */
02170 void
02171 nmg_loop_g(struct loop *l, const struct bn_tol *tol)
02172 {
02173         struct edgeuse  *eu;
02174         struct vertex_g *vg;
02175         struct loop_g   *lg;
02176         struct loopuse  *lu;
02177         struct model    *m;
02178         long            magic1;
02179         FAST fastf_t    thickening;
02180 
02181         NMG_CK_LOOP(l);
02182         BN_CK_TOL(tol);
02183         lu = l->lu_p;
02184         NMG_CK_LOOPUSE(lu);
02185 
02186         if ( (lg = l->lg_p) ) {
02187                 NMG_CK_LOOP_G(lg);
02188         } else {
02189                 m = nmg_find_model( lu->up.magic_p );
02190                 GET_LOOP_G(l->lg_p, m);
02191                 lg = l->lg_p;
02192                 lg->magic = NMG_LOOP_G_MAGIC;
02193         }
02194         VSETALL( lg->max_pt, -INFINITY );
02195         VSETALL( lg->min_pt,  INFINITY );
02196 
02197         magic1 = BU_LIST_FIRST_MAGIC( &lu->down_hd );
02198         if (magic1 == NMG_EDGEUSE_MAGIC) {
02199                 for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )  {
02200                         vg = eu->vu_p->v_p->vg_p;
02201                         NMG_CK_VERTEX_G(vg);
02202                         VMINMAX(lg->min_pt, lg->max_pt, vg->coord);
02203                         if( !eu->g.magic_p && eu->vu_p->v_p != eu->eumate_p->vu_p->v_p )
02204                                 nmg_edge_g(eu);
02205                 }
02206         } else if (magic1 == NMG_VERTEXUSE_MAGIC) {
02207                 struct vertexuse        *vu;
02208                 vu = BU_LIST_FIRST(vertexuse, &lu->down_hd);
02209                 NMG_CK_VERTEXUSE(vu);
02210                 NMG_CK_VERTEX(vu->v_p);
02211                 vg = vu->v_p->vg_p;
02212                 NMG_CK_VERTEX_G(vg);
02213                 VMOVE(lg->min_pt, vg->coord);
02214                 VMOVE(lg->max_pt, vg->coord);
02215         } else {
02216                 bu_log("nmg_loop_g() loopuse down is %s (x%x)\n",
02217                         bu_identify_magic(magic1), magic1 );
02218                 rt_bomb("nmg_loop_g() loopuse has bad child\n");
02219         }
02220 
02221         /*
02222          *  For the case of an axis-aligned loop, ensure that a 0-thickness
02223          *  face is not missed, e.g. by rt_in_rpp(). Thicken the bounding
02224          *  RPP so that it is 10*dist_tol thicker than the MINMAX
02225          *  calculations above report.
02226          *  This ensures enough "surface area" on the thin side of the RPP
02227          *  that a ray won't miss it.
02228          */
02229         thickening = 5 * tol->dist;
02230         lg->min_pt[X] -= thickening;
02231         lg->min_pt[Y] -= thickening;
02232         lg->min_pt[Z] -= thickening;
02233         lg->max_pt[X] += thickening;
02234         lg->max_pt[Y] += thickening;
02235         lg->max_pt[Z] += thickening;
02236 
02237         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02238                 bu_log("nmg_loop_g(l=x%x, tol=x%x)\n", l , tol);
02239         }
02240 
02241 }
02242 
02243 /**                     N M G _ F A C E _ G
02244  *
02245  *      Assign plane equation to face.
02246  * XXX Should probably be called nmg_face_g_plane()
02247  *
02248  *  In the interest of modularity this no longer calls nmg_face_bb().
02249  */
02250 void
02251 nmg_face_g(struct faceuse *fu, const fastf_t *p)
02252 {
02253         int i;
02254         struct face_g_plane     *fg;
02255         struct face     *f;
02256         struct model    *m;
02257 
02258         NMG_CK_FACEUSE(fu);
02259         f = fu->f_p;
02260         NMG_CK_FACE(f);
02261 
02262         fu->orientation = OT_SAME;
02263         fu->fumate_p->orientation = OT_OPPOSITE;
02264 
02265         fg = f->g.plane_p;
02266         if (fg) {
02267                 /* Face already has face_g_plane associated with it */
02268                 NMG_CK_FACE_G_PLANE(fg);
02269         } else {
02270                 m = nmg_find_model( &fu->l.magic );
02271                 GET_FACE_G_PLANE(f->g.plane_p, m);
02272                 f->flip = 0;
02273                 fg = f->g.plane_p;
02274                 fg->magic = NMG_FACE_G_PLANE_MAGIC;
02275                 BU_LIST_INIT(&fg->f_hd);
02276                 BU_LIST_APPEND( &fg->f_hd, &f->l );
02277         }
02278 
02279         if( f->flip )  {
02280                 for (i=0 ; i < ELEMENTS_PER_PLANE ; i++)
02281                         fg->N[i] = -p[i];
02282         } else {
02283                 HMOVE( fg->N, p );
02284         }
02285 
02286         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02287                 bu_log("nmg_face_g(fu=x%x, p=(%g %g %g %g))\n", fu , V4ARGS( p ));
02288         }
02289 }
02290 
02291 
02292 /**             N M G _ F A C E _ N E W _ P L A N E
02293  *
02294  *      Assign plane equation to this face. If other faces use current
02295  *      geometry for this face, then make a new geometry for this face.
02296  */
02297 void
02298 nmg_face_new_g(struct faceuse *fu, const fastf_t *pl)
02299 {
02300         struct face *f;
02301         struct face *f_tmp;
02302         struct face_g_plane *fg;
02303         struct model *m;
02304         int use_count=0;
02305 
02306         NMG_CK_FACEUSE( fu );
02307         f = fu->f_p;
02308         NMG_CK_FACE( f );
02309         fg = f->g.plane_p;
02310 
02311         /* if this face has no geometry, just call nmg_face_g() */
02312         if( !fg )
02313         {
02314                 nmg_face_g( fu, pl );
02315                 return;
02316         }
02317 
02318         /* count uses of this face geometry */
02319         for( BU_LIST_FOR( f_tmp, face, &fg->f_hd ) )
02320                 use_count++;
02321 
02322         /* if this is the only use, just call nmg_face_g() */
02323         if( use_count < 2 )
02324         {
02325                 nmg_face_g( fu, pl );
02326                 return;
02327         }
02328 
02329         /* There is at least one other use of this face geometry */
02330 
02331         fu->orientation = OT_SAME;
02332         fu->fumate_p->orientation = OT_OPPOSITE;
02333 
02334         /* dequeue this face from fg's face list */
02335         BU_LIST_DEQUEUE( &f->l );
02336 
02337         /* get a new geometry sructure */
02338         m = nmg_find_model( &fu->l.magic );
02339         GET_FACE_G_PLANE(f->g.plane_p, m);
02340         f->flip = 0;
02341         fg = f->g.plane_p;
02342         fg->magic = NMG_FACE_G_PLANE_MAGIC;
02343         BU_LIST_INIT(&fg->f_hd);
02344         BU_LIST_APPEND( &fg->f_hd, &f->l );
02345 
02346         HMOVE( fg->N, pl );
02347 
02348         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02349                 bu_log("nmg_face_new_g(fu=x%x, pl=(%g %g %g %g))\n", fu , V4ARGS( pl ));
02350         }
02351 }
02352 
02353 /**
02354  *                      N M G _ F A C E _ G _ S N U R B
02355  *
02356  *  Create a new NURBS surface to be the geometry for an NMG face.
02357  *
02358  *  If either of the knot vector arrays or the ctl_points arrays are
02359  *  given as non-null, then simply swipe the caller's arrays.
02360  *  The caller must have allocated them with bu_malloc() or malloc().
02361  *  If the pointers are NULL, then the necessary storage is allocated here.
02362  *
02363  *  This is the NMG parallel to rt_nurb_new_snurb().
02364  */
02365 void
02366 nmg_face_g_snurb(struct faceuse *fu, int u_order, int v_order, int n_u_knots, int n_v_knots, fastf_t *ukv, fastf_t *vkv, int n_rows, int n_cols, int pt_type, fastf_t *mesh)
02367 {
02368         struct face_g_snurb     *fg;
02369         struct face     *f;
02370         struct model    *m;
02371 
02372         NMG_CK_FACEUSE(fu);
02373         f = fu->f_p;
02374         NMG_CK_FACE(f);
02375 
02376         fu->orientation = OT_SAME;
02377         fu->fumate_p->orientation = OT_OPPOSITE;
02378 
02379         fg = f->g.snurb_p;
02380         if (fg) {
02381                 /* Face already has geometry associated with it */
02382                 rt_bomb("nmg_face_g_snurb() face already has geometry\n");
02383         }
02384 
02385         m = nmg_find_model( &fu->l.magic );
02386         GET_FACE_G_SNURB(f->g.snurb_p, m);
02387         fg = f->g.snurb_p;
02388 
02389         fg->order[0] = u_order;
02390         fg->order[1] = v_order;
02391         fg->u.magic = NMG_KNOT_VECTOR_MAGIC;
02392         fg->v.magic = NMG_KNOT_VECTOR_MAGIC;
02393         fg->u.k_size = n_u_knots;
02394         fg->v.k_size = n_v_knots;
02395 
02396         if( ukv )  {
02397                 fg->u.knots = ukv;
02398         } else {
02399                 fg->u.knots = (fastf_t *)bu_calloc(
02400                         n_u_knots, sizeof(fastf_t), "u.knots[]" );
02401         }
02402         if( vkv )  {
02403                 fg->v.knots = vkv;
02404         } else {
02405                 fg->v.knots = (fastf_t *)bu_calloc(
02406                         n_v_knots, sizeof(fastf_t), "v.knots[]" );
02407         }
02408 
02409         fg->s_size[0] = n_rows;
02410         fg->s_size[1] = n_cols;
02411         fg->pt_type = pt_type;
02412 
02413         if( mesh )  {
02414                 fg->ctl_points = mesh;
02415         } else {
02416                 int     nwords;
02417                 nwords = n_rows * n_cols * RT_NURB_EXTRACT_COORDS(pt_type);
02418                 fg->ctl_points = (fastf_t *)bu_calloc(
02419                         nwords, sizeof(fastf_t), "snurb ctl_points[]" );
02420         }
02421 
02422         f->flip = 0;
02423         BU_LIST_INIT(&fg->f_hd);
02424         BU_LIST_APPEND( &fg->f_hd, &f->l );
02425         fg->l.magic = NMG_FACE_G_SNURB_MAGIC;
02426 
02427         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02428                 bu_log("nmg_face_g_snurb(fu=x%x, u_order=%d, v_order=%d, n_u_knots=%d, n_v_knots=%d, ukv=x%x, vkv=x%x, n_rows=%d, n_cols=%d, pt_type=x%x, mesh=x%x) fg=x%x\n",
02429                         fu, u_order, v_order, n_u_knots, n_v_knots,
02430                         fg->u.knots, fg->v.knots,
02431                         n_rows, n_cols, pt_type, fg->ctl_points, fg );
02432         }
02433 }
02434 
02435 /**                     N M G _ F A C E _ B B
02436  *
02437  *      Build the bounding box for a face
02438  *
02439  */
02440 void
02441 nmg_face_bb(struct face *f, const struct bn_tol *tol)
02442 {
02443         struct loopuse  *lu;
02444         struct faceuse  *fu;
02445 
02446         BN_CK_TOL(tol);
02447         NMG_CK_FACE(f);
02448         fu = f->fu_p;
02449         NMG_CK_FACEUSE(fu);
02450 
02451         f->max_pt[X] = f->max_pt[Y] = f->max_pt[Z] = -MAX_FASTF;
02452         f->min_pt[X] = f->min_pt[Y] = f->min_pt[Z] = MAX_FASTF;
02453 
02454         /* compute the extent of the face by looking at the extent of
02455          * each of the loop children.
02456          */
02457         for( BU_LIST_FOR( lu, loopuse, &fu->lu_hd ) )  {
02458                 nmg_loop_g(lu->l_p, tol);
02459 
02460                 if (lu->orientation != OT_BOOLPLACE) {
02461                         VMIN(f->min_pt, lu->l_p->lg_p->min_pt);
02462                         VMAX(f->max_pt, lu->l_p->lg_p->max_pt);
02463                 }
02464         }
02465 
02466         /* Note, calculating the bounding box for face_g_snurbs
02467          * from the extents of the the loop does not work
02468          * since the loops are most likely in parametric space
02469          * thus we need to calcualte the bounding box for the
02470          * face_g_snurb here instead.  There may be a more efficient
02471          * way, and one may need some time to take a good look at
02472          * this
02473          */
02474 
02475         if( *fu->f_p->g.magic_p == NMG_FACE_G_SNURB_MAGIC )
02476         {
02477                 rt_nurb_s_bound( fu->f_p->g.snurb_p, fu->f_p->g.snurb_p->min_pt,
02478                         fu->f_p->g.snurb_p->max_pt);
02479                 VMIN(f->min_pt, fu->f_p->g.snurb_p->min_pt );
02480                 VMAX(f->max_pt, fu->f_p->g.snurb_p->max_pt );
02481         }
02482 
02483         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02484                 bu_log("nmg_face_bb(f=x%x, tol=x%x)\n", f , tol);
02485         }
02486 }
02487 
02488 /**                     N M G _ S H E L L _ A
02489  *
02490  *      Build the bounding box for a shell
02491  *
02492  */
02493 void
02494 nmg_shell_a(struct shell *s, const struct bn_tol *tol)
02495 {
02496         struct shell_a *sa;
02497         struct vertex_g *vg;
02498         struct faceuse *fu;
02499         struct loopuse *lu;
02500         struct edgeuse *eu;
02501         struct model    *m;
02502 
02503         NMG_CK_SHELL(s);
02504         BN_CK_TOL(tol);
02505 
02506         if (s->sa_p) {
02507                 NMG_CK_SHELL_A(s->sa_p);
02508         } else {
02509                 m = nmg_find_model( &s->l.magic );
02510                 GET_SHELL_A(s->sa_p, m);
02511                 s->sa_p->magic = NMG_SHELL_A_MAGIC;
02512         }
02513         sa = s->sa_p;
02514 
02515         VSETALL( sa->max_pt , -MAX_FASTF);
02516         VSETALL( sa->min_pt , MAX_FASTF);
02517 
02518         for( BU_LIST_FOR( fu, faceuse, &s->fu_hd ) )  {
02519                 struct face     *f;
02520 
02521                 f = fu->f_p;
02522                 NMG_CK_FACE(f);
02523                 nmg_face_bb(f, tol);
02524 
02525                 VMIN(sa->min_pt, f->min_pt);
02526                 VMAX(sa->max_pt, f->max_pt);
02527 
02528                 /* If next faceuse shares this face, skip it */
02529                 if( BU_LIST_NOT_HEAD(fu, &fu->l) &&
02530                     ( BU_LIST_NEXT(faceuse, &fu->l)->f_p == f ) )  {
02531                         fu = BU_LIST_PNEXT(faceuse,fu);
02532                 }
02533         }
02534         for( BU_LIST_FOR( lu, loopuse, &s->lu_hd ) )  {
02535                 nmg_loop_g(lu->l_p, tol);
02536 
02537                 VMIN(sa->min_pt, lu->l_p->lg_p->min_pt);
02538                 VMAX(sa->max_pt, lu->l_p->lg_p->max_pt);
02539         }
02540         for( BU_LIST_FOR( eu, edgeuse, &s->eu_hd ) )  {
02541                 NMG_CK_EDGEUSE(eu);
02542                 NMG_CK_EDGE(eu->e_p);
02543                 vg = eu->vu_p->v_p->vg_p;
02544                 NMG_CK_VERTEX_G(vg);
02545                 VMINMAX(sa->min_pt, sa->max_pt, vg->coord);
02546         }
02547         if (s->vu_p) {
02548                 NMG_CK_VERTEXUSE(s->vu_p);
02549                 NMG_CK_VERTEX(s->vu_p->v_p);
02550                 if( s->vu_p->v_p->vg_p )
02551                 {
02552                         NMG_CK_VERTEX_G(s->vu_p->v_p->vg_p);
02553                         vg = s->vu_p->v_p->vg_p;
02554                         VMINMAX(sa->min_pt, sa->max_pt, vg->coord);
02555                 }
02556         }
02557 
02558 
02559         if( BU_LIST_IS_EMPTY( &s->fu_hd ) &&
02560             BU_LIST_IS_EMPTY( &s->lu_hd ) &&
02561             BU_LIST_IS_EMPTY( &s->eu_hd ) && !s->vu_p )  {
02562                 bu_log("nmg_shell_a() at %d in %s. Shell has no children\n",
02563                     __LINE__, __FILE__);
02564                 rt_bomb("nmg_shell_a\n");
02565         }
02566 
02567         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02568                 bu_log("nmg_shell_a(s=x%x, tol=x%x)\n", s , tol);
02569         }
02570 }
02571 
02572 /**                     N M G _ R E G I O N _ A
02573  *
02574  *      build attributes/extents for all shells in a region
02575  *
02576  */
02577 void
02578 nmg_region_a(struct nmgregion *r, const struct bn_tol *tol)
02579 {
02580         register struct shell   *s;
02581         struct nmgregion_a      *ra;
02582 
02583         NMG_CK_REGION(r);
02584         BN_CK_TOL(tol);
02585         if( r->ra_p )  {
02586                 ra = r->ra_p;
02587                 NMG_CK_REGION_A(ra);
02588         } else {
02589                 GET_REGION_A(ra, r->m_p);
02590                 r->ra_p = ra;
02591         }
02592 
02593         ra->magic = NMG_REGION_A_MAGIC;
02594 
02595         VSETALL(ra->max_pt, -MAX_FASTF);
02596         VSETALL(ra->min_pt, MAX_FASTF);
02597 
02598         for( BU_LIST_FOR( s, shell, &r->s_hd ) )  {
02599                 nmg_shell_a(s, tol);
02600                 NMG_CK_SHELL_A(s->sa_p);
02601                 VMIN(ra->min_pt, s->sa_p->min_pt);
02602                 VMAX(ra->max_pt, s->sa_p->max_pt);
02603         }
02604 
02605         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02606                 bu_log("nmg_region_a(r=x%x, tol=x%x)\n", r , tol);
02607         }
02608 }
02609 
02610 /************************************************************************
02611  *                                                                      *
02612  *                              "Demote" Routines                       *
02613  *                                                                      *
02614  *  As part of the boolean operations, sometimes it is desirable        *
02615  *  to "demote" entities down the "chain of being".  The sequence is:   *
02616  *                                                                      *
02617  *      face --> wire loop --> wire edge (line segment) --> vertex      *
02618  *                                                                      *
02619  ************************************************************************/
02620 
02621 
02622 /**
02623  *                      N M G _ D E M O T E _ L U
02624  *
02625  *      Demote a loopuse of edgeuses to a bunch of wire edges in the shell.
02626  *
02627  *  Returns -
02628  *      0       If all is well (edges moved to shell, loopuse deleted).
02629  *      1       If parent is empty, and is thus "illegal".  Still successful.
02630  */
02631 int
02632 nmg_demote_lu(struct loopuse *lu1)
02633 {
02634         struct edgeuse *eu1;
02635         struct shell *s;
02636         int ret_val;
02637 
02638         NMG_CK_LOOPUSE(lu1);
02639 
02640         if (rt_g.NMG_debug & DEBUG_CLASSIFY)
02641                 bu_log("nmg_demote_lu(x%x)\n", lu1);
02642 
02643         if (BU_LIST_FIRST_MAGIC(&lu1->down_hd) == NMG_VERTEXUSE_MAGIC) {
02644                 rt_bomb("nmg_demote_lu() demoting loopuse of a single vertex\n");
02645         }
02646 
02647         if (BU_LIST_FIRST_MAGIC(&lu1->down_hd) != NMG_EDGEUSE_MAGIC)
02648                 rt_bomb("nmg_demote_lu: bad loopuse child\n");
02649 
02650         /* get the parent shell */
02651         s = nmg_find_s_of_lu(lu1);
02652         NMG_CK_SHELL(s);
02653 
02654         /* move all edgeuses (&mates) to shell
02655          */
02656         while ( BU_LIST_NON_EMPTY(&lu1->down_hd) ) {
02657 
02658                 eu1 = BU_LIST_FIRST(edgeuse, &lu1->down_hd);
02659                 NMG_CK_EDGEUSE(eu1);
02660                 NMG_CK_EDGE(eu1->e_p);
02661                 NMG_CK_EDGEUSE(eu1->eumate_p);
02662                 NMG_CK_EDGE(eu1->eumate_p->e_p);
02663 
02664                 BU_LIST_DEQUEUE(&eu1->eumate_p->l);
02665                 BU_LIST_APPEND(&s->eu_hd, &eu1->eumate_p->l);
02666 
02667                 BU_LIST_DEQUEUE(&eu1->l);
02668                 BU_LIST_APPEND(&s->eu_hd, &eu1->l);
02669 
02670                 eu1->up.s_p = eu1->eumate_p->up.s_p = s;
02671         }
02672         /* lu1 is in an illegal state here, with a null edge list */
02673 
02674         if (BU_LIST_NON_EMPTY(&lu1->lumate_p->down_hd))
02675                 rt_bomb("nmg_demote_lu: loopuse mates don't have same # of edges\n");
02676 
02677         ret_val = nmg_klu(lu1);
02678 
02679         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02680                 bu_log("nmg_demote_lu(lu=x%x) returns %d\n", lu1 , ret_val);
02681         }
02682 
02683         return( ret_val );
02684 }
02685 
02686 /**                     N M G _ D E M O T E _ E U
02687  *
02688  *      Demote a wire edge into a pair of self-loop verticies
02689  *
02690  *
02691  *  Returns -
02692  *      0       If all is well
02693  *      1       If shell is empty, and is thus "illegal".
02694  */
02695 int
02696 nmg_demote_eu(struct edgeuse *eu)
02697 {
02698         struct shell    *s;
02699         struct vertex   *v;
02700         int             ret_val;
02701 
02702         if (*eu->up.magic_p != NMG_SHELL_MAGIC)
02703                 rt_bomb("nmg_demote_eu() up is not shell\n");
02704         s = eu->up.s_p;
02705         NMG_CK_SHELL(s);
02706 
02707         NMG_CK_EDGEUSE(eu);
02708         v = eu->vu_p->v_p;
02709         if( !nmg_is_vertex_a_selfloop_in_shell(v, s) )
02710                 (void)nmg_mlv(&s->l.magic, v, OT_SAME);
02711 
02712         NMG_CK_EDGEUSE(eu->eumate_p);
02713         v = eu->eumate_p->vu_p->v_p;
02714         if( !nmg_is_vertex_a_selfloop_in_shell(v, s) )
02715                 (void)nmg_mlv(&s->l.magic, v, OT_SAME);
02716 
02717         (void)nmg_keu(eu);
02718 
02719         ret_val = nmg_shell_is_empty(s);
02720 
02721         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02722                 bu_log("nmg_demote_eu(eu=x%x) returns %d\n", eu , ret_val);
02723         }
02724 
02725         return( ret_val );
02726 }
02727 
02728 /************************************************************************
02729  *                                                                      *
02730  *                              "Modify" Routines                       *
02731  *                                                                      *
02732  *  These routines would go in nmg_mod.c, except that they create       *
02733  *  or delete fundamental entities directly as part of their operation. *
02734  *  Thus, they are part of the make/kill purpose of this module.        *
02735  *                                                                      *
02736  ************************************************************************/
02737 
02738 /**                     N M G _ M O V E V U
02739  *
02740  *      Move a vertexuse from an old vertex to a new vertex.
02741  *      If this was the last use, the old vertex is destroyed.
02742  *
02743  * XXX nmg_jvu() as a better name?
02744  */
02745 void
02746 nmg_movevu(struct vertexuse *vu, struct vertex *v)
02747 {
02748         struct vertex   *oldv;
02749 
02750         NMG_CK_VERTEXUSE(vu);
02751         NMG_CK_VERTEX(v);
02752 
02753         oldv = vu->v_p;
02754         NMG_CK_VERTEX(oldv);
02755 
02756         BU_LIST_DEQUEUE( &vu->l );
02757         if( BU_LIST_IS_EMPTY( &oldv->vu_hd ) )  {
02758                 /* last vertexuse on vertex */
02759                 if (oldv->vg_p) FREE_VERTEX_G(oldv->vg_p);
02760                 FREE_VERTEX(oldv);
02761         }
02762         BU_LIST_APPEND( &v->vu_hd, &vu->l );
02763         vu->v_p = v;
02764 
02765         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02766                 bu_log("nmg_movevu(vu=x%x, v=x%x)\n", vu , v);
02767         }
02768 }
02769 
02770 /**
02771  *                      N M G _ J E
02772  *
02773  *      Move a pair of edgeuses onto a single edge (glue edgeuse).
02774  *      The edgeuse eusrc and its mate are moved to the edge
02775  *      used by eudst.  eusrc is made to be immediately radial to eudst.
02776  *      if eusrc does not share the same vertices as eudst, we bomb.
02777  *
02778  *      The edgeuse geometry pointers are not changed by this operation.
02779  *
02780  *      This routine was formerly called nmg_moveeu().
02781  */
02782 void
02783 nmg_je(struct edgeuse *eudst, struct edgeuse *eusrc)
02784 {
02785         struct edgeuse  *eudst_mate;
02786         struct edgeuse  *eusrc_mate;
02787         struct edge     *e;
02788 
02789         NMG_CK_EDGEUSE(eudst);
02790         NMG_CK_EDGEUSE(eusrc);
02791         eudst_mate = eudst->eumate_p;
02792         eusrc_mate = eusrc->eumate_p;
02793         NMG_CK_EDGEUSE(eudst_mate);
02794         NMG_CK_EDGEUSE(eusrc_mate);
02795 
02796         /* protect the morons from themselves.  Don't let them
02797          * move an edgeuse to itself or it's mate
02798          */
02799         if (eusrc == eudst || eusrc_mate == eudst)  {
02800                 bu_log("nmg_je() moving edgeuse to itself\n");
02801                 return;
02802         }
02803 
02804         if (eusrc->e_p == eudst->e_p &&
02805             (eusrc->radial_p == eudst || eudst->radial_p == eusrc))  {
02806                 bu_log("nmg_je() edgeuses already share edge\n");
02807                 return;
02808         }
02809 
02810         /* make sure vertices are shared */
02811         if ( ! ( (eudst_mate->vu_p->v_p == eusrc->vu_p->v_p &&
02812             eudst->vu_p->v_p == eusrc_mate->vu_p->v_p) ||
02813             (eudst->vu_p->v_p == eusrc->vu_p->v_p &&
02814             eudst_mate->vu_p->v_p == eusrc_mate->vu_p->v_p) ) ) {
02815                 /* edgeuses do NOT share verticies. */
02816                 bu_log( "eusrc (v=x%x) (%g %g %g)\n", eusrc->vu_p->v_p, V3ARGS( eusrc->vu_p->v_p->vg_p->coord ) );
02817                 bu_log( "eusrc_mate (v=x%x) (%g %g %g)\n", eusrc_mate->vu_p->v_p, V3ARGS( eusrc_mate->vu_p->v_p->vg_p->coord ) );
02818                 bu_log( "eudst (v=x%x) (%g %g %g)\n", eudst->vu_p->v_p, V3ARGS( eudst->vu_p->v_p->vg_p->coord ) );
02819                 bu_log( "eudst_mate (v=x%x) (%g %g %g)\n", eudst_mate->vu_p->v_p, V3ARGS( eudst_mate->vu_p->v_p->vg_p->coord ) );
02820                 rt_bomb("nmg_je() edgeuses do not share vertices, cannot share edge\n");
02821         }
02822 
02823         e = eusrc->e_p;
02824         eusrc_mate->e_p = eusrc->e_p = eudst->e_p;
02825 
02826         /* if we're not deleting the edge, make sure it will be able
02827          * to reference the remaining uses, otherwise, take care of disposing
02828          * of the (now unused) edge
02829          */
02830         if (eusrc->radial_p != eusrc_mate) {
02831                 /* this is NOT the only use of the eusrc edge! */
02832                 if (e->eu_p == eusrc || e->eu_p == eusrc_mate)
02833                         e->eu_p = eusrc->radial_p;
02834 
02835                 /* disconnect from the list of uses of this edge */
02836                 eusrc->radial_p->radial_p = eusrc_mate->radial_p;
02837                 eusrc_mate->radial_p->radial_p = eusrc->radial_p;
02838         } else {
02839                 /* this is the only use of the eusrc edge.  Kill edge. */
02840                 FREE_EDGE(e);
02841         }
02842 
02843         eusrc->radial_p = eudst;
02844         eusrc_mate->radial_p = eudst->radial_p;
02845 
02846         eudst->radial_p->radial_p = eusrc_mate;
02847         eudst->radial_p = eusrc;
02848 
02849         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02850                 bu_log("nmg_je(eudst=x%x, eusrc=x%x)\n", eudst , eusrc);
02851         }
02852 }
02853 
02854 /**
02855  *                      N M G _ U N G L U E E D G E
02856  *
02857  *      If edgeuse is part of a shared edge (more than one pair of edgeuses
02858  *      on the edge), it and its mate are "unglued" from the edge, and
02859  *      associated with a new edge structure.
02860  *
02861  *      Primarily a support routine for nmg_eusplit()
02862  *
02863  *  If the original edge had edge geometry, that is *not* duplicated here,
02864  *  because it is not easy (or appropriate) for nmg_eusplit() to know
02865  *  whether the new vertex lies on the previous edge geometry or not.
02866  *  Hence having the nmg_ebreak() interface, which preserves the ege
02867  *  geometry across a split, and nmg_esplit() which does not.
02868  */
02869 void
02870 nmg_unglueedge(struct edgeuse *eu)
02871 {
02872         struct edge     *old_e;
02873         struct edge     *new_e;
02874         struct model    *m;
02875 
02876         NMG_CK_EDGEUSE(eu);
02877         old_e = eu->e_p;
02878         NMG_CK_EDGE(old_e);
02879 
02880         /* if we're already a single edge, just return */
02881         if (eu->radial_p == eu->eumate_p)
02882         {
02883                 if (rt_g.NMG_debug & DEBUG_BASIC)  {
02884                         bu_log("nmg_unglueedge(eu=x%x) (nothing unglued)\n", eu);
02885                 }
02886                 return;
02887         }
02888 
02889         m = nmg_find_model( &eu->l.magic );
02890         GET_EDGE(new_e, m);             /* create new edge */
02891 
02892         new_e->magic = NMG_EDGE_MAGIC;
02893         new_e->eu_p = eu;
02894 
02895         /* make sure the old edge isn't pointing at this edgeuse */
02896         if (old_e->eu_p == eu || old_e->eu_p == eu->eumate_p ) {
02897                 old_e->eu_p = old_e->eu_p->radial_p;
02898         }
02899 
02900         /* unlink edgeuses from old edge */
02901         eu->radial_p->radial_p = eu->eumate_p->radial_p;
02902         eu->eumate_p->radial_p->radial_p = eu->radial_p;
02903         eu->eumate_p->radial_p = eu;
02904         eu->radial_p = eu->eumate_p;
02905 
02906         /* Associate edgeuse and mate with new edge */
02907         eu->eumate_p->e_p = eu->e_p = new_e;
02908 
02909         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02910                 bu_log("nmg_unglueedge(eu=x%x)\n", eu);
02911         }
02912 }
02913 
02914 /**
02915  *                      N M G _ J V
02916  *
02917  *      Join two vertexes into one.
02918  *      v1 inherits all the vertexuses presently pointing to v2,
02919  *      and v2 is then destroyed.
02920  */
02921 void
02922 nmg_jv(register struct vertex *v1, register struct vertex *v2)
02923 {
02924         register struct vertexuse       *vu;
02925 
02926         NMG_CK_VERTEX(v1);
02927         NMG_CK_VERTEX(v2);
02928 
02929         if (v1 == v2) return;
02930 
02931         /*
02932          *  Walk the v2 list, unlinking vertexuse structs,
02933          *  and adding them to the *end* of the v1 list
02934          *  (which preserves relative ordering).
02935          */
02936         vu = BU_LIST_FIRST(vertexuse, &v2->vu_hd );
02937         while( BU_LIST_NOT_HEAD( vu, &v2->vu_hd ) )  {
02938                 register struct vertexuse       *vunext;
02939 
02940                 NMG_CK_VERTEXUSE(vu);
02941                 vunext = BU_LIST_PNEXT(vertexuse, vu);
02942                 BU_LIST_DEQUEUE( &vu->l );
02943                 BU_LIST_INSERT( &v1->vu_hd, &vu->l );
02944                 vu->v_p = v1;           /* "up" to new vertex */
02945                 vu = vunext;
02946         }
02947 
02948         /* Kill vertex v2 */
02949         if (v2->vg_p) {
02950                 if( !v1->vg_p )  {
02951                         v1->vg_p = v2->vg_p;
02952                 } else {
02953                         FREE_VERTEX_G(v2->vg_p);
02954                 }
02955         }
02956         FREE_VERTEX(v2);
02957 
02958         if (rt_g.NMG_debug & DEBUG_BASIC)  {
02959                 bu_log("nmg_jv(v1=x%x, v2=x%x)\n", v1 , v2);
02960         }
02961 }
02962 
02963 /**
02964  *                      N M G _ J F G
02965  *
02966  *  Join two faces, so that they share one underlying face geometry.
02967  *  The loops of the two faces remains unchanged.
02968  *
02969  *  If one of the faces does not have any geometry, then it
02970  *  is made to share the geometry of the other.
02971  */
02972 void
02973 nmg_jfg(struct face *f1, struct face *f2)
02974 {
02975         struct face_g_plane     *fg1;
02976         struct face_g_plane     *fg2;
02977         struct face     *f;
02978 
02979         NMG_CK_FACE(f1);
02980         NMG_CK_FACE(f2);
02981         fg1 = f1->g.plane_p;
02982         fg2 = f2->g.plane_p;
02983         if( fg2 && !fg1 )  {
02984                 /* Make f1 share existing geometry of f2 */
02985                 NMG_CK_FACE_G_PLANE(fg1);
02986                 f1->g.plane_p = fg2;
02987                 f1->flip = f2->flip;
02988                 BU_LIST_INSERT( &fg2->f_hd, &f1->l );
02989 
02990                 if (rt_g.NMG_debug & DEBUG_BASIC)  {
02991                         bu_log("nmg_jfg(f1=x%x, f2=x%x)\n", f1 , f2);
02992                 }
02993                 return;
02994         }
02995         if( fg1 && !fg2 )  {
02996                 /* Make f2 share existing geometry of f1 */
02997                 NMG_CK_FACE_G_PLANE(fg1);
02998                 f2->g.plane_p = fg1;
02999                 f2->flip = f1->flip;
03000                 BU_LIST_INSERT( &fg1->f_hd, &f2->l );
03001 
03002                 if (rt_g.NMG_debug & DEBUG_BASIC)  {
03003                         bu_log("nmg_jfg(f1=x%x, f2=x%x)\n", f1 , f2);
03004                 }
03005                 return;
03006         }
03007 
03008         NMG_CK_FACE_G_PLANE(fg1);
03009         NMG_CK_FACE_G_PLANE(fg2);
03010 
03011         if( fg1 == fg2 )
03012         {
03013                 if (rt_g.NMG_debug & DEBUG_BASIC)  {
03014                         bu_log("nmg_jfg(f1=x%x, f2=x%x)\n", f1 , f2);
03015                 }
03016                 return;
03017         }
03018 
03019         /* Unhook all the faces on fg2 list, and add to fg1 list */
03020         while( BU_LIST_NON_EMPTY( &fg2->f_hd ) )  {
03021                 f = BU_LIST_FIRST( face, &fg2->f_hd );
03022                 BU_LIST_DEQUEUE( &f->l );
03023                 NMG_CK_FACE(f);
03024                 f->g.plane_p = fg1;
03025                 /* flip flag is left unchanged here, on purpose */
03026                 BU_LIST_INSERT( &fg1->f_hd, &f->l );
03027         }
03028 
03029         /* fg2 list is now empty, release that face geometry */
03030         FREE_FACE_G_PLANE(fg2);
03031 
03032         if (rt_g.NMG_debug & DEBUG_BASIC)  {
03033                 bu_log("nmg_jfg(f1=x%x, f2=x%x)\n", f1 , f2);
03034         }
03035 }
03036 
03037 /**
03038  *                      N M G _ J E G
03039  *
03040  *  Join two edge geometries.
03041  *  For all edges in the model which refer to 'src_eg',
03042  *  change them to refer to 'dest_eg'.  The source is destroyed.
03043  *
03044  *  It is the responsibility of the caller to make certain that the
03045  *  'dest_eg' is the best one for these edges.
03046  *  Outrageously wrong requests will cause this routine to abort.
03047  *
03048  *  This algorithm does not make sense if dest_eg is an edge_g_cnurb;
03049  *  those only make sense in the parameter space of their associated face.
03050  */
03051 void
03052 nmg_jeg(struct edge_g_lseg *dest_eg, struct edge_g_lseg *src_eg)
03053 {
03054         register struct edgeuse         *eu;
03055 
03056         NMG_CK_EDGE_G_LSEG(src_eg);
03057         NMG_CK_EDGE_G_LSEG(dest_eg);
03058         if (rt_g.NMG_debug & DEBUG_BASIC)  {
03059                 bu_log("nmg_jeg( src_eg=x%x, dest_eg=x%x )\n",
03060                         src_eg, dest_eg );
03061         }
03062 
03063 #if 0
03064         /* Sanity check */
03065         VMOVE( dir_src, src_eg->e_dir );
03066         VUNITIZE( dir_src );
03067         VMOVE( dir_dest, dest_eg->e_dir );
03068         VUNITIZE( dir_dest );
03069         cos_ang = fabs(VDOT( dir_src, dir_dest ));
03070         if( cos_ang > 1.0 )
03071                 cos_ang = 1.0;
03072         deg = acos( cos_ang ) * bn_radtodeg;
03073         if( fabs(deg) > 2 )  {
03074                 VPRINT( "dir_src ", dir_src );
03075                 VPRINT( "dir_dest", dir_dest );
03076                 bu_log("Angle between lines is %g degrees\n", deg );
03077                 /* This can happen while fixing mistakes, don't bomb. */
03078         }
03079 #endif
03080         while( BU_LIST_NON_EMPTY( &src_eg->eu_hd2 ) )  {
03081                 struct bu_list  *midway;        /* &eu->l2, midway into edgeuse */
03082 
03083                 NMG_CK_EDGE_G_LSEG(src_eg);
03084 
03085                 /* Obtain an eu from src_eg */
03086                 midway = BU_LIST_FIRST(bu_list, &src_eg->eu_hd2 );
03087                 NMG_CKMAG(midway, NMG_EDGEUSE2_MAGIC, "edgeuse2 [l2]");
03088                 eu = BU_LIST_MAIN_PTR( edgeuse, midway, l2 );
03089                 NMG_CK_EDGEUSE(eu);
03090 
03091                 if( eu->g.lseg_p != src_eg )  {
03092                         bu_log("nmg_jeg() eu=x%x, eu->g=x%x != src_eg=x%x??  dest_eg=x%x\n",
03093                                 eu, eu->g.lseg_p, src_eg, dest_eg );
03094                         rt_bomb("nmg_jeg() edge geometry fumble\n");
03095                 }
03096 
03097                 /* Associate eu and mate with dest_eg. src_eg freed when unused. */
03098                 if( nmg_use_edge_g( eu, &dest_eg->l.magic ) )
03099                         break;          /* src_eg destroyed */
03100         }
03101 }
03102 
03103 /*
03104  * Local Variables:
03105  * mode: C
03106  * tab-width: 8
03107  * c-basic-offset: 4
03108  * indent-tabs-mode: t
03109  * End:
03110  * ex: shiftwidth=4 tabstop=8
03111  */

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