iMSTK
Interactive Medical Simulation Toolkit
imstkSurfaceMeshToSphereCD.cpp
1 /*
2 ** This file is part of the Interactive Medical Simulation Toolkit (iMSTK)
3 ** iMSTK is distributed under the Apache License, Version 2.0.
4 ** See accompanying NOTICE for details.
5 */
6 
7 #include "imstkSurfaceMeshToSphereCD.h"
8 #include "imstkCollisionData.h"
9 #include "imstkCollisionUtils.h"
10 #include "imstkParallelUtils.h"
11 #include "imstkSphere.h"
12 #include "imstkSurfaceMesh.h"
13 
14 namespace imstk
15 {
16 SurfaceMeshToSphereCD::SurfaceMeshToSphereCD()
17 {
18  setRequiredInputType<SurfaceMesh>(0);
19  setRequiredInputType<Sphere>(1);
20 }
21 
22 void
24  std::shared_ptr<Geometry> geomA,
25  std::shared_ptr<Geometry> geomB,
26  std::vector<CollisionElement>& elementsA,
27  std::vector<CollisionElement>& elementsB)
28 {
29  std::shared_ptr<SurfaceMesh> surfMesh = std::dynamic_pointer_cast<SurfaceMesh>(geomA);
30  std::shared_ptr<Sphere> sphere = std::dynamic_pointer_cast<Sphere>(geomB);
31 
32  const Vec3d& spherePos = sphere->getPosition();
33  const double sphereRadius = sphere->getRadius();
34 
35  std::shared_ptr<VecDataArray<int, 3>> indicesPtr = surfMesh->getCells();
36  const VecDataArray<int, 3>& indices = *indicesPtr;
37  std::shared_ptr<VecDataArray<double, 3>> verticesPtr = surfMesh->getVertexPositions();
38  const VecDataArray<double, 3>& vertices = *verticesPtr;
39 
40  // \todo: Doesn't remove duplicate contacts (shared edges), refer to SurfaceMeshCD for easy method to do so
42  ParallelUtils::parallelFor(indices.size(), [&](int i)
43  {
44  const Vec3i& cell = indices[i];
45  const Vec3d& x1 = vertices[cell[0]];
46  const Vec3d& x2 = vertices[cell[1]];
47  const Vec3d& x3 = vertices[cell[2]];
48 
49  // This approach does a built in sphere sweep
50  // \todo: Spatial accelerators need to be abstracted
51  const Vec3d centroid = (x1 + x2 + x3) / 3.0;
52 
53  // Find the maximal point from centroid for radius
54  const double rSqr1 = (centroid - x1).squaredNorm();
55  const double rSqr2 = (centroid - x2).squaredNorm();
56  const double rSqr3 = (centroid - x3).squaredNorm();
57  const double triangleBoundingRadius = std::sqrt(std::max(rSqr1, std::max(rSqr2, rSqr3)));
58 
59  const double distSqr = (centroid - spherePos).squaredNorm();
60  const double rSum = triangleBoundingRadius + sphereRadius;
61  if (distSqr < rSum * rSum)
62  {
63  Vec3d triangleContactPt;
64  Vec2i edgeContact;
65  int pointContact;
66  int caseType = CollisionUtils::testSphereToTriangle(
67  spherePos, sphereRadius,
68  cell, x1, x2, x3,
69  triangleContactPt,
70  edgeContact, pointContact);
71  if (caseType == 1) // Edge vs point on sphere
72  {
73  // Edge contact
74  CellIndexElement elemA;
75  elemA.ids[0] = edgeContact[0];
76  elemA.ids[1] = edgeContact[1];
77  elemA.idCount = 2;
78  elemA.parentId = i; // Triangle id
79  elemA.cellType = IMSTK_EDGE;
80 
81  Vec3d contactNormal = (spherePos - triangleContactPt);
82  const double dist = contactNormal.norm();
83  const double penetrationDepth = sphereRadius - dist;
84  contactNormal /= dist;
85 
87  elemB.dir = contactNormal; // Direction to resolve sphere
88  elemB.pt = spherePos - sphereRadius * contactNormal; // Contact point on sphere
89  elemB.penetrationDepth = penetrationDepth;
90 
91  lock.lock();
92  elementsA.push_back(elemA);
93  elementsB.push_back(elemB);
94  lock.unlock();
95  }
96  else if (caseType == 2) // Triangle vs point on sphere
97  {
98  // Face contact
99  CellIndexElement elemA;
100  elemA.ids[0] = cell[0];
101  elemA.ids[1] = cell[1];
102  elemA.ids[2] = cell[2];
103  elemA.idCount = 3;
104  elemA.parentId = i; // Triangle id
105  elemA.cellType = IMSTK_TRIANGLE;
106 
107  Vec3d contactNormal = (spherePos - triangleContactPt);
108  const double dist = contactNormal.norm();
109  const double penetrationDepth = sphereRadius - dist;
110  contactNormal /= dist;
111 
112  PointDirectionElement elemB;
113  elemB.dir = contactNormal; // Direction to resolve sphere
114  elemB.pt = spherePos - sphereRadius * contactNormal; // Contact point on sphere
115  elemB.penetrationDepth = penetrationDepth;
116 
117  lock.lock();
118  elementsA.push_back(elemA);
119  elementsB.push_back(elemB);
120  lock.unlock();
121  }
122  else if (caseType == 3)
123  {
124  Vec3d contactNormal = (spherePos - triangleContactPt);
125  const double dist = contactNormal.norm();
126  const double penetrationDepth = sphereRadius - dist;
127  contactNormal /= dist;
128 
129  // Point contact
131  elemA.ptIndex = pointContact; // Point on triangle
132  elemA.dir = -contactNormal; // Direction to resolve point on triangle
133  elemA.penetrationDepth = penetrationDepth;
134 
135  PointDirectionElement elemB;
136  elemB.pt = spherePos - sphereRadius * contactNormal; // Contact point on sphere
137  elemB.dir = contactNormal; // Direction to resolve point on sphere
138  elemB.penetrationDepth = penetrationDepth;
139 
140  lock.lock();
141  elementsA.push_back(elemA);
142  elementsB.push_back(elemB);
143  lock.unlock();
144  }
145  }
146  });
147 }
148 } // namespace imstk
The SpinLock class.
Definition: imstkSpinLock.h:20
void unlock()
End a thread-safe region.
Definition: imstkSpinLock.h:53
Vec3d getPosition(DataType type=DataType::PostTransform)
Get the local or global position (post transformed)
Compound Geometry.
void computeCollisionDataAB(std::shared_ptr< Geometry > geomA, std::shared_ptr< Geometry > geomB, std::vector< CollisionElement > &elementsA, std::vector< CollisionElement > &elementsB) override
Compute collision data for AB simultaneously.
void lock()
Start a thread-safe region, where only one thread can execute at a time until a call to the unlock fu...
Definition: imstkSpinLock.h:45
Represents a set of triangles & vertices via an array of Vec3d double vertices & Vec3i integer indice...
Represents a sphere via its position & radius.
Definition: imstkSphere.h:19
Represents a cell by a single cell id OR by N vertex ids. Which case can be determined by the idCount...
Direclty gives a point-direction contact as its collision data, point given by index.
Direclty gives a point-direction contact as its collision data.