33#include < CollisionAlgorithm/BaseAlgorithm.h>
44#include < CollisionAlgorithm/BaseGeometry.h>
55#include < CollisionAlgorithm/BaseOperation.h>
6+ #include < CollisionAlgorithm/operations/ContainsPoint.h>
67#include < CollisionAlgorithm/operations/CreateCenterProximity.h>
78#include < CollisionAlgorithm/operations/FindClosestProximity.h>
8- #include < CollisionAlgorithm/operations/Project.h>
9- #include < CollisionAlgorithm/operations/ContainsPoint.h>
109#include < CollisionAlgorithm/operations/NeedleOperations.h>
10+ #include < CollisionAlgorithm/operations/Project.h>
1111#include < CollisionAlgorithm/proximity/EdgeProximity.h>
1212#include < sofa/component/constraint/lagrangian/solver/ConstraintSolverImpl.h>
1313#include < sofa/component/statecontainer/MechanicalObject.h>
@@ -29,7 +29,7 @@ class SOFA_COLLISIONALGORITHM_API InsertionAlgorithm : public BaseAlgorithm
2929
3030 GeomLink l_tipGeom, l_surfGeom, l_shaftGeom, l_volGeom;
3131 Data<AlgorithmOutput> d_collisionOutput, d_insertionOutput;
32- Data<bool > d_projective;
32+ Data<bool > d_projective, d_enablePuncture, d_enableInsertion, d_enableShaftCollision ;
3333 Data<SReal> d_punctureForceThreshold, d_tipDistThreshold;
3434 ConstraintSolver::SPtr m_constraintSolver;
3535 std::vector<BaseProximity::SPtr> m_couplingPts;
@@ -50,6 +50,12 @@ class SOFA_COLLISIONALGORITHM_API InsertionAlgorithm : public BaseAlgorithm
5050 d_projective(initData(
5151 &d_projective, false , " projective" ,
5252 " Projection of closest detected proximity back onto the needle tip element." )),
53+ d_enablePuncture(
54+ initData (&d_enablePuncture, true , " enablePuncture" , " Enable puncture algorithm." )),
55+ d_enableInsertion(
56+ initData (&d_enableInsertion, true , " enableInsertion" , " Enable insertion algorithm." )),
57+ d_enableShaftCollision(initData(&d_enableShaftCollision, true , " enableShaftCollision" ,
58+ " Enable shaft-surface collision." )),
5359 d_punctureForceThreshold(initData(&d_punctureForceThreshold, -1_sreal,
5460 " punctureForceThreshold" ,
5561 " Threshold for the force applied to the needle tip. "
@@ -70,24 +76,30 @@ class SOFA_COLLISIONALGORITHM_API InsertionAlgorithm : public BaseAlgorithm
7076 void init () override
7177 {
7278 BaseAlgorithm::init ();
73- this ->getContext ()->get <ConstraintSolver>(m_constraintSolver);
74- msg_warning_when (!m_constraintSolver)
75- << " No constraint solver found in context. Insertion algorithm is disabled." ;
7679
77- if (d_punctureForceThreshold .getValue () < 0 )
80+ if (d_enablePuncture .getValue ())
7881 {
79- msg_warning () << d_punctureForceThreshold.getName () +
80- " parameter not defined or set to negative value." msgendl
81- << " Puncture will not function properly; provide a positive value" ;
82- d_punctureForceThreshold.setValue (std::numeric_limits<double >::max ());
82+ this ->getContext ()->get <ConstraintSolver>(m_constraintSolver);
83+ msg_warning_when (!m_constraintSolver)
84+ << " No constraint solver found in context. Insertion algorithm is disabled." ;
85+ if (d_punctureForceThreshold.getValue () < 0 )
86+ {
87+ msg_warning () << d_punctureForceThreshold.getName () +
88+ " parameter not defined or set to negative value." msgendl
89+ << " Puncture will not function properly; provide a positive value" ;
90+ d_punctureForceThreshold.setValue (std::numeric_limits<double >::max ());
91+ }
8392 }
8493
85- if (d_tipDistThreshold .getValue () < 0 )
94+ if (d_enableInsertion .getValue ())
8695 {
87- msg_warning () << d_tipDistThreshold.getName () +
88- " parameter not defined or set to negative value." msgendl
89- << " Needle-volume coupling is disabled; provide a positive value" ;
90- d_tipDistThreshold.setValue (std::numeric_limits<double >::max ());
96+ if (d_tipDistThreshold.getValue () < 0 )
97+ {
98+ msg_warning () << d_tipDistThreshold.getName () +
99+ " parameter not defined or set to negative value." msgendl
100+ << " Needle-volume coupling is disabled; provide a positive value" ;
101+ d_tipDistThreshold.setValue (std::numeric_limits<double >::max ());
102+ }
91103 }
92104 }
93105
@@ -118,61 +130,64 @@ class SOFA_COLLISIONALGORITHM_API InsertionAlgorithm : public BaseAlgorithm
118130
119131 void doDetection ()
120132 {
121- if (!l_tipGeom || !l_surfGeom || !l_shaftGeom || !l_volGeom) return ;
122-
123133 auto & collisionOutput = *d_collisionOutput.beginEdit ();
124134 auto & insertionOutput = *d_insertionOutput.beginEdit ();
125135
126136 insertionOutput.clear ();
127137 collisionOutput.clear ();
128138
129- if (m_couplingPts.empty ())
139+ if (m_couplingPts.empty () && l_surfGeom )
130140 {
131- // 1. Puncture algorithm
132- auto createTipProximity =
133- Operations::CreateCenterProximity::Operation::get (l_tipGeom->getTypeInfo ());
141+ // Operations on surface geometry
134142 auto findClosestProxOnSurf =
135143 Operations::FindClosestProximity::Operation::get (l_surfGeom);
136144 auto projectOnSurf = Operations::Project::Operation::get (l_surfGeom);
137- auto projectOnTip = Operations::Project::Operation::get (l_tipGeom);
138145
139- const SReal punctureForceThreshold = d_punctureForceThreshold. getValue ();
140- for ( auto itTip = l_tipGeom-> begin (); itTip != l_tipGeom-> end (); itTip++ )
146+ // Puncture sequence
147+ if (d_enablePuncture. getValue () && l_tipGeom)
141148 {
142- BaseProximity::SPtr tipProx = createTipProximity (itTip->element ());
143- if (!tipProx) continue ;
144- const BaseProximity::SPtr surfProx = findClosestProxOnSurf (
145- tipProx, l_surfGeom.get (), projectOnSurf, getFilterFunc ());
146- if (surfProx)
147- {
148- surfProx->normalize ();
149+ auto createTipProximity =
150+ Operations::CreateCenterProximity::Operation::get (l_tipGeom->getTypeInfo ());
151+ auto projectOnTip = Operations::Project::Operation::get (l_tipGeom);
149152
150- // 1.1 Check whether puncture is happening - if so, create coupling point
151- if (m_constraintSolver)
153+ const SReal punctureForceThreshold = d_punctureForceThreshold.getValue ();
154+ for (auto itTip = l_tipGeom->begin (); itTip != l_tipGeom->end (); itTip++)
155+ {
156+ BaseProximity::SPtr tipProx = createTipProximity (itTip->element ());
157+ if (!tipProx) continue ;
158+ const BaseProximity::SPtr surfProx = findClosestProxOnSurf (
159+ tipProx, l_surfGeom.get (), projectOnSurf, getFilterFunc ());
160+ if (surfProx)
152161 {
153- const MechStateTipType::SPtr mstate =
154- l_tipGeom->getContext ()->get <MechStateTipType>();
155- const auto & lambda =
156- m_constraintSolver->getLambda ()[mstate.get ()].read ()->getValue ();
157- SReal norm{0_sreal};
158- for (const auto & l : lambda)
159- {
160- norm += l.norm ();
161- }
162- if (norm > punctureForceThreshold)
162+ surfProx->normalize ();
163+
164+ // Check whether puncture is happening - if so, create coupling point ...
165+ if (m_constraintSolver)
163166 {
164- m_couplingPts.push_back (surfProx);
165- continue ;
167+ const MechStateTipType::SPtr mstate =
168+ l_tipGeom->getContext ()->get <MechStateTipType>();
169+ const auto & lambda =
170+ m_constraintSolver->getLambda ()[mstate.get ()].read ()->getValue ();
171+ SReal norm{0_sreal};
172+ for (const auto & l : lambda)
173+ {
174+ norm += l.norm ();
175+ }
176+ if (norm > punctureForceThreshold)
177+ {
178+ m_couplingPts.push_back (surfProx);
179+ continue ;
180+ }
166181 }
167- }
168182
169- // ... if not, create a proximity pair for the tip-surface collision
170- collisionOutput.add (tipProx, surfProx);
183+ // ... if not, create a proximity pair for the tip-surface collision
184+ collisionOutput.add (tipProx, surfProx);
185+ }
171186 }
172187 }
173188
174- // 1.3 Collision with the shaft geometry
175- if (m_couplingPts.empty ())
189+ // Shaft collision sequence - Disable if coupling points have been added
190+ if (d_enableShaftCollision. getValue () && m_couplingPts.empty () && l_shaftGeom )
176191 {
177192 auto createShaftProximity =
178193 Operations::CreateCenterProximity::Operation::get (l_shaftGeom->getTypeInfo ());
@@ -187,11 +202,17 @@ class SOFA_COLLISIONALGORITHM_API InsertionAlgorithm : public BaseAlgorithm
187202 {
188203 surfProx->normalize ();
189204
190- // 1.2 If not, create a proximity pair for the tip-surface collision
191205 if (d_projective.getValue ())
192206 {
193- shaftProx =
194- projectOnShaft (surfProx->getPosition (), itShaft->element ()).prox ;
207+ // shaftProx =
208+ // projectOnShaft(surfProx->getPosition(), itShaft->element()).prox;
209+ // if (!shaftProx) continue;
210+ // shaftProx->normalize();
211+ // Experimental - This enables projection anywhere on the edge
212+ auto findClosestProxOnShaft =
213+ Operations::FindClosestProximity::Operation::get (l_shaftGeom);
214+ shaftProx = findClosestProxOnShaft (surfProx, l_shaftGeom,
215+ projectOnShaft, getFilterFunc ());
195216 if (!shaftProx) continue ;
196217 shaftProx->normalize ();
197218 }
@@ -202,7 +223,9 @@ class SOFA_COLLISIONALGORITHM_API InsertionAlgorithm : public BaseAlgorithm
202223 }
203224 else
204225 {
205- // 2. Needle insertion algorithm
226+ // Insertion sequence
227+ if (!d_enableInsertion.getValue () || !l_tipGeom || !l_volGeom || !l_shaftGeom) return ;
228+
206229 ElementIterator::SPtr itTip = l_tipGeom->begin ();
207230 auto createTipProximity =
208231 Operations::CreateCenterProximity::Operation::get (itTip->getTypeInfo ());
@@ -256,7 +279,7 @@ class SOFA_COLLISIONALGORITHM_API InsertionAlgorithm : public BaseAlgorithm
256279
257280 const int numCPs = floor (lastCPToP1.norm () / tipDistThreshold);
258281
259- for (int idCP = 0 ; idCP < numCPs ; idCP++)
282+ for (int idCP = 0 ; idCP < numCPs; idCP++)
260283 {
261284 // Candidate coupling point along shaft segment
262285 const type::Vec3 candidateCP = lastCP + tipDistThreshold * shaftEdgeDir;
@@ -270,7 +293,7 @@ class SOFA_COLLISIONALGORITHM_API InsertionAlgorithm : public BaseAlgorithm
270293 // Skip if candidate CP is outside current edge segment
271294 if (projPtOnEdge < 0_sreal || projPtOnEdge > edgeSegmentLength) break ;
272295
273- // Project candidate CP onto shaft geometry ...
296+ // Project candidate CP onto shaft geometry ...
274297 shaftProx = projectOnShaft (candidateCP, itShaft->element ()).prox ;
275298 if (!shaftProx) continue ;
276299
@@ -279,8 +302,8 @@ class SOFA_COLLISIONALGORITHM_API InsertionAlgorithm : public BaseAlgorithm
279302 shaftProx, l_volGeom.get (), projectOnVol, getFilterFunc ());
280303 if (!volProx) continue ;
281304
282- // Proximity can be detected before the tip enters the tetra (e.g. near a
283- // boundary face) Only accept proximities if the tip is inside the tetra
305+ // Proximity can be detected before the tip enters the tetra (e.g. near a
306+ // boundary face) Only accept proximities if the tip is inside the tetra
284307 // during insertion
285308 if (containsPointInVol (shaftProx->getPosition (), volProx))
286309 {
@@ -291,11 +314,19 @@ class SOFA_COLLISIONALGORITHM_API InsertionAlgorithm : public BaseAlgorithm
291314 }
292315 }
293316 }
317+ else // Don't bother with removing the point that was just added
318+ {
319+ // Remove coupling points that are ahead of the tip in the insertion direction
320+ ElementIterator::SPtr itShaft = l_shaftGeom->begin (l_shaftGeom->getSize () - 2 );
321+ auto prunePointsAheadOfTip =
322+ Operations::Needle::PrunePointsAheadOfTip::get (itShaft->getTypeInfo ());
323+ prunePointsAheadOfTip (m_couplingPts, itShaft->element ());
324+ }
294325 }
295326
296- if (!m_couplingPts.empty ())
327+ if (d_enableInsertion. getValue () && !m_couplingPts.empty () && l_shaftGeom )
297328 {
298- // 3. Re-project proximities on the shaft geometry
329+ // Reprojection on shaft geometry sequence
299330 auto findClosestProxOnShaft =
300331 Operations::FindClosestProximity::Operation::get (l_shaftGeom);
301332 auto projectOnShaft = Operations::Project::Operation::get (l_shaftGeom);
0 commit comments