Select Git revision
Forked from
gmsh / gmsh
Source project has a limited visibility.
-
Christophe Geuzaine authored
add missing sanity check in interpolateUBS
Christophe Geuzaine authoredadd missing sanity check in interpolateUBS
Nurbs.cpp 11.45 KiB
// $Id: Nurbs.cpp,v 1.18 2006-01-07 16:12:32 geuzaine Exp $
//
// Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA.
//
// Please report all bugs and problems to <gmsh@geuz.org>.
#include "Gmsh.h"
#include "Nurbs.h"
#include "Mesh.h"
#include "Geo.h"
#include "GeoUtils.h"
#include "Create.h"
#include "CAD.h"
extern Mesh *THEM;
// Cubic spline
Vertex InterpolateCubicSpline(Vertex * v[4], double t, double mat[4][4],
int derivee, double t1, double t2)
{
Vertex V;
int i, j;
double vec[4], T[4];
V.Pos.X = V.Pos.Y = V.Pos.Z = 0.0;
V.lc = (1 - t) * v[1]->lc + t * v[2]->lc;
V.w = (1 - t) * v[1]->w + t * v[2]->w;
if(derivee) {
T[3] = 0.;
T[2] = 1.;
T[1] = 2. * t;
T[0] = 3. * t * t;
}
else {
T[3] = 1.;
T[2] = t;
T[1] = t * t;
T[0] = t * t * t;
}
for(i = 0; i < 4; i++) {
vec[i] = 0.0;
}
/* X */
for(i = 0; i < 4; i++) {
for(j = 0; j < 4; j++) {
vec[i] += mat[i][j] * v[j]->Pos.X;
}
}
for(j = 0; j < 4; j++) {
V.Pos.X += T[j] * vec[j];
vec[j] = 0.0;
}
/* Y */
for(i = 0; i < 4; i++) {
for(j = 0; j < 4; j++) {
vec[i] += mat[i][j] * v[j]->Pos.Y;
}
}
for(j = 0; j < 4; j++) {
V.Pos.Y += T[j] * vec[j];
vec[j] = 0.0;
}
/* Z */
for(i = 0; i < 4; i++) {
for(j = 0; j < 4; j++) {
vec[i] += mat[i][j] * v[j]->Pos.Z;
}
}
for(j = 0; j < 4; j++) {
V.Pos.Z += T[j] * vec[j];
vec[j] = 0.0;
}
if(derivee) {
V.Pos.X /= ((t2 - t1));
V.Pos.Y /= ((t2 - t1));
V.Pos.Z /= ((t2 - t1));
}
return V;
}
// Uniform BSplines
Vertex InterpolateUBS(Curve * Curve, double u, int derivee)
{
int NbControlPoints, NbCurves, iCurve;
double t, t1, t2;
Vertex *v[4];
NbControlPoints = List_Nbr(Curve->Control_Points);
NbCurves = NbControlPoints - 3;
iCurve = (int)(u * (double)NbCurves) + 1;
if(iCurve > NbCurves)
iCurve = NbCurves;
else if (iCurve < 1)
iCurve = 1;
t1 = (double)(iCurve - 1) / (double)(NbCurves);
t2 = (double)(iCurve) / (double)(NbCurves);
t = (u - t1) / (t2 - t1);
List_Read(Curve->Control_Points, iCurve - 1, &v[0]);
List_Read(Curve->Control_Points, iCurve, &v[1]);
List_Read(Curve->Control_Points, iCurve + 1, &v[2]);
List_Read(Curve->Control_Points, iCurve + 2, &v[3]);
return InterpolateCubicSpline(v, t, Curve->mat, derivee, t1, t2);
}
// Non Uniform BSplines
int findSpan(double u, int deg, int n, float *U)
{
if(u >= U[n])
return n - 1;
if(u <= U[0])
return deg;
int low = deg;
int high = n + 1;
int mid = (low + high) / 2;
while(u < U[mid] || u >= U[mid + 1]) {
if(u < U[mid])
high = mid;
else
low = mid;
mid = (low + high) / 2;
}
return mid;
}
void basisFuns(double u, int i, int deg, float *U, double *N)
{
double left[1000];
double *right = &left[deg + 1];
double temp, saved;
//N.resize(deg+1) ;
N[0] = 1.0;
for(int j = 1; j <= deg; j++) {
left[j] = u - U[i + 1 - j];
right[j] = U[i + j] - u;
saved = 0.0;
for(int r = 0; r < j; r++) {
temp = N[r] / (right[r + 1] + left[j - r]);
N[r] = saved + right[r + 1] * temp;
saved = left[j - r] * temp;
}
N[j] = saved;
}
}
Vertex InterpolateNurbs(Curve * Curve, double u, int derivee)
{
static double Nb[1000];
int span =
findSpan(u, Curve->degre, List_Nbr(Curve->Control_Points), Curve->k);
Vertex p, *v;
basisFuns(u, span, Curve->degre, Curve->k, Nb);
p.Pos.X = p.Pos.Y = p.Pos.Z = p.w = p.lc = 0.0;
for(int i = Curve->degre; i >= 0; --i) {
List_Read(Curve->Control_Points, span - Curve->degre + i, &v);
p.Pos.X += Nb[i] * v->Pos.X;
p.Pos.Y += Nb[i] * v->Pos.Y;
p.Pos.Z += Nb[i] * v->Pos.Z;
p.w += Nb[i] * v->w;
p.lc += Nb[i] * v->lc;
}
return p;
}
Vertex InterpolateNurbsSurface(Surface * s, double u, double v)
{
int uspan = findSpan(u, s->OrderU, s->Nu, s->ku);
int vspan = findSpan(v, s->OrderV, s->Nv, s->kv);
double Nu[1000], Nv[1000];
Vertex sp, temp[1000], *pv;
basisFuns(u, uspan, s->OrderU, s->ku, Nu);
basisFuns(v, vspan, s->OrderV, s->kv, Nv);
int l, ll, kk;
for(l = 0; l <= s->OrderV; l++) {
temp[l].Pos.X = temp[l].Pos.Y = temp[l].Pos.Z = temp[l].w = temp[l].lc =
0.0;
for(int k = 0; k <= s->OrderU; k++) {
kk = uspan - s->OrderU + k;
ll = vspan - s->OrderV + l;
List_Read(s->Control_Points, kk + s->Nu * ll, &pv);
temp[l].Pos.X += Nu[k] * pv->Pos.X;
temp[l].Pos.Y += Nu[k] * pv->Pos.Y;
temp[l].Pos.Z += Nu[k] * pv->Pos.Z;
temp[l].w += Nu[k] * pv->w;
temp[l].lc += Nu[k] * pv->lc;
}
}
sp.Pos.X = sp.Pos.Y = sp.Pos.Z = sp.w = sp.lc = 0.0;
for(l = 0; l <= s->OrderV; l++) {
sp.Pos.X += Nv[l] * temp[l].Pos.X;
sp.Pos.Y += Nv[l] * temp[l].Pos.Y;
sp.Pos.Z += Nv[l] * temp[l].Pos.Z;
sp.w += Nv[l] * temp[l].w;
sp.lc += Nv[l] * temp[l].lc;
}
return sp;
}
// Surface creation helpers
void CreateNurbsSurfaceSupport(int Num, int Order1, int Order2,
List_T * List, List_T * ku, List_T * kv)
{
// This routine has been heavily modified to fit the new interfaces,
// but has not been tested since then. It's probably full of bugs
// now.
List_T *ListOfDouble_L;
List_T *ListCP = List_Create(2, 2, sizeof(int));
for(int j = 0; j < List_Nbr(List); j++) {
List_Read(List, j, &ListOfDouble_L);
for(int i = 0; i < List_Nbr(ListOfDouble_L); i++) {
double d;
List_Read(ListOfDouble_L, i, &d);
int N = (int)d;
List_Add(ListCP, &N);
}
}
List_Read(List, 0, &ListOfDouble_L);
int Nu = List_Nbr(List);
int Nv = List_Nbr(ListOfDouble_L);
Surface *s = Create_Surface(Num, MSH_SURF_NURBS);
s->Support = NULL;
s->Control_Points = List_Create(4, 1, sizeof(Vertex *));
s->OrderU = Order1;
s->OrderV = Order2;
s->Nu = Nu;
s->Nv = Nv;
for(int i = 0; i < List_Nbr(ListCP); i++) {
int j;
List_Read(ListCP, i, &j);
Vertex *v = FindPoint(j, THEM);
if(v){
List_Add(s->Control_Points, &v);
}
else{
Msg(GERROR, "Unknown control point %d in nurbs surface", j);
}
}
s->ku = (float *)malloc(List_Nbr(ku) * sizeof(float));
s->kv = (float *)malloc(List_Nbr(kv) * sizeof(float));
double kumin = 0., kumax = 1.;
double kvmin = 0., kvmax = 1.;
for(int i = 0; i < List_Nbr(ku); i++) {
double d;
List_Read(ku, i, &d);
float f = (float)((d - kumin) / (kumax - kumin));
s->ku[i] = f;
}
for(int i = 0; i < List_Nbr(kv); i++) {
double d;
List_Read(kv, i, &d);
float f = (float)((d - kvmin) / (kvmax - kvmin));
s->kv[i] = f;
}
List_Delete(ListCP);
End_Surface(s);
Tree_Add(THEM->Surfaces, &s);
}
void CreateNurbsSurface(int Num, int Order1, int Order2, List_T * List,
List_T * ku, List_T * kv)
{
// This routine has been heavily modified to fit the new interfaces,
// but has not been tested since then. It's probably full of bugs
// now.
List_T *ListOfDouble_L, *Listint, *ListCP;
int Loop[4];
ListCP = List_Create(2, 2, sizeof(int));
double kumin, kumax;
List_Read(ku, 0, &kumin);
List_Read(ku, List_Nbr(ku) - 1, &kumax);
double kvmin, kvmax;
List_Read(kv, 0, &kvmin);
List_Read(kv, List_Nbr(kv) - 1, &kvmax);
for(int j = 0; j < List_Nbr(List); j++) {
List_Read(List, j, &ListOfDouble_L);
for(int i = 0; i < List_Nbr(ListOfDouble_L); i++) {
double d;
List_Read(ListOfDouble_L, i, &d);
int N = (int)d;
List_Add(ListCP, &N);
}
}
// 1st and 3rd gen
List_Read(List, 0, &ListOfDouble_L);
Listint = ListOfDouble2ListOfInt(ListOfDouble_L);
if(recognize_seg(MSH_SEGM_NURBS, Listint, &Loop[0])) {
}
else {
Loop[0] = NEWREG();
Curve *c = Create_Curve(Loop[0], MSH_SEGM_NURBS, Order1, Listint, NULL,
-1, -1, kumin, kumax);
Tree_Add(THEM->Curves, &c);
CreateReversedCurve(THEM, c);
c->k = (float *)malloc(4 * List_Nbr(ku) * sizeof(float));
for(int i = 0; i < List_Nbr(ku); i++) {
double d;
List_Read(ku, i, &d);
c->k[i] = (float)d /*((d-kumin)/(kumax-kumin)) */ ;
}
}
List_Delete(Listint);
List_Read(List, List_Nbr(List) - 1, &ListOfDouble_L);
Listint = ListOfDouble2ListOfInt(ListOfDouble_L);
if(recognize_seg(MSH_SEGM_NURBS, Listint, &Loop[2])) {
}
else {
Loop[2] = NEWREG();
Curve *c = Create_Curve(Loop[2], MSH_SEGM_NURBS, Order1, Listint, NULL,
-1, -1, kumin, kumax);
Tree_Add(THEM->Curves, &c);
CreateReversedCurve(THEM, c);
c->k = (float *)malloc(4 * List_Nbr(ku) * sizeof(float));
for(int i = 0; i < List_Nbr(ku); i++) {
double d;
List_Read(ku, i, &d);
c->k[i] = (float)d /*((d-kumin)/(kumax-kumin)) */ ;
}
}
List_Delete(Listint);
// 2nd and 4th gen
List_T *List1 = List_Create(List_Nbr(List), 1, sizeof(double));
List_T *List2 = List_Create(List_Nbr(List), 1, sizeof(double));
for(int i = 0; i < List_Nbr(List); i++) {
List_Read(List, i, &ListOfDouble_L);
List_Add(List1, List_Pointer(ListOfDouble_L, 0));
List_Add(List2, List_Pointer(ListOfDouble_L, List_Nbr(ListOfDouble_L) - 1));
}
Listint = ListOfDouble2ListOfInt(List1);
if(recognize_seg(MSH_SEGM_NURBS, Listint, &Loop[1])) {
}
else {
Loop[1] = NEWREG();
Curve *c = Create_Curve(Loop[1], MSH_SEGM_NURBS, Order2, Listint, NULL,
-1, -1, kumin, kumax);
Tree_Add(THEM->Curves, &c);
CreateReversedCurve(THEM, c);
c->k = (float *)malloc(4 * List_Nbr(kv) * sizeof(float));
for(int i = 0; i < List_Nbr(kv); i++) {
double d;
List_Read(kv, i, &d);
c->k[i] = (float)d /*((d-kvmin)/(kvmax-kvmin)) */ ;
}
}
List_Delete(Listint);
Listint = ListOfDouble2ListOfInt(List2);
if(recognize_seg(MSH_SEGM_NURBS, Listint, &Loop[3])) {
}
else {
Loop[3] = NEWREG();
Curve *c = Create_Curve(Loop[3], MSH_SEGM_NURBS, Order2, Listint, NULL,
-1, -1, kumin, kumax);
Tree_Add(THEM->Curves, &c);
CreateReversedCurve(THEM, c);
c->k = (float *)malloc(4 * List_Nbr(kv) * sizeof(float));
for(int i = 0; i < List_Nbr(kv); i++) {
double d;
List_Read(kv, i, &d);
c->k[i] = (float)d /*((d-kvmin)/(kvmax-kvmin)) */ ;
}
}
List_Delete(Listint);
List_Delete(List1);
List_Delete(List2);
Listint = List_Create(10, 10, sizeof(int));
int l0 = -Loop[0];
List_Add(Listint, &l0);
List_Add(Listint, &Loop[1]);
List_Add(Listint, &Loop[2]);
int l3 = -Loop[3];
List_Add(Listint, &l3);
int topnew = NEWREG();
CreateNurbsSurfaceSupport(topnew, Order1, Order2, List, ku, kv);
int il = NEWREG();
SurfaceLoop *l = Create_SurfaceLoop(il, Listint);
Tree_Add(THEM->SurfaceLoops, &l);
List_Reset(Listint);
List_Add(Listint, &il);
Surface *s = Create_Surface(NEWREG(), MSH_SURF_TRIMMED);
setSurfaceGeneratrices(s, Listint);
s->Support = s;
End_Surface(s);
Tree_Add(THEM->Surfaces, &s);
List_Delete(Listint);
List_Delete(ListCP);
}