Skip to content

Commit 3c16631

Browse files
committed
[src] Merge and absorb modifications due to the addition of operation classes into the new architecture
2 parents cd45f8a + e6d3e39 commit 3c16631

File tree

10 files changed

+256
-63
lines changed

10 files changed

+256
-63
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/CollisionAlgorithm/algorithm/InsertionAlgorithm.h

Lines changed: 69 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
#include <CollisionAlgorithm/operations/CreateCenterProximity.h>
77
#include <CollisionAlgorithm/operations/FindClosestProximity.h>
88
#include <CollisionAlgorithm/operations/Project.h>
9+
#include <CollisionAlgorithm/operations/ContainsPoint.h>
10+
#include <CollisionAlgorithm/operations/NeedleOperations.h>
911
#include <CollisionAlgorithm/proximity/EdgeProximity.h>
10-
#include <CollisionAlgorithm/proximity/TetrahedronProximity.h>
1112
#include <sofa/component/constraint/lagrangian/solver/ConstraintSolverImpl.h>
1213
#include <sofa/component/statecontainer/MechanicalObject.h>
1314

@@ -16,7 +17,7 @@ namespace sofa::collisionalgorithm
1617

1718
class InsertionAlgorithm : public BaseAlgorithm
1819
{
19-
public:
20+
public:
2021
SOFA_CLASS(InsertionAlgorithm, BaseAlgorithm);
2122

2223
typedef core::behavior::MechanicalState<defaulttype::Vec3Types> MechStateTipType;
@@ -215,70 +216,87 @@ class InsertionAlgorithm : public BaseAlgorithm
215216
const BaseProximity::SPtr tipProx = createTipProximity(itTip->element());
216217
if (!tipProx) return;
217218

218-
// 2.1 Check whether coupling point should be added
219-
const type::Vec3 tip2Pt = m_couplingPts.back()->getPosition() - tipProx->getPosition();
220-
if (tip2Pt.norm() > d_tipDistThreshold.getValue())
219+
type::Vec3 lastCP = m_couplingPts.back()->getPosition();
220+
const SReal tipDistThreshold = this->d_tipDistThreshold.getValue();
221+
222+
// Vector from tip to last coupling point; used for distance and directional checks
223+
const type::Vec3 tipToLastCP = lastCP - tipProx->getPosition();
224+
225+
// Only add a new coupling point if the needle tip has advanced far enough
226+
if (tipToLastCP.norm() > tipDistThreshold)
221227
{
228+
// Prepare the operations before entering the loop
229+
auto createShaftProximity =
230+
Operations::CreateCenterProximity::Operation::get(l_shaftGeom->getTypeInfo());
231+
auto projectOnShaft = Operations::Project::Operation::get(l_shaftGeom);
222232
auto findClosestProxOnVol =
223233
Operations::FindClosestProximity::Operation::get(l_volGeom);
224234
auto projectOnVol = Operations::Project::Operation::get(l_volGeom);
225-
const BaseProximity::SPtr volProx =
226-
findClosestProxOnVol(tipProx, l_volGeom.get(), projectOnVol, getFilterFunc());
227-
// Proximity can be detected before the tip enters the tetra (e.g. near a boundary face)
228-
// Only accept proximities if the tip is inside the tetra during insertion
229-
if (volProx)
235+
auto containsPointInVol =
236+
Operations::ContainsPointInProximity::Operation::get(l_volGeom);
237+
238+
// Iterate over shaft segments to find which one contains the next candidate CP
239+
for (auto itShaft = l_shaftGeom->begin(); itShaft != l_shaftGeom->end(); itShaft++)
230240
{
231-
TetrahedronProximity::SPtr tetProx =
232-
dynamic_pointer_cast<TetrahedronProximity>(volProx);
233-
if (tetProx)
241+
BaseProximity::SPtr shaftProx = createShaftProximity(itShaft->element());
242+
if (!shaftProx) continue;
243+
244+
const EdgeProximity::SPtr edgeProx =
245+
dynamic_pointer_cast<EdgeProximity>(shaftProx);
246+
if (!edgeProx) continue;
247+
248+
const type::Vec3 p0 = edgeProx->element()->getP0()->getPosition();
249+
const type::Vec3 p1 = edgeProx->element()->getP1()->getPosition();
250+
const type::Vec3 shaftEdgeDir = (p1 - p0).normalized();
251+
const type::Vec3 lastCPToP1 = p1 - lastCP;
252+
253+
// Skip if last CP lies after edge end point
254+
if (dot(shaftEdgeDir, lastCPToP1) < 0_sreal) continue;
255+
256+
const int numCPs = floor(lastCPToP1.norm() / tipDistThreshold);
257+
258+
for(int idCP = 0 ; idCP < numCPs ; idCP++)
234259
{
235-
double f0(tetProx->f0()), f1(tetProx->f1()), f2(tetProx->f2()),
236-
f3(tetProx->f3());
237-
bool isInTetra = toolbox::TetrahedronToolBox::isInTetra(
238-
tipProx->getPosition(), tetProx->element()->getTetrahedronInfo(), f0,
239-
f1, f2, f3);
240-
if (isInTetra)
260+
// Candidate coupling point along shaft segment
261+
const type::Vec3 candidateCP = lastCP + tipDistThreshold * shaftEdgeDir;
262+
263+
// Project candidate CP onto the edge element and compute scalar coordinate
264+
// along segment
265+
const SReal edgeSegmentLength = (p1 - p0).norm();
266+
const type::Vec3 p0ToCandidateCP = candidateCP - p0;
267+
const SReal projPtOnEdge = dot(p0ToCandidateCP, shaftEdgeDir);
268+
269+
// Skip if candidate CP is outside current edge segment
270+
if (projPtOnEdge < 0_sreal || projPtOnEdge > edgeSegmentLength) break;
271+
272+
// Project candidate CP onto shaft geometry ...
273+
shaftProx = projectOnShaft(candidateCP, itShaft->element()).prox;
274+
if (!shaftProx) continue;
275+
276+
// ... then find nearest volume proximity
277+
const BaseProximity::SPtr volProx = findClosestProxOnVol(
278+
shaftProx, l_volGeom.get(), projectOnVol, getFilterFunc());
279+
if (!volProx) continue;
280+
281+
// Proximity can be detected before the tip enters the tetra (e.g. near a
282+
// boundary face) Only accept proximities if the tip is inside the tetra
283+
// during insertion
284+
if (containsPointInVol(shaftProx->getPosition(), volProx))
241285
{
242286
volProx->normalize();
243287
m_couplingPts.push_back(volProx);
288+
lastCP = volProx->getPosition();
244289
}
245290
}
246291
}
247292
}
248293
else // Don't bother with removing the point that was just added
249294
{
250-
// 2.2. Check whether coupling point should be removed
295+
// Remove coupling points that are ahead of the tip in the insertion direction
251296
ElementIterator::SPtr itShaft = l_shaftGeom->begin(l_shaftGeom->getSize() - 2);
252-
auto createShaftProximity =
253-
Operations::CreateCenterProximity::Operation::get(itShaft->getTypeInfo());
254-
const BaseProximity::SPtr shaftProx = createShaftProximity(itShaft->element());
255-
if (shaftProx)
256-
{
257-
const EdgeProximity::SPtr edgeProx =
258-
dynamic_pointer_cast<EdgeProximity>(shaftProx);
259-
if (edgeProx)
260-
{
261-
const type::Vec3 normal = (edgeProx->element()->getP1()->getPosition() -
262-
edgeProx->element()->getP0()->getPosition())
263-
.normalized();
264-
// If the (last) coupling point lies ahead of the tip (positive dot product),
265-
// the needle is retreating. Thus, that point is removed.
266-
if (dot(tip2Pt, normal) > 0_sreal)
267-
{
268-
m_couplingPts.pop_back();
269-
}
270-
}
271-
else
272-
{
273-
msg_warning() << "shaftGeom: " << l_shaftGeom->getName()
274-
<< " is not an EdgeGeometry. Point removal is disabled";
275-
}
276-
}
277-
else
278-
{
279-
msg_warning() << "Cannot create proximity from shaftGeom: "
280-
<< l_shaftGeom->getName() << " - point removal is disabled";
281-
}
297+
auto prunePointsAheadOfTip =
298+
Operations::Needle::PrunePointsAheadOfTip::get(itShaft->getTypeInfo());
299+
prunePointsAheadOfTip(m_couplingPts, itShaft->element());
282300
}
283301
}
284302

@@ -299,8 +317,7 @@ class InsertionAlgorithm : public BaseAlgorithm
299317
// This is a final-frontier check: If there are coupling points stored, but the
300318
// findClosestProxOnShaf operation yields no proximities on the shaft, it could be
301319
// because the needle has exited abruptly. Thus, we clear the coupling points.
302-
if (insertionOutput.size() == 0)
303-
m_couplingPts.clear();
320+
if (insertionOutput.size() == 0) m_couplingPts.clear();
304321
}
305322

306323
d_collisionOutput.endEdit();
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include <CollisionAlgorithm/operations/ContainsPoint.h>
2+
#include <CollisionAlgorithm/proximity/TetrahedronProximity.h>
3+
#include <CollisionAlgorithm/proximity/TriangleProximity.h>
4+
5+
namespace sofa::collisionalgorithm::Operations::ContainsPointInElement
6+
{
7+
8+
int register_ContainsPoint_Triangle =
9+
Operation::register_func<TriangleElement>(&toolbox::TriangleToolBox::containsPoint);
10+
11+
int register_ContainsPoint_Tetrahedron =
12+
Operation::register_func<TetrahedronElement>(&toolbox::TetrahedronToolBox::containsPoint);
13+
14+
} // namespace sofa::collisionalgorithm::Operations::ContainsPointInElement
15+
16+
namespace sofa::collisionalgorithm::Operations::ContainsPointInProximity
17+
{
18+
19+
int register_ContainsPointInProximity_Triangle =
20+
Operation::register_func<TriangleElement>(&containsPoint<TriangleProximity>);
21+
22+
int register_ContainsPointInProximity_Tetrahedron =
23+
Operation::register_func<TetrahedronElement>(&containsPoint<TetrahedronProximity>);
24+
25+
} // namespace sofa::collisionalgorithm::Operations::ContainsPointInProximity
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#pragma once
2+
3+
#include <CollisionAlgorithm/BaseElement.h>
4+
#include <CollisionAlgorithm/BaseOperation.h>
5+
6+
namespace sofa::collisionalgorithm::Operations::ContainsPointInElement
7+
{
8+
9+
typedef bool Result;
10+
11+
class Operation : public GenericOperation<Operation, // Type of the operation
12+
Result, // Default return type
13+
const type::Vec3&, const BaseElement::SPtr& // Parameters
14+
>
15+
{
16+
public:
17+
Result defaultFunc(const type::Vec3&, const BaseElement::SPtr&) const override { return false; }
18+
19+
void notFound(const std::type_info& id) const override
20+
{
21+
msg_error("ContainsPointInElement")
22+
<< "The operation ContainsPointInElementOperation is not registered with for type = "
23+
<< sofa::helper::NameDecoder::decodeFullName(id);
24+
}
25+
};
26+
27+
typedef Operation::FUNC FUNC;
28+
29+
} // namespace sofa::collisionalgorithm::Operations::ContainsPointInElement
30+
31+
namespace sofa::collisionalgorithm::Operations::ContainsPointInProximity
32+
{
33+
34+
typedef bool Result;
35+
36+
class Operation
37+
: public GenericOperation<Operation, // Type of the operation
38+
Result, // Default return type
39+
const type::Vec3&, const BaseProximity::SPtr& // Parameters
40+
>
41+
{
42+
public:
43+
Result defaultFunc(const type::Vec3&, const BaseProximity::SPtr&) const override
44+
{
45+
return false;
46+
}
47+
48+
void notFound(const std::type_info& id) const override
49+
{
50+
msg_error("ContainsPointInProximity")
51+
<< "The operation ContainsPointInProximityOperation is not registered with for type = "
52+
<< sofa::helper::NameDecoder::decodeFullName(id);
53+
}
54+
};
55+
56+
template <typename PROX>
57+
Result containsPoint(const type::Vec3& P, const typename std::shared_ptr<PROX>& prox)
58+
{
59+
if (!prox)
60+
{
61+
msg_warning("ContainsPointInProximity") << "Null proximity pointer in containsPoint"
62+
<< "Operation is disabled; returning false";
63+
return false;
64+
}
65+
66+
auto elem = prox->element();
67+
auto containsPointInElem =
68+
sofa::collisionalgorithm::Operations::ContainsPointInElement::Operation::get(elem);
69+
return containsPointInElem(P, elem);
70+
}
71+
72+
typedef Operation::FUNC FUNC;
73+
74+
} // namespace sofa::collisionalgorithm::Operations::ContainsPointInProximity
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#include <CollisionAlgorithm/operations/NeedleOperations.h>
2+
3+
namespace sofa::collisionalgorithm::Operations::Needle
4+
{
5+
6+
bool prunePointsUsingEdges(std::vector<BaseProximity::SPtr>& couplingPts,
7+
const EdgeElement::SPtr& edge)
8+
{
9+
if (!edge)
10+
{
11+
msg_warning("Needle::PrunePointsAheadOfTip")
12+
<< "Null element pointer in prunePointsUsingEdges; returning false";
13+
return false;
14+
}
15+
const type::Vec3 edgeBase(edge->getP0()->getPosition());
16+
const type::Vec3 tip(edge->getP1()->getPosition());
17+
18+
const type::Vec3 edgeDirection = tip - edgeBase;
19+
20+
if (couplingPts.empty()) return true;
21+
const type::Vec3 tip2Pt = couplingPts.back()->getPosition() - tip;
22+
23+
// Positive dot product means the point is ahead of the tip
24+
if (dot(tip2Pt, edgeDirection) > 0_sreal) couplingPts.pop_back();
25+
26+
return true;
27+
}
28+
29+
int register_PrunePointsAheadOfTip_Edge =
30+
PrunePointsAheadOfTip::register_func<EdgeElement>(&prunePointsUsingEdges);
31+
} // namespace sofa::collisionalgorithm::Operations::Needle
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#pragma once
2+
3+
#include <CollisionAlgorithm/BaseOperation.h>
4+
#include <CollisionAlgorithm/BaseProximity.h>
5+
#include <CollisionAlgorithm/elements/EdgeElement.h>
6+
7+
namespace sofa::collisionalgorithm::Operations::Needle
8+
{
9+
10+
class PrunePointsAheadOfTip
11+
: public GenericOperation<PrunePointsAheadOfTip, // Type of the operation
12+
bool, // Default return type
13+
std::vector<BaseProximity::SPtr>&,
14+
const BaseElement::SPtr& // Parameters
15+
>
16+
{
17+
public:
18+
bool defaultFunc(std::vector<BaseProximity::SPtr>&, const BaseElement::SPtr&) const override
19+
{
20+
return false;
21+
}
22+
23+
void notFound(const std::type_info& id) const override
24+
{
25+
msg_error("Needle::PrunePointsAheadOfTip")
26+
<< "The operation PrunePointsAheadOfTipOperation is not registered with for type = "
27+
<< sofa::helper::NameDecoder::decodeFullName(id);
28+
}
29+
};
30+
31+
bool prunePointsUsingEdges(std::vector<BaseProximity::SPtr>& couplingPts,
32+
const EdgeElement::SPtr& edgeProx);
33+
34+
} // namespace sofa::collisionalgorithm::Operations::Needle

src/CollisionAlgorithm/toolbox/TetrahedronToolBox.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ Operations::CreateCenterProximity::Result TetrahedronToolBox::createCenterProxim
1010
return TetrahedronProximity::create(tetra, 1.0/4.0,1.0/4.0,1.0/4.0,1.0/4.0);
1111
}
1212

13+
Operations::ContainsPointInElement::Result TetrahedronToolBox::containsPoint(const type::Vec3 & P, const TetrahedronElement::SPtr & tetra) {
14+
TetrahedronProximity::SPtr prox = TetrahedronProximity::create(tetra, 1.0/4.0,1.0/4.0,1.0/4.0,1.0/4.0);
15+
double f0(prox->f0()), f1(prox->f1()), f2(prox->f2()), f3(prox->f3());
16+
return isInTetra(P,tetra->getTetrahedronInfo(),f0,f1,f2,f3);
17+
}
18+
1319
Operations::Project::Result TetrahedronToolBox::project(const type::Vec3 & P, const TetrahedronElement::SPtr & tetra) {
1420
double fact[4];
1521
projectOnTetra(P, tetra->getTetrahedronInfo(),fact[0],fact[1],fact[2],fact[3]);

0 commit comments

Comments
 (0)