nmg_manif.c

Go to the documentation of this file.
00001 /*                     N M G _ M A N I F . 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_manif.c
00026  *  Routines for assessing the manifold dimension of an object.
00027  *
00028  *  Author -
00029  *      Lee A. Butler
00030  *
00031  *  Source -
00032  *      The U. S. Army Research Laboratory
00033  *      Aberdeen Proving Ground, Maryland  21005-5068  USA
00034  */
00035 /*@}*/
00036 
00037 #ifndef lint
00038 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/nmg_manif.c,v 14.12 2006/09/16 02:04:25 lbutler Exp $ (ARL)";
00039 #endif
00040 
00041 #include "common.h"
00042 
00043 
00044 #include <stdio.h>
00045 #ifdef HAVE_STRING_H
00046 #include <string.h>
00047 #else
00048 #include <strings.h>
00049 #endif
00050 #include "machine.h"
00051 #include "vmath.h"
00052 #include "nmg.h"
00053 #include "raytrace.h"
00054 
00055 #define PAINT_INTERIOR 1
00056 #define PAINT_EXTERIOR 0
00057 
00058 #define BU_LIST_LINK_CHECK( p ) \
00059         if (BU_LIST_PNEXT_PLAST(bu_list, p) != p || \
00060             BU_LIST_PLAST_PNEXT(bu_list, p) != p) { \
00061                 bu_log("%s[%d]: linked list integrity check failed\n", \
00062                                 __FILE__, __LINE__); \
00063                 bu_log("0x%08x->forw(0x%08x)->back = 0x%08x\n", \
00064                         (p), (p)->forw, (p)->forw->back); \
00065                 bu_log("0x%08x->back(0x%08x)->forw = 0x%08x\n", \
00066                         (p), (p)->back, (p)->back->forw); \
00067                 rt_bomb("Goodbye\n"); \
00068         }
00069 
00070 
00071 /**     N M G _ D A N G L I N G _ F A C E
00072  *
00073  *      Determine if a face has any "dangling" edges.
00074  *
00075  *      Return
00076  *      1       face has dangling edge
00077  *      0       face does not have a dangling edge
00078  */
00079 int
00080 nmg_dangling_face(const struct faceuse *fu, register const char *manifolds)
00081 {
00082         struct loopuse *lu;
00083         struct edgeuse *eu;
00084         const struct edgeuse *eur;
00085         struct faceuse *newfu;
00086 
00087         NMG_CK_FACEUSE(fu);
00088 
00089         if (rt_g.NMG_debug & DEBUG_MANIF)
00090                 bu_log("nmg_dangling_face(0x%08x 0x%08x)\n", fu, manifolds);
00091 
00092         for(BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) {
00093             NMG_CK_LOOPUSE(lu);
00094             BU_LIST_LINK_CHECK( &lu->l );
00095 
00096             if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_EDGEUSE_MAGIC) {
00097                 /* go looking around each edge for a face of the same
00098                  * shell which isn't us and isn't our mate.  If we
00099                  * find us or our mate before another face of this
00100                  * shell, we are non-3-manifold.
00101                  */
00102 
00103                 for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
00104 
00105                     NMG_CK_EDGEUSE( eu );
00106                     BU_LIST_LINK_CHECK( &eu->l );
00107 
00108                     eur = nmg_radial_face_edge_in_shell(eu);
00109                     newfu = eur->up.lu_p->up.fu_p;
00110 
00111                     /* skip any known dangling-edge faces or
00112                      * faces known to be 2manifolds.
00113                      */
00114                     while (manifolds &&
00115                         NMG_MANIFOLDS(manifolds,newfu) & NMG_2MANIFOLD &&
00116                         eur != eu->eumate_p) {
00117                                 eur = nmg_radial_face_edge_in_shell(
00118                                         eur->eumate_p);
00119                                 newfu = eur->up.lu_p->up.fu_p;
00120                     }
00121 
00122                     if (eur == eu->eumate_p) {
00123                         goto out;
00124                     }
00125                 }
00126             }
00127         }
00128         eur = (const struct edgeuse *)NULL;
00129 
00130 out:
00131         if (rt_g.NMG_debug & DEBUG_BASIC)  {
00132                 struct bn_tol   tol;    /* HACK */
00133                 tol.magic = BN_TOL_MAGIC;
00134                 tol.dist = 1;
00135                 tol.dist_sq = tol.dist * tol.dist;
00136                 tol.perp = 1e-5;
00137                 tol.para = 1 - tol.perp;
00138 
00139                 bu_log("nmg_dangling_face(fu=x%x, manifolds=x%x) dangling_eu=x%x\n", fu, manifolds, eur);
00140                 if( eur )  nmg_pr_fu_around_eu( eur, &tol );
00141         }
00142         if ((rt_g.NMG_debug & DEBUG_MANIF) && (eur != (const struct edgeuse *)NULL) )
00143                 bu_log( "\tdangling eu x%x\n", eur );
00144 
00145         return eur != (const struct edgeuse *)NULL;
00146 }
00147 
00148 /**
00149  *      "Paint" the elements of a face with a meaning.  For example
00150  *      mark everything in a face as being part of a 2-manifold
00151  */
00152 static void paint_face(struct faceuse *fu, char *paint_table, int paint_color, char *paint_meaning, char *tbl)
00153 {
00154         struct faceuse *newfu;
00155         struct loopuse *lu;
00156         struct edgeuse *eu;
00157         const struct edgeuse *eur;
00158 
00159 #if 1
00160         if (rt_g.NMG_debug & DEBUG_MANIF)
00161                 bu_log("nmg_paint_face(%08x, %d)\n", fu, paint_color);
00162 #endif
00163         if (NMG_INDEX_VALUE(paint_table, fu->index) != 0)
00164                 return;
00165 
00166         NMG_INDEX_ASSIGN(paint_table, fu, paint_color);
00167 
00168         for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) {
00169 
00170                 if (rt_g.NMG_debug & DEBUG_MANIF)
00171                         bu_log( "\tlu=x%x\n", lu );
00172 
00173                 NMG_CK_LOOPUSE( lu );
00174                 BU_LIST_LINK_CHECK( &lu->l );
00175 
00176                 if (BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_EDGEUSE_MAGIC)
00177                         continue;
00178 
00179                 for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
00180                         if (rt_g.NMG_debug & DEBUG_MANIF)
00181                                 bu_log( "\t\teu=x%x\n", eu );
00182                         NMG_CK_EDGEUSE(eu);
00183                         NMG_CK_EDGEUSE(eu->eumate_p);
00184                         eur = nmg_radial_face_edge_in_shell(eu);
00185                         NMG_CK_EDGEUSE(eur);
00186                         NMG_CK_FACEUSE(eur->up.lu_p->up.fu_p);
00187                         newfu = eur->up.lu_p->up.fu_p;
00188 
00189                         if (rt_g.NMG_debug & DEBUG_MANIF)
00190                                 bu_log( "\t\t\teur=x%x, newfu=x%x\n", eur, newfu );
00191 
00192                         BU_LIST_LINK_CHECK( &eu->l );
00193                         BU_LIST_LINK_CHECK( &eur->l );
00194 
00195                         while (NMG_MANIFOLDS(tbl, newfu) & NMG_2MANIFOLD &&
00196                             eur != eu->eumate_p) {
00197                                 eur = nmg_radial_face_edge_in_shell(
00198                                                         eur->eumate_p);
00199                                 newfu = eur->up.lu_p->up.fu_p;
00200 
00201                                 if (rt_g.NMG_debug & DEBUG_MANIF)
00202                                         bu_log( "\t\t\teur=x%x, newfu=x%x\n", eur, newfu );
00203                         }
00204 
00205                         if( newfu == fu->fumate_p )
00206                                 continue;
00207                         else if (newfu->orientation == OT_SAME)
00208                                 paint_face(newfu,paint_table,paint_color,
00209                                         paint_meaning,tbl);
00210                         else {
00211                                 /* mark this group as being interior */
00212                                 paint_meaning[paint_color] = PAINT_INTERIOR;
00213 
00214                                 if (rt_g.NMG_debug & DEBUG_MANIF)
00215                                         bu_log( "\t---- Painting fu x%x as interior, new_fu = x%x, eu=x%x, eur=x%x\n", fu, newfu, eu, eur );
00216                         }
00217                 }
00218         }
00219 }
00220 
00221 static void set_edge_sub_manifold(char *tbl, struct edgeuse *eu_p, char manifold)
00222 {
00223 
00224         NMG_CK_EDGEUSE(eu_p);
00225         NMG_CK_EDGE(eu_p->e_p);
00226         NMG_CK_VERTEXUSE(eu_p->vu_p);
00227         NMG_CK_VERTEX(eu_p->vu_p->v_p);
00228 
00229         NMG_SET_MANIFOLD(tbl, eu_p, manifold);
00230         NMG_SET_MANIFOLD(tbl, eu_p->e_p, manifold);
00231 
00232         NMG_SET_MANIFOLD(tbl, eu_p->vu_p, manifold);
00233         NMG_SET_MANIFOLD(tbl, eu_p->vu_p->v_p, manifold);
00234 }
00235 
00236 
00237 static void set_loop_sub_manifold(char *tbl, struct loopuse *lu_p, char manifold)
00238 {
00239         struct edgeuse *eu_p;
00240         struct vertexuse *vu_p;
00241 #if 0
00242         if (rt_g.NMG_debug & DEBUG_MANIF)
00243                 bu_log("nmg_set_loop_sub_manifold(%08x)\n", lu_p);
00244 #endif
00245         NMG_CK_LOOPUSE(lu_p);
00246 
00247         NMG_SET_MANIFOLD(tbl, lu_p, manifold);
00248         NMG_SET_MANIFOLD(tbl, lu_p->l_p, manifold);
00249         if (BU_LIST_FIRST_MAGIC(&lu_p->down_hd) == NMG_VERTEXUSE_MAGIC) {
00250                 vu_p = BU_LIST_FIRST(vertexuse, &lu_p->down_hd);
00251                 NMG_SET_MANIFOLD(tbl, vu_p, manifold);
00252                 NMG_SET_MANIFOLD(tbl, vu_p->v_p, manifold);
00253         } else if (BU_LIST_FIRST_MAGIC(&lu_p->down_hd) == NMG_EDGEUSE_MAGIC) {
00254                 for (BU_LIST_FOR(eu_p, edgeuse, &lu_p->down_hd)) {
00255                         BU_LIST_LINK_CHECK( &eu_p->l );
00256                         set_edge_sub_manifold(tbl, eu_p, manifold);
00257                 }
00258         } else
00259                 rt_bomb("bad child of loopuse\n");
00260 }
00261 static void set_face_sub_manifold(char *tbl, struct faceuse *fu_p, char manifold)
00262 {
00263         struct loopuse *lu_p;
00264 
00265         NMG_CK_FACEUSE(fu_p);
00266         NMG_CK_FACE(fu_p->f_p);
00267 
00268         NMG_SET_MANIFOLD(tbl, fu_p, manifold);
00269         NMG_SET_MANIFOLD(tbl, fu_p->f_p, manifold);
00270         for (BU_LIST_FOR(lu_p, loopuse, &fu_p->lu_hd)) {
00271                 BU_LIST_LINK_CHECK( &lu_p->l );
00272                 set_loop_sub_manifold(tbl, lu_p, manifold);
00273         }
00274 }
00275 
00276 
00277 
00278 char *
00279 nmg_shell_manifolds(struct shell *sp, char *tbl)
00280 {
00281         struct edgeuse *eu_p;
00282         struct loopuse *lu_p;
00283         struct faceuse *fu_p;
00284         char *paint_meaning, *paint_table, paint_color;
00285         int found;
00286 
00287         if (rt_g.NMG_debug & DEBUG_MANIF)
00288                 bu_log("nmg_shell_manifolds(%08x)\n", sp);
00289 
00290         NMG_CK_SHELL(sp);
00291 
00292         if (tbl == (char *)NULL)
00293                 tbl = bu_calloc(sp->r_p->m_p->maxindex, 1, "manifold table");
00294 
00295         /*
00296          * points in shells form 0-manifold objects.
00297          */
00298         if (sp->vu_p) {
00299                 NMG_CK_VERTEXUSE(sp->vu_p);
00300                 NMG_SET_MANIFOLD(tbl, sp, NMG_0MANIFOLD);
00301                 NMG_SET_MANIFOLD(tbl, sp->vu_p, NMG_0MANIFOLD);
00302                 NMG_SET_MANIFOLD(tbl, sp->vu_p->v_p, NMG_0MANIFOLD);
00303                 BU_LIST_LINK_CHECK( &sp->vu_p->l );
00304         }
00305 
00306         /* edges in shells are (components of)
00307          * 1-manifold objects.
00308          */
00309         if (BU_LIST_NON_EMPTY(&sp->eu_hd)) {
00310 
00311                 for (BU_LIST_FOR(eu_p, edgeuse, &sp->eu_hd)) {
00312                         BU_LIST_LINK_CHECK( &eu_p->l );
00313                         set_edge_sub_manifold(tbl, eu_p, NMG_1MANIFOLD);
00314                 }
00315                 NMG_SET_MANIFOLD(tbl, sp, NMG_1MANIFOLD);
00316         }
00317 
00318         /* loops in shells are (components of)
00319          * 1-manifold objects.
00320          */
00321         if (BU_LIST_NON_EMPTY(&sp->lu_hd)) {
00322 
00323                 for (BU_LIST_FOR(lu_p, loopuse, &sp->lu_hd)) {
00324                         BU_LIST_LINK_CHECK( &lu_p->l );
00325 
00326                         set_loop_sub_manifold(tbl, lu_p, NMG_1MANIFOLD);
00327                 }
00328                 NMG_SET_MANIFOLD(tbl, sp, NMG_1MANIFOLD);
00329         }
00330 
00331         if (rt_g.NMG_debug & DEBUG_MANIF)
00332                 bu_log("starting manifold classification on shell faces\n");
00333 
00334         /*
00335          * faces may be either 2 or 3 manifold components.
00336          */
00337         if (BU_LIST_IS_EMPTY(&sp->fu_hd))
00338                 return tbl;
00339 
00340 
00341         /* mark all externally dangling faces and faces
00342          * with or adjacent to dangling edges.
00343          */
00344         do {
00345                 found = 0;
00346                 for (BU_LIST_FOR(fu_p, faceuse, &sp->fu_hd)) {
00347                         NMG_CK_FACEUSE(fu_p);
00348                         BU_LIST_LINK_CHECK( &fu_p->l );
00349 
00350                         /* if this has already been marked as a 2-manifold
00351                          * then we don't need to check it again
00352                          */
00353                         if (NMG_MANIFOLDS(tbl,fu_p) & NMG_2MANIFOLD)
00354                                 continue;
00355 
00356                         if (nmg_dangling_face(fu_p, tbl)) {
00357                                 found = 1;
00358 
00359                                 NMG_SET_MANIFOLD(tbl, fu_p, NMG_2MANIFOLD);
00360 
00361                                 if (rt_g.NMG_debug & DEBUG_MANIF)
00362                                         bu_log("found dangling face\n");
00363                         }
00364                 }
00365         } while (found);
00366 
00367         /* paint the exterior faces to discover what the
00368          * actual enclosing shell is
00369          */
00370 
00371         if (rt_g.NMG_debug & DEBUG_MANIF)
00372                 bu_log("starting to paint non-dangling faces\n");
00373 
00374         paint_meaning = bu_calloc(256, 1, "paint meaning table");
00375         paint_table = bu_calloc(sp->r_p->m_p->maxindex, 1, "paint table");
00376         paint_color = 1;
00377 
00378         for (BU_LIST_FOR(fu_p, faceuse, &sp->fu_hd)) {
00379                 BU_LIST_LINK_CHECK( &fu_p->l );
00380 
00381                 if (fu_p->orientation != OT_SAME ||
00382                     NMG_INDEX_VALUE(paint_table, fu_p->index) != 0)
00383                         continue;
00384 
00385                 paint_face(fu_p, paint_table, paint_color, paint_meaning, tbl);
00386                 paint_color++;
00387         }
00388 
00389 
00390         if (rt_g.NMG_debug & DEBUG_MANIF)
00391                 bu_log("painting done, looking at colors\n");
00392 
00393 
00394         /* all the faces painted with "interior" paint are 2manifolds
00395          * those faces still painted with "exterior" paint are
00396          * 3manifolds, ie. part of the enclosing surface
00397          */
00398         for (BU_LIST_FOR(fu_p, faceuse, &sp->fu_hd)) {
00399                 BU_LIST_LINK_CHECK( &fu_p->l );
00400 
00401                 paint_color = NMG_INDEX_VALUE(paint_table,
00402                                                 fu_p->index);
00403 
00404                 if (NMG_INDEX_VALUE(paint_meaning, (int)paint_color) ==
00405                     PAINT_INTERIOR) {
00406                         set_face_sub_manifold(tbl, fu_p, NMG_2MANIFOLD);
00407                 } else if (NMG_INDEX_VALUE(paint_meaning, (int)paint_color)
00408                     == PAINT_EXTERIOR) {
00409                         set_face_sub_manifold(tbl, fu_p, NMG_3MANIFOLD);
00410                 }
00411         }
00412 
00413         bu_free(paint_meaning, "paint meaning table");
00414         bu_free(paint_table, "paint table");
00415 
00416         for (BU_LIST_FOR(fu_p, faceuse, &sp->fu_hd)) {
00417                 BU_LIST_LINK_CHECK( &fu_p->l );
00418 
00419                 if (fu_p->orientation != OT_SAME)
00420                         NMG_CP_MANIFOLD(tbl, fu_p, fu_p->fumate_p);
00421         }
00422 
00423         return(tbl);
00424 }
00425 
00426 
00427 char *
00428 nmg_manifolds(struct model *m)
00429 {
00430         struct nmgregion *rp;
00431         struct shell *sp;
00432         char *tbl;
00433 
00434 
00435         NMG_CK_MODEL(m);
00436         if (rt_g.NMG_debug & DEBUG_MANIF)
00437                 bu_log("nmg_manifolds(%08x)\n", m);
00438 
00439         tbl = bu_calloc(m->maxindex, 1, "manifold table");
00440 
00441 
00442         for (BU_LIST_FOR(rp, nmgregion, &m->r_hd)) {
00443                 NMG_CK_REGION(rp);
00444                 BU_LIST_LINK_CHECK( &rp->l );
00445 
00446                 for (BU_LIST_FOR(sp, shell, &rp->s_hd)) {
00447 
00448                         NMG_CK_SHELL( sp );
00449                         BU_LIST_LINK_CHECK( &sp->l );
00450 
00451                         nmg_shell_manifolds(sp, tbl);
00452 
00453                         /* make sure the region manifold bits are a superset
00454                          * of the shell manifold bits
00455                          */
00456                         NMG_CP_MANIFOLD(tbl, rp, sp);
00457                 }
00458         }
00459 
00460         return(tbl);
00461 }
00462 
00463 
00464 /*
00465  * Local Variables:
00466  * mode: C
00467  * tab-width: 8
00468  * c-basic-offset: 4
00469  * indent-tabs-mode: t
00470  * End:
00471  * ex: shiftwidth=4 tabstop=8
00472  */

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