diff --git a/Common/Context.h b/Common/Context.h index 311baab94c0294dbad11bb8edc9f2350a1935d6d..01c9db6a97e191ca5c2ef8510414cb00b4a528ab 100644 --- a/Common/Context.h +++ b/Common/Context.h @@ -156,7 +156,7 @@ class CTX { double normals, tangents, scalingFactor; int autoCoherence, highlightOrphans, clip, useTransform; double tolerance, snap[3], transform[3][3], offset[3]; - int occFixSmallEdges, occFixSmallFaces, occSewFaces; + int occFixSmallEdges, occFixSmallFaces, occSewFaces, occConnectFaces; int copyMeshingMethod, exactExtrusion; } geom; // mesh options diff --git a/Common/DefaultOptions.h b/Common/DefaultOptions.h index e281ebcd544e36a7b366f6f26ca7826f426131dd..30d0197e0e2596560f03458867c79980e743fd67 100644 --- a/Common/DefaultOptions.h +++ b/Common/DefaultOptions.h @@ -840,6 +840,8 @@ StringXNumber GeometryOptions_Number[] = { "Fix small faces in STEP, IGES and BRep models" }, { F|O, "OCCSewFaces" , opt_geometry_occ_sew_faces , 0. , "Sew faces in STEP, IGES and BRep models" }, + { F|O, "OCCConnectFaces" , opt_geometry_occ_connect_faces , 0. , + "Cut and connect faces in STEP, IGES and BRep models" }, { F, "OffsetX" , opt_geometry_offset0 , 0. , "Model diplay offset along X-axis (in model coordinates)" }, { F, "OffsetY" , opt_geometry_offset1 , 0. , diff --git a/Common/Options.cpp b/Common/Options.cpp index 1ba582792f5fd1db80cc01903dd7c7efcbfe9080..111e90add395ba9d1fe6313e3e5a66755be0e7d3 100644 --- a/Common/Options.cpp +++ b/Common/Options.cpp @@ -4588,6 +4588,19 @@ double opt_geometry_occ_sew_faces(OPT_ARGS_NUM) return CTX::instance()->geom.occSewFaces; } +double opt_geometry_occ_connect_faces(OPT_ARGS_NUM) +{ + if(action & GMSH_SET) + CTX::instance()->geom.occConnectFaces = val ? 1 : 0; +#if defined(HAVE_FLTK) + if(GUI::available() && (action & GMSH_GUI)) { + GUI::instance()->options->geo.butt[15]->value + (CTX::instance()->geom.occConnectFaces); + } +#endif + return CTX::instance()->geom.occConnectFaces; +} + double opt_geometry_old_circle(OPT_ARGS_NUM) { if(action & GMSH_SET) diff --git a/Common/Options.h b/Common/Options.h index 335b7ade4d518e8fe7b1e4d6081c81266972fbca..90a76826a7a926f5ab08db6d9e69ac25aa77905e 100644 --- a/Common/Options.h +++ b/Common/Options.h @@ -422,6 +422,7 @@ double opt_geometry_light_two_side(OPT_ARGS_NUM); double opt_geometry_occ_fix_small_edges(OPT_ARGS_NUM); double opt_geometry_occ_fix_small_faces(OPT_ARGS_NUM); double opt_geometry_occ_sew_faces(OPT_ARGS_NUM); +double opt_geometry_occ_connect_faces(OPT_ARGS_NUM); double opt_geometry_old_circle(OPT_ARGS_NUM); double opt_geometry_old_newreg(OPT_ARGS_NUM); double opt_geometry_num_sub_edges(OPT_ARGS_NUM); diff --git a/Fltk/optionWindow.cpp b/Fltk/optionWindow.cpp index 288e2f89b0c88bacbda88da664f0056989b6db42..1903b5c5f12da9c197d2fdb63fc8f3b32d196a91 100644 --- a/Fltk/optionWindow.cpp +++ b/Fltk/optionWindow.cpp @@ -351,6 +351,7 @@ static void geometry_options_ok_cb(Fl_Widget *w, void *data) opt_geometry_occ_fix_small_faces(0, GMSH_SET, o->geo.butt[12]->value()); opt_geometry_occ_sew_faces(0, GMSH_SET, o->geo.butt[13]->value()); opt_geometry_light_two_side(0, GMSH_SET, o->geo.butt[14]->value()); + opt_geometry_occ_connect_faces(0, GMSH_SET, o->geo.butt[15]->value()); opt_geometry_normals(0, GMSH_SET, o->geo.value[0]->value()); opt_geometry_tangents(0, GMSH_SET, o->geo.value[1]->value()); @@ -1627,11 +1628,16 @@ optionWindow::optionWindow(int deltaFontSize) (L + 2 * WB, 2 * WB + 5 * BH, BW, BH, "Sew faces in OpenCascade models"); geo.butt[13]->type(FL_TOGGLE_BUTTON); geo.butt[13]->callback(geometry_options_ok_cb); + geo.butt[15] = new Fl_Check_Button + (L + 2 * WB, 2 * WB + 6 * BH, BW, BH, "Cut and merge faces in OpenCascade models"); + geo.butt[15]->type(FL_TOGGLE_BUTTON); + geo.butt[15]->callback(geometry_options_ok_cb); #if !defined(HAVE_OCC) geo.butt[11]->deactivate(); geo.butt[12]->deactivate(); geo.butt[13]->deactivate(); + geo.butt[15]->deactivate(); #endif o->end(); } diff --git a/Fltk/visibilityWindow.cpp b/Fltk/visibilityWindow.cpp index 3237de1c9c7843b8046dc66673dba33672914f58..d656458eb54afc7c28f3a946e887661cee84addb 100644 --- a/Fltk/visibilityWindow.cpp +++ b/Fltk/visibilityWindow.cpp @@ -619,6 +619,7 @@ static void _recur_update_selected(Flu_Tree_Browser::Node *n) static void visibility_tree_apply_cb(Fl_Widget *w, void *data) { + CTX::instance()->mesh.changed |= (ENT_LINE | ENT_SURFACE | ENT_VOLUME); bool recursive = GUI::instance()->visibility->butt[0]->value() ? true : false; Flu_Tree_Browser::Node *root = GUI::instance()->visibility->tree->first(); for(int i = 0; i < root->children(); i++){ diff --git a/Geo/GModel.cpp b/Geo/GModel.cpp index 8c161bc9dee772ba2d06472f17756c884f84689c..73c6391b84a2aafaff8f58d960c51822c418fb5a 100644 --- a/Geo/GModel.cpp +++ b/Geo/GModel.cpp @@ -588,22 +588,10 @@ int GModel::indexMeshVertices(bool all) // renumber all the mesh vertices tagged with 0 int numVertices = 0; for(unsigned int i = 0; i < entities.size(); i++) - for(unsigned int j = 0; j < entities[i]->mesh_vertices.size(); j++){ - //printf("-->entity with %d elems and index %d and mesh_vertices=%d \n ", entities[i]->getNumMeshElements(), entities[i]->mesh_vertices[j]->getIndex(), entities[i]->mesh_vertices.size()); - if(!entities[i]->mesh_vertices[j]->getIndex()){ - int newIndex= ++numVertices; - entities[i]->mesh_vertices[j]->setIndex(newIndex); - //printf("-->entity with %d elems with index=%d\n ", entities[i]->getNumMeshElements(), newIndex); - } - } + for(unsigned int j = 0; j < entities[i]->mesh_vertices.size(); j++) + if(!entities[i]->mesh_vertices[j]->getIndex()) + entities[i]->mesh_vertices[j]->setIndex(++numVertices); -// printf("numvertices=%d \n", numVertices); -// for(unsigned int i = 0; i < entities.size(); i++) -// for(unsigned int j = 0; j < entities[i]->getNumMeshElements(); j++) -// for(int k = 0; k < entities[i]->getMeshElement(j)->getNumVertices(); k++) -// printf("entity with =%d elems, and mesh_vertices =%d index=%d \n", entities[i]->getNumMeshElements(), entities[i]->mesh_vertices.size(), entities[i]->getMeshElement(j)->getVertex(k)->getIndex()); -// exit(1); - return numVertices; } diff --git a/Geo/GModelIO_OCC.cpp b/Geo/GModelIO_OCC.cpp index 5638af5c2645f612c24cc8389caf8e398addfb95..3d59f8aff1b5ad258479d5d8dd78d04f6165948d 100644 --- a/Geo/GModelIO_OCC.cpp +++ b/Geo/GModelIO_OCC.cpp @@ -13,6 +13,7 @@ #include "OCCRegion.h" #include "MElement.h" #include "OpenFile.h" +#include "OCC_Connect.h" #if defined(HAVE_OCC_MESH_CONSTRAINTS) #include "MeshGmsh_Constrain.hxx" @@ -182,7 +183,7 @@ void OCC_Internals::buildLists() void OCC_Internals::healGeometry(double tolerance, bool fixsmalledges, bool fixspotstripfaces, bool sewfaces, - bool makesolids) + bool makesolids, bool connect) { int nrc = 0, nrcs = 0; TopExp_Explorer e; @@ -339,6 +340,14 @@ void OCC_Internals::healGeometry(double tolerance, bool fixsmalledges, Msg::Info(" not possible"); } } + + if(connect) { + OCC_Connect connect; + for(TopExp_Explorer p(shape,TopAbs_SOLID); p.More(); p.Next()) + connect.Add(p.Current()); + connect.Connect(); + shape=connect; + } } void OCC_Internals::loadBREP(const char *fn) @@ -349,7 +358,9 @@ void OCC_Internals::loadBREP(const char *fn) healGeometry(CTX::instance()->geom.tolerance, CTX::instance()->geom.occFixSmallEdges, CTX::instance()->geom.occFixSmallFaces, - CTX::instance()->geom.occSewFaces); + CTX::instance()->geom.occSewFaces, + false, + CTX::instance()->geom.occConnectFaces); BRepTools::Clean(shape); buildLists(); } @@ -365,7 +376,9 @@ void OCC_Internals::loadSTEP(const char *fn) healGeometry(CTX::instance()->geom.tolerance, CTX::instance()->geom.occFixSmallEdges, CTX::instance()->geom.occFixSmallFaces, - CTX::instance()->geom.occSewFaces); + CTX::instance()->geom.occSewFaces, + false, + CTX::instance()->geom.occConnectFaces); BRepTools::Clean(shape); buildLists(); } @@ -381,7 +394,9 @@ void OCC_Internals::loadIGES(const char *fn) healGeometry(CTX::instance()->geom.tolerance, CTX::instance()->geom.occFixSmallEdges, CTX::instance()->geom.occFixSmallFaces, - CTX::instance()->geom.occSewFaces); + CTX::instance()->geom.occSewFaces, + false, + CTX::instance()->geom.occConnectFaces); BRepTools::Clean(shape); buildLists(); } diff --git a/Geo/GModelIO_OCC.h b/Geo/GModelIO_OCC.h index 86febd7bf08497945756141607b40e32e97d266d..b373bceb999d16dc5531bb30066fb5c227743f8b 100644 --- a/Geo/GModelIO_OCC.h +++ b/Geo/GModelIO_OCC.h @@ -36,7 +36,7 @@ class OCC_Internals { } void healGeometry(double tolerance, bool fixsmalledges, bool fixspotstripfaces, bool sewfaces, - bool makesolids=false); + bool makesolids=false, bool connect=false); void loadBREP(const char *); void loadSTEP(const char *); void loadIGES(const char *); diff --git a/Geo/Makefile b/Geo/Makefile index 783f0a009850048e8a71255bb461f05e1bfca02d..043e10073f05ffc124f07c5e76c444750e66a081 100644 --- a/Geo/Makefile +++ b/Geo/Makefile @@ -26,6 +26,7 @@ SRC = GEntity.cpp\ GModelIO_Geo.cpp\ GModelIO_Mesh.cpp\ GModelIO_OCC.cpp\ + OCC_Connect.cpp\ GModelIO_Fourier.cpp\ GModelIO_CGNS.cpp\ GModelIO_MED.cpp\ diff --git a/Geo/OCC_Connect.cpp b/Geo/OCC_Connect.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6a3612b97df166ac0a2bc44a66203e32180dc342 --- /dev/null +++ b/Geo/OCC_Connect.cpp @@ -0,0 +1,1063 @@ +// Gmsh - Copyright (C) 1997-2009 C. Geuzaine, J.-F. Remacle +// +// See the LICENSE.txt file for license information. Please report all +// bugs and problems to <gmsh@geuz.org>. +// +// Contributed by Mark van Doesburg, Technolution B.V. + +#include "OCC_Connect.h" + +#include <vector> +#include <list> +#include <deque> +#include <iostream> +#include <iterator> + +#if defined(HAVE_OCC) + +#include <TopoDS.hxx> +#include <TopoDS_Vertex.hxx> +#include <TopoDS_Solid.hxx> +#include <TopoDS_Compound.hxx> + +#include <TopExp.hxx> +#include <TopExp_Explorer.hxx> +#include <TopOpeBRep_Point2d.hxx> +#include <TopOpeBRep_ShapeIntersector.hxx> +#include <TopTools.hxx> + +#include <BRepTools.hxx> +#include <BRepTools_ReShape.hxx> +#include <BRepTools_WireExplorer.hxx> +#include <BRepBuilderAPI_MakeVertex.hxx> +#include <BRepBuilderAPI_MakeWire.hxx> +#include <BRepExtrema_ExtCC.hxx> +#include <BRepExtrema_ExtCF.hxx> +#include <BRepExtrema_ExtFF.hxx> +#include <BRepExtrema_ExtPF.hxx> +#include <BRepExtrema_ExtPC.hxx> +#include <BRep_Tool.hxx> +#include <BRepClass_FaceClassifier.hxx> + +#include <IntTools_Context.hxx> + +#include <BRepExtrema_DistShapeShape.hxx> +#include <BRepOffsetAPI_NormalProjection.hxx> +#include <BRepTopAdaptor_FClass2d.hxx> +#include <BRepTools_Substitution.hxx> +#include <BRepAlgo_Loop.hxx> + +#include <BRep_TEdge.hxx> +#include <TopoDS_TShape.hxx> +#include <ShapeFix_Edge.hxx> +#include <Geom_Surface.hxx> +#include <gce_MakeScale.hxx> +#include <BRepBuilderAPI_GTransform.hxx> +#include <BRepBuilderAPI_Transform.hxx> + + +template <typename T> +T max(T const &a, T const &b) +{ + return a<b? b:a; +} + +//////////////////////////////////////////////////////////////////////////////// +// Printing routines +//////////////////////////////////////////////////////////////////////////////// + +static inline ostream &operator <<(ostream &o,const TopAbs_ShapeEnum &A) +{ + switch(A) { + case TopAbs_COMPOUND: return o << "COMPOUND"; + case TopAbs_COMPSOLID: return o << "COMPSOLID"; + case TopAbs_SOLID: return o << "SOLID"; + case TopAbs_SHELL: return o << "SHELL"; + case TopAbs_FACE: return o << "FACE"; + case TopAbs_WIRE: return o << "WIRE"; + case TopAbs_EDGE: return o << "EDGE"; + case TopAbs_VERTEX: return o << "VERTEX"; + case TopAbs_SHAPE: return o << "SHAPE"; + default: return o << "Unknown"; + } +} + +static inline ostream &operator <<(ostream &o,const TopAbs_State &A) +{ + switch(A) { + case TopAbs_IN: return o << "IN"; + case TopAbs_OUT: return o << "OUT"; + case TopAbs_ON: return o << "ON"; + case TopAbs_UNKNOWN: return o << "UNKNOWN"; + default: return o << "Unknown"; + } +} + +static inline ostream &operator <<(ostream &o,const gp_Pnt &p) +{ + return o << "(" << p.Coord(1) << "," << p.Coord(2) << "," << p.Coord(3) << ")"; +} + +static inline ostream &operator <<(ostream &o,const TopOpeBRep_P2Dstatus &A) +{ + switch(A) { + case TopOpeBRep_P2DUNK: return o << "P2DUNK"; + case TopOpeBRep_P2DINT: return o << "P2DINT"; + case TopOpeBRep_P2DSGF: return o << "P2DSGF"; + case TopOpeBRep_P2DSGL: return o << "P2DSGL "; + case TopOpeBRep_P2DNEW: return o << "P2DNEW "; + default: return o << "Unknown"; + } +} + +template <typename T> +static inline std::ostream &operator<<(std::ostream &out, std::set<T> const &a) +{ + std::copy(a.begin(),a.end(),std::ostream_iterator<T>(out," ")); + return out; +} + +bool OCC_Connect::LessThanIntegerSet::operator()(std::set<int> const &a, + std::set<int> const &b) +{ + std::set<int>::iterator pa=a.begin(), pb=b.begin(); + for(; pa!=a.end() && pb!=b.end(); pa++, pb++ ) { + if(*pa<*pb) + return 1; + if(*pb<*pa) + return 0; + } + if(pb!=b.end()) + return 1; + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +// OCC_Connect +//////////////////////////////////////////////////////////////////////////////// + +int OCC_Connect::SaveBRep(char const *name) +{ + gp_Pnt center(0,0,0); + gce_MakeScale transform(center, 0.001); + BRepBuilderAPI_Transform scale(assembly.front(), transform.Value()); + BRep_Builder BB; + TopoDS_Compound compound; + BB.MakeCompound(compound); + TopTools_ListOfShape p; + for(p=scale.Modified(assembly.front()); + !p.IsEmpty(); + p.RemoveFirst() + ) + BB.Add(compound,p.First()); + BRepTools::Write(compound,name); +} + +void OCC_Connect::Dump(ostream &out) const +{ + BRepTools::Dump(assembly.front(),out); +} + +void OCC_Connect::Connect(void) +{ + while(assembly.size()>1) { + TopoDS_Compound result; + BRep_Builder BB; + BB.MakeCompound(result); + Intersect(BB,result,assembly.front(),assembly.back()); + assembly.pop_front(); + assembly.pop_back(); + assembly.push_back(result); + } +} + +void OCC_Connect::Collect(void) +{ + TopoDS_Compound result; + BRep_Builder BB; + BB.MakeCompound(result); + while(assembly.size()>0) { + if(verbose&Cutting) + cout << "Adding item\n"; + BB.Add(result,assembly.front()); + assembly.pop_front(); + } + assembly.push_back(result); +} + +void OCC_Connect::FaceCutters::Add(TopoDS_Edge const &edge) +{ + edges.push_back(edge); + rebuilt=0; +} + +int OCC_Connect::FaceCutters::FindConnectedEdge(int v, + std::vector<int> &done, + std::vector<std::vector<int> > &v_edge +) { + int re_used=-1; + for(std::vector<int>::iterator p=v_edge[v].begin();p!=v_edge[v].end(); p++){ + if(done[*p]) { + re_used=*p; + continue; + } + return *p; // Found an unused edge + } + return re_used; +} + +void dump(std::vector<std::pair<int,int> > const &e2v, std::ostream &out, + const char *name="name") +{ + out << "graph " << name << " {\n"; + for(int e=0; e<e2v.size(); e++) { + out << " " << e2v[e].first << " -- " << e2v[e].second << "[label=" << e+1 << "]\n"; + } + out << "}\n"; +} + +void FinishEdge(int edge, + std::vector<std::set<int> > &v2e, + std::vector<std::pair<int,int> > &e2v) +{ + int verbose=0; + if(verbose) + std::cout << "Finishing edge " << edge << "\n"; + + int fv=e2v[edge].first; + v2e[fv].erase(edge); + while(v2e[fv].size()>1) { + std::set<int>::iterator e=v2e[fv].begin(); + int nv=v2e.size(); + v2e.push_back(std::set<int>()); + v2e[nv].insert(*e); + if(e2v[*e].first==fv) + e2v[*e].first=nv; + else + e2v[*e].second=nv; + if(verbose) + std::cout << "Created vertex " << nv << "(" << fv << "), edge[" << *e + << "]=" << e2v[*e].first << " " << e2v[*e].second << "\n"; + v2e[fv].erase(*e); + } + + int sv=e2v[edge].second; + v2e[sv].erase(edge); + while(v2e[sv].size()>1) { + std::set<int>::iterator e=v2e[sv].begin(); + int nv=v2e.size(); + v2e.push_back(std::set<int>()); + v2e[nv].insert(*e); + if(e2v[*e].first==sv) + e2v[*e].first=nv; + else + e2v[*e].second=nv; + if(verbose) + std::cout << "Created vertex " << nv << "(" << sv << "), edge[" << *e << + "]=" << e2v[*e].first << " " << e2v[*e].second << "\n"; + v2e[sv].erase(*e); + } +} + +void OCC_Connect::FaceCutters::Build(TopoDS_Face const &face, + TopoDS_Shape &result, int verbose) +{ + clear(); + + /* First we create some data structures to access the topology */ + TopTools_IndexedMapOfShape vertices; + std::vector<std::pair<int,int> > e2v; + for(int i=0; i<edges.size(); i++) { + TopExp::MapShapes(edges[i],TopAbs_VERTEX,vertices); + TopoDS_Vertex v1, v2; + TopExp::Vertices(edges[i],v1,v2); + std::pair<int,int> t(vertices.FindIndex(v1),vertices.FindIndex(v2)); + e2v.push_back(t); + } + + std::vector<std::set<int> > v2e; + for(int e=0; e<e2v.size(); e++) { + if(e2v[e].first>=v2e.size()) + v2e.resize(e2v[e].first+1); + v2e[e2v[e].first].insert(e); + if(e2v[e].second>=v2e.size()) + v2e.resize(e2v[e].second+1); + v2e[e2v[e].second].insert(e); + } + + std::set<int> open, odd; + for(int i=0; i<v2e.size(); i++) { + if(v2e[i].size()==0) + continue; + else if(v2e[i].size()==1) + open.insert(i); + else if(v2e[i].size()&1) + odd.insert(i); + } + + if(open.size()&1) + std::cerr << "Inconsistent open loops\n"; + if(odd.size()&1) + std::cerr << "Inconsistent odd loops\n"; + int first_edge=-1; + for(;;) { + int open_mode; + std::set<int> current_vertices; + for(int start=0; start<v2e.size(); start++) { + if(v2e[start].size()==1) { + if(verbose&Cutting) + std::cout << "start open at " << start << "\n"; + current_vertices.insert(start); + open_mode=1; + break; + } + } + if(!current_vertices.size()) { + for(int start=0; start<v2e.size(); start++) { + if(v2e[start].size()) { + if(verbose&Cutting) + std::cout << "start closed at " << start << "\n"; + current_vertices.insert(start); + open_mode=0; + break; + } + } + } + if(!current_vertices.size()) + break; + + std::map<int,std::deque<int> > wires; + std::set<int> processed_edges; + do { + std::set<int> next_vertices; + for(std::set<int>::iterator v=current_vertices.begin(); + v!=current_vertices.end(); + v++ + ) { + for(std::set<int>::iterator e=v2e[*v].begin() ; + e!=v2e[*v].end(); + e++ + ) { + if(processed_edges.count(*e)) + continue; + + int other=e2v[*e].first==*v? + e2v[*e].second:e2v[*e].first; + + if(open_mode) { + if(v2e[other].size()==1) { + // Other is open end too, finish wire. + wires[*v].push_back(*e); + std::deque<int>::const_iterator p; + BRepBuilderAPI_MakeWire wire; + if(verbose&Cutting) + std::cout << "CUT Open wire:"; + for(p=wires[*v].begin(); + p!=wires[*v].end(); + p++ + ) { + FinishEdge(*p, v2e, e2v); + wire.Add(edges[*p]); + if(verbose&Cutting) + std::cout << ' ' << (*p)+1; + } + if(verbose&Cutting) + std::cout << "\n"; + push_back(wire); + goto next_vertex; + } + } else { + if( current_vertices.count(other) || + next_vertices.count(other) + ) { + if(verbose&Cutting) + std::cout << "CUT Closed wire:"; + wires[*v].push_back(*e); + while(wires[other].front() + ==wires[*v].front() + ) { + wires[other].pop_front(); + wires[*v].pop_front(); + } + + BRepBuilderAPI_MakeWire wire; + std::deque<int>::const_iterator p; + for(p=wires[other].begin(); + p!=wires[other].end(); + p++ + ) { + FinishEdge(*p, v2e, e2v); + wire.Add(edges[*p]); + if(verbose&Cutting) + std::cout << ' ' << (*p)+1; + } + std::deque<int>::reverse_iterator rp; + for(rp=wires[*v].rbegin(); + rp!=wires[*v].rend(); + rp++ + ) { + FinishEdge(*rp, v2e, e2v); + wire.Add(edges[*rp]); + if(verbose&Cutting) + std::cout << ' ' << (*rp)+1; + } + if(verbose&Cutting) + std::cout << "\n"; + push_back(wire); + goto next_vertex; + } + } + if(current_vertices.count(other)==0) { + wires[other]=wires[*v]; + wires[other].push_back(*e); + processed_edges.insert(*e); + next_vertices.insert(other); + } + } + } + current_vertices=next_vertices; + } while(current_vertices.size()); + next_vertex: ; + } + + if(size()>1 && verbose&CuttingIntermediate) { + if(verbose&Cutting) + std::cout << "Saving multiple cuts\n"; + BRep_Builder BB; + TopoDS_Compound compound; + BB.MakeCompound(compound); + for(int i=0; i<edges.size(); i++) + BB.Add(compound,edges[i]); + BRepTools::Write(compound,"cutter.brep"); + ofstream out("cutter.dot",ios::trunc|ios::out); + dump(e2v,out); + } +} + +inline OCC_Connect::cutmap_t OCC_Connect::SelectCuttingEdges( + TopTools_IndexedMapOfShape &edges, + TopTools_IndexedMapOfShape &faces) +{ + cutmap_t cutters; + for(int face=1;face<=faces.Extent();face++) { + for(int edge=1;edge<=edges.Extent();edge++) { + TopoDS_Edge c_edge=TopoDS::Edge(edges(edge)); + TopoDS_Face c_face=TopoDS::Face(faces(face)); + + if(BRep_Tool::Degenerated(c_edge)) { + if(verbose&CuttingReject) + cout << "Rejected(" << __LINE__ << ") edge " << edge + << " in face " << face << endl; + continue; + } + + TopTools_IndexedMapOfShape already_there; + TopExp::MapShapes(c_face,TopAbs_EDGE,already_there); + if(already_there.Contains(c_edge)) { + if(verbose&CuttingReject) + cout << "Rejected(" << __LINE__ << ") edge " << edge + << " in face " << face << endl; + continue; + } + + BRepExtrema_DistShapeShape dist(c_edge,c_face); + double tol=BRep_Tool::Tolerance(c_face); + if(dist.Value()>tol) { + if(verbose&CuttingReject) + cout << "Rejected(" << __LINE__ << ") edge " << edge + << " in face " << face << endl; + continue; + } + + Standard_Real s, e; + Handle(Geom_Curve) c3d=BRep_Tool::Curve(c_edge,s,e); + if(c3d.IsNull()) { + if(verbose&CuttingReject) + cout << "Rejected(" << __LINE__ << ") edge " << edge + << " in face " << face << endl; + continue; + } + + // FIXME, checking only the middle may be a bit optimistic. + TopoDS_Vertex vm=BRepBuilderAPI_MakeVertex(c3d->Value((s+e)/2)); + BRepExtrema_DistShapeShape dist_mf(vm,c_face); + if(dist_mf.Value()>tol) { + if(verbose&CuttingReject) + cout << "Rejected(" << __LINE__ << ") edge " << edge + << " in face " << face << endl; + continue; + } + + if(verbose&Cutting) + cout << "Accepted edge " << edge << " in face " << face << endl; + + // Add missing PCurve if necessary + Handle_Geom2d_Curve c=BRep_Tool::CurveOnSurface(c_edge,c_face,s,e); + if(c.IsNull()) { + if(verbose&Cutting) + cout << "Adding missing PCurve\n"; + ShapeFix_Edge().FixAddPCurve(c_edge,c_face,false,1e-7); + } + cutters[face].Add(c_edge); + } + } + return cutters; +} + +void OCC_Connect::Intersect(BRep_Builder &BB, TopoDS_Shape &target, + TopoDS_Shape &shape, TopoDS_Shape &tool) +{ + int t=0; + /*************************************************************************** + We start by splitting edges at all the edge-edge intersections. + This may generate new vertices and edges. + ***************************************************************************/ + MergeVertices(shape,tool); + LocOpe_SplitShape splitter1(shape); + LocOpe_SplitShape splitter2(tool); + TopOpeBRep_ShapeIntersector intersector; + for(intersector.InitIntersection(shape,tool); + intersector.MoreIntersection(); + intersector.NextIntersection() + ) { + if(verbose&Cutting) { + cout << "++++++++++++++++++++++++++++++++++++++++" + "++++++++++++++++++++++++++++++++++++++++\n"; + intersector.DumpCurrent(1); cout << " --> "; + intersector.DumpCurrent(2); cout << '\n'; + } + + TopOpeBRep_EdgesIntersector &ee=intersector.ChangeEdgesIntersector(); + if( intersector.CurrentGeomShape(1).ShapeType()==TopAbs_EDGE && + intersector.CurrentGeomShape(2).ShapeType()==TopAbs_EDGE + ) { + for(ee.InitPoint(); ee.MorePoint(); ee.NextPoint()) { + TopOpeBRep_Point2d const &p=ee.Point(); + if(verbose&Cutting) + cout << "point loop " << p.Parameter(1) << '\n'; + TopoDS_Vertex vertex; + if(p.IsVertex(1)) + vertex=p.Vertex(1); + else if(p.IsVertex(2)) + vertex=p.Vertex(2); + else + vertex=BRepBuilderAPI_MakeVertex(p.Value()); + if(!p.IsVertex(1)) { + TopoDS_Edge edge=TopoDS::Edge(ee.Edge(1)); + if(!splitter1.CanSplit(edge)) { + if(verbose&Cutting) + cout << "Cannot split 1\n";; + } else { + if(verbose&Cutting) + cout << "splitting model 1\n"; + try { splitter1.Add(vertex,p.Parameter(1),edge); } + catch(Standard_ConstructionError c) { + if(verbose&Cutting) + cout << "Ooops \n"; + } + } + } + if(!p.IsVertex(2)) { + TopoDS_Edge edge=TopoDS::Edge(ee.Edge(2)); + if(!splitter2.CanSplit(edge)) { + if(verbose&Cutting) + cout << "Cannot split 2\n";; + } else { + if(verbose&Cutting) + cout << "splitting model 2\n"; + try { splitter2.Add(vertex,p.Parameter(2),edge); } + catch(Standard_ConstructionError c) { + if(verbose&Cutting) + cout << "Ooops \n"; + } + } + } + } + } + } + + /*************************************************************************** + Not all intersections seem to be caught, this is an attempt to catch + some missing intersections. FIXME, this is almost certainly incomplete. + ***************************************************************************/ + TopTools_IndexedMapOfShape edges, faces, vertices; + vertices.Clear(); + TopExp::MapShapes(shape,TopAbs_VERTEX,vertices); + TopExp::MapShapes(tool,TopAbs_VERTEX,vertices); + + edges.Clear(); + TopExp::MapShapes(shape,TopAbs_EDGE,edges); + for(int e=1; e<=edges.Extent(); e++) { + TopoDS_Edge edge=TopoDS::Edge(edges(e)); + TopoDS_Vertex o1, o2; + TopExp::Vertices(edge,o1,o2); + int skip1=vertices.FindIndex(o1); + int skip2=vertices.FindIndex(o2); + for(int v=1; v<=vertices.Extent(); v++) { + if(v==skip1 || v==skip2) + continue; + TopoDS_Vertex vertex=TopoDS::Vertex(vertices(v)); + BRepExtrema_ExtPC distance(vertex,edge); + if(!distance.IsDone()) + continue; + double tolerance=max(BRep_Tool::Tolerance(edge), + BRep_Tool::Tolerance(vertex)); + for(int i=1;i<=distance.NbExt();i++) { + if(distance.Value(i)<tolerance) { + try { + // No idea why this can fail + splitter1.Add(vertex,distance.Parameter(i),edge); + } + catch(Standard_ConstructionError c) { + if(verbose&Cutting) { + cout << "Adding vertex to edge failed\n"; + TopoDS_Vertex v1, v2; + TopExp::Vertices(edge,v1,v2); + if(BRepTools::Compare(v1,vertex)) + cout << "Merge v1\n"; + if(BRepTools::Compare(v2,vertex)) + cout << "Merge v2\n"; + double d1=BRep_Tool::Pnt(v1).Distance( + BRep_Tool::Pnt(vertex)); + double d2=BRep_Tool::Pnt(v2).Distance( + BRep_Tool::Pnt(vertex)); + cout << "Adding " << i << " to edge " << e + << " distance=" << distance.Value(i) + << " parameter=" << distance.Parameter(i) + << " point=" << distance.Point(i) + << " dv1=" << d1 + << " dv2=" << d2 + << endl; + BRepTools::Dump(vertex,cout); + BRepTools::Dump(edge,cout); + } + } + } + } + } + } + + edges.Clear(); + TopExp::MapShapes(tool,TopAbs_EDGE,edges); + for(int e=1; e<=edges.Extent(); e++) { + TopoDS_Edge edge=TopoDS::Edge(edges(e)); + TopoDS_Vertex o1, o2; + TopExp::Vertices(edge,o1,o2); + int skip1=vertices.FindIndex(o1); + int skip2=vertices.FindIndex(o2); + for(int v=1; v<=vertices.Extent(); v++) { + if(v==skip1 || v==skip2) + continue; + TopoDS_Vertex vertex=TopoDS::Vertex(vertices(v)); + BRepExtrema_ExtPC distance(vertex,edge); + if(!distance.IsDone()) + continue; + double tolerance=max(BRep_Tool::Tolerance(edge), + BRep_Tool::Tolerance(vertex)); + for(int i=1;i<=distance.NbExt();i++) { + if(distance.Value(i)<tolerance) { + try { + splitter2.Add(vertex,distance.Parameter(i),edge); + } + catch(Standard_ConstructionError c) { + if(verbose&Cutting) { + cout << "Adding vertex to edge failed\n"; + TopoDS_Vertex v1, v2; + TopExp::Vertices(edge,v1,v2); + if(BRepTools::Compare(v1,vertex)) + cout << "Merge v1\n"; + if(BRepTools::Compare(v2,vertex)) + cout << "Merge v2\n"; + double d1=BRep_Tool::Pnt(v1).Distance( + BRep_Tool::Pnt(vertex)); + double d2=BRep_Tool::Pnt(v2).Distance( + BRep_Tool::Pnt(vertex)); + cout << "Adding " << i << " to edge " << e + << " distance=" << distance.Value(i) + << " parameter=" << distance.Parameter(i) + << " point=" << distance.Point(i) + << " dv1=" << d1 + << " dv2=" << d2 + << endl; + BRepTools::Dump(vertex,cout); + BRepTools::Dump(edge,cout); + } + } + } + } + } + } + + /*************************************************************************** + We need the shapes with all the edge-edge intersections to split + all the faces. All vertices and edges which can be merged, will + be merged. + ***************************************************************************/ + TopoDS_Compound intermediate1; + BB.MakeCompound(intermediate1); + for(TopTools_ListIteratorOfListOfShape p(splitter1.DescendantShapes(shape)); + p.More(); + p.Next() + ) { + BB.Add(intermediate1,p.Value()); + } + TopoDS_Compound intermediate2; + BB.MakeCompound(intermediate2); + for(TopTools_ListIteratorOfListOfShape p(splitter2.DescendantShapes(tool)); + p.More(); + p.Next() + ) { + BB.Add(intermediate2,p.Value()); + } + if(verbose&Cutting) { + cout << "Before merging vertices and edges\n"; + TopoDS_Compound t; + BB.MakeCompound(t); + BB.Add(t,intermediate1); + BB.Add(t,intermediate2); + PrintItemCount(t); + } + MergeVertices(intermediate1,intermediate2); + MergeEdges(intermediate1,intermediate2); + if(verbose&Cutting) { + cout << "After merging vertices and edges\n"; + TopoDS_Compound t; + BB.MakeCompound(t); + BB.Add(t,intermediate1); + BB.Add(t,intermediate2); + PrintItemCount(t); + } + + // Create the result + TopoDS_Compound result; + BB.MakeCompound(result); + BB.Add(result,intermediate1); + BB.Add(result,intermediate2); + + // Add any missing PCurves + for(TopExp_Explorer face(result,TopAbs_FACE); face.More(); face.Next()) { + for(TopExp_Explorer edge(face.Current(),TopAbs_EDGE); + edge.More(); + edge.Next() + ) { + Standard_Real s, e; + TopoDS_Edge c_edge=TopoDS::Edge(edge.Current()); + TopoDS_Face c_face=TopoDS::Face(face.Current()); + Handle_Geom2d_Curve c=BRep_Tool::CurveOnSurface(c_edge,c_face,s,e); + if(c.IsNull()) { + if(verbose&Cutting) + cout << "Adding missing PCurve\n"; + ShapeFix_Edge().FixAddPCurve(c_edge,c_face,false,1e-7); + } + } + } + + /*************************************************************************** + We determine which edges/wires are going to cut a face. To do this + we create a map of FaceCutters which is indexed by the face number + in the faces map. The FaceCutters generate the correct cutting wires. + ***************************************************************************/ + int retry; +do { + if(verbose&Cutting) + std::cout << "STARTED CUTTING\n"; + retry=0; + edges.Clear(); TopExp::MapShapes(result,TopAbs_EDGE,edges); + faces.Clear(); TopExp::MapShapes(result,TopAbs_FACE,faces); + cutmap_t cutters=SelectCuttingEdges(edges,faces); + + /*************************************************************************** + Apply all face splits stored in the map. + ***************************************************************************/ + int cut_count=0; + LocOpe_SplitShape splitter(result); + for(cutmap_t::iterator f=cutters.begin(); f!=cutters.end(); f++) { + TopoDS_Face const &face=TopoDS::Face(faces(f->first)); + FaceCutters &cutter=f->second; + cut_count+=cutter.size(); + if(verbose&Cutting) { + cout << "Cutting face " << f->first << " *************************\n"; + BRepTools::Dump(face,cout); + } + cutter.Build(face,result,verbose); + for(FaceCutters::iterator p=cutter.begin(); p!=cutter.end(); p++) { + TopTools_IndexedMapOfShape edges; + TopExp::MapShapes(*p,TopAbs_EDGE,edges); + if(edges.Extent()<3 && BRep_Tool::IsClosed(*p)) { + // FIXME This doesn't work. + cout << "IGNORED Closed wire with less than three edges\n"; + continue; + } + //BRepTools::Dump(*p,cout); + try { + splitter.Add(*p,face); + } + catch(Standard_ConstructionError c) { + cout << "splitting the face failed\n"; + retry=1; + } + } + } + if(verbose&Cutting) + cout << cut_count << " cuts in " << cutters.size() << " faces\n"; + + // Create the final shape with the cutted faces. + TopoDS_Compound cutted; + BB.MakeCompound(cutted); + int count=0; + for(TopTools_ListIteratorOfListOfShape p(splitter.DescendantShapes(result)); + p.More(); + p.Next() + ) { + if(++count==1) { + if(verbose&Cutting) { + cout << "--------- " << count << " ---------------------------\n"; + BRepTools::Dump(p.Value(),cout); + } + BB.Add(cutted,p.Value()); + } + } + MergeFaces(cutted); + result=cutted; +} while(0 && retry); + target=result; +} + +void OCC_Connect::MergeVertices(TopoDS_Shape &shape1,TopoDS_Shape &shape2) const +{ + TopTools_IndexedMapOfShape imap, omap; + TopExp::MapShapes(shape1,TopAbs_VERTEX,imap); + TopExp::MapShapes(shape2,TopAbs_VERTEX,imap); + BRepTools_ReShape replacer; + for(int i=0;i<imap.Extent();i++) { + for(int j=0;j<omap.Extent();j++) { + TopoDS_Vertex orig=TopoDS::Vertex(imap(i+1)); + TopoDS_Vertex repl=TopoDS::Vertex(omap(j+1)); + if(BRepTools::Compare(orig,repl)) { + repl.Orientation(orig.Orientation()); + replacer.Replace(orig,repl); + // FIXME, tolerance and point should be updated + goto skip; + } + } + omap.Add(imap(i+1)); + skip:; + } + TopoDS_Shape t=shape1; + shape1=replacer.Apply(t); + t=shape2; + shape2=replacer.Apply(t); +} + +bool OCC_Connect::CanMergeCurve(TopoDS_Edge edge1,TopoDS_Edge edge2) const +{ + if(BRep_Tool::Degenerated(edge1) && BRep_Tool::Degenerated(edge2)) + return 1; + + double tol=1e-7; + + Standard_Real s,e; + Handle(Geom_Curve) curve=BRep_Tool::Curve(edge1,s,e); + for(Standard_Real i=s;i<=e;i+=(e-s)/10) { + TopoDS_Vertex v=BRepBuilderAPI_MakeVertex(curve->Value(i)); + double dist=BRepExtrema_DistShapeShape(edge2,v).Value(); + if(dist>tol) + return 0; + } + return 1; +} + +void OCC_Connect::MergeEdges(TopoDS_Shape &shape1, TopoDS_Shape &shape2) const +{ + TopTools_IndexedMapOfShape imap, omap; + TopExp::MapShapes(shape1,TopAbs_EDGE,imap); + TopExp::MapShapes(shape2,TopAbs_EDGE,imap); + BRepTools_ReShape replacer; + for(int i=0;i<imap.Extent();i++) { + for(int j=0;j<omap.Extent();j++) { + TopoDS_Edge orig=TopoDS::Edge(imap(i+1)); + TopoDS_Edge repl=TopoDS::Edge(omap(j+1)); + + TopoDS_Vertex o1, o2, r1, r2; + TopExp::Vertices(orig,o1,o2,true); + TopExp::Vertices(repl,r1,r2,true); + + if(o1.IsSame(o2)) { + if(!BRep_Tool::Degenerated(orig)) { + if(verbose&Cutting) { + cout << "Same vertex in edge\n"; + BRepTools::Dump(orig,cout); + } + replacer.Remove(orig); + goto skip; + } else if(o1.IsSame(r1) && o1.IsSame(r2) + && CanMergeCurve(orig,repl) + ) { + if(verbose&Cutting) { + cout << "Degenerated edge, replace " << i+1 + << " with " << j+1 << '\n'; + BRepTools::Dump(orig,cout); + BRepTools::Dump(repl,cout); + } + // FIXME, update tolerance + BRepTools::Dump(repl.Complemented(),cout); + replacer.Replace(orig,repl.Complemented()); + goto skip; + } + cout << i+1 << " Degenerated\n"; + } + if(o1.IsSame(r1) && o2.IsSame(r2) && CanMergeCurve(orig,repl)) { + if(verbose&Cutting) { + cout << "Same order of vertices, replace " << i+1 + << " with " << j+1 << '\n'; + BRepTools::Dump(orig,cout); + BRepTools::Dump(repl,cout); + } + // FIXME, update tolerance + replacer.Replace(orig,repl); + goto skip; + } + if(o1.IsSame(r2) && o2.IsSame(r1) && CanMergeCurve(orig,repl)) { + if(verbose&Cutting) { + cout << "Reversed order of vertices, replace " << i+1 + << " with " << j+1 << '\n'; + BRepTools::Dump(orig,cout); + BRepTools::Dump(repl,cout); + } + // FIXME, update tolerance + replacer.Replace(orig,repl.Complemented()); + goto skip; + } + } + if(verbose&Cutting) + cout << "Adding " << i+1 << " as " << omap.Extent()+1<<" to keep map\n"; + omap.Add(imap(i+1)); + skip:; + } + TopoDS_Shape t=shape1; + shape1=replacer.Apply(t); + t=shape2; + shape2=replacer.Apply(t); +} + +bool OCC_Connect::CanMergeFace(TopoDS_Face face1,TopoDS_Face face2) const +{ + // FIXME, this really does not work. + return 1; + + double tol=1e-7; + + Handle(Geom_Surface) surface=BRep_Tool::Surface(face1); + Standard_Real u1, u2, v1, v2; + surface->Bounds(u1,u2,v1,v2); + cout << "u1=" << u1 << " u2=" << u2 << " v1=" << v1 << " v2=" << v2 << endl; + for(Standard_Real u=u1+(u2-u1)/10;u<u2;u+=(u2-u1)/10) { + for(Standard_Real v=v1+(v2-v1)/10;v<v2;v+=(v2-v1)/10) { + TopoDS_Vertex vtx=BRepBuilderAPI_MakeVertex(surface->Value(u,v)); + BRepExtrema_DistShapeShape dss(face2,vtx); + dss.Perform(); +#if 0 + double dist=dss.Value(); + if(dist>tol) { + cout << "Distance=" << dist << " v=" << v << " u=" << u + << " pnt=" << surface->Value(u,v) << endl; + BRepTools::Dump(face2,cout); + return 0; + } +#else + dss.Dump(cout); +#endif + } + } + return 1; +} + +void OCC_Connect::MergeFaces(TopoDS_Shape &shape) const +{ + /*************************************************************************** + We must find faces which are the same. Since all edges are already + merged, we know that faces which can be merged have identical edges. + ***************************************************************************/ + TopTools_IndexedMapOfShape faces, edges; + TopExp::MapShapes(shape,TopAbs_FACE,faces); + TopExp::MapShapes(shape,TopAbs_EDGE,edges); + mapping_t mapping; + for(int i=0;i<faces.Extent();i++) { + std::set<int> face_edges; + for(TopExp_Explorer p(faces(i+1),TopAbs_EDGE); p.More(); p.Next()) { + int edge=edges.FindIndex(p.Current()); + if(BRep_Tool::Degenerated(TopoDS::Edge(edges(edge)))) { + cout << "Degenerate edge " << edge << " inserted a 0\n"; + face_edges.insert(0); + } else + face_edges.insert(edge); + } + mapping[face_edges].insert(i+1); + } + + if(verbose&Cutting) { + for(mapping_t::iterator p=mapping.begin(); p!=mapping.end(); p++) + cout << "edges [ " << p->first << "] in face" + << (p->second.size()<2? " ":"s ") << "[ " << p->second << "]\n"; + } + + /*************************************************************************** + If two faces have an identical set of edges, they can be merged + when the planes are never seperated by more than the tolerance. + ***************************************************************************/ + BRepTools_ReShape replacer; + for(mapping_t::iterator p=mapping.begin(); p!=mapping.end(); p++) { + if(p->second.size()<2) + continue; + std::vector<int> uniq; + for(std::set<int>::iterator q=p->second.begin(); + q!=p->second.end(); + q++ + ) { + for(std::vector<int>::iterator r=uniq.begin(); r!=uniq.end(); r++) { + TopoDS_Face orig=TopoDS::Face(faces(*q)); + TopoDS_Face repl=TopoDS::Face(faces(*r)); + if(verbose&Cutting) + cout << "Check face " << *q << " and " << *r << endl; + if(CanMergeFace(orig,repl)) { + if(verbose&Cutting) { + cout << "replace face " << *q << " with " << *r << '\n'; + } + repl.Orientation(orig.Orientation()); + replacer.Replace(orig,repl); + // FIXME, tolerance should be updated + goto skip; + } + } + uniq.push_back(*q); + skip:; + } + } + + TopoDS_Shape t=shape; + shape=replacer.Apply(t); +} + +void OCC_Connect::PrintItemCount(TopoDS_Shape const &shape) const +{ + TopTools_IndexedMapOfShape imap; + TopExp::MapShapes(shape,TopAbs_VERTEX,imap); + cout << "Input map contains " << imap.Extent() << " vertices\n"; + imap.Clear(); + TopExp::MapShapes(shape,TopAbs_EDGE,imap); + cout << "Input map contains " << imap.Extent() << " edges\n"; + imap.Clear(); + TopExp::MapShapes(shape,TopAbs_FACE,imap); + cout << "Input map contains " << imap.Extent() << " faces\n"; + imap.Clear(); + TopExp::MapShapes(shape,TopAbs_SOLID,imap); + cout << "Input map contains " << imap.Extent() << " solids\n"; + imap.Clear(); + TopExp::MapShapes(shape,TopAbs_COMPSOLID,imap); + cout << "Input map contains " << imap.Extent() << " compsolids\n"; + imap.Clear(); + TopExp::MapShapes(shape,TopAbs_COMPOUND,imap); + cout << "Input map contains " << imap.Extent() << " compounds\n"; +} + +#endif diff --git a/Geo/OCC_Connect.h b/Geo/OCC_Connect.h new file mode 100644 index 0000000000000000000000000000000000000000..9d848f2d72279eb81f7589acbc6923f9a115e726 --- /dev/null +++ b/Geo/OCC_Connect.h @@ -0,0 +1,87 @@ +// Gmsh - Copyright (C) 1997-2009 C. Geuzaine, J.-F. Remacle +// +// See the LICENSE.txt file for license information. Please report all +// bugs and problems to <gmsh@geuz.org>. +// +// Contributed by Mark van Doesburg, Technolution B.V. + +#ifndef _OCC_CONNECT_H_ +#define _OCC_CONNECT_H_ + +#include <stdlib.h> +#include <math.h> +#include <string.h> +#include <deque> +#include <map> +#include <vector> +#include <set> + +#include "GmshConfig.h" + +#if defined(HAVE_OCC) + +#if !defined(HAVE_NO_OCC_CONFIG_H) +#include <config.h> +#endif + +#include <TopoDS_Shape.hxx> +#include <TopoDS_Edge.hxx> +#include <TopoDS_Wire.hxx> +#include <TopoDS_Face.hxx> +#include <TopTools_IndexedMapOfShape.hxx> + +#include <BRep_Builder.hxx> +#include <LocOpe_SplitShape.hxx> + +//////////////////////////////////////////////////////////////////////////////// +// +//////////////////////////////////////////////////////////////////////////////// +class OCC_Connect { + struct LessThanIntegerSet { + bool operator()(std::set<int> const &a, std::set<int> const &b); + }; + typedef std::map<std::set<int>,std::set<int>,LessThanIntegerSet> mapping_t; + + class FaceCutters:public std::vector<TopoDS_Wire> { + std::vector<TopoDS_Edge> edges; + int rebuilt; + public: + FaceCutters(void) { rebuilt=0; } + void Build(TopoDS_Face const &,TopoDS_Shape&,int); + void Add(TopoDS_Edge const&); + private: + int FindConnectedEdge(int v, std::vector<int> &done, + std::vector<std::vector<int> > &v_edge); + }; + typedef std::map<int,FaceCutters> cutmap_t; + + std::deque<TopoDS_Shape> assembly; +protected: + int verbose; + +public: + enum Verbose { Cutting=1, CuttingReject=4, CuttingIntermediate=8 }; + OCC_Connect(int v=0) { verbose=v; } + int SaveBRep(char const *); + void Connect(void); + void Collect(void); + void Add(TopoDS_Shape const &a) { assembly.push_back(a); } + void Dump(std::ostream &) const; + operator TopoDS_Shape(void) { return assembly.front(); } +private: + void MergeVertices(TopoDS_Shape&,TopoDS_Shape&) const; + void MergeEdges(TopoDS_Shape&,TopoDS_Shape&) const; + void MergeFaces(TopoDS_Shape&) const; + void PerformBoolean(union tree*); + void Intersect(BRep_Builder &BB, TopoDS_Shape &target, + TopoDS_Shape &shape, TopoDS_Shape &tool); + bool CanMergeCurve(TopoDS_Edge edge1,TopoDS_Edge edge2) const; + bool CanMergeFace(TopoDS_Face face1,TopoDS_Face face2) const; + void PrintItemCount(TopoDS_Shape const &shape) const; + cutmap_t SelectCuttingEdges(TopTools_IndexedMapOfShape &edges, + TopTools_IndexedMapOfShape &faces); +}; + +#endif + +#endif diff --git a/doc/CREDITS.txt b/doc/CREDITS.txt index a7839f1d099097e7043c687a08f9ef6e2461b6be..38e72f286dbc8c461c7fdf4a67b99073fcc30778 100644 --- a/doc/CREDITS.txt +++ b/doc/CREDITS.txt @@ -22,7 +22,8 @@ list code; Matt Gundry for the Plot3d mesh format; Jozef Vesely for help with the Tetgen integration; Koen Hillewaert for high order element mappings and other improvements; Jacques Lechelle for the DIFFPACK mesh format; Ruth Sabariego for pyramids; Gaetan Bricteux for -Gauss integration routines; Emilie Marchandise for edge compounds. +Gauss integration routines; Emilie Marchandise for edge compounds; +Mark van Doesburg for OpenCascade face connection code. The AVL tree code (Common/avl.*) and the YUV image code (Graphics/gl2yuv.*) are copyright (C) 1988-1993, 1995 The Regents of