nurb_tess.c

Go to the documentation of this file.
00001 /*                     N U R B _ T E S S . 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 
00022 /** @addtogroup nurb */
00023 /*@{*/
00024 /** @file nurb_tess.c
00025  *      Given Epsilon, compute the number of internal knots to
00026  *      add so that every triangle generated in parametric space
00027  *      is within epsilon of the original surface.
00028  *
00029  *  Author -
00030  *      Paul Randal Stay
00031  *
00032  *  Source -
00033  *      SECAD/VLD Computing Consortium, Bldg 394
00034  *      The U.S. Army Ballistic Research Laboratory
00035  *      Aberdeen Proving Ground, Maryland 21005
00036  *
00037  */
00038 /*@}*/
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 /* Algorithm -
00053  *
00054  * See paper in Computer Aided Design (CAD) Volumne 27, Number 1, January 1995
00055  *      TESSELATING TRIMMMED NURBS SURFACES, Leslie A Piegl and Arnaud Richard.
00056  *
00057  * There is a slight deviation from the paper, Since libnurb (rt_nurb_s_diff)
00058  * differentiation correctly handles rational surfaces, no special processing for
00059  * rational is needed.
00060  *
00061  * The idea is to compute the longest edge size in parametric space such that
00062  * a the edge (or curve) in real space is within epsilon tolerance. The mapping
00063  * from parametric space is done as a separate step.
00064  *
00065  */
00066 
00067 fastf_t
00068 rt_nurb_par_edge(const struct face_g_snurb *srf, fastf_t epsilon)
00069 {
00070         struct face_g_snurb * us, *vs, * uus, * vvs, *uvs;
00071         fastf_t d1,d2,d3;
00072         int i;
00073         fastf_t *pt;
00074 
00075 
00076         us = rt_nurb_s_diff(srf, RT_NURB_SPLIT_ROW);
00077         vs = rt_nurb_s_diff(srf, RT_NURB_SPLIT_COL);
00078         uus = rt_nurb_s_diff(us, RT_NURB_SPLIT_ROW);
00079         vvs = rt_nurb_s_diff(vs, RT_NURB_SPLIT_COL);
00080         uvs = rt_nurb_s_diff(vs, RT_NURB_SPLIT_ROW);
00081 
00082         d1 = 0.0;
00083         d2 = 0.0;
00084         d3 = 0.0;
00085 
00086         pt = (fastf_t *) uus->ctl_points;
00087 
00088         /* Find the maximum value of the 2nd derivative in U */
00089 
00090         for( i = 0; i < uus->s_size[0] * uus->s_size[1]; i++)
00091         {
00092                 fastf_t mag;
00093 
00094                 mag = MAGNITUDE( pt );
00095 
00096                 if ( mag > d1) d1 = mag;
00097 
00098                 pt += RT_NURB_EXTRACT_COORDS(uus->pt_type);
00099 
00100         }
00101 
00102         /* Find the maximum value of the partial derivative in UV */
00103 
00104         pt = (fastf_t *) uvs->ctl_points;
00105 
00106         for( i = 0; i < uvs->s_size[0] * uvs->s_size[1]; i++)
00107         {
00108                 fastf_t mag;
00109 
00110                 mag = MAGNITUDE( pt );
00111 
00112                 if ( mag > d2) d2 = mag;
00113 
00114                 pt += RT_NURB_EXTRACT_COORDS(uvs->pt_type);
00115 
00116         }
00117 
00118 
00119         /* Find the maximum value of the 2nd derivative in V */
00120         pt = (fastf_t *) vvs->ctl_points;
00121 
00122         for( i = 0; i < vvs->s_size[0] * vvs->s_size[1]; i++)
00123         {
00124                 fastf_t mag;
00125 
00126                 mag = MAGNITUDE( pt );
00127 
00128                 if ( mag > d3) d3 = mag;
00129 
00130                 pt += RT_NURB_EXTRACT_COORDS(vvs->pt_type);
00131 
00132         }
00133 
00134         /* free up storage */
00135 
00136         rt_nurb_free_snurb( us, (struct resource *)NULL);
00137         rt_nurb_free_snurb( vs, (struct resource *)NULL);
00138         rt_nurb_free_snurb( uus, (struct resource *)NULL);
00139         rt_nurb_free_snurb( vvs, (struct resource *)NULL);
00140         rt_nurb_free_snurb( uvs, (struct resource *)NULL);
00141 
00142 
00143         /* The paper uses the following to calculate the longest edge size
00144          *                                1/2
00145          *  3.0 * (                     )
00146          *        (        2.0          )
00147          *        _________________________
00148          *        (2.0 * (d1 + 2 D2 + d3)
00149          */
00150 
00151         return ( 3.0 * sqrt( epsilon / (2.0*(d1 + (2.0 * d2)+ d3))));
00152 }
00153 
00154 /*
00155  *              R T _ C N U R B _ P A R _ E D G E
00156  *
00157  *      Calculate the maximum edge length (in parameter space)
00158  *      that will keep the curve approximation within epsilon
00159  *      of the true curve
00160  *
00161  *      This is a temporary guess until legitimate code can be found
00162  *
00163  *      returns:
00164  *              -1.0 if the curve is a straight line
00165  *              maximum parameter increment otherwise
00166  */
00167 fastf_t
00168 rt_cnurb_par_edge(const struct edge_g_cnurb *crv, fastf_t epsilon)
00169 {
00170         struct edge_g_cnurb *d1, *d2;
00171         fastf_t der2[5], t, *pt;
00172         fastf_t num_coord_factor, final_t;
00173         int num_coords;
00174         int i,j;
00175 
00176         if( crv->order < 3)
00177                 return( -1.0 );
00178 
00179         num_coords = RT_NURB_EXTRACT_COORDS( crv->pt_type );
00180         if( num_coords > 5 )
00181         {
00182                 bu_log( "ERROR: rt_cnurb_par_edge() cannot handle curves with more than 5 coordinates (curve has %d)\n",
00183                         num_coords );
00184                 bu_bomb( "ERROR: rt_cnurb_par_edge() cannot handle curves with more than 5 coordinates\n" );
00185         }
00186 
00187         for( i=0 ; i<num_coords ; i++ )
00188         {
00189                 der2[i] = 0.0;
00190         }
00191 
00192         final_t = MAX_FASTF;
00193         num_coord_factor = sqrt( (double)num_coords );
00194 
00195         d1 = rt_nurb_c_diff( crv );
00196         d2 = rt_nurb_c_diff( d1 );
00197 
00198 #if 0
00199         pt = d1->ctl_points;
00200         for( i=0 ; i<d1->c_size ; i++ )
00201         {
00202                 for( j=0 ; j<num_coords ; j++ )
00203                 {
00204                         fastf_t abs_val;
00205 
00206                         abs_val = *pt > 0.0 ? *pt : -(*pt);
00207                         if( abs_val > der1[j] )
00208                                 der1[j] = abs_val;
00209                         pt++;
00210                 }
00211         }
00212 #endif
00213         pt = d2->ctl_points;
00214         for( i=0 ; i<d2->c_size ; i++ )
00215         {
00216                 for( j=0 ; j<num_coords ; j++ )
00217                 {
00218                         fastf_t abs_val;
00219 
00220                         abs_val = *pt > 0.0 ? *pt : -(*pt);
00221                         if( abs_val > der2[j] )
00222                                 der2[j] = abs_val;
00223                         pt++;
00224                 }
00225         }
00226 
00227         rt_nurb_free_cnurb( d1 );
00228         rt_nurb_free_cnurb( d2 );
00229 
00230         for( j=0 ; j<num_coords ; j++ )
00231         {
00232                 if( NEAR_ZERO( der2[j], SMALL_FASTF ) )
00233                         continue;
00234 
00235                 t = sqrt( 2.0 * epsilon / (num_coord_factor * der2[j] ) );
00236                 if( t < final_t )
00237                         final_t = t;
00238         }
00239 
00240         if( final_t == MAX_FASTF )
00241                 return( -1.0 );
00242         else
00243                 return( final_t/2.0 );
00244 }
00245 
00246 /*
00247  * Local Variables:
00248  * mode: C
00249  * tab-width: 8
00250  * c-basic-offset: 4
00251  * indent-tabs-mode: t
00252  * End:
00253  * ex: shiftwidth=4 tabstop=8
00254  */

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