| |
|
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | #include <algorithm>
|
| | #include <cstdlib>
|
| | #include <iterator>
|
| | #include <limits>
|
| |
|
| | #include <Base/Console.h>
|
| | #include <Base/Converter.h>
|
| | #include <Mod/Mesh/App/WildMagic4/Wm4ApprLineFit3.h>
|
| |
|
| | #include "CylinderFit.h"
|
| |
|
| |
|
| | using namespace MeshCoreFit;
|
| |
|
| | CylinderFit::CylinderFit()
|
| | : _vBase(0, 0, 0)
|
| | , _vAxis(0, 0, 1)
|
| | {}
|
| |
|
| |
|
| | void CylinderFit::SetApproximations(double radius, const Base::Vector3d& base, const Base::Vector3d& axis)
|
| | {
|
| | _bIsFitted = false;
|
| | _fLastResult = std::numeric_limits<float>::max();
|
| | _numIter = 0;
|
| | _dRadius = radius;
|
| | _vBase = base;
|
| | _vAxis = axis;
|
| | _vAxis.Normalize();
|
| | }
|
| |
|
| |
|
| |
|
| | void CylinderFit::SetApproximations(const Base::Vector3d& base, const Base::Vector3d& axis)
|
| | {
|
| | _bIsFitted = false;
|
| | _fLastResult = std::numeric_limits<float>::max();
|
| | _numIter = 0;
|
| | _vBase = base;
|
| | _vAxis = axis;
|
| | _vAxis.Normalize();
|
| | _dRadius = 0.0;
|
| | if (!_vPoints.empty()) {
|
| | for (const auto& it : _vPoints) {
|
| | _dRadius += Base::Vector3d(it.x, it.y, it.z).DistanceToLine(_vBase, _vAxis);
|
| | }
|
| | _dRadius /= (double)_vPoints.size();
|
| | }
|
| | }
|
| |
|
| |
|
| |
|
| | void CylinderFit::SetConvergenceCriteria(
|
| | double posConvLimit,
|
| | double dirConvLimit,
|
| | double vConvLimit,
|
| | int maxIter
|
| | )
|
| | {
|
| | if (posConvLimit > 0.0) {
|
| | _posConvLimit = posConvLimit;
|
| | }
|
| | if (dirConvLimit > 0.0) {
|
| | _dirConvLimit = dirConvLimit;
|
| | }
|
| | if (vConvLimit > 0.0) {
|
| | _vConvLimit = vConvLimit;
|
| | }
|
| | if (maxIter > 0) {
|
| | _maxIter = maxIter;
|
| | }
|
| | }
|
| |
|
| |
|
| | double CylinderFit::GetRadius() const
|
| | {
|
| | if (_bIsFitted) {
|
| | return _dRadius;
|
| | }
|
| |
|
| | return 0.0;
|
| | }
|
| |
|
| | Base::Vector3d CylinderFit::GetBase() const
|
| | {
|
| | if (_bIsFitted) {
|
| | return _vBase;
|
| | }
|
| |
|
| | return Base::Vector3d();
|
| | }
|
| |
|
| | Base::Vector3d CylinderFit::GetAxis() const
|
| | {
|
| | if (_bIsFitted) {
|
| | return _vAxis;
|
| | }
|
| |
|
| | return Base::Vector3d();
|
| | }
|
| |
|
| | int CylinderFit::GetNumIterations() const
|
| | {
|
| | if (_bIsFitted) {
|
| | return _numIter;
|
| | }
|
| |
|
| | return 0;
|
| | }
|
| |
|
| | float CylinderFit::GetDistanceToCylinder(const Base::Vector3f& rcPoint) const
|
| | {
|
| | float fResult = std::numeric_limits<float>::max();
|
| | if (_bIsFitted) {
|
| | Base::Vector3d pt(rcPoint.x, rcPoint.y, rcPoint.z);
|
| | fResult = static_cast<float>(pt.DistanceToLine(_vBase, _vAxis) - _dRadius);
|
| | }
|
| | return fResult;
|
| | }
|
| |
|
| | float CylinderFit::GetStdDeviation() const
|
| | {
|
| |
|
| |
|
| |
|
| | if (!_bIsFitted) {
|
| | return std::numeric_limits<float>::max();
|
| | }
|
| |
|
| | double sumXi = 0.0;
|
| | double sumXi2 = 0.0;
|
| | double dist = 0.0;
|
| | for (auto it : _vPoints) {
|
| | dist = GetDistanceToCylinder(it);
|
| | sumXi += dist;
|
| | sumXi2 += (dist * dist);
|
| | }
|
| |
|
| | double N = static_cast<double>(CountPoints());
|
| | double mean = sumXi / N;
|
| | return static_cast<float>(sqrt((N / (N - 1.0)) * (sumXi2 / N - mean * mean)));
|
| | }
|
| |
|
| | void CylinderFit::ProjectToCylinder()
|
| | {
|
| | auto cBase = Base::convertTo<Base::Vector3f>(_vBase);
|
| | auto cAxis = Base::convertTo<Base::Vector3f>(_vAxis);
|
| |
|
| | for (auto& cPnt : _vPoints) {
|
| | if (cPnt.DistanceToLine(cBase, cAxis) > 0) {
|
| | Base::Vector3f proj;
|
| | cBase.ProjectToPlane(cPnt, cAxis, proj);
|
| | Base::Vector3f diff = cPnt - proj;
|
| | diff.Normalize();
|
| | cPnt = proj + diff * _dRadius;
|
| | }
|
| | else {
|
| |
|
| |
|
| | Base::Vector3f cMov(cPnt);
|
| | do {
|
| | float x = (float(rand()) / float(RAND_MAX));
|
| | float y = (float(rand()) / float(RAND_MAX));
|
| | float z = (float(rand()) / float(RAND_MAX));
|
| | cMov.Move(x, y, z);
|
| | } while (cMov.DistanceToLine(cBase, cAxis) == 0);
|
| |
|
| | Base::Vector3f proj;
|
| | cMov.ProjectToPlane(cPnt, cAxis, proj);
|
| | Base::Vector3f diff = cPnt - proj;
|
| | diff.Normalize();
|
| | cPnt = proj + diff * _dRadius;
|
| | }
|
| | }
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | void CylinderFit::ComputeApproximationsLine()
|
| | {
|
| | _bIsFitted = false;
|
| | _fLastResult = std::numeric_limits<float>::max();
|
| | _numIter = 0;
|
| | _vBase.Set(0.0, 0.0, 0.0);
|
| | _vAxis.Set(0.0, 0.0, 0.0);
|
| | _dRadius = 0.0;
|
| | if (!_vPoints.empty()) {
|
| | std::vector<Wm4::Vector3d> input;
|
| | std::transform(
|
| | _vPoints.begin(),
|
| | _vPoints.end(),
|
| | std::back_inserter(input),
|
| | [](const Base::Vector3f& v) { return Wm4::Vector3d(v.x, v.y, v.z); }
|
| | );
|
| | Wm4::Line3<double> kLine = Wm4::OrthogonalLineFit3(input.size(), input.data());
|
| | _vBase.Set(kLine.Origin.X(), kLine.Origin.Y(), kLine.Origin.Z());
|
| | _vAxis.Set(kLine.Direction.X(), kLine.Direction.Y(), kLine.Direction.Z());
|
| |
|
| | for (const auto& it : _vPoints) {
|
| | _dRadius += Base::Vector3d(it.x, it.y, it.z).DistanceToLine(_vBase, _vAxis);
|
| | }
|
| | _dRadius /= (double)_vPoints.size();
|
| | }
|
| | }
|
| |
|
| | float CylinderFit::Fit()
|
| | {
|
| | _bIsFitted = false;
|
| | _fLastResult = std::numeric_limits<float>::max();
|
| | _numIter = 0;
|
| |
|
| |
|
| | const int minPts = 5;
|
| | if (CountPoints() < minPts) {
|
| | return std::numeric_limits<float>::max();
|
| | }
|
| |
|
| |
|
| | if (_dRadius == 0.0) {
|
| | ComputeApproximationsLine();
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | SolutionD solDir {};
|
| | findBestSolDirection(solDir);
|
| |
|
| |
|
| | const int dim = 5;
|
| | std::vector<Base::Vector3d> residuals(CountPoints(), Base::Vector3d(0.0, 0.0, 0.0));
|
| | Matrix5x5 atpa;
|
| | Eigen::VectorXd atpl(dim);
|
| |
|
| |
|
| | double sigma0 {};
|
| | bool cont = true;
|
| | while (cont && (_numIter < _maxIter)) {
|
| | ++_numIter;
|
| |
|
| |
|
| | setupNormalEquationMatrices(solDir, residuals, atpa, atpl);
|
| |
|
| |
|
| | Eigen::LLT<Matrix5x5> llt(atpa);
|
| | if (llt.info() != Eigen::Success) {
|
| | return std::numeric_limits<float>::max();
|
| | }
|
| | Eigen::VectorXd x = llt.solve(atpl);
|
| |
|
| |
|
| | cont = false;
|
| |
|
| |
|
| |
|
| | if ((fabs(x(0)) > _posConvLimit) || (fabs(x(1)) > _posConvLimit)
|
| | || (fabs(x(2)) > _dirConvLimit) || (fabs(x(3)) > _dirConvLimit)
|
| | || (fabs(x(4)) > _posConvLimit)) {
|
| | cont = true;
|
| | }
|
| |
|
| |
|
| |
|
| | bool vConverged {};
|
| | if (!computeResiduals(solDir, x, residuals, sigma0, _vConvLimit, vConverged)) {
|
| | return std::numeric_limits<float>::max();
|
| | }
|
| | if (!vConverged) {
|
| | cont = true;
|
| | }
|
| |
|
| |
|
| | if (!updateParameters(solDir, x)) {
|
| | return std::numeric_limits<float>::max();
|
| | }
|
| | }
|
| |
|
| |
|
| | if (cont) {
|
| | return std::numeric_limits<float>::max();
|
| | }
|
| |
|
| | _bIsFitted = true;
|
| | _fLastResult = sigma0;
|
| |
|
| | return _fLastResult;
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | void CylinderFit::findBestSolDirection(SolutionD& solDir)
|
| | {
|
| |
|
| |
|
| | Base::Vector3d dir = _vAxis;
|
| | Base::Vector3d pos = _vBase;
|
| | dir.Normalize();
|
| | double biggest = dir.x;
|
| | solDir = solL;
|
| | if (fabs(dir.y) > fabs(biggest)) {
|
| | biggest = dir.y;
|
| | solDir = solM;
|
| | }
|
| | if (fabs(dir.z) > fabs(biggest)) {
|
| | biggest = dir.z;
|
| | solDir = solN;
|
| | }
|
| | if (biggest < 0.0) {
|
| | dir.Set(-dir.x, -dir.y, -dir.z);
|
| | }
|
| |
|
| | double fixedVal = 0.0;
|
| | double lambda {};
|
| | switch (solDir) {
|
| | case solL:
|
| | fixedVal = meanXObs();
|
| | lambda = (fixedVal - pos.x) / dir.x;
|
| | pos.x = fixedVal;
|
| | pos.y = pos.y + lambda * dir.y;
|
| | pos.z = pos.z + lambda * dir.z;
|
| | break;
|
| | case solM:
|
| | fixedVal = meanYObs();
|
| | lambda = (fixedVal - pos.y) / dir.y;
|
| | pos.x = pos.x + lambda * dir.x;
|
| | pos.y = fixedVal;
|
| | pos.z = pos.z + lambda * dir.z;
|
| | break;
|
| | case solN:
|
| | fixedVal = meanZObs();
|
| | lambda = (fixedVal - pos.z) / dir.z;
|
| | pos.x = pos.x + lambda * dir.x;
|
| | pos.y = pos.y + lambda * dir.y;
|
| | pos.z = fixedVal;
|
| | break;
|
| | }
|
| | _vAxis = dir;
|
| | _vBase = pos;
|
| | }
|
| |
|
| | double CylinderFit::meanXObs()
|
| | {
|
| | double mx = 0.0;
|
| | if (!_vPoints.empty()) {
|
| | for (const auto& it : _vPoints) {
|
| | mx += it.x;
|
| | }
|
| | mx /= double(_vPoints.size());
|
| | }
|
| | return mx;
|
| | }
|
| |
|
| | double CylinderFit::meanYObs()
|
| | {
|
| | double my = 0.0;
|
| | if (!_vPoints.empty()) {
|
| | for (const auto& it : _vPoints) {
|
| | my += it.y;
|
| | }
|
| | my /= double(_vPoints.size());
|
| | }
|
| | return my;
|
| | }
|
| |
|
| | double CylinderFit::meanZObs()
|
| | {
|
| | double mz = 0.0;
|
| | if (!_vPoints.empty()) {
|
| | for (const auto& it : _vPoints) {
|
| | mz += it.z;
|
| | }
|
| | mz /= double(_vPoints.size());
|
| | }
|
| | return mz;
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| | void CylinderFit::setupNormalEquationMatrices(
|
| | SolutionD solDir,
|
| | const std::vector<Base::Vector3d>& residuals,
|
| | Matrix5x5& atpa,
|
| | Eigen::VectorXd& atpl
|
| | ) const
|
| | {
|
| |
|
| | atpa.setZero();
|
| | atpl.setZero();
|
| |
|
| |
|
| |
|
| | DoubleArray5 a {};
|
| | DoubleArray3 b {};
|
| | double f0 {};
|
| | double qw {};
|
| | auto vIt = residuals.begin();
|
| | for (auto cIt = _vPoints.begin(); cIt != _vPoints.end(); ++cIt, ++vIt) {
|
| |
|
| |
|
| | setupObservation(solDir, *cIt, *vIt, a, f0, qw, b);
|
| | addObservationU(a, f0, qw, atpa, atpl);
|
| |
|
| | }
|
| | setLowerPart(atpa);
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | void CylinderFit::setupObservation(SolutionD solDir,
|
| | const Base::Vector3f& point,
|
| | const Base::Vector3d& residual,
|
| | DoubleArray5& a,
|
| | double& f0,
|
| | double& qw,
|
| | DoubleArray3& b) const
|
| | {
|
| |
|
| |
|
| |
|
| | double xEstimate = (double)point.x + residual.x;
|
| | double yEstimate = (double)point.y + residual.y;
|
| | double zEstimate = (double)point.z + residual.z;
|
| |
|
| |
|
| | double lambda = _vAxis.x * (xEstimate - _vBase.x) + _vAxis.y * (yEstimate - _vBase.y) + _vAxis.z * (zEstimate - _vBase.z);
|
| | double x0 = _vBase.x + lambda * _vAxis.x;
|
| | double y0 = _vBase.y + lambda * _vAxis.y;
|
| | double z0 = _vBase.z + lambda * _vAxis.z;
|
| | double dx = xEstimate - x0;
|
| | double dy = yEstimate - y0;
|
| | double dz = zEstimate - z0;
|
| | double dx00 = _vBase.x - xEstimate;
|
| | double dy00 = _vBase.y - yEstimate;
|
| | double dz00 = _vBase.z - zEstimate;
|
| |
|
| |
|
| | b[0] = 2.0 * (dx - _vAxis.x * _vAxis.x * dx - _vAxis.x * _vAxis.y * dy - _vAxis.x * _vAxis.z * dz);
|
| | b[1] = 2.0 * (dy - _vAxis.x * _vAxis.y * dx - _vAxis.y * _vAxis.y * dy - _vAxis.y * _vAxis.z * dz);
|
| | b[2] = 2.0 * (dz - _vAxis.x * _vAxis.z * dx - _vAxis.y * _vAxis.z * dy - _vAxis.z * _vAxis.z * dz);
|
| |
|
| | double ddxdl {}, ddydl {}, ddzdl {};
|
| | double ddxdm {}, ddydm {}, ddzdm {};
|
| | double ddxdn {}, ddydn {}, ddzdn {};
|
| |
|
| |
|
| | switch (solDir) {
|
| | case solL:
|
| |
|
| | ddxdm = -2.0 * _vAxis.y * dx00 + (_vAxis.x - _vAxis.y * _vAxis.y / _vAxis.x) * dy00 - (_vAxis.y * _vAxis.z / _vAxis.x) * dz00;
|
| | ddydm = (_vAxis.x - _vAxis.y * _vAxis.y / _vAxis.x) * dx00 + 2.0 * _vAxis.y * dy00 + _vAxis.z * dz00;
|
| | ddzdm = -(_vAxis.y * _vAxis.z / _vAxis.x) * dx00 + _vAxis.z * dy00;
|
| | ddxdn = -2.0 * _vAxis.z * dx00 - (_vAxis.y * _vAxis.z / _vAxis.x) * dy00 + (_vAxis.x - _vAxis.z * _vAxis.z / _vAxis.x) * dz00;
|
| | ddydn = -(_vAxis.y * _vAxis.z / _vAxis.x) * dx00 + _vAxis.y * dz00;
|
| | ddzdn = (_vAxis.x - _vAxis.z * _vAxis.z / _vAxis.x) * dx00 + _vAxis.y * dy00 + 2.0 * _vAxis.z * dz00;
|
| | a[0] = -b[1];
|
| | a[1] = -b[2];
|
| | a[2] = 2.0 * (dx * ddxdm + dy * ddydm + dz * ddzdm);
|
| | a[3] = 2.0 * (dx * ddxdn + dy * ddydn + dz * ddzdn);
|
| | a[4] = -2.0 * _dRadius;
|
| | break;
|
| | case solM:
|
| |
|
| | ddxdl = 2.0 * _vAxis.x * dx00 + (_vAxis.y - _vAxis.x * _vAxis.x / _vAxis.y) * dy00 + _vAxis.z * dz00;
|
| | ddydl = (_vAxis.y - _vAxis.x * _vAxis.x / _vAxis.y) * dx00 - 2.0 * _vAxis.x * dy00 - (_vAxis.x * _vAxis.z / _vAxis.y) * dz00;
|
| | ddzdl = _vAxis.z * dx00 - (_vAxis.x * _vAxis.z / _vAxis.y) * dy00;
|
| | ddxdn = -(_vAxis.x * _vAxis.z / _vAxis.y) * dy00 + _vAxis.x * dz00;
|
| | ddydn = -(_vAxis.x * _vAxis.z / _vAxis.y) * dx00 - 2.0 * _vAxis.z * dy00 + (_vAxis.y - _vAxis.z * _vAxis.z / _vAxis.y) * dz00;
|
| | ddzdn = _vAxis.x * dx00 + (_vAxis.y - _vAxis.z * _vAxis.z / _vAxis.y) * dy00 + 2.0 * _vAxis.z * dz00;
|
| | a[0] = -b[0];
|
| | a[1] = -b[2];
|
| | a[2] = 2.0 * (dx * ddxdl + dy * ddydl + dz * ddzdl);
|
| | a[3] = 2.0 * (dx * ddxdn + dy * ddydn + dz * ddzdn);
|
| | a[4] = -2.0 * _dRadius;
|
| | break;
|
| | case solN:
|
| |
|
| | ddxdl = 2.0 * _vAxis.x * dx00 + _vAxis.y * dy00 + (_vAxis.z - _vAxis.x * _vAxis.x / _vAxis.z) * dz00;
|
| | ddydl = _vAxis.y * dx00 - (_vAxis.x * _vAxis.y / _vAxis.z) * dz00;
|
| | ddzdl = (_vAxis.z - _vAxis.x * _vAxis.x / _vAxis.z) * dx00 - (_vAxis.x * _vAxis.y / _vAxis.z) * dy00 - 2.0 * _vAxis.x * dz00;
|
| | ddxdm = _vAxis.x * dy00 - (_vAxis.x * _vAxis.y / _vAxis.z) * dz00;
|
| | ddydm = _vAxis.x * dx00 + 2.0 * _vAxis.y * dy00 + (_vAxis.z - _vAxis.y * _vAxis.y / _vAxis.z) * dz00;
|
| | ddzdm = -(_vAxis.x * _vAxis.y / _vAxis.z) * dx00 + (_vAxis.z - _vAxis.y * _vAxis.y / _vAxis.z) * dy00 - 2.0 * _vAxis.y * dz00;
|
| | a[0] = -b[0];
|
| | a[1] = -b[1];
|
| | a[2] = 2.0 * (dx * ddxdl + dy * ddydl + dz * ddzdl);
|
| | a[3] = 2.0 * (dx * ddxdm + dy * ddydm + dz * ddzdm);
|
| | a[4] = -2.0 * _dRadius;
|
| | break;
|
| | }
|
| |
|
| |
|
| | f0 = _dRadius * _dRadius - dx * dx - dy * dy - dz * dz + b[0] * residual.x + b[1] * residual.y + b[2] * residual.z;
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | qw = 1.0 / (b[0] * b[0] + b[1] * b[1] + b[2] * b[2]);
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | void CylinderFit::addObservationU(
|
| | DoubleArray5 a,
|
| | double li,
|
| | double pi,
|
| | Matrix5x5& atpa,
|
| | Eigen::VectorXd& atpl
|
| | ) const
|
| | {
|
| | const int dim = 5;
|
| | for (int i = 0; i < dim; ++i) {
|
| | double aipi = a[i] * pi;
|
| | for (int j = i; j < dim; ++j) {
|
| | atpa(i, j) += aipi * a[j];
|
| |
|
| |
|
| | }
|
| | atpl(i) += aipi * li;
|
| | }
|
| | }
|
| |
|
| |
|
| |
|
| | void CylinderFit::setLowerPart(Matrix5x5& atpa) const
|
| | {
|
| | const int dim = 5;
|
| | for (int i = 0; i < dim; ++i) {
|
| | for (int j = i + 1; j < dim; ++j) {
|
| | atpa(j, i) = atpa(i, j);
|
| | }
|
| | }
|
| | }
|
| |
|
| |
|
| | bool CylinderFit::computeResiduals(
|
| | SolutionD solDir,
|
| | const Eigen::VectorXd& x,
|
| | std::vector<Base::Vector3d>& residuals,
|
| | double& sigma0,
|
| | double vConvLimit,
|
| | bool& vConverged
|
| | ) const
|
| | {
|
| | const int dim = 5;
|
| |
|
| | const int minPts = 5;
|
| | vConverged = true;
|
| | int nPtsUsed = 0;
|
| | sigma0 = 0.0;
|
| | DoubleArray5 a {};
|
| | DoubleArray3 b {};
|
| | double f0 {};
|
| | double qw {};
|
| |
|
| |
|
| |
|
| |
|
| | auto vIt = residuals.begin();
|
| | for (auto cIt = _vPoints.begin(); cIt != _vPoints.end(); ++cIt, ++vIt) {
|
| |
|
| |
|
| | ++nPtsUsed;
|
| | Base::Vector3d& v = *vIt;
|
| | setupObservation(solDir, *cIt, v, a, f0, qw, b);
|
| | double qv = -f0;
|
| | for (int i = 0; i < dim; ++i) {
|
| | qv += a[i] * x(i);
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | double vx = -qw * qv * b[0];
|
| | double vy = -qw * qv * b[1];
|
| | double vz = -qw * qv * b[2];
|
| | double dVx = fabs(vx - v.x);
|
| | double dVy = fabs(vy - v.y);
|
| | double dVz = fabs(vz - v.z);
|
| | v.x = vx;
|
| | v.y = vy;
|
| | v.z = vz;
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | sigma0 += v.x * v.x + v.y * v.y + v.z * v.z;
|
| |
|
| | if ((dVx > vConvLimit) || (dVy > vConvLimit) || (dVz > vConvLimit)) {
|
| | vConverged = false;
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | }
|
| |
|
| |
|
| | if (nPtsUsed < minPts) {
|
| | sigma0 = 0.0;
|
| | return false;
|
| | }
|
| | int df = nPtsUsed - minPts;
|
| | if (df == 0) {
|
| | sigma0 = 0.0;
|
| | }
|
| | else {
|
| | sigma0 = sqrt(sigma0 / (double)df);
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | return true;
|
| | }
|
| |
|
| |
|
| | bool CylinderFit::updateParameters(SolutionD solDir, const Eigen::VectorXd& x)
|
| | {
|
| |
|
| | switch (solDir) {
|
| | case solL:
|
| | _vBase.y += x(0);
|
| | _vBase.z += x(1);
|
| | _vAxis.y += x(2);
|
| | _vAxis.z += x(3);
|
| | _dRadius += x(4);
|
| | break;
|
| | case solM:
|
| | _vBase.x += x(0);
|
| | _vBase.z += x(1);
|
| | _vAxis.x += x(2);
|
| | _vAxis.z += x(3);
|
| | _dRadius += x(4);
|
| | break;
|
| | case solN:
|
| | _vBase.x += x(0);
|
| | _vBase.y += x(1);
|
| | _vAxis.x += x(2);
|
| | _vAxis.y += x(3);
|
| | _dRadius += x(4);
|
| | break;
|
| | }
|
| |
|
| |
|
| | double l2 {};
|
| | double m2 {};
|
| | double n2 {};
|
| | switch (solDir) {
|
| | case solL:
|
| | l2 = 1.0 - _vAxis.y * _vAxis.y - _vAxis.z * _vAxis.z;
|
| | if (l2 <= 0.0) {
|
| | return false;
|
| | }
|
| | _vAxis.x = sqrt(l2);
|
| |
|
| | break;
|
| | case solM:
|
| | m2 = 1.0 - _vAxis.x * _vAxis.x - _vAxis.z * _vAxis.z;
|
| | if (m2 <= 0.0) {
|
| | return false;
|
| | }
|
| | _vAxis.y = sqrt(m2);
|
| |
|
| | break;
|
| | case solN:
|
| | n2 = 1.0 - _vAxis.x * _vAxis.x - _vAxis.y * _vAxis.y;
|
| | if (n2 <= 0.0) {
|
| | return false;
|
| | }
|
| | _vAxis.z = sqrt(n2);
|
| |
|
| | break;
|
| | }
|
| |
|
| | return true;
|
| | }
|
| |
|