Main Page | Modules | Data Structures | File List | Data Fields | Globals | Related Pages

ray_intersect.c

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------- 00002 @COPYRIGHT : 00003 Copyright 1993,1994,1995 David MacDonald, 00004 McConnell Brain Imaging Centre, 00005 Montreal Neurological Institute, McGill University. 00006 Permission to use, copy, modify, and distribute this 00007 software and its documentation for any purpose and without 00008 fee is hereby granted, provided that the above copyright 00009 notice appear in all copies. The author and McGill University 00010 make no representations about the suitability of this 00011 software for any purpose. It is provided "as is" without 00012 express or implied warranty. 00013 ---------------------------------------------------------------------------- */ 00014 00015 #include <volume_io/internal_volume_io.h> 00016 #include <bicpl/geom.h> 00017 #include <bicpl/numerical.h> 00018 00019 #define MAX_POINTS 30 00020 #ifndef lint 00021 static char rcsid[] = "$Header: /software/source//libraries/bicpl/Geometry/ray_intersect.c,v 1.31 2000/02/06 15:30:17 stever Exp $"; 00022 #endif 00023 00024 00025 #define TOLERANCE 1.0e-2 00026 #define TRIANGLE_TOLERANCE 1.0e-3 00027 00028 private BOOLEAN point_within_triangle_2d( 00029 Point *pt, 00030 Point points[] ); 00031 private BOOLEAN point_within_polygon_2d( 00032 Point *pt, 00033 int n_points, 00034 Point points[], 00035 Vector *polygon_normal ); 00036 00037 private int n_dirs = -1; 00038 private Real *dirs = NULL; 00039 00040 public void initialize_intersect_directions( void ) 00041 { 00042 if( n_dirs > 0 ) 00043 { 00044 FREE( dirs ); 00045 } 00046 n_dirs = 0; 00047 } 00048 00049 public Real *get_intersect_directions( void ) 00050 { 00051 int i; 00052 Real *d; 00053 00054 if( n_dirs > 0 ) 00055 { 00056 ALLOC( d, n_dirs ); 00057 for_less( i, 0, n_dirs ) 00058 d[i] = dirs[i]; 00059 00060 FREE( dirs ); 00061 } 00062 00063 n_dirs = -1; 00064 00065 return( d ); 00066 } 00067 00068 private BOOLEAN intersect_ray_triangle( 00069 Point *ray_origin, 00070 Vector *ray_direction, 00071 Point *point0, 00072 Point *point1, 00073 Point *point2, 00074 Real *dist ) 00075 { 00076 Real n_dot_d, d; 00077 Real v01x, v01y, v01z, v02x, v02y, v02z, nx, ny, nz, rx, ry, rz; 00078 Real vx, vy, vz; 00079 Real tx0, ty0, tz0, tx1, ty1, tz1, tx2, ty2, tz2; 00080 Real sign; 00081 00082 tx0 = RPoint_x( *point0 ) - RPoint_x( *ray_origin ); 00083 ty0 = RPoint_y( *point0 ) - RPoint_y( *ray_origin ); 00084 tz0 = RPoint_z( *point0 ) - RPoint_z( *ray_origin ); 00085 00086 tx1 = RPoint_x( *point1 ) - RPoint_x( *ray_origin ); 00087 ty1 = RPoint_y( *point1 ) - RPoint_y( *ray_origin ); 00088 tz1 = RPoint_z( *point1 ) - RPoint_z( *ray_origin ); 00089 00090 tx2 = RPoint_x( *point2 ) - RPoint_x( *ray_origin ); 00091 ty2 = RPoint_y( *point2 ) - RPoint_y( *ray_origin ); 00092 tz2 = RPoint_z( *point2 ) - RPoint_z( *ray_origin ); 00093 00094 v01x = tx1 - tx0; 00095 v01y = ty1 - ty0; 00096 v01z = tz1 - tz0; 00097 v02x = tx2 - tx0; 00098 v02y = ty2 - ty0; 00099 v02z = tz2 - tz0; 00100 00101 nx = v01y * v02z - v01z * v02y; 00102 ny = v01z * v02x - v01x * v02z; 00103 nz = v01x * v02y - v01y * v02x; 00104 00105 rx = RVector_x(*ray_direction); 00106 ry = RVector_y(*ray_direction); 00107 rz = RVector_z(*ray_direction); 00108 00109 n_dot_d = rx * nx + ry * ny + rz * nz; 00110 00111 if( n_dot_d == 0.0 ) 00112 return( FALSE ); 00113 00114 vx = ty1 * tz0 - tz1 * ty0; 00115 vy = tz1 * tx0 - tx1 * tz0; 00116 vz = tx1 * ty0 - ty1 * tx0; 00117 d = rx * vx + ry * vy + rz * vz; 00118 if( n_dot_d * d > 0.0 ) 00119 return( FALSE ); 00120 00121 vx = ty2 * tz1 - tz2 * ty1; 00122 vy = tz2 * tx1 - tx2 * tz1; 00123 vz = tx2 * ty1 - ty2 * tx1; 00124 d = rx * vx + ry * vy + rz * vz; 00125 if( n_dot_d * d > 0.0 ) 00126 return( FALSE ); 00127 00128 vx = ty0 * tz2 - tz0 * ty2; 00129 vy = tz0 * tx2 - tx0 * tz2; 00130 vz = tx0 * ty2 - ty0 * tx2; 00131 d = rx * vx + ry * vy + rz * vz; 00132 if( n_dot_d * d > 0.0 ) 00133 return( FALSE ); 00134 00135 *dist = (nx * tx0 + ny * ty0 + nz * tz0)/ n_dot_d; 00136 00137 if( *dist >= 0.0 ) 00138 { 00139 if( n_dot_d < 0.0 ) 00140 sign = -1.0; 00141 else if( n_dot_d == 0.0 ) 00142 sign = 0.0; 00143 else 00144 sign = 1.0; 00145 00146 if( n_dirs >= 0 ) 00147 { 00148 ADD_ELEMENT_TO_ARRAY( dirs, n_dirs, sign, DEFAULT_CHUNK_SIZE ); 00149 } 00150 } 00151 00152 return( *dist >= 0.0 ); 00153 } 00154 00155 /* ----------------------------- MNI Header ----------------------------------- 00156 @NAME : intersect_ray_polygon_points 00157 @INPUT : ray_origin 00158 ray_direction 00159 n_points 00160 points 00161 @OUTPUT : dist 00162 @RETURNS : TRUE if ray intersects 00163 @DESCRIPTION: Tests if the ray intersects the polygon, passing back the 00164 distance. 00165 @METHOD : 00166 @GLOBALS : 00167 @CALLS : 00168 @CREATED : 1993 David MacDonald 00169 @MODIFIED : 00170 ---------------------------------------------------------------------------- */ 00171 00172 private BOOLEAN intersect_ray_polygon_points( 00173 Point *ray_origin, 00174 Vector *ray_direction, 00175 int n_points, 00176 Point points[], 00177 Real *dist ) 00178 { 00179 BOOLEAN intersects; 00180 int p; 00181 00182 intersects = FALSE; 00183 00184 for_less( p, 1, n_points-1 ) 00185 { 00186 intersects = intersect_ray_triangle( ray_origin, ray_direction, 00187 &points[0], &points[p], &points[p+1], dist ); 00188 00189 if( intersects ) 00190 break; 00191 } 00192 00193 return( intersects ); 00194 } 00195 00196 /* ----------------------------- MNI Header ----------------------------------- 00197 @NAME : intersect_ray_polygon 00198 @INPUT : ray_origin 00199 ray_direction 00200 polygons 00201 poly_index 00202 @OUTPUT : dist 00203 @RETURNS : TRUE if intersects 00204 @DESCRIPTION: Tests if a ray intersects a given poly in the polygons. 00205 @METHOD : 00206 @GLOBALS : 00207 @CALLS : 00208 @CREATED : 1993 David MacDonald 00209 @MODIFIED : 00210 ---------------------------------------------------------------------------- */ 00211 00212 private BOOLEAN intersect_ray_polygon( 00213 Point *ray_origin, 00214 Vector *ray_direction, 00215 Real *dist, 00216 polygons_struct *polygons, 00217 int poly_index ) 00218 { 00219 BOOLEAN intersects; 00220 Point points[MAX_POINTS]; 00221 int ind, p, start_index, end_index, size; 00222 00223 intersects = FALSE; 00224 00225 if( polygons->visibilities == (Smallest_int *) 0 || 00226 polygons->visibilities[poly_index] ) 00227 { 00228 start_index = START_INDEX( polygons->end_indices, poly_index ); 00229 end_index = polygons->end_indices[poly_index]; 00230 00231 size = end_index - start_index; 00232 00233 if( size == 3 ) 00234 { 00235 intersects = intersect_ray_triangle( ray_origin, ray_direction, 00236 &polygons->points[polygons->indices[start_index]], 00237 &polygons->points[polygons->indices[start_index+1]], 00238 &polygons->points[polygons->indices[start_index+2]], 00239 dist ); 00240 } 00241 else 00242 { 00243 if( size > MAX_POINTS ) 00244 { 00245 print_error( "Warning: awfully big polygon, size = %d\n", size); 00246 size = MAX_POINTS; 00247 end_index = start_index + size - 1; 00248 } 00249 00250 for_less( p, start_index, end_index ) 00251 { 00252 ind = polygons->indices[p]; 00253 points[p-start_index] = polygons->points[ind]; 00254 } 00255 00256 intersects = intersect_ray_polygon_points( ray_origin, 00257 ray_direction, size, points, dist ); 00258 } 00259 } 00260 00261 return( intersects ); 00262 } 00263 00264 /* ----------------------------- MNI Header ----------------------------------- 00265 @NAME : point_within_polygon 00266 @INPUT : pt 00267 n_points 00268 points 00269 polygon_normal 00270 @OUTPUT : 00271 @RETURNS : TRUE if inside 00272 @DESCRIPTION: Tests if a point is within a 3d polygon. 00273 @METHOD : 00274 @GLOBALS : 00275 @CALLS : 00276 @CREATED : 1993 David MacDonald 00277 @MODIFIED : 00278 ---------------------------------------------------------------------------- */ 00279 00280 public BOOLEAN point_within_polygon( 00281 Point *pt, 00282 int n_points, 00283 Point points[], 00284 Vector *polygon_normal ) 00285 { 00286 BOOLEAN intersects; 00287 00288 if( n_points == 3 ) 00289 intersects = point_within_triangle_2d( pt, points ); 00290 else 00291 intersects = point_within_polygon_2d( pt, n_points, points, 00292 polygon_normal ); 00293 00294 return( intersects ); 00295 } 00296 00297 /* ----------------------------- MNI Header ----------------------------------- 00298 @NAME : point_within_triangle_2d 00299 @INPUT : pt 00300 points 00301 @OUTPUT : 00302 @RETURNS : TRUE if inside 00303 @DESCRIPTION: Tests if a point is within a 3D triangle. The point should 00304 be on or close to on the plane of the triangle. 00305 @METHOD : 00306 @GLOBALS : 00307 @CALLS : 00308 @CREATED : 1993 David MacDonald 00309 @MODIFIED : 00310 ---------------------------------------------------------------------------- */ 00311 00312 private BOOLEAN point_within_triangle_2d( 00313 Point *pt, 00314 Point points[] ) 00315 { 00316 Real x_pos, y_pos, sum, bottom; 00317 Real x_dot_x, x_dot_y, x_dot_v, y_dot_y, y_dot_v; 00318 Vector x_axis, y_axis, v; 00319 00320 SUB_VECTORS( x_axis, points[1], points[0] ); 00321 SUB_VECTORS( y_axis, points[2], points[0] ); 00322 SUB_VECTORS( v, *pt, points[0] ); 00323 00324 x_dot_x = DOT_VECTORS( x_axis, x_axis ); 00325 x_dot_y = DOT_VECTORS( x_axis, y_axis ); 00326 x_dot_v = DOT_VECTORS( x_axis, v ); 00327 y_dot_y = DOT_VECTORS( y_axis, y_axis ); 00328 y_dot_v = DOT_VECTORS( y_axis, v ); 00329 00330 bottom = x_dot_x * y_dot_y - x_dot_y * x_dot_y; 00331 00332 if( bottom == 0.0 ) 00333 return( FALSE ); 00334 00335 x_pos = (x_dot_v * y_dot_y - y_dot_v * x_dot_y) / bottom; 00336 00337 if( x_pos < -TRIANGLE_TOLERANCE || x_pos > 1.0 + TRIANGLE_TOLERANCE ) 00338 return( FALSE ); 00339 00340 y_pos = (y_dot_v * x_dot_x - x_dot_v * x_dot_y) / bottom; 00341 00342 if( y_pos < -TRIANGLE_TOLERANCE || y_pos > 1.0 + TRIANGLE_TOLERANCE ) 00343 return( FALSE ); 00344 00345 sum = x_pos + y_pos; 00346 return( sum >= -TRIANGLE_TOLERANCE && sum <= 1.0 + TRIANGLE_TOLERANCE ); 00347 } 00348 00349 /* ----------------------------- MNI Header ----------------------------------- 00350 @NAME : point_within_polygon_2d 00351 @INPUT : pt 00352 n_points 00353 points 00354 polygon_normal 00355 @OUTPUT : 00356 @RETURNS : TRUE if inside 00357 @DESCRIPTION: Tests if the point is within the 3D polygon, by projecting 00358 the problem to 2 dimensions. The polygon may be convex or not. 00359 @METHOD : 00360 @GLOBALS : 00361 @CALLS : 00362 @CREATED : 1993 David MacDonald 00363 @MODIFIED : 00364 ---------------------------------------------------------------------------- */ 00365 00366 private BOOLEAN point_within_polygon_2d( 00367 Point *pt, 00368 int n_points, 00369 Point points[], 00370 Vector *polygon_normal ) 00371 { 00372 BOOLEAN intersects, cross; 00373 Real x, y, x1, y1, x2, y2, x_inter, dx, dy, tx, ty, len, t; 00374 Real nx, ny, nz, max_val; 00375 int i1, i2; 00376 int i; 00377 00378 nx = FABS( (Real) Vector_x(*polygon_normal) ); 00379 ny = FABS( (Real) Vector_y(*polygon_normal) ); 00380 nz = FABS( (Real) Vector_z(*polygon_normal) ); 00381 00382 max_val = MAX3( nx, ny, nz ); 00383 00384 if( nx == max_val ) 00385 { 00386 i1 = Y; 00387 i2 = Z; 00388 } 00389 else if( ny == max_val ) 00390 { 00391 i1 = Z; 00392 i2 = X; 00393 } 00394 else 00395 { 00396 i1 = X; 00397 i2 = Y; 00398 } 00399 00400 x = (Real) Point_coord( *pt, i1 ); 00401 y = (Real) Point_coord( *pt, i2 ); 00402 00403 cross = FALSE; 00404 00405 x2 = (Real) Point_coord(points[n_points-1],i1); 00406 y2 = (Real) Point_coord(points[n_points-1],i2); 00407 00408 for_less( i, 0, n_points ) 00409 { 00410 x1 = x2; 00411 y1 = y2; 00412 00413 x2 = (Real) Point_coord(points[i],i1); 00414 y2 = (Real) Point_coord(points[i],i2); 00415 00416 if( !( (y1 > y && y2 > y ) || 00417 (y1 < y && y2 < y ) || 00418 (x1 > x && x2 > x )) ) 00419 { 00420 dy = y2 - y1; 00421 if( dy != 0.0 ) 00422 { 00423 if( y1 == y ) 00424 { 00425 if( y2 > y1 && x1 <= x ) 00426 { 00427 cross = !cross; 00428 } 00429 } 00430 else if( y2 == y ) 00431 { 00432 if( y1 > y2 && x2 <= x ) 00433 { 00434 cross = !cross; 00435 } 00436 } 00437 else if( x1 <= x && x2 <= x ) 00438 { 00439 cross = !cross; 00440 } 00441 else 00442 { 00443 x_inter = x1 + (y - y1) / dy * (x2 - x1); 00444 00445 if( x_inter < x ) 00446 { 00447 cross = !cross; 00448 } 00449 } 00450 } 00451 } 00452 } 00453 00454 intersects = cross; 00455 00456 if( !intersects ) 00457 { 00458 x2 = (Real) Point_coord(points[n_points-1],i1); 00459 y2 = (Real) Point_coord(points[n_points-1],i2); 00460 00461 for_less( i, 0, n_points ) 00462 { 00463 x1 = x2; 00464 y1 = y2; 00465 00466 x2 = (Real) Point_coord(points[i],i1); 00467 y2 = (Real) Point_coord(points[i],i2); 00468 00469 if( x1 - TOLERANCE <= x && x <= x1 + TOLERANCE && 00470 y1 - TOLERANCE <= y && y <= y1 + TOLERANCE ) 00471 { 00472 intersects = TRUE; 00473 break; 00474 } 00475 00476 dx = x2 - x1; 00477 dy = y2 - y1; 00478 tx = x - x1; 00479 ty = y - y1; 00480 00481 len = dx * dx + dy * dy; 00482 if( len == 0.0 ) 00483 continue; 00484 00485 t = (tx * dx + ty * dy) / len; 00486 00487 if( t < 0.0 || t > 1.0 ) 00488 continue; 00489 00490 tx = tx - t * dx; 00491 ty = ty - t * dy; 00492 00493 if( tx * tx + ty * ty < TOLERANCE * TOLERANCE ) 00494 { 00495 intersects = TRUE; 00496 break; 00497 } 00498 } 00499 } 00500 00501 return( intersects ); 00502 } 00503 00504 /* ----------------------------- MNI Header ----------------------------------- 00505 @NAME : intersect_ray_quadmesh_patch 00506 @INPUT : ray_origin 00507 ray_direction 00508 dist 00509 quadmesh 00510 obj_index 00511 @OUTPUT : 00512 @RETURNS : TRUE if intersects 00513 @DESCRIPTION: Tests if a ray intersects a given quadrilateral of a quadmesh. 00514 @METHOD : 00515 @GLOBALS : 00516 @CALLS : 00517 @CREATED : 1993 David MacDonald 00518 @MODIFIED : 00519 ---------------------------------------------------------------------------- */ 00520 00521 private BOOLEAN intersect_ray_quadmesh_patch( 00522 Point *ray_origin, 00523 Vector *ray_direction, 00524 Real *dist, 00525 quadmesh_struct *quadmesh, 00526 int obj_index ) 00527 { 00528 BOOLEAN intersects; 00529 Point points[4]; 00530 int i, j, m, n; 00531 00532 get_quadmesh_n_objects( quadmesh, &m, &n ); 00533 00534 i = obj_index / n; 00535 j = obj_index % n; 00536 00537 get_quadmesh_patch( quadmesh, i, j, points ); 00538 00539 intersects = intersect_ray_polygon_points( ray_origin, ray_direction, 00540 4, points, dist ); 00541 00542 return( intersects ); 00543 } 00544 00545 /* ----------------------------- MNI Header ----------------------------------- 00546 @NAME : line_intersects_ellipsoid 00547 @INPUT : line_origin 00548 line_direction 00549 sphere_centre 00550 x_size 00551 y_size 00552 z_size 00553 @OUTPUT : t_min 00554 t_max 00555 @RETURNS : TRUE if intersects 00556 @DESCRIPTION: Tests if the line intersects the ellipsoid, and if so, passes 00557 back the enter and exit distance, as a multiple of line_direction. 00558 @METHOD : 00559 @GLOBALS : 00560 @CALLS : 00561 @CREATED : 1993 David MacDonald 00562 @MODIFIED : 00563 ---------------------------------------------------------------------------- */ 00564 00565 public BOOLEAN line_intersects_ellipsoid( 00566 Point *line_origin, 00567 Vector *line_direction, 00568 Point *sphere_centre, 00569 Real x_size, 00570 Real y_size, 00571 Real z_size, 00572 Real *t_min, 00573 Real *t_max ) 00574 { 00575 BOOLEAN intersects; 00576 int n_solutions; 00577 Real a, b, c, ox, oy, oz, dx, dy, dz, t1, t2; 00578 00579 ox = ((Real) Point_x(*line_origin) - (Real) Point_x(*sphere_centre)) / 00580 x_size; 00581 oy = ((Real) Point_y(*line_origin) - (Real) Point_y(*sphere_centre)) / 00582 y_size; 00583 oz = ((Real) Point_z(*line_origin) - (Real) Point_z(*sphere_centre)) / 00584 z_size; 00585 00586 dx = (Real) Vector_x(*line_direction) / x_size; 00587 dy = (Real) Vector_y(*line_direction) / y_size; 00588 dz = (Real) Vector_z(*line_direction) / z_size; 00589 00590 a = dx * dx + dy * dy + dz * dz; 00591 b = 2.0 * ( ox * dx + oy * dy + oz * dz); 00592 c = ox * ox + oy * oy + oz * oz - 1.0; 00593 00594 n_solutions = solve_quadratic( a, b, c, &t1, &t2 ); 00595 00596 if( n_solutions == 0 ) 00597 intersects = FALSE; 00598 else if( n_solutions == 1 ) 00599 { 00600 intersects = TRUE; 00601 *t_min = t1; 00602 *t_max = t2; 00603 } 00604 else 00605 { 00606 intersects = TRUE; 00607 *t_min = MIN( t1, t2 ); 00608 *t_max = MAX( t1, t2 ); 00609 } 00610 00611 return( intersects ); 00612 } 00613 00614 /* ----------------------------- MNI Header ----------------------------------- 00615 @NAME : ray_intersects_sphere 00616 @INPUT : origin 00617 direction 00618 centre 00619 radius 00620 @OUTPUT : dist 00621 @RETURNS : TRUE if intersects 00622 @DESCRIPTION: Tests if a ray intersects a sphere. 00623 @METHOD : 00624 @GLOBALS : 00625 @CALLS : 00626 @CREATED : 1993 David MacDonald 00627 @MODIFIED : 00628 ---------------------------------------------------------------------------- */ 00629 00630 public BOOLEAN ray_intersects_sphere( 00631 Point *origin, 00632 Vector *direction, 00633 Point *centre, 00634 Real radius, 00635 Real *dist ) 00636 { 00637 BOOLEAN intersects; 00638 Real t_min, t_max; 00639 00640 intersects = line_intersects_ellipsoid( origin, direction, centre, 00641 radius, radius, radius, 00642 &t_min, &t_max ); 00643 00644 if( intersects ) 00645 { 00646 if( t_min >= 0.0 ) 00647 *dist = t_min; 00648 else if( t_max >= 0.0 ) 00649 *dist = t_max; 00650 else 00651 intersects = FALSE; 00652 } 00653 00654 return( intersects ); 00655 } 00656 00657 /* ----------------------------- MNI Header ----------------------------------- 00658 @NAME : ray_intersects_tube 00659 @INPUT : origin 00660 direction 00661 p1 00662 p2 00663 radius 00664 @OUTPUT : dist 00665 @RETURNS : TRUE if intersects 00666 @DESCRIPTION: Tests if a ray intersects a cylinder from p1 to p2 with given 00667 radius. Solution of a quadratic is required. 00668 @METHOD : 00669 @GLOBALS : 00670 @CALLS : 00671 @CREATED : 1993 David MacDonald 00672 @MODIFIED : 00673 ---------------------------------------------------------------------------- */ 00674 00675 private BOOLEAN ray_intersects_tube( 00676 Point *origin, 00677 Vector *direction, 00678 Point *p1, 00679 Point *p2, 00680 Real radius, 00681 Real *dist ) 00682 { 00683 Point point; 00684 int n_sols; 00685 Real a, b, c, sols[2], t_min, t_max; 00686 Real len_axis, x, y, z, dx, dy, ox, oy; 00687 Point trans_origin; 00688 Vector tube_axis, hor, vert, trans_direction; 00689 Transform transform; 00690 00691 if( EQUAL_POINTS( *p1, *p2 ) ) 00692 return( FALSE ); 00693 00694 SUB_POINTS( tube_axis, *p2, *p1 ); 00695 create_two_orthogonal_vectors( &tube_axis, &hor, &vert ); 00696 len_axis = MAGNITUDE( tube_axis ); 00697 SCALE_VECTOR( tube_axis, tube_axis, 1.0 / len_axis ); 00698 NORMALIZE_VECTOR( hor, hor ); 00699 NORMALIZE_VECTOR( vert, vert ); 00700 make_change_from_bases_transform( p1, &hor, &vert, &tube_axis, &transform ); 00701 00702 transform_point( &transform, 00703 RPoint_x(*origin), RPoint_y(*origin), RPoint_z(*origin), 00704 &x, &y, &z ); 00705 fill_Point( trans_origin, x, y, z ); 00706 00707 transform_vector( &transform, 00708 RVector_x(*direction), RVector_y(*direction), RVector_z(*direction), 00709 &x, &y, &z ); 00710 fill_Vector( trans_direction, x, y, z ); 00711 00712 if( !clip_line_to_box( &trans_origin, &trans_direction, 00713 -radius, radius, -radius, radius, 00714 -radius, len_axis + radius, &t_min, &t_max ) ) 00715 { 00716 return( FALSE ); 00717 } 00718 00719 ox = RPoint_x( trans_origin ); 00720 oy = RPoint_y( trans_origin ); 00721 dx = RVector_x( trans_direction ); 00722 dy = RVector_y( trans_direction ); 00723 00724 a = dx * dx + dy * dy; 00725 b = 2.0 * (ox * dx + oy * dy); 00726 c = ox * ox + oy * oy - radius * radius; 00727 00728 n_sols = solve_quadratic( a, b, c, &sols[0], &sols[1] ); 00729 00730 if( n_sols == 0 ) 00731 *dist = -1.0; 00732 else if( n_sols == 1 ) 00733 *dist = sols[0]; 00734 else 00735 { 00736 t_min = MIN( sols[0], sols[1] ); 00737 t_max = MAX( sols[0], sols[1] ); 00738 if( t_min >= 0.0 ) 00739 *dist = t_min; 00740 else if( t_max >= 0.0 ) 00741 *dist = t_max; 00742 else 00743 *dist = -1.0; 00744 } 00745 00746 /*--- if intersects infinitely long tube, check if it intersects 00747 between p1 and p2 */ 00748 00749 if( *dist >= 0.0 ) 00750 { 00751 GET_POINT_ON_RAY( point, trans_origin, trans_direction, *dist ); 00752 if( RPoint_z(point) < 0.0 || RPoint_z(point) > len_axis ) 00753 *dist = -1.0; 00754 } 00755 00756 return( *dist >= 0.0 ); 00757 } 00758 00759 /* ----------------------------- MNI Header ----------------------------------- 00760 @NAME : intersect_ray_tube_segment 00761 @INPUT : origin 00762 direction 00763 lines 00764 obj_index 00765 @OUTPUT : dist 00766 @RETURNS : TRUE if intersects 00767 @DESCRIPTION: Tests if a ray intersects the tube segment corresponding to 00768 a line segment. 00769 @METHOD : 00770 @GLOBALS : 00771 @CALLS : 00772 @CREATED : 1993 David MacDonald 00773 @MODIFIED : 00774 ---------------------------------------------------------------------------- */ 00775 00776 private BOOLEAN intersect_ray_tube_segment( 00777 Point *origin, 00778 Vector *direction, 00779 Real *dist, 00780 lines_struct *lines, 00781 int obj_index ) 00782 { 00783 Real a_dist; 00784 int line, seg, p1, p2; 00785 BOOLEAN found; 00786 00787 get_line_segment_index( lines, obj_index, &line, &seg ); 00788 00789 p1 = lines->indices[POINT_INDEX(lines->end_indices,line,seg)]; 00790 p2 = lines->indices[POINT_INDEX(lines->end_indices,line,seg+1)]; 00791 00792 found = ray_intersects_sphere( origin, direction, &lines->points[p1], 00793 (Real) lines->line_thickness, dist ); 00794 00795 if( ray_intersects_sphere( origin, direction, &lines->points[p2], 00796 (Real) lines->line_thickness, &a_dist ) && 00797 (!found || a_dist < *dist ) ) 00798 { 00799 found = TRUE; 00800 *dist = a_dist; 00801 } 00802 00803 if( ray_intersects_tube( origin, direction, 00804 &lines->points[p1], 00805 &lines->points[p2], 00806 (Real) lines->line_thickness, &a_dist ) && 00807 (!found || a_dist < *dist ) ) 00808 { 00809 found = TRUE; 00810 *dist = a_dist; 00811 } 00812 00813 return( found ); 00814 } 00815 00816 /* ----------------------------- MNI Header ----------------------------------- 00817 @NAME : intersect_ray_with_cube 00818 @INPUT : ray_origin 00819 ray_direction 00820 centre 00821 size 00822 @OUTPUT : dist 00823 @RETURNS : TRUE if intersects 00824 @DESCRIPTION: Tests if the ray intersects the cube. 00825 @METHOD : 00826 @GLOBALS : 00827 @CALLS : 00828 @CREATED : 1993 David MacDonald 00829 @MODIFIED : 00830 ---------------------------------------------------------------------------- */ 00831 00832 private BOOLEAN intersect_ray_with_cube( 00833 Point *ray_origin, 00834 Vector *ray_direction, 00835 Point *centre, 00836 Real size, 00837 Real *dist ) 00838 { 00839 Real t_min, t_max; 00840 BOOLEAN intersects; 00841 00842 intersects = clip_line_to_box( ray_origin, ray_direction, 00843 (Real) Point_x(*centre) - size / 2.0, 00844 (Real) Point_x(*centre) + size / 2.0, 00845 (Real) Point_y(*centre) - size / 2.0, 00846 (Real) Point_y(*centre) + size / 2.0, 00847 (Real) Point_z(*centre) - size / 2.0, 00848 (Real) Point_z(*centre) + size / 2.0, 00849 &t_min, &t_max ); 00850 00851 if( intersects ) 00852 { 00853 if( t_min >= 0.0 ) 00854 *dist = t_min; 00855 else if( t_max >= 0.0 ) 00856 *dist = t_max; 00857 else 00858 intersects = FALSE; 00859 } 00860 00861 return( intersects ); 00862 } 00863 00864 /* ----------------------------- MNI Header ----------------------------------- 00865 @NAME : intersect_ray_with_marker 00866 @INPUT : ray_origin 00867 ray_direction 00868 marker 00869 @OUTPUT : dist 00870 @RETURNS : TRUE if intersects 00871 @DESCRIPTION: Tests if the ray intersects the marker, which can be a cube 00872 or a sphere. 00873 @METHOD : 00874 @GLOBALS : 00875 @CALLS : 00876 @CREATED : 1993 David MacDonald 00877 @MODIFIED : 00878 ---------------------------------------------------------------------------- */ 00879 00880 private BOOLEAN intersect_ray_with_marker( 00881 Point *ray_origin, 00882 Vector *ray_direction, 00883 marker_struct *marker, 00884 Real *dist ) 00885 { 00886 if( marker->type == BOX_MARKER ) 00887 { 00888 return( intersect_ray_with_cube( ray_origin, ray_direction, 00889 &marker->position, marker->size, dist)); 00890 } 00891 else 00892 { 00893 return( ray_intersects_sphere( ray_origin, ray_direction, 00894 &marker->position, marker->size, dist) ); 00895 } 00896 } 00897 00898 /* ----------------------------- MNI Header ----------------------------------- 00899 @NAME : intersect_ray_object 00900 @INPUT : origin 00901 direction 00902 object 00903 obj_index 00904 @OUTPUT : closest_obj_index 00905 closest_dist 00906 n_intersections 00907 distances 00908 @RETURNS : 00909 @DESCRIPTION: Tests if the ray intersects the given object. 00910 @METHOD : 00911 @GLOBALS : 00912 @CALLS : 00913 @CREATED : 1993 David MacDonald 00914 @MODIFIED : 00915 ---------------------------------------------------------------------------- */ 00916 00917 public void intersect_ray_object( 00918 Point *origin, 00919 Vector *direction, 00920 object_struct *object, 00921 int obj_index, 00922 int *closest_obj_index, 00923 Real *closest_dist, 00924 int *n_intersections, 00925 Real *distances[] ) 00926 { 00927 BOOLEAN found; 00928 Real dist; 00929 00930 if( get_object_type( object ) == POLYGONS ) 00931 { 00932 found = intersect_ray_polygon( origin, direction, &dist, 00933 get_polygons_ptr(object), obj_index ); 00934 } 00935 else if( get_object_type( object ) == QUADMESH ) 00936 { 00937 found = intersect_ray_quadmesh_patch( origin, direction, &dist, 00938 get_quadmesh_ptr(object), obj_index ); 00939 } 00940 else if( get_object_type( object ) == LINES ) 00941 { 00942 found = intersect_ray_tube_segment( origin, direction, &dist, 00943 get_lines_ptr(object), obj_index ); 00944 } 00945 else if( get_object_type( object ) == MARKER ) 00946 { 00947 found = intersect_ray_with_marker( origin, direction, 00948 get_marker_ptr(object), &dist ); 00949 } 00950 00951 if( found ) 00952 { 00953 if( distances != (Real **) NULL ) 00954 { 00955 SET_ARRAY_SIZE( *distances, *n_intersections, 00956 *n_intersections + 1, DEFAULT_CHUNK_SIZE ); 00957 (*distances)[*n_intersections] = dist; 00958 } 00959 00960 if( closest_obj_index != (int *) NULL && 00961 ((*n_intersections == 0) || dist < *closest_dist ) ) 00962 { 00963 *closest_obj_index = obj_index; 00964 *closest_dist = dist; 00965 } 00966 00967 ++(*n_intersections); 00968 } 00969 } 00970 00971 /* ----------------------------- MNI Header ----------------------------------- 00972 @NAME : intersect_ray_with_object 00973 @INPUT : origin 00974 direction 00975 object 00976 @OUTPUT : obj_index 00977 dist 00978 distances 00979 @RETURNS : n_intersections 00980 @DESCRIPTION: Tests for intersection of the ray with an object. 00981 @METHOD : 00982 @GLOBALS : 00983 @CALLS : 00984 @CREATED : 1993 David MacDonald 00985 @MODIFIED : 00986 ---------------------------------------------------------------------------- */ 00987 00988 public int intersect_ray_with_object( 00989 Point *origin, 00990 Vector *direction, 00991 object_struct *object, 00992 int *obj_index, 00993 Real *dist, 00994 Real *distances[] ) 00995 { 00996 lines_struct *lines; 00997 polygons_struct *polygons; 00998 quadmesh_struct *quadmesh; 00999 int i, n_intersections, m, n, n_objects; 01000 01001 n_intersections = 0; 01002 if( obj_index != (int *) NULL ) 01003 *obj_index = -1; 01004 01005 switch( get_object_type( object ) ) 01006 { 01007 case LINES: 01008 lines = get_lines_ptr( object ); 01009 if( lines->n_items == 0 ) 01010 { 01011 n_objects = 0; 01012 break; 01013 } 01014 01015 if( lines->bintree != (bintree_struct_ptr) NULL ) 01016 { 01017 return( intersect_ray_with_bintree( origin, direction, 01018 lines->bintree, object, 01019 obj_index, dist, distances ) ); 01020 } 01021 01022 n_objects = lines->end_indices[lines->n_items-1] - lines->n_items; 01023 break; 01024 01025 case POLYGONS: 01026 polygons = get_polygons_ptr( object ); 01027 if( polygons->bintree != (bintree_struct_ptr) NULL ) 01028 { 01029 return( intersect_ray_with_bintree( origin, direction, 01030 polygons->bintree, object, 01031 obj_index, dist, distances ) ); 01032 } 01033 n_objects = polygons->n_items; 01034 break; 01035 01036 case QUADMESH: 01037 quadmesh = get_quadmesh_ptr( object ); 01038 if( quadmesh->bintree != (bintree_struct_ptr) NULL ) 01039 { 01040 return( intersect_ray_with_bintree( origin, direction, 01041 quadmesh->bintree, object, 01042 obj_index, dist, distances ) ); 01043 } 01044 get_quadmesh_n_objects( quadmesh, &m, &n ); 01045 n_objects = m * n; 01046 break; 01047 01048 case MARKER: 01049 n_objects = 1; 01050 break; 01051 01052 default: 01053 n_objects = 0; 01054 break; 01055 } 01056 01057 for_less( i, 0, n_objects ) 01058 { 01059 intersect_ray_object( origin, direction, object, i, obj_index, 01060 dist, &n_intersections, distances ); 01061 } 01062 01063 return( n_intersections ); 01064 }

Generated on Wed Jul 28 09:10:58 2004 for BICPL by doxygen 1.3.7