23
#include "PreCompiled.h"
31
#include <Base/BoundBox.h>
32
#include <Base/Console.h>
33
#include <Mod/Mesh/App/WildMagic4/Wm4ApprPolyFit3.h>
34
#include <Mod/Mesh/App/WildMagic4/Wm4ApprQuadraticFit3.h>
35
#include <Mod/Mesh/App/WildMagic4/Wm4ApprSphereFit3.h>
36
#include <boost/math/special_functions/fpclassify.hpp>
42
#include <Eigen/Eigenvalues>
45
#include "Approximation.h"
46
#include "CylinderFit.h"
52
using namespace MeshCore;
54
Approximation::Approximation() = default;
56
Approximation::~Approximation()
61
void Approximation::GetMgcVectorArray(std::vector<Wm4::Vector3<double>>& rcPts) const
63
std::list<Base::Vector3f>::const_iterator It;
64
rcPts.reserve(_vPoints.size());
65
for (It = _vPoints.begin(); It != _vPoints.end(); ++It) {
66
rcPts.push_back(Base::convertTo<Wm4::Vector3d>(*It));
70
void Approximation::AddPoint(const Base::Vector3f& rcVector)
72
_vPoints.push_back(rcVector);
76
void Approximation::AddPoints(const std::vector<Base::Vector3f>& points)
78
std::copy(points.begin(), points.end(), std::back_inserter(_vPoints));
82
void Approximation::AddPoints(const std::set<Base::Vector3f>& points)
84
std::copy(points.begin(), points.end(), std::back_inserter(_vPoints));
88
void Approximation::AddPoints(const std::list<Base::Vector3f>& points)
90
std::copy(points.begin(), points.end(), std::back_inserter(_vPoints));
94
void Approximation::AddPoints(const MeshPointArray& points)
96
std::copy(points.begin(), points.end(), std::back_inserter(_vPoints));
100
Base::Vector3f Approximation::GetGravity() const
102
Base::Vector3f clGravity;
103
if (!_vPoints.empty()) {
104
for (const auto& vPoint : _vPoints) {
107
clGravity *= 1.0f / float(_vPoints.size());
112
std::size_t Approximation::CountPoints() const
114
return _vPoints.size();
117
void Approximation::Clear()
123
float Approximation::GetLastResult() const
128
bool Approximation::Done() const
145
if (CountPoints() < 3) {
159
for (const auto& vPoint : _vPoints) {
160
sxx += double(vPoint.x * vPoint.x);
161
sxy += double(vPoint.x * vPoint.y);
162
sxz += double(vPoint.x * vPoint.z);
163
syy += double(vPoint.y * vPoint.y);
164
syz += double(vPoint.y * vPoint.z);
165
szz += double(vPoint.z * vPoint.z);
166
mx += double(vPoint.x);
167
my += double(vPoint.y);
168
mz += double(vPoint.z);
171
size_t nSize = _vPoints.size();
172
sxx = sxx - mx * mx / (double(nSize));
173
sxy = sxy - mx * my / (double(nSize));
174
sxz = sxz - mx * mz / (double(nSize));
175
syy = syy - my * my / (double(nSize));
176
syz = syz - my * mz / (double(nSize));
177
szz = szz - mz * mz / (double(nSize));
179
#if defined(FC_USE_EIGEN)
180
Eigen::Matrix3d covMat = Eigen::Matrix3d::Zero();
190
Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> eig(covMat);
192
Eigen::Vector3d u = eig.eigenvectors().col(1);
193
Eigen::Vector3d v = eig.eigenvectors().col(2);
194
Eigen::Vector3d w = eig.eigenvectors().col(0);
196
_vDirU.Set(u.x(), u.y(), u.z());
197
_vDirV.Set(v.x(), v.y(), v.z());
198
_vDirW.Set(w.x(), w.y(), w.z());
199
_vBase.Set(mx / (float)nSize, my / (float)nSize, mz / (float)nSize);
201
float sigma = w.dot(covMat * w);
204
Wm4::Matrix3<double> akMat(sxx, sxy, sxz, sxy, syy, syz, sxz, syz, szz);
205
Wm4::Matrix3<double> rkRot, rkDiag;
207
akMat.EigenDecomposition(rkRot, rkDiag);
209
catch (const std::exception&) {
217
if (rkDiag(1, 1) <= 0) {
221
Wm4::Vector3<double> U = rkRot.GetColumn(1);
222
Wm4::Vector3<double> V = rkRot.GetColumn(2);
223
Wm4::Vector3<double> W = rkRot.GetColumn(0);
226
for (int i = 0; i < 3; i++) {
227
if (boost::math::isnan(W[i])) {
236
for (int i = 0; i < 3; i++) {
237
if (boost::math::isnan(U[i]) || boost::math::isnan(V[i])) {
244
Wm4::Vector3<double>::GenerateOrthonormalBasis(U, V, W);
247
_vDirU.Set(float(U.X()), float(U.Y()), float(U.Z()));
248
_vDirV.Set(float(V.X()), float(V.Y()), float(V.Z()));
249
_vDirW.Set(float(W.X()), float(W.Y()), float(W.Z()));
250
_vBase.Set(float(mx / nSize), float(my / nSize), float(mz / nSize));
251
float sigma = float(W.Dot(akMat * W));
255
if (boost::math::isnan(sigma)) {
266
if ((_vDirU % _vDirV) * _vDirW < 0.0f) {
267
Base::Vector3f tmp = _vDirU;
273
sigma = sqrt(sigma / (nSize - 3));
279
_fLastResult = sigma;
283
Base::Vector3f PlaneFit::GetBase() const
289
return Base::Vector3f();
293
Base::Vector3f PlaneFit::GetDirU() const
299
return Base::Vector3f();
303
Base::Vector3f PlaneFit::GetDirV() const
309
return Base::Vector3f();
313
Base::Vector3f PlaneFit::GetNormal() const
319
return Base::Vector3f();
323
float PlaneFit::GetDistanceToPlane(const Base::Vector3f& rcPoint) const
325
float fResult = FLOAT_MAX;
327
fResult = (rcPoint - _vBase) * _vDirW;
332
float PlaneFit::GetStdDeviation() const
342
float fSumXi = 0.0f, fSumXi2 = 0.0f, fMean = 0.0f, fDist = 0.0f;
344
float ulPtCt = float(CountPoints());
345
std::list<Base::Vector3f>::const_iterator cIt;
347
for (cIt = _vPoints.begin(); cIt != _vPoints.end(); ++cIt) {
348
fDist = GetDistanceToPlane(*cIt);
350
fSumXi2 += (fDist * fDist);
353
fMean = (1.0f / ulPtCt) * fSumXi;
354
return sqrt((ulPtCt / (ulPtCt - 1.0f)) * ((1.0f / ulPtCt) * fSumXi2 - fMean * fMean));
357
float PlaneFit::GetSignedStdDeviation() const
366
float fSumXi = 0.0F, fSumXi2 = 0.0F, fMean = 0.0F, fDist = 0.0F;
367
float fMinDist = FLOAT_MAX;
368
float fFactor = 0.0F;
370
float ulPtCt = float(CountPoints());
371
Base::Vector3f clGravity, clPt;
372
std::list<Base::Vector3f>::const_iterator cIt;
373
for (cIt = _vPoints.begin(); cIt != _vPoints.end(); ++cIt) {
376
clGravity *= (1.0f / ulPtCt);
378
for (cIt = _vPoints.begin(); cIt != _vPoints.end(); ++cIt) {
379
if ((clGravity - *cIt).Length() < fMinDist) {
380
fMinDist = (clGravity - *cIt).Length();
383
fDist = GetDistanceToPlane(*cIt);
385
fSumXi2 += (fDist * fDist);
389
if ((clPt - clGravity) * GetNormal() > 0) {
396
fMean = 1.0f / ulPtCt * fSumXi;
398
return fFactor * sqrt((ulPtCt / (ulPtCt - 3.0f)) * ((1.0f / ulPtCt) * fSumXi2 - fMean * fMean));
401
void PlaneFit::ProjectToPlane()
403
Base::Vector3f cGravity(GetGravity());
404
Base::Vector3f cNormal(GetNormal());
406
for (auto& cPnt : _vPoints) {
407
float fD = (cPnt - cGravity) * cNormal;
408
cPnt = cPnt - fD * cNormal;
412
void PlaneFit::Dimension(float& length, float& width) const
414
const Base::Vector3f& bs = _vBase;
415
const Base::Vector3f& ex = _vDirU;
416
const Base::Vector3f& ey = _vDirV;
418
Base::BoundBox3f bbox;
419
std::list<Base::Vector3f>::const_iterator cIt;
420
for (cIt = _vPoints.begin(); cIt != _vPoints.end(); ++cIt) {
421
Base::Vector3f pnt = *cIt;
422
pnt.TransformToCoordinateSystem(bs, ex, ey);
426
length = bbox.MaxX - bbox.MinX;
427
width = bbox.MaxY - bbox.MinY;
430
std::vector<Base::Vector3f> PlaneFit::GetLocalPoints() const
432
std::vector<Base::Vector3f> localPoints;
433
if (_bIsFitted && _fLastResult < FLOAT_MAX) {
434
Base::Vector3d bs = Base::convertTo<Base::Vector3d>(this->_vBase);
435
Base::Vector3d ex = Base::convertTo<Base::Vector3d>(this->_vDirU);
436
Base::Vector3d ey = Base::convertTo<Base::Vector3d>(this->_vDirV);
439
localPoints.insert(localPoints.begin(), _vPoints.begin(), _vPoints.end());
440
for (auto& localPoint : localPoints) {
441
Base::Vector3d clPoint = Base::convertTo<Base::Vector3d>(localPoint);
442
clPoint.TransformToCoordinateSystem(bs, ex, ey);
443
localPoint.Set(static_cast<float>(clPoint.x),
444
static_cast<float>(clPoint.y),
445
static_cast<float>(clPoint.z));
452
Base::BoundBox3f PlaneFit::GetBoundings() const
454
Base::BoundBox3f bbox;
455
std::vector<Base::Vector3f> pts = GetLocalPoints();
456
for (const auto& it : pts) {
464
bool QuadraticFit::GetCurvatureInfo(double x,
469
Base::Vector3f& rkDir0,
470
Base::Vector3f& rkDir1,
474
bool bResult = false;
477
Wm4::Vector3<double> Dir0, Dir1;
478
FunctionContainer clFuncCont(_fCoeff);
479
bResult = clFuncCont.CurvatureInfo(x, y, z, rfCurv0, rfCurv1, Dir0, Dir1, dDistance);
481
dDistance = double(clFuncCont.GetGradient(x, y, z).Length());
482
rkDir0 = Base::convertTo<Base::Vector3f>(Dir0);
483
rkDir1 = Base::convertTo<Base::Vector3f>(Dir1);
489
bool QuadraticFit::GetCurvatureInfo(double x, double y, double z, double& rfCurv0, double& rfCurv1)
491
bool bResult = false;
494
FunctionContainer clFuncCont(_fCoeff);
495
bResult = clFuncCont.CurvatureInfo(x, y, z, rfCurv0, rfCurv1);
501
const double& QuadraticFit::GetCoeffArray() const
506
double QuadraticFit::GetCoeff(std::size_t ulIndex) const
508
assert(ulIndex < 10);
511
return _fCoeff[ulIndex];
514
return double(FLOAT_MAX);
518
float QuadraticFit::Fit()
520
float fResult = FLOAT_MAX;
522
if (CountPoints() > 0) {
523
std::vector<Wm4::Vector3<double>> cPts;
524
GetMgcVectorArray(cPts);
525
fResult = (float)Wm4::QuadraticFit3<double>(CountPoints(), &(cPts[0]), _fCoeff);
526
_fLastResult = fResult;
534
void QuadraticFit::CalcEigenValues(double& dLambda1,
537
Base::Vector3f& clEV1,
538
Base::Vector3f& clEV2,
539
Base::Vector3f& clEV3) const
565
Wm4::Matrix3<double> akMat(_fCoeff[4],
575
Wm4::Matrix3<double> rkRot, rkDiag;
576
akMat.EigenDecomposition(rkRot, rkDiag);
578
Wm4::Vector3<double> vEigenU = rkRot.GetColumn(0);
579
Wm4::Vector3<double> vEigenV = rkRot.GetColumn(1);
580
Wm4::Vector3<double> vEigenW = rkRot.GetColumn(2);
582
clEV1 = Base::convertTo<Base::Vector3f>(vEigenU);
583
clEV2 = Base::convertTo<Base::Vector3f>(vEigenV);
584
clEV3 = Base::convertTo<Base::Vector3f>(vEigenW);
586
dLambda1 = rkDiag[0][0];
587
dLambda2 = rkDiag[1][1];
588
dLambda3 = rkDiag[2][2];
591
void QuadraticFit::CalcZValues(double x, double y, double& dZ1, double& dZ2) const
595
double dDisk = _fCoeff[3] * _fCoeff[3] + 2 * _fCoeff[3] * _fCoeff[8] * x
596
+ 2 * _fCoeff[3] * _fCoeff[9] * y + _fCoeff[8] * _fCoeff[8] * x * x
597
+ 2 * _fCoeff[8] * x * _fCoeff[9] * y + _fCoeff[9] * _fCoeff[9] * y * y
598
- 4 * _fCoeff[6] * _fCoeff[0] - 4 * _fCoeff[6] * _fCoeff[1] * x
599
- 4 * _fCoeff[6] * _fCoeff[2] * y - 4 * _fCoeff[6] * _fCoeff[7] * x * y
600
- 4 * _fCoeff[6] * _fCoeff[4] * x * x - 4 * _fCoeff[6] * _fCoeff[5] * y * y;
602
if (fabs(_fCoeff[6]) < 0.000005) {
603
dZ1 = double(FLOAT_MAX);
604
dZ2 = double(FLOAT_MAX);
609
dZ1 = double(FLOAT_MAX);
610
dZ2 = double(FLOAT_MAX);
617
dZ1 = 0.5 * ((-_fCoeff[3] - _fCoeff[8] * x - _fCoeff[9] * y + dDisk) / _fCoeff[6]);
618
dZ2 = 0.5 * ((-_fCoeff[3] - _fCoeff[8] * x - _fCoeff[9] * y - dDisk) / _fCoeff[6]);
623
SurfaceFit::SurfaceFit()
627
float SurfaceFit::Fit()
629
float fResult = FLOAT_MAX;
631
if (CountPoints() > 0) {
632
fResult = float(PolynomFit());
633
_fLastResult = fResult;
641
bool SurfaceFit::GetCurvatureInfo(double x,
646
Base::Vector3f& rkDir0,
647
Base::Vector3f& rkDir1,
650
bool bResult = false;
653
Wm4::Vector3<double> Dir0, Dir1;
654
FunctionContainer clFuncCont(_fCoeff);
655
bResult = clFuncCont.CurvatureInfo(x, y, z, rfCurv0, rfCurv1, Dir0, Dir1, dDistance);
657
dDistance = double(clFuncCont.GetGradient(x, y, z).Length());
658
rkDir0 = Base::convertTo<Base::Vector3f>(Dir0);
659
rkDir1 = Base::convertTo<Base::Vector3f>(Dir1);
665
bool SurfaceFit::GetCurvatureInfo(double x, double y, double z, double& rfCurv0, double& rfCurv1)
668
bool bResult = false;
671
FunctionContainer clFuncCont(_fCoeff);
672
bResult = clFuncCont.CurvatureInfo(x, y, z, rfCurv0, rfCurv1);
678
double SurfaceFit::PolynomFit()
680
if (PlaneFit::Fit() >= FLOAT_MAX) {
681
return double(FLOAT_MAX);
684
Base::Vector3d bs = Base::convertTo<Base::Vector3d>(this->_vBase);
685
Base::Vector3d ex = Base::convertTo<Base::Vector3d>(this->_vDirU);
686
Base::Vector3d ey = Base::convertTo<Base::Vector3d>(this->_vDirV);
705
Eigen::Matrix<double, 6, 6> A = Eigen::Matrix<double, 6, 6>::Zero();
706
Eigen::Matrix<double, 6, 1> b = Eigen::Matrix<double, 6, 1>::Zero();
707
Eigen::Matrix<double, 6, 1> x = Eigen::Matrix<double, 6, 1>::Zero();
709
std::vector<Base::Vector3d> transform;
710
transform.reserve(_vPoints.size());
713
for (std::list<Base::Vector3f>::const_iterator it = _vPoints.begin(); it != _vPoints.end();
715
Base::Vector3d clPoint = Base::convertTo<Base::Vector3d>(*it);
716
clPoint.TransformToCoordinateSystem(bs, ex, ey);
717
transform.push_back(clPoint);
718
double dU = clPoint.x;
719
double dV = clPoint.y;
720
double dW = clPoint.z;
722
double dU2 = dU * dU;
723
double dV2 = dV * dV;
724
double dUV = dU * dV;
728
A(0, 0) = A(0, 0) + dU2 * dU2;
729
A(0, 1) = A(0, 1) + dU2 * dV2;
730
A(0, 2) = A(0, 2) + dU2 * dUV;
731
A(0, 3) = A(0, 3) + dU2 * dU;
732
A(0, 4) = A(0, 4) + dU2 * dV;
733
A(0, 5) = A(0, 5) + dU2;
734
b(0) = b(0) + dU2 * dW;
736
A(1, 1) = A(1, 1) + dV2 * dV2;
737
A(1, 2) = A(1, 2) + dV2 * dUV;
738
A(1, 3) = A(1, 3) + dV2 * dU;
739
A(1, 4) = A(1, 4) + dV2 * dV;
740
A(1, 5) = A(1, 5) + dV2;
741
b(1) = b(1) + dV2 * dW;
743
A(2, 2) = A(2, 2) + dUV * dUV;
744
A(2, 3) = A(2, 3) + dUV * dU;
745
A(2, 4) = A(2, 4) + dUV * dV;
746
A(2, 5) = A(2, 5) + dUV;
747
b(3) = b(3) + dUV * dW;
749
A(3, 3) = A(3, 3) + dU * dU;
750
A(3, 4) = A(3, 4) + dU * dV;
751
A(3, 5) = A(3, 5) + dU;
752
b(3) = b(3) + dU * dW;
754
A(4, 4) = A(4, 4) + dV * dV;
755
A(4, 5) = A(4, 5) + dV;
756
b(5) = b(5) + dV * dW;
758
A(5, 5) = A(5, 5) + 1;
759
b(5) = b(5) + 1 * dW;
784
Eigen::HouseholderQR<Eigen::Matrix<double, 6, 6>> qr(A);
822
FunctionContainer clFuncCont(_fCoeff);
823
for (const auto& it : transform) {
826
double z = clFuncCont.F(u, v, 0.0);
830
sigma += dW2 - 2 * x.dot(b);
836
if (!_vPoints.empty()) {
837
sigma = sqrt(sigma / _vPoints.size());
840
_fLastResult = static_cast<float>(sigma);
841
return double(_fLastResult);
844
double SurfaceFit::Value(double x, double y) const
848
FunctionContainer clFuncCont(_fCoeff);
849
z = clFuncCont.F(x, y, 0.0);
855
void SurfaceFit::GetCoefficients(double& a, double& b, double& c, double& d, double& e, double& f)
866
void SurfaceFit::Transform(std::vector<Base::Vector3f>& pts) const
868
Base::Vector3d bs = Base::convertTo<Base::Vector3d>(this->_vBase);
869
Base::Vector3d ex = Base::convertTo<Base::Vector3d>(this->_vDirU);
870
Base::Vector3d ey = Base::convertTo<Base::Vector3d>(this->_vDirV);
871
Base::Vector3d ez = Base::convertTo<Base::Vector3d>(this->_vDirW);
889
std::transform(pts.begin(), pts.end(), pts.begin(), [&mat](const Base::Vector3f& pt) {
890
Base::Vector3f v(pt);
896
void SurfaceFit::Transform(std::vector<Base::Vector3d>& pts) const
898
Base::Vector3d bs = Base::convertTo<Base::Vector3d>(this->_vBase);
899
Base::Vector3d ex = Base::convertTo<Base::Vector3d>(this->_vDirU);
900
Base::Vector3d ey = Base::convertTo<Base::Vector3d>(this->_vDirV);
901
Base::Vector3d ez = Base::convertTo<Base::Vector3d>(this->_vDirW);
919
std::transform(pts.begin(), pts.end(), pts.begin(), [&mat](const Base::Vector3d& pt) {
920
Base::Vector3d v(pt);
932
std::vector<Base::Vector3d>
933
SurfaceFit::toBezier(double umin, double umax, double vmin, double vmax) const
935
std::vector<Base::Vector3d> pts;
950
double umid = 0.5 * (umin + umax);
951
double vmid = 0.5 * (vmin + vmax);
954
double z11 = Value(umin, vmin);
955
double v21 = Value(umid, vmin);
956
double z31 = Value(umax, vmin);
957
double z21 = 2.0 * v21 - 0.5 * (z11 + z31);
960
double z13 = Value(umin, vmax);
961
double v23 = Value(umid, vmax);
962
double z33 = Value(umax, vmax);
963
double z23 = 2.0 * v23 - 0.5 * (z13 + z33);
966
double v12 = Value(umin, vmid);
967
double z12 = 2.0 * v12 - 0.5 * (z11 + z13);
968
double v32 = Value(umax, vmid);
969
double z32 = 2.0 * v32 - 0.5 * (z31 + z33);
970
double v22 = Value(umid, vmid);
971
double z22 = 4.0 * v22 - 0.25 * (z11 + z31 + z13 + z33 + 2.0 * (z12 + z21 + z32 + z23));
974
pts.emplace_back(umin, vmin, z11);
975
pts.emplace_back(umid, vmin, z21);
976
pts.emplace_back(umax, vmin, z31);
979
pts.emplace_back(umin, vmid, z12);
980
pts.emplace_back(umid, vmid, z22);
981
pts.emplace_back(umax, vmid, z32);
984
pts.emplace_back(umin, vmax, z13);
985
pts.emplace_back(umid, vmax, z23);
986
pts.emplace_back(umax, vmax, z33);
995
struct LMCylinderFunctor
997
Eigen::MatrixXd measuredValues;
1000
int operator()(const Eigen::VectorXd& xvec, Eigen::VectorXd& fvec) const
1007
double aParam = xvec(0);
1008
double bParam = xvec(1);
1009
double cParam = xvec(2);
1010
double dParam = xvec(3);
1011
double eParam = xvec(4);
1012
double fParam = xvec(5);
1013
double gParam = xvec(6);
1017
for (int i = 0; i < values(); i++) {
1018
double xValue = measuredValues(i, 0);
1019
double yValue = measuredValues(i, 1);
1020
double zValue = measuredValues(i, 2);
1022
double a = aParam / (sqrt(aParam * aParam + bParam * bParam + cParam * cParam));
1023
double b = bParam / (sqrt(aParam * aParam + bParam * bParam + cParam * cParam));
1024
double c = cParam / (sqrt(aParam * aParam + bParam * bParam + cParam * cParam));
1028
double u = c * (yValue - y) - b * (zValue - z);
1029
double v = a * (zValue - z) - c * (xValue - x);
1030
double w = b * (xValue - x) - a * (yValue - y);
1032
fvec(i) = sqrt(u * u + v * v + w * w) - gParam;
1038
int df(const Eigen::VectorXd& x, Eigen::MatrixXd& fjac) const
1046
const double epsilon = 1e-5;
1048
for (int i = 0; i < x.size(); i++) {
1049
Eigen::VectorXd xPlus(x);
1050
xPlus(i) += epsilon;
1051
Eigen::VectorXd xMinus(x);
1052
xMinus(i) -= epsilon;
1054
Eigen::VectorXd fvecPlus(values());
1055
operator()(xPlus, fvecPlus);
1057
Eigen::VectorXd fvecMinus(values());
1058
operator()(xMinus, fvecMinus);
1060
Eigen::VectorXd fvecDiff(values());
1061
fvecDiff = (fvecPlus - fvecMinus) / (2.0f * epsilon);
1063
fjac.block(0, i, values(), 1) = fvecDiff;
1090
CylinderFit::CylinderFit()
1095
Base::Vector3f CylinderFit::GetInitialAxisFromNormals(const std::vector<Base::Vector3f>& n) const
1102
for (int i = 0; i < (int)n.size()-1; ++i) {
1103
for (int j = i+1; j < (int)n.size(); ++j) {
1104
Base::Vector3f cross = n[i] % n[j];
1105
if (cross.Sqr() > 1.0e-6) {
1119
Base::Vector3f axis(x,y,z);
1125
planeFit.AddPoints(n);
1127
return planeFit.GetNormal();
1139
sxx += double(it.x * it.x);
1140
sxy += double(it.x * it.y);
1141
sxz += double(it.x * it.z);
1142
syy += double(it.y * it.y);
1143
syz += double(it.y * it.z);
1144
szz += double(it.z * it.z);
1147
Eigen::Matrix3d covMat = Eigen::Matrix3d::Zero();
1157
Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> eig(covMat);
1158
Eigen::Vector3d w = eig.eigenvectors().col(0);
1160
Base::Vector3f normal;
1161
normal.Set(w.x(), w.y(), w.z());
1165
void CylinderFit::SetInitialValues(const Base::Vector3f& b, const Base::Vector3f& n)
1169
_initialGuess = true;
1172
float CylinderFit::Fit()
1174
if (CountPoints() < 7) {
1181
MeshCoreFit::CylinderFit cylFit;
1182
cylFit.AddPoints(_vPoints);
1183
if (_initialGuess) {
1184
cylFit.SetApproximations(_fRadius,
1185
Base::Vector3d(_vBase.x, _vBase.y, _vBase.z),
1186
Base::Vector3d(_vAxis.x, _vAxis.y, _vAxis.z));
1189
float result = cylFit.Fit();
1190
if (result < FLOAT_MAX) {
1191
Base::Vector3d base = cylFit.GetBase();
1192
Base::Vector3d dir = cylFit.GetAxis();
1194
#if defined(FC_DEBUG)
1195
Base::Console().Log(
1196
"MeshCoreFit::Cylinder Fit: Base: (%0.4f, %0.4f, %0.4f), Axis: (%0.6f, %0.6f, "
1197
"%0.6f), Radius: %0.4f, Std Dev: %0.4f, Iterations: %d\n",
1205
cylFit.GetStdDeviation(),
1206
cylFit.GetNumIterations());
1208
_vBase = Base::convertTo<Base::Vector3f>(base);
1209
_vAxis = Base::convertTo<Base::Vector3f>(dir);
1210
_fRadius = (float)cylFit.GetRadius();
1211
_fLastResult = result;
1214
int m = static_cast<int>(_vPoints.size());
1217
Eigen::MatrixXd measuredValues(m, 3);
1219
for (const auto& it : _vPoints) {
1220
measuredValues(index, 0) = it.x;
1221
measuredValues(index, 1) = it.y;
1222
measuredValues(index, 2) = it.z;
1226
Eigen::VectorXd x(n);
1240
LMCylinderFunctor functor;
1241
functor.measuredValues = measuredValues;
1245
Eigen::LevenbergMarquardt<LMCylinderFunctor, double> lm(functor);
1246
int status = lm.minimize(x);
1247
Base::Console().Log("Cylinder fit: %d, iterations: %d, gradient norm: %f\n",
1263
_fLastResult = lm.gnorm;
1266
return _fLastResult;
1269
float CylinderFit::GetRadius() const
1274
Base::Vector3f CylinderFit::GetBase() const
1280
return Base::Vector3f();
1284
Base::Vector3f CylinderFit::GetAxis() const
1290
return Base::Vector3f();
1294
float CylinderFit::GetDistanceToCylinder(const Base::Vector3f& rcPoint) const
1296
float fResult = FLOAT_MAX;
1298
fResult = rcPoint.DistanceToLine(_vBase, _vAxis) - _fRadius;
1303
float CylinderFit::GetStdDeviation() const
1313
float fSumXi = 0.0f, fSumXi2 = 0.0f, fMean = 0.0f, fDist = 0.0f;
1315
float ulPtCt = float(CountPoints());
1316
std::list<Base::Vector3f>::const_iterator cIt;
1318
for (cIt = _vPoints.begin(); cIt != _vPoints.end(); ++cIt) {
1319
fDist = GetDistanceToCylinder(*cIt);
1321
fSumXi2 += (fDist * fDist);
1324
fMean = (1.0f / ulPtCt) * fSumXi;
1325
return sqrt((ulPtCt / (ulPtCt - 1.0f)) * ((1.0f / ulPtCt) * fSumXi2 - fMean * fMean));
1328
void CylinderFit::GetBounding(Base::Vector3f& bottom, Base::Vector3f& top) const
1330
float distMin = FLT_MAX;
1331
float distMax = FLT_MIN;
1333
std::list<Base::Vector3f>::const_iterator cIt;
1334
for (cIt = _vPoints.begin(); cIt != _vPoints.end(); ++cIt) {
1335
float dist = cIt->DistanceToPlane(_vBase, _vAxis);
1336
if (dist < distMin) {
1340
if (dist > distMax) {
1347
bottom = bottom.Perpendicular(_vBase, _vAxis);
1348
top = top.Perpendicular(_vBase, _vAxis);
1351
void CylinderFit::ProjectToCylinder()
1353
Base::Vector3f cBase(GetBase());
1354
Base::Vector3f cAxis(GetAxis());
1356
for (auto& cPnt : _vPoints) {
1357
if (cPnt.DistanceToLine(cBase, cAxis) > 0) {
1358
Base::Vector3f proj;
1359
cBase.ProjectToPlane(cPnt, cAxis, proj);
1360
Base::Vector3f diff = cPnt - proj;
1362
cPnt = proj + diff * _fRadius;
1367
Base::Vector3f cMov(cPnt);
1369
float x = (float(rand()) / float(RAND_MAX));
1370
float y = (float(rand()) / float(RAND_MAX));
1371
float z = (float(rand()) / float(RAND_MAX));
1373
} while (cMov.DistanceToLine(cBase, cAxis) == 0);
1375
Base::Vector3f proj;
1376
cMov.ProjectToPlane(cPnt, cAxis, proj);
1377
Base::Vector3f diff = cPnt - proj;
1379
cPnt = proj + diff * _fRadius;
1386
SphereFit::SphereFit()
1390
float SphereFit::GetRadius() const
1400
Base::Vector3f SphereFit::GetCenter() const
1406
return Base::Vector3f();
1410
float SphereFit::Fit()
1413
if (CountPoints() < 4) {
1417
std::vector<Wm4::Vector3d> input;
1418
std::transform(_vPoints.begin(),
1420
std::back_inserter(input),
1421
[](const Base::Vector3f& v) {
1422
return Wm4::Vector3d(v.x, v.y, v.z);
1425
Wm4::Sphere3d sphere;
1426
Wm4::SphereFit3<double>(input.size(), input.data(), 10, sphere, false);
1427
_vCenter = Base::convertTo<Base::Vector3f>(sphere.Center);
1428
_fRadius = float(sphere.Radius);
1434
Base::Console().Message(" WildMagic Sphere Fit: Center: (%0.4f, %0.4f, %0.4f), Radius: "
1435
"%0.4f, Std Dev: %0.4f\n",
1443
MeshCoreFit::SphereFit sphereFit;
1444
sphereFit.AddPoints(_vPoints);
1445
sphereFit.ComputeApproximations();
1446
float result = sphereFit.Fit();
1447
if (result < FLOAT_MAX) {
1448
Base::Vector3d center = sphereFit.GetCenter();
1450
Base::Console().Message("MeshCoreFit::Sphere Fit: Center: (%0.4f, %0.4f, %0.4f), Radius: "
1451
"%0.4f, Std Dev: %0.4f, Iterations: %d\n",
1455
sphereFit.GetRadius(),
1456
sphereFit.GetStdDeviation(),
1457
sphereFit.GetNumIterations());
1459
_vCenter = Base::convertTo<Base::Vector3f>(center);
1460
_fRadius = (float)sphereFit.GetRadius();
1461
_fLastResult = result;
1464
return _fLastResult;
1467
float SphereFit::GetDistanceToSphere(const Base::Vector3f& rcPoint) const
1469
float fResult = FLOAT_MAX;
1471
fResult = Base::Vector3f(rcPoint - _vCenter).Length() - _fRadius;
1476
float SphereFit::GetStdDeviation() const
1486
float fSumXi = 0.0f, fSumXi2 = 0.0f, fMean = 0.0f, fDist = 0.0f;
1488
float ulPtCt = float(CountPoints());
1489
std::list<Base::Vector3f>::const_iterator cIt;
1491
for (cIt = _vPoints.begin(); cIt != _vPoints.end(); ++cIt) {
1492
fDist = GetDistanceToSphere(*cIt);
1494
fSumXi2 += (fDist * fDist);
1497
fMean = (1.0f / ulPtCt) * fSumXi;
1498
return sqrt((ulPtCt / (ulPtCt - 1.0f)) * ((1.0f / ulPtCt) * fSumXi2 - fMean * fMean));
1501
void SphereFit::ProjectToSphere()
1503
for (auto& cPnt : _vPoints) {
1508
Base::Vector3f diff = cPnt - _vCenter;
1509
double length = diff.Length();
1510
if (length == 0.0) {
1517
cPnt = _vCenter + diff * _fRadius;
1524
PolynomialFit::PolynomialFit()
1528
float PolynomialFit::Fit()
1530
std::vector<float> x, y, z;
1531
x.reserve(_vPoints.size());
1532
y.reserve(_vPoints.size());
1533
z.reserve(_vPoints.size());
1534
for (std::list<Base::Vector3f>::const_iterator it = _vPoints.begin(); it != _vPoints.end();
1542
float* coeff = Wm4::PolyFit3<float>(_vPoints.size(), &(x[0]), &(y[0]), &(z[0]), 2, 2);
1543
for (int i = 0; i < 9; i++) {
1544
_fCoeff[i] = coeff[i];
1547
catch (const std::exception&) {
1554
float PolynomialFit::Value(float x, float y) const
1556
float fValue = _fCoeff[0] + _fCoeff[1] * x + _fCoeff[2] * x * x + _fCoeff[3] * y
1557
+ _fCoeff[4] * x * y + _fCoeff[5] * x * x * y + _fCoeff[6] * y * y + _fCoeff[7] * x * y * y
1558
+ _fCoeff[8] * x * x * y * y;