Skip to content

Commit 915ed01

Browse files
authored
[src] Add CollisionDetectionDisplay component to gather all collision output into a Data and also allow display of those collision info (similar to DetectionOutput) (#26)
1 parent bf6c1e5 commit 915ed01

4 files changed

Lines changed: 394 additions & 1 deletion

File tree

CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ set(USE_INFINYTOOLKIT_PLUGIN true CACHE BOOL "Use Interaction Tools plugin")
2525
set(INFINYTOOLKIT_SRC_DIR src/InfinyToolkit)
2626

2727
set(HEADER_FILES
28-
${INFINYTOOLKIT_SRC_DIR}/config.h.in
28+
${INFINYTOOLKIT_SRC_DIR}/config.h.in
29+
${INFINYTOOLKIT_SRC_DIR}/CollisionDetectionDisplay.h
2930
${INFINYTOOLKIT_SRC_DIR}/RotationEngine.h
3031
${INFINYTOOLKIT_SRC_DIR}/PliersToolManager.h
3132
${INFINYTOOLKIT_SRC_DIR}/PliersPositionsMapper.h
@@ -50,6 +51,7 @@ set(HEADER_FILES
5051
)
5152

5253
set(SOURCE_FILES
54+
${INFINYTOOLKIT_SRC_DIR}/CollisionDetectionDisplay.cpp
5355
${INFINYTOOLKIT_SRC_DIR}/RotationEngine.cpp
5456
${INFINYTOOLKIT_SRC_DIR}/PliersToolManager.cpp
5557
${INFINYTOOLKIT_SRC_DIR}/PliersPositionsMapper.cpp
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
<?xml version="1.0"?>
2+
<Node name="root" dt="0.03333">
3+
<RequiredPlugin name="Sofa.Component.Collision.Detection.Algorithm"/> <!-- Needed to use components [BVHNarrowPhase BruteForceBroadPhase CollisionPipeline] -->
4+
<RequiredPlugin name="Sofa.Component.Collision.Detection.Intersection"/> <!-- Needed to use components [MinProximityIntersection] -->
5+
<RequiredPlugin name="Sofa.Component.Collision.Geometry"/> <!-- Needed to use components [LineCollisionModel PointCollisionModel TriangleCollisionModel] -->
6+
<RequiredPlugin name="Sofa.Component.Collision.Response.Contact"/> <!-- Needed to use components [CollisionResponse] -->
7+
<RequiredPlugin name="Sofa.Component.IO.Mesh"/> <!-- Needed to use components [MeshOBJLoader] -->
8+
<RequiredPlugin name="Sofa.Component.LinearSolver.Iterative"/> <!-- Needed to use components [CGLinearSolver] -->
9+
<RequiredPlugin name="Sofa.Component.Mapping.Linear"/> <!-- Needed to use components [BarycentricMapping] -->
10+
<RequiredPlugin name="Sofa.Component.Mass"/> <!-- Needed to use components [UniformMass] -->
11+
<RequiredPlugin name="Sofa.Component.ODESolver.Backward"/> <!-- Needed to use components [EulerImplicitSolver] -->
12+
<RequiredPlugin name="Sofa.Component.SolidMechanics.Spring"/> <!-- Needed to use components [RegularGridSpringForceField] -->
13+
<RequiredPlugin name="Sofa.Component.StateContainer"/> <!-- Needed to use components [MechanicalObject] -->
14+
<RequiredPlugin name="Sofa.Component.Topology.Container.Constant"/> <!-- Needed to use components [MeshTopology] -->
15+
<RequiredPlugin name="Sofa.Component.Topology.Container.Grid"/> <!-- Needed to use components [RegularGridTopology] -->
16+
<RequiredPlugin name="Sofa.GL.Component.Rendering3D"/> <!-- Needed to use components [OglModel] -->
17+
<RequiredPlugin name="InfinyToolkit" />
18+
19+
<CollisionPipeline verbose="0" depth="10" draw="0" />
20+
<DefaultAnimationLoop/>
21+
<BruteForceBroadPhase/>
22+
<BVHNarrowPhase/>
23+
<MinProximityIntersection name="Proximity" alarmDistance="0.75" contactDistance="0.5" />
24+
<CollisionResponse name="Response" response="PenalityContactForceField" />
25+
<CollisionDetectionDisplay name="CollisionDetectionDisplay"/>
26+
27+
<MeshOBJLoader name='Loader-torus' filename='mesh/torus2_scale3.obj'/>
28+
<MeshOBJLoader name='Loader-dragon' filename='mesh/dragon.obj'/>
29+
<MeshOBJLoader name='Loader-frog_body' filename='mesh/frog_body.obj'/>
30+
<MeshOBJLoader name='Loader-frog_eyes' filename='mesh/frog_eyes.obj'/>
31+
<MeshOBJLoader name='Loader-frog_eyebrows' filename='mesh/frog_eyebrows.obj'/>
32+
<MeshOBJLoader name='Loader-frog_lips' filename='mesh/frog_lips.obj'/>
33+
<MeshOBJLoader name='Loader-floor' filename='mesh/floor2b.obj'/>
34+
35+
<Node name="Torus">
36+
<EulerImplicitSolver name="cg_odesolver" printLog="false" rayleighStiffness="0.1" rayleighMass="0.1" />
37+
<CGLinearSolver iterations="25" name="linear solver" tolerance="1.0e-9" threshold="1.0e-9" />
38+
<MechanicalObject dx="0" dy="20" dz="29" rz="64" />
39+
<UniformMass totalMass="10" />
40+
<RegularGridTopology nx="6" ny="5" nz="2" xmin="-7.5" xmax="7.5" ymin="-6" ymax="6" zmin="-1.75" zmax="1.75" />
41+
<RegularGridSpringForceField name="Springs" stiffness="350" damping="1" />
42+
<Node name="Torus_visu" tags="Visual">
43+
<OglModel name="Visual" src="@../../Loader-torus" color="blue" />
44+
<BarycentricMapping input="@.." output="@Visual" />
45+
</Node>
46+
<Node name="Torus_collision">
47+
<MeshOBJLoader name="loader" filename="mesh/torus2_scale3.obj" />
48+
<MeshTopology src="@loader" />
49+
<MechanicalObject src="@loader"/>
50+
<TriangleCollisionModel />
51+
<LineCollisionModel />
52+
<PointCollisionModel />
53+
<BarycentricMapping />
54+
</Node>
55+
</Node>
56+
57+
<Node name="Dragon">
58+
<EulerImplicitSolver name="cg_odesolver" printLog="false" />
59+
<CGLinearSolver iterations="25" name="linear solver" tolerance="1.0e-9" threshold="1.0e-9" />
60+
<MechanicalObject dx="20" dy="20" dz="29" rx="33" />
61+
<UniformMass totalMass="10" />
62+
<RegularGridTopology nx="6" ny="5" nz="3" xmin="-11" xmax="11" ymin="-7" ymax="7" zmin="-4" zmax="4" />
63+
<RegularGridSpringForceField name="Springs" stiffness="350" damping="1" />
64+
<Node name="Dragon_visu" tags="Visual">
65+
<OglModel name="Visual" src="@../../Loader-dragon" color="red" />
66+
<BarycentricMapping input="@.." output="@Visual" />
67+
</Node>
68+
<Node name="Dragon_collision">
69+
<MeshOBJLoader name="loader" filename="mesh/dragon.obj" />
70+
<MeshTopology src="@loader" />
71+
<MechanicalObject src="@loader" />
72+
<TriangleCollisionModel />
73+
<LineCollisionModel />
74+
<PointCollisionModel />
75+
<BarycentricMapping />
76+
</Node>
77+
</Node>
78+
79+
<Node name="Frog">
80+
<EulerImplicitSolver name="cg_odesolver" printLog="false" />
81+
<CGLinearSolver iterations="25" name="linear solver" tolerance="1.0e-9" threshold="1.0e-9" />
82+
<MechanicalObject dx="-20" dy="20" dz="29" ry="10" />
83+
<UniformMass totalMass="10" />
84+
<RegularGridTopology nx="6" ny="3" nz="5" xmin="-10" xmax="8" ymin="-3" ymax="2.5" zmin="-7" zmax="7" />
85+
<RegularGridSpringForceField name="Springs" stiffness="350" damping="1" />
86+
<Node name="VisualFrog" tags="Visual">
87+
<Node name="Frog_body_visu">
88+
<OglModel name="VisualBody" src="@../../../Loader-frog_body" normals="0" color="0.17 0.70 0.05" />
89+
<BarycentricMapping input="@.." output="@VisualBody" />
90+
</Node>
91+
<Node name="Frog_eyes_visu">
92+
<OglModel name="VisualEyes" src="@../../../Loader-frog_eyes" normals="0" color="0.04 0.19 0.52" />
93+
<BarycentricMapping input="@.." output="@VisualEyes" />
94+
</Node>
95+
<Node name="Frog_eyebrows_visu">
96+
<OglModel name="VisualEyebrows" src="@../../../Loader-frog_eyebrows" normals="0" color="0.44 0.43 0.00" />
97+
<BarycentricMapping input="@.." output="@VisualEyebrows" />
98+
</Node>
99+
<Node name="Frog_lips_visu">
100+
<OglModel name="VisualLips" src="@../../../Loader-frog_lips" normals="0" color="0.47 0.25 0.03" />
101+
<BarycentricMapping input="@.." output="@VisualLips" />
102+
</Node>
103+
</Node>
104+
<Node name="Frog_collision">
105+
<MeshOBJLoader name="loader" filename="mesh/frog-push25.obj" />
106+
<MeshTopology src="@loader" />
107+
<MechanicalObject src="@loader" />
108+
<TriangleCollisionModel />
109+
<LineCollisionModel />
110+
<PointCollisionModel />
111+
<BarycentricMapping />
112+
</Node>
113+
</Node>
114+
115+
<Node name="Floor">
116+
<MeshOBJLoader name="loader" filename="mesh/floor2b.obj" />
117+
<MeshTopology src="@loader" />
118+
<MechanicalObject src="@loader" dy="-10.25" scale="0.5" />
119+
<TriangleCollisionModel name="FloorTriangleModel" simulated="0" moving="0" />
120+
<LineCollisionModel name="FloorLineModel" simulated="0" moving="0" />
121+
<PointCollisionModel name="FloorPointModel" simulated="0" moving="0" />
122+
<OglModel name="FloorV" src="@../../Loader-floor" scale="0.5" texturename="textures/floor.bmp" dy="-10" />
123+
</Node>
124+
</Node>
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
/*****************************************************************************
2+
* - Copyright (C) - 2020 - InfinyTech3D - *
3+
* *
4+
* This file is part of the InfinyToolkit plugin for the SOFA framework *
5+
* *
6+
* Commercial License Usage: *
7+
* Licensees holding valid commercial license from InfinyTech3D may use this *
8+
* file in accordance with the commercial license agreement provided with *
9+
* the Software or, alternatively, in accordance with the terms contained in *
10+
* a written agreement between you and InfinyTech3D. For further information *
11+
* on the licensing terms and conditions, contact: contact@infinytech3d.com *
12+
* *
13+
* GNU General Public License Usage: *
14+
* Alternatively, this file may be used under the terms of the GNU General *
15+
* Public License version 3. The licenses are as published by the Free *
16+
* Software Foundation and appearing in the file LICENSE.GPL3 included in *
17+
* the packaging of this file. Please review the following information to *
18+
* ensure the GNU General Public License requirements will be met: *
19+
* https://www.gnu.org/licenses/gpl-3.0.html. *
20+
* *
21+
* Authors: see Authors.txt *
22+
* Further information: https://infinytech3d.com *
23+
****************************************************************************/
24+
25+
#include <InfinyToolkit/CollisionDetectionDisplay.h>
26+
#include <sofa/core/visual/VisualParams.h>
27+
#include <sofa/core/ObjectFactory.h>
28+
#include <sofa/simulation/AnimateEndEvent.h>
29+
#include <limits>
30+
31+
namespace sofa::infinytoolkit
32+
{
33+
34+
int CollisionDetectionDisplayClass = core::RegisterObject("Class to track the current position of the needle tip.")
35+
.add< CollisionDetectionDisplay >()
36+
;
37+
38+
39+
CollisionDetectionDisplay::CollisionDetectionDisplay()
40+
: d_drawContacts(initData(&d_drawContacts, false, "drawContacts", "if true, will draw slices BB, ray and intersected triangles"))
41+
, d_collisionPoints(initData(&d_collisionPoints, "collisionPoints", "vector of pair of collision points"))
42+
{
43+
f_listening.setValue(true);
44+
}
45+
46+
47+
CollisionDetectionDisplay::~CollisionDetectionDisplay()
48+
{
49+
clearContacts();
50+
}
51+
52+
void CollisionDetectionDisplay::init()
53+
{
54+
sofa::core::objectmodel::BaseObject::d_componentState.setValue(sofa::core::objectmodel::ComponentState::Loading);
55+
56+
// If no NarrowPhaseDetection is set using the link try to find the component
57+
if (l_detectionNP.get() == nullptr)
58+
{
59+
l_detectionNP.set(getContext()->get<core::collision::NarrowPhaseDetection>());
60+
}
61+
62+
if (l_detectionNP.get() == nullptr) {
63+
msg_error() << "NarrowPhaseDetection not found";
64+
sofa::core::objectmodel::BaseObject::d_componentState.setValue(sofa::core::objectmodel::ComponentState::Invalid);
65+
}
66+
67+
sofa::core::objectmodel::BaseObject::d_componentState.setValue(sofa::core::objectmodel::ComponentState::Valid);
68+
}
69+
70+
71+
void CollisionDetectionDisplay::handleEvent(sofa::core::objectmodel::Event* event)
72+
{
73+
if (d_componentState.getValue() != sofa::core::objectmodel::ComponentState::Valid)
74+
return;
75+
76+
if (simulation::AnimateEndEvent::checkEventType(event))
77+
{
78+
filterCollision();
79+
}
80+
}
81+
82+
83+
void CollisionDetectionDisplay::filterCollision()
84+
{
85+
if (!this->isComponentStateValid())
86+
return;
87+
88+
clearContacts();
89+
90+
// get the collision output
91+
const core::collision::NarrowPhaseDetection::DetectionOutputMap& detectionOutputs = l_detectionNP.get()->getDetectionOutputs();
92+
if (detectionOutputs.size() == 0) // exit if no collision
93+
{
94+
return;
95+
}
96+
97+
// loop on the contact to get the one between the CarvingSurface and the CarvingTool collision model
98+
const ContactVector* contacts = nullptr;
99+
auto colPoints = sofa::helper::getWriteAccessor(d_collisionPoints);
100+
for (core::collision::NarrowPhaseDetection::DetectionOutputMap::const_iterator it = detectionOutputs.begin(); it != detectionOutputs.end(); ++it)
101+
{
102+
sofa::core::CollisionModel* collMod1 = it->first.first;
103+
sofa::core::CollisionModel* collMod2 = it->first.second;
104+
105+
dmsg_info() << "collMod1: " << collMod1->getTypeName() << " -> " << collMod1->getContext()->getName();
106+
dmsg_info() << "collMod1: " << collMod2->getTypeName() << " -> " << collMod2->getContext()->getName();
107+
108+
109+
// Get the number of contacts
110+
contacts = dynamic_cast<const ContactVector*>(it->second);
111+
if (contacts == nullptr)
112+
continue;
113+
114+
size_t ncontacts = contacts->size();
115+
if (contacts->size() == 0)
116+
continue;
117+
118+
for (size_t j = 0; j < ncontacts; ++j)
119+
{
120+
const ContactVector::value_type& c = (*contacts)[j];
121+
// update the triangle id if a mapping is present
122+
contactInfo* info = new contactInfo();
123+
124+
dmsg_info() << j << " contact: " << c.elem.first.getIndex() << " | " << c.elem.second.getIndex()
125+
<< " -> " << " pA: " << c.point[0] << " pB: " << c.point[1]
126+
<< " | normal: " << c.normal << " d: " << c.value
127+
<< " | cDir: " << (c.point[1] - c.point[0]).normalized() << " d: " << (c.point[1] - c.point[0]).norm();
128+
129+
info->idA = c.elem.first.getIndex();
130+
info->idB = c.elem.second.getIndex();
131+
info->normal = c.normal;
132+
info->pointA = c.point[0];
133+
info->pointB = c.point[1];
134+
info->dist = c.value;
135+
136+
m_contactInfos.push_back(info);
137+
colPoints.push_back(info->pointA);
138+
colPoints.push_back(info->pointB);
139+
}
140+
}
141+
}
142+
143+
void CollisionDetectionDisplay::clearContacts()
144+
{
145+
for (unsigned int i = 0; i < m_contactInfos.size(); i++)
146+
{
147+
delete m_contactInfos[i];
148+
m_contactInfos[i] = nullptr;
149+
}
150+
m_contactInfos.clear();
151+
152+
auto points = sofa::helper::getWriteAccessor(d_collisionPoints);
153+
points.clear();
154+
}
155+
156+
157+
void CollisionDetectionDisplay::draw(const core::visual::VisualParams* vparams)
158+
{
159+
if (!this->isComponentStateValid() || !d_drawContacts.getValue())
160+
return;
161+
162+
const auto stateLifeCycle = vparams->drawTool()->makeStateLifeCycle();
163+
for (contactInfo* cInfo : m_contactInfos)
164+
{
165+
std::vector<Vec3> vertices;
166+
vertices.push_back(cInfo->pointA);
167+
vertices.push_back(cInfo->pointB);
168+
169+
sofa::type::RGBAColor color4(1.0f, 1.0, 0.0f, 1.0);
170+
171+
vparams->drawTool()->drawLines(vertices, 1, color4);
172+
}
173+
}
174+
175+
176+
} // namespace sofa::infinytoolkit

0 commit comments

Comments
 (0)