33 #include <visp3/ustk_core/usBSpline3D.h>
37 #include <visp3/core/vpConfig.h>
38 #ifdef VISP_HAVE_EIGEN3
39 #include <eigen3/Eigen/SparseCore>
40 #include <eigen3/Eigen/SparseLU>
43 #include <visp3/core/vpException.h>
64 for (
unsigned int i = 0; i <
m_spline.size(); i++) {
65 l +=
m_spline.at(i).getParametricLength();
73 for (
unsigned int i = 0; i <
m_spline.size(); i++) {
74 l +=
m_spline.at(i).getLength(nbSubSeg);
103 if (points.size() < 2)
104 throw vpException(vpException::dimensionError,
105 "usBSpline3D::defineFromPoints: should have at least two points to define the curve");
107 throw vpException(vpException::dimensionError,
"usBSpline3D::defineFromPoints: order should be greater than zero");
109 unsigned int nbSeg = points.size() - 1;
111 if (lengths.size() != nbSeg)
112 throw vpException(vpException::dimensionError,
113 "usBSpline3D::defineFromPoints: mismathcing number of segments and points");
115 #ifdef VISP_HAVE_EIGEN3
117 int nbSegCoef = order + 1;
118 int nbCoef = nbSegCoef * nbSeg;
120 typedef Eigen::Triplet<double> T;
123 int nbHardConstraints = (nbSeg + 1) + (nbSeg - 1);
125 nbHardConstraints += (nbSeg - 1);
127 nbHardConstraints += (nbSeg - 1);
129 L.reserve((nbHardConstraints + nbCoef) * (nbHardConstraints + nbCoef) / 10);
131 Eigen::MatrixX3d A = Eigen::MatrixX3d::Zero(nbHardConstraints + nbCoef, 3);
132 Eigen::MatrixX3d B = Eigen::MatrixX3d::Zero(nbHardConstraints + nbCoef, 3);
141 for (
unsigned int i = 0; i < nbSeg; i++) {
142 L.push_back(T(line, startIndex, 1));
143 L.push_back(T(startIndex, line, -1));
144 for (
int dim = 0; dim < 3; dim++)
145 B(line, dim) = points.at(i)[dim];
148 double segLength = lengths.at(i);
149 double *tmp =
new double[nbSegCoef];
152 for (
int j = 1; j < nbSegCoef; j++)
153 tmp[j] = segLength * tmp[j - 1];
155 for (
int j = 0; j < nbSegCoef; j++) {
156 L.push_back(T(line, startIndex + j, tmp[j]));
157 L.push_back(T(startIndex + j, line, -tmp[j]));
159 for (
int dim = 0; dim < 3; dim++)
160 B(line, dim) = points.at(i + 1)[dim];
164 startIndex += nbSegCoef;
170 for (
unsigned int i = 0; i < nbSeg - 1; i++) {
171 double segLength = lengths.at(i);
172 double *tmp =
new double[nbSegCoef];
178 for (
int j = 2; j < nbSegCoef; j++)
179 tmp[j] = segLength * tmp[j - 1];
180 for (
int j = 1; j < nbSegCoef; j++)
183 for (
int j = 1; j < nbSegCoef; j++) {
184 L.push_back(T(line, startIndex + j, tmp[j]));
185 L.push_back(T(startIndex + j, line, -tmp[j]));
187 L.push_back(T(line, startIndex + nbSegCoef + 1, -1));
188 L.push_back(T(startIndex + nbSegCoef + 1, line, 1));
196 for (
int j = 3; j < nbSegCoef; j++)
197 tmp[j] = segLength * tmp[j - 1];
198 for (
int j = 2; j < nbSegCoef; j++)
199 tmp[j] *= j * (j - 1);
201 for (
int j = 2; j < nbSegCoef; j++) {
202 L.push_back(T(line, startIndex + j, tmp[j]));
203 L.push_back(T(startIndex + j, line, -tmp[j]));
205 L.push_back(T(line, startIndex + nbSegCoef + 2, -2));
206 L.push_back(T(startIndex + nbSegCoef + 2, line, 2));
210 startIndex += nbSegCoef;
217 for (
unsigned int i = 0; i < nbSeg; i++) {
218 double segLength = lengths.at(i);
220 for (
int j = 2; j < nbSegCoef; j++) {
221 for (
int k = 2; k < nbSegCoef; k++) {
222 double c = pow(segLength, j + k - 3) * j * (j - 1) * k * (k - 1) / (j + k - 3);
223 L.push_back(T(line + j, startIndex + k, c));
227 startIndex += nbSegCoef;
231 Eigen::SparseMatrix<double> M(nbHardConstraints + nbCoef, nbHardConstraints + nbCoef);
232 M.setFromTriplets(L.begin(), L.end());
234 Eigen::SparseLU<Eigen::SparseMatrix<double> > solver;
238 }
catch (std::exception &e) {
239 throw vpException(vpException::fatalError,
"usBSpline3D::defineFromPoints: %s\n", e.what());
244 for (
unsigned int i = 0; i < nbSeg; i++) {
246 vpMatrix m(3, nbSegCoef);
247 for (
int j = 0; j < nbSegCoef; j++) {
248 for (
int dim = 0; dim < 3; dim++) {
249 m[dim][j] = A(startIndex + j, dim);
256 startIndex += nbSegCoef;
261 int nbSegCoef = order + 1;
262 int nbCoef = nbSegCoef * nbSeg;
264 int nbHardConstraints = (nbSeg + 1) + (nbSeg - 1);
266 nbHardConstraints += (nbSeg - 1);
268 nbHardConstraints += (nbSeg - 1);
270 vpMatrix M(nbHardConstraints + nbCoef, nbHardConstraints + nbCoef, 0);
272 vpMatrix A(nbHardConstraints + nbCoef, 3, 0);
273 vpMatrix B(nbHardConstraints + nbCoef, 3, 0);
282 for (
unsigned int i = 0; i < nbSeg; i++) {
283 M[line][startIndex] = 1;
284 M[startIndex][line] = -1;
285 for (
int dim = 0; dim < 3; dim++)
286 B[line][dim] = points.at(i)[dim];
289 double segLength = lengths.at(i);
290 double *tmp =
new double[nbSegCoef];
293 for (
int j = 1; j < nbSegCoef; j++)
294 tmp[j] = segLength * tmp[j - 1];
296 for (
int j = 0; j < nbSegCoef; j++) {
297 M[line][startIndex + j] = tmp[j];
298 M[startIndex + j][line] = -tmp[j];
300 for (
int dim = 0; dim < 3; dim++)
301 B[line][dim] = points.at(i + 1)[dim];
305 startIndex += nbSegCoef;
311 for (
unsigned int i = 0; i < nbSeg - 1; i++) {
312 double segLength = lengths.at(i);
313 double *tmp =
new double[nbSegCoef];
319 for (
int j = 2; j < nbSegCoef; j++)
320 tmp[j] = segLength * tmp[j - 1];
321 for (
int j = 1; j < nbSegCoef; j++)
324 for (
int j = 1; j < nbSegCoef; j++) {
325 M[line][startIndex + j] = tmp[j];
326 M[startIndex + j][line] = -tmp[j];
328 M[line][startIndex + nbSegCoef + 1] = -1;
329 M[startIndex + nbSegCoef + 1][line] = 1;
337 for (
int j = 3; j < nbSegCoef; j++)
338 tmp[j] = segLength * tmp[j - 1];
339 for (
int j = 2; j < nbSegCoef; j++)
340 tmp[j] *= j * (j - 1);
342 for (
int j = 2; j < nbSegCoef; j++) {
343 M[line][startIndex + j] = tmp[j];
344 M[startIndex + j][line] = -tmp[j];
346 M[line][startIndex + nbSegCoef + 2] = -2;
347 M[startIndex + nbSegCoef + 2][line] = 2;
351 startIndex += nbSegCoef;
358 for (
unsigned int i = 0; i < nbSeg; i++) {
359 double segLength = lengths.at(i);
361 for (
int j = 2; j < nbSegCoef; j++) {
362 for (
int k = 2; k < nbSegCoef; k++) {
363 double c = pow(segLength, j + k - 3) * j * (j - 1) * k * (k - 1) / (j + k - 3);
364 M[line + j][startIndex + k] = c;
368 startIndex += nbSegCoef;
372 A = M.inverseByLU() * B;
373 }
catch (std::exception &e) {
374 throw vpException(vpException::fatalError,
"usBSpline3D::defineFromPoints: %s\n", e.what());
379 for (
unsigned int i = 0; i < nbSeg; i++) {
381 vpMatrix m(3, nbSegCoef);
382 for (
int j = 0; j < nbSegCoef; j++) {
383 for (
int dim = 0; dim < 3; dim++) {
384 m[dim][j] = A[startIndex + j][dim];
391 startIndex += nbSegCoef;
415 while (t +
m_spline.at(i).getParametricLength() < a && i + 1 <
m_spline.size()) {
417 t +=
m_spline.at(i).getParametricLength();
424 if (t + (
m_spline.at(i).getParametricLength() - ta) > b || i + 1 >=
m_spline.size()) {
426 p =
m_spline.at(i).getSubPolynomialCurve(ta, tb);
429 tb =
m_spline.at(i).getParametricLength();
430 p =
m_spline.at(i).getSubPolynomialCurve(ta, tb);
448 for (
unsigned int i = 0; i <
m_spline.size(); i++) {
456 return this->
move(vpHomogeneousMatrix(x, y, z, tx, ty, tz));
462 return m_spline.front().getPoint(l);
464 unsigned int seg = 0;
467 while (L <= l && seg <
m_spline.size()) {
468 L +=
m_spline.at(seg).getParametricLength();
472 double s = l - (L -
m_spline.at(seg).getParametricLength());
474 vpColVector P =
m_spline.at(seg).getPoint(s);
481 unsigned int seg = 0;
484 while (L <= param && seg <
m_spline.size()) {
485 L +=
m_spline.at(seg).getParametricLength();
489 double s = param - (L -
m_spline.at(seg).getParametricLength());
491 vpColVector D =
m_spline.at(seg).getTangent(s);
499 throw vpException(vpException::dimensionError,
"usBSpline3D::getDistanceFromPoint: invalid point dimension");
504 if (stop == -1 || stop > length)
509 throw vpException(vpException::badValue,
"usBSpline3D::getDistanceFromPoint: invalid start-stop parameters");
511 double middle = (start + stop) / 2;
512 while ((stop - start) > threshold) {
513 double d0 = (this->
getPoint(start) - P).frobeniusNorm();
514 double d1 = (this->
getPoint(middle) - P).frobeniusNorm();
515 double d2 = (this->
getPoint(stop) - P).frobeniusNorm();
517 if (d0 <= d1 && d0 < d2)
519 else if (d2 < d0 && d2 <= d1)
522 start = (start + middle) / 2;
523 stop = (middle + stop) / 2;
525 middle = (start + stop) / 2;
528 double l = (this->
getPoint(middle) - P).frobeniusNorm();
538 unsigned int seg = 0;
541 while (L <= l && seg <
m_spline.size()) {
542 L +=
m_spline.at(seg).getParametricLength();
546 if (L <= l && seg ==
m_spline.size())
550 L -=
m_spline.at(seg).getParametricLength();
558 vpColVector &direction3D)
const
575 unsigned int seg = 0;
578 while (L <= start && seg <
m_spline.size()) {
579 L +=
m_spline.at(seg).getParametricLength();
582 int nStart = seg - 1;
584 while (L <= end && seg <
m_spline.size()) {
585 L +=
m_spline.at(seg).getParametricLength();
591 int nbPoints = nEnd - nStart + 1;
600 vpMatrix M(nbPoints, 3);
601 vpRowVector mean(3, 0);
603 for (
int i = 0; i < nbPoints; i++)
604 M.insert(
m_spline.at(nStart + i).getPoint(
m_spline.at(nStart + i).getEndParameter()).t(), i, 0);
606 for (
int i = 0; i < nbPoints; i++)
610 for (
int i = 0; i < nbPoints; i++) {
625 U.resize(nbPoints, 2,
false);
627 S.resize(2, 2,
false);
632 vpColVector d(nbPoints);
633 for (
int i = 0; i < nbPoints; i++) {
634 d[i] = pow(P.t().getCol(i).frobeniusNorm(), 2);
637 vpColVector x(nbPoints, 1);
638 vpMatrix B(nbPoints, 3);
642 vpColVector y = B.pseudoInverse(0) * d;
644 vpColVector center(2);
645 center[0] = y[0] / 2;
646 center[1] = y[1] / 2;
648 double r = sqrt(y[2] + pow(center.frobeniusNorm(), 2));
659 if (direction3D.size() == 3) {
660 direction3D = V.getCol(2);
661 }
else if (direction3D.size() == 4) {
662 direction3D.insert(0, V.getCol(2));
666 if (center3D.size() == 3) {
667 V.resize(3, 2,
false);
668 center3D = V * center;
669 }
else if (center3D.size() == 4) {
670 V.resize(3, 2,
false);
671 center3D.insert(0, V * center + mean.t());
692 std::ostream &operator<<(std::ostream &s,
const usBSpline3D &spline)
694 s <<
"usBSpline3D\n";
696 unsigned int n = spline.
m_spline.size();
698 for (
unsigned int i = 0; i < n; i++)
709 if (c !=
"usBSpline3D") {
710 vpException e(vpException::ioError,
"Stream does not contain BSpline3D data");
718 for (
int i = 0; i < n; i++)
723 std::ostream &operator<<=(std::ostream &s,
const usBSpline3D &spline)
725 s.write(
"usBSpline3D", 12);
728 s.write((
char *)&n,
sizeof(
int));
729 for (
int i = 0; i < n; i++)
740 if (strcmp(c,
"usBSpline3D")) {
741 vpException e(vpException::ioError,
"Stream does not contain BSpline3D data");
746 s.read((
char *)&n,
sizeof(
int));
749 for (
int i = 0; i < n; i++)
void setSegment(int i, const usPolynomialCurve3D &poly)
double getLength(int nbSubSeg=50) const
bool getParametersFromLength(double l, int &index, double ¶m) const
void insertSegment(int i, const usPolynomialCurve3D &seg)
void removeSegments(int i, int j)
double getDistanceFromPoint(const vpColVector &point, double start=0, double stop=-1, double threshold=1e-5) const
const usPolynomialCurve3D & accessSegment(int i) const
std::vector< usPolynomialCurve3D > m_spline
Polynomials container.
vpColVector getTangent(double param) const
void addSegment(const usPolynomialCurve3D &seg)
Spline definition.
const usBSpline3D & operator=(const usBSpline3D &spline)
usBSpline3D()
Constructors, destructor.
int getNbSegments() const
Parameters setters and getters.
const usPolynomialCurve3D & accessLastSegment() const
bool move(const vpHomogeneousMatrix &H)
Move.
vpColVector getPoint(double param) const
Measure curve information.
virtual usBSpline3D * clone() const
usBSpline3D getSubSpline(double a, double b) const
double getCurvatureFromShape(double start, double end, vpColVector ¢er3D, vpColVector &direction3D) const
Curvature.
void defineFromPoints(const std::vector< vpColVector > &points, const std::vector< double > &lengths, int order=3)
void removeSegment(int i)
double getParametricLength() const
void setParametricLength(double length)
void setPolynomialCoefficients(const vpMatrix &polynomialCoefficients)
double getParametricLength() const
void changeCoefficientsToFitBoundaries(double startParameter, double endParameter)