Mesh Oriented datABase  (version 5.4.1)
Array-based unstructured mesh datastructure
VerdictVector.cpp
Go to the documentation of this file.
00001 /*=========================================================================
00002 
00003   Module:    $RCSfile: VerdictVector.cpp,v $
00004 
00005   Copyright (c) 2006 Sandia Corporation.
00006   All rights reserved.
00007   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
00008 
00009      This software is distributed WITHOUT ANY WARRANTY; without even
00010      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
00011      PURPOSE.  See the above copyright notice for more information.
00012 
00013 =========================================================================*/
00014 
00015 /*
00016  *
00017  * VerdictVector.cpp contains implementation of Vector operations
00018  *
00019  * This file is part of VERDICT
00020  *
00021  */
00022 
00023 #define VERDICT_EXPORTS
00024 
00025 #include "moab/verdict.h"
00026 #include <cmath>
00027 #include "VerdictVector.hpp"
00028 #include <cfloat>
00029 
00030 #if defined( __BORLANDC__ )
00031 #pragma warn - 8004 /* "assigned a value that is never used" */
00032 #endif
00033 
00034 const double TWO_VERDICT_PI = 2.0 * VERDICT_PI;
00035 
00036 VerdictVector& VerdictVector::length( const double new_length )
00037 {
00038     double len = this->length();
00039     xVal *= new_length / len;
00040     yVal *= new_length / len;
00041     zVal *= new_length / len;
00042     return *this;
00043 }
00044 
00045 double VerdictVector::distance_between( const VerdictVector& test_vector )
00046 {
00047     double xv = xVal - test_vector.x();
00048     double yv = yVal - test_vector.y();
00049     double zv = zVal - test_vector.z();
00050 
00051     return ( sqrt( xv * xv + yv * yv + zv * zv ) );
00052 }
00053 
00054 /*
00055 void VerdictVector::print_me()
00056 {
00057   PRINT_INFO("X: %f\n",xVal);
00058   PRINT_INFO("Y: %f\n",yVal);
00059   PRINT_INFO("Z: %f\n",zVal);
00060 
00061 }
00062 */
00063 
00064 double VerdictVector::interior_angle( const VerdictVector& otherVector )
00065 {
00066     double cosAngle = 0., angleRad = 0., len1, len2 = 0.;
00067 
00068     if( ( ( len1 = this->length() ) > 0 ) && ( ( len2 = otherVector.length() ) > 0 ) )
00069         cosAngle = ( *this % otherVector ) / ( len1 * len2 );
00070     else
00071     {
00072         assert( len1 > 0 );
00073         assert( len2 > 0 );
00074     }
00075 
00076     if( ( cosAngle > 1.0 ) && ( cosAngle < 1.0001 ) )
00077     {
00078         cosAngle = 1.0;
00079         angleRad = acos( cosAngle );
00080     }
00081     else if( cosAngle < -1.0 && cosAngle > -1.0001 )
00082     {
00083         cosAngle = -1.0;
00084         angleRad = acos( cosAngle );
00085     }
00086     else if( cosAngle >= -1.0 && cosAngle <= 1.0 )
00087         angleRad = acos( cosAngle );
00088     else
00089     {
00090         assert( cosAngle < 1.0001 && cosAngle > -1.0001 );
00091     }
00092 
00093     return ( ( angleRad * 180. ) / VERDICT_PI );
00094 }
00095 
00096 // Interpolate between two vectors.
00097 // Returns (1-param)*v1 + param*v2
00098 VerdictVector interpolate( const double param, const VerdictVector& v1, const VerdictVector& v2 )
00099 {
00100     VerdictVector temp = ( 1.0 - param ) * v1;
00101     temp += param * v2;
00102     return temp;
00103 }
00104 
00105 void VerdictVector::xy_to_rtheta()
00106 {
00107     // careful about overwriting
00108     double r_     = length();
00109     double theta_ = atan2( y(), x() );
00110     if( theta_ < 0.0 ) theta_ += TWO_VERDICT_PI;
00111 
00112     r( r_ );
00113     theta( theta_ );
00114 }
00115 
00116 void VerdictVector::rtheta_to_xy()
00117 {
00118     // careful about overwriting
00119     double x_ = r() * cos( theta() );
00120     double y_ = r() * sin( theta() );
00121 
00122     x( x_ );
00123     y( y_ );
00124 }
00125 
00126 void VerdictVector::rotate( double angle, double )
00127 {
00128     xy_to_rtheta();
00129     theta() += angle;
00130     rtheta_to_xy();
00131 }
00132 
00133 void VerdictVector::blow_out( double gamma, double rmin )
00134 {
00135     // if gamma == 1, then
00136     // map on a circle : r'^2 = sqrt( 1 - (1-r)^2 )
00137     // if gamma ==0, then map back to itself
00138     // in between, linearly interpolate
00139     xy_to_rtheta();
00140     //  r() = sqrt( (2. - r()) * r() ) * gamma  + r() * (1-gamma);
00141     assert( gamma > 0.0 );
00142     // the following limits should really be roundoff-based
00143     if( r() > rmin * 1.001 && r() < 1.001 )
00144     {
00145         r() = rmin + pow( r(), gamma ) * ( 1.0 - rmin );
00146     }
00147     rtheta_to_xy();
00148 }
00149 
00150 void VerdictVector::reflect_about_xaxis( double, double )
00151 {
00152     yVal = -yVal;
00153 }
00154 
00155 void VerdictVector::scale_angle( double gamma, double )
00156 {
00157     const double r_factor     = 0.3;
00158     const double theta_factor = 0.6;
00159 
00160     xy_to_rtheta();
00161 
00162     // if neary 2pi, treat as zero
00163     // some near zero stuff strays due to roundoff
00164     if( theta() > TWO_VERDICT_PI - 0.02 ) theta() = 0;
00165     // the above screws up on big sheets - need to overhaul at the sheet level
00166 
00167     if( gamma < 1 )
00168     {
00169         // squeeze together points of short radius so that
00170         // long chords won't cross them
00171         theta() += ( VERDICT_PI - theta() ) * ( 1 - gamma ) * theta_factor * ( 1 - r() );
00172 
00173         // push away from center of circle, again so long chords won't cross
00174         r( ( r_factor + r() ) / ( 1 + r_factor ) );
00175 
00176         // scale angle by gamma
00177         theta() *= gamma;
00178     }
00179     else
00180     {
00181         // scale angle by gamma, making sure points nearly 2pi are treated as zero
00182         double new_theta = theta() * gamma;
00183         if( new_theta < 2.5 * VERDICT_PI || r() < 0.2 ) theta( new_theta );
00184     }
00185     rtheta_to_xy();
00186 }
00187 
00188 double VerdictVector::vector_angle_quick( const VerdictVector& vec1, const VerdictVector& vec2 )
00189 {
00190     //- compute the angle between two vectors in the plane defined by this vector
00191     // build yAxis and xAxis such that xAxis is the projection of
00192     // vec1 onto the normal plane of this vector
00193 
00194     // NOTE: vec1 and vec2 are Vectors from the vertex of the angle along
00195     //       the two sides of the angle.
00196     //       The angle returned is the right-handed angle around this vector
00197     //       from vec1 to vec2.
00198 
00199     // NOTE: vector_angle_quick gives exactly the same answer as vector_angle below
00200     //       providing this vector is normalized.  It does so with two fewer
00201     //       cross-product evaluations and two fewer vector normalizations.
00202     //       This can be a substantial time savings if the function is called
00203     //       a significant number of times (e.g Hexer) ... (jrh 11/28/94)
00204     // NOTE: vector_angle() is much more robust. Do not use vector_angle_quick()
00205     //       unless you are very sure of the safety of your input vectors.
00206 
00207     VerdictVector ry = ( *this ) * vec1;
00208     VerdictVector rx = ry * ( *this );
00209 
00210     double xv = vec2 % rx;
00211     double yv = vec2 % ry;
00212 
00213     double angle;
00214     assert( xv != 0.0 || yv != 0.0 );
00215 
00216     angle = atan2( yv, xv );
00217 
00218     if( angle < 0.0 )
00219     {
00220         angle += TWO_VERDICT_PI;
00221     }
00222     return angle;
00223 }
00224 
00225 VerdictVector vectorRotate( const double angle, const VerdictVector& normalAxis, const VerdictVector& referenceAxis )
00226 {
00227     // A new coordinate system is created with the xy plane corresponding
00228     // to the plane normal to the normal axis, and the x axis corresponding to
00229     // the projection of the reference axis onto the normal plane.  The normal
00230     // plane is the tangent plane at the root point.  A unit vector is
00231     // constructed along the local x axis and then rotated by the given
00232     // ccw angle to form the new point.  The new point, then is a unit
00233     // distance from the global origin in the tangent plane.
00234 
00235     double x, y;
00236 
00237     // project a unit distance from root along reference axis
00238 
00239     VerdictVector yAxis = normalAxis * referenceAxis;
00240     VerdictVector xAxis = yAxis * normalAxis;
00241     yAxis.normalize();
00242     xAxis.normalize();
00243 
00244     x = cos( angle );
00245     y = sin( angle );
00246 
00247     xAxis *= x;
00248     yAxis *= y;
00249     return VerdictVector( xAxis + yAxis );
00250 }
00251 
00252 double VerdictVector::vector_angle( const VerdictVector& vector1, const VerdictVector& vector2 ) const
00253 {
00254     // This routine does not assume that any of the input vectors are of unit
00255     // length. This routine does not normalize the input vectors.
00256     // Special cases:
00257     //     If the normal vector is zero length:
00258     //         If a new one can be computed from vectors 1 & 2:
00259     //             the normal is replaced with the vector cross product
00260     //         else the two vectors are colinear and zero or 2PI is returned.
00261     //     If the normal is colinear with either (or both) vectors
00262     //         a new one is computed with the cross products
00263     //         (and checked again).
00264 
00265     // Check for zero length normal vector
00266     VerdictVector normal = *this;
00267     double normal_lensq  = normal.length_squared();
00268     double len_tol       = 0.0000001;
00269     if( normal_lensq <= len_tol )
00270     {
00271         // null normal - make it the normal to the plane defined by vector1
00272         // and vector2. If still null, the vectors are colinear so check
00273         // for zero or 180 angle.
00274         normal       = vector1 * vector2;
00275         normal_lensq = normal.length_squared();
00276         if( normal_lensq <= len_tol )
00277         {
00278             double cosine = vector1 % vector2;
00279             if( cosine > 0.0 )
00280                 return 0.0;
00281             else
00282                 return VERDICT_PI;
00283         }
00284     }
00285 
00286     // Trap for normal vector colinear to one of the other vectors. If so,
00287     // use a normal defined by the two vectors.
00288     double dot_tol = 0.985;
00289     double dot     = vector1 % normal;
00290     if( dot * dot >= vector1.length_squared() * normal_lensq * dot_tol )
00291     {
00292         normal       = vector1 * vector2;
00293         normal_lensq = normal.length_squared();
00294 
00295         // Still problems if all three vectors were colinear
00296         if( normal_lensq <= len_tol )
00297         {
00298             double cosine = vector1 % vector2;
00299             if( cosine >= 0.0 )
00300                 return 0.0;
00301             else
00302                 return VERDICT_PI;
00303         }
00304     }
00305     else
00306     {
00307         // The normal and vector1 are not colinear, now check for vector2
00308         dot = vector2 % normal;
00309         if( dot * dot >= vector2.length_squared() * normal_lensq * dot_tol )
00310         {
00311             normal = vector1 * vector2;
00312         }
00313     }
00314 
00315     // Assume a plane such that the normal vector is the plane's normal.
00316     // Create yAxis perpendicular to both the normal and vector1. yAxis is
00317     // now in the plane. Create xAxis as the perpendicular to both yAxis and
00318     // the normal. xAxis is in the plane and is the projection of vector1
00319     // into the plane.
00320 
00321     normal.normalize();
00322     VerdictVector yAxis = normal;
00323     yAxis *= vector1;
00324     double yv = vector2 % yAxis;
00325     //  yAxis memory slot will now be used for xAxis
00326     yAxis *= normal;
00327     double xv = vector2 % yAxis;
00328 
00329     //  assert(x != 0.0 || y != 0.0);
00330     if( xv == 0.0 && yv == 0.0 )
00331     {
00332         return 0.0;
00333     }
00334     double angle = atan2( yv, xv );
00335 
00336     if( angle < 0.0 )
00337     {
00338         angle += TWO_VERDICT_PI;
00339     }
00340     return angle;
00341 }
00342 
00343 bool VerdictVector::within_tolerance( const VerdictVector& vectorPtr2, double tolerance ) const
00344 {
00345     if( ( fabs( this->x() - vectorPtr2.x() ) < tolerance ) && ( fabs( this->y() - vectorPtr2.y() ) < tolerance ) &&
00346         ( fabs( this->z() - vectorPtr2.z() ) < tolerance ) )
00347     {
00348         return true;
00349     }
00350 
00351     return false;
00352 }
00353 
00354 void VerdictVector::orthogonal_vectors( VerdictVector& vector2, VerdictVector& vector3 )
00355 {
00356     double xv[3];
00357     unsigned short i    = 0;
00358     unsigned short imin = 0;
00359     double rmin         = 1.0E20;
00360     unsigned short iperm1[3];
00361     unsigned short iperm2[3];
00362     unsigned short cont_flag = 1;
00363     double vec1[3], vec2[3];
00364     double rmag;
00365 
00366     // Copy the input vector and normalize it
00367     VerdictVector vector1 = *this;
00368     vector1.normalize();
00369 
00370     // Initialize perm flags
00371     iperm1[0] = 1;
00372     iperm1[1] = 2;
00373     iperm1[2] = 0;
00374     iperm2[0] = 2;
00375     iperm2[1] = 0;
00376     iperm2[2] = 1;
00377 
00378     // Get into the array format we can work with
00379     vector1.get_xyz( vec1 );
00380 
00381     while( i < 3 && cont_flag )
00382     {
00383         if( fabs( vec1[i] ) < 1e-6 )
00384         {
00385             vec2[i]         = 1.0;
00386             vec2[iperm1[i]] = 0.0;
00387             vec2[iperm2[i]] = 0.0;
00388             cont_flag       = 0;
00389         }
00390 
00391         if( fabs( vec1[i] ) < rmin )
00392         {
00393             imin = i;
00394             rmin = fabs( vec1[i] );
00395         }
00396         ++i;
00397     }
00398 
00399     if( cont_flag )
00400     {
00401         xv[imin]         = 1.0;
00402         xv[iperm1[imin]] = 0.0;
00403         xv[iperm2[imin]] = 0.0;
00404 
00405         // Determine cross product
00406         vec2[0] = vec1[1] * xv[2] - vec1[2] * xv[1];
00407         vec2[1] = vec1[2] * xv[0] - vec1[0] * xv[2];
00408         vec2[2] = vec1[0] * xv[1] - vec1[1] * xv[0];
00409 
00410         // Unitize
00411         rmag = sqrt( vec2[0] * vec2[0] + vec2[1] * vec2[1] + vec2[2] * vec2[2] );
00412         vec2[0] /= rmag;
00413         vec2[1] /= rmag;
00414         vec2[2] /= rmag;
00415     }
00416 
00417     // Copy 1st orthogonal vector into VerdictVector vector2
00418     vector2.set( vec2 );
00419 
00420     // Cross vectors to determine last orthogonal vector
00421     vector3 = vector1 * vector2;
00422 }
00423 
00424 //- Find next point from this point using a direction and distance
00425 void VerdictVector::next_point( const VerdictVector& direction, double distance, VerdictVector& out_point )
00426 {
00427     VerdictVector my_direction = direction;
00428     my_direction.normalize();
00429 
00430     // Determine next point in space
00431     out_point.x( xVal + ( distance * my_direction.x() ) );
00432     out_point.y( yVal + ( distance * my_direction.y() ) );
00433     out_point.z( zVal + ( distance * my_direction.z() ) );
00434 
00435     return;
00436 }
00437 
00438 VerdictVector::VerdictVector( const double xyz[3] ) : xVal( xyz[0] ), yVal( xyz[1] ), zVal( xyz[2] ) {}
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines