nmg_pt_fu.c

Go to the documentation of this file.
00001 /*                     N M G _ P T _ F U . 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 /** @file nmg_pt_fu.c
00025  *  Routines for classifying a point with respect to a faceuse.
00026  *
00027  *  Author -
00028  *      Lee A. Butler
00029  *
00030  *  Source -
00031  *      The U. S. Army Research Laboratory
00032  *      Aberdeen Proving Ground, Maryland  21005-5068  USA
00033  */
00034 /*@}*/
00035 
00036 #include "common.h"
00037 
00038 #include <stdlib.h>
00039 #include <stdio.h>
00040 #include <math.h>
00041 
00042 #include "machine.h"
00043 #include "vmath.h"
00044 #include "nmg.h"
00045 #include "raytrace.h"
00046 #include "plot3.h"
00047 
00048 
00049 /* vertex/edge distance
00050  * Each loop geometry element (edge/vertex) has one of these computed.
00051  * We keep track of them for the whole face so that this value is computed
00052  * only once per geometry element.  This way we get consistent answers
00053  */
00054 struct ve_dist {
00055         struct bu_list  l;
00056         long            *magic_p;/* pointer to edge/vertex structure */
00057         double          dist;   /* distance squared from point to edge */
00058         struct vertex   *v1;
00059         struct vertex   *v2;
00060         int             status; /* return code from bn_dist_pt3_lseg3 */
00061 };
00062 #define NMG_VE_DIST_MAGIC       0x102938
00063 #define NMG_CK_VED(_p)  NMG_CKMAG(_p, NMG_VE_DIST_MAGIC, "vertex/edge_dist")
00064 
00065 /* The loop builds a list of these things so that it can figure out the point
00066  * classification based upon the classification of the pt vs each edge of
00067  * the loop.  This list is sorted in ascending "ved_p->dist" order.
00068  */
00069 struct edge_info {
00070         struct bu_list          l;
00071         struct ve_dist          *ved_p;   /* ptr to ve_dist for this item */
00072         struct edgeuse          *eu_p;    /* edgeuse pointer */
00073         int                     class;    /* pt classification WRT this item use */
00074 };
00075 #define NMG_EDGE_INFO_MAGIC 0xe100
00076 #define NMG_CK_EI(_p)   NMG_CKMAG(_p, NMG_EDGE_INFO_MAGIC, "edge_info")
00077 
00078 struct fpi {
00079         long                    magic;
00080         const struct bn_tol     *tol;
00081         const struct faceuse    *fu_p;
00082         struct bu_list  ve_dh;          /* ve_dist list head */
00083         plane_t         norm;           /* surface normal for face(use) */
00084         point_t         pt;             /* pt in plane of face to classify */
00085         void            (*eu_func)();   /* call w/eu when pt on edgeuse */
00086         void            (*vu_func)();   /* call w/vu when pt on vertexuse */
00087         const char      *priv;          /* caller's private data */
00088         int             hits;           /* flag PERUSE/PERGEOM */
00089 };
00090 #define NMG_FPI_MAGIC 12345678 /* fpi\0 */
00091 #define NMG_CK_FPI(_fpi) \
00092         NMG_CKMAG(_fpi, NMG_FPI_MAGIC, "fu_pt_info") ; \
00093         BN_CK_TOL( _fpi->tol ); \
00094         BU_CK_LIST_HEAD(&_fpi->ve_dh)
00095 
00096 #define NMG_FPI_TOUCHED 27
00097 #define NMG_FPI_MISSED  32768
00098 
00099 #ifdef USE_PROTOTYPES
00100 static int      nmg_class_pt_vu(struct fpi *fpi, struct vertexuse *vu);
00101 
00102 static struct edge_info *nmg_class_pt_eu(struct fpi *fpi, struct edgeuse *eu, struct edge_info *edge_list, const int in_or_out_only);
00103 static int      compute_loop_class(struct fpi *fpi, const struct loopuse *lu,struct edge_info *edge_list);
00104 static int      nmg_class_pt_lu(struct loopuse *lu, struct fpi *fpi, const int in_or_out_only);
00105 int             nmg_class_pt_fu_except(const point_t pt, const struct faceuse *fu, const struct loopuse *ignore_lu, void (*eu_func)(), void (*vu_func)(), const char *priv, const int call_on_hits, const int in_or_out_only, const struct bn_tol *tol);
00106 #endif
00107 
00108 /**
00109  *                      B N _ D I S T S Q _ P T 3 _ L S E G 3 _ J R A
00110  *
00111  *  Find the square of the distance from a point P to a line segment described
00112  *  by the two endpoints A and B.
00113  *
00114  *                      P
00115  *                     *
00116  *                    /.
00117  *                   / .
00118  *                  /  .
00119  *                 /   . (dist)
00120  *                /    .
00121  *               /     .
00122  *              *------*--------*
00123  *              A      PCA      B
00124  *
00125  *  There are six distinct cases, with these return codes -
00126  *      0       P is within tolerance of lseg AB.  *dist =  0.
00127  *      1       P is within tolerance of point A.  *dist = 0.
00128  *      2       P is within tolerance of point B.  *dist = 0.
00129  *      3       PCA is within tolerance of A. *dist = |P-A|**2.
00130  *      4       PCA is within tolerance of B. *dist = |P-B|**2.
00131  *      5       P is "above/below" lseg AB.  *dist=|PCA-P|**2.
00132  *
00133  * This routine was formerly called bn_dist_pt_lseg().
00134  * This is a special version that returns the square of the distance
00135  * and does not actually calculate PCA.
00136  *
00137  */
00138 int
00139 bn_distsq_pt3_lseg3(fastf_t *dist, const fastf_t *a, const fastf_t *b, const fastf_t *p, const struct bn_tol *tol)
00140 {
00141         vect_t  PtoA;           /* P-A */
00142         vect_t  PtoB;           /* P-B */
00143         vect_t  AtoB;           /* B-A */
00144         fastf_t P_A_sq;         /* |P-A|**2 */
00145         fastf_t P_B_sq;         /* |P-B|**2 */
00146         fastf_t B_A_sq;         /* |B-A|**2 */
00147         fastf_t t;              /* distance squared along ray of projection of P */
00148         fastf_t dot;
00149 
00150         BN_CK_TOL(tol);
00151 #if 0
00152         if( RT_G_DEBUG & DEBUG_MATH )   {
00153                 bu_log("bn_distsq_pt3_lseg3() a=(%g,%g,%g) b=(%g,%g,%g)\n\tp=(%g,%g,%g), tol->dist=%g sq=%g\n",
00154                         V3ARGS(a),
00155                         V3ARGS(b),
00156                         V3ARGS(p),
00157                         tol->dist, tol->dist_sq );
00158         }
00159 #endif
00160 
00161         /* Check proximity to endpoint A */
00162         VSUB2(PtoA, p, a);
00163         if( (P_A_sq = MAGSQ(PtoA)) < tol->dist_sq )  {
00164                 /* P is within the tol->dist radius circle around A */
00165                 *dist = 0.0;
00166                 return 1;
00167         }
00168 
00169         /* Check proximity to endpoint B */
00170         VSUB2(PtoB, p, b);
00171         if( (P_B_sq = MAGSQ(PtoB)) < tol->dist_sq )  {
00172                 /* P is within the tol->dist radius circle around B */
00173                 *dist = 0.0;
00174                 return 2;
00175         }
00176 
00177         VSUB2(AtoB, b, a);
00178         B_A_sq = MAGSQ(AtoB);
00179 
00180         /* compute distance squared (in actual units) along line to PROJECTION of
00181          * point p onto the line: point pca
00182          */
00183         dot = VDOT(PtoA, AtoB);
00184         t = dot * dot / B_A_sq;
00185 
00186         if( dot < 0.0 && t > tol->dist_sq )  {
00187                 /* P is "left" of A */
00188                 *dist = P_A_sq;
00189                 return 3;
00190         }
00191         if( t < B_A_sq - tol->dist_sq )  {
00192                 /* PCA falls between A and B */
00193                 register fastf_t        dsq;
00194 
00195                 /* Find distance from PCA to line segment (Pythagorus) */
00196                 if( (dsq = P_A_sq - t ) <= tol->dist_sq )  {
00197                         /* PCA is on lseg */
00198                         *dist = 0.0;
00199                         return 0;
00200                 }
00201 
00202                 /* P is above or below lseg */
00203                 *dist = dsq;
00204                 return 5;
00205         }
00206 
00207         /* P is "right" of B */
00208         *dist = P_B_sq;
00209         return 4;
00210 }
00211 
00212 
00213 /**
00214  *      N M G _ C L A S S _ P T _ V U
00215  *
00216  *      Classify a point vs a vertex (touching/missed)
00217  */
00218 static int
00219 nmg_class_pt_vu(struct fpi *fpi, struct vertexuse *vu)
00220 {
00221         vect_t delta;
00222         struct ve_dist  *ved;
00223 
00224         NMG_CK_VERTEXUSE(vu);
00225 
00226         /* see if we've classified this vertex WRT the point already */
00227         for (BU_LIST_FOR(ved, ve_dist, &fpi->ve_dh)){
00228                 NMG_CK_VED(ved);
00229                 if (ved->magic_p == &vu->v_p->magic) {
00230                         goto found;
00231                 }
00232         }
00233 
00234         /* if we get here, we didn't find the vertex in the list of
00235          * previously classified geometry.  Create an entry in the
00236          * face's list of processed geometry.
00237          */
00238         VSUB2(delta, vu->v_p->vg_p->coord, fpi->pt);
00239 
00240         ved = (struct ve_dist *) bu_malloc(sizeof(struct ve_dist), "ve_dist structure");
00241         ved->magic_p = &vu->v_p->magic;
00242         ved->dist = MAGNITUDE(delta);
00243         if (ved->dist < fpi->tol->dist_sq ) {
00244                 ved->status = NMG_FPI_TOUCHED;
00245                 if (fpi->hits == NMG_FPI_PERGEOM)
00246                         fpi->vu_func(vu, fpi->pt, fpi->priv);
00247         }
00248         else ved->status = NMG_FPI_MISSED;
00249 
00250         ved->v1 = ved->v2 = vu->v_p;
00251 
00252         BU_LIST_MAGIC_SET(&ved->l, NMG_VE_DIST_MAGIC);
00253         BU_LIST_APPEND(&fpi->ve_dh, &ved->l);
00254 found:
00255 
00256         if (fpi->vu_func  &&
00257             ved->status == NMG_FPI_TOUCHED &&
00258             fpi->hits == NMG_FPI_PERUSE)
00259                 fpi->vu_func(vu, fpi->pt, fpi->priv);
00260 
00261         return ved->status;
00262 }
00263 
00264 #if 0
00265 static void
00266 pl_pt_e(fpi, ei)
00267 struct fpi *fpi;
00268 struct edge_info *ei;
00269 {
00270         FILE *fd;
00271         char name[25];
00272         long *b;
00273         point_t pca;
00274         fastf_t dist;
00275         static int plot_file_number=0;
00276         struct bn_tol tmp_tol;
00277 
00278         NMG_CK_FPI(fpi);
00279         NMG_CK_FACEUSE(fpi->fu_p);
00280         NMG_CK_EI(ei);
00281 
00282         sprintf(name, "pt_e%02d.pl", plot_file_number++);
00283         if ((fd=fopen(name, "w")) == (FILE *)NULL) {
00284                 perror(name);
00285                 bu_bomb("unable to open file for writing");
00286         }
00287 
00288         bu_log("\toverlay %s\n", name);
00289         b = (long *)bu_calloc( fpi->fu_p->s_p->r_p->m_p->maxindex,
00290                 sizeof(long), "bit vec"),
00291 
00292         pl_erase(fd);
00293         pd_3space(fd,
00294                 fpi->fu_p->f_p->min_pt[0]-1.0,
00295                 fpi->fu_p->f_p->min_pt[1]-1.0,
00296                 fpi->fu_p->f_p->min_pt[2]-1.0,
00297                 fpi->fu_p->f_p->max_pt[0]+1.0,
00298                 fpi->fu_p->f_p->max_pt[1]+1.0,
00299                 fpi->fu_p->f_p->max_pt[2]+1.0);
00300 
00301         nmg_pl_eu(fd, ei->eu_p, b, 255, 255, 255);
00302 
00303         tmp_tol.magic = BN_TOL_MAGIC;
00304         tmp_tol.dist = 0.005;
00305         tmp_tol.dist_sq = tmp_tol.dist * tmp_tol.dist;
00306         tmp_tol.perp = 1e-6;
00307         tmp_tol.para = 1 - tmp_tol.perp;
00308 
00309         (void)bn_dist_pt3_lseg3( &dist, pca, ei->eu_p->vu_p->v_p->vg_p->coord,
00310                 ei->eu_p->eumate_p->vu_p->v_p->vg_p->coord, fpi->pt, &tmp_tol );
00311         pl_color(fd, 255, 255, 50);
00312         pdv_3line(fd, pca, fpi->pt);
00313 
00314         bu_free((char *)b, "bit vec");
00315         fclose(fd);
00316 }
00317 #endif
00318 static int
00319 Quadrant(fastf_t x, fastf_t y)
00320 {
00321         if( x >= 0.0 )
00322         {
00323                 if( y >= 0.0 )
00324                         return( 1 );
00325                 else
00326                         return( 4 );
00327         }
00328         else
00329         {
00330                 if( y >= 0.0 )
00331                         return( 2 );
00332                 else
00333                         return( 3 );
00334         }
00335 }
00336 
00337 int
00338 nmg_eu_is_part_of_crack(const struct edgeuse *eu)
00339 {
00340         struct loopuse *lu;
00341         struct edgeuse *eu_test;
00342 
00343         NMG_CK_EDGEUSE( eu );
00344 
00345         /* must be part of a loop to be a crack */
00346         if( *eu->up.magic_p != NMG_LOOPUSE_MAGIC )
00347                 return( 0 );
00348 
00349         lu = eu->up.lu_p;
00350         NMG_CK_LOOPUSE( lu );
00351 
00352         for( BU_LIST_FOR( eu_test, edgeuse, &lu->down_hd ) )
00353         {
00354                 if( eu_test == eu )
00355                         continue;
00356 
00357                 if( eu_test->vu_p->v_p == eu->eumate_p->vu_p->v_p &&
00358                     eu_test->eumate_p->vu_p->v_p == eu->vu_p->v_p )
00359                                 return( 1 );
00360         }
00361 
00362         return( 0 );
00363 }
00364 
00365 /**             N M G _ C L A S S _ P T _ E U V U
00366  *
00367  *      Classify a point with respect to an EU where the VU is the
00368  *      closest to the point. The EU and its left vector form an XY
00369  *      coordinate system in the face, with EU along the X-axis and
00370  *      its left vector along the Y-axis. Use these to decompose the
00371  *      direction of the prev_eu into X and Y coordinates (xo,yo) then
00372  *      do the same for the vector to the point to be classed (xpt,ypt).
00373  *      If (xpt,ypt) makes a smaller angle with EU than does (xo,yo),
00374  *      then PT is in the face, otherwise it is out.
00375  *
00376  *
00377  *      It is assumed that eu is from an OT_SAME faceuse, and that
00378  *      the PCA of PT to EU is at eu->vu_p.
00379  */
00380 
00381 int
00382 nmg_class_pt_euvu(const fastf_t *pt, struct edgeuse *eu_in, const struct bn_tol *tol)
00383 {
00384         struct loopuse *lu;
00385         struct edgeuse *prev_eu;
00386         struct edgeuse *eu;
00387         struct vertex *v0,*v1,*v2;
00388         vect_t left;
00389         vect_t eu_dir;
00390         vect_t other_eudir;
00391         vect_t pt_dir;
00392         fastf_t xo,yo;
00393         fastf_t xpt,ypt;
00394         fastf_t len;
00395         int quado,quadpt;
00396         int class = NMG_CLASS_Unknown;
00397         int eu_is_crack=0;
00398         int prev_eu_is_crack=0;
00399 
00400         NMG_CK_EDGEUSE( eu_in );
00401         BN_CK_TOL( tol );
00402 
00403         eu = eu_in;
00404 
00405         if(rt_g.NMG_debug & DEBUG_PT_FU )
00406                 bu_log( "nmg_class_pt_euvu( (%g %g %g), eu=x%x )\n", V3ARGS( pt ), eu );
00407 
00408         if( *eu->up.magic_p != NMG_LOOPUSE_MAGIC )
00409         {
00410                 bu_log( "nmg_class_pt_euvu() called with eu (x%x) that isn't part of a loop\n", eu );
00411                 rt_bomb( "nmg_class_pt_euvu() called with eu that isn't part of a loop" );
00412         }
00413         lu = eu->up.lu_p;
00414         NMG_CK_LOOPUSE( lu );
00415 
00416         eu_is_crack = nmg_eu_is_part_of_crack( eu );
00417 
00418         prev_eu = BU_LIST_PPREV_CIRC( edgeuse, &eu->l );
00419 
00420         prev_eu_is_crack = nmg_eu_is_part_of_crack( prev_eu );
00421 
00422         /* if both EU's are cracks, we cannot classify */
00423         if( eu_is_crack && prev_eu_is_crack )
00424                 return( NMG_CLASS_Unknown );
00425 
00426         if( eu_is_crack )
00427         {
00428                 struct edgeuse *eu_test;
00429                 int done=0;
00430 
00431                 if(rt_g.NMG_debug & DEBUG_PT_FU )
00432                         bu_log( "nmg_class_pt_euvu: eu x%x is a crack\n", eu );
00433 
00434                 /* find next eu from this vertex that is not a crack */
00435                 eu_test = BU_LIST_PNEXT_CIRC( edgeuse, &eu->l );
00436                 while( !done )
00437                 {
00438                         while( eu_test->vu_p->v_p != eu->vu_p->v_p && eu_test != eu )
00439                                 eu_test = BU_LIST_PNEXT_CIRC( edgeuse, &eu_test->l );
00440 
00441                         if( eu_test == eu )
00442                                 done = 1;
00443 
00444                         if( !nmg_eu_is_part_of_crack( eu_test ) )
00445                                 done = 1;
00446 
00447                         if( !done )
00448                                 eu_test = BU_LIST_PNEXT_CIRC( edgeuse, &eu_test->l );
00449                 }
00450 
00451                 if( eu_test == eu ) /* can't get away from crack */
00452                         return( NMG_CLASS_Unknown );
00453                 else
00454                         eu = eu_test;
00455 
00456                 if(rt_g.NMG_debug & DEBUG_PT_FU )
00457                         bu_log( "\tUsing eu x%x instead\n", eu );
00458         }
00459 
00460         if( prev_eu_is_crack )
00461         {
00462                 struct edgeuse *eu_test;
00463                 int done=0;
00464 
00465                 if(rt_g.NMG_debug & DEBUG_PT_FU )
00466                         bu_log( "nmg_class_pt_euvu: prev_eu (x%x) is a crack\n" );
00467 
00468                 /* find previous eu ending at this vertex that is not a crack */
00469                 eu_test = BU_LIST_PPREV_CIRC( edgeuse, &prev_eu->l );
00470                 while( !done )
00471                 {
00472                         while( eu_test->eumate_p->vu_p->v_p != eu->vu_p->v_p && eu_test != prev_eu )
00473                                 eu_test = BU_LIST_PPREV_CIRC( edgeuse, &eu_test->l );
00474 
00475                         if( eu_test == prev_eu )
00476                                 done = 1;
00477 
00478                         if( !nmg_eu_is_part_of_crack( eu_test ) )
00479                                 done = 1;
00480 
00481                         if( !done )
00482                                 eu_test = BU_LIST_PPREV_CIRC( edgeuse, &eu_test->l );
00483                 }
00484 
00485                 if( eu_test == prev_eu ) /* can't get away from crack */
00486                         return( NMG_CLASS_Unknown );
00487                 else
00488                         prev_eu = eu_test;
00489 
00490                 if(rt_g.NMG_debug & DEBUG_PT_FU )
00491                         bu_log( "\tUsing prev_eu x%x instead\n", prev_eu );
00492         }
00493 
00494         /* left is the Y-axis of our XY-coordinate system */
00495         if( nmg_find_eu_leftvec( left,  eu ) )
00496         {
00497                 bu_log( "nmg_class_pt_euvu: nmg_find_eu_leftvec() for eu=x%x failed!\n",eu );
00498                 rt_bomb( "nmg_class_pt_euvu: nmg_find_eu_leftvec() failed!" );
00499         }
00500 
00501         if(rt_g.NMG_debug & DEBUG_PT_FU )
00502                 bu_log( "\tprev_eu = x%x, left = (%g %g %g)\n", prev_eu, V3ARGS( left ) );
00503 
00504         /* v0 is the origin of the XY-coordinat system */
00505         v0 = eu->vu_p->v_p;
00506         NMG_CK_VERTEX( v0 );
00507 
00508         /* v1 is on the X-axis */
00509         v1 = eu->eumate_p->vu_p->v_p;
00510         NMG_CK_VERTEX( v1 );
00511 
00512         /* v2 determines angle prev_eu makes with X-axis */
00513         v2 = prev_eu->vu_p->v_p;
00514         NMG_CK_VERTEX( v2 );
00515 
00516         if(rt_g.NMG_debug & DEBUG_PT_FU )
00517                 bu_log( "\tv0=x%x, v1=x%x, v2=x%x\n", v0, v1, v2 );
00518 
00519         /*  eu_dir is our X-direction */
00520         VSUB2( eu_dir, v1->vg_p->coord, v0->vg_p->coord );
00521 
00522         /* other_eudir is direction along the previous EU (from origin) */
00523         VSUB2( other_eudir, v2->vg_p->coord, v0->vg_p->coord );
00524 
00525         if(rt_g.NMG_debug & DEBUG_PT_FU )
00526                 bu_log( "\teu_dir=(%g %g %g), other_eudir=(%x %x %x)\n",V3ARGS( eu_dir ), V3ARGS( other_eudir ) );
00527 
00528         /* get X and Y components for other_eu */
00529         xo = VDOT( eu_dir, other_eudir );
00530         yo = VDOT( left, other_eudir );
00531 
00532         /* which quadrant does this XY point lie in */
00533         quado = Quadrant( xo, yo );
00534 
00535         if(rt_g.NMG_debug & DEBUG_PT_FU )
00536                 bu_log( "\txo=%g, yo=%g, qudarant=%d\n", xo,yo,quado );
00537 
00538         /* get direction to PT from origin */
00539         VSUB2( pt_dir, pt, v0->vg_p->coord );
00540 
00541         if(rt_g.NMG_debug & DEBUG_PT_FU )
00542                 bu_log( "\tpt_dir=( %g %g %g )\n", V3ARGS( pt_dir ) );
00543 
00544         /* get X and Y components for PT */
00545         xpt = VDOT( eu_dir, pt_dir );
00546         ypt = VDOT( left, pt_dir );
00547 
00548         /* which quadrant does this XY point lie in */
00549         quadpt = Quadrant( xpt, ypt );
00550 
00551         if(rt_g.NMG_debug & DEBUG_PT_FU )
00552                 bu_log( "\txpt=%g, ypt=%g, qudarant=%d\n", xpt,ypt,quadpt );
00553 
00554         /* do a quadrant comparison first (cheap!!!) */
00555         if( quadpt < quado )
00556                 return( NMG_CLASS_AinB );
00557 
00558         if( quadpt > quado )
00559                 return( NMG_CLASS_AoutB );
00560 
00561         /* both are in the same quadrant, need to normalize the corrdinates */
00562         len = sqrt( xo*xo + yo*yo );
00563         xo = xo/len;
00564         yo = yo/len;
00565 
00566         len = sqrt( xpt*xpt + ypt*ypt );
00567         xpt = xpt/len;
00568         ypt = ypt/len;
00569 
00570         if(rt_g.NMG_debug & DEBUG_PT_FU )
00571                 bu_log( "\tNormalized xo,yo=(%g %g), xpt,ypt=( %g %g )\n", xo,yo,xpt,ypt );
00572 
00573         switch( quadpt )
00574         {
00575                 case 1:
00576                         if( xpt >= xo && ypt <= yo )
00577                                 class = NMG_CLASS_AinB;
00578                         else
00579                                 class = NMG_CLASS_AoutB;
00580                         break;
00581                 case 2:
00582                         if( xpt >= xo && ypt >= yo )
00583                                 class = NMG_CLASS_AinB;
00584                         else
00585                                 class = NMG_CLASS_AoutB;
00586                         break;
00587                 case 3:
00588                         if( xpt <= xo && ypt >= yo )
00589                                 class = NMG_CLASS_AinB;
00590                         else
00591                                 class = NMG_CLASS_AoutB;
00592                         break;
00593                 case 4:
00594                         if( xpt <= xo && ypt <= yo )
00595                                 class = NMG_CLASS_AinB;
00596                         else
00597                                 class = NMG_CLASS_AoutB;
00598                         break;
00599                 default:
00600                         bu_log( "This can't happen (illegal quadrant %d)\n", quadpt );
00601                         rt_bomb( "This can't happen (illegal quadrant)\n" );
00602                         break;
00603         }
00604         if(rt_g.NMG_debug & DEBUG_PT_FU )
00605                 bu_log( "returning %s\n", nmg_class_name( class ) );
00606 
00607         return( class );
00608 }
00609 
00610 /**     N M G _ C L A S S _ P T _ E U
00611  *
00612  * If there is no ve_dist structure for this edge, compute one and
00613  * add it to the list.
00614  *
00615  * Sort an edge_info structure into the loops list of edgeuse status
00616  */
00617 static struct edge_info *
00618 nmg_class_pt_eu(struct fpi *fpi, struct edgeuse *eu, struct edge_info *edge_list, const int in_or_out_only)
00619 {
00620         struct bn_tol   tmp_tol;
00621         struct edgeuse  *next_eu;
00622         struct ve_dist  *ved, *ed;
00623         struct edge_info        *ei_p;
00624         struct edge_info        *ei;
00625         pointp_t                eu_pt;
00626         vect_t          left;
00627         vect_t          v_to_pt;
00628         int             found_data = 0;
00629 
00630         NMG_CK_FPI(fpi);
00631         BN_CK_TOL(fpi->tol);
00632 
00633         if (rt_g.NMG_debug & DEBUG_PT_FU) {
00634                 bu_log("pt (%g %g %g) vs_edge (%g %g %g) (%g %g %g) (eu=x%x)\n",
00635                         V3ARGS(fpi->pt),
00636                         V3ARGS(eu->vu_p->v_p->vg_p->coord),
00637                         V3ARGS(eu->eumate_p->vu_p->v_p->vg_p->coord), eu);
00638         }
00639 #if 0
00640         /* try to find this edge in the list of ve_dist's */
00641         for (BU_LIST_FOR(ed, ve_dist, &fpi->ve_dh)) {
00642                 NMG_CK_VED(ed);
00643                 if (ed->magic_p == &eu->e_p->magic) {
00644 
00645                         /* found the data for this edge */
00646 
00647                         if (rt_g.NMG_debug & DEBUG_PT_FU)
00648                                 bu_log ("pt previously classified WRT Edge\n");
00649 
00650                         ved = ed;
00651                         found_data = 1;
00652                         goto found;
00653                 }
00654 
00655                 if (ed->dist <= fpi->tol->dist_sq &&
00656                     (ed->magic_p == &eu->vu_p->v_p->magic ||
00657                      ed->magic_p == &eu->eumate_p->vu_p->v_p->magic) ) {
00658                         /* The point is within tolerance of an endpoint
00659                          * of the edge.
00660                          */
00661                         if (rt_g.NMG_debug & DEBUG_PT_FU) {
00662                                 register struct vertex *v_p =
00663                                         (struct vertex *)ed->magic_p;
00664                                 bu_log ("vertex (%g %g %g) of edge previously touched\n",
00665                                         V3ARGS(v_p->vg_p->coord));
00666                         }
00667                         ved = ed;
00668                         found_data = 1;
00669                         goto found;
00670                 }
00671         }
00672 #endif
00673 
00674         /* we didn't find a ve_dist structure for this edge, so we'll
00675          * have to do the calculations.
00676          */
00677         tmp_tol = (*fpi->tol);
00678         if( in_or_out_only )
00679         {
00680                 tmp_tol.dist = 0.0;
00681                 tmp_tol.dist_sq = 0.0;
00682         }
00683 
00684         ved = (struct ve_dist *)bu_malloc(sizeof(struct ve_dist), "ve_dist structure");
00685         ved->magic_p = &eu->e_p->magic;
00686         ved->status = bn_distsq_pt3_lseg3(&ved->dist,
00687                                         eu->vu_p->v_p->vg_p->coord,
00688                                         eu->eumate_p->vu_p->v_p->vg_p->coord,
00689                                         fpi->pt,
00690                                         &tmp_tol);
00691         ved->v1 = eu->vu_p->v_p;
00692         ved->v2 = eu->eumate_p->vu_p->v_p;
00693         BU_LIST_MAGIC_SET(&ved->l, NMG_VE_DIST_MAGIC);
00694         BU_LIST_APPEND(&fpi->ve_dh, &ved->l);
00695         eu_pt = ved->v1->vg_p->coord;
00696 
00697         if (rt_g.NMG_debug & DEBUG_PT_FU )
00698         {
00699                 bu_log( "nmg_class_pt_eu: status for eu x%x (%g %g %g)<->(%g %g %g) vs pt (%g %g %g) is %d\n",
00700                         eu, V3ARGS( eu->vu_p->v_p->vg_p->coord ),
00701                         V3ARGS( eu->eumate_p->vu_p->v_p->vg_p->coord ),
00702                         V3ARGS( fpi->pt ), ved->status );
00703                 bu_log( "\tdist = %g\n", ved->dist );
00704         }
00705 
00706 
00707 
00708         /* Add a struct for this edgeuse to the loop's list of dist-sorted
00709          * edgeuses.
00710          */
00711         ei = (struct edge_info *)bu_malloc(sizeof(struct edge_info), "struct edge_info");
00712         ei->ved_p = ved;
00713         ei->eu_p = eu;
00714         BU_LIST_MAGIC_SET(&ei->l, NMG_EDGE_INFO_MAGIC);
00715 
00716         /* compute the status (ei->status) of the point WRT this edge */
00717 
00718         switch (ved->status) {
00719         case 0: /* pt is on the edge(use) */
00720                 ei->class = NMG_CLASS_AonBshared;
00721                 if (fpi->eu_func &&
00722                     (fpi->hits == NMG_FPI_PERUSE ||
00723                      (fpi->hits == NMG_FPI_PERGEOM && !found_data) ) ) {
00724                         fpi->eu_func(eu, fpi->pt, fpi->priv);
00725                 }
00726                 break;
00727         case 1: /* within tolerance of endpoint at ved->v1 */
00728                 ei->class = NMG_CLASS_AonBshared;
00729                 /* add an entry for the vertex in the edge list so that
00730                  * other uses of this vertex will claim the point is within
00731                  * tolerance without re-computing
00732                  */
00733                 ed = (struct ve_dist *)bu_malloc(sizeof(struct ve_dist), "ve_dist structure");
00734                 ed->magic_p = &ved->v1->magic;
00735                 ed->status = ved->status;
00736                 ed->v1 = ed->v2 = ved->v1;
00737 
00738                 BU_LIST_MAGIC_SET(&ed->l, NMG_VE_DIST_MAGIC);
00739                 BU_LIST_APPEND(&fpi->ve_dh, &ed->l);
00740 
00741                 if (fpi->vu_func &&
00742                     (fpi->hits == NMG_FPI_PERUSE ||
00743                      (fpi->hits == NMG_FPI_PERGEOM && !found_data) ) ) {
00744                         fpi->vu_func(eu->vu_p, fpi->pt, fpi->priv);
00745                 }
00746 
00747                 break;
00748         case 2: /* within tolerance of endpoint at ved->v2 */
00749                 ei->class = NMG_CLASS_AonBshared;
00750                 /* add an entry for the vertex in the edge list so that
00751                  * other uses of this vertex will claim the point is within
00752                  * tolerance without re-computing
00753                  */
00754                 ed = (struct ve_dist *)bu_malloc(sizeof(struct ve_dist), "ve_dist structure");
00755                 ed->magic_p = &ved->v2->magic;
00756                 ed->status = ved->status;
00757                 ed->v1 = ed->v2 = ved->v2;
00758 
00759                 BU_LIST_MAGIC_SET(&ed->l, NMG_VE_DIST_MAGIC);
00760                 BU_LIST_APPEND(&fpi->ve_dh, &ed->l);
00761                 if (fpi->vu_func &&
00762                     (fpi->hits == NMG_FPI_PERUSE ||
00763                      (fpi->hits == NMG_FPI_PERGEOM && !found_data) ) ) {
00764                         fpi->vu_func(eu->eumate_p->vu_p, fpi->pt, fpi->priv);
00765                 }
00766                 break;
00767 
00768         case 3: /* PCA of pt on line is within tolerance of ved->v1 of segment */
00769                 ei->class = nmg_class_pt_euvu( fpi->pt, eu, fpi->tol );
00770                 if( ei->class == NMG_CLASS_Unknown )
00771                         ei->ved_p->dist = MAX_FASTF;
00772                 break;
00773         case 4: /* PCA of pt on line is within tolerance of ved->v2 of segment */
00774                 next_eu = BU_LIST_PNEXT_CIRC( edgeuse, &eu->l);
00775                 ei->class = nmg_class_pt_euvu( fpi->pt, next_eu, fpi->tol );
00776                 if( ei->class == NMG_CLASS_Unknown )
00777                         ei->ved_p->dist = MAX_FASTF;
00778                 break;
00779 
00780         case 5: /* PCA is along length of edge, but point is NOT on edge. */
00781                 if (nmg_find_eu_left_non_unit( left, eu ))
00782                         rt_bomb("can't find left vector\n");
00783                 /* take dot product of v->pt vector with left to determine
00784                  * if pt is inside/left of edge
00785                  */
00786                 VSUB2(v_to_pt, fpi->pt, eu_pt);
00787                 if (VDOT(v_to_pt, left) >= 0.0)
00788                         ei->class = NMG_CLASS_AinB;
00789                 else
00790                         ei->class = NMG_CLASS_AoutB;
00791                 break;
00792         default:
00793                 bu_log("%s:%d status = %d\n", __FILE__, __LINE__, ved->status);
00794                 rt_bomb("Why did this happen?");
00795                 break;
00796         }
00797 
00798 
00799         if (rt_g.NMG_debug & DEBUG_PT_FU) {
00800                 bu_log("pt @ dist %g from edge classed %s vs edge\n",
00801                         ei->ved_p->dist, nmg_class_name(ei->class));
00802 /*              pl_pt_e(fpi, ei); */
00803         }
00804 
00805         /* now that it's complete, add ei to the edge list */
00806         for (BU_LIST_FOR(ei_p, edge_info, &edge_list->l)) {
00807                 /* if the distance to this edge is smaller, or
00808                  * if the distance is the same & the edge is the same
00809                  *      Insert edge_info struct here in list
00810                  */
00811                 if (ved->dist < ei_p->ved_p->dist ||
00812                    (ved->dist == ei_p->ved_p->dist &&
00813                     ei_p->ved_p->magic_p == ved->magic_p) )
00814                         break;
00815         }
00816 
00817         BU_LIST_INSERT(&ei_p->l, &ei->l);
00818         return ei;
00819 }
00820 
00821 /**
00822  * Make a list of all edgeuses which are at the same distance as the
00823  * first element on the list.  Toss out opposing pairs of edgeuses of the
00824  * same edge.
00825  *
00826  */
00827 HIDDEN void make_near_list( struct edge_info *edge_list, struct bu_list *near1)
00828 {
00829         struct edge_info *ei;
00830         struct edge_info *ei_p;
00831         struct edge_info *tmp;
00832         double dist;
00833 
00834         BU_CK_LIST_HEAD(&edge_list->l);
00835         BU_CK_LIST_HEAD(near1);
00836 
00837         /* toss opposing pairs of uses of the same edge from the list */
00838         ei = BU_LIST_FIRST( edge_info, &edge_list->l);
00839         while( BU_LIST_NOT_HEAD( &ei->l, &edge_list->l)) {
00840                 NMG_CK_EI(ei);
00841                 ei_p = BU_LIST_FIRST( edge_info, &edge_list->l);
00842                 while( BU_LIST_NOT_HEAD( &ei_p->l, &edge_list->l)) {
00843                         NMG_CK_EI(ei_p);
00844                         NMG_CK_VED(ei_p->ved_p);
00845 
00846                         /* if we've found an opposing use of the same
00847                          *    edge toss the pair of them
00848                          */
00849                         if (ei_p->ved_p->magic_p == ei->ved_p->magic_p &&
00850                             ei_p->eu_p->eumate_p->vu_p->v_p == ei->eu_p->vu_p->v_p &&
00851                             ei_p->eu_p->vu_p->v_p == ei->eu_p->eumate_p->vu_p->v_p ) {
00852                                 if (rt_g.NMG_debug & DEBUG_PT_FU ) {
00853                                         bu_log("tossing edgeuse pair:\n");
00854                                         bu_log("(%g %g %g) -> (%g %g %g)\n",
00855                                                 V3ARGS(ei->eu_p->vu_p->v_p->vg_p->coord),
00856                                                 V3ARGS(ei->eu_p->eumate_p->vu_p->v_p->vg_p->coord));
00857                                         bu_log("(%g %g %g) -> (%g %g %g)\n",
00858                                                 V3ARGS(ei_p->eu_p->vu_p->v_p->vg_p->coord),
00859                                                 V3ARGS(ei_p->eu_p->eumate_p->vu_p->v_p->vg_p->coord));
00860                                 }
00861 
00862                                 tmp = ei_p;
00863                                 ei_p = BU_LIST_PLAST(edge_info, &ei_p->l);
00864                                 BU_LIST_DEQUEUE(&tmp->l);
00865                                 bu_free((char *)tmp, "edge info struct");
00866                                 tmp = ei;
00867                                 ei = BU_LIST_PLAST(edge_info, &ei->l);
00868                                 BU_LIST_DEQUEUE(&tmp->l);
00869                                 bu_free((char *)tmp, "edge info struct");
00870                                 break;
00871                         }
00872                         ei_p = BU_LIST_PNEXT( edge_info, &ei_p->l );
00873                 }
00874                 ei = BU_LIST_PNEXT( edge_info, &ei->l );
00875         }
00876 
00877         if( BU_LIST_IS_EMPTY( &edge_list->l ) )
00878                 return;
00879 
00880         ei = BU_LIST_FIRST(edge_info, &edge_list->l);
00881         NMG_CK_EI(ei);
00882         NMG_CK_VED(ei->ved_p);
00883         dist = ei->ved_p->dist;
00884 
00885         /* create "near" list with all ei's at this dist */
00886         for (BU_LIST_FOR(ei, edge_info, &edge_list->l)) {
00887                 NMG_CK_EI(ei);
00888                 NMG_CK_VED(ei->ved_p);
00889                 if (ei->ved_p->dist == dist) {
00890                         ei_p = BU_LIST_PLAST(edge_info, &ei->l);
00891                         BU_LIST_DEQUEUE(&ei->l);
00892                         BU_LIST_APPEND(near1, &ei->l);
00893                         ei = ei_p;
00894                 }
00895         }
00896 
00897         if (rt_g.NMG_debug & DEBUG_PT_FU ) {
00898                 bu_log("dist %g near list\n", dist);
00899                 for (BU_LIST_FOR(ei, edge_info, near1)) {
00900                         bu_log("\t(%g %g %g) -> (%g %g %g)\n",
00901                                 V3ARGS(ei->eu_p->vu_p->v_p->vg_p->coord),
00902                                 V3ARGS(ei->eu_p->eumate_p->vu_p->v_p->vg_p->coord));
00903                         bu_log("\tdist:%g class:%s status:%d\n\t\tv1(%g %g %g) v2(%g %g %g)\n",
00904                         ei->ved_p->dist, nmg_class_name(ei->class),
00905                         ei->ved_p->status,
00906                         V3ARGS(ei->ved_p->v1->vg_p->coord),
00907                         V3ARGS(ei->ved_p->v2->vg_p->coord));
00908                         bu_log( "\tei->ved_p->magic_p=x%x, ei->eu_p->vu_p=x%x, ei->eu_p->eumate_p->vu_p=x%x\n",
00909                                 ei->ved_p->magic_p, ei->eu_p->vu_p, ei->eu_p->eumate_p->vu_p );
00910                 }
00911         }
00912 }
00913 
00914 
00915 
00916 
00917 
00918 static void
00919 pl_pt_lu(struct fpi *fpi, const struct loopuse *lu, struct edge_info *ei)
00920 {
00921         FILE *fd;
00922         char name[25];
00923         long *b;
00924         static int plot_file_number=0;
00925         int i;
00926         point_t p1, p2;
00927         point_t pca;
00928         fastf_t dist;
00929         struct bn_tol tmp_tol;
00930 
00931         NMG_CK_FPI(fpi);
00932         NMG_CK_FACEUSE(fpi->fu_p);
00933         NMG_CK_LOOPUSE(lu);
00934         NMG_CK_EI(ei);
00935 
00936         sprintf(name, "pt_lu%02d.pl", plot_file_number++);
00937         if ((fd=fopen(name, "w")) == (FILE *)NULL) {
00938                 perror(name);
00939                 bu_bomb("unable to open file for writing");
00940         }
00941 
00942         bu_log("\toverlay %s\n", name);
00943         b = (long *)bu_calloc( fpi->fu_p->s_p->r_p->m_p->maxindex,
00944                 sizeof(long), "bit vec"),
00945 
00946         pl_erase(fd);
00947         pd_3space(fd,
00948                 fpi->fu_p->f_p->min_pt[0]-1.0,
00949                 fpi->fu_p->f_p->min_pt[1]-1.0,
00950                 fpi->fu_p->f_p->min_pt[2]-1.0,
00951                 fpi->fu_p->f_p->max_pt[0]+1.0,
00952                 fpi->fu_p->f_p->max_pt[1]+1.0,
00953                 fpi->fu_p->f_p->max_pt[2]+1.0);
00954 
00955         nmg_pl_lu(fd, lu, b, 255, 255, 255);
00956 
00957         tmp_tol.magic = BN_TOL_MAGIC;
00958         tmp_tol.dist = 0.005;
00959         tmp_tol.dist_sq = tmp_tol.dist * tmp_tol.dist;
00960         tmp_tol.perp = 1e-6;
00961         tmp_tol.para = 1 - tmp_tol.perp;
00962 
00963         (void)bn_dist_pt3_lseg3( &dist, pca, ei->eu_p->vu_p->v_p->vg_p->coord,
00964                 ei->eu_p->eumate_p->vu_p->v_p->vg_p->coord, fpi->pt, &tmp_tol );
00965 
00966         pl_color(fd, 255, 255, 50);
00967         pdv_3line(fd, pca, fpi->pt);
00968 
00969         pl_color(fd, 255, 64, 255);
00970 
00971         /* make a nice axis-cross at the point in question */
00972         for (i=0 ; i < 3 ; i++) {
00973                 VMOVE(p1, fpi->pt);
00974                 p1[i] -= 1.0;
00975                 VMOVE(p2, fpi->pt);
00976                 p2[i] += 1.0;
00977                 pdv_3line(fd, p1, p2);
00978         }
00979 
00980         bu_free((char *)b, "bit vec");
00981         fclose(fd);
00982 }
00983 
00984 
00985 
00986 
00987 /**     C O M P U T E _ L O O P _ C L A S S
00988  *
00989  * Given a list of edge_info structures for the edges of a loop,
00990  *      determine what the classification for the loop should be.
00991  *
00992  *  If passed a "crack" loop, will produce random results.
00993  */
00994 
00995 static int
00996 compute_loop_class(struct fpi *fpi,
00997                    const struct loopuse *lu,
00998                    struct edge_info *edge_list)
00999 {
01000         struct edge_info *ei;
01001         struct edge_info *ei_vdot_max;
01002         struct bu_list  near1;
01003         int             lu_class = NMG_CLASS_Unknown;
01004 
01005         if (rt_g.NMG_debug & DEBUG_PT_FU ) {
01006                 bu_log("compute_loop_class()\n");
01007                 for (BU_LIST_FOR(ei, edge_info, &edge_list->l)) {
01008 bu_log("dist:%g class:%s status:%d\n\tv1(%g %g %g) v2(%g %g %g)\n",
01009                                 ei->ved_p->dist, nmg_class_name(ei->class),
01010                                 ei->ved_p->status,
01011                                 V3ARGS(ei->ved_p->v1->vg_p->coord),
01012                                 V3ARGS(ei->ved_p->v2->vg_p->coord));
01013                 }
01014         }
01015 
01016         BU_CK_LIST_HEAD(&edge_list->l);
01017         BU_LIST_INIT(&near1);
01018 
01019         /* get a list of "closest/useful" edges to use in classifying
01020          * the pt WRT the loop
01021          */
01022         while (BU_LIST_IS_EMPTY(&near1) && BU_LIST_NON_EMPTY(&edge_list->l)) {
01023                 make_near_list(edge_list, &near1);
01024         }
01025 
01026         if (BU_LIST_IS_EMPTY(&near1)) {
01027                 /* This was a "crack" or "snake" loop */
01028 
01029                 if (lu->orientation == OT_SAME) {
01030                         lu_class = NMG_CLASS_AoutB;
01031                 } else if (lu->orientation == OT_OPPOSITE) {
01032                         lu_class = NMG_CLASS_AinB;
01033                 } else
01034                         rt_bomb("bad lu orientation\n");
01035 
01036                 if (rt_g.NMG_debug & DEBUG_PT_FU ) {
01037                         bu_log("list was empty, so class is %s\n",
01038                                 nmg_class_name(lu_class));
01039                 }
01040                 goto departure;
01041         }
01042 
01043 
01044         ei_vdot_max = (struct edge_info *)NULL;
01045 
01046         for (BU_LIST_FOR(ei, edge_info, &near1)) {
01047                 NMG_CK_EI(ei);
01048                 NMG_CK_VED(ei->ved_p);
01049                 switch (ei->ved_p->status) {
01050                 case 0: /* pt is on edge */
01051                 case 1: /* pt is on ei->ved_p->v1 */
01052                 case 2: /* pt is on ei->ved_p->v2 */
01053                         lu_class = NMG_CLASS_AonBshared;
01054                         if (rt_g.NMG_debug & DEBUG_PT_FU )
01055                                 pl_pt_lu(fpi, lu, ei);
01056                         goto departure;
01057                 case 3: /* pt pca is v1 */
01058                 case 4: /* pt pca is v2 */
01059                 case 5: /* pt pca between v1 and v2 */
01060                         lu_class = ei->class;
01061                         if (rt_g.NMG_debug & DEBUG_PT_FU ) {
01062                                 bu_log("found status 5 edge, loop class is %s\n",
01063                                         nmg_class_name(lu_class));
01064                         }
01065                         if (rt_g.NMG_debug & DEBUG_PT_FU )
01066                                 pl_pt_lu(fpi, lu, ei);
01067                         goto departure;
01068                 default:
01069                         bu_log("%s:%d status = %d\n",
01070                                 __FILE__, __LINE__, ei->ved_p->status);
01071                         rt_bomb("Why did this happen?");
01072                         break;
01073                 }
01074         }
01075         if (ei_vdot_max) {
01076                 if (rt_g.NMG_debug & DEBUG_PT_FU)
01077                         pl_pt_lu(fpi, lu, ei_vdot_max);
01078         } else {
01079                 bu_log("%s:%d ei_vdot_max not set\n",
01080                         __FILE__, __LINE__);
01081                 rt_bomb("How does this happen?\n");
01082         }
01083 departure:
01084 
01085         /* the caller will get whatever is left of the edge_list, but
01086          * we need to free up the "near" list
01087          */
01088         while (BU_LIST_WHILE(ei, edge_info, &near1)) {
01089                 BU_LIST_DEQUEUE( &ei->l );
01090                 bu_free( (char *)ei, "edge_info struct");
01091         }
01092 
01093         if (rt_g.NMG_debug & DEBUG_PT_FU ) {
01094                 bu_log("compute_loop_class() returns %s\n",
01095                         nmg_class_name(lu_class));
01096         }
01097 
01098         return lu_class;
01099 }
01100 /**
01101  *
01102  * For each edgeuse, compute an edge_info structure.
01103  *
01104  * if min_dist == 0 return ON
01105  *
01106  * For dist min -> max
01107  *      if even # of uses of edge in this loop
01108  *              "ignore" all uses of this edge since we can't answer the
01109  *                  "spike" problem:    *---------*
01110  *                                      | .       |
01111  *                                      *---*     |  .
01112  *                                      |         *----*
01113  *                                      |         |
01114  *                                      *---------*
01115  *      else (odd # of uses of edge in this loop)
01116  *              "ignore" consecutive uses of the same edge to avoid the
01117  *                  "accordian pleat" problem:  *-------*
01118  *                                              |  .    |
01119  *                                              *----*  |
01120  *                                              *----*  |
01121  *                                              *----*  |
01122  *                                              *----*--*
01123  *              classify pt WRT remaining edgeuse
01124  *
01125  * The "C-clamp" problem:
01126  *      *---------------*
01127  *      |               |
01128  *      |  *----*       |
01129  *      |  |    |   .   |
01130  *      |  |    *-------*
01131  *      |  |    |       |
01132  *      |  *----*       |
01133  *      |               |
01134  *      *---------------*
01135  *
01136  */
01137 static int
01138 nmg_class_pt_lu(struct loopuse *lu, struct fpi *fpi, const int in_or_out_only)
01139 {
01140         int     lu_class = NMG_CLASS_Unknown;
01141 
01142         NMG_CK_FPI(fpi);
01143         NMG_CK_LOOPUSE(lu);
01144         NMG_CK_LOOP(lu->l_p);
01145         NMG_CK_LOOP_G(lu->l_p->lg_p);
01146 
01147 
01148         if (!V3PT_IN_RPP( fpi->pt, lu->l_p->lg_p->min_pt, lu->l_p->lg_p->max_pt)) {
01149                 /* point is not in RPP of loop */
01150 
01151                 if (rt_g.NMG_debug & DEBUG_PT_FU )
01152                 {
01153                         bu_log("nmg_class_pt_lu( pt(%g %g %g) outside loop RPP\n",
01154                                 V3ARGS(fpi->pt));
01155                         bu_log( "   lu RPP: ( %g %g %g ) <-> ( %g %g %g )\n",
01156                                 V3ARGS(lu->l_p->lg_p->min_pt), V3ARGS( lu->l_p->lg_p->max_pt) );
01157                 }
01158 
01159                 if (lu->orientation == OT_SAME)
01160                         return NMG_CLASS_AoutB;
01161                 else if (lu->orientation == OT_OPPOSITE)
01162                         return NMG_CLASS_AinB;
01163                 else if (lu->orientation == OT_UNSPEC)
01164                         return NMG_CLASS_Unknown;
01165 
01166         }
01167 
01168         if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_EDGEUSE_MAGIC) {
01169                 register struct edgeuse *eu;
01170                 struct edge_info edge_list;
01171                 struct edge_info *ei;
01172                 int             is_crack;
01173 
01174                 is_crack = nmg_loop_is_a_crack(lu);
01175                 if( lu->orientation == OT_OPPOSITE && is_crack )  {
01176                         /*  Even if point lies on a crack, if it's an
01177                          *  OT_OPPOSITE crack loop, it subtracts nothing.
01178                          *  Just ignore it.
01179                          */
01180                         lu_class = NMG_CLASS_AinB;
01181                         if (rt_g.NMG_debug & DEBUG_PT_FU )
01182                                 bu_log("nmg_class_pt_lu() ignoring OT_OPPOSITE crack loop\n");
01183                         goto out;
01184                 }
01185 
01186                 BU_LIST_INIT(&edge_list.l);
01187 
01188                 for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
01189                         ei = nmg_class_pt_eu(fpi, eu, &edge_list, in_or_out_only);
01190                         NMG_CK_EI(ei);
01191                         NMG_CK_VED(ei->ved_p);
01192                         if ( !in_or_out_only && ei->ved_p->dist < fpi->tol->dist_sq) {
01193                                 lu_class = NMG_CLASS_AinB;
01194                                 break;
01195                         }
01196                 }
01197                 /* */
01198                 if (lu_class == NMG_CLASS_Unknown)  {
01199                         /* pt does not touch any edge or vertex */
01200                         if( is_crack )  {
01201                                 /* orientation here is OT_SAME */
01202                                 lu_class = NMG_CLASS_AoutB;
01203                         } else {
01204                                 lu_class = compute_loop_class(fpi, lu, &edge_list);
01205                         }
01206                 } else {
01207                         /* pt touches edge or vertex */
01208                         if (rt_g.NMG_debug & DEBUG_PT_FU )
01209                                 bu_log("loop class already known (pt must touch edge)\n");
01210                 }
01211 
01212                 /* free up the edge_list elements */
01213                 while ( BU_LIST_WHILE(ei, edge_info, &edge_list.l) ) {
01214                         BU_LIST_DEQUEUE( &ei->l );
01215                         bu_free( (char *)ei, "edge info struct");
01216                 }
01217         } else if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_VERTEXUSE_MAGIC) {
01218                 register struct vertexuse *vu;
01219                 int v_class;
01220 
01221                 vu = BU_LIST_FIRST(vertexuse, &lu->down_hd);
01222                 v_class = nmg_class_pt_vu(fpi, vu);
01223 
01224                 switch (lu->orientation) {
01225                 case OT_BOOLPLACE:
01226                 case OT_SAME:
01227                         if (v_class == NMG_FPI_TOUCHED)
01228                                 lu_class = NMG_CLASS_AinB;
01229                         else
01230                                 lu_class = NMG_CLASS_AoutB;
01231                         break;
01232                 case OT_OPPOSITE:
01233                         /* Why even call nmg_class_pt_vu() here, if return isn't used? */
01234                                 lu_class = NMG_CLASS_AinB;
01235                         break;
01236                 case OT_UNSPEC:
01237                                 lu_class = NMG_CLASS_Unknown;
01238                         break;
01239                 default:
01240                         bu_log("nmg_class_pt_lu() hit %s loop at vu=x%x\n",
01241                                 nmg_orientation(lu->orientation), vu);
01242                         rt_bomb("nmg_class_pt_lu() Loop orientation error\n");
01243                         break;
01244                 }
01245         } else {
01246                 bu_log("%s:%d bad child of loopuse\n", __FILE__, __LINE__);
01247                 rt_bomb("nmg_class_pt_lu() crash and burn\n");
01248         }
01249 
01250 
01251 out:
01252         if (rt_g.NMG_debug & DEBUG_PT_FU )
01253                 bu_log("nmg_class_pt_lu() pt classed %s vs loop\n", nmg_class_name(lu_class));
01254 
01255         return lu_class;
01256 }
01257 
01258 
01259 static void
01260 plot_parity_error(const struct faceuse *fu, const fastf_t *pt)
01261 {
01262         long *b;
01263         FILE *fp;
01264         point_t p1, p2;
01265         int i;
01266 
01267         NMG_CK_FACEUSE(fu);
01268 
01269         if (!(fp=fopen("pt_fu_parity_error.pl", "w")) )
01270                 rt_bomb("error opening pt_fu_parity_error.pl\n");
01271 
01272 
01273         bu_log("overlay pt_fu_parity_error.pl\n");
01274 
01275         b = (long *)bu_calloc( fu->s_p->r_p->m_p->maxindex,
01276                               sizeof(long), "bit vec"),
01277 
01278 
01279         pl_erase(fp);
01280         pd_3space(fp,
01281                 fu->f_p->min_pt[0]-1.0,
01282                 fu->f_p->min_pt[1]-1.0,
01283                 fu->f_p->min_pt[2]-1.0,
01284                 fu->f_p->max_pt[0]+1.0,
01285                 fu->f_p->max_pt[1]+1.0,
01286                 fu->f_p->max_pt[2]+1.0);
01287 
01288         nmg_pl_fu(fp, fu, b, 200, 200, 200);
01289 
01290 
01291         /* make a nice axis-cross at the point in question */
01292         for (i=0 ; i < 3 ; i++) {
01293                 VMOVE(p1, pt);
01294                 p1[i] -= 1.0;
01295                 VMOVE(p2, pt);
01296                 p2[i] += 1.0;
01297                 pdv_3line(fp, p1, p2);
01298         }
01299 
01300         bu_free((char *)b, "plot table");
01301         fclose(fp);
01302 
01303 }
01304 
01305 /**
01306  *
01307  * Classify a point on a face's plane as being inside/outside the area
01308  * of the face.
01309  *
01310  * For each loopuse, compute IN/ON/OUT
01311  *
01312  * if any loop has pt classified as "ON" return "ON" (actually returns "IN" -jra)
01313  *
01314  * ignore all OT_SAME loops w/pt classified as "OUT"
01315  * ignore all OT_OPPOSITE loops w/pt classified as "IN"
01316  * If (# OT_SAME loops == # OT_OPPOSITE loops)
01317  *      pt is "OUT"
01318  * else if (# OT_SAME loops - 1 == # OT_OPPOSITE loops)
01319  *      pt is "IN"
01320  * else
01321  *      Error! panic!
01322  *
01323  *
01324  *  Values for "call_on_hits"
01325  *      1       find all elements pt touches, call user routine for each geom.
01326  *      2       find all elements pt touches, call user routine for each use
01327  *
01328  *  in_or_out_only:
01329  *      non-zero        pt is known NOT to be on an EU of FU
01330  *         0            pt may be on an EU of FU
01331  *
01332  *  Returns -
01333  *      NMG_CLASS_AonB, etc...
01334  */
01335 int
01336 nmg_class_pt_fu_except(const fastf_t *pt, const struct faceuse *fu, const struct loopuse *ignore_lu, void (*eu_func) (/* ??? */), void (*vu_func) (/* ??? */), const char *priv, const int call_on_hits, const int in_or_out_only, const struct bn_tol *tol)
01337 
01338 
01339 
01340                                         /* func to call when pt on edgeuse */
01341                                         /* func to call when pt on vertexuse*/
01342                                         /* private data for [ev]u_func */
01343 
01344 
01345 
01346 {
01347         struct fpi      fpi;
01348         struct loopuse  *lu;
01349         int             ot_same_in = 0;
01350         int             ot_opposite_out = 0;
01351         int             ot_same[4];
01352         int             ot_opposite[4];
01353         int             lu_class;
01354         int             fu_class = NMG_CLASS_Unknown;
01355         double          dist;
01356         struct ve_dist  *ved_p;
01357         int             i;
01358 
01359         if (rt_g.NMG_debug & DEBUG_PT_FU )
01360                 bu_log("nmg_class_pt_fu_except( pt=(%g %g %g), fu=x%x )\n", V3ARGS(pt), fu);
01361 
01362         if(fu->orientation != OT_SAME) rt_bomb("nmg_class_pt_fu_except() not OT_SAME\n");
01363 
01364         NMG_CK_FACEUSE(fu);
01365         NMG_CK_FACE(fu->f_p);
01366         NMG_CK_FACE_G_PLANE(fu->f_p->g.plane_p);
01367         if(ignore_lu) NMG_CK_LOOPUSE(ignore_lu);
01368         BN_CK_TOL(tol);
01369 
01370         /* Validate distance from point to plane */
01371         NMG_GET_FU_PLANE( fpi.norm, fu );
01372         if( (dist=fabs(DIST_PT_PLANE( pt, fpi.norm ))) > tol->dist )  {
01373                 bu_log("nmg_class_pt_fu_except() ERROR, point (%g,%g,%g)\nnot on face %g %g %g %g,\ndist=%g\n",
01374                         V3ARGS(pt), V4ARGS(fpi.norm), dist );
01375         }
01376 
01377         if( !V3PT_IN_RPP( pt, fu->f_p->min_pt, fu->f_p->max_pt ) )  {
01378                 /* point is not in RPP of face, so there's NO WAY this point
01379                  * is anything but OUTSIDE
01380                  */
01381                 if (rt_g.NMG_debug & DEBUG_PT_FU )
01382                         bu_log("nmg_class_pt_fu_except( (%g %g %g) ouside face RPP\n",
01383                                 V3ARGS(pt));
01384 
01385                 return NMG_CLASS_AoutB;
01386         }
01387 
01388         for( i=0; i<4; i++ )  {
01389                 ot_same[i] = ot_opposite[i] = 0;
01390         }
01391 
01392         fpi.fu_p = fu;
01393         fpi.tol = tol;
01394         BU_LIST_INIT(&fpi.ve_dh);
01395         VMOVE(fpi.pt, pt);
01396         fpi.eu_func = eu_func;
01397         fpi.vu_func = vu_func;
01398         fpi.priv = priv;
01399         fpi.hits = call_on_hits;
01400         fpi.magic = NMG_FPI_MAGIC;
01401 
01402         for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) {
01403                 if( ignore_lu && (ignore_lu==lu || ignore_lu==lu->lumate_p) )
01404                         continue;
01405 
01406                 /* Ignore OT_BOOLPLACE, etc */
01407                 if( lu->orientation != OT_SAME && lu->orientation != OT_OPPOSITE )
01408                         continue;
01409 
01410                 lu_class = nmg_class_pt_lu(lu, &fpi, in_or_out_only);
01411                 if (rt_g.NMG_debug & DEBUG_PT_FU )
01412                         bu_log("loop %s says pt is %s\n",
01413                                 nmg_orientation(lu->orientation),
01414                                 nmg_class_name(lu_class) );
01415 
01416                 if( lu_class < 0 || lu_class > 3 )  {
01417                         bu_log("nmg_class_pt_fu_except() lu_class=%s %d\n",
01418                                 nmg_class_name(lu_class), lu_class);
01419                         rt_bomb("nmg_class_pt_fu_except() bad lu_class\n");
01420                 }
01421 
01422                 if (lu->orientation == OT_OPPOSITE)  {
01423                         ot_opposite[lu_class]++;
01424                         if( lu_class == NMG_CLASS_AoutB )
01425                                 ot_opposite_out++;
01426                 } else if (lu->orientation == OT_SAME )  {
01427                         ot_same[lu_class]++;
01428                         if (lu_class == NMG_CLASS_AinB ||
01429                              lu_class == NMG_CLASS_AonBshared)
01430                                 ot_same_in++;
01431                 }
01432         }
01433 
01434         if (rt_g.NMG_debug & DEBUG_PT_FU )  {
01435                 bu_log("loops ot_same_in:%d ot_opposite_out:%d\n",
01436                         ot_same_in, ot_opposite_out);
01437                 bu_log("loops in/onS/onA/out ot_same=%d/%d/%d/%d ot_opp=%d/%d/%d/%d\n",
01438                         ot_same[0], ot_same[1], ot_same[2], ot_same[3],
01439                         ot_opposite[0], ot_opposite[1], ot_opposite[2], ot_opposite[3] );
01440         }
01441 
01442         if (ot_same_in == ot_opposite_out)  {
01443                 /* All the holes cancel out the solid loops */
01444                 fu_class = NMG_CLASS_AoutB;
01445         } else if (ot_same_in > ot_opposite_out) {
01446                 /* XXX How can this difference be > 1 ? */
01447                 fu_class = NMG_CLASS_AinB;
01448         } else {
01449                 /* Panic time!  How did I get a parity mis-match? */
01450                 bu_log("loops in/onS/onA/out ot_same=%d/%d/%d/%d ot_opp=%d/%d/%d/%d\n",
01451                         ot_same[0], ot_same[1], ot_same[2], ot_same[3],
01452                         ot_opposite[0], ot_opposite[1], ot_opposite[2], ot_opposite[3] );
01453                 bu_log("nmg_class_pt_fu_except(%g %g %g)\nParity error @ %s:%d ot_same_in:%d ot_opposite_out:%d\n",
01454                         V3ARGS(pt), __FILE__, __LINE__,
01455                         ot_same_in, ot_opposite_out);
01456                 bu_log( "fu=x%x\n",  fu );
01457                 nmg_pr_fu_briefly( fu, "" );
01458 
01459                 plot_parity_error(fu, pt);
01460 
01461 #if 0
01462                 /* Debug code -- go back and do it again while I'm watching! */
01463                 rt_g.NMG_debug |= DEBUG_PT_FU;
01464                 for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) {
01465                         if( ignore_lu && (ignore_lu==lu || ignore_lu==lu->lumate_p) )
01466                                 continue;
01467 
01468                         /* Ignore OT_BOOLPLACE, etc */
01469                         if( lu->orientation != OT_SAME && lu->orientation != OT_OPPOSITE )
01470                                 continue;
01471 
01472                         lu_class = nmg_class_pt_lu(lu, &fpi, in_or_out_only);
01473                 }
01474 #endif
01475                 rt_bomb("nmg_class_pt_fu_except() loop classification parity error\n");
01476         }
01477 
01478         while (BU_LIST_WHILE(ved_p, ve_dist, &fpi.ve_dh)) {
01479                 BU_LIST_DEQUEUE( &ved_p->l );
01480                 bu_free( (char *)ved_p, "ve_dist struct");
01481         }
01482 
01483 
01484         if (rt_g.NMG_debug & DEBUG_PT_FU )
01485                 bu_log("nmg_class_pt_fu_except() returns %s\n",
01486                         nmg_class_name(fu_class));
01487 
01488         return fu_class;
01489 }
01490 
01491 
01492 /**
01493  *      N M G _ C L A S S _ P T _ L U _ E X C E P T
01494  *
01495  *      Classify a point as being in/on/out of the area bounded by a loop,
01496  *      ignoring any uses of a particular edge in the loop.
01497  *
01498  *      This routine must be called with a face-loop of edges!
01499  *      It will not work properly on crack loops.
01500  */
01501 int
01502 nmg_class_pt_lu_except(fastf_t *pt, const struct loopuse *lu, const struct edge *e_p, const struct bn_tol *tol)
01503 {
01504         register struct edgeuse *eu;
01505         struct edge_info edge_list;
01506         struct edge_info *ei;
01507         struct fpi      fpi;
01508         int             lu_class = NMG_CLASS_Unknown;
01509         struct ve_dist  *ved_p;
01510         double          dist;
01511 
01512         if (rt_g.NMG_debug & DEBUG_PT_FU ) {
01513                 bu_log("nmg_class_pt_lu_except( (%g %g %g) ", V3ARGS(pt), e_p);
01514                 if (e_p)
01515                         bu_log(" e_p=(%g %g %g) <-> (%g %g %g) )\n",
01516                                 V3ARGS(e_p->eu_p->vu_p->v_p->vg_p->coord),
01517                                 V3ARGS(e_p->eu_p->eumate_p->vu_p->v_p->vg_p->coord) );
01518                 else
01519                         bu_log(" e_p=(NULL) )\n");
01520         }
01521 
01522         NMG_CK_LOOPUSE(lu);
01523 
01524         if (e_p) NMG_CK_EDGE(e_p);
01525 
01526         NMG_CK_FACEUSE(lu->up.fu_p);
01527 
01528         /* Validate distance from point to plane */
01529         NMG_GET_FU_PLANE( fpi.norm, lu->up.fu_p );
01530         if( (dist=fabs(DIST_PT_PLANE( pt, fpi.norm ))) > tol->dist )  {
01531                 bu_log("nmg_class_pt_lu_except() ERROR, point (%g,%g,%g)\nnot on face %g %g %g %g,\ndist=%g\n",
01532                         V3ARGS(pt), V4ARGS(fpi.norm), dist );
01533         }
01534 
01535 
01536         if (!V3PT_IN_RPP( pt, lu->l_p->lg_p->min_pt, lu->l_p->lg_p->max_pt)) {
01537                 /* point is not in RPP of loop */
01538 
01539                 if (rt_g.NMG_debug & DEBUG_PT_FU )
01540                         bu_log("nmg_class_pt_lu_except( pt(%g %g %g) outside loop RPP\n",
01541                                 V3ARGS(pt));
01542 
01543                 if (lu->orientation == OT_SAME) return NMG_CLASS_AoutB;
01544                 else if (lu->orientation == OT_OPPOSITE) return NMG_CLASS_AinB;
01545                 else {
01546                         bu_log("What kind of loop is this anyway? %s?\n",
01547                                 nmg_orientation(lu->orientation) );
01548                         rt_bomb("");
01549                 }
01550         }
01551 
01552         if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_VERTEXUSE_MAGIC) {
01553                 bu_log("%s:%d Improper use of nmg_class_pt_lu_except(pt(%g %g %g), vu)\n",
01554                         __FILE__, __LINE__, V3ARGS(pt));
01555                 rt_bomb("giving up\n");
01556         }
01557 
01558         BU_LIST_INIT(&edge_list.l);
01559         fpi.fu_p = lu->up.fu_p;
01560 
01561         fpi.tol = tol;
01562         BU_LIST_INIT(&fpi.ve_dh);
01563         VMOVE(fpi.pt, pt);
01564         fpi.eu_func = (void (*)())NULL;
01565         fpi.vu_func = (void (*)())NULL;
01566         fpi.priv = (char *)NULL;
01567         fpi.hits = 0;
01568         fpi.magic = NMG_FPI_MAGIC;
01569 
01570         for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
01571                 if (eu->e_p == e_p) {
01572                         if (rt_g.NMG_debug & DEBUG_PT_FU )
01573                                 bu_log("skipping edguse (%g %g %g) -> (%g %g %g) on \"except\" edge\n",
01574                                         V3ARGS(eu->vu_p->v_p->vg_p->coord),
01575                                         V3ARGS(eu->eumate_p->vu_p->v_p->vg_p->coord) );
01576 
01577                         continue;
01578                 }
01579 
01580                 ei = nmg_class_pt_eu(&fpi, eu, &edge_list, 0);
01581                 NMG_CK_EI(ei);
01582                 NMG_CK_VED(ei->ved_p);
01583                 if (ei->ved_p->dist < tol->dist_sq) {
01584                         lu_class = NMG_CLASS_AonBshared;
01585                         break;
01586                 }
01587         }
01588         if (lu_class == NMG_CLASS_Unknown)
01589                 lu_class = compute_loop_class(&fpi, lu, &edge_list);
01590         else if (rt_g.NMG_debug & DEBUG_PT_FU )
01591                 bu_log("loop class already known (pt must touch edge)\n");
01592 
01593         /* free up the edge_list elements */
01594         while ( BU_LIST_WHILE(ei, edge_info, &edge_list.l) ) {
01595                 BU_LIST_DEQUEUE( &ei->l );
01596                 bu_free( (char *)ei, "edge info struct");
01597         }
01598 
01599         while (BU_LIST_WHILE(ved_p, ve_dist, &fpi.ve_dh)) {
01600                 BU_LIST_DEQUEUE( &ved_p->l );
01601                 bu_free( (char *)ved_p, "ve_dist struct");
01602         }
01603 
01604         if (rt_g.NMG_debug & DEBUG_PT_FU )
01605                 bu_log("nmg_class_pt_lu_except() returns %s\n",
01606                         nmg_class_name(lu_class));
01607 
01608         return lu_class;
01609 }
01610 
01611 /*
01612  * Local Variables:
01613  * mode: C
01614  * tab-width: 8
01615  * c-basic-offset: 4
01616  * indent-tabs-mode: t
01617  * End:
01618  * ex: shiftwidth=4 tabstop=8
01619  */

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