gmsh-TingyuanDoc  0.1
An Open-Source Timing-driven Analytical Mixed-size FPGA Placer
GModelIO_OCC.cpp
Go to the documentation of this file.
1 // Gmsh - Copyright (C) 1997-2022 C. Geuzaine, J.-F. Remacle
2 //
3 // See the LICENSE.txt file in the Gmsh root directory for license information.
4 // Please report all issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5 
6 #include <numeric>
7 #include <utility>
8 #include "GmshConfig.h"
9 #include "GmshMessage.h"
10 #include "GModelIO_OCC.h"
11 #include "Context.h"
12 #include "OCCVertex.h"
13 #include "OCCEdge.h"
14 #include "OCCFace.h"
15 #include "OCCRegion.h"
16 #include "MElement.h"
17 #include "MLine.h"
18 #include "OpenFile.h"
19 #include "StringUtils.h"
20 #include "ExtrudeParams.h"
21 
22 #if defined(HAVE_OCC)
23 
24 #include <BRepAlgoAPI_Common.hxx>
25 #include <BRepAlgoAPI_Cut.hxx>
26 #include <BRepAlgoAPI_Fuse.hxx>
27 #include <BRepAlgoAPI_Section.hxx>
28 #include <BRepBndLib.hxx>
29 #include <BRepBuilderAPI_Copy.hxx>
30 #include <BRepBuilderAPI_GTransform.hxx>
31 #include <BRepBuilderAPI_MakeEdge.hxx>
32 #include <BRepBuilderAPI_MakeFace.hxx>
33 #include <BRepBuilderAPI_MakeShell.hxx>
34 #include <BRepBuilderAPI_MakeSolid.hxx>
35 #include <BRepBuilderAPI_MakeVertex.hxx>
36 #include <BRepBuilderAPI_MakeWire.hxx>
37 #include <BRepBuilderAPI_NurbsConvert.hxx>
38 #include <BRepBuilderAPI_Transform.hxx>
39 #include <BRepCheck_Analyzer.hxx>
40 #include <BRepExtrema_DistShapeShape.hxx>
41 #include <BRepFill_CurveConstraint.hxx>
42 #include <BRepFilletAPI_MakeChamfer.hxx>
43 #include <BRepFilletAPI_MakeFillet.hxx>
44 #include <BRepGProp.hxx>
45 #include <BRepLib.hxx>
46 #include <BRepOffsetAPI_MakeFilling.hxx>
47 #include <BRepOffsetAPI_MakePipe.hxx>
48 #include <BRepOffsetAPI_MakeThickSolid.hxx>
49 #include <BRepOffsetAPI_Sewing.hxx>
50 #include <BRepOffsetAPI_ThruSections.hxx>
51 #include <BRepPrimAPI_MakeBox.hxx>
52 #include <BRepPrimAPI_MakeCone.hxx>
53 #include <BRepPrimAPI_MakeCylinder.hxx>
54 #include <BRepPrimAPI_MakePrism.hxx>
55 #include <BRepPrimAPI_MakeRevol.hxx>
56 #include <BRepPrimAPI_MakeSphere.hxx>
57 #include <BRepPrimAPI_MakeTorus.hxx>
58 #include <BRepPrimAPI_MakeWedge.hxx>
59 #include <BRepTools.hxx>
60 #include <BRepTools_WireExplorer.hxx>
61 #include <BRep_Tool.hxx>
62 #include <Bnd_Box.hxx>
63 #include <ElCLib.hxx>
64 #include <GProp_GProps.hxx>
65 #include <Geom2d_Curve.hxx>
66 #include <GeomAPI_Interpolate.hxx>
67 #include <GeomConvert.hxx>
68 #include <GeomFill_BSplineCurves.hxx>
69 #include <GeomFill_BezierCurves.hxx>
70 #include <GeomProjLib.hxx>
71 #include <Geom_BSplineCurve.hxx>
72 #include <Geom_BSplineSurface.hxx>
73 #include <Geom_BezierCurve.hxx>
74 #include <Geom_BezierSurface.hxx>
75 #include <Geom_Circle.hxx>
76 #include <Geom_Ellipse.hxx>
77 #include <Geom_Plane.hxx>
78 #include <Geom_Surface.hxx>
79 #include <Geom_TrimmedCurve.hxx>
80 #include <IGESControl_Reader.hxx>
81 #include <IGESControl_Writer.hxx>
82 #include <Interface_Static.hxx>
83 #include <Poly_PolygonOnTriangulation.hxx>
84 #include <Poly_Triangle.hxx>
85 #include <Poly_Triangulation.hxx>
86 #include <ProjLib_ProjectedCurve.hxx>
87 #include <STEPControl_Reader.hxx>
88 #include <STEPControl_Writer.hxx>
89 #include <ShapeBuild_ReShape.hxx>
90 #include <ShapeFix_FixSmallFace.hxx>
91 #include <ShapeFix_Shape.hxx>
92 #include <ShapeFix_Wireframe.hxx>
93 #include <Standard_Version.hxx>
94 #include <TColStd_Array1OfInteger.hxx>
95 #include <TColStd_Array1OfReal.hxx>
96 #include <TColStd_Array2OfReal.hxx>
97 #include <TColgp_Array1OfPnt.hxx>
98 #include <TColgp_Array1OfPnt2d.hxx>
99 #include <TColgp_Array2OfPnt.hxx>
100 #include <TColgp_HArray1OfPnt.hxx>
101 #include <TopExp.hxx>
102 #include <TopExp_Explorer.hxx>
103 #include <TopTools_DataMapIteratorOfDataMapOfIntegerShape.hxx>
104 #include <TopTools_DataMapIteratorOfDataMapOfShapeInteger.hxx>
105 #include <TopTools_ListIteratorOfListOfShape.hxx>
106 #include <TopoDS.hxx>
107 #include <gce_MakeCirc.hxx>
108 #include <gce_MakeElips.hxx>
109 #include <gce_MakePln.hxx>
110 
111 #include "OCCAttributes.h"
112 
113 #if OCC_VERSION_HEX < 0x060900
114 #error "Gmsh requires OpenCASCADE >= 6.9"
115 #endif
116 
117 #if OCC_VERSION_HEX > 0x070100
118 #include <BOPAlgo_Alerts.hxx>
119 #endif
120 
121 #if OCC_VERSION_HEX > 0x070300
122 #include <BRepMesh_IncrementalMesh.hxx>
123 #else
124 #include <BRepMesh_FastDiscret.hxx>
125 #endif
126 
127 #if OCC_VERSION_HEX < 0x070400
128 #include <ShapeUpgrade_UnifySameDomain.hxx>
129 #endif
130 
131 #if defined(HAVE_OCC_CAF)
132 #include <IGESCAFControl_Reader.hxx>
133 #include <Quantity_Color.hxx>
134 #include <STEPCAFControl_Reader.hxx>
135 #include <TDF_ChildIterator.hxx>
136 #include <TDF_Tool.hxx>
137 #include <TDataStd_Name.hxx>
138 #include <TDocStd_Document.hxx>
139 #include <XCAFApp_Application.hxx>
140 #include <XCAFDoc_Color.hxx>
141 #include <XCAFDoc_ColorTool.hxx>
142 #include <XCAFDoc_DocumentTool.hxx>
143 #include <XCAFDoc_Location.hxx>
144 #include <XCAFDoc_MaterialTool.hxx>
145 #include <XCAFDoc_ShapeTool.hxx>
146 #endif
147 
148 // for debugging:
149 template <class T>
150 void writeBrep(const T &shapes, const std::string &fileName = "debug.brep")
151 {
152  BRep_Builder b;
153  TopoDS_Compound c;
154  b.MakeCompound(c);
155  for(auto s : shapes) b.Add(c, s);
156  BRepTools::Write(c, fileName.c_str());
157 }
158 
160 {
161  for(int i = 0; i < 6; i++) _maxTag[i] = 0;
162  _changed = true;
163  _attributes = new OCCAttributesRTree(CTX::instance()->geom.tolerance);
164 }
165 
166 OCC_Internals::~OCC_Internals() { delete _attributes; }
167 
169 {
170  _attributes->clear();
171  _somap.Clear();
172  _shmap.Clear();
173  _fmap.Clear();
174  _wmap.Clear();
175  _emap.Clear();
176  _vmap.Clear();
177  _unbind();
178 }
179 
180 void OCC_Internals::setMaxTag(int dim, int val)
181 {
182  if(dim < -2 || dim > 3) return;
183  _maxTag[dim + 2] = std::max(_maxTag[dim + 2], val);
184 }
185 
186 int OCC_Internals::getMaxTag(int dim) const
187 {
188  if(dim < -2 || dim > 3) return 0;
189  return _maxTag[dim + 2];
190 }
191 
192 void OCC_Internals::_recomputeMaxTag(int dim)
193 {
194  if(dim < -2 || dim > 3) return;
195  _maxTag[dim + 2] = 0;
196  TopTools_DataMapIteratorOfDataMapOfIntegerShape exp;
197  switch(dim) {
198  case 0: exp.Initialize(_tagVertex); break;
199  case 1: exp.Initialize(_tagEdge); break;
200  case 2: exp.Initialize(_tagFace); break;
201  case 3: exp.Initialize(_tagSolid); break;
202  case -1: exp.Initialize(_tagWire); break;
203  case -2: exp.Initialize(_tagShell); break;
204  }
205  for(; exp.More(); exp.Next())
206  _maxTag[dim + 2] = std::max(_maxTag[dim + 2], exp.Key());
207 }
208 
209 void OCC_Internals::_bind(const TopoDS_Vertex &vertex, int tag, bool recursive)
210 {
211  if(vertex.IsNull()) return;
212  if(_vertexTag.IsBound(vertex)) {
213  if(_vertexTag.Find(vertex) != tag) {
214  Msg::Info("Cannot bind existing OpenCASCADE point %d to second tag %d",
215  _vertexTag.Find(vertex), tag);
216  }
217  }
218  else {
219  if(_tagVertex.IsBound(tag)) {
220  // this leaves the old vertex bound in _vertexTag, but we cannot remove it
221  Msg::Info("Rebinding OpenCASCADE point %d", tag);
222  }
223  _vertexTag.Bind(vertex, tag);
224  _tagVertex.Bind(tag, vertex);
225  setMaxTag(0, tag);
226  _changed = true;
227  _attributes->insert(new OCCAttributes(0, vertex));
228  }
229 }
230 
231 void OCC_Internals::_bind(const TopoDS_Edge &edge, int tag, bool recursive)
232 {
233  if(edge.IsNull()) return;
234  if(_edgeTag.IsBound(edge)) {
235  if(_edgeTag.Find(edge) != tag) {
236  Msg::Info("Cannot bind existing OpenCASCADE curve %d to second tag %d",
237  _edgeTag.Find(edge), tag);
238  }
239  }
240  else {
241  if(_tagEdge.IsBound(tag)) {
242  // this leaves the old edge bound in _edgeTag, but we cannot remove it
243  Msg::Info("Rebinding OpenCASCADE curve %d", tag);
244  }
245  _edgeTag.Bind(edge, tag);
246  _tagEdge.Bind(tag, edge);
247  setMaxTag(1, tag);
248  _changed = true;
249  _attributes->insert(new OCCAttributes(1, edge));
250  }
251  if(recursive) {
252  TopExp_Explorer exp0;
253  for(exp0.Init(edge, TopAbs_VERTEX); exp0.More(); exp0.Next()) {
254  TopoDS_Vertex vertex = TopoDS::Vertex(exp0.Current());
255  if(!_vertexTag.IsBound(vertex)) {
256  int t = getMaxTag(0) + 1;
257  _bind(vertex, t, recursive);
258  }
259  }
260  }
261 }
262 
263 void OCC_Internals::_bind(const TopoDS_Wire &wire, int tag, bool recursive)
264 {
265  if(wire.IsNull()) return;
266  if(_wireTag.IsBound(wire)) {
267  if(_wireTag.Find(wire) != tag) {
268  Msg::Info("Cannot bind existing OpenCASCADE wire %d to second tag %d",
269  _wireTag.Find(wire), tag);
270  }
271  }
272  else {
273  if(_tagWire.IsBound(tag)) {
274  // this leaves the old wire bound in _wireTag, but we cannot remove it
275  Msg::Info("Rebinding OpenCASCADE wire %d", tag);
276  }
277  _wireTag.Bind(wire, tag);
278  _tagWire.Bind(tag, wire);
279  setMaxTag(-1, tag);
280  _changed = true;
281  }
282  if(recursive) {
283  TopExp_Explorer exp0;
284  for(exp0.Init(wire, TopAbs_EDGE); exp0.More(); exp0.Next()) {
285  TopoDS_Edge edge = TopoDS::Edge(exp0.Current());
286  if(!_edgeTag.IsBound(edge)) {
287  int t = getMaxTag(1) + 1;
288  _bind(edge, t, recursive);
289  }
290  }
291  }
292 }
293 
294 void OCC_Internals::_bind(const TopoDS_Face &face, int tag, bool recursive)
295 {
296  if(face.IsNull()) return;
297  if(_faceTag.IsBound(face)) {
298  if(_faceTag.Find(face) != tag) {
299  Msg::Info("Cannot bind existing OpenCASCADE surface %d to second tag %d",
300  _faceTag.Find(face), tag);
301  }
302  }
303  else {
304  if(_tagFace.IsBound(tag)) {
305  // this leaves the old face bound in _faceTag, but we cannot remove it
306  Msg::Info("Rebinding OpenCASCADE surface %d", tag);
307  }
308  _faceTag.Bind(face, tag);
309  _tagFace.Bind(tag, face);
310  setMaxTag(2, tag);
311  _changed = true;
312  _attributes->insert(new OCCAttributes(2, face));
313  }
314  if(recursive) {
315  TopExp_Explorer exp0;
316  for(exp0.Init(face, TopAbs_WIRE); exp0.More(); exp0.Next()) {
317  TopoDS_Wire wire = TopoDS::Wire(exp0.Current());
318  if(!_wireTag.IsBound(wire)) {
319  int t = getMaxTag(-1) + 1;
320  _bind(wire, t, recursive);
321  }
322  }
323  for(exp0.Init(face, TopAbs_EDGE); exp0.More(); exp0.Next()) {
324  TopoDS_Edge edge = TopoDS::Edge(exp0.Current());
325  if(!_edgeTag.IsBound(edge)) {
326  int t = getMaxTag(1) + 1;
327  _bind(edge, t, recursive);
328  }
329  }
330  }
331 }
332 
333 void OCC_Internals::_bind(const TopoDS_Shell &shell, int tag, bool recursive)
334 {
335  if(shell.IsNull()) return;
336  if(_shellTag.IsBound(shell)) {
337  if(_shellTag.Find(shell) != tag) {
338  Msg::Info("Cannot bind existing OpenCASCADE shell %d to second tag %d",
339  _shellTag.Find(shell), tag);
340  }
341  }
342  else {
343  if(_tagShell.IsBound(tag)) {
344  // this leaves the old shell bound in _shellTag, but we cannot remove it
345  Msg::Info("Rebinding OpenCASCADE shell %d", tag);
346  }
347  _shellTag.Bind(shell, tag);
348  _tagShell.Bind(tag, shell);
349  setMaxTag(-2, tag);
350  _changed = true;
351  }
352  if(recursive) {
353  TopExp_Explorer exp0;
354  for(exp0.Init(shell, TopAbs_FACE); exp0.More(); exp0.Next()) {
355  TopoDS_Face face = TopoDS::Face(exp0.Current());
356  if(!_faceTag.IsBound(face)) {
357  int t = getMaxTag(2) + 1;
358  _bind(face, t, recursive);
359  }
360  }
361  }
362 }
363 
364 void OCC_Internals::_bind(const TopoDS_Solid &solid, int tag, bool recursive)
365 {
366  if(solid.IsNull()) return;
367  if(_solidTag.IsBound(solid)) {
368  if(_solidTag.Find(solid) != tag) {
369  Msg::Info("Cannot bind existing OpenCASCADE volume %d to second tag %d",
370  _solidTag.Find(solid), tag);
371  }
372  }
373  else {
374  if(_tagSolid.IsBound(tag)) {
375  // this leaves the old solid bound in _solidTag, but we cannot remove it
376  Msg::Info("Rebinding OpenCASCADE volume %d", tag);
377  }
378  _solidTag.Bind(solid, tag);
379  _tagSolid.Bind(tag, solid);
380  setMaxTag(3, tag);
381  _changed = true;
382  _attributes->insert(new OCCAttributes(3, solid));
383  }
384  if(recursive) {
385  TopExp_Explorer exp0;
386  for(exp0.Init(solid, TopAbs_SHELL); exp0.More(); exp0.Next()) {
387  TopoDS_Shell shell = TopoDS::Shell(exp0.Current());
388  if(!_shellTag.IsBound(shell)) {
389  int t = getMaxTag(-2) + 1;
390  _bind(shell, t, recursive);
391  }
392  }
393  for(exp0.Init(solid, TopAbs_FACE); exp0.More(); exp0.Next()) {
394  TopoDS_Face face = TopoDS::Face(exp0.Current());
395  if(!_faceTag.IsBound(face)) {
396  int t = getMaxTag(2) + 1;
397  _bind(face, t, recursive);
398  }
399  }
400  }
401 }
402 
403 void OCC_Internals::_bind(TopoDS_Shape shape, int dim, int tag, bool recursive)
404 {
405  switch(dim) {
406  case 0: _bind(TopoDS::Vertex(shape), tag, recursive); break;
407  case 1: _bind(TopoDS::Edge(shape), tag, recursive); break;
408  case 2: _bind(TopoDS::Face(shape), tag, recursive); break;
409  case 3: _bind(TopoDS::Solid(shape), tag, recursive); break;
410  case -1: _bind(TopoDS::Wire(shape), tag, recursive); break;
411  case -2: _bind(TopoDS::Shell(shape), tag, recursive); break;
412  default: break;
413  }
414 }
415 
416 void OCC_Internals::_unbind(const TopoDS_Vertex &vertex, int tag, bool recursive)
417 {
418  TopTools_DataMapIteratorOfDataMapOfIntegerShape exp0(_tagEdge);
419  for(; exp0.More(); exp0.Next()) {
420  TopoDS_Edge edge = TopoDS::Edge(exp0.Value());
421  TopExp_Explorer exp1;
422  for(exp1.Init(edge, TopAbs_VERTEX); exp1.More(); exp1.Next()) {
423  if(exp1.Current().IsSame(vertex)) return;
424  }
425  }
426  std::pair<int, int> dimTag(0, tag);
427  if(_toPreserve.find(dimTag) != _toPreserve.end()) return;
428  _vertexTag.UnBind(vertex);
429  _tagVertex.UnBind(tag);
430  _toRemove.insert(dimTag);
431  _recomputeMaxTag(0);
432  _changed = true;
433 }
434 
435 void OCC_Internals::_unbind(const TopoDS_Edge &edge, int tag, bool recursive)
436 {
437  TopTools_DataMapIteratorOfDataMapOfIntegerShape exp2(_tagFace);
438  for(; exp2.More(); exp2.Next()) {
439  TopoDS_Face face = TopoDS::Face(exp2.Value());
440  TopExp_Explorer exp1;
441  for(exp1.Init(face, TopAbs_EDGE); exp1.More(); exp1.Next()) {
442  if(exp1.Current().IsSame(edge)) return;
443  }
444  }
445  std::pair<int, int> dimTag(1, tag);
446  if(_toPreserve.find(dimTag) != _toPreserve.end()) return;
447  _edgeTag.UnBind(edge);
448  _tagEdge.UnBind(tag);
449  _toRemove.insert(dimTag);
450  _recomputeMaxTag(1);
451  if(recursive) {
452  TopExp_Explorer exp0;
453  for(exp0.Init(edge, TopAbs_VERTEX); exp0.More(); exp0.Next()) {
454  TopoDS_Vertex vertex = TopoDS::Vertex(exp0.Current());
455  if(_vertexTag.IsBound(vertex)) {
456  int t = _vertexTag.Find(vertex);
457  _unbind(vertex, t, recursive);
458  }
459  }
460  }
461  _changed = true;
462 }
463 
464 void OCC_Internals::_unbind(const TopoDS_Wire &wire, int tag, bool recursive)
465 {
466  TopTools_DataMapIteratorOfDataMapOfIntegerShape exp0(_tagFace);
467  for(; exp0.More(); exp0.Next()) {
468  TopoDS_Face face = TopoDS::Face(exp0.Value());
469  TopExp_Explorer exp1;
470  for(exp1.Init(face, TopAbs_WIRE); exp1.More(); exp1.Next()) {
471  if(exp1.Current().IsSame(wire)) return;
472  }
473  }
474  std::pair<int, int> dimTag(-1, tag);
475  if(_toPreserve.find(dimTag) != _toPreserve.end()) return;
476  _wireTag.UnBind(wire);
477  _tagWire.UnBind(tag);
478  _toRemove.insert(dimTag);
479  _recomputeMaxTag(-1);
480  if(recursive) {
481  TopExp_Explorer exp0;
482  for(exp0.Init(wire, TopAbs_EDGE); exp0.More(); exp0.Next()) {
483  TopoDS_Edge edge = TopoDS::Edge(exp0.Current());
484  if(_edgeTag.IsBound(edge)) {
485  int t = _edgeTag.Find(edge);
486  _unbind(edge, t, recursive);
487  }
488  }
489  }
490  _changed = true;
491 }
492 
493 void OCC_Internals::_unbind(const TopoDS_Face &face, int tag, bool recursive)
494 {
495  TopTools_DataMapIteratorOfDataMapOfIntegerShape exp2(_tagSolid);
496  for(; exp2.More(); exp2.Next()) {
497  TopoDS_Solid solid = TopoDS::Solid(exp2.Value());
498  TopExp_Explorer exp1;
499  for(exp1.Init(solid, TopAbs_FACE); exp1.More(); exp1.Next()) {
500  if(exp1.Current().IsSame(face)) return;
501  }
502  }
503  std::pair<int, int> dimTag(2, tag);
504  if(_toPreserve.find(dimTag) != _toPreserve.end()) return;
505  _faceTag.UnBind(face);
506  _tagFace.UnBind(tag);
507  _toRemove.insert(dimTag);
508  _recomputeMaxTag(2);
509  if(recursive) {
510  TopExp_Explorer exp0;
511  for(exp0.Init(face, TopAbs_WIRE); exp0.More(); exp0.Next()) {
512  TopoDS_Wire wire = TopoDS::Wire(exp0.Current());
513  if(_wireTag.IsBound(wire)) {
514  int t = _wireTag.Find(wire);
515  _unbind(wire, t, recursive);
516  }
517  }
518  for(exp0.Init(face, TopAbs_EDGE); exp0.More(); exp0.Next()) {
519  TopoDS_Edge edge = TopoDS::Edge(exp0.Current());
520  if(_edgeTag.IsBound(edge)) {
521  int t = _edgeTag.Find(edge);
522  _unbind(edge, t, recursive);
523  }
524  }
525  }
526  _changed = true;
527 }
528 
529 void OCC_Internals::_unbind(const TopoDS_Shell &shell, int tag, bool recursive)
530 {
531  TopTools_DataMapIteratorOfDataMapOfIntegerShape exp0(_tagSolid);
532  for(; exp0.More(); exp0.Next()) {
533  TopoDS_Solid solid = TopoDS::Solid(exp0.Value());
534  TopExp_Explorer exp1;
535  for(exp1.Init(solid, TopAbs_SHELL); exp1.More(); exp1.Next()) {
536  if(exp1.Current().IsSame(shell)) return;
537  }
538  }
539  std::pair<int, int> dimTag(-2, tag);
540  if(_toPreserve.find(dimTag) != _toPreserve.end()) return;
541  _shellTag.UnBind(shell);
542  _tagShell.UnBind(tag);
543  _toRemove.insert(dimTag);
544  _recomputeMaxTag(-2);
545  if(recursive) {
546  TopExp_Explorer exp0;
547  for(exp0.Init(shell, TopAbs_FACE); exp0.More(); exp0.Next()) {
548  TopoDS_Face face = TopoDS::Face(exp0.Current());
549  if(_faceTag.IsBound(face)) {
550  int t = _faceTag.Find(face);
551  _unbind(face, t, recursive);
552  }
553  }
554  }
555  _changed = true;
556 }
557 
558 void OCC_Internals::_unbind(const TopoDS_Solid &solid, int tag, bool recursive)
559 {
560  std::pair<int, int> dimTag(3, tag);
561  if(_toPreserve.find(dimTag) != _toPreserve.end()) return;
562  _solidTag.UnBind(solid);
563  _tagSolid.UnBind(tag);
564  _toRemove.insert(dimTag);
565  _recomputeMaxTag(3);
566  if(recursive) {
567  TopExp_Explorer exp0;
568  for(exp0.Init(solid, TopAbs_SHELL); exp0.More(); exp0.Next()) {
569  TopoDS_Shell shell = TopoDS::Shell(exp0.Current());
570  if(_shellTag.IsBound(shell)) {
571  int t = _shellTag.Find(shell);
572  _unbind(shell, t, recursive);
573  }
574  }
575  for(exp0.Init(solid, TopAbs_FACE); exp0.More(); exp0.Next()) {
576  TopoDS_Face face = TopoDS::Face(exp0.Current());
577  if(_faceTag.IsBound(face)) {
578  int t = _faceTag.Find(face);
579  _unbind(face, t, recursive);
580  }
581  }
582  }
583  _changed = true;
584 }
585 
586 void OCC_Internals::_unbind(TopoDS_Shape shape, int dim, int tag, bool recursive)
587 {
588  switch(dim) {
589  case 0: _unbind(TopoDS::Vertex(shape), tag, recursive); break;
590  case 1: _unbind(TopoDS::Edge(shape), tag, recursive); break;
591  case 2: _unbind(TopoDS::Face(shape), tag, recursive); break;
592  case 3: _unbind(TopoDS::Solid(shape), tag, recursive); break;
593  case -1: _unbind(TopoDS::Wire(shape), tag, recursive); break;
594  case -2: _unbind(TopoDS::Shell(shape), tag, recursive); break;
595  default: break;
596  }
597 }
598 
599 void OCC_Internals::_unbindWithoutChecks(TopoDS_Shape shape)
600 {
601  TopExp_Explorer exp0;
602  for(exp0.Init(shape, TopAbs_SOLID); exp0.More(); exp0.Next()) {
603  TopoDS_Solid solid = TopoDS::Solid(exp0.Current());
604  if(_solidTag.IsBound(solid)) {
605  int tag = _solidTag.Find(solid);
606  _solidTag.UnBind(solid);
607  _tagSolid.UnBind(tag);
608  _toRemove.insert(std::make_pair(3, tag));
609  _changed = true;
610  }
611  }
612  for(exp0.Init(shape, TopAbs_SHELL); exp0.More(); exp0.Next()) {
613  TopoDS_Shell shell = TopoDS::Shell(exp0.Current());
614  if(_shellTag.IsBound(shell)) {
615  int tag = _shellTag.Find(shell);
616  _shellTag.UnBind(shell);
617  _tagShell.UnBind(tag);
618  _toRemove.insert(std::make_pair(-2, tag));
619  _changed = true;
620  }
621  }
622  for(exp0.Init(shape, TopAbs_FACE); exp0.More(); exp0.Next()) {
623  TopoDS_Face face = TopoDS::Face(exp0.Current());
624  if(_faceTag.IsBound(face)) {
625  int tag = _faceTag.Find(face);
626  _faceTag.UnBind(face);
627  _tagFace.UnBind(tag);
628  _toRemove.insert(std::make_pair(2, tag));
629  _changed = true;
630  }
631  }
632  for(exp0.Init(shape, TopAbs_WIRE); exp0.More(); exp0.Next()) {
633  TopoDS_Wire wire = TopoDS::Wire(exp0.Current());
634  if(_wireTag.IsBound(wire)) {
635  int tag = _wireTag.Find(wire);
636  _wireTag.UnBind(wire);
637  _tagWire.UnBind(tag);
638  _toRemove.insert(std::make_pair(-1, tag));
639  _changed = true;
640  }
641  }
642  for(exp0.Init(shape, TopAbs_EDGE); exp0.More(); exp0.Next()) {
643  TopoDS_Edge edge = TopoDS::Edge(exp0.Current());
644  if(_edgeTag.IsBound(edge)) {
645  int tag = _edgeTag.Find(edge);
646  _edgeTag.UnBind(edge);
647  _tagEdge.UnBind(tag);
648  _toRemove.insert(std::make_pair(1, tag));
649  _changed = true;
650  }
651  }
652  for(exp0.Init(shape, TopAbs_VERTEX); exp0.More(); exp0.Next()) {
653  TopoDS_Vertex vertex = TopoDS::Vertex(exp0.Current());
654  if(_vertexTag.IsBound(vertex)) {
655  int tag = _vertexTag.Find(vertex);
656  _vertexTag.UnBind(vertex);
657  _tagVertex.UnBind(tag);
658  _toRemove.insert(std::make_pair(0, tag));
659  _changed = true;
660  }
661  }
662  for(int d = -2; d <= 3; d++) _recomputeMaxTag(d);
663 }
664 
665 void OCC_Internals::_unbind()
666 {
667  for(int i = 0; i < 6; i++) _maxTag[i] = 0;
668 
669  TopTools_DataMapIteratorOfDataMapOfIntegerShape exp;
670  exp.Initialize(_tagVertex);
671  for(; exp.More(); exp.Next())
672  _toRemove.insert(std::make_pair(0, exp.Key()));
673  exp.Initialize(_tagEdge);
674  for(; exp.More(); exp.Next())
675  _toRemove.insert(std::make_pair(1, exp.Key()));
676  exp.Initialize(_tagFace);
677  for(; exp.More(); exp.Next())
678  _toRemove.insert(std::make_pair(2, exp.Key()));
679  exp.Initialize(_tagSolid);
680  for(; exp.More(); exp.Next())
681  _toRemove.insert(std::make_pair(3, exp.Key()));
682  exp.Initialize(_tagWire);
683  for(; exp.More(); exp.Next())
684  _toRemove.insert(std::make_pair(-1, exp.Key()));
685  exp.Initialize(_tagShell);
686  for(; exp.More(); exp.Next())
687  _toRemove.insert(std::make_pair(-2, exp.Key()));
688 
689  _tagVertex.Clear();
690  _tagEdge.Clear();
691  _tagFace.Clear();
692  _tagSolid.Clear();
693  _tagWire.Clear();
694  _tagShell.Clear();
695 
696  _vertexTag.Clear();
697  _edgeTag.Clear();
698  _faceTag.Clear();
699  _solidTag.Clear();
700  _wireTag.Clear();
701  _shellTag.Clear();
702 
703  _changed = true;
704 }
705 
706 void OCC_Internals::_multiBind(const TopoDS_Shape &shape, int tag,
707  std::vector<std::pair<int, int> > &outDimTags,
708  bool highestDimOnly, bool recursive,
709  bool returnNewOnly)
710 {
711  TopExp_Explorer exp0;
712  int count = 0;
713  for(exp0.Init(shape, TopAbs_SOLID); exp0.More(); exp0.Next()) {
714  TopoDS_Solid solid = TopoDS::Solid(exp0.Current());
715  bool exists = false;
716  int t = tag;
717  if(t <= 0) {
718  if(_solidTag.IsBound(solid)) {
719  t = _solidTag.Find(solid);
720  exists = true;
721  }
722  else
723  t = getMaxTag(3) + 1;
724  }
725  else if(count) {
726  Msg::Error("Cannot bind multiple volumes to single tag %d", t);
727  return;
728  }
729  if(!exists) _bind(solid, t, recursive);
730  if(!exists || !returnNewOnly)
731  outDimTags.push_back(std::make_pair(3, t));
732  count++;
733  }
734  if(highestDimOnly && count) return;
735  for(exp0.Init(shape, TopAbs_FACE); exp0.More(); exp0.Next()) {
736  TopoDS_Face face = TopoDS::Face(exp0.Current());
737  bool exists = false;
738  int t = tag;
739  if(t <= 0) {
740  if(_faceTag.IsBound(face)) {
741  t = _faceTag.Find(face);
742  exists = true;
743  }
744  else
745  t = getMaxTag(2) + 1;
746  }
747  else if(count) {
748  Msg::Error("Cannot bind multiple surfaces to single tag %d", t);
749  return;
750  }
751  if(!exists) _bind(face, t, recursive);
752  if(!exists || !returnNewOnly)
753  outDimTags.push_back(std::make_pair(2, t));
754  count++;
755  }
756  if(highestDimOnly && count) return;
757  for(exp0.Init(shape, TopAbs_EDGE); exp0.More(); exp0.Next()) {
758  TopoDS_Edge edge = TopoDS::Edge(exp0.Current());
759  bool exists = false;
760  int t = tag;
761  if(t <= 0) {
762  if(_edgeTag.IsBound(edge)) {
763  t = _edgeTag.Find(edge);
764  exists = true;
765  }
766  else
767  t = getMaxTag(1) + 1;
768  }
769  else if(count) {
770  Msg::Error("Cannot bind multiple curves to single tag %d", t);
771  return;
772  }
773  if(!exists) _bind(edge, t, recursive);
774  if(!exists || !returnNewOnly)
775  outDimTags.push_back(std::make_pair(1, t));
776  count++;
777  }
778  if(highestDimOnly && count) return;
779  for(exp0.Init(shape, TopAbs_VERTEX); exp0.More(); exp0.Next()) {
780  TopoDS_Vertex vertex = TopoDS::Vertex(exp0.Current());
781  bool exists = false;
782  int t = tag;
783  if(t <= 0) {
784  if(_vertexTag.IsBound(vertex)) {
785  t = _vertexTag.Find(vertex);
786  exists = true;
787  }
788  else
789  t = getMaxTag(0) + 1;
790  }
791  else if(count) {
792  Msg::Error("Cannot bind multiple points to single tag %d", t);
793  return;
794  }
795  if(!exists) _bind(vertex, t, recursive);
796  if(!exists || !returnNewOnly)
797  outDimTags.push_back(std::make_pair(0, t));
798  count++;
799  }
800 }
801 
802 bool OCC_Internals::_isBound(int dim, int tag)
803 {
804  switch(dim) {
805  case 0: return _tagVertex.IsBound(tag);
806  case 1: return _tagEdge.IsBound(tag);
807  case 2: return _tagFace.IsBound(tag);
808  case 3: return _tagSolid.IsBound(tag);
809  case -1: return _tagWire.IsBound(tag);
810  case -2: return _tagShell.IsBound(tag);
811  default: return false;
812  }
813 }
814 
815 bool OCC_Internals::_isBound(int dim, const TopoDS_Shape &shape)
816 {
817  switch(dim) {
818  case 0: return _vertexTag.IsBound(shape);
819  case 1: return _edgeTag.IsBound(shape);
820  case 2: return _faceTag.IsBound(shape);
821  case 3: return _solidTag.IsBound(shape);
822  case -1: return _wireTag.IsBound(shape);
823  case -2: return _shellTag.IsBound(shape);
824  default: return false;
825  }
826 }
827 
828 TopoDS_Shape OCC_Internals::_find(int dim, int tag)
829 {
830  switch(dim) {
831  case 0: return _tagVertex.Find(tag);
832  case 1: return _tagEdge.Find(tag);
833  case 2: return _tagFace.Find(tag);
834  case 3: return _tagSolid.Find(tag);
835  case -1: return _tagWire.Find(tag);
836  case -2: return _tagShell.Find(tag);
837  default: return TopoDS_Shape();
838  }
839 }
840 
841 int OCC_Internals::_find(int dim, const TopoDS_Shape &shape)
842 {
843  switch(dim) {
844  case 0: return _vertexTag.Find(shape);
845  case 1: return _edgeTag.Find(shape);
846  case 2: return _faceTag.Find(shape);
847  case 3: return _solidTag.Find(shape);
848  case -1: return _wireTag.Find(shape);
849  case -2: return _shellTag.Find(shape);
850  default: return -1;
851  }
852 }
853 
854 bool OCC_Internals::addVertex(int &tag, double x, double y, double z,
855  double meshSize)
856 {
857  if(tag >= 0 && _tagVertex.IsBound(tag)) {
858  Msg::Error("OpenCASCADE point with tag %d already exists", tag);
859  return false;
860  }
861  TopoDS_Vertex result;
862  try {
863  gp_Pnt aPnt(x, y, z);
864  BRepBuilderAPI_MakeVertex v(aPnt);
865  v.Build();
866  if(!v.IsDone()) {
867  Msg::Error("Could not create point");
868  return false;
869  }
870  result = v.Vertex();
871  } catch(Standard_Failure &err) {
872  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
873  return false;
874  }
875  if(meshSize > 0 && meshSize < MAX_LC)
876  _attributes->insert(new OCCAttributes(0, result, meshSize));
877  if(tag < 0) tag = getMaxTag(0) + 1;
878  _bind(result, tag, true);
879  return true;
880 }
881 
882 bool OCC_Internals::addLine(int &tag, int startTag, int endTag)
883 {
884  if(tag >= 0 && _tagEdge.IsBound(tag)) {
885  Msg::Error("OpenCASCADE curve with tag %d already exists", tag);
886  return false;
887  }
888  if(!_tagVertex.IsBound(startTag)) {
889  Msg::Error("Unknown OpenCASCADE point with tag %d", startTag);
890  return false;
891  }
892  if(!_tagVertex.IsBound(endTag)) {
893  Msg::Error("Unknown OpenCASCADE point with tag %d", endTag);
894  return false;
895  }
896  if(startTag == endTag) {
897  Msg::Error("Start and end points of line should be different");
898  return false;
899  }
900  TopoDS_Edge result;
901  try {
902  TopoDS_Vertex start = TopoDS::Vertex(_tagVertex.Find(startTag));
903  TopoDS_Vertex end = TopoDS::Vertex(_tagVertex.Find(endTag));
904  BRepBuilderAPI_MakeEdge e(start, end);
905  e.Build();
906  if(!e.IsDone()) {
907  Msg::Error("Could not create line");
908  return false;
909  }
910  result = e.Edge();
911  } catch(Standard_Failure &err) {
912  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
913  return false;
914  }
915  if(tag < 0) tag = getMaxTag(1) + 1;
916  _bind(result, tag, true);
917  return true;
918 }
919 
920 bool OCC_Internals::addLine(int &tag, const std::vector<int> &pointTags)
921 {
922  if(pointTags.size() == 2) return addLine(tag, pointTags[0], pointTags[1]);
923 
924  // FIXME: if tag < 0 we could create multiple lines
925  Msg::Error("OpenCASCADE polyline currently not supported");
926  return false;
927 }
928 
929 bool OCC_Internals::addCircleArc(int &tag, int startTag, int centerTag,
930  int endTag)
931 {
932  if(tag >= 0 && _tagEdge.IsBound(tag)) {
933  Msg::Error("OpenCASCADE curve with tag %d already exists", tag);
934  return false;
935  }
936  if(!_tagVertex.IsBound(startTag)) {
937  Msg::Error("Unknown OpenCASCADE point with tag %d", startTag);
938  return false;
939  }
940  if(!_tagVertex.IsBound(centerTag)) {
941  Msg::Error("Unknown OpenCASCADE point with tag %d", centerTag);
942  return false;
943  }
944  if(!_tagVertex.IsBound(endTag)) {
945  Msg::Error("Unknown OpenCASCADE point with tag %d", endTag);
946  return false;
947  }
948 
949  TopoDS_Edge result;
950  TopoDS_Vertex start = TopoDS::Vertex(_tagVertex.Find(startTag));
951  TopoDS_Vertex center = TopoDS::Vertex(_tagVertex.Find(centerTag));
952  TopoDS_Vertex end = TopoDS::Vertex(_tagVertex.Find(endTag));
953  gp_Pnt aP1 = BRep_Tool::Pnt(start);
954  gp_Pnt aP2 = BRep_Tool::Pnt(center);
955  gp_Pnt aP3 = BRep_Tool::Pnt(end);
956  Standard_Real Radius = aP1.Distance(aP2);
957 
958  gp_Pln p;
959  try {
960  p = gce_MakePln(aP1, aP2, aP3).Value();
961  }
962  catch (...){
963  Msg::Info("Could not make plane from 3 points - assuming z=%g", aP2.Z());
964  gp_Dir N_dir(0., 0., 1.);
965  p = gce_MakePln(aP2, N_dir).Value();
966  }
967 
968  try {
969  gce_MakeCirc MC(aP2, p, Radius);
970  if(!MC.IsDone()) {
971  Msg::Error("Could not build circle");
972  return false;
973  }
974  const gp_Circ &Circ = MC.Value();
975  Standard_Real Alpha1 = ElCLib::Parameter(Circ, aP1);
976  Standard_Real Alpha2 = ElCLib::Parameter(Circ, aP3);
977  Handle(Geom_Circle) C = new Geom_Circle(Circ);
978  Handle(Geom_TrimmedCurve) arc =
979  new Geom_TrimmedCurve(C, Alpha1, Alpha2, false);
980  BRepBuilderAPI_MakeEdge e(arc, start, end);
981  e.Build();
982  if(!e.IsDone()) {
983  Msg::Error("Could not create circle arc");
984  return false;
985  }
986  result = e.Edge();
987  } catch(Standard_Failure &err) {
988  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
989  return false;
990  }
991  if(tag < 0) tag = getMaxTag(1) + 1;
992  _bind(result, tag, true);
993  return true;
994 }
995 
996 bool OCC_Internals::addEllipseArc(int &tag, int startTag, int centerTag,
997  int majorTag, int endTag)
998 {
999  if(tag >= 0 && _tagEdge.IsBound(tag)) {
1000  Msg::Error("OpenCASCADE curve with tag %d already exists", tag);
1001  return false;
1002  }
1003  if(!_tagVertex.IsBound(startTag)) {
1004  Msg::Error("Unknown OpenCASCADE point with tag %d", startTag);
1005  return false;
1006  }
1007  if(!_tagVertex.IsBound(centerTag)) {
1008  Msg::Error("Unknown OpenCASCADE point with tag %d", centerTag);
1009  return false;
1010  }
1011  if(!_tagVertex.IsBound(majorTag)) {
1012  Msg::Error("Unknown OpenCASCADE point with tag %d", majorTag);
1013  return false;
1014  }
1015  if(!_tagVertex.IsBound(endTag)) {
1016  Msg::Error("Unknown OpenCASCADE point with tag %d", endTag);
1017  return false;
1018  }
1019 
1020  TopoDS_Edge result;
1021  try {
1022  TopoDS_Vertex start = TopoDS::Vertex(_tagVertex.Find(startTag));
1023  TopoDS_Vertex center = TopoDS::Vertex(_tagVertex.Find(centerTag));
1024  TopoDS_Vertex major = TopoDS::Vertex(_tagVertex.Find(majorTag));
1025  TopoDS_Vertex end = TopoDS::Vertex(_tagVertex.Find(endTag));
1026  gp_Pnt startPnt = BRep_Tool::Pnt(start);
1027  gp_Pnt centerPnt = BRep_Tool::Pnt(center);
1028  gp_Pnt majorPnt = BRep_Tool::Pnt(major);
1029  gp_Pnt endPnt = BRep_Tool::Pnt(end);
1030  gp_XYZ x1 = startPnt.XYZ() - centerPnt.XYZ();
1031  gp_XYZ x2 = endPnt.XYZ() - centerPnt.XYZ();
1032  gp_Dir u = majorPnt.XYZ() - centerPnt.XYZ();
1033  gp_Dir v;
1034  if(!u.IsParallel(x1, 1e-6))
1035  v = x1 - x1.Dot(u.XYZ()) * u.XYZ();
1036  else if(!u.IsParallel(x2, 1e-6))
1037  v = x2 - x2.Dot(u.XYZ()) * u.XYZ();
1038  else {
1039  Msg::Error("The points do not define an ellipse");
1040  return false;
1041  }
1042  Standard_Real x1u = Square(x1.Dot(u.XYZ()));
1043  Standard_Real x1v = Square(x1.Dot(v.XYZ()));
1044  Standard_Real x2u = Square(x2.Dot(u.XYZ()));
1045  Standard_Real x2v = Square(x2.Dot(v.XYZ()));
1046  if(IsEqual(x1u, x2u) || IsEqual(x1v, x2v)) {
1047  Msg::Error("The points do not define an ellipse");
1048  return false;
1049  }
1050  Standard_Real a2 = (x1v * x2u - x1u * x2v) / (x1v - x2v);
1051  Standard_Real b2 = (x1u * x2v - x1v * x2u) / (x1u - x2u);
1052  if(a2 <= 0.0 || b2 <= 0.0) {
1053  Msg::Error("The points do not define an ellipse");
1054  return false;
1055  }
1056  Standard_Real a; // major radius
1057  Standard_Real b; // minor radius
1058  gp_Ax2 Axes; // ellipse local coordinate system
1059  if(a2 >= b2) {
1060  a = Sqrt(a2);
1061  b = Sqrt(b2);
1062  Axes = gp_Ax2(centerPnt, u ^ v, u);
1063  }
1064  else {
1065  Msg::Warning("Major radius smaller than minor radius");
1066  a = Sqrt(b2);
1067  b = Sqrt(a2);
1068  Axes = gp_Ax2(centerPnt, v ^ u, v);
1069  }
1070  gce_MakeElips ME(Axes, a, b);
1071  if(!ME.IsDone()) {
1072  Msg::Error("Could not build ellipse");
1073  return false;
1074  }
1075  const gp_Elips &Elips = ME.Value();
1076  Standard_Real Alpha1 = ElCLib::Parameter(Elips, startPnt);
1077  Standard_Real Alpha2 = ElCLib::Parameter(Elips, endPnt);
1078  Handle(Geom_Ellipse) E = new Geom_Ellipse(Elips);
1079  Handle(Geom_TrimmedCurve) arc;
1080  if((Alpha2 > Alpha1 && Alpha2 - Alpha1 < M_PI) || Alpha1 - Alpha2 > M_PI)
1081  arc = new Geom_TrimmedCurve(E, Alpha1, Alpha2, true);
1082  else
1083  arc = new Geom_TrimmedCurve(E, Alpha2, Alpha1, false);
1084  BRepBuilderAPI_MakeEdge e(arc, start, end);
1085  e.Build();
1086  if(!e.IsDone()) {
1087  Msg::Error("Could not create ellipse arc");
1088  return false;
1089  }
1090  result = e.Edge();
1091  } catch(Standard_Failure &err) {
1092  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
1093  return false;
1094  }
1095  if(tag < 0) tag = getMaxTag(1) + 1;
1096  _bind(result, tag, true);
1097  return true;
1098 }
1099 
1100 bool OCC_Internals::addCircle(int &tag, double x, double y, double z, double r,
1101  double angle1, double angle2,
1102  const std::vector<double> &N,
1103  const std::vector<double> &V)
1104 {
1105  if(tag >= 0 && _tagEdge.IsBound(tag)) {
1106  Msg::Error("OpenCASCADE curve with tag %d already exists", tag);
1107  return false;
1108  }
1109  if(r <= 0) {
1110  Msg::Error("Circle radius should be positive");
1111  return false;
1112  }
1113 
1114  TopoDS_Edge result;
1115  try {
1116  gp_Circ circ;
1117  gp_Pnt center(x, y, z);
1118  if(N.size() == 3 && V.size() == 3) {
1119  gp_Dir N_dir(N[0], N[1], N[2]);
1120  gp_Dir x_dir(V[0], V[1], V[2]);
1121  gp_Ax2 axis(center, N_dir, x_dir);
1122  circ.SetPosition(axis);
1123  }
1124  else if(N.size() == 3) {
1125  gp_Dir N_dir(N[0], N[1], N[2]);
1126  gp_Ax2 axis(center, N_dir);
1127  circ.SetPosition(axis);
1128  }
1129  else {
1130  gp_Dir N_dir(0., 0., 1.);
1131  gp_Dir x_dir(1., 0., 0.);
1132  gp_Ax2 axis(center, N_dir, x_dir);
1133  circ.SetPosition(axis);
1134  }
1135  circ.SetRadius(r);
1136  if(angle1 == 0. && angle2 == 2 * M_PI) {
1137  result = BRepBuilderAPI_MakeEdge(circ);
1138  }
1139  else {
1140  Handle(Geom_Circle) C = new Geom_Circle(circ);
1141  Handle(Geom_TrimmedCurve) arc =
1142  new Geom_TrimmedCurve(C, angle1, angle2, true);
1143  BRepBuilderAPI_MakeEdge e(arc);
1144  if(!e.IsDone()) {
1145  Msg::Error("Could not create circle arc");
1146  return false;
1147  }
1148  result = e.Edge();
1149  }
1150  } catch(Standard_Failure &err) {
1151  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
1152  return false;
1153  }
1154  if(tag < 0) tag = getMaxTag(1) + 1;
1155  _bind(result, tag, true);
1156  return true;
1157 }
1158 
1159 bool OCC_Internals::addEllipse(int &tag, double x, double y, double z,
1160  double rx, double ry, double angle1,
1161  double angle2, const std::vector<double> &N,
1162  const std::vector<double> &V)
1163 {
1164  if(tag >= 0 && _tagEdge.IsBound(tag)) {
1165  Msg::Error("OpenCASCADE curve with tag %d already exists", tag);
1166  return false;
1167  }
1168  if(ry > rx) {
1169  Msg::Error("Major radius rx should be larger than minor radius ry");
1170  return false;
1171  }
1172  if(ry <= 0 || rx <= 0) {
1173  Msg::Error("Ellipse radii should be positive");
1174  return false;
1175  }
1176 
1177  TopoDS_Edge result;
1178  try {
1179  gp_Elips el;
1180  gp_Pnt center(x, y, z);
1181  if(N.size() == 3 && V.size() == 3) {
1182  gp_Dir N_dir(N[0], N[1], N[2]);
1183  gp_Dir x_dir(V[0], V[1], V[2]);
1184  gp_Ax2 axis(center, N_dir, x_dir);
1185  el.SetPosition(axis);
1186  }
1187  else if(N.size() == 3) {
1188  gp_Dir N_dir(N[0], N[1], N[2]);
1189  gp_Ax2 axis(center, N_dir);
1190  el.SetPosition(axis);
1191  }
1192  else {
1193  gp_Dir N_dir(0., 0., 1.);
1194  gp_Dir x_dir(1., 0., 0.);
1195  gp_Ax2 axis(center, N_dir, x_dir);
1196  el.SetPosition(axis);
1197  }
1198  el.SetMajorRadius(rx);
1199  el.SetMinorRadius(ry);
1200  if(angle1 == 0 && angle2 == 2 * M_PI) {
1201  result = BRepBuilderAPI_MakeEdge(el);
1202  }
1203  else {
1204  Handle(Geom_Ellipse) E = new Geom_Ellipse(el);
1205  Handle(Geom_TrimmedCurve) arc =
1206  new Geom_TrimmedCurve(E, angle1, angle2, true);
1207  BRepBuilderAPI_MakeEdge e(arc);
1208  if(!e.IsDone()) {
1209  Msg::Error("Could not create ellipse arc");
1210  return false;
1211  }
1212  result = e.Edge();
1213  }
1214  } catch(Standard_Failure &err) {
1215  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
1216  return false;
1217  }
1218  if(tag < 0) tag = getMaxTag(1) + 1;
1219  _bind(result, tag, true);
1220  return true;
1221 }
1222 
1223 void debugBSpline(const Handle(Geom_BSplineCurve) & curve)
1224 {
1225  int degree = curve->Degree();
1226  bool periodic = curve->IsPeriodic();
1227  bool rational = curve->IsRational();
1228 
1229  int npoles = curve->NbPoles();
1230  TColgp_Array1OfPnt poles(1, npoles);
1231  curve->Poles(poles);
1232 
1233  TColStd_Array1OfReal weights(1, npoles);
1234  curve->Weights(weights);
1235 
1236  int nknots = curve->NbKnots();
1237  TColStd_Array1OfReal knots(1, nknots);
1238  curve->Knots(knots);
1239 
1240  TColStd_Array1OfInteger mults(1, nknots);
1241  curve->Multiplicities(mults);
1242 
1243  printf("BSpline: degree %d, periodic %d, rational %d\n", degree, periodic,
1244  rational);
1245  printf("Poles:\n");
1246  for(int i = 1; i <= npoles; i++)
1247  printf(" %d (%g, %g, %g) weight %g\n", i, poles(i).X(), poles(i).Y(),
1248  poles(i).Z(), weights(i));
1249  printf("Knots:\n");
1250  for(int i = 1; i <= nknots; i++)
1251  printf(" %d (%g) mult %d\n", i, knots(i), mults(i));
1252 }
1253 
1254 bool OCC_Internals::_addBSpline(int &tag, const std::vector<int> &pointTags,
1255  int mode, const int degree,
1256  const std::vector<double> &weights,
1257  const std::vector<double> &knots,
1258  const std::vector<int> &multiplicities,
1259  const std::vector<SVector3> &tangents)
1260 {
1261  if(tag >= 0 && _tagEdge.IsBound(tag)) {
1262  Msg::Error("OpenCASCADE curve with tag %d already exists", tag);
1263  return false;
1264  }
1265  if(pointTags.size() < 2) {
1266  Msg::Error("Number of control points should be at least 2");
1267  return false;
1268  }
1269 
1270  TopoDS_Edge result;
1271  try {
1272  TColgp_Array1OfPnt ctrlPoints(1, pointTags.size());
1273  TopoDS_Vertex start, end;
1274  for(std::size_t i = 0; i < pointTags.size(); i++) {
1275  if(!_tagVertex.IsBound(pointTags[i])) {
1276  Msg::Error("Unknown OpenCASCADE point with tag %d", pointTags[i]);
1277  return false;
1278  }
1279  TopoDS_Vertex vertex = TopoDS::Vertex(_tagVertex.Find(pointTags[i]));
1280  ctrlPoints.SetValue(i + 1, BRep_Tool::Pnt(vertex));
1281  if(i == 0) start = vertex;
1282  if(i == pointTags.size() - 1) end = vertex;
1283  }
1284  bool periodic = (pointTags.front() == pointTags.back());
1285  if(mode == 0) {
1286  // BSpline through points (called "Spline" in Gmsh; will be C2, whereas it
1287  // is only C1 in the GEO kernel)
1288  int np = periodic ? ctrlPoints.Length() - 1 : ctrlPoints.Length();
1289  Handle(TColgp_HArray1OfPnt) p = new TColgp_HArray1OfPnt(1, np);
1290  for(int i = 1; i <= np; i++) p->SetValue(i, ctrlPoints(i));
1291  GeomAPI_Interpolate intp(p, periodic, CTX::instance()->geom.tolerance);
1292  if(tangents.size() == 2) {
1293  gp_Vec t1(tangents[0].x(), tangents[0].y(), tangents[0].z());
1294  gp_Vec tN(tangents[1].x(), tangents[1].y(), tangents[1].z());
1295  intp.Load(t1, tN);
1296  }
1297  else if(tangents.size() == pointTags.size()) {
1298  TColgp_Array1OfVec Tangents(1, tangents.size());
1299  Handle(TColStd_HArray1OfBoolean) TangentFlags =
1300  new TColStd_HArray1OfBoolean(1, tangents.size());
1301  for(std::size_t i = 1; i <= tangents.size(); i++) {
1302  gp_Vec t(tangents[i - 1].x(), tangents[i - 1].y(), tangents[i - 1].z());
1303  Tangents.SetValue(i, t);
1304  if(tangents[i - 1].normSq() < 1e-12) {
1305  TangentFlags->SetValue(i, Standard_False);
1306  }
1307  else {
1308  TangentFlags->SetValue(i, Standard_True);
1309  }
1310  }
1311  intp.Load(Tangents, TangentFlags);
1312  }
1313  else if(!tangents.empty()) {
1314  Msg::Warning("Wrong number of tangent constraints for spline (%lu != %lu)",
1315  tangents.size(), pointTags.size());
1316  }
1317  intp.Perform();
1318  if(!intp.IsDone()) {
1319  Msg::Error("Could not interpolate spline");
1320  return false;
1321  }
1322  Handle(Geom_BSplineCurve) curve = intp.Curve();
1323  BRepBuilderAPI_MakeEdge e(curve, start, end);
1324  if(!e.IsDone()) {
1325  Msg::Error("Could not create spline");
1326  return false;
1327  }
1328  result = e.Edge();
1329  }
1330  else if(mode == 1) {
1331  // Bezier curve
1332  Handle(Geom_BezierCurve) curve = new Geom_BezierCurve(ctrlPoints);
1333  BRepBuilderAPI_MakeEdge e(curve, start, end);
1334  if(!e.IsDone()) {
1335  Msg::Error("Could not create Bezier curve");
1336  return false;
1337  }
1338  result = e.Edge();
1339  }
1340  else if(mode == 2) {
1341  // General BSpline curve, polynomial or rational, with explicit degree,
1342  // weights, knots and multiplicities
1343  if(degree < 0) {
1344  Msg::Error("BSpline degree (%d) should be >= 0", degree);
1345  return false;
1346  }
1347  if(weights.size() != pointTags.size()) {
1348  Msg::Error("Number of BSpline weights (%d) and control points (%d) "
1349  "should be equal",
1350  weights.size(), pointTags.size());
1351  return false;
1352  }
1353  if(knots.size() != multiplicities.size()) {
1354  Msg::Error(
1355  "Number of BSpline knots (%d) and multiplicities (%d) should be "
1356  "equal",
1357  knots.size(), multiplicities.size());
1358  return false;
1359  }
1360  if(knots.size() < 2) {
1361  Msg::Error("Number of BSpline knots (%d) should be >= 2", knots.size());
1362  return false;
1363  }
1364  for(std::size_t i = 0; i < knots.size() - 1; i++) {
1365  if(knots[i] >= knots[i + 1]) {
1366  Msg::Error("BSpline knots should be increasing: knot %d (%g) > "
1367  "knot %d (%g)",
1368  i, knots[i], i + 1, knots[i + 1]);
1369  return false;
1370  }
1371  }
1372  for(std::size_t i = 0; i < multiplicities.size(); i++) {
1373  if(multiplicities[i] < 1) {
1374  Msg::Error("BSpline multiplicities should be >= 1");
1375  return false;
1376  }
1377  if(i != 0 && i != multiplicities.size() - 1 &&
1378  multiplicities[i] > degree) {
1379  Msg::Error(
1380  "BSpline interior knot multiplicities should be <= degree");
1381  return false;
1382  }
1383  if((i == 0 || i == multiplicities.size() - 1) &&
1384  multiplicities[i] > degree + 1) {
1385  Msg::Error("BSpline end knot multiplicities should be <= degree + 1");
1386  return false;
1387  }
1388  }
1389  if(periodic) {
1390  if(multiplicities.front() != multiplicities.back()) {
1391  Msg::Error(
1392  "Periodic BSpline end knot multiplicies (%d and %d) should "
1393  "be equal",
1394  multiplicities.front(), multiplicities.back());
1395  return false;
1396  }
1397  const auto sum = std::accumulate(
1398  begin(multiplicities), std::prev(std::end(multiplicities)),
1399  std::size_t(0),
1400  [](std::size_t const partial_sum, int const multiplicity) {
1401  return partial_sum + multiplicity;
1402  });
1403  if(pointTags.size() - 1 != sum) {
1404  Msg::Error("Number of control points - 1 for periodic BSpline should "
1405  "be equal to the sum of multiplicities for all knots "
1406  "except the first (or last)");
1407  return false;
1408  }
1409  }
1410  else {
1411  const auto sum = std::accumulate(
1412  begin(multiplicities), std::end(multiplicities), std::size_t(0),
1413  [](std::size_t const partial_sum, int const multiplicity) {
1414  return partial_sum + multiplicity;
1415  });
1416  if(pointTags.size() != sum - degree - 1) {
1417  Msg::Error("Number of control points for non-periodic BSpline should "
1418  "be equal to the sum of multiplicities - degree - 1");
1419  return false;
1420  }
1421  }
1422  int np = (periodic ? ctrlPoints.Length() - 1 : ctrlPoints.Length());
1423  TColgp_Array1OfPnt p(1, np);
1424  TColStd_Array1OfReal w(1, np);
1425  for(int i = 1; i <= np; i++) {
1426  p.SetValue(i, ctrlPoints(i));
1427  w.SetValue(i, weights[i - 1]);
1428  }
1429  TColStd_Array1OfReal k(1, knots.size());
1430  for(std::size_t i = 0; i < knots.size(); i++) k.SetValue(i + 1, knots[i]);
1431  TColStd_Array1OfInteger m(1, multiplicities.size());
1432  for(std::size_t i = 0; i < multiplicities.size(); i++)
1433  m.SetValue(i + 1, multiplicities[i]);
1434  Handle(Geom_BSplineCurve) curve =
1435  new Geom_BSplineCurve(p, w, k, m, degree, periodic);
1436  if(curve->StartPoint().IsEqual(BRep_Tool::Pnt(start),
1438  curve->EndPoint().IsEqual(BRep_Tool::Pnt(end),
1440  !curve->StartPoint().IsEqual(curve->EndPoint(),
1442  BRepBuilderAPI_MakeEdge e(curve, start, end);
1443  if(!e.IsDone()) {
1444  Msg::Error("Could not create BSpline curve (with end points)");
1445  return false;
1446  }
1447  result = e.Edge();
1448  }
1449  else { // will create new topo vertices as necessary
1450  BRepBuilderAPI_MakeEdge e(curve);
1451  if(!e.IsDone()) {
1452  Msg::Error("Could not create BSpline curve (without end points)");
1453  return false;
1454  }
1455  result = e.Edge();
1456  // copy mesh size from start control point to new topo vertex; this way
1457  // we'll behave more like the built-in kernel (although the built-in
1458  // kernel keeps track of all the control points)
1459  double lc = _attributes->getMeshSize(0, start);
1460  if(lc > 0 && lc < MAX_LC) {
1461  TopExp_Explorer exp0;
1462  for(exp0.Init(result, TopAbs_VERTEX); exp0.More(); exp0.Next()) {
1463  TopoDS_Vertex vertex = TopoDS::Vertex(exp0.Current());
1464  _attributes->insert(new OCCAttributes(0, vertex, lc));
1465  }
1466  }
1467  }
1468  }
1469  } catch(Standard_Failure &err) {
1470  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
1471  return false;
1472  }
1473  if(tag < 0) tag = getMaxTag(1) + 1;
1474  _bind(result, tag, true);
1475  return true;
1476 }
1477 
1478 bool OCC_Internals::addSpline(int &tag, const std::vector<int> &pointTags,
1479  const std::vector<SVector3> &tangents)
1480 {
1481  std::vector<double> weights;
1482  std::vector<double> knots;
1483  std::vector<int> multiplicities;
1484  return _addBSpline(tag, pointTags, 0, -1, weights, knots, multiplicities,
1485  tangents);
1486 }
1487 
1488 bool OCC_Internals::addBezier(int &tag, const std::vector<int> &pointTags)
1489 {
1490  return _addBSpline(tag, pointTags, 1);
1491 }
1492 
1493 bool OCC_Internals::addBSpline(int &tag, const std::vector<int> &pointTags,
1494  const int degree,
1495  const std::vector<double> &weights,
1496  const std::vector<double> &knots,
1497  const std::vector<int> &multiplicities)
1498 {
1499  int np = pointTags.size();
1500  if(np < 2) {
1501  Msg::Error("BSpline curve requires at least 2 control points");
1502  return false;
1503  }
1504  int d = degree;
1505  std::vector<double> w(weights), k(knots);
1506  std::vector<int> m(multiplicities);
1507  // degree 3 if not specified...
1508  if(d <= 0) d = 3;
1509  // ... or number of control points - 1 if not enough points
1510  if(d > np - 1) d = np - 1;
1511  // automatic default weights if not provided:
1512  if(w.empty()) w.resize(np, 1);
1513  // automatic default knots and multiplicities if not provided:
1514  if(k.empty()) {
1515  bool periodic = (pointTags.front() == pointTags.back());
1516  if(!periodic) {
1517  int sumOfAllMult = np + d + 1;
1518  int numKnots = sumOfAllMult - 2 * d;
1519  if(numKnots < 2) {
1520  Msg::Error("Not enough control points for building BSpline of "
1521  "degree %d",
1522  d);
1523  return false;
1524  }
1525  k.resize(numKnots);
1526  for(std::size_t i = 0; i < k.size(); i++) k[i] = i;
1527  m.resize(numKnots, 1);
1528  m.front() = d + 1;
1529  m.back() = d + 1;
1530  }
1531  else {
1532  k.resize(np);
1533  for(std::size_t i = 0; i < k.size(); i++) k[i] = i;
1534  m.resize(k.size(), 1);
1535  }
1536  }
1537  return _addBSpline(tag, pointTags, 2, d, w, k, m);
1538 }
1539 
1540 bool OCC_Internals::addWire(int &tag, const std::vector<int> &curveTags,
1541  bool checkClosed)
1542 {
1543  if(tag >= 0 && _tagWire.IsBound(tag)) {
1544  Msg::Error("OpenCASCADE wire or curve loop with tag %d already exists", tag);
1545  return false;
1546  }
1547 
1548  // Note: contrary to shells wires are always "sewed", i.e., a valid wire is
1549  // constructed if points are geometrically at the same location (even if they
1550  // are not topologically identical); there is thus no need to add a "sewing"
1551  // option.
1552  try {
1553  BRepBuilderAPI_MakeWire w;
1554  TopoDS_Wire wire;
1555  for(std::size_t i = 0; i < curveTags.size(); i++) {
1556  // all curve tags are > 0 for OCC : but to improve compatibility between
1557  // GEO and OCC factories, we allow negative tags - and simply ignore the
1558  // sign here
1559  int t = std::abs(curveTags[i]);
1560  if(!_tagEdge.IsBound(t)) {
1561  Msg::Error("Unknown OpenCASCADE curve with tag %d", t);
1562  return false;
1563  }
1564  TopoDS_Edge edge = TopoDS::Edge(_tagEdge.Find(t));
1565  w.Add(edge);
1566  }
1567  w.Build();
1568  if(!w.IsDone()) {
1569  Msg::Error("Could not create wire");
1570  return false;
1571  }
1572  wire = w.Wire();
1573  if(checkClosed && !wire.Closed()) {
1574  Msg::Error("Curve loop is not closed");
1575  return false;
1576  }
1577  if(tag < 0) tag = getMaxTag(-1) + 1;
1578  _bind(wire, tag, true);
1579  } catch(Standard_Failure &err) {
1580  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
1581  return false;
1582  }
1583  return true;
1584 }
1585 
1586 bool OCC_Internals::addCurveLoop(int &tag, const std::vector<int> &curveTags)
1587 {
1588  return addWire(tag, curveTags, true);
1589 }
1590 
1591 static bool makeRectangle(TopoDS_Face &result, double x, double y, double z,
1592  double dx, double dy, double roundedRadius)
1593 {
1594  if(!dx || !dy) {
1595  Msg::Error("Rectangle with zero width or height");
1596  return false;
1597  }
1598  try {
1599  TopoDS_Wire wire;
1600  if(roundedRadius <= 0.) {
1601  double x1 = x, y1 = y, z1 = z, x2 = x1 + dx, y2 = y1 + dy;
1602  TopoDS_Vertex v1 = BRepBuilderAPI_MakeVertex(gp_Pnt(x1, y1, z1));
1603  TopoDS_Vertex v2 = BRepBuilderAPI_MakeVertex(gp_Pnt(x2, y1, z1));
1604  TopoDS_Vertex v3 = BRepBuilderAPI_MakeVertex(gp_Pnt(x2, y2, z1));
1605  TopoDS_Vertex v4 = BRepBuilderAPI_MakeVertex(gp_Pnt(x1, y2, z1));
1606  TopoDS_Edge e1 = BRepBuilderAPI_MakeEdge(v1, v2);
1607  TopoDS_Edge e2 = BRepBuilderAPI_MakeEdge(v2, v3);
1608  TopoDS_Edge e3 = BRepBuilderAPI_MakeEdge(v3, v4);
1609  TopoDS_Edge e4 = BRepBuilderAPI_MakeEdge(v4, v1);
1610  wire = BRepBuilderAPI_MakeWire(e1, e2, e3, e4);
1611  }
1612  else {
1613  double x1, y1, z1 = z, x2, y2;
1614  double r = roundedRadius;
1615  if(dx > 0.) {
1616  x1 = x;
1617  x2 = x1 + dx;
1618  }
1619  else {
1620  x2 = x;
1621  x1 = x2 + dx;
1622  }
1623  if(dy > 0.) {
1624  y1 = y;
1625  y2 = y1 + dy;
1626  }
1627  else {
1628  y2 = y;
1629  y1 = y2 + dy;
1630  }
1631  TopoDS_Vertex v1 = BRepBuilderAPI_MakeVertex(gp_Pnt(x1 + r, y1, z1));
1632  TopoDS_Vertex v2 = BRepBuilderAPI_MakeVertex(gp_Pnt(x2 - r, y1, z1));
1633  TopoDS_Vertex v3 = BRepBuilderAPI_MakeVertex(gp_Pnt(x2, y1 + r, z1));
1634  TopoDS_Vertex v4 = BRepBuilderAPI_MakeVertex(gp_Pnt(x2, y2 - r, z1));
1635  TopoDS_Vertex v5 = BRepBuilderAPI_MakeVertex(gp_Pnt(x2 - r, y2, z1));
1636  TopoDS_Vertex v6 = BRepBuilderAPI_MakeVertex(gp_Pnt(x1 + r, y2, z1));
1637  TopoDS_Vertex v7 = BRepBuilderAPI_MakeVertex(gp_Pnt(x1, y2 - r, z1));
1638  TopoDS_Vertex v8 = BRepBuilderAPI_MakeVertex(gp_Pnt(x1, y1 + r, z1));
1639  TopoDS_Edge e1 = BRepBuilderAPI_MakeEdge(v1, v2);
1640  TopoDS_Edge e2 = BRepBuilderAPI_MakeEdge(v3, v4);
1641  TopoDS_Edge e3 = BRepBuilderAPI_MakeEdge(v5, v6);
1642  TopoDS_Edge e4 = BRepBuilderAPI_MakeEdge(v7, v8);
1643  gp_Pnt c1(x1 + r, y1 + r, z1);
1644  gp_Pnt c2(x2 - r, y1 + r, z1);
1645  gp_Pnt c3(x2 - r, y2 - r, z1);
1646  gp_Pnt c4(x1 + r, y2 - r, z1);
1647  gp_Pln plane = gce_MakePln(c1, c2, c3).Value();
1648  gp_Circ circ1 = gce_MakeCirc(c1, plane, r).Value();
1649  gp_Circ circ2 = gce_MakeCirc(c2, plane, r).Value();
1650  gp_Circ circ3 = gce_MakeCirc(c3, plane, r).Value();
1651  gp_Circ circ4 = gce_MakeCirc(c4, plane, r).Value();
1652  Handle(Geom_Circle) circle1 = new Geom_Circle(circ1);
1653  Handle(Geom_Circle) circle2 = new Geom_Circle(circ2);
1654  Handle(Geom_Circle) circle3 = new Geom_Circle(circ3);
1655  Handle(Geom_Circle) circle4 = new Geom_Circle(circ4);
1656  Handle(Geom_TrimmedCurve) arc1 =
1657  new Geom_TrimmedCurve(circle1, -M_PI, -M_PI / 2., true);
1658  Handle(Geom_TrimmedCurve) arc2 =
1659  new Geom_TrimmedCurve(circle2, -M_PI / 2, 0, true);
1660  Handle(Geom_TrimmedCurve) arc3 =
1661  new Geom_TrimmedCurve(circle3, 0, M_PI / 2, true);
1662  Handle(Geom_TrimmedCurve) arc4 =
1663  new Geom_TrimmedCurve(circle4, M_PI / 2, M_PI, true);
1664  TopoDS_Edge ce1 = BRepBuilderAPI_MakeEdge(arc1, v8, v1);
1665  TopoDS_Edge ce2 = BRepBuilderAPI_MakeEdge(arc2, v2, v3);
1666  TopoDS_Edge ce3 = BRepBuilderAPI_MakeEdge(arc3, v4, v5);
1667  TopoDS_Edge ce4 = BRepBuilderAPI_MakeEdge(arc4, v6, v7);
1668  BRepBuilderAPI_MakeWire w;
1669  w.Add(e1);
1670  w.Add(ce2);
1671  w.Add(e2);
1672  w.Add(ce3);
1673  w.Add(e3);
1674  w.Add(ce4);
1675  w.Add(e4);
1676  w.Add(ce1);
1677  wire = w.Wire();
1678  }
1679  result = BRepBuilderAPI_MakeFace(wire);
1680  } catch(Standard_Failure &err) {
1681  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
1682  return false;
1683  }
1684  return true;
1685 }
1686 
1687 bool OCC_Internals::addRectangle(int &tag, double x, double y, double z,
1688  double dx, double dy, double roundedRadius)
1689 {
1690  if(tag >= 0 && _tagFace.IsBound(tag)) {
1691  Msg::Error("OpenCASCADE surface with tag %d already exists", tag);
1692  return false;
1693  }
1694  TopoDS_Face result;
1695  if(!makeRectangle(result, x, y, z, dx, dy, roundedRadius)) return false;
1696  if(tag < 0) tag = getMaxTag(2) + 1;
1697  _bind(result, tag, true);
1698  return true;
1699 }
1700 
1701 static bool makeDisk(TopoDS_Face &result, double xc, double yc, double zc,
1702  double rx, double ry,
1703  const std::vector<double> &N = std::vector<double>(),
1704  const std::vector<double> &V = std::vector<double>())
1705 {
1706  if(ry > rx) {
1707  Msg::Error("Major radius rx should be larger than minor radius ry");
1708  return false;
1709  }
1710  if(ry <= 0 || rx <= 0) {
1711  Msg::Error("Disk radius should be positive");
1712  return false;
1713  }
1714  try {
1715  gp_Elips el;
1716  gp_Pnt center(xc, yc, zc);
1717  if(N.size() == 3 && V.size() == 3) {
1718  gp_Dir N_dir(N[0], N[1], N[2]);
1719  gp_Dir x_dir(V[0], V[1], V[2]);
1720  gp_Ax2 axis(center, N_dir, x_dir);
1721  el.SetPosition(axis);
1722  }
1723  else if(N.size() == 3) {
1724  gp_Dir N_dir(N[0], N[1], N[2]);
1725  gp_Ax2 axis(center, N_dir);
1726  el.SetPosition(axis);
1727  }
1728  else {
1729  gp_Dir N_dir(0., 0., 1.);
1730  gp_Dir x_dir(1., 0., 0.);
1731  gp_Ax2 axis(center, N_dir, x_dir);
1732  el.SetPosition(axis);
1733  }
1734  el.SetMajorRadius(rx);
1735  el.SetMinorRadius(ry);
1736  TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(el);
1737  TopoDS_Wire wire = BRepBuilderAPI_MakeWire(edge);
1738  result = BRepBuilderAPI_MakeFace(wire);
1739  } catch(Standard_Failure &err) {
1740  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
1741  return false;
1742  }
1743  return true;
1744 }
1745 
1746 bool OCC_Internals::addDisk(int &tag, double xc, double yc, double zc,
1747  double rx, double ry, const std::vector<double> &N,
1748  const std::vector<double> &V)
1749 {
1750  if(tag >= 0 && _tagFace.IsBound(tag)) {
1751  Msg::Error("OpenCASCADE surface with tag %d already exists", tag);
1752  return false;
1753  }
1754  TopoDS_Face result;
1755  if(!makeDisk(result, xc, yc, zc, rx, ry, N, V)) return false;
1756  if(tag < 0) tag = getMaxTag(2) + 1;
1757  _bind(result, tag, true);
1758  return true;
1759 }
1760 
1761 bool OCC_Internals::addPlaneSurface(int &tag, const std::vector<int> &wireTags)
1762 {
1763  if(tag >= 0 && _tagFace.IsBound(tag)) {
1764  Msg::Error("OpenCASCADE surface with tag %d already exists", tag);
1765  return false;
1766  }
1767 
1768  std::vector<TopoDS_Wire> wires;
1769  for(std::size_t i = 0; i < wireTags.size(); i++) {
1770  // all wire tags are > 0 for OCC : to improve compatibility between GEO and
1771  // OCC factories, allow negative tags - and simply ignore the sign here
1772  int wireTag = std::abs(wireTags[i]);
1773  if(!_tagWire.IsBound(wireTag)) {
1774  Msg::Error("Unknown OpenCASCADE curve loop with tag %d", wireTag);
1775  return false;
1776  }
1777  TopoDS_Wire wire = TopoDS::Wire(_tagWire.Find(wireTag));
1778  wires.push_back(wire);
1779  }
1780 
1781  TopoDS_Face result;
1782  if(wires.size() == 0) {
1783  Msg::Error("Plane surface requires at least one curve loop");
1784  return false;
1785  }
1786 
1787  try {
1788  BRepBuilderAPI_MakeFace f(wires[0]);
1789  for(std::size_t i = 1; i < wires.size(); i++) {
1790  // holes
1791  TopoDS_Wire w = wires[i];
1792  w.Orientation(TopAbs_REVERSED);
1793  f.Add(w);
1794  }
1795  f.Build();
1796  if(!f.IsDone()) {
1797  Msg::Error("Could not create surface");
1798  return false;
1799  }
1800  result = f.Face();
1801  if(CTX::instance()->geom.occAutoFix) {
1802  // make sure wires are oriented correctly
1803  ShapeFix_Face fix(result);
1804  fix.Perform();
1805  result = fix.Face();
1806  }
1807  } catch(Standard_Failure &err) {
1808  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
1809  return false;
1810  }
1811 
1812  if(tag < 0) tag = getMaxTag(2) + 1;
1813  _bind(result, tag, true);
1814  return true;
1815 }
1816 
1817 bool OCC_Internals::addSurfaceFilling(int &tag, int wireTag,
1818  const std::vector<int> &pointTags,
1819  const std::vector<int> &surfaceTags,
1820  const std::vector<int> &surfaceContinuity,
1821  const int degree,
1822  const int numPointsOnCurves,
1823  const int numIter,
1824  const bool anisotropic,
1825  const double tol2d,
1826  const double tol3d,
1827  const double tolAng,
1828  const double tolCurv,
1829  const int maxDegree,
1830  const int maxSegments)
1831 {
1832  if(tag >= 0 && _tagFace.IsBound(tag)) {
1833  Msg::Error("OpenCASCADE surface with tag %d already exists", tag);
1834  return false;
1835  }
1836 
1837  TopoDS_Face result;
1838  try {
1839  BRepOffsetAPI_MakeFilling f(degree, numPointsOnCurves, numIter, anisotropic,
1840  tol2d, tol3d, tolAng, tolCurv, maxDegree,
1841  maxSegments);
1842  // bounding edge constraints
1843  if(!_tagWire.IsBound(wireTag)) {
1844  Msg::Error("Unknown OpenCASCADE curve loop with tag %d", wireTag);
1845  return false;
1846  }
1847  TopoDS_Wire wire = TopoDS::Wire(_tagWire.Find(wireTag));
1848  BRepTools_WireExplorer exp0; // guarantees edges are ordered
1849  std::size_t i = 0;
1850  for(exp0.Init(wire); exp0.More(); exp0.Next()) {
1851  TopoDS_Edge edge = exp0.Current();
1852  if(i < surfaceTags.size()) {
1853  // associated face constraint (does not seem to work...)
1854  if(!_tagFace.IsBound(surfaceTags[i])) {
1855  Msg::Error("Unknown OpenCASCADE surface with tag %d", surfaceTags[i]);
1856  return false;
1857  }
1858  TopoDS_Face face = TopoDS::Face(_tagFace.Find(surfaceTags[i]));
1859  if(i < surfaceContinuity.size() && surfaceContinuity[i] == 2)
1860  f.Add(edge, face, GeomAbs_G2);
1861  else
1862  f.Add(edge, face, GeomAbs_G1);
1863  }
1864  else {
1865  f.Add(edge, GeomAbs_C0);
1866  }
1867  i++;
1868  }
1869  // point constraints
1870  for(std::size_t i = 0; i < pointTags.size(); i++) {
1871  if(!_tagVertex.IsBound(pointTags[i])) {
1872  Msg::Error("Unknown OpenCASCADE point with tag %d", pointTags[i]);
1873  return false;
1874  }
1875  TopoDS_Vertex vertex = TopoDS::Vertex(_tagVertex.Find(pointTags[i]));
1876  f.Add(BRep_Tool::Pnt(vertex));
1877  }
1878  f.Build();
1879  if(!f.IsDone()) {
1880  Msg::Error("Could not build surface filling");
1881  return false;
1882  }
1883  // face filling duplicates the edges, so we need to go back to the
1884  // underlying surface, and remake a new face explicitly with the wire
1885  TopoDS_Face tmp = TopoDS::Face(f.Shape());
1886  Handle(Geom_Surface) s = BRep_Tool::Surface(tmp);
1887  ShapeFix_Face sff;
1888  sff.Init(s, CTX::instance()->geom.tolerance);
1889  sff.Add(wire);
1890  sff.Perform();
1891  bool reverse = sff.FixOrientation();
1892  result = sff.Face();
1893  if(reverse) result.Orientation(TopAbs_REVERSED);
1894  } catch(Standard_Failure &err) {
1895  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
1896  return false;
1897  }
1898 
1899  if(tag < 0) tag = getMaxTag(2) + 1;
1900  _bind(result, tag, true);
1901  return true;
1902 }
1903 
1904 bool OCC_Internals::addBSplineFilling(int &tag, int wireTag,
1905  const std::string &type)
1906 {
1907  if(tag >= 0 && _tagFace.IsBound(tag)) {
1908  Msg::Error("OpenCASCADE surface with tag %d already exists", tag);
1909  return false;
1910  }
1911 
1912  // TODO: make this a parameter
1913  int degree = 0; // 0 = use the degree of the input curves
1914 
1915  const double tol = CTX::instance()->geom.tolerance;
1916  TopoDS_Face result;
1917  try {
1918  GeomFill_BSplineCurves f;
1919  if(!_tagWire.IsBound(wireTag)) {
1920  Msg::Error("Unknown OpenCASCADE curve loop with tag %d", wireTag);
1921  return false;
1922  }
1923  TopoDS_Wire wire = TopoDS::Wire(_tagWire.Find(wireTag));
1924  std::vector<Handle(Geom_BSplineCurve)> bsplines;
1925  BRepTools_WireExplorer exp0; // guarantees edges are ordered
1926  for(exp0.Init(wire); exp0.More(); exp0.Next()) {
1927  TopoDS_Edge edge = exp0.Current();
1928  double s0, s1;
1929  Handle(Geom_Curve) curve = BRep_Tool::Curve(edge, s0, s1);
1930  Handle(Geom_BSplineCurve) bspline;
1931  bool approx = false;
1932  if(curve->DynamicType() == STANDARD_TYPE(Geom_BSplineCurve)) {
1933  bspline = Handle(Geom_BSplineCurve)::DownCast(curve);
1934  if(bspline->Degree() < degree) approx = true;
1935  }
1936  else {
1937  approx = true;
1938  }
1939  if(approx) {
1940  // cannot directly use GeomConvert::CurveToBSplineCurve because it does
1941  // not handle infinite curves (e.g. straight lines)
1942  BRepBuilderAPI_NurbsConvert nurbs(edge);
1943  TopoDS_Edge edge2 = TopoDS::Edge(nurbs.ModifiedShape(edge));
1944  curve = BRep_Tool::Curve(edge2, s0, s1);
1945  if(curve->DynamicType() != STANDARD_TYPE(Geom_BSplineCurve)) {
1946  Msg::Error("Could not convert bounding curve for BSpline filling to "
1947  "a BSpline");
1948  return false;
1949  }
1950  bspline = Handle(Geom_BSplineCurve)::DownCast(curve);
1951  if(bspline->Degree() < degree)
1952  bspline->IncreaseDegree(degree);
1953  }
1954  // if trimmed, create an approximation
1955  TopoDS_Vertex v0 = TopExp::FirstVertex(edge);
1956  TopoDS_Vertex v1 = TopExp::LastVertex(edge);
1957  if(!bspline->StartPoint().IsEqual(BRep_Tool::Pnt(v0), tol) ||
1958  !bspline->EndPoint().IsEqual(BRep_Tool::Pnt(v1), tol)) {
1959  bspline = GeomConvert::SplitBSplineCurve(bspline, s0, s1, 1e-6);
1960  }
1961  bsplines.push_back(bspline);
1962  }
1963 
1964  GeomFill_FillingStyle t;
1965  if(type == "Stretch")
1966  t = GeomFill_StretchStyle; // flattest patch
1967  else if(type == "Coons")
1968  t = GeomFill_CoonsStyle; // rounded with less depth than Curved
1969  else
1970  t = GeomFill_CurvedStyle; // most rounded patch
1971 
1972  if(bsplines.size() == 4) {
1973  f.Init(bsplines[0], bsplines[1], bsplines[2], bsplines[3], t);
1974  }
1975  else if(bsplines.size() == 3) {
1976  // workaround bug in 3-sided case in GeomFill_BSplineCurves, which fails
1977  // to detect correct ordering when the first curve should be reversed:
1978  if(!bsplines[0]->EndPoint().IsEqual(bsplines[1]->StartPoint(), tol) &&
1979  !bsplines[0]->EndPoint().IsEqual(bsplines[1]->EndPoint(), tol)) {
1980  f.Init(bsplines[0], bsplines[2], bsplines[1], t);
1981  }
1982  else {
1983  f.Init(bsplines[0], bsplines[1], bsplines[2], t);
1984  }
1985  }
1986  else if(bsplines.size() == 2) {
1987  f.Init(bsplines[0], bsplines[1], t);
1988  }
1989  else {
1990  Msg::Error(
1991  "BSpline filling requires between 2 and 4 boundary BSpline curves");
1992  return false;
1993  }
1994  ShapeFix_Face sff;
1995  sff.Init(f.Surface(), tol);
1996  sff.Add(wire);
1997  sff.Perform();
1998  bool reverse = sff.FixOrientation();
1999  result = sff.Face();
2000  if(reverse) result.Orientation(TopAbs_REVERSED);
2001  } catch(Standard_Failure &err) {
2002  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
2003  return false;
2004  }
2005 
2006  if(tag < 0) tag = getMaxTag(2) + 1;
2007  _bind(result, tag, true);
2008  return true;
2009 }
2010 
2011 bool OCC_Internals::addBezierFilling(int &tag, int wireTag,
2012  const std::string &type)
2013 {
2014  if(tag >= 0 && _tagFace.IsBound(tag)) {
2015  Msg::Error("OpenCASCADE surface with tag %d already exists", tag);
2016  return false;
2017  }
2018 
2019  TopoDS_Face result;
2020  try {
2021  GeomFill_BezierCurves f;
2022  if(!_tagWire.IsBound(wireTag)) {
2023  Msg::Error("Unknown OpenCASCADE curve loop with tag %d", wireTag);
2024  return false;
2025  }
2026  TopoDS_Wire wire = TopoDS::Wire(_tagWire.Find(wireTag));
2027  BRepTools_WireExplorer exp0; // guarantees edges are ordered
2028  std::vector<Handle(Geom_BezierCurve)> beziers;
2029  for(exp0.Init(wire); exp0.More(); exp0.Next()) {
2030  TopoDS_Edge edge = exp0.Current();
2031  double s0, s1;
2032  Handle(Geom_Curve) curve = BRep_Tool::Curve(edge, s0, s1);
2033  if(curve->DynamicType() == STANDARD_TYPE(Geom_BezierCurve)) {
2034  beziers.push_back(Handle(Geom_BezierCurve)::DownCast(curve));
2035  }
2036  else {
2037  Msg::Error(
2038  "Bounding curve for Bezier filling should be a Bezier curve");
2039  }
2040  }
2041 
2042  GeomFill_FillingStyle t;
2043  if(type == "Stretch")
2044  t = GeomFill_StretchStyle; // flattest patch
2045  else if(type == "Coons")
2046  t = GeomFill_CoonsStyle; // rounded with less depth than Curved
2047  else
2048  t = GeomFill_CurvedStyle; // most rounded patch
2049 
2050  if(beziers.size() == 4) {
2051  f.Init(beziers[0], beziers[1], beziers[2], beziers[3], t);
2052  }
2053  else if(beziers.size() == 3) {
2054  f.Init(beziers[0], beziers[1], beziers[2], t);
2055  }
2056  else if(beziers.size() == 2) {
2057  f.Init(beziers[0], beziers[1], t);
2058  }
2059  else {
2060  Msg::Error(
2061  "Bezier filling requires between 2 and 4 boundary Bezier curves");
2062  return false;
2063  }
2064  ShapeFix_Face sff;
2065  sff.Init(f.Surface(), CTX::instance()->geom.tolerance);
2066  sff.Add(wire);
2067  sff.Perform();
2068  bool reverse = sff.FixOrientation();
2069  result = sff.Face();
2070  if(reverse) result.Orientation(TopAbs_REVERSED);
2071  } catch(Standard_Failure &err) {
2072  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
2073  return false;
2074  }
2075 
2076  if(tag < 0) tag = getMaxTag(2) + 1;
2077  _bind(result, tag, true);
2078  return true;
2079 }
2080 
2081 static bool makeEdgeOnSurface(const TopoDS_Edge &edge,
2082  const Handle(Geom_Surface) &surf,
2083  bool curve3D, TopoDS_Edge &edgeOnSurf)
2084 {
2085  try {
2086  Standard_Real first, last;
2087  Handle(Geom_Curve) c = BRep_Tool::Curve(edge, first, last);
2088  if(curve3D) {
2089  // use the 3D curves in the wire and project them onto the patch
2090  Handle(Geom_Curve) cProj = GeomProjLib::Project
2091  (new Geom_TrimmedCurve(c, first, last, Standard_True, Standard_False),
2092  surf);
2093  edgeOnSurf = BRepBuilderAPI_MakeEdge
2094  (cProj, cProj->FirstParameter(), cProj->LastParameter());
2095  }
2096  else {
2097  // assume the 3D curve is actually a 2D curve in the parametric plane of the
2098  // surface: to retrieve the 2D curve, project the 3D curve on the z=0 plane
2099  Handle(Geom_Plane) p = new Geom_Plane(0, 0, 1, 0);
2100  TopLoc_Location loc;
2101  Handle(Geom2d_Curve) c2d =
2102  BRep_Tool::CurveOnSurface(edge, p, loc, first, last);
2103  // BRep_Tool::CurveOnPlane(edge, p, loc, first, last); // OCCT >= 7.2
2104  edgeOnSurf = BRepBuilderAPI_MakeEdge(c2d, surf, first, last);
2105  }
2106  }
2107  catch(Standard_Failure &err) {
2108  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
2109  return false;
2110  }
2111  return true;
2112 }
2113 
2114 static bool makeTrimmedSurface(const Handle(Geom_Surface) &surf,
2115  const std::vector<TopoDS_Wire> &wires,
2116  bool wire3D, TopoDS_Face &result)
2117 {
2118  if(wires.empty()) { // natural bounds
2119  result = BRepBuilderAPI_MakeFace(surf, CTX::instance()->geom.tolerance);
2120 #if 0
2121  // Activate this to use input points as corners if they are on the corners
2122  // of the patch. (Since the natural "Replace(old_vertex, new_vertex)" on the
2123  // face does not work, we do it on each edge. Sigh...) Since when buiding
2124  // multi-patch models a fragment or sewing will eventually be necessary to
2125  // glue the patches, it's not that useful - let's leave this commented out.
2126  ShapeBuild_ReShape rebuild;
2127  TopExp_Explorer exp0;
2128  for(exp0.Init(result, TopAbs_EDGE); exp0.More(); exp0.Next()) {
2129  TopoDS_Edge e = TopoDS::Edge(exp0.Current());
2130  TopoDS_Vertex v1 = TopExp::FirstVertex(e);
2131  TopoDS_Vertex v2 = TopExp::LastVertex(e);
2132  double s0, s1;
2133  Handle(Geom_Curve) curve = BRep_Tool::Curve(e, s0, s1);
2134  if(curve->DynamicType() == STANDARD_TYPE(Geom_BSplineCurve)){
2135  Handle(Geom_BSplineCurve) bs = Handle(Geom_BSplineCurve)::DownCast(curve);
2136  for(std::size_t i = 0; i < corners.size(); i++) {
2137  if(bs->StartPoint().IsEqual(BRep_Tool::Pnt(corners[i]),
2139  v1 = corners[i];
2140  }
2141  if(bs->EndPoint().IsEqual(BRep_Tool::Pnt(corners[i]),
2143  v2 = corners[i];
2144  }
2145  }
2146  }
2147  BRepBuilderAPI_MakeEdge newe(curve, v1, v2);
2148  rebuild.Replace(e, newe);
2149  }
2150  result = TopoDS::Face(rebuild.Apply(result));
2151  ShapeFix_Face fix(result); // not sure why, but this is necessary
2152  fix.SetPrecision(CTX::instance()->geom.tolerance);
2153  fix.Perform();
2154  fix.FixOrientation();
2155  result = fix.Face();
2156 #endif
2157  }
2158  else { // trimmed patch, using provided wires
2159  std::vector<TopoDS_Wire> wiresProj;
2160  for(std::size_t i = 0; i < wires.size(); i++) {
2161  BRepBuilderAPI_MakeWire w;
2162  BRepTools_WireExplorer exp0; // guarantees edges are ordered
2163  for(exp0.Init(wires[i]); exp0.More(); exp0.Next()) {
2164  TopoDS_Edge edge = exp0.Current(), edgeOnSurf;
2165  if(makeEdgeOnSurface(edge, surf, wire3D, edgeOnSurf)) {
2166  w.Add(edgeOnSurf);
2167  }
2168  }
2169  w.Build();
2170  if(!w.IsDone()) {
2171  Msg::Error("Could not create wire");
2172  return false;
2173  }
2174  TopoDS_Wire wire = w.Wire();
2175  wiresProj.push_back(wire);
2176  }
2177  BRepBuilderAPI_MakeFace f(surf, wiresProj[0]);
2178  for(std::size_t i = 1; i < wiresProj.size(); i++) f.Add(wiresProj[i]);
2179  f.Build();
2180  if(!f.IsDone()) {
2181  Msg::Error("Could not create surface");
2182  return false;
2183  }
2184  result = f.Face();
2185  // recover 3D curves for pcurves
2186  ShapeFix_Face fix(result);
2187  fix.Perform();
2188  result = fix.Face();
2189  }
2190  return true;
2191 }
2192 
2194  int &tag, const std::vector<int> &pointTags, const int numPointsU,
2195  const int degreeU, const int degreeV, const std::vector<double> &weights,
2196  const std::vector<double> &knotsU, const std::vector<double> &knotsV,
2197  const std::vector<int> &multiplicitiesU,
2198  const std::vector<int> &multiplicitiesV, const std::vector<int> &wireTags,
2199  bool wire3D)
2200 {
2201  if(tag >= 0 && _tagFace.IsBound(tag)) {
2202  Msg::Error("OpenCASCADE surface with tag %d already exists", tag);
2203  return false;
2204  }
2205 
2206  // deal with default values
2207  if(numPointsU < 1) {
2208  Msg::Error("Wrong number of control points along U for BSpline surface");
2209  return false;
2210  }
2211  int numPointsV = pointTags.size() / numPointsU;
2212  if(numPointsU * numPointsV != (int)pointTags.size()) {
2213  Msg::Error("Wrong number of control points for BSpline surface");
2214  return false;
2215  }
2216  int dU = degreeU, dV = degreeV;
2217  std::vector<double> w(weights), kU(knotsU), kV(knotsV);
2218  std::vector<int> mU(multiplicitiesU), mV(multiplicitiesV);
2219  // degree 3 if not specified...
2220  if(dU <= 0) dU = 3;
2221  if(dV <= 0) dV = 3;
2222  // ... or number of control points - 1 if not enough points
2223  if(dU > numPointsU - 1) dU = numPointsU - 1;
2224  if(dV > numPointsV - 1) dV = numPointsV - 1;
2225  // automatic default weights if not provided:
2226  if(w.empty()) w.resize(pointTags.size(), 1);
2227  if(w.size() != pointTags.size()) {
2228  Msg::Error("Wrong number of weights for BSpline surface");
2229  return false;
2230  }
2231  bool periodicU = true;
2232  for(int i = 0; i < numPointsV; i++) {
2233  if(pointTags[i * numPointsU] != pointTags[(i + 1) * numPointsU - 1]) {
2234  periodicU = false;
2235  break;
2236  }
2237  }
2238  bool periodicV = true;
2239  for(int i = 0; i < numPointsU; i++) {
2240  if(pointTags[i * numPointsV] != pointTags[(i + 1) * numPointsV - 1]) {
2241  periodicV = false;
2242  break;
2243  }
2244  }
2245  // automatic default knots and multiplicities along U if not provided:
2246  if(kU.empty()) {
2247  if(!periodicU) {
2248  int sumOfAllMultU = numPointsU + dU + 1;
2249  int numKnotsU = sumOfAllMultU - 2 * dU;
2250  if(numKnotsU < 2) {
2251  Msg::Error("Not enough control points along U for building BSpline of "
2252  "degree %d x %d",
2253  dU, dV);
2254  return false;
2255  }
2256  kU.resize(numKnotsU);
2257  for(std::size_t i = 0; i < kU.size(); i++) kU[i] = i;
2258  mU.resize(numKnotsU, 1);
2259  mU.front() = dU + 1;
2260  mU.back() = dU + 1;
2261  }
2262  else {
2263  kU.resize(numPointsU - dU + 2);
2264  for(std::size_t i = 0; i < kU.size(); i++) kU[i] = i;
2265  mU.resize(kU.size(), 1);
2266  mU.front() = dU - 1;
2267  mU.back() = dU - 1;
2268  }
2269  }
2270  if(kU.size() != mU.size()) {
2271  Msg::Error("Number of BSpline knots and multiplicities should be equal");
2272  return false;
2273  }
2274  // automatic default knots and multiplicities along V if not provided:
2275  if(kV.empty()) {
2276  if(!periodicV) {
2277  int sumOfAllMultV = numPointsV + dV + 1;
2278  int numKnotsV = sumOfAllMultV - 2 * dV;
2279  if(numKnotsV < 2) {
2280  Msg::Error("Not enough control points along V for building BSpline of "
2281  "degree %d x %d",
2282  dU, dV);
2283  return false;
2284  }
2285  kV.resize(numKnotsV);
2286  for(std::size_t i = 0; i < kV.size(); i++) kV[i] = i;
2287  mV.resize(numKnotsV, 1);
2288  mV.front() = dV + 1;
2289  mV.back() = dV + 1;
2290  }
2291  else {
2292  kV.resize(numPointsV - dV + 2);
2293  for(std::size_t i = 0; i < kV.size(); i++) kV[i] = i;
2294  mV.resize(kV.size(), 1);
2295  mV.front() = dV - 1;
2296  mV.back() = dV - 1;
2297  }
2298  }
2299  if(kV.size() != mV.size()) {
2300  Msg::Error("Number of BSpline knots and multiplicities should be equal");
2301  return false;
2302  }
2303 
2304  std::vector<TopoDS_Wire> wires;
2305  for(std::size_t i = 0; i < wireTags.size(); i++) {
2306  int wireTag = std::abs(wireTags[i]);
2307  if(!_tagWire.IsBound(wireTag)) {
2308  Msg::Error("Unknown OpenCASCADE curve loop with tag %d", wireTag);
2309  return false;
2310  }
2311  TopoDS_Wire wire = TopoDS::Wire(_tagWire.Find(wireTag));
2312  wires.push_back(wire);
2313  }
2314 
2315  TopoDS_Face result;
2316  try {
2317  std::vector<TopoDS_Vertex> corners;
2318  int npU = (periodicU ? numPointsU - 1 : numPointsU);
2319  int npV = (periodicV ? numPointsV - 1 : numPointsV);
2320  TColgp_Array2OfPnt pp(1, npU, 1, npV);
2321  for(int i = 1; i <= npU; i++) {
2322  for(int j = 1; j <= npV; j++) {
2323  int k = (j - 1) * numPointsU + (i - 1);
2324  if(!_tagVertex.IsBound(pointTags[k])) {
2325  Msg::Error("Unknown OpenCASCADE point with tag %d", pointTags[k]);
2326  return false;
2327  }
2328  TopoDS_Vertex vertex = TopoDS::Vertex(_tagVertex.Find(pointTags[k]));
2329  if((i == 1 && j == 1) || (i == 1 && j == npV) || (i == npU && j == 1) ||
2330  (i == npU && j == npV))
2331  corners.push_back(vertex);
2332  pp.SetValue(i, j, BRep_Tool::Pnt(vertex));
2333  }
2334  }
2335  TColStd_Array2OfReal ww(1, npU, 1, npV);
2336  for(int i = 1; i <= npU; i++) {
2337  for(int j = 1; j <= npV; j++) {
2338  int k = (j - 1) * numPointsU + (i - 1);
2339  ww.SetValue(i, j, w[k]);
2340  }
2341  }
2342  TColStd_Array1OfReal kkU(1, kU.size());
2343  for(std::size_t i = 1; i <= kU.size(); i++) kkU.SetValue(i, kU[i - 1]);
2344  TColStd_Array1OfReal kkV(1, kV.size());
2345  for(std::size_t i = 1; i <= kV.size(); i++) kkV.SetValue(i, kV[i - 1]);
2346  TColStd_Array1OfInteger mmU(1, mU.size());
2347  for(std::size_t i = 1; i <= mU.size(); i++) mmU.SetValue(i, mU[i - 1]);
2348  TColStd_Array1OfInteger mmV(1, mV.size());
2349  for(std::size_t i = 1; i <= mV.size(); i++) mmV.SetValue(i, mV[i - 1]);
2350  Handle(Geom_BSplineSurface) surf = new Geom_BSplineSurface(
2351  pp, ww, kkU, kkV, mmU, mmV, dU, dV, periodicU, periodicV);
2352  makeTrimmedSurface(surf, wires, wire3D, result);
2353  } catch(Standard_Failure &err) {
2354  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
2355  return false;
2356  }
2357 
2358  if(tag < 0) tag = getMaxTag(2) + 1;
2359  _bind(result, tag, true);
2360  return true;
2361 }
2362 
2363 bool OCC_Internals::addBezierSurface(int &tag,
2364  const std::vector<int> &pointTags,
2365  const int numPointsU,
2366  const std::vector<int> &wireTags,
2367  bool wire3D)
2368 {
2369  if(tag >= 0 && _tagFace.IsBound(tag)) {
2370  Msg::Error("OpenCASCADE surface with tag %d already exists", tag);
2371  return false;
2372  }
2373 
2374  // deal with default values
2375  if(numPointsU < 1) {
2376  Msg::Error("Wrong number of control points along U for Bezier surface");
2377  return false;
2378  }
2379  int numPointsV = pointTags.size() / numPointsU;
2380  if(numPointsU * numPointsV != (int)pointTags.size()) {
2381  Msg::Error("Wrong number of control points for Bezier surface");
2382  return false;
2383  }
2384 
2385  std::vector<TopoDS_Wire> wires;
2386  for(std::size_t i = 0; i < wireTags.size(); i++) {
2387  int wireTag = std::abs(wireTags[i]);
2388  if(!_tagWire.IsBound(wireTag)) {
2389  Msg::Error("Unknown OpenCASCADE curve loop with tag %d", wireTag);
2390  return false;
2391  }
2392  TopoDS_Wire wire = TopoDS::Wire(_tagWire.Find(wireTag));
2393  wires.push_back(wire);
2394  }
2395 
2396  TopoDS_Face result;
2397  try {
2398  TColgp_Array2OfPnt pp(1, numPointsU, 1, numPointsV);
2399  for(int i = 1; i <= numPointsU; i++) {
2400  for(int j = 1; j <= numPointsV; j++) {
2401  int k = (j - 1) * numPointsU + (i - 1);
2402  if(!_tagVertex.IsBound(pointTags[k])) {
2403  Msg::Error("Unknown OpenCASCADE point with tag %d", pointTags[k]);
2404  return false;
2405  }
2406  TopoDS_Vertex vertex = TopoDS::Vertex(_tagVertex.Find(pointTags[k]));
2407  pp.SetValue(i, j, BRep_Tool::Pnt(vertex));
2408  }
2409  }
2410  Handle(Geom_BezierSurface) surf = new Geom_BezierSurface(pp);
2411  makeTrimmedSurface(surf, wires, wire3D, result);
2412  } catch(Standard_Failure &err) {
2413  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
2414  return false;
2415  }
2416 
2417  if(tag < 0) tag = getMaxTag(2) + 1;
2418  _bind(result, tag, true);
2419  return true;
2420 }
2421 
2422 bool OCC_Internals::addTrimmedSurface(int &tag, int surfaceTag,
2423  const std::vector<int> &wireTags,
2424  bool wire3D)
2425 {
2426  if(tag >= 0 && _tagFace.IsBound(tag)) {
2427  Msg::Error("OpenCASCADE surface with tag %d already exists", tag);
2428  return false;
2429  }
2430 
2431  if(!_tagFace.IsBound(surfaceTag)) {
2432  Msg::Error("Unknown OpenCASCADE surface with tag %d", surfaceTag);
2433  return false;
2434  }
2435  TopoDS_Face face = TopoDS::Face(_tagFace.Find(surfaceTag));
2436 
2437  std::vector<TopoDS_Wire> wires;
2438  for(std::size_t i = 0; i < wireTags.size(); i++) {
2439  int wireTag = std::abs(wireTags[i]);
2440  if(!_tagWire.IsBound(wireTag)) {
2441  Msg::Error("Unknown OpenCASCADE curve loop with tag %d", wireTag);
2442  return false;
2443  }
2444  TopoDS_Wire wire = TopoDS::Wire(_tagWire.Find(wireTag));
2445  wires.push_back(wire);
2446  }
2447 
2448  TopoDS_Face result;
2449  try {
2450  Handle(Geom_Surface) surf = BRep_Tool::Surface(face);
2451  makeTrimmedSurface(surf, wires, wire3D, result);
2452  } catch(Standard_Failure &err) {
2453  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
2454  return false;
2455  }
2456 
2457  if(tag < 0) tag = getMaxTag(2) + 1;
2458  _bind(result, tag, true);
2459  return true;
2460 }
2461 
2462 bool OCC_Internals::addSurfaceLoop(int &tag,
2463  const std::vector<int> &surfaceTags,
2464  bool sewing)
2465 {
2466  if(tag >= 0 && _tagShell.IsBound(tag)) {
2467  Msg::Error("OpenCASCADE surface loop with tag %d already exists", tag);
2468  return false;
2469  }
2470 
2471  if(sewing) {
2472  // this allows one to build a shell made of surfaces that share
2473  // geometrically identical (but topologically different) curves.
2474  TopoDS_Shape result;
2475  try {
2476  BRepBuilderAPI_Sewing s;
2477  for(std::size_t i = 0; i < surfaceTags.size(); i++) {
2478  if(!_tagFace.IsBound(surfaceTags[i])) {
2479  Msg::Error("Unknown OpenCASCADE surface with tag %d", surfaceTags[i]);
2480  return false;
2481  }
2482  TopoDS_Face face = TopoDS::Face(_tagFace.Find(surfaceTags[i]));
2483  s.Add(face);
2484  }
2485  s.Perform();
2486  result = s.SewedShape();
2487  } catch(Standard_Failure &err) {
2488  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
2489  return false;
2490  }
2491  bool first = true;
2492  TopExp_Explorer exp0;
2493  for(exp0.Init(result, TopAbs_SHELL); exp0.More(); exp0.Next()) {
2494  TopoDS_Shell shell = TopoDS::Shell(exp0.Current());
2495  if(CTX::instance()->geom.occAutoFix) {
2496  // make sure faces in shell are oriented correctly
2497  ShapeFix_Shell fix(shell);
2498  fix.Perform();
2499  shell = fix.Shell();
2500  }
2501  if(first) { first = false; }
2502  else {
2503  tag = getMaxTag(-2) + 1;
2504  Msg::Warning("Creating additional surface loop %d", tag);
2505  }
2506  if(tag < 0) tag = getMaxTag(-2) + 1;
2507  _bind(shell, tag, true);
2508  return true;
2509  }
2510  }
2511 
2512  try {
2513  BRep_Builder builder;
2514  BRepPrim_Builder b(builder);
2515  TopoDS_Shell shell;
2516  b.MakeShell(shell);
2517  for(std::size_t i = 0; i < surfaceTags.size(); i++) {
2518  if(!_tagFace.IsBound(surfaceTags[i])) {
2519  Msg::Error("Unknown OpenCASCADE surface with tag %d", surfaceTags[i]);
2520  return false;
2521  }
2522  TopoDS_Face face = TopoDS::Face(_tagFace.Find(surfaceTags[i]));
2523  b.AddShellFace(shell, face);
2524  }
2525  if(CTX::instance()->geom.occAutoFix) {
2526  // make sure faces in shell are oriented correctly
2527  ShapeFix_Shell fix(shell);
2528  fix.Perform();
2529  shell = fix.Shell();
2530  }
2531  if(tag < 0) tag = getMaxTag(-2) + 1;
2532  _bind(shell, tag, true);
2533  return true;
2534  } catch(Standard_Failure &err) {
2535  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
2536  return false;
2537  }
2538 }
2539 
2540 bool OCC_Internals::addVolume(int &tag, const std::vector<int> &shellTags)
2541 {
2542  if(tag >= 0 && _tagSolid.IsBound(tag)) {
2543  Msg::Error("OpenCASCADE volume with tag %d already exists", tag);
2544  return false;
2545  }
2546 
2547  TopoDS_Solid result;
2548  try {
2549  BRepBuilderAPI_MakeSolid s;
2550  for(std::size_t i = 0; i < shellTags.size(); i++) {
2551  if(!_tagShell.IsBound(shellTags[i])) {
2552  Msg::Error("Unknown OpenCASCADE surface loop with tag %d",
2553  shellTags[i]);
2554  return false;
2555  }
2556  TopoDS_Shell shell = TopoDS::Shell(_tagShell.Find(shellTags[i]));
2557  s.Add(shell);
2558  }
2559  result = s.Solid();
2560  if(CTX::instance()->geom.occAutoFix) {
2561  // make sure the volume is finite
2562  ShapeFix_Solid fix(result);
2563  fix.Perform();
2564  result = TopoDS::Solid(fix.Solid());
2565  }
2566  } catch(Standard_Failure &err) {
2567  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
2568  return false;
2569  }
2570  if(tag < 0) tag = getMaxTag(3) + 1;
2571  _bind(result, tag, true);
2572  return true;
2573 }
2574 
2575 static bool makeSphere(TopoDS_Solid &result, double xc, double yc, double zc,
2576  double radius, double angle1, double angle2,
2577  double angle3)
2578 {
2579  if(radius <= 0) {
2580  Msg::Error("Sphere radius should be positive");
2581  return false;
2582  }
2583  if(angle3 <= 0 || angle3 > 2 * M_PI) {
2584  Msg::Error("Cannot build sphere with angle <= 0 or angle > 2*Pi");
2585  return false;
2586  }
2587  try {
2588  gp_Pnt p(xc, yc, zc);
2589  BRepPrimAPI_MakeSphere s(p, radius, angle1, angle2, angle3);
2590  s.Build();
2591  if(!s.IsDone()) {
2592  Msg::Error("Could not create sphere");
2593  return false;
2594  }
2595  result = TopoDS::Solid(s.Shape());
2596  } catch(Standard_Failure &err) {
2597  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
2598  return false;
2599  }
2600  return true;
2601 }
2602 
2603 bool OCC_Internals::addSphere(int &tag, double xc, double yc, double zc,
2604  double radius, double angle1, double angle2,
2605  double angle3)
2606 {
2607  if(tag >= 0 && _tagSolid.IsBound(tag)) {
2608  Msg::Error("OpenCASCADE volume with tag %d already exists", tag);
2609  return false;
2610  }
2611  TopoDS_Solid result;
2612  if(!makeSphere(result, xc, yc, zc, radius, angle1, angle2, angle3))
2613  return false;
2614  if(tag < 0) tag = getMaxTag(3) + 1;
2615  _bind(result, tag, true);
2616  return true;
2617 }
2618 
2619 static bool makeBox(TopoDS_Solid &result, double x, double y, double z,
2620  double dx, double dy, double dz)
2621 {
2622  if(!dx || !dy || !dz) {
2623  Msg::Error("Degenerate box");
2624  return false;
2625  }
2626  try {
2627  gp_Pnt P1(x, y, z);
2628  gp_Pnt P2(x + dx, y + dy, z + dz);
2629  BRepPrimAPI_MakeBox b(P1, P2);
2630  b.Build();
2631  if(!b.IsDone()) {
2632  Msg::Error("Could not create box");
2633  return false;
2634  }
2635  result = TopoDS::Solid(b.Shape());
2636  } catch(Standard_Failure &err) {
2637  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
2638  return false;
2639  }
2640  return true;
2641 }
2642 
2643 bool OCC_Internals::addBox(int &tag, double x, double y, double z, double dx,
2644  double dy, double dz)
2645 {
2646  if(tag >= 0 && _tagSolid.IsBound(tag)) {
2647  Msg::Error("OpenCASCADE volume with tag %d already exists", tag);
2648  return false;
2649  }
2650  TopoDS_Solid result;
2651  if(!makeBox(result, x, y, z, dx, dy, dz)) return false;
2652  if(tag < 0) tag = getMaxTag(3) + 1;
2653  _bind(result, tag, true);
2654  return true;
2655 }
2656 
2657 static bool makeCylinder(TopoDS_Solid &result, double x, double y, double z,
2658  double dx, double dy, double dz, double r,
2659  double angle)
2660 {
2661  const double H = sqrt(dx * dx + dy * dy + dz * dz);
2662  if(!H) {
2663  Msg::Error("Cannot build cylinder of zero height");
2664  return false;
2665  }
2666  if(angle <= 0 || angle > 2 * M_PI) {
2667  Msg::Error("Cannot build cylinder with angle <= 0 or angle > 2*Pi");
2668  return false;
2669  }
2670  try {
2671  gp_Pnt p(x, y, z);
2672  gp_Vec v(dx / H, dy / H, dz / H);
2673  gp_Ax2 axis(p, v);
2674  BRepPrimAPI_MakeCylinder c(axis, r, H, angle);
2675  c.Build();
2676  if(!c.IsDone()) {
2677  Msg::Error("Could not create cylinder");
2678  return false;
2679  }
2680  result = TopoDS::Solid(c.Shape());
2681  } catch(Standard_Failure &err) {
2682  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
2683  return false;
2684  }
2685  return true;
2686 }
2687 
2688 bool OCC_Internals::addCylinder(int &tag, double x, double y, double z,
2689  double dx, double dy, double dz, double r,
2690  double angle)
2691 {
2692  if(tag >= 0 && _tagSolid.IsBound(tag)) {
2693  Msg::Error("OpenCASCADE volume with tag %d already exists", tag);
2694  return false;
2695  }
2696  TopoDS_Solid result;
2697  if(!makeCylinder(result, x, y, z, dx, dy, dz, r, angle)) return false;
2698  if(tag < 0) tag = getMaxTag(3) + 1;
2699  _bind(result, tag, true);
2700  return true;
2701 }
2702 
2703 static bool makeTorus(TopoDS_Solid &result, double x, double y, double z,
2704  double r1, double r2, double angle,
2705  const std::vector<double> &N = std::vector<double>())
2706 {
2707  if(r1 <= 0 || r2 <= 0) {
2708  Msg::Error("Torus radii should be positive");
2709  return false;
2710  }
2711  try {
2712  gp_Pnt p(x, y, z);
2713  std::vector<double> NN(N);
2714  if(NN.size() != 3) {
2715  NN.resize(3);
2716  NN[0] = 0.;
2717  NN[1] = 0.;
2718  NN[2] = 1.;
2719  }
2720  gp_Vec v(NN[0], NN[1], NN[2]);
2721  gp_Ax2 axis(p, v);
2722  BRepPrimAPI_MakeTorus t(axis, r1, r2, angle);
2723  t.Build();
2724  if(!t.IsDone()) {
2725  Msg::Error("Could not create torus");
2726  return false;
2727  }
2728  result = TopoDS::Solid(t.Shape());
2729  } catch(Standard_Failure &err) {
2730  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
2731  return false;
2732  }
2733  return true;
2734 }
2735 
2736 bool OCC_Internals::addTorus(int &tag, double x, double y, double z, double r1,
2737  double r2, double angle,
2738  const std::vector<double> &N)
2739 {
2740  if(tag >= 0 && _tagSolid.IsBound(tag)) {
2741  Msg::Error("OpenCASCADE volume with tag %d already exists", tag);
2742  return false;
2743  }
2744  TopoDS_Solid result;
2745  if(!makeTorus(result, x, y, z, r1, r2, angle, N)) return false;
2746  if(tag < 0) tag = getMaxTag(3) + 1;
2747  _bind(result, tag, true);
2748  return true;
2749 }
2750 
2751 static bool makeCone(TopoDS_Solid &result, double x, double y, double z,
2752  double dx, double dy, double dz, double r1, double r2,
2753  double angle)
2754 {
2755  const double H = sqrt(dx * dx + dy * dy + dz * dz);
2756  if(!H) {
2757  Msg::Error("Cannot build cone of zero height");
2758  return false;
2759  }
2760  if(angle <= 0) {
2761  Msg::Error("Cone angle should be positive");
2762  return false;
2763  }
2764  try {
2765  gp_Pnt aP(x, y, z);
2766  gp_Vec aV(dx / H, dy / H, dz / H);
2767  gp_Ax2 anAxes(aP, aV);
2768  BRepPrimAPI_MakeCone c(anAxes, r1, r2, H, angle);
2769  c.Build();
2770  if(!c.IsDone()) {
2771  Msg::Error("Could not create cone");
2772  return false;
2773  }
2774  result = TopoDS::Solid(c.Shape());
2775  } catch(Standard_Failure &err) {
2776  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
2777  return false;
2778  }
2779  return true;
2780 }
2781 
2782 bool OCC_Internals::addCone(int &tag, double x, double y, double z, double dx,
2783  double dy, double dz, double r1, double r2,
2784  double angle)
2785 {
2786  if(tag >= 0 && _tagSolid.IsBound(tag)) {
2787  Msg::Error("OpenCASCADE volume with tag %d already exists", tag);
2788  return false;
2789  }
2790  TopoDS_Solid result;
2791  if(!makeCone(result, x, y, z, dx, dy, dz, r1, r2, angle)) return false;
2792  if(tag < 0) tag = getMaxTag(3) + 1;
2793  _bind(result, tag, true);
2794  return true;
2795 }
2796 
2797 static bool makeWedge(TopoDS_Solid &result, double x, double y, double z,
2798  double dx, double dy, double dz, double ltx,
2799  const std::vector<double> &N = std::vector<double>())
2800 {
2801  try {
2802  gp_Pnt p(x, y, z);
2803  std::vector<double> NN(N);
2804  if(NN.size() != 3) {
2805  NN.resize(3);
2806  NN[0] = 0.;
2807  NN[1] = 0.;
2808  NN[2] = 1.;
2809  }
2810  gp_Vec v(NN[0], NN[1], NN[2]);
2811  gp_Ax2 axis(p, v);
2812  BRepPrimAPI_MakeWedge w(axis, dx, dy, dz, ltx);
2813  w.Build();
2814  if(!w.IsDone()) {
2815  Msg::Error("Could not create wedge");
2816  return false;
2817  }
2818  result = TopoDS::Solid(w.Shape());
2819  } catch(Standard_Failure &err) {
2820  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
2821  return false;
2822  }
2823  return true;
2824 }
2825 
2826 bool OCC_Internals::addWedge(int &tag, double x, double y, double z, double dx,
2827  double dy, double dz, double ltx,
2828  const std::vector<double> &N)
2829 {
2830  if(tag >= 0 && _tagSolid.IsBound(tag)) {
2831  Msg::Error("OpenCASCADE volume with tag %d already exists", tag);
2832  return false;
2833  }
2834  TopoDS_Solid result;
2835  if(!makeWedge(result, x, y, z, dx, dy, dz, ltx, N)) return false;
2836  if(tag < 0) tag = getMaxTag(3) + 1;
2837  _bind(result, tag, true);
2838  return true;
2839 }
2840 
2842  int tag, const std::vector<int> &wireTags, bool makeSolid, bool makeRuled,
2843  std::vector<std::pair<int, int> > &outDimTags, int maxDegree,
2844  const std::string &continuity, const std::string &parametrization,
2845  bool smoothing)
2846 {
2847  int dim = makeSolid ? 3 : 2;
2848  if(tag >= 0 && _isBound(dim, tag)) {
2849  Msg::Error("OpenCASCADE entity of dimension %d with tag %d already exists",
2850  dim, tag);
2851  return false;
2852  }
2853  if(wireTags.size() < 2) {
2854  Msg::Error("ThruSections require at least 2 wires");
2855  return false;
2856  }
2857  TopoDS_Shape result;
2858  try {
2859  BRepOffsetAPI_ThruSections ts(makeSolid, makeRuled);
2860  if(continuity == "C0")
2861  ts.SetContinuity(GeomAbs_C0);
2862  else if(continuity == "G1")
2863  ts.SetContinuity(GeomAbs_G1);
2864  else if(continuity == "C1")
2865  ts.SetContinuity(GeomAbs_C1);
2866  else if(continuity == "G2")
2867  ts.SetContinuity(GeomAbs_G2);
2868  else if(continuity == "C2")
2869  ts.SetContinuity(GeomAbs_C2);
2870  else if(continuity == "C3")
2871  ts.SetContinuity(GeomAbs_C3);
2872  else if(continuity == "CN")
2873  ts.SetContinuity(GeomAbs_CN);
2874 
2875  // ts.SetCriteriumWeight(1, 1, 1);
2876 
2877  if(maxDegree > 0)
2878  ts.SetMaxDegree(maxDegree);
2879  else if(CTX::instance()->geom.occThruSectionsDegree > 0)
2880  ts.SetMaxDegree(CTX::instance()->geom.occThruSectionsDegree);
2881 
2882  if(parametrization == "ChordLength")
2883  ts.SetParType(Approx_ChordLength);
2884  else if(parametrization == "Centripetal")
2885  ts.SetParType(Approx_Centripetal);
2886  else if(parametrization == "IsoParametric")
2887  ts.SetParType(Approx_IsoParametric);
2888 
2889  ts.SetSmoothing(smoothing ? Standard_True : Standard_False);
2890 
2891  for(std::size_t i = 0; i < wireTags.size(); i++) {
2892  if(!_tagWire.IsBound(wireTags[i])) {
2893  Msg::Error("Unknown OpenCASCADE wire or curve loop with tag %d",
2894  wireTags[i]);
2895  return false;
2896  }
2897  TopoDS_Wire wire = TopoDS::Wire(_tagWire.Find(wireTags[i]));
2898  if(makeSolid && !wire.Closed()) {
2899  Msg::Error("Making solid requires closed wires");
2900  return false;
2901  }
2902  ts.AddWire(wire);
2903  }
2904  ts.CheckCompatibility(Standard_False);
2905  ts.Build();
2906  if(!ts.IsDone()) {
2907  Msg::Error("Could not create ThruSection");
2908  return false;
2909  }
2910  result = ts.Shape();
2911  } catch(Standard_Failure &err) {
2912  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
2913  return false;
2914  }
2915  _multiBind(result, tag, outDimTags, true, true);
2916  return true;
2917 }
2918 
2919 bool OCC_Internals::addThickSolid(int tag, int solidTag,
2920  const std::vector<int> &excludeFaceTags,
2921  double offset,
2922  std::vector<std::pair<int, int> > &outDimTags)
2923 {
2924  if(tag >= 0 && _isBound(3, tag)) {
2925  Msg::Error("OpenCASCADE volume with tag %d already exists", tag);
2926  return false;
2927  }
2928  if(!_isBound(3, solidTag)) {
2929  Msg::Error("Unknown OpenCASCADE volume with tag %d", solidTag);
2930  return false;
2931  }
2932  TopoDS_Shape result;
2933  try {
2934  TopoDS_Shape shape = _find(3, solidTag);
2935  TopTools_ListOfShape exclude;
2936  for(std::size_t i = 0; i < excludeFaceTags.size(); i++) {
2937  if(!_tagFace.IsBound(excludeFaceTags[i])) {
2938  Msg::Error("Unknown OpenCASCADE surface with tag %d",
2939  excludeFaceTags[i]);
2940  return false;
2941  }
2942  exclude.Append(_tagFace.Find(excludeFaceTags[i]));
2943  }
2944 #if OCC_VERSION_HEX > 0x070400
2945  BRepOffsetAPI_MakeThickSolid ts;
2946  ts.MakeThickSolidByJoin(shape, exclude, offset,
2947  CTX::instance()->geom.tolerance);
2948 #else
2949  BRepOffsetAPI_MakeThickSolid ts(shape, exclude, offset,
2950  CTX::instance()->geom.tolerance);
2951  ts.Build();
2952 #endif
2953  if(!ts.IsDone()) {
2954  Msg::Error("Could not build thick solid");
2955  return false;
2956  }
2957  result = ts.Shape();
2958  } catch(Standard_Failure &err) {
2959  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
2960  return false;
2961  }
2962  _multiBind(result, tag, outDimTags, true, true);
2963  return true;
2964 }
2965 
2966 void OCC_Internals::_setExtrudedAttributes(
2967  const TopoDS_Compound &c, BRepSweep_Prism *p, BRepSweep_Revol *r,
2968  ExtrudeParams *e, double x, double y, double z, double dx, double dy,
2969  double dz, double ax, double ay, double az, double angle)
2970 {
2971  if(!p && !r) return;
2972 
2973  bool extrude_attributes = (e ? true : false);
2974 
2975  if(extrude_attributes && r && angle >= 2 * M_PI) {
2976  // OCC removes the origin edge from e.g. disks, which makes it impossible to
2977  // generate the 2D surface mesh by extrusion of the 1D edge mesh
2978  Msg::Warning("Extruded meshes by revolution only for angle < 2*Pi");
2979  extrude_attributes = false;
2980  }
2981 
2982  TopExp_Explorer exp0;
2983 
2984  for(exp0.Init(c, TopAbs_FACE); exp0.More(); exp0.Next()) {
2985  TopoDS_Face face = TopoDS::Face(exp0.Current());
2986  TopoDS_Shape bot = p ? p->FirstShape(face) : r->FirstShape(face);
2987  TopoDS_Shape top = p ? p->LastShape(face) : r->LastShape(face);
2988  if(extrude_attributes) {
2990  ee->fill(p ? TRANSLATE : ROTATE, dx, dy, dz, ax, ay, az, x, y, z, angle);
2991  ee->mesh = e->mesh;
2992  _attributes->insert(new OCCAttributes(2, top, ee, 2, bot));
2993  }
2994  TopoDS_Shape vol = p ? p->Shape(face) : r->Shape(face);
2995  if(extrude_attributes) {
2997  ee->fill(p ? TRANSLATE : ROTATE, dx, dy, dz, ax, ay, az, x, y, z, angle);
2998  ee->mesh = e->mesh;
2999  _attributes->insert(new OCCAttributes(3, vol, ee, 2, bot));
3000  }
3001  }
3002 
3003  for(exp0.Init(c, TopAbs_EDGE); exp0.More(); exp0.Next()) {
3004  TopoDS_Edge edge = TopoDS::Edge(exp0.Current());
3005  TopoDS_Shape bot = p ? p->FirstShape(edge) : r->FirstShape(edge);
3006  TopoDS_Shape top = p ? p->LastShape(edge) : r->LastShape(edge);
3007  if(extrude_attributes) {
3009  ee->fill(p ? TRANSLATE : ROTATE, dx, dy, dz, ax, ay, az, x, y, z, angle);
3010  ee->mesh = e->mesh;
3011  _attributes->insert(new OCCAttributes(1, top, ee, 1, bot));
3012  }
3013  TopoDS_Shape sur = p ? p->Shape(edge) : r->Shape(edge);
3014  if(extrude_attributes) {
3016  ee->fill(p ? TRANSLATE : ROTATE, dx, dy, dz, ax, ay, az, x, y, z, angle);
3017  ee->mesh = e->mesh;
3018  _attributes->insert(new OCCAttributes(2, sur, ee, 1, bot));
3019  }
3020  }
3021 
3022  for(exp0.Init(c, TopAbs_VERTEX); exp0.More(); exp0.Next()) {
3023  TopoDS_Vertex vertex = TopoDS::Vertex(exp0.Current());
3024  TopoDS_Shape bot = p ? p->FirstShape(vertex) : r->FirstShape(vertex);
3025  TopoDS_Shape top = p ? p->LastShape(vertex) : r->LastShape(vertex);
3026  TopoDS_Shape lin = p ? p->Shape(vertex) : r->Shape(vertex);
3027  if(extrude_attributes) {
3029  ee->fill(p ? TRANSLATE : ROTATE, dx, dy, dz, ax, ay, az, x, y, z, angle);
3030  ee->mesh = e->mesh;
3031  _attributes->insert(new OCCAttributes(1, lin, ee, 0, bot));
3032  }
3033  {
3034  double lc = _attributes->getMeshSize(0, bot);
3035  if(lc > 0 && lc < MAX_LC)
3036  _attributes->insert(new OCCAttributes(0, top, lc));
3037  }
3038  }
3039 }
3040 
3041 int OCC_Internals::_getFuzzyTag(int dim, const TopoDS_Shape &s)
3042 {
3043  if(_isBound(dim, s)) return _find(dim, s);
3044 
3045  std::vector<TopoDS_Shape> candidates;
3046  _attributes->getSimilarShapes(dim, s, candidates);
3047 
3048  int num = 0;
3049  for(std::size_t i = 0; i < candidates.size(); i++) {
3050  if(_isBound(dim, candidates[i])) { num++; }
3051  }
3052  Msg::Debug("Extruded mesh constraint fuzzy search: found %d candidates "
3053  "(dim=%d, %d bound)",
3054  (int)candidates.size(), dim, num);
3055  for(std::size_t i = 0; i < candidates.size(); i++) {
3056  if(_isBound(dim, candidates[i])) { return _find(dim, candidates[i]); }
3057  }
3058  return -1;
3059 }
3060 
3061 void OCC_Internals::_copyExtrudedAttributes(TopoDS_Edge edge, GEdge *ge)
3062 {
3063  int sourceDim = -1;
3064  TopoDS_Shape sourceShape;
3065  ExtrudeParams *e =
3066  _attributes->getExtrudeParams(1, edge, sourceDim, sourceShape);
3067  if(!e) return;
3068  if(e->geo.Mode == EXTRUDED_ENTITY) {
3069  e->geo.Source = _getFuzzyTag(0, sourceShape);
3070  }
3071  else if(e->geo.Mode == COPIED_ENTITY) {
3072  e->geo.Source = _getFuzzyTag(1, sourceShape);
3073  // detect degenerate extrusions or cycles
3074  ExtrudeParams *p = e;
3075  int recur = 0;
3076  while(++recur < CTX::instance()->mesh.maxRetries) {
3077  if(ge->tag() == p->geo.Source) {
3078  Msg::Info("Extrusion layer cycle detected for curve %d", ge->tag());
3079  e = nullptr;
3080  break;
3081  }
3082  GEdge *src = ge->model()->getEdgeByTag(p->geo.Source);
3083  if(src && src->meshAttributes.extrude &&
3085  p = src->meshAttributes.extrude;
3086  }
3087  else {
3088  break;
3089  }
3090  }
3091  }
3092  ge->meshAttributes.extrude = e;
3093 }
3094 
3095 void OCC_Internals::_copyExtrudedAttributes(TopoDS_Face face, GFace *gf)
3096 {
3097  int sourceDim = -1;
3098  TopoDS_Shape sourceShape;
3099  ExtrudeParams *e =
3100  _attributes->getExtrudeParams(2, face, sourceDim, sourceShape);
3101  if(!e) return;
3102  if(e->geo.Mode == EXTRUDED_ENTITY) {
3103  e->geo.Source = _getFuzzyTag(1, sourceShape);
3104  }
3105  else if(e->geo.Mode == COPIED_ENTITY) {
3106  e->geo.Source = _getFuzzyTag(2, sourceShape);
3107  // detect degenerate extrusions or cycles
3108  ExtrudeParams *p = e;
3109  int recur = 0;
3110  while(++recur < CTX::instance()->mesh.maxRetries) {
3111  if(gf->tag() == p->geo.Source) {
3112  Msg::Info("Extrusion layer cycle detected for surface %d", gf->tag());
3113  e = nullptr;
3114  break;
3115  }
3116  GFace *src = gf->model()->getFaceByTag(p->geo.Source);
3117  if(src && src->meshAttributes.extrude &&
3119  p = src->meshAttributes.extrude;
3120  }
3121  else {
3122  break;
3123  }
3124  }
3125  }
3126  gf->meshAttributes.extrude = e;
3127 }
3128 
3129 void OCC_Internals::_copyExtrudedAttributes(TopoDS_Solid solid, GRegion *gr)
3130 {
3131  int sourceDim = -1;
3132  TopoDS_Shape sourceShape;
3133  ExtrudeParams *e =
3134  _attributes->getExtrudeParams(3, solid, sourceDim, sourceShape);
3135  if(!e) return;
3136  if(e->geo.Mode == EXTRUDED_ENTITY) {
3137  e->geo.Source = _getFuzzyTag(2, sourceShape);
3138  }
3139  gr->meshAttributes.extrude = e;
3140 }
3141 
3142 template <class T>
3143 static int getReturnedShapes(const TopoDS_Compound &c, T *sweep,
3144  std::vector<TopoDS_Shape> &top,
3145  std::vector<TopoDS_Shape> &body,
3146  std::vector<std::vector<TopoDS_Shape> > &lateral)
3147 {
3148  TopExp_Explorer exp0, exp1;
3149  for(exp0.Init(c, TopAbs_FACE); exp0.More(); exp0.Next()) {
3150  TopoDS_Face face = TopoDS::Face(exp0.Current());
3151  top.push_back(sweep->LastShape(face));
3152  body.push_back(sweep->Shape(face));
3153  lateral.push_back(std::vector<TopoDS_Shape>());
3154  for(exp1.Init(face, TopAbs_EDGE); exp1.More(); exp1.Next()) {
3155  TopoDS_Edge edge = TopoDS::Edge(exp1.Current());
3156  lateral.back().push_back(sweep->Shape(edge));
3157  }
3158  }
3159  if(top.size()) return 3;
3160  for(exp0.Init(c, TopAbs_EDGE); exp0.More(); exp0.Next()) {
3161  TopoDS_Edge edge = TopoDS::Edge(exp0.Current());
3162  top.push_back(sweep->LastShape(edge));
3163  body.push_back(sweep->Shape(edge));
3164  lateral.push_back(std::vector<TopoDS_Shape>());
3165  for(exp1.Init(edge, TopAbs_VERTEX); exp1.More(); exp1.Next()) {
3166  TopoDS_Vertex vertex = TopoDS::Vertex(exp1.Current());
3167  lateral.back().push_back(sweep->Shape(vertex));
3168  }
3169  }
3170  if(top.size()) return 2;
3171  for(exp0.Init(c, TopAbs_VERTEX); exp0.More(); exp0.Next()) {
3172  TopoDS_Vertex vertex = TopoDS::Vertex(exp0.Current());
3173  top.push_back(sweep->LastShape(vertex));
3174  body.push_back(sweep->Shape(vertex));
3175  }
3176  if(top.size()) return 1;
3177  return 0;
3178 }
3179 
3180 bool OCC_Internals::_extrudePerDim(
3181  int mode, int inDim, const std::vector<int> &inTags, double x, double y,
3182  double z, double dx, double dy, double dz, double ax, double ay, double az,
3183  double angle, int wireTag, std::vector<std::pair<int, int> > &outDimTags,
3184  ExtrudeParams *e, const std::string &trihedron)
3185 {
3186  // build a single compound shape, so that we won't duplicate internal
3187  // boundaries
3188  BRep_Builder b;
3189  TopoDS_Compound c;
3190  b.MakeCompound(c);
3191  for(std::size_t i = 0; i < inTags.size(); i++) {
3192  if(!_isBound(inDim, inTags[i])) {
3193  Msg::Error("Unknown OpenCASCADE entity of dimension %d with tag %d",
3194  inDim, inTags[i]);
3195  return false;
3196  }
3197  TopoDS_Shape shape = _find(inDim, inTags[i]);
3198  b.Add(c, shape);
3199  }
3200  TopoDS_Shape result;
3201  std::vector<TopoDS_Shape> top, body;
3202  std::vector<std::vector<TopoDS_Shape> > lateral;
3203  int dim = -1;
3204  try {
3205  if(mode == 0) { // extrude
3206  BRepPrimAPI_MakePrism p(c, gp_Vec(dx, dy, dz), Standard_False);
3207  p.Build();
3208  if(!p.IsDone()) {
3209  Msg::Error("Could not extrude");
3210  return false;
3211  }
3212  result = p.Shape();
3213  const BRepSweep_Prism &prism(p.Prism());
3214  _setExtrudedAttributes(c, (BRepSweep_Prism *)&prism, nullptr, e, 0., 0.,
3215  0., dx, dy, dz, 0., 0., 0., 0.);
3216  dim = getReturnedShapes(c, (BRepSweep_Prism *)&prism, top, body, lateral);
3217  }
3218  else if(mode == 1) { // revolve
3219  gp_Ax1 axisOfRevolution(gp_Pnt(x, y, z), gp_Dir(ax, ay, az));
3220  BRepPrimAPI_MakeRevol r(c, axisOfRevolution, angle, Standard_False);
3221  r.Build();
3222  if(!r.IsDone()) {
3223  Msg::Error("Could not revolve");
3224  return false;
3225  }
3226  result = r.Shape();
3227  const BRepSweep_Revol &revol(r.Revol());
3228  _setExtrudedAttributes(c, nullptr, (BRepSweep_Revol *)&revol, e, x, y, z,
3229  0., 0., 0., ax, ay, az, angle);
3230  dim = getReturnedShapes(c, (BRepSweep_Revol *)&revol, top, body, lateral);
3231  }
3232  else if(mode == 2) { // pipe
3233  if(!_tagWire.IsBound(wireTag)) {
3234  Msg::Error("Unknown OpenCASCADE wire with tag %d", wireTag);
3235  return false;
3236  }
3237  TopoDS_Wire wire = TopoDS::Wire(_tagWire.Find(wireTag));
3238  // DiscreteTrihedron seems the most robust; CorrectedFrenet e.g. fails on
3239  // very simple cases with straight extrusions.
3240  GeomFill_Trihedron mode = GeomFill_IsDiscreteTrihedron;
3241  if(trihedron == "DiscreteTrihedron")
3242  mode = GeomFill_IsDiscreteTrihedron;
3243  else if(trihedron == "CorrectedFrenet")
3244  mode = GeomFill_IsCorrectedFrenet;
3245  else if(trihedron == "Fixed")
3246  mode = GeomFill_IsFixed;
3247  else if(trihedron == "Frenet")
3248  mode = GeomFill_IsFrenet;
3249  else if(trihedron == "ConstantNormal")
3250  mode = GeomFill_IsConstantNormal;
3251  else if(trihedron == "Darboux")
3252  mode = GeomFill_IsDarboux;
3253  else if(trihedron == "GuideAC")
3254  mode = GeomFill_IsGuideAC;
3255  else if(trihedron == "GuidePlan")
3256  mode = GeomFill_IsGuidePlan;
3257  else if(trihedron == "GuideACWithContact")
3258  mode = GeomFill_IsGuideACWithContact;
3259  else if(trihedron == "GuidePlanWithContact")
3260  mode = GeomFill_IsGuidePlanWithContact;
3261  else
3262  Msg::Warning(
3263  "Unknown trihedron mode for pipe: using 'DiscreteTrihedron'");
3264  BRepOffsetAPI_MakePipe p(wire, c, mode);
3265  p.Build();
3266  if(!p.IsDone()) {
3267  Msg::Error("Could not create pipe");
3268  return false;
3269  }
3270  result = p.Shape();
3271  // const BRepFill_Pipe &pipe(p.Pipe());
3272  if(e)
3273  Msg::Warning(
3274  "Structured meshes not yet available with OpenCASCADE pipe");
3275  // Check if
3276  // pipe.FirstShape() gives us "bottom"
3277  // pipe.LastShape() gives us "top"
3278  // pipe.Shape() gives us "body"
3279  // using pipe.Spine(), pipe.{Face,Edge}(spine, c) gives us the lateral
3280  // entities
3281  // dim = getReturnedShapesForPipe(c, pipe, top, body, lateral);
3282  }
3283  } catch(Standard_Failure &err) {
3284  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
3285  return false;
3286  }
3287 
3288  _multiBind(result, -1, outDimTags, true, true);
3289 
3290  // return entities in the same order as the built-in kernel extrusion
3291  if(dim >= 1 && dim <= 3 && top.size() == inTags.size() &&
3292  top.size() == body.size()) {
3293  outDimTags.clear();
3294  for(std::size_t i = 0; i < top.size(); i++) {
3295  if(_isBound(dim - 1, top[i]))
3296  outDimTags.push_back(
3297  std::make_pair(dim - 1, _find(dim - 1, top[i])));
3298  if(_isBound(dim, body[i]))
3299  outDimTags.push_back(std::make_pair(dim, _find(dim, body[i])));
3300  if(CTX::instance()->geom.extrudeReturnLateral &&
3301  top.size() == lateral.size()) {
3302  for(std::size_t j = 0; j < lateral[i].size(); j++) {
3303  if(_isBound(dim - 1, lateral[i][j]))
3304  outDimTags.push_back(
3305  std::make_pair(dim - 1, _find(dim - 1, lateral[i][j])));
3306  }
3307  }
3308  }
3309  }
3310  return true;
3311 }
3312 
3313 bool OCC_Internals::_extrude(int mode,
3314  const std::vector<std::pair<int, int> > &inDimTags,
3315  double x, double y, double z, double dx, double dy,
3316  double dz, double ax, double ay, double az,
3317  double angle, int wireTag,
3318  std::vector<std::pair<int, int> > &outDimTags,
3319  ExtrudeParams *e, const std::string &trihedron)
3320 {
3321  std::vector<int> inTags[4];
3322  for(std::size_t i = 0; i < inDimTags.size(); i++) {
3323  int dim = inDimTags[i].first;
3324  if(dim < 0 || dim > 3) {
3325  Msg::Error("Wrong input dimension in extrusion");
3326  return false;
3327  }
3328  inTags[dim].push_back(inDimTags[i].second);
3329  }
3330  for(int dim = 0; dim < 4; dim++) {
3331  if(!inTags[dim].empty()) {
3332  std::vector<std::pair<int, int> > out;
3333  if(_extrudePerDim(mode, dim, inTags[dim], x, y, z, dx, dy, dz, ax, ay, az,
3334  angle, wireTag, out, e, trihedron)) {
3335  outDimTags.insert(outDimTags.end(), out.begin(), out.end());
3336  }
3337  }
3338  }
3339  return true;
3340 }
3341 
3342 bool OCC_Internals::extrude(const std::vector<std::pair<int, int> > &inDimTags,
3343  double dx, double dy, double dz,
3344  std::vector<std::pair<int, int> > &outDimTags,
3345  ExtrudeParams *e)
3346 {
3347  return _extrude(0, inDimTags, 0., 0., 0., dx, dy, dz, 0., 0., 0., 0., 0,
3348  outDimTags, e);
3349 }
3350 
3351 bool OCC_Internals::revolve(const std::vector<std::pair<int, int> > &inDimTags,
3352  double x, double y, double z, double ax, double ay,
3353  double az, double angle,
3354  std::vector<std::pair<int, int> > &outDimTags,
3355  ExtrudeParams *e)
3356 {
3357  return _extrude(1, inDimTags, x, y, z, 0., 0., 0., ax, ay, az, angle, 0,
3358  outDimTags, e);
3359 }
3360 
3361 bool OCC_Internals::addPipe(const std::vector<std::pair<int, int> > &inDimTags,
3362  int wireTag,
3363  std::vector<std::pair<int, int> > &outDimTags,
3364  const std::string &trihedron)
3365 {
3366  std::string t = trihedron;
3367  if(t.empty()) t = CTX::instance()->geom.pipeDefaultTrihedron;
3368  return _extrude(2, inDimTags, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., wireTag,
3369  outDimTags, nullptr, t);
3370 }
3371 
3372 bool OCC_Internals::_fillet(int mode, const std::vector<int> &volumeTags,
3373  const std::vector<int> &curveTags,
3374  const std::vector<int> &surfaceTags,
3375  const std::vector<double> &param,
3376  std::vector<std::pair<int, int> > &outDimTags,
3377  bool removeVolume)
3378 {
3379  std::vector<TopoDS_Edge> edges;
3380  for(std::size_t i = 0; i < curveTags.size(); i++) {
3381  if(!_tagEdge.IsBound(curveTags[i])) {
3382  Msg::Error("Unknown OpenCASCADE curve with tag %d", curveTags[i]);
3383  return false;
3384  }
3385  edges.push_back(TopoDS::Edge(_tagEdge.Find(curveTags[i])));
3386  }
3387 
3388  std::vector<TopoDS_Face> faces;
3389  for(std::size_t i = 0; i < surfaceTags.size(); i++) {
3390  if(!_tagFace.IsBound(surfaceTags[i])) {
3391  Msg::Error("Unknown OpenCASCADE surface with tag %d", surfaceTags[i]);
3392  return false;
3393  }
3394  faces.push_back(TopoDS::Face(_tagFace.Find(surfaceTags[i])));
3395  }
3396  if(mode && edges.size() != faces.size()) {
3397  Msg::Error("Different number of curves and surfaces for chamfer");
3398  return false;
3399  }
3400 
3401  // build a single compound shape
3402  BRep_Builder b;
3403  TopoDS_Compound c;
3404  b.MakeCompound(c);
3405  for(std::size_t i = 0; i < volumeTags.size(); i++) {
3406  if(!_isBound(3, volumeTags[i])) {
3407  Msg::Error("Unknown OpenCASCADE volume with tag %d", volumeTags[i]);
3408  return false;
3409  }
3410  TopoDS_Shape shape = _find(3, volumeTags[i]);
3411  if(removeVolume) _unbind(shape, 3, volumeTags[i], true);
3412  if(CTX::instance()->geom.occAutoFix) {
3413  // make sure the volume is finite
3414  ShapeFix_Solid fix(TopoDS::Solid(shape));
3415  fix.Perform();
3416  shape = fix.Solid();
3417  }
3418  b.Add(c, shape);
3419  }
3420  TopoDS_Shape result;
3421  try {
3422  if(mode == 0) { // fillet
3423  BRepFilletAPI_MakeFillet f(c);
3424  for(std::size_t i = 0; i < edges.size(); i++) {
3425  if(param.size() == 1)
3426  f.Add(param[0], edges[i]);
3427  else if(param.size() == edges.size())
3428  f.Add(param[i], edges[i]);
3429  else if(param.size() == 2 * edges.size())
3430  f.Add(param[2 * i], param[2 * i + 1], edges[i]);
3431  }
3432  f.Build();
3433  if(!f.IsDone()) {
3434  Msg::Error("Could not compute fillet");
3435  return false;
3436  }
3437  result = f.Shape();
3438  }
3439  else { // chamfer
3440  BRepFilletAPI_MakeChamfer f(c);
3441  for(std::size_t i = 0; i < edges.size(); i++) {
3442  if(param.size() == 1)
3443  f.Add(param[0], param[0], edges[i], faces[i]);
3444  else if(param.size() == edges.size())
3445  f.Add(param[i], param[i], edges[i], faces[i]);
3446  else if(param.size() == 2 * edges.size())
3447  f.Add(param[2 * i], param[2 * i + 1], edges[i], faces[i]);
3448  }
3449  f.Build();
3450  if(!f.IsDone()) {
3451  Msg::Error("Could not compute chamfer");
3452  return false;
3453  }
3454  result = f.Shape();
3455  }
3456  } catch(Standard_Failure &err) {
3457  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
3458  return false;
3459  }
3460 
3461  if(result.IsNull()) {
3462  Msg::Error("%s produces empty shape", mode ? "Chamfer" : "Fillet");
3463  return false;
3464  }
3465 
3466  // TODO: if removeVolume and CTX::instance()->geom.occBooleanPreserveNumbering
3467  // are set we could use Generated(), Modified() and IsDeleted() in a similar
3468  // way as what we do for boolean operation, in order to try to preserve tags
3469 
3470  _multiBind(result, -1, outDimTags, true, true);
3471  return true;
3472 }
3473 
3474 bool OCC_Internals::fillet(const std::vector<int> &volumeTags,
3475  const std::vector<int> &curveTags,
3476  const std::vector<double> &radii,
3477  std::vector<std::pair<int, int> > &outDimTags,
3478  bool removeVolume)
3479 {
3480  std::vector<int> dummy;
3481  return _fillet(0, volumeTags, curveTags, dummy, radii, outDimTags,
3482  removeVolume);
3483 }
3484 
3485 bool OCC_Internals::chamfer(const std::vector<int> &volumeTags,
3486  const std::vector<int> &curveTags,
3487  const std::vector<int> &surfaceTags,
3488  const std::vector<double> &distances,
3489  std::vector<std::pair<int, int> > &outDimTags,
3490  bool removeVolume)
3491 {
3492  return _fillet(1, volumeTags, curveTags, surfaceTags, distances, outDimTags,
3493  removeVolume);
3494 }
3495 
3496 static void _filterTags(std::vector<std::pair<int, int> > &outDimTags,
3497  int minDim)
3498 {
3499  std::vector<std::pair<int, int> > tmp(outDimTags);
3500  outDimTags.clear();
3501  for(std::size_t i = 0; i < tmp.size(); i++) {
3502  if(tmp[i].first >= minDim) outDimTags.push_back(tmp[i]);
3503  }
3504 }
3505 
3507  int tag, BooleanOperator op,
3508  const std::vector<std::pair<int, int> > &objectDimTags,
3509  const std::vector<std::pair<int, int> > &toolDimTags,
3510  std::vector<std::pair<int, int> > &outDimTags,
3511  std::vector<std::vector<std::pair<int, int> > > &outDimTagsMap,
3512  bool removeObject, bool removeTool)
3513 {
3515  bool parallel = CTX::instance()->geom.occParallel;
3516  bool preserveNumbering = CTX::instance()->geom.occBooleanPreserveNumbering;
3517 
3518  if(objectDimTags.empty()) return true;
3519 
3520  if(tag >= 0 && _isBound(objectDimTags[0].first, tag)) {
3521  Msg::Error("OpenCASCADE entity with tag %d already exists", tag);
3522  return false;
3523  }
3524 
3525  int minDim = 3;
3526  TopTools_ListOfShape objectShapes, toolShapes;
3527  for(std::size_t i = 0; i < objectDimTags.size(); i++) {
3528  int dim = objectDimTags[i].first;
3529  int t = objectDimTags[i].second;
3530  if(!_isBound(dim, t)) {
3531  Msg::Error("Unknown OpenCASCADE entity of dimension %d with tag %d", dim,
3532  t);
3533  return false;
3534  }
3535  else {
3536  TopoDS_Shape object = _find(dim, t);
3537  objectShapes.Append(object);
3538  }
3539  minDim = std::min(minDim, dim);
3540  }
3541  for(std::size_t i = 0; i < toolDimTags.size(); i++) {
3542  int dim = toolDimTags[i].first;
3543  int t = toolDimTags[i].second;
3544  if(!_isBound(dim, t)) {
3545  Msg::Error("Unknown OpenCASCADE entity of dimension %d with tag %d", dim,
3546  t);
3547  return false;
3548  }
3549  else {
3550  TopoDS_Shape tool = _find(dim, t);
3551  toolShapes.Append(tool);
3552  }
3553  minDim = std::min(minDim, dim);
3554  }
3555 
3556  TopoDS_Shape result;
3557  std::vector<TopoDS_Shape> mapOriginal;
3558  std::vector<TopTools_ListOfShape> mapModified, mapGenerated;
3559  std::vector<bool> mapDeleted;
3560  try {
3561  switch(op) {
3562  case OCC_Internals::Union: {
3563  BRepAlgoAPI_Fuse fuse;
3564  fuse.SetRunParallel(parallel);
3565  fuse.SetArguments(objectShapes);
3566  fuse.SetTools(toolShapes);
3567  if(tolerance > 0.0) fuse.SetFuzzyValue(tolerance);
3568 
3569  // TODO: add gluing option to speed-up operations when no "real"
3570  // intersections are present
3571  // * default:
3572  // fuse.SetGlue(BOPAlgo_GlueOff);
3573  // * speed up if no real intersection but partial or full overlapping
3574  // faces/edges:
3575  // fuse.SetGlue(BOPAlgo_Shift);
3576  // * speed up if no real intersection and no partial overlaps:
3577  // fuse.SetGlue(BOPAlgo_GlueFull);
3578 
3579  // TODO: add option to prevent reuse of existing shapes:
3580  // fuse.SetNonDestructive(true);
3581 
3582  fuse.Build();
3583  if(!fuse.IsDone()) {
3584  Msg::Error("Fuse operation cannot be performed");
3585  return false;
3586  }
3587  if(CTX::instance()->geom.occUnionUnify) {
3588  // try to unify faces and edges of the shape (remove internal seams)
3589  // which lie on the same geometry
3590 #if OCC_VERSION_HEX < 0x070400
3591  result = fuse.Shape();
3592  ShapeUpgrade_UnifySameDomain unify(result);
3593  unify.Build();
3594  result = unify.Shape();
3595 #else
3596  // better, as it preserves the history; TODO: maybe we should also make
3597  // this available for the other boolean operations
3598  fuse.SimplifyResult();
3599  result = fuse.Shape();
3600 #endif
3601  }
3602  else {
3603  result = fuse.Shape();
3604  }
3605  TopTools_ListIteratorOfListOfShape it(objectShapes);
3606  for(; it.More(); it.Next()) {
3607  mapOriginal.push_back(it.Value());
3608  mapModified.push_back(fuse.Modified(it.Value()));
3609  mapDeleted.push_back(fuse.IsDeleted(it.Value()));
3610  mapGenerated.push_back(fuse.Generated(it.Value()));
3611  }
3612  TopTools_ListIteratorOfListOfShape it2(toolShapes);
3613  for(; it2.More(); it2.Next()) {
3614  mapOriginal.push_back(it2.Value());
3615  mapModified.push_back(fuse.Modified(it2.Value()));
3616  mapDeleted.push_back(fuse.IsDeleted(it2.Value()));
3617  mapGenerated.push_back(fuse.Generated(it2.Value()));
3618  }
3619  } break;
3621  BRepAlgoAPI_Common common;
3622  common.SetRunParallel(parallel);
3623  common.SetArguments(objectShapes);
3624  common.SetTools(toolShapes);
3625  if(tolerance > 0.0) common.SetFuzzyValue(tolerance);
3626  common.Build();
3627  if(!common.IsDone()) {
3628  Msg::Error("Intersection operation cannot be performed");
3629  return false;
3630  }
3631  result = common.Shape();
3632  TopTools_ListIteratorOfListOfShape it(objectShapes);
3633  for(; it.More(); it.Next()) {
3634  mapOriginal.push_back(it.Value());
3635  mapModified.push_back(common.Modified(it.Value()));
3636  mapDeleted.push_back(common.IsDeleted(it.Value()));
3637  mapGenerated.push_back(common.Generated(it.Value()));
3638  }
3639  TopTools_ListIteratorOfListOfShape it2(toolShapes);
3640  for(; it2.More(); it2.Next()) {
3641  mapOriginal.push_back(it2.Value());
3642  mapModified.push_back(common.Modified(it2.Value()));
3643  mapDeleted.push_back(common.IsDeleted(it2.Value()));
3644  mapGenerated.push_back(common.Generated(it2.Value()));
3645  }
3646  } break;
3647 
3649  BRepAlgoAPI_Cut cut;
3650  cut.SetRunParallel(parallel);
3651  cut.SetArguments(objectShapes);
3652  cut.SetTools(toolShapes);
3653  if(tolerance > 0.0) cut.SetFuzzyValue(tolerance);
3654  cut.Build();
3655  if(!cut.IsDone()) {
3656  Msg::Error("Intersection operation cannot be performed");
3657  return false;
3658  }
3659  result = cut.Shape();
3660  TopTools_ListIteratorOfListOfShape it(objectShapes);
3661  for(; it.More(); it.Next()) {
3662  mapOriginal.push_back(it.Value());
3663  mapModified.push_back(cut.Modified(it.Value()));
3664  mapDeleted.push_back(cut.IsDeleted(it.Value()));
3665  mapGenerated.push_back(cut.Generated(it.Value()));
3666  }
3667  TopTools_ListIteratorOfListOfShape it2(toolShapes);
3668  for(; it2.More(); it2.Next()) {
3669  mapOriginal.push_back(it2.Value());
3670  mapModified.push_back(cut.Modified(it2.Value()));
3671  mapDeleted.push_back(cut.IsDeleted(it2.Value()));
3672  mapGenerated.push_back(cut.Generated(it2.Value()));
3673  }
3674  } break;
3675 
3677  default: {
3678  BRepAlgoAPI_BuilderAlgo fragments;
3679  fragments.SetRunParallel(parallel);
3680  objectShapes.Append(toolShapes);
3681  toolShapes.Clear();
3682  fragments.SetArguments(objectShapes);
3683  if(tolerance > 0.0) fragments.SetFuzzyValue(tolerance);
3684  fragments.Build();
3685 #if OCC_VERSION_HEX > 0x070100
3686  if(fragments.HasErrors() &&
3687  fragments.HasError(STANDARD_TYPE(BOPAlgo_AlertTooFewArguments))) {
3688  Msg::Warning("Boolean fragments skipped - too few arguments");
3689  return true;
3690  }
3691 #endif
3692  if(!fragments.IsDone()) {
3693  Msg::Error("Boolean fragments failed");
3694  return false;
3695  }
3696  result = fragments.Shape();
3697  TopTools_ListIteratorOfListOfShape it(objectShapes);
3698  for(; it.More(); it.Next()) {
3699  mapOriginal.push_back(it.Value());
3700  mapModified.push_back(fragments.Modified(it.Value()));
3701  mapDeleted.push_back(fragments.IsDeleted(it.Value()));
3702  mapGenerated.push_back(fragments.Generated(it.Value()));
3703  }
3704  } break;
3705  }
3706  } catch(Standard_Failure &err) {
3707  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
3708  return false;
3709  }
3710 
3711  std::vector<std::pair<int, int> > inDimTags;
3712  inDimTags.insert(inDimTags.end(), objectDimTags.begin(), objectDimTags.end());
3713  inDimTags.insert(inDimTags.end(), toolDimTags.begin(), toolDimTags.end());
3714  std::size_t numObjects = objectDimTags.size();
3715 
3716  if(tag >= 0 || !preserveNumbering) {
3717  // if we specify the tag explicitly, or if we don't care about preserving
3718  // the numering, just go ahead and bind the resulting shape (and sub-shapes)
3719  for(std::size_t i = 0; i < inDimTags.size(); i++) {
3720  bool remove = (i < numObjects) ? removeObject : removeTool;
3721  if(remove) {
3722  int d = inDimTags[i].first;
3723  int t = inDimTags[i].second;
3724  if(_isBound(d, t)) {
3726  _unbind(_find(d, t), d, t, true);
3727  else
3728  _unbindWithoutChecks(_find(d, t));
3729  }
3730  }
3731  }
3732  _multiBind(result, tag, outDimTags, (tag >= 0) ? true : false, true,
3733  (tag >= 0) ? false : true);
3734  _filterTags(outDimTags, minDim);
3735  }
3736  else {
3737  // otherwise, try to preserve the numbering of the input shapes that did not
3738  // change, or that were replaced by a single shape. Note that to preserve
3739  // the numbering of smaller dimension entities (on boundaries) they should
3740  // appear *before* higher dimensional entities in the object/tool lists.
3741  _toPreserve.clear();
3742  for(std::size_t i = 0; i < inDimTags.size(); i++) {
3743  int dim = inDimTags[i].first;
3744  int tag = inDimTags[i].second;
3745  bool remove = (i < numObjects) ? removeObject : removeTool;
3746  if(mapDeleted[i]) { // deleted
3747  if(remove) {
3749  _unbind(mapOriginal[i], dim, tag, true);
3750  else
3751  _unbindWithoutChecks(mapOriginal[i]);
3752  }
3753  Msg::Debug("BOOL (%d,%d) deleted", dim, tag);
3754  }
3755  else if(mapModified[i].Extent() == 0) { // not modified
3756  auto ins = _toPreserve.insert(std::make_pair(dim, tag));
3757  if(ins.second) // it's not yet in outDimTags
3758  outDimTags.push_back(std::make_pair(dim, tag));
3759  Msg::Debug("BOOL (%d,%d) not modified", dim, tag);
3760  }
3761  else if(mapModified[i].Extent() == 1) { // replaced by single one
3762  if(remove) {
3763  _unbind(mapOriginal[i], dim, tag, true);
3764  _bind(mapModified[i].First(), dim, tag, false); // not recursive!
3765  int t = _find(dim, mapModified[i].First());
3766  if(tag != t)
3767  Msg::Info("Could not preserve tag of %dD object %d (->%d)", dim,
3768  tag, t);
3769  auto ins = _toPreserve.insert(std::make_pair(dim, t));
3770  if(ins.second) // it's not yet in outDimTags
3771  outDimTags.push_back(std::make_pair(dim, t));
3772  }
3773  Msg::Debug("BOOL (%d,%d) replaced by 1", dim, tag);
3774  }
3775  else {
3776  if(remove) _unbind(mapOriginal[i], dim, tag, true);
3777  Msg::Debug("BOOL (%d,%d) other", dim, tag);
3778  }
3779  }
3780  for(int d = -2; d <= 3; d++) _recomputeMaxTag(d);
3781  // bind all remaining entities and add the new ones to the returned list
3782  _multiBind(result, -1, outDimTags, false, true, true);
3783  _filterTags(outDimTags, minDim);
3784  _toPreserve.clear();
3785  }
3786 
3787  // return input/output correspondence maps
3788  for(std::size_t i = 0; i < inDimTags.size(); i++) {
3789  int dim = inDimTags[i].first;
3790  int tag = inDimTags[i].second;
3791  std::pair<int, int> dimTag(dim, tag);
3792  std::vector<std::pair<int, int> > dimTags;
3793  if(mapDeleted[i]) { // deleted
3794  }
3795  else if(mapModified[i].Extent() == 0) { // not modified
3796  if(_isBound(dim, tag)) dimTags.push_back(dimTag);
3797  }
3798  else {
3799  TopTools_ListIteratorOfListOfShape it(mapModified[i]);
3800  for(; it.More(); it.Next()) {
3801  if(_isBound(dim, it.Value())) {
3802  int t = _find(dim, it.Value());
3803  dimTags.push_back(std::make_pair(dim, t));
3804  }
3805  }
3806  TopTools_ListIteratorOfListOfShape it2(mapGenerated[i]);
3807  for(; it2.More(); it2.Next()) {
3808  if(_isBound(dim, it2.Value())) {
3809  int t = _find(dim, it2.Value());
3810  dimTags.push_back(std::make_pair(dim, t));
3811  }
3812  }
3813  }
3814  std::ostringstream sstream;
3815  sstream << "BOOL in (" << dim << "," << tag << ") -> out";
3816  for(std::size_t j = 0; j < dimTags.size(); j++)
3817  sstream << " (" << dimTags[j].first << "," << dimTags[j].second << ")";
3818  Msg::Debug("%s", sstream.str().c_str());
3819  outDimTagsMap.push_back(dimTags);
3820  }
3821 
3822  return true;
3823 }
3824 
3826  int tag, const std::vector<std::pair<int, int> > &objectDimTags,
3827  const std::vector<std::pair<int, int> > &toolDimTags,
3828  std::vector<std::pair<int, int> > &outDimTags,
3829  std::vector<std::vector<std::pair<int, int> > > &outDimTagsMap,
3830  bool removeObject, bool removeTool)
3831 {
3832  return booleanOperator(tag, OCC_Internals::Union, objectDimTags, toolDimTags,
3833  outDimTags, outDimTagsMap, removeObject, removeTool);
3834 }
3835 
3837  int tag, const std::vector<std::pair<int, int> > &objectDimTags,
3838  const std::vector<std::pair<int, int> > &toolDimTags,
3839  std::vector<std::pair<int, int> > &outDimTags,
3840  std::vector<std::vector<std::pair<int, int> > > &outDimTagsMap,
3841  bool removeObject, bool removeTool)
3842 {
3843  return booleanOperator(tag, OCC_Internals::Intersection, objectDimTags,
3844  toolDimTags, outDimTags, outDimTagsMap, removeObject,
3845  removeTool);
3846 }
3847 
3849  int tag, const std::vector<std::pair<int, int> > &objectDimTags,
3850  const std::vector<std::pair<int, int> > &toolDimTags,
3851  std::vector<std::pair<int, int> > &outDimTags,
3852  std::vector<std::vector<std::pair<int, int> > > &outDimTagsMap,
3853  bool removeObject, bool removeTool)
3854 {
3855  return booleanOperator(tag, OCC_Internals::Difference, objectDimTags,
3856  toolDimTags, outDimTags, outDimTagsMap, removeObject,
3857  removeTool);
3858 }
3859 
3861  int tag, const std::vector<std::pair<int, int> > &objectDimTags,
3862  const std::vector<std::pair<int, int> > &toolDimTags,
3863  std::vector<std::pair<int, int> > &outDimTags,
3864  std::vector<std::vector<std::pair<int, int> > > &outDimTagsMap,
3865  bool removeObject, bool removeTool)
3866 {
3867  return booleanOperator(tag, OCC_Internals::Fragments, objectDimTags,
3868  toolDimTags, outDimTags, outDimTagsMap, removeObject,
3869  removeTool);
3870 }
3871 
3872 int OCC_Internals::_getMaxDim()
3873 {
3874  if(_tagSolid.Extent()) return 3;
3875  if(_tagFace.Extent()) return 2;
3876  if(_tagEdge.Extent()) return 1;
3877  return 0;
3878 }
3879 
3880 void OCC_Internals::_getAllDimTags(std::vector<std::pair<int, int> > &dimTags,
3881  int dim)
3882 {
3883  for(int d = -2; d < 4; d++) {
3884  if(dim != 99 && dim != d) continue;
3885  TopTools_DataMapIteratorOfDataMapOfIntegerShape exp;
3886  switch(d) {
3887  case 0: exp.Initialize(_tagVertex); break;
3888  case 1: exp.Initialize(_tagEdge); break;
3889  case 2: exp.Initialize(_tagFace); break;
3890  case 3: exp.Initialize(_tagSolid); break;
3891  case -1: exp.Initialize(_tagWire); break;
3892  case -2: exp.Initialize(_tagShell); break;
3893  }
3894  for(; exp.More(); exp.Next())
3895  dimTags.push_back(std::pair<int, int>(d, exp.Key()));
3896  }
3897 }
3898 
3900 {
3901  std::vector<std::pair<int, int> > objectDimTags, toolDimTags, outDimTags;
3902  std::vector<std::vector<std::pair<int, int> > > outDimTagsMap;
3903  _getAllDimTags(objectDimTags, _getMaxDim());
3904  booleanFragments(-1, objectDimTags, toolDimTags, outDimTags, outDimTagsMap,
3905  true, true);
3906 }
3907 
3908 bool OCC_Internals::mergeVertices(const std::vector<int> &tags)
3909 {
3910  std::vector<std::pair<int, int> > objectDimTags, toolDimTags, outDimTags;
3911  std::vector<std::vector<std::pair<int, int> > > outDimTagsMap;
3912  for(std::size_t i = 0; i < tags.size(); i++)
3913  objectDimTags.push_back(std::pair<int, int>(0, tags[i]));
3914  return booleanFragments(-1, objectDimTags, toolDimTags, outDimTags,
3915  outDimTagsMap, true, true);
3916 }
3917 
3918 void _addSimpleShapes(const TopoDS_Shape &shape,
3919  std::vector<TopoDS_Shape> &simple)
3920 {
3921  if(shape.ShapeType() != TopAbs_COMPOUND &&
3922  shape.ShapeType() != TopAbs_COMPSOLID) {
3923  simple.push_back(shape);
3924  return;
3925  }
3926 
3927  TopTools_MapOfShape mapShape;
3928  TopoDS_Iterator It(shape, Standard_True, Standard_True);
3929 
3930  for(; It.More(); It.Next()) {
3931  const TopoDS_Shape &s = It.Value();
3932  if(mapShape.Add(s)) {
3933  if(s.ShapeType() == TopAbs_COMPOUND ||
3934  s.ShapeType() == TopAbs_COMPSOLID) {
3935  _addSimpleShapes(s, simple);
3936  }
3937  else {
3938  simple.push_back(s);
3939  }
3940  }
3941  }
3942 }
3943 
3944 bool OCC_Internals::_transform(
3945  const std::vector<std::pair<int, int> > &inDimTags,
3946  BRepBuilderAPI_Transform *tfo, BRepBuilderAPI_GTransform *gtfo)
3947 {
3948  // build a single compound shape, so that we won't duplicate internal
3949  // boundaries
3950  BRep_Builder b;
3951  TopoDS_Compound c;
3952  b.MakeCompound(c);
3953  for(std::size_t i = 0; i < inDimTags.size(); i++) {
3954  int dim = inDimTags[i].first;
3955  int tag = inDimTags[i].second;
3956  if(!_isBound(dim, tag)) {
3957  Msg::Error("Unknown OpenCASCADE entity of dimension %d with tag %d", dim,
3958  tag);
3959  return false;
3960  }
3961  TopoDS_Shape shape = _find(dim, tag);
3962  b.Add(c, shape);
3963  }
3964 
3965  std::vector<TopoDS_Shape> inShapes;
3966  _addSimpleShapes(c, inShapes);
3967 
3968  TopoDS_Shape result;
3969  if(tfo) {
3970  tfo->Perform(c, Standard_False);
3971  if(!tfo->IsDone()) {
3972  Msg::Error("Could not apply transformation");
3973  return false;
3974  }
3975  result = tfo->Shape();
3976  }
3977  else if(gtfo) {
3978  gtfo->Perform(c, Standard_False);
3979  if(!gtfo->IsDone()) {
3980  Msg::Error("Could not apply transformation");
3981  return false;
3982  }
3983  result = gtfo->Shape();
3984  }
3985 
3986  // copy vertex-based meshing attributes
3987  TopExp_Explorer exp0;
3988  for(exp0.Init(c, TopAbs_VERTEX); exp0.More(); exp0.Next()) {
3989  TopoDS_Vertex vertex = TopoDS::Vertex(exp0.Current());
3990  TopoDS_Shape transformed;
3991  if(tfo)
3992  transformed = tfo->ModifiedShape(vertex);
3993  else if(gtfo)
3994  transformed = gtfo->ModifiedShape(vertex);
3995  if(!transformed.IsNull()) {
3996  double lc = _attributes->getMeshSize(0, vertex);
3997  if(lc > 0 && lc < MAX_LC)
3998  _attributes->insert(new OCCAttributes(0, transformed, lc));
3999  }
4000  }
4001 
4002  // try to re-bind trasnformed shapes to same tags as original shapes
4003  std::vector<TopoDS_Shape> outShapes;
4004  _addSimpleShapes(result, outShapes);
4005 
4006  if(inShapes.size() != inDimTags.size() ||
4007  inShapes.size() != outShapes.size()) {
4008  Msg::Error("OpenCASCADE transform changed the number of shapes");
4009  return false;
4010  }
4011  for(std::size_t i = 0; i < inDimTags.size(); i++) {
4012  int dim = inDimTags[i].first;
4013  int tag = inDimTags[i].second;
4014  if(CTX::instance()->geom.occSafeUnbind) {
4015  // safe, but slow: _unbind() has linear complexity with respect to the number
4016  // of entities in the model (due to the dependency checking of upward
4017  // adjencencies and the maximum tag update). Using this in a for loop to
4018  // translate copies of entities leads to quadratic complexity.
4019  _unbind(inShapes[i], dim, tag, true);
4020  }
4021  else {
4022  // bypass it by unbinding the shape and all its subshapes without checking
4023  // dependencies: this is a bit dangerous, as one could translate e.g. the
4024  // face of a cube (this is not allowed!) - which will unbind the face of
4025  // the cube. But the original face will actually be re-bound (with a
4026  // warning) at the next syncronization point, so it's not too bad...
4027  _unbindWithoutChecks(inShapes[i]);
4028  }
4029  // TODO: it would be even better to code a rebind() function to reuse the
4030  // tags not only of the shape, but of all the sub-shapes as well
4031  _bind(outShapes[i], dim, tag, true);
4032  }
4033 
4034  return true;
4035 }
4036 
4038  const std::vector<std::pair<int, int> > &inDimTags, double dx, double dy,
4039  double dz)
4040 {
4041  try {
4042  gp_Trsf t;
4043  t.SetTranslation(gp_Pnt(0, 0, 0), gp_Pnt(dx, dy, dz));
4044  BRepBuilderAPI_Transform tfo(t);
4045  return _transform(inDimTags, &tfo, nullptr);
4046  } catch(Standard_Failure &err) {
4047  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
4048  return false;
4049  }
4050 }
4051 
4052 bool OCC_Internals::rotate(const std::vector<std::pair<int, int> > &inDimTags,
4053  double x, double y, double z, double ax, double ay,
4054  double az, double angle)
4055 {
4056  try {
4057  gp_Trsf t;
4058  gp_Ax1 axisOfRevolution(gp_Pnt(x, y, z), gp_Dir(ax, ay, az));
4059  t.SetRotation(axisOfRevolution, angle);
4060  BRepBuilderAPI_Transform tfo(t);
4061  return _transform(inDimTags, &tfo, nullptr);
4062  } catch(Standard_Failure &err) {
4063  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
4064  return false;
4065  }
4066 }
4067 
4068 bool OCC_Internals::dilate(const std::vector<std::pair<int, int> > &inDimTags,
4069  double x, double y, double z, double a, double b,
4070  double c)
4071 {
4072  try {
4073  gp_GTrsf gt;
4074  gt.SetVectorialPart(gp_Mat(a, 0, 0, 0, b, 0, 0, 0, c));
4075  gt.SetTranslationPart(gp_XYZ(x * (1 - a), y * (1 - b), z * (1 - c)));
4076  BRepBuilderAPI_GTransform gtfo(gt);
4077  return _transform(inDimTags, nullptr, &gtfo);
4078  } catch(Standard_Failure &err) {
4079  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
4080  return false;
4081  }
4082 }
4083 
4084 bool OCC_Internals::symmetry(const std::vector<std::pair<int, int> > &inDimTags,
4085  double a, double b, double c, double d)
4086 {
4087  try {
4088  gp_GTrsf gt;
4089  double p = (a * a + b * b + c * c);
4090  if(!p) p = 1e-12;
4091  double f = -2.0 / p;
4092  gt.SetVectorialPart(gp_Mat(1 + a * a * f, a * b * f, a * c * f, a * b * f,
4093  1. + b * b * f, b * c * f, a * c * f, b * c * f,
4094  1. + c * c * f));
4095  gt.SetTranslationPart(gp_XYZ(a * d * f, b * d * f, c * d * f));
4096  BRepBuilderAPI_GTransform gtfo(gt);
4097  return _transform(inDimTags, nullptr, &gtfo);
4098  } catch(Standard_Failure &err) {
4099  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
4100  return false;
4101  }
4102 }
4103 
4104 bool OCC_Internals::affine(const std::vector<std::pair<int, int> > &inDimTags,
4105  const std::vector<double> &mat)
4106 {
4107  try {
4108  std::vector<double> a(mat);
4109  if(a.size() < 12) {
4110  Msg::Warning("%d < 12 entries in affine transform matrix", (int)a.size());
4111  a.resize(12, 0.);
4112  }
4113  gp_GTrsf gt;
4114  gt.SetVectorialPart(
4115  gp_Mat(a[0], a[1], a[2], a[4], a[5], a[6], a[8], a[9], a[10]));
4116  gt.SetTranslationPart(gp_XYZ(a[3], a[7], a[11]));
4117  BRepBuilderAPI_GTransform gtfo(gt);
4118  return _transform(inDimTags, nullptr, &gtfo);
4119  } catch(Standard_Failure &err) {
4120  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
4121  return false;
4122  }
4123 }
4124 
4125 bool OCC_Internals::copy(const std::vector<std::pair<int, int> > &inDimTags,
4126  std::vector<std::pair<int, int> > &outDimTags)
4127 {
4128  // build a single compound shape, so that we won't duplicate internal
4129  // boundaries
4130  BRep_Builder b;
4131  TopoDS_Compound c;
4132  b.MakeCompound(c);
4133  for(std::size_t i = 0; i < inDimTags.size(); i++) {
4134  int dim = inDimTags[i].first;
4135  int tag = inDimTags[i].second;
4136  if(!_isBound(dim, tag)) {
4137  Msg::Error("Unknown OpenCASCADE entity of dimension %d with tag %d", dim,
4138  tag);
4139  return false;
4140  }
4141  TopoDS_Shape shape = _find(dim, tag);
4142  b.Add(c, shape);
4143  }
4144 
4145  TopoDS_Shape result = BRepBuilderAPI_Copy(c).Shape();
4146  _multiBind(result, -1, outDimTags, true, true);
4147  return true;
4148 }
4149 
4150 bool OCC_Internals::remove(int dim, int tag, bool recursive)
4151 {
4152  if(!_isBound(dim, tag)) {
4153  Msg::Warning("Unknown OpenCASCADE entity of dimension %d with tag %d", dim,
4154  tag);
4155  return false;
4156  }
4157  _unbind(_find(dim, tag), dim, tag, recursive);
4158  return true;
4159 }
4160 
4161 bool OCC_Internals::remove(const std::vector<std::pair<int, int> > &dimTags,
4162  bool recursive)
4163 {
4164  bool ret = true;
4165  for(std::size_t i = 0; i < dimTags.size(); i++) {
4166  if(!remove(dimTags[i].first, dimTags[i].second, recursive)) ret = false;
4167  }
4168  return ret;
4169 }
4170 
4171 static void setTargetUnit(const std::string &unit)
4172 {
4173  if(unit.empty()) return; // use unit specified in the file
4174  if(!Interface_Static::SetCVal("xstep.cascade.unit", unit.c_str()))
4175  Msg::Error("Could not set OpenCASCADE target unit '%s'", unit.c_str());
4176 }
4177 
4178 #if defined(HAVE_OCC_CAF)
4179 
4180 static void getColorRGB(const Quantity_Color &col, double &r, double &g, double &b)
4181 {
4182 #if OCC_VERSION_HEX >= 0x070500
4183  // necessary to not alter RGB colors specified in STEP files (cf. #1399 and
4184  // #1723)
4185  col.Values(r, g, b, Quantity_TOC_sRGB);
4186 #else
4187  r = col.Red();
4188  g = col.Green();
4189  b = col.Blue();
4190 #endif
4191 }
4192 
4193 static void setShapeAttributes(OCCAttributesRTree *attributes,
4194  const Handle_XCAFDoc_ShapeTool &shapeTool,
4195  const Handle_XCAFDoc_ColorTool &colorTool,
4196  const Handle_XCAFDoc_MaterialTool &materialTool,
4197  const TDF_Label &label,
4198  const TopLoc_Location &loc,
4199  const std::string &pathName, bool isRef)
4200 {
4201  std::string phys = pathName;
4202  Handle(TDataStd_Name) n;
4203  if(label.FindAttribute(TDataStd_Name::GetID(), n)) {
4204  TCollection_ExtendedString name = n->Get();
4205  if(!phys.empty()) phys += "/";
4206  phys += TCollection_AsciiString(name).ToCString();
4207  }
4208 
4209  TopLoc_Location partLoc = loc;
4210  Handle(XCAFDoc_Location) l;
4211  if(label.FindAttribute(XCAFDoc_Location::GetID(), l)) {
4212  if(isRef)
4213  partLoc = partLoc * l->Get();
4214  else
4215  partLoc = l->Get();
4216  }
4217 
4218  TDF_Label ref;
4219  if(shapeTool->IsReference(label) && shapeTool->GetReferredShape(label, ref)) {
4220  setShapeAttributes(attributes, shapeTool, colorTool, materialTool, ref,
4221  partLoc, phys, true);
4222  }
4223 
4224  if(shapeTool->IsSimpleShape(label) && (isRef || shapeTool->IsFree(label))) {
4225  TopoDS_Shape shape = shapeTool->GetShape(label);
4226  shape.Location(isRef ? loc : partLoc);
4227  int dim =
4228  (shape.ShapeType() == TopAbs_VERTEX) ? 0 :
4229  (shape.ShapeType() == TopAbs_EDGE || shape.ShapeType() == TopAbs_WIRE) ?
4230  1 :
4231  (shape.ShapeType() == TopAbs_FACE || shape.ShapeType() == TopAbs_SHELL) ?
4232  2 :
4233  3;
4234 
4235  Handle(TCollection_HAsciiString) matName;
4236  Handle(TCollection_HAsciiString) matDescription;
4237  Standard_Real matDensity;
4238  Handle(TCollection_HAsciiString) matDensName;
4239  Handle(TCollection_HAsciiString) matDensValType;
4240  if(materialTool->GetMaterial(label, matName, matDescription, matDensity,
4241  matDensName, matDensValType)) {
4242  if(!phys.empty()) phys += " & ";
4243  phys += matName->ToCString();
4244  Msg::Info(" - Label & material '%s' (%dD)", phys.c_str());
4245  }
4246  else if(phys.size()) {
4247  Msg::Info(" - Label '%s' (%dD)", phys.c_str(), dim);
4248  }
4249  if(phys.size()) { attributes->insert(new OCCAttributes(dim, shape, phys)); }
4250 
4251  Quantity_Color col;
4252  if(colorTool->GetColor(label, XCAFDoc_ColorGen, col)) {
4253  double r, g, b;
4254  getColorRGB(col, r, g, b);
4255  Msg::Info(" - Color (%g, %g, %g) (%dD)", r, g, b, dim);
4256  attributes->insert(new OCCAttributes(dim, shape, r, g, b, 1.));
4257  }
4258  else if(colorTool->GetColor(label, XCAFDoc_ColorSurf, col)) {
4259  double r, g, b;
4260  getColorRGB(col, r, g, b);
4261  Msg::Info(" - Color (%g, %g, %g) (%dD & Surfaces)", r, g, b, dim);
4262  attributes->insert(new OCCAttributes(dim, shape, r, g, b, 1., 1));
4263  }
4264  else if(colorTool->GetColor(label, XCAFDoc_ColorCurv, col)) {
4265  double r, g, b;
4266  getColorRGB(col, r, g, b);
4267  Msg::Info(" - Color (%g, %g, %g) (%dD & Curves)", r, g, b, dim);
4268  attributes->insert(new OCCAttributes(dim, shape, r, g, b, 1., 2));
4269  }
4270  // check explicit coloring of boundary entities
4271  if(dim == 3) {
4272  TopExp_Explorer xp2(shape, TopAbs_FACE);
4273  while(xp2.More()) {
4274  if(colorTool->GetColor(xp2.Current(), XCAFDoc_ColorGen, col) ||
4275  colorTool->GetColor(xp2.Current(), XCAFDoc_ColorSurf, col) ||
4276  colorTool->GetColor(xp2.Current(), XCAFDoc_ColorCurv, col)) {
4277  double r, g, b;
4278  getColorRGB(col, r, g, b);
4279  Msg::Info(" - Color (%g, %g, %g) (Surface)", r, g, b);
4280  TopoDS_Face face = TopoDS::Face(xp2.Current());
4281  attributes->insert(new OCCAttributes(2, face, r, g, b, 1.));
4282  }
4283  xp2.Next();
4284  }
4285  }
4286  else if(dim == 2) {
4287  TopExp_Explorer xp1(shape, TopAbs_EDGE);
4288  while(xp1.More()) {
4289  if(colorTool->GetColor(xp1.Current(), XCAFDoc_ColorGen, col) ||
4290  colorTool->GetColor(xp1.Current(), XCAFDoc_ColorSurf, col) ||
4291  colorTool->GetColor(xp1.Current(), XCAFDoc_ColorCurv, col)) {
4292  double r, g, b;
4293  getColorRGB(col, r, g, b);
4294  Msg::Info(" - Color (%g, %g, %g) (Curve)", r, g, b);
4295  TopoDS_Edge edge = TopoDS::Edge(xp1.Current());
4296  attributes->insert(new OCCAttributes(1, edge, r, g, b, 1.));
4297  }
4298  xp1.Next();
4299  }
4300  }
4301  }
4302  else {
4303  for(TDF_ChildIterator it(label); it.More(); it.Next()) {
4304  setShapeAttributes(attributes, shapeTool, colorTool, materialTool,
4305  it.Value(), partLoc, phys, isRef);
4306  }
4307  }
4308 }
4309 
4310 template <class T>
4311 void readAttributes(OCCAttributesRTree *attributes, T &reader,
4312  const std::string &format)
4313 {
4314  // dummy XCAF Application to handle the STEP XCAF Document
4315  static Handle_XCAFApp_Application dummy_app =
4316  XCAFApp_Application::GetApplication();
4317  // XCAF Document to contain the STEP/IGES file itself
4318  Handle_TDocStd_Document doc;
4319  // check if a file is already open under this handle, if so, close it to
4320  // prevent segfaults when trying to create a new document
4321  if(dummy_app->NbDocuments() > 0) {
4322  dummy_app->GetDocument(1, doc);
4323  dummy_app->Close(doc);
4324  }
4325  dummy_app->NewDocument(format.c_str(), doc);
4326  // transfer STEP/IGES into the document, and get the main label
4327  reader.Transfer(doc);
4328  TDF_Label mainLabel = doc->Main();
4329  Handle_XCAFDoc_ShapeTool shapeTool =
4330  XCAFDoc_DocumentTool::ShapeTool(mainLabel);
4331  Handle_XCAFDoc_ColorTool colorTool =
4332  XCAFDoc_DocumentTool::ColorTool(mainLabel);
4333  Handle_XCAFDoc_MaterialTool materialTool =
4334  XCAFDoc_DocumentTool::MaterialTool(mainLabel);
4335  // traverse the labels recursively to set attributes on shapes
4336  setShapeAttributes(attributes, shapeTool, colorTool, materialTool, mainLabel,
4337  TopLoc_Location(), "", false);
4338 }
4339 
4340 #endif
4341 
4342 bool OCC_Internals::importShapes(const std::string &fileName,
4343  bool highestDimOnly,
4344  std::vector<std::pair<int, int> > &outDimTags,
4345  const std::string &format)
4346 {
4347  std::vector<std::string> split = SplitFileName(fileName);
4348 
4349  TCollection_AsciiString occfile(fileName.c_str());
4350 
4351  TopoDS_Shape result;
4352  try {
4353  if(format == "brep" || split[2] == ".brep" || split[2] == ".BREP") {
4354  BRep_Builder aBuilder;
4355  BRepTools::Read(result, occfile.ToCString(), aBuilder);
4356  }
4357  else if(format == "step" || split[2] == ".step" || split[2] == ".stp" ||
4358  split[2] == ".STEP" || split[2] == ".STP") {
4359  STEPControl_Reader reader;
4360  setTargetUnit(CTX::instance()->geom.occTargetUnit);
4361  Interface_Static::SetIVal("read.step.ideas", 1);
4362  Interface_Static::SetIVal("read.step.nonmanifold", 1);
4363 #if defined(HAVE_OCC_CAF)
4364  //Interface_Static::SetIVal("read.stepcaf.subshapes.name", 1);
4365  STEPCAFControl_Reader cafreader;
4366  if(cafreader.ReadFile(occfile.ToCString()) != IFSelect_RetDone) {
4367  Msg::Error("Could not read file '%s'", fileName.c_str());
4368  return false;
4369  }
4370  if(CTX::instance()->geom.occImportLabels)
4371  readAttributes(_attributes, cafreader, "STEP-XCAF");
4372  reader = cafreader.ChangeReader();
4373 #else
4374  if(reader.ReadFile(occfile.ToCString()) != IFSelect_RetDone) {
4375  Msg::Error("Could not read file '%s'", fileName.c_str());
4376  return false;
4377  }
4378 #endif
4379  reader.NbRootsForTransfer();
4380  reader.TransferRoots();
4381  result = reader.OneShape();
4382  }
4383  else if(format == "iges" || split[2] == ".iges" || split[2] == ".igs" ||
4384  split[2] == ".IGES" || split[2] == ".IGS") {
4385  setTargetUnit(CTX::instance()->geom.occTargetUnit);
4386 #if defined(HAVE_OCC_CAF)
4387  IGESCAFControl_Reader reader;
4388  if(reader.ReadFile(occfile.ToCString()) != IFSelect_RetDone) {
4389  Msg::Error("Could not read file '%s'", fileName.c_str());
4390  return false;
4391  }
4392  if(CTX::instance()->geom.occImportLabels)
4393  readAttributes(_attributes, reader, "IGES-XCAF");
4394 #else
4395  IGESControl_Reader reader;
4396  if(reader.ReadFile(occfile.ToCString()) != IFSelect_RetDone) {
4397  Msg::Error("Could not read file '%s'", fileName.c_str());
4398  return false;
4399  }
4400 #endif
4401  reader.NbRootsForTransfer();
4402  reader.TransferRoots();
4403  result = reader.OneShape();
4404  }
4405  else {
4406  Msg::Error("Unknown file type '%s'", fileName.c_str());
4407  return false;
4408  }
4409  } catch(Standard_Failure &err) {
4410  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
4411  return false;
4412  }
4413 
4414  BRepTools::Clean(result);
4415 
4416  _healShape(
4417  result, CTX::instance()->geom.tolerance,
4422 
4423  _multiBind(result, -1, outDimTags, highestDimOnly, true);
4424  return true;
4425 }
4426 
4427 bool OCC_Internals::importShapes(const TopoDS_Shape *shape, bool highestDimOnly,
4428  std::vector<std::pair<int, int> > &outDimTags)
4429 {
4430  if(!shape) return false;
4431  _multiBind(*shape, -1, outDimTags, highestDimOnly, true);
4432  return true;
4433 }
4434 
4435 bool OCC_Internals::exportShapes(GModel *model, const std::string &fileName,
4436  const std::string &format, bool onlyVisible)
4437 {
4438  // put all top-level OCC shapes from a GModel in a single compound (we use the
4439  // topology to only consider top-level shapes; otherwise we get duplicates in
4440  // the STEP export)
4441  BRep_Builder b;
4442  TopoDS_Compound c;
4443  b.MakeCompound(c);
4444  for(auto it = model->firstRegion(); it != model->lastRegion(); it++) {
4445  GRegion *gr = *it;
4446  if(onlyVisible) {
4447  if(!gr->getVisibility()) continue;
4448  }
4450  Msg::Debug("Adding volume %d to exported compound", gr->tag());
4451  b.Add(c, *(TopoDS_Solid *)gr->getNativePtr());
4452  }
4453  }
4454  for(auto it = model->firstFace(); it != model->lastFace(); it++) {
4455  GFace *gf = *it;
4456  if(onlyVisible) {
4457  if(!gf->getVisibility()) continue;
4458  auto regions = gf->regions();
4459  bool skip = false;
4460  for(auto gr : regions) {
4461  if(gr->getVisibility()) { skip = true; break; }
4462  }
4463  if(skip) continue;
4464  }
4465  else {
4466  if(gf->numRegions()) continue;
4467  }
4469  Msg::Debug("Adding surface %d to exported compound", gf->tag());
4470  b.Add(c, *(TopoDS_Face *)gf->getNativePtr());
4471  }
4472  }
4473  for(auto it = model->firstEdge(); it != model->lastEdge(); it++) {
4474  GEdge *ge = *it;
4475  if(onlyVisible) {
4476  if(!ge->getVisibility()) continue;
4477  auto faces = ge->faces();
4478  bool skip = false;
4479  for(auto gf : faces) {
4480  if(gf->getVisibility()) { skip = true; break; }
4481  }
4482  if(skip) continue;
4483  }
4484  else {
4485  if(ge->numFaces()) continue;
4486  }
4488  Msg::Debug("Adding curve %d to exported compound", ge->tag());
4489  b.Add(c, *(TopoDS_Edge *)ge->getNativePtr());
4490  }
4491  }
4492  for(auto it = model->firstVertex(); it != model->lastVertex(); it++) {
4493  GVertex *gv = *it;
4494  if(onlyVisible) {
4495  if(!gv->getVisibility()) continue;
4496  auto edges = gv->edges();
4497  bool skip = false;
4498  for(auto ge : edges) {
4499  if(ge->getVisibility()) { skip = true; break; }
4500  }
4501  if(skip) continue;
4502  }
4503  else {
4504  if(gv->numEdges()) continue;
4505  }
4507  Msg::Debug("Adding point %d to exported compound", gv->tag());
4508  b.Add(c, *(TopoDS_Vertex *)gv->getNativePtr());
4509  }
4510  }
4511 
4512  std::vector<std::string> split = SplitFileName(fileName);
4513 
4514  TCollection_AsciiString occfile(fileName.c_str());
4515 
4516  try {
4517  if(format == "brep" || split[2] == ".brep" || split[2] == ".BREP") {
4518  BRepTools::Write(c, occfile.ToCString());
4519  }
4520  else if(format == "step" || split[2] == ".step" || split[2] == ".stp" ||
4521  split[2] == ".STEP" || split[2] == ".STP") {
4522  STEPControl_Writer writer;
4523  setTargetUnit(CTX::instance()->geom.occTargetUnit);
4524 
4525  // this does not seem to solve the issue that entities get duplicated when
4526  // exporting STEP files (see issue #906):
4527  Interface_Static::SetIVal("write.step.nonmanifold", 1);
4528 
4529  if(writer.Transfer(c, STEPControl_AsIs) == IFSelect_RetDone) {
4530  if(writer.Write(occfile.ToCString()) != IFSelect_RetDone) {
4531  Msg::Error("Could not create file '%s'", fileName.c_str());
4532  return false;
4533  }
4534  }
4535  else {
4536  Msg::Error("Could not create STEP data");
4537  return false;
4538  }
4539  }
4540  } catch(Standard_Failure &err) {
4541  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
4542  return false;
4543  }
4544  return true;
4545 }
4546 
4547 void OCC_Internals::setMeshSize(int dim, int tag, double size)
4548 {
4549  if(dim != 0) return;
4550  if(_tagVertex.IsBound(tag)) {
4551  OCCAttributes *a = new OCCAttributes(0, _tagVertex.Find(tag), size);
4552  // first remove any other constraint
4553  _attributes->remove(a);
4554  _attributes->insert(a);
4555  }
4556 }
4557 
4558 bool OCC_Internals::getEntities(std::vector<std::pair<int, int> > &dimTags,
4559  int dim)
4560 {
4561  for(int d = 0; d < 4; d++) {
4562  if(dim != -1 && dim != d) continue;
4563  TopTools_DataMapIteratorOfDataMapOfIntegerShape exp;
4564  switch(d) {
4565  case 0: exp.Initialize(_tagVertex); break;
4566  case 1: exp.Initialize(_tagEdge); break;
4567  case 2: exp.Initialize(_tagFace); break;
4568  case 3: exp.Initialize(_tagSolid); break;
4569  }
4570  for(; exp.More(); exp.Next())
4571  dimTags.push_back(std::make_pair(d, exp.Key()));
4572  }
4573  return true;
4574 }
4575 
4576 bool OCC_Internals::getVertex(int tag, double &x, double &y, double &z)
4577 {
4578  if(_tagVertex.IsBound(tag)) {
4579  gp_Pnt pnt = BRep_Tool::Pnt(TopoDS::Vertex(_tagVertex.Find(tag)));
4580  x = pnt.X();
4581  y = pnt.Y();
4582  z = pnt.Z();
4583  return true;
4584  }
4585  return false;
4586 }
4587 
4588 bool OCC_Internals::_getBoundingBox(const TopoDS_Shape &shape, double &xmin,
4589  double &ymin, double &zmin, double &xmax,
4590  double &ymax, double &zmax)
4591 {
4592  if(CTX::instance()->geom.occBoundsUseSTL) {
4593  std::vector<SPoint3> vertices;
4594  std::vector<SVector3> normals;
4595  std::vector<int> triangles;
4596  _makeSTL(shape, vertices, normals, triangles);
4597  // BRepBndLib can use the STL mesh if available, but unfortunately it
4598  // enlarges the box with the mesh deflection tolerance and the shape
4599  // tolerance, which makes it hard to get the expected minimal box in simple
4600  // cases (e.g. for plane surfaces), and always leads to boxes that are too
4601  // large; so we simply compute the box from the STL vertices. The downside
4602  // of this approach is that the bbox might be *smaller* than the actual box
4603  // for curved shapes, but this is preferable for us as boxes are mostly used
4604  // to find/identify entities
4605  if(vertices.size()) {
4606  SBoundingBox3d bbox;
4607  for(std::size_t i = 0; i < vertices.size(); i++)
4608  bbox += vertices[i];
4609  xmin = bbox.min().x();
4610  ymin = bbox.min().y();
4611  zmin = bbox.min().z();
4612  xmax = bbox.max().x();
4613  ymax = bbox.max().y();
4614  zmax = bbox.max().z();
4615  return true;
4616  }
4617  }
4618  Bnd_Box b;
4619  try {
4620  BRepBndLib::Add(shape, b);
4621  } catch(Standard_Failure &err) {
4622  Msg::Error("OpenCASCADE exception %s", err.GetMessageString());
4623  return false;
4624  }
4625  b.Get(xmin, ymin, zmin, xmax, ymax, zmax);
4626  return true;
4627 }
4628 
4629 bool OCC_Internals::getBoundingBox(int dim, int tag, double &xmin, double &ymin,
4630  double &zmin, double &xmax, double &ymax,
4631  double &zmax)
4632 {
4633  if(!_isBound(dim, tag)) {
4634  Msg::Error("Unknown OpenCASCADE entity of dimension %d with tag %d", dim,
4635  tag);
4636  return false;
4637  }
4638  TopoDS_Shape shape = _find(dim, tag);
4639  return _getBoundingBox(shape, xmin, ymin, zmin, xmax, ymax, zmax);
4640 }
4641 
4643  double xmin, double ymin, double zmin, double xmax, double ymax, double zmax,
4644  std::vector<std::pair<int, int> > &dimTags, int dim)
4645 {
4646  // if we use this often, create an rtree to avoid the linear search
4647  for(int d = 0; d < 4; d++) {
4648  if(dim != -1 && dim != d) continue;
4649  TopTools_DataMapIteratorOfDataMapOfIntegerShape exp;
4650  switch(d) {
4651  case 0: exp.Initialize(_tagVertex); break;
4652  case 1: exp.Initialize(_tagEdge); break;
4653  case 2: exp.Initialize(_tagFace); break;
4654  case 3: exp.Initialize(_tagSolid); break;
4655  }
4656  for(; exp.More(); exp.Next()) {
4657  double xmin2 = 0, ymin2 = 0, zmin2 = 0, xmax2 = 0, ymax2 = 0, zmax2 = 0;
4658  _getBoundingBox(exp.Value(), xmin2, ymin2, zmin2, xmax2, ymax2, zmax2);
4659  if(xmin2 >= xmin && xmax2 <= xmax && ymin2 >= ymin && ymax2 <= ymax &&
4660  zmin2 >= zmin && zmax2 <= zmax)
4661  dimTags.push_back(std::make_pair(d, exp.Key()));
4662  }
4663  }
4664  return true;
4665 }
4666 
4667 bool OCC_Internals::getCurveLoops(int surfaceTag, std::vector<int> &curveLoopTags,
4668  std::vector<std::vector<int> > &curveTags)
4669 {
4670  if(!_tagFace.IsBound(surfaceTag)) {
4671  Msg::Error("Unknown OpenCASCADE surface with tag %d", surfaceTag);
4672  return false;
4673  }
4674  curveLoopTags.clear();
4675  curveTags.clear();
4676  TopoDS_Face face = TopoDS::Face(_tagFace.Find(surfaceTag));
4677  TopExp_Explorer exp0;
4678  for(exp0.Init(face, TopAbs_WIRE); exp0.More(); exp0.Next()) {
4679  TopoDS_Wire wire = TopoDS::Wire(exp0.Current());
4680  if(_wireTag.IsBound(wire)) {
4681  curveLoopTags.push_back(_wireTag.Find(wire));
4682  }
4683  else {
4684  int t = getMaxTag(-1) + 1;
4685  _bind(wire, t);
4686  curveLoopTags.push_back(t);
4687  }
4688  curveTags.push_back(std::vector<int>());
4689  BRepTools_WireExplorer exp1; // guarantees edges are ordered
4690  for(exp1.Init(wire); exp1.More(); exp1.Next()) {
4691  TopoDS_Edge edge = exp1.Current();
4692  if(_edgeTag.IsBound(edge)) {
4693  curveTags.back().push_back(_edgeTag.Find(edge));
4694  }
4695  else {
4696  int t = getMaxTag(1) + 1;
4697  _bind(edge, t);
4698  curveTags.back().push_back(t);
4699  }
4700  }
4701  }
4702  return true;
4703 }
4704 
4705 bool OCC_Internals::getSurfaceLoops(int volumeTag, std::vector<int> &surfaceLoopTags,
4706  std::vector<std::vector<int> > &surfaceTags)
4707 {
4708  if(!_tagSolid.IsBound(volumeTag)) {
4709  Msg::Error("Unknown OpenCASCADE volume with tag %d", volumeTag);
4710  return false;
4711  }
4712  surfaceLoopTags.clear();
4713  surfaceTags.clear();
4714  TopoDS_Solid solid = TopoDS::Solid(_tagSolid.Find(volumeTag));
4715  TopExp_Explorer exp0;
4716  for(exp0.Init(solid, TopAbs_SHELL); exp0.More(); exp0.Next()) {
4717  TopoDS_Shell shell = TopoDS::Shell(exp0.Current());
4718  if(_shellTag.IsBound(shell)) {
4719  surfaceLoopTags.push_back(_shellTag.Find(shell));
4720  }
4721  else {
4722  int t = getMaxTag(-2) + 1;
4723  _bind(shell, t);
4724  surfaceLoopTags.push_back(t);
4725  }
4726  surfaceTags.push_back(std::vector<int>());
4727  TopExp_Explorer exp1;
4728  for(exp1.Init(shell, TopAbs_FACE); exp1.More(); exp1.Next()) {
4729  TopoDS_Face face = TopoDS::Face(exp1.Current());
4730  if(_faceTag.IsBound(face)) {
4731  surfaceTags.back().push_back(_faceTag.Find(face));
4732  }
4733  else {
4734  int t = getMaxTag(2) + 1;
4735  _bind(face, t);
4736  surfaceTags.back().push_back(t);
4737  }
4738  }
4739  }
4740  return true;
4741 }
4742 
4743 bool OCC_Internals::getMass(int dim, int tag, double &mass)
4744 {
4745  if(!_isBound(dim, tag)) {
4746  Msg::Error("Unknown OpenCASCADE entity of dimension %d with tag %d", dim,
4747  tag);
4748  return false;
4749  }
4750  TopoDS_Shape shape = _find(dim, tag);
4751  GProp_GProps System;
4752  switch(dim) {
4753  case 1: BRepGProp::LinearProperties(shape, System); break;
4754  case 2: BRepGProp::SurfaceProperties(shape, System); break;
4755  case 3: BRepGProp::VolumeProperties(shape, System); break;
4756  }
4757  mass = System.Mass();
4758  return true;
4759 }
4760 
4761 bool OCC_Internals::getCenterOfMass(int dim, int tag, double &x, double &y,
4762  double &z)
4763 {
4764  if(!_isBound(dim, tag)) {
4765  Msg::Error("Unknown OpenCASCADE entity of dimension %d with tag %d", dim,
4766  tag);
4767  return false;
4768  }
4769  TopoDS_Shape shape = _find(dim, tag);
4770  GProp_GProps System;
4771  switch(dim) {
4772  case 1: BRepGProp::LinearProperties(shape, System); break;
4773  case 2: BRepGProp::SurfaceProperties(shape, System); break;
4774  case 3: BRepGProp::VolumeProperties(shape, System); break;
4775  }
4776  gp_Pnt c = System.CentreOfMass();
4777  x = c.X();
4778  y = c.Y();
4779  z = c.Z();
4780  return true;
4781 }
4782 
4783 bool OCC_Internals::getMatrixOfInertia(int dim, int tag,
4784  std::vector<double> &mat)
4785 {
4786  if(!_isBound(dim, tag)) {
4787  Msg::Error("Unknown OpenCASCADE entity of dimension %d with tag %d", dim,
4788  tag);
4789  return false;
4790  }
4791  TopoDS_Shape shape = _find(dim, tag);
4792  GProp_GProps System;
4793  switch(dim) {
4794  case 1: BRepGProp::LinearProperties(shape, System); break;
4795  case 2: BRepGProp::SurfaceProperties(shape, System); break;
4796  case 3: BRepGProp::VolumeProperties(shape, System); break;
4797  }
4798  gp_Mat m = System.MatrixOfInertia();
4799  mat.clear();
4800  for(int i = 1; i <= 3; i++)
4801  for(int j = 1; j <= 3; j++) mat.push_back(m.Value(i, j));
4802  return true;
4803 }
4804 
4805 double OCC_Internals::getDistance(int dim1, int tag1,
4806  int dim2, int tag2,
4807  double &x1, double &y1, double &z1,
4808  double &x2, double &y2, double &z2)
4809 {
4810  if(!_isBound(dim1, tag1)) {
4811  Msg::Error("Unknown OpenCASCADE entity of dimension %d with tag %d",
4812  dim1, tag1);
4813  return false;
4814  }
4815  TopoDS_Shape shape1 = _find(dim1, tag1);
4816 
4817  if(!_isBound(dim2, tag2)) {
4818  Msg::Error("Unknown OpenCASCADE entity of dimension %d with tag %d",
4819  dim2, tag2);
4820  return false;
4821  }
4822  TopoDS_Shape shape2 = _find(dim2, tag2);
4823 
4824  BRepExtrema_DistShapeShape dist(shape1, shape2);
4825  if(dist.IsDone()) {
4826  double dmin = 1.e200;
4827  gp_Pnt pmin1, pmin2;
4828  for(int i = 1; i <= dist.NbSolution(); i++) {
4829  gp_Pnt p1 = dist.PointOnShape1(i);
4830  gp_Pnt p2 = dist.PointOnShape2(i);
4831  double d = p1.Distance(p2);
4832  if(d < dmin) {
4833  dmin = d;
4834  pmin1 = p1;
4835  pmin2 = p2;
4836  }
4837  }
4838  x1 = pmin1.X();
4839  y1 = pmin1.Y();
4840  z1 = pmin1.Z();
4841  x2 = pmin2.X();
4842  y2 = pmin2.Y();
4843  z2 = pmin2.Z();
4844  return dmin;
4845  }
4846 
4847  return -1.;
4848 }
4849 
4850 bool const sortByInvDim(std::pair<int, int> const &lhs,
4851  std::pair<int, int> const &rhs)
4852 {
4853  return lhs.first > rhs.first;
4854 }
4855 
4857 {
4858  Msg::Debug("Syncing OCC_Internals with GModel");
4859 
4860  // make sure to remove from GModel all entities that have been deleted in
4861  // OCC_Internals since the last synchronization
4862  std::vector<std::pair<int, int> > toRemove;
4863  toRemove.insert(toRemove.end(), _toRemove.begin(), _toRemove.end());
4864  Msg::Debug("Sync is removing %d model entities", toRemove.size());
4865  // make sure to delete highest dimensional entities first (model->remove()
4866  // will not remove entities that are the boundary of others!)
4867  std::sort(toRemove.begin(), toRemove.end(), sortByInvDim);
4868  std::vector<GEntity*> removed;
4869  model->remove(toRemove, removed);
4870  Msg::Debug("Destroying %lu entities in model", removed.size());
4871  for(std::size_t i = 0; i < removed.size(); i++) delete removed[i];
4872  _toRemove.clear();
4873 
4874  // iterate over all shapes with tags, and import them into the (sub)shape
4875  // _maps
4876  _somap.Clear();
4877  _shmap.Clear();
4878  _fmap.Clear();
4879  _wmap.Clear();
4880  _emap.Clear();
4881  _vmap.Clear();
4882  TopTools_DataMapIteratorOfDataMapOfIntegerShape exp0(_tagVertex);
4883  for(; exp0.More(); exp0.Next()) _addShapeToMaps(exp0.Value());
4884  TopTools_DataMapIteratorOfDataMapOfIntegerShape exp1(_tagEdge);
4885  for(; exp1.More(); exp1.Next()) _addShapeToMaps(exp1.Value());
4886  TopTools_DataMapIteratorOfDataMapOfIntegerShape exp2(_tagFace);
4887  for(; exp2.More(); exp2.Next()) _addShapeToMaps(exp2.Value());
4888  TopTools_DataMapIteratorOfDataMapOfIntegerShape exp3(_tagSolid);
4889  for(; exp3.More(); exp3.Next()) _addShapeToMaps(exp3.Value());
4890 
4891  // import all shapes in _maps into the GModel, preserving all explicit tags
4892  int vTagMax = std::max(model->getMaxElementaryNumber(0), getMaxTag(0));
4893  int eTagMax = std::max(model->getMaxElementaryNumber(1), getMaxTag(1));
4894  int fTagMax = std::max(model->getMaxElementaryNumber(2), getMaxTag(2));
4895  int rTagMax = std::max(model->getMaxElementaryNumber(3), getMaxTag(3));
4896  for(int i = 1; i <= _vmap.Extent(); i++) {
4897  TopoDS_Vertex vertex = TopoDS::Vertex(_vmap(i));
4898  GVertex *occv = getVertexForOCCShape(model, vertex);
4899  if(!occv) {
4900  int tag;
4901  if(_vertexTag.IsBound(vertex))
4902  tag = _vertexTag.Find(vertex);
4903  else {
4904  tag = ++vTagMax;
4905  Msg::Debug("Binding unbound OpenCASCADE point to tag %d", tag);
4906  _bind(vertex, tag);
4907  }
4908  occv = new OCCVertex(model, vertex, tag);
4909  model->add(occv);
4910  }
4911  double lc = _attributes->getMeshSize(0, vertex);
4912  if(lc != MAX_LC) occv->setPrescribedMeshSizeAtVertex(lc);
4913  std::vector<std::string> labels;
4914  _attributes->getLabels(0, vertex, labels);
4915  if(labels.size()) model->setElementaryName(0, occv->tag(), labels[0]);
4916  unsigned int col = 0, boundary = 0;
4917  if(!occv->useColor() && _attributes->getColor(0, vertex, col, boundary)) {
4918  occv->setColor(col);
4919  }
4920  }
4921  for(int i = 1; i <= _emap.Extent(); i++) {
4922  TopoDS_Edge edge = TopoDS::Edge(_emap(i));
4923  GEdge *occe = getEdgeForOCCShape(model, edge);
4924  if(!occe) {
4925  GVertex *v1 = getVertexForOCCShape(model, TopExp::FirstVertex(edge));
4926  GVertex *v2 = getVertexForOCCShape(model, TopExp::LastVertex(edge));
4927  int tag;
4928  if(_edgeTag.IsBound(edge))
4929  tag = _edgeTag.Find(edge);
4930  else {
4931  tag = ++eTagMax;
4932  Msg::Debug("Binding unbound OpenCASCADE curve to tag %d", tag);
4933  _bind(edge, tag);
4934  }
4935  occe = new OCCEdge(model, edge, tag, v1, v2);
4936  model->add(occe);
4937  }
4938  _copyExtrudedAttributes(edge, occe);
4939  std::vector<std::string> labels;
4940  _attributes->getLabels(1, edge, labels);
4941  if(labels.size()) model->setElementaryName(1, occe->tag(), labels[0]);
4942  unsigned int col = 0, boundary = 0;
4943  if(!occe->useColor() && _attributes->getColor(1, edge, col, boundary)) {
4944  occe->setColor(col);
4945  }
4946  }
4947  for(int i = 1; i <= _fmap.Extent(); i++) {
4948  TopoDS_Face face = TopoDS::Face(_fmap(i));
4949  GFace *occf = getFaceForOCCShape(model, face);
4950  if(!occf) {
4951  int tag;
4952  if(_faceTag.IsBound(face))
4953  tag = _faceTag.Find(face);
4954  else {
4955  tag = ++fTagMax;
4956  Msg::Debug("Binding unbound OpenCASCADE surface to tag %d", tag);
4957  _bind(face, tag);
4958  }
4959  occf = new OCCFace(model, face, tag);
4960  model->add(occf);
4961  }
4962  _copyExtrudedAttributes(face, occf);
4963  std::vector<std::string> labels;
4964  _attributes->getLabels(2, face, labels);
4965  if(labels.size()) model->setElementaryName(2, occf->tag(), labels[0]);
4966  unsigned int col = 0, boundary = 0;
4967  if(!occf->useColor() && _attributes->getColor(2, face, col, boundary)) {
4968  occf->setColor(col);
4969  if(boundary == 2) {
4970  std::vector<GEdge *> edges = occf->edges();
4971  for(std::size_t j = 0; j < edges.size(); j++) {
4972  if(!edges[j]->useColor()) edges[j]->setColor(col);
4973  }
4974  }
4975  }
4976  }
4977  for(int i = 1; i <= _somap.Extent(); i++) {
4978  TopoDS_Solid region = TopoDS::Solid(_somap(i));
4979  GRegion *occr = getRegionForOCCShape(model, region);
4980  if(!occr) {
4981  int tag;
4982  if(_solidTag.IsBound(region))
4983  tag = _solidTag(region);
4984  else {
4985  tag = ++rTagMax;
4986  Msg::Debug("Binding unbound OpenCASCADE volume to tag %d", tag);
4987  _bind(region, tag);
4988  }
4989  occr = new OCCRegion(model, region, tag);
4990  model->add(occr);
4991  }
4992  _copyExtrudedAttributes(region, occr);
4993  std::vector<std::string> labels;
4994  _attributes->getLabels(3, region, labels);
4995  if(labels.size()) model->setElementaryName(3, occr->tag(), labels[0]);
4996  unsigned int col = 0, boundary = 0;
4997  if(!occr->useColor() && _attributes->getColor(3, region, col, boundary)) {
4998  occr->setColor(col);
4999  if(boundary == 1) {
5000  std::vector<GFace *> faces = occr->faces();
5001  for(std::size_t j = 0; j < faces.size(); j++) {
5002  if(!faces[j]->useColor()) faces[j]->setColor(col);
5003  }
5004  }
5005  else if(boundary == 2) {
5006  std::vector<GEdge *> edges = occr->edges();
5007  for(std::size_t j = 0; j < edges.size(); j++) {
5008  if(!edges[j]->useColor()) edges[j]->setColor(col);
5009  }
5010  }
5011  }
5012  }
5013 
5014  // if fuzzy boolean tolerance was used, some vertex positions should be
5015  // recomputed (e.g. end point of curves
5016  if(CTX::instance()->geom.toleranceBoolean) model->snapVertices();
5017 
5018  // recompute global boundind box in CTX
5019  SetBoundingBox();
5020 
5021  Msg::Debug("GModel imported:");
5022  Msg::Debug("%d points", model->getNumVertices());
5023  Msg::Debug("%d curves", model->getNumEdges());
5024  Msg::Debug("%d surfaces", model->getNumFaces());
5025  Msg::Debug("%d volumes", model->getNumRegions());
5026  _changed = false;
5027 }
5028 
5029 GVertex *OCC_Internals::getVertexForOCCShape(GModel *model,
5030  const TopoDS_Vertex &toFind)
5031 {
5032  if(_vertexTag.IsBound(toFind))
5033  return model->getVertexByTag(_vertexTag.Find(toFind));
5034  return nullptr;
5035 }
5036 
5037 GEdge *OCC_Internals::getEdgeForOCCShape(GModel *model,
5038  const TopoDS_Edge &toFind)
5039 {
5040  if(_edgeTag.IsBound(toFind))
5041  return model->getEdgeByTag(_edgeTag.Find(toFind));
5042  return nullptr;
5043 }
5044 
5045 GFace *OCC_Internals::getFaceForOCCShape(GModel *model,
5046  const TopoDS_Face &toFind)
5047 {
5048  if(_faceTag.IsBound(toFind))
5049  return model->getFaceByTag(_faceTag.Find(toFind));
5050  return nullptr;
5051 }
5052 
5053 GRegion *OCC_Internals::getRegionForOCCShape(GModel *model,
5054  const TopoDS_Solid &toFind)
5055 {
5056  if(_solidTag.IsBound(toFind))
5057  return model->getRegionByTag(_solidTag.Find(toFind));
5058  return nullptr;
5059 }
5060 
5061 void OCC_Internals::_addShapeToMaps(const TopoDS_Shape &shape)
5062 {
5063  // Solids
5064  TopExp_Explorer exp0, exp1, exp2, exp3, exp4, exp5;
5065  for(exp0.Init(shape, TopAbs_SOLID); exp0.More(); exp0.Next()) {
5066  TopoDS_Solid solid = TopoDS::Solid(exp0.Current());
5067  if(_somap.FindIndex(solid) < 1) {
5068  _somap.Add(solid);
5069  for(exp1.Init(solid, TopAbs_SHELL); exp1.More(); exp1.Next()) {
5070  TopoDS_Shell shell = TopoDS::Shell(exp1.Current());
5071  if(_shmap.FindIndex(shell) < 1) {
5072  _shmap.Add(shell);
5073 
5074  for(exp2.Init(shell, TopAbs_FACE); exp2.More(); exp2.Next()) {
5075  TopoDS_Face face = TopoDS::Face(exp2.Current());
5076  if(_fmap.FindIndex(face) < 1) {
5077  _fmap.Add(face);
5078 
5079  for(exp3.Init(face.Oriented(TopAbs_FORWARD), TopAbs_WIRE);
5080  exp3.More(); exp3.Next()) {
5081  // for(exp3.Init(face, TopAbs_WIRE); exp3.More(); exp3.Next()){
5082  TopoDS_Wire wire = TopoDS::Wire(exp3.Current());
5083  if(_wmap.FindIndex(wire) < 1) {
5084  _wmap.Add(wire);
5085 
5086  for(exp4.Init(wire, TopAbs_EDGE); exp4.More(); exp4.Next()) {
5087  TopoDS_Edge edge = TopoDS::Edge(exp4.Current());
5088  if(_emap.FindIndex(edge) < 1) {
5089  _emap.Add(edge);
5090 
5091  for(exp5.Init(edge, TopAbs_VERTEX); exp5.More();
5092  exp5.Next()) {
5093  TopoDS_Vertex vertex = TopoDS::Vertex(exp5.Current());
5094  if(_vmap.FindIndex(vertex) < 1) _vmap.Add(vertex);
5095  }
5096  }
5097  }
5098  }
5099  }
5100  }
5101  }
5102  }
5103  }
5104  }
5105  }
5106 
5107  // Free Shells
5108  for(exp1.Init(shape, TopAbs_SHELL, TopAbs_SOLID); exp1.More(); exp1.Next()) {
5109  const TopoDS_Shape &shell = exp1.Current();
5110  if(_shmap.FindIndex(shell) < 1) {
5111  _shmap.Add(shell);
5112 
5113  for(exp2.Init(shell, TopAbs_FACE); exp2.More(); exp2.Next()) {
5114  TopoDS_Face face = TopoDS::Face(exp2.Current());
5115  if(_fmap.FindIndex(face) < 1) {
5116  _fmap.Add(face);
5117 
5118  for(exp3.Init(face, TopAbs_WIRE); exp3.More(); exp3.Next()) {
5119  TopoDS_Wire wire = TopoDS::Wire(exp3.Current());
5120  if(_wmap.FindIndex(wire) < 1) {
5121  _wmap.Add(wire);
5122 
5123  for(exp4.Init(wire, TopAbs_EDGE); exp4.More(); exp4.Next()) {
5124  TopoDS_Edge edge = TopoDS::Edge(exp4.Current());
5125  if(_emap.FindIndex(edge) < 1) {
5126  _emap.Add(edge);
5127 
5128  for(exp5.Init(edge, TopAbs_VERTEX); exp5.More();
5129  exp5.Next()) {
5130  TopoDS_Vertex vertex = TopoDS::Vertex(exp5.Current());
5131  if(_vmap.FindIndex(vertex) < 1) _vmap.Add(vertex);
5132  }
5133  }
5134  }
5135  }
5136  }
5137  }
5138  }
5139  }
5140  }
5141 
5142  // Free Faces
5143  for(exp2.Init(shape, TopAbs_FACE, TopAbs_SHELL); exp2.More(); exp2.Next()) {
5144  TopoDS_Face face = TopoDS::Face(exp2.Current());
5145  if(_fmap.FindIndex(face) < 1) {
5146  _fmap.Add(face);
5147 
5148  for(exp3.Init(face, TopAbs_WIRE); exp3.More(); exp3.Next()) {
5149  TopoDS_Wire wire = TopoDS::Wire(exp3.Current());
5150  if(_wmap.FindIndex(wire) < 1) {
5151  _wmap.Add(wire);
5152 
5153  for(exp4.Init(wire, TopAbs_EDGE); exp4.More(); exp4.Next()) {
5154  TopoDS_Edge edge = TopoDS::Edge(exp4.Current());
5155  if(_emap.FindIndex(edge) < 1) {
5156  _emap.Add(edge);
5157 
5158  for(exp5.Init(edge, TopAbs_VERTEX); exp5.More(); exp5.Next()) {
5159  TopoDS_Vertex vertex = TopoDS::Vertex(exp5.Current());
5160  if(_vmap.FindIndex(vertex) < 1) _vmap.Add(vertex);
5161  }
5162  }
5163  }
5164  }
5165  }
5166  }
5167  }
5168 
5169  // Free Wires
5170  for(exp3.Init(shape, TopAbs_WIRE, TopAbs_FACE); exp3.More(); exp3.Next()) {
5171  TopoDS_Wire wire = TopoDS::Wire(exp3.Current());
5172  if(_wmap.FindIndex(wire) < 1) {
5173  _wmap.Add(wire);
5174 
5175  for(exp4.Init(wire, TopAbs_EDGE); exp4.More(); exp4.Next()) {
5176  TopoDS_Edge edge = TopoDS::Edge(exp4.Current());
5177  if(_emap.FindIndex(edge) < 1) {
5178  _emap.Add(edge);
5179 
5180  for(exp5.Init(edge, TopAbs_VERTEX); exp5.More(); exp5.Next()) {
5181  TopoDS_Vertex vertex = TopoDS::Vertex(exp5.Current());
5182  if(_vmap.FindIndex(vertex) < 1) _vmap.Add(vertex);
5183  }
5184  }
5185  }
5186  }
5187  }
5188 
5189  // Free Edges
5190  for(exp4.Init(shape, TopAbs_EDGE, TopAbs_WIRE); exp4.More(); exp4.Next()) {
5191  TopoDS_Edge edge = TopoDS::Edge(exp4.Current());
5192  if(_emap.FindIndex(edge) < 1) {
5193  _emap.Add(edge);
5194 
5195  for(exp5.Init(edge, TopAbs_VERTEX); exp5.More(); exp5.Next()) {
5196  TopoDS_Vertex vertex = TopoDS::Vertex(exp5.Current());
5197  if(_vmap.FindIndex(vertex) < 1) _vmap.Add(vertex);
5198  }
5199  }
5200  }
5201 
5202  // Free Vertices
5203  for(exp5.Init(shape, TopAbs_VERTEX, TopAbs_EDGE); exp5.More(); exp5.Next()) {
5204  TopoDS_Vertex vertex = TopoDS::Vertex(exp5.Current());
5205  if(_vmap.FindIndex(vertex) < 1) { _vmap.Add(vertex); }
5206  }
5207 }
5208 
5209 void OCC_Internals::_healShape(TopoDS_Shape &myshape, double tolerance,
5210  bool fixDegenerated, bool fixSmallEdges,
5211  bool fixSmallFaces, bool sewFaces,
5212  bool makeSolids, double scaling)
5213 {
5214  if(scaling != 1.0) {
5215  Msg::Info("Scaling geometry (factor: %g)", scaling);
5216  gp_Trsf t;
5217  t.SetScaleFactor(scaling);
5218  BRepBuilderAPI_Transform trsf(myshape, t);
5219  myshape = trsf.Shape();
5220  }
5221 
5222  if(!fixDegenerated && !fixSmallEdges && !fixSmallFaces && !sewFaces &&
5223  !makeSolids)
5224  return;
5225 
5226  Msg::Info("Healing shapes (tolerance: %g)", tolerance);
5227  double t1 = Cpu(), w1 = TimeOfDay();
5228 
5229  _somap.Clear();
5230  _shmap.Clear();
5231  _fmap.Clear();
5232  _wmap.Clear();
5233  _emap.Clear();
5234  _vmap.Clear();
5235  _addShapeToMaps(myshape);
5236 
5237  TopExp_Explorer exp0, exp1;
5238  int nrc = 0, nrcs = 0;
5239  int nrso = _somap.Extent(), nrsh = _shmap.Extent(), nrf = _fmap.Extent();
5240  int nrw = _wmap.Extent(), nre = _emap.Extent(), nrv = _vmap.Extent();
5241  for(exp0.Init(myshape, TopAbs_COMPOUND); exp0.More(); exp0.Next()) nrc++;
5242  for(exp0.Init(myshape, TopAbs_COMPSOLID); exp0.More(); exp0.Next()) nrcs++;
5243 
5244  double surfacecont = 0;
5245  for(exp0.Init(myshape, TopAbs_FACE); exp0.More(); exp0.Next()) {
5246  TopoDS_Face face = TopoDS::Face(exp0.Current());
5247  GProp_GProps system;
5248  BRepGProp::SurfaceProperties(face, system);
5249  surfacecont += system.Mass();
5250  }
5251 
5252  if(fixDegenerated) {
5253  Msg::Info(" - Fixing degenerated edges and faces");
5254 
5255  {
5256  ShapeBuild_ReShape rebuild;
5257  for(exp1.Init(myshape, TopAbs_EDGE); exp1.More(); exp1.Next()) {
5258  TopoDS_Edge edge = TopoDS::Edge(exp1.Current());
5259  if(BRep_Tool::Degenerated(edge)) rebuild.Remove(edge);
5260  }
5261  myshape = rebuild.Apply(myshape);
5262  }
5263 
5264  {
5265  ShapeBuild_ReShape rebuild;
5266  for(exp0.Init(myshape, TopAbs_FACE); exp0.More(); exp0.Next()) {
5267  TopoDS_Face face = TopoDS::Face(exp0.Current());
5268 
5269  ShapeFix_Face sff(face);
5270  sff.FixAddNaturalBoundMode() = Standard_True;
5271  sff.FixSmallAreaWireMode() = Standard_True;
5272  sff.Perform();
5273 
5274  if(sff.Status(ShapeExtend_DONE1) || sff.Status(ShapeExtend_DONE2) ||
5275  sff.Status(ShapeExtend_DONE3) || sff.Status(ShapeExtend_DONE4) ||
5276  sff.Status(ShapeExtend_DONE5)) {
5277  Msg::Info(" . Repaired face");
5278  if(sff.Status(ShapeExtend_DONE1))
5279  Msg::Info(" . Some wires are fixed");
5280  else if(sff.Status(ShapeExtend_DONE2))
5281  Msg::Info(" . Orientation of wires fixed");
5282  else if(sff.Status(ShapeExtend_DONE3))
5283  Msg::Info(" . Missing seam added");
5284  else if(sff.Status(ShapeExtend_DONE4))
5285  Msg::Info(" . Small area wire removed");
5286  else if(sff.Status(ShapeExtend_DONE5))
5287  Msg::Info(" . Natural bounds added");
5288 
5289  TopoDS_Face newface = sff.Face();
5290  rebuild.Replace(face, newface);
5291  }
5292  }
5293  myshape = rebuild.Apply(myshape);
5294  }
5295 
5296  {
5297  ShapeBuild_ReShape rebuild;
5298  for(exp1.Init(myshape, TopAbs_EDGE); exp1.More(); exp1.Next()) {
5299  TopoDS_Edge edge = TopoDS::Edge(exp1.Current());
5300  if(BRep_Tool::Degenerated(edge)) rebuild.Remove(edge);
5301  }
5302  myshape = rebuild.Apply(myshape);
5303  }
5304  }
5305 
5306  if(fixSmallEdges) {
5307  Msg::Info(" - Fixing small edges");
5308 
5309  {
5310  ShapeBuild_ReShape rebuild;
5311 
5312  for(exp0.Init(myshape, TopAbs_FACE); exp0.More(); exp0.Next()) {
5313  TopoDS_Face face = TopoDS::Face(exp0.Current());
5314 
5315  for(exp1.Init(face, TopAbs_WIRE); exp1.More(); exp1.Next()) {
5316  TopoDS_Wire oldwire = TopoDS::Wire(exp1.Current());
5317  ShapeFix_Wire sfw(oldwire, face, tolerance);
5318  sfw.ModifyTopologyMode() = Standard_True;
5319  sfw.ClosedWireMode() = Standard_True;
5320  bool replace = false;
5321  replace = sfw.FixReorder() || replace;
5322  replace = sfw.FixConnected() || replace;
5323 
5324  if(sfw.FixSmall(Standard_False, tolerance) &&
5325  !(sfw.StatusSmall(ShapeExtend_FAIL1) ||
5326  sfw.StatusSmall(ShapeExtend_FAIL2) ||
5327  sfw.StatusSmall(ShapeExtend_FAIL3))) {
5328  Msg::Info(" . Fixed small edge in wire");
5329  replace = true;
5330  }
5331  else if(sfw.StatusSmall(ShapeExtend_FAIL1))
5332  Msg::Warning("Failed to fix small edge in wire, edge cannot be "
5333  "checked (no 3d curve and no pcurve)");
5334  else if(sfw.StatusSmall(ShapeExtend_FAIL2))
5335  Msg::Warning("Failed to fix small edge in wire, edge is null-"
5336  "length and has different vertives at begin and end, "
5337  "and lockvtx is True or ModifiyTopologyMode is False");
5338  else if(sfw.StatusSmall(ShapeExtend_FAIL3))
5339  Msg::Warning("Failed to fix small edge in wire, CheckConnected has "
5340  "failed");
5341 
5342  replace = sfw.FixEdgeCurves() || replace;
5343  replace = sfw.FixDegenerated() || replace;
5344  replace = sfw.FixSelfIntersection() || replace;
5345  replace = sfw.FixLacking(Standard_True) || replace;
5346  if(replace) {
5347  TopoDS_Wire newwire = sfw.Wire();
5348  rebuild.Replace(oldwire, newwire);
5349  }
5350  }
5351  }
5352  myshape = rebuild.Apply(myshape);
5353  }
5354 
5355  {
5356  ShapeBuild_ReShape rebuild;
5357 
5358  for(exp1.Init(myshape, TopAbs_EDGE); exp1.More(); exp1.Next()) {
5359  TopoDS_Edge edge = TopoDS::Edge(exp1.Current());
5360  GProp_GProps system;
5361  BRepGProp::LinearProperties(edge, system);
5362  if(system.Mass() < tolerance) {
5363  Msg::Info(" - Removing degenerated edge");
5364  rebuild.Remove(edge);
5365  }
5366  }
5367  myshape = rebuild.Apply(myshape);
5368  }
5369 
5370  {
5371  ShapeBuild_ReShape rebuild;
5372  for(exp1.Init(myshape, TopAbs_EDGE); exp1.More(); exp1.Next()) {
5373  TopoDS_Edge edge = TopoDS::Edge(exp1.Current());
5374  if(BRep_Tool::Degenerated(edge)) rebuild.Remove(edge);
5375  }
5376  myshape = rebuild.Apply(myshape);
5377  }
5378 
5379  ShapeFix_Wireframe sfwf;
5380  sfwf.SetPrecision(tolerance);
5381  sfwf.Load(myshape);
5382  sfwf.ModeDropSmallEdges() = Standard_True;
5383 
5384  if(sfwf.FixWireGaps()) {
5385  Msg::Info(" - Fixing wire gaps");
5386  if(sfwf.StatusWireGaps(ShapeExtend_OK)) Msg::Info(" no gaps found");
5387  if(sfwf.StatusWireGaps(ShapeExtend_DONE1))
5388  Msg::Info(" . Some 2D gaps fixed");
5389  if(sfwf.StatusWireGaps(ShapeExtend_DONE2))
5390  Msg::Info(" . Some 3D gaps fixed");
5391  if(sfwf.StatusWireGaps(ShapeExtend_FAIL1))
5392  Msg::Info(" . Failed to fix some 2D gaps");
5393  if(sfwf.StatusWireGaps(ShapeExtend_FAIL2))
5394  Msg::Info(" . Failed to fix some 3D gaps");
5395  }
5396 
5397  sfwf.SetPrecision(tolerance);
5398 
5399  if(sfwf.FixSmallEdges()) {
5400  Msg::Info(" - Fixing wire frames");
5401  if(sfwf.StatusSmallEdges(ShapeExtend_OK))
5402  Msg::Info(" . No small edges found");
5403  if(sfwf.StatusSmallEdges(ShapeExtend_DONE1))
5404  Msg::Info(" . Some small edges fixed");
5405  if(sfwf.StatusSmallEdges(ShapeExtend_FAIL1))
5406  Msg::Info(" . Failed to fix some small edges");
5407  }
5408 
5409  myshape = sfwf.Shape();
5410  }
5411 
5412  if(fixSmallFaces) {
5413  Msg::Info(" - Fixing spot and strip faces");
5414  ShapeFix_FixSmallFace sffsm;
5415  sffsm.Init(myshape);
5416  sffsm.SetPrecision(tolerance);
5417  sffsm.Perform();
5418  myshape = sffsm.FixShape();
5419  }
5420 
5421  if(sewFaces) {
5422  Msg::Info(" - Sewing faces");
5423 
5424  BRepOffsetAPI_Sewing sewedObj(tolerance);
5425 
5426  for(exp0.Init(myshape, TopAbs_FACE); exp0.More(); exp0.Next()) {
5427  TopoDS_Face face = TopoDS::Face(exp0.Current());
5428  sewedObj.Add(face);
5429  }
5430 
5431  sewedObj.Perform();
5432 
5433  if(!sewedObj.SewedShape().IsNull())
5434  myshape = sewedObj.SewedShape();
5435  else
5436  Msg::Info(" . Could not sew");
5437  }
5438 
5439  {
5440  ShapeBuild_ReShape rebuild;
5441  for(exp1.Init(myshape, TopAbs_EDGE); exp1.More(); exp1.Next()) {
5442  TopoDS_Edge edge = TopoDS::Edge(exp1.Current());
5443  if(BRep_Tool::Degenerated(edge)) rebuild.Remove(edge);
5444  }
5445  myshape = rebuild.Apply(myshape);
5446  }
5447 
5448  if(makeSolids) {
5449  Msg::Info(" - Making solids");
5450 
5451  BRepBuilderAPI_MakeSolid ms;
5452  int count = 0;
5453  for(exp0.Init(myshape, TopAbs_SHELL); exp0.More(); exp0.Next()) {
5454  count++;
5455  ms.Add(TopoDS::Shell(exp0.Current()));
5456  }
5457 
5458  if(!count) { Msg::Info(" . Could not make solid (no shells)"); }
5459  else {
5460  BRepCheck_Analyzer ba(ms);
5461  if(ba.IsValid()) {
5462  ShapeFix_Shape sfs;
5463  sfs.Init(ms);
5464  sfs.SetPrecision(tolerance);
5465  sfs.SetMaxTolerance(tolerance);
5466  sfs.Perform();
5467  myshape = sfs.Shape();
5468  for(exp0.Init(myshape, TopAbs_SOLID); exp0.More(); exp0.Next()) {
5469  TopoDS_Solid solid = TopoDS::Solid(exp0.Current());
5470  TopoDS_Solid newsolid = solid;
5471  BRepLib::OrientClosedSolid(newsolid);
5472  ShapeBuild_ReShape rebuild;
5473  rebuild.Replace(solid, newsolid);
5474  myshape = rebuild.Apply(myshape, TopAbs_COMPSOLID);
5475  }
5476  }
5477  else
5478  Msg::Info(" . Could not make solid");
5479  }
5480  }
5481 
5482  double newsurfacecont = 0;
5483  for(exp0.Init(myshape, TopAbs_FACE); exp0.More(); exp0.Next()) {
5484  TopoDS_Face face = TopoDS::Face(exp0.Current());
5485  GProp_GProps system;
5486  BRepGProp::SurfaceProperties(face, system);
5487  newsurfacecont += system.Mass();
5488  }
5489 
5490  _somap.Clear();
5491  _shmap.Clear();
5492  _fmap.Clear();
5493  _wmap.Clear();
5494  _emap.Clear();
5495  _vmap.Clear();
5496  _addShapeToMaps(myshape);
5497  int nnrc = 0, nnrcs = 0;
5498  int nnrso = _somap.Extent(), nnrsh = _shmap.Extent(), nnrf = _fmap.Extent();
5499  int nnrw = _wmap.Extent(), nnre = _emap.Extent(), nnrv = _vmap.Extent();
5500  for(exp0.Init(myshape, TopAbs_COMPOUND); exp0.More(); exp0.Next()) nnrc++;
5501  for(exp0.Init(myshape, TopAbs_COMPSOLID); exp0.More(); exp0.Next()) nnrcs++;
5502 
5503  double t2 = Cpu(), w2 = TimeOfDay();
5504  Msg::Info("Done healing shapes (Wall %gs, CPU %gs):", w2 - w1, t2 - t1);
5505  Msg::Info(" - Compounds : %d (%d)", nnrc, nrc);
5506  Msg::Info(" - Composite solids : %d (%d)", nnrcs, nrcs);
5507  Msg::Info(" - Solids : %d (%d)", nnrso, nrso);
5508  Msg::Info(" - Shells : %d (%d)", nnrsh, nrsh);
5509  Msg::Info(" - Wires : %d (%d)", nnrw, nrw);
5510  Msg::Info(" - Faces : %d (%d)", nnrf, nrf);
5511  Msg::Info(" - Edges : %d (%d)", nnre, nre);
5512  Msg::Info(" - Vertices : %d (%d)", nnrv, nrv);
5513  Msg::Info(" - Total surface area : %g (%g)", newsurfacecont, surfacecont);
5514 }
5515 
5517  const std::vector<std::pair<int, int> > &inDimTags,
5518  std::vector<std::pair<int, int> > &outDimTags, double tolerance,
5519  bool fixDegenerated, bool fixSmallEdges, bool fixSmallFaces, bool sewFaces,
5520  bool makeSolids)
5521 {
5522  BRep_Builder b;
5523  TopoDS_Compound c;
5524  b.MakeCompound(c);
5525 
5526  // construct a compound with all the shapes with tags
5527  _somap.Clear();
5528  _shmap.Clear();
5529  _fmap.Clear();
5530  _wmap.Clear();
5531  _emap.Clear();
5532  _vmap.Clear();
5533  TopTools_DataMapIteratorOfDataMapOfIntegerShape exp0(_tagVertex);
5534  for(; exp0.More(); exp0.Next()) _addShapeToMaps(exp0.Value());
5535  TopTools_DataMapIteratorOfDataMapOfIntegerShape exp1(_tagEdge);
5536  for(; exp1.More(); exp1.Next()) _addShapeToMaps(exp1.Value());
5537  TopTools_DataMapIteratorOfDataMapOfIntegerShape exp2(_tagFace);
5538  for(; exp2.More(); exp2.Next()) _addShapeToMaps(exp2.Value());
5539  TopTools_DataMapIteratorOfDataMapOfIntegerShape exp3(_tagSolid);
5540  for(; exp3.More(); exp3.Next()) _addShapeToMaps(exp3.Value());
5541  for(int i = 1; i <= _vmap.Extent(); i++) b.Add(c, _vmap(i));
5542  for(int i = 1; i <= _emap.Extent(); i++) b.Add(c, _emap(i));
5543  for(int i = 1; i <= _wmap.Extent(); i++) b.Add(c, _wmap(i));
5544  for(int i = 1; i <= _fmap.Extent(); i++) b.Add(c, _fmap(i));
5545  for(int i = 1; i <= _shmap.Extent(); i++) b.Add(c, _shmap(i));
5546  for(int i = 1; i <= _somap.Extent(); i++) b.Add(c, _somap(i));
5547 
5548  std::vector<TopoDS_Shape> toHeal;
5549  for(std::size_t i = 0; i < inDimTags.size(); i++) {
5550  int dim = inDimTags[i].first;
5551  int tag = inDimTags[i].second;
5552  if(!_isBound(dim, tag)) {
5553  Msg::Error("Unknown OpenCASCADE entity of dimension %d with tag %d",
5554  dim, tag);
5555  return false;
5556  }
5557  toHeal.push_back(_find(dim, tag));
5558  }
5559 
5560  // unbind everything
5561  _unbind();
5562 
5563  if(toHeal.empty()) { // heal all the shapes
5564  _healShape(c, tolerance, fixDegenerated, fixSmallEdges, fixSmallFaces,
5565  sewFaces, makeSolids, 1.0);
5566  }
5567  else {
5568  for(std::size_t i = 0; i < toHeal.size(); i++) {
5569  TopoDS_Shape olds = toHeal[i];
5570  TopoDS_Shape news = olds;
5571  _healShape(news, tolerance, fixDegenerated, fixSmallEdges, fixSmallFaces,
5572  sewFaces, makeSolids, 1.0);
5573  ShapeBuild_ReShape rebuild;
5574  rebuild.Replace(olds, news);
5575  c = TopoDS::Compound(rebuild.Apply(c));
5576  }
5577  }
5578 
5579  // rebind
5580  _multiBind(c, -1, outDimTags, false, true);
5581 
5582  return true;
5583 }
5584 
5586  const std::vector<std::pair<int, int> > &inDimTags)
5587 {
5588  for(std::size_t i = 0; i < inDimTags.size(); i++) {
5589  int dim = inDimTags[i].first;
5590  int tag = inDimTags[i].second;
5591  if(!_isBound(dim, tag)) {
5592  Msg::Error("Unknown OpenCASCADE entity of dimension %d with tag %d", dim,
5593  tag);
5594  return false;
5595  }
5596  TopoDS_Shape shape = _find(dim, tag);
5597  BRepBuilderAPI_NurbsConvert nurbs(shape);
5598  TopoDS_Shape res = nurbs.ModifiedShape(shape);
5599  _unbindWithoutChecks(shape);
5600  _bind(res, dim, tag, true);
5601  }
5602 
5603  return true;
5604 }
5605 
5606 static bool makeSTL(const TopoDS_Face &s, std::vector<SPoint2> *verticesUV,
5607  std::vector<SPoint3> *verticesXYZ,
5608  std::vector<SVector3> *normals, std::vector<int> &triangles)
5609 {
5610  if(CTX::instance()->geom.occDisableSTL) return false;
5611 
5612  double lin = CTX::instance()->mesh.stlLinearDeflection;
5614  double ang = CTX::instance()->mesh.stlAngularDeflection;
5615 
5616 #if OCC_VERSION_HEX > 0x070300
5617  BRepMesh_IncrementalMesh aMesher(s, lin, rel, ang, Standard_True);
5618 #elif OCC_VERSION_HEX > 0x070000
5619  Bnd_Box aBox;
5620  BRepBndLib::Add(s, aBox);
5621  BRepMesh_FastDiscret::Parameters parameters;
5622  parameters.Deflection = lin;
5623  parameters.Relative = rel;
5624  parameters.Angle = ang;
5625  BRepMesh_FastDiscret aMesher(aBox, parameters);
5626  aMesher.Perform(s);
5627 #else
5628  Bnd_Box aBox;
5629  BRepBndLib::Add(s, aBox);
5630  BRepMesh_FastDiscret aMesher(lin, ang, aBox, Standard_False, Standard_False,
5631  Standard_True, Standard_True);
5632  aMesher.Perform(s);
5633 #endif
5634 
5635  TopLoc_Location loc;
5636  Handle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation(s, loc);
5637 
5638  if(triangulation.IsNull()) return false;
5639 
5640  if(verticesUV && !triangulation->HasUVNodes()) return false;
5641 
5642  if(normals && !triangulation->HasUVNodes()) return false;
5643 
5644  int start = 0;
5645  if(verticesUV) start = verticesUV->size();
5646  if(verticesXYZ) start = verticesXYZ->size();
5647  for(int i = 1; i <= triangulation->NbNodes(); i++) {
5648  if(verticesUV) {
5649 #if OCC_VERSION_HEX >= 0x070600
5650  gp_Pnt2d p = triangulation->UVNode(i);
5651 #else
5652  gp_Pnt2d p = (triangulation->UVNodes())(i);
5653 #endif
5654  verticesUV->push_back(SPoint2(p.X(), p.Y()));
5655  }
5656  if(verticesXYZ) {
5657 #if OCC_VERSION_HEX >= 0x070600
5658  gp_Pnt pp = triangulation->Node(i);
5659 #else
5660  gp_Pnt pp = (triangulation->Nodes())(i);
5661 #endif
5662  double x = pp.X(), y = pp.Y(), z = pp.Z();
5663  loc.Transformation().Transforms(x, y, z);
5664  verticesXYZ->push_back(SPoint3(x, y, z));
5665  }
5666  if(normals) {
5667 #if OCC_VERSION_HEX >= 0x070600
5668  gp_Pnt2d p = triangulation->UVNode(i);
5669 #else
5670  gp_Pnt2d p = (triangulation->UVNodes())(i);
5671 #endif
5672  Handle(Geom_Surface) sur = BRep_Tool::Surface(s);
5673  gp_Pnt pnt;
5674  gp_Vec du, dv;
5675  sur->D1(p.X(), p.Y(), pnt, du, dv);
5676  SVector3 t1(du.X(), du.Y(), du.Z());
5677  SVector3 t2(dv.X(), dv.Y(), dv.Z());
5678  SVector3 n(crossprod(t1, t2));
5679  n.normalize();
5680  if(s.Orientation() == TopAbs_REVERSED) n *= -1.;
5681  normals->push_back(n);
5682  }
5683  }
5684  for(int i = 1; i <= triangulation->NbTriangles(); i++) {
5685 #if OCC_VERSION_HEX >= 0x070600
5686  Poly_Triangle triangle = triangulation->Triangle(i);
5687 #else
5688  Poly_Triangle triangle = (triangulation->Triangles())(i);
5689 #endif
5690  int p1, p2, p3;
5691  triangle.Get(p1, p2, p3);
5692  triangles.push_back(start + p1 - 1);
5693  if(s.Orientation() == TopAbs_REVERSED) {
5694  triangles.push_back(start + p3 - 1);
5695  triangles.push_back(start + p2 - 1);
5696  }
5697  else {
5698  triangles.push_back(start + p2 - 1);
5699  triangles.push_back(start + p3 - 1);
5700  }
5701  }
5702  return true;
5703 }
5704 
5705 bool OCC_Internals::makeEdgeSTLFromFace(const TopoDS_Edge &c,
5706  const TopoDS_Face &s,
5707  std::vector<SPoint3> *verticesXYZ)
5708 {
5709  TopLoc_Location transf;
5710  Handle(Poly_Triangulation) trian = BRep_Tool::Triangulation(s, transf);
5711  if(trian.IsNull()) return false;
5712 
5713  Handle(Poly_PolygonOnTriangulation) edgepoly =
5714  BRep_Tool::PolygonOnTriangulation(c, trian, transf);
5715  if(edgepoly.IsNull()) return false;
5716  if(edgepoly->NbNodes() < 2) return false;
5717 
5718  for(int i = 1; i <= edgepoly->NbNodes(); i++) {
5719 #if OCC_VERSION_HEX > 0x070600
5720  int j = edgepoly->Node(i);
5721 #else
5722  int j = (edgepoly->Nodes())(i);
5723 #endif
5724 #if OCC_VERSION_HEX >= 0x070600
5725  gp_Pnt pp = trian->Node(j);
5726 #else
5727  gp_Pnt pp = (trian->Nodes())(j);
5728 #endif
5729  if(!transf.IsIdentity()) { pp.Transform(transf); }
5730  verticesXYZ->push_back(SPoint3(pp.X(), pp.Y(), pp.Z()));
5731  }
5732  return true;
5733 }
5734 
5735 bool OCC_Internals::makeFaceSTL(const TopoDS_Face &s,
5736  std::vector<SPoint2> &vertices_uv,
5737  std::vector<int> &triangles)
5738 {
5739  return makeSTL(s, &vertices_uv, nullptr, nullptr, triangles);
5740 }
5741 
5742 bool OCC_Internals::makeFaceSTL(const TopoDS_Face &s,
5743  std::vector<SPoint2> &vertices_uv,
5744  std::vector<SPoint3> &vertices,
5745  std::vector<SVector3> &normals,
5746  std::vector<int> &triangles)
5747 {
5748  return makeSTL(s, &vertices_uv, &vertices, &normals, triangles);
5749 }
5750 
5751 bool OCC_Internals::makeFaceSTL(const TopoDS_Face &s,
5752  std::vector<SPoint3> &vertices,
5753  std::vector<SVector3> &normals,
5754  std::vector<int> &triangles)
5755 {
5756  return makeSTL(s, nullptr, &vertices, &normals, triangles);
5757 }
5758 
5759 bool OCC_Internals::_makeSTL(const TopoDS_Shape &s,
5760  std::vector<SPoint3> &vertices,
5761  std::vector<SVector3> &normals,
5762  std::vector<int> &triangles)
5763 {
5764  bool ret = true;
5765  TopExp_Explorer exp0;
5766  for(exp0.Init(s, TopAbs_FACE); exp0.More(); exp0.Next()) {
5767  TopoDS_Face face = TopoDS::Face(exp0.Current());
5768  bool tmp = makeSTL(TopoDS::Face(face.Oriented(TopAbs_FORWARD)), nullptr,
5769  &vertices, &normals, triangles);
5770  if(!tmp) ret = false;
5771  }
5772  return ret;
5773 }
5774 
5775 bool OCC_Internals::makeRectangleSTL(double x, double y, double z, double dx,
5776  double dy, double roundedRadius,
5777  std::vector<SPoint3> &vertices,
5778  std::vector<SVector3> &normals,
5779  std::vector<int> &triangles)
5780 {
5781  TopoDS_Face result;
5782  if(!makeRectangle(result, x, y, z, dx, dy, roundedRadius)) return false;
5783  if(!makeFaceSTL(result, vertices, normals, triangles)) return false;
5784  return true;
5785 }
5786 
5787 bool OCC_Internals::makeDiskSTL(double xc, double yc, double zc, double rx,
5788  double ry, std::vector<SPoint3> &vertices,
5789  std::vector<SVector3> &normals,
5790  std::vector<int> &triangles)
5791 {
5792  TopoDS_Face result;
5793  if(!makeDisk(result, xc, yc, zc, rx, ry)) return false;
5794  if(!makeFaceSTL(result, vertices, normals, triangles)) return false;
5795  return true;
5796 }
5797 
5798 bool OCC_Internals::makeSphereSTL(double xc, double yc, double zc,
5799  double radius, double angle1, double angle2,
5800  double angle3, std::vector<SPoint3> &vertices,
5801  std::vector<SVector3> &normals,
5802  std::vector<int> &triangles)
5803 {
5804  TopoDS_Solid result;
5805  if(!makeSphere(result, xc, yc, zc, radius, angle1, angle2, angle3))
5806  return false;
5807  if(!_makeSTL(result, vertices, normals, triangles)) return false;
5808  return true;
5809 }
5810 
5811 bool OCC_Internals::makeBoxSTL(double x, double y, double z, double dx,
5812  double dy, double dz,
5813  std::vector<SPoint3> &vertices,
5814  std::vector<SVector3> &normals,
5815  std::vector<int> &triangles)
5816 {
5817  TopoDS_Solid result;
5818  if(!makeBox(result, x, y, z, dx, dy, dz)) return false;
5819  if(!_makeSTL(result, vertices, normals, triangles)) return false;
5820  return true;
5821 }
5822 
5823 bool OCC_Internals::makeCylinderSTL(double x, double y, double z, double dx,
5824  double dy, double dz, double r,
5825  double angle,
5826  std::vector<SPoint3> &vertices,
5827  std::vector<SVector3> &normals,
5828  std::vector<int> &triangles)
5829 {
5830  TopoDS_Solid result;
5831  if(!makeCylinder(result, x, y, z, dx, dy, dz, r, angle)) return false;
5832  if(!_makeSTL(result, vertices, normals, triangles)) return false;
5833  return true;
5834 }
5835 
5836 bool OCC_Internals::makeConeSTL(double x, double y, double z, double dx,
5837  double dy, double dz, double r1, double r2,
5838  double angle, std::vector<SPoint3> &vertices,
5839  std::vector<SVector3> &normals,
5840  std::vector<int> &triangles)
5841 {
5842  TopoDS_Solid result;
5843  if(!makeCone(result, x, y, z, dx, dy, dz, r1, r2, angle)) return false;
5844  if(!_makeSTL(result, vertices, normals, triangles)) return false;
5845  return true;
5846 }
5847 
5848 bool OCC_Internals::makeWedgeSTL(double x, double y, double z, double dx,
5849  double dy, double dz, double ltx,
5850  std::vector<SPoint3> &vertices,
5851  std::vector<SVector3> &normals,
5852  std::vector<int> &triangles)
5853 {
5854  TopoDS_Solid result;
5855  if(!makeWedge(result, x, y, z, dx, dy, dz, ltx)) return false;
5856  if(!_makeSTL(result, vertices, normals, triangles)) return false;
5857  return true;
5858 }
5859 
5860 bool OCC_Internals::makeTorusSTL(double x, double y, double z, double r1,
5861  double r2, double angle,
5862  std::vector<SPoint3> &vertices,
5863  std::vector<SVector3> &normals,
5864  std::vector<int> &triangles)
5865 {
5866  TopoDS_Solid result;
5867  if(!makeTorus(result, x, y, z, r1, r2, angle)) return false;
5868  if(!_makeSTL(result, vertices, normals, triangles)) return false;
5869  return true;
5870 }
5871 
5872 #endif
5873 
5875 {
5876  if(_occ_internals) delete _occ_internals;
5878 }
5879 
5881 {
5882  if(_occ_internals) delete _occ_internals;
5883  _occ_internals = nullptr;
5884 }
5885 
5887 {
5888  if(!_occ_internals) return;
5889  _occ_internals->reset();
5890 }
5891 
5892 int GModel::readOCCBREP(const std::string &fn)
5893 {
5895  std::vector<std::pair<int, int> > outDimTags;
5896  _occ_internals->importShapes(fn, false, outDimTags, "brep");
5897  _occ_internals->synchronize(this);
5898  snapVertices();
5899  return 1;
5900 }
5901 
5902 int GModel::readOCCSTEP(const std::string &fn)
5903 {
5905  std::vector<std::pair<int, int> > outDimTags;
5906  _occ_internals->importShapes(fn, false, outDimTags, "step");
5907  _occ_internals->synchronize(this);
5908  return 1;
5909 }
5910 
5911 int GModel::readOCCIGES(const std::string &fn)
5912 {
5914  std::vector<std::pair<int, int> > outDimTags;
5915  _occ_internals->importShapes(fn, false, outDimTags, "iges");
5916  _occ_internals->synchronize(this);
5917  return 1;
5918 }
5919 
5920 int GModel::writeOCCBREP(const std::string &fn)
5921 {
5922  if(!_occ_internals) {
5923  Msg::Error("No OpenCASCADE model found");
5924  return 0;
5925  }
5926  _occ_internals->exportShapes(this, fn, "brep",
5927  CTX::instance()->geom.occExportOnlyVisible);
5928  return 1;
5929 }
5930 
5931 int GModel::writeOCCSTEP(const std::string &fn)
5932 {
5933  if(!_occ_internals) {
5934  Msg::Error("No OpenCASCADE model found");
5935  return 0;
5936  }
5937  _occ_internals->exportShapes(this, fn, "step",
5938  CTX::instance()->geom.occExportOnlyVisible);
5939  return 1;
5940 }
5941 
5942 int GModel::importOCCShape(const void *shape)
5943 {
5945 #if defined(HAVE_OCC)
5946  std::vector<std::pair<int, int> > outDimTags;
5947  _occ_internals->importShapes((TopoDS_Shape *)shape, false, outDimTags);
5948 #else
5949  Msg::Error("Gmsh requires OpenCASCADE to import TopoDS_Shape");
5950 #endif
5951  _occ_internals->synchronize(this);
5952  snapVertices();
5953  return 1;
5954 }
5955 
5957 {
5958  if(!_occ_internals) return nullptr;
5959 #if defined(HAVE_OCC)
5960  return _occ_internals->getVertexForOCCShape(this, *(TopoDS_Vertex *)shape);
5961 #else
5962  return 0;
5963 #endif
5964 }
5965 
5967 {
5968  if(!_occ_internals) return nullptr;
5969 #if defined(HAVE_OCC)
5970  return _occ_internals->getEdgeForOCCShape(this, *(TopoDS_Edge *)shape);
5971 #else
5972  return 0;
5973 #endif
5974 }
5975 
5977 {
5978  if(!_occ_internals) return nullptr;
5979 #if defined(HAVE_OCC)
5980  return _occ_internals->getFaceForOCCShape(this, *(TopoDS_Face *)shape);
5981 #else
5982  return 0;
5983 #endif
5984 }
5985 
5987 {
5988  if(!_occ_internals) return nullptr;
5989 #if defined(HAVE_OCC)
5990  return _occ_internals->getRegionForOCCShape(this, *(TopoDS_Solid *)shape);
5991 #else
5992  return 0;
5993 #endif
5994 }
OCC_Internals::setMaxTag
void setMaxTag(int dim, int val)
Definition: GModelIO_OCC.h:484
OCC_Internals::Fragments
@ Fragments
Definition: GModelIO_OCC.h:480
OCC_Internals::Intersection
@ Intersection
Definition: GModelIO_OCC.h:480
crossprod
SVector3 crossprod(const SVector3 &a, const SVector3 &b)
Definition: SVector3.h:150
contextMeshOptions::stlLinearDeflectionRelative
bool stlLinearDeflectionRelative
Definition: Context.h:65
OCC_Internals::addVertex
bool addVertex(int &tag, double x, double y, double z, double meshSize=MAX_LC)
Definition: GModelIO_OCC.h:486
OCC_Internals::symmetry
bool symmetry(const std::vector< std::pair< int, int > > &inDimTags, double a, double b, double c, double d)
Definition: GModelIO_OCC.h:764
TimeOfDay
double TimeOfDay()
Definition: OS.cpp:399
tags
static std::map< SPoint2, unsigned int > tags
Definition: drawGraph2d.cpp:400
triangle
Definition: shapeFunctions.h:414
contextGeometryOptions::toleranceBoolean
double toleranceBoolean
Definition: Context.h:99
OCC_Internals::addCircleArc
bool addCircleArc(int &tag, int startTag, int centerTag, int endTag)
Definition: GModelIO_OCC.h:499
contextGeometryOptions::tolerance
double tolerance
Definition: Context.h:99
SplitFileName
std::vector< std::string > SplitFileName(const std::string &fileName)
Definition: StringUtils.cpp:93
OCC_Internals::setMeshSize
void setMeshSize(int dim, int tag, double size)
Definition: GModelIO_OCC.h:802
OCC_Internals::booleanIntersection
bool booleanIntersection(int tag, const std::vector< std::pair< int, int > > &objectDimTags, const std::vector< std::pair< int, int > > &toolDimTags, std::vector< std::pair< int, int > > &outDimTags, std::vector< std::vector< std::pair< int, int > > > &outDimTagsMap, bool removeObject, bool removeTool)
Definition: GModelIO_OCC.h:717
GModel::firstEdge
eiter firstEdge()
Definition: GModel.h:356
GFace::edges
virtual std::vector< GEdge * > const & edges() const
Definition: GFace.h:121
OCC_Internals::addTorus
bool addTorus(int &tag, double x, double y, double z, double r1, double r2, double angle, const std::vector< double > &N=std::vector< double >())
Definition: GModelIO_OCC.h:642
OCC_Internals::addLine
bool addLine(int &tag, int startTag, int endTag)
Definition: GModelIO_OCC.h:491
OCC_Internals::addVolume
bool addVolume(int &tag, const std::vector< int > &shellTags)
Definition: GModelIO_OCC.h:612
contextGeometryOptions::occScaling
double occScaling
Definition: Context.h:105
contextGeometryOptions::occParallel
int occParallel
Definition: Context.h:102
OCC_Internals::makeTorusSTL
bool makeTorusSTL(double x, double y, double z, double r1, double r2, double angle, std::vector< SPoint3 > &vertices, std::vector< SVector3 > &normals, std::vector< int > &triangles)
Definition: GModelIO_OCC.h:900
OCC_Internals::makeSphereSTL
bool makeSphereSTL(double xc, double yc, double zc, double radius, double angle1, double angle2, double angle3, std::vector< SPoint3 > &vertices, std::vector< SVector3 > &normals, std::vector< int > &triangles)
Definition: GModelIO_OCC.h:865
GModel::getMaxElementaryNumber
int getMaxElementaryNumber(int dim)
Definition: GModel.cpp:817
GModel::createOCCInternals
void createOCCInternals()
Definition: GModelIO_OCC.cpp:5874
GModel::importOCCShape
int importOCCShape(const void *shape)
Definition: GModelIO_OCC.cpp:5942
OCC_Internals::revolve
bool revolve(const std::vector< std::pair< int, int > > &inDimTags, double x, double y, double z, double ax, double ay, double az, double angle, std::vector< std::pair< int, int > > &outDimTags, ExtrudeParams *e=0)
Definition: GModelIO_OCC.h:670
OCC_Internals::copy
bool copy(const std::vector< std::pair< int, int > > &inDimTags, std::vector< std::pair< int, int > > &outDimTags)
Definition: GModelIO_OCC.h:774
OCC_Internals::addSurfaceLoop
bool addSurfaceLoop(int &tag, const std::vector< int > &surfaceTags, bool sewing)
Definition: GModelIO_OCC.h:607
GFace
Definition: GFace.h:33
Msg::Info
static void Info(const char *fmt,...)
Definition: GmshMessage.cpp:587
GEntity::model
GModel * model() const
Definition: GEntity.h:277
angle
double angle(const SVector3 &a, const SVector3 &b)
Definition: SVector3.h:157
SPoint2
Definition: SPoint2.h:12
Msg::Debug
static void Debug(const char *fmt,...)
Definition: GmshMessage.cpp:752
c
static double c(int i, int j, fullMatrix< double > &CA, const std::vector< SPoint3 > &P, const std::vector< SPoint3 > &Q)
Definition: discreteFrechetDistance.cpp:15
GModel::deleteOCCInternals
void deleteOCCInternals()
Definition: GModelIO_OCC.cpp:5880
OCC_Internals::getMass
bool getMass(int dim, int tag, double &mass)
Definition: GModelIO_OCC.h:836
GModel::remove
bool remove(GRegion *r)
Definition: GModel.cpp:435
Msg::Warning
static void Warning(const char *fmt,...)
Definition: GmshMessage.cpp:543
GEntity::OpenCascadeModel
@ OpenCascadeModel
Definition: GEntity.h:82
Msg::Error
static void Error(const char *fmt,...)
Definition: GmshMessage.cpp:482
OCCFace.h
GFace::extrude
ExtrudeParams * extrude
Definition: GFace.h:357
OCC_Internals::addSphere
bool addSphere(int &tag, double xc, double yc, double zc, double radius, double angle1, double angle2, double angle3)
Definition: GModelIO_OCC.h:616
SPoint3
Definition: SPoint3.h:14
LegendrePolynomials::f
void f(int n, double u, double *val)
Definition: orthogonalBasis.cpp:77
COPIED_ENTITY
#define COPIED_ENTITY
Definition: ExtrudeParams.h:18
GModel::getFaceByTag
GFace * getFaceByTag(int n) const
Definition: GModel.cpp:326
OCC_Internals::booleanDifference
bool booleanDifference(int tag, const std::vector< std::pair< int, int > > &objectDimTags, const std::vector< std::pair< int, int > > &toolDimTags, std::vector< std::pair< int, int > > &outDimTags, std::vector< std::vector< std::pair< int, int > > > &outDimTagsMap, bool removeObject, bool removeTool)
Definition: GModelIO_OCC.h:726
OCC_Internals::addSpline
bool addSpline(int &tag, const std::vector< int > &pointTags, const std::vector< SVector3 > &tangents=std::vector< SVector3 >())
Definition: GModelIO_OCC.h:522
GFace::meshAttributes
struct GFace::@18 meshAttributes
SBoundingBox3d::min
SPoint3 min() const
Definition: SBoundingBox3d.h:90
GModel::readOCCSTEP
int readOCCSTEP(const std::string &name)
Definition: GModelIO_OCC.cpp:5902
OCC_Internals::getDistance
double getDistance(int dim1, int tag1, int dim2, int tag2, double &x1, double &y1, double &z1, double &x2, double &y2, double &z2)
Definition: GModelIO_OCC.h:845
OCC_Internals::addCurveLoop
bool addCurveLoop(int &tag, const std::vector< int > &curveTags)
Definition: GModelIO_OCC.h:543
SVector3
Definition: SVector3.h:16
OCCVertex.h
GEdge::numFaces
virtual std::size_t numFaces() const
Definition: GEdge.h:116
GModelIO_OCC.h
GVertex::edges
virtual std::vector< GEdge * > const & edges() const
Definition: GVertex.h:54
GEntity::getNativeType
virtual ModelType getNativeType() const
Definition: GEntity.h:268
OCC_Internals::dilate
bool dilate(const std::vector< std::pair< int, int > > &inDimTags, double x, double y, double z, double a, double b, double c)
Definition: GModelIO_OCC.h:759
GModel::getFaceForOCCShape
GFace * getFaceForOCCShape(const void *shape)
Definition: GModelIO_OCC.cpp:5976
GEdge::extrude
ExtrudeParams * extrude
Definition: GEdge.h:257
GModel::firstVertex
viter firstVertex()
Definition: GModel.h:357
GVertex::numEdges
virtual std::size_t numEdges() const
Definition: GVertex.h:57
contextMeshOptions::stlLinearDeflection
double stlLinearDeflection
Definition: Context.h:64
OCC_Internals::addBezierFilling
bool addBezierFilling(int &tag, int wireTag, const std::string &type="")
Definition: GModelIO_OCC.h:579
GModel::getEdgeByTag
GEdge * getEdgeByTag(int n) const
Definition: GModel.cpp:336
GmshMessage.h
MLine.h
edges
static int edges[6][2]
Definition: meshGRegionLocalMeshMod.cpp:23
MAX_LC
#define MAX_LC
Definition: GEntity.h:19
w1
const double w1
Definition: GaussQuadratureHex.cpp:18
ExtrudeParams::geo
struct ExtrudeParams::@15 geo
GModel::getVertexForOCCShape
GVertex * getVertexForOCCShape(const void *shape)
Definition: GModelIO_OCC.cpp:5956
SetBoundingBox
void SetBoundingBox(double xmin, double xmax, double ymin, double ymax, double zmin, double zmax)
Definition: OpenFile.cpp:115
OCC_Internals::addWedge
bool addWedge(int &tag, double x, double y, double z, double dx, double dy, double dz, double ltx, const std::vector< double > &N=std::vector< double >())
Definition: GModelIO_OCC.h:636
GFace::regions
std::list< GRegion * > regions() const
Definition: GFace.h:92
GModel::snapVertices
void snapVertices()
Definition: GModel.cpp:616
OCC_Internals::addPipe
bool addPipe(const std::vector< std::pair< int, int > > &inDimTags, int wireTag, std::vector< std::pair< int, int > > &outDimTags, const std::string &trihedron="")
Definition: GModelIO_OCC.h:677
OCC_Internals::addBSplineSurface
bool addBSplineSurface(int &tag, const std::vector< int > &pointTags, const int numPointsU, const int degreeU, const int degreeV, const std::vector< double > &weights, const std::vector< double > &knotsU, const std::vector< double > &knotsV, const std::vector< int > &multiplicitiesU, const std::vector< int > &multiplicitiesV, const std::vector< int > &wireTags=std::vector< int >(), bool wire3D=true)
Definition: GModelIO_OCC.h:583
GModel::getEdgeForOCCShape
GEdge * getEdgeForOCCShape(const void *shape)
Definition: GModelIO_OCC.cpp:5966
OCC_Internals::convertToNURBS
bool convertToNURBS(const std::vector< std::pair< int, int > > &dimTags)
Definition: GModelIO_OCC.h:798
OCC_Internals::addRectangle
bool addRectangle(int &tag, double x, double y, double z, double dx, double dy, double roundedRadius=0.)
Definition: GModelIO_OCC.h:547
GEntity::setColor
virtual void setColor(unsigned color, bool recursive=false)
Definition: GEntity.h:319
GEntity::getNativePtr
virtual void * getNativePtr() const
Definition: GEntity.h:271
OCC_Internals::addBSplineFilling
bool addBSplineFilling(int &tag, int wireTag, const std::string &type="")
Definition: GModelIO_OCC.h:575
contextGeometryOptions::occSafeUnbind
int occSafeUnbind
Definition: Context.h:100
OCC_Internals::booleanFragments
bool booleanFragments(int tag, const std::vector< std::pair< int, int > > &objectDimTags, const std::vector< std::pair< int, int > > &toolDimTags, std::vector< std::pair< int, int > > &outDimTags, std::vector< std::vector< std::pair< int, int > > > &outDimTagsMap, bool removeObject, bool removeTool)
Definition: GModelIO_OCC.h:735
CTX::instance
static CTX * instance()
Definition: Context.cpp:122
GRegion::faces
virtual std::vector< GFace * > faces() const
Definition: GRegion.h:64
SPoint3::x
double x(void) const
Definition: SPoint3.h:125
GModel::lastFace
fiter lastFace()
Definition: GModel.h:359
GRegion::extrude
ExtrudeParams * extrude
Definition: GRegion.h:148
contextGeometryOptions::occMakeSolids
int occMakeSolids
Definition: Context.h:102
contextGeometryOptions::occFixSmallFaces
int occFixSmallFaces
Definition: Context.h:101
GRegion::setColor
virtual void setColor(unsigned int val, bool recursive=false)
Definition: GRegion.cpp:261
OCCEdge.h
OCC_Internals::booleanOperator
bool booleanOperator(int tag, BooleanOperator op, const std::vector< std::pair< int, int > > &objectDimTags, const std::vector< std::pair< int, int > > &toolDimTags, std::vector< std::pair< int, int > > &outDimTags, std::vector< std::vector< std::pair< int, int > > > &outDimTagsMap, bool removeObject, bool removeTool)
Definition: GModelIO_OCC.h:698
OCC_Internals::Difference
@ Difference
Definition: GModelIO_OCC.h:480
contextGeometryOptions::occBooleanPreserveNumbering
int occBooleanPreserveNumbering
Definition: Context.h:102
ExtrudeParams::mesh
struct ExtrudeParams::@14 mesh
OCC_Internals::makeConeSTL
bool makeConeSTL(double x, double y, double z, double dx, double dy, double dz, double r1, double r2, double angle, std::vector< SPoint3 > &vertices, std::vector< SVector3 > &normals, std::vector< int > &triangles)
Definition: GModelIO_OCC.h:887
OCC_Internals::addDisk
bool addDisk(int &tag, double xc, double yc, double zc, double rx, double ry, const std::vector< double > &N=std::vector< double >(), const std::vector< double > &V=std::vector< double >())
Definition: GModelIO_OCC.h:552
GModel::setElementaryName
void setElementaryName(int dim, int tag, const std::string &name)
Definition: GModel.h:500
OCC_Internals::addEllipseArc
bool addEllipseArc(int &tag, int startTag, int centerTag, int majorTag, int endTag)
Definition: GModelIO_OCC.h:510
GModel::lastVertex
viter lastVertex()
Definition: GModel.h:361
OCC_Internals::extrude
bool extrude(const std::vector< std::pair< int, int > > &inDimTags, double dx, double dy, double dz, std::vector< std::pair< int, int > > &outDimTags, ExtrudeParams *e=0)
Definition: GModelIO_OCC.h:663
EXTRUDED_ENTITY
#define EXTRUDED_ENTITY
Definition: ExtrudeParams.h:17
GVertex
Definition: GVertex.h:23
OCC_Internals::addBezierSurface
bool addBezierSurface(int &tag, const std::vector< int > &pointTags, const int numPointsU, const std::vector< int > &wireTags=std::vector< int >(), bool wire3D=true)
Definition: GModelIO_OCC.h:595
OCC_Internals::makeBoxSTL
bool makeBoxSTL(double x, double y, double z, double dx, double dy, double dz, std::vector< SPoint3 > &vertices, std::vector< SVector3 > &normals, std::vector< int > &triangles)
Definition: GModelIO_OCC.h:873
tolerance
#define tolerance
Definition: curvature.cpp:11
OCC_Internals::getEntitiesInBoundingBox
bool getEntitiesInBoundingBox(double xmin, double ymin, double zmin, double xmax, double ymax, double zmax, std::vector< std::pair< int, int > > &dimTags, int dim)
Definition: GModelIO_OCC.h:819
OCC_Internals::getMaxTag
int getMaxTag(int dim) const
Definition: GModelIO_OCC.h:485
contextGeometryOptions::occFixDegenerated
int occFixDegenerated
Definition: Context.h:101
GEntity::useColor
virtual bool useColor()
Definition: GEntity.cpp:43
ExtrudeParams::fill
void fill(int type, double T0, double T1, double T2, double A0, double A1, double A2, double X0, double X1, double X2, double angle)
Definition: ExtrudeParams.cpp:34
OCC_Internals::addSurfaceFilling
bool addSurfaceFilling(int &tag, int wireTag, const std::vector< int > &pointTags=std::vector< int >(), const std::vector< int > &surfaceTags=std::vector< int >(), const std::vector< int > &surfaceContinuity=std::vector< int >(), const int degree=2, const int numPointsOnCurves=15, const int numIter=2, const bool anisotropic=false, const double tol2d=0.00001, const double tol3d=0.0001, const double tolAng=0.01, const double tolCurv=0.1, const int maxDegree=8, const int maxSegments=9)
Definition: GModelIO_OCC.h:562
prism
Definition: shapeFunctions.h:1031
GModel::getNumVertices
std::size_t getNumVertices() const
Definition: GModel.h:347
GModel
Definition: GModel.h:44
Cpu
double Cpu()
Definition: OS.cpp:366
ExtrudeParams.h
OCC_Internals::makeCylinderSTL
bool makeCylinderSTL(double x, double y, double z, double dx, double dy, double dz, double r, double angle, std::vector< SPoint3 > &vertices, std::vector< SVector3 > &normals, std::vector< int > &triangles)
Definition: GModelIO_OCC.h:879
OCC_Internals::translate
bool translate(const std::vector< std::pair< int, int > > &inDimTags, double dx, double dy, double dz)
Definition: GModelIO_OCC.h:749
OCC_Internals::makeRectangleSTL
bool makeRectangleSTL(double x, double y, double z, double dx, double dy, double roundedRadius, std::vector< SPoint3 > &vertices, std::vector< SVector3 > &normals, std::vector< int > &triangles)
Definition: GModelIO_OCC.h:852
GModel::firstFace
fiter firstFace()
Definition: GModel.h:355
OCC_Internals
Definition: GModelIO_OCC.h:471
GEdge::meshAttributes
struct GEdge::@16 meshAttributes
SPoint3::y
double y(void) const
Definition: SPoint3.h:127
OCC_Internals::makeDiskSTL
bool makeDiskSTL(double xc, double yc, double zc, double rx, double ry, std::vector< SPoint3 > &vertices, std::vector< SVector3 > &normals, std::vector< int > &triangles)
Definition: GModelIO_OCC.h:859
OCC_Internals::getSurfaceLoops
bool getSurfaceLoops(int volumeTag, std::vector< int > &surfaceLoopTags, std::vector< std::vector< int > > &surfaceTags)
Definition: GModelIO_OCC.h:831
GRegion::edges
virtual std::vector< GEdge * > const & edges() const
Definition: GRegion.cpp:459
contextGeometryOptions::pipeDefaultTrihedron
std::string pipeDefaultTrihedron
Definition: Context.h:96
OCC_Internals::addThickSolid
bool addThickSolid(int tag, int solidTag, const std::vector< int > &excludeFaceTags, double offset, std::vector< std::pair< int, int > > &outDimTags)
Definition: GModelIO_OCC.h:657
OCC_Internals::fillet
bool fillet(const std::vector< int > &volumeTags, const std::vector< int > &curveTags, const std::vector< double > &radii, std::vector< std::pair< int, int > > &outDimTags, bool removeVolume)
Definition: GModelIO_OCC.h:683
GModel::add
bool add(GRegion *r)
Definition: GModel.h:394
GModel::writeOCCBREP
int writeOCCBREP(const std::string &name)
Definition: GModelIO_OCC.cpp:5920
CTX::mesh
contextMeshOptions mesh
Definition: Context.h:313
ExtrudeParams::Mode
int Mode
Definition: ExtrudeParams.h:49
OCC_Internals::removeAllDuplicates
void removeAllDuplicates()
Definition: GModelIO_OCC.h:744
OCC_Internals::addEllipse
bool addEllipse(int &tag, double x, double y, double z, double r1, double r2, double angle1, double angle2, const std::vector< double > &N=std::vector< double >(), const std::vector< double > &V=std::vector< double >())
Definition: GModelIO_OCC.h:515
GModel::getNumRegions
std::size_t getNumRegions() const
Definition: GModel.h:344
skip
void skip(const char *skip, const char *until)
OCC_Internals::getEntities
bool getEntities(std::vector< std::pair< int, int > > &dimTags, int dim)
Definition: GModelIO_OCC.h:809
OCC_Internals::importShapes
bool importShapes(const std::string &fileName, bool highestDimOnly, std::vector< std::pair< int, int > > &outDimTags, const std::string &format="")
Definition: GModelIO_OCC.h:785
ROTATE
#define ROTATE
Definition: ExtrudeParams.h:22
GModel::resetOCCInternals
void resetOCCInternals()
Definition: GModelIO_OCC.cpp:5886
GEntity::tag
int tag() const
Definition: GEntity.h:280
GModel::getNumFaces
std::size_t getNumFaces() const
Definition: GModel.h:345
OCC_Internals::addBox
bool addBox(int &tag, double x, double y, double z, double dx, double dy, double dz)
Definition: GModelIO_OCC.h:621
OCC_Internals::getBoundingBox
bool getBoundingBox(int dim, int tag, double &xmin, double &ymin, double &zmin, double &xmax, double &ymax, double &zmax)
Definition: GModelIO_OCC.h:814
a2
const double a2
Definition: GaussQuadratureHex.cpp:12
CTX::geom
contextGeometryOptions geom
Definition: Context.h:311
GRegion
Definition: GRegion.h:28
GModel::getRegionForOCCShape
GRegion * getRegionForOCCShape(const void *shape)
Definition: GModelIO_OCC.cpp:5986
GFace::numRegions
std::size_t numRegions() const
Definition: GFace.h:87
OCC_Internals::rotate
bool rotate(const std::vector< std::pair< int, int > > &inDimTags, double x, double y, double z, double ax, double ay, double az, double angle)
Definition: GModelIO_OCC.h:754
GModel::getNumEdges
std::size_t getNumEdges() const
Definition: GModel.h:346
GEdge::faces
virtual std::vector< GFace * > faces() const
Definition: GEdge.h:113
ExtrudeParams::Source
int Source
Definition: ExtrudeParams.h:51
StringUtils.h
contextGeometryOptions::occSewFaces
int occSewFaces
Definition: Context.h:102
OCC_Internals::exportShapes
bool exportShapes(GModel *model, const std::string &fileName, const std::string &format="", bool onlyVisible=false)
Definition: GModelIO_OCC.h:804
GModel::firstRegion
riter firstRegion()
Definition: GModel.h:354
GModel::lastRegion
riter lastRegion()
Definition: GModel.h:358
OCC_Internals::makeWedgeSTL
bool makeWedgeSTL(double x, double y, double z, double dx, double dy, double dz, double ltx, std::vector< SPoint3 > &vertices, std::vector< SVector3 > &normals, std::vector< int > &triangles)
Definition: GModelIO_OCC.h:894
OCC_Internals::addCircle
bool addCircle(int &tag, double x, double y, double z, double r, double angle1, double angle2, const std::vector< double > &N=std::vector< double >(), const std::vector< double > &V=std::vector< double >())
Definition: GModelIO_OCC.h:503
Context.h
OCC_Internals::getVertex
bool getVertex(int tag, double &x, double &y, double &z)
Definition: GModelIO_OCC.h:813
contextMeshOptions::stlAngularDeflection
double stlAngularDeflection
Definition: Context.h:64
GModel::readOCCBREP
int readOCCBREP(const std::string &name)
Definition: GModelIO_OCC.cpp:5892
GFace::setColor
virtual void setColor(unsigned int val, bool recursive=false)
Definition: GFace.cpp:420
z
const double z
Definition: GaussQuadratureQuad.cpp:56
OCC_Internals::addBezier
bool addBezier(int &tag, const std::vector< int > &pointTags)
Definition: GModelIO_OCC.h:527
GRegion::meshAttributes
struct GRegion::@20 meshAttributes
OCC_Internals::addCone
bool addCone(int &tag, double x, double y, double z, double dx, double dy, double dz, double r1, double r2, double angle)
Definition: GModelIO_OCC.h:631
OCC_Internals::addWire
bool addWire(int &tag, const std::vector< int > &curveTags, bool closed)
Definition: GModelIO_OCC.h:539
MElement.h
OCCAttributes.h
OCC_Internals::getCenterOfMass
bool getCenterOfMass(int dim, int tag, double &x, double &y, double &z)
Definition: GModelIO_OCC.h:837
GEdge
Definition: GEdge.h:26
OCC_Internals::synchronize
void synchronize(GModel *model)
Definition: GModelIO_OCC.h:803
GModel::_occ_internals
OCC_Internals * _occ_internals
Definition: GModel.h:121
SPoint3::z
double z(void) const
Definition: SPoint3.h:129
OCC_Internals::getCurveLoops
bool getCurveLoops(int surfaceTag, std::vector< int > &curveLoopTags, std::vector< std::vector< int > > &curveTags)
Definition: GModelIO_OCC.h:826
OCC_Internals::addBSpline
bool addBSpline(int &tag, const std::vector< int > &pointTags, const int degree=-1, const std::vector< double > &weights=std::vector< double >(), const std::vector< double > &knots=std::vector< double >(), const std::vector< int > &multiplicities=std::vector< int >())
Definition: GModelIO_OCC.h:531
GModel::lastEdge
eiter lastEdge()
Definition: GModel.h:360
OCC_Internals::affine
bool affine(const std::vector< std::pair< int, int > > &inDimTags, const std::vector< double > &mat)
Definition: GModelIO_OCC.h:769
GEdge::setColor
virtual void setColor(unsigned int val, bool recursive=false)
Definition: GEdge.cpp:286
OCC_Internals::OCC_Internals
OCC_Internals()
Definition: GModelIO_OCC.h:481
GModel::readOCCIGES
int readOCCIGES(const std::string &name)
Definition: GModelIO_OCC.cpp:5911
OCC_Internals::addPlaneSurface
bool addPlaneSurface(int &tag, const std::vector< int > &wireTags)
Definition: GModelIO_OCC.h:558
normSq
double normSq(const SVector3 &v)
Definition: SVector3.h:148
GModel::getRegionByTag
GRegion * getRegionByTag(int n) const
Definition: GModel.cpp:316
OCCRegion.h
GVertex::setPrescribedMeshSizeAtVertex
virtual void setPrescribedMeshSizeAtVertex(double l)
Definition: GVertex.h:76
OCC_Internals::booleanUnion
bool booleanUnion(int tag, const std::vector< std::pair< int, int > > &objectDimTags, const std::vector< std::pair< int, int > > &toolDimTags, std::vector< std::pair< int, int > > &outDimTags, std::vector< std::vector< std::pair< int, int > > > &outDimTagsMap, bool removeObject, bool removeTool)
Definition: GModelIO_OCC.h:709
TRANSLATE
#define TRANSLATE
Definition: ExtrudeParams.h:21
OCC_Internals::Union
@ Union
Definition: GModelIO_OCC.h:480
OCC_Internals::mergeVertices
bool mergeVertices(const std::vector< int > &tags)
Definition: GModelIO_OCC.h:745
SBoundingBox3d::max
SPoint3 max() const
Definition: SBoundingBox3d.h:91
contextGeometryOptions::occFixSmallEdges
int occFixSmallEdges
Definition: Context.h:101
GModel::getVertexByTag
GVertex * getVertexByTag(int n) const
Definition: GModel.cpp:346
ExtrudeParams
Definition: ExtrudeParams.h:26
OCC_Internals::healShapes
bool healShapes(const std::vector< std::pair< int, int > > &inDimTags, std::vector< std::pair< int, int > > &outDimTags, double tolerance, bool fixDegenerated, bool fixSmallEdges, bool fixSmallFaces, bool sewFaces, bool makeSolids)
Definition: GModelIO_OCC.h:791
GEntity::getVisibility
virtual char getVisibility()
Definition: GEntity.cpp:35
Square
#define Square(a, x, y)
Definition: robustPredicates.cpp:254
c1
const double c1
Definition: GaussQuadratureHex.cpp:16
OCC_Internals::remove
bool remove(int dim, int tag, bool recursive=false)
Definition: GModelIO_OCC.h:779
SBoundingBox3d
Definition: SBoundingBox3d.h:21
OCC_Internals::addCylinder
bool addCylinder(int &tag, double x, double y, double z, double dx, double dy, double dz, double r, double angle)
Definition: GModelIO_OCC.h:626
OCC_Internals::chamfer
bool chamfer(const std::vector< int > &volumeTags, const std::vector< int > &curveTags, const std::vector< int > &surfaceTags, const std::vector< double > &distances, std::vector< std::pair< int, int > > &outDimTags, bool removeVolume)
Definition: GModelIO_OCC.h:690
OpenFile.h
OCC_Internals::reset
void reset()
Definition: GModelIO_OCC.h:483
OCC_Internals::getMatrixOfInertia
bool getMatrixOfInertia(int dim, int tag, std::vector< double > &mat)
Definition: GModelIO_OCC.h:841
OCC_Internals::addTrimmedSurface
bool addTrimmedSurface(int &tag, int surfaceTag, const std::vector< int > &wireTags, bool wire3D)
Definition: GModelIO_OCC.h:602
GModel::writeOCCSTEP
int writeOCCSTEP(const std::string &name)
Definition: GModelIO_OCC.cpp:5931
faces
static int faces[4][3]
Definition: meshGRegionDelaunayInsertion.cpp:165
OCC_Internals::addThruSections
bool addThruSections(int tag, const std::vector< int > &wireTags, bool makeSolid, bool makeRuled, std::vector< std::pair< int, int > > &outDimTags, int maxDegree=-1, const std::string &continuity="", const std::string &parametrization="", bool smoothing=false)
Definition: GModelIO_OCC.h:648