Simbody
|
00001 #ifndef SimTK_SIMBODY_CONTACT_GEOMETRY_IMPL_H_ 00002 #define SimTK_SIMBODY_CONTACT_GEOMETRY_IMPL_H_ 00003 00004 /* -------------------------------------------------------------------------- * 00005 * SimTK Core: SimTK Simbody(tm) * 00006 * -------------------------------------------------------------------------- * 00007 * This is part of the SimTK Core biosimulation toolkit originating from * 00008 * Simbios, the NIH National Center for Physics-Based Simulation of * 00009 * Biological Structures at Stanford, funded under the NIH Roadmap for * 00010 * Medical Research, grant U54 GM072970. See https://simtk.org. * 00011 * * 00012 * Portions copyright (c) 2008-10 Stanford University and the Authors. * 00013 * Authors: Peter Eastman * 00014 * Contributors: Michael Sherman * 00015 * * 00016 * Permission is hereby granted, free of charge, to any person obtaining a * 00017 * copy of this software and associated documentation files (the "Software"), * 00018 * to deal in the Software without restriction, including without limitation * 00019 * the rights to use, copy, modify, merge, publish, distribute, sublicense, * 00020 * and/or sell copies of the Software, and to permit persons to whom the * 00021 * Software is furnished to do so, subject to the following conditions: * 00022 * * 00023 * The above copyright notice and this permission notice shall be included in * 00024 * all copies or substantial portions of the Software. * 00025 * * 00026 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 00027 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * 00028 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * 00029 * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 00030 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 00031 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * 00032 * USE OR OTHER DEALINGS IN THE SOFTWARE. * 00033 * -------------------------------------------------------------------------- */ 00034 00035 00036 #include "simbody/internal/ContactGeometry.h" 00037 00038 namespace SimTK { 00039 00040 //============================================================================== 00041 // CONTACT GEOMETRY IMPL 00042 //============================================================================== 00043 class SimTK_SIMBODY_EXPORT ContactGeometryImpl { 00044 public: 00045 ContactGeometryImpl(const std::string& type); 00046 virtual ~ContactGeometryImpl() { 00047 clearMyHandle(); 00048 } 00049 const std::string& getType() const { 00050 return type; 00051 } 00052 int getTypeIndex() const { 00053 return typeIndex; 00054 } 00055 static int getIndexForType(std::string type); 00056 00057 /* Create a new ContactGeometryTypeId and return this unique integer 00058 (thread safe). Each distinct type of ContactGeometry should use this to 00059 initialize a static variable for that concrete class. */ 00060 static ContactGeometryTypeId createNewContactGeometryTypeId() 00061 { static AtomicInteger nextAvailableId = 1; 00062 return ContactGeometryTypeId(nextAvailableId++); } 00063 00064 virtual ContactGeometryTypeId getTypeId() const = 0; 00065 00066 virtual ContactGeometryImpl* clone() const = 0; 00067 virtual Vec3 findNearestPoint(const Vec3& position, bool& inside, UnitVec3& normal) const = 0; 00068 virtual bool intersectsRay(const Vec3& origin, const UnitVec3& direction, Real& distance, UnitVec3& normal) const = 0; 00069 virtual void getBoundingSphere(Vec3& center, Real& radius) const = 0; 00070 ContactGeometry* getMyHandle() { 00071 return myHandle; 00072 } 00073 void setMyHandle(ContactGeometry& h) { 00074 myHandle = &h; 00075 } 00076 void clearMyHandle() { 00077 myHandle = 0; 00078 } 00079 protected: 00080 ContactGeometry* myHandle; 00081 const std::string& type; 00082 int typeIndex; 00083 }; 00084 00085 00086 00087 //============================================================================== 00088 // HALF SPACE IMPL 00089 //============================================================================== 00090 class ContactGeometry::HalfSpaceImpl : public ContactGeometryImpl { 00091 public: 00092 HalfSpaceImpl() : ContactGeometryImpl(Type()) { 00093 } 00094 ContactGeometryImpl* clone() const { 00095 return new HalfSpaceImpl(); 00096 } 00097 00098 ContactGeometryTypeId getTypeId() const {return classTypeId();} 00099 static ContactGeometryTypeId classTypeId() { 00100 static const ContactGeometryTypeId id = 00101 createNewContactGeometryTypeId(); 00102 return id; 00103 } 00104 00105 static const std::string& Type() { 00106 static std::string type = "halfspace"; 00107 return type; 00108 } 00109 Vec3 findNearestPoint(const Vec3& position, bool& inside, UnitVec3& normal) const; 00110 bool intersectsRay(const Vec3& origin, const UnitVec3& direction, Real& distance, UnitVec3& normal) const; 00111 void getBoundingSphere(Vec3& center, Real& radius) const; 00112 }; 00113 00114 00115 00116 //============================================================================== 00117 // SPHERE IMPL 00118 //============================================================================== 00119 class ContactGeometry::SphereImpl : public ContactGeometryImpl { 00120 public: 00121 SphereImpl(Real radius) : ContactGeometryImpl(Type()), radius(radius) { 00122 } 00123 ContactGeometryImpl* clone() const { 00124 return new SphereImpl(radius); 00125 } 00126 Real getRadius() const { 00127 return radius; 00128 } 00129 void setRadius(Real r) { 00130 radius = r; 00131 } 00132 00133 ContactGeometryTypeId getTypeId() const {return classTypeId();} 00134 static ContactGeometryTypeId classTypeId() { 00135 static const ContactGeometryTypeId id = 00136 createNewContactGeometryTypeId(); 00137 return id; 00138 } 00139 00140 static const std::string& Type() { 00141 static std::string type = "sphere"; 00142 return type; 00143 } 00144 Vec3 findNearestPoint(const Vec3& position, bool& inside, UnitVec3& normal) const; 00145 bool intersectsRay(const Vec3& origin, const UnitVec3& direction, Real& distance, UnitVec3& normal) const; 00146 void getBoundingSphere(Vec3& center, Real& radius) const; 00147 private: 00148 Real radius; 00149 }; 00150 00151 00152 00153 //============================================================================== 00154 // ELLIPSOID IMPL 00155 //============================================================================== 00156 class ContactGeometry::EllipsoidImpl : public ContactGeometryImpl { 00157 public: 00158 EllipsoidImpl(const Vec3& radii) 00159 : ContactGeometryImpl(Type()), radii(radii), 00160 curvatures(Vec3(1/radii[0],1/radii[1],1/radii[2])) {} 00161 00162 ContactGeometryImpl* clone() const {return new EllipsoidImpl(radii);} 00163 const Vec3& getRadii() const {return radii;} 00164 void setRadii(const Vec3& r) 00165 { radii = r; curvatures = Vec3(1/r[0],1/r[1],1/r[2]); } 00166 00167 const Vec3& getCurvatures() const {return curvatures;} 00168 00169 // See below. 00170 inline Vec3 findPointWithThisUnitNormal(const UnitVec3& n) const; 00171 inline Vec3 findPointInSameDirection(const Vec3& Q) const; 00172 inline UnitVec3 findUnitNormalAtPoint(const Vec3& Q) const; 00173 00174 // Cost is findParaboloidAtPointWithNormal + about 50 flops. 00175 void findParaboloidAtPoint(const Vec3& Q, Transform& X_EP, Vec2& k) const 00176 { findParaboloidAtPointWithNormal(Q,findUnitNormalAtPoint(Q),X_EP,k); } 00177 00178 void findParaboloidAtPointWithNormal(const Vec3& Q, const UnitVec3& n, 00179 Transform& X_EP, Vec2& k) const; 00180 00181 ContactGeometryTypeId getTypeId() const {return classTypeId();} 00182 static ContactGeometryTypeId classTypeId() { 00183 static const ContactGeometryTypeId id = createNewContactGeometryTypeId(); 00184 return id; 00185 } 00186 00187 static const std::string& Type() { 00188 static std::string type = "ellipsoid"; 00189 return type; 00190 } 00191 Vec3 findNearestPoint(const Vec3& position, bool& inside, UnitVec3& normal) const; 00192 bool intersectsRay(const Vec3& origin, const UnitVec3& direction, Real& distance, UnitVec3& normal) const; 00193 void getBoundingSphere(Vec3& center, Real& radius) const; 00194 private: 00195 Vec3 radii; 00196 // The curvatures are calculated whenever the radii are set. 00197 Vec3 curvatures; // (1/radii[0], 1/radii[1], 1/radii[2]) 00198 }; 00199 00200 // Given an ellipsoid and a unit normal direction, find the unique point on the 00201 // ellipsoid whose outward normal matches. The unnormalized normal was 00202 // n = [x/a^2, y/b^2, z/c^2] 00203 // If we had that, we'd have x=n[0]*a^2,y=n[1]*b^2,z=n[2]*c^2, 00204 // but instead we're given the normalized normal that has been divided 00205 // by the length of n: 00206 // nn = n/|n| = s * [x/a^2, y/b^2, z/c^2] 00207 // where s = 1/|n|. We can solve for s using the fact that x,y,z must 00208 // lie on the ellipsoid so |x/a,y/b,z/c|=1. Construct the vector 00209 // v = [nn[0]*a, nn[1]*b, nn[2]*c] = s*[x/a, y/b, z/c] 00210 // Now we have |v|=s. So n = nn/|v|. 00211 // Cost is about 50 flops. 00212 inline Vec3 ContactGeometry::EllipsoidImpl:: 00213 findPointWithThisUnitNormal(const UnitVec3& nn) const { 00214 const Real& a=radii[0]; const Real& b=radii[1]; const Real& c=radii[2]; 00215 const Vec3 v = Vec3(nn[0]*a, nn[1]*b, nn[2]*c); 00216 const Vec3 p = Vec3( v[0]*a, v[1]*b, v[2]*c) / v.norm(); 00217 return p; 00218 } 00219 00220 // Given a point Q=(x,y,z) measured from ellipse center O, find the intersection 00221 // of the ray d=Q-O with the ellipse surface. This just requires scaling the 00222 // direction vector d by a factor s so that f(s*d)=0, that is, 00223 // s*|x/a y/b z/c|=1 => s = 1/|x/a y/b z/c| 00224 // Cost is about 50 flops. 00225 inline Vec3 ContactGeometry::EllipsoidImpl:: 00226 findPointInSameDirection(const Vec3& Q) const { 00227 Real s = 1/Vec3(Q[0]*curvatures[0], 00228 Q[1]*curvatures[1], 00229 Q[2]*curvatures[2]).norm(); 00230 return s*Q; 00231 } 00232 00233 // The implicit equation of the ellipsoid surface is f(x,y,z)=0 where 00234 // f(x,y,z) = (ka x)^2 + (kb y)^2 (kc z)^2 - 1. Points p inside the ellipsoid 00235 // have f(p)<0, outside f(p)>0. f defines a field in space; its positive 00236 // gradient [df/dx df/dy df/dz] points outward. So, given an ellipsoid with 00237 // principal curvatures ka,kb,kc and a point Q allegedly on the ellipsoid, the 00238 // outward normal (unnormalized) n at that point is 00239 // n(p) = grad(f(p)) = 2*[ka^2 x, kb^2 y, kc^2 z] 00240 // so the unit norm we're interested in is nn=n/|n| (the "2" drops out). 00241 // If Q is not on the ellipsoid this is equivalent to scaling the ray Q-O 00242 // until it hits the ellipsoid surface at Q'=s*Q, and then reporting the outward 00243 // normal at Q' instead. 00244 // Cost is about 50 flops. 00245 inline UnitVec3 ContactGeometry::EllipsoidImpl:: 00246 findUnitNormalAtPoint(const Vec3& Q) const { 00247 const Vec3 kk(square(curvatures[0]), square(curvatures[1]), 00248 square(curvatures[2])); 00249 return UnitVec3(kk[0]*Q[0], kk[1]*Q[1], kk[2]*Q[2]); 00250 } 00251 00252 00253 //============================================================================== 00254 // OBB TREE NODE IMPL 00255 //============================================================================== 00256 class OBBTreeNodeImpl { 00257 public: 00258 OBBTreeNodeImpl() : child1(NULL), child2(NULL) { 00259 } 00260 OBBTreeNodeImpl(const OBBTreeNodeImpl& copy); 00261 ~OBBTreeNodeImpl(); 00262 OrientedBoundingBox bounds; 00263 OBBTreeNodeImpl* child1; 00264 OBBTreeNodeImpl* child2; 00265 Array_<int> triangles; 00266 int numTriangles; 00267 Vec3 findNearestPoint(const ContactGeometry::TriangleMeshImpl& mesh, const Vec3& position, Real cutoff2, Real& distance2, int& face, Vec2& uv) const; 00268 bool intersectsRay(const ContactGeometry::TriangleMeshImpl& mesh, const Vec3& origin, const UnitVec3& direction, Real& distance, int& face, Vec2& uv) const; 00269 }; 00270 00271 00272 00273 //============================================================================== 00274 // TRIANGLE MESH IMPL 00275 //============================================================================== 00276 class ContactGeometry::TriangleMeshImpl : public ContactGeometryImpl { 00277 public: 00278 class Edge; 00279 class Face; 00280 class Vertex; 00281 00282 TriangleMeshImpl(const ArrayViewConst_<Vec3>& vertexPositions, const ArrayViewConst_<int>& faceIndices, bool smooth); 00283 TriangleMeshImpl(const PolygonalMesh& mesh, bool smooth); 00284 ContactGeometryImpl* clone() const { 00285 return new TriangleMeshImpl(*this); 00286 } 00287 00288 ContactGeometryTypeId getTypeId() const {return classTypeId();} 00289 static ContactGeometryTypeId classTypeId() { 00290 static const ContactGeometryTypeId id = 00291 createNewContactGeometryTypeId(); 00292 return id; 00293 } 00294 00295 static const std::string& Type() { 00296 static std::string type = "triangle mesh"; 00297 return type; 00298 } 00299 Vec3 findPoint(int face, const Vec2& uv) const; 00300 Vec3 findCentroid(int face) const; 00301 UnitVec3 findNormalAtPoint(int face, const Vec2& uv) const; 00302 Vec3 findNearestPoint(const Vec3& position, bool& inside, UnitVec3& normal) const; 00303 Vec3 findNearestPoint(const Vec3& position, bool& inside, int& face, Vec2& uv) const; 00304 Vec3 findNearestPointToFace(const Vec3& position, int face, Vec2& uv) const; 00305 bool intersectsRay(const Vec3& origin, const UnitVec3& direction, Real& distance, UnitVec3& normal) const; 00306 bool intersectsRay(const Vec3& origin, const UnitVec3& direction, Real& distance, int& face, Vec2& uv) const; 00307 void getBoundingSphere(Vec3& center, Real& radius) const; 00308 00309 void createPolygonalMesh(PolygonalMesh& mesh) const; 00310 private: 00311 void init(const Array_<Vec3>& vertexPositions, const Array_<int>& faceIndices); 00312 void createObbTree(OBBTreeNodeImpl& node, const Array_<int>& faceIndices); 00313 void splitObbAxis(const Array_<int>& parentIndices, Array_<int>& child1Indices, Array_<int>& child2Indices, int axis); 00314 void findBoundingSphere(Vec3* point[], int p, int b, Vec3& center, Real& radius); 00315 friend class ContactGeometry::TriangleMesh; 00316 friend class OBBTreeNodeImpl; 00317 00318 Array_<Edge> edges; 00319 Array_<Face> faces; 00320 Array_<Vertex> vertices; 00321 Vec3 boundingSphereCenter; 00322 Real boundingSphereRadius; 00323 OBBTreeNodeImpl obb; 00324 bool smooth; 00325 }; 00326 00327 00328 00329 //============================================================================== 00330 // TriangleMeshImpl EDGE 00331 //============================================================================== 00332 class ContactGeometry::TriangleMeshImpl::Edge { 00333 public: 00334 Edge(int vert1, int vert2, int face1, int face2) { 00335 vertices[0] = vert1; 00336 vertices[1] = vert2; 00337 faces[0] = face1; 00338 faces[1] = face2; 00339 } 00340 int vertices[2]; 00341 int faces[2]; 00342 }; 00343 00344 00345 00346 //============================================================================== 00347 // TriangleMeshImpl FACE 00348 //============================================================================== 00349 class ContactGeometry::TriangleMeshImpl::Face { 00350 public: 00351 Face(int vert1, int vert2, int vert3, 00352 const Vec3& normal, Real area) 00353 : normal(normal), area(area) { 00354 vertices[0] = vert1; 00355 vertices[1] = vert2; 00356 vertices[2] = vert3; 00357 } 00358 int vertices[3]; 00359 int edges[3]; 00360 UnitVec3 normal; 00361 Real area; 00362 }; 00363 00364 00365 00366 //============================================================================== 00367 // TriangleMeshImpl VERTEX 00368 //============================================================================== 00369 class ContactGeometry::TriangleMeshImpl::Vertex { 00370 public: 00371 Vertex(Vec3 pos) : pos(pos), firstEdge(-1) { 00372 } 00373 Vec3 pos; 00374 UnitVec3 normal; 00375 int firstEdge; 00376 }; 00377 00378 } // namespace SimTK 00379 00380 #endif // SimTK_SIMBODY_CONTACT_GEOMETRY_IMPL_H_