// Copyright Epic Games, Inc. All Rights Reserved. #include "Math/BSpline.h" #include "Geo/Curves/NURBSCurve.h" #include "Geo/Sampling/SurfacicSampling.h" #include "Geo/Surfaces/NURBSSurface.h" #include "Math/MatrixH.h" #include "Mesh/Structure/Grid.h" #include "UI/Display.h" #include "Utils/Util.h" #include namespace UE::CADKernel { const FLinearBoundary FLinearBoundary::DefaultBoundary(0., 1.); const FSurfacicBoundary FSurfacicBoundary::DefaultBoundary(0., 1., 0., 1.); namespace BSpline { // DeBoor Valeurs B-Spline void DeBoorValeursBSpline(const int32 degre, const double* const knot, const int32 segment, const int32 ndim, const int32 derivee, const double u, double* const pole_aux, double* const grad_aux, double* const lap_aux, double* const valeur, double* const Gradient, double* const Laplacian); void InsertKnot(TArray& vn, TArray& poles, TArray& weights, double u, double* newU = nullptr); void Blossom(int32 degre, const TArray& poles, const TArray& vecteurNodal, const TArray& poids, int32 seg, TArray& params, FVector& pnt, double& weight); void DuplicateNurbsCurveWithHigherDegree(int32 degre, const TArray& poles, const TArray& nodalVector, const TArray& weights, TArray& newPoles, TArray& newNodalVector, TArray& newWeights); #define DEGRE_MAX_POLY 9 namespace { // anonymous ns for static int32 CoefficientsBinomiaux[][10] = { { 1 }, { 1, 1 }, { 1, 2, 1}, { 1, 3, 3, 1 }, { 1, 4, 6, 4, 1 }, { 1, 5, 10, 10, 5, 1 }, { 1, 6, 15, 20, 15, 6, 1 }, { 1, 7, 21, 35, 35, 21, 7, 1}, { 1, 8, 28, 56, 70, 56, 28, 8, 1}, { 1, 9, 36, 84, 126, 126, 84, 36, 9, 1} }; } int32 fact_r(int32 n) { if (n <= 0) return 1; return n * fact_r(n - 1); } int32 fact(int32 n) { if (n <= 0) return 1; int32 k = n; int32 result = k--; while (k > 0) { result *= k; k--; } return result; } int32 CoefficientBinomial(int32 n, int32 k) { if (n <= DEGRE_MAX_POLY) return CoefficientsBinomiaux[n][k]; return fact(n) / (fact(k) * fact(n - k)); } // #cadkernel_check: Precompute Bernstein values. void Bernstein(int32 Degree, double InCoordinateU, double* BernsteinValuesAtU, double* BernsteinGradientsAtU, double* BernsteinLaplaciansAtU) { int32 i; double t, s; const int32 Order = Degree + 1; TArray Buffer; Buffer.SetNum(3 * Order); double* ti = Buffer.GetData(); double* si = ti + Order; double* ci = si + Order; // calculer les coefficient ci ci[0] = 1; ci[Degree] = 1; for (i = 1; i < Degree; i++) { ci[i] = ci[i - 1] * (Order - i) / (double)i; } ti[0] = 1.; si[0] = 1.; // calculer les monomes t**i et s**i=(1-t)**i t = InCoordinateU; s = 1. - InCoordinateU; for (i = 1; i <= Degree; i++) { ti[i] = ti[i - 1] * t; si[i] = si[i - 1] * s; } // calculer les polynomes de bernstein for (i = 0; i <= Degree; i++) { BernsteinValuesAtU[i] = ci[i] * ti[i] * si[Degree - i]; } if (BernsteinGradientsAtU) { // calculer les derivees premieres BernsteinGradientsAtU[0] = -Degree * si[Degree - 1]; BernsteinGradientsAtU[Degree] = Degree * ti[Degree - 1]; for (i = 1; i < Degree; i++) { BernsteinGradientsAtU[i] = ci[i] * (i * ti[i - 1] * si[Degree - i] - (Degree - i) * ti[i] * si[Degree - i - 1]); } if (BernsteinLaplaciansAtU) { // calculer les derivees secondes if (Degree > 1) { BernsteinLaplaciansAtU[0] = Degree * (Degree - 1) * si[Degree - 2]; BernsteinLaplaciansAtU[1] = ci[1] * (-2) * (Degree - 1) * si[Degree - 2]; if (Degree > 2) BernsteinLaplaciansAtU[1] += ci[1] * (Degree - 1) * (Degree - 2) * ti[1] * si[Degree - 3]; BernsteinLaplaciansAtU[Degree] = Degree * (Degree - 1) * ti[Degree - 2]; BernsteinLaplaciansAtU[Degree - 1] = ci[Degree - 1] * (-2) * (Degree - 1) * ti[Degree - 2]; if (Degree > 2) BernsteinLaplaciansAtU[Degree - 1] += ci[Degree - 1] * (Degree - 1) * (Degree - 2) * ti[Degree - 3] * si[1]; for (i = 2; i < Degree - 1; i++) { BernsteinLaplaciansAtU[i] = ci[i] * (i * (i - 1) * ti[i - 2] * si[Degree - i] - 2 * i * (Degree - i) * ti[i - 1] * si[Degree - i - 1] + (Degree - i) * (Degree - i - 1) * ti[i] * si[Degree - i - 2]); } } else { BernsteinLaplaciansAtU[0] = 0.0f; } } } } int32 Dichotomy(const double* const tab, double key, int32 first, int32 last) { int32 center; int32 a = first; int32 b = last; while (a < b) { center = (a + b) >> 1; if (key > tab[center] && key <= tab[center + 1]) { return center; } else if (key <= tab[center]) { b = center; } else { a = center + 1; } } return a; } /******************************description fonction*****************************/ /* Auteur: - Fichier: bspline.c */ /* Role:- Calculer l'interpolation par fonctions BSplines 1D d'ordre "degre" */ /* d'une liste de nb_pole poles de dimensionnalite ndim stokes dans */ /* tab_pole, par rapport au vecteur nodal knot , le calcul portant sur*/ /* nb_pt points definis dans tab_u . */ /* On recupere en sortie les valeurs interpolees dans */ /* valeur[point][composante] et selon l'ordre de derivation desire */ /* (0, 1 ou 2) leurs derivees premieres et secondes dans */ /* Gradient[point][composante] et Laplacian[point][composante]. */ /*******************************fin fonction************************************/ void Interpolate1DBSpline( const int32 Degre, /* E-Odre de la bspline*/ const int32 PoleNum, /* E-Nombre de poles de la bspline*/ const double* const NodalVector, /* E-Le vecteur nodale de la bspline*/ const int32 SpaceDimension, /* E-Dimension des poles (1D,2D,3D,4D=3D+poids...)*/ const double* const Poles, /* E-La liste des poles de dimension ndim*/ const int32 PointNum, /* E-Le nombre de valeurs a calculer*/ const double* const Coordinate, /* E-La liste des parametres a calculer*/ const int32 Derivee, /* E-L'odre de derivation*/ double* const OutPoints, /* S-Les points calcules*/ double* const OutGradient, /* S-Les derivees premieres*/ double* const OutLaplacian /* S-Les derivees secondes*/ ) { TArray pole_aux; TArray grad_aux; TArray lap_aux; int32 Index, IndexK, StartIndex, EndIndex, Segment, PreviousSegment, IndexSegment, DegrePlus1, SquareDegre; TArray tab_u; tab_u.SetNum(PointNum); std::copy(Coordinate, Coordinate + PointNum, tab_u.GetData()); DegrePlus1 = Degre + 1; SquareDegre = DegrePlus1 * DegrePlus1; /* allocations des tables de travail*/ /* Allocations pour Algorithme De Boor*/ pole_aux.Init(0., SquareDegre * SpaceDimension); if (Derivee >= 1) { grad_aux.Init(0., SquareDegre * SpaceDimension); } if (Derivee >= 2) { lap_aux.Init(0., SquareDegre * SpaceDimension); } /* initialiser les index de debut et fin du domaine nodal*/ StartIndex = Degre; EndIndex = PoleNum; PreviousSegment = 0; /* calcul des points apres definition du segment BSpline*/ for (Index = 0; Index < PointNum; Index++) { double& currentU = tab_u[Index]; /* Verifier la coordonnee parametrique*/ if (currentU < NodalVector[Degre]) currentU = NodalVector[Degre]; if (currentU > NodalVector[EndIndex]) currentU = NodalVector[EndIndex]; /* Calculer le segment auquel appartient la coordonnee parametrique*/ if (currentU < NodalVector[StartIndex]) StartIndex = Degre; //for(iseg = ideb ; iseg knot[iseg +1]; ++iseg); IndexSegment = Dichotomy(NodalVector, currentU, StartIndex, EndIndex); if (IndexSegment > EndIndex) IndexSegment = EndIndex; Segment = IndexSegment; /* mise a jour du segment courant pour un point suivant a evaluer*/ StartIndex = IndexSegment; /* calcul par la methode de De Boor*/ if (Segment != PreviousSegment) { /* reinitialiser le vecteur des poles du segment courant*/ for (IndexK = 0; IndexK <= Degre; ++IndexK) { memcpy(&pole_aux[IndexK * SpaceDimension], &Poles[(Segment - Degre + IndexK) * SpaceDimension], SpaceDimension * sizeof(pole_aux[0])); } } DeBoorValeursBSpline(Degre, NodalVector, Segment, SpaceDimension, Derivee, currentU, &(pole_aux[0]), Derivee > 0 ? &(grad_aux[0]) : nullptr, Derivee > 1 ? &(lap_aux[0]) : nullptr, OutPoints + (Index * SpaceDimension), OutGradient + (Index * SpaceDimension), OutLaplacian + (Index * SpaceDimension)); PreviousSegment = Segment; } } /******************************description fonction*****************************/ /* Auteur: - Fichier: bspline.c */ /* Role:- Calculer l'interpolation par fonctions BSplines 2D d'une liste de */ /* (n_pole_u*n_pole_v) poles de dimensionnalite ndim stokees dans pole,*/ /* par rapport aux vecteurs nodaux knot_u,knot_v ,le calcul s'effectuant*/ /* sur un pave tab_u*tab_v comprenant nb_pt_u*nb_pt_v points. */ /* On recupere en sortie les valeurs interpolees dans valeur, et selon*/ /* l'ordre de derivation desire 0, 1 ou 2 leurs derivees premieres */ /* deru,derv et secondes deruu, dervv, deruv. */ /*******************************fin fonction************************************/ void InterpolerBSpline2D(const FNURBSSurface& Nurbs, FGrid& Grid) { } /******************************description fonction*****************************/ /* Auteur: - Fichier: bspline.c */ /* Role:- Calculer l'interpolation par fonctions BSplines 2D d'une liste de */ /* (n_pole_u*n_pole_v) poles de dimensionnalite ndim stokees dans pole,*/ /* par rapport aux vecteurs nodaux knot_u,knot_v ,le calcul s'effectuant*/ /* sur un pave tab_u*tab_v comprenant nb_pt_u*nb_pt_v points. */ /* On recupere en sortie les valeurs interpolees dans valeur, et selon*/ /* l'ordre de derivation desire 0, 1 ou 2 leurs derivees premieres */ /* deru,derv et secondes deruu, dervv, deruv. */ /*******************************fin fonction************************************/ void Interpolate2DBSpline( const int32 UDegre, /* E-Le degre en U de la bspline*/ const int32 VDegre, /* E-Le degre en V de la bspline*/ const int32 PoleUNum, /* E-Le nombre de poles en U de la bspline*/ const int32 PoleVNum, /* E-Le nombre de poles en V de la bspline*/ const double* const UNodalVector, /* E-Le vecteur nodale en U de la bspline*/ const double* const VNodalVector, /* E-Le vecteur nodale en V de la bspline*/ const int32 ndim, /* E-Dimension des poles (1D,2D,3D,4D=3D+poids...)*/ const double* const PoleUV, /* E-La liste des poles*/ const int32 nb_pt_u, /* E-Le nombre de parametre U de la grille a calculer*/ const double* const tab_u, /* E-La liste des paramletres U de la grille a calculer*/ const int32 nb_pt_v, /* E-Le nombre de parametre V de la grille a calculer*/ const double* const tab_v, /* E-La liste des paramletres V de la grille a calculer*/ const int32 derivee, /* E-L'ordre desiree de derivation*/ double* const valeur, /* S-La liste des valeurs*/ double* const deru, /* S-Les derivee premiere par rapport a U*/ double* const derv, /* S-Les derivee premiere par rapport a V*/ double* const deruu, /* S-Les derivee seconde par rapport a U*/ double* const dervv, /* S-Les derivee seconde par rapport a V*/ double* const deruv /* S-Les derivee seconde croise (dUdV)*/ ) { EIso IsoType; int32 deg1, deg2, nb_pt1, nb_pt2, nb_pole1, nb_pole2; bool inversion_uv; int32 IndexV, IndexU; /* initialisations*/ TArray tab_t1; TArray tab_t2; TArray pole1; TArray pole2; TArray pole_aux; TArray val_aux; TArray d1pole_aux; TArray d1pole2; TArray d1val_aux; TArray d2val_aux; TArray d11pole_aux; TArray d11pole2; TArray d11val_aux; TArray d22val_aux; TArray d21val_aux; double const* knot1; double const* knot2; /* Calculer le nombre d'evaluation necessaires suivant les 2 strategies isoV ==> on cree nb_pt_v iso_v d'abord puis calcul de nb_pt_u points isoU ==> on cree nb_pt_u iso_u d'abord puis calcul de nb_pt_v points Choisir le nombre Minimal d'evaluations*/ if (((1 + derivee) * (nb_pt_v * PoleUNum * VDegre * (VDegre + 1)) + (1 + 2 * derivee) * (nb_pt_u * nb_pt_v * UDegre * (UDegre + 1))) < ((1 + derivee) * (nb_pt_u * PoleVNum * UDegre * (UDegre + 1)) + (1 + 2 * derivee) * (nb_pt_u * nb_pt_v * VDegre * (VDegre + 1)))) { /* choisir la strategie isoV*/ nb_pt1 = nb_pt_v; knot1 = VNodalVector; nb_pt2 = nb_pt_u; knot2 = UNodalVector; deg1 = VDegre; deg2 = UDegre; nb_pole1 = PoleVNum; nb_pole2 = PoleUNum; IsoType = EIso::IsoV; inversion_uv = true; /* derivation par rapport a v d'abord*/ } else { /* choisir la strategie isoU*/ nb_pt1 = nb_pt_u; knot1 = UNodalVector; nb_pt2 = nb_pt_v; knot2 = VNodalVector; deg1 = UDegre; deg2 = VDegre; nb_pole1 = PoleUNum; nb_pole2 = PoleVNum; IsoType = EIso::IsoU; inversion_uv = false; /* derivation par rapport a u d'abord*/ } /* recopie des parametres en entree*/ tab_t1.SetNum(nb_pt1); tab_t2.SetNum(nb_pt2); if (IsoType == EIso::IsoV) { std::copy(tab_v, tab_v + nb_pt1, tab_t1.GetData()); std::copy(tab_u, tab_u + nb_pt2, tab_t2.GetData()); } else // (IsoType == EIso::IsoU) { std::copy(tab_u, tab_u + nb_pt1, tab_t1.GetData()); std::copy(tab_v, tab_v + nb_pt2, tab_t2.GetData()); } /* constituer le reseau de pole pour chaque courbe de construction*/ pole1.SetNum(nb_pole2 * nb_pole1 * ndim); /* on constitue un vecteur de nb_pole1 comportant (nb_pole2*ndim) composantes (ces composantes seront ensuite interpretes comme une sucession de (point(x,y,z),poids) a la suite les uns des autres)*/ if (IsoType == EIso::IsoV) { for (IndexV = 0; IndexV < nb_pole1; IndexV++) { for (IndexU = 0; IndexU < nb_pole2; IndexU++) { std::copy(PoleUV + ((IndexV * PoleUNum + IndexU) * ndim), PoleUV + ((IndexV * PoleUNum + IndexU) + 1) * ndim, pole1.GetData() + ((IndexV * nb_pole2 + IndexU) * ndim)); } } } else // (IsoType == EIso::IsoU) { for (IndexV = 0; IndexV < nb_pole1; IndexV++) { for (IndexU = 0; IndexU < nb_pole2; IndexU++) { std::copy(PoleUV + (IndexU * PoleUNum + IndexV) * ndim, PoleUV + ((IndexU * PoleUNum + IndexV) + 1) * ndim, pole1.GetData() + ((IndexV * nb_pole2 + IndexU) * ndim)); } } } /* Allouer pour chaque valeur du premier parametre (nb_pt1 points) les tableaux des poles fictifs interpoles et derivees correspondants a la courbe iso-parametre generee (nb_pt1 courbes)*/ pole_aux.SetNum(nb_pt1 * nb_pole2 * ndim); /* derivee premiere*/ if (derivee >= 1) { d1pole_aux.SetNum(nb_pt1 * nb_pole2 * ndim); } /* derivee seconde*/ if (derivee >= 2) { d11pole_aux.SetNum(nb_pt1 * nb_pole2 * ndim); } /* allouer les tables de travail necessaires a l'interpolation par rapport au second parametre de vecteurs de (nb_pt1 * ndim) composantes*/ pole2.SetNum(nb_pole2 * nb_pt1 * ndim); val_aux.SetNum(nb_pt2 * nb_pt1 * ndim); /* derivee premiere*/ if (derivee >= 1) { d1pole2.SetNum(nb_pole2 * nb_pt1 * ndim); d1val_aux.SetNum(nb_pt2 * nb_pt1 * ndim); d2val_aux.SetNum(nb_pt2 * nb_pt1 * ndim); } /* derivee seconde*/ if (derivee >= 2) { d11pole2.SetNum(nb_pole2 * nb_pt1 * ndim); d11val_aux.SetNum(nb_pt2 * nb_pt1 * ndim); d22val_aux.SetNum(nb_pt2 * nb_pt1 * ndim); d21val_aux.SetNum(nb_pt2 * nb_pt1 * ndim); } /* interpoler et deriver le vecteur pole fictif de dimension (nb_pole2*ndim) par rapport au premier parametre*/ Interpolate1DBSpline(deg1, nb_pole1, knot1, nb_pole2 * ndim, &(pole1[0]), nb_pt1, &(tab_t1[0]), derivee, &(pole_aux[0]), derivee > 0 ? &(d1pole_aux[0]) : nullptr, derivee > 1 ? &(d11pole_aux[0]) : nullptr); /* Constituer les vecteurs de travail de (nb_pt1*ndim) composantes a interpoler par rapport au 2 eme parametre*/ /* valeurs*/ for (IndexV = 0; IndexV < nb_pole2; IndexV++) { for (IndexU = 0; IndexU < nb_pt1; IndexU++) { std::copy(pole_aux.GetData() + (IndexU * nb_pole2 + IndexV) * ndim, pole_aux.GetData() + ((IndexU * nb_pole2 + IndexV) + 1) * ndim, pole2.GetData() + (IndexV * nb_pt1 + IndexU) * ndim); } } /* derivee premiere des valeurs par rapport au premier parametre*/ if (derivee >= 1) { for (IndexV = 0; IndexV < nb_pole2; IndexV++) { for (IndexU = 0; IndexU < nb_pt1; IndexU++) { //for(k=0; k= 2) { for (IndexV = 0; IndexV < nb_pole2; IndexV++) { for (IndexU = 0; IndexU < nb_pt1; IndexU++) { //for(k=0; k 0 ? &(d2val_aux[0]) : nullptr, derivee > 1 ? &(d22val_aux[0]) : nullptr); /* sauver les valeurs en sortie*/ if (inversion_uv) { for (IndexV = 0; IndexV < nb_pt2; IndexV++) { for (IndexU = 0; IndexU < nb_pt1; IndexU++) { std::copy(val_aux.GetData() + (IndexV * nb_pt1 + IndexU) * ndim, val_aux.GetData() + ((IndexV * nb_pt1 + IndexU) + 1) * ndim, valeur + (IndexU * nb_pt2 + IndexV) * ndim); } } } else { for (IndexV = 0; IndexV < nb_pt2; IndexV++) { for (IndexU = 0; IndexU < nb_pt1; IndexU++) { std::copy(val_aux.GetData() + (IndexV * nb_pt1 + IndexU) * ndim, val_aux.GetData() + ((IndexV * nb_pt1 + IndexU) + 1) * ndim, valeur + (IndexV * nb_pt1 + IndexU) * ndim); } } } /* calculer les derivees premieres*/ if (derivee >= 1) { /* interpoler et deriver une seule fois (eventuellement) le vecteur a (nb_pt1*ndim) composantes des derivees premieres par rapport au second parametre*/ Interpolate1DBSpline(deg2, nb_pole2, knot2, nb_pt1 * ndim, &(d1pole2[0]), nb_pt2, &(tab_t2[0]), derivee - 1, &(d1val_aux[0]), derivee > 1 ? &(d21val_aux[0]) : nullptr, nullptr); /* sauver les derivees premieres en sortie*/ if (IsoType == EIso::IsoV) { for (IndexV = 0; IndexV < nb_pt2; IndexV++) { for (IndexU = 0; IndexU < nb_pt1; IndexU++) { std::copy(d2val_aux.GetData() + (IndexV * nb_pt1 + IndexU) * ndim, d2val_aux.GetData() + ((IndexV * nb_pt1 + IndexU) + 1) * ndim, deru + (IndexU * nb_pt2 + IndexV) * ndim); std::copy(d1val_aux.GetData() + (IndexV * nb_pt1 + IndexU) * ndim, d1val_aux.GetData() + ((IndexV * nb_pt1 + IndexU) + 1) * ndim, derv + (IndexU * nb_pt2 + IndexV) * ndim); } } } else // (IsoType == EIso::IsoU) { for (IndexV = 0; IndexV < nb_pt2; IndexV++) { for (IndexU = 0; IndexU < nb_pt1; IndexU++) { std::copy(d1val_aux.GetData() + (IndexV * nb_pt1 + IndexU) * ndim, d1val_aux.GetData() + ((IndexV * nb_pt1 + IndexU) + 1) * ndim, deru + (IndexV * nb_pt1 + IndexU) * ndim); std::copy(d2val_aux.GetData() + (IndexV * nb_pt1 + IndexU) * ndim, d2val_aux.GetData() + ((IndexV * nb_pt1 + IndexU) + 1) * ndim, derv + (IndexV * nb_pt1 + IndexU) * ndim); } } } } /* calculer les derivees secondes*/ if (derivee >= 2) { /* interpoler le vecteur des derivees secondes a (nb_pt1*ndim) composantes par rapport au second parametre*/ Interpolate1DBSpline(deg2, nb_pole2, knot2, nb_pt1 * ndim, &(d11pole2[0]), nb_pt2, &(tab_t2[0]), (int32)0, &(d11val_aux[0]), nullptr, nullptr); /* sauver les derivees secondes en sortie*/ if (IsoType == EIso::IsoV) { for (IndexV = 0; IndexV < nb_pt2; IndexV++) { for (IndexU = 0; IndexU < nb_pt1; IndexU++) { std::copy(d22val_aux.GetData() + (IndexV * nb_pt1 + IndexU) * ndim, d22val_aux.GetData() + ((IndexV * nb_pt1 + IndexU) + 1) * ndim, deruu + (IndexU * nb_pt2 + IndexV) * ndim); std::copy(d11val_aux.GetData() + (IndexV * nb_pt1 + IndexU) * ndim, d11val_aux.GetData() + ((IndexV * nb_pt1 + IndexU) + 1) * ndim, dervv + (IndexU * nb_pt2 + IndexV) * ndim); std::copy(d21val_aux.GetData() + (IndexV * nb_pt1 + IndexU) * ndim, d21val_aux.GetData() + ((IndexV * nb_pt1 + IndexU) + 1) * ndim, deruv + (IndexU * nb_pt2 + IndexV) * ndim); } } } else // (IsoType == EIso::IsoU) { for (IndexV = 0; IndexV < nb_pt2; IndexV++) { for (IndexU = 0; IndexU < nb_pt1; IndexU++) { std::copy(d11val_aux.GetData() + (IndexV * nb_pt1 + IndexU) * ndim, d11val_aux.GetData() + ((IndexV * nb_pt1 + IndexU) + 1) * ndim, deruu + (IndexV * nb_pt1 + IndexU) * ndim); std::copy(d22val_aux.GetData() + (IndexV * nb_pt1 + IndexU) * ndim, d22val_aux.GetData() + ((IndexV * nb_pt1 + IndexU) + 1) * ndim, dervv + (IndexV * nb_pt1 + IndexU) * ndim); std::copy(d21val_aux.GetData() + (IndexV * nb_pt1 + IndexU) * ndim, d21val_aux.GetData() + ((IndexV * nb_pt1 + IndexU) + 1) * ndim, deruv + (IndexV * nb_pt1 + IndexU) * ndim); } } } } } void EvaluatePoint(const FNURBSCurve& Nurbs, double Coordinate, FCurvePoint& OutPoint, int32 DerivativeOrder) { ensureCADKernel(Nurbs.GetDimension() == 3); OutPoint.DerivativeOrder = DerivativeOrder; double ValueH[4]; double GradientH[4]; double LaplacianH[4]; int32 PoleDimension = Nurbs.GetDimension() + (Nurbs.IsRational() ? 1 : 0); BSpline::Interpolate1DBSpline(Nurbs.GetDegree(), Nurbs.GetPoleCount(), Nurbs.GetNodalVector().GetData(), PoleDimension, Nurbs.GetHPoles().GetData(), 1, &Coordinate, DerivativeOrder, ValueH, GradientH, LaplacianH); if (Nurbs.IsRational()) { OutPoint.Point.Set(ValueH[0] / ValueH[3], ValueH[1] / ValueH[3], ValueH[2] / ValueH[3]); } else { OutPoint.Point.Set(ValueH[0], ValueH[1], ValueH[2]); } if (DerivativeOrder > 0) { if (Nurbs.IsRational()) { OutPoint.Gradient.X = (GradientH[0] - GradientH[3] * ValueH[0] / ValueH[3]) / ValueH[3]; OutPoint.Gradient.Y = (GradientH[1] - GradientH[3] * ValueH[1] / ValueH[3]) / ValueH[3]; OutPoint.Gradient.Z = (GradientH[2] - GradientH[3] * ValueH[2] / ValueH[3]) / ValueH[3]; } else { OutPoint.Gradient.Set(GradientH[0], GradientH[1], GradientH[2]); } if (DerivativeOrder > 1) { if (Nurbs.IsRational()) { OutPoint.Laplacian.X = (LaplacianH[0] * ValueH[3] - LaplacianH[3] * ValueH[0] - 2.0 * GradientH[3] * (GradientH[0] - GradientH[3] * ValueH[0] / ValueH[3])) / (ValueH[3] * ValueH[3]); OutPoint.Laplacian.Y = (LaplacianH[1] * ValueH[3] - LaplacianH[3] * ValueH[1] - 2.0 * GradientH[3] * (GradientH[1] - GradientH[3] * ValueH[1] / ValueH[3])) / (ValueH[3] * ValueH[3]); OutPoint.Laplacian.Z = (LaplacianH[2] * ValueH[3] - LaplacianH[3] * ValueH[2] - 2.0 * GradientH[3] * (GradientH[2] - GradientH[3] * ValueH[2] / ValueH[3])) / (ValueH[3] * ValueH[3]); } else { OutPoint.Laplacian.Set(LaplacianH[0], LaplacianH[1], LaplacianH[2]); } } } } void Evaluate2DPoint(const FNURBSCurve& Nurbs, double Coordinate, FCurvePoint2D& OutPoint, int32 DerivativeOrder) { ensureCADKernel(Nurbs.GetDimension() == 2); OutPoint.DerivativeOrder = DerivativeOrder; double ValueH[3]; double GradientH[3]; double LaplacianH[3]; int32 PoleDimension = Nurbs.GetDimension() + (Nurbs.IsRational() ? 1 : 0); BSpline::Interpolate1DBSpline(Nurbs.GetDegree(), Nurbs.GetPoleCount(), Nurbs.GetNodalVector().GetData(), PoleDimension, Nurbs.GetHPoles().GetData(), 1, &Coordinate, DerivativeOrder, ValueH, GradientH, LaplacianH); const double InvWeight = 1. / ValueH[2]; if (Nurbs.IsRational()) { OutPoint.Point.Set(ValueH[0] * InvWeight, ValueH[1] * InvWeight); } else { OutPoint.Point.Set(ValueH[0], ValueH[1]); } if (DerivativeOrder > 0) { if (Nurbs.IsRational()) { OutPoint.Gradient.X = (GradientH[0] - GradientH[2] * ValueH[0] * InvWeight) * InvWeight; OutPoint.Gradient.Y = (GradientH[1] - GradientH[2] * ValueH[1] * InvWeight) * InvWeight; } else { OutPoint.Gradient.Set(GradientH[0], GradientH[1]); } if (DerivativeOrder > 1) { if (Nurbs.IsRational()) { const double InvWeightSquared = InvWeight * InvWeight; OutPoint.Laplacian.X = (LaplacianH[0] * ValueH[2] - LaplacianH[2] * ValueH[0] - 2.0 * GradientH[2] * (GradientH[0] - GradientH[2] * ValueH[0] * InvWeight)) * InvWeightSquared; OutPoint.Laplacian.Y = (LaplacianH[1] * ValueH[2] - LaplacianH[2] * ValueH[1] - 2.0 * GradientH[2] * (GradientH[1] - GradientH[2] * ValueH[1] * InvWeight)) * InvWeightSquared; } else { OutPoint.Laplacian.Set(LaplacianH[0], LaplacianH[1]); } } } } TSharedPtr DuplicateNurbsCurveWithHigherDegree(int32 Degre, const FNURBSCurve& InCurve) { // To avoid crashes while waiting for the fix (jira UETOOL-5046) return TSharedPtr(); #ifdef UETOOL_5046_WIP TArray NewPoles; TArray NewNodalVector; TArray NewWeights; DuplicateNurbsCurveWithHigherDegree(Degre, InCurve.GetPoles(), InCurve.GetNodalVector(), InCurve.GetWeights(), NewPoles, NewNodalVector, NewWeights); if (NewPoles.IsEmpty()) { return TSharedPtr(); } return FEntity::MakeShared(Degre, NewNodalVector, NewPoles, NewWeights, InCurve.GetDimension()); #endif } void EvaluatePoint(const FNURBSSurface& Nurbs, const FVector2d& InPoint2D, FSurfacicPoint& OutPoint3D, int32 InDerivativeOrder) { double Point4[4]; double GradientU[4]; double GradientV[4]; double LaplacianU[4]; double LaplacianV[4]; double LaplacianUV[4]; BSpline::Interpolate2DBSpline(Nurbs.GetDegree(EIso::IsoU), Nurbs.GetDegree(EIso::IsoV), Nurbs.GetPoleCount(EIso::IsoU), Nurbs.GetPoleCount(EIso::IsoV), Nurbs.GetNodalVector(EIso::IsoU).GetData(), Nurbs.GetNodalVector(EIso::IsoV).GetData(), Nurbs.IsRational() ? 4 : 3, Nurbs.GetHPoles().GetData(), 1, &InPoint2D.X, 1, &InPoint2D.Y, InDerivativeOrder, Point4, GradientU, GradientV, LaplacianU, LaplacianV, LaplacianUV); OutPoint3D.DerivativeOrder = InDerivativeOrder; if (Nurbs.IsRational()) { OutPoint3D.Point.Set(Point4[0] / Point4[3], Point4[1] / Point4[3], Point4[2] / Point4[3]); double PointHSquare = FMath::Square(Point4[3]); if (InDerivativeOrder > 0) { OutPoint3D.GradientU.X = (GradientU[0] * Point4[3] - Point4[0] * GradientU[3]) / PointHSquare; OutPoint3D.GradientU.Y = (GradientU[1] * Point4[3] - Point4[1] * GradientU[3]) / PointHSquare; OutPoint3D.GradientU.Z = (GradientU[2] * Point4[3] - Point4[2] * GradientU[3]) / PointHSquare; OutPoint3D.GradientV.X = (GradientV[0] * Point4[3] - Point4[0] * GradientV[3]) / PointHSquare; OutPoint3D.GradientV.Y = (GradientV[1] * Point4[3] - Point4[1] * GradientV[3]) / PointHSquare; OutPoint3D.GradientV.Z = (GradientV[2] * Point4[3] - Point4[2] * GradientV[3]) / PointHSquare; } if (InDerivativeOrder > 1) { double PointHCubic = Point4[3] * Point4[3] * Point4[3]; double GradientUHSquare = FMath::Square(GradientU[3]); double GradientVHSquare = FMath::Square(GradientV[3]); double GradientUHVH = GradientU[3] * GradientV[3]; OutPoint3D.LaplacianU.X = (LaplacianU[0] * Point4[3] - Point4[0] * LaplacianU[3] - 2.0 * GradientU[0] * GradientU[3]) / PointHSquare + 2.0 * Point4[0] * GradientUHSquare / PointHCubic; OutPoint3D.LaplacianU.Y = (LaplacianU[1] * Point4[3] - Point4[1] * LaplacianU[3] - 2.0 * GradientU[1] * GradientU[3]) / PointHSquare + 2.0 * Point4[1] * GradientUHSquare / PointHCubic; OutPoint3D.LaplacianU.Z = (LaplacianU[2] * Point4[3] - Point4[2] * LaplacianU[3] - 2.0 * GradientU[2] * GradientU[3]) / PointHSquare + 2.0 * Point4[2] * GradientUHSquare / PointHCubic; OutPoint3D.LaplacianV.X = (LaplacianV[0] * Point4[3] - Point4[0] * LaplacianV[3] - 2.0 * GradientV[0] * GradientV[3]) / PointHSquare + 2.0 * Point4[0] * GradientVHSquare / PointHCubic; OutPoint3D.LaplacianV.Y = (LaplacianV[1] * Point4[3] - Point4[1] * LaplacianV[3] - 2.0 * GradientV[1] * GradientV[3]) / PointHSquare + 2.0 * Point4[1] * GradientVHSquare / PointHCubic; OutPoint3D.LaplacianV.Z = (LaplacianV[2] * Point4[3] - Point4[2] * LaplacianV[3] - 2.0 * GradientV[2] * GradientV[3]) / PointHSquare + 2.0 * Point4[2] * GradientVHSquare / PointHCubic; OutPoint3D.LaplacianUV.X = (LaplacianUV[0] * Point4[3] - Point4[0] * LaplacianUV[3] - GradientU[0] * GradientV[3] - GradientV[0] * GradientU[3]) / PointHSquare + 2.0 * Point4[0] * GradientUHVH / PointHCubic; OutPoint3D.LaplacianUV.Y = (LaplacianUV[1] * Point4[3] - Point4[1] * LaplacianUV[3] - GradientU[1] * GradientV[3] - GradientV[1] * GradientU[3]) / PointHSquare + 2.0 * Point4[1] * GradientUHVH / PointHCubic; OutPoint3D.LaplacianUV.Z = (LaplacianUV[2] * Point4[3] - Point4[2] * LaplacianUV[3] - GradientU[2] * GradientV[3] - GradientV[2] * GradientU[3]) / PointHSquare + 2.0 * Point4[2] * GradientUHVH / PointHCubic; } } else { OutPoint3D.Point.Set(Point4[0], Point4[1], Point4[2]); if (InDerivativeOrder > 0) { OutPoint3D.GradientU.Set(GradientU[0], GradientU[1], GradientU[2]); OutPoint3D.GradientV.Set(GradientV[0], GradientV[1], GradientV[2]); if (InDerivativeOrder > 1) { OutPoint3D.LaplacianU.Set(LaplacianU[0], LaplacianU[1], LaplacianU[2]); OutPoint3D.LaplacianV.Set(LaplacianV[0], LaplacianV[1], LaplacianV[2]); OutPoint3D.LaplacianUV.Set(LaplacianUV[0], LaplacianUV[1], LaplacianUV[2]); } } } } void EvaluatePointGrid(const FNURBSSurface& Nurbs, const FCoordinateGrid& Coords, FSurfacicSampling& OutPoints, bool bComputeNormals) { const int32 ULineCount = (int32)Coords.IsoCount(EIso::IsoU); const int32 VLineCount = (int32)Coords.IsoCount(EIso::IsoV); const int32 PointCount = ULineCount * VLineCount; OutPoints.bWithNormals = bComputeNormals; OutPoints.Set2DCoordinates(Coords); TArray HPoints; int32 PointDim = Nurbs.IsRational() ? 4 : 3; HPoints.SetNum(PointCount * PointDim); TArray UGradients; TArray VGradients; int32 DerivativeOrder = 0; if (bComputeNormals) { OutPoints.bWithNormals = true; UGradients.SetNum(PointCount * PointDim); VGradients.SetNum(PointCount * PointDim); DerivativeOrder = 1; } BSpline::Interpolate2DBSpline(Nurbs.GetDegree(EIso::IsoU), Nurbs.GetDegree(EIso::IsoV), Nurbs.GetPoleCount(EIso::IsoU), Nurbs.GetPoleCount(EIso::IsoV), Nurbs.GetNodalVector(EIso::IsoU).GetData(), Nurbs.GetNodalVector(EIso::IsoV).GetData(), Nurbs.IsRational() ? 4 : 3, Nurbs.GetHPoles().GetData(), ULineCount, Coords[EIso::IsoU].GetData(), VLineCount, Coords[EIso::IsoV].GetData(), DerivativeOrder, HPoints.GetData(), UGradients.GetData(), VGradients.GetData(), nullptr, nullptr, nullptr); OutPoints.Points3D.SetNum(PointCount); if (Nurbs.IsRational()) { for (int32 Index = 0, Hndex = 0; Index < PointCount; Index++, Hndex += 4) { double* HPoint = HPoints.GetData() + Hndex; OutPoints.Points3D[Index].Set(HPoint[0] / HPoint[3], HPoint[1] / HPoint[3], HPoint[2] / HPoint[3]); } } else { memcpy(OutPoints.Points3D.GetData(), HPoints.GetData(), PointCount * sizeof(FVector)); } if (bComputeNormals) { OutPoints.Normals.SetNum(PointCount); if (Nurbs.IsRational()) { FVector DeltaU; FVector DeltaV; for (int32 Index = 0; Index < PointCount; Index++) { double* HPoint = HPoints.GetData() + Index * 4; double SquarePointH = FMath::Square(HPoint[3]); double* UGradient = UGradients.GetData() + Index * 4; double* VGradient = VGradients.GetData() + Index * 4; DeltaU.X = (UGradient[0] * HPoint[3] - HPoint[0] * UGradient[3]) / SquarePointH; DeltaU.Y = (UGradient[1] * HPoint[3] - HPoint[1] * UGradient[3]) / SquarePointH; DeltaU.Z = (UGradient[2] * HPoint[3] - HPoint[2] * UGradient[3]) / SquarePointH; DeltaV.X = (VGradient[0] * HPoint[3] - HPoint[0] * VGradient[3]) / SquarePointH; DeltaV.Y = (VGradient[1] * HPoint[3] - HPoint[1] * VGradient[3]) / SquarePointH; DeltaV.Z = (VGradient[2] * HPoint[3] - HPoint[2] * VGradient[3]) / SquarePointH; OutPoints.Normals[Index] = (FVector3f)(DeltaU ^ DeltaV); } } else { double* UGradientsPtr = UGradients.GetData(); double* VGradientsPtr = VGradients.GetData(); for (int32 Index = 0; Index < PointCount; Index++, UGradientsPtr += 3, VGradientsPtr += 3) { const FVector UGradient(UGradientsPtr[0], UGradientsPtr[1], UGradientsPtr[2]); const FVector VGradient(VGradientsPtr[0], VGradientsPtr[1], VGradientsPtr[2]); OutPoints.Normals[Index] = (FVector3f)(UGradient ^ VGradient); } } OutPoints.NormalizeNormals(); } } /******************************description fonction*****************************/ /* Auteur: - Fichier: bspline.c */ /* Role:- Calculer selon la methode de "DeBoor" l'interpolation par fonctions*/ /* BSplines d'ordre "degre" sur l'intervalle numero "segment" d'une */ /* liste de poles de dimensionnalite ndim stokes dans pole_aux[0], par*/ /* rapport au vecteur nodal knot. */ /* On recupere en sortie les valeurs interpolees dans valeur[composante]*/ /* et selon l'ordre de derivation desire (0, 1 ou 2) leurs derivees */ /* premieres et secondes dans Gradient[composante] et Laplacian[composante]. */ /* Toutes les tables de travail (pole_aux, grad_aux, lap_aux) et les */ /* tables de resultats doivent etre allouees par l'appelant. */ /*******************************fin fonction************************************/ void DeBoorValeursBSpline( const int32 Degre, /* E-Ordre de la bspline*/ const double* const NodalVector, /* E-Vecteur nodale de la bspline*/ const int32 SegmentIndex, /* E-Segment sur lequel faire le calcul*/ const int32 PointDimension, /* E-Dimension des poles (1D,2D,3D,4D=3D+poids...)*/ const int32 DeriveOrder, /* E-Ordre de derivation desire*/ const double Coordinate, /* E-*/ double* const InterationPoles, /* S-Les valeurs tempo*/ double* const InterationGardient, /* S-Les derivee premieres tempo*/ double* const lap_aux, /* S-Les derivee secondes tempo*/ double* const OutPoint, /* S-Les valeurs*/ double* const OutGradient, /* S-Les derivee premieres*/ double* const OutLaplacien /* S-Les derivee secondes*/ ) { double DeltaU, OneOnDeltaU, tu, tu1; int32 Index, IndexJ, i_aux, IndexK, deg1; deg1 = Degre + 1; /*Calculer par recurrence les valeurs*/ for (IndexK = 1; IndexK <= Degre; IndexK++) { for (Index = SegmentIndex - Degre + IndexK + 1, i_aux = IndexK; Index <= SegmentIndex + 1; Index++, i_aux++) { DeltaU = NodalVector[Index + Degre - IndexK] - NodalVector[Index - 1]; if (DeltaU <= 1.e-13) { tu = 0.; OneOnDeltaU = 0.; } else { tu = (Coordinate - NodalVector[Index - 1]) / DeltaU; OneOnDeltaU = 1. / DeltaU; } tu1 = 1. - tu; ///*Calcul du point courant*/ int32 A = (i_aux + IndexK * deg1) * PointDimension; int32 B = A - deg1 * PointDimension; for (IndexJ = 0; IndexJ < PointDimension; IndexJ++, A++, B++) { InterationPoles[A] = InterationPoles[B - PointDimension] * tu1 + InterationPoles[B] * tu; } /*Calcul de la derivee premiere*/ if (DeriveOrder >= 1) { A = (i_aux + IndexK * deg1) * PointDimension; B = A - deg1 * PointDimension; for (IndexJ = 0; IndexJ < PointDimension; IndexJ++, A++, B++) { InterationGardient[A] = (InterationPoles[B] - InterationPoles[B - PointDimension]) * OneOnDeltaU + InterationGardient[B - PointDimension] * tu1 + InterationGardient[B] * tu; //InterationGardient[(i_aux + IndexK * deg1)*PointDimension + IndexJ] = InterationGardient[(i_aux - 1 + (IndexK - 1)*deg1)*PointDimension + IndexJ] * tu1 + InterationGardient[(i_aux + (IndexK - 1)*deg1)*PointDimension + IndexJ] * tu + (InterationPoles[(i_aux + (IndexK - 1)*deg1)*PointDimension + IndexJ] - InterationPoles[(i_aux - 1 + (IndexK - 1)*deg1)*PointDimension + IndexJ])* OneOnDeltaU; } } /*Calcul de la derivee seconde*/ if (DeriveOrder >= 2) { for (IndexJ = 0; IndexJ < PointDimension; IndexJ++) { lap_aux[(i_aux + IndexK * deg1) * PointDimension + IndexJ] = lap_aux[(i_aux - 1 + (IndexK - 1) * deg1) * PointDimension + IndexJ] * tu1 + lap_aux[(i_aux + (IndexK - 1) * deg1) * PointDimension + IndexJ] * tu + 2. * (InterationGardient[(i_aux + (IndexK - 1) * deg1) * PointDimension + IndexJ] - InterationGardient[(i_aux - 1 + (IndexK - 1) * deg1) * PointDimension + IndexJ]) * OneOnDeltaU; } } } } /*stocker le point courant*/ std::copy(InterationPoles + (deg1 * deg1 - 1) * PointDimension, InterationPoles + ((deg1 * deg1 - 1) + 1) * PointDimension, OutPoint); /*stocker la derivee premiere*/ if (DeriveOrder > 0) { std::copy(InterationGardient + (deg1 * deg1 - 1) * PointDimension, InterationGardient + ((deg1 * deg1 - 1) + 1) * PointDimension, OutGradient); } /*stocker la derivee seconde*/ if (DeriveOrder > 1) { std::copy(lap_aux + (deg1 * deg1 - 1) * PointDimension, lap_aux + ((deg1 * deg1 - 1) + 1) * PointDimension, OutLaplacien); } } /******************************description fonction*****************************/ /* Auteur: - Fichier: bspline.c */ /* Role:- Calcul des valeurs des fonctions de base BSpline ou de leurs derivees*/ /* jusqu'a l'ordre derivee. */ /* Les fonctions sont definies par: */ /* - degre: degre des fonctions */ /* - nb_pole: nombre total de fonctions */ /* - knot[]: table representant le vecteur nodal */ /* Le calcul est a effectuer sur nb_pt points de coordonnees curvilignes*/ /* definis dans tab_u[] . */ /* On recupere en sortie les valeurs interpolees dans valeur[point] */ /* et selon l'ordre de derivation desire (0, 1 ou 2) leurs derivees */ /* premieres et secondes dans Gradient[point] et Laplacian[point]. */ /*******************************fin fonction************************************/ void calculerBaseBSpline( const int32 degre, /* E-degre des fonctions*/ const int32 derivee, /* E-Ordre de derivation souhaite*/ const int32 nb_pole, /* E-nombre total de fonctions*/ const double* const knot, /* E-table representant le vecteur nodal*/ const int32 nb_pt, /* E-Nombre de parametre a evaluer*/ const double* const tab_u, /* E-La table des parametres*/ double* const valeur, /* S-Les points calcules*/ double* const Gradient, /* S-Les derivees premeieres*/ double* const Laplacian /* S-Les derivees secondes*/ ) { TArray tab_p, val, gra, la; int32 i, ndim; ndim = 1; /* dimensionner les tables necessaires*/ tab_p.SetNum(nb_pole); val.SetNum(nb_pt); if (derivee > 0) { gra.SetNum(nb_pt); if (derivee > 1) { la.SetNum(nb_pt); } } for (i = 0; i < nb_pole; i++) { //for(j=0;j 0 ? &gra[0] : nullptr, derivee > 1 ? &la[0] : nullptr); //for(j=0;j 0) { //for(j=0;j 1) { //for(j=0;j& valeur, /* S-Les points calcules*/ TArray& Gradient, /* S-Les derivees premeieres*/ TArray& Laplacian, /* S-Les derivees secondes*/ TArray& der3 /* S-Les derivees secondes*/ ) { int32 cnt = 0; for (int32 p = 0; p < nb_pole; p++) { for (int32 v = 0; v < nb_pt; v++) { //Calculate the value basis for each pole valeur[cnt] = calculateN_HR(tab_u[v], knot + 1, degre, p); if (derivee >= 1) { Gradient[cnt] = calculateNd1_HR(tab_u[v], knot + 1, degre, p); } if (derivee >= 2) { Laplacian[cnt] = calculateNd2_HR(tab_u[v], knot + 1, degre, p); } if (derivee >= 3) { der3[cnt] = calculateNd3_HR(tab_u[v], knot + 1, degre, p); } cnt++; } } } void matricePassageMonomeBernstein(int32 ordre, TArray& matrice) { int32 i, j, n, signe; TArray C; n = ordre - 1; // allouer la table permettant le calcul des C(i,j) C.SetNum(ordre * ordre); // initialiser les C(i,j) et matrice(i,j) for (i = 0; i < ordre * ordre; i++) { C[i] = 0.0; matrice[i] = 0.0; } // calculer les C(i,j) for (i = 0; i < ordre; i++) { C[i * ordre + 0] = 1.0; C[i * ordre + i] = 1.0; for (j = 1; j < i; j++) { C[i * ordre + j] = C[i * ordre + j - 1] * (i - j + 1) / j; } } // Calculer les coefficients de la matrice for (i = 0; i < ordre; i++) { signe = 1; for (j = i; j < ordre; j++) { matrice[i * ordre + j] = signe * C[n * ordre + j] * C[j * ordre + i]; signe *= -1; } } } void coeffCourbeToPolesBezier(int32 order, int32 nbDim, TArray& tabCoeff, TArray& tabPoles) { TArray C; C.SetNum(order * order); // calcul de la matrice de passage matricePassageMonomeBernstein(order, C); // inversion de cette matrice InverseMatrixN(C.GetData(), order); // effectuer le produit tab_pole[] = tab_coeff[] * C1[] MatrixProduct(nbDim, order, order, tabCoeff.GetData(), C.GetData(), tabPoles.GetData()); } void coeffSurfaceToPolesBezier(int32 orderU, int32 orderV, int32 nbDim, const TArray& tabCoeff, TArray& tabPoles) { TArray Cu, Cv, Cvt, Mtp; int32 nbVal = orderU * orderV; TArray vecCoeff; TArray vecPoles; Cu.SetNum(orderU * orderU); Cv.SetNum(orderV * orderV); Cvt.SetNum(orderV * orderV); Mtp.SetNum(orderU * orderV); vecPoles.SetNum(nbVal); // calcul de la matrice de passage matricePassageMonomeBernstein(orderU, Cu); // calcul de la matrice de passage matricePassageMonomeBernstein(orderV, Cv); // transposer la matrice Cv[] TransposeMatrix(orderV, orderV, Cv.GetData(), Cvt.GetData()); // inversion de ces matrices InverseMatrixN(Cu.GetData(), orderU); InverseMatrixN(Cvt.GetData(), orderV); // pour chaque coordonnees effectuer le produit : // tab_pole[] = Cvt[]* tab_coeff[] * Cu[] for (int32 i = 0; i < nbDim; i++) { vecCoeff.Empty(); vecCoeff.Reserve(nbVal); for (int32 k = 0; k < nbVal; k++) { vecCoeff.Add(tabCoeff[i * nbVal + k]); } MatrixProduct(orderV, orderV, orderU, Cvt.GetData(), vecCoeff.GetData(), Mtp.GetData()); MatrixProduct(orderV, orderU, orderU, Mtp.GetData(), Cu.GetData(), vecPoles.GetData()); for (int32 k = 0; k < nbVal; k++) { tabPoles[i * nbVal + k] = vecPoles[k]; } } } void FindNotDerivableParameters(int32 Degree, int32 PoleCount, const TArray& NodalVector, int32 DerivativeOrder, const FLinearBoundary& Boundary, TArray& OutNotDerivableParameters) { double udeb; int32 i, multiplicite; udeb = NodalVector[0]; i = 1; multiplicite = 1; while (i < Degree + PoleCount + 1) { // noter la valeur courante du noeud udeb = NodalVector[i]; multiplicite = 1; // definir l'ordre de multiplicite du noeud while (i < Degree + PoleCount) { if (FMath::Abs(NodalVector[i + 1] - udeb) > DOUBLE_SMALL_NUMBER) break; multiplicite++; i++; } // si le noeud est different du noeud debut ou fin tester la discontinuite if ((udeb > NodalVector[0]) && (udeb < NodalVector[Degree + PoleCount])) { // ne rechercher la discontinuite que dans l'intervalle specifie if ((udeb > Boundary.Min) && (udeb < Boundary.Max)) { // verifier la condition necessaire de derivabilite if (multiplicite > Degree - DerivativeOrder) { OutNotDerivableParameters.Add(udeb); } } } i++; } } void FindNotDerivableParameters(const FNURBSCurve& Curve, int32 InDerivativeOrder, const FLinearBoundary& Boundary, TArray& OutNotDerivableParameters) { FindNotDerivableParameters(Curve.GetDegree(), Curve.GetPoleCount(), Curve.GetNodalVector(), InDerivativeOrder, Boundary, OutNotDerivableParameters); } void FindNotDerivableParameters(const FNURBSSurface& Nurbs, int32 InDerivativeOrder, const FSurfacicBoundary& Boundary, FCoordinateGrid& OutNotDerivableParameters) { FindNotDerivableParameters(Nurbs.GetDegree(EIso::IsoU), Nurbs.GetPoleCount(EIso::IsoU), Nurbs.GetNodalVector(EIso::IsoU), InDerivativeOrder, Boundary[EIso::IsoU], OutNotDerivableParameters[EIso::IsoU]); FindNotDerivableParameters(Nurbs.GetDegree(EIso::IsoV), Nurbs.GetPoleCount(EIso::IsoV), Nurbs.GetNodalVector(EIso::IsoV), InDerivativeOrder, Boundary[EIso::IsoV], OutNotDerivableParameters[EIso::IsoV]); } void SampleNodalVector(double UMin, double UMax, TArray& nodalVector, int32 nbPoles, int32 degre, TArray* TabU) { int32 ideb = degre; int32 ifin = nbPoles; double uCourant = nodalVector[ideb]; double u1 = UMin; double u2 = UMax; TabU->Empty(); for (int32 i = ideb; i < ifin; i++) { if (nodalVector[i + 1] < UMin) { uCourant = nodalVector[i + 1]; continue; } // passer sur les noeuds multiples if (FMath::Abs(nodalVector[i + 1] - nodalVector[i]) < DOUBLE_SMALL_NUMBER) continue; else uCourant = nodalVector[i]; // definir les bornes de l'intervalle a discretiser if (uCourant > u1 + DOUBLE_SMALL_NUMBER) u1 = uCourant; if (nodalVector[i + 1] < u2 - DOUBLE_SMALL_NUMBER) u2 = nodalVector[i + 1]; // repartir les parametres dans l'intervalle courant*/ if (degre <= 1) { // prendre le point milieu si on n'est pas dans le premier intervalle // ou dans le dernier intervalle if (u1 > UMin && u2 < UMax) { TabU->Add((u1 + u2) / 2.0); } else if (FMath::IsNearlyEqual(u1, UMin)) { TabU->Add(u1); } } else { TabU->Reserve(TabU->Num() + degre); for (int32 j = 0; j < degre; j++) { TabU->Add(u1 + (u2 - u1) * (double)j / (double)degre); } } // tester s'il s'agit du dernier intervalle if (u2 > UMax - DOUBLE_SMALL_NUMBER) break; // passer a l'intervalle suivant u1 = u2; u2 = UMax; } // dernier point TabU->Add(UMax); } void DuplicateNurbsCurveWithHigherDegree(int32 degre, const TArray& poles, const TArray& nodalVector, const TArray& weights, TArray& newPoles, TArray& newNodalVector, TArray& newWeights) { //Count number of polynomial segments and //create new knot vector TArray segMaps; newNodalVector.Empty(); int32 nbSegs = 0; for (int32 i = 0; i < nodalVector.Num(); i++) { newNodalVector.Add(nodalVector[i]); if (i == nodalVector.Num() - 1) { newNodalVector.Add(nodalVector[i]); break; } if (!FMath::IsNearlyEqual(nodalVector[i], nodalVector[i + 1])) { segMaps.Add(i); segMaps.Add((int32)newNodalVector.Num()); newNodalVector.Add(nodalVector[i]); nbSegs++; } } newPoles.SetNum(poles.Num() + nbSegs); newWeights.SetNum(poles.Num() + nbSegs); //int32 newN=n+1; int32 newN = degre + 1; if (newPoles.Num() + newN - 1 != newNodalVector.Num()) { // To avoid crashes while waiting for the fix (jira UETOOL-5046) newPoles.Empty(); return; } TArray polesDone; polesDone.Init(false, newPoles.Num()); //Calculate all poles for each segment. for (int32 l = 0; l < segMaps.Num(); l += 2) { int32 seg = segMaps[l]; int32 newSeg = segMaps[l + 1]; int32 i; for (i = 0; i < newN + 1; i++) { if (polesDone[newSeg - newN + 1 + i]) continue; TArray> params; params.SetNum(newN); for (int32 j = 0; j < newN; j++) { for (int32 k = 0; k < newN; k++) { if (k != j) { params[j].Add(newNodalVector[newSeg - newN + 1 + k + i]); } } } TArray poles_; poles_.SetNum(newN); TArray weightsTmp; weightsTmp.SetNum(newN); for (int32 k = 0; k < newN; k++) { Blossom(degre, poles, nodalVector, weights, seg, params[k], poles_[k], weightsTmp[k]); } FVector pole(0, 0, 0); double w = 0; for (int32 k = 0; k < newN; k++) { pole[0] += poles_[k][0] * weightsTmp[k]; pole[1] += poles_[k][1] * weightsTmp[k]; pole[2] += poles_[k][2] * weightsTmp[k]; w += weightsTmp[k]; } pole[0] *= 1.0 / newN; pole[1] *= 1.0 / newN; pole[2] *= 1.0 / newN; w /= newN; pole[0] *= 1.0 / w; pole[1] *= 1.0 / w; pole[2] *= 1.0 / w; newPoles[newSeg - newN + 1 + i][0] = pole[0]; newPoles[newSeg - newN + 1 + i][1] = pole[1]; newPoles[newSeg - newN + 1 + i][2] = pole[2]; newWeights[newSeg - newN + 1 + i] = w; polesDone[newSeg - newN + 1 + i] = true; } } } int32 getKnotMultiplicity(const TArray& knots, double u) { int32 m = 0; for (int32 i = 0; i < (int32)knots.Num(); i++) if (FMath::IsNearlyEqual(knots[i], u)) m++; return m; } void insertKnotInKnots(TArray& vn, double u, double* newU = nullptr) { TArray newKnots; newKnots.Reserve(vn.Num() + 1); bool done = false; for (int32 i = 0; i < (int32)vn.Num() - 1; i++) { newKnots.Add(vn[i]); if ((!done) && vn[i] <= u && u <= vn[i + 1]) { newKnots.Add(newU ? *newU : u); done = true; } } newKnots.Add(vn[vn.Num() - 1]); Swap(vn, newKnots); } void InsertKnot(TArray& vn, TArray& poles, TArray& weights, double u, double* newU) { int32 i = 0; int32 n = (int32)vn.Num() - (int32)poles.Num() + 1; //Degree TArray newPoles; TArray newWeights; newPoles.Reserve(poles.Num() + vn.Num()); newWeights.Reserve(poles.Num() + vn.Num()); newPoles.Add(poles[0]); newWeights.Add(weights[0]); int32 front = 1; for (i = 0; i < (int32)poles.Num() - 1; i++) { if (vn[i] <= u && u < vn[i + n]) { double w1 = weights[i]; double w2 = weights[i + 1]; double c1 = ((vn[i + n] - u) / (vn[i + n] - vn[i])); double c2 = ((u - vn[i]) / (vn[i + n] - vn[i])); double w = w1 * c1 + w2 * c2; FVector p((poles[i][0] * w1 * c1 + poles[i + 1][0] * w2 * c2) / w, (poles[i][1] * w1 * c1 + poles[i + 1][1] * w2 * c2) / w, (poles[i][2] * w1 * c1 + poles[i + 1][2] * w2 * c2) / w); newPoles.Add(p); newWeights.Add(w); front = 0; continue; } newPoles.Add(poles[i + front]); newWeights.Add(weights[i + front]); } newPoles.Add(poles[poles.Num() - 1]); newWeights.Add(weights[poles.Num() - 1]); Swap(poles, newPoles); Swap(weights, newWeights); insertKnotInKnots(vn, u, newU); } void insertKnotVInPatch(double v, int32 nbTime, TArray& knotsV, TArray>& poles, TArray>& weights) { TArray knotsTmp; int32 nbCurveV = (int32)poles.Num(); for (int32 i = 0; i < nbCurveV; i++) { knotsTmp = knotsV; for (int32 j = 0; j < nbTime; j++) { InsertKnot(knotsTmp, poles[i], weights[i], v); } } knotsV = knotsTmp; } void insertKnotUInPatch(double u, int32 nbTime, TArray& knotsU, TArray>& poles, TArray>& weights) { int32 nbCurveU = (int32)poles[0].Num(); int32 nbPoleCurveU = (int32)poles.Num(); int32 i, j; TArray polesCurveU; TArray weightsCurveU; TArray knotsTmp; for (j = 0; j < nbTime; j++) { TArray& SubPoles = poles.Emplace_GetRef(); SubPoles.SetNum(nbCurveU); TArray& SubWeights = weights.Emplace_GetRef(); SubWeights.Reserve(nbCurveU); } for (i = 0; i < nbCurveU; i++) { knotsTmp = knotsU; polesCurveU.SetNum(nbPoleCurveU); weightsCurveU.SetNum(nbPoleCurveU); for (j = 0; j < nbPoleCurveU; j++) { polesCurveU[j] = poles[j][i]; weightsCurveU[j] = weights[j][i]; } for (j = 0; j < nbTime; j++) { InsertKnot(knotsTmp, polesCurveU, weightsCurveU, u); } for (j = 0; j < (int32)polesCurveU.Num(); j++) { poles[j][i] = polesCurveU[j]; weights[j][i] = weightsCurveU[j]; } } knotsU = knotsTmp; } void rebound(TArray& knots, TArray& poles, TArray& weights, double u1, double u2) { // TD 21/09/2016 : corrige un crash à l'import de certaines pièces if (u1 > u2) { //si les points ne sont pas ordonnés correctement, on inverse les listes Algo::Reverse(knots); Algo::Reverse(poles); Algo::Reverse(weights); } int32 deg = (int32)knots.Num() - (int32)poles.Num() + 1; //Rebound curve by knot insertion of u1 then u2... while (getKnotMultiplicity(knots, u1) < deg) { InsertKnot(knots, poles, weights, u1); } while (getKnotMultiplicity(knots, u2) < deg) { InsertKnot(knots, poles, weights, u2); } //Now find the corresponding greville abscissas int32 u1Ind = -1, u2Ind = -1; for (int32 i = 0; i < (int32)knots.Num(); i++) { if (FMath::IsNearlyEqual(knots[i], u1) && u1Ind == -1) u1Ind = i; if (FMath::IsNearlyEqual(knots[i], u2) && u2Ind == -1) u2Ind = i; } //Now trim the NURBS around these abscissas TArray tKnots; tKnots.Append(knots.GetData() + u1Ind, u2Ind + 1 - u1Ind); TArray tPoles; tPoles.Append(poles.GetData() + u1Ind, u2Ind + 1 - u1Ind); TArray tWeights; tWeights.Append(weights.GetData() + u1Ind, u2Ind + 1 - u1Ind); //Add the deg-1 knots to end the knot vector tKnots.Reserve(tKnots.Num() + deg - 1); for (int32 i = 0; i < deg - 1; i++) tKnots.Add(knots[u2Ind]); Swap(poles, tPoles); Swap(weights, tWeights); Swap(knots, tKnots); } TArray homogeniseCurveKnots(TArray>& cbKnots, double uMin, double uMax) { TArray knots; int32 j = 0; for (int32 i = 0; i < (int32)cbKnots.Num(); i++) { TArray& cbKnot = cbKnots[i]; if (cbKnot.Num() == 0) continue; double cbUMin = cbKnot[0], cbUMax = cbKnot[0]; for (j = 1; j < (int32)cbKnot.Num(); j++) { if (cbUMin > cbKnot[j]) cbUMin = cbKnot[j]; if (cbUMax < cbKnot[j]) cbUMax = cbKnot[j]; } //Normalize between uMin and uMax. for (j = 0; j < (int32)cbKnot.Num(); j++) cbKnot[j] = uMin + (uMax - uMin) * (cbKnot[j] - cbUMin) / (cbUMax - cbUMin); for (j = 0; j < (int32)cbKnot.Num(); j++) { while (getKnotMultiplicity(knots, cbKnot[j]) < getKnotMultiplicity(cbKnot, cbKnot[j])) { //This not doesn't exist with this multiplicity... So add it knots.Add(cbKnot[j]); } } for (int32 k = 0; k < (int32)knots.Num(); k++) { for (j = k; j < (int32)knots.Num(); j++) { if (knots[j] < knots[k]) { double t = knots[j]; knots[j] = knots[k]; knots[k] = t; } } } } return knots; } void Blossom(int32 degre, const TArray& poles, const TArray& nodalVector, const TArray& weights, int32 seg, TArray& params, FVector& pnt, double& weight) { int32 n = degre; int32 i = 0; //There must be n params. //Check interval is valid if (seg < n - 1) seg = n - 1; if (seg > (int32)nodalVector.Num() - n - 1) seg = (int32)nodalVector.Num() - n - 1; //Make recursion table so that (with first concerned pole =2 //because for example n=3 and seg=4) // d(2,0) // d(3,0) d(3,1) // d(4,0) d(4,1) d(4,2) // d(5,0) d(5,1) d(5,2) d(5,3) //So with firstPole=2, recursion[4-firstPole][1]=d(4,1); TArray> recursion; recursion.SetNum(n + 1); //We have n+1 lines for (i = 0; i < n + 1; i++) { recursion[i].SetNum(n + 1); //Make the triangle } TArray> recWeights; recWeights.SetNum(n + 1); //We have n+1 lines for (i = 0; i < n + 1; i++) { recWeights[i].SetNum(n + 1); //Make the triangle } //For each pole startParam is the param value if the pole //is the first on the polygon segment and endParam is the //param value if the pole is at the end of the polygone //segment. TArray> startParam; startParam.SetNum(n + 1); //We have n+1 lines for (i = 0; i < n + 1; i++) { startParam[i].SetNum(n + 1); //Make the triangle } TArray> endParam; endParam.SetNum(n + 1); //We have n+1 lines for (i = 0; i < n + 1; i++) { endParam[i].SetNum(n + 1); //Make the triangle } //Calculate first and last concerned initial poles. int32 firstPole = seg - n + 1; int32 lastPole = firstPole + n; //Fill first colonne for (i = firstPole; i <= lastPole; i++) { recursion[i - firstPole][0][0] = poles[i][0] * weights[i]; recursion[i - firstPole][0][1] = poles[i][1] * weights[i]; recursion[i - firstPole][0][2] = poles[i][2] * weights[i]; recWeights[i - firstPole][0] = weights[i]; } //Set start and end params for (i = firstPole; i <= lastPole; i++) { //For example pole 0 starts at u0 and ends at u3 (for n=3) startParam[i - firstPole][0] = nodalVector[i]; endParam[i - firstPole][0] = nodalVector[i + n - 1]; } //Apply de Boor algorithm for each param, there must be n params. //For colonne 1 we use param 1, for colonne 2 we use param 2, ... for (int32 c = 1; c <= n; c++) { //colonne goes from 1 to n //Calculate pole for (int32 l = c; l <= n; l++) { //line goes from line to n //Evaluate intermediate pole. double dt = (endParam[l - 0][c - 1] - startParam[l - 1][c - 1]); FVector pole; double div = (params[c - 1] - startParam[l - 1][c - 1]) / dt; pole[0] = recursion[l - 1][c - 1][0] * 1.0 + (-recursion[l - 1][c - 1][0] + recursion[l][c - 1][0]) * div; pole[1] = recursion[l - 1][c - 1][1] * 1.0 + (-recursion[l - 1][c - 1][1] + recursion[l][c - 1][1]) * div; pole[2] = recursion[l - 1][c - 1][2] * 1.0 + (-recursion[l - 1][c - 1][2] + recursion[l][c - 1][2]) * div; double w = recWeights[l - 1][c - 1] * 1.0 + (-recWeights[l - 1][c - 1] + recWeights[l][c - 1]) * div; recursion[l][c][0] = pole[0]; recursion[l][c][1] = pole[1]; recursion[l][c][2] = pole[2]; recWeights[l][c] = w; //For FParameters, the new pole takes startParam of pole c-1 and endParam of pole l-1,c-1 (because new param is inserted here). startParam[l][c] = startParam[l][c - 1]; endParam[l][c] = endParam[l - 1][c - 1]; } } pnt[0] = recursion[n][n][0] / recWeights[n][n]; pnt[1] = recursion[n][n][1] / recWeights[n][n]; pnt[2] = recursion[n][n][2] / recWeights[n][n]; weight = recWeights[n][n]; } void composeNodalVector(double UMin, double UMax, int32 degre, int32 nbPoles, TArray* nodalVector) { nodalVector->Empty(); nodalVector->Reserve(2 * (degre + 1) + nbPoles - degre + 1); for (int32 k = 0; k < degre + 1; k++) { nodalVector->Add(UMin); } int32 nbInter = nbPoles + 1 - degre; for (int32 k = 1; k < nbInter - 1; k++) { double val = UMin + ((double)k) / (nbInter - 1) * (UMax - UMin); nodalVector->Add(val); } for (int32 k = 0; k < degre + 1; k++) nodalVector->Add(UMax); } void hermite(double t, double* H, double* dH, double* ddH) { H[0] = 2.0 * t * t * t - 3.0 * t * t + 1.0; H[1] = t * t * t - 2.0 * t * t + t; H[2] = t * t * t - t * t; H[3] = -2.0 * t * t * t + 3.0 * t * t; if (dH) { dH[0] = 6. * t * t - 6. * t; dH[1] = 3. * t * t - 4. * t + 1.; dH[2] = 3. * t * t - 2. * t; dH[3] = -6. * t * t + 6. * t; } if (ddH) { ddH[0] = 12. * t - 6.; ddH[1] = 6. * t - 4.; ddH[2] = 6. * t - 2.; ddH[3] = -12. * t + 6.; } } } // namespace Bspline } // namespace UE::CADKernel