Files
UnrealEngine/Engine/Source/Runtime/Datasmith/CADKernel/Base/Private/Math/BSpline.cpp
2025-05-18 13:04:45 +08:00

1847 lines
62 KiB
C++

// 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 <algorithm>
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<double>& vn, TArray<FVector>& poles, TArray<double>& weights, double u, double* newU = nullptr);
void Blossom(int32 degre, const TArray<FVector>& poles, const TArray<double>& vecteurNodal, const TArray<double>& poids, int32 seg, TArray<double>& params, FVector& pnt, double& weight);
void DuplicateNurbsCurveWithHigherDegree(int32 degre, const TArray<FVector>& poles, const TArray<double>& nodalVector, const TArray<double>& weights, TArray<FVector>& newPoles, TArray<double>& newNodalVector, TArray<double>& 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<double> 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<double> pole_aux;
TArray<double> grad_aux;
TArray<double> lap_aux;
int32 Index, IndexK, StartIndex, EndIndex, Segment, PreviousSegment, IndexSegment, DegrePlus1, SquareDegre;
TArray<double> 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 <ifin && currentU > 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<double> tab_t1;
TArray<double> tab_t2;
TArray<double> pole1;
TArray<double> pole2;
TArray<double> pole_aux;
TArray<double> val_aux;
TArray<double> d1pole_aux;
TArray<double> d1pole2;
TArray<double> d1val_aux;
TArray<double> d2val_aux;
TArray<double> d11pole_aux;
TArray<double> d11pole2;
TArray<double> d11val_aux;
TArray<double> d22val_aux;
TArray<double> 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<ndim; k++) d1pole2[(i*nb_pt1+j)*ndim+k] = d1pole_aux[(j*nb_pole2 +i)*ndim+k];
std::copy(d1pole_aux.GetData() + (IndexU * nb_pole2 + IndexV) * ndim, d1pole_aux.GetData() + ((IndexU * nb_pole2 + IndexV) + 1) * ndim, d1pole2.GetData() + (IndexV * nb_pt1 + IndexU) * ndim);
}
}
}
/* derivee seconde des valeurs par rapport au premier parametre*/
if (derivee >= 2)
{
for (IndexV = 0; IndexV < nb_pole2; IndexV++)
{
for (IndexU = 0; IndexU < nb_pt1; IndexU++)
{
//for(k=0; k<ndim; k++) d11pole2[(i*nb_pt1+j)*ndim+k] = d11pole_aux[(j*nb_pole2 +i)*ndim+k];
std::copy(d11pole_aux.GetData() + (IndexU * nb_pole2 + IndexV) * ndim, d11pole_aux.GetData() + ((IndexU * nb_pole2 + IndexV) + 1) * ndim, d11pole2.GetData() + (IndexV * nb_pt1 + IndexU) * ndim);
}
}
}
/* interpoler et deriver le vecteur des valeurs par rapport au second parametre*/
Interpolate1DBSpline(deg2, nb_pole2, knot2, nb_pt1 * ndim, &(pole2[0]), nb_pt2, &(tab_t2[0]), derivee, &(val_aux[0]), derivee > 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<FNURBSCurve> DuplicateNurbsCurveWithHigherDegree(int32 Degre, const FNURBSCurve& InCurve)
{
// To avoid crashes while waiting for the fix (jira UETOOL-5046)
return TSharedPtr<FNURBSCurve>();
#ifdef UETOOL_5046_WIP
TArray<FVector> NewPoles;
TArray<double> NewNodalVector;
TArray<double> NewWeights;
DuplicateNurbsCurveWithHigherDegree(Degre, InCurve.GetPoles(), InCurve.GetNodalVector(), InCurve.GetWeights(), NewPoles, NewNodalVector, NewWeights);
if (NewPoles.IsEmpty())
{
return TSharedPtr<FNURBSCurve>();
}
return FEntity::MakeShared<FNURBSCurve>(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<double> HPoints;
int32 PointDim = Nurbs.IsRational() ? 4 : 3;
HPoints.SetNum(PointCount * PointDim);
TArray<double> UGradients;
TArray<double> 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<double> 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<nb_pole;j++) tab_p[j] = 0.0;
tab_p.Init(0.0, nb_pole);
tab_p[i] = 1.0;
Interpolate1DBSpline(degre, nb_pole, knot, ndim, &tab_p[0], nb_pt, tab_u, derivee, &val[0], derivee > 0 ? &gra[0] : nullptr, derivee > 1 ? &la[0] : nullptr);
//for(j=0;j<nb_pt;j++) valeur[i*nb_pt+j] = val[j];
std::copy(valeur + i * nb_pt, valeur + i * nb_pt + nb_pt, val.GetData());
if (derivee > 0)
{
//for(j=0;j<nb_pt;j++) Gradient[i*nb_pt+j] = gra[j];
std::copy(Gradient + i * nb_pt, Gradient + i * nb_pt + nb_pt, gra.GetData());
if (derivee > 1)
{
//for(j=0;j<nb_pt;j++) Laplacian[i*nb_pt+j] = la[j];
std::copy(Laplacian + i * nb_pt, Laplacian + i * nb_pt + nb_pt, la.GetData());
}
}
}
}
double calculateN_HR(double u, const double* knots, int32 n, int32 l)
{
if (n == 0)
{
if (FMath::IsNearlyEqual(knots[l - 1], knots[l]) && FMath::IsNearlyEqual(u, knots[l])) return 1;
else if (knots[l - 1] <= u && u < knots[l]) return 1;
return 0;
}
double n1 = calculateN_HR(u, knots, n - 1, l);
double n2 = calculateN_HR(u, knots, n - 1, l + 1);
double c1 = 0, c2 = 0;
if (!FMath::IsNearlyZero(n1)) c1 = (u - knots[l - 1]) / (knots[l + n - 1] - knots[l - 1]);
if (!FMath::IsNearlyZero(n2)) c2 = (knots[l + n] - u) / (knots[l + n] - knots[l]);
return c1 * n1 + c2 * n2;
}
double calculateNd1_HR(double u, const double* knots, int32 n, int32 l)
{
if (n == 0) return 0;
double n1 = calculateN_HR(u, knots, n - 1, l);
double n2 = calculateN_HR(u, knots, n - 1, l + 1);
double n1d1 = calculateNd1_HR(u, knots, n - 1, l);
double n2d1 = calculateNd1_HR(u, knots, n - 1, l + 1);
double c1 = 0, c2 = 0, c1d1 = 0, c2d1 = 0;
if (!FMath::IsNearlyZero(n1)) c1d1 = (1. - 0.) / (knots[l + n - 1] - knots[l - 1]);
if (!FMath::IsNearlyZero(n1d1)) c1 = (u - knots[l - 1]) / (knots[l + n - 1] - knots[l - 1]);
if (!FMath::IsNearlyZero(n2)) c2d1 = (0. - 1.) / (knots[l + n] - knots[l]);
if (!FMath::IsNearlyZero(n2d1)) c2 = (knots[l + n] - u) / (knots[l + n] - knots[l]);
return c1d1 * n1 + c1 * n1d1 +
c2d1 * n2 + c2 * n2d1;
}
double calculateNd2_HR(double u, const double* knots, int32 n, int32 l)
{
if (n == 0)
{
return 0;
}
double n1 = calculateN_HR(u, knots, n - 1, l);
double n2 = calculateN_HR(u, knots, n - 1, l + 1);
double n1d1 = calculateNd1_HR(u, knots, n - 1, l);
double n2d1 = calculateNd1_HR(u, knots, n - 1, l + 1);
double n1d2 = calculateNd2_HR(u, knots, n - 1, l);
double n2d2 = calculateNd2_HR(u, knots, n - 1, l + 1);
double c1 = 0, c2 = 0, c1d1 = 0, c2d1 = 0, c1d2 = 0, c2d2 = 0;
if (!FMath::IsNearlyZero(knots[l + n - 1] - knots[l - 1])) c1d1 = (1. - 0.) / (knots[l + n - 1] - knots[l - 1]);
if (!FMath::IsNearlyZero(knots[l + n - 1] - knots[l - 1])) c1 = (u - knots[l - 1]) / (knots[l + n - 1] - knots[l - 1]);
if (!FMath::IsNearlyZero(knots[l + n] - knots[l])) c2d1 = (0. - 1.) / (knots[l + n] - knots[l]);
if (!FMath::IsNearlyZero(knots[l + n] - knots[l])) c2 = (knots[l + n] - u) / (knots[l + n] - knots[l]);
return c1d2 * n1 + c1d1 * n1d1 +
c1d1 * n1d1 + c1 * n1d2 +
c2d2 * n2 + c2d1 * n2d1 +
c2d1 * n2d1 + c2 * n2d2;
}
double calculateNd3_HR(double u, const double* knots, int32 n, int32 l)
{
if (n == 0) return 0;
double n1 = calculateN_HR(u, knots, n - 1, l);
double n2 = calculateN_HR(u, knots, n - 1, l + 1);
double n1d1 = calculateNd1_HR(u, knots, n - 1, l);
double n2d1 = calculateNd1_HR(u, knots, n - 1, l + 1);
double n1d2 = calculateNd2_HR(u, knots, n - 1, l);
double n2d2 = calculateNd2_HR(u, knots, n - 1, l + 1);
double n1d3 = calculateNd3_HR(u, knots, n - 1, l);
double n2d3 = calculateNd3_HR(u, knots, n - 1, l + 1);
double c1 = 0, c2 = 0, c1d1 = 0, c2d1 = 0, c1d2 = 0, c2d2 = 0, c1d3 = 0, c2d3 = 0;
if (!FMath::IsNearlyZero(knots[l + n - 1] - knots[l - 1])) c1d1 = (1. - 0.) / (knots[l + n - 1] - knots[l - 1]);
if (!FMath::IsNearlyZero(knots[l + n - 1] - knots[l - 1])) c1 = (u - knots[l - 1]) / (knots[l + n - 1] - knots[l - 1]);
if (!FMath::IsNearlyZero(knots[l + n] - knots[l])) c2d1 = (0. - 1.) / (knots[l + n] - knots[l]);
if (!FMath::IsNearlyZero(knots[l + n] - knots[l])) c2 = (knots[l + n] - u) / (knots[l + n] - knots[l]);
return c1d3 * n1 + c1d2 * n1d1 +
c1d2 * n1d1 + c1d1 * n1d2 +
c1d2 * n1d1 + c1d1 * n1d2 +
c1d1 * n1d2 + c1 * n1d3 +
c2d3 * n2 + c2d2 * n2d1 +
c2d2 * n2d1 + c2d1 * n2d2 +
c2d2 * n2d1 + c2d1 * n2d2 +
c2d1 * n2d2 + c2 * n2d3;
}
void calculerBaseBSpline_HR(
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*/
TArray<double>& valeur, /* S-Les points calcules*/
TArray<double>& Gradient, /* S-Les derivees premeieres*/
TArray<double>& Laplacian, /* S-Les derivees secondes*/
TArray<double>& 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<double>& matrice)
{
int32 i, j, n, signe;
TArray<double> 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<double>& tabCoeff, TArray<double>& tabPoles)
{
TArray<double> 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<double>& tabCoeff, TArray<double>& tabPoles)
{
TArray<double> Cu, Cv, Cvt, Mtp;
int32 nbVal = orderU * orderV;
TArray<double> vecCoeff;
TArray<double> 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<double>& NodalVector, int32 DerivativeOrder, const FLinearBoundary& Boundary, TArray<double>& 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<double>& 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<double>& nodalVector, int32 nbPoles, int32 degre, TArray<double>* 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<FVector>& poles, const TArray<double>& nodalVector, const TArray<double>& weights,
TArray<FVector>& newPoles, TArray<double>& newNodalVector, TArray<double>& newWeights)
{
//Count number of polynomial segments and
//create new knot vector
TArray<int32> 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<bool> 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<TArray<double>> 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<FVector> poles_;
poles_.SetNum(newN);
TArray<double> 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<double>& 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<double>& vn, double u, double* newU = nullptr)
{
TArray<double> 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<double>& vn, TArray<FVector>& poles, TArray<double>& weights, double u, double* newU)
{
int32 i = 0;
int32 n = (int32)vn.Num() - (int32)poles.Num() + 1; //Degree
TArray<FVector> newPoles;
TArray<double> 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<double>& knotsV, TArray<TArray<FVector>>& poles, TArray<TArray<double>>& weights)
{
TArray<double> 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<double>& knotsU, TArray<TArray<FVector>>& poles, TArray<TArray<double>>& weights)
{
int32 nbCurveU = (int32)poles[0].Num();
int32 nbPoleCurveU = (int32)poles.Num();
int32 i, j;
TArray<FVector> polesCurveU;
TArray<double> weightsCurveU;
TArray<double> knotsTmp;
for (j = 0; j < nbTime; j++)
{
TArray<FVector>& SubPoles = poles.Emplace_GetRef();
SubPoles.SetNum(nbCurveU);
TArray<double>& 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<double>& knots, TArray<FVector>& poles, TArray<double>& 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<double> tKnots;
tKnots.Append(knots.GetData() + u1Ind, u2Ind + 1 - u1Ind);
TArray<FVector> tPoles;
tPoles.Append(poles.GetData() + u1Ind, u2Ind + 1 - u1Ind);
TArray<double> 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<double> homogeniseCurveKnots(TArray<TArray<double>>& cbKnots, double uMin, double uMax)
{
TArray<double> knots;
int32 j = 0;
for (int32 i = 0; i < (int32)cbKnots.Num(); i++)
{
TArray<double>& 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<FVector>& poles, const TArray<double>& nodalVector, const TArray<double>& weights, int32 seg, TArray<double>& 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<TArray<FVector>> 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<TArray<double>> 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<TArray<double>> 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<TArray<double>> 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<double>* 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