@@ -18,7 +18,7 @@ namespace sofa::collisionAlgorithm
1818
1919class InsertionAlgorithm : public BaseAlgorithm
2020{
21- public:
21+ public:
2222 SOFA_CLASS (InsertionAlgorithm, BaseAlgorithm);
2323
2424 typedef core::behavior::MechanicalState<defaulttype::Vec3Types> MechStateTipType;
@@ -225,26 +225,77 @@ class InsertionAlgorithm : public BaseAlgorithm
225225
226226 if (m_couplingPts.empty ()) return ;
227227
228- // 2.1 Check whether coupling point should be added
229- const type::Vec3 tip2Pt = m_couplingPts.back ()->getPosition () - tipProx->getPosition ();
230- if (tip2Pt.norm () > d_tipDistThreshold.getValue ())
228+ type::Vec3 lastCP = m_couplingPts.back ()->getPosition ();
229+ const SReal tipDistThreshold = this ->d_tipDistThreshold .getValue ();
230+
231+ // Vector from tip to last coupling point; used for distance and directional checks
232+ const type::Vec3 tipToLastCP = lastCP - tipProx->getPosition ();
233+
234+ // Only add a new coupling point if the needle tip has advanced far enough
235+ if (tipToLastCP.norm () > tipDistThreshold)
231236 {
237+ // Prepare the operations before entering the loop
238+ auto createShaftProximity =
239+ Operations::CreateCenterProximity::Operation::get (l_shaftGeom->getTypeInfo ());
240+ auto projectOnShaft = Operations::Project::Operation::get (l_shaftGeom);
232241 auto findClosestProxOnVol =
233242 Operations::FindClosestProximity::Operation::get (l_volGeom);
234243 auto projectOnVol = Operations::Project::Operation::get (l_volGeom);
235- const BaseProximity::SPtr volProx =
236- findClosestProxOnVol (tipProx, l_volGeom. get (), projectOnVol, getFilterFunc () );
244+ auto containsPointInVol =
245+ Operations::ContainsPointInProximity::Operation:: get (l_volGeom );
237246
238- // Proximity can be detected before the tip enters the tetra (e.g. near a boundary face)
239- // Only accept proximities if the tip is inside the tetra during insertion
240- if (volProx)
247+ // Iterate over shaft segments to find which one contains the next candidate CP
248+ for (auto itShaft = l_shaftGeom->begin (); itShaft != l_shaftGeom->end (); itShaft++)
241249 {
242- auto containsPointInVol = Operations::ContainsPointInProximity::Operation::get (
243- l_volGeom->getTypeInfo ());
244- if (containsPointInVol (tipProx->getPosition (), volProx))
250+ BaseProximity::SPtr shaftProx = createShaftProximity (itShaft->element ());
251+ if (!shaftProx) continue ;
252+
253+ const EdgeProximity::SPtr edgeProx =
254+ dynamic_pointer_cast<EdgeProximity>(shaftProx);
255+ if (!edgeProx) continue ;
256+
257+ const type::Vec3 p0 = edgeProx->element ()->getP0 ()->getPosition ();
258+ const type::Vec3 p1 = edgeProx->element ()->getP1 ()->getPosition ();
259+ const type::Vec3 shaftEdgeDir = (p1 - p0).normalized ();
260+ const type::Vec3 lastCPToP1 = p1 - lastCP;
261+
262+ // Skip if last CP lies after edge end point
263+ if (dot (shaftEdgeDir, lastCPToP1) < 0_sreal) continue ;
264+
265+ const int numCPs = floor (lastCPToP1.norm () / tipDistThreshold);
266+
267+ for (int idCP = 0 ; idCP < numCPs ; idCP++)
245268 {
246- volProx->normalize ();
247- m_couplingPts.push_back (volProx);
269+ // Candidate coupling point along shaft segment
270+ const type::Vec3 candidateCP = lastCP + tipDistThreshold * shaftEdgeDir;
271+
272+ // Project candidate CP onto the edge element and compute scalar coordinate
273+ // along segment
274+ const SReal edgeSegmentLength = (p1 - p0).norm ();
275+ const type::Vec3 p0ToCandidateCP = candidateCP - p0;
276+ const SReal projPtOnEdge = dot (p0ToCandidateCP, shaftEdgeDir);
277+
278+ // Skip if candidate CP is outside current edge segment
279+ if (projPtOnEdge < 0_sreal || projPtOnEdge > edgeSegmentLength) break ;
280+
281+ // Project candidate CP onto shaft geometry ...
282+ shaftProx = projectOnShaft (candidateCP, itShaft->element ()).prox ;
283+ if (!shaftProx) continue ;
284+
285+ // ... then find nearest volume proximity
286+ const BaseProximity::SPtr volProx = findClosestProxOnVol (
287+ shaftProx, l_volGeom.get (), projectOnVol, getFilterFunc ());
288+ if (!volProx) continue ;
289+
290+ // Proximity can be detected before the tip enters the tetra (e.g. near a
291+ // boundary face) Only accept proximities if the tip is inside the tetra
292+ // during insertion
293+ if (containsPointInVol (shaftProx->getPosition (), volProx))
294+ {
295+ volProx->normalize ();
296+ m_couplingPts.push_back (volProx);
297+ lastCP = volProx->getPosition ();
298+ }
248299 }
249300 }
250301 }
@@ -267,8 +318,7 @@ class InsertionAlgorithm : public BaseAlgorithm
267318 // This is a final-frontier check: If there are coupling points stored, but the
268319 // findClosestProxOnShaf operation yields no proximities on the shaft, it could be
269320 // because the needle has exited abruptly. Thus, we clear the coupling points.
270- if (insertionOutput.size () == 0 )
271- m_couplingPts.clear ();
321+ if (insertionOutput.size () == 0 ) m_couplingPts.clear ();
272322 }
273323
274324 d_collisionOutput.endEdit ();
0 commit comments