/*************************************************************************** * Copyright (c) 2008 Werner Mayer * * * * 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 "PreCompiled.h" #include #include #include #include #include #include #include "ApproxSurface.h" using namespace Reen; // SplineBasisfunction SplineBasisfunction::SplineBasisfunction(int iSize) : _vKnotVector(0,iSize-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) { // Werfe Exception Standard_ConstructionError::Raise("BSplineBasis"); } int k=0; for (int i=vMults.Lower(); i<=vMults.Upper(); i++) { for (int j=0; j= _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.0f; 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.0f; for (int r=0; r= _vKnotVector(iIndex+p+1)) { return 0.0f; } for (int j=0; j<=p; j++) { if (fParam >= _vKnotVector(iIndex+j) && fParam < _vKnotVector(iIndex+j+1)) N(j) = 1.0f; else N(j) = 0.0f; } for (int k=1; k<=p; k++) { if (N(0) == 0.0f) saved = 0.0f; else saved = ((fParam - _vKnotVector(iIndex))*N(0)) / (_vKnotVector(iIndex+k) - _vKnotVector(iIndex)); for (int j=0; jGrad) sind Null if (iMax >= _iOrder) { for (int i=_iOrder; i<=iMaxDer; i++) Derivat(i) = 0.0f; iMax = _iOrder - 1; } TColStd_Array1OfReal ND(0, iMax); int p = _iOrder-1; math_Matrix N(0,p,0,p); double saved; // falls Wert außerhalb Intervall, dann Funktionswert und alle Ableitungen gleich Null if (fParam < _vKnotVector(iIndex) || fParam >= _vKnotVector(iIndex+p+1)) { for (int k=0; k<=iMax; k++) Derivat(k) = 0.0f; return; } // Berechne die Basisfunktionen der Ordnung 1 for (int j=0; j<_iOrder; j++) { if (fParam >= _vKnotVector(iIndex+j) && fParam < _vKnotVector(iIndex+j+1)) N(j,0) = 1.0f; else N(j,0) = 0.0f; } // Berechne Dreieckstabelle der Funktionswerte for (int k=1; k<_iOrder; k++) { if (N(0,k-1) == 0.0f) saved = 0.0f; else saved = ((fParam - _vKnotVector(iIndex))*N(0,k-1))/(_vKnotVector(iIndex+k)-_vKnotVector(iIndex)); for (int j=0; jGrad) sind Null if (iMax >= _iOrder) { return 0.0f; } TColStd_Array1OfReal ND(0, iMax); int p = _iOrder-1; math_Matrix N(0,p,0,p); double saved; // falls Wert außerhalb Intervall, dann Funktionswert und Ableitungen gleich Null if (fParam < _vKnotVector(iIndex) || fParam >= _vKnotVector(iIndex+p+1)) { return 0.0f; } // Berechne die Basisfunktionen der Ordnung 1 for (int j=0; j<_iOrder; j++) { if (fParam >= _vKnotVector(iIndex+j) && fParam < _vKnotVector(iIndex+j+1)) N(j,0) = 1.0f; else N(j,0) = 0.0f; } // Berechne Dreieckstabelle der Funktionswerte for (int k=1; k<_iOrder; k++) { if (N(0,k-1) == 0.0f) saved = 0.0f; else saved = ((fParam - _vKnotVector(iIndex))*N(0,k-1))/(_vKnotVector(iIndex+k)-_vKnotVector(iIndex)); for (int j=0; j 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(); //Nullstellen der Legendre-Polynome und die zugeh. Gewichte if (iSize == 1) { vRoots(0) = 0.0f; vWeights(0) = 2.0f; } 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) { // nach Index ordnen 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 short usUOrder, unsigned short usVOrder, unsigned short usUCtrlpoints, unsigned short 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.0f; } void ParameterCorrection::CalcEigenvectors() { MeshCore::PlaneFit planeFit; //for (it = aclPoints.begin(); it!=aclPoints.end(); ++it) // planeFit.AddPoint(*it); for (int i=_pvcPoints->Lower(); i<=_pvcPoints->Upper(); i++) { planeFit.AddPoint(Base::Vector3f( (float)(*_pvcPoints)(i).X(), (float)(*_pvcPoints)(i).Y(), (float)(*_pvcPoints)(i).Z())); } planeFit.Fit(); _clU = Base::toVector(planeFit.GetDirU()); _clV = Base::toVector(planeFit.GetDirV()); _clW = Base::toVector(planeFit.GetNormal()); } bool ParameterCorrection::DoInitialParameterCorrection(double fSizeFactor) { // falls Richtungen nicht vorgegeben, selber berechnen if (_bGetUVDir == false) 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) { // Eigenvektoren als neue Basis Base::Vector3d e[3]; e[0] = _clU; e[1] = _clV; e[2] = _clW; //kanonische Basis des 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); // Erzeuge ein Rechtssystem aus den orthogonalen Eigenvektoren if ((e[0]%e[1])*e[2] < 0) { Base::Vector3d tmp = e[0]; e[0] = e[1]; e[1] = tmp; } // Nun erzeuge die transpon. Rotationsmatrix 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 vcProjPts; Base::BoundBox2D clBBox; // Berechne die Koordinaten der transf. Punkte und projiz. diese auf die x,y-Ebene des neuen // Koordinatensystems for (int ii=_pvcPoints->Lower(); ii<=_pvcPoints->Upper(); ii++) { Wm4::Vector3d clProjPnt = clRotMatTrans * ( Wm4::Vector3d( (*_pvcPoints)(ii).X(), (*_pvcPoints)(ii).Y(), (*_pvcPoints)(ii).Z())); vcProjPts.push_back(Base::Vector2D(clProjPnt.X(), clProjPnt.Y())); clBBox &= (Base::Vector2D(clProjPnt.X(), clProjPnt.Y())); } if ((clBBox.fMaxX == clBBox.fMinX) || (clBBox.fMaxY == clBBox.fMinY)) return false; double tx = fSizeFactor*clBBox.fMinX-(fSizeFactor-1.0f)*clBBox.fMaxX; double ty = fSizeFactor*clBBox.fMinY-(fSizeFactor-1.0f)*clBBox.fMaxY; double fDeltaX = (2*fSizeFactor-1.0f)*(clBBox.fMaxX - clBBox.fMinX); double fDeltaY = (2*fSizeFactor-1.0f)*(clBBox.fMaxY - clBBox.fMinY); // Berechne die u,v-Parameter mit u,v aus [0,1] _pvcUVParam->Init(gp_Pnt2d(0.0f, 0.0f)); int ii=0; if (clBBox.fMaxX - clBBox.fMinX >= clBBox.fMaxY - clBBox.fMinY) for (std::vector::iterator It2=vcProjPts.begin(); It2!=vcProjPts.end(); It2++) { (*_pvcUVParam)(ii) = gp_Pnt2d((It2->fX-tx)/fDeltaX, (It2->fY-ty)/fDeltaY); ii++; } else for (std::vector::iterator It2=vcProjPts.begin(); It2!=vcProjPts.end(); It2++) { (*_pvcUVParam)(ii) = gp_Pnt2d((It2->fY-ty)/fDeltaY, (It2->fX-tx)/fDeltaX); ii++; } return true; } void ParameterCorrection::SetUVW(const Base::Vector3d& clU, const Base::Vector3d& clV, const Base::Vector3d& clW, bool bUseDir) { _clU = clU; _clV = clV; _clW = clW; _bGetUVDir = bUseDir; } void ParameterCorrection::GetUVW(Base::Vector3d& clU, Base::Vector3d& clV, Base::Vector3d& clW) const { clU = _clU; clV = _clV; clW = _clW; } Base::Vector3d ParameterCorrection::GetGravityPoint() const { unsigned long ulSize = _pvcPoints->Length(); double x=0.0, y=0.0, z=0.0; for (int i=_pvcPoints->Lower(); i<=_pvcPoints->Upper(); i++) { x += (*_pvcPoints)(i).X(); y += (*_pvcPoints)(i).Y(); z += (*_pvcPoints)(i).Z(); } return Base::Vector3d(x/ulSize, y/ulSize, z/ulSize); } Handle(Geom_BSplineSurface) ParameterCorrection::CreateSurface(const TColgp_Array1OfPnt& points, unsigned short usIter, bool bParaCor, double fSizeFactor) { if (_pvcPoints != NULL) { delete _pvcPoints; _pvcPoints = NULL; delete _pvcUVParam; _pvcUVParam = NULL; } _pvcPoints = new TColgp_Array1OfPnt(points.Lower(), points.Upper()); *_pvcPoints = points; _pvcUVParam = new TColgp_Array1OfPnt2d(points.Lower(), points.Upper()); if (_usUCtrlpoints*_usVCtrlpoints > _pvcPoints->Length()) return NULL; //LGS unterbestimmt if(!DoInitialParameterCorrection(fSizeFactor)) return NULL; if (bParaCor) DoParameterCorrection(usIter); 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 short usUOrder, unsigned short usVOrder, unsigned short usUCtrlpoints, unsigned short 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() { // Initialisierungen _pvcUVParam = NULL; _pvcPoints = NULL; _clFirstMatrix.Init(0.0); _clSecondMatrix.Init(0.0); _clThirdMatrix.Init(0.0); _clSmoothMatrix.Init(0.0); /* Berechne die Knotenvektoren */ unsigned short usUMax = _usUCtrlpoints-_usUOrder+1; unsigned short usVMax = _usVCtrlpoints-_usVOrder+1; // Knotenvektor für die CAS.CADE-Klasse // u-Richtung for (int i=0;i<=usUMax; i++) { _vUKnots(i) = i / usUMax; _vUMults(i) = 1; } _vUMults(0) = _usUOrder; _vUMults(usUMax) = _usUOrder; // v-Richtung for (int i=0; i<=usVMax; i++) { _vVKnots(i) = i / usVMax; _vVMults(i) = 1; } _vVMults(0) = _usVOrder; _vVMults(usVMax) = _usVOrder; // Setzen der B-Spline-Basisfunktionen _clUSpline.SetKnots(_vUKnots, _vUMults, _usUOrder); _clVSpline.SetKnots(_vVKnots, _vVMults, _usVOrder); } void BSplineParameterCorrection::SetUKnots(const std::vector& afKnots) { if (afKnots.size() != (unsigned long)(_usUCtrlpoints+_usUOrder)) return; unsigned short usUMax = _usUCtrlpoints-_usUOrder+1; // Knotenvektor für die CAS.CADE-Klasse // u-Richtung for (int i=1;i& afKnots) { if (afKnots.size() != (unsigned long)(_usVCtrlpoints+_usVOrder)) return; unsigned short usVMax = _usVCtrlpoints-_usVOrder+1; // Knotenvektor für die CAS.CADE-Klasse // v-Richtung for (int i=1; iLength()); do { fMaxScalar = 1.0f; fMaxDiff = 0.0f; 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; gp_Vec P((*_pvcPoints)(ii).X(), (*_pvcPoints)(ii).Y(), (*_pvcPoints)(ii).Z()); gp_Pnt PntX; gp_Vec Xu, Xv, Xuv, Xuu, Xvv; //Berechne die ersten beiden Ableitungen und Punkt an der Stelle (u,v) pclBSplineSurf->D2((*_pvcUVParam)(ii).X(), (*_pvcUVParam)(ii).Y(), PntX, Xu, Xv, Xuu, Xvv, Xuv); gp_Vec X(PntX.X(), PntX.Y(), PntX.Z()); gp_Vec ErrorVec = X - P; // Berechne Xu x Xv die Normale in X(u,v) gp_Dir clNormal = Xu ^ Xv; //Prüfe, ob X = P if (!(X.IsEqual(P,0.001,0.001))) { ErrorVec.Normalize(); if(fabs(clNormal*ErrorVec) < fMaxScalar) fMaxScalar = (float)fabs(clNormal*ErrorVec); } fDeltaU = ( (P-X) * Xu ) / ( (P-X)*Xuu - Xu*Xu ); if (fabs(fDeltaU) < FLOAT_EPS) fDeltaU = 0.0f; fDeltaV = ( (P-X) * Xv ) / ( (P-X)*Xvv - Xv*Xv ); if (fabs(fDeltaV) < FLOAT_EPS) fDeltaV = 0.0f; //Ersetze die alten u/v-Werte durch die neuen fU = (*_pvcUVParam)(ii).X() - fDeltaU; fV = (*_pvcUVParam)(ii).Y() - fDeltaV; if (fU <= 1.0f && fU >= 0.0f && fV <= 1.0f && fV >= 0.0f) { (*_pvcUVParam)(ii).SetX(fU); (*_pvcUVParam)(ii).SetY(fV); fMaxDiff = std::max(float(fabs(fDeltaU)), fMaxDiff); fMaxDiff = std::max(float(fabs(fDeltaV)), fMaxDiff); } seq.next(); } if (_bSmoothing) { fWeight *= 0.5f; SolveWithSmoothing(fWeight); } else SolveWithoutSmoothing(); i++; } while(i FLOAT_EPS && fMaxScalar < 0.99); } bool BSplineParameterCorrection::SolveWithoutSmoothing() { unsigned long ulSize = _pvcPoints->Length(); math_Matrix M (0, ulSize-1, 0,_usUCtrlpoints*_usVCtrlpoints-1); math_Matrix Xx (0, _usUCtrlpoints*_usVCtrlpoints-1,0,0); math_Matrix Xy (0, _usUCtrlpoints*_usVCtrlpoints-1,0,0); math_Matrix Xz (0, _usUCtrlpoints*_usVCtrlpoints-1,0,0); math_Vector bx (0, ulSize-1); math_Vector by (0, ulSize-1); math_Vector bz (0, ulSize-1); //Bestimmung der Koeffizientenmatrix des überbestimmten LGS for (unsigned long i=0; iLower(); ii<=_pvcPoints->Upper(); ii++) { bx(ii) = (*_pvcPoints)(ii).X(); by(ii) = (*_pvcPoints)(ii).Y(); bz(ii) = (*_pvcPoints)(ii).Z(); } // Löse das überbest. LGS mit der 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 konnte nicht gelöst werden return false; Xx = hhX.AllValues(); Xy = hhY.AllValues(); Xz = hhZ.AllValues(); unsigned long ulIdx=0; for (unsigned short j=0;j<_usUCtrlpoints;j++) { for (unsigned short k=0;k<_usVCtrlpoints;k++) { _vCtrlPntsOfSurf(j,k) = gp_Pnt(Xx(ulIdx,0),Xy(ulIdx,0),Xz(ulIdx,0)); ulIdx++; } } return true; } bool BSplineParameterCorrection::SolveWithSmoothing(double fWeight) { unsigned long ulSize = _pvcPoints->Length(); unsigned long ulDim = _usUCtrlpoints*_usVCtrlpoints; math_Matrix M (0, ulSize-1, 0,_usUCtrlpoints*_usVCtrlpoints-1); math_Matrix MTM(0, _usUCtrlpoints*_usVCtrlpoints-1, 0, _usUCtrlpoints*_usVCtrlpoints-1); math_Vector Xx (0, _usUCtrlpoints*_usVCtrlpoints-1); math_Vector Xy (0, _usUCtrlpoints*_usVCtrlpoints-1); math_Vector Xz (0, _usUCtrlpoints*_usVCtrlpoints-1); math_Vector bx (0, ulSize-1); math_Vector by (0, ulSize-1); math_Vector bz (0, ulSize-1); math_Vector Mbx(0, _usUCtrlpoints*_usVCtrlpoints-1); math_Vector Mby(0, _usUCtrlpoints*_usVCtrlpoints-1); math_Vector Mbz(0, _usUCtrlpoints*_usVCtrlpoints-1); //Bestimmung der Koeffizientenmatrix des überbestimmten LGS for (unsigned long i=0; iLower(); ii<=_pvcPoints->Upper(); ii++) { bx(ii) = (*_pvcPoints)(ii).X(); by(ii) = (*_pvcPoints)(ii).Y(); bz(ii) = (*_pvcPoints)(ii).Z(); } for (unsigned long i=0; i