33 #include <visp3/ustk_needle_modeling/usNeedleInsertionModelVirtualSprings.h>
37 #include <visp3/ustk_core/usGeometryTools.h>
39 #include <visp3/core/vpConfig.h>
41 #ifdef VISP_HAVE_EIGEN3
42 #include <eigen3/Eigen/SparseCore>
43 #include <eigen3/Eigen/SparseLU>
46 #ifdef VISP_HAVE_OPENCV
47 #include <opencv2/core/core.hpp>
48 #include <opencv2/imgproc/imgproc.hpp>
51 #include <visp3/core/vpException.h>
52 #include <visp3/core/vpPoseVector.h>
53 #include <visp3/core/vpRotationMatrix.h>
54 #include <visp3/core/vpTime.h>
55 #include <visp3/core/vpTranslationVector.h>
56 #include <visp3/gui/vpDisplayX.h>
61 m_tipForce(0), m_tipMoment(0), m_cutAngle(0), m_bevelLength(0.001),
63 m_defaultSpringStiffness(100), m_stiffnessPerUnitLength(25000),
64 m_tissueSurface(vpColVector(3, 0), vpColVector(3, 0)),
66 m_interSpringDistance(0.005), m_interTipSpringDistance(0.0005),
68 m_IsStateConsistent(false),
70 m_LastSegmentLengthComputed(true),
72 m_insertionBehavior(
InsertionType::NaturalBehavior), m_IsInserting(false), m_AllowSpringAddition(true),
73 m_AllowSpringRemoval(true), m_AutomaticSpringAddition(true),
75 m_tipSpringsIndex(0), m_nbMinTipSprings(1), m_nbMaxTipSprings(10)
84 : m_needle(needle.m_needle),
86 m_tipForce(needle.m_tipForce), m_tipMoment(needle.m_tipMoment), m_cutAngle(needle.m_cutAngle),
87 m_bevelLength(needle.m_bevelLength),
89 m_defaultSpringStiffness(needle.m_defaultSpringStiffness),
90 m_stiffnessPerUnitLength(needle.m_stiffnessPerUnitLength),
92 m_springs(needle.m_springs), m_inactiveAutoAddedSprings(needle.m_inactiveAutoAddedSprings),
93 m_inactiveMeasureSprings(needle.m_inactiveMeasureSprings), m_tissueSurface(needle.m_tissueSurface),
94 m_interSpringDistance(needle.m_interSpringDistance), m_interTipSpringDistance(needle.m_interTipSpringDistance),
96 m_IsStateConsistent(needle.m_IsStateConsistent),
98 m_LastSegmentLengthComputed(needle.m_LastSegmentLengthComputed),
100 m_insertionBehavior(needle.m_insertionBehavior), m_IsInserting(needle.m_IsInserting),
101 m_AllowSpringAddition(needle.m_AllowSpringAddition), m_AllowSpringRemoval(needle.m_AllowSpringRemoval),
102 m_AutomaticSpringAddition(needle.m_AutomaticSpringAddition),
104 m_tipSpringsIndex(needle.m_tipSpringsIndex), m_nbMinTipSprings(needle.m_nbMinTipSprings),
105 m_nbMaxTipSprings(needle.m_nbMaxTipSprings)
288 for (
unsigned int i = 0; i <
m_springs.size(); i++)
289 if (!
m_springs.at(i).IsPositionUpdateAllowed())
434 throw vpException(vpException::dimensionError,
435 "usNeedleInsertionModelVirtualSprings::getPathDistanceFromPoint: invalid point dimension");
437 double min = std::numeric_limits<double>::infinity();
439 for (
unsigned int i = 0; i <
m_springs.size(); i++) {
441 double d = (
m_springs.at(i).getPosition() - p).frobeniusNorm();
453 for (
unsigned int n = 0; n <
m_springs.size(); n++) {
454 double K =
m_springs.at(n).getStiffness();
457 E += 0.5 * K * l * l;
481 double totalLength = 0;
483 for (
unsigned int i = 0; i <
m_springs.size(); i++) {
504 for (
unsigned int i = 0; i <
m_springs.size(); i++) {
510 mean += d * (l1 + l2) / 2;
512 if (L > std::numeric_limits<double>::epsilon())
523 vpColVector position(pose.getTranslationVector());
539 if (index < 0 || index > (
int)
m_springs.size() - 1)
540 throw vpException(vpException::badValue,
541 "usNeedleInsertionModelVirtualSprings::setSpringPosition: invlaid spring index");
544 throw vpException(vpException::dimensionError,
545 "usNeedleInsertionModelVirtualSprings::setSpringPosition: bad vector dimension");
556 if (index < 0 || index > (
int)
m_springs.size() - 1)
557 throw vpException(vpException::badValue,
558 "usNeedleInsertionModelVirtualSprings::setSpringDirection: invalid spring index");
560 throw vpException(vpException::dimensionError,
561 "usNeedleInsertionModelVirtualSprings::setSpringDirection: invalid vector dimension");
572 if (index < 0 || index > (
int)
m_springs.size() - 1)
573 throw vpException(vpException::badValue,
574 "usNeedleInsertionModelVirtualSprings::setSpringStiffness: bad spring index");
576 throw vpException(vpException::badValue,
577 "usNeedleInsertionModelVirtualSprings::setSpringStiffness: negative stiffness");
591 vpRotationMatrix R(thetaU);
613 throw vpException(vpException::badValue,
614 "usNeedleInsertionModelVirtualSprings::addInsertionPointOnSegment: invalid segment index");
618 vpException::badValue,
619 "usNeedleInsertionModelVirtualSprings::addInsertionPointOnSegment: invalid segment length parameter");
635 vpColVector bevelDirection(vpHomogeneousMatrix(
m_needle.
getTipPose()).getCol(1), 0, 3);
659 throw vpException(vpException::badValue,
660 "usNeedleInsertionModelVirtualSprings::addInsertionPointOnSegment: bad segment index");
663 throw vpException(vpException::badValue,
664 "usNeedleInsertionModelVirtualSprings::addInsertionPointOnSegment: bad segment length parameter");
667 double l2 = Lseg - s;
682 K =
m_springs.at(segment - 1).getStiffness() * (L - s / 2) / (L1 / 2 + L);
683 m_springs.at(segment - 1).addStiffness(-K);
691 vpColVector x0 =
m_springs.at(segment - 1).getPosition();
692 vpColVector x1 =
m_springs.at(segment).getPosition();
693 vpColVector d0 =
m_springs.at(segment - 1).getDirection();
694 vpColVector d1 =
m_springs.at(segment).getDirection();
696 vpColVector P = c * x1 + (1 - c) * x0;
697 vpColVector D = c * d1 + (1 - c) * d0;
700 if (segment - 1 == 0)
706 double K1 =
m_springs.at(segment - 1).getStiffness() * l2 / (L1 + L);
707 double K2 =
m_springs.at(segment).getStiffness() * s / (L + L2);
708 m_springs.at(segment - 1).addStiffness(-K1);
714 m_springs.at(segment).setStiffness(K1 + K2);
726 if (segment == 0 &&
m_springs.size() != 0)
727 throw vpException(vpException::badValue,
728 "usNeedleInsertionModelVirtualSprings::addInsertionPoint: cannot add spring on first segment");
730 throw vpException(vpException::badValue,
731 "usNeedleInsertionModelVirtualSprings::addInsertionPoint: spring does not cross the needle");
740 double l2 = Lseg - s;
755 K =
m_springs.at(segment - 1).getStiffness() * (L - s / 2) / (L1 / 2 + L);
756 m_springs.at(segment - 1).addStiffness(-K);
762 if (segment - 1 == 0)
768 double K1 =
m_springs.at(segment - 1).getStiffness() * l2 / (L1 + L);
769 double K2 =
m_springs.at(segment).getStiffness() * s / (L + L2);
770 m_springs.at(segment - 1).addStiffness(-K1);
783 if (p.size() != 3 || d.size() != 3)
784 throw vpException(vpException::dimensionError,
785 "usNeedleInsertionModelVirtualSprings::addInsertionPoint: invalid vector dimension");
787 unsigned int index = 0;
791 if (index == 0 &&
m_springs.size() != 0) {
792 std::cout <<
"Warning in usNeedleInsertionModelVirtualSprings::addInsertionPoint: add spring on first segment"
810 spg.
setDirection(vpColVector::crossProd(P - p, vpColVector::crossProd(d, P - p)).normalize());
816 spg.
setDirection(vpColVector::crossProd(P - p, vpColVector::crossProd(d, P - p)).normalize());
821 double l2 = Lseg - s;
838 double K =
m_springs.at(segment - 1).getStiffness() * (L - s / 2) / (L1 / 2 + L);
839 m_springs.at(segment - 1).addStiffness(-K);
845 if (segment - 1 == 0)
851 double K1 =
m_springs.at(segment - 1).getStiffness() * l2 / (L1 + L);
852 double K2 =
m_springs.at(segment).getStiffness() * s / (L + L2);
853 m_springs.at(segment - 1).addStiffness(-K1);
878 if (first < 0 || (last < first) || last >= (
int)
m_springs.size())
880 vpException::badValue,
881 "usNeedleInsertionModelVirtualSprings::removeInsertionPointHard: bad index, cannot remove spring");
887 for (
int i = first + 1; i <= last + 1; i++) {
904 if (first < 0 || (last < first) || last >= (
int)
m_springs.size())
905 throw vpException(vpException::badValue,
906 "usNeedleInsertionModelVirtualSprings::removeInsertionPoint: bad index, cannot remove spring");
907 if ((first == 0) && (last != ((
int)
m_springs.size() - 1)))
908 throw vpException(vpException::badValue,
"usNeedleInsertionModelVirtualSprings::removeInsertionPoint: cannot "
909 "remove first insertion point without removing all insertion points");
918 else if (first == 0) {
919 for (
int i = first; i <= last; i++) {
920 if (!
m_springs.at(i).IsPositionUpdateAllowed())
940 (L1 / 2 + L2) / (L1 / 2 + L + L2));
942 if (!
m_springs.back().IsPositionUpdateAllowed())
955 for (
int spg =
m_springs.size() - 1; spg > 0; spg--) {
956 if (
m_springs.at(spg).IsPositionUpdateAllowed())
964 int nbSprings = lastSpring - firstSpring + 1;
965 if (firstSpring < 0 || nbSprings < 3 || lastSpring >= (
int)
m_springs.size())
966 throw vpException(vpException::badValue,
967 "usNeedleInsertionModelVirtualSprings::fusionSprings: bad springs indexes");
969 if (nbSprings == 3) {
971 if (firstSpring == 0)
977 if (lastSpring == (
int)
m_springs.size() - 1)
980 double K0 =
m_springs.at(firstSpring).getStiffness();
981 double K1 =
m_springs.at(firstSpring + 1).getStiffness();
982 double K2 =
m_springs.at(lastSpring).getStiffness();
983 double w0 = K0 * l2 / (L1 + l);
984 double w2 = K2 * l / (l2 + L2);
986 m_springs.at(firstSpring).addStiffness(K1 * w0 / (w0 + w2));
987 m_springs.at(lastSpring).addStiffness(K1 * w2 / (w0 + w2));
989 if (!
m_springs.at(firstSpring + 1).IsPositionUpdateAllowed())
993 int middle = (firstSpring + lastSpring) / 2;
1001 for (
unsigned int i = 0; i <
m_springs.size(); i++) {
1017 vpColVector z =
m_springs.back().getDirection();
1022 vpColVector ztip(worldMtip.getCol(2), 0, 3);
1023 vpColVector xtip(worldMtip.getCol(0), 0, 3);
1025 ztip = (ztip - vpColVector::dotProd(ztip, xtip) * xtip).normalize();
1026 z = (z - vpColVector::dotProd(z, xtip) * xtip).normalize();
1028 double vect = vpColVector::crossProd(z, ztip).frobeniusNorm();
1029 double dot = vpColVector::dotProd(z, ztip);
1046 (a * a * tan(cut_rad) / 2 - b * b * cos(bevel_rad) * tan(bevel_rad - cut_rad) / 2);
1049 (-a * a * a * tan(cut_rad) / 6 +
1050 b * b * tan(bevel_rad - cut_rad) / 2 *
1057 if (!
m_springs.at(i).IsDirectionUpdateAllowed())
1063 if (!
m_springs.at(i).IsDirectionUpdateAllowed())
1071 #ifdef VISP_HAVE_EIGEN3
1084 typedef Eigen::Triplet<double> T;
1086 L.reserve(144 / 10 * nbSeg * nbSeg);
1088 Eigen::VectorXd a = Eigen::VectorXd::Zero(12 * nbSeg);
1089 Eigen::VectorXd b = Eigen::VectorXd::Zero(12 * nbSeg);
1100 for (
int n = 0; n < nbSeg - 1; n++) {
1103 for (
int dim = 0; dim < 3; dim++) {
1105 col = 12 * n + 4 * dim;
1106 L.push_back(T(line, col, 1));
1107 L.push_back(T(line, col + 1, s));
1108 L.push_back(T(line, col + 2, s * s));
1109 L.push_back(T(line, col + 3, s * s * s));
1111 col = 12 * (n + 1) + 4 * dim;
1112 L.push_back(T(line, col, -1));
1117 col = 12 * n + 4 * dim;
1119 L.push_back(T(line, col + 1, 1));
1120 L.push_back(T(line, col + 2, 2 * s));
1121 L.push_back(T(line, col + 3, 3 * s * s));
1123 col = 12 * (n + 1) + 4 * dim;
1124 L.push_back(T(line, col + 1, -1));
1129 col = 12 * n + 4 * dim;
1131 L.push_back(T(line, col + 2, 2));
1132 L.push_back(T(line, col + 3, 6 * s));
1134 col = 12 * (n + 1) + 4 * dim;
1135 L.push_back(T(line, col + 2, -2));
1141 vpColVector tipForceVector(3, 0);
1142 vpColVector tipMomentVector(3, 0);
1145 vpColVector xtip(3);
1146 xtip[0] = worldMtip[0][0];
1147 xtip[1] = worldMtip[1][0];
1148 xtip[2] = worldMtip[2][0];
1150 vpColVector z =
m_springs.back().getDirection();
1151 vpColVector y = vpColVector::crossProd(z, xtip);
1153 tipForceVector = -y;
1154 tipMomentVector = -y;
1160 for (
int dim = 0; dim < 3; dim++) {
1164 L.push_back(T(line, col, 1));
1165 b(line) = basePose[dim];
1168 L.push_back(T(line, col + 1, 1));
1169 b(line) = worldMbase[dim][2];
1173 col = 12 * (nbSeg - 1) + 4 * dim;
1175 L.push_back(T(line, col + 3, 6 * EI));
1176 b(line) = -tipForceVector[dim];
1181 L.push_back(T(line, col + 2, 2 * EI));
1182 b(line) = -tipMomentVector[dim];
1187 for (
int n = 0; n < nbSeg - 1; n++) {
1189 double px_n =
m_springs.at(n).getPosition()[0];
1190 double py_n =
m_springs.at(n).getPosition()[1];
1191 double pz_n =
m_springs.at(n).getPosition()[2];
1192 double dx_n =
m_springs.at(n).getDirection()[0];
1193 double dy_n =
m_springs.at(n).getDirection()[1];
1194 double dz_n =
m_springs.at(n).getDirection()[2];
1197 vpColVector n1m_n(3);
1198 if ((fabs(dx_n) > std::numeric_limits<double>::epsilon()) ||
1199 (fabs(dy_n) > std::numeric_limits<double>::epsilon())) {
1204 n1m_n = vpColVector::crossProd(
m_springs.at(n).getDirection(), z);
1210 n1m_n = vpColVector::crossProd(
m_springs.at(n).getDirection(), y);
1214 double n1x_n = n1m_n[0];
1215 double n1y_n = n1m_n[1];
1216 double n1z_n = n1m_n[2];
1218 vpColVector n2m_n = vpColVector::cross(
m_springs.at(n).getDirection(), n1m_n);
1221 double n2x_n = n2m_n[0];
1222 double n2y_n = n2m_n[1];
1223 double n2z_n = n2m_n[2];
1227 L.push_back(T(line, col + 3, 6 * EI * n1x_n));
1228 L.push_back(T(line, col + 3 + 4, 6 * EI * n1y_n));
1229 L.push_back(T(line, col + 3 + 8, 6 * EI * n1z_n));
1230 L.push_back(T(line + 1, col + 3, 6 * EI * n2x_n));
1231 L.push_back(T(line + 1, col + 3 + 4, 6 * EI * n2y_n));
1232 L.push_back(T(line + 1, col + 3 + 8, 6 * EI * n2z_n));
1233 for (
int i = 0; i < nbSeg - 1 - n; i++) {
1234 double K =
m_springs.at(n + i).getStiffness();
1235 vpColVector p =
m_springs.at(n + i).getPosition();
1236 double dot1 = vpColVector::dotProd(p, n1m_n);
1237 L.push_back(T(line, col + 12 * (i + 1), -K * n1x_n));
1238 L.push_back(T(line, col + 12 * (i + 1) + 4, -K * n1y_n));
1239 L.push_back(T(line, col + 12 * (i + 1) + 8, -K * n1z_n));
1240 b(line) += -K * dot1;
1242 double dot2 = vpColVector::dotProd(p, n2m_n);
1243 L.push_back(T(line + 1, col + 12 * (i + 1), -K * n2x_n));
1244 L.push_back(T(line + 1, col + 12 * (i + 1) + 4, -K * n2y_n));
1245 L.push_back(T(line + 1, col + 12 * (i + 1) + 8, -K * n2z_n));
1246 b(line + 1) += -K * dot2;
1248 b(line) += -vpColVector::dotProd(tipForceVector, n1m_n);
1249 b(line + 1) += -vpColVector::dotProd(tipForceVector, n2m_n);
1255 double dotProd = dx_n * px_n + dy_n * py_n + dz_n * pz_n;
1257 L.push_back(T(line, col, dx_n));
1258 L.push_back(T(line, col + 4, dy_n));
1259 L.push_back(T(line, col + 8, dz_n));
1264 Eigen::SparseMatrix<double> M(12 * nbSeg, 12 * nbSeg);
1265 M.setFromTriplets(L.begin(), L.end());
1267 Eigen::SparseLU<Eigen::SparseMatrix<double> > solver;
1270 a = solver.solve(b);
1273 vpMatrix coef(3, 4);
1274 for (
int n = 0; n < nbSeg; n++) {
1276 for (
int dim = 0; dim < 3; dim++) {
1277 int seg = 12 * n + 4 * dim;
1278 coef[dim][0] = a(seg);
1279 coef[dim][1] = a(seg + 1);
1280 coef[dim][2] = a(seg + 2);
1281 coef[dim][3] = a(seg + 3);
1288 vpRotationMatrix worldRbase(worldMbase);
1290 vpRotationMatrix worldRtip(worldRbase);
1297 double theta = atan2(vect.frobeniusNorm(), dot);
1299 vect = theta * vect;
1300 vpThetaUVector thetaU(vect[0], vect[1], vect[2]);
1301 vpRotationMatrix Ri(thetaU);
1302 worldRtip = Ri * worldRtip;
1306 vpTranslationVector translation(t[0], t[1], t[2]);
1308 vpPoseVector tipPose(translation, worldRtip);
1313 vpException::functionNotImplementedError,
1314 "usNeedleInsertionModelVirtualSprings::solveSegmentsParametersSparseEigen: not implemented without Eigen3");
1320 #ifdef VISP_HAVE_OPENCV
1333 cv::Mat M = cv::Mat::zeros(12 * nbSeg, 12 * nbSeg, CV_64F);
1334 cv::Mat b = cv::Mat::zeros(12 * nbSeg, 1, CV_64F);
1335 cv::Mat a = cv::Mat::zeros(12 * nbSeg, 1, CV_64F);
1346 for (
int n = 0; n < nbSeg - 1; n++) {
1349 for (
int dim = 0; dim < 3; dim++) {
1351 col = 12 * n + 4 * dim;
1352 M.at<
double>(line, col) = 1;
1353 M.at<
double>(line, col + 1) = s;
1354 M.at<
double>(line, col + 2) = s * s;
1355 M.at<
double>(line, col + 3) = s * s * s;
1357 col = 12 * (n + 1) + 4 * dim;
1358 M.at<
double>(line, col) = -1;
1359 M.at<
double>(line, col + 1) = 0;
1360 M.at<
double>(line, col + 2) = 0;
1361 M.at<
double>(line, col + 3) = 0;
1366 col = 12 * n + 4 * dim;
1368 M.at<
double>(line, col) = 0;
1369 M.at<
double>(line, col + 1) = 1;
1370 M.at<
double>(line, col + 2) = 2 * s;
1371 M.at<
double>(line, col + 3) = 3 * s * s;
1373 col = 12 * (n + 1) + 4 * dim;
1374 M.at<
double>(line, col) = 0;
1375 M.at<
double>(line, col + 1) = -1;
1376 M.at<
double>(line, col + 2) = 0;
1377 M.at<
double>(line, col + 3) = 0;
1382 col = 12 * n + 4 * dim;
1384 M.at<
double>(line, col) = 0;
1385 M.at<
double>(line, col + 1) = 0;
1386 M.at<
double>(line, col + 2) = 2;
1387 M.at<
double>(line, col + 3) = 6 * s;
1389 col = 12 * (n + 1) + 4 * dim;
1390 M.at<
double>(line, col) = 0;
1391 M.at<
double>(line, col + 1) = 0;
1392 M.at<
double>(line, col + 2) = -2;
1393 M.at<
double>(line, col + 3) = 0;
1399 vpColVector tipForceVector(3, 0);
1400 vpColVector tipMomentVector(3, 0);
1403 vpColVector xtip(3);
1404 xtip[0] = worldMtip[0][0];
1405 xtip[1] = worldMtip[1][0];
1406 xtip[2] = worldMtip[2][0];
1408 vpColVector z =
m_springs.back().getDirection();
1409 vpColVector y = vpColVector::crossProd(z, xtip);
1411 tipForceVector = -y;
1412 tipMomentVector = -y;
1418 for (
int dim = 0; dim < 3; dim++) {
1422 M.at<
double>(line, col) = 1;
1423 b.at<
double>(line, 0) = basePose[dim];
1426 M.at<
double>(line, col + 1) = 1;
1427 b.at<
double>(line, 0) = worldMbase[dim][2];
1431 col = 12 * (nbSeg - 1) + 4 * dim;
1433 M.at<
double>(line, col + 3) = 6 * EI;
1434 b.at<
double>(line, 0) = -tipForceVector[dim];
1439 M.at<
double>(line, col + 2) = 2;
1440 b.at<
double>(line) = -tipMomentVector[dim];
1445 for (
int n = 0; n < nbSeg - 1; n++) {
1447 double px_n =
m_springs.at(n).getPosition()[0];
1448 double py_n =
m_springs.at(n).getPosition()[1];
1449 double pz_n =
m_springs.at(n).getPosition()[2];
1450 double dx_n =
m_springs.at(n).getDirection()[0];
1451 double dy_n =
m_springs.at(n).getDirection()[1];
1452 double dz_n =
m_springs.at(n).getDirection()[2];
1455 vpColVector n1m_n(3);
1456 if ((fabs(dx_n) > std::numeric_limits<double>::epsilon()) ||
1457 (fabs(dy_n) > std::numeric_limits<double>::epsilon())) {
1462 n1m_n = vpColVector::crossProd(
m_springs.at(n).getDirection(), z);
1468 n1m_n = vpColVector::crossProd(
m_springs.at(n).getDirection(), y);
1472 double n1x_n = n1m_n[0];
1473 double n1y_n = n1m_n[1];
1474 double n1z_n = n1m_n[2];
1476 vpColVector n2m_n = vpColVector::cross(
m_springs.at(n).getDirection(), n1m_n);
1479 double n2x_n = n2m_n[0];
1480 double n2y_n = n2m_n[1];
1481 double n2z_n = n2m_n[2];
1485 M.at<
double>(line, col + 3) = 6 * EI * n1x_n;
1486 M.at<
double>(line, col + 3 + 4) = 6 * EI * n1y_n;
1487 M.at<
double>(line, col + 3 + 8) = 6 * EI * n1z_n;
1488 M.at<
double>(line + 1, col + 3) = 6 * EI * n2x_n;
1489 M.at<
double>(line + 1, col + 3 + 4) = 6 * EI * n2y_n;
1490 M.at<
double>(line + 1, col + 3 + 8) = 6 * EI * n2z_n;
1491 for (
int i = 0; i < nbSeg - 1 - n; i++) {
1492 double K =
m_springs.at(n + i).getStiffness();
1493 vpColVector p =
m_springs.at(n + i).getPosition();
1495 M.at<
double>(line, col + 12 * (i + 1)) = -K * n1x_n;
1496 M.at<
double>(line, col + 12 * (i + 1) + 4) = -K * n1y_n;
1497 M.at<
double>(line, col + 12 * (i + 1) + 8) = -K * n1z_n;
1498 b.at<
double>(line, 0) += -K * (p[0] * n1x_n + p[1] * n1y_n + p[2] * n1z_n);
1500 M.at<
double>(line + 1, col + 12 * (i + 1)) = -K * n2x_n;
1501 M.at<
double>(line + 1, col + 12 * (i + 1) + 4) = -K * n2y_n;
1502 M.at<
double>(line + 1, col + 12 * (i + 1) + 8) = -K * n2z_n;
1503 b.at<
double>(line + 1, 0) += -K * (p[0] * n2x_n + p[1] * n2y_n + p[2] * n2z_n);
1505 b.at<
double>(line, 0) += -vpColVector::dotProd(tipForceVector, n1m_n);
1506 b.at<
double>(line + 1, 0) += -vpColVector::dotProd(tipForceVector, n2m_n);
1511 double dotProd = dx_n * px_n + dy_n * py_n + dz_n * pz_n;
1513 M.at<
double>(line, col) = dx_n;
1514 M.at<
double>(line, col + 4) = dy_n;
1515 M.at<
double>(line, col + 8) = dz_n;
1516 b.at<
double>(line, 0) = dotProd;
1525 vpMatrix coef(3, 4);
1526 for (
int n = 0; n < nbSeg; n++) {
1528 for (
int dim = 0; dim < 3; dim++) {
1529 int seg = 12 * n + 4 * dim;
1530 coef[dim][0] = a.at<
double>(seg);
1531 coef[dim][1] = a.at<
double>(seg + 1);
1532 coef[dim][2] = a.at<
double>(seg + 2);
1533 coef[dim][3] = a.at<
double>(seg + 3);
1540 vpRotationMatrix worldRbase(worldMbase);
1542 vpRotationMatrix worldRtip(worldRbase);
1549 double theta = atan2(vect.frobeniusNorm(), dot);
1551 vect = theta * vect;
1552 vpThetaUVector thetaU(vect[0], vect[1], vect[2]);
1553 vpRotationMatrix Ri(thetaU);
1554 worldRtip = Ri * worldRtip;
1558 vpTranslationVector translation(t[0], t[1], t[2]);
1560 vpPoseVector tipPose(translation, worldRtip);
1565 vpException::functionNotImplementedError,
1566 "usNeedleInsertionModelVirtualSprings::solveSegmentsParametersOpenCV: not implemented without OpenCV");
1583 vpMatrix M(12 * nbSeg, 12 * nbSeg, 0);
1584 vpColVector a(12 * nbSeg, 0);
1585 vpColVector b(12 * nbSeg, 0);
1596 for (
int n = 0; n < nbSeg - 1; n++) {
1599 for (
int dim = 0; dim < 3; dim++) {
1601 col = 12 * n + 4 * dim;
1603 M[line][col + 1] = s;
1604 M[line][col + 2] = s * s;
1605 M[line][col + 3] = s * s * s;
1607 col = 12 * (n + 1) + 4 * dim;
1609 M[line][col + 1] = 0;
1610 M[line][col + 2] = 0;
1611 M[line][col + 3] = 0;
1616 col = 12 * n + 4 * dim;
1619 M[line][col + 1] = 1;
1620 M[line][col + 2] = 2 * s;
1621 M[line][col + 3] = 3 * s * s;
1623 col = 12 * (n + 1) + 4 * dim;
1625 M[line][col + 1] = -1;
1626 M[line][col + 2] = 0;
1627 M[line][col + 3] = 0;
1632 col = 12 * n + 4 * dim;
1635 M[line][col + 1] = 0;
1636 M[line][col + 2] = 2;
1637 M[line][col + 3] = 6 * s;
1639 col = 12 * (n + 1) + 4 * dim;
1641 M[line][col + 1] = 0;
1642 M[line][col + 2] = -2;
1643 M[line][col + 3] = 0;
1649 vpColVector tipForceVector(3, 0);
1650 vpColVector tipMomentVector(3, 0);
1653 vpColVector xtip(3);
1654 xtip[0] = worldMtip[0][0];
1655 xtip[1] = worldMtip[1][0];
1656 xtip[2] = worldMtip[2][0];
1658 vpColVector z =
m_springs.back().getDirection();
1659 vpColVector y = vpColVector::crossProd(z, xtip);
1661 tipForceVector = -y;
1662 tipMomentVector = -y;
1668 for (
int dim = 0; dim < 3; dim++) {
1673 b[line] = basePose[dim];
1676 M[line][col + 1] = 1;
1677 b[line] = worldMbase[dim][2];
1681 col = 12 * (nbSeg - 1) + 4 * dim;
1683 M[line][col + 3] = 6 * EI;
1684 b[line] = -tipForceVector[dim];
1689 M[line][col + 2] = 2 * EI;
1690 b[line] = -tipMomentVector[dim];
1695 for (
int n = 0; n < nbSeg - 1; n++) {
1697 double px_n =
m_springs.at(n).getPosition()[0];
1698 double py_n =
m_springs.at(n).getPosition()[1];
1699 double pz_n =
m_springs.at(n).getPosition()[2];
1700 double dx_n =
m_springs.at(n).getDirection()[0];
1701 double dy_n =
m_springs.at(n).getDirection()[1];
1702 double dz_n =
m_springs.at(n).getDirection()[2];
1705 vpColVector n1m_n(3);
1706 if ((fabs(dx_n) > std::numeric_limits<double>::epsilon()) ||
1707 (fabs(dy_n) > std::numeric_limits<double>::epsilon())) {
1712 n1m_n = vpColVector::crossProd(
m_springs.at(n).getDirection(), z);
1718 n1m_n = vpColVector::crossProd(
m_springs.at(n).getDirection(), y);
1722 double n1x_n = n1m_n[0];
1723 double n1y_n = n1m_n[1];
1724 double n1z_n = n1m_n[2];
1726 vpColVector n2m_n = vpColVector::cross(
m_springs.at(n).getDirection(), n1m_n);
1729 double n2x_n = n2m_n[0];
1730 double n2y_n = n2m_n[1];
1731 double n2z_n = n2m_n[2];
1735 M[line][col + 3] = 6 * EI * n1x_n;
1736 M[line][col + 3 + 4] = 6 * EI * n1y_n;
1737 M[line][col + 3 + 8] = 6 * EI * n1z_n;
1738 M[line + 1][col + 3] = 6 * EI * n2x_n;
1739 M[line + 1][col + 3 + 4] = 6 * EI * n2y_n;
1740 M[line + 1][col + 3 + 8] = 6 * EI * n2z_n;
1741 for (
int i = 0; i < nbSeg - 1 - n; i++) {
1742 double K =
m_springs.at(n + i).getStiffness();
1743 vpColVector p =
m_springs.at(n + i).getPosition();
1744 double dot1 = vpColVector::dotProd(p, n1m_n);
1745 M[line][col + 12 * (i + 1)] = -K * n1x_n;
1746 M[line][col + 12 * (i + 1) + 4] = -K * n1y_n;
1747 M[line][col + 12 * (i + 1) + 8] = -K * n1z_n;
1748 b[line] += -K * dot1;
1750 double dot2 = vpColVector::dotProd(p, n2m_n);
1751 M[line + 1][col + 12 * (i + 1)] = -K * n2x_n;
1752 M[line + 1][col + 12 * (i + 1) + 4] = -K * n2y_n;
1753 M[line + 1][col + 12 * (i + 1) + 8] = -K * n2z_n;
1754 b[line + 1] += -K * dot2;
1756 b[line] += -vpColVector::dotProd(tipForceVector, n1m_n);
1757 b[line + 1] += -vpColVector::dotProd(tipForceVector, n2m_n);
1763 double dotProd = dx_n * px_n + dy_n * py_n + dz_n * pz_n;
1765 M[line][col] = dx_n;
1766 M[line][col + 4] = dy_n;
1767 M[line][col + 8] = dz_n;
1774 vpMatrix Minv = M.inverseByLU();
1778 vpMatrix coef(3, 4);
1779 for (
int n = 0; n < nbSeg; n++) {
1781 for (
int dim = 0; dim < 3; dim++) {
1782 int seg = 12 * n + 4 * dim;
1783 coef[dim][0] = a[seg];
1784 coef[dim][1] = a[seg + 1];
1785 coef[dim][2] = a[seg + 2];
1786 coef[dim][3] = a[seg + 3];
1793 vpRotationMatrix worldRbase(worldMbase);
1795 vpRotationMatrix worldRtip(worldRbase);
1802 double theta = atan2(vect.frobeniusNorm(), dot);
1804 vect = theta * vect;
1805 vpThetaUVector thetaU(vect[0], vect[1], vect[2]);
1806 vpRotationMatrix Ri(thetaU);
1807 worldRtip = Ri * worldRtip;
1811 vpTranslationVector translation(t[0], t[1], t[2]);
1813 vpPoseVector tipPose(translation, worldRtip);
1819 #if defined(VISP_HAVE_EIGEN3)
1821 #elif defined(VISP_HAVE_OPENCV)
1875 int nbTipSprings = 0;
1890 if (segment - 1 > 0) {
1891 double lastSegmentLength =
1893 int lastValidSpringIndex = segment - 2;
1899 lastValidSpringIndex++;
1912 lastValidSpringIndex++;
1980 std::vector<int> activated;
1985 activated.push_back(spg);
1990 for (
int i = activated.size() - 1; i >= 0; i--) {
1997 return (activated.size() != 0);
2002 if (p.size() != 3 || d.size() != 3)
2003 throw vpException(vpException::dimensionError,
2004 "usNeedleInsertionModelVirtualSprings::addMeasureSpring: invalid vector dimension");
2009 <<
"Warning in usNeedleInsertionModelVirtualSprings::addMeasureSpring: cannot add spring outside of tissue"
2028 bool needRecomputation =
false;
2058 while (i < 10 && needRecomputation) {
2077 if (needRecomputation) {
2081 while (i < 300 && needRecomputation) {
2105 std::cout <<
"Needle " <<
this <<
": " <<
m_springs.size() <<
" InsertionPoints: \n";
2106 for (
unsigned int i = 0; i <
m_springs.size(); i++) {
2107 std::cout <<
"\t Direction " << i <<
":\n";
2108 vpColVector d =
m_springs.at(i).getPosition();
2109 for (
int j = 0; j < 3; j++) {
2110 std::cout <<
"\t\t " << d[j] <<
"\n";
2113 std::cout << std::endl;
2118 std::cout <<
"Needle " <<
this <<
": " <<
m_springs.size() <<
" InsertionDirections: \n";
2119 for (
unsigned int i = 0; i <
m_springs.size(); i++) {
2120 std::cout <<
"\t Direction " << i <<
":\n";
2121 vpColVector d =
m_springs.at(i).getDirection();
2122 for (
int j = 0; j < 3; j++) {
2123 std::cout <<
"\t\t " << d[j] <<
"\n";
2126 std::cout << std::endl;
2131 std::cout <<
"Needle " <<
this <<
": " <<
m_springs.size() <<
" Springs: \n";
2132 for (
unsigned int i = 0; i <
m_springs.size(); i++) {
2133 std::cout <<
"\t Stiffness " << i <<
": " <<
m_springs.at(i).getStiffness() <<
"\n";
2135 std::cout << std::endl;
2140 s <<
"usNeedleInsertionModelVirtualSprings\n";
2153 for (
int i = 0; i < n; i++)
2157 for (
int i = 0; i < n; i++)
2161 for (
int i = 0; i < n; i++)
2190 if (c !=
"usNeedleInsertionModelVirtualSprings") {
2191 vpException e(vpException::ioError,
"operator>>=(std::istream&, usNeedleInsertionModelVirtualSprings&): Stream "
2192 "does not contain usNeedleInsertionModelVirtualSprings data");
2208 for (
int i = 0; i < n; i++)
2213 for (
int i = 0; i < n; i++)
2218 for (
int i = 0; i < n; i++)
2246 s.write(
"usNeedleInsertionModelVirtualSprings", 37);
2248 s.write((
char *)&(needle.
m_tipForce),
sizeof(
double));
2249 s.write((
char *)&(needle.
m_tipMoment),
sizeof(
double));
2250 s.write((
char *)&(needle.
m_cutAngle),
sizeof(
double));
2256 s.write((
char *)&n,
sizeof(
int));
2257 for (
int i = 0; i < n; i++)
2260 s.write((
char *)&n,
sizeof(
int));
2261 for (
int i = 0; i < n; i++)
2264 s.write((
char *)&n,
sizeof(
int));
2265 for (
int i = 0; i < n; i++)
2294 if (strcmp(c,
"usNeedleInsertionModelVirtualSprings")) {
2295 vpException e(vpException::ioError,
"operator>>=(std::istream&, usNeedleInsertionModelVirtualSprings&): Stream "
2296 "does not contain usNeedleInsertionModelVirtualSprings data");
2300 s.read((
char *)&(needle.
m_tipForce),
sizeof(
double));
2301 s.read((
char *)&(needle.
m_tipMoment),
sizeof(
double));
2302 s.read((
char *)&(needle.
m_cutAngle),
sizeof(
double));
2308 s.read((
char *)&n,
sizeof(
int));
2311 for (
int i = 0; i < n; i++)
2313 s.read((
char *)&n,
sizeof(
int));
2316 for (
int i = 0; i < n; i++)
2318 s.read((
char *)&n,
sizeof(
int));
2321 for (
int i = 0; i < n; i++)
2333 s.read((
char *)&b,
sizeof(
int));
void insertSegment(int i, const usPolynomialCurve3D &seg)
void removeSegments(int i, int j)
const usPolynomialCurve3D & accessSegment(int i) const
int getNbSegments() const
Parameters setters and getters.
const usPolynomialCurve3D & accessLastSegment() const
void setNbMinTipSprings(int nb)
void setSpringStiffness(int index, double K, bool update=false)
virtual ~usNeedleInsertionModelVirtualSprings()
InsertionType m_insertionBehavior
Insertion type.
std::vector< usVirtualSpring > m_inactiveMeasureSprings
double m_interTipSpringDistance
void solveSegmentsParametersOpenCV()
void setNbMaxTipSprings(int nb)
void showStiffnesses() const
double getInterSpringDistance() const
virtual bool setBasePose(const vpPoseVector &pose)=0
Control of the needle.
bool moveSpringDirection(int index, const vpThetaUVector &thetaU, bool update=false)
virtual usNeedleInsertionModelVirtualSprings * clone() const
double getNeedleFreeLength() const
bool m_IsStateConsistent
Internal.
usOrientedPlane3D m_tissueSurface
void addInsertionPointAtTipHard()
int addInsertionPoint(usVirtualSpring spg)
Internal model command.
void addMeasureSpring(const vpColVector &p, const vpColVector &d)
Control of the tissue.
void updateSpringsStiffness()
void removeAutoAddedSprings()
bool m_AutomaticSpringAddition
void AllowSpringAddition(bool flag)
Internal.
void setInterSpringDistance(double interSpringDistance)
bool checkInactiveMeasureSprings()
double getDefaultSpringStiffness() const
std::vector< usVirtualSpring > m_inactiveAutoAddedSprings
double getInsertionDepth() const
double m_defaultSpringStiffness
Tissue parameters.
void setDefaultSpringStiffness(double K)
Tissue parameters.
int getNbMaxTipSprings() const
bool setSpringPosition(int index, const vpColVector &P, bool update=false)
const usVirtualSpring & accessSpring(int i) const
bool m_LastSegmentLengthComputed
Segments lengths measurement.
void solveSegmentsParametersViSP()
double getTissueDeformationEnergy() const
Tissue deformation energy.
void fusionSprings(int firstSpring, int lastSpring)
double getBevelAngle() const
InsertionType getInsertionBehavior() const
double getSurfaceTissueStretch() const
void computeSegmentsLengths()
void removeInsertionPointsHard(int first, int last=-1)
void removeLastInsertionPointHard()
int getNbMinTipSprings() const
double getStiffnessPerUnitLength() const
void AllowSpringRemoval(bool flag)
const usOrientedPlane3D & accessSurface() const
Tissue.
double getPathDistanceFromPoint(const vpColVector &P) const
Measure model information.
void addInsertionPointOnSegment(int segment, double s)
void updateInsertionDirections()
void loadPreset(const ModelPreset preset)
Parameters saving and loading.
int getNbMeasureSprings() const
void setStiffnessPerUnitLength(double K)
void addSpringStiffness(int index, double dK, bool update=false)
void setInsertionBehavior(InsertionType type)
void addInsertionPointOnSegmentHard(int segment, double s)
vpPoseVector getBasePose() const
void removeInsertionPoints(int first, int last=-1)
bool IsNeedleInserted() const
const usNeedleModelSpline & accessNeedle() const
Model parameters.
bool m_AllowSpringAddition
bool setSpringDirection(int index, const vpColVector &D, bool update=false)
bool m_AllowSpringRemoval
void showInsertionPoints() const
Display.
void addInsertionPointAtTip()
void solveSegmentsParameters()
double m_interSpringDistance
void setTipForce(double tipForce)
Parameters setters and getters.
vpColVector getNeedleInsertionPoint() const
double getMaxTissueStretch(double *lmax=nullptr) const
void setBevelAngle(double angle)
const usNeedleInsertionModelVirtualSprings & operator=(const usNeedleInsertionModelVirtualSprings &needle)
usNeedleInsertionModelVirtualSprings()
Constructors, destructor.
int m_tipSpringsIndex
Tip springs.
std::vector< usVirtualSpring > m_springs
Model Parameters.
vpColVector getTissueInsertionPoint() const
double getMeanTissueStretch() const
usNeedleModelSpline m_needle
Needle parameters.
void removeLastInsertionPoint()
void solveSegmentsParametersSparseEigen()
bool moveSpringPosition(int index, const vpColVector &dP, bool update=false)
bool getAutomaticSpringAddition() const
void setAutomaticSpringAddition(bool flag)
void setInterTipSpringDistance(double interTipSpringDistance)
double getInterTipSpringDistance() const
double m_stiffnessPerUnitLength
void showInsertionDirections() const
vpPoseVector getBasePose() const
Parameters setters and getters.
void setBasePose(double tx, double ty, double tz, double thetax, double thetay, double thetaz)
Command of the needle.
vpColVector getTipPosition() const
vpHomogeneousMatrix getWorldMtip() const
vpHomogeneousMatrix getWorldMbase() const
vpPoseVector getTipPose() const
void setTipPose(double tx, double ty, double tz, double thetax, double thetay, double thetaz)
double getFullLength() const
double getOuterDiameter() const
void loadPreset(const NeedlePreset preset)
Parameters saving and loading.
vpColVector getDirection() const
void setDirection(const vpColVector &D)
void setPosition(const vpColVector &P)
vpColVector getStartTangent() const
usPolynomialCurve3D getSubPolynomialCurve(double startParameter, double endParameter) const
double getLength(int nbCountSeg=50) const
vpColVector getPoint(double parameter) const
void setParametricLength(double length)
void setPolynomialCoefficients(const vpMatrix &polynomialCoefficients)
vpColVector getEndPoint() const
vpColVector getEndTangent() const
double getParametricLength() const
void changeCoefficientsToFitBoundaries(double startParameter, double endParameter)
vpColVector getStartPoint() const
void AllowDirectionUpdate(bool flag)
void AllowStiffnessUpdate(bool flag)
void AllowPositionUpdate(bool flag)
void setStiffness(double K)
Parameters setters and getters.