@@ -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;
@@ -217,26 +217,77 @@ class InsertionAlgorithm : public BaseAlgorithm
217217 const BaseProximity::SPtr tipProx = createTipProximity (itTip->element ());
218218 if (!tipProx) return ;
219219
220- // 2.1 Check whether coupling point should be added
221- const type::Vec3 tip2Pt = m_couplingPts.back ()->getPosition () - tipProx->getPosition ();
222- if (tip2Pt.norm () > d_tipDistThreshold.getValue ())
220+ type::Vec3 lastCP = m_couplingPts.back ()->getPosition ();
221+ const SReal tipDistThreshold = this ->d_tipDistThreshold .getValue ();
222+
223+ // Vector from tip to last coupling point; used for distance and directional checks
224+ const type::Vec3 tipToLastCP = lastCP - tipProx->getPosition ();
225+
226+ // Only add a new coupling point if the needle tip has advanced far enough
227+ if (tipToLastCP.norm () > tipDistThreshold)
223228 {
229+ // Prepare the operations before entering the loop
230+ auto createShaftProximity =
231+ Operations::CreateCenterProximity::Operation::get (l_shaftGeom->getTypeInfo ());
232+ auto projectOnShaft = Operations::Project::Operation::get (l_shaftGeom);
224233 auto findClosestProxOnVol =
225234 Operations::FindClosestProximity::Operation::get (l_volGeom);
226235 auto projectOnVol = Operations::Project::Operation::get (l_volGeom);
227- const BaseProximity::SPtr volProx =
228- findClosestProxOnVol (tipProx, l_volGeom. get (), projectOnVol, getFilterFunc () );
236+ auto containsPointInVol =
237+ Operations::ContainsPointInProximity::Operation:: get (l_volGeom );
229238
230- // Proximity can be detected before the tip enters the tetra (e.g. near a boundary face)
231- // Only accept proximities if the tip is inside the tetra during insertion
232- if (volProx)
239+ // Iterate over shaft segments to find which one contains the next candidate CP
240+ for (auto itShaft = l_shaftGeom->begin (); itShaft != l_shaftGeom->end (); itShaft++)
233241 {
234- auto containsPointInVol = Operations::ContainsPointInProximity::Operation::get (
235- l_volGeom->getTypeInfo ());
236- if (containsPointInVol (tipProx->getPosition (), volProx))
242+ BaseProximity::SPtr shaftProx = createShaftProximity (itShaft->element ());
243+ if (!shaftProx) continue ;
244+
245+ const EdgeProximity::SPtr edgeProx =
246+ dynamic_pointer_cast<EdgeProximity>(shaftProx);
247+ if (!edgeProx) continue ;
248+
249+ const type::Vec3 p0 = edgeProx->element ()->getP0 ()->getPosition ();
250+ const type::Vec3 p1 = edgeProx->element ()->getP1 ()->getPosition ();
251+ const type::Vec3 shaftEdgeDir = (p1 - p0).normalized ();
252+ const type::Vec3 lastCPToP1 = p1 - lastCP;
253+
254+ // Skip if last CP lies after edge end point
255+ if (dot (shaftEdgeDir, lastCPToP1) < 0_sreal) continue ;
256+
257+ const int numCPs = floor (lastCPToP1.norm () / tipDistThreshold);
258+
259+ for (int idCP = 0 ; idCP < numCPs ; idCP++)
237260 {
238- volProx->normalize ();
239- m_couplingPts.push_back (volProx);
261+ // Candidate coupling point along shaft segment
262+ const type::Vec3 candidateCP = lastCP + tipDistThreshold * shaftEdgeDir;
263+
264+ // Project candidate CP onto the edge element and compute scalar coordinate
265+ // along segment
266+ const SReal edgeSegmentLength = (p1 - p0).norm ();
267+ const type::Vec3 p0ToCandidateCP = candidateCP - p0;
268+ const SReal projPtOnEdge = dot (p0ToCandidateCP, shaftEdgeDir);
269+
270+ // Skip if candidate CP is outside current edge segment
271+ if (projPtOnEdge < 0_sreal || projPtOnEdge > edgeSegmentLength) break ;
272+
273+ // Project candidate CP onto shaft geometry ...
274+ shaftProx = projectOnShaft (candidateCP, itShaft->element ()).prox ;
275+ if (!shaftProx) continue ;
276+
277+ // ... then find nearest volume proximity
278+ const BaseProximity::SPtr volProx = findClosestProxOnVol (
279+ shaftProx, l_volGeom.get (), projectOnVol, getFilterFunc ());
280+ if (!volProx) continue ;
281+
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
284+ // during insertion
285+ if (containsPointInVol (shaftProx->getPosition (), volProx))
286+ {
287+ volProx->normalize ();
288+ m_couplingPts.push_back (volProx);
289+ lastCP = volProx->getPosition ();
290+ }
240291 }
241292 }
242293 }
@@ -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