AbdulElahGwaith's picture
Upload folder using huggingface_hub
985c397 verified
// SPDX-License-Identifier: LGPL-2.1-or-later
/***************************************************************************
* Copyright (c) 2008 Werner Mayer <wmayer[at]users.sourceforge.net> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include <QFuture>
#include <QFutureWatcher>
#include <QtConcurrentMap>
#include <Geom_BSplineSurface.hxx>
#include <Precision.hxx>
#include <math_Gauss.hxx>
#include <math_Householder.hxx>
#include <Base/Sequencer.h>
#include <Base/Tools.h>
#include <Mod/Mesh/App/Core/Approximation.h>
#include "ApproxSurface.h"
using namespace Reen;
namespace sp = std::placeholders;
// SplineBasisfunction
SplineBasisfunction::SplineBasisfunction(int iSize)
: _vKnotVector(0, iSize - 1)
, _iOrder(1)
{}
SplineBasisfunction::SplineBasisfunction(
TColStd_Array1OfReal& vKnots,
TColStd_Array1OfInteger& vMults,
int iSize,
int iOrder
)
: _vKnotVector(0, iSize - 1)
{
int sum = 0;
for (int h = vMults.Lower(); h <= vMults.Upper(); h++) {
sum += vMults(h);
}
if (vKnots.Length() != vMults.Length() || iSize != sum) {
// Throw exception
Standard_ConstructionError::Raise("BSplineBasis");
}
int k = 0;
for (int i = vMults.Lower(); i <= vMults.Upper(); i++) {
for (int j = 0; j < vMults(i); j++) {
_vKnotVector(k) = vKnots(i);
k++;
}
}
_iOrder = iOrder;
}
SplineBasisfunction::SplineBasisfunction(TColStd_Array1OfReal& vKnots, int iOrder)
: _vKnotVector(0, vKnots.Length() - 1)
{
_vKnotVector = vKnots;
_iOrder = iOrder;
}
SplineBasisfunction::~SplineBasisfunction() = default;
void SplineBasisfunction::SetKnots(TColStd_Array1OfReal& vKnots, int iOrder)
{
if (_vKnotVector.Length() != vKnots.Length()) {
Standard_RangeError::Raise("BSplineBasis");
}
_vKnotVector = vKnots;
_iOrder = iOrder;
}
void SplineBasisfunction::SetKnots(TColStd_Array1OfReal& vKnots, TColStd_Array1OfInteger& vMults, int iOrder)
{
int sum = 0;
for (int h = vMults.Lower(); h <= vMults.Upper(); h++) {
sum += vMults(h);
}
if (vKnots.Length() != vMults.Length() || _vKnotVector.Length() != sum) {
// Throw exception
Standard_RangeError::Raise("BSplineBasis");
}
int k = 0;
for (int i = vMults.Lower(); i <= vMults.Upper(); i++) {
for (int j = 0; j < vMults(i); j++) {
_vKnotVector(k) = vKnots(i);
k++;
}
}
_iOrder = iOrder;
}
////////////////////////////////////////// BSplineBasis
BSplineBasis::BSplineBasis(int iSize)
: SplineBasisfunction(iSize)
{}
BSplineBasis::BSplineBasis(
TColStd_Array1OfReal& vKnots,
TColStd_Array1OfInteger& vMults,
int iSize,
int iOrder
)
: SplineBasisfunction(vKnots, vMults, iSize, iOrder)
{}
BSplineBasis::BSplineBasis(TColStd_Array1OfReal& vKnots, int iOrder)
: SplineBasisfunction(vKnots, iOrder)
{}
BSplineBasis::~BSplineBasis() = default;
int BSplineBasis::FindSpan(double fParam)
{
int n = _vKnotVector.Length() - _iOrder - 1;
if (fParam == _vKnotVector(n + 1)) {
return n;
}
int low = _iOrder - 1;
int high = n + 1;
int mid = (low + high) / 2; // Binary search
while (fParam < _vKnotVector(mid) || fParam >= _vKnotVector(mid + 1)) {
if (fParam < _vKnotVector(mid)) {
high = mid;
}
else {
low = mid;
}
mid = (low + high) / 2;
}
return mid;
}
void BSplineBasis::AllBasisFunctions(double fParam, TColStd_Array1OfReal& vFuncVals)
{
if (vFuncVals.Length() != _iOrder) {
Standard_RangeError::Raise("BSplineBasis");
}
int iIndex = FindSpan(fParam);
TColStd_Array1OfReal zaehler_left(1, _iOrder - 1);
TColStd_Array1OfReal zaehler_right(1, _iOrder - 1);
vFuncVals(0) = 1.0;
for (int j = 1; j < _iOrder; j++) {
zaehler_left(j) = fParam - _vKnotVector(iIndex + 1 - j);
zaehler_right(j) = _vKnotVector(iIndex + j) - fParam;
double saved = 0.0;
for (int r = 0; r < j; r++) {
double tmp = vFuncVals(r) / (zaehler_right(r + 1) + zaehler_left(j - r));
vFuncVals(r) = saved + zaehler_right(r + 1) * tmp;
saved = zaehler_left(j - r) * tmp;
}
vFuncVals(j) = saved;
}
}
BSplineBasis::ValueT BSplineBasis::LocalSupport(int iIndex, double fParam)
{
int m = _vKnotVector.Length() - 1;
int p = _iOrder - 1;
if ((iIndex == 0 && fParam == _vKnotVector(0))
|| (iIndex == m - p - 1 && fParam == _vKnotVector(m))) {
return BSplineBasis::Full;
}
if (fParam < _vKnotVector(iIndex) || fParam >= _vKnotVector(iIndex + p + 1)) {
return BSplineBasis::Zero;
}
return BSplineBasis::Other;
}
double BSplineBasis::BasisFunction(int iIndex, double fParam)
{
int m = _vKnotVector.Length() - 1;
int p = _iOrder - 1;
double saved;
TColStd_Array1OfReal N(0, p);
if ((iIndex == 0 && fParam == _vKnotVector(0))
|| (iIndex == m - p - 1 && fParam == _vKnotVector(m))) {
return 1.0;
}
if (fParam < _vKnotVector(iIndex) || fParam >= _vKnotVector(iIndex + p + 1)) {
return 0.0;
}
for (int j = 0; j <= p; j++) {
if (fParam >= _vKnotVector(iIndex + j) && fParam < _vKnotVector(iIndex + j + 1)) {
N(j) = 1.0;
}
else {
N(j) = 0.0;
}
}
for (int k = 1; k <= p; k++) {
if (N(0) == 0.0) {
saved = 0.0;
}
else {
saved = ((fParam - _vKnotVector(iIndex)) * N(0))
/ (_vKnotVector(iIndex + k) - _vKnotVector(iIndex));
}
for (int j = 0; j < p - k + 1; j++) {
double Tleft = _vKnotVector(iIndex + j + 1);
double Tright = _vKnotVector(iIndex + j + k + 1);
if (N(j + 1) == 0.0) {
N(j) = saved;
saved = 0.0;
}
else {
double tmp = N(j + 1) / (Tright - Tleft);
N(j) = saved + (Tright - fParam) * tmp;
saved = (fParam - Tleft) * tmp;
}
}
}
return N(0);
}
void BSplineBasis::DerivativesOfBasisFunction(
int iIndex,
int iMaxDer,
double fParam,
TColStd_Array1OfReal& Derivat
)
{
int iMax = iMaxDer;
if (Derivat.Length() != iMax + 1) {
Standard_RangeError::Raise("BSplineBasis");
}
// kth derivatives (k> degrees) are zero
if (iMax >= _iOrder) {
for (int i = _iOrder; i <= iMaxDer; i++) {
Derivat(i) = 0.0;
}
iMax = _iOrder - 1;
}
TColStd_Array1OfReal ND(0, iMax);
int p = _iOrder - 1;
math_Matrix N(0, p, 0, p);
double saved;
// if value is outside the interval, then function value and all derivatives equal null
if (fParam < _vKnotVector(iIndex) || fParam >= _vKnotVector(iIndex + p + 1)) {
for (int k = 0; k <= iMax; k++) {
Derivat(k) = 0.0;
}
return;
}
// Calculate the basis functions of Order 1
for (int j = 0; j < _iOrder; j++) {
if (fParam >= _vKnotVector(iIndex + j) && fParam < _vKnotVector(iIndex + j + 1)) {
N(j, 0) = 1.0;
}
else {
N(j, 0) = 0.0;
}
}
// Calculate a triangular table of the function values
for (int k = 1; k < _iOrder; k++) {
if (N(0, k - 1) == 0.0) {
saved = 0.0;
}
else {
saved = ((fParam - _vKnotVector(iIndex)) * N(0, k - 1))
/ (_vKnotVector(iIndex + k) - _vKnotVector(iIndex));
}
for (int j = 0; j < p - k + 1; j++) {
double Tleft = _vKnotVector(iIndex + j + 1);
double Tright = _vKnotVector(iIndex + j + k + 1);
if (N(j + 1, k - 1) == 0.0) {
N(j, k) = saved;
saved = 0.0;
}
else {
double tmp = N(j + 1, k - 1) / (Tright - Tleft);
N(j, k) = saved + (Tright - fParam) * tmp;
saved = (fParam - Tleft) * tmp;
}
}
}
// Function value
Derivat(0) = N(0, p);
// Calculate the derivatives from the triangle table
for (int k = 1; k <= iMax; k++) {
for (int j = 0; j <= k; j++) {
// Load the (p-k)th column
ND(j) = N(j, p - k);
}
for (int jj = 1; jj <= k; jj++) {
if (ND(0) == 0.0) {
saved = 0.0;
}
else {
saved = ND(0) / (_vKnotVector(iIndex + p - k + jj) - _vKnotVector(iIndex));
}
for (int j = 0; j < k - jj + 1; j++) {
double Tleft = _vKnotVector(iIndex + j + 1);
double Tright = _vKnotVector(iIndex + j + p - k + jj + 1);
if (ND(j + 1) == 0.0) {
ND(j) = (p - k + jj) * saved;
saved = 0.0;
}
else {
double tmp = ND(j + 1) / (Tright - Tleft);
ND(j) = (p - k + jj) * (saved - tmp);
saved = tmp;
}
}
}
Derivat(k) = ND(0); // kth derivative
}
}
double BSplineBasis::DerivativeOfBasisFunction(int iIndex, int iMaxDer, double fParam)
{
int iMax = iMaxDer;
// Function value (0th derivative)
if (iMax == 0) {
return BasisFunction(iIndex, fParam);
}
// The kth derivatives (k>degrees) are null
if (iMax >= _iOrder) {
return 0.0;
}
TColStd_Array1OfReal ND(0, iMax);
int p = _iOrder - 1;
math_Matrix N(0, p, 0, p);
double saved;
// If value is outside the interval, then function value and derivatives equal null
if (fParam < _vKnotVector(iIndex) || fParam >= _vKnotVector(iIndex + p + 1)) {
return 0.0;
}
// Calculate the basis functions of Order 1
for (int j = 0; j < _iOrder; j++) {
if (fParam >= _vKnotVector(iIndex + j) && fParam < _vKnotVector(iIndex + j + 1)) {
N(j, 0) = 1.0;
}
else {
N(j, 0) = 0.0;
}
}
// Calculate triangular table of function values
for (int k = 1; k < _iOrder; k++) {
if (N(0, k - 1) == 0.0) {
saved = 0.0;
}
else {
saved = ((fParam - _vKnotVector(iIndex)) * N(0, k - 1))
/ (_vKnotVector(iIndex + k) - _vKnotVector(iIndex));
}
for (int j = 0; j < p - k + 1; j++) {
double Tleft = _vKnotVector(iIndex + j + 1);
double Tright = _vKnotVector(iIndex + j + k + 1);
if (N(j + 1, k - 1) == 0.0) {
N(j, k) = saved;
saved = 0.0;
}
else {
double tmp = N(j + 1, k - 1) / (Tright - Tleft);
N(j, k) = saved + (Tright - fParam) * tmp;
saved = (fParam - Tleft) * tmp;
}
}
}
// Use the triangular table to calculate the derivatives
for (int j = 0; j <= iMax; j++) {
// Loading (p-iMax)th column
ND(j) = N(j, p - iMax);
}
for (int jj = 1; jj <= iMax; jj++) {
if (ND(0) == 0.0) {
saved = 0.0;
}
else {
saved = ND(0) / (_vKnotVector(iIndex + p - iMax + jj) - _vKnotVector(iIndex));
}
for (int j = 0; j < iMax - jj + 1; j++) {
double Tleft = _vKnotVector(iIndex + j + 1);
double Tright = _vKnotVector(iIndex + j + p - iMax + jj + 1);
if (ND(j + 1) == 0.0) {
ND(j) = (p - iMax + jj) * saved;
saved = 0.0;
}
else {
double tmp = ND(j + 1) / (Tright - Tleft);
ND(j) = (p - iMax + jj) * (saved - tmp);
saved = tmp;
}
}
}
return ND(0); // iMax-th derivative
}
double BSplineBasis::GetIntegralOfProductOfBSplines(int iIdx1, int iIdx2, int iOrd1, int iOrd2)
{
int iMax = CalcSize(iOrd1, iOrd2);
double dIntegral = 0.0;
double fMin, fMax;
TColStd_Array1OfReal vRoots(0, iMax), vWeights(0, iMax);
GenerateRootsAndWeights(vRoots, vWeights);
/*Calculate the integral*/
// Integration area
int iBegin = 0;
int iEnd = 0;
FindIntegrationArea(iIdx1, iIdx2, iBegin, iEnd);
for (int j = iBegin; j < iEnd; j++) {
fMax = _vKnotVector(j + 1);
fMin = _vKnotVector(j);
if (fMax > fMin) {
for (int i = 0; i <= iMax; i++) {
double fParam = 0.5 * (vRoots(i) + 1) * (fMax - fMin) + fMin;
dIntegral += 0.5 * (fMax - fMin) * vWeights(i)
* DerivativeOfBasisFunction(iIdx1, iOrd1, fParam)
* DerivativeOfBasisFunction(iIdx2, iOrd2, fParam);
}
}
}
return dIntegral;
}
void BSplineBasis::GenerateRootsAndWeights(TColStd_Array1OfReal& vRoots, TColStd_Array1OfReal& vWeights)
{
int iSize = vRoots.Length();
// Zeroing the Legendre-Polynomials and the corresponding weights
if (iSize == 1) {
vRoots(0) = 0.0;
vWeights(0) = 2.0;
}
else if (iSize == 2) {
vRoots(0) = 0.57735;
vWeights(0) = 1.0;
vRoots(1) = -vRoots(0);
vWeights(1) = vWeights(0);
}
else if (iSize == 4) {
vRoots(0) = 0.33998;
vWeights(0) = 0.65214;
vRoots(1) = 0.86113;
vWeights(1) = 0.34785;
vRoots(2) = -vRoots(0);
vWeights(2) = vWeights(0);
vRoots(3) = -vRoots(1);
vWeights(3) = vWeights(1);
}
else if (iSize == 6) {
vRoots(0) = 0.23861;
vWeights(0) = 0.46791;
vRoots(1) = 0.66120;
vWeights(1) = 0.36076;
vRoots(2) = 0.93246;
vWeights(2) = 0.17132;
vRoots(3) = -vRoots(0);
vWeights(3) = vWeights(0);
vRoots(4) = -vRoots(1);
vWeights(4) = vWeights(1);
vRoots(5) = -vRoots(2);
vWeights(5) = vWeights(2);
}
else if (iSize == 8) {
vRoots(0) = 0.18343;
vWeights(0) = 0.36268;
vRoots(1) = 0.52553;
vWeights(1) = 0.31370;
vRoots(2) = 0.79666;
vWeights(2) = 0.22238;
vRoots(3) = 0.96028;
vWeights(3) = 0.10122;
vRoots(4) = -vRoots(0);
vWeights(4) = vWeights(0);
vRoots(5) = -vRoots(1);
vWeights(5) = vWeights(1);
vRoots(6) = -vRoots(2);
vWeights(6) = vWeights(2);
vRoots(7) = -vRoots(3);
vWeights(7) = vWeights(3);
}
else if (iSize == 10) {
vRoots(0) = 0.14887;
vWeights(0) = 0.29552;
vRoots(1) = 0.43339;
vWeights(1) = 0.26926;
vRoots(2) = 0.67940;
vWeights(2) = 0.21908;
vRoots(3) = 0.86506;
vWeights(3) = 0.14945;
vRoots(4) = 0.97390;
vWeights(4) = 0.06667;
vRoots(5) = -vRoots(0);
vWeights(5) = vWeights(0);
vRoots(6) = -vRoots(1);
vWeights(6) = vWeights(1);
vRoots(7) = -vRoots(2);
vWeights(7) = vWeights(2);
vRoots(8) = -vRoots(3);
vWeights(8) = vWeights(3);
vRoots(9) = -vRoots(4);
vWeights(9) = vWeights(4);
}
else {
vRoots(0) = 0.12523;
vWeights(0) = 0.24914;
vRoots(1) = 0.36783;
vWeights(1) = 0.23349;
vRoots(2) = 0.58731;
vWeights(2) = 0.20316;
vRoots(3) = 0.76990;
vWeights(3) = 0.16007;
vRoots(4) = 0.90411;
vWeights(4) = 0.10693;
vRoots(5) = 0.98156;
vWeights(5) = 0.04717;
vRoots(6) = -vRoots(0);
vWeights(6) = vWeights(0);
vRoots(7) = -vRoots(1);
vWeights(7) = vWeights(1);
vRoots(8) = -vRoots(2);
vWeights(8) = vWeights(2);
vRoots(9) = -vRoots(3);
vWeights(9) = vWeights(3);
vRoots(10) = -vRoots(4);
vWeights(10) = vWeights(4);
vRoots(11) = -vRoots(5);
vWeights(11) = vWeights(5);
}
}
void BSplineBasis::FindIntegrationArea(int iIdx1, int iIdx2, int& iBegin, int& iEnd)
{
// order by index
if (iIdx2 < iIdx1) {
int tmp = iIdx1;
iIdx1 = iIdx2;
iIdx2 = tmp;
}
iBegin = iIdx2;
iEnd = iIdx1 + _iOrder;
if (iEnd == _vKnotVector.Upper()) {
iEnd -= 1;
}
}
int BSplineBasis::CalcSize(int r, int s)
{
int iMaxDegree = 2 * (_iOrder - 1) - r - s;
if (iMaxDegree < 0) {
return 0;
}
else if (iMaxDegree < 4) {
return 1;
}
else if (iMaxDegree < 8) {
return 3;
}
else if (iMaxDegree < 12) {
return 5;
}
else if (iMaxDegree < 16) {
return 7;
}
else if (iMaxDegree < 20) {
return 9;
}
else {
return 11;
}
}
/////////////////// ParameterCorrection
ParameterCorrection::ParameterCorrection(
unsigned usUOrder,
unsigned usVOrder,
unsigned usUCtrlpoints,
unsigned usVCtrlpoints
)
: _usUOrder(usUOrder)
, _usVOrder(usVOrder)
, _usUCtrlpoints(usUCtrlpoints)
, _usVCtrlpoints(usVCtrlpoints)
, _vCtrlPntsOfSurf(0, usUCtrlpoints - 1, 0, usVCtrlpoints - 1)
, _vUKnots(0, usUCtrlpoints - usUOrder + 1)
, _vVKnots(0, usVCtrlpoints - usVOrder + 1)
, _vUMults(0, usUCtrlpoints - usUOrder + 1)
, _vVMults(0, usVCtrlpoints - usVOrder + 1)
{
_bGetUVDir = false;
_bSmoothing = false;
_fSmoothInfluence = 0.0;
}
void ParameterCorrection::CalcEigenvectors()
{
MeshCore::PlaneFit planeFit;
for (int i = _pvcPoints->Lower(); i <= _pvcPoints->Upper(); i++) {
const gp_Pnt& pnt = (*_pvcPoints)(i);
planeFit.AddPoint(Base::Vector3f((float)pnt.X(), (float)pnt.Y(), (float)pnt.Z()));
}
planeFit.Fit();
_clU = Base::toVector<double>(planeFit.GetDirU());
_clV = Base::toVector<double>(planeFit.GetDirV());
_clW = Base::toVector<double>(planeFit.GetNormal());
}
bool ParameterCorrection::DoInitialParameterCorrection(double fSizeFactor)
{
// if directions are not given, calculate yourself
if (!_bGetUVDir) {
CalcEigenvectors();
}
if (!GetUVParameters(fSizeFactor)) {
return false;
}
if (_bSmoothing) {
if (!SolveWithSmoothing(_fSmoothInfluence)) {
return false;
}
}
else {
if (!SolveWithoutSmoothing()) {
return false;
}
}
return true;
}
bool ParameterCorrection::GetUVParameters(double fSizeFactor)
{
// Eigenvectors as a new base
Base::Vector3d e[3];
e[0] = _clU;
e[1] = _clV;
e[2] = _clW;
// Canonical base of R^3
Base::Vector3d b[3];
b[0] = Base::Vector3d(1.0, 0.0, 0.0);
b[1] = Base::Vector3d(0.0, 1.0, 0.0);
b[2] = Base::Vector3d(0.0, 0.0, 1.0);
// Create a right system from the orthogonal eigenvectors
if ((e[0] % e[1]) * e[2] < 0) {
Base::Vector3d tmp = e[0];
e[0] = e[1];
e[1] = tmp;
}
// Now generate the transpon. Rotation matrix
Wm4::Matrix3d clRotMatTrans;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
clRotMatTrans[i][j] = b[j] * e[i];
}
}
std::vector<Base::Vector2d> vcProjPts;
Base::BoundBox2d clBBox;
// Calculate the coordinates of the transf. Points and project
// these on to the x,y-plane of the new coordinate system
for (int ii = _pvcPoints->Lower(); ii <= _pvcPoints->Upper(); ii++) {
const gp_Pnt& pnt = (*_pvcPoints)(ii);
Wm4::Vector3d clProjPnt = clRotMatTrans * Wm4::Vector3d(pnt.X(), pnt.Y(), pnt.Z());
vcProjPts.emplace_back(clProjPnt.X(), clProjPnt.Y());
clBBox.Add(Base::Vector2d(clProjPnt.X(), clProjPnt.Y()));
}
if ((clBBox.MaxX == clBBox.MinX) || (clBBox.MaxY == clBBox.MinY)) {
return false;
}
double tx = fSizeFactor * clBBox.MinX - (fSizeFactor - 1.0) * clBBox.MaxX;
double ty = fSizeFactor * clBBox.MinY - (fSizeFactor - 1.0) * clBBox.MaxY;
double fDeltaX = (2 * fSizeFactor - 1.0) * (clBBox.MaxX - clBBox.MinX);
double fDeltaY = (2 * fSizeFactor - 1.0) * (clBBox.MaxY - clBBox.MinY);
// Calculate the u,v parameters with u,v from [0,1]
_pvcUVParam->Init(gp_Pnt2d(0.0, 0.0));
int ii = 0;
if (clBBox.MaxX - clBBox.MinX >= clBBox.MaxY - clBBox.MinY) {
for (const auto& pt : vcProjPts) {
(*_pvcUVParam)(ii) = gp_Pnt2d((pt.x - tx) / fDeltaX, (pt.y - ty) / fDeltaY);
ii++;
}
}
else {
for (const auto& pt : vcProjPts) {
(*_pvcUVParam)(ii) = gp_Pnt2d((pt.y - ty) / fDeltaY, (pt.x - tx) / fDeltaX);
ii++;
}
}
return true;
}
void ParameterCorrection::SetUV(const Base::Vector3d& clU, const Base::Vector3d& clV, bool bUseDir)
{
_bGetUVDir = bUseDir;
if (_bGetUVDir) {
_clU = clU;
_clW = clU % clV;
_clV = _clW % _clU;
}
}
void ParameterCorrection::GetUVW(Base::Vector3d& clU, Base::Vector3d& clV, Base::Vector3d& clW) const
{
clU = _clU;
clV = _clV;
clW = _clW;
}
Base::Vector3d ParameterCorrection::GetGravityPoint() const
{
Standard_Integer ulSize = _pvcPoints->Length();
double x = 0.0, y = 0.0, z = 0.0;
for (int i = _pvcPoints->Lower(); i <= _pvcPoints->Upper(); i++) {
const gp_Pnt& pnt = (*_pvcPoints)(i);
x += pnt.X();
y += pnt.Y();
z += pnt.Z();
}
return Base::Vector3d(x / ulSize, y / ulSize, z / ulSize);
}
void ParameterCorrection::ProjectControlPointsOnPlane()
{
Base::Vector3d base = GetGravityPoint();
for (unsigned j = 0; j < _usUCtrlpoints; j++) {
for (unsigned k = 0; k < _usVCtrlpoints; k++) {
gp_Pnt pole = _vCtrlPntsOfSurf(j, k);
Base::Vector3d pnt(pole.X(), pole.Y(), pole.Z());
pnt.ProjectToPlane(base, _clW);
pole.SetX(pnt.x);
pole.SetY(pnt.y);
pole.SetZ(pnt.z);
_vCtrlPntsOfSurf(j, k) = pole;
}
}
}
Handle(Geom_BSplineSurface) ParameterCorrection::CreateSurface(
const TColgp_Array1OfPnt& points,
int iIter,
bool bParaCor,
double fSizeFactor
)
{
if (_pvcPoints) {
delete _pvcPoints;
_pvcPoints = nullptr;
delete _pvcUVParam;
_pvcUVParam = nullptr;
}
_pvcPoints = new TColgp_Array1OfPnt(points.Lower(), points.Upper());
*_pvcPoints = points;
_pvcUVParam = new TColgp_Array1OfPnt2d(points.Lower(), points.Upper());
if (_usUCtrlpoints * _usVCtrlpoints > static_cast<unsigned>(_pvcPoints->Length())) {
return nullptr; // LGS under-determined
}
if (!DoInitialParameterCorrection(fSizeFactor)) {
return nullptr;
}
// Generate the approximation plane as a B-spline area
if (iIter < 0) {
bParaCor = false;
ProjectControlPointsOnPlane();
}
// No further parameter corrections
else if (iIter == 0) {
bParaCor = false;
}
if (bParaCor) {
DoParameterCorrection(iIter);
}
return new Geom_BSplineSurface(
_vCtrlPntsOfSurf,
_vUKnots,
_vVKnots,
_vUMults,
_vVMults,
_usUOrder - 1,
_usVOrder - 1
);
}
void ParameterCorrection::EnableSmoothing(bool bSmooth, double fSmoothInfl)
{
_bSmoothing = bSmooth;
_fSmoothInfluence = fSmoothInfl;
}
/////////////////// BSplineParameterCorrection
BSplineParameterCorrection::BSplineParameterCorrection(
unsigned usUOrder,
unsigned usVOrder,
unsigned usUCtrlpoints,
unsigned usVCtrlpoints
)
: ParameterCorrection(usUOrder, usVOrder, usUCtrlpoints, usVCtrlpoints)
, _clUSpline(usUCtrlpoints + usUOrder)
, _clVSpline(usVCtrlpoints + usVOrder)
, _clSmoothMatrix(0, usUCtrlpoints * usVCtrlpoints - 1, 0, usUCtrlpoints * usVCtrlpoints - 1)
, _clFirstMatrix(0, usUCtrlpoints * usVCtrlpoints - 1, 0, usUCtrlpoints * usVCtrlpoints - 1)
, _clSecondMatrix(0, usUCtrlpoints * usVCtrlpoints - 1, 0, usUCtrlpoints * usVCtrlpoints - 1)
, _clThirdMatrix(0, usUCtrlpoints * usVCtrlpoints - 1, 0, usUCtrlpoints * usVCtrlpoints - 1)
{
Init();
}
void BSplineParameterCorrection::Init()
{
// Initializations
_pvcUVParam = nullptr;
_pvcPoints = nullptr;
_clFirstMatrix.Init(0.0);
_clSecondMatrix.Init(0.0);
_clThirdMatrix.Init(0.0);
_clSmoothMatrix.Init(0.0);
/* Calculate the knot vectors */
unsigned usUMax = _usUCtrlpoints - _usUOrder + 1;
unsigned usVMax = _usVCtrlpoints - _usVOrder + 1;
// Knot vector for the CAS.CADE class
// u-direction
for (unsigned i = 0; i <= usUMax; i++) {
_vUKnots(i) = static_cast<double>(i) / static_cast<double>(usUMax);
_vUMults(i) = 1;
}
_vUMults(0) = _usUOrder;
_vUMults(usUMax) = _usUOrder;
// v-direction
for (unsigned i = 0; i <= usVMax; i++) {
_vVKnots(i) = static_cast<double>(i) / static_cast<double>(usVMax);
_vVMults(i) = 1;
}
_vVMults(0) = _usVOrder;
_vVMults(usVMax) = _usVOrder;
// Set the B-spline basic functions
_clUSpline.SetKnots(_vUKnots, _vUMults, _usUOrder);
_clVSpline.SetKnots(_vVKnots, _vVMults, _usVOrder);
}
void BSplineParameterCorrection::SetUKnots(const std::vector<double>& afKnots)
{
std::size_t numPoints = static_cast<std::size_t>(_usUCtrlpoints);
std::size_t order = static_cast<std::size_t>(_usUOrder);
if (afKnots.size() != (numPoints + order)) {
return;
}
unsigned usUMax = _usUCtrlpoints - _usUOrder + 1;
// Knot vector for the CAS.CADE class
// u-direction
for (unsigned i = 1; i < usUMax; i++) {
_vUKnots(i) = afKnots[_usUOrder + i - 1];
_vUMults(i) = 1;
}
// Set the B-spline basic functions
_clUSpline.SetKnots(_vUKnots, _vUMults, _usUOrder);
}
void BSplineParameterCorrection::SetVKnots(const std::vector<double>& afKnots)
{
std::size_t numPoints = static_cast<std::size_t>(_usVCtrlpoints);
std::size_t order = static_cast<std::size_t>(_usVOrder);
if (afKnots.size() != (numPoints + order)) {
return;
}
unsigned usVMax = _usVCtrlpoints - _usVOrder + 1;
// Knot vector for the CAS.CADE class
// v-direction
for (unsigned i = 1; i < usVMax; i++) {
_vVKnots(i) = afKnots[_usVOrder + i - 1];
_vVMults(i) = 1;
}
// Set the B-spline basic functions
_clVSpline.SetKnots(_vVKnots, _vVMults, _usVOrder);
}
void BSplineParameterCorrection::DoParameterCorrection(int iIter)
{
int i = 0;
double fMaxDiff = 0.0, fMaxScalar = 1.0;
double fWeight = _fSmoothInfluence;
Base::SequencerLauncher seq(
"Calc surface...",
static_cast<size_t>(iIter) * static_cast<size_t>(_pvcPoints->Length())
);
do {
fMaxScalar = 1.0;
fMaxDiff = 0.0;
Handle(Geom_BSplineSurface) pclBSplineSurf = new Geom_BSplineSurface(
_vCtrlPntsOfSurf,
_vUKnots,
_vVKnots,
_vUMults,
_vVMults,
_usUOrder - 1,
_usVOrder - 1
);
for (int ii = _pvcPoints->Lower(); ii <= _pvcPoints->Upper(); ii++) {
double fDeltaU, fDeltaV, fU, fV;
const gp_Pnt& pnt = (*_pvcPoints)(ii);
gp_Vec P(pnt.X(), pnt.Y(), pnt.Z());
gp_Pnt PntX;
gp_Vec Xu, Xv, Xuv, Xuu, Xvv;
// Calculate the first two derivatives and point at (u,v)
gp_Pnt2d& uvValue = (*_pvcUVParam)(ii);
pclBSplineSurf->D2(uvValue.X(), uvValue.Y(), PntX, Xu, Xv, Xuu, Xvv, Xuv);
gp_Vec X(PntX.X(), PntX.Y(), PntX.Z());
gp_Vec ErrorVec = X - P;
// Calculate Xu x Xv the normal in X(u,v)
gp_Dir clNormal = Xu ^ Xv;
// Check, if X = P
if (!(X.IsEqual(P, 0.001, 0.001))) {
ErrorVec.Normalize();
if (fabs(clNormal * ErrorVec) < fMaxScalar) {
fMaxScalar = fabs(clNormal * ErrorVec);
}
}
fDeltaU = ((P - X) * Xu) / ((P - X) * Xuu - Xu * Xu);
if (fabs(fDeltaU) < Precision::Confusion()) {
fDeltaU = 0.0;
}
fDeltaV = ((P - X) * Xv) / ((P - X) * Xvv - Xv * Xv);
if (fabs(fDeltaV) < Precision::Confusion()) {
fDeltaV = 0.0;
}
// Replace old u/v values with new ones
fU = uvValue.X() - fDeltaU;
fV = uvValue.Y() - fDeltaV;
if (fU <= 1.0 && fU >= 0.0 && fV <= 1.0 && fV >= 0.0) {
uvValue.SetX(fU);
uvValue.SetY(fV);
fMaxDiff = std::max<double>(fabs(fDeltaU), fMaxDiff);
fMaxDiff = std::max<double>(fabs(fDeltaV), fMaxDiff);
}
seq.next();
}
if (_bSmoothing) {
fWeight *= 0.5f;
SolveWithSmoothing(fWeight);
}
else {
SolveWithoutSmoothing();
}
i++;
} while (i < iIter && fMaxDiff > Precision::Confusion() && fMaxScalar < 0.99);
}
bool BSplineParameterCorrection::SolveWithoutSmoothing()
{
unsigned ulSize = _pvcPoints->Length();
unsigned ulDim = _usUCtrlpoints * _usVCtrlpoints;
math_Matrix M(0, ulSize - 1, 0, ulDim - 1);
math_Matrix Xx(0, ulDim - 1, 0, 0);
math_Matrix Xy(0, ulDim - 1, 0, 0);
math_Matrix Xz(0, ulDim - 1, 0, 0);
math_Vector bx(0, ulSize - 1);
math_Vector by(0, ulSize - 1);
math_Vector bz(0, ulSize - 1);
// Determining the coefficient matrix of the overdetermined LGS
for (unsigned i = 0; i < ulSize; i++) {
const gp_Pnt2d& uvValue = (*_pvcUVParam)(i);
double fU = uvValue.X();
double fV = uvValue.Y();
unsigned ulIdx = 0;
// Pre-calculation of the values of the base functions
std::vector<double> basisU(_usUCtrlpoints);
for (unsigned j = 0; j < _usUCtrlpoints; j++) {
basisU[j] = _clUSpline.BasisFunction(j, fU);
}
std::vector<double> basisV(_usVCtrlpoints);
for (unsigned k = 0; k < _usVCtrlpoints; k++) {
basisV[k] = _clVSpline.BasisFunction(k, fV);
}
for (unsigned j = 0; j < _usUCtrlpoints; j++) {
double valueU = basisU[j];
if (valueU == 0.0) {
for (unsigned k = 0; k < _usVCtrlpoints; k++) {
M(i, ulIdx) = 0.0;
ulIdx++;
}
}
else {
for (unsigned k = 0; k < _usVCtrlpoints; k++) {
M(i, ulIdx) = valueU * basisV[k];
ulIdx++;
}
}
}
}
// Determine the right side
for (int ii = _pvcPoints->Lower(); ii <= _pvcPoints->Upper(); ii++) {
const gp_Pnt& pnt = (*_pvcPoints)(ii);
bx(ii) = pnt.X();
by(ii) = pnt.Y();
bz(ii) = pnt.Z();
}
// Solve the over-determined LGS with Householder-Transformation
math_Householder hhX(M, bx);
math_Householder hhY(M, by);
math_Householder hhZ(M, bz);
if (!(hhX.IsDone() && hhY.IsDone() && hhZ.IsDone())) {
// LGS could not be solved
return false;
}
Xx = hhX.AllValues();
Xy = hhY.AllValues();
Xz = hhZ.AllValues();
unsigned ulIdx = 0;
for (unsigned j = 0; j < _usUCtrlpoints; j++) {
for (unsigned k = 0; k < _usVCtrlpoints; k++) {
_vCtrlPntsOfSurf(j, k) = gp_Pnt(Xx(ulIdx, 0), Xy(ulIdx, 0), Xz(ulIdx, 0));
ulIdx++;
}
}
return true;
}
namespace Reen
{
class ScalarProduct
{
public:
explicit ScalarProduct(const math_Matrix& mat)
: mat(mat)
{}
std::vector<double> multiply(int col) const
{
math_Vector vec = mat.Col(col);
std::vector<double> out(mat.ColNumber());
for (int n = mat.LowerCol(); n <= mat.UpperCol(); n++) {
out[n] = vec * mat.Col(n);
}
return out;
}
private:
const math_Matrix& mat;
};
} // namespace Reen
bool BSplineParameterCorrection::SolveWithSmoothing(double fWeight)
{
unsigned ulSize = _pvcPoints->Length();
unsigned ulDim = _usUCtrlpoints * _usVCtrlpoints;
math_Matrix M(0, ulSize - 1, 0, ulDim - 1);
math_Vector Xx(0, ulDim - 1);
math_Vector Xy(0, ulDim - 1);
math_Vector Xz(0, ulDim - 1);
math_Vector bx(0, ulSize - 1);
math_Vector by(0, ulSize - 1);
math_Vector bz(0, ulSize - 1);
math_Vector Mbx(0, ulDim - 1);
math_Vector Mby(0, ulDim - 1);
math_Vector Mbz(0, ulDim - 1);
// Determining the coefficient matrix of the overdetermined LGS
for (unsigned i = 0; i < ulSize; i++) {
const gp_Pnt2d& uvValue = (*_pvcUVParam)(i);
double fU = uvValue.X();
double fV = uvValue.Y();
int ulIdx = 0;
// Pre-calculation of the values of the basis functions
std::vector<double> basisU(_usUCtrlpoints);
for (unsigned j = 0; j < _usUCtrlpoints; j++) {
basisU[j] = _clUSpline.BasisFunction(j, fU);
}
std::vector<double> basisV(_usVCtrlpoints);
for (unsigned k = 0; k < _usVCtrlpoints; k++) {
basisV[k] = _clVSpline.BasisFunction(k, fV);
}
for (unsigned j = 0; j < _usUCtrlpoints; j++) {
double valueU = basisU[j];
if (valueU == 0.0) {
for (unsigned k = 0; k < _usVCtrlpoints; k++) {
M(i, ulIdx) = 0.0;
ulIdx++;
}
}
else {
for (unsigned k = 0; k < _usVCtrlpoints; k++) {
M(i, ulIdx) = valueU * basisV[k];
ulIdx++;
}
}
}
}
// The product of its transform and itself results in the quadratic
// system matrix (slowly)
#if 0
math_Matrix MTM = M.TMultiply(M);
#elif 0
math_Matrix MTM(0, ulDim - 1, 0, ulDim - 1);
for (unsigned m = 0; m < ulDim; m++) {
math_Vector Mm = M.Col(m);
for (unsigned n = m; n < ulDim; n++) {
MTM(m, n) = MTM(n, m) = Mm * M.Col(n);
}
}
#else // multi-threaded
std::vector<int> columns(ulDim);
std::generate(columns.begin(), columns.end(), Base::iotaGen<int>(0));
ScalarProduct scalar(M);
// NOLINTBEGIN
QFuture<std::vector<double>> future
= QtConcurrent::mapped(columns, std::bind(&ScalarProduct::multiply, &scalar, sp::_1));
// NOLINTEND
QFutureWatcher<std::vector<double>> watcher;
watcher.setFuture(future);
watcher.waitForFinished();
math_Matrix MTM(0, ulDim - 1, 0, ulDim - 1);
int rowIndex = 0;
for (const auto& it : future) {
int colIndex = 0;
for (std::vector<double>::const_iterator jt = it.begin(); jt != it.end(); ++jt, colIndex++) {
MTM(rowIndex, colIndex) = *jt;
}
rowIndex++;
}
#endif
// Determine the right side
for (int ii = _pvcPoints->Lower(); ii <= _pvcPoints->Upper(); ii++) {
const gp_Pnt& pnt = (*_pvcPoints)(ii);
bx(ii) = pnt.X();
by(ii) = pnt.Y();
bz(ii) = pnt.Z();
}
for (unsigned i = 0; i < ulDim; i++) {
math_Vector Mi = M.Col(i);
Mbx(i) = Mi * bx;
Mby(i) = Mi * by;
Mbz(i) = Mi * bz;
}
// Solve the LGS with the LU decomposition
math_Gauss mgGaussX(MTM + fWeight * _clSmoothMatrix);
math_Gauss mgGaussY(MTM + fWeight * _clSmoothMatrix);
math_Gauss mgGaussZ(MTM + fWeight * _clSmoothMatrix);
mgGaussX.Solve(Mbx, Xx);
if (!mgGaussX.IsDone()) {
return false;
}
mgGaussY.Solve(Mby, Xy);
if (!mgGaussY.IsDone()) {
return false;
}
mgGaussZ.Solve(Mbz, Xz);
if (!mgGaussZ.IsDone()) {
return false;
}
unsigned ulIdx = 0;
for (unsigned j = 0; j < _usUCtrlpoints; j++) {
for (unsigned k = 0; k < _usVCtrlpoints; k++) {
_vCtrlPntsOfSurf(j, k) = gp_Pnt(Xx(ulIdx), Xy(ulIdx), Xz(ulIdx));
ulIdx++;
}
}
return true;
}
void BSplineParameterCorrection::CalcSmoothingTerms(bool bRecalc, double fFirst, double fSecond, double fThird)
{
if (bRecalc) {
Base::SequencerLauncher seq(
"Initializing...",
static_cast<size_t>(3) * static_cast<size_t>(_usUCtrlpoints)
* static_cast<size_t>(_usUCtrlpoints) * static_cast<size_t>(_usVCtrlpoints)
* static_cast<size_t>(_usVCtrlpoints)
);
CalcFirstSmoothMatrix(seq);
CalcSecondSmoothMatrix(seq);
CalcThirdSmoothMatrix(seq);
}
_clSmoothMatrix = fFirst * _clFirstMatrix + fSecond * _clSecondMatrix + fThird * _clThirdMatrix;
}
void BSplineParameterCorrection::CalcFirstSmoothMatrix(Base::SequencerLauncher& seq)
{
unsigned m = 0;
for (unsigned k = 0; k < _usUCtrlpoints; k++) {
for (unsigned l = 0; l < _usVCtrlpoints; l++) {
unsigned n = 0;
for (unsigned i = 0; i < _usUCtrlpoints; i++) {
for (unsigned j = 0; j < _usVCtrlpoints; j++) {
_clFirstMatrix(m, n) = _clUSpline.GetIntegralOfProductOfBSplines(i, k, 1, 1)
* _clVSpline.GetIntegralOfProductOfBSplines(j, l, 0, 0)
+ _clUSpline.GetIntegralOfProductOfBSplines(i, k, 0, 0)
* _clVSpline.GetIntegralOfProductOfBSplines(j, l, 1, 1);
seq.next();
n++;
}
}
m++;
}
}
}
void BSplineParameterCorrection::CalcSecondSmoothMatrix(Base::SequencerLauncher& seq)
{
unsigned m = 0;
for (unsigned k = 0; k < _usUCtrlpoints; k++) {
for (unsigned l = 0; l < _usVCtrlpoints; l++) {
unsigned n = 0;
for (unsigned i = 0; i < _usUCtrlpoints; i++) {
for (unsigned j = 0; j < _usVCtrlpoints; j++) {
_clSecondMatrix(m, n) = _clUSpline.GetIntegralOfProductOfBSplines(i, k, 2, 2)
* _clVSpline.GetIntegralOfProductOfBSplines(j, l, 0, 0)
+ 2 * _clUSpline.GetIntegralOfProductOfBSplines(i, k, 1, 1)
* _clVSpline.GetIntegralOfProductOfBSplines(j, l, 1, 1)
+ _clUSpline.GetIntegralOfProductOfBSplines(i, k, 0, 0)
* _clVSpline.GetIntegralOfProductOfBSplines(j, l, 2, 2);
seq.next();
n++;
}
}
m++;
}
}
}
void BSplineParameterCorrection::CalcThirdSmoothMatrix(Base::SequencerLauncher& seq)
{
unsigned m = 0;
for (unsigned k = 0; k < _usUCtrlpoints; k++) {
for (unsigned l = 0; l < _usVCtrlpoints; l++) {
unsigned n = 0;
for (unsigned i = 0; i < _usUCtrlpoints; i++) {
for (unsigned j = 0; j < _usVCtrlpoints; j++) {
_clThirdMatrix(m, n) = _clUSpline.GetIntegralOfProductOfBSplines(i, k, 3, 3)
* _clVSpline.GetIntegralOfProductOfBSplines(j, l, 0, 0)
+ _clUSpline.GetIntegralOfProductOfBSplines(i, k, 3, 1)
* _clVSpline.GetIntegralOfProductOfBSplines(j, l, 0, 2)
+ _clUSpline.GetIntegralOfProductOfBSplines(i, k, 1, 3)
* _clVSpline.GetIntegralOfProductOfBSplines(j, l, 2, 0)
+ _clUSpline.GetIntegralOfProductOfBSplines(i, k, 1, 1)
* _clVSpline.GetIntegralOfProductOfBSplines(j, l, 2, 2)
+ _clUSpline.GetIntegralOfProductOfBSplines(i, k, 2, 2)
* _clVSpline.GetIntegralOfProductOfBSplines(j, l, 1, 1)
+ _clUSpline.GetIntegralOfProductOfBSplines(i, k, 0, 2)
* _clVSpline.GetIntegralOfProductOfBSplines(j, l, 3, 1)
+ _clUSpline.GetIntegralOfProductOfBSplines(i, k, 2, 0)
* _clVSpline.GetIntegralOfProductOfBSplines(j, l, 1, 3)
+ _clUSpline.GetIntegralOfProductOfBSplines(i, k, 0, 0)
* _clVSpline.GetIntegralOfProductOfBSplines(j, l, 3, 3);
seq.next();
n++;
}
}
m++;
}
}
}
void BSplineParameterCorrection::EnableSmoothing(bool bSmooth, double fSmoothInfl)
{
EnableSmoothing(bSmooth, fSmoothInfl, 1.0, 0.0, 0.0);
}
void BSplineParameterCorrection::EnableSmoothing(
bool bSmooth,
double fSmoothInfl,
double fFirst,
double fSec,
double fThird
)
{
if (_bSmoothing && bSmooth) {
CalcSmoothingTerms(false, fFirst, fSec, fThird);
}
else if (bSmooth) {
CalcSmoothingTerms(true, fFirst, fSec, fThird);
}
ParameterCorrection::EnableSmoothing(bSmooth, fSmoothInfl);
}
const math_Matrix& BSplineParameterCorrection::GetFirstSmoothMatrix() const
{
return _clFirstMatrix;
}
const math_Matrix& BSplineParameterCorrection::GetSecondSmoothMatrix() const
{
return _clSecondMatrix;
}
const math_Matrix& BSplineParameterCorrection::GetThirdSmoothMatrix() const
{
return _clThirdMatrix;
}
void BSplineParameterCorrection::SetFirstSmoothMatrix(const math_Matrix& rclMat)
{
_clFirstMatrix = rclMat;
}
void BSplineParameterCorrection::SetSecondSmoothMatrix(const math_Matrix& rclMat)
{
_clSecondMatrix = rclMat;
}
void BSplineParameterCorrection::SetThirdSmoothMatrix(const math_Matrix& rclMat)
{
_clThirdMatrix = rclMat;
}