MOAB: Mesh Oriented datABase
(version 5.4.1)
|
00001 /* ***************************************************************** 00002 MESQUITE -- The Mesh Quality Improvement Toolkit 00003 00004 Copyright 2007 Sandia National Laboratories. Developed at the 00005 University of Wisconsin--Madison under SNL contract number 00006 624796. The U.S. Government and the University of Wisconsin 00007 retain certain rights to this software. 00008 00009 This library is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU Lesser General Public 00011 License as published by the Free Software Foundation; either 00012 version 2.1 of the License, or (at your option) any later version. 00013 00014 This library is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 Lesser General Public License for more details. 00018 00019 You should have received a copy of the GNU Lesser General Public License 00020 (lgpl.txt) along with this library; if not, write to the Free Software 00021 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00022 00023 (2007) [email protected] 00024 00025 ***************************************************************** */ 00026 00027 /** \file MsqGeomPrim.cpp 00028 * \brief 00029 * \author Jason Kraftcheck 00030 */ 00031 00032 #include "Mesquite.hpp" 00033 #include "MsqGeomPrim.hpp" 00034 00035 namespace MBMesquite 00036 { 00037 00038 bool MsqLine::intersect( const MsqLine& other, double& param, double epsilon ) const 00039 { 00040 if( !closest( other, param ) ) return false; 00041 Vector3D p1 = point( param ); 00042 Vector3D p2 = other.point( other.closest( p1 ) ); 00043 return ( p1 - p2 ).length_squared() < epsilon * epsilon; 00044 } 00045 00046 bool MsqLine::closest( const MsqLine& other, double& param ) const 00047 { 00048 const Vector3D N = other.direction() * ( direction() * other.direction() ); 00049 const double D = -( N % other.point() ); 00050 const double dot = N % direction(); 00051 if( dot < DBL_EPSILON ) return false; // parallel 00052 param = -( N % point() + D ) / dot; 00053 return true; 00054 } 00055 00056 bool MsqCircle::three_point( const Vector3D& p1, const Vector3D& p2, const Vector3D& p3, MsqCircle& result ) 00057 { 00058 Vector3D norm = ( p1 - p2 ) * ( p3 - p2 ); 00059 if( norm.length_squared() < DBL_EPSILON ) return false; 00060 00061 MsqLine line1( 0.5 * ( p1 + p2 ), norm * ( p1 - p2 ) ); 00062 MsqLine line2( 0.5 * ( p2 + p3 ), norm * ( p3 - p2 ) ); 00063 double t_xsect; 00064 if( !line1.closest( line2, t_xsect ) ) return false; 00065 00066 Vector3D center = line1.point( t_xsect ); 00067 double radius = ( ( center - p1 ).length() + ( center - p2 ).length() + ( center - p3 ).length() ) / 3.0; 00068 result = MsqCircle( center, norm, radius ); 00069 return true; 00070 } 00071 00072 bool MsqCircle::two_point( const Vector3D& center, const Vector3D& p1, const Vector3D& p2, MsqCircle& result ) 00073 { 00074 Vector3D norm = ( p1 - center ) * ( p2 - center ); 00075 if( norm.length_squared() < DBL_EPSILON ) return false; 00076 00077 double radius = 0.5 * ( ( center - p1 ).length() + ( center - p2 ).length() ); 00078 result = MsqCircle( center, norm, radius ); 00079 return true; 00080 } 00081 00082 Vector3D MsqCircle::radial_vector() const 00083 { 00084 int min_idx = 0; 00085 if( normal()[1] < normal()[min_idx] ) min_idx = 1; 00086 if( normal()[2] < normal()[min_idx] ) min_idx = 2; 00087 Vector3D vect( 0, 0, 0 ); 00088 vect[min_idx] = 1; 00089 vect = normal() * vect; 00090 vect *= radius() / vect.length(); 00091 return vect; 00092 } 00093 00094 Vector3D MsqCircle::closest( const Vector3D& point ) const 00095 { 00096 const Vector3D from_center = point - center(); 00097 const Vector3D norm_proj = normal() * ( normal() % from_center ); // unit normal! 00098 const Vector3D in_plane = from_center - norm_proj; 00099 const double length = in_plane.length(); 00100 if( length < DBL_EPSILON ) 00101 return center() + radial_vector(); 00102 else 00103 return center() + in_plane * radius() / length; 00104 } 00105 00106 bool MsqCircle::closest( const Vector3D& point, Vector3D& result_pt, Vector3D& result_tngt ) const 00107 { 00108 const Vector3D from_center = point - center(); 00109 Vector3D in_plane = from_center - ( from_center % normal() ); 00110 if( in_plane.length_squared() < DBL_EPSILON ) return false; 00111 00112 result_pt = center() + in_plane * radius() / in_plane.length(); 00113 result_tngt = in_plane * normal(); 00114 return true; 00115 } 00116 00117 MsqPlane::MsqPlane( const Vector3D& p_normal, double coeff ) 00118 { 00119 const double len = p_normal.length(); 00120 mNormal = p_normal / len; 00121 mCoeff = coeff / len; 00122 } 00123 00124 MsqPlane::MsqPlane( const Vector3D& p_normal, const Vector3D& p_point ) 00125 : mNormal( p_normal / p_normal.length() ), mCoeff( -( mNormal % p_point ) ) 00126 { 00127 } 00128 00129 MsqPlane::MsqPlane( double a, double b, double c, double d ) : mNormal( a, b, c ), mCoeff( d ) 00130 { 00131 const double len = mNormal.length(); 00132 mNormal /= len; 00133 mCoeff /= len; 00134 } 00135 00136 bool MsqPlane::intersect( const MsqPlane& plane, MsqLine& result ) const 00137 { 00138 const double dot = normal() % plane.normal(); 00139 const double det = dot * dot - 1.0; 00140 if( fabs( det ) < DBL_EPSILON ) // parallel 00141 return false; 00142 00143 const double s1 = ( coefficient() - dot * plane.coefficient() ) / det; 00144 const double s2 = ( plane.coefficient() - dot * coefficient() ) / det; 00145 result = MsqLine( s1 * normal() + s2 * plane.normal(), normal() * plane.normal() ); 00146 return true; 00147 } 00148 00149 bool MsqPlane::intersect( const MsqLine& line, double& result ) const 00150 { 00151 const double dot = line.direction() % normal(); 00152 if( fabs( dot ) < DBL_EPSILON ) return false; 00153 00154 result = -( normal() % line.point() + coefficient() ) / dot; 00155 return true; 00156 } 00157 00158 Vector3D MsqSphere::closest( const Vector3D& point ) const 00159 { 00160 Vector3D diff = point - center(); 00161 double len = diff.length(); 00162 if( len < DBL_EPSILON ) 00163 { 00164 // pick any point 00165 diff = Vector3D( 1, 0, 0 ); 00166 len = 1; 00167 } 00168 00169 return center() + diff * radius() / len; 00170 } 00171 00172 bool MsqSphere::closest( const Vector3D& point, Vector3D& point_on_sphere, Vector3D& normal_at_point ) const 00173 { 00174 normal_at_point = point - center(); 00175 double len = normal_at_point.length(); 00176 if( len < DBL_EPSILON ) return false; 00177 00178 normal_at_point /= len; 00179 point_on_sphere = center() + radius() * normal_at_point; 00180 return true; 00181 } 00182 00183 bool MsqSphere::intersect( const MsqPlane& plane, MsqCircle& result ) const 00184 { 00185 const Vector3D plane_pt = plane.closest( center() ); 00186 const Vector3D plane_dir = plane_pt - center(); 00187 const double dir_sqr = plane_dir.length_squared(); 00188 if( dir_sqr < DBL_EPSILON ) 00189 { // plane passes through center of sphere 00190 result = MsqCircle( center(), plane.normal(), radius() ); 00191 return true; 00192 } 00193 00194 double rad_sqr = radius() * radius() - plane_dir.length_squared(); 00195 if( rad_sqr < 0 ) // no intersection 00196 return false; 00197 00198 result = MsqCircle( plane_pt, plane_dir, sqrt( rad_sqr ) ); 00199 return true; 00200 } 00201 00202 bool MsqSphere::intersect( const MsqSphere& sphere, MsqCircle& result ) const 00203 { 00204 const Vector3D d = sphere.center() - center(); 00205 const double dist = d.length(); 00206 if( dist > ( radius() + sphere.radius() ) ) return false; 00207 00208 const double r1_sqr = radius() * radius(); 00209 const double r2_sqr = sphere.radius() * sphere.radius(); 00210 const double f = ( d % d + r1_sqr - r2_sqr ) / 2; 00211 // const double d1 = f / dist; 00212 00213 const double rad = sqrt( r1_sqr - f * f / ( d % d ) ); 00214 Vector3D c = center() + d * f / ( d % d ); 00215 result = MsqCircle( c, d, rad ); 00216 return true; 00217 } 00218 00219 } // namespace MBMesquite