1 // Copyright (C) 2007-2008 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
23 #pragma warning( disable:4786 )
26 #include <Standard_Stream.hxx>
28 #include <GEOMImpl_IBlocksOperations.hxx>
30 #include <GEOMImpl_Types.hxx>
32 #include <GEOMImpl_BlockDriver.hxx>
33 #include <GEOMImpl_IBlocks.hxx>
34 #include <GEOMImpl_IBlockTrsf.hxx>
35 #include <GEOMImpl_CopyDriver.hxx>
36 #include <GEOMImpl_Block6Explorer.hxx>
38 #include <GEOM_Function.hxx>
39 #include <GEOM_PythonDump.hxx>
41 #include <GEOMAlgo_GlueAnalyser.hxx>
42 #include <GEOMAlgo_CoupleOfShapes.hxx>
43 #include <GEOMAlgo_ListOfCoupleOfShapes.hxx>
44 #include <GEOMAlgo_ListIteratorOfListOfCoupleOfShapes.hxx>
45 #include <BlockFix_CheckTool.hxx>
47 #include "utilities.h"
49 #include <Utils_ExceptHandlers.hxx>
51 #include <TFunction_DriverTable.hxx>
52 #include <TFunction_Driver.hxx>
53 #include <TFunction_Logbook.hxx>
54 #include <TDataStd_Integer.hxx>
55 #include <TDF_Tool.hxx>
57 #include <BRep_Tool.hxx>
58 #include <BRep_Builder.hxx>
59 #include <BRepTools.hxx>
60 #include <BRepTools_WireExplorer.hxx>
61 #include <BRepGProp.hxx>
62 #include <BRepBndLib.hxx>
63 #include <BRepAdaptor_Surface.hxx>
64 #include <BRepClass_FaceClassifier.hxx>
65 #include <BRepClass3d_SolidClassifier.hxx>
66 #include <BRepExtrema_DistShapeShape.hxx>
70 #include <TopoDS_Edge.hxx>
71 #include <TopoDS_Vertex.hxx>
72 #include <TopoDS_Compound.hxx>
73 #include <TopoDS_Iterator.hxx>
75 #include <TopExp_Explorer.hxx>
76 #include <TopTools_MapOfShape.hxx>
77 #include <TopTools_Array1OfShape.hxx>
78 #include <TopTools_IndexedMapOfShape.hxx>
79 #include <TopTools_DataMapOfShapeInteger.hxx>
80 #include <TopTools_ListIteratorOfListOfShape.hxx>
81 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
82 #include <TopTools_DataMapIteratorOfDataMapOfShapeInteger.hxx>
84 #include <Bnd_Box.hxx>
85 #include <GProp_GProps.hxx>
87 #include <Geom_Surface.hxx>
88 #include <ShapeAnalysis_Surface.hxx>
90 #include <TColStd_MapOfInteger.hxx>
91 #include <TColStd_Array1OfReal.hxx>
92 #include <TColStd_Array1OfInteger.hxx>
93 #include <TColStd_Array2OfInteger.hxx>
95 //#include <OSD_Timer.hxx>
97 #include <Precision.hxx>
99 #include <Standard_Failure.hxx>
100 #include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC
102 //=============================================================================
106 //=============================================================================
107 GEOMImpl_IBlocksOperations::GEOMImpl_IBlocksOperations (GEOM_Engine* theEngine, int theDocID)
108 : GEOM_IOperations(theEngine, theDocID)
110 MESSAGE("GEOMImpl_IBlocksOperations::GEOMImpl_IBlocksOperations");
113 //=============================================================================
117 //=============================================================================
118 GEOMImpl_IBlocksOperations::~GEOMImpl_IBlocksOperations()
120 MESSAGE("GEOMImpl_IBlocksOperations::~GEOMImpl_IBlocksOperations");
124 //=============================================================================
128 //=============================================================================
129 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuad
130 (Handle(GEOM_Object) theEdge1, Handle(GEOM_Object) theEdge2,
131 Handle(GEOM_Object) theEdge3, Handle(GEOM_Object) theEdge4)
135 if (theEdge1.IsNull() || theEdge2.IsNull() ||
136 theEdge3.IsNull() || theEdge4.IsNull()) return NULL;
138 //Add a new Face object
139 Handle(GEOM_Object) aFace = GetEngine()->AddObject(GetDocID(), GEOM_FACE);
141 //Add a new Face function
142 Handle(GEOM_Function) aFunction =
143 aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_FOUR_EDGES);
145 //Check if the function is set correctly
146 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
148 GEOMImpl_IBlocks aPI (aFunction);
150 Handle(GEOM_Function) aRef1 = theEdge1->GetLastFunction();
151 Handle(GEOM_Function) aRef2 = theEdge2->GetLastFunction();
152 Handle(GEOM_Function) aRef3 = theEdge3->GetLastFunction();
153 Handle(GEOM_Function) aRef4 = theEdge4->GetLastFunction();
154 if (aRef1.IsNull() || aRef2.IsNull() ||
155 aRef3.IsNull() || aRef4.IsNull()) return NULL;
157 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
158 aShapesSeq->Append(aRef1);
159 aShapesSeq->Append(aRef2);
160 aShapesSeq->Append(aRef3);
161 aShapesSeq->Append(aRef4);
163 aPI.SetShapes(aShapesSeq);
165 //Compute the Face value
167 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
170 if (!GetSolver()->ComputeFunction(aFunction)) {
171 SetErrorCode("Block driver failed to compute a face");
175 catch (Standard_Failure) {
176 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
177 SetErrorCode(aFail->GetMessageString());
181 //Make a Python command
182 GEOM::TPythonDump(aFunction) << aFace << " = geompy.MakeQuad("
183 << theEdge1 << ", " << theEdge2 << ", " << theEdge3 << ", " << theEdge4 << ")";
189 //=============================================================================
193 //=============================================================================
194 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuad2Edges
195 (Handle(GEOM_Object) theEdge1, Handle(GEOM_Object) theEdge2)
199 if (theEdge1.IsNull() || theEdge2.IsNull()) return NULL;
201 //Add a new Face object
202 Handle(GEOM_Object) aFace = GetEngine()->AddObject(GetDocID(), GEOM_FACE);
204 //Add a new Face function
205 Handle(GEOM_Function) aFunction =
206 aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_TWO_EDGES);
208 //Check if the function is set correctly
209 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
211 GEOMImpl_IBlocks aPI (aFunction);
213 Handle(GEOM_Function) aRef1 = theEdge1->GetLastFunction();
214 Handle(GEOM_Function) aRef2 = theEdge2->GetLastFunction();
215 if (aRef1.IsNull() || aRef2.IsNull()) return NULL;
217 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
218 aShapesSeq->Append(aRef1);
219 aShapesSeq->Append(aRef2);
221 aPI.SetShapes(aShapesSeq);
223 //Compute the Face value
225 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
228 if (!GetSolver()->ComputeFunction(aFunction)) {
229 SetErrorCode("Block driver failed to compute a face");
233 catch (Standard_Failure) {
234 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
235 SetErrorCode(aFail->GetMessageString());
239 //Make a Python command
240 GEOM::TPythonDump(aFunction) << aFace << " = geompy.MakeQuad2Edges("
241 << theEdge1 << ", " << theEdge2 << ")";
247 //=============================================================================
251 //=============================================================================
252 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuad4Vertices
253 (Handle(GEOM_Object) thePnt1, Handle(GEOM_Object) thePnt2,
254 Handle(GEOM_Object) thePnt3, Handle(GEOM_Object) thePnt4)
258 if (thePnt1.IsNull() || thePnt2.IsNull() ||
259 thePnt3.IsNull() || thePnt4.IsNull()) return NULL;
261 //Add a new Face object
262 Handle(GEOM_Object) aFace = GetEngine()->AddObject(GetDocID(), GEOM_FACE);
264 //Add a new Face function
265 Handle(GEOM_Function) aFunction =
266 aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_FOUR_PNT);
268 //Check if the function is set correctly
269 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
271 GEOMImpl_IBlocks aPI (aFunction);
273 Handle(GEOM_Function) aRef1 = thePnt1->GetLastFunction();
274 Handle(GEOM_Function) aRef2 = thePnt2->GetLastFunction();
275 Handle(GEOM_Function) aRef3 = thePnt3->GetLastFunction();
276 Handle(GEOM_Function) aRef4 = thePnt4->GetLastFunction();
277 if (aRef1.IsNull() || aRef2.IsNull() ||
278 aRef3.IsNull() || aRef4.IsNull()) return NULL;
280 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
281 aShapesSeq->Append(aRef1);
282 aShapesSeq->Append(aRef2);
283 aShapesSeq->Append(aRef3);
284 aShapesSeq->Append(aRef4);
286 aPI.SetShapes(aShapesSeq);
288 //Compute the Face value
290 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
293 if (!GetSolver()->ComputeFunction(aFunction)) {
294 SetErrorCode("Block driver failed to compute a face");
298 catch (Standard_Failure) {
299 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
300 SetErrorCode(aFail->GetMessageString());
304 //Make a Python command
305 GEOM::TPythonDump(aFunction) << aFace << " = geompy.MakeQuad4Vertices("
306 << thePnt1 << ", " << thePnt2 << ", " << thePnt3 << ", " << thePnt4 << ")";
312 //=============================================================================
316 //=============================================================================
317 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeHexa
318 (Handle(GEOM_Object) theFace1, Handle(GEOM_Object) theFace2,
319 Handle(GEOM_Object) theFace3, Handle(GEOM_Object) theFace4,
320 Handle(GEOM_Object) theFace5, Handle(GEOM_Object) theFace6)
324 if (theFace1.IsNull() || theFace2.IsNull() ||
325 theFace3.IsNull() || theFace4.IsNull() ||
326 theFace5.IsNull() || theFace6.IsNull()) return NULL;
328 //Add a new Solid object
329 Handle(GEOM_Object) aBlock = GetEngine()->AddObject(GetDocID(), GEOM_BLOCK);
331 //Add a new Block function
332 Handle(GEOM_Function) aFunction =
333 aBlock->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_SIX_FACES);
335 //Check if the function is set correctly
336 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
338 GEOMImpl_IBlocks aPI (aFunction);
340 Handle(GEOM_Function) aRef1 = theFace1->GetLastFunction();
341 Handle(GEOM_Function) aRef2 = theFace2->GetLastFunction();
342 Handle(GEOM_Function) aRef3 = theFace3->GetLastFunction();
343 Handle(GEOM_Function) aRef4 = theFace4->GetLastFunction();
344 Handle(GEOM_Function) aRef5 = theFace5->GetLastFunction();
345 Handle(GEOM_Function) aRef6 = theFace6->GetLastFunction();
346 if (aRef1.IsNull() || aRef2.IsNull() ||
347 aRef3.IsNull() || aRef4.IsNull() ||
348 aRef5.IsNull() || aRef6.IsNull()) return NULL;
350 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
351 aShapesSeq->Append(aRef1);
352 aShapesSeq->Append(aRef2);
353 aShapesSeq->Append(aRef3);
354 aShapesSeq->Append(aRef4);
355 aShapesSeq->Append(aRef5);
356 aShapesSeq->Append(aRef6);
358 aPI.SetShapes(aShapesSeq);
360 //Compute the Block value
362 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
365 if (!GetSolver()->ComputeFunction(aFunction)) {
366 SetErrorCode("Block driver failed to compute a block");
370 catch (Standard_Failure) {
371 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
372 SetErrorCode(aFail->GetMessageString());
376 //Make a Python command
377 GEOM::TPythonDump(aFunction) << aBlock << " = geompy.MakeHexa("
378 << theFace1 << ", " << theFace2 << ", " << theFace3 << ", "
379 << theFace4 << ", " << theFace5 << ", " << theFace6 << ")";
385 //=============================================================================
389 //=============================================================================
390 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeHexa2Faces
391 (Handle(GEOM_Object) theFace1, Handle(GEOM_Object) theFace2)
395 if (theFace1.IsNull() || theFace2.IsNull()) return NULL;
397 //Add a new Solid object
398 Handle(GEOM_Object) aBlock = GetEngine()->AddObject(GetDocID(), GEOM_BLOCK);
400 //Add a new Block function
401 Handle(GEOM_Function) aFunction =
402 aBlock->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_TWO_FACES);
404 //Check if the function is set correctly
405 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
407 GEOMImpl_IBlocks aPI (aFunction);
409 Handle(GEOM_Function) aRef1 = theFace1->GetLastFunction();
410 Handle(GEOM_Function) aRef2 = theFace2->GetLastFunction();
411 if (aRef1.IsNull() || aRef2.IsNull()) return NULL;
413 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
414 aShapesSeq->Append(aRef1);
415 aShapesSeq->Append(aRef2);
417 aPI.SetShapes(aShapesSeq);
419 //Compute the Block value
421 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
424 if (!GetSolver()->ComputeFunction(aFunction)) {
425 SetErrorCode("Block driver failed to compute a block");
429 catch (Standard_Failure) {
430 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
431 SetErrorCode(aFail->GetMessageString());
435 //Make a Python command
436 GEOM::TPythonDump(aFunction) << aBlock << " = geompy.MakeHexa2Faces("
437 << theFace1 << ", " << theFace2 << ")";
443 //=============================================================================
447 //=============================================================================
448 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeBlockCompound
449 (Handle(GEOM_Object) theCompound)
453 if (theCompound.IsNull()) return NULL;
456 Handle(GEOM_Object) aBlockComp = GetEngine()->AddObject(GetDocID(), GEOM_COMPOUND);
458 //Add a new BlocksComp function
459 Handle(GEOM_Function) aFunction =
460 aBlockComp->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_COMPOUND_GLUE);
462 //Check if the function is set correctly
463 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
465 GEOMImpl_IBlocks aPI (aFunction);
467 Handle(GEOM_Function) aRef1 = theCompound->GetLastFunction();
468 if (aRef1.IsNull()) return NULL;
470 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
471 aShapesSeq->Append(aRef1);
473 aPI.SetShapes(aShapesSeq);
475 //Compute the Blocks Compound value
477 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
480 if (!GetSolver()->ComputeFunction(aFunction)) {
481 SetErrorCode("Block driver failed to compute a blocks compound");
485 catch (Standard_Failure) {
486 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
487 SetErrorCode(aFail->GetMessageString());
491 //Make a Python command
492 GEOM::TPythonDump(aFunction) << aBlockComp
493 << " = geompy.MakeBlockCompound(" << theCompound << ")";
499 //=============================================================================
503 //=============================================================================
504 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetPoint
505 (Handle(GEOM_Object) theShape,
506 const Standard_Real theX,
507 const Standard_Real theY,
508 const Standard_Real theZ,
509 const Standard_Real theEpsilon)
514 Handle(GEOM_Object) aResult;
517 if (theShape.IsNull()) return NULL;
519 TopoDS_Shape aBlockOrComp = theShape->GetValue();
520 if (aBlockOrComp.IsNull()) {
521 SetErrorCode("Given shape is null");
525 //Compute the Vertex value
526 gp_Pnt P (theX, theY, theZ);
527 Standard_Real eps = Max(theEpsilon, Precision::Confusion());
530 Standard_Integer isFound = 0;
531 TopTools_MapOfShape mapShape;
532 TopExp_Explorer exp (aBlockOrComp, TopAbs_VERTEX);
534 for (; exp.More(); exp.Next()) {
535 if (mapShape.Add(exp.Current())) {
536 TopoDS_Vertex aVi = TopoDS::Vertex(exp.Current());
537 gp_Pnt aPi = BRep_Tool::Pnt(aVi);
538 if (aPi.Distance(P) < eps) {
546 SetErrorCode("Vertex has not been found");
548 } else if (isFound > 1) {
549 SetErrorCode("Multiple vertices found by the given coordinates and epsilon");
552 TopTools_IndexedMapOfShape anIndices;
553 TopExp::MapShapes(aBlockOrComp, anIndices);
554 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
555 anArray->SetValue(1, anIndices.FindIndex(V));
556 aResult = GetEngine()->AddSubShape(theShape, anArray);
559 //The GetPoint() doesn't change object so no new function is required.
560 Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
562 //Make a Python command
563 GEOM::TPythonDump(aFunction, /*append=*/true)
564 << aResult << " = geompy.GetPoint(" << theShape << ", "
565 << theX << ", " << theY << ", " << theZ << ", " << theEpsilon << ")";
571 //=============================================================================
575 //=============================================================================
576 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetEdge
577 (Handle(GEOM_Object) theShape,
578 Handle(GEOM_Object) thePoint1,
579 Handle(GEOM_Object) thePoint2)
584 Handle(GEOM_Object) aResult;
587 if (theShape.IsNull() || thePoint1.IsNull() || thePoint2.IsNull()) return NULL;
589 TopoDS_Shape aBlockOrComp = theShape->GetValue();
590 if (aBlockOrComp.IsNull()) {
591 SetErrorCode("Given shape is null");
595 TopoDS_Shape anArg1 = thePoint1->GetValue();
596 TopoDS_Shape anArg2 = thePoint2->GetValue();
597 if (anArg1.IsNull() || anArg2.IsNull()) {
598 SetErrorCode("Null shape is given as argument");
601 if (anArg1.ShapeType() != TopAbs_VERTEX ||
602 anArg2.ShapeType() != TopAbs_VERTEX) {
603 SetErrorCode("Element for edge identification is not a vertex");
607 //Compute the Edge value
609 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
612 TopTools_IndexedDataMapOfShapeListOfShape MVE;
613 GEOMImpl_Block6Explorer::MapShapesAndAncestors
614 (aBlockOrComp, TopAbs_VERTEX, TopAbs_EDGE, MVE);
617 Standard_Integer ish, ext = MVE.Extent();
619 if (MVE.Contains(anArg1)) {
622 for (ish = 1; ish <= ext; ish++) {
623 TopoDS_Shape aShi = MVE.FindKey(ish);
624 if (BRepTools::Compare(TopoDS::Vertex(anArg1), TopoDS::Vertex(aShi))) {
631 if (MVE.Contains(anArg2)) {
634 for (ish = 1; ish <= ext; ish++) {
635 TopoDS_Shape aShi = MVE.FindKey(ish);
636 if (BRepTools::Compare(TopoDS::Vertex(anArg2), TopoDS::Vertex(aShi))) {
643 if (V1.IsNull() || V2.IsNull()) {
644 SetErrorCode("The given vertex does not belong to the shape");
649 Standard_Integer isFound =
650 GEOMImpl_Block6Explorer::FindEdge(anEdge, V1, V2, MVE, Standard_True);
652 SetErrorCode("The given vertices do not belong to one edge of the given shape");
654 } else if (isFound > 1) {
655 SetErrorCode("Multiple edges found by the given vertices of the shape");
658 TopTools_IndexedMapOfShape anIndices;
659 TopExp::MapShapes(aBlockOrComp, anIndices);
660 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
661 anArray->SetValue(1, anIndices.FindIndex(anEdge));
662 aResult = GetEngine()->AddSubShape(theShape, anArray);
664 } catch (Standard_Failure) {
665 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
666 SetErrorCode(aFail->GetMessageString());
670 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
672 //Make a Python command
673 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetEdge("
674 << theShape << ", " << thePoint1 << ", " << thePoint2 << ")";
680 //=============================================================================
684 //=============================================================================
685 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetEdgeNearPoint
686 (Handle(GEOM_Object) theShape,
687 Handle(GEOM_Object) thePoint)
692 Handle(GEOM_Object) aResult;
695 if (theShape.IsNull() || thePoint.IsNull()) return NULL;
697 TopoDS_Shape aBlockOrComp = theShape->GetValue();
698 if (aBlockOrComp.IsNull()) {
699 SetErrorCode("Given shape is null");
703 TopoDS_Shape anArg = thePoint->GetValue();
704 if (anArg.IsNull()) {
705 SetErrorCode("Null shape is given as argument");
708 if (anArg.ShapeType() != TopAbs_VERTEX) {
709 SetErrorCode("Element for edge identification is not a vertex");
713 //Compute the Edge value
715 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
720 TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
722 // 1. Explode blocks on edges
723 TopTools_MapOfShape mapShape;
724 Standard_Integer nbEdges = 0;
725 TopExp_Explorer exp (aBlockOrComp, TopAbs_EDGE);
726 for (; exp.More(); exp.Next()) {
727 if (mapShape.Add(exp.Current())) {
733 SetErrorCode("Given shape contains no edges");
738 Standard_Integer ind = 1;
739 TopTools_Array1OfShape anEdges (1, nbEdges);
740 TColStd_Array1OfReal aDistances (1, nbEdges);
741 for (exp.Init(aBlockOrComp, TopAbs_EDGE); exp.More(); exp.Next()) {
742 if (mapShape.Add(exp.Current())) {
743 TopoDS_Shape anEdge = exp.Current();
744 anEdges(ind) = anEdge;
746 // 2. Classify the point relatively each edge
747 BRepExtrema_DistShapeShape aDistTool (aVert, anEdges(ind));
748 if (!aDistTool.IsDone()) {
749 SetErrorCode("Can not find a distance from the given point to one of edges");
752 aDistances(ind) = aDistTool.Value();
757 // 3. Define edge, having minimum distance to the point
758 Standard_Real nearest = RealLast(), nbFound = 0;
759 Standard_Real prec = Precision::Confusion();
760 for (ind = 1; ind <= nbEdges; ind++) {
761 if (Abs(aDistances(ind) - nearest) < prec) {
763 } else if (aDistances(ind) < nearest) {
764 nearest = aDistances(ind);
765 aShape = anEdges(ind);
771 SetErrorCode("Multiple edges near the given point are found");
773 } else if (nbFound == 0) {
774 SetErrorCode("There are no edges near the given point");
777 TopTools_IndexedMapOfShape anIndices;
778 TopExp::MapShapes(aBlockOrComp, anIndices);
779 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
780 anArray->SetValue(1, anIndices.FindIndex(aShape));
781 aResult = GetEngine()->AddSubShape(theShape, anArray);
784 catch (Standard_Failure) {
785 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
786 SetErrorCode(aFail->GetMessageString());
790 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
792 //Make a Python command
793 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetEdgeNearPoint("
794 << theShape << ", " << thePoint << ")";
800 //=============================================================================
804 //=============================================================================
805 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByPoints
806 (Handle(GEOM_Object) theShape,
807 Handle(GEOM_Object) thePoint1,
808 Handle(GEOM_Object) thePoint2,
809 Handle(GEOM_Object) thePoint3,
810 Handle(GEOM_Object) thePoint4)
815 Handle(GEOM_Object) aResult;
818 if (theShape.IsNull() ||
819 thePoint1.IsNull() || thePoint2.IsNull() ||
820 thePoint3.IsNull() || thePoint4.IsNull()) return NULL;
822 TopoDS_Shape aBlockOrComp = theShape->GetValue();
823 if (aBlockOrComp.IsNull()) {
824 SetErrorCode("Block or compound is null");
828 TopoDS_Shape anArg1 = thePoint1->GetValue();
829 TopoDS_Shape anArg2 = thePoint2->GetValue();
830 TopoDS_Shape anArg3 = thePoint3->GetValue();
831 TopoDS_Shape anArg4 = thePoint4->GetValue();
832 if (anArg1.IsNull() || anArg2.IsNull() ||
833 anArg3.IsNull() || anArg4.IsNull()) {
834 SetErrorCode("Null shape is given as argument");
837 if (anArg1.ShapeType() != TopAbs_VERTEX ||
838 anArg2.ShapeType() != TopAbs_VERTEX ||
839 anArg3.ShapeType() != TopAbs_VERTEX ||
840 anArg4.ShapeType() != TopAbs_VERTEX) {
841 SetErrorCode("Element for face identification is not a vertex");
845 //Compute the Face value
847 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
852 TopTools_IndexedDataMapOfShapeListOfShape MVF;
853 GEOMImpl_Block6Explorer::MapShapesAndAncestors(aBlockOrComp, TopAbs_VERTEX, TopAbs_FACE, MVF);
855 TopoDS_Shape V1,V2,V3,V4;
856 Standard_Integer ish, ext = MVF.Extent();
858 if (MVF.Contains(anArg1)) {
861 for (ish = 1; ish <= ext; ish++) {
862 TopoDS_Shape aShi = MVF.FindKey(ish);
863 if (BRepTools::Compare(TopoDS::Vertex(anArg1), TopoDS::Vertex(aShi))) {
870 if (MVF.Contains(anArg2)) {
873 for (ish = 1; ish <= ext; ish++) {
874 TopoDS_Shape aShi = MVF.FindKey(ish);
875 if (BRepTools::Compare(TopoDS::Vertex(anArg2), TopoDS::Vertex(aShi))) {
882 if (MVF.Contains(anArg3)) {
885 for (ish = 1; ish <= ext; ish++) {
886 TopoDS_Shape aShi = MVF.FindKey(ish);
887 if (BRepTools::Compare(TopoDS::Vertex(anArg3), TopoDS::Vertex(aShi))) {
894 if (MVF.Contains(anArg4)) {
897 for (ish = 1; ish <= ext; ish++) {
898 TopoDS_Shape aShi = MVF.FindKey(ish);
899 if (BRepTools::Compare(TopoDS::Vertex(anArg4), TopoDS::Vertex(aShi))) {
906 if (V1.IsNull() || V2.IsNull() || V3.IsNull() || V4.IsNull()) {
907 SetErrorCode("The given vertex does not belong to the shape");
911 Standard_Integer isFound =
912 GEOMImpl_Block6Explorer::FindFace(aShape, V1, V2, V3, V4, MVF, Standard_True);
914 SetErrorCode("The given vertices do not belong to one face of the given shape");
916 } else if (isFound > 1) {
917 SetErrorCode("The given vertices belong to several faces of the given shape");
920 TopTools_IndexedMapOfShape anIndices;
921 TopExp::MapShapes(aBlockOrComp, anIndices);
922 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
923 anArray->SetValue(1, anIndices.FindIndex(aShape));
924 aResult = GetEngine()->AddSubShape(theShape, anArray);
927 catch (Standard_Failure) {
928 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
929 SetErrorCode(aFail->GetMessageString());
933 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
935 //Make a Python command
936 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceByPoints("
937 << theShape << ", " << thePoint1 << ", " << thePoint2
938 << ", " << thePoint3 << ", " << thePoint4 << ")";
944 //=============================================================================
948 //=============================================================================
949 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByEdges
950 (Handle(GEOM_Object) theShape,
951 Handle(GEOM_Object) theEdge1,
952 Handle(GEOM_Object) theEdge2)
957 Handle(GEOM_Object) aResult;
960 if (theShape.IsNull() || theEdge1.IsNull() || theEdge2.IsNull()) return NULL;
962 TopoDS_Shape aBlockOrComp = theShape->GetValue();
963 if (aBlockOrComp.IsNull()) {
964 SetErrorCode("Block or compound is null");
968 TopoDS_Shape anArg1 = theEdge1->GetValue();
969 TopoDS_Shape anArg2 = theEdge2->GetValue();
970 if (anArg1.IsNull() || anArg2.IsNull()) {
971 SetErrorCode("Null shape is given as argument");
974 if (anArg1.ShapeType() != TopAbs_EDGE ||
975 anArg2.ShapeType() != TopAbs_EDGE) {
976 SetErrorCode("Element for face identification is not an edge");
980 //Compute the Face value
982 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
987 TopTools_IndexedDataMapOfShapeListOfShape MEF;
988 GEOMImpl_Block6Explorer::MapShapesAndAncestors(aBlockOrComp, TopAbs_EDGE, TopAbs_FACE, MEF);
991 Standard_Integer ish, ext = MEF.Extent();
993 if (MEF.Contains(anArg1)) {
996 for (ish = 1; ish <= ext; ish++) {
997 TopoDS_Shape aShi = MEF.FindKey(ish);
998 if (GEOMImpl_Block6Explorer::IsSimilarEdges(anArg1, aShi)) {
1004 if (MEF.Contains(anArg2)) {
1007 for (ish = 1; ish <= ext; ish++) {
1008 TopoDS_Shape aShi = MEF.FindKey(ish);
1009 if (GEOMImpl_Block6Explorer::IsSimilarEdges(anArg2, aShi)) {
1015 if (E1.IsNull() || E2.IsNull()) {
1016 SetErrorCode("The given edge does not belong to the shape");
1020 const TopTools_ListOfShape& aFacesOfE1 = MEF.FindFromKey(E1);
1021 const TopTools_ListOfShape& aFacesOfE2 = MEF.FindFromKey(E2);
1023 Standard_Integer isFound = 0;
1024 TopTools_ListIteratorOfListOfShape anIterF1 (aFacesOfE1);
1025 for (; anIterF1.More(); anIterF1.Next()) {
1027 TopTools_ListIteratorOfListOfShape anIterF2 (aFacesOfE2);
1028 for (; anIterF2.More(); anIterF2.Next()) {
1030 if (anIterF1.Value().IsSame(anIterF2.Value())) {
1033 // Store the face, defined by two edges
1034 aShape = anIterF1.Value();
1039 SetErrorCode("The given edges do not belong to one face of the given shape");
1041 } else if (isFound > 1) {
1042 SetErrorCode("The given edges belong to several faces of the given shape");
1045 TopTools_IndexedMapOfShape anIndices;
1046 TopExp::MapShapes(aBlockOrComp, anIndices);
1047 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1048 anArray->SetValue(1, anIndices.FindIndex(aShape));
1049 aResult = GetEngine()->AddSubShape(theShape, anArray);
1052 catch (Standard_Failure) {
1053 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1054 SetErrorCode(aFail->GetMessageString());
1058 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1060 //Make a Python command
1061 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceByEdges("
1062 << theShape << ", " << theEdge1 << ", " << theEdge2 << ")";
1068 //=============================================================================
1072 //=============================================================================
1073 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetOppositeFace
1074 (Handle(GEOM_Object) theShape,
1075 Handle(GEOM_Object) theFace)
1080 Handle(GEOM_Object) aResult;
1083 if (theShape.IsNull() || theFace.IsNull()) return NULL;
1085 TopoDS_Shape aBlockOrComp = theShape->GetValue();
1086 if (aBlockOrComp.IsNull()) {
1087 SetErrorCode("Block is null");
1090 if (aBlockOrComp.ShapeType() != TopAbs_SOLID) {
1091 SetErrorCode("Shape is not a block");
1095 TopoDS_Shape anArg = theFace->GetValue();
1096 if (anArg.IsNull()) {
1097 SetErrorCode("Null shape is given as argument");
1100 if (anArg.ShapeType() != TopAbs_FACE) {
1101 SetErrorCode("Element for face identification is not a face");
1105 //Compute the Face value
1107 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
1110 TopoDS_Shape aShape;
1112 GEOMImpl_Block6Explorer aBlockTool;
1113 aBlockTool.InitByBlockAndFace(aBlockOrComp, anArg);
1114 aShape = aBlockTool.GetFace(2);
1116 TopTools_IndexedMapOfShape anIndices;
1117 TopExp::MapShapes(aBlockOrComp, anIndices);
1118 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1119 anArray->SetValue(1, anIndices.FindIndex(aShape));
1120 aResult = GetEngine()->AddSubShape(theShape, anArray);
1122 catch (Standard_Failure) {
1123 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1124 SetErrorCode(aFail->GetMessageString());
1128 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1130 //Make a Python command
1131 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetOppositeFace("
1132 << theShape << ", " << theFace << ")";
1138 //=============================================================================
1142 //=============================================================================
1143 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceNearPoint
1144 (Handle(GEOM_Object) theShape,
1145 Handle(GEOM_Object) thePoint)
1150 Handle(GEOM_Object) aResult;
1153 if (theShape.IsNull() || thePoint.IsNull()) return NULL;
1155 TopoDS_Shape aBlockOrComp = theShape->GetValue();
1156 if (aBlockOrComp.IsNull()) {
1157 SetErrorCode("Block or compound is null");
1161 TopoDS_Shape anArg = thePoint->GetValue();
1162 if (anArg.IsNull()) {
1163 SetErrorCode("Null shape is given as argument");
1166 if (anArg.ShapeType() != TopAbs_VERTEX) {
1167 SetErrorCode("Element for face identification is not a vertex");
1171 //Compute the Face value
1173 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
1176 TopoDS_Shape aShape;
1178 TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
1179 gp_Pnt aPnt = BRep_Tool::Pnt(aVert);
1180 Standard_Real PX, PY, PZ;
1181 aPnt.Coord(PX, PY, PZ);
1183 // 1. Classify the point relatively each face
1184 Standard_Integer nearest = 2, nbFound = 0;
1185 TopTools_DataMapOfShapeInteger mapShapeDist;
1186 TopExp_Explorer exp (aBlockOrComp, TopAbs_FACE);
1187 for (; exp.More(); exp.Next()) {
1188 TopoDS_Shape aFace = exp.Current();
1190 if (!mapShapeDist.IsBound(aFace)) {
1191 Standard_Integer aDistance = 2;
1193 // 1.a. Classify relatively Surface
1194 Handle(Geom_Surface) aSurf = BRep_Tool::Surface(TopoDS::Face(aFace));
1195 Handle(ShapeAnalysis_Surface) aSurfAna = new ShapeAnalysis_Surface (aSurf);
1196 gp_Pnt2d p2dOnSurf = aSurfAna->ValueOfUV(aPnt, Precision::Confusion());
1197 gp_Pnt p3dOnSurf = aSurfAna->Value(p2dOnSurf);
1198 Standard_Real aDist = p3dOnSurf.Distance(aPnt);
1199 if (aDist > Precision::Confusion()) {
1203 // 1.b. Classify relatively the face itself
1204 BRepClass_FaceClassifier FC (TopoDS::Face(aFace), p2dOnSurf, Precision::Confusion());
1205 if (FC.State() == TopAbs_IN) {
1207 } else if (FC.State() == TopAbs_ON) {
1214 if (aDistance < nearest) {
1215 nearest = aDistance;
1219 // A first found face, containing the point inside, will be returned.
1220 // It is the solution, if there are no
1221 // coincident or intersecting faces in the compound.
1222 if (nearest == -1) break;
1224 } else if (aDistance == nearest) {
1229 mapShapeDist.Bind(aFace, aDistance);
1230 } // if (!mapShapeDist.IsBound(aFace))
1233 // 2. Define face, containing the point or having minimum distance to it
1236 // The point is on boundary of some faces and there are
1237 // no faces, having the point inside
1238 SetErrorCode("Multiple faces near the given point are found");
1241 } else if (nearest == 1) {
1242 // The point is outside some faces and there are
1243 // no faces, having the point inside or on boundary.
1244 // We will get a nearest face
1245 Standard_Real bigReal = RealLast();
1246 Standard_Real minDist = bigReal;
1247 TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
1248 for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
1249 if (mapShapeDistIter.Value() == 1) {
1250 TopoDS_Shape aFace = mapShapeDistIter.Key();
1251 Standard_Real aDist = bigReal;
1253 // 2.a. Fast check of distance - if point projection on surface is on face
1254 Handle(Geom_Surface) aSurf = BRep_Tool::Surface(TopoDS::Face(aFace));
1255 Handle(ShapeAnalysis_Surface) aSurfAna = new ShapeAnalysis_Surface (aSurf);
1256 gp_Pnt2d p2dOnSurf = aSurfAna->ValueOfUV(aPnt, Precision::Confusion());
1257 gp_Pnt p3dOnSurf = aSurfAna->Value(p2dOnSurf);
1258 aDist = p3dOnSurf.Distance(aPnt);
1260 BRepClass_FaceClassifier FC (TopoDS::Face(aFace), p2dOnSurf, Precision::Confusion());
1261 if (FC.State() == TopAbs_OUT) {
1262 if (aDist < minDist) {
1263 // 2.b. Slow check - if point projection on surface is outside of face
1264 BRepExtrema_DistShapeShape aDistTool (aVert, aFace);
1265 if (!aDistTool.IsDone()) {
1266 SetErrorCode("Can not find a distance from the given point to one of faces");
1269 aDist = aDistTool.Value();
1275 if (aDist < minDist) {
1281 } else { // nearest == -1
1282 // // The point is inside some faces.
1283 // // We will get a face with nearest center
1284 // Standard_Real minDist = RealLast();
1285 // TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
1286 // for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
1287 // if (mapShapeDistIter.Value() == -1) {
1288 // TopoDS_Shape aFace = mapShapeDistIter.Key();
1289 // GProp_GProps aSystem;
1290 // BRepGProp::SurfaceProperties(aFace, aSystem);
1291 // gp_Pnt aCenterMass = aSystem.CentreOfMass();
1293 // Standard_Real aDist = aCenterMass.Distance(aPnt);
1294 // if (aDist < minDist) {
1301 } // if (nbFound > 1)
1304 SetErrorCode("There are no faces near the given point");
1307 TopTools_IndexedMapOfShape anIndices;
1308 TopExp::MapShapes(aBlockOrComp, anIndices);
1309 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1310 anArray->SetValue(1, anIndices.FindIndex(aShape));
1311 aResult = GetEngine()->AddSubShape(theShape, anArray);
1314 catch (Standard_Failure) {
1315 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1316 SetErrorCode(aFail->GetMessageString());
1320 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1322 //Make a Python command
1323 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceNearPoint("
1324 << theShape << ", " << thePoint << ")";
1330 //=============================================================================
1334 //=============================================================================
1335 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByNormale
1336 (Handle(GEOM_Object) theShape,
1337 Handle(GEOM_Object) theVector)
1342 Handle(GEOM_Object) aResult;
1345 if (theShape.IsNull() || theVector.IsNull()) return NULL;
1347 TopoDS_Shape aBlockOrComp = theShape->GetValue();
1348 if (aBlockOrComp.IsNull()) {
1349 SetErrorCode("Block or compound is null");
1353 TopoDS_Shape anArg = theVector->GetValue();
1354 if (anArg.IsNull()) {
1355 SetErrorCode("Null shape is given as argument");
1358 if (anArg.ShapeType() != TopAbs_EDGE) {
1359 SetErrorCode("Element for normale identification is not an edge");
1363 //Compute the Face value
1365 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
1368 TopoDS_Shape aShape;
1370 TopoDS_Edge anEdge = TopoDS::Edge(anArg);
1371 TopoDS_Vertex V1, V2;
1372 TopExp::Vertices(anEdge, V1, V2, Standard_True);
1373 gp_Pnt P1 = BRep_Tool::Pnt(V1);
1374 gp_Pnt P2 = BRep_Tool::Pnt(V2);
1375 gp_Vec aVec (P1, P2);
1376 if (aVec.Magnitude() < Precision::Confusion()) {
1377 SetErrorCode("Vector with null magnitude is given");
1381 Standard_Real minAngle = RealLast();
1382 TopTools_MapOfShape mapShape;
1383 TopExp_Explorer exp (aBlockOrComp, TopAbs_FACE);
1384 for (; exp.More(); exp.Next()) {
1385 if (mapShape.Add(exp.Current())) {
1386 TopoDS_Face aFace = TopoDS::Face(exp.Current());
1387 BRepAdaptor_Surface SF (aFace);
1389 Standard_Real u, v, x;
1391 // find a point on the surface to get normal direction in
1392 u = SF.FirstUParameter();
1393 x = SF.LastUParameter();
1394 if (Precision::IsInfinite(u)) {
1395 u = (Precision::IsInfinite(x)) ? 0. : x;
1396 } else if (!Precision::IsInfinite(x)) {
1400 v = SF.FirstVParameter();
1401 x = SF.LastVParameter();
1402 if (Precision::IsInfinite(v)) {
1403 v = (Precision::IsInfinite(x)) ? 0. : x;
1404 } else if (!Precision::IsInfinite(x)) {
1408 // compute the normal direction
1410 SF.D1(u,v,P1,Vec1,Vec2);
1411 gp_Vec V = Vec1.Crossed(Vec2);
1413 if (V.Magnitude() < Precision::Confusion()) {
1414 SetErrorCode("Normal vector of a face has null magnitude");
1418 // consider the face orientation
1419 if (aFace.Orientation() == TopAbs_REVERSED ||
1420 aFace.Orientation() == TopAbs_INTERNAL) {
1424 // compute the angle and compare with the minimal one
1425 Standard_Real anAngle = aVec.Angle(V);
1426 if (anAngle < minAngle) {
1433 if (aShape.IsNull()) {
1434 SetErrorCode("Failed to find a face by the given normale");
1437 TopTools_IndexedMapOfShape anIndices;
1438 TopExp::MapShapes(aBlockOrComp, anIndices);
1439 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1440 anArray->SetValue(1, anIndices.FindIndex(aShape));
1441 aResult = GetEngine()->AddSubShape(theShape, anArray);
1444 catch (Standard_Failure) {
1445 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1446 SetErrorCode(aFail->GetMessageString());
1450 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1452 //Make a Python command
1453 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceByNormale("
1454 << theShape << ", " << theVector << ")";
1460 //=============================================================================
1462 * IsCompoundOfBlocks
1464 //=============================================================================
1465 Standard_Boolean GEOMImpl_IBlocksOperations::IsCompoundOfBlocks
1466 (Handle(GEOM_Object) theCompound,
1467 const Standard_Integer theMinNbFaces,
1468 const Standard_Integer theMaxNbFaces,
1469 Standard_Integer& theNbBlocks)
1472 Standard_Boolean isCompOfBlocks = Standard_False;
1475 if (theCompound.IsNull()) return isCompOfBlocks;
1476 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
1479 isCompOfBlocks = Standard_True;
1481 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
1484 TopTools_MapOfShape mapShape;
1485 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
1486 for (; exp.More(); exp.Next()) {
1487 if (mapShape.Add(exp.Current())) {
1488 TopoDS_Shape aSolid = exp.Current();
1490 TopTools_MapOfShape mapFaces;
1491 TopExp_Explorer expF (aSolid, TopAbs_FACE);
1492 Standard_Integer nbFaces = 0;
1493 for (; expF.More(); expF.Next()) {
1494 if (mapFaces.Add(expF.Current())) {
1496 if (nbFaces > theMaxNbFaces) {
1497 isCompOfBlocks = Standard_False;
1502 if (nbFaces < theMinNbFaces || theMaxNbFaces < nbFaces) {
1503 isCompOfBlocks = Standard_False;
1510 catch (Standard_Failure) {
1511 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1512 SetErrorCode(aFail->GetMessageString());
1513 return isCompOfBlocks;
1517 return isCompOfBlocks;
1520 //=============================================================================
1522 * Set of functions, used by CheckCompoundOfBlocks() method
1524 //=============================================================================
1525 void GEOMImpl_IBlocksOperations::AddBlocksFrom (const TopoDS_Shape& theShape,
1526 TopTools_ListOfShape& BLO,
1527 TopTools_ListOfShape& NOT,
1528 TopTools_ListOfShape& EXT)
1530 TopAbs_ShapeEnum aType = theShape.ShapeType();
1532 case TopAbs_COMPOUND:
1533 case TopAbs_COMPSOLID:
1535 TopoDS_Iterator It (theShape);
1536 for (; It.More(); It.Next()) {
1537 AddBlocksFrom(It.Value(), BLO, NOT, EXT);
1543 // Check, if there are seam or degenerated edges
1544 BlockFix_CheckTool aTool;
1545 aTool.SetShape(theShape);
1547 if (aTool.NbPossibleBlocks() > 0) {
1548 EXT.Append(theShape);
1550 // Count faces and edges in each face to recognize blocks
1551 TopTools_MapOfShape mapFaces;
1552 Standard_Integer nbFaces = 0;
1553 Standard_Boolean hasNonQuadr = Standard_False;
1554 TopExp_Explorer expF (theShape, TopAbs_FACE);
1556 for (; expF.More(); expF.Next()) {
1557 if (mapFaces.Add(expF.Current())) {
1559 if (nbFaces > 6) break;
1562 TopoDS_Shape aF = expF.Current();
1563 TopExp_Explorer wires (aF, TopAbs_WIRE);
1564 if (!wires.More()) {
1565 // no wire in the face
1566 hasNonQuadr = Standard_True;
1569 TopoDS_Shape aWire = wires.Current();
1572 // multiple wires in the face
1573 hasNonQuadr = Standard_True;
1577 // Check number of edges in the face
1578 Standard_Integer nbEdges = 0;
1579 TopTools_MapOfShape mapEdges;
1580 TopExp_Explorer expW (aWire, TopAbs_EDGE);
1581 for (; expW.More(); expW.Next()) {
1582 if (mapEdges.Add(expW.Current())) {
1584 if (nbEdges > 4) break;
1588 hasNonQuadr = Standard_True;
1593 if (nbFaces == 6 && !hasNonQuadr) {
1594 BLO.Append(theShape);
1596 NOT.Append(theShape);
1602 NOT.Append(theShape);
1606 void AddBlocksFromOld (const TopoDS_Shape& theShape,
1607 TopTools_ListOfShape& BLO,
1608 TopTools_ListOfShape& NOT,
1609 TopTools_ListOfShape& DEG,
1610 TopTools_ListOfShape& SEA)
1612 TopAbs_ShapeEnum aType = theShape.ShapeType();
1614 case TopAbs_COMPOUND:
1615 case TopAbs_COMPSOLID:
1617 TopoDS_Iterator It (theShape);
1618 for (; It.More(); It.Next()) {
1619 AddBlocksFromOld(It.Value(), BLO, NOT, DEG, SEA);
1625 TopTools_MapOfShape mapFaces;
1626 TopExp_Explorer expF (theShape, TopAbs_FACE);
1627 Standard_Integer nbFaces = 0;
1628 Standard_Boolean hasNonQuadr = Standard_False;
1629 Standard_Boolean hasDegenerated = Standard_False;
1630 Standard_Boolean hasSeam = Standard_False;
1631 for (; expF.More(); expF.Next()) {
1632 if (mapFaces.Add(expF.Current())) {
1634 if (nbFaces > 6) break;
1636 // Check number of edges in the face
1637 Standard_Integer nbEdges = 0;
1638 TopTools_MapOfShape mapEdges;
1641 TopoDS_Shape aF = expF.Current();
1642 TopExp_Explorer wires (aF, TopAbs_WIRE);
1643 if (!wires.More()) {
1644 // no wire in the face
1645 hasNonQuadr = Standard_True;
1648 TopoDS_Shape aWire = wires.Current();
1651 // multiple wires in the face
1652 hasNonQuadr = Standard_True;
1657 BRepTools_WireExplorer aWE (TopoDS::Wire(aWire), TopoDS::Face(aF));
1658 for (; aWE.More(); aWE.Next(), nbEdges++) {
1659 if (BRep_Tool::Degenerated(aWE.Current())) {
1660 // degenerated edge found
1661 hasDegenerated = Standard_True;
1664 if (mapEdges.Contains(aWE.Current())) {
1666 hasSeam = Standard_True;
1669 mapEdges.Add(aWE.Current());
1672 hasNonQuadr = Standard_True;
1677 if (hasDegenerated || hasSeam) {
1678 if (hasDegenerated) {
1679 DEG.Append(theShape);
1682 SEA.Append(theShape);
1684 } else if (hasNonQuadr) {
1685 NOT.Append(theShape);
1687 BLO.Append(theShape);
1690 NOT.Append(theShape);
1695 NOT.Append(theShape);
1699 #define REL_NOT_CONNECTED 0
1701 #define REL_NOT_GLUED 2
1702 #define REL_COLLISION_VV 3
1703 #define REL_COLLISION_FF 4
1704 #define REL_COLLISION_EE 5
1705 #define REL_UNKNOWN 6
1707 Standard_Integer BlocksRelation (const TopoDS_Shape& theBlock1,
1708 const TopoDS_Shape& theBlock2)
1710 // Compare bounding boxes before calling BRepExtrema_DistShapeShape
1711 Standard_Real Xmin1, Ymin1, Zmin1, Xmax1, Ymax1, Zmax1;
1712 Standard_Real Xmin2, Ymin2, Zmin2, Xmax2, Ymax2, Zmax2;
1714 BRepBndLib::Add(theBlock1, B1);
1715 BRepBndLib::Add(theBlock2, B2);
1716 B1.Get(Xmin1, Ymin1, Zmin1, Xmax1, Ymax1, Zmax1);
1717 B2.Get(Xmin2, Ymin2, Zmin2, Xmax2, Ymax2, Zmax2);
1718 if (Xmax2 < Xmin1 || Xmax1 < Xmin2 ||
1719 Ymax2 < Ymin1 || Ymax1 < Ymin2 ||
1720 Zmax2 < Zmin1 || Zmax1 < Zmin2) {
1721 return REL_NOT_CONNECTED;
1724 BRepExtrema_DistShapeShape dst (theBlock1, theBlock2);
1725 if (!dst.IsDone()) {
1729 if (dst.Value() > Precision::Confusion()) {
1730 return REL_NOT_CONNECTED;
1733 if (dst.InnerSolution()) {
1734 return REL_COLLISION_VV;
1737 Standard_Integer nbSol = dst.NbSolution();
1738 Standard_Integer relation = REL_OK;
1739 Standard_Integer nbVerts = 0;
1740 Standard_Integer nbEdges = 0;
1741 Standard_Integer sol = 1;
1742 for (; sol <= nbSol; sol++) {
1743 BRepExtrema_SupportType supp1 = dst.SupportTypeShape1(sol);
1744 BRepExtrema_SupportType supp2 = dst.SupportTypeShape2(sol);
1745 if (supp1 == BRepExtrema_IsVertex && supp2 == BRepExtrema_IsVertex) {
1747 } else if (supp1 == BRepExtrema_IsInFace || supp2 == BRepExtrema_IsInFace) {
1748 return REL_COLLISION_FF;
1749 } else if (supp1 == BRepExtrema_IsOnEdge && supp2 == BRepExtrema_IsOnEdge) {
1751 } else if ((supp1 == BRepExtrema_IsOnEdge && supp2 == BRepExtrema_IsVertex) ||
1752 (supp2 == BRepExtrema_IsOnEdge && supp1 == BRepExtrema_IsVertex)) {
1753 relation = REL_COLLISION_EE;
1758 if (relation != REL_OK) {
1762 TColStd_Array1OfInteger vertSol (1, nbVerts);
1763 TopTools_Array1OfShape V1 (1, nbVerts);
1764 TopTools_Array1OfShape V2 (1, nbVerts);
1765 Standard_Integer ivs = 0;
1766 for (sol = 1; sol <= nbSol; sol++) {
1767 if (dst.SupportTypeShape1(sol) == BRepExtrema_IsVertex &&
1768 dst.SupportTypeShape2(sol) == BRepExtrema_IsVertex) {
1769 TopoDS_Vertex Vcur = TopoDS::Vertex(dst.SupportOnShape1(sol));
1770 // Check, that this vertex is far enough from other solution vertices.
1771 Standard_Integer ii = 1;
1772 for (; ii <= ivs; ii++) {
1773 if (BRepTools::Compare(TopoDS::Vertex(V1(ii)), Vcur)) {
1780 V2(ivs) = dst.SupportOnShape2(sol);
1784 // As we deal only with quadrangles,
1785 // 2, 3 or 4 vertex solutions can be found.
1788 return REL_COLLISION_FF;
1790 return REL_NOT_CONNECTED;
1796 // Check sharing of coincident entities.
1797 if (ivs == 2 || ivs == 3) {
1798 // Map vertices and edges of the blocks
1799 TopTools_IndexedDataMapOfShapeListOfShape MVE1, MVE2;
1800 GEOMImpl_Block6Explorer::MapShapesAndAncestors
1801 (theBlock1, TopAbs_VERTEX, TopAbs_EDGE, MVE1);
1802 GEOMImpl_Block6Explorer::MapShapesAndAncestors
1803 (theBlock2, TopAbs_VERTEX, TopAbs_EDGE, MVE2);
1807 TopoDS_Shape anEdge1, anEdge2;
1808 GEOMImpl_Block6Explorer::FindEdge(anEdge1, V1(1), V1(2), MVE1);
1809 if (anEdge1.IsNull()) return REL_UNKNOWN;
1811 GEOMImpl_Block6Explorer::FindEdge(anEdge2, V2(1), V2(2), MVE2);
1812 if (anEdge2.IsNull()) return REL_UNKNOWN;
1814 if (!anEdge1.IsSame(anEdge2)) return REL_NOT_GLUED;
1816 } else { // ivs == 3
1817 // Find common edges
1818 Standard_Integer e1_v1 = 1;
1819 Standard_Integer e1_v2 = 2;
1820 Standard_Integer e2_v1 = 3;
1821 Standard_Integer e2_v2 = 1;
1823 TopoDS_Shape anEdge11, anEdge12;
1824 GEOMImpl_Block6Explorer::FindEdge(anEdge11, V1(e1_v1), V1(e1_v2), MVE1);
1825 if (anEdge11.IsNull()) {
1828 GEOMImpl_Block6Explorer::FindEdge(anEdge11, V1(e1_v1), V1(e1_v2), MVE1);
1829 if (anEdge11.IsNull()) return REL_UNKNOWN;
1831 GEOMImpl_Block6Explorer::FindEdge(anEdge12, V1(e2_v1), V1(e2_v2), MVE1);
1832 if (anEdge12.IsNull()) {
1834 GEOMImpl_Block6Explorer::FindEdge(anEdge12, V1(e2_v1), V1(e2_v2), MVE1);
1835 if (anEdge12.IsNull()) return REL_UNKNOWN;
1838 TopoDS_Shape anEdge21, anEdge22;
1839 GEOMImpl_Block6Explorer::FindEdge(anEdge21, V2(e1_v1), V2(e1_v2), MVE2);
1840 if (anEdge21.IsNull()) return REL_UNKNOWN;
1841 GEOMImpl_Block6Explorer::FindEdge(anEdge22, V2(e2_v1), V2(e2_v2), MVE2);
1842 if (anEdge22.IsNull()) return REL_UNKNOWN;
1844 // Check of edges coincidence (with some precision) have to be done here
1845 // if (!anEdge11.IsEqual(anEdge21)) return REL_UNKNOWN;
1846 // if (!anEdge12.IsEqual(anEdge22)) return REL_UNKNOWN;
1848 // Check of edges sharing
1849 if (!anEdge11.IsSame(anEdge21)) return REL_NOT_GLUED;
1850 if (!anEdge12.IsSame(anEdge22)) return REL_NOT_GLUED;
1855 // Map vertices and faces of the blocks
1856 TopTools_IndexedDataMapOfShapeListOfShape MVF1, MVF2;
1857 GEOMImpl_Block6Explorer::MapShapesAndAncestors
1858 (theBlock1, TopAbs_VERTEX, TopAbs_FACE, MVF1);
1859 GEOMImpl_Block6Explorer::MapShapesAndAncestors
1860 (theBlock2, TopAbs_VERTEX, TopAbs_FACE, MVF2);
1862 TopoDS_Shape aFace1, aFace2;
1863 GEOMImpl_Block6Explorer::FindFace(aFace1, V1(1), V1(2), V1(3), V1(4), MVF1);
1864 if (aFace1.IsNull()) return REL_UNKNOWN;
1865 GEOMImpl_Block6Explorer::FindFace(aFace2, V2(1), V2(2), V2(3), V2(4), MVF2);
1866 if (aFace2.IsNull()) return REL_UNKNOWN;
1868 // Check of faces coincidence (with some precision) have to be done here
1869 // if (!aFace1.IsEqual(aFace2)) return REL_UNKNOWN;
1871 // Check of faces sharing
1872 if (!aFace1.IsSame(aFace2)) return REL_NOT_GLUED;
1878 void FindConnected (const Standard_Integer theBlockIndex,
1879 const TColStd_Array2OfInteger& theRelations,
1880 TColStd_MapOfInteger& theProcessedMap,
1881 TColStd_MapOfInteger& theConnectedMap)
1883 theConnectedMap.Add(theBlockIndex);
1884 theProcessedMap.Add(theBlockIndex);
1886 Standard_Integer nbBlocks = theRelations.ColLength();
1887 Standard_Integer col = 1;
1888 for (; col <= nbBlocks; col++) {
1889 if (theRelations(theBlockIndex, col) == REL_OK ||
1890 theRelations(theBlockIndex, col) == REL_NOT_GLUED) {
1891 if (!theProcessedMap.Contains(col)) {
1892 FindConnected(col, theRelations, theProcessedMap, theConnectedMap);
1898 Standard_Boolean HasAnyConnection (const Standard_Integer theBlockIndex,
1899 const TColStd_MapOfInteger& theWith,
1900 const TColStd_Array2OfInteger& theRelations,
1901 TColStd_MapOfInteger& theProcessedMap)
1903 theProcessedMap.Add(theBlockIndex);
1905 Standard_Integer nbBlocks = theRelations.ColLength();
1906 Standard_Integer col = 1;
1907 for (; col <= nbBlocks; col++) {
1908 if (theRelations(theBlockIndex, col) != REL_NOT_CONNECTED) {
1909 if (!theProcessedMap.Contains(col)) {
1910 if (theWith.Contains(col))
1911 return Standard_True;
1912 if (HasAnyConnection(col, theWith, theRelations, theProcessedMap))
1913 return Standard_True;
1918 return Standard_False;
1921 //=============================================================================
1923 * CheckCompoundOfBlocksOld
1925 //=============================================================================
1926 Standard_Boolean GEOMImpl_IBlocksOperations::CheckCompoundOfBlocksOld
1927 (Handle(GEOM_Object) theCompound,
1928 std::list<BCError>& theErrors)
1932 if (theCompound.IsNull()) return Standard_False;
1933 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
1935 Standard_Boolean isCompOfBlocks = Standard_True;
1937 // Map sub-shapes and their indices
1938 TopTools_IndexedMapOfShape anIndices;
1939 TopExp::MapShapes(aBlockOrComp, anIndices);
1941 // 1. Report non-blocks
1942 TopTools_ListOfShape NOT; // Not blocks
1943 TopTools_ListOfShape DEG; // Hexahedral solids, having degenerated edges
1944 TopTools_ListOfShape SEA; // Hexahedral solids, having seam edges
1945 TopTools_ListOfShape BLO; // All blocks from the given compound
1946 AddBlocksFromOld(aBlockOrComp, BLO, NOT, DEG, SEA);
1948 if (NOT.Extent() > 0) {
1949 isCompOfBlocks = Standard_False;
1951 anErr.error = NOT_BLOCK;
1952 TopTools_ListIteratorOfListOfShape it (NOT);
1953 for (; it.More(); it.Next()) {
1954 anErr.incriminated.push_back(anIndices.FindIndex(it.Value()));
1956 theErrors.push_back(anErr);
1959 if (DEG.Extent() > 0 || SEA.Extent() > 0) {
1960 isCompOfBlocks = Standard_False;
1962 anErr.error = EXTRA_EDGE;
1964 TopTools_ListIteratorOfListOfShape itDEG (DEG);
1965 for (; itDEG.More(); itDEG.Next()) {
1966 anErr.incriminated.push_back(anIndices.FindIndex(itDEG.Value()));
1969 TopTools_ListIteratorOfListOfShape itSEA (SEA);
1970 for (; itSEA.More(); itSEA.Next()) {
1971 anErr.incriminated.push_back(anIndices.FindIndex(itSEA.Value()));
1974 theErrors.push_back(anErr);
1977 Standard_Integer nbBlocks = BLO.Extent();
1978 if (nbBlocks == 0) {
1979 isCompOfBlocks = Standard_False;
1981 return isCompOfBlocks;
1983 if (nbBlocks == 1) {
1985 return isCompOfBlocks;
1988 // Convert list of blocks into array for easy and fast access
1989 Standard_Integer ibl = 1;
1990 TopTools_Array1OfShape aBlocks (1, nbBlocks);
1991 TopTools_ListIteratorOfListOfShape BLOit (BLO);
1992 for (; BLOit.More(); BLOit.Next(), ibl++) {
1993 aBlocks.SetValue(ibl, BLOit.Value());
1996 // 2. Find relations between all blocks,
1997 // report connection errors (NOT_GLUED and INVALID_CONNECTION)
1998 TColStd_Array2OfInteger aRelations (1, nbBlocks, 1, nbBlocks);
1999 aRelations.Init(REL_NOT_CONNECTED);
2001 Standard_Integer row = 1;
2002 for (row = 1; row <= nbBlocks; row++) {
2003 TopoDS_Shape aBlock = aBlocks.Value(row);
2005 Standard_Integer col = row + 1;
2006 for (; col <= nbBlocks; col++) {
2007 Standard_Integer aRel = BlocksRelation(aBlock, aBlocks.Value(col));
2008 if (aRel != REL_NOT_CONNECTED) {
2009 aRelations.SetValue(row, col, aRel);
2010 aRelations.SetValue(col, row, aRel);
2011 if (aRel == REL_NOT_GLUED) {
2012 // report connection error
2013 isCompOfBlocks = Standard_False;
2015 anErr.error = NOT_GLUED;
2016 anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(row)));
2017 anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(col)));
2018 theErrors.push_back(anErr);
2019 } else if (aRel == REL_COLLISION_VV ||
2020 aRel == REL_COLLISION_FF ||
2021 aRel == REL_COLLISION_EE ||
2022 aRel == REL_UNKNOWN) {
2023 // report connection error
2024 isCompOfBlocks = Standard_False;
2026 anErr.error = INVALID_CONNECTION;
2027 anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(row)));
2028 anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(col)));
2029 theErrors.push_back(anErr);
2036 // 3. Find largest set of connected (good connection or not glued) blocks
2037 TColStd_MapOfInteger aProcessedMap;
2038 TColStd_MapOfInteger aLargestSet;
2039 TColStd_MapOfInteger aCurrentSet;
2040 for (ibl = 1; ibl <= nbBlocks; ibl++) {
2041 if (!aProcessedMap.Contains(ibl)) {
2042 aCurrentSet.Clear();
2043 FindConnected(ibl, aRelations, aProcessedMap, aCurrentSet);
2044 if (aCurrentSet.Extent() > aLargestSet.Extent()) {
2045 aLargestSet = aCurrentSet;
2050 // 4. Report all blocks, isolated from <aLargestSet>
2052 anErr.error = NOT_CONNECTED;
2053 Standard_Boolean hasIsolated = Standard_False;
2054 for (ibl = 1; ibl <= nbBlocks; ibl++) {
2055 if (!aLargestSet.Contains(ibl)) {
2056 aProcessedMap.Clear();
2057 if (!HasAnyConnection(ibl, aLargestSet, aRelations, aProcessedMap)) {
2058 // report connection absence
2059 hasIsolated = Standard_True;
2060 anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(ibl)));
2065 isCompOfBlocks = Standard_False;
2066 theErrors.push_back(anErr);
2070 return isCompOfBlocks;
2073 //=============================================================================
2077 //=============================================================================
2078 TCollection_AsciiString GEOMImpl_IBlocksOperations::PrintBCErrors
2079 (Handle(GEOM_Object) theCompound,
2080 const std::list<BCError>& theErrors)
2082 TCollection_AsciiString aDescr;
2084 std::list<BCError>::const_iterator errIt = theErrors.begin();
2086 for (; errIt != theErrors.end(); i++, errIt++) {
2087 BCError errStruct = *errIt;
2089 switch (errStruct.error) {
2091 aDescr += "\n\tNot a Blocks: ";
2094 aDescr += "\n\tHexahedral solids with degenerated and/or seam edges: ";
2096 case INVALID_CONNECTION:
2097 aDescr += "\n\tInvalid connection between two blocks: ";
2100 aDescr += "\n\tBlocks, not connected with main body: ";
2103 aDescr += "\n\tNot glued blocks: ";
2109 std::list<int> sshList = errStruct.incriminated;
2110 std::list<int>::iterator sshIt = sshList.begin();
2112 for (; sshIt != sshList.end(); jj++, sshIt++) {
2115 aDescr += TCollection_AsciiString(*sshIt);
2122 //=============================================================================
2124 * CheckCompoundOfBlocks
2126 //=============================================================================
2127 Standard_Boolean GEOMImpl_IBlocksOperations::CheckCompoundOfBlocks
2128 (Handle(GEOM_Object) theCompound,
2129 std::list<BCError>& theErrors)
2133 if (theCompound.IsNull()) return Standard_False;
2134 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2136 Standard_Boolean isCompOfBlocks = Standard_True;
2138 // Map sub-shapes and their indices
2139 TopTools_IndexedMapOfShape anIndices;
2140 TopExp::MapShapes(aBlockOrComp, anIndices);
2142 // 1. Separate blocks from non-blocks
2143 TopTools_ListOfShape NOT; // Not blocks
2144 TopTools_ListOfShape EXT; // Hexahedral solids, having degenerated and/or seam edges
2145 TopTools_ListOfShape BLO; // All blocks from the given compound
2146 AddBlocksFrom(aBlockOrComp, BLO, NOT, EXT);
2148 // Report non-blocks
2149 if (NOT.Extent() > 0) {
2150 isCompOfBlocks = Standard_False;
2152 anErr.error = NOT_BLOCK;
2153 TopTools_ListIteratorOfListOfShape it (NOT);
2154 for (; it.More(); it.Next()) {
2155 anErr.incriminated.push_back(anIndices.FindIndex(it.Value()));
2157 theErrors.push_back(anErr);
2160 // Report solids, having degenerated and/or seam edges
2161 if (EXT.Extent() > 0) {
2162 isCompOfBlocks = Standard_False;
2164 anErr.error = EXTRA_EDGE;
2165 TopTools_ListIteratorOfListOfShape it (EXT);
2166 for (; it.More(); it.Next()) {
2167 anErr.incriminated.push_back(anIndices.FindIndex(it.Value()));
2169 theErrors.push_back(anErr);
2172 Standard_Integer nbBlocks = BLO.Extent();
2173 if (nbBlocks == 0) {
2174 isCompOfBlocks = Standard_False;
2176 return isCompOfBlocks;
2178 if (nbBlocks == 1) {
2180 return isCompOfBlocks;
2183 // Prepare data for 2. and 3.
2184 TColStd_Array2OfInteger aRelations (1, nbBlocks, 1, nbBlocks);
2185 aRelations.Init(REL_NOT_CONNECTED);
2187 TopTools_IndexedMapOfShape mapBlocks;
2190 TopoDS_Compound aComp;
2191 BB.MakeCompound(aComp);
2193 TopTools_ListIteratorOfListOfShape BLOit (BLO);
2194 for (; BLOit.More(); BLOit.Next()) {
2195 mapBlocks.Add(BLOit.Value());
2196 BB.Add(aComp, BLOit.Value());
2199 // 2. Find glued blocks (having shared faces)
2200 TopTools_IndexedDataMapOfShapeListOfShape mapFaceBlocks;
2201 GEOMImpl_Block6Explorer::MapShapesAndAncestors
2202 (aComp, TopAbs_FACE, TopAbs_SOLID, mapFaceBlocks);
2204 Standard_Integer prevInd = 0, curInd = 0;
2205 Standard_Integer ind = 1, nbFaces = mapFaceBlocks.Extent();
2206 for (; ind <= nbFaces; ind++) {
2207 const TopTools_ListOfShape& aGluedBlocks = mapFaceBlocks.FindFromIndex(ind);
2208 if (aGluedBlocks.Extent() > 1) { // Shared face found
2209 TopTools_ListIteratorOfListOfShape aGluedBlocksIt (aGluedBlocks);
2210 TopoDS_Shape prevBlock, curBlock;
2211 for (; aGluedBlocksIt.More(); aGluedBlocksIt.Next()) {
2212 curBlock = aGluedBlocksIt.Value();
2213 if (!prevBlock.IsNull()) {
2214 prevInd = mapBlocks.FindIndex(prevBlock);
2215 curInd = mapBlocks.FindIndex(curBlock);
2216 aRelations.SetValue(prevInd, curInd, REL_OK);
2217 aRelations.SetValue(curInd, prevInd, REL_OK);
2219 prevBlock = curBlock;
2224 // 3. Find not glued blocks
2225 GEOMAlgo_GlueAnalyser aGD;
2227 aGD.SetShape(aComp);
2228 aGD.SetTolerance(Precision::Confusion());
2229 aGD.SetCheckGeometry(Standard_True);
2232 Standard_Integer iErr, iWrn;
2233 iErr = aGD.ErrorStatus();
2235 SetErrorCode("Error in GEOMAlgo_GlueAnalyser");
2236 return isCompOfBlocks;
2238 iWrn = aGD.WarningStatus();
2240 MESSAGE("Warning in GEOMAlgo_GlueAnalyser");
2243 // Report not glued blocks
2244 if (aGD.HasSolidsToGlue()) {
2245 isCompOfBlocks = Standard_False;
2246 Standard_Integer aSx1Ind, aSx2Ind;
2248 const GEOMAlgo_ListOfCoupleOfShapes& aLCS = aGD.SolidsToGlue();
2249 GEOMAlgo_ListIteratorOfListOfCoupleOfShapes aItCS (aLCS);
2250 for (; aItCS.More(); aItCS.Next()) {
2251 const GEOMAlgo_CoupleOfShapes& aCS = aItCS.Value();
2252 const TopoDS_Shape& aSx1 = aCS.Shape1();
2253 const TopoDS_Shape& aSx2 = aCS.Shape2();
2255 aSx1Ind = mapBlocks.FindIndex(aSx1);
2256 aSx2Ind = mapBlocks.FindIndex(aSx2);
2257 aRelations.SetValue(aSx1Ind, aSx2Ind, NOT_GLUED);
2258 aRelations.SetValue(aSx2Ind, aSx1Ind, NOT_GLUED);
2261 anErr.error = NOT_GLUED;
2262 anErr.incriminated.push_back(anIndices.FindIndex(aSx1));
2263 anErr.incriminated.push_back(anIndices.FindIndex(aSx2));
2264 theErrors.push_back(anErr);
2268 // 4. Find largest set of connected (good connection or not glued) blocks
2269 Standard_Integer ibl = 1;
2270 TColStd_MapOfInteger aProcessedMap;
2271 TColStd_MapOfInteger aLargestSet;
2272 TColStd_MapOfInteger aCurrentSet;
2273 for (ibl = 1; ibl <= nbBlocks; ibl++) {
2274 if (!aProcessedMap.Contains(ibl)) {
2275 aCurrentSet.Clear();
2276 FindConnected(ibl, aRelations, aProcessedMap, aCurrentSet);
2277 if (aCurrentSet.Extent() > aLargestSet.Extent()) {
2278 aLargestSet = aCurrentSet;
2283 // 5. Report all blocks, isolated from <aLargestSet>
2285 anErr.error = NOT_CONNECTED;
2286 Standard_Boolean hasIsolated = Standard_False;
2287 for (ibl = 1; ibl <= nbBlocks; ibl++) {
2288 if (!aLargestSet.Contains(ibl)) {
2289 aProcessedMap.Clear();
2290 if (!HasAnyConnection(ibl, aLargestSet, aRelations, aProcessedMap)) {
2291 // report connection absence
2292 hasIsolated = Standard_True;
2293 anErr.incriminated.push_back(anIndices.FindIndex(mapBlocks.FindKey(ibl)));
2298 isCompOfBlocks = Standard_False;
2299 theErrors.push_back(anErr);
2303 return isCompOfBlocks;
2306 //=============================================================================
2310 //=============================================================================
2311 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::RemoveExtraEdges
2312 (Handle(GEOM_Object) theObject,
2313 const Standard_Integer theOptimumNbFaces)
2317 if (theObject.IsNull()) return NULL;
2319 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
2320 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be fixed
2322 //Add a new Copy object
2323 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
2326 Handle(GEOM_Function) aFunction =
2327 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_REMOVE_EXTRA);
2329 //Check if the function is set correctly
2330 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
2332 GEOMImpl_IBlockTrsf aTI (aFunction);
2333 aTI.SetOriginal(aLastFunction);
2334 aTI.SetOptimumNbFaces(theOptimumNbFaces);
2336 //Compute the fixed shape
2338 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
2341 if (!GetSolver()->ComputeFunction(aFunction)) {
2342 SetErrorCode("Block driver failed to remove extra edges of the given shape");
2346 catch (Standard_Failure) {
2347 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2348 SetErrorCode(aFail->GetMessageString());
2352 //Make a Python command
2353 GEOM::TPythonDump(aFunction) << aCopy
2354 << " = geompy.RemoveExtraEdges(" << theObject << ")";
2360 //=============================================================================
2364 //=============================================================================
2365 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::CheckAndImprove
2366 (Handle(GEOM_Object) theObject)
2370 if (theObject.IsNull()) return NULL;
2372 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
2373 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be fixed
2375 //Add a new Copy object
2376 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
2379 Handle(GEOM_Function) aFunction =
2380 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_COMPOUND_IMPROVE);
2382 //Check if the function is set correctly
2383 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
2385 GEOMImpl_IBlockTrsf aTI (aFunction);
2386 aTI.SetOriginal(aLastFunction);
2387 aTI.SetOptimumNbFaces(6);
2389 //Compute the fixed shape
2391 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
2394 if (!GetSolver()->ComputeFunction(aFunction)) {
2395 SetErrorCode("Block driver failed to improve the given blocks compound");
2399 catch (Standard_Failure) {
2400 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2401 SetErrorCode(aFail->GetMessageString());
2405 //Make a Python command
2406 GEOM::TPythonDump(aFunction) << aCopy
2407 << " = geompy.CheckAndImprove(" << theObject << ")";
2413 //=============================================================================
2415 * ExplodeCompoundOfBlocks
2417 //=============================================================================
2418 Handle(TColStd_HSequenceOfTransient) GEOMImpl_IBlocksOperations::ExplodeCompoundOfBlocks
2419 (Handle(GEOM_Object) theCompound,
2420 const Standard_Integer theMinNbFaces,
2421 const Standard_Integer theMaxNbFaces)
2425 if (theCompound.IsNull()) return NULL;
2426 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2427 if (aBlockOrComp.IsNull()) return NULL;
2429 Handle(TColStd_HSequenceOfTransient) aBlocks = new TColStd_HSequenceOfTransient;
2430 Handle(GEOM_Object) anObj;
2431 Handle(GEOM_Function) aFunction;
2433 TopTools_MapOfShape mapShape;
2434 TCollection_AsciiString anAsciiList, anEntry;
2437 TopTools_IndexedMapOfShape anIndices;
2438 TopExp::MapShapes(aBlockOrComp, anIndices);
2439 Handle(TColStd_HArray1OfInteger) anArray;
2443 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
2446 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2447 for (; exp.More(); exp.Next()) {
2448 if (mapShape.Add(exp.Current())) {
2449 TopoDS_Shape aSolid = exp.Current();
2451 TopTools_MapOfShape mapFaces;
2452 TopExp_Explorer expF (aSolid, TopAbs_FACE);
2453 Standard_Integer nbFaces = 0;
2454 for (; expF.More(); expF.Next()) {
2455 if (mapFaces.Add(expF.Current())) {
2460 if (theMinNbFaces <= nbFaces && nbFaces <= theMaxNbFaces) {
2461 anArray = new TColStd_HArray1OfInteger(1,1);
2462 anArray->SetValue(1, anIndices.FindIndex(aSolid));
2463 anObj = GetEngine()->AddSubShape(theCompound, anArray);
2464 aBlocks->Append(anObj);
2466 //Make a Python command
2467 TDF_Tool::Entry(anObj->GetEntry(), anEntry);
2468 anAsciiList += anEntry + ", ";
2473 catch (Standard_Failure) {
2474 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2475 SetErrorCode(aFail->GetMessageString());
2479 if (aBlocks->IsEmpty()) {
2480 SetErrorCode("There are no specified blocks in the given shape");
2484 anAsciiList.Trunc(anAsciiList.Length() - 2);
2486 //The explode doesn't change object so no new function is required.
2487 aFunction = theCompound->GetLastFunction();
2489 //Make a Python command
2490 GEOM::TPythonDump(aFunction, /*append=*/true)
2491 << "[" << anAsciiList.ToCString() << "] = geompy.MakeBlockExplode("
2492 << theCompound << ", " << theMinNbFaces << ", " << theMaxNbFaces << ")";
2498 //=============================================================================
2502 //=============================================================================
2503 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetBlockNearPoint
2504 (Handle(GEOM_Object) theCompound,
2505 Handle(GEOM_Object) thePoint)
2510 Handle(GEOM_Object) aResult;
2513 if (theCompound.IsNull() || thePoint.IsNull()) return NULL;
2515 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2516 if (aBlockOrComp.IsNull()) {
2517 SetErrorCode("Compound is null");
2520 if (aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
2521 aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
2522 SetErrorCode("Shape to find block in is not a compound");
2526 TopoDS_Shape anArg = thePoint->GetValue();
2527 if (anArg.IsNull()) {
2528 SetErrorCode("Point is null");
2531 if (anArg.ShapeType() != TopAbs_VERTEX) {
2532 SetErrorCode("Shape for block identification is not a vertex");
2536 //Compute the Block value
2538 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
2541 TopoDS_Shape aShape;
2543 TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
2544 gp_Pnt aPnt = BRep_Tool::Pnt(aVert);
2545 Standard_Real PX, PY, PZ;
2546 aPnt.Coord(PX, PY, PZ);
2548 // 1. Classify the point relatively each block
2549 Standard_Integer nearest = 2, nbFound = 0;
2550 TopTools_DataMapOfShapeInteger mapShapeDist;
2551 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2552 for (; exp.More(); exp.Next()) {
2553 TopoDS_Shape aSolid = exp.Current();
2555 if (!mapShapeDist.IsBound(aSolid)) {
2556 Standard_Integer aDistance = 2;
2558 // 1.a. Classify relatively Bounding box
2559 Standard_Real Xmin, Ymin, Zmin, Xmax, Ymax, Zmax;
2561 BRepBndLib::Add(aSolid, BB);
2562 BB.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);
2563 if (PX < Xmin || Xmax < PX ||
2564 PY < Ymin || Ymax < PY ||
2565 PZ < Zmin || Zmax < PZ) {
2566 // OUT of bounding box
2569 // 1.b. Classify relatively the solid itself
2570 BRepClass3d_SolidClassifier SC (aSolid, aPnt, Precision::Confusion());
2571 if (SC.State() == TopAbs_IN) {
2573 } else if (SC.State() == TopAbs_ON) {
2580 if (aDistance < nearest) {
2581 nearest = aDistance;
2585 // A first found block, containing the point inside, will be returned.
2586 // It is the solution, if there are no intersecting blocks in the compound.
2587 if (nearest == -1) break;
2589 } else if (aDistance == nearest) {
2594 mapShapeDist.Bind(aSolid, aDistance);
2595 } // if (!mapShapeDist.IsBound(aSolid))
2598 // 2. Define block, containing the point or having minimum distance to it
2601 // The point is on boundary of some blocks and there are
2602 // no blocks, having the point inside their volume
2603 SetErrorCode("Multiple blocks near the given point are found");
2606 } else if (nearest == 1) {
2607 // The point is outside some blocks and there are
2608 // no blocks, having the point inside or on boundary.
2609 // We will get a nearest block
2610 Standard_Real minDist = RealLast();
2611 TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
2612 for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
2613 if (mapShapeDistIter.Value() == 1) {
2614 TopoDS_Shape aSolid = mapShapeDistIter.Key();
2615 BRepExtrema_DistShapeShape aDistTool (aVert, aSolid);
2616 if (!aDistTool.IsDone()) {
2617 SetErrorCode("Can not find a distance from the given point to one of blocks");
2620 Standard_Real aDist = aDistTool.Value();
2621 if (aDist < minDist) {
2627 } else { // nearest == -1
2628 // // The point is inside some blocks.
2629 // // We will get a block with nearest center
2630 // Standard_Real minDist = RealLast();
2631 // TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
2632 // for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
2633 // if (mapShapeDistIter.Value() == -1) {
2634 // TopoDS_Shape aSolid = mapShapeDistIter.Key();
2635 // GProp_GProps aSystem;
2636 // BRepGProp::VolumeProperties(aSolid, aSystem);
2637 // gp_Pnt aCenterMass = aSystem.CentreOfMass();
2639 // Standard_Real aDist = aCenterMass.Distance(aPnt);
2640 // if (aDist < minDist) {
2647 } // if (nbFound > 1)
2650 SetErrorCode("There are no blocks near the given point");
2653 TopTools_IndexedMapOfShape anIndices;
2654 TopExp::MapShapes(aBlockOrComp, anIndices);
2655 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
2656 anArray->SetValue(1, anIndices.FindIndex(aShape));
2657 aResult = GetEngine()->AddSubShape(theCompound, anArray);
2660 catch (Standard_Failure) {
2661 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2662 SetErrorCode(aFail->GetMessageString());
2666 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
2668 //Make a Python command
2669 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetBlockNearPoint("
2670 << theCompound << ", " << thePoint << ")";
2676 //=============================================================================
2680 //=============================================================================
2681 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetBlockByParts
2682 (Handle(GEOM_Object) theCompound,
2683 const Handle(TColStd_HSequenceOfTransient)& theParts)
2687 Handle(GEOM_Object) aResult;
2689 if (theCompound.IsNull() || theParts.IsNull()) return NULL;
2690 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2691 if (aBlockOrComp.IsNull()) return NULL;
2694 Standard_Integer argi, aLen = theParts->Length();
2695 TopTools_Array1OfShape anArgs (1, aLen);
2696 TCollection_AsciiString anEntry, aPartsDescr;
2697 for (argi = 1; argi <= aLen; argi++) {
2698 Handle(GEOM_Object) anObj = Handle(GEOM_Object)::DownCast(theParts->Value(argi));
2699 Handle(GEOM_Function) aRef = anObj->GetLastFunction();
2700 if (aRef.IsNull()) return NULL;
2702 TopoDS_Shape anArg = aRef->GetValue();
2703 if (anArg.IsNull()) {
2704 SetErrorCode("Null shape is given as argument");
2707 anArgs(argi) = anArg;
2709 // For Python command
2710 TDF_Tool::Entry(anObj->GetEntry(), anEntry);
2711 if (argi > 1) aPartsDescr += ", ";
2712 aPartsDescr += anEntry;
2715 //Compute the Block value
2717 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
2720 // 1. Explode compound on solids
2721 TopTools_MapOfShape mapShape;
2722 Standard_Integer nbSolids = 0;
2723 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2724 for (; exp.More(); exp.Next()) {
2725 if (mapShape.Add(exp.Current())) {
2731 Standard_Integer ind = 1;
2732 TopTools_Array1OfShape aSolids (1, nbSolids);
2733 TColStd_Array1OfInteger aNbParts (1, nbSolids);
2734 for (exp.Init(aBlockOrComp, TopAbs_SOLID); exp.More(); exp.Next(), ind++) {
2735 if (mapShape.Add(exp.Current())) {
2736 TopoDS_Shape aSolid = exp.Current();
2737 aSolids(ind) = aSolid;
2740 // 2. Define quantity of parts, contained in each solid
2741 TopTools_IndexedMapOfShape aSubShapes;
2742 TopExp::MapShapes(aSolid, aSubShapes);
2743 for (argi = 1; argi <= aLen; argi++) {
2744 if (aSubShapes.Contains(anArgs(argi))) {
2751 // 3. Define solid, containing maximum quantity of parts
2752 Standard_Integer maxNb = 0, nbFound = 0;
2753 TopoDS_Shape aShape;
2754 for (ind = 1; ind <= nbSolids; ind++) {
2755 if (aNbParts(ind) > maxNb) {
2756 maxNb = aNbParts(ind);
2757 aShape = aSolids(ind);
2759 } else if (aNbParts(ind) == maxNb) {
2765 SetErrorCode("Multiple blocks, containing maximum quantity of the given parts, are found");
2767 } else if (nbFound == 0) {
2768 SetErrorCode("There are no blocks, containing the given parts");
2771 TopTools_IndexedMapOfShape anIndices;
2772 TopExp::MapShapes(aBlockOrComp, anIndices);
2773 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
2774 anArray->SetValue(1, anIndices.FindIndex(aShape));
2775 aResult = GetEngine()->AddSubShape(theCompound, anArray);
2777 } catch (Standard_Failure) {
2778 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2779 SetErrorCode(aFail->GetMessageString());
2783 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
2785 //Make a Python command
2786 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetBlockByParts("
2787 << theCompound << ", [" << aPartsDescr.ToCString() << "])";
2793 //=============================================================================
2797 //=============================================================================
2798 Handle(TColStd_HSequenceOfTransient) GEOMImpl_IBlocksOperations::GetBlocksByParts
2799 (Handle(GEOM_Object) theCompound,
2800 const Handle(TColStd_HSequenceOfTransient)& theParts)
2804 if (theCompound.IsNull() || theParts.IsNull()) return NULL;
2805 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2806 if (aBlockOrComp.IsNull()) return NULL;
2808 Handle(TColStd_HSequenceOfTransient) aBlocks = new TColStd_HSequenceOfTransient;
2809 Handle(GEOM_Object) anObj;
2810 Handle(GEOM_Function) aFunction;
2813 Standard_Integer argi, aLen = theParts->Length();
2814 TopTools_Array1OfShape anArgs (1, aLen);
2815 TCollection_AsciiString anEntry, aPartsDescr, anAsciiList;
2817 for (argi = 1; argi <= aLen; argi++) {
2818 Handle(GEOM_Object) anObj = Handle(GEOM_Object)::DownCast(theParts->Value(argi));
2819 Handle(GEOM_Function) aRef = anObj->GetLastFunction();
2820 if (aRef.IsNull()) return NULL;
2822 TopoDS_Shape anArg = aRef->GetValue();
2823 if (anArg.IsNull()) {
2824 SetErrorCode("Null shape is given as argument");
2827 anArgs(argi) = anArg;
2829 // For Python command
2830 TDF_Tool::Entry(anObj->GetEntry(), anEntry);
2831 aPartsDescr += anEntry + ", ";
2836 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
2839 TopTools_MapOfShape mapShape;
2840 Standard_Integer nbSolids = 0;
2841 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2842 for (; exp.More(); exp.Next()) {
2843 if (mapShape.Add(exp.Current())) {
2849 Standard_Integer ind = 1;
2850 TopTools_Array1OfShape aSolids (1, nbSolids);
2851 TColStd_Array1OfInteger aNbParts (1, nbSolids);
2852 for (exp.Init(aBlockOrComp, TopAbs_SOLID); exp.More(); exp.Next(), ind++) {
2853 if (mapShape.Add(exp.Current())) {
2854 TopoDS_Shape aSolid = exp.Current();
2855 aSolids(ind) = aSolid;
2858 // 2. Define quantity of parts, contained in each solid
2859 TopTools_IndexedMapOfShape aSubShapes;
2860 TopExp::MapShapes(aSolid, aSubShapes);
2861 for (argi = 1; argi <= aLen; argi++) {
2862 if (aSubShapes.Contains(anArgs(argi))) {
2869 // 3. Define solid, containing maximum quantity of parts
2870 Standard_Integer maxNb = 0, nbFound = 0;
2871 for (ind = 1; ind <= nbSolids; ind++) {
2872 if (aNbParts(ind) > maxNb) {
2873 maxNb = aNbParts(ind);
2875 } else if (aNbParts(ind) == maxNb) {
2881 SetErrorCode("There are no blocks, containing the given parts");
2886 TopTools_IndexedMapOfShape anIndices;
2887 TopExp::MapShapes(aBlockOrComp, anIndices);
2888 Handle(TColStd_HArray1OfInteger) anArray;
2890 for (ind = 1; ind <= nbSolids; ind++) {
2891 if (aNbParts(ind) == maxNb) {
2892 anArray = new TColStd_HArray1OfInteger(1,1);
2893 anArray->SetValue(1, anIndices.FindIndex(aSolids(ind)));
2894 anObj = GetEngine()->AddSubShape(theCompound, anArray);
2895 aBlocks->Append(anObj);
2897 // For Python command
2898 TDF_Tool::Entry(anObj->GetEntry(), anEntry);
2899 anAsciiList += anEntry + ", ";
2900 if (aFunction.IsNull())
2901 aFunction = anObj->GetLastFunction();
2905 catch (Standard_Failure) {
2906 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2907 SetErrorCode(aFail->GetMessageString());
2911 //Make a Python command
2912 aPartsDescr.Trunc(aPartsDescr.Length() - 2);
2913 anAsciiList.Trunc(anAsciiList.Length() - 2);
2915 GEOM::TPythonDump(aFunction) << "[" << anAsciiList.ToCString()
2916 << "] = geompy.GetBlocksByParts(" << theCompound
2917 << ", [" << aPartsDescr.ToCString() << "])";
2923 //=============================================================================
2925 * MakeMultiTransformation1D
2927 //=============================================================================
2928 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeMultiTransformation1D
2929 (Handle(GEOM_Object) theObject,
2930 const Standard_Integer theDirFace1,
2931 const Standard_Integer theDirFace2,
2932 const Standard_Integer theNbTimes)
2936 if (theObject.IsNull()) return NULL;
2938 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
2939 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be moved
2941 //Add a new Copy object
2942 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
2944 //Add a translate function
2945 Handle(GEOM_Function) aFunction =
2946 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_MULTI_TRANSFORM_1D);
2948 //Check if the function is set correctly
2949 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
2951 GEOMImpl_IBlockTrsf aTI (aFunction);
2952 aTI.SetOriginal(aLastFunction);
2953 aTI.SetFace1U(theDirFace1);
2954 aTI.SetFace2U(theDirFace2);
2955 aTI.SetNbIterU(theNbTimes);
2957 //Compute the transformation
2959 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
2962 if (!GetSolver()->ComputeFunction(aFunction)) {
2963 SetErrorCode("Block driver failed to make multi-transformation");
2967 catch (Standard_Failure) {
2968 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2969 SetErrorCode(aFail->GetMessageString());
2973 //Make a Python command
2974 GEOM::TPythonDump(aFunction) << aCopy << " = geompy.MakeMultiTransformation1D("
2975 << theObject << ", " << theDirFace1 << ", " << theDirFace2 << ", " << theNbTimes << ")";
2981 //=============================================================================
2983 * MakeMultiTransformation2D
2985 //=============================================================================
2986 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeMultiTransformation2D
2987 (Handle(GEOM_Object) theObject,
2988 const Standard_Integer theDirFace1U,
2989 const Standard_Integer theDirFace2U,
2990 const Standard_Integer theNbTimesU,
2991 const Standard_Integer theDirFace1V,
2992 const Standard_Integer theDirFace2V,
2993 const Standard_Integer theNbTimesV)
2997 if (theObject.IsNull()) return NULL;
2999 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
3000 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be moved
3002 //Add a new Copy object
3003 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
3005 //Add a translate function
3006 Handle(GEOM_Function) aFunction =
3007 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_MULTI_TRANSFORM_2D);
3009 //Check if the function is set correctly
3010 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
3012 GEOMImpl_IBlockTrsf aTI (aFunction);
3013 aTI.SetOriginal(aLastFunction);
3014 aTI.SetFace1U(theDirFace1U);
3015 aTI.SetFace2U(theDirFace2U);
3016 aTI.SetNbIterU(theNbTimesU);
3017 aTI.SetFace1V(theDirFace1V);
3018 aTI.SetFace2V(theDirFace2V);
3019 aTI.SetNbIterV(theNbTimesV);
3021 //Compute the transformation
3023 #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100
3026 if (!GetSolver()->ComputeFunction(aFunction)) {
3027 SetErrorCode("Block driver failed to make multi-transformation");
3031 catch (Standard_Failure) {
3032 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
3033 SetErrorCode(aFail->GetMessageString());
3037 //Make a Python command
3038 GEOM::TPythonDump(aFunction) << aCopy << " = geompy.MakeMultiTransformation2D("
3039 << theObject << ", " << theDirFace1U << ", " << theDirFace2U << ", " << theNbTimesU
3040 << ", " << theDirFace1V << ", " << theDirFace2V << ", " << theNbTimesV << ")";
3046 //=============================================================================
3050 //=============================================================================
3051 Handle(TColStd_HSequenceOfTransient) GEOMImpl_IBlocksOperations::Propagate
3052 (Handle(GEOM_Object) theShape)
3056 if (theShape.IsNull()) return NULL;
3058 TopoDS_Shape aShape = theShape->GetValue();
3059 if (aShape.IsNull()) return NULL;
3061 TopTools_IndexedMapOfShape anIndices;
3062 TopExp::MapShapes(aShape, anIndices);
3064 TopTools_IndexedDataMapOfShapeListOfShape MEW;
3065 GEOMImpl_Block6Explorer::MapShapesAndAncestors
3066 (aShape, TopAbs_EDGE, TopAbs_WIRE, MEW);
3067 Standard_Integer ie, nbEdges = MEW.Extent();
3070 Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
3072 TopTools_MapOfShape mapAcceptedEdges;
3073 TCollection_AsciiString aListRes, anEntry;
3075 for (ie = 1; ie <= nbEdges; ie++) {
3076 TopoDS_Shape curE = MEW.FindKey(ie);
3078 if (mapAcceptedEdges.Contains(curE)) continue;
3081 TopTools_ListOfShape currentChain;
3082 TopTools_ListOfShape listPrevEdges;
3084 currentChain.Append(curE);
3085 listPrevEdges.Append(curE);
3086 mapAcceptedEdges.Add(curE);
3088 // Collect all edges pass by pass
3089 while (listPrevEdges.Extent() > 0) {
3090 // List of edges, added to chain on this cycle pass
3091 TopTools_ListOfShape listCurEdges;
3093 // Find the next portion of edges
3094 TopTools_ListIteratorOfListOfShape itE (listPrevEdges);
3095 for (; itE.More(); itE.Next()) {
3096 TopoDS_Shape anE = itE.Value();
3098 // Iterate on faces, having edge <anE>
3099 TopTools_ListIteratorOfListOfShape itW (MEW.FindFromKey(anE));
3100 for (; itW.More(); itW.Next()) {
3101 TopoDS_Shape aW = itW.Value();
3102 TopoDS_Shape anOppE;
3104 BRepTools_WireExplorer aWE (TopoDS::Wire(aW));
3105 Standard_Integer nb = 1, found = 0;
3106 TopTools_Array1OfShape anEdges (1,4);
3107 for (; aWE.More(); aWE.Next(), nb++) {
3112 anEdges(nb) = aWE.Current();
3113 if (anEdges(nb).IsSame(anE)) found = nb;
3116 if (nb == 5 && found > 0) {
3117 // Quadrangle face found, get an opposite edge
3118 Standard_Integer opp = found + 2;
3119 if (opp > 4) opp -= 4;
3120 anOppE = anEdges(opp);
3122 if (!mapAcceptedEdges.Contains(anOppE)) {
3123 // Add found edge to the chain
3124 currentChain.Append(anOppE);
3125 listCurEdges.Append(anOppE);
3126 mapAcceptedEdges.Add(anOppE);
3128 } // if (nb == 5 && found > 0)
3129 } // for (; itF.More(); itF.Next())
3130 } // for (; itE.More(); itE.Next())
3132 listPrevEdges = listCurEdges;
3133 } // while (listPrevEdges.Extent() > 0)
3135 // Store the chain in the document
3136 Handle(TColStd_HArray1OfInteger) anArray =
3137 new TColStd_HArray1OfInteger (1, currentChain.Extent());
3139 // Fill array of sub-shape indices
3140 TopTools_ListIteratorOfListOfShape itSub (currentChain);
3141 for (int index = 1; itSub.More(); itSub.Next(), ++index) {
3142 int id = anIndices.FindIndex(itSub.Value());
3143 anArray->SetValue(index, id);
3146 // Add a new group object
3147 Handle(GEOM_Object) aChain = GetEngine()->AddSubShape(theShape, anArray);
3150 aChain->SetType(GEOM_GROUP);
3152 // Set a sub shape type
3153 TDF_Label aFreeLabel = aChain->GetFreeLabel();
3154 TDataStd_Integer::Set(aFreeLabel, (Standard_Integer)TopAbs_EDGE);
3156 // Add the chain to the result
3157 aSeq->Append(aChain);
3159 //Make a Python command
3160 TDF_Tool::Entry(aChain->GetEntry(), anEntry);
3161 aListRes += anEntry + ", ";
3164 if (aSeq->IsEmpty()) {
3165 SetErrorCode("There are no quadrangle faces in the shape");
3169 aListRes.Trunc(aListRes.Length() - 2);
3171 // The Propagation doesn't change object so no new function is required.
3172 Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
3174 // Make a Python command
3175 GEOM::TPythonDump(aFunction, /*append=*/true)
3176 << "[" << aListRes.ToCString() << "] = geompy.Propagate(" << theShape << ")";