1 // Copyright (C) 2007-2023 CEA, EDF, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 #include <Standard_Stream.hxx>
25 #include <BRepOffsetAPI_MakeFilling.hxx>
27 #include <GEOMImpl_BlockDriver.hxx>
28 #include <GEOMImpl_IBlocks.hxx>
29 #include <GEOMImpl_IBlockTrsf.hxx>
30 #include <GEOMImpl_GlueDriver.hxx>
31 #include <GEOMImpl_Types.hxx>
32 #include <GEOMImpl_ILocalOperations.hxx>
33 #include <GEOMImpl_Block6Explorer.hxx>
34 #include <GEOMImpl_IBlocksOperations.hxx>
36 #include <GEOM_Function.hxx>
38 #include <ShHealOper_Sewing.hxx>
39 #include <ShHealOper_ShapeProcess.hxx>
40 //#include <GEOMAlgo_Gluer.hxx>
41 #include <BlockFix_BlockFixAPI.hxx>
42 #include <BlockFix_UnionFaces.hxx>
44 #include "utilities.h"
46 #include <TNaming_CopyShape.hxx>
48 #include <BRepAdaptor_Curve.hxx>
49 #include <BRepLib.hxx>
50 #include <BRep_Tool.hxx>
51 #include <BRepTools.hxx>
52 #include <BRepGProp.hxx>
53 #include <BRep_Builder.hxx>
54 #include <BRepTools_Quilt.hxx>
55 #include <BRepTools_WireExplorer.hxx>
56 #include <BRepBuilderAPI_MakeEdge.hxx>
57 #include <BRepBuilderAPI_MakeWire.hxx>
58 #include <BRepBuilderAPI_MakePolygon.hxx>
59 #include <BRepBuilderAPI_Transform.hxx>
60 #include <BRepCheck_Analyzer.hxx>
61 #include <BRepClass_FaceClassifier.hxx>
62 #include <BRepClass3d_SolidClassifier.hxx>
63 #include <BRepExtrema_ExtPF.hxx>
64 #include <BRepExtrema_DistShapeShape.hxx>
66 #include <ShapeUpgrade_UnifySameDomain.hxx>
70 #include <TopoDS_Shape.hxx>
71 #include <TopoDS_Edge.hxx>
72 #include <TopoDS_Wire.hxx>
73 #include <TopoDS_Shell.hxx>
74 #include <TopoDS_Solid.hxx>
75 #include <TopoDS_Compound.hxx>
76 #include <TopoDS_Iterator.hxx>
78 #include <TopExp_Explorer.hxx>
79 #include <TopTools_MapOfShape.hxx>
80 #include <TopTools_MapIteratorOfMapOfShape.hxx>
81 #include <TopTools_Array1OfShape.hxx>
82 #include <TopTools_SequenceOfShape.hxx>
83 #include <TopTools_ListOfShape.hxx>
84 #include <TopTools_ListIteratorOfListOfShape.hxx>
85 #include <TopTools_IndexedMapOfShape.hxx>
86 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
88 #include <GProp_GProps.hxx>
90 #include <Geom_Line.hxx>
91 #include <GC_MakeLine.hxx>
96 #include <Precision.hxx>
97 #include <TColgp_Array1OfPnt.hxx>
98 #include <TColStd_Array1OfInteger.hxx>
99 #include <TColStd_IndexedDataMapOfTransientTransient.hxx>
100 #include <StdFail_NotDone.hxx>
101 #include <Standard_NullObject.hxx>
102 #include <Standard_TypeMismatch.hxx>
103 #include <Standard_ConstructionError.hxx>
105 #include <Basics_OCCTVersion.hxx>
107 //=======================================================================
110 //=======================================================================
111 const Standard_GUID& GEOMImpl_BlockDriver::GetID()
113 static Standard_GUID aBlockDriver("FF1BBB67-5D14-4df2-980B-3A668264EA16");
118 //=======================================================================
119 //function : GEOMImpl_BlockDriver
121 //=======================================================================
122 GEOMImpl_BlockDriver::GEOMImpl_BlockDriver()
126 //=======================================================================
129 //=======================================================================
130 Standard_Integer GEOMImpl_BlockDriver::Execute(Handle(TFunction_Logbook)& log) const
132 if (Label().IsNull()) return 0;
133 Handle(GEOM_Function) aFunction = GEOM_Function::GetFunction(Label());
135 Standard_Integer aType = aFunction->GetType();
140 Standard_Real prec = Precision::Confusion();
142 Standard_Integer aNbSub = 0;
143 if (aType == BLOCK_COMPOUND_GLUE) {
147 } else if (aType == BLOCK_FACE_TWO_EDGES ||
148 aType == BLOCK_TWO_FACES) {
152 } else if (aType == BLOCK_FACE_FOUR_PNT ||
153 aType == BLOCK_FACE_FOUR_EDGES) {
157 } else if (aType == BLOCK_SIX_FACES) {
165 GEOMImpl_IBlocks aCI (aFunction);
166 Handle(TColStd_HSequenceOfTransient) aShapes = aCI.GetShapes();
167 Standard_Integer nbshapes = aShapes->Length();
169 if (nbshapes != aNbSub) {
170 Standard_TypeMismatch::Raise
171 ("Number of elements for object construction does not correspond to the used constructor");
174 TopTools_Array1OfShape anArgs (1, aNbSub);
175 Standard_Integer argi;
176 for (argi = 1; argi <= aNbSub; argi++) {
177 Handle(GEOM_Function) aRef = Handle(GEOM_Function)::DownCast(aShapes->Value(argi));
178 TopoDS_Shape anArg = aRef->GetValue();
179 if (anArg.IsNull()) {
180 Standard_NullObject::Raise("Null shape is given as argument");
182 anArgs(argi) = anArg;
185 if (aType == BLOCK_FACE_FOUR_EDGES) {
187 // Make face from four edges
188 if (anArgs(1).ShapeType() != TopAbs_EDGE || anArgs(2).ShapeType() != TopAbs_EDGE ||
189 anArgs(3).ShapeType() != TopAbs_EDGE || anArgs(4).ShapeType() != TopAbs_EDGE) {
190 Standard_TypeMismatch::Raise("Shape for face construction is not an edge");
193 // count corner vertices
194 TopTools_MapOfShape aVertMap;
195 for (Standard_Integer ii = 1; ii <= 4; ii++) {
196 TopoDS_Edge anEdge = TopoDS::Edge(anArgs(ii));
197 TopoDS_Vertex V1, V2;
198 TopExp::Vertices(anEdge, V1, V2, Standard_True);
199 if (V1.IsNull() || V2.IsNull()) {
200 Standard_NullObject::Raise("Bad edge for face construction: vertex is not defined");
202 if (BRepTools::Compare(V1,V2)) {
203 Standard_ConstructionError::Raise("Edge ends are too close");
205 Standard_Boolean isCoin1 = Standard_False, isCoin2 = Standard_False;
206 TopTools_MapIteratorOfMapOfShape anIter (aVertMap);
207 for (; anIter.More(); anIter.Next()) {
208 TopoDS_Vertex V = TopoDS::Vertex(anIter.Key());
209 if (BRepTools::Compare(V,V1)) isCoin1 = Standard_True;
210 if (BRepTools::Compare(V,V2)) isCoin2 = Standard_True;
212 if (!isCoin1) aVertMap.Add(V1);
213 if (!isCoin2) aVertMap.Add(V2);
215 if (aVertMap.Extent() != 4) {
216 Standard_ConstructionError::Raise("The edges must form a closed wire");
219 TopoDS_Edge anEdge1 = TopoDS::Edge(anArgs(1));
220 TopoDS_Edge anEdge2 = TopoDS::Edge(anArgs(2));
221 TopoDS_Edge anEdge3 = TopoDS::Edge(anArgs(3));
222 TopoDS_Edge anEdge4 = TopoDS::Edge(anArgs(4));
224 // check, if anEdge1 has common/coincident vertex with anEdge2,
225 Standard_Boolean isConnected12 = Standard_False;
226 TopoDS_Vertex V11, V12, V21, V22;
227 TopExp::Vertices(anEdge1, V11, V12, Standard_True);
228 TopExp::Vertices(anEdge2, V21, V22, Standard_True);
229 if (BRepTools::Compare(V11,V21) || BRepTools::Compare(V11,V22) ||
230 BRepTools::Compare(V12,V21) || BRepTools::Compare(V12,V22)) {
231 // the edges have common vertex
232 isConnected12 = Standard_True;
235 // build wire in right order, corresponding to edges connexity
236 BRepBuilderAPI_MakeWire* MW;
238 MW = new BRepBuilderAPI_MakeWire(anEdge1, anEdge2, anEdge3, anEdge4);
240 MW = new BRepBuilderAPI_MakeWire(anEdge1, anEdge3, anEdge2, anEdge4);
243 Standard_ConstructionError::Raise
244 ("Impossible to build a connected wire from the given edges");
246 TopoDS_Wire aWire = *MW;
249 // check the wire closure
250 TopoDS_Vertex aV1, aV2;
251 TopExp::Vertices(aWire, aV1, aV2);
252 if ( !aV1.IsNull() && !aV2.IsNull() && aV1.IsSame(aV2) )
253 aWire.Closed( true );
255 if (!aWire.Closed()) {
256 Standard_ConstructionError::Raise
257 ("Impossible to build a closed wire from the given edges");
260 // try to build face on the wire
261 GEOMImpl_Block6Explorer::MakeFace(aWire, Standard_False, aShape);
262 if (aShape.IsNull()) {
263 Standard_ConstructionError::Raise("Face construction failed");
266 } else if (aType == BLOCK_FACE_TWO_EDGES) {
268 // Make face from two opposite edges
269 if (anArgs(1).ShapeType() != TopAbs_EDGE ||
270 anArgs(2).ShapeType() != TopAbs_EDGE) {
271 Standard_TypeMismatch::Raise("Shape for face construction is not an edge");
274 TopoDS_Edge anEdge1 = TopoDS::Edge(anArgs(1));
275 TopoDS_Edge anEdge2 = TopoDS::Edge(anArgs(2));
277 if (anEdge1.IsSame(anEdge2)) {
278 Standard_ConstructionError::Raise("The edges must be different");
281 // create two edges, linking ends of the given edges
282 TopoDS_Vertex V11, V12, V21, V22;
283 TopExp::Vertices(anEdge1, V11, V12, Standard_False);
284 TopExp::Vertices(anEdge2, V21, V22, Standard_False);
285 if (V11.IsNull() || V12.IsNull() ||
286 V21.IsNull() || V22.IsNull()) {
287 Standard_NullObject::Raise("Bad edge for face construction: vertex is not defined");
290 BRepAdaptor_Curve C1 (anEdge1);
291 BRepAdaptor_Curve C2 (anEdge2);
292 gp_Pnt P11, P12, P21, P22;
294 // Mantis issue 0020599: Creation of a quadrangle face from 2 edges: SIGSEGV
295 P11 = C1.Value(C1.FirstParameter());
296 P12 = C1.Value(C1.LastParameter());
297 P21 = C2.Value(C2.FirstParameter());
298 P22 = C2.Value(C2.LastParameter());
299 //gp_Pnt P11 = BRep_Tool::Pnt(V11);
300 //gp_Pnt P12 = BRep_Tool::Pnt(V12);
301 //gp_Pnt P21 = BRep_Tool::Pnt(V21);
302 //gp_Pnt P22 = BRep_Tool::Pnt(V22);
304 if (P11.Distance(P21) < prec || P12.Distance(P22) < prec ||
305 P11.Distance(P22) < prec || P12.Distance(P21) < prec) {
306 Standard_ConstructionError::Raise("Given edges have too close ends");
309 Standard_Real per11 = P11.Distance(P21) + P12.Distance(P22);
310 Standard_Real per12 = P11.Distance(P22) + P12.Distance(P21);
317 // Mantis issue 0020599: Creation of a quadrangle face from 2 edges: SIGSEGV
319 Handle(Geom_Line) Line1 = GC_MakeLine(P11, P21).Value();
320 Handle(Geom_Line) Line2 = GC_MakeLine(P12, P22).Value();
322 BB.MakeEdge(anEdge3, Line1, Precision::Confusion());
323 BB.Range(anEdge3, 0., P11.Distance(P21));
324 BB.Add(anEdge3, V11.Oriented(TopAbs_FORWARD));
325 BB.Add(anEdge3, V21.Oriented(TopAbs_REVERSED));
327 BB.MakeEdge(anEdge4, Line2, Precision::Confusion());
328 BB.Range(anEdge4, 0., P12.Distance(P22));
329 BB.Add(anEdge4, V12.Oriented(TopAbs_FORWARD));
330 BB.Add(anEdge4, V22.Oriented(TopAbs_REVERSED));
333 Handle(Geom_Line) Line1 = GC_MakeLine(P11, P22).Value();
334 Handle(Geom_Line) Line2 = GC_MakeLine(P12, P21).Value();
336 BB.MakeEdge(anEdge3, Line1, Precision::Confusion());
337 BB.Range(anEdge3, 0., P11.Distance(P22));
338 BB.Add(anEdge3, V11.Oriented(TopAbs_FORWARD));
339 BB.Add(anEdge3, V22.Oriented(TopAbs_REVERSED));
341 BB.MakeEdge(anEdge4, Line2, Precision::Confusion());
342 BB.Range(anEdge4, 0., P12.Distance(P21));
343 BB.Add(anEdge4, V12.Oriented(TopAbs_FORWARD));
344 BB.Add(anEdge4, V21.Oriented(TopAbs_REVERSED));
346 //if (per11 < per12) {
347 // anEdge3 = BRepBuilderAPI_MakeEdge(V11, V21);
348 // anEdge4 = BRepBuilderAPI_MakeEdge(V12, V22);
350 // anEdge3 = BRepBuilderAPI_MakeEdge(V11, V22);
351 // anEdge4 = BRepBuilderAPI_MakeEdge(V12, V21);
355 BRepBuilderAPI_MakeWire* MW;
356 MW = new BRepBuilderAPI_MakeWire(anEdge1, anEdge3, anEdge2, anEdge4);
358 Standard_ConstructionError::Raise("Wire construction failed");
361 TopoDS_Wire aWire = *MW;
364 TopoDS_Vertex aV1, aV2;
365 TopExp::Vertices(aWire, aV1, aV2);
366 if ( !aV1.IsNull() && !aV2.IsNull() && aV1.IsSame(aV2) )
367 aWire.Closed( true );
369 if (!aWire.Closed()) {
370 Standard_ConstructionError::Raise
371 ("Impossible to build a closed wire from the given edges");
374 // try to build face on the wire
375 GEOMImpl_Block6Explorer::MakeFace(aWire, Standard_False, aShape);
376 if (aShape.IsNull()) {
377 Standard_ConstructionError::Raise("Face construction failed");
380 } else if (aType == BLOCK_FACE_FOUR_PNT) {
382 // Make face from four corner vertices
383 if (anArgs(1).ShapeType() != TopAbs_VERTEX ||
384 anArgs(2).ShapeType() != TopAbs_VERTEX ||
385 anArgs(3).ShapeType() != TopAbs_VERTEX ||
386 anArgs(4).ShapeType() != TopAbs_VERTEX) {
387 Standard_TypeMismatch::Raise("Shape for face construction is not a vertex");
390 TopoDS_Vertex V1 = TopoDS::Vertex(anArgs(1));
391 TopoDS_Vertex V2 = TopoDS::Vertex(anArgs(2));
392 TopoDS_Vertex V3 = TopoDS::Vertex(anArgs(3));
393 TopoDS_Vertex V4 = TopoDS::Vertex(anArgs(4));
395 gp_Pnt P1 = BRep_Tool::Pnt(V1);
396 gp_Pnt P2 = BRep_Tool::Pnt(V2);
397 gp_Pnt P3 = BRep_Tool::Pnt(V3);
398 gp_Pnt P4 = BRep_Tool::Pnt(V4);
400 if (P1.Distance(P2) < prec || P1.Distance(P3) < prec ||
401 P1.Distance(P4) < prec || P2.Distance(P3) < prec ||
402 P2.Distance(P4) < prec || P3.Distance(P4) < prec) {
403 Standard_ConstructionError::Raise("Four not coincident points must be given");
406 // calculate perimeters
407 Standard_Real per1234 = P1.Distance(P2) + P2.Distance(P3) +
408 P3.Distance(P4) + P4.Distance(P1);
409 Standard_Real per1243 = P1.Distance(P2) + P2.Distance(P4) +
410 P4.Distance(P3) + P3.Distance(P1);
411 Standard_Real per1324 = P1.Distance(P3) + P3.Distance(P2) +
412 P2.Distance(P4) + P4.Distance(P1);
415 if (per1243 < per1234 && per1243 < per1324) {
416 TopoDS_Vertex Vtmp = V3;
419 } else if (per1324 < per1234 && per1324 < per1243) {
420 TopoDS_Vertex Vtmp = V3;
427 BRepBuilderAPI_MakePolygon aMkPoly (V1, V2, V3, V4, Standard_True);
428 if (!aMkPoly.IsDone()) {
429 Standard_ConstructionError::Raise("Polygon construction failed");
432 // try to build face on the wire
434 GEOMImpl_Block6Explorer::MakeFace(aMkPoly, Standard_False, aShape);
435 if (aShape.IsNull()) {
436 Standard_ConstructionError::Raise("Face construction failed");
439 } else if (aType == BLOCK_SIX_FACES || aType == BLOCK_TWO_FACES) {
441 BRepTools_Quilt Glue;
443 if (aType == BLOCK_SIX_FACES) {
444 // Make block (hexahedral solid) from six faces
445 for (Standard_Integer ind = 1; ind <= nbshapes; ind++) {
446 if (anArgs(ind).ShapeType() != TopAbs_FACE) {
447 Standard_TypeMismatch::Raise("Shape for block construction is not a face");
449 Glue.Add(anArgs(ind));
454 // Make block (hexahedral solid) from two opposite faces
455 if (anArgs(1).ShapeType() != TopAbs_FACE ||
456 anArgs(2).ShapeType() != TopAbs_FACE) {
457 Standard_TypeMismatch::Raise("Shape for block construction is not a face");
460 // Get wires of the given faces
461 TopExp_Explorer wires1 (anArgs(1), TopAbs_WIRE);
462 TopExp_Explorer wires2 (anArgs(2), TopAbs_WIRE);
463 if (!wires1.More() || !wires2.More()) {
464 Standard_ConstructionError::Raise("A face for the block has no wires");
466 TopoDS_Shape aWire1 = wires1.Current();
467 TopoDS_Shape aWire2 = wires2.Current();
470 if (wires1.More() || wires2.More()) {
471 Standard_ConstructionError::Raise("A face for the block has more than one wire");
474 GEOMImpl_Block6Explorer aBlockTool;
475 aBlockTool.InitByTwoFaces(anArgs(1), anArgs(2));
477 // Construct the linking faces and add them in the gluing tool
479 Glue.Add(aBlockTool.GetFace(3, Standard_True));
480 Glue.Add(aBlockTool.GetFace(4, Standard_True));
481 Glue.Add(aBlockTool.GetFace(5, Standard_True));
482 Glue.Add(aBlockTool.GetFace(6, Standard_True));
486 TopExp_Explorer exp (Glue.Shells(), TopAbs_SHELL);
487 Standard_Integer ish = 0;
488 TopTools_MapOfShape mapShape;
489 for (; exp.More(); exp.Next()) {
490 if (mapShape.Add(exp.Current())) {
491 aShape = exp.Current();
497 aShape = Glue.Shells();
498 Standard_Real aTol = prec; // Precision::Confusion()
499 TopExp_Explorer expF (aShape, TopAbs_FACE);
500 TopTools_MapOfShape mapF;
503 for (; expF.More(); expF.Next()) {
504 if (mapF.Add(expF.Current())) {
505 B.Add(Shell, expF.Current());
506 Standard_Real aToler = BRep_Tool::Tolerance(TopoDS::Face(expF.Current()));
511 ShHealOper_Sewing aHealer (Shell, aTol);
512 if (aHealer.Perform())
513 aShape = aHealer.GetResultShape();
515 Standard_ConstructionError::Raise
516 ("Impossible to build a connected shell on the given faces");
519 if (aType == BLOCK_SIX_FACES) {
520 if (!aShape.Closed()) {
521 Standard_ConstructionError::Raise
522 ("Impossible to build a closed shell on the given faces");
529 BRepClass3d_SolidClassifier SC (Sol);
530 SC.PerformInfinitePoint(prec);
531 if (SC.State() == TopAbs_IN) {
533 B.Add(Sol, aShape.Reversed());
536 BRepLib::SameParameter(aShape, 1.E-5, Standard_True);
538 else if (aType == BLOCK_COMPOUND_GLUE) {
539 // Make blocks compound from a compound
540 if (anArgs(1).ShapeType() != TopAbs_COMPOUND &&
541 anArgs(2).ShapeType() != TopAbs_COMPSOLID) {
542 Standard_TypeMismatch::Raise("Not a compound given");
545 TopoDS_Shape aCompound = anArgs(1);
547 // Glue coincident faces and edges
548 aShape = GEOMImpl_GlueDriver::GlueFaces(aCompound, Precision::Confusion(), Standard_True);
549 //GEOMAlgo_Gluer aGluer;
550 //aGluer.SetShape(aCompound);
551 //aGluer.SetCheckGeometry(Standard_True);
553 //aShape = aGluer.Result();
558 } else { // Multi-transformations and compound improving
560 if (aType == BLOCK_REMOVE_EXTRA ||
561 aType == BLOCK_COMPOUND_IMPROVE) {
563 GEOMImpl_IBlockTrsf aCI (aFunction);
564 Handle(GEOM_Function) aRefShape = aCI.GetOriginal();
565 TopoDS_Shape aBlockOrComp = aRefShape->GetValue();
566 if (aBlockOrComp.IsNull()) {
567 Standard_NullObject::Raise("Null Shape given");
570 // Copy shape to avoid problems (Mantis issue 0021683)
571 TopoDS_Shape aShapeCopy;
572 TColStd_IndexedDataMapOfTransientTransient aMapTShapes;
573 TNaming_CopyShape::CopyTool(aBlockOrComp, aMapTShapes, aShapeCopy);
574 aBlockOrComp = aShapeCopy;
576 // 1. Improve solids with seam and/or degenerated edges
577 BlockFix_BlockFixAPI aTool;
578 //aTool.Tolerance() = toler;
579 aTool.OptimumNbFaces() = aCI.GetOptimumNbFaces();
580 aTool.SetShape(aBlockOrComp);
583 TopoDS_Shape aFixedExtra = aTool.Shape();
586 BRepCheck_Analyzer ana (aFixedExtra, false);
587 if (!ana.IsValid()) {
589 ShHealOper_ShapeProcess aHealer;
590 aHealer.Perform(aFixedExtra, aFixed);
591 if (aHealer.isDone())
592 aFixedExtra = aFixed;
595 if (aType == BLOCK_REMOVE_EXTRA)
597 aShape = aFixedExtra;
599 if (aShape == aBlockOrComp) {
600 MESSAGE("No modifications have been done");
603 else // aType == BLOCK_COMPOUND_IMPROVE
605 // 2. Separate non-blocks
606 TopTools_ListOfShape BLO; // All blocks from the given compound
607 TopTools_ListOfShape NOT; // Not blocks
608 TopTools_ListOfShape EXT; // Hexahedral solids, having degenerated and/or seam edges
609 TopTools_ListOfShape NOQ; // All non-quadrangular faces
610 GEOMImpl_IBlocksOperations::AddBlocksFrom(aFixedExtra, BLO, NOT, EXT, NOQ);
612 if (NOT.Extent() > 0) {
613 MESSAGE("Some non-blocks have been removed");
616 // 3. Warn about staying extra-edges
617 if (EXT.Extent() > 0) {
618 MESSAGE("Warning: Not all seam or degenerated edges was removed");
621 // ??? Throw away standalone blocks ???
623 // 4. Create compound of all blocks
624 TopoDS_Compound aComp;
626 BB.MakeCompound(aComp);
627 TopTools_ListIteratorOfListOfShape BLOit (BLO);
628 for (; BLOit.More(); BLOit.Next()) {
629 BB.Add(aComp, BLOit.Value());
633 aShape = GEOMImpl_GlueDriver::GlueFaces(aComp, Precision::Confusion(), Standard_False);
636 } else if (aType == BLOCK_MULTI_TRANSFORM_1D ||
637 aType == BLOCK_MULTI_TRANSFORM_2D) {
640 GEOMImpl_IBlockTrsf aCI (aFunction);
641 Handle(GEOM_Function) aRefShape = aCI.GetOriginal();
642 TopoDS_Shape aBlockIni = aRefShape->GetValue();
643 if (aBlockIni.IsNull()) {
644 Standard_NullObject::Raise("Null Block");
647 // Copy block to avoid problems (PAL6706)
648 TColStd_IndexedDataMapOfTransientTransient aMap;
650 TNaming_CopyShape::CopyTool(aBlockIni, aMap, aBlock);
652 // Block tolerance in vertices
653 Standard_Real aTol = prec;
654 TopExp_Explorer expV (aBlock, TopAbs_VERTEX);
655 TopTools_MapOfShape mapShape;
656 for (; expV.More(); expV.Next()) {
657 if (mapShape.Add(expV.Current())) {
658 TopoDS_Vertex aV = TopoDS::Vertex(expV.Current());
659 aTol = Max(BRep_Tool::Tolerance(aV), aTol);
663 if (aType == BLOCK_MULTI_TRANSFORM_1D) {
664 // Retrieve a faces by Ids
665 Standard_Integer aFace1Id = aCI.GetFace1U();
666 Standard_Integer aFace2Id = aCI.GetFace2U();
667 TopoDS_Shape aFace1, aFace2;
668 if (!GEOMImpl_ILocalOperations::GetSubShape(aBlock, aFace1Id, aFace1)) {
669 Standard_NullObject::Raise("Can not retrieve a sub-shape with given Id");
671 if (aFace1.ShapeType() != TopAbs_FACE) {
672 Standard_TypeMismatch::Raise("Sub-shape with given Id is not a face");
676 if (!GEOMImpl_ILocalOperations::GetSubShape(aBlock, aFace2Id, aFace2)) {
677 Standard_NullObject::Raise("Can not retrieve a sub-shape with given Id");
679 if (aFace2.ShapeType() != TopAbs_FACE) {
680 Standard_TypeMismatch::Raise("Sub-shape with given Id is not a face");
684 Standard_Integer aNbIter = aCI.GetNbIterU();
686 MultiTransformate1D(aBlock, aFace1, aFace2, aNbIter, aMulti);
688 } else { // aType == BLOCK_MULTI_TRANSFORM_2D
689 // Retrieve a faces by Ids
690 Standard_Integer aFace1UId = aCI.GetFace1U();
691 Standard_Integer aFace2UId = aCI.GetFace2U();
692 Standard_Integer aFace1VId = aCI.GetFace1V();
693 Standard_Integer aFace2VId = aCI.GetFace2V();
695 TopoDS_Shape aFace1U, aFace2U, aFace1V, aFace2V;
696 if (!GEOMImpl_ILocalOperations::GetSubShape(aBlock, aFace1UId, aFace1U) ||
697 !GEOMImpl_ILocalOperations::GetSubShape(aBlock, aFace1VId, aFace1V)) {
698 Standard_NullObject::Raise("Can not retrieve a sub-shape with given Id");
701 if (aFace1U.ShapeType() != TopAbs_FACE ||
702 aFace1V.ShapeType() != TopAbs_FACE) {
703 Standard_TypeMismatch::Raise("Sub-shape with given Id is not a face");
707 if (!GEOMImpl_ILocalOperations::GetSubShape(aBlock, aFace2UId, aFace2U)) {
708 Standard_NullObject::Raise("Can not retrieve a sub-shape with given Id");
711 if (aFace2U.ShapeType() != TopAbs_FACE) {
712 Standard_TypeMismatch::Raise("Sub-shape with given Id is not a face");
717 if (!GEOMImpl_ILocalOperations::GetSubShape(aBlock, aFace2VId, aFace2V)) {
718 Standard_NullObject::Raise("Can not retrieve a sub-shape with given Id");
721 if (aFace2V.ShapeType() != TopAbs_FACE) {
722 Standard_TypeMismatch::Raise("Sub-shape with given Id is not a face");
726 Standard_Integer aNbIterU = aCI.GetNbIterU();
727 Standard_Integer aNbIterV = aCI.GetNbIterV();
729 MultiTransformate2D(aBlock,
730 aFace1U, aFace2U, aNbIterU,
731 aFace1V, aFace2V, aNbIterV, aMulti);
734 if (aMulti.IsNull()) {
735 StdFail_NotDone::Raise("Multi-transformation failed");
738 // Glue faces of the multi-block
739 aShape = GEOMImpl_GlueDriver::GlueFaces(aMulti, aTol, Standard_False);
741 } else if (aType == BLOCK_UNION_FACES) {
742 GEOMImpl_IBlockTrsf aCI (aFunction);
743 Handle(GEOM_Function) aRefShape = aCI.GetOriginal();
744 TopoDS_Shape aBlockOrComp = aRefShape->GetValue();
745 if (aBlockOrComp.IsNull()) {
746 Standard_NullObject::Raise("Null Shape given");
749 #if OCC_VERSION_LARGE < 0x07050301
750 BlockFix_UnionFaces aFaceUnifier;
751 aFaceUnifier.GetOptimumNbFaces() = 0; // To force union faces.
752 aShape = aFaceUnifier.Perform(aBlockOrComp);
754 // Use OCCT algo ShapeUpgrade_UnifySameDomain instead of BlockFix_UnionFaces:
755 Standard_Boolean isUnifyEdges = Standard_False;
756 Standard_Boolean isUnifyFaces = Standard_True;
757 Standard_Boolean isConcatBSplines = Standard_True;
758 ShapeUpgrade_UnifySameDomain aUnifier (aBlockOrComp,
759 isUnifyEdges, isUnifyFaces, isConcatBSplines);
760 aUnifier.SetLinearTolerance(Precision::Confusion());
761 aUnifier.SetAngularTolerance(Precision::Confusion());
763 aShape = aUnifier.Shape();
765 } else { // unknown function type
770 if (aShape.IsNull()) return 0;
772 aFunction->SetValue(aShape);
774 log->SetTouched(Label());
779 //=======================================================================
780 //function : MultiTransformate1D
782 //=======================================================================
783 void GEOMImpl_BlockDriver::MultiTransformate1D (const TopoDS_Shape& theBlock,
784 const TopoDS_Shape& theFace1,
785 const TopoDS_Shape& theFace2,
786 const Standard_Integer theNbIter,
787 TopoDS_Shape& theResult) const
789 // Construct Tool, where <theFace1> will be the first face,
790 // and a face, opposite to <theFace1>, will be the second face
791 GEOMImpl_Block6Explorer aBlockTool;
792 aBlockTool.InitByBlockAndFace(theBlock, theFace1);
794 // Find IDs of the faces
795 Standard_Integer dir_face1 = 1, dir_face2 = 2;
796 if (!theFace2.IsNull()) {
797 dir_face2 = aBlockTool.GetFaceID(theFace2);
800 // Find three pairs of points
801 Standard_Integer v11_id = 0, v12_id = 0, v13_id = 0; // vertices of the first face
802 Standard_Integer v21_id = 0, v22_id = 0, v23_id = 0; // vertices of the second face
804 if (dir_face2 == 2) { // <theFace2> is opposite to <theFace1>
806 // We will take vertices with equal local numbers on the faces,
807 // as the Block6Explorer gives equal local numbers
808 // to the linked vertices on the opposite faces,
809 // i.e. v1* is linked with the v2* by an edge:
813 // / | / | dir_face1 - bottom
815 // /________ / | dir_face2 - top
824 v11_id = aBlockTool.GetVertexID(dir_face1, 1);
825 v12_id = aBlockTool.GetVertexID(dir_face1, 2);
826 v13_id = aBlockTool.GetVertexID(dir_face1, 4);
828 v21_id = aBlockTool.GetVertexID(dir_face2, 1);
829 v22_id = aBlockTool.GetVertexID(dir_face2, 2);
830 v23_id = aBlockTool.GetVertexID(dir_face2, 4);
836 // / | / | dir_face1 - bottom
838 // /________ / | dir_face2 - right (for example)
841 // | / | /v12 = v22 (common_vertex2)
845 // v13 v11 = v21 (common_vertex1)
847 Standard_Integer common_edge_id = aBlockTool.FindCommonEdgeID(dir_face1, dir_face2);
848 Standard_Integer common_vertex1 = aBlockTool.GetVertexOnEdgeID(common_edge_id, 1);
849 Standard_Integer common_vertex2 = aBlockTool.GetVertexOnEdgeID(common_edge_id, 2);
851 Standard_Integer not_common_v1 = 0;
852 Standard_Integer vid = 1;
853 Standard_Boolean isFound = Standard_False;
854 while (!isFound && vid <= 4) {
855 not_common_v1 = aBlockTool.GetVertexID(dir_face1, vid);
856 isFound = (not_common_v1 != common_vertex2 &&
857 aBlockTool.FindEdgeID(not_common_v1, common_vertex1) != 0);
861 Standard_Integer not_common_v2 = 0;
863 isFound = Standard_False;
864 while (!isFound && vid <= 4) {
865 not_common_v2 = aBlockTool.GetVertexID(dir_face2, vid);
866 isFound = (not_common_v2 != common_vertex2 &&
867 aBlockTool.FindEdgeID(not_common_v2, common_vertex1) != 0);
871 v11_id = common_vertex1;
872 v12_id = common_vertex2;
873 v13_id = not_common_v1;
875 v21_id = common_vertex1;
876 v22_id = common_vertex2;
877 v23_id = not_common_v2;
880 // Construct a transformation operator
881 TopoDS_Vertex V11 = TopoDS::Vertex(aBlockTool.GetVertex(v11_id));
882 TopoDS_Vertex V12 = TopoDS::Vertex(aBlockTool.GetVertex(v12_id));
883 TopoDS_Vertex V13 = TopoDS::Vertex(aBlockTool.GetVertex(v13_id));
885 TopoDS_Vertex V21 = TopoDS::Vertex(aBlockTool.GetVertex(v21_id));
886 TopoDS_Vertex V22 = TopoDS::Vertex(aBlockTool.GetVertex(v22_id));
887 TopoDS_Vertex V23 = TopoDS::Vertex(aBlockTool.GetVertex(v23_id));
889 // Axes of the first direction face
890 gp_Pnt P1 = BRep_Tool::Pnt(V11);
891 gp_Vec VecN1 (P1, BRep_Tool::Pnt(V12));
892 gp_Vec VecX1 (P1, BRep_Tool::Pnt(V13));
893 gp_Ax3 Ax1 (P1, VecN1, VecX1);
895 // Axes of the second direction face
896 gp_Pnt P2 = BRep_Tool::Pnt(V21);
897 gp_Vec VecN2 (P2, BRep_Tool::Pnt(V22));
898 gp_Vec VecX2 (P2, BRep_Tool::Pnt(V23));
899 gp_Ax3 Ax2 (P2, VecN2, VecX2);
902 aTrsf.SetDisplacement(Ax1, Ax2);
904 // Check, that <theFace2> is similar to <theFace1>.
905 // Actually, we need only to check right position of one
906 // vertex, not involved into the transformation construction.
907 if (!aBlockTool.IsSimilarFaces(dir_face1, dir_face2, aTrsf)) {
908 Standard_ConstructionError::Raise("The direction faces are not similar");
911 // Perform multi-transformation
912 TopoDS_Compound aCompound;
914 B.MakeCompound(aCompound);
916 TopoDS_Shape aPrevShape = theBlock;
917 for (Standard_Integer i = 0; i < theNbIter; i++) {
918 B.Add(aCompound, aPrevShape);
919 BRepBuilderAPI_Transform aTransformation (aPrevShape, aTrsf, Standard_False);
920 aPrevShape = aTransformation.Shape();
922 theResult = aCompound;
925 //=======================================================================
926 //function : MultiTransformate2D
928 //=======================================================================
929 void GEOMImpl_BlockDriver::MultiTransformate2D (const TopoDS_Shape& theBlock,
930 const TopoDS_Shape& theFace1U,
931 const TopoDS_Shape& theFace2U,
932 const Standard_Integer theNbIterU,
933 const TopoDS_Shape& theFace1V,
934 const TopoDS_Shape& theFace2V,
935 const Standard_Integer theNbIterV,
936 TopoDS_Shape& theResult) const
938 // Construct Tool, where <theFace1U> will be the first face,
939 // and a face, opposite to <theFace1U>, will be the second face
940 GEOMImpl_Block6Explorer aBlockTool;
941 aBlockTool.InitByBlockAndFace(theBlock, theFace1U);
943 gp_Trsf aTrsfU, aTrsfV;
945 for (Standard_Integer uv = 1; uv <= 2; uv++) {
947 TopoDS_Shape theFace1 = theFace1U;
948 TopoDS_Shape theFace2 = theFace2U;
951 theFace1 = theFace1V;
952 theFace2 = theFace2V;
955 // Find IDs of the faces
956 Standard_Integer dir_face1 = aBlockTool.GetFaceID(theFace1);
957 Standard_Integer dir_face2 = 0;
958 Standard_Integer opp_face1 = aBlockTool.GetOppositeFaceID(dir_face1);
959 if (theFace2.IsNull()) {
960 dir_face2 = opp_face1;
962 dir_face2 = aBlockTool.GetFaceID(theFace2);
965 // Find three pairs of points
966 Standard_Integer v11_id = 0, v12_id = 0, v13_id = 0; // vertices of the first face
967 Standard_Integer v21_id = 0, v22_id = 0, v23_id = 0; // vertices of the second face
969 if (dir_face2 == opp_face1) { // <theFace2> is opposite to <theFace1>
971 // We will take vertices with equal local numbers on the faces,
972 // as the Block6Explorer gives equal local numbers
973 // to the linked vertices on the opposite faces,
974 // i.e. v1* is linked with the v2* by an edge:
976 v11_id = aBlockTool.GetVertexID(dir_face1, 1);
977 v12_id = aBlockTool.GetVertexID(dir_face1, 2);
978 v13_id = aBlockTool.GetVertexID(dir_face1, 4);
980 v21_id = aBlockTool.GetVertexID(dir_face2, 1);
981 v22_id = aBlockTool.GetVertexID(dir_face2, 2);
982 v23_id = aBlockTool.GetVertexID(dir_face2, 4);
986 Standard_Integer common_edge_id = aBlockTool.FindCommonEdgeID(dir_face1, dir_face2);
987 Standard_Integer common_vertex1 = aBlockTool.GetVertexOnEdgeID(common_edge_id, 1);
988 Standard_Integer common_vertex2 = aBlockTool.GetVertexOnEdgeID(common_edge_id, 2);
990 Standard_Integer not_common_v1 = 0;
991 Standard_Integer vid = 1;
992 Standard_Boolean isFound = Standard_False;
993 while (!isFound && vid <= 4) {
994 not_common_v1 = aBlockTool.GetVertexID(dir_face1, vid);
995 isFound = (not_common_v1 != common_vertex2 &&
996 aBlockTool.FindEdgeID(not_common_v1, common_vertex1) != 0);
1000 Standard_Integer not_common_v2 = 0;
1002 isFound = Standard_False;
1003 while (!isFound && vid <= 4) {
1004 not_common_v2 = aBlockTool.GetVertexID(dir_face2, vid);
1005 isFound = (not_common_v2 != common_vertex2 &&
1006 aBlockTool.FindEdgeID(not_common_v2, common_vertex1) != 0);
1010 v11_id = common_vertex1;
1011 v12_id = common_vertex2;
1012 v13_id = not_common_v1;
1014 v21_id = common_vertex1;
1015 v22_id = common_vertex2;
1016 v23_id = not_common_v2;
1019 // Construct a transformation operator
1020 TopoDS_Vertex V11 = TopoDS::Vertex(aBlockTool.GetVertex(v11_id));
1021 TopoDS_Vertex V12 = TopoDS::Vertex(aBlockTool.GetVertex(v12_id));
1022 TopoDS_Vertex V13 = TopoDS::Vertex(aBlockTool.GetVertex(v13_id));
1024 TopoDS_Vertex V21 = TopoDS::Vertex(aBlockTool.GetVertex(v21_id));
1025 TopoDS_Vertex V22 = TopoDS::Vertex(aBlockTool.GetVertex(v22_id));
1026 TopoDS_Vertex V23 = TopoDS::Vertex(aBlockTool.GetVertex(v23_id));
1028 // Axes of the first direction face
1029 gp_Pnt P1 = BRep_Tool::Pnt(V11);
1030 gp_Vec VecN1 (P1, BRep_Tool::Pnt(V12));
1031 gp_Vec VecX1 (P1, BRep_Tool::Pnt(V13));
1032 gp_Ax3 Ax1 (P1, VecN1, VecX1);
1034 // Axes of the second direction face
1035 gp_Pnt P2 = BRep_Tool::Pnt(V21);
1036 gp_Vec VecN2 (P2, BRep_Tool::Pnt(V22));
1037 gp_Vec VecX2 (P2, BRep_Tool::Pnt(V23));
1038 gp_Ax3 Ax2 (P2, VecN2, VecX2);
1041 aTrsf.SetDisplacement(Ax1, Ax2);
1050 // Check, that <theFace2> is similar to <theFace1>.
1051 // Actually, we need only to check right position of one
1052 // vertex, not involved into the transformation construction.
1053 if (!aBlockTool.IsSimilarFaces(dir_face1, dir_face2, aTrsf)) {
1054 Standard_ConstructionError::Raise("The direction faces are not similar");
1058 // Perform multi-transformation
1059 TopoDS_Compound aCompound;
1061 B.MakeCompound(aCompound);
1063 TopoDS_Shape aPrevShapeU = theBlock;
1064 for (int i = 0; i < theNbIterU; i++) {
1065 TopoDS_Shape aPrevShapeV = aPrevShapeU;
1066 for (int j = 0; j < theNbIterV; j++) {
1067 B.Add(aCompound, aPrevShapeV);
1068 BRepBuilderAPI_Transform aTransformationV (aPrevShapeV, aTrsfV, Standard_False);
1069 aPrevShapeV = aTransformationV.Shape();
1071 BRepBuilderAPI_Transform aTransformationU (aPrevShapeU, aTrsfU, Standard_False);
1072 aPrevShapeU = aTransformationU.Shape();
1073 // Correction of the second transformation according to the first transformation
1074 Ax1V.Transform(aTrsfU);
1075 Ax2V.Transform(aTrsfU);
1076 aTrsfV.SetDisplacement(Ax1V, Ax2V);
1079 theResult = aCompound;
1082 //================================================================================
1084 * \brief Returns a name of creation operation and names and values of creation parameters
1086 //================================================================================
1088 bool GEOMImpl_BlockDriver::
1089 GetCreationInformation(std::string& theOperationName,
1090 std::vector<GEOM_Param>& theParams)
1092 if (Label().IsNull()) return 0;
1093 Handle(GEOM_Function) function = GEOM_Function::GetFunction(Label());
1095 Standard_Integer aType = function->GetType();
1096 GEOMImpl_IBlocks aCI1 (function);
1097 GEOMImpl_IBlockTrsf aCI2 (function);
1098 Handle(TColStd_HSequenceOfTransient) aShapes = aCI1.GetShapes();
1101 case BLOCK_FACE_FOUR_EDGES:
1102 theOperationName = "Q_FACE";
1103 AddParam( theParams, "Edge 1", aShapes->Value(1) );
1104 AddParam( theParams, "Edge 2", aShapes->Value(2) );
1105 AddParam( theParams, "Edge 3", aShapes->Value(3) );
1106 AddParam( theParams, "Edge 4", aShapes->Value(4) );
1108 case BLOCK_FACE_TWO_EDGES:
1109 theOperationName = "Q_FACE";
1110 AddParam( theParams, "Edge 1", aShapes->Value(1) );
1111 AddParam( theParams, "Edge 2", aShapes->Value(2) );
1113 case BLOCK_FACE_FOUR_PNT:
1114 theOperationName = "Q_FACE";
1115 AddParam( theParams, "Point 1", aShapes->Value(1) );
1116 AddParam( theParams, "Point 2", aShapes->Value(2) );
1117 AddParam( theParams, "Point 3", aShapes->Value(3) );
1118 AddParam( theParams, "Point 4", aShapes->Value(4) );
1120 case BLOCK_SIX_FACES:
1121 theOperationName = "HEX_SOLID";
1122 AddParam( theParams, "Face 1", aShapes->Value(1) );
1123 AddParam( theParams, "Face 2", aShapes->Value(2) );
1124 AddParam( theParams, "Face 3", aShapes->Value(3) );
1125 AddParam( theParams, "Face 4", aShapes->Value(4) );
1126 AddParam( theParams, "Face 5", aShapes->Value(5) );
1127 AddParam( theParams, "Face 6", aShapes->Value(6) );
1129 case BLOCK_TWO_FACES:
1130 theOperationName = "HEX_SOLID";
1131 AddParam( theParams, "Face 1", aShapes->Value(1) );
1132 AddParam( theParams, "Face 2", aShapes->Value(2) );
1134 case BLOCK_COMPOUND_GLUE:
1135 theOperationName = "MakeBlockCompound";
1136 AddParam( theParams, "Compound", aShapes->Value(1) );
1138 case BLOCK_REMOVE_EXTRA:
1139 theOperationName = "REMOVE_EXTRA_EDGES";
1140 AddParam( theParams, "Selected shape", aCI2.GetOriginal() );
1141 AddParam( theParams, "Union faces", aCI2.GetOptimumNbFaces() == 0);
1143 case BLOCK_COMPOUND_IMPROVE:
1144 theOperationName = "CHECK_COMPOUND";
1145 AddParam( theParams, "Selected shape", aCI2.GetOriginal() );
1147 case BLOCK_MULTI_TRANSFORM_1D:
1148 theOperationName = "MUL_TRANSFORM";
1149 AddParam( theParams, "Main Object", aCI2.GetOriginal() );
1150 AddParam( theParams, "Face 1", aCI2.GetFace1U() );
1151 AddParam( theParams, "Face 2", aCI2.GetFace2U() );
1152 AddParam( theParams, "Nb. Times", aCI2.GetNbIterU() );
1154 case BLOCK_MULTI_TRANSFORM_2D:
1155 theOperationName = "MUL_TRANSFORM";
1156 AddParam( theParams, "Main Object", aCI2.GetOriginal() );
1157 AddParam( theParams, "Face 1 U", aCI2.GetFace1U() );
1158 AddParam( theParams, "Face 2 U", aCI2.GetFace2U() );
1159 AddParam( theParams, "Nb. Times V", aCI2.GetNbIterV() );
1160 AddParam( theParams, "Face 1 V", aCI2.GetFace1V() );
1161 AddParam( theParams, "Face 2 V", aCI2.GetFace2V() );
1162 AddParam( theParams, "Nb. Times V", aCI2.GetNbIterV() );
1164 case BLOCK_UNION_FACES:
1165 theOperationName = "UNION_FACES";
1166 AddParam( theParams, "Selected shape", aCI2.GetOriginal() );
1175 IMPLEMENT_STANDARD_RTTIEXT (GEOMImpl_BlockDriver,GEOM_BaseDriver)