cgma
|
00001 //- Class: CubitVector 00002 //- Description: This file defines the CubitVector class. 00003 //- Owner: Greg Sjaardema 00004 //- Checked by: 00005 00006 #include <math.h> 00007 #include "CubitVector.hpp" 00008 #include <string> 00009 #include <stdexcept> 00010 #include "CubitPlane.hpp" 00011 #include "GeometryDefines.h" 00012 #include "CubitBox.hpp" 00013 00014 // Define PI and TWO_PI 00015 #undef PI 00016 #ifdef M_PI 00017 const double PI = M_PI; 00018 #else 00019 const double PI = 3.14159265358979323846; 00020 #endif 00021 const double TWO_PI = 2.0 * PI; 00022 00023 00024 CubitVector &CubitVector::length(const double new_length) 00025 { 00026 double length = this->length(); 00027 if(length > 1e-6) 00028 { 00029 xVal *= new_length / length; 00030 yVal *= new_length / length; 00031 zVal *= new_length / length; 00032 } 00033 return *this; 00034 } 00035 00036 00037 double CubitVector::distance_between_squared(const CubitVector& test_vector) const 00038 { 00039 double x = xVal - test_vector.xVal; 00040 double y = yVal - test_vector.yVal; 00041 double z = zVal - test_vector.zVal; 00042 00043 return(x*x + y*y + z*z); 00044 } 00045 00046 double CubitVector::distance_between(const CubitVector& test_vector) const 00047 { 00048 double x = xVal - test_vector.xVal; 00049 double y = yVal - test_vector.yVal; 00050 double z = zVal - test_vector.zVal; 00051 00052 return(sqrt(x*x + y*y + z*z)); 00053 } 00054 00055 double CubitVector::distance_from_infinite_line(const CubitVector& point_on_line, 00056 const CubitVector& line_direction) const 00057 { 00058 return sqrt(distance_from_infinite_line_squared(point_on_line, line_direction)); 00059 } 00060 00061 double CubitVector::distance_from_infinite_line_squared( 00062 const CubitVector& point_on_line, 00063 const CubitVector& line_direction) const 00064 { 00065 if (line_direction == CubitVector(0, 0, 0)) 00066 return distance_between_squared(point_on_line); 00067 00068 CubitVector v = *this - point_on_line; 00069 double v_dot_d = v % line_direction; 00070 return fabs(v.length_squared() - v_dot_d * v_dot_d / line_direction.length_squared()); 00071 } 00072 00073 // double CubitVector::distance_between(const CubitVector& test_vector, RefEdge* test_edge) 00074 // { 00075 // return( test_edge->get_arc_length(*this, test_vector) ); 00076 // } 00077 00078 00079 void CubitVector::print_me() 00080 { 00081 printf("X: %f\n",xVal); 00082 printf("Y: %f\n",yVal); 00083 printf("Z: %f\n",zVal); 00084 00085 } 00086 00087 00088 double CubitVector::interior_angle(const CubitVector &otherVector) const 00089 { 00090 double cosAngle = 0.0, angleRad = 0.0, len1, len2 = 0.0; 00091 00092 if (((len1 = this->length()) > 0) && ((len2 = otherVector.length()) > 0)) 00093 cosAngle = (*this % otherVector)/(len1 * len2); 00094 else 00095 { 00096 if(len1<=0||len2<=0) 00097 throw std::invalid_argument ("Length of 'this' or parameter must be > 0"); 00098 // assert(len1 > 0); 00099 // assert(len2 > 0); 00100 } 00101 00102 if ((cosAngle > 1.0) && (cosAngle < 1.0001)) 00103 { 00104 cosAngle = 1.0; 00105 angleRad = acos(cosAngle); 00106 } 00107 else if (cosAngle < -1.0 && cosAngle > -1.0001) 00108 { 00109 cosAngle = -1.0; 00110 angleRad = acos(cosAngle); 00111 } 00112 else if (cosAngle >= -1.0 && cosAngle <= 1.0) 00113 angleRad = acos(cosAngle); 00114 else 00115 { 00116 if(cosAngle > -1.0001 && cosAngle < 1.0001) 00117 throw std::invalid_argument ("cosAngle must be between -1.0001 and 1.0001"); 00118 // assert(cosAngle < 1.0001 && cosAngle > -1.0001); 00119 } 00120 00121 return( (angleRad * 180.) / PI ); 00122 } 00123 00124 00125 void CubitVector::xy_to_rtheta() 00126 { 00127 //careful about overwriting 00128 double r_ = length(); 00129 double theta_ = atan2( yVal, xVal ); 00130 if (theta_ < 0.0) 00131 theta_ += TWO_PI; 00132 00133 r( r_ ); 00134 theta( theta_ ); 00135 } 00136 00137 void CubitVector::rtheta_to_xy() 00138 { 00139 //careful about overwriting 00140 double x_ = r() * cos( theta() ); 00141 double y_ = r() * sin( theta() ); 00142 00143 x( x_ ); 00144 y( y_ ); 00145 } 00146 00147 void CubitVector::rotate(double angle, double ) 00148 { 00149 xy_to_rtheta(); 00150 theta() += angle; 00151 rtheta_to_xy(); 00152 } 00153 00154 void CubitVector::blow_out(double gamma, double rmin) 00155 { 00156 // if gamma == 1, then 00157 // map on a circle : r'^2 = sqrt( 1 - (1-r)^2 ) 00158 // if gamma ==0, then map back to itself 00159 // in between, linearly interpolate 00160 xy_to_rtheta(); 00161 // r() = sqrt( (2. - r()) * r() ) * gamma + r() * (1-gamma); 00162 if(gamma <= 0.0) 00163 { 00164 throw std::invalid_argument( "Gamma must be greater than zero" ); 00165 } 00166 // the following limits should really be roundoff-based 00167 if (r() > rmin*1.001 && r() < 1.001) { 00168 r() = rmin + pow(r(), gamma) * (1.0 - rmin); 00169 } 00170 rtheta_to_xy(); 00171 } 00172 00173 void CubitVector::reflect_about_xaxis(double, double ) 00174 { 00175 yVal = -yVal; 00176 } 00177 00178 void CubitVector::scale_angle(double gamma, double ) 00179 { 00180 const double r_factor = 0.3; 00181 const double theta_factor = 0.6; 00182 00183 xy_to_rtheta(); 00184 00185 // if neary 2pi, treat as zero 00186 // some near zero stuff strays due to roundoff 00187 if (theta() > TWO_PI - 0.02) 00188 theta() = 0; 00189 // the above screws up on big sheets - need to overhaul at the sheet level 00190 00191 if ( gamma < 1 ) 00192 { 00193 //squeeze together points of short radius so that 00194 //long chords won't cross them 00195 theta() += (CUBIT_PI-theta())*(1-gamma)*theta_factor*(1-r()); 00196 00197 //push away from center of circle, again so long chords won't cross 00198 r( (r_factor + r()) / (1 + r_factor) ); 00199 00200 //scale angle by gamma 00201 theta() *= gamma; 00202 } 00203 else 00204 { 00205 //scale angle by gamma, making sure points nearly 2pi are treated as zero 00206 double new_theta = theta() * gamma; 00207 if ( new_theta < 2.5 * CUBIT_PI || r() < 0.2) 00208 theta( new_theta ); 00209 } 00210 rtheta_to_xy(); 00211 } 00212 00213 double CubitVector::vector_angle_quick(const CubitVector& vec1, 00214 const CubitVector& vec2) 00215 { 00216 //- compute the angle between two vectors in the plane defined by this vector 00217 // build yAxis and xAxis such that xAxis is the projection of 00218 // vec1 onto the normal plane of this vector 00219 00220 // NOTE: vec1 and vec2 are Vectors from the vertex of the angle along 00221 // the two sides of the angle. 00222 // The angle returned is the right-handed angle around this vector 00223 // from vec1 to vec2. 00224 00225 // NOTE: vector_angle_quick gives exactly the same answer as vector_angle below 00226 // providing this vector is normalized. It does so with two fewer 00227 // cross-product evaluations and two fewer vector normalizations. 00228 // This can be a substantial time savings if the function is called 00229 // a significant number of times (e.g Hexer) ... (jrh 11/28/94) 00230 // NOTE: vector_angle() is much more robust. Do not use vector_angle_quick() 00231 // unless you are very sure of the safety of your input vectors. 00232 00233 CubitVector ry = (*this) * vec1; 00234 CubitVector rx = ry * (*this); 00235 00236 double x = vec2 % rx; 00237 double y = vec2 % ry; 00238 00239 double angle; 00240 if( x == 0.0 && y == 0.0 ) 00241 { 00242 return 0.0; 00243 } 00244 00245 angle = atan2(y, x); 00246 00247 if (angle < 0.0) 00248 { 00249 angle += TWO_PI; 00250 } 00251 00252 // Sometimes angle was slightly less than zero, 00253 // but adding TWO_PI puts us at exactly TWO_PI. 00254 // More likely on optimized builds. 00255 // "volatile" is to remove false precision 00256 // maintained within the scope of this function 00257 if((*(volatile double*)&angle) >= TWO_PI) 00258 { 00259 angle -= TWO_PI; 00260 } 00261 00262 return angle; 00263 } 00264 00265 CubitVector vectorRotate(const double angle, 00266 const CubitVector &normalAxis, 00267 const CubitVector &referenceAxis) 00268 { 00269 // A new coordinate system is created with the xy plane corresponding 00270 // to the plane normal to the normal axis, and the x axis corresponding to 00271 // the projection of the reference axis onto the normal plane. The normal 00272 // plane is the tangent plane at the root point. A unit vector is 00273 // constructed along the local x axis and then rotated by the given 00274 // ccw angle to form the new point. The new point, then is a unit 00275 // distance from the global origin in the tangent plane. 00276 00277 double x, y; 00278 00279 // project a unit distance from root along reference axis 00280 00281 CubitVector yAxis = normalAxis * referenceAxis; 00282 CubitVector xAxis = yAxis * normalAxis; 00283 yAxis.normalize(); 00284 xAxis.normalize(); 00285 00286 x = cos(angle); 00287 y = sin(angle); 00288 00289 xAxis *= x; 00290 yAxis *= y; 00291 return CubitVector(xAxis + yAxis); 00292 } 00293 00294 double CubitVector::vector_angle(const CubitVector &vector1, 00295 const CubitVector &vector2) const 00296 { 00297 // This routine does not assume that any of the input vectors are of unit 00298 // length. This routine does not normalize the input vectors. 00299 // Special cases: 00300 // If the normal vector is zero length: 00301 // If a new one can be computed from vectors 1 & 2: 00302 // the normal is replaced with the vector cross product 00303 // else the two vectors are colinear and zero or 2PI is returned. 00304 // If the normal is colinear with either (or both) vectors 00305 // a new one is computed with the cross products 00306 // (and checked again). 00307 00308 // Check for zero length normal vector 00309 CubitVector normal = *this; 00310 double normal_lensq = normal.length_squared(); 00311 double len_tol = 0.0000001; 00312 if( normal_lensq <= len_tol ) 00313 { 00314 // null normal - make it the normal to the plane defined by vector1 00315 // and vector2. If still null, the vectors are colinear so check 00316 // for zero or 180 angle. 00317 normal = vector1 * vector2; 00318 normal_lensq = normal.length_squared(); 00319 if( normal_lensq <= len_tol ) 00320 { 00321 double cosine = vector1 % vector2; 00322 if( cosine > 0.0 ) return 0.0; 00323 else return CUBIT_PI; 00324 } 00325 } 00326 00327 //Trap for normal vector colinear to one of the other vectors. If so, 00328 //use a normal defined by the two vectors. 00329 double dot_tol = 0.985; 00330 double dot = vector1 % normal; 00331 if( dot * dot >= vector1.length_squared() * normal_lensq * dot_tol ) 00332 { 00333 normal = vector1 * vector2; 00334 normal_lensq = normal.length_squared(); 00335 00336 //Still problems if all three vectors were colinear 00337 if( normal_lensq <= len_tol ) 00338 { 00339 double cosine = vector1 % vector2; 00340 if( cosine >= 0.0 ) return 0.0; 00341 else return CUBIT_PI; 00342 } 00343 } 00344 else 00345 { 00346 //The normal and vector1 are not colinear, now check for vector2 00347 dot = vector2 % normal; 00348 if( dot * dot >= vector2.length_squared() * normal_lensq * dot_tol ) 00349 { 00350 normal = vector1 * vector2; 00351 } 00352 } 00353 00354 // Assume a plane such that the normal vector is the plane's normal. 00355 // Create yAxis perpendicular to both the normal and vector1. yAxis is 00356 // now in the plane. Create xAxis as the perpendicular to both yAxis and 00357 // the normal. xAxis is in the plane and is the projection of vector1 00358 // into the plane. 00359 00360 normal.normalize(); 00361 CubitVector yAxis = normal; 00362 yAxis *= vector1; 00363 double y = vector2 % yAxis; 00364 // yAxis memory slot will now be used for xAxis 00365 yAxis *= normal; 00366 double x = vector2 % yAxis; 00367 00368 00369 // assert(x != 0.0 || y != 0.0); 00370 if( x == 0.0 && y == 0.0 ) 00371 { 00372 return 0.0; 00373 } 00374 double angle = atan2(y, x); 00375 00376 if (angle < 0.0) 00377 { 00378 angle += TWO_PI; 00379 } 00380 00381 // Sometimes angle was slightly less than zero, 00382 // but adding TWO_PI puts us at exactly TWO_PI. 00383 // More likely on optimized builds. 00384 // "volatile" is to remove false precision 00385 // maintained within the scope of this function 00386 if((*(volatile double*)&angle) >= TWO_PI) 00387 { 00388 angle -= TWO_PI; 00389 } 00390 00391 return angle; 00392 } 00393 00394 CubitBoolean CubitVector::within_tolerance( const CubitVector &vectorPtr2, 00395 double tolerance) const 00396 { 00397 return (( fabs (this->xVal - vectorPtr2.xVal) < tolerance) && 00398 ( fabs (this->yVal - vectorPtr2.yVal) < tolerance) && 00399 ( fabs (this->zVal - vectorPtr2.zVal) < tolerance) 00400 ); 00401 } 00402 00403 CubitBoolean CubitVector::within_scaled_tolerance(const CubitVector &v2, double tol) const 00404 { 00405 if (tol < 0) 00406 tol = -tol; 00407 00408 return (((fabs (xVal - v2.xVal) < tol) || (((xVal > 0) == (v2.xVal > 0)) && fabs(xVal) > tol && fabs(v2.xVal/xVal - 1) < tol)) && 00409 ((fabs (yVal - v2.yVal) < tol) || (((yVal > 0) == (v2.yVal > 0)) && fabs(yVal) > tol && fabs(v2.yVal/yVal - 1) < tol)) && 00410 ((fabs (zVal - v2.zVal) < tol) || (((zVal > 0) == (v2.zVal > 0)) && fabs(zVal) > tol && fabs(v2.zVal/zVal - 1) < tol)) 00411 ); 00412 } 00413 00414 CubitBoolean CubitVector::about_equal(const CubitVector &w, 00415 const double relative_tolerance, 00416 const double absolute_tolerance ) const 00417 { 00418 if ( absolute_tolerance == 0. && 00419 relative_tolerance == 0. ) 00420 { 00421 if ( xVal == w.xVal && 00422 yVal == w.yVal && 00423 zVal == w.zVal ) 00424 return CUBIT_TRUE; 00425 } 00426 else 00427 { 00428 const CubitVector diff = *this - w; 00429 const double diff_size = diff.length_squared(); 00430 const double a_tol_size = absolute_tolerance * absolute_tolerance; 00431 // catches v == w 00432 if ( diff_size <= a_tol_size ) 00433 return CUBIT_TRUE; 00434 if ( relative_tolerance > 0. ) 00435 { 00436 const CubitVector sum = *this + w; 00437 const double sum_size = sum.length_squared(); 00438 const double r_tol_size = relative_tolerance * relative_tolerance; 00439 if ( 4. * diff_size <= sum_size * r_tol_size ) 00440 // Q: why this formula? 00441 // A: because if v = 1,0,eps, w = 1,0,0, then 00442 // diff_size = eps^2 00443 // sum_size = about 4. 00444 // and function returns true if eps^2 <= tolerance^2 00445 return CUBIT_TRUE; 00446 } 00447 } 00448 return CUBIT_FALSE; 00449 } 00450 00451 00452 void CubitVector::orthogonal_vectors( CubitVector &vector2, 00453 CubitVector &vector3 ) const 00454 { 00455 double x[3]; 00456 unsigned short i = 0; 00457 unsigned short imin = 0; 00458 double rmin = 1.0E20; 00459 unsigned short iperm1[3]; 00460 unsigned short iperm2[3]; 00461 unsigned short cont_flag = 1; 00462 double vec1[3], vec2[3]; 00463 double rmag; 00464 00465 // Copy the input vector and normalize it 00466 CubitVector vector1 = *this; 00467 vector1.normalize(); 00468 00469 // Initialize perm flags 00470 iperm1[0] = 1; iperm1[1] = 2; iperm1[2] = 0; 00471 iperm2[0] = 2; iperm2[1] = 0; iperm2[2] = 1; 00472 00473 // Get into the array format we can work with 00474 vector1.get_xyz( vec1 ); 00475 00476 while (i<3 && cont_flag ) 00477 { 00478 if (fabs(vec1[i]) < 1e-6) 00479 { 00480 vec2[i] = 1.0; 00481 vec2[iperm1[i]] = 0.0; 00482 vec2[iperm2[i]] = 0.0; 00483 cont_flag = 0; 00484 } 00485 00486 if (fabs(vec1[i]) < rmin) 00487 { 00488 imin = i; 00489 rmin = fabs(vec1[i]); 00490 } 00491 ++i; 00492 } 00493 00494 if (cont_flag) 00495 { 00496 x[imin] = 1.0; 00497 x[iperm1[imin]] = 0.0; 00498 x[iperm2[imin]] = 0.0; 00499 00500 // Determine cross product 00501 vec2[0] = vec1[1] * x[2] - vec1[2] * x[1]; 00502 vec2[1] = vec1[2] * x[0] - vec1[0] * x[2]; 00503 vec2[2] = vec1[0] * x[1] - vec1[1] * x[0]; 00504 00505 // Unitize 00506 rmag = sqrt(vec2[0]*vec2[0] + vec2[1]*vec2[1] + vec2[2]*vec2[2]); 00507 vec2[0] /= rmag; 00508 vec2[1] /= rmag; 00509 vec2[2] /= rmag; 00510 } 00511 00512 // Copy 1st orthogonal vector into CubitVector vector2 00513 vector2.set( vec2 ); 00514 00515 // Cross vectors to determine last orthogonal vector 00516 vector3 = vector1 * vector2; 00517 00518 return; 00519 } 00520 00521 //- Find next point from this point using a direction and distance 00522 void CubitVector::next_point( const CubitVector &direction, 00523 double distance, CubitVector& out_point ) const 00524 { 00525 CubitVector my_direction = direction; 00526 my_direction.normalize(); 00527 00528 // Determine next point in space 00529 out_point.x( xVal + (distance * my_direction.xVal) ); 00530 out_point.y( yVal + (distance * my_direction.yVal) ); 00531 out_point.z( zVal + (distance * my_direction.zVal) ); 00532 00533 return; 00534 } 00535 00536 //- Project this vector onto the plane specified by the input plane normal 00537 void CubitVector::project_to_plane( const CubitVector &planenormal ) 00538 { 00539 CubitVector tmp = planenormal; 00540 tmp.normalize(); 00541 00542 // Cross the vector with the normal to get a vector on the plane 00543 CubitVector planevec = tmp * (*this); 00544 00545 // Cross the vector on the plane with the normal to get the 00546 // projection of the vector on the plane 00547 *this = planevec * tmp; 00548 } 00549 00550 //============================================================================ 00551 // Function: barycentric_coordinates 00552 // Author: mlstate 00553 // Description: compute the barycentric coordinates of a point w.r.t. to a 00554 // triangle. 00555 //============================================================================ 00556 bool CubitVector::barycentric_coordinates 00557 ( 00558 const CubitVector &v1, 00559 const CubitVector &v2, 00560 const CubitVector &v3, 00561 const CubitVector &point, 00562 double &coord_A, 00563 double &coord_B, 00564 double &coord_C 00565 ) 00566 { 00567 return private_barycentric_coordinates(true, v1, v2, v3, point, coord_A, coord_B, coord_C ); 00568 } 00569 00570 //============================================================================ 00571 // Function: private_barycentric_coordinates 00572 // Author: mlstate 00573 // Description: compute the barycentric coordinates of a point w.r.t. to a 00574 // triangle. The private version. 00575 //============================================================================ 00576 bool CubitVector::private_barycentric_coordinates 00577 ( 00578 bool adjust_on_fail, 00579 const CubitVector &v1, 00580 const CubitVector &v2, 00581 const CubitVector &v3, 00582 const CubitVector &point, 00583 double &coord_A, 00584 double &coord_B, 00585 double &coord_C 00586 ) 00587 { 00588 #define DETERM3(p1,q1,p2,q2,p3,q3) ((q3)*((p2)-(p1)) + \ 00589 (q2)*((p1)-(p3)) + \ 00590 (q1)*((p3)-(p2))) 00591 00592 if ( CubitVector::colinear(v1, v2, v3) ) 00593 { 00594 return false; 00595 } 00596 00597 CubitPlane tri_plane; 00598 tri_plane.mk_plane_with_points( v1, v2, v3 ); 00599 CubitVector pt = tri_plane.project( point ); 00600 double area2; 00601 CubitVector normal = tri_plane.normal(); 00602 double tol = CUBIT_RESABS; 00603 CubitVector absnorm( fabs(normal.x()), fabs(normal.y()), fabs(normal.z()) ); 00604 00605 // project to the closest coordinate plane so we only have to do this in 2D 00606 if (absnorm.x() >= absnorm.y() && absnorm.x() >= absnorm.z()) 00607 { 00608 area2 = DETERM3(v1.y(), v1.z(), 00609 v2.y(), v2.z(), 00610 v3.y(), v3.z()); 00611 if (fabs(area2) < tol) 00612 { 00613 if ( adjust_on_fail ) 00614 { 00615 return attempt_barycentric_coordinates_adjustment(v1, v2, v3, point, 00616 coord_A, coord_B, 00617 coord_C); 00618 } 00619 return false; 00620 } 00621 coord_A = ( DETERM3( pt.y(), pt.z(), 00622 v2.y(), v2.z(), 00623 v3.y(), v3.z() ) / area2 ); 00624 coord_B = ( DETERM3( v1.y(), v1.z(), 00625 pt.y(), pt.z(), 00626 v3.y(), v3.z() ) / area2 ); 00627 coord_C = ( DETERM3( v1.y(), v1.z(), 00628 v2.y(), v2.z(), 00629 pt.y(), pt.z() ) / area2 ); 00630 } 00631 else if(absnorm.y() >= absnorm.x() && absnorm.y() >= absnorm.z()) 00632 { 00633 area2 = DETERM3(v1.x(), v1.z(), 00634 v2.x(), v2.z(), 00635 v3.x(), v3.z()); 00636 if (fabs(area2) < tol) 00637 { 00638 if ( adjust_on_fail ) 00639 { 00640 return attempt_barycentric_coordinates_adjustment(v1, v2, v3, point, 00641 coord_A, coord_B, 00642 coord_C); 00643 } 00644 return false; 00645 } 00646 coord_A = ( DETERM3( pt.x(), pt.z(), 00647 v2.x(), v2.z(), 00648 v3.x(), v3.z() ) / area2 ); 00649 coord_B = ( DETERM3( v1.x(), v1.z(), 00650 pt.x(), pt.z(), 00651 v3.x(), v3.z() ) / area2 ); 00652 coord_C = ( DETERM3( v1.x(), v1.z(), 00653 v2.x(), v2.z(), 00654 pt.x(), pt.z() ) / area2 ); 00655 } 00656 else 00657 { 00658 area2 = DETERM3(v1.x(), v1.y(), 00659 v2.x(), v2.y(), 00660 v3.x(), v3.y()); 00661 if (fabs(area2) < tol) 00662 { 00663 if ( adjust_on_fail ) 00664 { 00665 return attempt_barycentric_coordinates_adjustment(v1, v2, v3, point, 00666 coord_A, coord_B, 00667 coord_C); 00668 } 00669 return false; 00670 } 00671 coord_A = ( DETERM3( pt.x(), pt.y(), 00672 v2.x(), v2.y(), 00673 v3.x(), v3.y() ) / area2 ); 00674 coord_B = ( DETERM3( v1.x(), v1.y(), 00675 pt.x(), pt.y(), 00676 v3.x(), v3.y() ) / area2 ); 00677 coord_C = ( DETERM3( v1.x(), v1.y(), 00678 v2.x(), v2.y(), 00679 pt.x(), pt.y() ) / area2 ); 00680 } 00681 return true; 00682 } 00683 00684 bool CubitVector::attempt_barycentric_coordinates_adjustment 00685 ( 00686 const CubitVector &v1, 00687 const CubitVector &v2, 00688 const CubitVector &v3, 00689 const CubitVector &point, 00690 double &coord_A, 00691 double &coord_B, 00692 double &coord_C 00693 ) 00694 { 00695 #if 0 00696 CubitVector v1_adjusted = v1-point; 00697 CubitVector v2_adjusted = v2-point; 00698 CubitVector v3_adjusted = v3-point; 00699 CubitVector origin(0,0,0); 00700 return private_barycentric_coordinates(false, 00701 v1_adjusted, v2_adjusted, v3_adjusted, origin, 00702 coord_A, coord_B, coord_C); 00703 #else 00704 CubitBox bbox(v1); 00705 bbox |= v2; 00706 bbox |= v3; 00707 double dist2 = bbox.diagonal().length(); 00708 00709 CubitVector v1_adjusted = v1 / dist2; 00710 CubitVector v2_adjusted = v2 / dist2; 00711 CubitVector v3_adjusted = v3 / dist2; 00712 CubitVector point_adjusted = point / dist2; 00713 return private_barycentric_coordinates(false, 00714 v1_adjusted, v2_adjusted, v3_adjusted, point_adjusted, 00715 coord_A, coord_B, coord_C); 00716 #endif 00717 } 00718 00719 bool CubitVector::colinear( const CubitVector &p0, 00720 const CubitVector &p1, 00721 const CubitVector &p2 ) 00722 { 00723 CubitVector v1 = p1 - p0; 00724 CubitVector v2 = p2 - p0; 00725 v1.normalize(); 00726 v2.normalize(); 00727 00728 // If the 3 points are collinear, then the cross product of these two 00729 // vectors will yield a null vector (one whose length is zero). 00730 CubitVector norm = v1 * v2; 00731 00732 if(norm.length() <= CUBIT_RESABS) 00733 { 00734 return true; 00735 } 00736 return false; 00737 } 00738 00739 void CubitVector::project_to_line_segment 00740 ( 00741 const CubitVector &pt0, 00742 const CubitVector &pt1 00743 ) 00744 { 00745 CubitVector v0 = pt1-pt0; 00746 CubitVector v1 = *this-pt0; 00747 00748 double len = v0.normalize(); 00749 double dot = v0%v1; 00750 CubitVector close_pt; 00751 if ( dot <= 0 ) 00752 close_pt = pt0; 00753 else if ( dot >= len ) 00754 close_pt = pt1; 00755 else 00756 close_pt = pt0 + dot *v0; 00757 00758 set(close_pt); 00759 }