Select Git revision
Forked from
gmsh / gmsh
Source project has a limited visibility.
-
Christophe Geuzaine authored
For all our mechanical engineering friends out there, I just cleaned up the stuff I did with Sean last year, i.e., allow to draw a vector field as a displacement map, with another scalar field displayed instead of the displacement norm. It's basically the same as Plugin(DisplacementRaise), but it does not modify the actual data inside the view (so e.g. you cannot save it). Instead, it's implemented as an alternative "Vector display" mode. This allows to easily animate deformed meshed with arbitrary scalar fields drawn on them. (The GUI for this is kinda lame, but it works: just select Vector display->Raised scalar view, select the scalar view number, et voila.) I also generalized the smooth normal code path a little, so that we can have smooth normals for vector-as-displacement and tensor-as-von-mises plots, too.
Christophe Geuzaine authoredFor all our mechanical engineering friends out there, I just cleaned up the stuff I did with Sean last year, i.e., allow to draw a vector field as a displacement map, with another scalar field displayed instead of the displacement norm. It's basically the same as Plugin(DisplacementRaise), but it does not modify the actual data inside the view (so e.g. you cannot save it). Instead, it's implemented as an alternative "Vector display" mode. This allows to easily animate deformed meshed with arbitrary scalar fields drawn on them. (The GUI for this is kinda lame, but it works: just select Vector display->Raised scalar view, select the scalar view number, et voila.) I also generalized the smooth normal code path a little, so that we can have smooth normals for vector-as-displacement and tensor-as-von-mises plots, too.
meshGEdge.cpp 11.03 KiB
// $Id: meshGEdge.cpp,v 1.45 2007-10-11 08:59:22 remacle Exp $
//
// Copyright (C) 1997-2007 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 "meshGEdge.h"
#include "GEdge.h"
#include "GFace.h"
#include "BackgroundMesh.h"
#include "Message.h"
typedef struct{
int Num;
double t, lc, p;
}IntPoint;
struct xi2lc
{
double xi, lc;
xi2lc(const double &_xi,const double _lc)
: xi(_xi), lc(_lc)
{
}
bool operator < (const xi2lc &other)
{
return xi < other.xi;
}
};
static std::vector<xi2lc> interpLc;
void smoothInterpLc(bool periodic, int nbSmooth)
{
if(periodic){
for(int i = 0; i < (int)interpLc.size() * nbSmooth; i++){
xi2lc &left = interpLc[(i - 1) % interpLc.size()];
xi2lc &mid = interpLc[i % interpLc.size()];
xi2lc &right = interpLc[(i + 1) % interpLc.size()];
if(1. / mid.lc > 1.1 * 1. / left.lc) mid.lc = left.lc/ 1.1;
if(1. / mid.lc > 1.1 * 1. / right.lc) mid.lc = right.lc/ 1.1;
}
}
else{
for(int j = 0; j < nbSmooth; j++){
for(int i = 0 ; i < (int)interpLc.size(); i++){
xi2lc &left = (i == 0) ? interpLc[0] : interpLc[i - 1];
xi2lc &mid = interpLc[i];
xi2lc &right = (i == (int)interpLc.size() - 1) ?
interpLc[interpLc.size() - 1] : interpLc[i+1];
if(1. / mid.lc > 1.1 * 1. / left.lc) mid.lc = left.lc / 1.1;
if(1. / mid.lc > 1.1 * 1. / right.lc) mid.lc = right.lc / 1.1;
}
}
}
}
void printInterpLc(const char *name)
{
FILE *f = fopen(name,"w");
for(unsigned int i = 0; i < interpLc.size(); i++){
xi2lc &interp = interpLc[i];
fprintf(f,"%12.5E %12.5E\n", interp.xi, 1 / interp.lc);
}
fclose(f);
}
void buildInterpLc(List_T *lcPoints)
{
IntPoint p;
interpLc.clear();
for(int i = 0; i < List_Nbr(lcPoints); i++){
List_Read(lcPoints, i, &p);
interpLc.push_back(xi2lc( p.t, p.lc));
}
}
double F_Lc_usingInterpLc(GEdge *ge, double t)
{
std::vector<xi2lc>::iterator it = std::lower_bound(interpLc.begin(),
interpLc.end(), xi2lc(t, 0));
double t1 = it->xi;
double l1 = it->lc;
it++;
SVector3 der = ge->firstDer(t);
const double d = norm(der);
if(it == interpLc.end()) return d * l1;
double t2 = it->xi;
double l2 = it->lc;
double l = l1 + ((t - t1) / (t2 - t1)) * (l2 - l1);
return d * l;
}
double F_Lc_usingInterpLcBis(GEdge *ge, double t)
{
GPoint p = ge->point(t);
double lc_here;
Range<double> bounds = ge->parBounds(0);
double t_begin = bounds.low();
double t_end = bounds.high();
if(t == t_begin)
lc_here = BGM_MeshSize(ge->getBeginVertex(), t, 0, p.x(), p.y(), p.z());
else if(t == t_end)
lc_here = BGM_MeshSize(ge->getEndVertex(), t, 0, p.x(), p.y(), p.z());
else
lc_here = BGM_MeshSize(ge, t, 0, p.x(), p.y(), p.z());
return 1 / lc_here;
}
double F_Lc(GEdge *ge, double t)
{
GPoint p = ge->point(t);
double lc_here;
Range<double> bounds = ge->parBounds(0);
double t_begin = bounds.low();
double t_end = bounds.high();
if(t == t_begin)
lc_here = BGM_MeshSize(ge->getBeginVertex(), t, 0, p.x(), p.y(), p.z());
else if(t == t_end)
lc_here = BGM_MeshSize(ge->getEndVertex(), t, 0, p.x(), p.y(), p.z());
else
lc_here = BGM_MeshSize(ge, t, 0, p.x(), p.y(), p.z());
SVector3 der = ge->firstDer(t);
const double d = norm(der);
return d / lc_here;
}
double F_Transfinite(GEdge *ge, double t)
{
double val, r;
SVector3 der = ge->firstDer(t) ;
double d = norm(der);
double coef = ge->meshAttributes.coeffTransfinite;
int type = ge->meshAttributes.typeTransfinite;
int nbpt = ge->meshAttributes.nbPointsTransfinite;
if(coef <= 0.0 || coef == 1.0) {
// coef < 0 should never happen
val = d * coef / ge->length();
}
else {
switch (abs(type)) {
case 1: // Geometric progression ar^i; Sum of n terms = length = a (r^n-1)/(r-1)
{
if(sign(type) >= 0)
r = coef;
else
r = 1. / coef;
double a = ge->length() * (r - 1.) / (pow(r, nbpt - 1.) - 1.);
int i = (int)(log(t * ge->length() / a * (r - 1.) + 1.) / log(r));
val = d / (a * pow(r, (double)i));
}
break;
case 2: // Bump
{
double a;
if(coef > 1.0) {
a = -4. * sqrt(coef - 1.) *
atan2(1., sqrt(coef - 1.)) /
((double)nbpt * ge->length());
}
else {
a = 2. * sqrt(1. - coef) *
log(fabs((1. + 1. / sqrt(1. - coef))
/ (1. - 1. / sqrt(1. - coef))))
/ ((double)nbpt * ge->length());
}
double b = -a * ge->length() * ge->length() / (4. * (coef - 1.));
val = d / (-a * DSQR(t * ge->length() - (ge->length()) * 0.5) + b);
}
break;
default:
Msg(WARNING, "Unknown case in Transfinite Line mesh");
val = 1.;
break;
}
}
return val;
}
double F_One(GEdge *ge, double t)
{
SVector3 der = ge->firstDer(t) ;
return norm(der);
}
double trapezoidal(IntPoint * P1, IntPoint * P2)
{
return (0.5 * (P1->lc + P2->lc) * (P2->t - P1->t));
}
void RecursiveIntegration(GEdge *ge, IntPoint * from, IntPoint * to,
double (*f) (GEdge *e, double X), List_T * pPoints,
double Prec, int *depth)
{
IntPoint P, p1;
(*depth)++;
P.t = 0.5 * (from->t + to->t);
P.lc = f(ge, P.t);
double val1 = trapezoidal(from, to);
double val2 = trapezoidal(from, &P);
double val3 = trapezoidal(&P, to);
double err = fabs(val1 - val2 - val3);
if(((err < Prec) && (*depth > 1)) || (*depth > 25)) {
List_Read(pPoints, List_Nbr(pPoints) - 1, &p1);
P.p = p1.p + val2;
List_Add(pPoints, &P);
List_Read(pPoints, List_Nbr(pPoints) - 1, &p1);
to->p = p1.p + val3;
List_Add(pPoints, to);
}
else {
RecursiveIntegration(ge, from, &P, f, pPoints, Prec, depth);
RecursiveIntegration(ge, &P, to, f, pPoints, Prec, depth);
}
(*depth)--;
}
double Integration(GEdge *ge, double t1, double t2,
double (*f) (GEdge *e, double X),
List_T * pPoints, double Prec)
{
IntPoint from, to;
int depth = 0;
from.t = t1;
from.lc = f(ge, from.t);
from.p = 0.0;
List_Add(pPoints, &from);
to.t = t2;
to.lc = f(ge, to.t);
RecursiveIntegration(ge, &from, &to, f, pPoints, Prec, &depth);
List_Read(pPoints, List_Nbr(pPoints) - 1, &to);
return to.p;
}
void deMeshGEdge::operator() (GEdge *ge)
{
if(ge->geomType() == GEntity::DiscreteCurve) return;
for (unsigned int i = 0; i < ge->mesh_vertices.size(); i++)
delete ge->mesh_vertices[i];
ge->mesh_vertices.clear();
for (unsigned int i = 0; i < ge->lines.size(); i++)
delete ge->lines[i];
ge->lines.clear();
ge->deleteVertexArrays();
}
void meshGEdge::operator() (GEdge *ge)
{
if(ge->geomType() == GEntity::DiscreteCurve) return;
if(ge->geomType() == GEntity::BoundaryLayerCurve) return;
// Send a messsage to the GMSH environment
Msg(INFO, "Meshing curve %d", ge->tag());
deMeshGEdge dem;
dem(ge);
if(MeshExtrudedCurve(ge)) return;
// Create a list of integration points
List_T *Points = List_Create(10, 10, sizeof(IntPoint));
// Create a list of points for interpolating the LC Field
List_T *lcPoints = List_Create(10, 10, sizeof(IntPoint));
// compute bounds
Range<double> bounds = ge->parBounds(0);
double t_begin = bounds.low();
double t_end = bounds.high();
// first compute the length of the curve by integrating one
double length = Integration(ge, t_begin, t_end, F_One, Points, 1.e-8);
ge->setLength(length);
List_Reset(Points);
// Integrate detJ/lc du
double a;
int N;
if(ge->meshAttributes.Method == TRANSFINI){
a = Integration(ge, t_begin, t_end, F_Transfinite, Points, 1.e-8);
N = ge->meshAttributes.nbPointsTransfinite;
}
else{
if(CTX.mesh.lc_integration_precision > 1.e-8){
Integration(ge, t_begin, t_end, F_Lc_usingInterpLcBis, lcPoints,
CTX.mesh.lc_integration_precision);
buildInterpLc(lcPoints);
printInterpLc("toto1.dat");
smoothInterpLc(ge->periodic(), 20);
printInterpLc("toto2.dat");
a = Integration(ge, t_begin, t_end, F_Lc_usingInterpLc, Points, 1.e-8);
}
else{
a = Integration(ge, t_begin, t_end, F_Lc, Points, 1.e-8);
}
N = std::max(ge->minimumMeshSegments() + 1, (int)(a + 1.));
}
// if the curve is periodic and if the begin vertex is identical to
// the end vertex and if this vertex has only one model curve
// adjacent to it, then the vertex is not connecting any other
// curve. So, the mesh vertex and its associated geom vertex are not
// necessary at the same location
GPoint beg_p, end_p;
if(ge->getBeginVertex() == ge->getEndVertex() &&
ge->getBeginVertex()->edges().size() == 1){
end_p = beg_p = ge->point(t_begin);
}
else{
MVertex *v0 = ge->getBeginVertex()->mesh_vertices[0];
MVertex *v1 = ge->getEndVertex()->mesh_vertices[0];
beg_p = GPoint(v0->x(), v0->y(), v0->z());
end_p = GPoint(v1->x(), v1->y(), v1->z());
}
// do not consider the first and the last vertex (those are not
// classified on this mesh edge)
if(N > 1){
const double b = a / (double)(N - 1);
int count = 1, NUMP = 1;
IntPoint P1, P2;
ge->mesh_vertices.resize(N - 2);
while(NUMP < N - 1) {
List_Read(Points, count - 1, &P1);
List_Read(Points, count, &P2);
const double d = (double)NUMP * b;
if((fabs(P2.p) >= fabs(d)) && (fabs(P1.p) < fabs(d))) {
double dt = P2.t - P1.t;
double dlc = P2.lc - P1.lc;
double dp = P2.p - P1.p;
double t = P1.t + dt / dp * (d - P1.p);
SVector3 der = ge->firstDer(t);
const double d = norm(der);
double lc = d/(P1.lc + dlc / dp * (d - P1.p));
GPoint V = ge->point(t);
ge->mesh_vertices[NUMP - 1] = new MEdgeVertex(V.x(), V.y(), V.z(), ge, t, lc);
// printf("lc = %12.5E %12.5E \n",lc,P1.lc,P2.lc);
NUMP++;
}
else {
count++;
}
}
ge->mesh_vertices.resize(NUMP - 1);
}
List_Delete(Points);
List_Delete(lcPoints);
for(unsigned int i = 0; i < ge->mesh_vertices.size() + 1; i++){
MVertex *v0 = (i == 0) ?
ge->getBeginVertex()->mesh_vertices[0] : ge->mesh_vertices[i - 1];
MVertex *v1 = (i == ge->mesh_vertices.size()) ?
ge->getEndVertex()->mesh_vertices[0] : ge->mesh_vertices[i];
ge->lines.push_back(new MLine(v0, v1));
}
if(ge->getBeginVertex() == ge->getEndVertex() &&
ge->getBeginVertex()->edges().size() == 1){
MVertex *v0 = ge->getBeginVertex()->mesh_vertices[0];
v0->x() = beg_p.x();
v0->y() = beg_p.y();
v0->z() = beg_p.z();
}
}