1 // Copyright (C) 2007-2010 CEA/DEN, EDF R&D, 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.
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
24 #pragma warning( disable:4786 )
27 #include <Standard_Stream.hxx>
29 #include <GEOMImpl_IBlocksOperations.hxx>
31 #include <GEOMImpl_Types.hxx>
33 #include <GEOMImpl_BlockDriver.hxx>
34 #include <GEOMImpl_IBlocks.hxx>
35 #include <GEOMImpl_IBlockTrsf.hxx>
36 #include <GEOMImpl_CopyDriver.hxx>
37 #include <GEOMImpl_Block6Explorer.hxx>
39 #include <GEOM_Function.hxx>
40 #include <GEOM_PythonDump.hxx>
42 #include <GEOMAlgo_GlueAnalyser.hxx>
43 #include <GEOMAlgo_CoupleOfShapes.hxx>
44 #include <GEOMAlgo_ListOfCoupleOfShapes.hxx>
45 #include <GEOMAlgo_ListIteratorOfListOfCoupleOfShapes.hxx>
46 #include <BlockFix_CheckTool.hxx>
48 #include "utilities.h"
50 #include <Utils_ExceptHandlers.hxx>
52 #include <TFunction_DriverTable.hxx>
53 #include <TFunction_Driver.hxx>
54 #include <TFunction_Logbook.hxx>
55 #include <TDataStd_Integer.hxx>
56 #include <TDF_Tool.hxx>
58 #include <BRep_Tool.hxx>
59 #include <BRep_Builder.hxx>
60 #include <BRepTools.hxx>
61 #include <BRepTools_WireExplorer.hxx>
62 #include <BRepGProp.hxx>
63 #include <BRepBndLib.hxx>
64 #include <BRepAdaptor_Surface.hxx>
65 #include <BRepClass_FaceClassifier.hxx>
66 #include <BRepClass3d_SolidClassifier.hxx>
67 #include <BRepExtrema_DistShapeShape.hxx>
71 #include <TopoDS_Edge.hxx>
72 #include <TopoDS_Vertex.hxx>
73 #include <TopoDS_Compound.hxx>
74 #include <TopoDS_Iterator.hxx>
76 #include <TopExp_Explorer.hxx>
77 #include <TopTools_MapOfShape.hxx>
78 #include <TopTools_Array1OfShape.hxx>
79 #include <TopTools_IndexedMapOfShape.hxx>
80 #include <TopTools_DataMapOfShapeInteger.hxx>
81 #include <TopTools_ListIteratorOfListOfShape.hxx>
82 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
83 #include <TopTools_DataMapIteratorOfDataMapOfShapeInteger.hxx>
85 #include <Bnd_Box.hxx>
86 #include <GProp_GProps.hxx>
88 #include <Geom_Surface.hxx>
89 #include <ShapeAnalysis_Surface.hxx>
91 #include <TColStd_MapOfInteger.hxx>
92 #include <TColStd_Array1OfReal.hxx>
93 #include <TColStd_Array1OfInteger.hxx>
94 #include <TColStd_Array2OfInteger.hxx>
96 //#include <OSD_Timer.hxx>
98 #include <Precision.hxx>
100 #include <Standard_Failure.hxx>
101 #include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC
103 //=============================================================================
107 //=============================================================================
108 GEOMImpl_IBlocksOperations::GEOMImpl_IBlocksOperations (GEOM_Engine* theEngine, int theDocID)
109 : GEOM_IOperations(theEngine, theDocID)
111 MESSAGE("GEOMImpl_IBlocksOperations::GEOMImpl_IBlocksOperations");
114 //=============================================================================
118 //=============================================================================
119 GEOMImpl_IBlocksOperations::~GEOMImpl_IBlocksOperations()
121 MESSAGE("GEOMImpl_IBlocksOperations::~GEOMImpl_IBlocksOperations");
125 //=============================================================================
129 //=============================================================================
130 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuad
131 (Handle(GEOM_Object) theEdge1, Handle(GEOM_Object) theEdge2,
132 Handle(GEOM_Object) theEdge3, Handle(GEOM_Object) theEdge4)
136 if (theEdge1.IsNull() || theEdge2.IsNull() ||
137 theEdge3.IsNull() || theEdge4.IsNull()) return NULL;
139 //Add a new Face object
140 Handle(GEOM_Object) aFace = GetEngine()->AddObject(GetDocID(), GEOM_FACE);
142 //Add a new Face function
143 Handle(GEOM_Function) aFunction =
144 aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_FOUR_EDGES);
146 //Check if the function is set correctly
147 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
149 GEOMImpl_IBlocks aPI (aFunction);
151 Handle(GEOM_Function) aRef1 = theEdge1->GetLastFunction();
152 Handle(GEOM_Function) aRef2 = theEdge2->GetLastFunction();
153 Handle(GEOM_Function) aRef3 = theEdge3->GetLastFunction();
154 Handle(GEOM_Function) aRef4 = theEdge4->GetLastFunction();
155 if (aRef1.IsNull() || aRef2.IsNull() ||
156 aRef3.IsNull() || aRef4.IsNull()) return NULL;
158 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
159 aShapesSeq->Append(aRef1);
160 aShapesSeq->Append(aRef2);
161 aShapesSeq->Append(aRef3);
162 aShapesSeq->Append(aRef4);
164 aPI.SetShapes(aShapesSeq);
166 //Compute the Face value
168 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
171 if (!GetSolver()->ComputeFunction(aFunction)) {
172 SetErrorCode("Block driver failed to compute a face");
176 catch (Standard_Failure) {
177 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
178 SetErrorCode(aFail->GetMessageString());
182 //Make a Python command
183 GEOM::TPythonDump(aFunction) << aFace << " = geompy.MakeQuad("
184 << theEdge1 << ", " << theEdge2 << ", " << theEdge3 << ", " << theEdge4 << ")";
190 //=============================================================================
194 //=============================================================================
195 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuad2Edges
196 (Handle(GEOM_Object) theEdge1, Handle(GEOM_Object) theEdge2)
200 if (theEdge1.IsNull() || theEdge2.IsNull()) return NULL;
202 //Add a new Face object
203 Handle(GEOM_Object) aFace = GetEngine()->AddObject(GetDocID(), GEOM_FACE);
205 //Add a new Face function
206 Handle(GEOM_Function) aFunction =
207 aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_TWO_EDGES);
209 //Check if the function is set correctly
210 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
212 GEOMImpl_IBlocks aPI (aFunction);
214 Handle(GEOM_Function) aRef1 = theEdge1->GetLastFunction();
215 Handle(GEOM_Function) aRef2 = theEdge2->GetLastFunction();
216 if (aRef1.IsNull() || aRef2.IsNull()) return NULL;
218 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
219 aShapesSeq->Append(aRef1);
220 aShapesSeq->Append(aRef2);
222 aPI.SetShapes(aShapesSeq);
224 //Compute the Face value
226 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
229 if (!GetSolver()->ComputeFunction(aFunction)) {
230 SetErrorCode("Block driver failed to compute a face");
234 catch (Standard_Failure) {
235 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
236 SetErrorCode(aFail->GetMessageString());
240 //Make a Python command
241 GEOM::TPythonDump(aFunction) << aFace << " = geompy.MakeQuad2Edges("
242 << theEdge1 << ", " << theEdge2 << ")";
248 //=============================================================================
252 //=============================================================================
253 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuad4Vertices
254 (Handle(GEOM_Object) thePnt1, Handle(GEOM_Object) thePnt2,
255 Handle(GEOM_Object) thePnt3, Handle(GEOM_Object) thePnt4)
259 if (thePnt1.IsNull() || thePnt2.IsNull() ||
260 thePnt3.IsNull() || thePnt4.IsNull()) return NULL;
262 //Add a new Face object
263 Handle(GEOM_Object) aFace = GetEngine()->AddObject(GetDocID(), GEOM_FACE);
265 //Add a new Face function
266 Handle(GEOM_Function) aFunction =
267 aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_FOUR_PNT);
269 //Check if the function is set correctly
270 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
272 GEOMImpl_IBlocks aPI (aFunction);
274 Handle(GEOM_Function) aRef1 = thePnt1->GetLastFunction();
275 Handle(GEOM_Function) aRef2 = thePnt2->GetLastFunction();
276 Handle(GEOM_Function) aRef3 = thePnt3->GetLastFunction();
277 Handle(GEOM_Function) aRef4 = thePnt4->GetLastFunction();
278 if (aRef1.IsNull() || aRef2.IsNull() ||
279 aRef3.IsNull() || aRef4.IsNull()) return NULL;
281 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
282 aShapesSeq->Append(aRef1);
283 aShapesSeq->Append(aRef2);
284 aShapesSeq->Append(aRef3);
285 aShapesSeq->Append(aRef4);
287 aPI.SetShapes(aShapesSeq);
289 //Compute the Face value
291 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
294 if (!GetSolver()->ComputeFunction(aFunction)) {
295 SetErrorCode("Block driver failed to compute a face");
299 catch (Standard_Failure) {
300 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
301 SetErrorCode(aFail->GetMessageString());
305 //Make a Python command
306 GEOM::TPythonDump(aFunction) << aFace << " = geompy.MakeQuad4Vertices("
307 << thePnt1 << ", " << thePnt2 << ", " << thePnt3 << ", " << thePnt4 << ")";
313 //=============================================================================
317 //=============================================================================
318 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeHexa
319 (Handle(GEOM_Object) theFace1, Handle(GEOM_Object) theFace2,
320 Handle(GEOM_Object) theFace3, Handle(GEOM_Object) theFace4,
321 Handle(GEOM_Object) theFace5, Handle(GEOM_Object) theFace6)
325 if (theFace1.IsNull() || theFace2.IsNull() ||
326 theFace3.IsNull() || theFace4.IsNull() ||
327 theFace5.IsNull() || theFace6.IsNull()) return NULL;
329 //Add a new Solid object
330 Handle(GEOM_Object) aBlock = GetEngine()->AddObject(GetDocID(), GEOM_BLOCK);
332 //Add a new Block function
333 Handle(GEOM_Function) aFunction =
334 aBlock->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_SIX_FACES);
336 //Check if the function is set correctly
337 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
339 GEOMImpl_IBlocks aPI (aFunction);
341 Handle(GEOM_Function) aRef1 = theFace1->GetLastFunction();
342 Handle(GEOM_Function) aRef2 = theFace2->GetLastFunction();
343 Handle(GEOM_Function) aRef3 = theFace3->GetLastFunction();
344 Handle(GEOM_Function) aRef4 = theFace4->GetLastFunction();
345 Handle(GEOM_Function) aRef5 = theFace5->GetLastFunction();
346 Handle(GEOM_Function) aRef6 = theFace6->GetLastFunction();
347 if (aRef1.IsNull() || aRef2.IsNull() ||
348 aRef3.IsNull() || aRef4.IsNull() ||
349 aRef5.IsNull() || aRef6.IsNull()) return NULL;
351 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
352 aShapesSeq->Append(aRef1);
353 aShapesSeq->Append(aRef2);
354 aShapesSeq->Append(aRef3);
355 aShapesSeq->Append(aRef4);
356 aShapesSeq->Append(aRef5);
357 aShapesSeq->Append(aRef6);
359 aPI.SetShapes(aShapesSeq);
361 //Compute the Block value
363 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
366 if (!GetSolver()->ComputeFunction(aFunction)) {
367 SetErrorCode("Block driver failed to compute a block");
371 catch (Standard_Failure) {
372 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
373 SetErrorCode(aFail->GetMessageString());
377 //Make a Python command
378 GEOM::TPythonDump(aFunction) << aBlock << " = geompy.MakeHexa("
379 << theFace1 << ", " << theFace2 << ", " << theFace3 << ", "
380 << theFace4 << ", " << theFace5 << ", " << theFace6 << ")";
386 //=============================================================================
390 //=============================================================================
391 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeHexa2Faces
392 (Handle(GEOM_Object) theFace1, Handle(GEOM_Object) theFace2)
396 if (theFace1.IsNull() || theFace2.IsNull()) return NULL;
398 //Add a new Solid object
399 Handle(GEOM_Object) aBlock = GetEngine()->AddObject(GetDocID(), GEOM_BLOCK);
401 //Add a new Block function
402 Handle(GEOM_Function) aFunction =
403 aBlock->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_TWO_FACES);
405 //Check if the function is set correctly
406 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
408 GEOMImpl_IBlocks aPI (aFunction);
410 Handle(GEOM_Function) aRef1 = theFace1->GetLastFunction();
411 Handle(GEOM_Function) aRef2 = theFace2->GetLastFunction();
412 if (aRef1.IsNull() || aRef2.IsNull()) return NULL;
414 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
415 aShapesSeq->Append(aRef1);
416 aShapesSeq->Append(aRef2);
418 aPI.SetShapes(aShapesSeq);
420 //Compute the Block value
422 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
425 if (!GetSolver()->ComputeFunction(aFunction)) {
426 SetErrorCode("Block driver failed to compute a block");
430 catch (Standard_Failure) {
431 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
432 SetErrorCode(aFail->GetMessageString());
436 //Make a Python command
437 GEOM::TPythonDump(aFunction) << aBlock << " = geompy.MakeHexa2Faces("
438 << theFace1 << ", " << theFace2 << ")";
444 //=============================================================================
448 //=============================================================================
449 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeBlockCompound
450 (Handle(GEOM_Object) theCompound)
454 if (theCompound.IsNull()) return NULL;
457 Handle(GEOM_Object) aBlockComp = GetEngine()->AddObject(GetDocID(), GEOM_COMPOUND);
459 //Add a new BlocksComp function
460 Handle(GEOM_Function) aFunction =
461 aBlockComp->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_COMPOUND_GLUE);
463 //Check if the function is set correctly
464 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
466 GEOMImpl_IBlocks aPI (aFunction);
468 Handle(GEOM_Function) aRef1 = theCompound->GetLastFunction();
469 if (aRef1.IsNull()) return NULL;
471 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
472 aShapesSeq->Append(aRef1);
474 aPI.SetShapes(aShapesSeq);
476 //Compute the Blocks Compound value
478 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
481 if (!GetSolver()->ComputeFunction(aFunction)) {
482 SetErrorCode("Block driver failed to compute a blocks compound");
486 catch (Standard_Failure) {
487 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
488 SetErrorCode(aFail->GetMessageString());
492 //Make a Python command
493 GEOM::TPythonDump(aFunction) << aBlockComp
494 << " = geompy.MakeBlockCompound(" << theCompound << ")";
500 //=============================================================================
504 //=============================================================================
505 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetPoint
506 (Handle(GEOM_Object) theShape,
507 const Standard_Real theX,
508 const Standard_Real theY,
509 const Standard_Real theZ,
510 const Standard_Real theEpsilon)
515 Handle(GEOM_Object) aResult;
518 if (theShape.IsNull()) return NULL;
520 TopoDS_Shape aBlockOrComp = theShape->GetValue();
521 if (aBlockOrComp.IsNull()) {
522 SetErrorCode("Given shape is null");
526 //Compute the Vertex value
527 gp_Pnt P (theX, theY, theZ);
528 Standard_Real eps = Max(theEpsilon, Precision::Confusion());
531 Standard_Integer isFound = 0;
532 TopTools_MapOfShape mapShape;
533 TopExp_Explorer exp (aBlockOrComp, TopAbs_VERTEX);
535 for (; exp.More(); exp.Next()) {
536 if (mapShape.Add(exp.Current())) {
537 TopoDS_Vertex aVi = TopoDS::Vertex(exp.Current());
538 gp_Pnt aPi = BRep_Tool::Pnt(aVi);
539 if (aPi.Distance(P) < eps) {
547 SetErrorCode("Vertex has not been found");
549 } else if (isFound > 1) {
550 SetErrorCode("Multiple vertices found by the given coordinates and epsilon");
553 TopTools_IndexedMapOfShape anIndices;
554 TopExp::MapShapes(aBlockOrComp, anIndices);
555 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
556 anArray->SetValue(1, anIndices.FindIndex(V));
557 aResult = GetEngine()->AddSubShape(theShape, anArray);
560 //The GetPoint() doesn't change object so no new function is required.
561 Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
563 //Make a Python command
564 GEOM::TPythonDump(aFunction, /*append=*/true)
565 << aResult << " = geompy.GetPoint(" << theShape << ", "
566 << theX << ", " << theY << ", " << theZ << ", " << theEpsilon << ")";
572 //=============================================================================
576 //=============================================================================
577 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetEdge
578 (Handle(GEOM_Object) theShape,
579 Handle(GEOM_Object) thePoint1,
580 Handle(GEOM_Object) thePoint2)
585 Handle(GEOM_Object) aResult;
588 if (theShape.IsNull() || thePoint1.IsNull() || thePoint2.IsNull()) return NULL;
590 TopoDS_Shape aBlockOrComp = theShape->GetValue();
591 if (aBlockOrComp.IsNull()) {
592 SetErrorCode("Given shape is null");
596 TopoDS_Shape anArg1 = thePoint1->GetValue();
597 TopoDS_Shape anArg2 = thePoint2->GetValue();
598 if (anArg1.IsNull() || anArg2.IsNull()) {
599 SetErrorCode("Null shape is given as argument");
602 if (anArg1.ShapeType() != TopAbs_VERTEX ||
603 anArg2.ShapeType() != TopAbs_VERTEX) {
604 SetErrorCode("Element for edge identification is not a vertex");
608 //Compute the Edge value
610 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
613 TopTools_IndexedDataMapOfShapeListOfShape MVE;
614 GEOMImpl_Block6Explorer::MapShapesAndAncestors
615 (aBlockOrComp, TopAbs_VERTEX, TopAbs_EDGE, MVE);
618 Standard_Integer ish, ext = MVE.Extent();
620 if (MVE.Contains(anArg1)) {
623 for (ish = 1; ish <= ext; ish++) {
624 TopoDS_Shape aShi = MVE.FindKey(ish);
625 if (BRepTools::Compare(TopoDS::Vertex(anArg1), TopoDS::Vertex(aShi))) {
632 if (MVE.Contains(anArg2)) {
635 for (ish = 1; ish <= ext; ish++) {
636 TopoDS_Shape aShi = MVE.FindKey(ish);
637 if (BRepTools::Compare(TopoDS::Vertex(anArg2), TopoDS::Vertex(aShi))) {
644 if (V1.IsNull() || V2.IsNull()) {
645 SetErrorCode("The given vertex does not belong to the shape");
650 Standard_Integer isFound =
651 GEOMImpl_Block6Explorer::FindEdge(anEdge, V1, V2, MVE, Standard_True);
653 SetErrorCode("The given vertices do not belong to one edge of the given shape");
655 } else if (isFound > 1) {
656 SetErrorCode("Multiple edges found by the given vertices of the shape");
659 TopTools_IndexedMapOfShape anIndices;
660 TopExp::MapShapes(aBlockOrComp, anIndices);
661 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
662 anArray->SetValue(1, anIndices.FindIndex(anEdge));
663 aResult = GetEngine()->AddSubShape(theShape, anArray);
665 } catch (Standard_Failure) {
666 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
667 SetErrorCode(aFail->GetMessageString());
671 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
673 //Make a Python command
674 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetEdge("
675 << theShape << ", " << thePoint1 << ", " << thePoint2 << ")";
681 //=============================================================================
685 //=============================================================================
686 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetEdgeNearPoint
687 (Handle(GEOM_Object) theShape,
688 Handle(GEOM_Object) thePoint)
693 Handle(GEOM_Object) aResult;
696 if (theShape.IsNull() || thePoint.IsNull()) return NULL;
698 TopoDS_Shape aBlockOrComp = theShape->GetValue();
699 if (aBlockOrComp.IsNull()) {
700 SetErrorCode("Given shape is null");
704 TopoDS_Shape anArg = thePoint->GetValue();
705 if (anArg.IsNull()) {
706 SetErrorCode("Null shape is given as argument");
709 if (anArg.ShapeType() != TopAbs_VERTEX) {
710 SetErrorCode("Element for edge identification is not a vertex");
714 //Compute the Edge value
716 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
721 TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
723 // 1. Explode blocks on edges
724 TopTools_MapOfShape mapShape;
725 Standard_Integer nbEdges = 0;
726 TopExp_Explorer exp (aBlockOrComp, TopAbs_EDGE);
727 for (; exp.More(); exp.Next()) {
728 if (mapShape.Add(exp.Current())) {
734 SetErrorCode("Given shape contains no edges");
739 Standard_Integer ind = 1;
740 TopTools_Array1OfShape anEdges (1, nbEdges);
741 TColStd_Array1OfReal aDistances (1, nbEdges);
742 for (exp.Init(aBlockOrComp, TopAbs_EDGE); exp.More(); exp.Next()) {
743 if (mapShape.Add(exp.Current())) {
744 TopoDS_Shape anEdge = exp.Current();
745 anEdges(ind) = anEdge;
747 // 2. Classify the point relatively each edge
748 BRepExtrema_DistShapeShape aDistTool (aVert, anEdges(ind));
749 if (!aDistTool.IsDone()) {
750 SetErrorCode("Can not find a distance from the given point to one of edges");
753 aDistances(ind) = aDistTool.Value();
758 // 3. Define edge, having minimum distance to the point
759 Standard_Real nearest = RealLast(), nbFound = 0;
760 Standard_Real prec = Precision::Confusion();
761 for (ind = 1; ind <= nbEdges; ind++) {
762 if (Abs(aDistances(ind) - nearest) < prec) {
764 } else if (aDistances(ind) < nearest) {
765 nearest = aDistances(ind);
766 aShape = anEdges(ind);
772 SetErrorCode("Multiple edges near the given point are found");
774 } else if (nbFound == 0) {
775 SetErrorCode("There are no edges near the given point");
778 TopTools_IndexedMapOfShape anIndices;
779 TopExp::MapShapes(aBlockOrComp, anIndices);
780 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
781 anArray->SetValue(1, anIndices.FindIndex(aShape));
782 aResult = GetEngine()->AddSubShape(theShape, anArray);
785 catch (Standard_Failure) {
786 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
787 SetErrorCode(aFail->GetMessageString());
791 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
793 //Make a Python command
794 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetEdgeNearPoint("
795 << theShape << ", " << thePoint << ")";
801 //=============================================================================
805 //=============================================================================
806 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByPoints
807 (Handle(GEOM_Object) theShape,
808 Handle(GEOM_Object) thePoint1,
809 Handle(GEOM_Object) thePoint2,
810 Handle(GEOM_Object) thePoint3,
811 Handle(GEOM_Object) thePoint4)
816 Handle(GEOM_Object) aResult;
819 if (theShape.IsNull() ||
820 thePoint1.IsNull() || thePoint2.IsNull() ||
821 thePoint3.IsNull() || thePoint4.IsNull()) return NULL;
823 TopoDS_Shape aBlockOrComp = theShape->GetValue();
824 if (aBlockOrComp.IsNull()) {
825 SetErrorCode("Block or compound is null");
829 TopoDS_Shape anArg1 = thePoint1->GetValue();
830 TopoDS_Shape anArg2 = thePoint2->GetValue();
831 TopoDS_Shape anArg3 = thePoint3->GetValue();
832 TopoDS_Shape anArg4 = thePoint4->GetValue();
833 if (anArg1.IsNull() || anArg2.IsNull() ||
834 anArg3.IsNull() || anArg4.IsNull()) {
835 SetErrorCode("Null shape is given as argument");
838 if (anArg1.ShapeType() != TopAbs_VERTEX ||
839 anArg2.ShapeType() != TopAbs_VERTEX ||
840 anArg3.ShapeType() != TopAbs_VERTEX ||
841 anArg4.ShapeType() != TopAbs_VERTEX) {
842 SetErrorCode("Element for face identification is not a vertex");
846 //Compute the Face value
848 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
853 TopTools_IndexedDataMapOfShapeListOfShape MVF;
854 GEOMImpl_Block6Explorer::MapShapesAndAncestors(aBlockOrComp, TopAbs_VERTEX, TopAbs_FACE, MVF);
856 TopoDS_Shape V1,V2,V3,V4;
857 Standard_Integer ish, ext = MVF.Extent();
859 if (MVF.Contains(anArg1)) {
862 for (ish = 1; ish <= ext; ish++) {
863 TopoDS_Shape aShi = MVF.FindKey(ish);
864 if (BRepTools::Compare(TopoDS::Vertex(anArg1), TopoDS::Vertex(aShi))) {
871 if (MVF.Contains(anArg2)) {
874 for (ish = 1; ish <= ext; ish++) {
875 TopoDS_Shape aShi = MVF.FindKey(ish);
876 if (BRepTools::Compare(TopoDS::Vertex(anArg2), TopoDS::Vertex(aShi))) {
883 if (MVF.Contains(anArg3)) {
886 for (ish = 1; ish <= ext; ish++) {
887 TopoDS_Shape aShi = MVF.FindKey(ish);
888 if (BRepTools::Compare(TopoDS::Vertex(anArg3), TopoDS::Vertex(aShi))) {
895 if (MVF.Contains(anArg4)) {
898 for (ish = 1; ish <= ext; ish++) {
899 TopoDS_Shape aShi = MVF.FindKey(ish);
900 if (BRepTools::Compare(TopoDS::Vertex(anArg4), TopoDS::Vertex(aShi))) {
907 if (V1.IsNull() || V2.IsNull() || V3.IsNull() || V4.IsNull()) {
908 SetErrorCode("The given vertex does not belong to the shape");
912 Standard_Integer isFound =
913 GEOMImpl_Block6Explorer::FindFace(aShape, V1, V2, V3, V4, MVF, Standard_True);
915 SetErrorCode("The given vertices do not belong to one face of the given shape");
917 } else if (isFound > 1) {
918 SetErrorCode("The given vertices belong to several faces of the given shape");
921 TopTools_IndexedMapOfShape anIndices;
922 TopExp::MapShapes(aBlockOrComp, anIndices);
923 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
924 anArray->SetValue(1, anIndices.FindIndex(aShape));
925 aResult = GetEngine()->AddSubShape(theShape, anArray);
928 catch (Standard_Failure) {
929 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
930 SetErrorCode(aFail->GetMessageString());
934 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
936 //Make a Python command
937 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceByPoints("
938 << theShape << ", " << thePoint1 << ", " << thePoint2
939 << ", " << thePoint3 << ", " << thePoint4 << ")";
945 //=============================================================================
949 //=============================================================================
950 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByEdges
951 (Handle(GEOM_Object) theShape,
952 Handle(GEOM_Object) theEdge1,
953 Handle(GEOM_Object) theEdge2)
958 Handle(GEOM_Object) aResult;
961 if (theShape.IsNull() || theEdge1.IsNull() || theEdge2.IsNull()) return NULL;
963 TopoDS_Shape aBlockOrComp = theShape->GetValue();
964 if (aBlockOrComp.IsNull()) {
965 SetErrorCode("Block or compound is null");
969 TopoDS_Shape anArg1 = theEdge1->GetValue();
970 TopoDS_Shape anArg2 = theEdge2->GetValue();
971 if (anArg1.IsNull() || anArg2.IsNull()) {
972 SetErrorCode("Null shape is given as argument");
975 if (anArg1.ShapeType() != TopAbs_EDGE ||
976 anArg2.ShapeType() != TopAbs_EDGE) {
977 SetErrorCode("Element for face identification is not an edge");
981 //Compute the Face value
983 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
988 TopTools_IndexedDataMapOfShapeListOfShape MEF;
989 GEOMImpl_Block6Explorer::MapShapesAndAncestors(aBlockOrComp, TopAbs_EDGE, TopAbs_FACE, MEF);
992 Standard_Integer ish, ext = MEF.Extent();
994 if (MEF.Contains(anArg1)) {
997 for (ish = 1; ish <= ext; ish++) {
998 TopoDS_Shape aShi = MEF.FindKey(ish);
999 if (GEOMImpl_Block6Explorer::IsSimilarEdges(anArg1, aShi)) {
1005 if (MEF.Contains(anArg2)) {
1008 for (ish = 1; ish <= ext; ish++) {
1009 TopoDS_Shape aShi = MEF.FindKey(ish);
1010 if (GEOMImpl_Block6Explorer::IsSimilarEdges(anArg2, aShi)) {
1016 if (E1.IsNull() || E2.IsNull()) {
1017 SetErrorCode("The given edge does not belong to the shape");
1021 const TopTools_ListOfShape& aFacesOfE1 = MEF.FindFromKey(E1);
1022 const TopTools_ListOfShape& aFacesOfE2 = MEF.FindFromKey(E2);
1024 Standard_Integer isFound = 0;
1025 TopTools_ListIteratorOfListOfShape anIterF1 (aFacesOfE1);
1026 for (; anIterF1.More(); anIterF1.Next()) {
1028 TopTools_ListIteratorOfListOfShape anIterF2 (aFacesOfE2);
1029 for (; anIterF2.More(); anIterF2.Next()) {
1031 if (anIterF1.Value().IsSame(anIterF2.Value())) {
1034 // Store the face, defined by two edges
1035 aShape = anIterF1.Value();
1040 SetErrorCode("The given edges do not belong to one face of the given shape");
1042 } else if (isFound > 1) {
1043 SetErrorCode("The given edges belong to several faces of the given shape");
1046 TopTools_IndexedMapOfShape anIndices;
1047 TopExp::MapShapes(aBlockOrComp, anIndices);
1048 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1049 anArray->SetValue(1, anIndices.FindIndex(aShape));
1050 aResult = GetEngine()->AddSubShape(theShape, anArray);
1053 catch (Standard_Failure) {
1054 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1055 SetErrorCode(aFail->GetMessageString());
1059 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1061 //Make a Python command
1062 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceByEdges("
1063 << theShape << ", " << theEdge1 << ", " << theEdge2 << ")";
1069 //=============================================================================
1073 //=============================================================================
1074 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetOppositeFace
1075 (Handle(GEOM_Object) theShape,
1076 Handle(GEOM_Object) theFace)
1081 Handle(GEOM_Object) aResult;
1084 if (theShape.IsNull() || theFace.IsNull()) return NULL;
1086 TopoDS_Shape aBlockOrComp = theShape->GetValue();
1087 if (aBlockOrComp.IsNull()) {
1088 SetErrorCode("Block is null");
1091 if (aBlockOrComp.ShapeType() != TopAbs_SOLID) {
1092 SetErrorCode("Shape is not a block");
1096 TopoDS_Shape anArg = theFace->GetValue();
1097 if (anArg.IsNull()) {
1098 SetErrorCode("Null shape is given as argument");
1101 if (anArg.ShapeType() != TopAbs_FACE) {
1102 SetErrorCode("Element for face identification is not a face");
1106 //Compute the Face value
1108 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
1111 TopoDS_Shape aShape;
1113 GEOMImpl_Block6Explorer aBlockTool;
1114 aBlockTool.InitByBlockAndFace(aBlockOrComp, anArg);
1115 aShape = aBlockTool.GetFace(2);
1117 TopTools_IndexedMapOfShape anIndices;
1118 TopExp::MapShapes(aBlockOrComp, anIndices);
1119 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1120 anArray->SetValue(1, anIndices.FindIndex(aShape));
1121 aResult = GetEngine()->AddSubShape(theShape, anArray);
1123 catch (Standard_Failure) {
1124 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1125 SetErrorCode(aFail->GetMessageString());
1129 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1131 //Make a Python command
1132 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetOppositeFace("
1133 << theShape << ", " << theFace << ")";
1139 //=============================================================================
1143 //=============================================================================
1144 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceNearPoint
1145 (Handle(GEOM_Object) theShape,
1146 Handle(GEOM_Object) thePoint)
1151 Handle(GEOM_Object) aResult;
1154 if (theShape.IsNull() || thePoint.IsNull()) return NULL;
1156 TopoDS_Shape aBlockOrComp = theShape->GetValue();
1157 if (aBlockOrComp.IsNull()) {
1158 SetErrorCode("Block or compound is null");
1162 TopoDS_Shape anArg = thePoint->GetValue();
1163 if (anArg.IsNull()) {
1164 SetErrorCode("Null shape is given as argument");
1167 if (anArg.ShapeType() != TopAbs_VERTEX) {
1168 SetErrorCode("Element for face identification is not a vertex");
1172 //Compute the Face value
1174 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
1177 TopoDS_Shape aShape;
1179 TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
1180 gp_Pnt aPnt = BRep_Tool::Pnt(aVert);
1181 Standard_Real PX, PY, PZ;
1182 aPnt.Coord(PX, PY, PZ);
1184 // 1. Classify the point relatively each face
1185 Standard_Integer nearest = 2, nbFound = 0;
1186 TopTools_DataMapOfShapeInteger mapShapeDist;
1187 TopExp_Explorer exp (aBlockOrComp, TopAbs_FACE);
1188 for (; exp.More(); exp.Next()) {
1189 TopoDS_Shape aFace = exp.Current();
1191 if (!mapShapeDist.IsBound(aFace)) {
1192 Standard_Integer aDistance = 2;
1194 // 1.a. Classify relatively Surface
1195 Handle(Geom_Surface) aSurf = BRep_Tool::Surface(TopoDS::Face(aFace));
1196 Handle(ShapeAnalysis_Surface) aSurfAna = new ShapeAnalysis_Surface (aSurf);
1197 gp_Pnt2d p2dOnSurf = aSurfAna->ValueOfUV(aPnt, Precision::Confusion());
1198 gp_Pnt p3dOnSurf = aSurfAna->Value(p2dOnSurf);
1199 Standard_Real aDist = p3dOnSurf.Distance(aPnt);
1200 if (aDist > Precision::Confusion()) {
1204 // 1.b. Classify relatively the face itself
1205 BRepClass_FaceClassifier FC (TopoDS::Face(aFace), p2dOnSurf, Precision::Confusion());
1206 if (FC.State() == TopAbs_IN) {
1208 } else if (FC.State() == TopAbs_ON) {
1215 if (aDistance < nearest) {
1216 nearest = aDistance;
1220 // A first found face, containing the point inside, will be returned.
1221 // It is the solution, if there are no
1222 // coincident or intersecting faces in the compound.
1223 if (nearest == -1) break;
1225 } else if (aDistance == nearest) {
1230 mapShapeDist.Bind(aFace, aDistance);
1231 } // if (!mapShapeDist.IsBound(aFace))
1234 // 2. Define face, containing the point or having minimum distance to it
1237 // The point is on boundary of some faces and there are
1238 // no faces, having the point inside
1239 SetErrorCode("Multiple faces near the given point are found");
1242 } else if (nearest == 1) {
1243 // The point is outside some faces and there are
1244 // no faces, having the point inside or on boundary.
1245 // We will get a nearest face
1246 Standard_Real bigReal = RealLast();
1247 Standard_Real minDist = bigReal;
1248 TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
1249 for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
1250 if (mapShapeDistIter.Value() == 1) {
1251 TopoDS_Shape aFace = mapShapeDistIter.Key();
1252 Standard_Real aDist = bigReal;
1254 // 2.a. Fast check of distance - if point projection on surface is on face
1255 Handle(Geom_Surface) aSurf = BRep_Tool::Surface(TopoDS::Face(aFace));
1256 Handle(ShapeAnalysis_Surface) aSurfAna = new ShapeAnalysis_Surface (aSurf);
1257 gp_Pnt2d p2dOnSurf = aSurfAna->ValueOfUV(aPnt, Precision::Confusion());
1258 gp_Pnt p3dOnSurf = aSurfAna->Value(p2dOnSurf);
1259 aDist = p3dOnSurf.Distance(aPnt);
1261 BRepClass_FaceClassifier FC (TopoDS::Face(aFace), p2dOnSurf, Precision::Confusion());
1262 if (FC.State() == TopAbs_OUT) {
1263 if (aDist < minDist) {
1264 // 2.b. Slow check - if point projection on surface is outside of face
1265 BRepExtrema_DistShapeShape aDistTool (aVert, aFace);
1266 if (!aDistTool.IsDone()) {
1267 SetErrorCode("Can not find a distance from the given point to one of faces");
1270 aDist = aDistTool.Value();
1276 if (aDist < minDist) {
1282 } else { // nearest == -1
1283 // // The point is inside some faces.
1284 // // We will get a face with nearest center
1285 // Standard_Real minDist = RealLast();
1286 // TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
1287 // for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
1288 // if (mapShapeDistIter.Value() == -1) {
1289 // TopoDS_Shape aFace = mapShapeDistIter.Key();
1290 // GProp_GProps aSystem;
1291 // BRepGProp::SurfaceProperties(aFace, aSystem);
1292 // gp_Pnt aCenterMass = aSystem.CentreOfMass();
1294 // Standard_Real aDist = aCenterMass.Distance(aPnt);
1295 // if (aDist < minDist) {
1302 } // if (nbFound > 1)
1305 SetErrorCode("There are no faces near the given point");
1308 TopTools_IndexedMapOfShape anIndices;
1309 TopExp::MapShapes(aBlockOrComp, anIndices);
1310 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1311 anArray->SetValue(1, anIndices.FindIndex(aShape));
1312 aResult = GetEngine()->AddSubShape(theShape, anArray);
1315 catch (Standard_Failure) {
1316 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1317 SetErrorCode(aFail->GetMessageString());
1321 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1323 //Make a Python command
1324 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceNearPoint("
1325 << theShape << ", " << thePoint << ")";
1331 //=============================================================================
1335 //=============================================================================
1336 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByNormale
1337 (Handle(GEOM_Object) theShape,
1338 Handle(GEOM_Object) theVector)
1343 Handle(GEOM_Object) aResult;
1346 if (theShape.IsNull() || theVector.IsNull()) return NULL;
1348 TopoDS_Shape aBlockOrComp = theShape->GetValue();
1349 if (aBlockOrComp.IsNull()) {
1350 SetErrorCode("Block or compound is null");
1354 TopoDS_Shape anArg = theVector->GetValue();
1355 if (anArg.IsNull()) {
1356 SetErrorCode("Null shape is given as argument");
1359 if (anArg.ShapeType() != TopAbs_EDGE) {
1360 SetErrorCode("Element for normale identification is not an edge");
1364 //Compute the Face value
1366 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
1369 TopoDS_Shape aShape;
1371 TopoDS_Edge anEdge = TopoDS::Edge(anArg);
1372 TopoDS_Vertex V1, V2;
1373 TopExp::Vertices(anEdge, V1, V2, Standard_True);
1374 gp_Pnt P1 = BRep_Tool::Pnt(V1);
1375 gp_Pnt P2 = BRep_Tool::Pnt(V2);
1376 gp_Vec aVec (P1, P2);
1377 if (aVec.Magnitude() < Precision::Confusion()) {
1378 SetErrorCode("Vector with null magnitude is given");
1382 Standard_Real minAngle = RealLast();
1383 TopTools_MapOfShape mapShape;
1384 TopExp_Explorer exp (aBlockOrComp, TopAbs_FACE);
1385 for (; exp.More(); exp.Next()) {
1386 if (mapShape.Add(exp.Current())) {
1387 TopoDS_Face aFace = TopoDS::Face(exp.Current());
1388 BRepAdaptor_Surface SF (aFace);
1390 Standard_Real u, v, x;
1392 // find a point on the surface to get normal direction in
1393 u = SF.FirstUParameter();
1394 x = SF.LastUParameter();
1395 if (Precision::IsInfinite(u)) {
1396 u = (Precision::IsInfinite(x)) ? 0. : x;
1397 } else if (!Precision::IsInfinite(x)) {
1401 v = SF.FirstVParameter();
1402 x = SF.LastVParameter();
1403 if (Precision::IsInfinite(v)) {
1404 v = (Precision::IsInfinite(x)) ? 0. : x;
1405 } else if (!Precision::IsInfinite(x)) {
1409 // compute the normal direction
1411 SF.D1(u,v,P1,Vec1,Vec2);
1412 gp_Vec V = Vec1.Crossed(Vec2);
1414 if (V.Magnitude() < Precision::Confusion()) {
1415 SetErrorCode("Normal vector of a face has null magnitude");
1419 // consider the face orientation
1420 if (aFace.Orientation() == TopAbs_REVERSED ||
1421 aFace.Orientation() == TopAbs_INTERNAL) {
1425 // compute the angle and compare with the minimal one
1426 Standard_Real anAngle = aVec.Angle(V);
1427 if (anAngle < minAngle) {
1434 if (aShape.IsNull()) {
1435 SetErrorCode("Failed to find a face by the given normale");
1438 TopTools_IndexedMapOfShape anIndices;
1439 TopExp::MapShapes(aBlockOrComp, anIndices);
1440 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1441 anArray->SetValue(1, anIndices.FindIndex(aShape));
1442 aResult = GetEngine()->AddSubShape(theShape, anArray);
1445 catch (Standard_Failure) {
1446 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1447 SetErrorCode(aFail->GetMessageString());
1451 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1453 //Make a Python command
1454 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceByNormale("
1455 << theShape << ", " << theVector << ")";
1461 //=============================================================================
1463 * IsCompoundOfBlocks
1465 //=============================================================================
1466 Standard_Boolean GEOMImpl_IBlocksOperations::IsCompoundOfBlocks
1467 (Handle(GEOM_Object) theCompound,
1468 const Standard_Integer theMinNbFaces,
1469 const Standard_Integer theMaxNbFaces,
1470 Standard_Integer& theNbBlocks)
1473 Standard_Boolean isCompOfBlocks = Standard_False;
1476 if (theCompound.IsNull()) return isCompOfBlocks;
1477 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
1480 isCompOfBlocks = Standard_True;
1482 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
1485 TopTools_MapOfShape mapShape;
1486 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
1487 for (; exp.More(); exp.Next()) {
1488 if (mapShape.Add(exp.Current())) {
1489 TopoDS_Shape aSolid = exp.Current();
1491 TopTools_MapOfShape mapFaces;
1492 TopExp_Explorer expF (aSolid, TopAbs_FACE);
1493 Standard_Integer nbFaces = 0;
1494 for (; expF.More(); expF.Next()) {
1495 if (mapFaces.Add(expF.Current())) {
1497 if (nbFaces > theMaxNbFaces) {
1498 isCompOfBlocks = Standard_False;
1503 if (nbFaces < theMinNbFaces || theMaxNbFaces < nbFaces) {
1504 isCompOfBlocks = Standard_False;
1511 catch (Standard_Failure) {
1512 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1513 SetErrorCode(aFail->GetMessageString());
1514 return isCompOfBlocks;
1518 return isCompOfBlocks;
1521 //=============================================================================
1523 * Set of functions, used by CheckCompoundOfBlocks() method
1525 //=============================================================================
1526 void GEOMImpl_IBlocksOperations::AddBlocksFrom (const TopoDS_Shape& theShape,
1527 TopTools_ListOfShape& BLO,
1528 TopTools_ListOfShape& NOT,
1529 TopTools_ListOfShape& EXT)
1531 TopAbs_ShapeEnum aType = theShape.ShapeType();
1533 case TopAbs_COMPOUND:
1534 case TopAbs_COMPSOLID:
1536 TopoDS_Iterator It (theShape);
1537 for (; It.More(); It.Next()) {
1538 AddBlocksFrom(It.Value(), BLO, NOT, EXT);
1544 // Check, if there are seam or degenerated edges
1545 BlockFix_CheckTool aTool;
1546 aTool.SetShape(theShape);
1548 if (aTool.NbPossibleBlocks() > 0) {
1549 EXT.Append(theShape);
1551 // Count faces and edges in each face to recognize blocks
1552 TopTools_MapOfShape mapFaces;
1553 Standard_Integer nbFaces = 0;
1554 Standard_Boolean hasNonQuadr = Standard_False;
1555 TopExp_Explorer expF (theShape, TopAbs_FACE);
1557 for (; expF.More(); expF.Next()) {
1558 if (mapFaces.Add(expF.Current())) {
1560 if (nbFaces > 6) break;
1563 TopoDS_Shape aF = expF.Current();
1564 TopExp_Explorer wires (aF, TopAbs_WIRE);
1565 if (!wires.More()) {
1566 // no wire in the face
1567 hasNonQuadr = Standard_True;
1570 TopoDS_Shape aWire = wires.Current();
1573 // multiple wires in the face
1574 hasNonQuadr = Standard_True;
1578 // Check number of edges in the face
1579 Standard_Integer nbEdges = 0;
1580 TopTools_MapOfShape mapEdges;
1581 TopExp_Explorer expW (aWire, TopAbs_EDGE);
1582 for (; expW.More(); expW.Next()) {
1583 if (mapEdges.Add(expW.Current())) {
1585 if (nbEdges > 4) break;
1589 hasNonQuadr = Standard_True;
1594 if (nbFaces == 6 && !hasNonQuadr) {
1595 BLO.Append(theShape);
1597 NOT.Append(theShape);
1603 NOT.Append(theShape);
1607 void AddBlocksFromOld (const TopoDS_Shape& theShape,
1608 TopTools_ListOfShape& BLO,
1609 TopTools_ListOfShape& NOT,
1610 TopTools_ListOfShape& DEG,
1611 TopTools_ListOfShape& SEA)
1613 TopAbs_ShapeEnum aType = theShape.ShapeType();
1615 case TopAbs_COMPOUND:
1616 case TopAbs_COMPSOLID:
1618 TopoDS_Iterator It (theShape);
1619 for (; It.More(); It.Next()) {
1620 AddBlocksFromOld(It.Value(), BLO, NOT, DEG, SEA);
1626 TopTools_MapOfShape mapFaces;
1627 TopExp_Explorer expF (theShape, TopAbs_FACE);
1628 Standard_Integer nbFaces = 0;
1629 Standard_Boolean hasNonQuadr = Standard_False;
1630 Standard_Boolean hasDegenerated = Standard_False;
1631 Standard_Boolean hasSeam = Standard_False;
1632 for (; expF.More(); expF.Next()) {
1633 if (mapFaces.Add(expF.Current())) {
1635 if (nbFaces > 6) break;
1637 // Check number of edges in the face
1638 Standard_Integer nbEdges = 0;
1639 TopTools_MapOfShape mapEdges;
1642 TopoDS_Shape aF = expF.Current();
1643 TopExp_Explorer wires (aF, TopAbs_WIRE);
1644 if (!wires.More()) {
1645 // no wire in the face
1646 hasNonQuadr = Standard_True;
1649 TopoDS_Shape aWire = wires.Current();
1652 // multiple wires in the face
1653 hasNonQuadr = Standard_True;
1658 BRepTools_WireExplorer aWE (TopoDS::Wire(aWire), TopoDS::Face(aF));
1659 for (; aWE.More(); aWE.Next(), nbEdges++) {
1660 if (BRep_Tool::Degenerated(aWE.Current())) {
1661 // degenerated edge found
1662 hasDegenerated = Standard_True;
1665 if (mapEdges.Contains(aWE.Current())) {
1667 hasSeam = Standard_True;
1670 mapEdges.Add(aWE.Current());
1673 hasNonQuadr = Standard_True;
1678 if (hasDegenerated || hasSeam) {
1679 if (hasDegenerated) {
1680 DEG.Append(theShape);
1683 SEA.Append(theShape);
1685 } else if (hasNonQuadr) {
1686 NOT.Append(theShape);
1688 BLO.Append(theShape);
1691 NOT.Append(theShape);
1696 NOT.Append(theShape);
1700 #define REL_NOT_CONNECTED 0
1702 #define REL_NOT_GLUED 2
1703 #define REL_COLLISION_VV 3
1704 #define REL_COLLISION_FF 4
1705 #define REL_COLLISION_EE 5
1706 #define REL_UNKNOWN 6
1708 Standard_Integer BlocksRelation (const TopoDS_Shape& theBlock1,
1709 const TopoDS_Shape& theBlock2)
1711 // Compare bounding boxes before calling BRepExtrema_DistShapeShape
1712 Standard_Real Xmin1, Ymin1, Zmin1, Xmax1, Ymax1, Zmax1;
1713 Standard_Real Xmin2, Ymin2, Zmin2, Xmax2, Ymax2, Zmax2;
1715 BRepBndLib::Add(theBlock1, B1);
1716 BRepBndLib::Add(theBlock2, B2);
1717 B1.Get(Xmin1, Ymin1, Zmin1, Xmax1, Ymax1, Zmax1);
1718 B2.Get(Xmin2, Ymin2, Zmin2, Xmax2, Ymax2, Zmax2);
1719 if (Xmax2 < Xmin1 || Xmax1 < Xmin2 ||
1720 Ymax2 < Ymin1 || Ymax1 < Ymin2 ||
1721 Zmax2 < Zmin1 || Zmax1 < Zmin2) {
1722 return REL_NOT_CONNECTED;
1725 BRepExtrema_DistShapeShape dst (theBlock1, theBlock2);
1726 if (!dst.IsDone()) {
1730 if (dst.Value() > Precision::Confusion()) {
1731 return REL_NOT_CONNECTED;
1734 if (dst.InnerSolution()) {
1735 return REL_COLLISION_VV;
1738 Standard_Integer nbSol = dst.NbSolution();
1739 Standard_Integer relation = REL_OK;
1740 Standard_Integer nbVerts = 0;
1741 Standard_Integer nbEdges = 0;
1742 Standard_Integer sol = 1;
1743 for (; sol <= nbSol; sol++) {
1744 BRepExtrema_SupportType supp1 = dst.SupportTypeShape1(sol);
1745 BRepExtrema_SupportType supp2 = dst.SupportTypeShape2(sol);
1746 if (supp1 == BRepExtrema_IsVertex && supp2 == BRepExtrema_IsVertex) {
1748 } else if (supp1 == BRepExtrema_IsInFace || supp2 == BRepExtrema_IsInFace) {
1749 return REL_COLLISION_FF;
1750 } else if (supp1 == BRepExtrema_IsOnEdge && supp2 == BRepExtrema_IsOnEdge) {
1752 } else if ((supp1 == BRepExtrema_IsOnEdge && supp2 == BRepExtrema_IsVertex) ||
1753 (supp2 == BRepExtrema_IsOnEdge && supp1 == BRepExtrema_IsVertex)) {
1754 relation = REL_COLLISION_EE;
1759 if (relation != REL_OK) {
1763 TColStd_Array1OfInteger vertSol (1, nbVerts);
1764 TopTools_Array1OfShape V1 (1, nbVerts);
1765 TopTools_Array1OfShape V2 (1, nbVerts);
1766 Standard_Integer ivs = 0;
1767 for (sol = 1; sol <= nbSol; sol++) {
1768 if (dst.SupportTypeShape1(sol) == BRepExtrema_IsVertex &&
1769 dst.SupportTypeShape2(sol) == BRepExtrema_IsVertex) {
1770 TopoDS_Vertex Vcur = TopoDS::Vertex(dst.SupportOnShape1(sol));
1771 // Check, that this vertex is far enough from other solution vertices.
1772 Standard_Integer ii = 1;
1773 for (; ii <= ivs; ii++) {
1774 if (BRepTools::Compare(TopoDS::Vertex(V1(ii)), Vcur)) {
1781 V2(ivs) = dst.SupportOnShape2(sol);
1785 // As we deal only with quadrangles,
1786 // 2, 3 or 4 vertex solutions can be found.
1789 return REL_COLLISION_FF;
1791 return REL_NOT_CONNECTED;
1797 // Check sharing of coincident entities.
1798 if (ivs == 2 || ivs == 3) {
1799 // Map vertices and edges of the blocks
1800 TopTools_IndexedDataMapOfShapeListOfShape MVE1, MVE2;
1801 GEOMImpl_Block6Explorer::MapShapesAndAncestors
1802 (theBlock1, TopAbs_VERTEX, TopAbs_EDGE, MVE1);
1803 GEOMImpl_Block6Explorer::MapShapesAndAncestors
1804 (theBlock2, TopAbs_VERTEX, TopAbs_EDGE, MVE2);
1808 TopoDS_Shape anEdge1, anEdge2;
1809 GEOMImpl_Block6Explorer::FindEdge(anEdge1, V1(1), V1(2), MVE1);
1810 if (anEdge1.IsNull()) return REL_UNKNOWN;
1812 GEOMImpl_Block6Explorer::FindEdge(anEdge2, V2(1), V2(2), MVE2);
1813 if (anEdge2.IsNull()) return REL_UNKNOWN;
1815 if (!anEdge1.IsSame(anEdge2)) return REL_NOT_GLUED;
1817 } else { // ivs == 3
1818 // Find common edges
1819 Standard_Integer e1_v1 = 1;
1820 Standard_Integer e1_v2 = 2;
1821 Standard_Integer e2_v1 = 3;
1822 Standard_Integer e2_v2 = 1;
1824 TopoDS_Shape anEdge11, anEdge12;
1825 GEOMImpl_Block6Explorer::FindEdge(anEdge11, V1(e1_v1), V1(e1_v2), MVE1);
1826 if (anEdge11.IsNull()) {
1829 GEOMImpl_Block6Explorer::FindEdge(anEdge11, V1(e1_v1), V1(e1_v2), MVE1);
1830 if (anEdge11.IsNull()) return REL_UNKNOWN;
1832 GEOMImpl_Block6Explorer::FindEdge(anEdge12, V1(e2_v1), V1(e2_v2), MVE1);
1833 if (anEdge12.IsNull()) {
1835 GEOMImpl_Block6Explorer::FindEdge(anEdge12, V1(e2_v1), V1(e2_v2), MVE1);
1836 if (anEdge12.IsNull()) return REL_UNKNOWN;
1839 TopoDS_Shape anEdge21, anEdge22;
1840 GEOMImpl_Block6Explorer::FindEdge(anEdge21, V2(e1_v1), V2(e1_v2), MVE2);
1841 if (anEdge21.IsNull()) return REL_UNKNOWN;
1842 GEOMImpl_Block6Explorer::FindEdge(anEdge22, V2(e2_v1), V2(e2_v2), MVE2);
1843 if (anEdge22.IsNull()) return REL_UNKNOWN;
1845 // Check of edges coincidence (with some precision) have to be done here
1846 // if (!anEdge11.IsEqual(anEdge21)) return REL_UNKNOWN;
1847 // if (!anEdge12.IsEqual(anEdge22)) return REL_UNKNOWN;
1849 // Check of edges sharing
1850 if (!anEdge11.IsSame(anEdge21)) return REL_NOT_GLUED;
1851 if (!anEdge12.IsSame(anEdge22)) return REL_NOT_GLUED;
1856 // Map vertices and faces of the blocks
1857 TopTools_IndexedDataMapOfShapeListOfShape MVF1, MVF2;
1858 GEOMImpl_Block6Explorer::MapShapesAndAncestors
1859 (theBlock1, TopAbs_VERTEX, TopAbs_FACE, MVF1);
1860 GEOMImpl_Block6Explorer::MapShapesAndAncestors
1861 (theBlock2, TopAbs_VERTEX, TopAbs_FACE, MVF2);
1863 TopoDS_Shape aFace1, aFace2;
1864 GEOMImpl_Block6Explorer::FindFace(aFace1, V1(1), V1(2), V1(3), V1(4), MVF1);
1865 if (aFace1.IsNull()) return REL_UNKNOWN;
1866 GEOMImpl_Block6Explorer::FindFace(aFace2, V2(1), V2(2), V2(3), V2(4), MVF2);
1867 if (aFace2.IsNull()) return REL_UNKNOWN;
1869 // Check of faces coincidence (with some precision) have to be done here
1870 // if (!aFace1.IsEqual(aFace2)) return REL_UNKNOWN;
1872 // Check of faces sharing
1873 if (!aFace1.IsSame(aFace2)) return REL_NOT_GLUED;
1879 void FindConnected (const Standard_Integer theBlockIndex,
1880 const TColStd_Array2OfInteger& theRelations,
1881 TColStd_MapOfInteger& theProcessedMap,
1882 TColStd_MapOfInteger& theConnectedMap)
1884 theConnectedMap.Add(theBlockIndex);
1885 theProcessedMap.Add(theBlockIndex);
1887 Standard_Integer nbBlocks = theRelations.ColLength();
1888 Standard_Integer col = 1;
1889 for (; col <= nbBlocks; col++) {
1890 if (theRelations(theBlockIndex, col) == REL_OK ||
1891 theRelations(theBlockIndex, col) == REL_NOT_GLUED) {
1892 if (!theProcessedMap.Contains(col)) {
1893 FindConnected(col, theRelations, theProcessedMap, theConnectedMap);
1899 Standard_Boolean HasAnyConnection (const Standard_Integer theBlockIndex,
1900 const TColStd_MapOfInteger& theWith,
1901 const TColStd_Array2OfInteger& theRelations,
1902 TColStd_MapOfInteger& theProcessedMap)
1904 theProcessedMap.Add(theBlockIndex);
1906 Standard_Integer nbBlocks = theRelations.ColLength();
1907 Standard_Integer col = 1;
1908 for (; col <= nbBlocks; col++) {
1909 if (theRelations(theBlockIndex, col) != REL_NOT_CONNECTED) {
1910 if (!theProcessedMap.Contains(col)) {
1911 if (theWith.Contains(col))
1912 return Standard_True;
1913 if (HasAnyConnection(col, theWith, theRelations, theProcessedMap))
1914 return Standard_True;
1919 return Standard_False;
1922 //=============================================================================
1924 * CheckCompoundOfBlocksOld
1926 //=============================================================================
1927 Standard_Boolean GEOMImpl_IBlocksOperations::CheckCompoundOfBlocksOld
1928 (Handle(GEOM_Object) theCompound,
1929 std::list<BCError>& theErrors)
1933 if (theCompound.IsNull()) return Standard_False;
1934 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
1936 Standard_Boolean isCompOfBlocks = Standard_True;
1938 // Map sub-shapes and their indices
1939 TopTools_IndexedMapOfShape anIndices;
1940 TopExp::MapShapes(aBlockOrComp, anIndices);
1942 // 1. Report non-blocks
1943 TopTools_ListOfShape NOT; // Not blocks
1944 TopTools_ListOfShape DEG; // Hexahedral solids, having degenerated edges
1945 TopTools_ListOfShape SEA; // Hexahedral solids, having seam edges
1946 TopTools_ListOfShape BLO; // All blocks from the given compound
1947 AddBlocksFromOld(aBlockOrComp, BLO, NOT, DEG, SEA);
1949 if (NOT.Extent() > 0) {
1950 isCompOfBlocks = Standard_False;
1952 anErr.error = NOT_BLOCK;
1953 TopTools_ListIteratorOfListOfShape it (NOT);
1954 for (; it.More(); it.Next()) {
1955 anErr.incriminated.push_back(anIndices.FindIndex(it.Value()));
1957 theErrors.push_back(anErr);
1960 if (DEG.Extent() > 0 || SEA.Extent() > 0) {
1961 isCompOfBlocks = Standard_False;
1963 anErr.error = EXTRA_EDGE;
1965 TopTools_ListIteratorOfListOfShape itDEG (DEG);
1966 for (; itDEG.More(); itDEG.Next()) {
1967 anErr.incriminated.push_back(anIndices.FindIndex(itDEG.Value()));
1970 TopTools_ListIteratorOfListOfShape itSEA (SEA);
1971 for (; itSEA.More(); itSEA.Next()) {
1972 anErr.incriminated.push_back(anIndices.FindIndex(itSEA.Value()));
1975 theErrors.push_back(anErr);
1978 Standard_Integer nbBlocks = BLO.Extent();
1979 if (nbBlocks == 0) {
1980 isCompOfBlocks = Standard_False;
1982 return isCompOfBlocks;
1984 if (nbBlocks == 1) {
1986 return isCompOfBlocks;
1989 // Convert list of blocks into array for easy and fast access
1990 Standard_Integer ibl = 1;
1991 TopTools_Array1OfShape aBlocks (1, nbBlocks);
1992 TopTools_ListIteratorOfListOfShape BLOit (BLO);
1993 for (; BLOit.More(); BLOit.Next(), ibl++) {
1994 aBlocks.SetValue(ibl, BLOit.Value());
1997 // 2. Find relations between all blocks,
1998 // report connection errors (NOT_GLUED and INVALID_CONNECTION)
1999 TColStd_Array2OfInteger aRelations (1, nbBlocks, 1, nbBlocks);
2000 aRelations.Init(REL_NOT_CONNECTED);
2002 Standard_Integer row = 1;
2003 for (row = 1; row <= nbBlocks; row++) {
2004 TopoDS_Shape aBlock = aBlocks.Value(row);
2006 Standard_Integer col = row + 1;
2007 for (; col <= nbBlocks; col++) {
2008 Standard_Integer aRel = BlocksRelation(aBlock, aBlocks.Value(col));
2009 if (aRel != REL_NOT_CONNECTED) {
2010 aRelations.SetValue(row, col, aRel);
2011 aRelations.SetValue(col, row, aRel);
2012 if (aRel == REL_NOT_GLUED) {
2013 // report connection error
2014 isCompOfBlocks = Standard_False;
2016 anErr.error = NOT_GLUED;
2017 anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(row)));
2018 anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(col)));
2019 theErrors.push_back(anErr);
2020 } else if (aRel == REL_COLLISION_VV ||
2021 aRel == REL_COLLISION_FF ||
2022 aRel == REL_COLLISION_EE ||
2023 aRel == REL_UNKNOWN) {
2024 // report connection error
2025 isCompOfBlocks = Standard_False;
2027 anErr.error = INVALID_CONNECTION;
2028 anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(row)));
2029 anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(col)));
2030 theErrors.push_back(anErr);
2037 // 3. Find largest set of connected (good connection or not glued) blocks
2038 TColStd_MapOfInteger aProcessedMap;
2039 TColStd_MapOfInteger aLargestSet;
2040 TColStd_MapOfInteger aCurrentSet;
2041 for (ibl = 1; ibl <= nbBlocks; ibl++) {
2042 if (!aProcessedMap.Contains(ibl)) {
2043 aCurrentSet.Clear();
2044 FindConnected(ibl, aRelations, aProcessedMap, aCurrentSet);
2045 if (aCurrentSet.Extent() > aLargestSet.Extent()) {
2046 aLargestSet = aCurrentSet;
2051 // 4. Report all blocks, isolated from <aLargestSet>
2053 anErr.error = NOT_CONNECTED;
2054 Standard_Boolean hasIsolated = Standard_False;
2055 for (ibl = 1; ibl <= nbBlocks; ibl++) {
2056 if (!aLargestSet.Contains(ibl)) {
2057 aProcessedMap.Clear();
2058 if (!HasAnyConnection(ibl, aLargestSet, aRelations, aProcessedMap)) {
2059 // report connection absence
2060 hasIsolated = Standard_True;
2061 anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(ibl)));
2066 isCompOfBlocks = Standard_False;
2067 theErrors.push_back(anErr);
2071 return isCompOfBlocks;
2074 //=============================================================================
2078 //=============================================================================
2079 TCollection_AsciiString GEOMImpl_IBlocksOperations::PrintBCErrors
2080 (Handle(GEOM_Object) theCompound,
2081 const std::list<BCError>& theErrors)
2083 TCollection_AsciiString aDescr;
2085 std::list<BCError>::const_iterator errIt = theErrors.begin();
2087 for (; errIt != theErrors.end(); i++, errIt++) {
2088 BCError errStruct = *errIt;
2090 switch (errStruct.error) {
2092 aDescr += "\n\tNot a Blocks: ";
2095 aDescr += "\n\tHexahedral solids with degenerated and/or seam edges: ";
2097 case INVALID_CONNECTION:
2098 aDescr += "\n\tInvalid connection between two blocks: ";
2101 aDescr += "\n\tBlocks, not connected with main body: ";
2104 aDescr += "\n\tNot glued blocks: ";
2110 std::list<int> sshList = errStruct.incriminated;
2111 std::list<int>::iterator sshIt = sshList.begin();
2113 for (; sshIt != sshList.end(); jj++, sshIt++) {
2116 aDescr += TCollection_AsciiString(*sshIt);
2123 //=============================================================================
2125 * CheckCompoundOfBlocks
2127 //=============================================================================
2128 Standard_Boolean GEOMImpl_IBlocksOperations::CheckCompoundOfBlocks
2129 (Handle(GEOM_Object) theCompound,
2130 std::list<BCError>& theErrors)
2134 if (theCompound.IsNull()) return Standard_False;
2135 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2137 Standard_Boolean isCompOfBlocks = Standard_True;
2139 // Map sub-shapes and their indices
2140 TopTools_IndexedMapOfShape anIndices;
2141 TopExp::MapShapes(aBlockOrComp, anIndices);
2143 // 1. Separate blocks from non-blocks
2144 TopTools_ListOfShape NOT; // Not blocks
2145 TopTools_ListOfShape EXT; // Hexahedral solids, having degenerated and/or seam edges
2146 TopTools_ListOfShape BLO; // All blocks from the given compound
2147 AddBlocksFrom(aBlockOrComp, BLO, NOT, EXT);
2149 // Report non-blocks
2150 if (NOT.Extent() > 0) {
2151 isCompOfBlocks = Standard_False;
2153 anErr.error = NOT_BLOCK;
2154 TopTools_ListIteratorOfListOfShape it (NOT);
2155 for (; it.More(); it.Next()) {
2156 anErr.incriminated.push_back(anIndices.FindIndex(it.Value()));
2158 theErrors.push_back(anErr);
2161 // Report solids, having degenerated and/or seam edges
2162 if (EXT.Extent() > 0) {
2163 isCompOfBlocks = Standard_False;
2165 anErr.error = EXTRA_EDGE;
2166 TopTools_ListIteratorOfListOfShape it (EXT);
2167 for (; it.More(); it.Next()) {
2168 anErr.incriminated.push_back(anIndices.FindIndex(it.Value()));
2170 theErrors.push_back(anErr);
2173 Standard_Integer nbBlocks = BLO.Extent();
2174 if (nbBlocks == 0) {
2175 isCompOfBlocks = Standard_False;
2177 return isCompOfBlocks;
2179 if (nbBlocks == 1) {
2181 return isCompOfBlocks;
2184 // Prepare data for 2. and 3.
2185 TColStd_Array2OfInteger aRelations (1, nbBlocks, 1, nbBlocks);
2186 aRelations.Init(REL_NOT_CONNECTED);
2188 TopTools_IndexedMapOfShape mapBlocks;
2191 TopoDS_Compound aComp;
2192 BB.MakeCompound(aComp);
2194 TopTools_ListIteratorOfListOfShape BLOit (BLO);
2195 for (; BLOit.More(); BLOit.Next()) {
2196 mapBlocks.Add(BLOit.Value());
2197 BB.Add(aComp, BLOit.Value());
2200 // 2. Find glued blocks (having shared faces)
2201 TopTools_IndexedDataMapOfShapeListOfShape mapFaceBlocks;
2202 GEOMImpl_Block6Explorer::MapShapesAndAncestors
2203 (aComp, TopAbs_FACE, TopAbs_SOLID, mapFaceBlocks);
2205 Standard_Integer prevInd = 0, curInd = 0;
2206 Standard_Integer ind = 1, nbFaces = mapFaceBlocks.Extent();
2207 for (; ind <= nbFaces; ind++) {
2208 const TopTools_ListOfShape& aGluedBlocks = mapFaceBlocks.FindFromIndex(ind);
2209 if (aGluedBlocks.Extent() > 1) { // Shared face found
2210 TopTools_ListIteratorOfListOfShape aGluedBlocksIt (aGluedBlocks);
2211 TopoDS_Shape prevBlock, curBlock;
2212 for (; aGluedBlocksIt.More(); aGluedBlocksIt.Next()) {
2213 curBlock = aGluedBlocksIt.Value();
2214 if (!prevBlock.IsNull()) {
2215 prevInd = mapBlocks.FindIndex(prevBlock);
2216 curInd = mapBlocks.FindIndex(curBlock);
2217 aRelations.SetValue(prevInd, curInd, REL_OK);
2218 aRelations.SetValue(curInd, prevInd, REL_OK);
2220 prevBlock = curBlock;
2225 // 3. Find not glued blocks
2226 GEOMAlgo_GlueAnalyser aGD;
2228 aGD.SetShape(aComp);
2229 aGD.SetTolerance(Precision::Confusion());
2230 aGD.SetCheckGeometry(Standard_True);
2233 Standard_Integer iErr, iWrn;
2234 iErr = aGD.ErrorStatus();
2236 SetErrorCode("Error in GEOMAlgo_GlueAnalyser");
2237 return isCompOfBlocks;
2239 iWrn = aGD.WarningStatus();
2241 MESSAGE("Warning in GEOMAlgo_GlueAnalyser");
2244 // Report not glued blocks
2245 if (aGD.HasSolidsToGlue()) {
2246 isCompOfBlocks = Standard_False;
2247 Standard_Integer aSx1Ind, aSx2Ind;
2249 const GEOMAlgo_ListOfCoupleOfShapes& aLCS = aGD.SolidsToGlue();
2250 GEOMAlgo_ListIteratorOfListOfCoupleOfShapes aItCS (aLCS);
2251 for (; aItCS.More(); aItCS.Next()) {
2252 const GEOMAlgo_CoupleOfShapes& aCS = aItCS.Value();
2253 const TopoDS_Shape& aSx1 = aCS.Shape1();
2254 const TopoDS_Shape& aSx2 = aCS.Shape2();
2256 aSx1Ind = mapBlocks.FindIndex(aSx1);
2257 aSx2Ind = mapBlocks.FindIndex(aSx2);
2258 aRelations.SetValue(aSx1Ind, aSx2Ind, NOT_GLUED);
2259 aRelations.SetValue(aSx2Ind, aSx1Ind, NOT_GLUED);
2262 anErr.error = NOT_GLUED;
2263 anErr.incriminated.push_back(anIndices.FindIndex(aSx1));
2264 anErr.incriminated.push_back(anIndices.FindIndex(aSx2));
2265 theErrors.push_back(anErr);
2269 // 4. Find largest set of connected (good connection or not glued) blocks
2270 Standard_Integer ibl = 1;
2271 TColStd_MapOfInteger aProcessedMap;
2272 TColStd_MapOfInteger aLargestSet;
2273 TColStd_MapOfInteger aCurrentSet;
2274 for (ibl = 1; ibl <= nbBlocks; ibl++) {
2275 if (!aProcessedMap.Contains(ibl)) {
2276 aCurrentSet.Clear();
2277 FindConnected(ibl, aRelations, aProcessedMap, aCurrentSet);
2278 if (aCurrentSet.Extent() > aLargestSet.Extent()) {
2279 aLargestSet = aCurrentSet;
2284 // 5. Report all blocks, isolated from <aLargestSet>
2286 anErr.error = NOT_CONNECTED;
2287 Standard_Boolean hasIsolated = Standard_False;
2288 for (ibl = 1; ibl <= nbBlocks; ibl++) {
2289 if (!aLargestSet.Contains(ibl)) {
2290 aProcessedMap.Clear();
2291 if (!HasAnyConnection(ibl, aLargestSet, aRelations, aProcessedMap)) {
2292 // report connection absence
2293 hasIsolated = Standard_True;
2294 anErr.incriminated.push_back(anIndices.FindIndex(mapBlocks.FindKey(ibl)));
2299 isCompOfBlocks = Standard_False;
2300 theErrors.push_back(anErr);
2304 return isCompOfBlocks;
2307 //=============================================================================
2311 //=============================================================================
2312 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::RemoveExtraEdges
2313 (Handle(GEOM_Object) theObject,
2314 const Standard_Integer theOptimumNbFaces)
2318 if (theObject.IsNull()) return NULL;
2320 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
2321 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be fixed
2323 //Add a new Copy object
2324 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
2327 Handle(GEOM_Function) aFunction =
2328 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_REMOVE_EXTRA);
2330 //Check if the function is set correctly
2331 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
2333 GEOMImpl_IBlockTrsf aTI (aFunction);
2334 aTI.SetOriginal(aLastFunction);
2335 aTI.SetOptimumNbFaces(theOptimumNbFaces);
2337 //Compute the fixed shape
2339 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
2342 if (!GetSolver()->ComputeFunction(aFunction)) {
2343 SetErrorCode("Block driver failed to remove extra edges of the given shape");
2347 catch (Standard_Failure) {
2348 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2349 SetErrorCode(aFail->GetMessageString());
2353 //Make a Python command
2354 std::string doUnionFaces = (theOptimumNbFaces < 0) ? "False" : "True";
2355 GEOM::TPythonDump(aFunction) << aCopy << " = geompy.RemoveExtraEdges("
2356 << theObject << ", " << doUnionFaces.data() << ")";
2362 //=============================================================================
2366 //=============================================================================
2367 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::CheckAndImprove
2368 (Handle(GEOM_Object) theObject)
2372 if (theObject.IsNull()) return NULL;
2374 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
2375 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be fixed
2377 //Add a new Copy object
2378 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
2381 Handle(GEOM_Function) aFunction =
2382 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_COMPOUND_IMPROVE);
2384 //Check if the function is set correctly
2385 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
2387 GEOMImpl_IBlockTrsf aTI (aFunction);
2388 aTI.SetOriginal(aLastFunction);
2390 // -1 means do not unite faces on common surface (?except case of seam edge between them?)
2391 //aTI.SetOptimumNbFaces(-1);
2392 aTI.SetOptimumNbFaces(6);
2394 //Compute the fixed shape
2396 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
2399 if (!GetSolver()->ComputeFunction(aFunction)) {
2400 SetErrorCode("Block driver failed to improve the given blocks compound");
2404 catch (Standard_Failure) {
2405 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2406 SetErrorCode(aFail->GetMessageString());
2410 //Make a Python command
2411 GEOM::TPythonDump(aFunction) << aCopy
2412 << " = geompy.CheckAndImprove(" << theObject << ")";
2418 //=============================================================================
2420 * ExplodeCompoundOfBlocks
2422 //=============================================================================
2423 Handle(TColStd_HSequenceOfTransient) GEOMImpl_IBlocksOperations::ExplodeCompoundOfBlocks
2424 (Handle(GEOM_Object) theCompound,
2425 const Standard_Integer theMinNbFaces,
2426 const Standard_Integer theMaxNbFaces)
2430 if (theCompound.IsNull()) return NULL;
2431 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2432 if (aBlockOrComp.IsNull()) return NULL;
2434 Handle(TColStd_HSequenceOfTransient) aBlocks = new TColStd_HSequenceOfTransient;
2435 Handle(GEOM_Object) anObj;
2436 Handle(GEOM_Function) aFunction;
2438 TopTools_MapOfShape mapShape;
2439 TCollection_AsciiString anAsciiList, anEntry;
2442 TopTools_IndexedMapOfShape anIndices;
2443 TopExp::MapShapes(aBlockOrComp, anIndices);
2444 Handle(TColStd_HArray1OfInteger) anArray;
2448 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
2451 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2452 for (; exp.More(); exp.Next()) {
2453 if (mapShape.Add(exp.Current())) {
2454 TopoDS_Shape aSolid = exp.Current();
2456 TopTools_MapOfShape mapFaces;
2457 TopExp_Explorer expF (aSolid, TopAbs_FACE);
2458 Standard_Integer nbFaces = 0;
2459 for (; expF.More(); expF.Next()) {
2460 if (mapFaces.Add(expF.Current())) {
2465 if (theMinNbFaces <= nbFaces && nbFaces <= theMaxNbFaces) {
2466 anArray = new TColStd_HArray1OfInteger(1,1);
2467 anArray->SetValue(1, anIndices.FindIndex(aSolid));
2468 anObj = GetEngine()->AddSubShape(theCompound, anArray);
2469 aBlocks->Append(anObj);
2471 //Make a Python command
2472 TDF_Tool::Entry(anObj->GetEntry(), anEntry);
2473 anAsciiList += anEntry + ", ";
2478 catch (Standard_Failure) {
2479 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2480 SetErrorCode(aFail->GetMessageString());
2484 if (aBlocks->IsEmpty()) {
2485 SetErrorCode("There are no specified blocks in the given shape");
2489 anAsciiList.Trunc(anAsciiList.Length() - 2);
2491 //The explode doesn't change object so no new function is required.
2492 aFunction = theCompound->GetLastFunction();
2494 //Make a Python command
2495 GEOM::TPythonDump(aFunction, /*append=*/true)
2496 << "[" << anAsciiList.ToCString() << "] = geompy.MakeBlockExplode("
2497 << theCompound << ", " << theMinNbFaces << ", " << theMaxNbFaces << ")";
2503 //=============================================================================
2507 //=============================================================================
2508 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetBlockNearPoint
2509 (Handle(GEOM_Object) theCompound,
2510 Handle(GEOM_Object) thePoint)
2515 Handle(GEOM_Object) aResult;
2518 if (theCompound.IsNull() || thePoint.IsNull()) return NULL;
2520 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2521 if (aBlockOrComp.IsNull()) {
2522 SetErrorCode("Compound is null");
2525 if (aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
2526 aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
2527 SetErrorCode("Shape to find block in is not a compound");
2531 TopoDS_Shape anArg = thePoint->GetValue();
2532 if (anArg.IsNull()) {
2533 SetErrorCode("Point is null");
2536 if (anArg.ShapeType() != TopAbs_VERTEX) {
2537 SetErrorCode("Shape for block identification is not a vertex");
2541 //Compute the Block value
2543 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
2546 TopoDS_Shape aShape;
2548 TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
2549 gp_Pnt aPnt = BRep_Tool::Pnt(aVert);
2550 Standard_Real PX, PY, PZ;
2551 aPnt.Coord(PX, PY, PZ);
2553 // 1. Classify the point relatively each block
2554 Standard_Integer nearest = 2, nbFound = 0;
2555 TopTools_DataMapOfShapeInteger mapShapeDist;
2556 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2557 for (; exp.More(); exp.Next()) {
2558 TopoDS_Shape aSolid = exp.Current();
2560 if (!mapShapeDist.IsBound(aSolid)) {
2561 Standard_Integer aDistance = 2;
2563 // 1.a. Classify relatively Bounding box
2564 Standard_Real Xmin, Ymin, Zmin, Xmax, Ymax, Zmax;
2566 BRepBndLib::Add(aSolid, BB);
2567 BB.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);
2568 if (PX < Xmin || Xmax < PX ||
2569 PY < Ymin || Ymax < PY ||
2570 PZ < Zmin || Zmax < PZ) {
2571 // OUT of bounding box
2574 // 1.b. Classify relatively the solid itself
2575 BRepClass3d_SolidClassifier SC (aSolid, aPnt, Precision::Confusion());
2576 if (SC.State() == TopAbs_IN) {
2578 } else if (SC.State() == TopAbs_ON) {
2585 if (aDistance < nearest) {
2586 nearest = aDistance;
2590 // A first found block, containing the point inside, will be returned.
2591 // It is the solution, if there are no intersecting blocks in the compound.
2592 if (nearest == -1) break;
2594 } else if (aDistance == nearest) {
2599 mapShapeDist.Bind(aSolid, aDistance);
2600 } // if (!mapShapeDist.IsBound(aSolid))
2603 // 2. Define block, containing the point or having minimum distance to it
2606 // The point is on boundary of some blocks and there are
2607 // no blocks, having the point inside their volume
2608 SetErrorCode("Multiple blocks near the given point are found");
2611 } else if (nearest == 1) {
2612 // The point is outside some blocks and there are
2613 // no blocks, having the point inside or on boundary.
2614 // We will get a nearest block
2615 Standard_Real minDist = RealLast();
2616 TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
2617 for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
2618 if (mapShapeDistIter.Value() == 1) {
2619 TopoDS_Shape aSolid = mapShapeDistIter.Key();
2620 BRepExtrema_DistShapeShape aDistTool (aVert, aSolid);
2621 if (!aDistTool.IsDone()) {
2622 SetErrorCode("Can not find a distance from the given point to one of blocks");
2625 Standard_Real aDist = aDistTool.Value();
2626 if (aDist < minDist) {
2632 } else { // nearest == -1
2633 // // The point is inside some blocks.
2634 // // We will get a block with nearest center
2635 // Standard_Real minDist = RealLast();
2636 // TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
2637 // for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
2638 // if (mapShapeDistIter.Value() == -1) {
2639 // TopoDS_Shape aSolid = mapShapeDistIter.Key();
2640 // GProp_GProps aSystem;
2641 // BRepGProp::VolumeProperties(aSolid, aSystem);
2642 // gp_Pnt aCenterMass = aSystem.CentreOfMass();
2644 // Standard_Real aDist = aCenterMass.Distance(aPnt);
2645 // if (aDist < minDist) {
2652 } // if (nbFound > 1)
2655 SetErrorCode("There are no blocks near the given point");
2658 TopTools_IndexedMapOfShape anIndices;
2659 TopExp::MapShapes(aBlockOrComp, anIndices);
2660 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
2661 anArray->SetValue(1, anIndices.FindIndex(aShape));
2662 aResult = GetEngine()->AddSubShape(theCompound, anArray);
2665 catch (Standard_Failure) {
2666 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2667 SetErrorCode(aFail->GetMessageString());
2671 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
2673 //Make a Python command
2674 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetBlockNearPoint("
2675 << theCompound << ", " << thePoint << ")";
2681 //=============================================================================
2685 //=============================================================================
2686 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetBlockByParts
2687 (Handle(GEOM_Object) theCompound,
2688 const Handle(TColStd_HSequenceOfTransient)& theParts)
2692 Handle(GEOM_Object) aResult;
2694 if (theCompound.IsNull() || theParts.IsNull()) return NULL;
2695 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2696 if (aBlockOrComp.IsNull()) return NULL;
2699 Standard_Integer argi, aLen = theParts->Length();
2700 TopTools_Array1OfShape anArgs (1, aLen);
2701 TCollection_AsciiString anEntry, aPartsDescr;
2702 for (argi = 1; argi <= aLen; argi++) {
2703 Handle(GEOM_Object) anObj = Handle(GEOM_Object)::DownCast(theParts->Value(argi));
2704 Handle(GEOM_Function) aRef = anObj->GetLastFunction();
2705 if (aRef.IsNull()) return NULL;
2707 TopoDS_Shape anArg = aRef->GetValue();
2708 if (anArg.IsNull()) {
2709 SetErrorCode("Null shape is given as argument");
2712 anArgs(argi) = anArg;
2714 // For Python command
2715 TDF_Tool::Entry(anObj->GetEntry(), anEntry);
2716 if (argi > 1) aPartsDescr += ", ";
2717 aPartsDescr += anEntry;
2720 //Compute the Block value
2722 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
2725 // 1. Explode compound on solids
2726 TopTools_MapOfShape mapShape;
2727 Standard_Integer nbSolids = 0;
2728 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2729 for (; exp.More(); exp.Next()) {
2730 if (mapShape.Add(exp.Current())) {
2736 Standard_Integer ind = 1;
2737 TopTools_Array1OfShape aSolids (1, nbSolids);
2738 TColStd_Array1OfInteger aNbParts (1, nbSolids);
2739 for (exp.Init(aBlockOrComp, TopAbs_SOLID); exp.More(); exp.Next(), ind++) {
2740 if (mapShape.Add(exp.Current())) {
2741 TopoDS_Shape aSolid = exp.Current();
2742 aSolids(ind) = aSolid;
2745 // 2. Define quantity of parts, contained in each solid
2746 TopTools_IndexedMapOfShape aSubShapes;
2747 TopExp::MapShapes(aSolid, aSubShapes);
2748 for (argi = 1; argi <= aLen; argi++) {
2749 if (aSubShapes.Contains(anArgs(argi))) {
2756 // 3. Define solid, containing maximum quantity of parts
2757 Standard_Integer maxNb = 0, nbFound = 0;
2758 TopoDS_Shape aShape;
2759 for (ind = 1; ind <= nbSolids; ind++) {
2760 if (aNbParts(ind) > maxNb) {
2761 maxNb = aNbParts(ind);
2762 aShape = aSolids(ind);
2764 } else if (aNbParts(ind) == maxNb) {
2770 SetErrorCode("Multiple blocks, containing maximum quantity of the given parts, are found");
2772 } else if (nbFound == 0) {
2773 SetErrorCode("There are no blocks, containing the given parts");
2776 TopTools_IndexedMapOfShape anIndices;
2777 TopExp::MapShapes(aBlockOrComp, anIndices);
2778 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
2779 anArray->SetValue(1, anIndices.FindIndex(aShape));
2780 aResult = GetEngine()->AddSubShape(theCompound, anArray);
2782 } catch (Standard_Failure) {
2783 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2784 SetErrorCode(aFail->GetMessageString());
2788 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
2790 //Make a Python command
2791 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetBlockByParts("
2792 << theCompound << ", [" << aPartsDescr.ToCString() << "])";
2798 //=============================================================================
2802 //=============================================================================
2803 Handle(TColStd_HSequenceOfTransient) GEOMImpl_IBlocksOperations::GetBlocksByParts
2804 (Handle(GEOM_Object) theCompound,
2805 const Handle(TColStd_HSequenceOfTransient)& theParts)
2809 if (theCompound.IsNull() || theParts.IsNull()) return NULL;
2810 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2811 if (aBlockOrComp.IsNull()) return NULL;
2813 Handle(TColStd_HSequenceOfTransient) aBlocks = new TColStd_HSequenceOfTransient;
2814 Handle(GEOM_Object) anObj;
2815 Handle(GEOM_Function) aFunction;
2818 Standard_Integer argi, aLen = theParts->Length();
2819 TopTools_Array1OfShape anArgs (1, aLen);
2820 TCollection_AsciiString anEntry, aPartsDescr, anAsciiList;
2822 for (argi = 1; argi <= aLen; argi++) {
2823 Handle(GEOM_Object) anObj = Handle(GEOM_Object)::DownCast(theParts->Value(argi));
2824 Handle(GEOM_Function) aRef = anObj->GetLastFunction();
2825 if (aRef.IsNull()) return NULL;
2827 TopoDS_Shape anArg = aRef->GetValue();
2828 if (anArg.IsNull()) {
2829 SetErrorCode("Null shape is given as argument");
2832 anArgs(argi) = anArg;
2834 // For Python command
2835 TDF_Tool::Entry(anObj->GetEntry(), anEntry);
2836 aPartsDescr += anEntry + ", ";
2841 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
2844 TopTools_MapOfShape mapShape;
2845 Standard_Integer nbSolids = 0;
2846 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2847 for (; exp.More(); exp.Next()) {
2848 if (mapShape.Add(exp.Current())) {
2854 Standard_Integer ind = 1;
2855 TopTools_Array1OfShape aSolids (1, nbSolids);
2856 TColStd_Array1OfInteger aNbParts (1, nbSolids);
2857 for (exp.Init(aBlockOrComp, TopAbs_SOLID); exp.More(); exp.Next(), ind++) {
2858 if (mapShape.Add(exp.Current())) {
2859 TopoDS_Shape aSolid = exp.Current();
2860 aSolids(ind) = aSolid;
2863 // 2. Define quantity of parts, contained in each solid
2864 TopTools_IndexedMapOfShape aSubShapes;
2865 TopExp::MapShapes(aSolid, aSubShapes);
2866 for (argi = 1; argi <= aLen; argi++) {
2867 if (aSubShapes.Contains(anArgs(argi))) {
2874 // 3. Define solid, containing maximum quantity of parts
2875 Standard_Integer maxNb = 0, nbFound = 0;
2876 for (ind = 1; ind <= nbSolids; ind++) {
2877 if (aNbParts(ind) > maxNb) {
2878 maxNb = aNbParts(ind);
2880 } else if (aNbParts(ind) == maxNb) {
2886 SetErrorCode("There are no blocks, containing the given parts");
2891 TopTools_IndexedMapOfShape anIndices;
2892 TopExp::MapShapes(aBlockOrComp, anIndices);
2893 Handle(TColStd_HArray1OfInteger) anArray;
2895 for (ind = 1; ind <= nbSolids; ind++) {
2896 if (aNbParts(ind) == maxNb) {
2897 anArray = new TColStd_HArray1OfInteger(1,1);
2898 anArray->SetValue(1, anIndices.FindIndex(aSolids(ind)));
2899 anObj = GetEngine()->AddSubShape(theCompound, anArray);
2900 aBlocks->Append(anObj);
2902 // For Python command
2903 TDF_Tool::Entry(anObj->GetEntry(), anEntry);
2904 anAsciiList += anEntry + ", ";
2905 if (aFunction.IsNull())
2906 aFunction = anObj->GetLastFunction();
2910 catch (Standard_Failure) {
2911 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2912 SetErrorCode(aFail->GetMessageString());
2916 //Make a Python command
2917 aPartsDescr.Trunc(aPartsDescr.Length() - 2);
2918 anAsciiList.Trunc(anAsciiList.Length() - 2);
2920 GEOM::TPythonDump(aFunction) << "[" << anAsciiList.ToCString()
2921 << "] = geompy.GetBlocksByParts(" << theCompound
2922 << ", [" << aPartsDescr.ToCString() << "])";
2928 //=============================================================================
2930 * MakeMultiTransformation1D
2932 //=============================================================================
2933 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeMultiTransformation1D
2934 (Handle(GEOM_Object) theObject,
2935 const Standard_Integer theDirFace1,
2936 const Standard_Integer theDirFace2,
2937 const Standard_Integer theNbTimes)
2941 if (theObject.IsNull()) return NULL;
2943 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
2944 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be moved
2946 //Add a new Copy object
2947 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
2949 //Add a translate function
2950 Handle(GEOM_Function) aFunction =
2951 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_MULTI_TRANSFORM_1D);
2953 //Check if the function is set correctly
2954 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
2956 GEOMImpl_IBlockTrsf aTI (aFunction);
2957 aTI.SetOriginal(aLastFunction);
2958 aTI.SetFace1U(theDirFace1);
2959 aTI.SetFace2U(theDirFace2);
2960 aTI.SetNbIterU(theNbTimes);
2962 //Compute the transformation
2964 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
2967 if (!GetSolver()->ComputeFunction(aFunction)) {
2968 SetErrorCode("Block driver failed to make multi-transformation");
2972 catch (Standard_Failure) {
2973 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2974 SetErrorCode(aFail->GetMessageString());
2978 //Make a Python command
2979 GEOM::TPythonDump(aFunction) << aCopy << " = geompy.MakeMultiTransformation1D("
2980 << theObject << ", " << theDirFace1 << ", " << theDirFace2 << ", " << theNbTimes << ")";
2986 //=============================================================================
2988 * MakeMultiTransformation2D
2990 //=============================================================================
2991 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeMultiTransformation2D
2992 (Handle(GEOM_Object) theObject,
2993 const Standard_Integer theDirFace1U,
2994 const Standard_Integer theDirFace2U,
2995 const Standard_Integer theNbTimesU,
2996 const Standard_Integer theDirFace1V,
2997 const Standard_Integer theDirFace2V,
2998 const Standard_Integer theNbTimesV)
3002 if (theObject.IsNull()) return NULL;
3004 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
3005 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be moved
3007 //Add a new Copy object
3008 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
3010 //Add a translate function
3011 Handle(GEOM_Function) aFunction =
3012 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_MULTI_TRANSFORM_2D);
3014 //Check if the function is set correctly
3015 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
3017 GEOMImpl_IBlockTrsf aTI (aFunction);
3018 aTI.SetOriginal(aLastFunction);
3019 aTI.SetFace1U(theDirFace1U);
3020 aTI.SetFace2U(theDirFace2U);
3021 aTI.SetNbIterU(theNbTimesU);
3022 aTI.SetFace1V(theDirFace1V);
3023 aTI.SetFace2V(theDirFace2V);
3024 aTI.SetNbIterV(theNbTimesV);
3026 //Compute the transformation
3028 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
3031 if (!GetSolver()->ComputeFunction(aFunction)) {
3032 SetErrorCode("Block driver failed to make multi-transformation");
3036 catch (Standard_Failure) {
3037 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
3038 SetErrorCode(aFail->GetMessageString());
3042 //Make a Python command
3043 GEOM::TPythonDump(aFunction) << aCopy << " = geompy.MakeMultiTransformation2D("
3044 << theObject << ", " << theDirFace1U << ", " << theDirFace2U << ", " << theNbTimesU
3045 << ", " << theDirFace1V << ", " << theDirFace2V << ", " << theNbTimesV << ")";
3051 //=============================================================================
3055 //=============================================================================
3056 Handle(TColStd_HSequenceOfTransient) GEOMImpl_IBlocksOperations::Propagate
3057 (Handle(GEOM_Object) theShape)
3061 if (theShape.IsNull()) return NULL;
3063 TopoDS_Shape aShape = theShape->GetValue();
3064 if (aShape.IsNull()) return NULL;
3066 TopTools_IndexedMapOfShape anIndices;
3067 TopExp::MapShapes(aShape, anIndices);
3069 TopTools_IndexedDataMapOfShapeListOfShape MEW;
3070 GEOMImpl_Block6Explorer::MapShapesAndAncestors
3071 (aShape, TopAbs_EDGE, TopAbs_WIRE, MEW);
3072 Standard_Integer ie, nbEdges = MEW.Extent();
3075 Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
3077 TopTools_MapOfShape mapAcceptedEdges;
3078 TCollection_AsciiString aListRes, anEntry;
3080 for (ie = 1; ie <= nbEdges; ie++) {
3081 TopoDS_Shape curE = MEW.FindKey(ie);
3083 if (mapAcceptedEdges.Contains(curE)) continue;
3086 TopTools_ListOfShape currentChain;
3087 TopTools_ListOfShape listPrevEdges;
3089 currentChain.Append(curE);
3090 listPrevEdges.Append(curE);
3091 mapAcceptedEdges.Add(curE);
3093 // Collect all edges pass by pass
3094 while (listPrevEdges.Extent() > 0) {
3095 // List of edges, added to chain on this cycle pass
3096 TopTools_ListOfShape listCurEdges;
3098 // Find the next portion of edges
3099 TopTools_ListIteratorOfListOfShape itE (listPrevEdges);
3100 for (; itE.More(); itE.Next()) {
3101 TopoDS_Shape anE = itE.Value();
3103 // Iterate on faces, having edge <anE>
3104 TopTools_ListIteratorOfListOfShape itW (MEW.FindFromKey(anE));
3105 for (; itW.More(); itW.Next()) {
3106 TopoDS_Shape aW = itW.Value();
3107 TopoDS_Shape anOppE;
3109 BRepTools_WireExplorer aWE (TopoDS::Wire(aW));
3110 Standard_Integer nb = 1, found = 0;
3111 TopTools_Array1OfShape anEdges (1,4);
3112 for (; aWE.More(); aWE.Next(), nb++) {
3117 anEdges(nb) = aWE.Current();
3118 if (anEdges(nb).IsSame(anE)) found = nb;
3121 if (nb == 5 && found > 0) {
3122 // Quadrangle face found, get an opposite edge
3123 Standard_Integer opp = found + 2;
3124 if (opp > 4) opp -= 4;
3125 anOppE = anEdges(opp);
3127 if (!mapAcceptedEdges.Contains(anOppE)) {
3128 // Add found edge to the chain
3129 currentChain.Append(anOppE);
3130 listCurEdges.Append(anOppE);
3131 mapAcceptedEdges.Add(anOppE);
3133 } // if (nb == 5 && found > 0)
3134 } // for (; itF.More(); itF.Next())
3135 } // for (; itE.More(); itE.Next())
3137 listPrevEdges = listCurEdges;
3138 } // while (listPrevEdges.Extent() > 0)
3140 // Store the chain in the document
3141 Handle(TColStd_HArray1OfInteger) anArray =
3142 new TColStd_HArray1OfInteger (1, currentChain.Extent());
3144 // Fill array of sub-shape indices
3145 TopTools_ListIteratorOfListOfShape itSub (currentChain);
3146 for (int index = 1; itSub.More(); itSub.Next(), ++index) {
3147 int id = anIndices.FindIndex(itSub.Value());
3148 anArray->SetValue(index, id);
3151 // Add a new group object
3152 Handle(GEOM_Object) aChain = GetEngine()->AddSubShape(theShape, anArray);
3155 aChain->SetType(GEOM_GROUP);
3157 // Set a sub shape type
3158 TDF_Label aFreeLabel = aChain->GetFreeLabel();
3159 TDataStd_Integer::Set(aFreeLabel, (Standard_Integer)TopAbs_EDGE);
3161 // Add the chain to the result
3162 aSeq->Append(aChain);
3164 //Make a Python command
3165 TDF_Tool::Entry(aChain->GetEntry(), anEntry);
3166 aListRes += anEntry + ", ";
3169 if (aSeq->IsEmpty()) {
3170 SetErrorCode("There are no quadrangle faces in the shape");
3174 aListRes.Trunc(aListRes.Length() - 2);
3176 // The Propagation doesn't change object so no new function is required.
3177 Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
3179 // Make a Python command
3180 GEOM::TPythonDump(aFunction, /*append=*/true)
3181 << "[" << aListRes.ToCString() << "] = geompy.Propagate(" << theShape << ")";