nurb_ray.c

Go to the documentation of this file.
00001 /*                      N U R B _ R A Y . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1991-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_ray.c
00025  *      Functions which support the ray intersection
00026  *      for surfaces.
00027  *
00028  *  Author -
00029  *      Paul R. Stay
00030  *
00031  *  Source -
00032  *     SECAD/VLD Computing Consortium, Bldg 394
00033  *     The U.S. Army Ballistic Research Laboratory
00034  *     Aberdeen Proving Ground, Maryland 21005
00035  *
00036  */
00037 /*@}*/
00038 
00039 #include "common.h"
00040 
00041 
00042 
00043 #include <stdio.h>
00044 #include "machine.h"
00045 #include "vmath.h"
00046 #include "nmg.h"
00047 #include "raytrace.h"
00048 #include "nurb.h"
00049 #include "../librt/debug.h"
00050 
00051 
00052 void rt_nurb_pbound(struct face_g_snurb *srf, fastf_t *vmin, fastf_t *vmax);
00053 
00054 struct face_g_snurb *
00055 rt_nurb_project_srf(const struct face_g_snurb *srf, fastf_t *plane1, fastf_t *plane2, struct resource *res)
00056 {
00057 
00058         register struct face_g_snurb *psrf;
00059         register fastf_t *mp1, *mp2;
00060         int     n_pt_type;
00061         int     rational;
00062         int     i;
00063 
00064         if (rt_g.NMG_debug & DEBUG_RT_ISECT)
00065                 bu_log( "rt_nurb_project_srf: projecting surface, planes = (%g %g %g %g) (%g %g %g %g)\n",
00066                         V4ARGS( plane1 ), V4ARGS( plane2 ) );
00067 
00068         rational = RT_NURB_IS_PT_RATIONAL( srf->pt_type);
00069 
00070         n_pt_type = RT_NURB_MAKE_PT_TYPE( 2, RT_NURB_PT_PROJ, 0);
00071 
00072         psrf = (struct face_g_snurb *) rt_nurb_new_snurb( srf->order[0], srf->order[1],
00073             srf->u.k_size, srf->v.k_size,
00074             srf->s_size[0], srf->s_size[1], n_pt_type, res);
00075 
00076         psrf->dir = RT_NURB_SPLIT_COL;
00077 
00078         for ( i = 0; i < srf->u.k_size; i++) {
00079                 psrf->u.knots[i] = srf->u.knots[i];
00080         }
00081 
00082         for ( i = 0; i < srf->v.k_size; i++) {
00083                 psrf->v.knots[i] = srf->v.knots[i];
00084         }
00085 
00086         mp1 = srf->ctl_points;
00087         mp2 = psrf->ctl_points;
00088 
00089         for ( i = 0; i < srf->s_size[0] * srf->s_size[1]; i++) {
00090 
00091                 if ( rational ) {
00092                         mp2[0] = (mp1[0] / mp1[3] * plane1[0] +
00093                             mp1[1] / mp1[3] * plane1[1] +
00094                             mp1[2] / mp1[3] * plane1[2] - plane1[3]) *
00095                             mp1[3];
00096                         mp2[1] = (mp1[0] / mp1[3] * plane2[0] +
00097                             mp1[1] / mp1[3] * plane2[1] +
00098                             mp1[2] / mp1[3] * plane2[2] - plane2[3]) *
00099                             mp1[3];
00100                 } else
00101                  {
00102                         mp2[0] = mp1[0] * plane1[0] + mp1[1] * plane1[1] +
00103                             mp1[2] * plane1[2] - plane1[3];
00104                         mp2[1] = mp1[0] * plane2[0] + mp1[1] * plane2[1] +
00105                             mp1[2] * plane2[2] - plane2[3];
00106                 }
00107 
00108                 if (rt_g.NMG_debug & DEBUG_RT_ISECT)
00109                 {
00110                         if( rational )
00111                                 bu_log( "\tmesh pt (%g %g %g %g), becomes (%g %g)\n", V4ARGS( mp1 ), mp2[0], mp2[1] );
00112                         else
00113                                 bu_log( "\tmesh pt (%g %g %g), becomes (%g %g)\n", V3ARGS( mp1 ), mp2[0], mp2[1] );
00114                 }
00115 
00116                 mp1 += RT_NURB_EXTRACT_COORDS(srf->pt_type);
00117                 mp2 += RT_NURB_EXTRACT_COORDS(psrf->pt_type);
00118         }
00119 
00120         return (struct face_g_snurb *) psrf;
00121 }
00122 
00123 
00124 /* This routine should go away and be changed into a macro
00125  * but for now I want to be able to useit with debugging.
00126  *                                              - Paul
00127  */
00128 #define FINDZERO(x0,x1,y0,y1) (x0 - y0 * ( x1 - x0) / (y1-y0))
00129 
00130 struct internal_line {
00131         fastf_t a, b;
00132 };
00133 
00134 struct internal_convex_hull {
00135         fastf_t param;
00136         fastf_t min, max;
00137 };
00138 
00139 
00140 #define SIGN(a) ((a < 0.0)? -1 : 1)
00141 
00142 void
00143 rt_nurb_clip_srf(const struct face_g_snurb *srf, int dir, fastf_t *min, fastf_t *max)
00144 {
00145         struct internal_convex_hull ch[20]; /* max order is 10 */
00146         register fastf_t * mp1;
00147         fastf_t * p1, *p2, *p3, *p4;    /* corner points of the mesh */
00148         fastf_t v1[2], v2[2], v3[2];            /* vectors from corneres */
00149         struct internal_line l1;
00150         fastf_t norm;
00151         fastf_t value;
00152         int     i;
00153         register int    j;
00154         int     k;
00155         int     coords;
00156         int col_size, row_size;
00157 
00158         col_size = srf->s_size[1];
00159         row_size = srf->s_size[0];
00160 
00161         coords = RT_NURB_EXTRACT_COORDS(srf->pt_type);
00162 
00163         p1 = srf->ctl_points;
00164         p2 = srf->ctl_points + coords * (col_size - 1);
00165         p3 = srf->ctl_points + (coords * col_size *
00166             (row_size - 1));
00167         p4 = srf->ctl_points + (coords * col_size *
00168             (row_size - 1)) +
00169             ((col_size - 1) * coords);
00170 
00171         if ( dir == RT_NURB_SPLIT_ROW) {
00172                 v1[0] = p1[0] - p3[0];
00173                 v1[1] = p1[1] - p3[1];
00174 
00175                 v2[0] = p2[0] - p4[0];
00176                 v2[1] = p2[1] - p4[1];
00177         } else
00178          {
00179                 v1[0] = p1[0] - p2[0];
00180                 v1[1] = p1[1] - p2[1];
00181 
00182                 v2[0] = p3[0] - p4[0];
00183                 v2[1] = p3[1] - p4[1];
00184         }
00185 
00186         v3[0] = v1[0] + v2[0];
00187         v3[1] = v1[1] + v1[1];
00188 
00189         norm = sqrt( v3[1] * v3[1] + v3[0] * v3[0]);
00190         l1.a = v3[1] / norm;
00191         l1.b = -v3[0] / norm;
00192 
00193         *min = 1.0e8;
00194         *max = -1.0e8;
00195 
00196         if( dir == RT_NURB_SPLIT_ROW)
00197         {
00198                 for( i = 0; i < col_size; i++)
00199                 {
00200                         ch[i].param = (fastf_t) i / (col_size - 1.0);
00201                         ch[i].min = 1.0e8;
00202                         ch[i].max = -1.0e8;
00203                 }
00204 
00205                 mp1 = srf->ctl_points;
00206 
00207                 for( i = 0; i < row_size; i++)
00208                 {
00209                         for( j = 0; j < col_size; j++)
00210                         {
00211                                 value = - (mp1[0] * l1.a + mp1[1] * l1.b);
00212                                 if( value <= ch[j].min)
00213                                         ch[j].min = value;
00214                                 if( value >= ch[j].max)
00215                                         ch[j].max = value;
00216                                 mp1 += coords;
00217                         }
00218                 }
00219 
00220                 for( k = 0; k < col_size - 1; k++)
00221                 for( j = k+1; j < col_size; j++)
00222                 {
00223                         fastf_t d;
00224                         fastf_t param1, param2;
00225 
00226                         param1 = ch[k].param;
00227                         param2 = ch[j].param;
00228 
00229                         d = FINDZERO( param1, param2, ch[k].max, ch[j].max);
00230                         if( d <= *min ) *min = d * .99;
00231                         if( d >= *max ) *max = d * .99 + .01;
00232 
00233                         d = FINDZERO( param1, param2, ch[k].min, ch[j].min);
00234                         if( d <= *min ) *min = d * .99;
00235                         if( d >= *max ) *max = d * .99 + .01;
00236                 }
00237 
00238                 if (*min <= 0.0)
00239                         *min = 0.0;
00240                 if (*max >= 1.0)
00241                         *max = 1.0;
00242                 if ( SIGN(ch[0].min) != SIGN(ch[0].max))
00243                         *min = 0.0;
00244                 i = SIGN(ch[col_size -1].min);
00245                 j = SIGN(ch[col_size -1].max);
00246                 if ( i != j)
00247                         *max = 1.0;
00248         } else
00249         {
00250                 for( i = 0; i < row_size; i++)
00251                 {
00252                         ch[i].param = (fastf_t) i / (row_size - 1.0);
00253                         ch[i].min = 1.0e8;
00254                         ch[i].max = -1.0e8;
00255                 }
00256 
00257 
00258                 for( i = 0; i < col_size; i++)
00259                 {
00260                         int stride;
00261 
00262                         stride = coords * col_size;
00263 
00264                         mp1 = srf->ctl_points + i * coords;
00265                         for( j = 0; j < row_size; j++)
00266                         {
00267                                 value = - (mp1[0] * l1.a + mp1[1] * l1.b);
00268                                 if( value <= ch[j].min)
00269                                         ch[j].min = value;
00270                                 if( value >= ch[j].max)
00271                                         ch[j].max = value;
00272                                 mp1 += stride;
00273                         }
00274                 }
00275 
00276                 for( k = 0; k < row_size - 1; k++)
00277                 for( j = k+1; j < row_size; j++)
00278                 {
00279                         fastf_t d;
00280                         fastf_t param1, param2;
00281 
00282                         param1 = ch[k].param;
00283                         param2 = ch[j].param;
00284 
00285                         d = FINDZERO( param1, param2, ch[k].max, ch[j].max);
00286                         if( d <= *min ) *min = d * .99;
00287                         if( d >= *max ) *max = d * .99 + .01;
00288 
00289                         d = FINDZERO( param1, param2, ch[k].min, ch[j].min);
00290                         if( d <= *min ) *min = d * .99;
00291                         if( d >= *max ) *max = d * .99 + .01;
00292                 }
00293                 if (*min <= 0.0)
00294                         *min = 0.0;
00295                 if (*max >= 1.0)
00296                         *max = 1.0;
00297                 if ( SIGN(ch[0].min) != SIGN(ch[0].max))
00298                         *min = 0.0;
00299                 i = SIGN(ch[row_size-1 ].min);
00300                 j = SIGN(ch[row_size -1].max);
00301                 if ( i != j )
00302                         *max = 1.0;     }
00303 }
00304 
00305 /*
00306  *                      R T _ N U R B _ R E G I O N _ F R O M _ S R F
00307  */
00308 struct face_g_snurb *
00309 rt_nurb_region_from_srf(const struct face_g_snurb *srf, int dir, fastf_t param1, fastf_t param2, struct resource *res)
00310 {
00311         register int    i;
00312         struct face_g_snurb *region;
00313         struct knot_vector new_knots;
00314         fastf_t knot_vec[40];
00315 
00316         /* Build the new knot vector in the local array */
00317         /* XXX fill in magic number here? */
00318         new_knots.knots = & knot_vec[0];
00319 
00320         if ( dir == RT_NURB_SPLIT_ROW) {
00321                 new_knots.k_size = srf->order[0] * 2;
00322 
00323                 for ( i = 0; i < srf->order[0]; i++) {
00324                         knot_vec[i] = param1;
00325                         knot_vec[i+srf->order[0]] = param2;
00326                 }
00327         } else
00328          {
00329                 new_knots.k_size = srf->order[1] * 2;
00330 
00331                 for ( i = 0; i < srf->order[1]; i++) {
00332                         knot_vec[i] = param1;
00333                         knot_vec[i+srf->order[1]] = param2;
00334                 }
00335 
00336         }
00337         if( new_knots.k_size >= 40 )  rt_bomb("rt_nurb_region_from_srf() local kv overflow\n");
00338 
00339         region = rt_nurb_s_refine( srf, dir, &new_knots, res);
00340 
00341         return region;
00342 }
00343 
00344 /*
00345  *                      R T _ N U R B _ I N T E R S E C T
00346  */
00347 struct rt_nurb_uv_hit *
00348 rt_nurb_intersect(const struct face_g_snurb *srf, fastf_t *plane1, fastf_t *plane2, double uv_tol, struct resource *res)
00349 {
00350         struct rt_nurb_uv_hit * h;
00351         struct face_g_snurb     * psrf,
00352                         * osrf;
00353         int             dir,
00354                         sub;
00355 
00356         point_t         vmin,
00357                         vmax;
00358         fastf_t         u[2],
00359                         v[2];
00360         struct bu_list  plist;
00361 
00362         NMG_CK_SNURB(srf);
00363 
00364         h = (struct rt_nurb_uv_hit *) 0;
00365         BU_LIST_INIT( &plist );
00366 
00367         /* project the surface to a 2 dimensional problem */
00368         /* NOTE that this gives a single snurb back, NOT a list */
00369         psrf = rt_nurb_project_srf( srf, plane2, plane1, res );
00370         psrf->dir = 1;
00371         BU_LIST_APPEND( &plist, &psrf->l );
00372 
00373         if( RT_G_DEBUG & DEBUG_SPLINE )
00374                 rt_nurb_s_print("srf", psrf);
00375 
00376         /* This list starts out with only a single snurb,
00377          * but more may be added on as work progresses.
00378          */
00379 top:
00380         while( BU_LIST_WHILE( psrf, face_g_snurb, &plist ) )  {
00381                 int flat;
00382 
00383                 BU_LIST_DEQUEUE( &psrf->l );
00384                 NMG_CK_SNURB(psrf);
00385                 sub = 0;
00386                 flat = 0;
00387                 dir = psrf->dir;
00388 
00389                 while(!flat)
00390                 {
00391                         fastf_t smin, smax;
00392 
00393                         sub++;
00394                         dir = (dir == 0)?1:0;   /* change direction */
00395 
00396                         if( RT_G_DEBUG & DEBUG_SPLINE )
00397                                 rt_nurb_s_print("psrf", psrf);
00398 
00399                         rt_nurb_pbound( psrf, vmin, vmax);
00400 
00401                         /* Check for origin to be included in the bounding box */
00402                         if( !(vmin[0] <= 0.0 && vmin[1] <= 0.0 &&
00403                                 vmax[0] >= 0.0 && vmax[1] >= 0.0 ))
00404                         {
00405                                 if( RT_G_DEBUG & DEBUG_SPLINE )
00406                                         bu_log( "this srf doesn't include the origin\n" );
00407                                 flat = 1;
00408                                 rt_nurb_free_snurb( psrf, res );
00409                                 continue;
00410                         }
00411 
00412                         rt_nurb_clip_srf( psrf, dir, &smin, &smax);
00413 
00414                         if( (smax - smin) > .8)  {
00415                                 /* Split surf, requeue both sub-surfs at head */
00416                                 /* New surfs will have same dir as arg, here */
00417                                 if( RT_G_DEBUG & DEBUG_SPLINE )
00418                                         bu_log( "splitting this surface\n" );
00419                                 rt_nurb_s_split( &plist, psrf, dir, res );
00420                                 rt_nurb_free_snurb( psrf, res );
00421                                 goto top;
00422                         }
00423                         if( smin > 1.0 || smax < 0.0 )
00424                         {
00425                                 if( RT_G_DEBUG & DEBUG_SPLINE )
00426                                         bu_log( "eliminating this surface (smin=%g, smax=%g)\n", smin, smax );
00427                                 flat = 1;
00428                                 rt_nurb_free_snurb( psrf, res );
00429                                 continue;
00430                         }
00431                         if ( dir == RT_NURB_SPLIT_ROW)
00432                         {
00433                                 smin = (1.0 - smin) * psrf->u.knots[0] +
00434                                         smin * psrf->u.knots[
00435                                         psrf->u.k_size -1];
00436                                 smax = (1.0 - smax) * psrf->u.knots[0] +
00437                                         smax * psrf->u.knots[
00438                                         psrf->u.k_size -1];
00439                         } else
00440                         {
00441                                 smin = (1.0 - smin) * psrf->v.knots[0] +
00442                                         smin * psrf->v.knots[
00443                                         psrf->v.k_size -1];
00444                                 smax = (1.0 - smax) * psrf->v.knots[0] +
00445                                         smax * psrf->v.knots[
00446                                         psrf->v.k_size -1];
00447                         }
00448 
00449                         osrf = psrf;
00450                         psrf = (struct face_g_snurb *)  rt_nurb_region_from_srf(
00451                                 osrf, dir, smin, smax, res);
00452 
00453                         psrf->dir = dir;
00454                         rt_nurb_free_snurb(osrf, res);
00455 
00456                         if( RT_G_DEBUG & DEBUG_SPLINE )
00457                         {
00458                                 bu_log( "After call to rt_nurb_region_from_srf() (smin=%g, smax=%g)\n", smin, smax );
00459                                 rt_nurb_s_print("psrf", psrf);
00460                         }
00461 
00462                         u[0] = psrf->u.knots[0];
00463                         u[1] = psrf->u.knots[psrf->u.k_size -1];
00464 
00465                         v[0] = psrf->v.knots[0];
00466                         v[1] = psrf->v.knots[psrf->v.k_size -1];
00467 
00468                         if( (u[1] - u[0]) < uv_tol && (v[1] - v[0]) < uv_tol)
00469                         {
00470                                 struct rt_nurb_uv_hit * hit;
00471 
00472                                 if( RT_G_DEBUG & DEBUG_SPLINE )
00473                                 {
00474                                         fastf_t p1[4], p2[4];
00475                                         int coords;
00476                                         vect_t diff;
00477 
00478                                         coords = RT_NURB_EXTRACT_COORDS( srf->pt_type );
00479                                         rt_nurb_s_eval( srf, u[0], v[0], p1 );
00480                                         rt_nurb_s_eval( srf, u[1], v[1], p2 );
00481 
00482                                         if( RT_NURB_IS_PT_RATIONAL( srf->pt_type ) )
00483                                         {
00484                                                 fastf_t inv_w;
00485 
00486                                                 inv_w = 1.0 / p1[coords-1];
00487                                                 VSCALE( p1, p1, inv_w )
00488 
00489                                                 inv_w = 1.0 / p2[coords-1];
00490                                                 VSCALE( p2, p2, inv_w )
00491                                         }
00492 
00493                                         VSUB2( diff, p1, p2 )
00494                                         bu_log( "Precision of hit point = %g (%f %f %f) <-> (%f %f %f)\n",
00495                                                 MAGNITUDE( diff ), V3ARGS( p1 ), V3ARGS( p2 ) );
00496                                 }
00497 
00498                                 hit = (struct rt_nurb_uv_hit *) bu_malloc(
00499                                                 sizeof( struct rt_nurb_uv_hit),  "hit" );
00500 
00501                                 hit->next = (struct rt_nurb_uv_hit *)0;
00502                                 hit->sub = sub;
00503                                 hit->u = (u[0] + u[1])/2.0;
00504                                 hit->v = (v[0] + v[1])/2.0;
00505 
00506                                 if( h == (struct rt_nurb_uv_hit *)0)
00507                                         h = hit;
00508                                 else
00509                                 {
00510                                         hit->next = h;
00511                                         h = hit;
00512                                 }
00513                                 flat = 1;
00514                                 rt_nurb_free_snurb( psrf, res );
00515                         }
00516                         if( (u[1] - u[0]) > (v[1] - v[0]) )
00517                                 dir = 1;
00518                         else dir = 0;
00519                 }
00520         }
00521 
00522         return (struct rt_nurb_uv_hit *)h;
00523 }
00524 
00525 void
00526 rt_nurb_pbound(struct face_g_snurb *srf, fastf_t *vmin, fastf_t *vmax)
00527 {
00528         register fastf_t * ptr;
00529         register int coords;
00530         int i;
00531 
00532         vmin[0] = vmin[1] = vmin[2] = INFINITY;
00533         vmax[0] = vmax[1] = vmax[2] = -INFINITY;
00534 
00535         ptr = srf->ctl_points;
00536 
00537         coords = RT_NURB_EXTRACT_COORDS(srf->pt_type);
00538 
00539         for( i = (srf->s_size[RT_NURB_SPLIT_ROW] *
00540             srf->s_size[RT_NURB_SPLIT_COL] ); i > 0; i--)
00541         {
00542                 V_MIN( (vmin[0]), (ptr[0]));
00543                 V_MAX( (vmax[0]), (ptr[0]));
00544 
00545                 V_MIN( (vmin[1]), (ptr[1]));
00546                 V_MAX( (vmax[1]), (ptr[1]));
00547 
00548                 ptr += coords;
00549         }
00550 }
00551 
00552 /*
00553  * Local Variables:
00554  * mode: C
00555  * tab-width: 8
00556  * c-basic-offset: 4
00557  * indent-tabs-mode: t
00558  * End:
00559  * ex: shiftwidth=4 tabstop=8
00560  */

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