Forked from
gmsh / gmsh
12672 commits behind the upstream repository.
-
Christophe Geuzaine authoredChristophe Geuzaine authored
Geo.cpp 100.34 KiB
// Gmsh - Copyright (C) 1997-2012 C. Geuzaine, J.-F. Remacle
//
// See the LICENSE.txt file for license information. Please report all
// bugs and problems to <gmsh@geuz.org>.
#include <stdlib.h>
#include <string.h>
#include "GmshMessage.h"
#include "Numeric.h"
#include "Geo.h"
#include "GModel.h"
#include "GeoInterpolation.h"
#include "Context.h"
#if defined(HAVE_MESH)
#include "Field.h"
#endif
static List_T *ListOfTransformedPoints = NULL;
// Comparison routines
int compareVertex(const void *a, const void *b)
{
Vertex *q = *(Vertex **)a;
Vertex *w = *(Vertex **)b;
return abs(q->Num) - abs(w->Num);
}
static int comparePosition(const void *a, const void *b)
{
Vertex *q = *(Vertex **)a;
Vertex *w = *(Vertex **)b;
// Warning: tolerance! (before 1.61, it was set to 1.e-10 * CTX::instance()->lc)
double eps = CTX::instance()->geom.tolerance * CTX::instance()->lc;
if(q->Pos.X - w->Pos.X > eps) return 1;
if(q->Pos.X - w->Pos.X < -eps) return -1;
if(q->Pos.Y - w->Pos.Y > eps) return 1;
if(q->Pos.Y - w->Pos.Y < -eps) return -1;
if(q->Pos.Z - w->Pos.Z > eps) return 1;
if(q->Pos.Z - w->Pos.Z < -eps) return -1;
return 0;
}
static int compareSurfaceLoop(const void *a, const void *b)
{
SurfaceLoop *q = *(SurfaceLoop **)a;
SurfaceLoop *w = *(SurfaceLoop **)b;
return q->Num - w->Num;
}
static int compareEdgeLoop(const void *a, const void *b)
{
EdgeLoop *q = *(EdgeLoop **)a;
EdgeLoop *w = *(EdgeLoop **)b;
return q->Num - w->Num;
}
static int compareCurve(const void *a, const void *b)
{
Curve *q = *(Curve **)a;
Curve *w = *(Curve **)b;
return q->Num - w->Num;
}
static int compareSurface(const void *a, const void *b)
{
Surface *q = *(Surface **)a;
Surface *w = *(Surface **)b;
return q->Num - w->Num;
}
static int compareVolume(const void *a, const void *b)
{
Volume *q = *(Volume **)a;
Volume *w = *(Volume **)b;
return q->Num - w->Num;
}
static int compareLevelSet(const void *a, const void *b)
{
LevelSet *q = *(LevelSet **)a;
LevelSet *w = *(LevelSet **)b;
return q->Num - w->Num;
}
static int comparePhysicalGroup(const void *a, const void *b)
{
PhysicalGroup *q = *(PhysicalGroup **)a;
PhysicalGroup *w = *(PhysicalGroup **)b;
int cmp = q->Typ - w->Typ;
if(cmp)
return cmp;
else
return q->Num - w->Num;
}
void Projette(Vertex *v, double mat[3][3])
{
double X = v->Pos.X * mat[0][0] + v->Pos.Y * mat[0][1] + v->Pos.Z * mat[0][2];
double Y = v->Pos.X * mat[1][0] + v->Pos.Y * mat[1][1] + v->Pos.Z * mat[1][2];
double Z = v->Pos.X * mat[2][0] + v->Pos.Y * mat[2][1] + v->Pos.Z * mat[2][2];
v->Pos.X = X;
v->Pos.Y = Y;
v->Pos.Z = Z;
}
// Basic entity creation/deletion functions
Vertex *Create_Vertex(int Num, double X, double Y, double Z, double lc, double u)
{
Vertex *pV = new Vertex(X, Y, Z, lc);
pV->w = 1.0;
pV->Num = Num;
GModel::current()->getGEOInternals()->MaxPointNum =
std::max(GModel::current()->getGEOInternals()->MaxPointNum, Num);
pV->u = u;
pV->geometry = 0;
return pV;
}
Vertex *Create_Vertex(int Num, double u, double v, gmshSurface *surf, double lc)
{
SPoint3 p = surf->point(u, v);
Vertex *pV = new Vertex(p.x(), p.y(), p.z(), lc);
pV->w = 1.0;
pV->Num = Num;
GModel::current()->getGEOInternals()->MaxPointNum =
std::max(GModel::current()->getGEOInternals()->MaxPointNum, Num);
pV->u = u;
pV->geometry = surf;
pV->pntOnGeometry = SPoint2(u, v);
surf->vertex_defined_on_surface = true;
return pV;
}
static void Free_Vertex(void *a, void *b)
{
Vertex *v = *(Vertex **)a;
if(v) {
delete v;
v = NULL;
}
}
PhysicalGroup *Create_PhysicalGroup(int Num, int typ, List_T *intlist)
{
PhysicalGroup *p = new PhysicalGroup;
p->Entities = List_Create(List_Nbr(intlist), 1, sizeof(int));
p->Num = Num;
GModel::current()->getGEOInternals()->MaxPhysicalNum =
std::max(GModel::current()->getGEOInternals()->MaxPhysicalNum, Num);
p->Typ = typ;
p->Visible = 1;
for(int i = 0; i < List_Nbr(intlist); i++) {
int j;
List_Read(intlist, i, &j);
List_Add(p->Entities, &j);
}
return p;
}
static void Free_PhysicalGroup(void *a, void *b)
{
PhysicalGroup *p = *(PhysicalGroup **)a;
if(p) {
List_Delete(p->Entities);
delete p;
p = NULL;
}
}
EdgeLoop *Create_EdgeLoop(int Num, List_T *intlist)
{
EdgeLoop *l = new EdgeLoop;
l->Curves = List_Create(List_Nbr(intlist), 1, sizeof(int));
l->Num = Num;
GModel::current()->getGEOInternals()->MaxLineLoopNum =
std::max(GModel::current()->getGEOInternals()->MaxLineLoopNum, Num);
for(int i = 0; i < List_Nbr(intlist); i++) {
int j;
List_Read(intlist, i, &j);
List_Add(l->Curves, &j);
}
return l;
}
static void Free_EdgeLoop(void *a, void *b)
{
EdgeLoop *l = *(EdgeLoop **)a;
if(l) {
List_Delete(l->Curves);
delete l;
l = NULL;
}
}
SurfaceLoop *Create_SurfaceLoop(int Num, List_T *intlist)
{
SurfaceLoop *l = new SurfaceLoop;
l->Surfaces = List_Create(List_Nbr(intlist), 1, sizeof(int));
l->Num = Num;
GModel::current()->getGEOInternals()->MaxSurfaceLoopNum =
std::max(GModel::current()->getGEOInternals()->MaxSurfaceLoopNum, Num);
for(int i = 0; i < List_Nbr(intlist); i++) {
int j;
List_Read(intlist, i, &j);
List_Add(l->Surfaces, &j);
}
return l;
}
static void Free_SurfaceLoop(void *a, void *b)
{
SurfaceLoop *l = *(SurfaceLoop **)a;
if(l) {
List_Delete(l->Surfaces);
delete l;
l = NULL;
}
}
static void direction(Vertex *v1, Vertex *v2, double d[3])
{
d[0] = v2->Pos.X - v1->Pos.X;
d[1] = v2->Pos.Y - v1->Pos.Y;
d[2] = v2->Pos.Z - v1->Pos.Z;
}
void End_Curve(Curve *c)
{
// if all control points of a curve are on the same geometry, then
// the curve is also on the geometry
if(c->Control_Points){
int NN = List_Nbr(c->Control_Points);
Vertex *pV;
List_Read (c->Control_Points, 0, &pV);
c->geometry = pV->geometry;
for(int i = 1; i < NN; i++){
List_Read (c->Control_Points, i, &pV);
if(c->geometry != pV->geometry){
c->geometry = 0;
break;
}
}
}
c->degenerated = false;
if(c->Typ == MSH_SEGM_CIRC || c->Typ == MSH_SEGM_CIRC_INV ||
c->Typ == MSH_SEGM_ELLI || c->Typ == MSH_SEGM_ELLI_INV) {
// v[0] = first point
// v[1] = center
// v[2] = last point
// v[3] = major axis point
Vertex *v[4];
if(List_Nbr(c->Control_Points) == 4)
List_Read(c->Control_Points, 2, &v[3]);
else
v[3] = NULL;
if(c->Typ == MSH_SEGM_CIRC_INV || c->Typ == MSH_SEGM_ELLI_INV) {
List_Read(c->Control_Points, 0, &v[2]);
List_Read(c->Control_Points, 1, &v[1]);
if(!v[3])
List_Read(c->Control_Points, 2, &v[0]);
else
List_Read(c->Control_Points, 3, &v[0]);
}
else {
List_Read(c->Control_Points, 0, &v[0]);
List_Read(c->Control_Points, 1, &v[1]);
if(!v[3])
List_Read(c->Control_Points, 2, &v[2]);
else
List_Read(c->Control_Points, 3, &v[2]);
}
double dir12[3], dir32[3], dir42[3] = {0., 0. , 0.};
direction(v[1], v[0], dir12);
direction(v[1], v[2], dir32);
if(v[3])
direction(v[1], v[3], dir42);
// v0 = vector center->first pt
// v2 = vector center->last pt
// v3 = vector center->major axis pt
Vertex v0, v2, v3;
v0.Pos.X = dir12[0];
v0.Pos.Y = dir12[1];
v0.Pos.Z = dir12[2];
v2.Pos.X = dir32[0];
v2.Pos.Y = dir32[1];
v2.Pos.Z = dir32[2];
if(v[3]) {
v3.Pos.X = dir42[0];
v3.Pos.Y = dir42[1];
v3.Pos.Z = dir42[2];
}
norme(dir12);
norme(dir32);
double n[3];
prodve(dir12, dir32, n);
norme(n);
// use provided plane if unable to compute it from input points...
if(fabs(n[0]) < 1.e-5 && fabs(n[1]) < 1.e-5 && fabs(n[2]) < 1.e-5) {
n[0] = c->Circle.n[0];
n[1] = c->Circle.n[1];
n[2] = c->Circle.n[2];
norme(n);
}
double m[3];
prodve(n, dir12, m);
norme(m);
double mat[3][3];
mat[2][0] = c->Circle.invmat[0][2] = n[0];
mat[2][1] = c->Circle.invmat[1][2] = n[1];
mat[2][2] = c->Circle.invmat[2][2] = n[2];
mat[1][0] = c->Circle.invmat[0][1] = m[0];
mat[1][1] = c->Circle.invmat[1][1] = m[1];
mat[1][2] = c->Circle.invmat[2][1] = m[2];
mat[0][0] = c->Circle.invmat[0][0] = dir12[0];
mat[0][1] = c->Circle.invmat[1][0] = dir12[1];
mat[0][2] = c->Circle.invmat[2][0] = dir12[2];
// assume circle in z=0 plane
if(CTX::instance()->geom.oldCircle) {
if(n[0] == 0.0 && n[1] == 0.0) {
mat[2][0] = c->Circle.invmat[0][2] = 0;
mat[2][1] = c->Circle.invmat[1][2] = 0;
mat[2][2] = c->Circle.invmat[2][2] = 1;
mat[1][0] = c->Circle.invmat[0][1] = 0;
mat[1][1] = c->Circle.invmat[1][1] = 1;
mat[1][2] = c->Circle.invmat[2][1] = 0;
mat[0][0] = c->Circle.invmat[0][0] = 1;
mat[0][1] = c->Circle.invmat[1][0] = 0;
mat[0][2] = c->Circle.invmat[2][0] = 0;
}
}
Projette(&v0, mat);
Projette(&v2, mat);
if(v[3])
Projette(&v3, mat);
double R = sqrt(v0.Pos.X * v0.Pos.X + v0.Pos.Y * v0.Pos.Y);
double R2 = sqrt(v2.Pos.X * v2.Pos.X + v2.Pos.Y * v2.Pos.Y);
if(!R || !R2){
// check radius
Msg::Error("Zero radius in Circle/Ellipse %d", c->Num);
}
else if(!v[3] && fabs((R - R2) / (R + R2)) > 0.1){
// check cocircular pts (allow 10% error)
Msg::Error("Control points of Circle %d are not cocircular %g %g",
c->Num, R, R2);
}
// A1 = angle first pt
// A3 = angle last pt
// A4 = angle major axis
double A3, A1, A4;
double f1, f2;
if(v[3]) {
A4 = myatan2(v3.Pos.Y, v3.Pos.X);
A4 = angle_02pi(A4);
double x1 = v0.Pos.X * cos(A4) + v0.Pos.Y * sin(A4);
double y1 = -v0.Pos.X * sin(A4) + v0.Pos.Y * cos(A4);
double x3 = v2.Pos.X * cos(A4) + v2.Pos.Y * sin(A4);
double y3 = -v2.Pos.X * sin(A4) + v2.Pos.Y * cos(A4);
double sys[2][2], rhs[2], sol[2];
sys[0][0] = x1 * x1;
sys[0][1] = y1 * y1;
sys[1][0] = x3 * x3;
sys[1][1] = y3 * y3;
rhs[0] = 1;
rhs[1] = 1;
sys2x2(sys, rhs, sol);
if(sol[0] <= 0 || sol[1] <= 0) {
Msg::Error("Ellipse %d is wrong", c->Num);
A1 = A3 = 0.;
f1 = f2 = R;
}
else {
f1 = sqrt(1. / sol[0]);
f2 = sqrt(1. / sol[1]);
// myasin() permet de contourner les problemes de precision
// sur y1/f2 ou y3/f2, qui peuvent legerement etre hors de
// [-1,1]
if(x1 < 0)
A1 = -myasin(y1 / f2) + A4 + M_PI;
else
A1 = myasin(y1 / f2) + A4;
if(x3 < 0)
A3 = -myasin(y3 / f2) + A4 + M_PI;
else
A3 = myasin(y3 / f2) + A4;
}
}
else {
A1 = myatan2(v0.Pos.Y, v0.Pos.X);
A3 = myatan2(v2.Pos.Y, v2.Pos.X);
A4 = 0.;
f1 = f2 = R;
}
A1 = angle_02pi(A1);
A3 = angle_02pi(A3);
if(A1 >= A3)
A3 += 2 * M_PI;
c->Circle.t1 = A1;
c->Circle.t2 = A3;
c->Circle.incl = A4;
c->Circle.f1 = f1;
c->Circle.f2 = f2;
if(!CTX::instance()->expertMode && c->Num > 0 && A3 - A1 > 1.01 * M_PI){
Msg::Error("Circle or ellipse arc %d greater than Pi (angle=%g)", c->Num, A3-A1);
Msg::Error("(If you understand what this implies, you can disable this error");
Msg::Error("message by selecting `Enable expert mode' in the option dialog.");
Msg::Error("Otherwise, please subdivide the arc in smaller pieces.)");
}
}
}
void End_Surface(Surface *s)
{
// if all generatrices of a surface are on the same geometry, then
// the surface is also on the geometry
if(List_Nbr(s->Generatrices)){
Curve *c;
int NN = List_Nbr(s->Generatrices);
List_Read (s->Generatrices, 0, &c);
s->geometry = c->geometry;
for (int i = 1; i < NN; i++){
List_Read (s->Generatrices, i, &c);
if (c->geometry != s->geometry){
s->geometry = 0;
break;
}
}
}
}
Curve *Create_Curve(int Num, int Typ, int Order, List_T *Liste,
List_T *Knots, int p1, int p2, double u1, double u2)
{
double matcr[4][4] = { {-0.5, 1.5, -1.5, 0.5},
{1.0, -2.5, 2.0, -0.5},
{-0.5, 0.0, 0.5, 0.0},
{0.0, 1.0, 0.0, 0.0} };
double matbs[4][4] = { {-1.0, 3, -3, 1},
{3, -6, 3.0, 0},
{-3, 0.0, 3, 0.0},
{1, 4, 1, 0.0} };
double matbez[4][4] = { {-1.0, 3, -3, 1},
{3, -6, 3.0, 0},
{-3, 3.0, 0, 0.0},
{1, 0, 0, 0.0} };
Curve *pC = new Curve;
pC->Color.type = 0;
pC->Visible = 1;
pC->Extrude = NULL;
pC->Typ = Typ;
pC->Num = Num;
pC->meshMaster = Num;
GModel::current()->getGEOInternals()->MaxLineNum =
std::max(GModel::current()->getGEOInternals()->MaxLineNum, Num);
pC->Method = MESH_UNSTRUCTURED;
pC->degre = Order;
pC->Circle.n[0] = 0.0;
pC->Circle.n[1] = 0.0;
pC->Circle.n[2] = 1.0;
pC->geometry = 0;
pC->nbPointsTransfinite = 0;
pC->typeTransfinite = 0;
pC->coeffTransfinite = 0.;
if(Typ == MSH_SEGM_SPLN) {
for(int i = 0; i < 4; i++)
for(int j = 0; j < 4; j++)
pC->mat[i][j] = matcr[i][j];
}
else if(Typ == MSH_SEGM_BSPLN) {
for(int i = 0; i < 4; i++)
for(int j = 0; j < 4; j++)
pC->mat[i][j] = matbs[i][j] / 6.0;
}
else if(Typ == MSH_SEGM_BEZIER) {
for(int i = 0; i < 4; i++)
for(int j = 0; j < 4; j++)
pC->mat[i][j] = matbez[i][j];
}
pC->ubeg = u1;
pC->uend = u2;
if(Knots) {
pC->k = new float[List_Nbr(Knots)];
double kmin = .0, kmax = 1.;
List_Read(Knots, 0, &kmin);
List_Read(Knots, List_Nbr(Knots) - 1, &kmax);
pC->ubeg = kmin;
pC->uend = kmax;
for(int i = 0; i < List_Nbr(Knots); i++) {
double d;
List_Read(Knots, i, &d);
pC->k[i] = (float)d;
}
}
else
pC->k = NULL;
if(Liste) {
pC->Control_Points = List_Create(List_Nbr(Liste), 1, sizeof(Vertex *));
for(int j = 0; j < List_Nbr(Liste); j++) {
int iPnt;
List_Read(Liste, j, &iPnt);
Vertex *v;
if((v = FindPoint(iPnt)))
List_Add(pC->Control_Points, &v);
else{
Msg::Error("Unknown control point %d in Curve %d", iPnt, pC->Num);
}
}
}
else {
pC->Control_Points = NULL;
pC->beg = NULL;
pC->end = NULL;
return pC;
}
if(p1 < 0) {
List_Read(pC->Control_Points, 0, &pC->beg);
List_Read(pC->Control_Points, List_Nbr(pC->Control_Points) - 1, &pC->end);
}
else {
Vertex *v;
if((v = FindPoint(p1))) {
Msg::Info("Curve %d first control point %d ", pC->Num, v->Num);
pC->beg = v;
}
else {
Msg::Error("Unknown control point %d in Curve %d", p1, pC->Num);
}
if((v = FindPoint(p2))) {
Msg::Info("Curve %d first control point %d ", pC->Num, v->Num);
pC->end = v;
}
else {
Msg::Error("Unknown control point %d in Curve %d", p2, pC->Num);
}
}
End_Curve(pC);
return pC;
}
static void Free_Curve(void *a, void *b)
{
Curve *pC = *(Curve **)a;
if(pC) {
delete [] pC->k;
List_Delete(pC->Control_Points);
delete pC;
pC = NULL;
}
}
Surface *Create_Surface(int Num, int Typ)
{
Surface *pS = new Surface;
pS->Color.type = 0;
pS->Visible = 1;
pS->Num = Num;
pS->geometry = 0;
pS->InSphereCenter = 0;
pS->meshMaster = Num;
GModel::current()->getGEOInternals()->MaxSurfaceNum =
std::max(GModel::current()->getGEOInternals()->MaxSurfaceNum, Num);
pS->Typ = Typ;
pS->Method = MESH_UNSTRUCTURED;
pS->Recombine = 0;
pS->RecombineAngle = 45;
pS->Recombine_Dir = -1;
pS->TransfiniteSmoothing = -1;
pS->TrsfPoints = List_Create(4, 4, sizeof(Vertex *));
pS->Generatrices = NULL;
pS->EmbeddedPoints = NULL;
pS->EmbeddedCurves = NULL;
pS->Extrude = NULL;
pS->geometry = NULL;
return (pS);
}
static void Free_Surface(void *a, void *b)
{
Surface *pS = *(Surface **)a;
if(pS) {
List_Delete(pS->TrsfPoints);
List_Delete(pS->Generatrices);
List_Delete(pS->EmbeddedCurves);
List_Delete(pS->EmbeddedPoints);
delete pS;
pS = NULL;
}
}
Volume *Create_Volume(int Num, int Typ)
{
Volume *pV = new Volume;
pV->Color.type = 0;
pV->Visible = 1;
pV->Num = Num;
GModel::current()->getGEOInternals()->MaxVolumeNum =
std::max(GModel::current()->getGEOInternals()->MaxVolumeNum, Num);
pV->Typ = Typ;
pV->Method = MESH_UNSTRUCTURED;
pV->QuadTri = NO_QUADTRI;
pV->TrsfPoints = List_Create(6, 6, sizeof(Vertex *));
pV->Surfaces = List_Create(1, 2, sizeof(Surface *));
pV->SurfacesOrientations = List_Create(1, 2, sizeof(int));
pV->SurfacesByTag = List_Create(1, 2, sizeof(int));
pV->Extrude = NULL;
return pV;
}
static void Free_Volume(void *a, void *b)
{
Volume *pV = *(Volume **)a;
if(pV) {
List_Delete(pV->TrsfPoints);
List_Delete(pV->Surfaces);
List_Delete(pV->SurfacesOrientations);
List_Delete(pV->SurfacesByTag);
delete pV;
pV = NULL;
}
}
LevelSet *Create_LevelSet(int Num, gLevelset *l)
{
LevelSet *pL = new LevelSet;
pL->Num = Num;
pL->ls = l;
return pL;
}
static void Free_LevelSet(void *a, void *b)
{
LevelSet *pL = *(LevelSet **)a;
if(pL) {
delete pL;
pL = NULL;
}
}
int NEWPOINT(void)
{
return (GModel::current()->getGEOInternals()->MaxPointNum + 1);
}
int NEWLINE(void)
{
if(CTX::instance()->geom.oldNewreg)
return NEWREG();
else
return (GModel::current()->getGEOInternals()->MaxLineNum + 1);
}
int NEWLINELOOP(void)
{
if(CTX::instance()->geom.oldNewreg)
return NEWREG();
else
return (GModel::current()->getGEOInternals()->MaxLineLoopNum + 1);
}
int NEWSURFACE(void)
{
if(CTX::instance()->geom.oldNewreg)
return NEWREG();
else
return (GModel::current()->getGEOInternals()->MaxSurfaceNum + 1);
}
int NEWSURFACELOOP(void)
{
if(CTX::instance()->geom.oldNewreg)
return NEWREG();
else
return (GModel::current()->getGEOInternals()->MaxSurfaceLoopNum + 1);
}
int NEWVOLUME(void)
{
if(CTX::instance()->geom.oldNewreg)
return NEWREG();
else
return (GModel::current()->getGEOInternals()->MaxVolumeNum + 1);
}
int NEWFIELD(void)
{
#if defined(HAVE_MESH)
return (GModel::current()->getFields()->maxId() + 1);
#else
return 0;
#endif
}
int NEWPHYSICAL(void)
{
if(CTX::instance()->geom.oldNewreg)
return NEWREG();
else
return (GModel::current()->getGEOInternals()->MaxPhysicalNum + 1);
}
int NEWREG(void)
{
return (std::max(GModel::current()->getGEOInternals()->MaxLineNum,
std::max(GModel::current()->getGEOInternals()->MaxLineLoopNum,
std::max(GModel::current()->getGEOInternals()->MaxSurfaceNum,
std::max(GModel::current()->getGEOInternals()->MaxSurfaceLoopNum,
std::max(GModel::current()->getGEOInternals()->MaxVolumeNum,
GModel::current()->getGEOInternals()->MaxPhysicalNum)))))
+ 1);
}
static int compare2Lists(List_T *List1, List_T *List2,
int (*fcmp) (const void *a, const void *b))
{
int i, found;
if(!List_Nbr(List1) && !List_Nbr(List2))
return 0;
if(!List_Nbr(List1) || !List_Nbr(List2) ||
(List_Nbr(List1) != List_Nbr(List2)))
return List_Nbr(List1) - List_Nbr(List2);
List_T *List1Prime = List_Create(List_Nbr(List1), 1, List1->size);
List_T *List2Prime = List_Create(List_Nbr(List2), 1, List2->size);
List_Copy(List1, List1Prime);
List_Copy(List2, List2Prime);
List_Sort(List1Prime, fcmp);
List_Sort(List2Prime, fcmp);
for(i = 0; i < List_Nbr(List1Prime); i++) {
found = fcmp(List_Pointer(List1Prime, i), List_Pointer(List2Prime, i));
if(found != 0) {
List_Delete(List1Prime);
List_Delete(List2Prime);
return found;
}
}
List_Delete(List1Prime);
List_Delete(List2Prime);
return 0;
}
static Vertex *FindPoint(int inum, Tree_T *t)
{
Vertex C, *pc;
pc = &C;
pc->Num = inum;
if(Tree_Query(t, &pc)) {
return pc;
}
return NULL;
}
Vertex *FindPoint(int inum)
{
return FindPoint(inum, GModel::current()->getGEOInternals()->Points);
}
static Curve *FindCurve(int inum, Tree_T *t)
{
Curve C, *pc;
pc = &C;
pc->Num = inum;
if(Tree_Query(t, &pc)) {
return pc;
}
return NULL;
}
Curve *FindCurve(int inum)
{
return FindCurve(inum, GModel::current()->getGEOInternals()->Curves);
}
static Surface *FindSurface(int inum, Tree_T *t)
{
Surface S, *ps;
ps = &S;
ps->Num = inum;
if(Tree_Query(t, &ps)) {
return ps;
}
return NULL;
}
Surface *FindSurface(int inum)
{
return FindSurface(inum, GModel::current()->getGEOInternals()->Surfaces);
}
Volume *FindVolume(int inum)
{
Volume V, *pv;
pv = &V;
pv->Num = inum;
if(Tree_Query(GModel::current()->getGEOInternals()->Volumes, &pv)) {
return pv;
}
return NULL;
}
LevelSet *FindLevelSet(int inum)
{
LevelSet L, *pl;
pl = &L;
pl->Num = inum;
if(Tree_Query(GModel::current()->getGEOInternals()->LevelSets, &pl)) {
return pl;
}
return NULL;
}
EdgeLoop *FindEdgeLoop(int inum)
{
EdgeLoop S, *ps;
ps = &S;
ps->Num = inum;
if(Tree_Query(GModel::current()->getGEOInternals()->EdgeLoops, &ps)) {
return ps;
}
return NULL;
}
SurfaceLoop *FindSurfaceLoop(int inum)
{
SurfaceLoop S, *ps;
ps = &S;
ps->Num = inum;
if(Tree_Query(GModel::current()->getGEOInternals()->SurfaceLoops, &ps)) {
return ps;
}
return NULL;
}
PhysicalGroup *FindPhysicalGroup(int num, int type)
{
PhysicalGroup P, *pp, **ppp;
pp = &P;
pp->Num = num;
pp->Typ = type;
if((ppp = (PhysicalGroup **)
List_PQuery(GModel::current()->getGEOInternals()->PhysicalGroups, &pp,
comparePhysicalGroup))) {
return *ppp;
}
return NULL;
}
static void GetAllEntityNumbers(int dim, std::set<int> &nums)
{
GModel *m = GModel::current();
switch(dim){
case 0:
{
List_T *l = Tree2List(m->getGEOInternals()->Points);
Vertex *p;
for(int i = 0; i < List_Nbr(l); i++){
List_Read(l, i, &p);
nums.insert(p->Num);
}
List_Delete(l);
for(GModel::viter it = m->firstVertex(); it != m->lastVertex(); it++)
nums.insert((*it)->tag());
}
break;
case 1:
{
List_T *l = Tree2List(m->getGEOInternals()->Curves);
Curve *p;
for(int i = 0; i < List_Nbr(l); i++){
List_Read(l, i, &p);
if(p->Num >= 0)
nums.insert(p->Num);
}
List_Delete(l);
for(GModel::eiter it = m->firstEdge(); it != m->lastEdge(); it++){
if((*it)->tag() >= 0)
nums.insert((*it)->tag());
}
}
break;
case 2:
{
List_T *l = Tree2List(m->getGEOInternals()->Surfaces);
Surface *p;
for(int i = 0; i < List_Nbr(l); i++){
List_Read(l, i, &p);
nums.insert(p->Num);
}
List_Delete(l);
for(GModel::fiter it = m->firstFace(); it != m->lastFace(); it++)
nums.insert((*it)->tag());
}
break;
case 3:
{
List_T *l = Tree2List(m->getGEOInternals()->Volumes);
Volume *p;
for(int i = 0; i < List_Nbr(l); i++){
List_Read(l, i, &p);
nums.insert(p->Num);
}
List_Delete(l);
for(GModel::riter it = m->firstRegion(); it != m->lastRegion(); it++)
nums.insert((*it)->tag());
}
break;
}
}
List_T *GetAllEntityNumbers(int dim)
{
std::set<int> nums;
GetAllEntityNumbers(dim, nums);
List_T *l = List_Create(nums.size(), 1, sizeof(double));
for(std::set<int>::iterator it = nums.begin(); it != nums.end(); it++){
double a = *it;
List_Add(l, &a);
}
return l;
}
static void CopyVertex(Vertex *v, Vertex *vv)
{
vv->lc = v->lc;
vv->u = v->u;
vv->Pos.X = v->Pos.X;
vv->Pos.Y = v->Pos.Y;
vv->Pos.Z = v->Pos.Z;
}
static Vertex *DuplicateVertex(Vertex *v)
{
if(!v) return NULL;
Vertex *pv = Create_Vertex(NEWPOINT(), 0, 0, 0, 0, 0);
CopyVertex(v, pv);
Tree_Insert(GModel::current()->getGEOInternals()->Points, &pv);
return pv;
}
static int compareAbsCurve(const void *a, const void *b)
{
Curve *q = *(Curve **)a;
Curve *w = *(Curve **)b;
return abs(q->Num) - abs(w->Num);
}
static void CopyCurve(Curve *c, Curve *cc, bool copyMeshingMethod)
{
cc->Typ = c->Typ;
if(copyMeshingMethod){
cc->Method = c->Method;
cc->nbPointsTransfinite = c->nbPointsTransfinite;
cc->typeTransfinite = c->typeTransfinite;
cc->coeffTransfinite = c->coeffTransfinite;
}
cc->l = c->l;
for(int i = 0; i < 4; i++)
for(int j = 0; j < 4; j++)
cc->mat[i][j] = c->mat[i][j];
cc->beg = c->beg;
cc->end = c->end;
cc->ubeg = c->ubeg;
cc->uend = c->uend;
cc->Control_Points = List_Create(List_Nbr(c->Control_Points), 1, sizeof(Vertex *));
List_Copy(c->Control_Points, cc->Control_Points);
End_Curve(cc);
}
static Curve *DuplicateCurve(Curve *c, bool copyMeshingMethod)
{
Curve *pc = Create_Curve(NEWLINE(), 0, 1, NULL, NULL, -1, -1, 0., 1.);
CopyCurve(c, pc, copyMeshingMethod);
Tree_Insert(GModel::current()->getGEOInternals()->Curves, &pc);
for(int i = 0; i < List_Nbr(c->Control_Points); i++) {
Vertex *v;
List_Read(pc->Control_Points, i, &v);
Vertex *newv = DuplicateVertex(v);
List_Write(pc->Control_Points, i, &newv);
}
pc->beg = DuplicateVertex(c->beg);
pc->end = DuplicateVertex(c->end);
CreateReversedCurve(pc);
return pc;
}
static void CopySurface(Surface *s, Surface *ss, bool copyMeshingMethod)
{
ss->Typ = s->Typ;
if(copyMeshingMethod){
ss->Method = s->Method;
ss->Recombine = s->Recombine;
ss->RecombineAngle = s->RecombineAngle;
if(List_Nbr(s->TrsfPoints))
Msg::Warning("Only automatic transfinite surface specifications can be copied");
}
ss->Generatrices = List_Create(List_Nbr(s->Generatrices), 1, sizeof(Curve *));
ss->InSphereCenter = s->InSphereCenter; // FIXME: hack...
List_Copy(s->Generatrices, ss->Generatrices);
End_Surface(ss);
}
static Surface *DuplicateSurface(Surface *s, bool copyMeshingMethod)
{
Surface *ps = Create_Surface(NEWSURFACE(), 0);
CopySurface(s, ps, copyMeshingMethod);
Tree_Insert(GModel::current()->getGEOInternals()->Surfaces, &ps);
for(int i = 0; i < List_Nbr(ps->Generatrices); i++) {
Curve *c;
List_Read(ps->Generatrices, i, &c);
Curve *newc = DuplicateCurve(c, copyMeshingMethod);
List_Write(ps->Generatrices, i, &newc);
}
return ps;
}
static void CopyVolume(Volume *v, Volume *vv, bool copyMeshingMethod)
{
vv->Typ = v->Typ;
if(copyMeshingMethod){
vv->Method = v->Method;
vv->QuadTri = v->QuadTri;
if(List_Nbr(v->TrsfPoints))
Msg::Warning("Only automatic transfinite volume specifications can be copied");
}
List_Copy(v->Surfaces, vv->Surfaces);
List_Copy(v->SurfacesOrientations, vv->SurfacesOrientations);
List_Copy(v->SurfacesByTag, vv->SurfacesByTag);
}
static Volume *DuplicateVolume(Volume *v, bool copyMeshingMethod)
{
Volume *pv = Create_Volume(NEWVOLUME(), 0);
CopyVolume(v, pv, copyMeshingMethod);
Tree_Insert(GModel::current()->getGEOInternals()->Volumes, &pv);
for(int i = 0; i < List_Nbr(pv->Surfaces); i++) {
Surface *s;
List_Read(pv->Surfaces, i, &s);
Surface *news = DuplicateSurface(s, copyMeshingMethod);
List_Write(pv->Surfaces, i, &news);
}
return pv;
}
void CopyShape(int Type, int Num, int *New)
{
Surface *s, *news;
Curve *c, *newc;
Vertex *v, *newv;
Volume *vol, *newvol;
switch (Type) {
case MSH_POINT:
if(!(v = FindPoint(Num))) {
Msg::Error("Unknown vertex %d", Num);
return;
}
newv = DuplicateVertex(v);
*New = newv->Num;
break;
case MSH_SEGM_LINE:
case MSH_SEGM_SPLN:
case MSH_SEGM_BSPLN:
case MSH_SEGM_BEZIER:
case MSH_SEGM_CIRC:
case MSH_SEGM_CIRC_INV:
case MSH_SEGM_ELLI:
case MSH_SEGM_ELLI_INV:
case MSH_SEGM_NURBS:
if(!(c = FindCurve(Num))) {
Msg::Error("Unknown curve %d", Num);
return;
}
newc = DuplicateCurve(c, CTX::instance()->geom.copyMeshingMethod);
*New = newc->Num;
break;
case MSH_SURF_TRIC:
case MSH_SURF_REGL:
case MSH_SURF_PLAN:
if(!(s = FindSurface(Num))) {
Msg::Error("Unknown surface %d", Num);
return;
}
news = DuplicateSurface(s, CTX::instance()->geom.copyMeshingMethod);
*New = news->Num;
break;
case MSH_VOLUME:
if(!(vol = FindVolume(Num))) {
Msg::Error("Unknown volume %d", Num);
return;
}
newvol = DuplicateVolume(vol, CTX::instance()->geom.copyMeshingMethod);
*New = newvol->Num;
break;
default:
Msg::Error("Impossible to copy entity %d (of type %d)", Num, Type);
break;
}
}
static void DeletePoint(int ip)
{
Vertex *v = FindPoint(ip);
if(!v)
return;
List_T *Curves = Tree2List(GModel::current()->getGEOInternals()->Curves);
for(int i = 0; i < List_Nbr(Curves); i++) {
Curve *c;
List_Read(Curves, i, &c);
for(int j = 0; j < List_Nbr(c->Control_Points); j++) {
if(!compareVertex(List_Pointer(c->Control_Points, j), &v)){
List_Delete(Curves);
return;
}
}
}
List_Delete(Curves);
if(v->Num == GModel::current()->getGEOInternals()->MaxPointNum)
GModel::current()->getGEOInternals()->MaxPointNum--;
Tree_Suppress(GModel::current()->getGEOInternals()->Points, &v);
Free_Vertex(&v, NULL);
}
static void DeleteCurve(int ip)
{
Curve *c = FindCurve(ip);
if(!c)
return;
List_T *Surfs = Tree2List(GModel::current()->getGEOInternals()->Surfaces);
for(int i = 0; i < List_Nbr(Surfs); i++) {
Surface *s;
List_Read(Surfs, i, &s);
for(int j = 0; j < List_Nbr(s->Generatrices); j++) {
if(!compareAbsCurve(List_Pointer(s->Generatrices, j), &c)){
List_Delete(Surfs);
return;
}
}
}
List_Delete(Surfs);
if(c->Num == GModel::current()->getGEOInternals()->MaxLineNum)
GModel::current()->getGEOInternals()->MaxLineNum--;
Tree_Suppress(GModel::current()->getGEOInternals()->Curves, &c);
Free_Curve(&c, NULL);
}
static void DeleteSurface(int is)
{
Surface *s = FindSurface(is);
if(!s)
return;
List_T *Vols = Tree2List(GModel::current()->getGEOInternals()->Volumes);
for(int i = 0; i < List_Nbr(Vols); i++) {
Volume *v;
List_Read(Vols, i, &v);
for(int j = 0; j < List_Nbr(v->Surfaces); j++) {
if(!compareSurface(List_Pointer(v->Surfaces, j), &s)){
List_Delete(Vols);
return;
}
}
}
List_Delete(Vols);
if(s->Num == GModel::current()->getGEOInternals()->MaxSurfaceNum)
GModel::current()->getGEOInternals()->MaxSurfaceNum--;
Tree_Suppress(GModel::current()->getGEOInternals()->Surfaces, &s);
Free_Surface(&s, NULL);
}
static void DeleteVolume(int iv)
{
Volume *v = FindVolume(iv);
if(!v)
return;
if(v->Num == GModel::current()->getGEOInternals()->MaxVolumeNum)
GModel::current()->getGEOInternals()->MaxVolumeNum--;
Tree_Suppress(GModel::current()->getGEOInternals()->Volumes, &v);
Free_Volume(&v, NULL);
}
void DeleteShape(int Type, int Num)
{
switch (Type) {
case MSH_POINT:
DeletePoint(Num);
break;
case MSH_SEGM_LINE:
case MSH_SEGM_SPLN:
case MSH_SEGM_BSPLN:
case MSH_SEGM_BEZIER:
case MSH_SEGM_CIRC:
case MSH_SEGM_CIRC_INV:
case MSH_SEGM_ELLI:
case MSH_SEGM_ELLI_INV:
case MSH_SEGM_NURBS:
case MSH_SEGM_COMPOUND:
DeleteCurve(Num);
DeleteCurve(-Num);
break;
case MSH_SURF_TRIC:
case MSH_SURF_REGL:
case MSH_SURF_PLAN:
case MSH_SURF_COMPOUND:
DeleteSurface(Num);
break;
case MSH_VOLUME:
case MSH_VOLUME_COMPOUND:
DeleteVolume(Num);
break;
case MSH_POINT_FROM_GMODEL:
{
GVertex *gv = GModel::current()->getVertexByTag(Num);
if(gv) GModel::current()->remove(gv);
}
break;
case MSH_SEGM_FROM_GMODEL:
{
GEdge *ge = GModel::current()->getEdgeByTag(Num);
if(ge) GModel::current()->remove(ge);
}
break;
case MSH_SURF_FROM_GMODEL:
{
GFace *gf = GModel::current()->getFaceByTag(Num);
if(gf) GModel::current()->remove(gf);
}
break;
case MSH_VOLUME_FROM_GMODEL:
{
GRegion *gr = GModel::current()->getRegionByTag(Num);
if(gr) GModel::current()->remove(gr);
}
break;
default:
Msg::Error("Impossible to delete entity %d (of type %d)", Num, Type);
break;
}
}
static void ColorCurve(int ip, unsigned int col)
{
Curve *c = FindCurve(ip);
if(!c)
return;
c->Color.type = 1;
c->Color.mesh = c->Color.geom = col;
}
static void ColorSurface(int is, unsigned int col)
{
Surface *s = FindSurface(is);
if(!s)
return;
s->Color.type = 1;
s->Color.mesh = s->Color.geom = col;
}
static void ColorVolume(int iv, unsigned int col)
{
Volume *v = FindVolume(iv);
if(!v)
return;
v->Color.type = 1;
v->Color.mesh = v->Color.geom = col;
}
void ColorShape(int Type, int Num, unsigned int Color)
{
switch (Type) {
case MSH_POINT:
break;
case MSH_SEGM_LINE:
case MSH_SEGM_SPLN:
case MSH_SEGM_BSPLN:
case MSH_SEGM_BEZIER:
case MSH_SEGM_CIRC:
case MSH_SEGM_CIRC_INV:
case MSH_SEGM_ELLI:
case MSH_SEGM_ELLI_INV:
case MSH_SEGM_NURBS:
case MSH_SEGM_DISCRETE:
ColorCurve(Num, Color);
break;
case MSH_SURF_TRIC:
case MSH_SURF_REGL:
case MSH_SURF_PLAN:
case MSH_SURF_DISCRETE:
ColorSurface(Num, Color);
break;
case MSH_VOLUME:
case MSH_VOLUME_DISCRETE:
ColorVolume(Num, Color);
break;
default:
break;
}
}
void VisibilityShape(int Type, int Num, int Mode)
{
Vertex *v;
Curve *c;
Surface *s;
Volume *V;
switch (Type) {
case MSH_POINT:
case MSH_POINT_FROM_GMODEL:
{
if((v = FindPoint(Num))) v->Visible = Mode;
GVertex *gv = GModel::current()->getVertexByTag(Num);
if(gv) gv->setVisibility(Mode);
}
break;
case MSH_SEGM_LINE:
case MSH_SEGM_SPLN:
case MSH_SEGM_BSPLN:
case MSH_SEGM_BEZIER:
case MSH_SEGM_CIRC:
case MSH_SEGM_CIRC_INV:
case MSH_SEGM_ELLI:
case MSH_SEGM_ELLI_INV:
case MSH_SEGM_NURBS:
case MSH_SEGM_DISCRETE:
case MSH_SEGM_COMPOUND:
case MSH_SEGM_FROM_GMODEL:
{
if((c = FindCurve(Num))) c->Visible = Mode;
GEdge *ge = GModel::current()->getEdgeByTag(Num);
if(ge) ge->setVisibility(Mode);
}
break;
case MSH_SURF_TRIC:
case MSH_SURF_REGL:
case MSH_SURF_PLAN:
case MSH_SURF_DISCRETE:
case MSH_SURF_COMPOUND:
case MSH_SURF_FROM_GMODEL:
{
if((s = FindSurface(Num))) s->Visible = Mode;
GFace *gf = GModel::current()->getFaceByTag(Num);
if(gf) gf->setVisibility(Mode);
}
break;
case MSH_VOLUME:
case MSH_VOLUME_DISCRETE:
case MSH_VOLUME_COMPOUND:
case MSH_VOLUME_FROM_GMODEL:
{
if((V = FindVolume(Num))) V->Visible = Mode;
GRegion *gr = GModel::current()->getRegionByTag(Num);
if(gr) gr->setVisibility(Mode);
}
break;
default:
break;
}
}
static int vmode;
static void vis_nod(void *a, void *b){ (*(Vertex **)a)->Visible = vmode; }
static void vis_cur(void *a, void *b){ (*(Curve **)a)->Visible = vmode; }
static void vis_sur(void *a, void *b){ (*(Surface **)a)->Visible = vmode; }
static void vis_vol(void *a, void *b){ (*(Volume **)a)->Visible = vmode; }
void VisibilityShape(char *str, int Type, int Mode)
{
vmode = Mode;
if(!strcmp(str, "all") || !strcmp(str, "*")) {
switch (Type) {
case 0:
Tree_Action(GModel::current()->getGEOInternals()->Points, vis_nod);
for(GModel::viter it = GModel::current()->firstVertex();
it != GModel::current()->lastVertex(); it++)
(*it)->setVisibility(Mode);
break;
case 1:
Tree_Action(GModel::current()->getGEOInternals()->Curves, vis_cur);
for(GModel::eiter it = GModel::current()->firstEdge();
it != GModel::current()->lastEdge(); it++)
(*it)->setVisibility(Mode);
break;
case 2:
Tree_Action(GModel::current()->getGEOInternals()->Surfaces, vis_sur);
for(GModel::fiter it = GModel::current()->firstFace();
it != GModel::current()->lastFace(); it++)
(*it)->setVisibility(Mode);
break;
case 3:
Tree_Action(GModel::current()->getGEOInternals()->Volumes, vis_vol);
for(GModel::riter it = GModel::current()->firstRegion();
it != GModel::current()->lastRegion(); it++)
(*it)->setVisibility(Mode);
break;
}
}
else {
VisibilityShape(Type, atoi(str), Mode);
}
}
Curve *CreateReversedCurve(Curve *c)
{
Curve *newc = Create_Curve(-c->Num, c->Typ, 1, NULL, NULL, -1, -1, 0., 1.);
if(List_Nbr(c->Control_Points)){
newc->Control_Points =
List_Create(List_Nbr(c->Control_Points), 1, sizeof(Vertex *));
if(c->Typ == MSH_SEGM_ELLI || c->Typ == MSH_SEGM_ELLI_INV) {
Vertex *e1, *e2, *e3, *e4;
List_Read(c->Control_Points, 0, &e1);
List_Read(c->Control_Points, 1, &e2);
List_Read(c->Control_Points, 2, &e3);
List_Read(c->Control_Points, 3, &e4);
List_Add(newc->Control_Points, &e4);
List_Add(newc->Control_Points, &e2);
List_Add(newc->Control_Points, &e3);
List_Add(newc->Control_Points, &e1);
}
else
List_Invert(c->Control_Points, newc->Control_Points);
}
if(c->Typ == MSH_SEGM_NURBS && c->k) {
newc->k = new float[c->degre + List_Nbr(c->Control_Points) + 1];
for(int i = 0; i < c->degre + List_Nbr(c->Control_Points) + 1; i++)
newc->k[c->degre + List_Nbr(c->Control_Points) - i] = c->k[i];
}
if(c->Typ == MSH_SEGM_CIRC)
newc->Typ = MSH_SEGM_CIRC_INV;
if(c->Typ == MSH_SEGM_CIRC_INV)
newc->Typ = MSH_SEGM_CIRC;
if(c->Typ == MSH_SEGM_ELLI)
newc->Typ = MSH_SEGM_ELLI_INV;
if(c->Typ == MSH_SEGM_ELLI_INV)
newc->Typ = MSH_SEGM_ELLI;
newc->beg = c->end;
newc->end = c->beg;
newc->Method = c->Method;
newc->nbPointsTransfinite = c->nbPointsTransfinite;
newc->typeTransfinite = -c->typeTransfinite;
newc->coeffTransfinite = c->coeffTransfinite;
newc->degre = c->degre;
newc->ubeg = 1. - c->uend;
newc->uend = 1. - c->ubeg;
End_Curve(newc);
Curve **pc;
if((pc = (Curve **)Tree_PQuery(GModel::current()->getGEOInternals()->Curves, &newc))) {
Free_Curve(&newc, NULL);
return *pc;
}
else{
Tree_Add(GModel::current()->getGEOInternals()->Curves, &newc);
return newc;
}
}
int recognize_seg(int typ, List_T *liste, int *seg)
{
List_T *temp = Tree2List(GModel::current()->getGEOInternals()->Curves);
int beg, end;
List_Read(liste, 0, &beg);
List_Read(liste, List_Nbr(liste) - 1, &end);
for(int i = 0; i < List_Nbr(temp); i++) {
Curve *pc;
List_Read(temp, i, &pc);
if(pc->Typ == typ && pc->beg->Num == beg && pc->end->Num == end) {
List_Delete(temp);
*seg = pc->Num;
return 1;
}
}
List_Delete(temp);
return 0;
}
int recognize_loop(List_T *liste, int *loop)
{
int res = 0;
*loop = 0;
List_T *temp = Tree2List(GModel::current()->getGEOInternals()->EdgeLoops);
for(int i = 0; i < List_Nbr(temp); i++) {
EdgeLoop *pe;
List_Read(temp, i, &pe);
if(!compare2Lists(pe->Curves, liste, fcmp_absint)) {
res = 1;
*loop = pe->Num;
break;
}
}
List_Delete(temp);
return res;
}
int recognize_surfloop(List_T *liste, int *loop)
{
int res = 0;
*loop = 0;
List_T *temp = Tree2List(GModel::current()->getGEOInternals()->SurfaceLoops);
for(int i = 0; i < List_Nbr(temp); i++) {
EdgeLoop *pe;
List_Read(temp, i, &pe);
if(!compare2Lists(pe->Curves, liste, fcmp_absint)) {
res = 1;
*loop = pe->Num;
break;
}
}
List_Delete(temp);
return res;
}
// Linear applications
static void SetTranslationMatrix(double matrix[4][4], double T[3])
{
for(int i = 0; i < 4; i++) {
for(int j = 0; j < 4; j++) {
matrix[i][j] = (i == j) ? 1.0 : 0.0;
}
}
for(int i = 0; i < 3; i++)
matrix[i][3] = T[i];
}
static void SetSymmetryMatrix(double matrix[4][4], double A, double B, double C,
double D)
{
double F = -2.0 / (A * A + B * B + C * C);
matrix[0][0] = 1. + A * A * F;
matrix[0][1] = A * B * F;
matrix[0][2] = A * C * F;
matrix[0][3] = A * D * F;
matrix[1][0] = A * B * F;
matrix[1][1] = 1. + B * B * F;
matrix[1][2] = B * C * F;
matrix[1][3] = B * D * F;
matrix[2][0] = A * C * F;
matrix[2][1] = B * C * F;
matrix[2][2] = 1. + C * C * F;
matrix[2][3] = C * D * F;
matrix[3][0] = B * C * F;
matrix[3][1] = 0.0;
matrix[3][2] = 0.0;
matrix[3][3] = 1.0;
}
static void SetDilatationMatrix(double matrix[4][4], double T[3], double A)
{
matrix[0][0] = A;
matrix[0][1] = 0.0;
matrix[0][2] = 0.0;
matrix[0][3] = T[0] * (1.0 - A);
matrix[1][0] = 0.0;
matrix[1][1] = A;
matrix[1][2] = 0.0;
matrix[1][3] = T[1] * (1.0 - A);
matrix[2][0] = 0.0;
matrix[2][1] = 0.0;
matrix[2][2] = A;
matrix[2][3] = T[2] * (1.0 - A);
matrix[3][0] = 0.0;
matrix[3][1] = 0.0;
matrix[3][2] = 0.0;
matrix[3][3] = 1.0;
}
static void GramSchmidt(double v1[3], double v2[3], double v3[3])
{
double tmp[3];
norme(v1);
prodve(v3, v1, tmp);
norme(tmp);
v2[0] = tmp[0];
v2[1] = tmp[1];
v2[2] = tmp[2];
prodve(v1, v2, v3);
norme(v3);
}
static void SetRotationMatrix(double matrix[4][4], double Axe[3], double alpha)
{
double t1[3], t2[3];
if(Axe[0] != 0.0) {
t1[0] = 0.0;
t1[1] = 1.0;
t1[2] = 0.0;
t2[0] = 0.0;
t2[1] = 0.0;
t2[2] = 1.0;
}
else if(Axe[1] != 0.0) {
t1[0] = 1.0;
t1[1] = 0.0;
t1[2] = 0.0;
t2[0] = 0.0;
t2[1] = 0.0;
t2[2] = 1.0;
}
else {
t1[0] = 1.0;
t1[1] = 0.0;
t1[2] = 0.0;
t2[0] = 0.0;
t2[1] = 1.0;
t2[2] = 0.0;
}
GramSchmidt(Axe, t1, t2);
double rot[3][3], plan[3][3], invplan[3][3];
plan[0][0] = Axe[0];
plan[0][1] = Axe[1];
plan[0][2] = Axe[2];
plan[1][0] = t1[0];
plan[1][1] = t1[1];
plan[1][2] = t1[2];
plan[2][0] = t2[0];
plan[2][1] = t2[1];
plan[2][2] = t2[2];
rot[2][2] = cos(alpha);
rot[2][1] = sin(alpha);
rot[2][0] = 0.;
rot[1][2] = -sin(alpha);
rot[1][1] = cos(alpha);
rot[1][0] = 0.;
rot[0][2] = 0.;
rot[0][1] = 0.;
rot[0][0] = 1.;
int i, j, k;
for(i = 0; i < 3; i++)
for(j = 0; j < 3; j++)
invplan[i][j] = plan[j][i];
double interm[3][3];
for(i = 0; i < 3; i++)
for(j = 0; j < 3; j++) {
interm[i][j] = 0.0;
for(k = 0; k < 3; k++)
interm[i][j] += invplan[i][k] * rot[k][j];
}
for(i = 0; i < 4; i++)
for(j = 0; j < 4; j++)
matrix[i][j] = 0.0;
for(i = 0; i < 3; i++)
for(j = 0; j < 3; j++) {
for(k = 0; k < 3; k++)
matrix[i][j] += interm[i][k] * plan[k][j];
}
matrix[3][3] = 1.0;
}
static void vecmat4x4(double mat[4][4], double vec[4], double res[4])
{
for(int i = 0; i < 4; i++) {
res[i] = 0.0;
for(int j = 0; j < 4; j++) {
res[i] += mat[i][j] * vec[j];
}
}
}
#if 0
static void printCurve(Curve *c)
{
Vertex *v;
int N = List_Nbr(c->Control_Points);
Msg::Debug("Curve %d %d cp (%d->%d)", c->Num, N, c->beg->Num, c->end->Num);
for(int i = 0; i < N; i++) {
List_Read(c->Control_Points, i, &v);
Msg::Debug("Vertex %d (%g,%g,%g,%g)", v->Num, v->Pos.X, v->Pos.Y,
v->Pos.Z, v->lc);
}
}
static void printSurface(Surface *s)
{
Curve *c;
int N = List_Nbr(s->Generatrices);
Msg::Debug("Surface %d, %d generatrices", s->Num, N);
for(int i = 0; i < N; i++) {
List_Read(s->Generatrices, i, &c);
printCurve(c);
}
}
#endif
static void ApplyTransformationToPoint(double matrix[4][4], Vertex *v,
bool end_curve_surface=false)
{
double pos[4], vec[4];
if(!ListOfTransformedPoints)
ListOfTransformedPoints = List_Create(50, 50, sizeof(int));
if(!List_Search(ListOfTransformedPoints, &v->Num, fcmp_absint)) {
List_Add(ListOfTransformedPoints, &v->Num);
}
else
return;
vec[0] = v->Pos.X;
vec[1] = v->Pos.Y;
vec[2] = v->Pos.Z;
vec[3] = v->w;
vecmat4x4(matrix, vec, pos);
v->Pos.X = pos[0];
v->Pos.Y = pos[1];
v->Pos.Z = pos[2];
v->w = pos[3];
// Warning: in theory we should always redo these checks if
// end_curve_surface is true; but in practice this is so slow for
// big models that we need to provide a way to bypass it (which is
// OK if the guy who builds the geometry knowns what he's
// doing). Instead of adding one more option, let's just bypass all
// the checks if auto_coherence==0...
if(CTX::instance()->geom.autoCoherence && end_curve_surface){
List_T *All = Tree2List(GModel::current()->getGEOInternals()->Curves);
for(int i = 0; i < List_Nbr(All); i++) {
Curve *c;
List_Read(All, i, &c);
for(int j = 0; j < List_Nbr(c->Control_Points); j++) {
Vertex *pv = *(Vertex **)List_Pointer(c->Control_Points, j);
if(pv->Num == v->Num){
End_Curve(c);
break;
}
}
}
List_Delete(All);
}
}
static void ApplyTransformationToCurve(double matrix[4][4], Curve *c)
{
if(!c->beg || !c->end){
Msg::Error("Cannot transform curve with no begin/end points");
return;
}
ApplyTransformationToPoint(matrix, c->beg);
ApplyTransformationToPoint(matrix, c->end);
for(int i = 0; i < List_Nbr(c->Control_Points); i++) {
Vertex *v;
List_Read(c->Control_Points, i, &v);
ApplyTransformationToPoint(matrix, v);
}
End_Curve(c);
}
static void ApplyTransformationToSurface(double matrix[4][4], Surface *s)
{
for(int i = 0; i < List_Nbr(s->Generatrices); i++) {
Curve *c;
List_Read(s->Generatrices, i, &c);
Curve *cc = FindCurve(abs(c->Num));
ApplyTransformationToCurve(matrix, cc);
}
End_Surface(s);
}
static void ApplyTransformationToVolume(double matrix[4][4], Volume *v)
{
for(int i = 0; i < List_Nbr(v->Surfaces); i++) {
Surface *s;
List_Read(v->Surfaces, i, &s);
ApplyTransformationToSurface(matrix, s);
}
}
static void ApplicationOnShapes(double matrix[4][4], List_T *shapes)
{
Vertex *v;
Curve *c;
Surface *s;
Volume *vol;
List_Reset(ListOfTransformedPoints);
for(int i = 0; i < List_Nbr(shapes); i++) {
Shape O;
List_Read(shapes, i, &O);
switch (O.Type) {
case MSH_POINT:
v = FindPoint(O.Num);
if(v)
ApplyTransformationToPoint(matrix, v, true);
else
Msg::Error("Unknown point %d", O.Num);
break;
case MSH_SEGM_LINE:
case MSH_SEGM_SPLN:
case MSH_SEGM_BSPLN:
case MSH_SEGM_BEZIER:
case MSH_SEGM_CIRC:
case MSH_SEGM_CIRC_INV:
case MSH_SEGM_ELLI:
case MSH_SEGM_ELLI_INV:
case MSH_SEGM_NURBS:
c = FindCurve(O.Num);
if(c)
ApplyTransformationToCurve(matrix, c);
else
Msg::Error("Unknown curve %d", O.Num);
break;
case MSH_SURF_REGL:
case MSH_SURF_TRIC:
case MSH_SURF_PLAN:
s = FindSurface(O.Num);
if(s)
ApplyTransformationToSurface(matrix, s);
else
Msg::Error("Unknown surface %d", O.Num);
break;
case MSH_VOLUME:
vol = FindVolume(O.Num);
if(vol)
ApplyTransformationToVolume(matrix, vol);
else
Msg::Error("Unknown volume %d", O.Num);
break;
default:
Msg::Error("Impossible to transform entity %d (of type %d)", O.Num,
O.Type);
break;
}
}
List_Reset(ListOfTransformedPoints);
}
void TranslateShapes(double X, double Y, double Z, List_T *shapes)
{
double T[3], matrix[4][4];
T[0] = X;
T[1] = Y;
T[2] = Z;
SetTranslationMatrix(matrix, T);
ApplicationOnShapes(matrix, shapes);
if(CTX::instance()->geom.autoCoherence)
ReplaceAllDuplicates();
}
void DilatShapes(double X, double Y, double Z, double A, List_T *shapes)
{
double T[3], matrix[4][4];
T[0] = X;
T[1] = Y;
T[2] = Z;
SetDilatationMatrix(matrix, T, A);
ApplicationOnShapes(matrix, shapes);
if(CTX::instance()->geom.autoCoherence)
ReplaceAllDuplicates();
}
void RotateShapes(double Ax, double Ay, double Az,
double Px, double Py, double Pz,
double alpha, List_T *shapes)
{
double A[3], T[3], matrix[4][4];
T[0] = -Px;
T[1] = -Py;
T[2] = -Pz;
SetTranslationMatrix(matrix, T);
ApplicationOnShapes(matrix, shapes);
A[0] = Ax;
A[1] = Ay;
A[2] = Az;
SetRotationMatrix(matrix, A, alpha);
ApplicationOnShapes(matrix, shapes);
T[0] = Px;
T[1] = Py;
T[2] = Pz;
SetTranslationMatrix(matrix, T);
ApplicationOnShapes(matrix, shapes);
if(CTX::instance()->geom.autoCoherence)
ReplaceAllDuplicates();
}
void SymmetryShapes(double A, double B, double C, double D, List_T *shapes)
{
double matrix[4][4];
SetSymmetryMatrix(matrix, A, B, C, D);
ApplicationOnShapes(matrix, shapes);
if(CTX::instance()->geom.autoCoherence)
ReplaceAllDuplicates();
}
class ShapeLessThan{
public:
bool operator()(Shape *v1, Shape *v2) const
{
if(std::abs(v1->Num) < std::abs(v2->Num)) return true;
return false;
}
};
void BoundaryShapes(List_T *shapes, List_T *shapesBoundary, bool combined)
{
for(int i = 0; i < List_Nbr(shapes); i++) {
Shape O;
List_Read(shapes, i, &O);
switch (O.Type) {
case MSH_POINT:
case MSH_POINT_BND_LAYER:
case MSH_POINT_FROM_GMODEL:
return;
break;
case MSH_SEGM_LINE:
case MSH_SEGM_SPLN:
case MSH_SEGM_CIRC:
case MSH_SEGM_CIRC_INV:
case MSH_SEGM_ELLI:
case MSH_SEGM_ELLI_INV:
case MSH_SEGM_BSPLN:
case MSH_SEGM_NURBS:
case MSH_SEGM_BEZIER:
case MSH_SEGM_BND_LAYER:
case MSH_SEGM_DISCRETE:
{
Curve *c = FindCurve(O.Num);
if(c){
if(c->beg){
Shape sh;
sh.Type = MSH_POINT;
sh.Num = c->beg->Num;
List_Add(shapesBoundary, &sh);
}
if(c->end){
Shape sh;
sh.Type = MSH_POINT;
sh.Num = c->end->Num;
List_Add(shapesBoundary, &sh);
}
}
else
Msg::Error("Unknown curve %d", O.Num);
}
break;
case MSH_SEGM_FROM_GMODEL:
{
GEdge *ge = GModel::current()->getEdgeByTag(O.Num);
if(ge){
if(ge->getBeginVertex()){
Shape sh;
sh.Type = MSH_POINT_FROM_GMODEL;
sh.Num = ge->getBeginVertex()->tag();
List_Add(shapesBoundary, &sh);
}
if(ge->getEndVertex()){
Shape sh;
sh.Type = MSH_POINT_FROM_GMODEL;
sh.Num = ge->getEndVertex()->tag();
List_Add(shapesBoundary, &sh);
}
}
else
Msg::Error("Unknown curve %d", O.Num);
}
break;
case MSH_SURF_PLAN:
case MSH_SURF_REGL:
case MSH_SURF_TRIC:
case MSH_SURF_BND_LAYER:
case MSH_SURF_DISCRETE:
{
Surface *s = FindSurface(O.Num);
if(s){
for(int j = 0; j < List_Nbr(s->Generatrices); j++){
Curve *c;
List_Read(s->Generatrices, j, &c);
Shape sh;
sh.Type = c->Typ;
sh.Num = c->Num;
List_Add(shapesBoundary, &sh);
}
}
else
Msg::Error("Unknown surface %d", O.Num);
}
break;
case MSH_SURF_FROM_GMODEL:
{
GFace *gf = GModel::current()->getFaceByTag(O.Num);
if(gf){
std::list<GEdge*> edges(gf->edges());
for(std::list<GEdge*>::iterator it = edges.begin(); it != edges.end(); it++){
Shape sh;
sh.Type = MSH_SEGM_FROM_GMODEL;
sh.Num = (*it)->tag();
List_Add(shapesBoundary, &sh);
}
}
else
Msg::Error("Unknown surface %d", O.Num);
}
break;
case MSH_VOLUME:
case MSH_VOLUME_DISCRETE:
{
Volume *v = FindVolume(O.Num);
if(v){
for(int j = 0; j < List_Nbr(v->Surfaces); j++){
Surface *s;
List_Read(v->Surfaces, j, &s);
Shape sh;
sh.Type = s->Typ;
sh.Num = s->Num;
List_Add(shapesBoundary, &sh);
}
}
else
Msg::Error("Unknown volume %d", O.Num);
}
break;
case MSH_VOLUME_FROM_GMODEL:
{
GRegion *gr = GModel::current()->getRegionByTag(O.Num);
if(gr){
std::list<GFace*> faces(gr->faces());
for(std::list<GFace*>::iterator it = faces.begin(); it != faces.end(); it++){
Shape sh;
sh.Type = MSH_SURF_FROM_GMODEL;
sh.Num = (*it)->tag();
List_Add(shapesBoundary, &sh);
}
}
else
Msg::Error("Unknown volume %d", O.Num);
}
break;
default:
Msg::Error("Impossible to take boundary of entity %d (of type %d)", O.Num,
O.Type);
break;
}
}
if(combined){
// compute boundary of the combined shapes
std::set<Shape*, ShapeLessThan> combined;
for(int i = 0; i < List_Nbr(shapesBoundary); i++){
Shape *s = (Shape*)List_Pointer(shapesBoundary, i);
std::set<Shape*, ShapeLessThan>::iterator it = combined.find(s);
if(it == combined.end())
combined.insert(s);
else
combined.erase(it);
}
List_T *tmp = List_Create(combined.size(), 10, sizeof(Shape));
for(std::set<Shape*, ShapeLessThan>::iterator it = combined.begin();
it != combined.end(); it++)
List_Add(tmp, *it);
List_Reset(shapesBoundary);
List_Copy(tmp, shapesBoundary);
List_Delete(tmp);
}
}
// Extrusion routines
void ProtudeXYZ(double &x, double &y, double &z, ExtrudeParams *e)
{
double matrix[4][4];
double T[3];
Vertex v(x, y, z);
T[0] = -e->geo.pt[0];
T[1] = -e->geo.pt[1];
T[2] = -e->geo.pt[2];
SetTranslationMatrix(matrix, T);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToPoint(matrix, &v);
SetRotationMatrix(matrix, e->geo.axe, e->geo.angle);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToPoint(matrix, &v);
T[0] = -T[0];
T[1] = -T[1];
T[2] = -T[2];
SetTranslationMatrix(matrix, T);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToPoint(matrix, &v);
x = v.Pos.X;
y = v.Pos.Y;
z = v.Pos.Z;
List_Reset(ListOfTransformedPoints);
}
static int Extrude_ProtudePoint(int type, int ip,
double T0, double T1, double T2,
double A0, double A1, double A2,
double X0, double X1, double X2, double alpha,
Curve **pc, Curve **prc, int final,
ExtrudeParams *e)
{
double matrix[4][4], T[3], Ax[3], d;
Vertex V, *pv, *newp, *chapeau;
Curve *c;
int i;
pv = &V;
pv->Num = ip;
*pc = *prc = NULL;
if(!Tree_Query(GModel::current()->getGEOInternals()->Points, &pv))
return 0;
Msg::Debug("Extrude Point %d", ip);
chapeau = DuplicateVertex(pv);
switch (type) {
case TRANSLATE:
T[0] = T0;
T[1] = T1;
T[2] = T2;
SetTranslationMatrix(matrix, T);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToPoint(matrix, chapeau);
if(!comparePosition(&pv, &chapeau))
return pv->Num;
c = Create_Curve(NEWLINE(), MSH_SEGM_LINE, 1, NULL, NULL, -1, -1, 0., 1.);
c->Control_Points = List_Create(2, 1, sizeof(Vertex *));
c->Extrude = new ExtrudeParams;
c->Extrude->fill(type, T0, T1, T2, A0, A1, A2, X0, X1, X2, alpha);
if(e)
c->Extrude->mesh = e->mesh;
List_Add(c->Control_Points, &pv);
List_Add(c->Control_Points, &chapeau);
c->beg = pv;
c->end = chapeau;
break;
case BOUNDARY_LAYER:
chapeau->Typ = MSH_POINT_BND_LAYER;
if(e) chapeau->boundaryLayerIndex = e->mesh.BoundaryLayerIndex;
c = Create_Curve(NEWLINE(), MSH_SEGM_BND_LAYER, 1, NULL, NULL, -1, -1, 0., 1.);
c->Control_Points = List_Create(2, 1, sizeof(Vertex *));
c->Extrude = new ExtrudeParams;
c->Extrude->fill(type, T0, T1, T2, A0, A1, A2, X0, X1, X2, alpha);
if(e) c->Extrude->mesh = e->mesh;
List_Add(c->Control_Points, &pv);
List_Add(c->Control_Points, &chapeau);
c->beg = pv;
c->end = chapeau;
break;
case ROTATE:
T[0] = -X0;
T[1] = -X1;
T[2] = -X2;
SetTranslationMatrix(matrix, T);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToPoint(matrix, chapeau);
Ax[0] = A0;
Ax[1] = A1;
Ax[2] = A2;
SetRotationMatrix(matrix, Ax, alpha);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToPoint(matrix, chapeau);
T[0] = X0;
T[1] = X1;
T[2] = X2;
SetTranslationMatrix(matrix, T);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToPoint(matrix, chapeau);
if(!comparePosition(&pv, &chapeau))
return pv->Num;
c = Create_Curve(NEWLINE(), MSH_SEGM_CIRC, 1, NULL, NULL, -1, -1, 0., 1.);
c->Control_Points = List_Create(3, 1, sizeof(Vertex *));
c->Extrude = new ExtrudeParams;
c->Extrude->fill(type, T0, T1, T2, A0, A1, A2, X0, X1, X2, alpha);
if(e)
c->Extrude->mesh = e->mesh;
List_Add(c->Control_Points, &pv);
// compute circle center
newp = DuplicateVertex(pv);
Ax[0] = A0;
Ax[1] = A1;
Ax[2] = A2;
norme(Ax);
T[0] = pv->Pos.X - X0;
T[1] = pv->Pos.Y - X1;
T[2] = pv->Pos.Z - X2;
prosca(T, Ax, &d);
newp->Pos.X = X0 + d * Ax[0];
newp->Pos.Y = X1 + d * Ax[1];
newp->Pos.Z = X2 + d * Ax[2];
List_Add(c->Control_Points, &newp);
List_Add(c->Control_Points, &chapeau);
c->beg = pv;
c->end = chapeau;
break;
case TRANSLATE_ROTATE:
d = CTX::instance()->geom.extrudeSplinePoints;
d = d ? d : 1;
c = Create_Curve(NEWLINE(), MSH_SEGM_SPLN, 1, NULL, NULL, -1, -1, 0., 1.);
c->Control_Points =
List_Create(CTX::instance()->geom.extrudeSplinePoints + 1, 1, sizeof(Vertex *));
c->Extrude = new ExtrudeParams;
c->Extrude->fill(type, T0, T1, T2, A0, A1, A2, X0, X1, X2, alpha);
if(e)
c->Extrude->mesh = e->mesh;
List_Add(c->Control_Points, &pv);
c->beg = pv;
for(i = 0; i < CTX::instance()->geom.extrudeSplinePoints; i++) {
if(i)
chapeau = DuplicateVertex(chapeau);
T[0] = -X0;
T[1] = -X1;
T[2] = -X2;
SetTranslationMatrix(matrix, T);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToPoint(matrix, chapeau);
Ax[0] = A0;
Ax[1] = A1;
Ax[2] = A2;
SetRotationMatrix(matrix, Ax, alpha / d);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToPoint(matrix, chapeau);
T[0] = X0;
T[1] = X1;
T[2] = X2;
SetTranslationMatrix(matrix, T);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToPoint(matrix, chapeau);
T[0] = T0 / d;
T[1] = T1 / d;
T[2] = T2 / d;
SetTranslationMatrix(matrix, T);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToPoint(matrix, chapeau);
List_Add(c->Control_Points, &chapeau);
}
c->end = chapeau;
break;
default:
Msg::Error("Unknown extrusion type");
return pv->Num;
}
End_Curve(c);
Tree_Add(GModel::current()->getGEOInternals()->Curves, &c);
CreateReversedCurve(c);
*pc = c;
*prc = FindCurve(-c->Num);
List_Reset(ListOfTransformedPoints);
if(CTX::instance()->geom.autoCoherence && final)
ReplaceAllDuplicates();
return chapeau->Num;
}
static int Extrude_ProtudeCurve(int type, int ic,
double T0, double T1, double T2,
double A0, double A1, double A2,
double X0, double X1, double X2, double alpha,
Surface **ps, int final,
ExtrudeParams *e)
{
double matrix[4][4], T[3], Ax[3];
Curve *CurveBeg, *CurveEnd;
Curve *ReverseChapeau, *ReverseBeg, *ReverseEnd;
Curve *pc, *revpc, *chapeau;
Surface *s;
pc = FindCurve(ic);
revpc = FindCurve(-ic);
*ps = NULL;
if(!pc || !revpc){
return 0;
}
if(!pc->beg || !pc->end){
Msg::Error("Cannot extrude curve with no begin/end points");
return 0;
}
Msg::Debug("Extrude Curve %d", ic);
chapeau = DuplicateCurve(pc, false);
chapeau->Extrude = new ExtrudeParams(COPIED_ENTITY);
chapeau->Extrude->fill(type, T0, T1, T2, A0, A1, A2, X0, X1, X2, alpha);
chapeau->Extrude->geo.Source = pc->Num;
if(e)
chapeau->Extrude->mesh = e->mesh;
switch (type) {
case TRANSLATE:
T[0] = T0;
T[1] = T1;
T[2] = T2;
SetTranslationMatrix(matrix, T);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToCurve(matrix, chapeau);
break;
case BOUNDARY_LAYER:
chapeau->Typ = MSH_SEGM_BND_LAYER;
if(chapeau->beg){
chapeau->beg->Typ = MSH_POINT_BND_LAYER;
if(e) chapeau->beg->boundaryLayerIndex = e->mesh.BoundaryLayerIndex;
}
if(chapeau->end){
chapeau->end->Typ = MSH_POINT_BND_LAYER;
if(e) chapeau->end->boundaryLayerIndex = e->mesh.BoundaryLayerIndex;
}
for(int i = 0; i < List_Nbr(chapeau->Control_Points); i++){
Vertex *v;
List_Read(chapeau->Control_Points, i, &v);
if(e) v->boundaryLayerIndex = e->mesh.BoundaryLayerIndex;
}
revpc = FindCurve(-chapeau->Num);
if(revpc) revpc->Typ = MSH_SEGM_BND_LAYER;
break;
case ROTATE:
T[0] = -X0;
T[1] = -X1;
T[2] = -X2;
SetTranslationMatrix(matrix, T);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToCurve(matrix, chapeau);
Ax[0] = A0;
Ax[1] = A1;
Ax[2] = A2;
SetRotationMatrix(matrix, Ax, alpha);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToCurve(matrix, chapeau);
T[0] = X0;
T[1] = X1;
T[2] = X2;
SetTranslationMatrix(matrix, T);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToCurve(matrix, chapeau);
break;
case TRANSLATE_ROTATE:
T[0] = -X0;
T[1] = -X1;
T[2] = -X2;
SetTranslationMatrix(matrix, T);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToCurve(matrix, chapeau);
Ax[0] = A0;
Ax[1] = A1;
Ax[2] = A2;
SetRotationMatrix(matrix, Ax, alpha);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToCurve(matrix, chapeau);
T[0] = X0;
T[1] = X1;
T[2] = X2;
SetTranslationMatrix(matrix, T);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToCurve(matrix, chapeau);
T[0] = T0;
T[1] = T1;
T[2] = T2;
SetTranslationMatrix(matrix, T);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToCurve(matrix, chapeau);
break;
default:
Msg::Error("Unknown extrusion type");
return pc->Num;
}
Extrude_ProtudePoint(type, pc->beg->Num, T0, T1, T2,
A0, A1, A2, X0, X1, X2, alpha,
&CurveBeg, &ReverseBeg, 0, e);
Extrude_ProtudePoint(type, pc->end->Num, T0, T1, T2,
A0, A1, A2, X0, X1, X2, alpha,
&CurveEnd, &ReverseEnd, 0, e);
if(!CurveBeg && !CurveEnd){
return pc->Num;
}
if(type == BOUNDARY_LAYER)
s = Create_Surface(NEWSURFACE(), MSH_SURF_BND_LAYER);
else if(!CurveBeg || !CurveEnd)
s = Create_Surface(NEWSURFACE(), MSH_SURF_TRIC);
else
s = Create_Surface(NEWSURFACE(), MSH_SURF_REGL);
s->Generatrices = List_Create(4, 1, sizeof(Curve *));
s->Extrude = new ExtrudeParams;
s->Extrude->fill(type, T0, T1, T2, A0, A1, A2, X0, X1, X2, alpha);
s->Extrude->geo.Source = pc->Num;
if(e)
s->Extrude->mesh = e->mesh;
ReverseChapeau = FindCurve(-chapeau->Num);
if(!CurveBeg) {
List_Add(s->Generatrices, &pc);
List_Add(s->Generatrices, &CurveEnd);
List_Add(s->Generatrices, &ReverseChapeau);
}
else if(!CurveEnd) {
List_Add(s->Generatrices, &ReverseChapeau);
List_Add(s->Generatrices, &ReverseBeg);
List_Add(s->Generatrices, &pc);
}
else {
List_Add(s->Generatrices, &pc);
List_Add(s->Generatrices, &CurveEnd);
List_Add(s->Generatrices, &ReverseChapeau);
List_Add(s->Generatrices, &ReverseBeg);
}
End_Surface(s);
Tree_Add(GModel::current()->getGEOInternals()->Surfaces, &s);
List_Reset(ListOfTransformedPoints);
*ps = s;
if(CTX::instance()->geom.autoCoherence && final)
ReplaceAllDuplicates();
return chapeau->Num;
}
static int Extrude_ProtudeSurface(int type, int is,
double T0, double T1, double T2,
double A0, double A1, double A2,
double X0, double X1, double X2, double alpha,
Volume **pv, ExtrudeParams *e)
{
double matrix[4][4], T[3], Ax[3];
Curve *c, *c2;
int i;
Surface *s, *ps, *chapeau;
*pv = NULL;
// 'is' can be negative, to signify that the surface orientation
// should be reverted. This orientation information is only used at
// the moment when creating boundary layers
if(!(ps = FindSurface(std::abs(is))))
return 0;
Msg::Debug("Extrude Surface %d", is);
chapeau = DuplicateSurface(ps, false);
chapeau->Extrude = new ExtrudeParams(COPIED_ENTITY);
chapeau->Extrude->fill(type, T0, T1, T2, A0, A1, A2, X0, X1, X2, alpha);
chapeau->Extrude->geo.Source = is; // not ps->Num: we need the sign info
if(e)
chapeau->Extrude->mesh = e->mesh;
for(i = 0; i < List_Nbr(chapeau->Generatrices); i++) {
List_Read(ps->Generatrices, i, &c2);
List_Read(chapeau->Generatrices, i, &c);
if(c->Num < 0)
if(!(c = FindCurve(-c->Num))) {
Msg::Error("Unknown curve %d", -c->Num);
return ps->Num;
}
c->Extrude = new ExtrudeParams(COPIED_ENTITY);
c->Extrude->fill(type, T0, T1, T2, A0, A1, A2, X0, X1, X2, alpha);
// don't take the abs(): the sign of c2->Num is important (used
// when copying the mesh in the extrusion routine)
c->Extrude->geo.Source = c2->Num;
if(e)
c->Extrude->mesh = e->mesh;
}
// FIXME: this is a really ugly hack for backward compatibility, so
// that we don't screw up the old .geo files too much. (Before
// version 1.54, we didn't always create new volumes during "Extrude
// Surface". Now we do, but with "CTX::instance()->geom.oldNewreg==1", this
// bumps the NEWREG() counter, and thus changes the whole automatic
// numbering sequence.) So we locally force oldNewreg to 0: in most
// cases, since we define points, curves, etc., before defining
// volumes, the NEWVOLUME() call below will return a fairly low
// number, that will not interfere with the other numbers...
int tmp = CTX::instance()->geom.oldNewreg;
CTX::instance()->geom.oldNewreg = 0;
Volume *v = Create_Volume(NEWVOLUME(), MSH_VOLUME);
CTX::instance()->geom.oldNewreg = tmp;
v->Extrude = new ExtrudeParams;
v->Extrude->fill(type, T0, T1, T2, A0, A1, A2, X0, X1, X2, alpha);
v->Extrude->geo.Source = is;
if(e)
v->Extrude->mesh = e->mesh;
int ori = -1;
List_Add(v->Surfaces, &ps);
List_Add(v->SurfacesOrientations, &ori);
ori = 1;
List_Add(v->Surfaces, &chapeau);
List_Add(v->SurfacesOrientations, &ori);
for(i = 0; i < List_Nbr(ps->Generatrices); i++) {
List_Read(ps->Generatrices, i, &c);
Extrude_ProtudeCurve(type, c->Num, T0, T1, T2, A0, A1, A2, X0, X1, X2,
alpha, &s, 0, e);
if(s){
if(c->Num < 0)
ori = -1;
else
ori = 1;
List_Add(v->Surfaces, &s);
List_Add(v->SurfacesOrientations, &ori);
}
}
switch (type) {
case TRANSLATE:
T[0] = T0;
T[1] = T1;
T[2] = T2;
SetTranslationMatrix(matrix, T);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToSurface(matrix, chapeau);
break;
case BOUNDARY_LAYER:
chapeau->Typ = MSH_SURF_BND_LAYER;
for(int i = 0; i < List_Nbr(chapeau->Generatrices); i++) {
List_Read(chapeau->Generatrices, i, &c);
c->Typ = MSH_SEGM_BND_LAYER;
c = FindCurve(-c->Num);
c->Typ = MSH_SEGM_BND_LAYER;
if(c->beg){
c->beg->Typ = MSH_POINT_BND_LAYER;
if(e) c->beg->boundaryLayerIndex = e->mesh.BoundaryLayerIndex;
}
if(c->end){
c->end->Typ = MSH_POINT_BND_LAYER;
if(e) c->end->boundaryLayerIndex = e->mesh.BoundaryLayerIndex;
}
for(int i = 0; i < List_Nbr(c->Control_Points); i++){
Vertex *v;
List_Read(c->Control_Points, i, &v);
if(e) v->boundaryLayerIndex = e->mesh.BoundaryLayerIndex;
}
}
break;
case ROTATE:
T[0] = -X0;
T[1] = -X1;
T[2] = -X2;
SetTranslationMatrix(matrix, T);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToSurface(matrix, chapeau);
Ax[0] = A0;
Ax[1] = A1;
Ax[2] = A2;
SetRotationMatrix(matrix, Ax, alpha);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToSurface(matrix, chapeau);
T[0] = X0;
T[1] = X1;
T[2] = X2;
SetTranslationMatrix(matrix, T);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToSurface(matrix, chapeau);
break;
case TRANSLATE_ROTATE:
T[0] = -X0;
T[1] = -X1;
T[2] = -X2;
SetTranslationMatrix(matrix, T);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToSurface(matrix, chapeau);
Ax[0] = A0;
Ax[1] = A1;
Ax[2] = A2;
SetRotationMatrix(matrix, Ax, alpha);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToSurface(matrix, chapeau);
T[0] = X0;
T[1] = X1;
T[2] = X2;
SetTranslationMatrix(matrix, T);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToSurface(matrix, chapeau);
T[0] = T0;
T[1] = T1;
T[2] = T2;
SetTranslationMatrix(matrix, T);
List_Reset(ListOfTransformedPoints);
ApplyTransformationToSurface(matrix, chapeau);
break;
default:
Msg::Error("Unknown extrusion type");
return ps->Num;
}
// this is done only for backward compatibility with the old
// numbering scheme
Tree_Suppress(GModel::current()->getGEOInternals()->Surfaces, &chapeau);
chapeau->Num = NEWSURFACE();
chapeau->meshMaster = chapeau->Num;
GModel::current()->getGEOInternals()->MaxSurfaceNum = chapeau->Num;
Tree_Add(GModel::current()->getGEOInternals()->Surfaces, &chapeau);
Tree_Add(GModel::current()->getGEOInternals()->Volumes, &v);
*pv = v;
if(CTX::instance()->geom.autoCoherence)
ReplaceAllDuplicates();
List_Reset(ListOfTransformedPoints);
return chapeau->Num;
}
void ExtrudeShape(int extrude_type, int shape_type, int shape_num,
double T0, double T1, double T2,
double A0, double A1, double A2,
double X0, double X1, double X2, double alpha,
ExtrudeParams *e,
List_T *list_out)
{
Shape shape;
shape.Type = shape_type;
shape.Num = shape_num;
List_T *tmp = List_Create(1, 1, sizeof(Shape));
List_Add(tmp, &shape);
ExtrudeShapes(extrude_type, tmp,
T0, T1, T2,
A0, A1, A2,
X0, X1, X2, alpha,
e,
list_out);
List_Delete(tmp);
}
void ExtrudeShapes(int type, List_T *list_in,
double T0, double T1, double T2,
double A0, double A1, double A2,
double X0, double X1, double X2, double alpha,
ExtrudeParams *e,
List_T *list_out)
{
for(int i = 0; i < List_Nbr(list_in); i++){
Shape shape;
List_Read(list_in, i, &shape);
switch(shape.Type){
case MSH_POINT:
{
Curve *pc = 0, *prc = 0;
Shape top;
top.Num = Extrude_ProtudePoint(type, shape.Num, T0, T1, T2,
A0, A1, A2, X0, X1, X2, alpha,
&pc, &prc, 1, e);
top.Type = MSH_POINT;
List_Add(list_out, &top);
if(pc){
Shape body;
body.Num = pc->Num;
body.Type = pc->Typ;
List_Add(list_out, &body);
}
}
break;
case MSH_SEGM_LINE:
case MSH_SEGM_SPLN:
case MSH_SEGM_BSPLN:
case MSH_SEGM_BEZIER:
case MSH_SEGM_CIRC:
case MSH_SEGM_CIRC_INV:
case MSH_SEGM_ELLI:
case MSH_SEGM_ELLI_INV:
case MSH_SEGM_NURBS:
{
Surface *ps = 0;
Shape top;
top.Num = Extrude_ProtudeCurve(type, shape.Num, T0, T1, T2,
A0, A1, A2, X0, X1, X2, alpha,
&ps, 1, e);
Curve *pc = FindCurve(top.Num);
top.Type = pc ? pc->Typ : 0;
List_Add(list_out, &top);
if(ps){
Shape body;
body.Num = ps->Num;
body.Type = ps->Typ;
List_Add(list_out, &body);
if(CTX::instance()->geom.extrudeReturnLateral){
for(int j = 0; j < List_Nbr(ps->Generatrices); j++){
Curve *c;
List_Read(ps->Generatrices, j, &c);
if(abs(c->Num) != shape.Num && abs(c->Num) != top.Num){
Shape side;
side.Num = c->Num;
side.Type = c->Typ;
List_Add(list_out, &side);
}
}
}
}
}
break;
case MSH_SURF_REGL:
case MSH_SURF_TRIC:
case MSH_SURF_PLAN:
case MSH_SURF_DISCRETE:
{
Volume *pv = 0;
Shape top;
top.Num = Extrude_ProtudeSurface(type, shape.Num, T0, T1, T2,
A0, A1, A2, X0, X1, X2, alpha,
&pv, e);
Surface *ps = FindSurface(top.Num);
top.Type = ps ? ps->Typ : 0;
List_Add(list_out, &top);
if(pv){
Shape body;
body.Num = pv->Num;
body.Type = pv->Typ;
List_Add(list_out, &body);
if(CTX::instance()->geom.extrudeReturnLateral){
for(int j = 0; j < List_Nbr(pv->Surfaces); j++){
Surface *s;
List_Read(pv->Surfaces, j, &s);
if(abs(s->Num) != shape.Num && abs(s->Num) != top.Num){
Shape side;
side.Num = s->Num;
side.Type = s->Typ;
List_Add(list_out, &side);
}
}
}
}
}
break;
default:
Msg::Error("Impossible to extrude entity %d (of type %d)",
shape.Num, shape.Type);
break;
}
}
}
// Duplicate removal
static int compareTwoPoints(const void *a, const void *b)
{
Vertex *q = *(Vertex **)a;
Vertex *w = *(Vertex **)b;
if(q->Typ != w->Typ)
return q->Typ - w->Typ;
if(q->boundaryLayerIndex != w->boundaryLayerIndex)
return q->boundaryLayerIndex - w->boundaryLayerIndex;
return comparePosition(a, b);
}
static int compareTwoCurves(const void *a, const void *b)
{
Curve *c1 = *(Curve **)a;
Curve *c2 = *(Curve **)b;
int comp;
if(c1->Typ != c2->Typ){
if((c1->Typ == MSH_SEGM_CIRC && c2->Typ == MSH_SEGM_CIRC_INV) ||
(c1->Typ == MSH_SEGM_CIRC_INV && c2->Typ == MSH_SEGM_CIRC) ||
(c1->Typ == MSH_SEGM_ELLI && c2->Typ == MSH_SEGM_ELLI_INV) ||
(c1->Typ == MSH_SEGM_ELLI_INV && c2->Typ == MSH_SEGM_ELLI)){
// this is still ok
}
else
return c1->Typ - c2->Typ;
}
if(List_Nbr(c1->Control_Points) != List_Nbr(c2->Control_Points))
return List_Nbr(c1->Control_Points) - List_Nbr(c2->Control_Points);
if(!List_Nbr(c1->Control_Points)){
if(!c1->beg || !c2->beg)
return 1;
comp = compareVertex(&c1->beg, &c2->beg);
if(comp)
return comp;
if(!c1->end || !c2->end)
return 1;
comp = compareVertex(&c1->end, &c2->end);
if(comp)
return comp;
}
else {
for(int i = 0; i < List_Nbr(c1->Control_Points); i++){
Vertex *v1, *v2;
List_Read(c1->Control_Points, i, &v1);
List_Read(c2->Control_Points, i, &v2);
comp = compareVertex(&v1, &v2);
if(comp)
return comp;
}
}
return 0;
}
static int compareTwoSurfaces(const void *a, const void *b)
{
Surface *s1 = *(Surface **)a;
Surface *s2 = *(Surface **)b;
// checking types is the "right thing" to do (see e.g. compareTwoCurves)
// but it would break backward compatibility (see e.g. tutorial/t2.geo),
// so let's just do it for boundary layer surfaces for now:
if(s1->Typ == MSH_SURF_BND_LAYER || s2->Typ == MSH_SURF_BND_LAYER){
if(s1->Typ != s2->Typ) return s1->Typ - s2->Typ;
}
// if both surfaces have no generatrices, stay on the safe side and
// assume they are different
if(!List_Nbr(s1->Generatrices) && !List_Nbr(s2->Generatrices))
return 1;
return compare2Lists(s1->Generatrices, s2->Generatrices, compareAbsCurve);
}
static void MaxNumPoint(void *a, void *b)
{
Vertex *v = *(Vertex **)a;
GModel::current()->getGEOInternals()->MaxPointNum =
std::max(GModel::current()->getGEOInternals()->MaxPointNum, v->Num);
}
static void MaxNumCurve(void *a, void *b)
{
Curve *c = *(Curve **)a;
GModel::current()->getGEOInternals()->MaxLineNum =
std::max(GModel::current()->getGEOInternals()->MaxLineNum, c->Num);
}
static void MaxNumSurface(void *a, void *b)
{
Surface *s = *(Surface **)a;
GModel::current()->getGEOInternals()->MaxSurfaceNum =
std::max(GModel::current()->getGEOInternals()->MaxSurfaceNum, s->Num);
}
static void ReplaceDuplicatePoints()
{
// FIXME: This routine is in fact logically wrong (the
// compareTwoPoints function used in the avl tree is not a
// appropriate comparison function). The fix is simple (use a multi
// dimensional tree, e.g., MVertexPositionSet), but fixing the
// routine would break backward compatibility with old .geo
// files. This will be fixed in the new abstract GModel CAD creation
// routines.
Vertex *v, *v2, **pv, **pv2;
Curve *c;
Surface *s;
Volume *vol;
Tree_T *points2delete = Tree_Create(sizeof(Vertex *), compareVertex);
Tree_T *allNonDuplicatedPoints = Tree_Create(sizeof(Vertex *), compareTwoPoints);
// Create unique points
int start = Tree_Nbr(GModel::current()->getGEOInternals()->Points);
List_T *All = Tree2List(GModel::current()->getGEOInternals()->Points);
for(int i = 0; i < List_Nbr(All); i++) {
List_Read(All, i, &v);
if(!Tree_Search(allNonDuplicatedPoints, &v)) {
Tree_Insert(allNonDuplicatedPoints, &v);
}
else {
Tree_Suppress(GModel::current()->getGEOInternals()->Points, &v);
Tree_Insert(points2delete, &v);
}
}
List_Delete(All);
int end = Tree_Nbr(GModel::current()->getGEOInternals()->Points);
if(start == end) {
Tree_Delete(points2delete);
Tree_Delete(allNonDuplicatedPoints);
return;
}
Msg::Debug("Removed %d duplicate points", start - end);
if(CTX::instance()->geom.oldNewreg) {
GModel::current()->getGEOInternals()->MaxPointNum = 0;
Tree_Action(GModel::current()->getGEOInternals()->Points, MaxNumPoint);
}
// Replace old points in curves
All = Tree2List(GModel::current()->getGEOInternals()->Curves);
for(int i = 0; i < List_Nbr(All); i++) {
List_Read(All, i, &c);
// replace begin/end points
if(!Tree_Query(allNonDuplicatedPoints, &c->beg))
Msg::Error("Weird point %d in Coherence", c->beg->Num);
if(!Tree_Query(allNonDuplicatedPoints, &c->end))
Msg::Error("Weird point %d in Coherence", c->end->Num);
// replace control points
for(int j = 0; j < List_Nbr(c->Control_Points); j++) {
pv = (Vertex **)List_Pointer(c->Control_Points, j);
if(!(pv2 = (Vertex **)Tree_PQuery(allNonDuplicatedPoints, pv)))
Msg::Error("Weird point %d in Coherence", (*pv)->Num);
else
List_Write(c->Control_Points, j, pv2);
}
// replace extrusion sources
if(c->Extrude && c->Extrude->geo.Mode == EXTRUDED_ENTITY){
v2 = FindPoint(std::abs(c->Extrude->geo.Source), points2delete);
if(v2){
if(!(pv2 = (Vertex **)Tree_PQuery(allNonDuplicatedPoints, &v2)))
Msg::Error("Weird point %d in Coherence", v2->Num);
else
c->Extrude->geo.Source = (*pv2)->Num;
}
}
}
List_Delete(All);
// Replace old points in surfaces
All = Tree2List(GModel::current()->getGEOInternals()->Surfaces);
for(int i = 0; i < List_Nbr(All); i++) {
List_Read(All, i, &s);
// replace transfinite corners
for(int j = 0; j < List_Nbr(s->TrsfPoints); j++){
pv = (Vertex **)List_Pointer(s->TrsfPoints, j);
if(!(pv2 = (Vertex **)Tree_PQuery(allNonDuplicatedPoints, pv)))
Msg::Error("Weird point %d in Coherence", (*pv)->Num);
else
List_Write(s->TrsfPoints, j, pv2);
}
}
List_Delete(All);
// Replace old points in volumes
All = Tree2List(GModel::current()->getGEOInternals()->Volumes);
for(int i = 0; i < List_Nbr(All); i++) {
List_Read(All, i, &vol);
// replace transfinite corners
for(int j = 0; j < List_Nbr(vol->TrsfPoints); j++){
pv = (Vertex **)List_Pointer(vol->TrsfPoints, j);
if(!(pv2 = (Vertex **)Tree_PQuery(allNonDuplicatedPoints, pv)))
Msg::Error("Weird point %d in Coherence", (*pv)->Num);
else
List_Write(vol->TrsfPoints, j, pv2);
}
}
List_Delete(All);
// TODO: replace old points in physical groups
Tree_Action(points2delete, Free_Vertex);
Tree_Delete(points2delete);
Tree_Delete(allNonDuplicatedPoints);
}
static void ReplaceDuplicateCurves()
{
Curve *c, *c2, **pc, **pc2;
Surface *s;
Tree_T *curves2delete = Tree_Create(sizeof(Curve *), compareCurve);
Tree_T *allNonDuplicatedCurves = Tree_Create(sizeof(Curve *), compareTwoCurves);
// Create unique curves
int start = Tree_Nbr(GModel::current()->getGEOInternals()->Curves);
List_T *All = Tree2List(GModel::current()->getGEOInternals()->Curves);
for(int i = 0; i < List_Nbr(All); i++) {
List_Read(All, i, &c);
if(c->Num > 0) {
if(!Tree_Search(allNonDuplicatedCurves, &c)) {
Tree_Insert(allNonDuplicatedCurves, &c);
if(!(c2 = FindCurve(-c->Num))) {
Msg::Error("Unknown curve %d", -c->Num);
List_Delete(All);
return;
}
Tree_Insert(allNonDuplicatedCurves, &c2);
}
else {
Tree_Suppress(GModel::current()->getGEOInternals()->Curves, &c);
if(!(c2 = FindCurve(-c->Num))) {
Msg::Error("Unknown curve %d", -c->Num);
break;
}
Tree_Suppress(GModel::current()->getGEOInternals()->Curves, &c2);
Tree_Insert(curves2delete, &c);
Tree_Insert(curves2delete, &c2);
}
}
}
List_Delete(All);
int end = Tree_Nbr(GModel::current()->getGEOInternals()->Curves);
if(start == end) {
Tree_Delete(curves2delete);
Tree_Delete(allNonDuplicatedCurves);
return;
}
Msg::Debug("Removed %d duplicate curves", start - end);
if(CTX::instance()->geom.oldNewreg) {
GModel::current()->getGEOInternals()->MaxLineNum = 0;
Tree_Action(GModel::current()->getGEOInternals()->Curves, MaxNumCurve);
}
// Replace old curves in curves
All = Tree2List(GModel::current()->getGEOInternals()->Curves);
for(int i = 0; i < List_Nbr(All); i++) {
List_Read(All, i, &c);
// replace extrusion sources
if(c->Extrude && c->Extrude->geo.Mode == COPIED_ENTITY){
c2 = FindCurve(std::abs(c->Extrude->geo.Source), curves2delete);
if(c2){
if(!(pc2 = (Curve **)Tree_PQuery(allNonDuplicatedCurves, &c2)))
Msg::Error("Weird curve %d in Coherence", c2->Num);
else
c->Extrude->geo.Source = (*pc2)->Num;
}
}
}
List_Delete(All);
// Replace old curves in surfaces
All = Tree2List(GModel::current()->getGEOInternals()->Surfaces);
for(int i = 0; i < List_Nbr(All); i++) {
List_Read(All, i, &s);
// replace bounding curves
for(int j = 0; j < List_Nbr(s->Generatrices); j++) {
pc = (Curve **)List_Pointer(s->Generatrices, j);
if(!(pc2 = (Curve **)Tree_PQuery(allNonDuplicatedCurves, pc)))
Msg::Error("Weird curve %d in Coherence", (*pc)->Num);
else {
List_Write(s->Generatrices, j, pc2);
// arghhh: check compareTwoCurves!
End_Curve(*pc2);
}
}
// replace extrusion sources
if(s->Extrude && s->Extrude->geo.Mode == EXTRUDED_ENTITY){
c2 = FindCurve(std::abs(s->Extrude->geo.Source), curves2delete);
if(c2){
if(!(pc2 = (Curve **)Tree_PQuery(allNonDuplicatedCurves, &c2)))
Msg::Error("Weird curve %d in Coherence", c2->Num);
else
s->Extrude->geo.Source = (*pc2)->Num;
}
}
}
List_Delete(All);
// TODO: replace old curves in physical groups
Tree_Action(curves2delete, Free_Curve);
Tree_Delete(curves2delete);
Tree_Delete(allNonDuplicatedCurves);
}
static void ReplaceDuplicateSurfaces()
{
Surface *s, *s2, **ps, **ps2;
Volume *vol;
Tree_T *surfaces2delete = Tree_Create(sizeof(Surface *), compareSurface);
Tree_T *allNonDuplicatedSurfaces = Tree_Create(sizeof(Surface *), compareTwoSurfaces);
// Create unique surfaces
int start = Tree_Nbr(GModel::current()->getGEOInternals()->Surfaces);
List_T *All = Tree2List(GModel::current()->getGEOInternals()->Surfaces);
for(int i = 0; i < List_Nbr(All); i++) {
List_Read(All, i, &s);
if(s->Num > 0) {
if(!Tree_Search(allNonDuplicatedSurfaces, &s)) {
Tree_Insert(allNonDuplicatedSurfaces, &s);
}
else {
Tree_Suppress(GModel::current()->getGEOInternals()->Surfaces, &s);
Tree_Insert(surfaces2delete, &s);
}
}
}
List_Delete(All);
int end = Tree_Nbr(GModel::current()->getGEOInternals()->Surfaces);
if(start == end) {
Tree_Delete(surfaces2delete);
Tree_Delete(allNonDuplicatedSurfaces);
return;
}
Msg::Debug("Removed %d duplicate surfaces", start - end);
if(CTX::instance()->geom.oldNewreg) {
GModel::current()->getGEOInternals()->MaxSurfaceNum = 0;
Tree_Action(GModel::current()->getGEOInternals()->Surfaces, MaxNumSurface);
}
// Replace old surfaces in surfaces
All = Tree2List(GModel::current()->getGEOInternals()->Surfaces);
for(int i = 0; i < List_Nbr(All); i++) {
List_Read(All, i, &s);
// replace extrusion sources
if(s->Extrude && s->Extrude->geo.Mode == COPIED_ENTITY){
s2 = FindSurface(std::abs(s->Extrude->geo.Source), surfaces2delete);
if(s2){
if(!(ps2 = (Surface **)Tree_PQuery(allNonDuplicatedSurfaces, &s2)))
Msg::Error("Weird surface %d in Coherence", s2->Num);
else
s->Extrude->geo.Source = (*ps2)->Num;
}
}
}
List_Delete(All);
// Replace old surfaces in volumes
All = Tree2List(GModel::current()->getGEOInternals()->Volumes);
for(int i = 0; i < List_Nbr(All); i++) {
List_Read(All, i, &vol);
// replace bounding surfaces
for(int j = 0; j < List_Nbr(vol->Surfaces); j++) {
ps = (Surface **)List_Pointer(vol->Surfaces, j);
if(!(ps2 = (Surface **)Tree_PQuery(allNonDuplicatedSurfaces, ps)))
Msg::Error("Weird surface %d in Coherence", (*ps)->Num);
else
List_Write(vol->Surfaces, j, ps2);
}
// replace extrusion sources
if(vol->Extrude && vol->Extrude->geo.Mode == EXTRUDED_ENTITY){
s2 = FindSurface(std::abs(vol->Extrude->geo.Source), surfaces2delete);
if(s2){
if(!(ps2 = (Surface **)Tree_PQuery(allNonDuplicatedSurfaces, &s2)))
Msg::Error("Weird surface %d in Coherence", s2->Num);
else
vol->Extrude->geo.Source = (*ps2)->Num;
}
}
}
List_Delete(All);
// TODO: replace old surfaces in physical groups
Tree_Action(surfaces2delete, Free_Surface);
Tree_Delete(surfaces2delete);
Tree_Delete(allNonDuplicatedSurfaces);
}
void ReplaceAllDuplicates()
{
ReplaceDuplicatePoints();
ReplaceDuplicateCurves();
ReplaceDuplicateSurfaces();
}
// Projection of a point on a surface
struct PointSurface{
Vertex *p;
Surface *s;
};
static void projectPS(fullVector<double> &x, fullVector<double> &res, void *data)
{
PointSurface *ps = (PointSurface*)data;
Vertex c = InterpolateSurface(ps->s, x(0), x(1), 0, 0);
Vertex du = InterpolateSurface(ps->s, x(0), x(1), 1, 1);
Vertex dv = InterpolateSurface(ps->s, x(0), x(1), 1, 2);
res(0) =
(c.Pos.X - ps->p->Pos.X) * du.Pos.X +
(c.Pos.Y - ps->p->Pos.Y) * du.Pos.Y +
(c.Pos.Z - ps->p->Pos.Z) * du.Pos.Z;
res(1) =
(c.Pos.X - ps->p->Pos.X) * dv.Pos.X +
(c.Pos.Y - ps->p->Pos.Y) * dv.Pos.Y +
(c.Pos.Z - ps->p->Pos.Z) * dv.Pos.Z;
}
bool ProjectPointOnSurface(Surface *s, Vertex &p, double uv[2])
{
fullVector<double> x(2);
x(0) = uv[0];
x(1) = uv[1];
PointSurface ps = {&p, s};
Vertex pp = InterpolateSurface(s, uv[0], uv[1], 0, 0);
double d2 =
(pp.Pos.X - p.Pos.X) * (pp.Pos.X - p.Pos.X) +
(pp.Pos.Y - p.Pos.Y) * (pp.Pos.Y - p.Pos.Y) +
(pp.Pos.Z - p.Pos.Z) * (pp.Pos.Z - p.Pos.Z) ;
if(d2 < 1.e-12) return true;
double UMIN = 0.;
double UMAX = 1.;
double VMIN = 0.;
double VMAX = 1.;
int ITER = 0;
while(1) {
bool success = newton_fd(projectPS, x, &ps);
if(success && x(0) >= UMIN && x(0) <= UMAX && x(1) >= VMIN && x(1) <= VMAX){
p = InterpolateSurface(s, x(0), x(1), 0, 0);
uv[0] = x(0);
uv[1] = x(1);
if (ITER >= 0)
Msg::Info("ProjectPoint (%g,%g,%g) On Surface %d converged after %d iterations",
p.Pos.X, p.Pos.Y, p.Pos.Z, s->Num, ITER);
return true;
}
x(0) = UMIN + (UMAX - UMIN) * ((rand() % 10000) / 10000.);
x(1) = VMIN + (VMAX - VMIN) * ((rand() % 10000) / 10000.);
if(ITER++ > 100) break;
}
{
int NSAMPLES = 500;
double uok = 0.5, vok = 0.5;
double dmin = 1.e22;
for (int i = 0; i < NSAMPLES; i++){
const double U = i / (double)(NSAMPLES - 1);
for (int j = 0; j < NSAMPLES; j++){
const double V = j / (double)(NSAMPLES - 1);
Vertex pp = InterpolateSurface(s, U, V, 0, 0);
double d2 =
(pp.Pos.X - p.Pos.X) * (pp.Pos.X - p.Pos.X) +
(pp.Pos.Y - p.Pos.Y) * (pp.Pos.Y - p.Pos.Y) +
(pp.Pos.Z - p.Pos.Z) * (pp.Pos.Z - p.Pos.Z);
if (d2 < dmin) {
dmin = d2;
uok = U;
vok = V;
}
}
}
p = InterpolateSurface(s, uok, vok, 0, 0);
uv[0] = uok;
uv[1] = vok;
if (ITER > 0)
Msg::Info("Brute force method used for projection of point (%g %g %g) on surface %d",
p.Pos.X, p.Pos.Y, p.Pos.Z, s->Num);
return true;
}
return false;
}
// Split line
static Curve *_create_splitted_curve(Curve *c,List_T *nodes)
{
int beg, end;
List_Read(nodes, 0, &beg);
List_Read(nodes, List_Nbr(nodes) - 1, &end);
int id = NEWLINE();
Curve *cnew = NULL;
switch(c->Typ){
case MSH_SEGM_LINE:
cnew = Create_Curve(id, c->Typ, 1, nodes, NULL, -1, -1, 0., 1.);
break;
case MSH_SEGM_SPLN:
cnew = Create_Curve(id, c->Typ, 3, nodes, NULL, -1, -1, 0., 1.);
break;
case MSH_SEGM_BSPLN:
cnew = Create_Curve(id, c->Typ, 2, nodes, NULL, -1, -1, 0., 1.);
break;
default : //should never reach this point...
Msg::Error("Cannot split a curve with type %i", c->Typ);
return NULL;
}
Tree_Add(GModel::current()->getGEOInternals()->Curves, &cnew);
CreateReversedCurve(cnew);
return cnew;
}
bool SplitCurve(int line_id, List_T *vertices_id, List_T *shapes)
{
Curve *c = FindCurve(line_id);
if(!c){
Msg::Error("Curve %i does not exists", line_id);
return false;
}
switch (c->Typ){
case MSH_SEGM_LINE:
case MSH_SEGM_SPLN:
case MSH_SEGM_BSPLN:
break;
default:
Msg::Error("Cannot split curve %i with type %i", line_id, c->Typ);
return false;
}
std::set<int> v_break;
for(int i = 0; i < List_Nbr(vertices_id); i++){
int id;
List_Read(vertices_id, i, &id);
v_break.insert(id);
}
bool is_periodic = (c->beg == c->end);
bool first_periodic = true;
bool last_periodic = false;
List_T *new_list = List_Create(1, List_Nbr(c->Control_Points) / 10, sizeof(int));
Vertex *pv;
for (int i = 0; i < List_Nbr(c->Control_Points); i++){
List_Read(c->Control_Points, i, &pv);
List_Add(new_list, &pv->Num);
if(v_break.find(pv->Num) != v_break.end() && List_Nbr(new_list) > 1){
if(last_periodic)
break;
if(!(is_periodic&&first_periodic)){
Curve *cnew = _create_splitted_curve(c, new_list);
List_Add(shapes, &cnew);
}
first_periodic = false;
List_Reset(new_list);
List_Add(new_list, &pv->Num);
}
if( i== (List_Nbr(c->Control_Points) - 1) && is_periodic && ! first_periodic){
i = 0;
last_periodic = true;
}
}
if(List_Nbr(new_list) > 1){
Curve *cnew = _create_splitted_curve(c, new_list);
List_Add(shapes, &cnew);
}
// replace original curve by the new curves in all surfaces (and for
// the opposite curve)
List_T *rshapes = List_Create(2, 1, sizeof(Shape));
int N = List_Nbr(shapes);
for(int i = 0; i < List_Nbr(shapes); i++){
Curve *cc, *rcc;
List_Read(shapes, N - i - 1, &cc);
rcc=FindCurve(-cc->Num);
List_Add(rshapes, &rcc);
}
List_T *Surfs = Tree2List(GModel::current()->getGEOInternals()->Surfaces);
for(int i = 0; i < List_Nbr(Surfs); i++) {
Surface *s;
List_Read(Surfs, i, &s);
for(int j = 0; j < List_Nbr(s->Generatrices); j++) {
Curve *surface_curve;
List_Read(s->Generatrices, j, &surface_curve);
if(surface_curve->Num == c->Num){
List_Remove(s->Generatrices, j);
List_Insert_In_List(shapes, j, s->Generatrices);
j += List_Nbr(shapes) - 1;
}
else if(surface_curve->Num == -c->Num){
List_Remove(s->Generatrices, j);
List_Insert_In_List(rshapes, j, s->Generatrices);
j += List_Nbr(shapes) - 1;
}
}
}
List_Delete(Surfs);
DeleteShape(c->Typ, c->Num);
List_Delete(new_list);
List_Delete(rshapes);
return true;
}
// Intersect a curve with a surface
struct CurveSurface{
Curve *c;
Surface *s;
};
static void intersectCS(fullVector<double> &uvt, fullVector<double> &res, void *data)
{
CurveSurface *cs = (CurveSurface*)data;
Vertex vs = InterpolateSurface(cs->s, uvt(0), uvt(1), 0, 0);
Vertex vc = InterpolateCurve(cs->c, uvt(2), 0);
res(0) = vs.Pos.X - vc.Pos.X;
res(1) = vs.Pos.Y - vc.Pos.Y;
res(2) = vs.Pos.Z - vc.Pos.Z;
}
bool IntersectCurvesWithSurface(List_T *curve_ids, int surface_id, List_T *shapes)
{
Surface *s = FindSurface(surface_id);
if(!s){
Msg::Error("Unknown surface %d", surface_id);
return false;
}
for(int i = 0; i < List_Nbr(curve_ids); i++){
double curve_id;
List_Read(curve_ids, i, &curve_id);
Curve *c = FindCurve((int)curve_id);
if(c){
CurveSurface cs = {c, s};
fullVector<double> uvt(3);
uvt(0) = 0.5;
uvt(1) = 0.5;
uvt(2) = 0.5;
if(newton_fd(intersectCS, uvt, &cs)){
Vertex p = InterpolateCurve(c, uvt(2), 0);
Vertex *v = Create_Vertex(NEWPOINT(), p.Pos.X, p.Pos.Y, p.Pos.Z, p.lc, p.u);
Tree_Insert(GModel::current()->getGEOInternals()->Points, &v);
Shape sh;
sh.Type = MSH_POINT;
sh.Num = v->Num;
List_Add(shapes, &sh);
}
}
else{
Msg::Error("Uknown curve %d", (int)curve_id);
return false;
}
}
return true;
}
// Bunch of utility routines
void sortEdgesInLoop(int num, List_T *edges)
{
// This function sorts the edges in an EdgeLoop and detects any
// subloops. Warning: the input edges are supposed to be *oriented*
// (Without this sort, it is very difficult to write general
// scriptable surface generation in complex cases)
Curve *c, *c0, *c1, *c2;
int nbEdges = List_Nbr(edges);
List_T *temp = List_Create(nbEdges, 1, sizeof(Curve *));
for(int i = 0; i < nbEdges; i++) {
int j;
List_Read(edges, i, &j);
if((c = FindCurve(j))){
List_Add(temp, &c);
if(c->Typ == MSH_SEGM_DISCRETE){
Msg::Warning("Aborting line loop sort for discrete edge: hope you know "
"what you're doing ;-)");
return;
}
}
else{
return;
Msg::Error("Unknown curve %d in line loop %d", j, num);
}
}
List_Reset(edges);
int j = 0, k = 0;
c0 = c1 = *(Curve **)List_Pointer(temp, 0);
List_Add(edges, &c1->Num);
List_PSuppress(temp, 0);
while(List_Nbr(edges) < nbEdges) {
for(int i = 0; i < List_Nbr(temp); i++) {
c2 = *(Curve **)List_Pointer(temp, i);
if(c1->end == c2->beg) {
List_Add(edges, &c2->Num);
List_PSuppress(temp, i);
c1 = c2;
if(c2->end == c0->beg) {
if(List_Nbr(temp)) {
Msg::Info("Starting subloop %d in Line Loop %d (are you sure about this?)",
++k, num);
c0 = c1 = *(Curve **)List_Pointer(temp, 0);
List_Add(edges, &c1->Num);
List_PSuppress(temp, 0);
}
}
break;
}
}
if(j++ > nbEdges) {
Msg::Error("Line Loop %d is wrong", num);
break;
}
}
List_Delete(temp);
}
void setSurfaceEmbeddedPoints(Surface *s, List_T *points)
{
if(!s->EmbeddedPoints)
s->EmbeddedPoints = List_Create(4, 4, sizeof(Vertex *));
int nbPoints = List_Nbr(points);
for(int i = 0; i < nbPoints; i++) {
double iPoint;
List_Read(points, i, &iPoint);
Vertex *v = FindPoint((int)iPoint);
if(v)
List_Add(s->EmbeddedPoints, &v);
else
Msg::Error("Unknown point %d", iPoint);
}
}
void setSurfaceEmbeddedCurves(Surface *s, List_T *curves)
{
if (!s->EmbeddedCurves)
s->EmbeddedCurves = List_Create(4, 4, sizeof(Curve *));
int nbCurves = List_Nbr(curves);
for(int i = 0; i < nbCurves; i++) {
double iCurve;
List_Read(curves, i, &iCurve);
Curve *c = FindCurve((int)iCurve);
if(c)
List_Add(s->EmbeddedCurves, &c);
else
Msg::Error("Unknown curve %d", (int)iCurve);
}
}
void setSurfaceGeneratrices(Surface *s, List_T *loops)
{
int nbLoop = List_Nbr(loops);
s->Generatrices = List_Create(4, 4, sizeof(Curve *));
for(int i = 0; i < nbLoop; i++) {
int iLoop;
List_Read(loops, i, &iLoop);
EdgeLoop *el;
if(!(el = FindEdgeLoop(abs(iLoop)))) {
Msg::Error("Unknown line loop %d", iLoop);
List_Delete(s->Generatrices);
s->Generatrices = NULL;
return;
}
else {
int ic;
Curve *c;
if((i == 0 && iLoop > 0) || // exterior boundary
(i != 0 && iLoop < 0)){ // hole
for(int j = 0; j < List_Nbr(el->Curves); j++) {
List_Read(el->Curves, j, &ic);
ic *= sign(iLoop);
if(i != 0) ic *= -1; // hole
if(!(c = FindCurve(ic))) {
Msg::Error("Unknown curve %d", ic);
List_Delete(s->Generatrices);
s->Generatrices = NULL;
return;
}
else
List_Add(s->Generatrices, &c);
}
}
else{
for(int j = List_Nbr(el->Curves)-1; j >= 0; j--) {
List_Read(el->Curves, j, &ic);
ic *= sign(iLoop);
if(i != 0) ic *= -1; // hole
if(!(c = FindCurve(ic))) {
Msg::Error("Unknown curve %d", ic);
List_Delete(s->Generatrices);
s->Generatrices = NULL;
return;
}
else
List_Add(s->Generatrices, &c);
}
}
}
}
}
void setVolumeSurfaces(Volume *v, List_T *loops)
{
List_Reset(v->Surfaces);
List_Reset(v->SurfacesOrientations);
List_Reset(v->SurfacesByTag);
for(int i = 0; i < List_Nbr(loops); i++) {
int il;
List_Read(loops, i, &il);
SurfaceLoop *sl;
if(!(sl = FindSurfaceLoop(abs(il)))) {
Msg::Error("Unknown surface loop %d", il);
return;
}
else {
for(int j = 0; j < List_Nbr(sl->Surfaces); j++) {
int is;
List_Read(sl->Surfaces, j, &is);
Surface *s = FindSurface(abs(is));
if(s) {
// contrary to curves in edge loops, we don't actually
// create "negative" surfaces. So we just store the signs in
// another list
List_Add(v->Surfaces, &s);
int tmp = sign(is) * sign(il);
if(i > 0) tmp *= -1; // this is a hole
List_Add(v->SurfacesOrientations, &tmp);
}
else{
GFace *gf = GModel::current()->getFaceByTag(abs(is));
if(gf) {
List_Add(v->SurfacesByTag, &is);
}
else{
Msg::Error("Unknown surface %d", is);
return;
}
}
}
}
}
}
// GEO_Internals routines
void GEO_Internals::alloc_all()
{
MaxPointNum = MaxLineNum = MaxLineLoopNum = MaxSurfaceNum = 0;
MaxSurfaceLoopNum = MaxVolumeNum = MaxPhysicalNum = 0;
Points = Tree_Create(sizeof(Vertex *), compareVertex);
Curves = Tree_Create(sizeof(Curve *), compareCurve);
EdgeLoops = Tree_Create(sizeof(EdgeLoop *), compareEdgeLoop);
Surfaces = Tree_Create(sizeof(Surface *), compareSurface);
SurfaceLoops = Tree_Create(sizeof(SurfaceLoop *), compareSurfaceLoop);
Volumes = Tree_Create(sizeof(Volume *), compareVolume);
LevelSets = Tree_Create(sizeof(LevelSet *), compareLevelSet);
PhysicalGroups = List_Create(5, 5, sizeof(PhysicalGroup *));
}
void GEO_Internals::free_all()
{
MaxPointNum = MaxLineNum = MaxLineLoopNum = MaxSurfaceNum = 0;
MaxSurfaceLoopNum = MaxVolumeNum = MaxPhysicalNum = 0;
Tree_Action(Points, Free_Vertex); Tree_Delete(Points);
Tree_Action(Curves, Free_Curve); Tree_Delete(Curves);
Tree_Action(EdgeLoops, Free_EdgeLoop); Tree_Delete(EdgeLoops);
Tree_Action(Surfaces, Free_Surface); Tree_Delete(Surfaces);
Tree_Action(SurfaceLoops, Free_SurfaceLoop); Tree_Delete(SurfaceLoops);
Tree_Action(Volumes, Free_Volume); Tree_Delete(Volumes);
Tree_Action(LevelSets, Free_LevelSet); Tree_Delete(LevelSets);
List_Action(PhysicalGroups, Free_PhysicalGroup); List_Delete(PhysicalGroups);
}
void GEO_Internals::reset_physicals()
{
List_Action(PhysicalGroups, Free_PhysicalGroup);
List_Reset(PhysicalGroups);
}
int select_contour(int type, int num, List_T * List)
{
int k = 0;
switch (type) {
case ENT_LINE:
k = allEdgesLinked(num, List);
for(int i = 0; i < List_Nbr(List); i++) {
int ip;
List_Read(List, i, &ip);
GEdge *ge = GModel::current()->getEdgeByTag(abs(ip));
if(ge) ge->setSelection(1);
}
break;
case ENT_SURFACE:
k = allFacesLinked(num, List);
for(int i = 0; i < List_Nbr(List); i++) {
int ip;
List_Read(List, i, &ip);
GFace *gf = GModel::current()->getFaceByTag(abs(ip));
if(gf) gf->setSelection(1);
}
break;
}
return k;
}