Skip to content

Commit 50f392f

Browse files
authored
Merge branch 'master' into fix-retraction
2 parents 192e5c9 + e6d3e39 commit 50f392f

File tree

2 files changed

+71
-21
lines changed

2 files changed

+71
-21
lines changed

scenes/NeedleInsertion.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
g_needleRadius = 0.001 #(m)
77
g_needleMechanicalParameters = {
88
"radius":g_needleRadius,
9-
"youngModulus":1e11,
9+
"youngModulus":1e12,
1010
"poissonRatio":0.3
1111
}
1212
g_needleTotalMass=0.01
@@ -17,7 +17,7 @@
1717
"max":[0.125, 0.125, -0.100]
1818
} #Again all in mm
1919
g_gelMechanicalParameters = {
20-
"youngModulus":8e5,
20+
"youngModulus":1e6,
2121
"poissonRatio":0.45,
2222
"method":"large"
2323
}
@@ -60,7 +60,7 @@ def createScene(root):
6060
root.addObject("ConstraintAttachButtonSetting")
6161
root.addObject("VisualStyle", displayFlags="showVisualModels hideBehaviorModels showCollisionModels hideMappings hideForceFields showWireframe showInteractionForceFields" )
6262
root.addObject("FreeMotionAnimationLoop")
63-
root.addObject("GenericConstraintSolver", tolerance=0.00001, maxIt=5000)
63+
root.addObject("GenericConstraintSolver", tolerance=1e-5, maxIt=5000)
6464
root.addObject("CollisionLoop")
6565

6666
needleBaseMaster = root.addChild("NeedleBaseMaster")
@@ -189,7 +189,7 @@ def createScene(root):
189189
surfGeom="@Volume/collision/geom_tri",
190190
shaftGeom="@Needle/bodyCollision/geom_body",
191191
volGeom="@Volume/geom_tetra",
192-
punctureForceThreshold=2.,
192+
punctureForceThreshold=20,
193193
tipDistThreshold=0.003,
194194
drawcollision=True,
195195
drawPointsScale=0.0001
@@ -199,4 +199,4 @@ def createScene(root):
199199
root.addObject("ConstraintUnilateral",input="@InsertionAlgo.collisionOutput",directions="@punctureDirection",draw_scale=0.001)
200200

201201
root.addObject("FirstDirection",name="bindDirection", handler="@Needle/bodyCollision/NeedleBeams")
202-
root.addObject("ConstraintInsertion",input="@InsertionAlgo.insertionOutput", directions="@bindDirection",draw_scale=0.002, frictionCoeff=0.05)
202+
root.addObject("ConstraintInsertion",input="@InsertionAlgo.insertionOutput", directions="@bindDirection",draw_scale=0.002, frictionCoeff=0.01)

src/sofa/collisionAlgorithm/algorithm/InsertionAlgorithm.h

Lines changed: 66 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ namespace sofa::collisionAlgorithm
1818

1919
class 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

Comments
 (0)