/*************************************************************************** * Copyright (c) 2007 * * Joachim Zettler * * * Mohamad Najib Muhammad Noor * * * * 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 * * * ***************************************************************************/ /*********ROUTINE.CPP*********/ #include "PreCompiled.h" #include #include "routine.h" ///*********BINDINGS********/ #include #include #include using namespace boost::numeric::bindings; using namespace boost::numeric; /*! \brief Numerical Integration according to trapezoid rules This routine assumes that the Intergral values are already corresponding with WithRespectTo i.e: Intergral[i] == Intergral(WithRespectTo[i]); Also, it is assumed that WithRespectTo are evenly spaced with it's stepWidth */ double Routines::TrapezoidIntergration(const std::vector &WithRespectTo, const std::vector &Integral) { m_h = 0; m_result = 0; m_N = Integral.size(); if (m_N==1) // trapzf(x,y) returns zero for a scalar x { m_result = 0; return m_result; } m_h = WithRespectTo[1] - WithRespectTo[0]; /* the integration stepsize */ for (int i=1; i< m_N - 1; i++) m_result = m_result + Integral[i]; m_result = m_h/2 * (Integral[0] + 2*(m_result) + Integral[m_N -1]); return m_result; } std::vector Routines::NewtonStep(std::vector &F,std::vector > &DF) { // löst folgendes Gleichungssystem: DF*x = F int siz = (int) F.size(); std::vector x_new(siz); std::vector piv(siz); // pivotelement ublas::matrix A(siz, siz); ublas::matrix b(1, siz); // füllt blas-matrizen for (unsigned int i=0; i > &RHS1, std::vector& RHS2, std::vector &LHS) { double MainMatrixDet = det2(RHS1); std::vector< std::vector > Temp(2,std::vector(2,0.0)); for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) Temp[i][j] = RHS1[i][j]; //first pass for (int i = 0; i < 2; i++) Temp[i][0] = RHS2[i]; LHS[0] = det2(Temp) / MainMatrixDet; //restore for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) Temp[i][j] = RHS1[i][j]; //second pass for (int i = 0; i < 2; i++) Temp[i][1] = RHS2[i]; LHS[1] = det2(Temp) / MainMatrixDet; } /*! \brief Calculate angle between two vectors Dependencies: Vector3D definitions and routines */ double Routines::CalcAngle(Base::Vector3f a,Base::Vector3f b,Base::Vector3f c) { Base::Vector3f First = a - b; Base::Vector3f Second = c - b; Base::Vector3f Third = c - a; //double test1 = First.Length(), test2 = Second.Length(), test3 = Third.Length(); double UpperTerm = (First.Length() * First.Length()) + (Second.Length() *Second.Length()) - (Third.Length() * Third.Length() ); double LowerTerm = 2 * First.Length() * Second.Length() ; double ang = acos( UpperTerm / LowerTerm ); return ang; } /*! \brief Algorithm A2.1 from NURBS Book Page 68*/ int Routines::FindSpan(int n, int p, double u, std::vector KnotSequence) { if (u == KnotSequence[n+1]) return n; int low, high, mid, i; i = 0; low = p; high = n+1; mid = (low+high) / 2; while (u < KnotSequence[mid] || u >= KnotSequence[mid+1]) { if (u < KnotSequence[mid]) high = mid; else low = mid; mid = (low + high) / 2; i++; } return mid; } /*! \brief Algorithm A2.4 from NURBS Book page 70*/ void Routines::Basisfun(int i, double u, int p, std::vector &KnotSequence, std::vector &output) { double temp, saved; std::vector leftie(p+1, 0.0); std::vector rightie(p+1, 0.0); output[0] = 1.0; for (int j = 1; j <= p; j++) { leftie[j] = u - KnotSequence[i+1-j]; rightie[j] = KnotSequence[i+j] - u; saved = 0.0; for (int r = 0; r < j; r++) { temp = output[r] / (rightie[r+1] + leftie[j-r]); output[r] = saved + (rightie[r+1]*temp); saved = leftie[j-r]*temp; } output[j] = saved; } } /*! \brief Algorithm A2.3 from NURBS Book Page 72 */ void Routines::DersBasisFuns(int i, double u, int p, int n, std::vector &KnotSequence, std::vector< std::vector > &Derivate) { std::vector< std::vector > ndu(p+1, std::vector(p+1,0.0)); std::vector< std::vector > a(2, std::vector(p+1,0.0)); std::vector leftie(p+1, 0.0); std::vector rightie(p+1, 0.0); ndu[0][0] = 1.0; for (int j = 1; j <= p; j++) { leftie[j] = u - KnotSequence[i+1-j]; rightie[j] = KnotSequence[i+j] - u; double saved = 0.0; for (int r = 0; r < j; r++) { ndu[j][r] = rightie[r+1] + leftie[j-r]; double temp = ndu[r][j-1] / ndu[j][r]; ndu[r][j] = saved + rightie[r+1]*temp; saved = leftie[j-r]*temp; } ndu[j][j] = saved; } for (int j = 0; j <= p; j++) Derivate[0][j] = ndu[j][p]; for (int r = 0; r <= p; r++) { int j1, j2; int s1 = 0; int s2 = 1; a[0][0] = 1.0; for (int k = 1; k <= n; k++) { double d = 0.0; int j; int rk = r - k; int pk = p - k; if (r >= k) { a[s2][0] = a[s1][0] / ndu[pk+1][rk]; d += a[s2][0] * ndu[rk][pk]; } if (rk >= -1) j1 = 1; else j1 = -rk; if (r -1 <= pk) j2 = k -1; else j2 = p - r; for (j = j1; j <= j2; j++) { a[s2][j] = (a[s1][j]-a[s1][j-1]) / ndu[pk+1][rk+j]; d += a[s2][j] * ndu[rk+j][pk]; } if (r <= pk) { a[s2][k] = -a[s1][k-1] / ndu[pk+1][r]; d += a[s2][k] * ndu[r][pk]; } Derivate[k][r] = d; j = s1; s1 = s2; s2 = j; } } int r = p; for (int k = 1; k <= n; k++) { for (int j = 0; j <= p; j++) Derivate[k][j] *= r; r*= (p-k); } } /*! \brief Translation from nrbeval.m from NURBS Toolbox. WARNING: ONLY POINT EVALUATION ARE CONSIDERED!!!! */ void Routines::PointNrbEval(std::vector &p, std::vector &CurPoint, NURBS &MainNurb) { if (!p.empty()) p.clear(); int i = 0, j = 0; //val = reshape(nurbs.coefs,4*num1,num2); std::vector< std::vector > CntrlPoints(((MainNurb.MaxU+1)*3), std::vector((MainNurb.MaxV+1), 0.0)); for (unsigned int a = 0; a < MainNurb.CntrlArray.size(); ) { CntrlPoints[i][j] = MainNurb.CntrlArray[a]; CntrlPoints[i+1][j] = MainNurb.CntrlArray[a+1]; CntrlPoints[i+2][j] = MainNurb.CntrlArray[a+2]; i += 3; a += 3; if (i == ((MainNurb.MaxU+1)*3)) { i = 0; j++; } } //v direction...? i = 0; std::vector Output(CntrlPoints.size(), 0.0); PointBSPEval(MainNurb.DegreeV, CntrlPoints, MainNurb.KnotV, Output, CurPoint[1]); std::vector< std::vector > RedoneOutput(3, std::vector(MainNurb.MaxU+1, 0.0)); for (unsigned int a = 0; a < Output.size(); ) { RedoneOutput[0][i] = Output[a]; RedoneOutput[1][i] = Output[a+1]; RedoneOutput[2][i] = Output[a+2]; a += 3; i++; } std::vector OutVect(4,0.0); PointBSPEval(MainNurb.DegreeU, RedoneOutput, MainNurb.KnotU, OutVect,CurPoint[0]); p.push_back(OutVect[0]); p.push_back(OutVect[1]); p.push_back(OutVect[2]); } /*! \brief Translation from bspeval.m from NURBS Toolbox. WARNING: ONLY POINT EVALUATION ARE CONSIDERED!!!! */ void Routines::PointBSPEval(int Degree, std::vector< std::vector > &Cntrl, std::vector &KnotSequence, std::vector< double > &Output, double CurEvalPoint) { std::vector Basis(Degree+1, 0.0); int s = FindSpan(Cntrl[0].size() - 1,Degree,CurEvalPoint,KnotSequence); Basisfun(s,CurEvalPoint,Degree,KnotSequence,Basis); int tmp1 = s - Degree; for (unsigned int row = 0;row < Cntrl.size();row++) { double tmp2 = 0.0; for (int i = 0; i <= Degree; i++) tmp2 += Basis[i] *Cntrl[row][tmp1+i]; Output[row] = tmp2; } } /*! \brief Translation from nrbderivate.m from NURBS Toolbox. WARNING: ONLY POINT EVALUATION ARE CONSIDERED!!!! */ void Routines::PointNrbDerivate(NURBS MainNurb, std::vector &OutNurbs) { if (!OutNurbs.empty()) OutNurbs.clear(); NURBS Temp; int i = 0, j = 0, k = 0; std::vector< std::vector > ControlDerivate; std::vector KnotDerivate; std::vector< std::vector > CntrlPoints(((MainNurb.MaxV+1)*3), std::vector((MainNurb.MaxU+1), 0.0)); for (unsigned int a = 0; a < MainNurb.CntrlArray.size(); ) { CntrlPoints[i][j] = MainNurb.CntrlArray[a]; CntrlPoints[i+1][j] = MainNurb.CntrlArray[a+1]; CntrlPoints[i+2][j] = MainNurb.CntrlArray[a+2]; j++; a += 3; i = k*3; if (j == (MainNurb.MaxU+1)) { j = 0; k++; i = k*3; } } //U derivate bspderiv(MainNurb.DegreeU, CntrlPoints, MainNurb.KnotU, ControlDerivate, KnotDerivate); Temp.CntrlArray.resize(ControlDerivate.size() * ControlDerivate[0].size()); i = 0, j = 0, k = 0; for (unsigned int a = 0; a < Temp.CntrlArray.size(); ) { Temp.CntrlArray[a] = ControlDerivate[i][j]; Temp.CntrlArray[a+1] = ControlDerivate[i+1][j]; Temp.CntrlArray[a+2] = ControlDerivate[i+2][j]; j++; a += 3; i = k*3; if (j == (int)ControlDerivate[i].size()) { j = 0; k++; i = k*3; } } Temp.KnotU = KnotDerivate; Temp.KnotV = MainNurb.KnotV; Temp.MaxKnotU = Temp.KnotU.size(); Temp.MaxKnotV = Temp.KnotV.size(); Temp.MaxU = ControlDerivate[0].size(); Temp.MaxV = ControlDerivate.size() / 3; Temp.DegreeU = Temp.MaxKnotU - Temp.MaxU - 1; Temp.DegreeV = Temp.MaxKnotV - Temp.MaxV - 1; Temp.MaxU--; Temp.MaxV--; OutNurbs.push_back(Temp); //reset i = 0, j = 0, k = 0; CntrlPoints.clear(); ControlDerivate.clear(); KnotDerivate.clear(); CntrlPoints.resize((MainNurb.MaxU+1)*3); for (unsigned int a = 0; a < CntrlPoints.size(); a++) CntrlPoints[a].resize(MainNurb.MaxV+1); for (unsigned int a = 0; a < MainNurb.CntrlArray.size(); ) { CntrlPoints[i][j] = MainNurb.CntrlArray[a]; CntrlPoints[i+1][j] = MainNurb.CntrlArray[a+1]; CntrlPoints[i+2][j] = MainNurb.CntrlArray[a+2]; i += 3; a += 3; if (i == ((MainNurb.MaxU+1)*3)) { i = 0; j++; } } //V derivate bspderiv(MainNurb.DegreeV, CntrlPoints, MainNurb.KnotV, ControlDerivate, KnotDerivate); Temp.CntrlArray.resize(ControlDerivate.size() * ControlDerivate[0].size()); i = 0, j = 0, k = 0; for (unsigned int a = 0; a < Temp.CntrlArray.size(); ) { Temp.CntrlArray[a] = ControlDerivate[i][j]; Temp.CntrlArray[a+1] = ControlDerivate[i+1][j]; Temp.CntrlArray[a+2] = ControlDerivate[i+2][j]; a += 3; i += 3; if (i == (int)ControlDerivate.size()) { j++; i = 0; } } Temp.KnotU = MainNurb.KnotU; Temp.KnotV = KnotDerivate; Temp.MaxKnotU = Temp.KnotU.size(); Temp.MaxKnotV = Temp.KnotV.size(); Temp.MaxU = ControlDerivate.size() / 3; Temp.MaxV = ControlDerivate[0].size(); Temp.DegreeU = Temp.MaxKnotU - Temp.MaxU - 1; Temp.DegreeV = Temp.MaxKnotV - Temp.MaxV - 1; Temp.MaxU--; Temp.MaxV--; OutNurbs.push_back(Temp); } /*! \brief Translation from bspderiv.m from NURBS Toolbox. WARNING: ONLY POINT EVALUATION ARE CONSIDERED!!!! */ void Routines::bspderiv(int d, std::vector< std::vector > &c, std::vector &k, std::vector< std::vector > &OutputC, std::vector &Outputk) { OutputC.resize(c.size()); for (unsigned int i = 0; i < OutputC.size(); i++) OutputC[i].resize(c[i].size()-1); double tmp = 0.0; for (unsigned int i = 0; i < OutputC[0].size(); i++) { tmp = d / (k[i+d+1]-k[i+1]); for (unsigned int j = 0; j < OutputC.size(); j++) OutputC[j][i] = tmp * (c[j][i+1] - c[j][i]); } Outputk.resize(k.size() - 2); for (unsigned int i = 0; i < Outputk.size(); i++) Outputk[i] = k[i+1]; } /*! \brief Translation from nrbdeval.m from NURBS Toolbox. WARNING: ONLY POINT EVALUATION ARE CONSIDERED!!!! */ void Routines::NrbDEval(NURBS &MainNurb, std::vector &DerivNurb, std::vector &Point, std::vector &EvalPoint, std::vector > &jac) { if (!EvalPoint.empty()) EvalPoint.clear(); if (!jac.empty()) jac.clear(); std::vector TempoPointDeriv; PointNrbEval(EvalPoint, Point, MainNurb); for (unsigned int i = 0; i < DerivNurb.size(); i++) { PointNrbEval(TempoPointDeriv, Point, DerivNurb[i]); jac.push_back(TempoPointDeriv); TempoPointDeriv.clear(); } } /*! \brief Uniform Knot Generator */ void Routines::GenerateUniformKnot(int MaxCntrl, int NurbDegree, std::vector &KnotSequence) { if (!KnotSequence.empty()) KnotSequence.clear(); for (int i = 0; i < (MaxCntrl + NurbDegree + 2); i++) KnotSequence.push_back(0); for (int i = NurbDegree; i < MaxCntrl; i++) KnotSequence[i+1] = (double)(i - NurbDegree + 1.0) / (double)(MaxCntrl - NurbDegree + 1.0); for (unsigned int i = MaxCntrl+1; i < KnotSequence.size(); i++) KnotSequence[i] = 1; } /*! \brief Find the corner points Idea: From the neighbour list, find the shortest distance of a point to the given parameter X and Y. Parameter X and Y are the bounding boxes parameter of the mesh (combinations of Min and Max of X and Y) */ unsigned long Routines::FindCorner(float ParamX, float ParamY, std::vector &v_neighbour, std::vector &v_pnts) { unsigned int j = 0; bool change = false; //double distance = sqrt(((ParamX - ParameterMesh.GetPoint(v_neighbour[0])[0])*(ParamX - ParameterMesh.GetPoint(v_neighbour[0])[0])) + // ((ParamY - ParameterMesh.GetPoint(v_neighbour[0])[1])*(ParamY - ParameterMesh.GetPoint(v_neighbour[0])[1]))); double distance = sqrt(((ParamX - v_pnts[0][0])*(ParamX - v_pnts[0][0])) + ((ParamY - v_pnts[0][1])*(ParamY - v_pnts[0][1]))); for (unsigned int k = 1; k < v_neighbour.size(); ++k) { double eps= sqrt(((ParamX - v_pnts[k][0])*(ParamX - v_pnts[k][0])) + ((ParamY - v_pnts[k][1])*(ParamY - v_pnts[k][1]))); if (eps < distance) { distance = eps; j = k; change = true; } } if (change) return v_neighbour[j]; else return v_neighbour[0]; } /*! \brief Calculate the Area of the triangle, bounded by three vectors from origin. A (bad) diagram is included in source code */ double Routines::AreaTriangle(Base::Vector3f &a, Base::Vector3f &b, Base::Vector3f &c) { /* a * x----->x b * \ / * \ / * \/ * V * x c */ Base::Vector3f First = b - a; Base::Vector3f Second = c - a; std::vector < std::vector > Matrix(2, std::vector(2)); Matrix[0][0] = First.x; Matrix[1][0] = First.y; Matrix[0][1] = Second.x; Matrix[1][1] = Second.y; return (0.5 * det2(Matrix)); } /*! \brief Knot Extension This method will extend the knots by 2. ErrPnt will tell where the knots should be inserted, NurbDegree and MaxCntrl will make sure that the amount of 0's and 1's are left untouched. The new values will be calculated here and will be inserted in Extension function */ void Routines::ExtendKnot(double ErrPnt, int NurbDegree, int MaxCntrl, std::vector &KnotSequence) { double tol_knot = 0.02; int ind_1 = 0; double new1 = 0; int ind_2 = 0; double new2 = 0; bool flag = false; if (KnotSequence.size()>40) tol_knot = 0.015; for (unsigned int i = NurbDegree; i < (KnotSequence.size() - NurbDegree); i++) { if ((KnotSequence[i] > ErrPnt) && (ErrPnt >= KnotSequence[i-1])) { ind_1 = i; new1 = (KnotSequence[ind_1] + KnotSequence[ind_1-1]) / 2; } } //START CHANGE if (!flag) { double mid = (double)KnotSequence.size() / 2.0; if (ind_1 == mid) { KnotSequence.resize(KnotSequence.size() + 2); //MainNurb.MaxKnotU += 2; for (int i = KnotSequence.size() - 1; i > ind_1; i--) KnotSequence[i] = KnotSequence[i-2]; KnotSequence[ind_1] = KnotSequence[ind_1-1] + ((new1 - KnotSequence[ind_1-1]) / 2.0); KnotSequence[ind_1+1] = new1 +((new1 - KnotSequence[ind_1-1]) / 2.0); } else { double temp = mid - ((double)ind_1); ind_2 = (int)(mid + temp); new2 = (KnotSequence[ind_2-1] + KnotSequence[ind_2]) / 2.0; if (ind_1 < ind_2) Extension(KnotSequence,ind_1,ind_2,new1,new2); else Extension(KnotSequence,ind_2,ind_1,new2,new1); } } else { if (ind_1 < ind_2) Extension(KnotSequence,ind_1,ind_2,new1,new2); else Extension(KnotSequence,ind_2,ind_1,new2,new1); } } /*! \brief This routine is because it is done over and over again... */ void Routines::Extension(std::vector &KnotSequence, int SmallerIndex, int LargerIndex, double SmallerIndNewValue, double LargerIndNewValue) { KnotSequence.resize(KnotSequence.size() + 1); for (int i = KnotSequence.size() - 1; i > SmallerIndex; i--) KnotSequence[i] = KnotSequence[i-1]; KnotSequence[SmallerIndex] = SmallerIndNewValue; LargerIndex++; KnotSequence.resize(KnotSequence.size() + 1); for (int i = KnotSequence.size() - 1; i > LargerIndex; i--) KnotSequence[i] = KnotSequence[i-1]; KnotSequence[LargerIndex] = LargerIndNewValue; }