7 #include "imstkPointPicker.h" 8 #include "imstkCollisionUtils.h" 9 #include "imstkLineMesh.h" 10 #include "imstkOrientedBox.h" 11 #include "imstkPlane.h" 12 #include "imstkSphere.h" 13 #include "imstkSurfaceMesh.h" 14 #include "imstkTetrahedralMesh.h" 15 #include "imstkVecDataArray.h" 29 const double sqrDistA = (a.
pickPoint - m_rayStart).squaredNorm();
30 const double sqrDistB = (b.pickPoint - m_rayStart).squaredNorm();
31 return sqrDistA < sqrDistB;
33 std::set<PickData, decltype(pred)> resultSet(pred);
35 std::shared_ptr<Geometry> geomToPick =
getInput(0);
36 geomToPick->updatePostTransformData();
37 if (
auto surfMeshToPick = std::dynamic_pointer_cast<SurfaceMesh>(geomToPick))
39 std::shared_ptr<VecDataArray<double, 3>> verticesPtr = surfMeshToPick->getVertexPositions();
41 std::shared_ptr<VecDataArray<int, 3>> indicesPtr = surfMeshToPick->getCells();
46 for (
int i = 0; i < indices.size(); i++)
48 const Vec3i& cell = indices[i];
49 const Vec3d& a = vertices[cell[0]];
50 const Vec3d& b = vertices[cell[1]];
51 const Vec3d& c = vertices[cell[2]];
52 const Vec3d n = (b - a).cross(c - a).normalized();
53 Vec3d iPt = Vec3d::Zero();
54 if (CollisionUtils::testRayToPlane(m_rayStart, m_rayDir, vertices[cell[0]], n, iPt))
56 const Vec3d uvw = baryCentric(iPt, a, b, c);
57 if (uvw[0] >= 0.0 && uvw[1] >= 0.0 && uvw[2] >= 0.0)
59 resultSet.insert({ { i }, 1, IMSTK_TRIANGLE, iPt });
64 else if (
auto tetMeshToPick = std::dynamic_pointer_cast<TetrahedralMesh>(geomToPick))
67 static int faces[4][3] = { { 0, 1, 2 }, { 1, 2, 3 }, { 0, 2, 3 }, { 0, 1, 3 } };
69 std::shared_ptr<VecDataArray<double, 3>> verticesPtr = tetMeshToPick->getVertexPositions();
71 std::shared_ptr<VecDataArray<int, 4>> indicesPtr = tetMeshToPick->getCells();
75 for (
int i = 0; i < indices.size(); i++)
77 const Vec4i& tet = indices[i];
80 for (
int j = 0; j < 4; j++)
83 const Vec3d& a = vertices[tet[faces[j][0]]];
84 const Vec3d& b = vertices[tet[faces[j][1]]];
85 const Vec3d& c = vertices[tet[faces[j][2]]];
88 if (CollisionUtils::testRayToPlane(m_rayStart, m_rayDir, a,
89 (b - a).cross(c - a).normalized(), iPt))
91 const Vec3d uvw = baryCentric(iPt, a, b, c);
92 if (uvw[0] >= 0.0 && uvw[1] >= 0.0 && uvw[2] >= 0.0)
94 resultSet.insert({ { i }, 1, IMSTK_TETRAHEDRON, iPt });
100 else if (
auto lineMeshToPick = std::dynamic_pointer_cast<LineMesh>(geomToPick))
103 LOG(FATAL) <<
"LineMesh picking not implemented yet";
105 else if (
auto sphereToPick = std::dynamic_pointer_cast<Sphere>(geomToPick))
107 Vec3d iPt = Vec3d::Zero();
108 if (CollisionUtils::testRayToSphere(m_rayStart, m_rayDir,
109 sphereToPick->getPosition(), sphereToPick->getRadius(), iPt))
111 resultSet.insert({ { 0 }, 1, IMSTK_VERTEX, iPt });
115 else if (
auto planeToPick = std::dynamic_pointer_cast<Plane>(geomToPick))
117 Vec3d iPt = Vec3d::Zero();
118 if (CollisionUtils::testRayToPlane(m_rayStart, m_rayDir,
119 planeToPick->getPosition(), planeToPick->getNormal(), iPt))
121 resultSet.insert({ { 0 }, 1, IMSTK_VERTEX, iPt });
127 else if (
auto obbToPick = std::dynamic_pointer_cast<OrientedBox>(geomToPick))
129 Mat4d worldToBox = mat4dTranslate(obbToPick->getPosition()) *
130 mat4dRotation(obbToPick->getOrientation());
131 Vec2d t = Vec2d::Zero();
132 if (CollisionUtils::testRayToObb(m_rayStart, m_rayDir,
133 worldToBox.inverse(), obbToPick->getExtents(), t))
135 resultSet.insert({ { 0 }, 1, IMSTK_VERTEX, m_rayStart + m_rayDir * t[0] });
136 resultSet.insert({ { 1 }, 1, IMSTK_VERTEX, m_rayStart + m_rayDir * t[1] });
139 else if (
auto implicitGeom = std::dynamic_pointer_cast<ImplicitGeometry>(geomToPick))
147 implicitGeom->computeBoundingBox(min, max);
148 const Vec3d center = (min + max) * 0.5;
149 const Vec3d extents = (max - min) * 0.5;
150 const double size = extents.norm() * 2.0;
151 const double stepLength = size / 50.0;
153 const Mat4d boxTransform = mat4dTranslate(center);
154 Vec2d tPt = Vec2d::Zero();
155 if (CollisionUtils::testRayToObb(m_rayStart, m_rayDir, boxTransform.inverse(), extents, tPt))
158 Vec3d iPt = m_rayStart + m_rayDir * tPt[0];
161 double currDist = IMSTK_DOUBLE_MAX;
163 double prevDist = IMSTK_DOUBLE_MAX;
165 for (
int i = 0; i < 50; i++)
172 const double t =
static_cast<double>(i) / 50.0;
173 currPt = iPt + t * m_rayDir * stepLength;
174 currDist = implicitGeom->getFunctionValue(currPt);
177 if (std::signbit(currDist) != std::signbit(prevDist))
180 iPt = (currPt + prevPt) * 0.5;
181 resultSet.insert({ { 0 }, 1, IMSTK_VERTEX, iPt });
188 LOG(FATAL) <<
"Tried to point pick with an unsupported geometry " << geomToPick->getTypeName();
193 const double maxSqrDist = m_maxDist * m_maxDist;
194 const bool useMaxDist = (m_maxDist != -1.0);
198 double minSqrDist = useMaxDist ? maxSqrDist : IMSTK_DOUBLE_MAX;
200 bool resultsFound =
false;
201 for (
const auto& pickData : resultSet)
204 const double sqrDist = (pickData.pickPoint - m_rayStart).squaredNorm();
205 if (sqrDist <= minSqrDist)
209 minSqrDist = sqrDist;
216 m_results[0] = results;
221 m_results = std::vector<PickData>();
222 for (
auto pickData : resultSet)
224 const double sqrDist = (pickData.pickPoint - m_rayStart).squaredNorm();
225 if (!useMaxDist || sqrDist <= maxSqrDist)
227 m_results.push_back(pickData);
std::shared_ptr< Geometry > getInput(size_t port=0) const
Returns input geometry given port, returns nullptr if doesn't exist.
void requestUpdate() override
Users can implement this for the logic to be run.
Vec3d pickPoint
Some pickings may produce specific points on an element.
PickData provides ids to indicate what was picked These may be optionally used to indicate the select...