Simbody

ContactGeometryImpl.h

Go to the documentation of this file.
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_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines