00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include "common.h"
00038
00039
00040
00041 #include <stdio.h>
00042 #include "machine.h"
00043 #include "vmath.h"
00044 #include "nmg.h"
00045 #include "raytrace.h"
00046 #include "nurb.h"
00047 #include "../librt/debug.h"
00048
00049 #define SGN(_x) (((_x)<0) ? -1 : 1)
00050 #define MAXDEPTH 64
00051
00052
00053
00054
00055
00056
00057
00058 int CrossingCount(
00059 point2d_t *V,
00060 int degree,
00061 point2d_t ray_start,
00062 point2d_t ray_dir,
00063 point2d_t ray_perp)
00064 {
00065 int i;
00066 int n_crossings = 0;
00067 int sign, old_sign;
00068 point2d_t to_pt;
00069
00070 V2SUB2( to_pt, ray_start, V[0] );
00071 sign = old_sign = SGN( V2DOT( to_pt, ray_perp ) );
00072 for (i = 1; i <= degree; i++) {
00073 V2SUB2( to_pt, ray_start, V[i] );
00074 sign = SGN( V2DOT( to_pt, ray_perp ) );
00075 if (sign != old_sign) n_crossings++;
00076 old_sign = sign;
00077 }
00078
00079 return n_crossings;
00080 }
00081
00082
00083
00084
00085
00086
00087
00088
00089 int
00090 ControlPolygonFlatEnough(
00091 point2d_t *V,
00092 int degree,
00093 fastf_t epsilon)
00094 {
00095 int i;
00096 double *distance;
00097 double max_distance_above;
00098 double max_distance_below;
00099 double error;
00100 double intercept_1,
00101 intercept_2,
00102 left_intercept,
00103 right_intercept;
00104 double a, b, c;
00105
00106
00107
00108
00109
00110 distance = (double *)bu_malloc((unsigned)(degree + 1) * sizeof(double), "ControlPolygonFlatEnough");
00111 {
00112 double abSquared;
00113
00114
00115
00116 a = V[0][Y] - V[degree][Y];
00117 b = V[degree][X] - V[0][X];
00118 c = V[0][X] * V[degree][Y] - V[degree][X] * V[0][Y];
00119
00120 abSquared = (a * a) + (b * b);
00121
00122 for (i = 1; i < degree; i++) {
00123
00124 distance[i] = a * V[i][X] + b * V[i][Y] + c;
00125 if (distance[i] > 0.0) {
00126 distance[i] = (distance[i] * distance[i]) / abSquared;
00127 }
00128 if (distance[i] < 0.0) {
00129 distance[i] = -((distance[i] * distance[i]) / abSquared);
00130 }
00131 }
00132 }
00133
00134
00135
00136 max_distance_above = 0.0;
00137 max_distance_below = 0.0;
00138 for (i = 1; i < degree; i++) {
00139 if (distance[i] < 0.0) {
00140 max_distance_below = MIN(max_distance_below, distance[i]);
00141 };
00142 if (distance[i] > 0.0) {
00143 max_distance_above = MAX(max_distance_above, distance[i]);
00144 }
00145 }
00146 bu_free((char *)distance,"ControlPolygonFlatEnough" );
00147
00148 {
00149 double det, dInv;
00150 double a1, b1, c1, a2, b2, c2;
00151
00152
00153 a1 = 0.0;
00154 b1 = 1.0;
00155 c1 = 0.0;
00156
00157
00158 a2 = a;
00159 b2 = b;
00160 c2 = c + max_distance_above;
00161
00162 det = a1 * b2 - a2 * b1;
00163 dInv = 1.0/det;
00164
00165 intercept_1 = (b1 * c2 - b2 * c1) * dInv;
00166
00167
00168 a2 = a;
00169 b2 = b;
00170 c2 = c + max_distance_below;
00171
00172 det = a1 * b2 - a2 * b1;
00173 dInv = 1.0/det;
00174
00175 intercept_2 = (b1 * c2 - b2 * c1) * dInv;
00176 }
00177
00178
00179 left_intercept = MIN(intercept_1, intercept_2);
00180 right_intercept = MAX(intercept_1, intercept_2);
00181
00182 error = 0.5 * (right_intercept-left_intercept);
00183
00184 if (error < epsilon) {
00185 return 1;
00186 }
00187 else {
00188 return 0;
00189 }
00190 }
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200 void
00201 Bezier(
00202 point2d_t *V,
00203 int degree,
00204 double t,
00205 point2d_t *Left,
00206 point2d_t *Right,
00207 point2d_t eval_pt,
00208 point2d_t normal )
00209 {
00210 int i, j;
00211 fastf_t len;
00212 point2d_t tangent;
00213 point2d_t **Vtemp;
00214
00215
00216 Vtemp = (point2d_t **)bu_calloc( degree+1, sizeof(point2d_t *), "Bezier: Vtemp array" );
00217 for( i=0 ; i<=degree ; i++ )
00218 Vtemp[i] = (point2d_t *)bu_calloc( degree+1, sizeof( point2d_t ),
00219 "Bezier: Vtemp[i] array" );
00220
00221 for (j =0; j <= degree; j++) {
00222 V2MOVE( Vtemp[0][j], V[j]);
00223 }
00224
00225
00226 for (i = 1; i <= degree; i++) {
00227 for (j =0 ; j <= degree - i; j++) {
00228 Vtemp[i][j][X] =
00229 (1.0 - t) * Vtemp[i-1][j][X] + t * Vtemp[i-1][j+1][X];
00230 Vtemp[i][j][Y] =
00231 (1.0 - t) * Vtemp[i-1][j][Y] + t * Vtemp[i-1][j+1][Y];
00232 }
00233 }
00234
00235 if (Left != NULL) {
00236 for (j = 0; j <= degree; j++) {
00237 V2MOVE( Left[j], Vtemp[j][0]);
00238 }
00239 }
00240 if (Right != NULL) {
00241 for (j = 0; j <= degree; j++) {
00242 V2MOVE( Right[j], Vtemp[degree-j][j]);
00243 }
00244 }
00245
00246 V2MOVE( eval_pt, Vtemp[degree][0] );
00247
00248 if( normal ) {
00249 V2SUB2( tangent, Vtemp[degree-1][1], Vtemp[degree-1][0] );
00250 normal[X] = tangent[Y];
00251 normal[Y] = -tangent[X];
00252 len = sqrt( MAG2SQ( normal ) );
00253 normal[X] /= len;
00254 normal[Y] /= len;
00255 }
00256
00257 for( i=0 ; i<=degree ; i++ )
00258 bu_free( (char *)Vtemp[i], "Bezier: Vtemp[i]" );
00259 bu_free( (char *)Vtemp, "Bezier: Vtemp" );
00260
00261 return;
00262 }
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277 static int
00278 ComputeXIntercept(
00279 point2d_t *V,
00280 int degree,
00281 point2d_t ray_start,
00282 point2d_t ray_dir,
00283 double epsilon,
00284 point2d_t intercept,
00285 point2d_t normal )
00286 {
00287 fastf_t beta;
00288 fastf_t denom;
00289 fastf_t len;
00290 point2d_t seg_line;
00291
00292 denom = (V[degree][X] - V[0][X]) * ray_dir[Y] -
00293 (V[degree][Y] - V[0][Y]) * ray_dir[X];
00294
00295 if( NEAR_ZERO( denom, SMALL_FASTF ) )
00296 return 0;
00297
00298 beta = (V[0][Y] * ray_dir[X] - V[0][X] * ray_dir[Y] +
00299 ray_start[X] * ray_dir[Y] - ray_start[Y] * ray_dir[X] ) / denom;
00300
00301 if( beta < 0.0 || beta > 1.0 )
00302 return 0;
00303
00304 V2SUB2( seg_line, V[degree], V[0] );
00305 V2JOIN1( intercept, V[0], beta, seg_line );
00306
00307
00308 normal[X] = seg_line[Y];
00309 normal[Y] = -seg_line[X];
00310 len = sqrt( MAG2SQ( seg_line ) );
00311 normal[X] /= len;
00312 normal[Y] /= len;
00313
00314 return 1;
00315 #if 0
00316 V2MOVE( p, ray_start );
00317 p[Z] = 0.0;
00318 V2MOVE( d, ray_dir );
00319 d[Z] = 0.0;
00320 V2MOVE( a, V[0] );
00321 a[Z] = 0.0;
00322 V2SUB2( c, V[degree], V[0] );
00323 c[Z] = 0.0;
00324
00325
00326 ret = bn_isect_line2_lseg2( dist, p, d, a, c, &tol );
00327
00328 bu_log( "\tbn_isect_line2_lseg2() returned %d\n", ret );
00329
00330 if( ret <= 0 )
00331 return 0;
00332
00333 switch( ret ) {
00334 case 1:
00335
00336 V2MOVE( intercept, V[0] );
00337 break;
00338 case 2:
00339
00340 V2MOVE( intercept, V[degree] );
00341 break;
00342 case 3:
00343
00344 V2JOIN1( intercept, ray_start, dist[0], ray_dir );
00345 break;
00346 }
00347
00348
00349 normal[X] = c[Y];
00350 normal[Y] = -c[X];
00351 len = sqrt( MAG2SQ( c ) );
00352 normal[X] /= len;
00353 normal[Y] /= len;
00354
00355 return 1;
00356 #endif
00357 }
00358
00359
00360
00361
00362
00363
00364
00365
00366 int
00367 FindRoots(
00368 point2d_t *w,
00369 int degree,
00370 point2d_t **intercept,
00371 point2d_t **normal,
00372 point2d_t ray_start,
00373 point2d_t ray_dir,
00374 point2d_t ray_perp,
00375 int depth,
00376 fastf_t epsilon)
00377 {
00378 int i;
00379 point2d_t *Left,
00380 *Right;
00381 int left_count,
00382 right_count;
00383 point2d_t *left_t,
00384 *right_t;
00385 point2d_t *left_n,
00386 *right_n;
00387 int total_count;
00388 point2d_t eval_pt;
00389
00390 switch (CrossingCount(w, degree, ray_start, ray_dir, ray_perp)) {
00391 case 0 : {
00392 return 0;
00393 }
00394 case 1 : {
00395
00396
00397 if (depth >= MAXDEPTH) {
00398 *intercept = (point2d_t *)bu_malloc( sizeof( point2d_t ), "FindRoots: unique solution (intercept)" );
00399 *normal = (point2d_t *)bu_malloc( sizeof( point2d_t ), "FindRoots: unique solution (normal)" );
00400 Bezier( w, degree, 0.5, NULL, NULL, *intercept[0], *normal[0] );
00401 return 1;
00402 }
00403 if (ControlPolygonFlatEnough(w, degree, epsilon)) {
00404 *intercept = (point2d_t *)bu_malloc( sizeof( point2d_t ), "FindRoots: unique solution (intercept)" );
00405 *normal = (point2d_t *)bu_malloc( sizeof( point2d_t ), "FindRoots: unique solution (normal)" );
00406 if( !ComputeXIntercept( w, degree, ray_start, ray_dir, epsilon, *intercept[0], *normal[0] ) ){
00407 bu_free( (char *)(*intercept), "FindRoots: no solution" );
00408 bu_free( (char *)(*normal), "FindRoots: no solution" );
00409 return 0;
00410 }
00411 return 1;
00412 }
00413 break;
00414 }
00415 }
00416
00417
00418
00419 Left = (point2d_t *)bu_calloc( degree+1, sizeof( point2d_t ), "FindRoots: Left" );
00420 Right = (point2d_t *)bu_calloc( degree+1, sizeof( point2d_t ), "FindRoots: Right" );
00421 Bezier(w, degree, 0.5, Left, Right, eval_pt, NULL);
00422
00423 left_count = FindRoots(Left, degree, &left_t, &left_n, ray_start, ray_dir, ray_perp, depth+1, epsilon);
00424 right_count = FindRoots(Right, degree, &right_t, &right_n, ray_start, ray_dir, ray_perp, depth+1, epsilon);
00425
00426 total_count = left_count + right_count;
00427
00428 bu_free( (char *)Left, "FindRoots: Left" );
00429 bu_free( (char *)Right, "FindRoots: Right" );
00430 if( total_count ) {
00431 *intercept = (point2d_t *)bu_calloc( total_count, sizeof( point2d_t ),
00432 "FindRoots: roots compilation" );
00433 *normal = (point2d_t *)bu_calloc( total_count, sizeof( point2d_t ),
00434 "FindRoots: normal compilation" );
00435 }
00436
00437
00438 for (i = 0; i < left_count; i++) {
00439 V2MOVE( (*intercept)[i], left_t[i] );
00440 V2MOVE( (*normal)[i], left_n[i] );
00441 }
00442 for (i = 0; i < right_count; i++) {
00443 V2MOVE( (*intercept)[i+left_count], right_t[i] );
00444 V2MOVE( (*normal)[i+left_count], right_n[i] );
00445 }
00446
00447 if( left_count ) {
00448 bu_free( (char *)left_t, "Left roots" );
00449 bu_free( (char *)left_n, "Left normals" );
00450 }
00451 if( right_count ) {
00452 bu_free( (char *)right_t, "Right roots" );
00453 bu_free( (char *)right_n, "Right normals" );
00454 }
00455
00456
00457 return (total_count);
00458 }
00459
00460 struct bezier_2d_list *
00461 subdivide_bezier( struct bezier_2d_list *bezier_in, int degree, fastf_t epsilon, int depth )
00462 {
00463 struct bezier_2d_list *bz_l, *bz_r, *new_head;
00464 struct bezier_2d_list *left_rtrn, *rt_rtrn;
00465 point2d_t pt;
00466
00467
00468 new_head = (struct bezier_2d_list *)bu_malloc( sizeof( struct bezier_2d_list ),
00469 "subdivide_bezier: new_head" );
00470 BU_LIST_INIT( &new_head->l );
00471 if( depth >= MAXDEPTH ){
00472 BU_LIST_APPEND( &new_head->l, &bezier_in->l );
00473 return( new_head );
00474 }
00475
00476 if( ControlPolygonFlatEnough( bezier_in->ctl, degree, epsilon ) ) {
00477 BU_LIST_APPEND( &new_head->l, &bezier_in->l );
00478 return( new_head );
00479 }
00480
00481
00482 bz_l = (struct bezier_2d_list *)bu_malloc( sizeof( struct bezier_2d_list ), "subdivide_bezier: bz_l" );
00483 BU_LIST_INIT( &bz_l->l );
00484 bz_r = (struct bezier_2d_list *)bu_malloc( sizeof( struct bezier_2d_list ), "subdivide_bezier: bz_r" );
00485 BU_LIST_INIT( &bz_r->l );
00486 bz_l->ctl = (point2d_t *)bu_calloc( degree + 1, sizeof( point2d_t ),
00487 "subdivide_bezier: bz_l->ctl" );
00488 bz_r->ctl = (point2d_t *)bu_calloc( degree + 1, sizeof( point2d_t ),
00489 "subdivide_bezier: bz_r->ctl" );
00490
00491
00492 Bezier( bezier_in->ctl, degree, 0.5, bz_l->ctl, bz_r->ctl, pt, NULL );
00493
00494
00495 BU_LIST_DEQUEUE( &bezier_in->l );
00496 bu_free( (char *)bezier_in->ctl, "subdivide_bezier: bezier_in->ctl" );
00497 bu_free( (char *)bezier_in, "subdivide_bezier: bezier_in" );
00498
00499
00500 left_rtrn = subdivide_bezier( bz_l, degree, epsilon, depth+1 );
00501
00502
00503 rt_rtrn = subdivide_bezier( bz_r, degree, epsilon, depth+1 );
00504
00505 BU_LIST_APPEND_LIST( &new_head->l, &left_rtrn->l );
00506 BU_LIST_APPEND_LIST( &new_head->l, &rt_rtrn->l );
00507 bu_free( (char *)left_rtrn, "subdivide_bezier: left_rtrn (head)" );
00508 bu_free( (char *)rt_rtrn, "subdivide_bezier: rt_rtrn (head)" );
00509
00510 return( new_head );
00511 }
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522