Forked from
gmsh / gmsh
12731 commits behind the upstream repository.
-
Emilie Marchandise authoredEmilie Marchandise authored
CenterlineField.cpp 35.65 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>.
//
// Contributor(s):
// Emilie Marchandise
//
#include "CenterlineField.h"
#include <vector>
#include <map>
#include <set>
#include <list>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include "OS.h"
#include "GModel.h"
#include "MElement.h"
#include "MTriangle.h"
#include "MVertex.h"
#include "MLine.h"
#include "GEntity.h"
#include "Field.h"
#include "GFace.h"
#include "discreteEdge.h"
#include "discreteFace.h"
#include "GEdgeCompound.h"
#include "GFaceCompound.h"
#include "meshGFace.h"
#include "meshGEdge.h"
#include "MQuadrangle.h"
#include "MElement.h"
#if defined(HAVE_ANN)
#include <ANN/ANN.h>
#include <algorithm>
void erase(std::vector<MLine*>& lines, MLine* l) {
std::vector<MLine*>::iterator it = std::remove(lines.begin(), lines.end(), l);
lines.erase(it, lines.end());
}
double computeLength(std::vector<MLine*> lines){
double length= 0.0;
for (int i = 0; i< lines.size(); i++){
length += lines[i]->getInnerRadius();
}
return length;
}
bool isClosed(std::set<MEdge, Less_Edge> &theCut){
std::multiset<MVertex*> boundV;
std::set<MEdge,Less_Edge>::iterator it = theCut.begin();
for (; it!= theCut.end(); it++){
boundV.insert(it->getVertex(0));
boundV.insert(it->getVertex(1));
}
std::multiset<MVertex*>::iterator itb = boundV.begin();
for ( ; itb != boundV.end(); ++itb){
if (boundV.count(*itb) != 2) {
return false;
}
}
return true;
// std::list<MEdge> segments;
// std::map<MVertex*, MEdge> boundv;
// std::set<MEdge,Less_Edge>::iterator it = theCut.begin();
// for (; it!= theCut.end(); it++){
// segments.push_back(*it);
// }
// // find a lonely MEdge
// for (std::list<MEdge>::iterator it = segments.begin();
// it != segments.end(); ++it){
// MVertex *vL = it->getVertex(0);
// MVertex *vR = it->getVertex(1);
// std::map<MVertex*,MEdge>::iterator it1 = boundv.find(vL);
// if (it1 == boundv.end()) boundv.insert(std::make_pair(vL,*it));
// else boundv.erase(it1);
// std::map<MVertex*,MEdge>::iterator it2 = boundv.find(vR);
// if (it2 == boundv.end()) boundv.insert(std::make_pair(vR,*it));
// else boundv.erase(it2);
// }
// if (boundv.size() == 0) return true;
// else return false;
}
void orderMLines(std::vector<MLine*> &lines, MVertex *vB, MVertex *vE){
std::vector<MLine*> _m;
std::list<MLine*> segments;
std::map<MVertex*, MLine*> boundv;
std::vector<int> _orientation;
// store all lines in a list : segments
for (unsigned int i = 0; i < lines.size(); i++){
segments.push_back(lines[i]);
}
// find a lonely 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
MVertex *v = (boundv.begin())->first;
if ( v == vB) firstLine = (boundv.begin())->second;
else{
MVertex *v = (boundv.rbegin())->first;
if (v == vB) firstLine = (boundv.rbegin())->second;
else{ Msg::Error("begin vertex not found for branch"); exit(1);}
}
for (std::list<MLine*>::iterator it = segments.begin();
it != segments.end(); ++it){
if (*it == firstLine){
segments.erase(it);
break;
}
}
}
else{
Msg::Error("line is wrong (it has %d end points)", 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("lines is wrong");
return;
}
}
}
//lines is now a list of ordered MLines
lines = _m;
//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];
}
// if (junctions.find(lines[0]->getVertex(0)) != junctions.end()) vB = lines[0]->getVertex(0);
// else if (junctions.find(lines[0]->getVertex(1)) != junctions.end()) vB = lines[0]->getVertex(1);
// else printf("no vB junc found %d %d \n", lines[0]->getVertex(0)->getNum(), lines[0]->getVertex(1)->getNum());
// if (junctions.find(lines[lines.size()-1]->getVertex(0)) != junctions.end()) vE = lines[lines.size()-1]->getVertex(0);
// else if (junctions.find(lines[lines.size()-1]->getVertex(1)) != junctions.end()) vE = lines[lines.size()-1]->getVertex(1);
// else printf("no vE junc found %d %d \n", lines[0]->getVertex(0)->getNum(), lines[0]->getVertex(1)->getNum());
// printf("in order vB= %d =%d \n", vB->getNum(), vE->getNum());
}
static void recurConnectByMEdge(const MEdge &e,
std::multimap<MEdge, MTriangle*, Less_Edge> &e2e,
std::set<MTriangle*> &group,
std::set<MEdge, Less_Edge> &touched,
std::set<MEdge, Less_Edge> &theCut)
{
if (touched.find(e) != touched.end()) return;
touched.insert(e);
for (std::multimap <MEdge, MTriangle*, Less_Edge>::iterator it = e2e.lower_bound(e);
it != e2e.upper_bound(e); ++it){
group.insert(it->second);
for (int i = 0; i < it->second->getNumEdges(); ++i){
MEdge me = it->second->getEdge(i);
if (theCut.find(me) != theCut.end()){
touched.insert(me); //break;
}
else recurConnectByMEdge(me, e2e, group, touched, theCut);
}
}
}
void cutTriangle(MTriangle *tri,
std::map<MEdge,MVertex*,Less_Edge> &cutEdges,
std::set<MVertex*> &cutVertices,
std::vector<MTriangle*> &newTris,
std::set<MEdge,Less_Edge> &newCut){
MVertex *c[3] = {0,0,0};
for (int j=0;j<3;j++){
MEdge ed = tri->getEdge(j);
std::map<MEdge,MVertex*,Less_Edge> :: iterator it = cutEdges.find(ed);
if (it != cutEdges.end()){
c[j] = it->second;
}
}
MVertex *old_v0 = tri->getVertex(0);
MVertex *old_v1 = tri->getVertex(1);
MVertex *old_v2 = tri->getVertex(2);
if (c[0] && c[1]){
newTris.push_back(new MTriangle (c[0],old_v1,c[1]));
newTris.push_back(new MTriangle (old_v0,c[0],old_v2));
newTris.push_back(new MTriangle (old_v2,c[0],c[1]));
newCut.insert(MEdge(c[0],c[1]));
}
else if (c[0] && c[2]){
newTris.push_back(new MTriangle (old_v0,c[0],c[2]));
newTris.push_back(new MTriangle (c[0],old_v1,old_v2));
newTris.push_back(new MTriangle (old_v2,c[2],c[0]));
newCut.insert(MEdge(c[0],c[2]));
}
else if (c[1] && c[2]){
newTris.push_back(new MTriangle (old_v2,c[2],c[1]));
newTris.push_back(new MTriangle (old_v0,old_v1,c[2]));
newTris.push_back(new MTriangle (c[2],old_v1,c[1]));
newCut.insert(MEdge(c[1],c[2]));
}
else if (c[0]){
newTris.push_back(new MTriangle (old_v0,c[0],old_v2));
newTris.push_back(new MTriangle (old_v2,c[0],old_v1));
if (cutVertices.find (old_v0) != cutVertices.end()){
newCut.insert(MEdge(c[0],old_v0));
}
else if (cutVertices.find (old_v1) != cutVertices.end()) {
newCut.insert(MEdge(c[0],old_v1));
}
else if (cutVertices.find (old_v2) != cutVertices.end()){
newCut.insert(MEdge(c[0],old_v2));
}
}
else if (c[1]){
newTris.push_back(new MTriangle (old_v1,c[1],old_v0));
newTris.push_back(new MTriangle (old_v0,c[1],old_v2));
if (cutVertices.find (old_v0) != cutVertices.end()){
newCut.insert(MEdge(c[1],old_v0));
}
else if (cutVertices.find (old_v1) != cutVertices.end()) {
newCut.insert(MEdge(old_v1, c[1]));
}
else if (cutVertices.find (old_v2) != cutVertices.end()){
newCut.insert(MEdge(c[1],old_v2));
}
}
else if (c[2]){
newTris.push_back(new MTriangle (old_v0,old_v1, c[2]));
newTris.push_back(new MTriangle (old_v1,old_v2, c[2]));
if (cutVertices.find (old_v0) != cutVertices.end()){
newCut.insert(MEdge(c[2],old_v0));
}
else if (cutVertices.find (old_v1) != cutVertices.end()) {
newCut.insert(MEdge(c[2], old_v1));
}
else if (cutVertices.find (old_v2) != cutVertices.end()){
newCut.insert(MEdge(c[2], old_v2));
}
}
else {
newTris.push_back(tri);
//newTris.push_back(new MTriangle (old_v0, old_v1,old_v2));
if (cutVertices.find (old_v0) != cutVertices.end() &&
cutVertices.find (old_v1) != cutVertices.end())
newCut.insert(MEdge(old_v0,old_v1));
else if (cutVertices.find (old_v1) != cutVertices.end() &&
cutVertices.find (old_v2) != cutVertices.end())
newCut.insert(MEdge(old_v1,old_v2));
else if (cutVertices.find (old_v2) != cutVertices.end() &&
cutVertices.find (old_v0) != cutVertices.end())
newCut.insert(MEdge(old_v2,old_v0));
}
}
Centerline::Centerline(std::string fileName): kdtree(0), nodes(0){
recombine = CTX::instance()->mesh.recombineAll;
index = new ANNidx[1];
dist = new ANNdist[1];
printf("centerline filename =%s \n", fileName.c_str());
importFile(fileName);
buildKdTree();
nbPoints = 25;
update_needed = false;
is_cut = false;
}
Centerline::Centerline(): kdtree(0), nodes(0){
index = new ANNidx[1];
dist = new ANNdist[1];
recombine = CTX::instance()->mesh.recombineAll;
fileName = "centerlines.vtk";//default
nbPoints = 25;
options["FileName"] = new FieldOptionString (fileName, "File name for the centerlines", &update_needed);
options["nbPoints"] = new FieldOptionInt(nbPoints, "Number of mesh elements in a circle");
callbacks["cutMesh"] = new FieldCallbackGeneric<Centerline>(this, &Centerline::cutMesh, "Cut the initial mesh in different mesh partitions using the centerlines \n");
is_cut = false;
}
Centerline::~Centerline(){
if (mod) delete mod;
if(kdtree) delete kdtree;
if(nodes) annDeallocPts(nodes);
delete[]index;
delete[]dist;
}
void Centerline::importFile(std::string fileName){
current = GModel::current();
std::vector<GFace*> currentFaces = current->bindingsGetFaces();
for (int i = 0; i < currentFaces.size(); i++){
GFace *gf = currentFaces[i];
if (gf->geomType() == GEntity::DiscreteSurface){
for(unsigned int j = 0; j < gf->triangles.size(); j++)
triangles.push_back(gf->triangles[j]);
gf->triangles.clear();
gf->deleteVertexArrays();
current->remove(gf);
}
}
if(triangles.empty()){
Msg::Error("Current GModel has no triangles ...");
exit(1);
}
mod = new GModel();
mod->load(fileName);
mod->removeDuplicateMeshVertices(1.e-8);
current->setAsCurrent();
int maxN = 0.0;
std::vector<GEdge*> modEdges = mod->bindingsGetEdges();
for (int i = 0; i < modEdges.size(); i++){
GEdge *ge = modEdges[i];
for(unsigned int j = 0; j < ge->lines.size(); j++){
MLine *l = ge->lines[j];
MVertex *v0 = l->getVertex(0);
MVertex *v1 = l->getVertex(1);
std::map<MVertex*, int>::iterator it0 = colorp.find(v0);
std::map<MVertex*, int>::iterator it1 = colorp.find(v1);
if (it0 == colorp.end() || it1 == colorp.end()){
lines.push_back(l);
colorl.insert(std::make_pair(l, ge->tag()));
maxN = std::max(maxN, ge->tag());
}
if (it0 == colorp.end()) colorp.insert(std::make_pair(v0, ge->tag()));
if (it1 == colorp.end()) colorp.insert(std::make_pair(v1, ge->tag()));
}
}
createBranches(maxN);
}
void Centerline::createBranches(int maxN){
//sort colored lines and create edges
std::vector<std::vector<MLine*> > color_edges;
color_edges.resize(maxN);
std::multiset<MVertex*> allV;
std::map<MLine*, int>::iterator itl = colorl.begin();
while (itl != colorl.end()){
int color = itl->second;
MLine* l = itl->first;
allV.insert(l->getVertex(0));
allV.insert(l->getVertex(1));
color_edges[color-1].push_back(l);
itl++;
}
//detect junctions
std::multiset<MVertex*>::iterator it = allV.begin();
for ( ; it != allV.end(); ++it){
if (allV.count(*it) != 2) {
junctions.insert(*it);
}
}
// printf("junctions =%d \n", junctions.size());
// std::set<MVertex*>::iterator itt = junctions.begin();
// for ( ; itt != junctions.end(); ++itt){
// MVertex *v = *itt;
// printf("JUNC = %d \n", v->getNum());
// }
//split edges
int tag = 0;
for(unsigned int i = 0; i < color_edges.size(); ++i){
std::vector<MLine*> lines = color_edges[i];
//printf("EDGE %d line = %d \n", lines.size());
while (!lines.empty()) {
std::vector<MLine*> myLines;
std::vector<MLine*>::iterator itl = lines.begin();
MVertex *vB = (*itl)->getVertex(0);
MVertex *vE = (*itl)->getVertex(1);
//printf("VB =%d vE = %d \n", vB->getNum(), vE->getNum());
myLines.push_back(*itl);
erase(lines, *itl);
itl = lines.begin();
while ( !( junctions.find(vE) != junctions.end() &&
junctions.find(vB) != junctions.end()) ) {
MVertex *v1 = (*itl)->getVertex(0);
MVertex *v2 = (*itl)->getVertex(1);
//printf("line %d, VB = %d vE = %d v1=%d v2=%d \n", (*itl)->getNum(), vB->getNum(), vE->getNum(), v1->getNum(), v2->getNum());
bool goVE = (junctions.find(vE) == junctions.end()) ? true : false ;
bool goVB = (junctions.find(vB) == junctions.end()) ? true : false;
if (v1 == vE && goVE){
myLines.push_back(*itl);
erase(lines, *itl);
itl = lines.begin();
vE = v2;
}
else if ( v2 == vE && goVE){
myLines.push_back(*itl);
erase(lines, *itl);
itl = lines.begin();
vE = v1;
}
else if ( v1 == vB && goVB){
myLines.push_back(*itl);
erase(lines, *itl);
itl = lines.begin();
vB = v2;
}
else if ( v2 == vB && goVB){
myLines.push_back(*itl);
erase(lines, *itl);
itl = lines.begin();
vB = v1;
}
else itl++;
}
if (vB == vE) { Msg::Error("Begin and end points branch are the same \n");break;}
orderMLines(myLines, vB, vE);
std::vector<Branch> children;
Branch newBranch ={ tag++, myLines, computeLength(myLines), vB, vE, children, 1.e6, 0.0};
//printf("branch = %d VB = %d VE %d \n", myLines.size(), vB->getNum(), vE->getNum());
edges.push_back(newBranch) ;
}
}
printf("in/outlets =%d branches =%d \n", (int)color_edges.size(), (int)edges.size());
//create children
for(unsigned int i = 0; i < edges.size(); ++i) {
MVertex *vE = edges[i].vE;
std::vector<Branch> myChildren;
for (std::vector<Branch>::iterator it = edges.begin(); it != edges.end(); ++it){
Branch myBranch = *it;
if (myBranch.vB == vE) myChildren.push_back(myBranch);
}
edges[i].children = myChildren;
}
//compute radius
distanceToLines();
computeRadii();
printSplit();
//print info
// for(unsigned int i = 0; i < edges.size(); ++i) {
// printf("EDGE =%d tag=%d length = %g childs = %d \n", i, edges[i].tag, edges[i].length, edges[i].children.size());
// for(unsigned int j = 0; j < edges[i].children.size(); ++j) {
// printf("children (%d) =%d \n", edges[i].children.size(), edges[i].children[j].tag);
// }
// }
// std::set<MVertex*>::iterator itj = junctions.begin();
// for ( ; itj != junctions.end(); ++itj){
// MVertex *v = *itj;
// printf("JUNC = %d \n", v->getNum());
// }
}
void Centerline::distanceToLines(){
Msg::Info("Centerline: computing distance to lines ");
//SOLUTION 1: REVERSE ANN TREE (SURFACE POINTS IN TREE)
ANNkd_tree *kdtreeR;
ANNpointArray nodesR;
ANNidxArray indexR = new ANNidx[1];
ANNdistArray distR = new ANNdist[1];
std::set<MVertex*> allVS;
for(int j = 0; j < triangles.size(); j++)
for(int k = 0; k<3; k++) allVS.insert(triangles[j]->getVertex(k));
int nbSNodes = allVS.size();
nodesR = annAllocPts(nbSNodes, 3);
int ind = 0;
std::set<MVertex*>::iterator itp = allVS.begin();
while (itp != allVS.end()){
MVertex *v = *itp;
nodesR[ind][0] = v->x();
nodesR[ind][1] = v->y();
nodesR[ind][2] = v->z();
itp++; ind++;
}
kdtreeR = new ANNkd_tree(nodesR, nbSNodes, 3);
for(unsigned int i = 0; i < lines.size(); i++){
MLine *l = lines[i];
MVertex *v1 = l->getVertex(0);
MVertex *v2 = l->getVertex(1);
double midp[3] = {0.5*(v1->x()+v2->x()), 0.5*(v1->y()+v1->y()),0.5*(v1->z()+v2->z())};
kdtreeR->annkSearch(midp, 1, indexR, distR);
double minRad = sqrt(distR[0]);
radiusl.insert(std::make_pair(lines[i], minRad));
}
delete kdtreeR;
annDeallocPts(nodesR);
delete[]indexR;
delete[]distR;
// //SOLUTION 2: DISTANCE TO LINES (QUITE SLOW)
// std::vector<SPoint3> pts;
// std::set<SPoint3> pts_set;
// std::vector<double> distances;
// std::vector<double> distancesE;
// std::vector<SPoint3> closePts;
// for(unsigned int i = 0; i < surfaces.size(); i++){
// for(int j = 0; j < surfaces[i]->getNumMeshElements(); j++){
// MElement *e = surfaces[i]->getMeshElement(j);
// for (int k = 0; k < e->getNumVertices(); k++){
// MVertex *v = e->getVertex(k);
// pts_set.insert(SPoint3(v->x(), v->y(),v->z()));
// }
// }
// }
// std::set<SPoint3>::iterator its = pts_set.begin();
// for (; its != pts_set.end(); its++){
// pts.push_back(*its);
// }
// if (pts.size() == 0) {Msg::Error("Centerline needs a GModel with a surface \n"); exit(1);}
// for(unsigned int i = 0; i < lines.size(); i++){
// std::vector<double> iDistances;
// std::vector<SPoint3> iClosePts;
// std::vector<double> iDistancesE;
// MLine *l = lines[i];
// MVertex *v1 = l->getVertex(0);
// MVertex *v2 = l->getVertex(1);
// SPoint3 p1(v1->x(), v1->y(), v1->z());
// SPoint3 p2(v2->x(), v2->y(), v2->z());
// signedDistancesPointsLine(iDistances, iClosePts, pts, p1,p2);
// double minRad = std::abs(iDistances[0]);
// for (unsigned int kk = 1; kk< pts.size(); kk++) {
// if (std::abs(iDistances[kk]) < minRad)
// minRad = std::abs(iDistances[kk]);
// }
// radiusl.insert(std::make_pair(lines[i], minRad));
// }
}
void Centerline::computeRadii(){
for(unsigned int i = 0; i < edges.size(); ++i) {
std::vector<MLine*> lines = edges[i].lines;
for(unsigned int j = 0; j < lines.size(); ++j) {
MLine *l = lines[j];
std::map<MLine*,double>::iterator itr = radiusl.find(l);
if (itr != radiusl.end()){
edges[i].minRad = std::min(itr->second, edges[i].minRad);
edges[i].maxRad = std::max(itr->second, edges[i].maxRad);
}
else printf("ARGG line not found \n");
}
}
}
void Centerline::buildKdTree(){
FILE * f = fopen("myPOINTS.pos","w");
fprintf(f, "View \"\"{\n");
int nbPL = 3; //10 points per line
//int nbNodes = (lines.size()+1) + (nbPL*lines.size());
int nbNodes = (colorp.size()) + (nbPL*lines.size());
nodes = annAllocPts(nbNodes, 3);
int ind = 0;
std::map<MVertex*, int>::iterator itp = colorp.begin();
while (itp != colorp.end()){
MVertex *v = itp->first;
nodes[ind][0] = v->x();
nodes[ind][1] = v->y();
nodes[ind][2] = v->z();
itp++; ind++;
}
for(unsigned int k = 0; k < lines.size(); ++k){
MVertex *v0 = lines[k]->getVertex(0);
MVertex *v1 = lines[k]->getVertex(1);
SVector3 P0(v0->x(),v0->y(), v0->z());
SVector3 P1(v1->x(),v1->y(), v1->z());
for (int j= 1; j < nbPL+1; j++){
double inc = (double)j/(double)(nbPL+1);
SVector3 Pj = P0+inc*(P1-P0);
nodes[ind][0] = Pj.x();
nodes[ind][1] = Pj.y();
nodes[ind][2] = Pj.z();
ind++;
}
}
kdtree = new ANNkd_tree(nodes, nbNodes, 3);
for(unsigned int i = 0; i < nbNodes; ++i){
fprintf(f, "SP(%g,%g,%g){%g};\n",
nodes[i][0], nodes[i][1],nodes[i][2],1.0);
}
fprintf(f,"};\n");
fclose(f);
}
void Centerline::createSplitCompounds(){
NV = current->getMaxElementaryNumber(0);
NE = current->getMaxElementaryNumber(1);
NF = current->getMaxElementaryNumber(2);
// Remesh new faces (Compound Lines and Compound Surfaces)
Msg::Info("*** Starting parametrize compounds:");
double t0 = Cpu();
//Parametrize Compound Lines
for (int i=0; i < NE; i++){
std::vector<GEdge*>e_compound;
GEdge *pe = current->getEdgeByTag(i+1);//current edge
e_compound.push_back(pe);
int num_gec = NE+i+1;
Msg::Info("Parametrize Compound Line (%d) = %d discrete edge",
num_gec, pe->tag());
GEdgeCompound *gec = new GEdgeCompound(current, num_gec, e_compound);
current->add(gec);
//gec->parametrize();
}
// Parametrize Compound surfaces
std::list<GEdge*> U0;
for (int i=0; i < NF; i++){
std::list<GFace*> f_compound;
GFace *pf = current->getFaceByTag(i+1);//current face
f_compound.push_back(pf);
int num_gfc = NF+i+1;
Msg::Info("Parametrize Compound Surface (%d) = %d discrete face",
num_gfc, pf->tag());
GFaceCompound::typeOfMapping typ = GFaceCompound::CONFORMAL;
GFaceCompound *gfc = new GFaceCompound(current, num_gfc, f_compound, U0,
typ, 0);
gfc->meshAttributes.recombine = recombine;
gfc->addPhysicalEntity(i+1);
current->add(gfc);
//gfc->parametrize();
// for(unsigned int j = 0; j < pf->triangles.size(); ++j){
// MTriangle *t = pf->triangles[j];
// for(int k = 0; k < 3; k++){
// MVertex *v = t->getVertex(k);
// v->setEntity(pf);
// }
//}
}
}
void Centerline::cleanMesh(){
for (int i=0; i < NF; i++){
std::ostringstream oss;
oss << "new" << NF+i+1 ;
std::string name = oss.str();
current->setPhysicalName(name, 2, i+1);
}
Msg::Info("Writing new splitted mesh mySPLITMESH.msh");
current->writeMSH("mySPLITMESH.msh", 2.2, false, false);
if (!is_cut) return;
std::set<MVertex*> allNod;
std::list<GEdge*> U0;
discreteFace * mySplitMesh;
mySplitMesh= new discreteFace(current, 2*NF+1);
current->add(mySplitMesh);
for (int i=0; i < NF; i++){
GFace *gfc = current->getFaceByTag(NF+i+1);
for(unsigned int j = 0; j < gfc->triangles.size(); ++j){
MTriangle *t = gfc->triangles[j];
std::vector<MVertex *> v(3);
for(int k = 0; k < 3; k++){
v[k] = t->getVertex(k);
allNod.insert(v[k]);
}
mySplitMesh->triangles.push_back(new MTriangle(v[0], v[1], v[2]));
}
for(unsigned int j = 0; j < gfc->quadrangles.size(); ++j){
MQuadrangle *q = gfc->quadrangles[j];
std::vector<MVertex *> v(4);
for(int k = 0; k < 4; k++){
v[k] = q->getVertex(k);
allNod.insert(v[k]);
}
mySplitMesh->quadrangles.push_back(new MQuadrangle(v[0], v[1], v[2], v[3]));
}
}
//Removing discrete Vertices - Edges - Faces
for (int i=0; i < NV; i++){
GVertex *gv = current->getVertexByTag(i+1);
current->remove(gv);
}
for (int i=0; i < NE; i++){
GEdge *ge = current->getEdgeByTag(i+1);
GEdge *gec = current->getEdgeByTag(NE+i+1);
current->remove(ge);
current->remove(gec);
}
for (int i=0; i < NF; i++){
GFace *gf = current->getFaceByTag(i+1);
GFace *gfc = current->getFaceByTag(NF+i+1);
current->remove(gf);
current->remove(gfc);
}
//Put new mesh in a new discreteFace
for(std::set<MVertex*>::iterator it = allNod.begin(); it != allNod.end(); ++it)
mySplitMesh->mesh_vertices.push_back(*it);
mySplitMesh->meshStatistics.status = GFace::DONE;
current->createTopologyFromMesh();
}
void Centerline::createFaces(){
std::vector<std::vector<MTriangle*> > faces;
std::multimap<MEdge, MTriangle*, Less_Edge> e2e;
for(unsigned int i = 0; i < triangles.size(); ++i)
for(int j = 0; j < 3; j++)
e2e.insert(std::make_pair(triangles[i]->getEdge(j), triangles[i]));
int iGroup = 0;
while(!e2e.empty()){
std::set<MTriangle*> group;
std::set<MEdge, Less_Edge> touched;
group.clear();
touched.clear();
std::multimap<MEdge, MTriangle*, Less_Edge>::iterator ite = e2e.begin();
MEdge me = ite->first;
while (theCut.find(me) != theCut.end()){
ite++;
me = ite->first;
}
recurConnectByMEdge(me,e2e, group, touched, theCut);
std::vector<MTriangle*> temp;
temp.insert(temp.begin(), group.begin(), group.end());
faces.push_back(temp);
for(std::set<MEdge, Less_Edge>::iterator it = touched.begin();
it != touched.end(); ++it)
e2e.erase(*it);
}
printf("%d faces created \n", (int)faces.size());
//create discFaces
int numBef = current->getMaxElementaryNumber(2) + 1;
for(unsigned int i = 0; i < faces.size(); ++i){
int numF = current->getMaxElementaryNumber(2) + 1;
discreteFace *f = new discreteFace(current, numF);
current->add(f);
discFaces.push_back(f);
std::set<MVertex*> myVertices;
std::vector<MTriangle*> myFace = faces[i];
for(int j= 0; j< myFace.size(); j++){
MTriangle *t = myFace[j];
f->triangles.push_back(t);
for (int k= 0; k< 3; k++){
MVertex *v = t->getVertex(k);
myVertices.insert(v);
v->setEntity(f);
}
}
f->mesh_vertices.insert(f->mesh_vertices.begin(),
myVertices.begin(), myVertices.end());
}
}
void Centerline::cutMesh(){
is_cut = true;
if (update_needed){
std::ifstream input;
input.open(fileName.c_str());
if(StatFile(fileName)) Msg::Fatal("Centerline file '%s' does not exist", fileName.c_str());
importFile(fileName);
buildKdTree();
update_needed = false;
}
// std::vector<GFace*> currentFaces = current->bindingsGetFaces();
// for (int i=0; i< currentFaces.size(); i++){
// printf("gf =%d \n", currentFaces[i]->tag());
// if(currentFaces[i]->geomType() == GEntity::CompoundSurface) {
// std::list<GFace*> cFaces = ((GFaceCompound*)currentFaces[i])->getCompounds();
// for (std::list<GFace*>::iterator it = cFaces.begin(); it!= cFaces.end(); it++) {
// printf("comp = %d\n", (*it)->tag());
// }
// if (cFaces.size() > 0) currentGFC.push_back(currentFaces[i]);
// }
// }
Msg::Info("Splitting surface mesh (%d tris) with centerline %s ", triangles.size(), fileName.c_str());
//splitMesh
for(unsigned int i = 0; i < edges.size(); i++){
std::vector<MLine*> lines = edges[i].lines;
double L = edges[i].length;
double R = edges[i].minRad;
double AR = L/R;
printf("*** branch =%d \n", i, AR);
if( AR > 4.5){
int nbSplit = (int)ceil(AR/4.0);
double li = L/nbSplit;
double lc = 0.0;
for (int j= 0; j < lines.size(); j++){
lc += lines[j]->getInnerRadius();
if (lc > li && nbSplit > 1) {
MVertex *v1 = lines[j]->getVertex(0);
MVertex *v2 = lines[j]->getVertex(1);
SVector3 pt(v1->x(), v1->y(), v1->z());
SVector3 dir(v2->x()-v1->x(),v2->y()-v1->y(),v2->z()-v1->z());
printf("-> cut length (AR=%g) split %d\n", AR, nbSplit);
cutByDisk(pt, dir, edges[i].maxRad);
nbSplit--;
lc = 0.0;
}
}
}
if(edges[i].children.size() > 0.0 && AR > 1.5){
MVertex *v1 = lines[lines.size()-1]->getVertex(1);//end vertex
MVertex *v2;
if(L/R < 2.0) v2 = lines[0]->getVertex(0);
else if (lines.size() > 4) v2 = lines[lines.size()-4]->getVertex(0);
else v2 = lines[lines.size()-1]->getVertex(0);
SVector3 pt(v1->x(), v1->y(), v1->z());
SVector3 dir(v2->x()-v1->x(),v2->y()-v1->y(),v2->z()-v1->z());
printf("-->> cut bifurcation \n");
cutByDisk(pt, dir, edges[i].maxRad);
}
}
//create discreteFaces
createFaces();
current->createTopologyFromFaces(discFaces);
//write
Msg::Info("Writing splitted mesh 'myPARTS.msh'");
current->writeMSH("myPARTS.msh", 2.2, false, true);
//create compounds
createSplitCompounds();
Msg::Info("Splitting mesh by centerlines done ");
}
void Centerline::cutByDisk(SVector3 &PT, SVector3 &NORM, double &maxRad){
double a = NORM.x();
double b = NORM.y();
double c = NORM.z();
double d = -a * PT.x() - b * PT.y() - c * PT.z();
printf("cut disk (R=%g)= %g %g %g %g \n", maxRad, a, b, c, d);
const double EPS = 0.007;
std::set<MEdge,Less_Edge> allEdges;
for(unsigned int i = 0; i < triangles.size(); i++)
for ( unsigned int j= 0; j < 3; j++)
allEdges.insert(triangles[i]->getEdge(j));
bool closedCut = false;
int step = 0;
while (!closedCut && step < 10){
double rad = 1.2*maxRad+0.1*step*maxRad;
std::map<MEdge,MVertex*,Less_Edge> cutEdges;
std::set<MVertex*> cutVertices;
std::vector<MTriangle*> newTris;
std::set<MEdge,Less_Edge> newCut;
cutEdges.clear();
cutVertices.clear();
newTris.clear();
newCut.clear();
for (std::set<MEdge,Less_Edge>::iterator it = allEdges.begin();
it != allEdges.end() ; ++it){
MEdge me = *it;
SVector3 P1(me.getVertex(0)->x(),me.getVertex(0)->y(), me.getVertex(0)->z());
SVector3 P2(me.getVertex(1)->x(),me.getVertex(1)->y(), me.getVertex(1)->z());
double V1 = a * P1.x() + b * P1.y() + c * P1.z() + d;
double V2 = a * P2.x() + b * P2.y() + c * P2.z() + d;
bool inters = (V1*V2<=0.0) ? true: false;
bool inDisk = ((norm(P1-PT) < rad ) || (norm(P2-PT) < rad)) ? true : false;
double rdist = -V1/(V2-V1);
if (inters && rdist > EPS && rdist < 1.-EPS){
SVector3 PZ = P1+rdist*(P2-P1);
MVertex *newv = new MVertex (PZ.x(), PZ.y(), PZ.z());
if (inDisk) cutEdges.insert(std::make_pair(*it,newv));
}
else if (inters && rdist <= EPS && inDisk )
cutVertices.insert(me.getVertex(0));
else if (inters && rdist >= 1.-EPS && inDisk)
cutVertices.insert(me.getVertex(1));
}
for(unsigned int i = 0; i < triangles.size(); i++){
cutTriangle(triangles[i], cutEdges,cutVertices, newTris, newCut);
}
if (isClosed(newCut)) {
triangles.clear();
triangles = newTris;
theCut.insert(newCut.begin(),newCut.end());
//if (step > 1) printf("YOUPIIIIIIIIIIIIIIIIIIIIIII \n");
break;
}
else {
if (step ==19) {printf("no closed cut %d \n", (int)newCut.size()); };
step++;
// // triangles = newTris;
// // theCut.insert(newCut.begin(),newCut.end());
// char name[256];
// sprintf(name, "myCUT-%d.pos", step);
// FILE * f2 = fopen(name,"w");
// fprintf(f2, "View \"\"{\n");
// std::set<MEdge,Less_Edge>::iterator itp = newCut.begin();
// while (itp != newCut.end()){
// MEdge l = *itp;
// fprintf(f2, "SL(%g,%g,%g,%g,%g,%g){%g,%g};\n",
// l.getVertex(0)->x(), l.getVertex(0)->y(), l.getVertex(0)->z(),
// l.getVertex(1)->x(), l.getVertex(1)->y(), l.getVertex(1)->z(),
// 1.0,1.0);
// itp++;
// }
// fprintf(f2,"};\n");
// fclose(f2);
}
}
return;
}
double Centerline::operator() (double x, double y, double z, GEntity *ge){
if (update_needed){
std::ifstream input;
input.open(fileName.c_str());
if(StatFile(fileName)) Msg::Fatal("Centerline file '%s' does not exist", fileName.c_str());
importFile(fileName);
buildKdTree();
update_needed = false;
}
double xyz[3] = {x,y,z };
int num_neighbours = 1;
kdtree->annkSearch(xyz, num_neighbours, index, dist);
double d = sqrt(dist[0]);
double lc = 2*M_PI*d/nbPoints;
return lc;
}
void Centerline::operator() (double x, double y, double z, SMetric3 &metr, GEntity *ge){
//printf("in operator metric xyz centerline \n");
if (update_needed){
std::ifstream input;
input.open(fileName.c_str());
if(StatFile(fileName)) Msg::Fatal("Centerline file '%s' does not exist", fileName.c_str());
importFile(fileName);
buildKdTree();
update_needed = false;
}
//double lc = operator()(x,y,z,ge);
//metr = SMetric3(1./(lc*lc));
double xyz[3] = {x,y,z };
ANNidxArray index2 = new ANNidx[2];
ANNdistArray dist2 = new ANNdist[2];
int num_neighbours = 2;
kdtree->annkSearch(xyz, num_neighbours, index2, dist2);
double d = sqrt(dist2[0]);
double lc = 2*M_PI*d/nbPoints;
SVector3 p0(nodes[index2[0]][0], nodes[index2[0]][1], nodes[index2[0]][2]);
SVector3 p1(nodes[index2[1]][0], nodes[index2[1]][1], nodes[index2[1]][2]);
SVector3 dir = p1-p0;
dir.normalize();
SVector3 dir1, dir2;
if (dir[1]!=0.0 && dir[2]!=0.0){
dir1 = SVector3(1.0, 0.0, -dir[0]/dir[2]);
dir2 = SVector3 (dir[0]/dir[2], -(dir[0]*dir[0]+dir[2]*dir[2])/(dir[1]*dir[2]), 1.0);
}
else if (dir[0]!=0.0 && dir[2]!=0.0){
dir1 = SVector3(-dir[1]/dir[0], 1.0, 0.0);
dir2 = SVector3(1.0, dir[1]/dir[0], -(dir[1]*dir[1]+dir[0]*dir[0])/(dir[0]*dir[2]));
}
else if (dir[0]!=0.0 && dir[1]!=0.0){
dir1 = SVector3(0.0, -dir[2]/dir[1], 1.0);
dir2 = SVector3(-(dir[1]*dir[1]+dir[2]*dir[2])/(dir[0]*dir[1]), 1.0, dir[2]/dir[1]);
}
else if (dir[0]==0.0 && dir[1]==0.0){
dir1 = SVector3(0.0, 1.0, 0.0);
dir2 = SVector3(1.0, 0.0, 0.0);
}
else if (dir[1]==0.0 && dir[2]==0.0){
dir1 = SVector3(0.0, 1.0, 0.0);
dir2 = SVector3(0.0, 0.0, 1.0);
}
else if (dir[0]==0.0 && dir[2]==0.0){
dir1 = SVector3(1.0, 0.0, 0.0);
dir2 = SVector3(0.0, 0.0, 1.0);
}
else {printf("ARGHH EMI DO STHG \n"); exit(1);}
// printf("XYZ =%g %g %g r=%g dir0 = %g %g %g dir1 = %g %g %g dir2 =%g %g %g\n",
// x,y,z,d, dir[0], dir[1], dir[2], dir1[0], dir1[1], dir1[2], dir2[0], dir2[1], dir2[2] );
// printf("0x1 =%g 1x2=%g 2x1=%g \n", dot(dir, dir1), dot(dir1,dir2), dot(dir2,dir));
dir1.normalize();
dir2.normalize();
//dir = SVector3(1.0, 0.0, 0.0);
//dir1 = SVector3(0.0, 1.0, 0.0);
//dir2 = SVector3(0.0, 0.0, 1.0);
double lcA = 4.*lc;
double lam1 = 1./(lcA*lcA);
double lam2 = 1./(lc*lc);
metr = SMetric3(lam1,lam2,lam2, dir, dir1, dir2);
delete[]index2;
delete[]dist2;
return;
}
void Centerline::printSplit() const{
FILE * f = fopen("mySPLIT.pos","w");
fprintf(f, "View \"\"{\n");
for(unsigned int i = 0; i < edges.size(); ++i){
std::vector<MLine*> lines = edges[i].lines;
for(unsigned int k = 0; k < lines.size(); ++k){
MLine *l = lines[k];
fprintf(f, "SL(%g,%g,%g,%g,%g,%g){%g,%g};\n",
l->getVertex(0)->x(), l->getVertex(0)->y(), l->getVertex(0)->z(),
l->getVertex(1)->x(), l->getVertex(1)->y(), l->getVertex(1)->z(),
(double)i, (double)i);
}
}
fprintf(f,"};\n");
fclose(f);
// FILE * f3 = fopen("myJUNCTIONS.pos","w");
// fprintf(f3, "View \"\"{\n");
// std::set<MVertex*>::const_iterator itj = junctions.begin();
// while (itj != junctions.end()){
// MVertex *v = *itj;
// fprintf(f3, "SP(%g,%g,%g){%g};\n",
// v->x(), v->y(), v->z(),
// (double)v->getNum());
// itj++;
// }
// fprintf(f3,"};\n");
// fclose(f3);
FILE * f4 = fopen("myRADII.pos","w");
fprintf(f4, "View \"\"{\n");
for(unsigned int i = 0; i < lines.size(); ++i){
MLine *l = lines[i];
std::map<MLine*,double>::const_iterator itc = radiusl.find(l);
fprintf(f4, "SL(%g,%g,%g,%g,%g,%g){%g,%g};\n",
l->getVertex(0)->x(), l->getVertex(0)->y(), l->getVertex(0)->z(),
l->getVertex(1)->x(), l->getVertex(1)->y(), l->getVertex(1)->z(),
itc->second,itc->second);
}
fprintf(f4,"};\n");
fclose(f4);
}
#endif