Forked from
gmsh / gmsh
8340 commits behind the upstream repository.
-
PA Beaufort authoredPA Beaufort authored
discreteEdge.cpp 18.98 KiB
// Gmsh - Copyright (C) 1997-2016 C. Geuzaine, J.-F. Remacle
//
// See the LICENSE.txt file for license information. Please report all
// bugs and problems to the public mailing list <gmsh@onelab.info>.
#include <vector>
#include <list>
#include "GmshConfig.h"
#include "GmshMessage.h"
#include "discreteEdge.h"
#include "MLine.h"
#include "Numeric.h"
#include "MPoint.h"
#include "MTriangle.h"
#include "MQuadrangle.h"
#include "MPrism.h"
#include "MTetrahedron.h"
#include "MHexahedron.h"
#include "MPyramid.h"
#include "Geo.h"
#include "OS.h"
#include "Curvature.h"
#include "GEdgeCompound.h"
#if defined(HAVE_MESH)
#include "meshGEdge.h"
#include "Context.h"
#endif
discreteEdge::discreteEdge(GModel *model, int num, GVertex *_v0, GVertex *_v1)
: GEdge(model, num, _v0, _v1)
{
createdTopo = false;
Curve *c = Create_Curve(num, MSH_SEGM_DISCRETE, 0, 0, 0, -1, -1, 0., 1.);
Tree_Add(model->getGEOInternals()->Curves, &c);
CreateReversedCurve(c);
}
// topology is already set
void discreteEdge::setTopo(std::vector<MLine*> mlines)
{
createdTopo = true;
lines = mlines;
_orientation = std::vector<int>(lines.size(),1);
}
void discreteEdge::createTopo()
{
if(!createdTopo){
orderMLines();
setBoundVertices();
createdTopo = true;
}
}
// FULL OF BUGS !!!!!!
void discreteEdge::orderMLines()
{
//printf("ordering line %d (%d,%d)\n", tag(),getBeginVertex()->mesh_vertices[0]->getNum(),getEndVertex()->mesh_vertices[0]->getNum());
//if(lines.size() <= 1) return;
std::vector<MLine*> _m;
std::list<MLine*> segments;
// store all lines in a list : segments
for (unsigned int i = 0; i < lines.size(); i++) segments.push_back(lines[i]);
// find a lonly MLine
for (std::list<MLine*>::iterator it = segments.begin();
it != segments.end(); ++it){
MVertex *vL = (*it)->getVertex(0);
MVertex *vR = (*it)->getVertex(1);
std::map<MVertex*,MLine*>::iterator it1 = boundv.find(vL);
if (it1 == boundv.end()) boundv.insert(std::make_pair(vL,*it));
else boundv.erase(it1);
std::map<MVertex*,MLine*>::iterator it2 = boundv.find(vR);
if (it2 == boundv.end()) boundv.insert(std::make_pair(vR,*it));
else boundv.erase(it2);
}
// find the first MLine and erase it from the list segments
MLine *firstLine;
if (boundv.size() == 2){ // non periodic
firstLine = (boundv.begin())->second;
for (std::list<MLine*>::iterator it = segments.begin();
it != segments.end(); ++it){
if (*it == firstLine){
segments.erase(it);
break;
}
}
}
else if (boundv.size() == 0){ // periodic
firstLine = *(segments.begin());
segments.erase(segments.begin());
}
else{
Msg::Error("EdgeCompound %d is wrong (it has %d end points)",
tag(), boundv.size());
}
// loop over all segments to order segments and store it in the list _m
_m.push_back(firstLine);
_orientation.push_back(1);
MVertex *first = _m[0]->getVertex(0);
MVertex *last = _m[0]->getVertex(1);
while (first != last){
if (segments.empty()) break;
bool found = false;
for (std::list<MLine*>::iterator it = segments.begin();
it != segments.end(); ++it){
MLine *e = *it;
if (e->getVertex(0) == last){
_m.push_back(e);
segments.erase(it);
_orientation.push_back(1);
last = e->getVertex(1);
found = true;
break;
}
else if (e->getVertex(1) == last){
_m.push_back(e);
segments.erase(it);
_orientation.push_back(0);
last = e->getVertex(0);
found = true;
break;
}
}
if (!found && _orientation[0]==1){ //reverse orientation of first Line
if (_m.size() == 1 ){
MVertex *temp = first;
first = last;
last = temp;
_orientation[0] = 0;
}
else {
Msg::Error("Discrete Edge %d is wrong",tag());
return;
}
}
}
//lines is now a list of ordered MLines
lines = _m;
//mesh_vertices
mesh_vertices.clear();
for (unsigned int i = 0; i < lines.size()-1; ++i){
MVertex *v1 = lines[i]->getVertex(0);
MVertex *v2 = lines[i]->getVertex(1);
if (std::find(mesh_vertices.begin(), mesh_vertices.end(), v1) ==
mesh_vertices.end()) mesh_vertices.push_back(v1);
if (std::find(mesh_vertices.begin(), mesh_vertices.end(), v2) ==
mesh_vertices.end()) mesh_vertices.push_back(v2);
}
//special case reverse orientation
if (lines.size() < 2) return;
if (_orientation[0] && lines[0]->getVertex(1) != lines[1]->getVertex(1)
&& lines[0]->getVertex(1) != lines[1]->getVertex(0)){
for (unsigned int i = 0; i < lines.size(); i++)
_orientation[i] = !_orientation[i];
}
}
void discreteEdge::setBoundVertices()
{
if (boundv.size() == 2){
std::vector<GVertex*> bound_vertices;
for (std::map<MVertex*,MLine*>::const_iterator iter = boundv.begin();
iter != boundv.end(); iter++){
MVertex* vE = (iter)->first;
bool existVertex = false;
for(GModel::viter point = model()->firstVertex();
point != model()->lastVertex(); point++){
if ((*point)->mesh_vertices[0]->getNum() == vE->getNum()){
bound_vertices.push_back((*point));
existVertex = true;
break;
}
}
if(!existVertex){
GVertex *gvB = new discreteVertex
(model(), model()->getMaxElementaryNumber(0) + 1);
//printf("*** Created discreteVertex %d\n", gvB->tag());
bound_vertices.push_back(gvB);
vE->setEntity(gvB);
gvB->mesh_vertices.push_back(vE);
gvB->points.push_back(new MPoint(gvB->mesh_vertices.back()));
model()->add(gvB);
}
std::vector<MVertex*>::iterator itve =
std::find(mesh_vertices.begin(), mesh_vertices.end(), vE);
if (itve != mesh_vertices.end()) mesh_vertices.erase(itve);
for(GModel::eiter edge = model()->firstEdge(); edge != model()->lastEdge(); edge++){
std::vector<MVertex*>::iterator itve =
std::find((*edge)->mesh_vertices.begin(), (*edge)->mesh_vertices.end(), vE);
if (itve != (*edge)->mesh_vertices.end()) (*edge)->mesh_vertices.erase(itve);
}
for(GModel::fiter face = model()->firstFace(); face != model()->lastFace(); face++){
std::vector<MVertex*>::iterator itve =
std::find((*face)->mesh_vertices.begin(), (*face)->mesh_vertices.end(), vE);
if (itve != (*face)->mesh_vertices.end()) (*face)->mesh_vertices.erase(itve);
}
for(GModel::riter reg = model()->firstRegion(); reg != model()->lastRegion(); reg++){
std::vector<MVertex*>::iterator itve =
std::find((*reg)->mesh_vertices.begin(), (*reg)->mesh_vertices.end(), vE);
if (itve != (*reg)->mesh_vertices.end()) (*reg)->mesh_vertices.erase(itve);
}
}
v0 = bound_vertices[0];
v1 = bound_vertices[1];
}
else if (boundv.size() == 0){
//printf("closed loop for discrete Edge =%d \n", this->tag());
GVertex* bound_vertex;
std::vector<MLine*>::const_iterator it = lines.begin();
MVertex* vE = (*it)->getVertex(0);
bool existVertex = false;
for(GModel::viter point = model()->firstVertex();
point != model()->lastVertex(); point++){
if ((*point)->mesh_vertices[0]->getNum() == vE->getNum()){
bound_vertex = (*point);
existVertex = true;
//printf("vertex exist (%g,%g,%g)\n", vE->x(), vE->y(), vE->z());
break;
}
}
if(!existVertex){
GVertex *gvB = new discreteVertex
(model(), model()->getMaxElementaryNumber(0) + 1);
//printf("*** Created discreteVertex %d\n", gvB->tag());
bound_vertex = gvB;
vE->setEntity(gvB);
gvB->mesh_vertices.push_back(vE);
gvB->points.push_back(new MPoint(gvB->mesh_vertices.back()));
model()->add(gvB);
}
std::vector<MVertex*>::iterator itve =
std::find(mesh_vertices.begin(),mesh_vertices.end(), vE);
if (itve != mesh_vertices.end()) mesh_vertices.erase(itve);
for(GModel::eiter edge = model()->firstEdge();
edge != model()->lastEdge(); edge++){
std::vector<MVertex*>::iterator itve =
std::find((*edge)->mesh_vertices.begin(), (*edge)->mesh_vertices.end(), vE);
if (itve != (*edge)->mesh_vertices.end()) (*edge)->mesh_vertices.erase(itve);
}
for(GModel::fiter face = model()->firstFace();
face != model()->lastFace(); face++){
std::vector<MVertex*>::iterator itve =
std::find((*face)->mesh_vertices.begin(), (*face)->mesh_vertices.end(), vE);
if (itve != (*face)->mesh_vertices.end()) (*face)->mesh_vertices.erase(itve);
}
for(GModel::riter reg = model()->firstRegion();
reg != model()->lastRegion(); reg++){
std::vector<MVertex*>::iterator itve =
std::find((*reg)->mesh_vertices.begin(), (*reg)->mesh_vertices.end(), vE);
if (itve != (*reg)->mesh_vertices.end()) (*reg)->mesh_vertices.erase(itve);
}
v0 = bound_vertex;
v1 = bound_vertex;
}
v0->addEdge(this);
v1->addEdge(this);
}
/*
+---------------+--------------+----------- ... ----------+
_pars[0]=0 _pars[1]=1 _pars[2]=2 _pars[N+1]=N+1
*/
void discreteEdge::parametrize(std::map<GFace*, std::map<MVertex*, MVertex*,
std::less<MVertex*> > > &face2Vert,
std::map<GRegion*, std::map<MVertex*, MVertex*,
std::less<MVertex*> > > ®ion2Vert)
{
if (_pars.empty()){
for (unsigned int i = 0; i < lines.size() + 1; i++){
_pars.push_back(i);
}
}
//Replace MVertex by MedgeVertex
std::map<MVertex*, MVertex*, std::less<MVertex*> > old2new;
old2new.clear();
std::vector<MVertex* > newVertices;
std::vector<MLine*> newLines;
MVertex *vL = getBeginVertex()->mesh_vertices[0];
int i = 0;
for(i = 0; i < (int)lines.size() - 1; i++){
MVertex *vR = lines[i]->getVertex(_orientation[i]);
int param = i+1;
MVertex *vNEW = new MEdgeVertex(vR->x(),vR->y(),vR->z(), this,
param, -1., vR->getNum());
old2new.insert(std::make_pair(vR,vNEW));
newVertices.push_back(vNEW);
newLines.push_back(new MLine(vL, vNEW));
_orientation[i] = 1;
vL = vNEW;
}
MVertex *vR = getEndVertex()->mesh_vertices[0];
newLines.push_back(new MLine(vL, vR));
_orientation[i] = 1;
deleteVertexArrays();
model()->destroyMeshCaches();
mesh_vertices = newVertices;
lines.clear();
lines = newLines;
// we need to recreate lines, triangles and tets
// that contain those new MEdgeVertices
for(std::list<GFace*>::iterator iFace = l_faces.begin();
iFace != l_faces.end(); ++iFace){
face2Vert[*iFace].insert(old2new.begin(),old2new.end());
// // for each face find correspondane face2Vertex
// std::map<GFace*, std::map<MVertex*, MVertex*,
// std::less<MVertex*> > >::iterator itmap = face2Vert.find(*iFace);
// if (itmap == face2Vert.end()) {
// face2Vert.insert(std::make_pair(*iFace, old2new));
// }
// else{
// std::map<MVertex*, MVertex*, std::less<MVertex*> > mapVert = itmap->second;
// for (std::map<MVertex*, MVertex*, std::less<MVertex*> >::iterator it =
// old2new.begin(); it != old2new.end(); it++)
// mapVert.insert(*it);
// itmap->second = mapVert;
// }
// do the same for regions
for ( int j = 0; j < (*iFace)->numRegions(); j++){
GRegion *r = (*iFace)->getRegion(j);
region2Vert[r].insert(old2new.begin(),old2new.end());
// std::map<GRegion*, std::map<MVertex*, MVertex*,
// std::less<MVertex*> > >::iterator itmap = region2Vert.find(r);
// if (itmap == region2Vert.end()) {
// region2Vert.insert(std::make_pair(r, old2new));
// }
// else{
// std::map<MVertex*, MVertex*, std::less<MVertex*> > mapVert = itmap->second;
// for (std::map<MVertex*, MVertex*, std::less<MVertex*> >::iterator it =
// old2new.begin(); it != old2new.end(); it++)
// mapVert.insert(*it);
// itmap->second = mapVert;
// }
}
}
}
void discreteEdge::parametrize(std::map<MVertex*, MVertex*>& old2new)
{
if (_pars.empty()){
for (unsigned int i = 0; i < lines.size() + 1; i++){
_pars.push_back(i);
}
}
std::vector<MVertex* > newVertices;
std::vector<MLine*> newLines;
MVertex *vL = getBeginVertex()->mesh_vertices[0];
int i = 0;
for(i = 0; i < (int)lines.size() - 1; i++){
MVertex *vR;
if (_orientation[i] == 1 ) vR = lines[i]->getVertex(1);
else vR = lines[i]->getVertex(0);
int param = i+1;
MVertex *vNEW = new MEdgeVertex(vR->x(),vR->y(),vR->z(), this,
param, -1., vR->getNum());
old2new.insert(std::make_pair(vR,vNEW));
newVertices.push_back(vNEW);
newLines.push_back(new MLine(vL, vNEW));
_orientation[i] = 1;
vL = vNEW;
}
MVertex *vR = getEndVertex()->mesh_vertices[0];
newLines.push_back(new MLine(vL, vR));
_orientation[i] = 1;
deleteVertexArrays();
model()->destroyMeshCaches();
mesh_vertices = newVertices;
lines.clear();
lines = newLines;
}
void discreteEdge::computeNormals () const
{
_normals.clear();
for (unsigned int i= 0; i < mesh_vertices.size(); i++)
_normals[mesh_vertices[i]] = SVector3(0.0,0.0,0.0);
_normals[getBeginVertex()->mesh_vertices[0]] = SVector3(0.0,0.0,0.0);
_normals[getBeginVertex()->mesh_vertices[0]] = SVector3(0.0,0.0,0.0);
double J[3][3];
for(std::list<GFace*>::const_iterator iFace = l_faces.begin();
iFace != l_faces.end(); ++iFace){
for (unsigned int i = 0; i < (*iFace)->triangles.size(); ++i){
MTriangle *t = (*iFace)->triangles[i];
for (int j = 0; j < 3; j++){
std::map<MVertex*, SVector3, std::less<MVertex*> >::iterator
itn = _normals.find(t->getVertex(j));
if (itn != _normals.end()){
t->getJacobian(0, 0, 0, J);
SVector3 d1(J[0][0], J[0][1], J[0][2]);
SVector3 d2(J[1][0], J[1][1], J[1][2]);
SVector3 n = crossprod(d1, d2);
n.normalize();
_normals[t->getVertex(j)] += n;
}
}
}
}
std::map<MVertex*,SVector3, std::less<MVertex*> >::iterator itn = _normals.begin();
for ( ; itn != _normals.end(); ++itn){
itn->second.normalize();
}
}
/// WE REWRITE WHAT FOLLOWS : THIS WAS WRONG (PAB -JFR)
bool discreteEdge::getLocalParameter(const double &t, int &iLine,
double &tLoc) const
{
for (iLine = 0; iLine < (int)discrete_lines.size(); iLine++){
double tmin = _pars[iLine];
double tmax = _pars[iLine+1];
if (t >= tmin && t <= tmax){
tLoc = (t-tmin)/(tmax-tmin);
return true;
}
}
return false;
}
GPoint discreteEdge::point(double par) const
{
double tLoc;
int iEdge;
if(!getLocalParameter(par, iEdge, tLoc)) return GPoint();
double x, y, z;
MVertex *vB = discrete_lines[iEdge]->getVertex(0);
MVertex *vE = discrete_lines[iEdge]->getVertex(1);
//linear Lagrange mesh
x = vB->x() + tLoc * (vE->x()- vB->x());
y = vB->y() + tLoc * (vE->y()- vB->y());
z = vB->z() + tLoc * (vE->z()- vB->z());
return GPoint(x,y,z,this,par);
}
SVector3 discreteEdge::firstDer(double par) const
{
double tLoc;
int iEdge;
if(!getLocalParameter(par, iEdge, tLoc)) return SVector3();
MVertex *vB = discrete_lines[iEdge]->getVertex(0);
MVertex *vE = discrete_lines[iEdge]->getVertex(1);
double dx, dy, dz;
// double dt = 1.0;
dx = (vE->x() - vB->x());// / dt;
dy = (vE->y() - vB->y());// / dt;
dz = (vE->z() - vB->z());// / dt;
SVector3 der(dx, dy, dz);
return der;
}
double discreteEdge::curvature(double par) const
{
double tLoc;
int iEdge;
if(!getLocalParameter(par, iEdge, tLoc)) return MAX_LC;
double c0, c1;
Curvature& curvature = Curvature::getInstance();
if( !Curvature::valueAlreadyComputed() ) {
Msg::Warning("Need to compute discrete curvature (in discreteEdge)");
Curvature::typeOfCurvature type = Curvature::RUSIN; //RUSIN; //RBF
curvature.computeCurvature(model(), type);
}
curvature.edgeNodalValues(lines[iEdge],c0, c1, 1);
double cv = (1-tLoc)*c0 + tLoc*c1;
return cv;
}
double discreteEdge::curvatures(const double par, SVector3 *dirMax, SVector3 *dirMin,
double *curvMax, double *curvMin) const
{
if (getCompound()){
return getCompound()->curvatures(par, dirMax, dirMin, curvMax, curvMin);
}
else{
Msg::Error("Cannot evaluate curvatures and curvature directions on discrete edge");
return false;
}
}
Range<double> discreteEdge::parBounds(int i) const
{
return Range<double>(0, (double)discrete_lines.size());
}
void discreteEdge::createGeometry()
{
if (discrete_lines.empty()){
createTopo();
// copy the mesh
for (unsigned int i = 0; i < mesh_vertices.size(); i++){
MEdgeVertex *v = new MEdgeVertex(mesh_vertices[i]->x(), mesh_vertices[i]->y(),
mesh_vertices[i]->z(), this, (double)(i+1));
v2v[mesh_vertices[i]] = v;
}
std::vector<MLine*> _temp;
for (unsigned int i = 0; i < lines.size(); i++){
MVertex *v0 = lines[i]->getVertex(0);
MVertex *v1 = lines[i]->getVertex(1);
MVertex *v00 = (v2v.find(v0) == v2v.end()) ? v0 : v2v[v0];
MVertex *v01 = (v2v.find(v1) == v2v.end()) ? v1 : v2v[v1];
if (_orientation[i] == 1){
discrete_lines.push_back(new MLine(v00,v01));
}
else{
lines[i]->setVertex(0, v1);
lines[i]->setVertex(1, v0);
_orientation[i] = 1;
discrete_lines.push_back(new MLine(v01,v00));
}
}
// compute parameters and recompute the vertices
_pars.push_back(0.0);
for (unsigned int i = 1; i < discrete_lines.size(); i++){
_pars.push_back((double)i);
MVertex *newv = discrete_lines[i]->getVertex(0);
discrete_vertices.push_back(newv);
}
_pars.push_back((double)discrete_lines.size());
}
}
MVertex * discreteEdge::getGeometricalVertex (MVertex *v)
{
std::map<MVertex*,MVertex*>::const_iterator it = v2v.find(v);
if (it == v2v.end()){
Msg::Error("fatality %ld %ld %ld", v2v.size(), mesh_vertices.size(),
discrete_vertices.size());
}
return it->second;
}
void discreteEdge::interpolateInGeometry(MVertex *v, MVertex **v1,
MVertex **v2, double &xi) const
{
double t;
if (v->onWhat() != this)Msg::Fatal("%s %d",__FILE__,__LINE__);
v->getParameter (0,t);
int i = (int) t;
MLine *l = discrete_lines [i];
*v1 = l->getVertex(0);
*v2 = l->getVertex(1);
xi = t - i;
}
void discreteEdge::mesh(bool verbose){
#if defined(HAVE_MESH)
if (!CTX::instance()->meshDiscrete) return;
/*
if(tag()==47 || tag() == 50 || tag() == 51 || tag() == 53 || tag() == 56){
for(unsigned int i =0; i<mesh_vertices.size(); i++){
double p;
mesh_vertices[i]->getParameter(0,p);
printf("%f\t",p);
}
printf("\n\n");
}
*/
meshGEdge mesher;
mesher(this);
#endif
}
void discreteEdge::writeGEO(FILE *fp)
{
if (getBeginVertex() && getEndVertex())
fprintf(fp, "Discrete Line(%d) = {%d,%d};\n", tag(),
getBeginVertex()->tag(), getEndVertex()->tag());
}