iMSTK
Interactive Medical Simulation Toolkit
imstkEdgeEdgeCCDState.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 "imstkEdgeEdgeCCDState.h"
8 
9 namespace imstk
10 {
11 EdgeEdgeCCDState::EdgeEdgeCCDState(const Vec3d& i0, const Vec3d& i1, const Vec3d& j0, const Vec3d& j1)
12  : xi(i0), xi1(i1), xj(j0), xj1(j1),
13  ei(xi1 - xi), ej(xj1 - xj), w0(xj - xi),
14  w(shortestDistanceVector())
15 {
16  m_si = computeSi();
17  m_sj = computeSj();
18  m_pi = computePi();
19  m_pj = computePj();
20 }
21 
22 Vec3d
24 {
30  // modify s_i and s_j accordingly
31  struct VertexPair
32  {
33  public:
34  Vec3d m_diff;
35  double m_si, m_sj;
36  VertexPair(const Vec3d& diff, double si, double sj) : m_diff(diff), m_si(si), m_sj(sj)
37  {}
38 
39  bool operator<(const VertexPair& A) const
40  {
41  return(this->m_diff.norm() < A.m_diff.norm());
42  }
43  };
44 
45  VertexPair p1(xj - xi, 0, 0);
46  VertexPair p2(xj1 - xi, 1, 0);
47  VertexPair p3(xj - xi1, 0, 1);
48  VertexPair p4(xj1 - xi1, 1, 1);
49  auto result = std::min<VertexPair>({ p1, p2, p3, p4 });
50 
51  // CAUTION: we are overwriting m_si and m_sj values of EdgeEdgeCCDState here, assuming that
52  // they are no longer needed. computeWBar() should only be called once it has
53  // already been determined that an internal intersection doesn't exist.
54  m_si = result.m_si;
55  m_sj = result.m_sj;
56 
57  // Since m_si and m_sj have changed, recompute m_pi and m_pj
58  m_pi = computePi();
59  m_pj = computePj();
60 
61  return result.m_diff;
62 }
63 
64 Vec3d
66 {
67  Vec3d p1 = (xj - xi);
68  Vec3d p2 = (xj1 - xi);
69  Vec3d p3 = (xj - xi1);
70  Vec3d p4 = (xj1 - xi1);
71  return std::min<Vec3d>({ p1, p2, p3, p4 }, [](const Vec3d& a, const Vec3d& b) { return (a.norm() < b.norm()); });
72 }
73 
74 int
75 EdgeEdgeCCDState::testCollision(const EdgeEdgeCCDState& prev, EdgeEdgeCCDState& curr, double& relativeTimeOfImpact)
76 {
77  relativeTimeOfImpact = 0.0;
78  const double tol = 0.01;
79  const bool externalIntersection = (curr.si() < 0 - tol || curr.si() > 1 + tol || curr.sj() < 0 - tol || curr.sj() > 1 + tol);
80 
81  Vec3d curr_wbar = curr.w;
82  if (externalIntersection)
83  {
84  curr_wbar = curr.computeWBar2();
85  }
86 
87  if (curr_wbar.norm() < prev.thickness() + prev.m_epsilon)
88  {
89  relativeTimeOfImpact = 1.0; // impact happens in current time step.
90  return externalIntersection ? 2 : 1;
91  }
92 
93  const bool crossedEachOther = (prev.w.dot(curr.w) < 0);
94  if (crossedEachOther && !externalIntersection)
95  {
96  double m = std::copysign(1.0, curr.w.dot(prev.w)); // get the sign of w_t dot w_{t+1}
97  double denom = prev.w.norm() - m * curr.w.norm();
98 
99  if (denom > prev.m_epsilon) // avoid dividing by zero
100  {
101  relativeTimeOfImpact = prev.w.norm() / (prev.w.norm() - m * curr.w.norm());
102  }
103  return 3;
104  }
105 
106  return 0;
107 }
108 
109 double
110 EdgeEdgeCCDState::computeSi() const
111 {
112  double ac_bb = denom();
113  if (abs(ac_bb) < m_epsilon)
114  {
115  // Return something significantly outside the interval [0,1]
116  // so that the downstream algorithm understands that it is not an internal intersection,
117  // and directly checks for vertex-vertex closeness of the two segments.
118  return -1.0;
119  }
120 
121  // use of -1 multiplier is necessary because w0 is inverted.
122  return -1.0 * (b() * e() - c() * d()) / ac_bb;
123 }
124 
125 double
126 EdgeEdgeCCDState::computeSj() const
127 {
128  double ac_bb = denom();
129  if (abs(ac_bb) < m_epsilon)
130  {
131  if (b() < m_epsilon)
132  {
133  // Return something significantly outside the interval [0,1]
134  // so that the downstream algorithm understands that it is not an internal intersection,
135  // and directly checks for vertex-vertex closeness of the two segments.
136  return -1.0;
137  }
138  else
139  {
140  return d() / b();
141  }
142  }
143 
144  // use of -1 multiplier is necessary because w0 is inverted.
145  return -1.0 * (a() * e() - b() * d()) / ac_bb;
146 }
147 
148 Vec3d
149 EdgeEdgeCCDState::shortestDistanceVector() const
150 {
151  auto n = ei.cross(ej).normalized();
152  auto d = w0.dot(n);
153  return (d * n);
154 }
155 } // namespace imstk
Compound Geometry.
const Vec3d w
Shortest distance vector between the infinite lines defined by the two segments.
static int testCollision(const EdgeEdgeCCDState &prev, EdgeEdgeCCDState &curr, double &relativeTimeOfImpact)
Performs a collision test based on two given timesteps that store the state of two lines each...
const double sj() const
Parameterized position of closest point on segment xj–xj1 to segment xi–xi1.
const double si() const
Parameterized position of closest point on segment xi–xi1 to segment xj–xj1.