nurb_trim.c

Go to the documentation of this file.
00001 /*                     N U R B _ T R I M . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1990-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 /** @addtogroup */
00022 /*@{*/
00023 /** @file nurb_trim.c
00024  * Trimming curve routines.
00025  *
00026  * Author:  Paul R. Stay
00027  * Source
00028  *      SECAD/VLD Computing Consortium, Bldg 394
00029  *      The US Army Ballistic Research Laboratory
00030  *      Aberdeen Proving Ground, Maryland 21005
00031  *
00032  * Date: Mon June 1, 1992
00033  */
00034 /*@}*/
00035 
00036 #ifndef lint
00037 static const char rcs_ident[] = "$Header: /cvsroot/brlcad/brlcad/src/librt/nurb_trim.c,v 14.11 2006/09/16 02:04:25 lbutler Exp $";
00038 #endif
00039 
00040 #include "common.h"
00041 
00042 
00043 
00044 #include <stdio.h>
00045 #include <math.h>
00046 
00047 #include "machine.h"
00048 #include "vmath.h"
00049 #include "raytrace.h"
00050 #include "nurb.h"
00051 
00052 extern void     rt_clip_cnurb(struct bu_list *plist, struct edge_g_cnurb *crv, fastf_t u, fastf_t v);
00053 
00054 struct _interior_line {
00055         int axis;
00056         fastf_t o_dist;
00057 };
00058 
00059 #define QUAD1 0
00060 #define QUAD2 1
00061 #define QUAD3 2
00062 #define QUAD4 3
00063 
00064 
00065 #define TRIM_OUT        0
00066 #define TRIM_IN         1
00067 #define TRIM_ON         2
00068 
00069 /* The following defines need to be 0,2,3 in order to drive the quad table
00070  * and determine the appropriate case for processing the trimming curve.
00071  */
00072 
00073 #define CASE_A          0
00074 #define CASE_B          2
00075 #define CASE_C          3
00076 
00077 int quad_table[16]  = {         /* A = 0, B = 2, C = 3 */
00078 0,0,0,0,0,3,0,3,0,2,3,3,0,3,3,3
00079 };
00080 
00081 /* This routine determines what quadrants the trimming curves lies
00082  * in,  It then uses a table look up to determine the whether its
00083  * CASE{A,B,C}, One difference from the paper is the fact that
00084  * if any of the points lie on the axis of the u,v quadrant system
00085  * then the axis is only in either Quadrant 1 or Quadrant 2 and not
00086  * q3 or q4. THis handles the case of endpoint problems correctly.
00087  */
00088 
00089 int
00090 rt_trim_case(struct edge_g_cnurb *trim, fastf_t u, fastf_t v)
00091 {
00092         int quadrant;
00093         int qstats;
00094         fastf_t * pts;
00095         int coords, rat;
00096         int i;
00097 
00098         qstats = 0;
00099 
00100         coords = RT_NURB_EXTRACT_COORDS(trim->pt_type);
00101         pts = trim->ctl_points;
00102         rat = RT_NURB_IS_PT_RATIONAL( trim->pt_type );
00103 
00104         /* Handle rational specially since we need to divide the rational
00105          * portion.
00106          */
00107 
00108         if( rat )
00109                 for( i = 0; i < trim->c_size; i++)
00110                 {
00111                         if(pts[0]/pts[2] > u )
00112                                 quadrant = (pts[1]/pts[2] >= v)? QUAD1:QUAD4;
00113                         else
00114                                 quadrant = (pts[1]/pts[2] >= v)? QUAD2:QUAD3;
00115 
00116                         qstats |= (1 << quadrant);
00117                         pts += coords;
00118                 }
00119         else
00120                 for( i = 0; i < trim->c_size; i++)
00121                 {
00122                         if(pts[0] > u )
00123                                 quadrant = (pts[1] >= v)? QUAD1:QUAD4;
00124                         else
00125                                 quadrant = (pts[1] >= v)? QUAD2:QUAD3;
00126 
00127                         qstats |= (1 << quadrant);
00128                         pts += coords;
00129                 }
00130 
00131         return quad_table[qstats];      /* return the special case of the curve */
00132 }
00133 
00134 /* Process Case B curves.
00135  *
00136  * If the two endpoints of the curve lie in different quadrants than
00137  * the axis crosses the curve an odd number of times (TRIM_IN). Otherwise
00138  * the curve crosses the u,v axis a even number of times (TRIM_OUT).
00139  * No further processing is required.
00140  */
00141 int
00142 rt_process_caseb(struct edge_g_cnurb *trim, fastf_t u, fastf_t v)
00143 {
00144         int q1, q2;
00145         fastf_t * pts;
00146         int rat;
00147 
00148         rat = RT_NURB_IS_PT_RATIONAL( trim->pt_type );
00149 
00150         pts = trim->ctl_points;
00151 
00152         if( rat)
00153         {
00154                 if( pts[0]/pts[2] > u) q1 = (pts[1]/pts[2] >= v)?QUAD1:QUAD4;
00155                 else             q1 = (pts[1]/pts[2] >= v)?QUAD2:QUAD3;
00156 
00157 
00158                 pts = trim->ctl_points + RT_NURB_EXTRACT_COORDS(trim->pt_type) *
00159                         (trim->c_size -1);
00160                 if( pts[0]/pts[2] > u) q2 = (pts[1]/pts[2] >= v)?QUAD1:QUAD4;
00161                 else             q2 = (pts[1]/pts[2] >= v)?QUAD2:QUAD3;
00162 
00163         } else
00164         {
00165                 if( pts[0] > u) q1 = (pts[1] >= v)?QUAD1:QUAD4;
00166                 else             q1 = (pts[1] >= v)?QUAD2:QUAD3;
00167 
00168 
00169                 pts = trim->ctl_points +
00170                         RT_NURB_EXTRACT_COORDS(trim->pt_type)   *
00171                         (trim->c_size -1);
00172                 if( pts[0] > u) q2 = (pts[1] >= v)?QUAD1:QUAD4;
00173                 else             q2 = (pts[1] >= v)?QUAD2:QUAD3;
00174         }
00175 
00176         if( q1 != q2 )
00177                 return TRIM_IN;
00178         else
00179                 return TRIM_OUT;
00180 
00181 }
00182 
00183 /* Only check end points of the curve */
00184 
00185 int
00186 rt_nurb_uv_dist(struct edge_g_cnurb *trim, fastf_t u, fastf_t v)
00187 {
00188 
00189         fastf_t dist;
00190         fastf_t * ptr;
00191         int coords;
00192         int rat;
00193         fastf_t u2, v2;
00194 
00195         ptr = trim->ctl_points;
00196         coords = RT_NURB_EXTRACT_COORDS(trim->pt_type);
00197         rat = RT_NURB_IS_PT_RATIONAL(trim->pt_type);
00198 
00199         u2 = 0.0;
00200         v2 = 0.0;
00201 
00202         if ( rat )
00203         {
00204                 u2 = ptr[0]/ptr[2] - u; u2 *= u2;
00205                 v2 = ptr[1]/ptr[2] - v; v2 *= v2;
00206         }
00207         else
00208         {
00209                 u2 = ptr[0] - u; u2 *= u2;
00210                 v2 = ptr[1] - v; v2 *= v2;
00211         }
00212 
00213         dist = sqrt( u2 + v2);
00214         if ( NEAR_ZERO( dist, 1.0e-4) )
00215                 return TRIM_ON;
00216 
00217         ptr = trim->ctl_points + coords * (trim->c_size -1);
00218 
00219         u2 = 0.0;
00220         v2 = 0.0;
00221 
00222         if ( rat )
00223         {
00224                 u2 = ptr[0]/ptr[2] - u; u2 *= u2;
00225                 v2 = ptr[1]/ptr[2] - v; v2 *= v2;
00226         }
00227         else
00228         {
00229                 u2 = ptr[0] - u; u2 *= u2;
00230                 v2 = ptr[1] - v; v2 *= v2;
00231         }
00232 
00233         dist = sqrt( u2 + v2);
00234         if ( NEAR_ZERO( dist, 1.0e-4) )
00235                 return TRIM_ON;
00236 
00237         return TRIM_OUT;
00238 
00239 }
00240 
00241 
00242 
00243 /* Process Case C curves;
00244  * A check is placed here to determin if the u,v is on the curve.
00245  * Determine how many times the curve will cross the u,v axis. If
00246  * the curve crosses an odd number of times than the point is IN,
00247  * else the point is OUT. Since a case C curve need processin a
00248  * call to clip hte curve so that it becomes either Case B, or Case A
00249  * is required to determine the number of crossing acurately. Thus
00250  * we need to keep the original curve and expect the calling routine
00251  * to free the storage. Additional curves are generated in this
00252  * routine, each of these new curves are proccesed, and then are
00253  * deleted before exiting this procedure.
00254  */
00255 
00256 int
00257 rt_process_casec(struct edge_g_cnurb *trim, fastf_t u, fastf_t v)
00258 {
00259 
00260         struct edge_g_cnurb * clip;
00261         int jordan_hit;
00262         struct bu_list  plist;
00263         int trim_flag = 0;
00264         int caset;
00265 
00266         /* determine if the the u,v values are on the curve */
00267 
00268         if( rt_nurb_uv_dist(trim, u, v)  == TRIM_ON) return TRIM_IN;
00269 
00270         jordan_hit = 0;
00271 
00272         BU_LIST_INIT(&plist);
00273 
00274         if( nurb_crv_is_bezier( trim ) )
00275                 rt_clip_cnurb(&plist, trim, u, v);
00276         else
00277                 nurb_c_to_bezier( &plist, trim );
00278 
00279         while( BU_LIST_WHILE( clip, edge_g_cnurb, &plist ) )
00280         {
00281                 BU_LIST_DEQUEUE( &clip->l );
00282 
00283                 caset = rt_trim_case(clip, u,v);
00284 
00285                 trim_flag = 0;
00286 
00287                 if( caset == CASE_B)
00288                         trim_flag = rt_process_caseb(clip, u, v);
00289                 if( caset == CASE_C)
00290                         trim_flag = rt_process_casec(clip, u, v);
00291 
00292                 rt_nurb_free_cnurb( clip );
00293 
00294                 if( trim_flag == TRIM_IN) jordan_hit++;
00295                 if( trim_flag == TRIM_ON) break;
00296         }
00297 
00298         while( BU_LIST_WHILE( clip, edge_g_cnurb, &plist) )
00299         {
00300                 BU_LIST_DEQUEUE( &clip->l );
00301                 rt_nurb_free_cnurb( clip );
00302         }
00303 
00304         if( trim_flag == TRIM_ON)
00305                 return TRIM_ON;
00306 
00307         else if( jordan_hit & 01 )
00308                 return TRIM_IN;
00309         else
00310                 return TRIM_OUT;
00311 }
00312 
00313 
00314 /* This routine will be called several times, once for each portion of
00315  * the trimming curve. It returns wheter a line extended from the
00316  * the <u,v> point will cross the trimming curve an even or odd number
00317  * of times. Or the <u,v> point could be on the curve in which case
00318  * TRIM_ON will be returned. THe algorithm uses the approach taken
00319  * Tom Sederburge and uses bezier clipping to produce caseA and caseB
00320  * curves. If the original trimming curve is a CASE C curve then further
00321  * processing is required.
00322  */
00323 int
00324 rt_uv_in_trim(struct edge_g_cnurb *trim, fastf_t u, fastf_t v)
00325 {
00326 
00327         int quad_case;
00328 
00329         quad_case = rt_trim_case( trim, u, v);  /* determine quadrants */
00330 
00331                                                         /* CASE A */
00332         if( quad_case == CASE_A )
00333                 return TRIM_OUT;
00334         if( quad_case == CASE_B )                       /* CASE B */
00335                 return rt_process_caseb(trim, u, v);
00336         if( quad_case == CASE_C )                       /* CASE C */
00337                 return rt_process_casec(trim, u, v);
00338 
00339         bu_log( "rt_uv_in_trim: rt_trim_case() returned illegal value %d\n", quad_case );
00340         return( -1 );
00341 }
00342 
00343 
00344 
00345 
00346 
00347 /* This routines is used to determine how far a point is
00348  * from the u,v quadrant axes.
00349  *
00350  *      Equations 3, 4, 5 in Sederberg '90 paper
00351  */
00352 
00353 fastf_t
00354 rt_trim_line_pt_dist(struct _interior_line *l, fastf_t *pt, int pt_type)
00355 {
00356         fastf_t h;
00357         int h_flag;
00358 
00359         h_flag = RT_NURB_IS_PT_RATIONAL(pt_type);
00360 
00361         if( l->axis == 0)
00362         {
00363                 if( h_flag) h = (pt[1] / pt[2] - l->o_dist) * pt[2]; /* pt[2] is weight */
00364                 else h = pt[1] - l->o_dist;
00365 
00366         } else
00367         {
00368                 if( h_flag) h = (pt[0] / pt[2] - l->o_dist) * pt[2];
00369                 else h = pt[0] - l->o_dist;
00370 
00371         }
00372 
00373         return h;
00374 }
00375 
00376 /* Return the SIGN of the value */
00377 int
00378 _SIGN(fastf_t f)
00379 {
00380         if (f < 0.0)
00381                 return -1;
00382         else
00383                 return 1;
00384 
00385 }
00386 
00387 /*
00388  *  We try and clip a curve so that it can be either Case A, or Case C.
00389  *  Sometimes one of the curves is still case C though, but it is much
00390  *  small than the original, and further clipping will either show that
00391  *  it is on the curve or provide all Case B or Case A curves.
00392  *  We try and pick the best axis to clip against, but this may not always
00393  *  work. One extra step that was included, that is not in the paper for
00394  *  curves but is for surfaces, is the fact that sometimes the curve is
00395  *  not clipped enough, if the maximum clip is less than .2 than we sub
00396  *  divide the curve in three equal parts, at .3 and .6,
00397  *  Subdivision is done using the Oslo Algorithm, rather than the other
00398  *  methods which were prossed.
00399  */
00400 void
00401 rt_clip_cnurb(struct bu_list *plist, struct edge_g_cnurb *crv, fastf_t u, fastf_t v)
00402 {
00403         fastf_t ds1, dt1;
00404         struct _interior_line s_line, t_line;
00405         int axis, i;
00406         fastf_t umin, umax;
00407         int coords;
00408         struct edge_g_cnurb * c1, *c2, *tmp;
00409         fastf_t m1, m2;
00410         int zero_changed;
00411         fastf_t *ptr;
00412         fastf_t dist[10];
00413 
00414         coords = RT_NURB_EXTRACT_COORDS( crv->pt_type);
00415 
00416         s_line.axis = 0;        s_line.o_dist = v;
00417         t_line.axis = 1;        t_line.o_dist = u;
00418 
00419         ds1 = 0.0;
00420         dt1 = 0.0;
00421 
00422         ptr = crv->ctl_points;
00423 
00424 
00425         /* determine what axis to clip against */
00426 
00427         for( i = 0; i < crv->c_size; i++, ptr += coords)
00428         {
00429                 ds1 +=
00430                     fabs( rt_trim_line_pt_dist( &s_line, ptr, crv->pt_type) );
00431                 dt1 +=
00432                     fabs( rt_trim_line_pt_dist( &t_line, ptr, crv->pt_type) );
00433         }
00434 
00435         if( ds1 >= dt1 ) axis = 0; else axis = 1;
00436 
00437         ptr = crv->ctl_points;
00438 
00439         for( i = 0; i < crv->c_size; i++)
00440         {
00441                 if( axis == 1)
00442                         dist[i] = rt_trim_line_pt_dist(&t_line, ptr, crv->pt_type);
00443                 else
00444                         dist[i] = rt_trim_line_pt_dist(&s_line, ptr, crv->pt_type);
00445 
00446                 ptr += coords;
00447         }
00448 
00449         /* Find the convex hull of the distances and determine the
00450          * minimum and maximum distance to clip against. See the
00451          * paper for details about this step
00452          */
00453 
00454         umin = 10e40;
00455         umax = -10e40;
00456         zero_changed = 0;
00457 
00458         for( i = 0; i < crv->c_size; i++)
00459         {
00460                 fastf_t d1, d2;
00461                 fastf_t x0, x1, zero;
00462 
00463                 if ( i == (crv->c_size -1 ) )
00464                 {
00465                         d1 = dist[i];
00466                         d2 = dist[0];
00467                         x0 = (fastf_t) i / (fastf_t) (crv->c_size - 1);
00468                         x1 = 0.0;
00469                 } else
00470                 {
00471                         d1 = dist[i];
00472                         d2 = dist[i+1];
00473                         x0 = (fastf_t) i / (fastf_t) (crv->c_size - 1 );
00474                         x1 = (i+1.0) / (crv->c_size - 1);
00475                 }
00476 
00477                 if( _SIGN(d1) != _SIGN(d2) )
00478                 {
00479                         zero = x0 - d1 * (x1 - x0)/ (d2-d1);
00480                         if( zero <= umin)
00481                                 umin = zero * .99;
00482                         if( zero >= umax)
00483                                 umax = zero * .99 + .01;
00484                         zero_changed = 1;
00485                 }
00486         }
00487 
00488         if( !zero_changed)
00489                 return;
00490 
00491         /* Clip is not large enough, split in thiords and try again */
00492 
00493         if( umax - umin < .2)
00494         {
00495                 umin = .3; umax = .6;
00496         }
00497 
00498         /* Translate the 0.0-->1.09 clipping against the real knots */
00499 
00500         m1 = (crv->k.knots[0] * (1 - umin)) +
00501                 crv->k.knots[crv->k.k_size -1] *  umin;
00502 
00503         m2 = (crv->k.knots[0] * (1-umax)) +
00504                 crv->k.knots[crv->k.k_size -1] * umax;
00505 
00506         /* subdivide the curve */
00507         c1 = (struct edge_g_cnurb *) rt_nurb_c_xsplit(crv, m1);
00508         c2 = rt_nurb_c_xsplit((struct edge_g_cnurb *) c1->l.forw, m2);
00509 
00510         tmp = (struct edge_g_cnurb *) c1->l.forw;
00511         BU_LIST_DEQUEUE( &tmp->l);
00512         rt_nurb_free_cnurb( tmp );
00513 
00514         BU_LIST_INIT( plist );
00515         BU_LIST_INSERT( &c2->l, plist);
00516         BU_LIST_APPEND( plist, &c1->l);
00517 }
00518 
00519 
00520 
00521 int
00522 nmg_uv_in_lu(const fastf_t u, const fastf_t v, const struct loopuse *lu)
00523 {
00524         struct edgeuse *eu;
00525         int crossings=0;
00526 
00527         NMG_CK_LOOPUSE( lu );
00528 
00529         if( BU_LIST_FIRST_MAGIC( &lu->down_hd ) != NMG_EDGEUSE_MAGIC )
00530                 return( 0 );
00531 
00532         for( BU_LIST_FOR( eu, edgeuse, &lu->down_hd ) )
00533         {
00534                 struct edge_g_cnurb *eg;
00535 
00536                 if( !eu->g.magic_p )
00537                 {
00538                         bu_log( "nmg_uv_in_lu: eu (x%x) has no geometry!!!\n", eu );
00539                         bu_bomb( "nmg_uv_in_lu: eu has no geometry!!!\n" );
00540                 }
00541 
00542                 if( *eu->g.magic_p != NMG_EDGE_G_CNURB_MAGIC )
00543                 {
00544                         bu_log( "nmg_uv_in_lu: Called with lu (x%x) containing eu (x%x) that is not CNURB!!!!\n",
00545                                 lu, eu );
00546                         bu_bomb( "nmg_uv_in_lu: Called with lu containing eu that is not CNURB!!!\n" );
00547                 }
00548 
00549                 eg = eu->g.cnurb_p;
00550 
00551                 if( eg->order <= 0 )
00552                 {
00553                         struct vertexuse *vu1, *vu2;
00554                         struct vertexuse_a_cnurb *vua1, *vua2;
00555                         point_t uv1, uv2;
00556                         fastf_t slope, intersept;
00557                         fastf_t u_on_curve;
00558 
00559                         vu1 = eu->vu_p;
00560                         vu2 = eu->eumate_p->vu_p;
00561 
00562                         if( !vu1->a.magic_p || !vu2->a.magic_p )
00563                         {
00564                                 bu_log( "nmg_uv_in_lu: Called with lu (x%x) containing vu with no attribute!!!!\n",
00565                                         lu );
00566                                 bu_bomb( "nmg_uv_in_lu: Called with lu containing vu with no attribute!!!\n" );
00567                         }
00568 
00569                         if( *vu1->a.magic_p != NMG_VERTEXUSE_A_CNURB_MAGIC ||
00570                             *vu2->a.magic_p != NMG_VERTEXUSE_A_CNURB_MAGIC )
00571                         {
00572                                 bu_log( "nmg_uv_in_lu: Called with lu (x%x) containing vu that is not CNURB!!!!\n",
00573                                         lu );
00574                                 bu_bomb( "nmg_uv_in_lu: Called with lu containing vu that is not CNURB!!!\n" );
00575                         }
00576 
00577                         vua1 = vu1->a.cnurb_p;
00578                         vua2 = vu2->a.cnurb_p;
00579 
00580                         VMOVE( uv1, vua1->param );
00581                         VMOVE( uv2, vua2->param );
00582 
00583                         if( RT_NURB_IS_PT_RATIONAL( eg->pt_type ) )
00584                         {
00585                                 uv1[0] /= uv1[2];
00586                                 uv1[1] /= uv1[2];
00587                                 uv2[0] /= uv2[2];
00588                                 uv2[1] /= uv2[2];
00589                         }
00590 
00591                         if( uv1[1] < v && uv2[1] < v )
00592                                 continue;
00593                         if( uv1[1] > v && uv2[1] > v )
00594                                 continue;
00595                         if( uv1[0] <= u && uv2[0] <= u )
00596                                 continue;
00597                         if( uv1[0] == uv2[0] )
00598                         {
00599                                 if( (uv1[1] <= v && uv2[1] >= v) ||
00600                                     (uv2[1] <= v && uv1[1] >= v) )
00601                                         crossings++;
00602 
00603                                 continue;
00604                         }
00605 
00606                         /* need to calculate intersection */
00607                         slope = (uv1[1] - uv2[1])/(uv1[0] - uv2[0]);
00608                         intersept = uv1[1] - slope * uv1[0];
00609                         u_on_curve = (v - intersept)/slope;
00610                         if( u_on_curve > u )
00611                                 crossings++;
00612                 }
00613                 else
00614                         crossings += rt_uv_in_trim( eg, u, v );
00615         }
00616 
00617         if( crossings & 01 )
00618                 return( 1 );
00619         else
00620                 return( 0 );
00621 }
00622 
00623 /*
00624  * Local Variables:
00625  * mode: C
00626  * tab-width: 8
00627  * c-basic-offset: 4
00628  * indent-tabs-mode: t
00629  * End:
00630  * ex: shiftwidth=4 tabstop=8
00631  */

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