1 // Copyright (C) 2007-2014 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, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
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_Block6Explorer.hxx>
38 #include <GEOMUtils.hxx>
40 #include <GEOM_Function.hxx>
41 #include <GEOM_PythonDump.hxx>
43 #include <GEOMAlgo_GlueAnalyser.hxx>
44 #include <GEOMAlgo_CoupleOfShapes.hxx>
45 #include <GEOMAlgo_ListOfCoupleOfShapes.hxx>
46 #include <GEOMAlgo_ListIteratorOfListOfCoupleOfShapes.hxx>
47 #include <BlockFix_CheckTool.hxx>
49 #include <Basics_OCCTVersion.hxx>
51 #include "utilities.h"
53 #include <Utils_ExceptHandlers.hxx>
55 #include <TFunction_DriverTable.hxx>
56 #include <TFunction_Driver.hxx>
57 #include <TFunction_Logbook.hxx>
58 #include <TDataStd_Integer.hxx>
59 #include <TDF_Tool.hxx>
61 #include <BRep_Tool.hxx>
62 #include <BRep_Builder.hxx>
63 #include <BRepTools.hxx>
64 #include <BRepTools_WireExplorer.hxx>
65 #include <BRepGProp.hxx>
66 #include <BRepBndLib.hxx>
67 #include <BRepAdaptor_Surface.hxx>
68 #include <BRepClass_FaceClassifier.hxx>
69 #include <BRepClass3d_SolidClassifier.hxx>
70 #include <BRepExtrema_DistShapeShape.hxx>
74 #include <TopoDS_Edge.hxx>
75 #include <TopoDS_Vertex.hxx>
76 #include <TopoDS_Compound.hxx>
77 #include <TopoDS_Iterator.hxx>
79 #include <TopExp_Explorer.hxx>
80 #include <TopTools_MapOfShape.hxx>
81 #include <TopTools_Array1OfShape.hxx>
82 #include <TopTools_IndexedMapOfShape.hxx>
83 #include <TopTools_DataMapOfShapeInteger.hxx>
84 #include <TopTools_ListIteratorOfListOfShape.hxx>
85 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
86 #include <TopTools_DataMapIteratorOfDataMapOfShapeInteger.hxx>
88 #include <Bnd_Box.hxx>
89 #include <GProp_GProps.hxx>
91 #include <Geom_Surface.hxx>
92 #include <ShapeAnalysis_Surface.hxx>
94 #include <TColStd_MapOfInteger.hxx>
95 #include <TColStd_Array1OfReal.hxx>
96 #include <TColStd_Array1OfInteger.hxx>
97 #include <TColStd_Array2OfInteger.hxx>
99 //#include <OSD_Timer.hxx>
101 #include <Precision.hxx>
103 #include <Standard_Failure.hxx>
104 #include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC
106 //=============================================================================
110 //=============================================================================
111 GEOMImpl_IBlocksOperations::GEOMImpl_IBlocksOperations (GEOM_Engine* theEngine, int theDocID)
112 : GEOM_IOperations(theEngine, theDocID)
114 MESSAGE("GEOMImpl_IBlocksOperations::GEOMImpl_IBlocksOperations");
117 //=============================================================================
121 //=============================================================================
122 GEOMImpl_IBlocksOperations::~GEOMImpl_IBlocksOperations()
124 MESSAGE("GEOMImpl_IBlocksOperations::~GEOMImpl_IBlocksOperations");
128 //=============================================================================
132 //=============================================================================
133 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuad
134 (Handle(GEOM_Object) theEdge1, Handle(GEOM_Object) theEdge2,
135 Handle(GEOM_Object) theEdge3, Handle(GEOM_Object) theEdge4)
139 if (theEdge1.IsNull() || theEdge2.IsNull() ||
140 theEdge3.IsNull() || theEdge4.IsNull()) return NULL;
142 //Add a new Face object
143 Handle(GEOM_Object) aFace = GetEngine()->AddObject(GetDocID(), GEOM_FACE);
145 //Add a new Face function
146 Handle(GEOM_Function) aFunction =
147 aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_FOUR_EDGES);
149 //Check if the function is set correctly
150 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
152 GEOMImpl_IBlocks aPI (aFunction);
154 Handle(GEOM_Function) aRef1 = theEdge1->GetLastFunction();
155 Handle(GEOM_Function) aRef2 = theEdge2->GetLastFunction();
156 Handle(GEOM_Function) aRef3 = theEdge3->GetLastFunction();
157 Handle(GEOM_Function) aRef4 = theEdge4->GetLastFunction();
158 if (aRef1.IsNull() || aRef2.IsNull() ||
159 aRef3.IsNull() || aRef4.IsNull()) return NULL;
161 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
162 aShapesSeq->Append(aRef1);
163 aShapesSeq->Append(aRef2);
164 aShapesSeq->Append(aRef3);
165 aShapesSeq->Append(aRef4);
167 aPI.SetShapes(aShapesSeq);
169 //Compute the Face value
172 if (!GetSolver()->ComputeFunction(aFunction)) {
173 SetErrorCode("Block driver failed to compute a face");
177 catch (Standard_Failure) {
178 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
179 SetErrorCode(aFail->GetMessageString());
183 //Make a Python command
184 GEOM::TPythonDump(aFunction) << aFace << " = geompy.MakeQuad("
185 << theEdge1 << ", " << theEdge2 << ", " << theEdge3 << ", " << theEdge4 << ")";
191 //=============================================================================
195 //=============================================================================
196 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuad2Edges
197 (Handle(GEOM_Object) theEdge1, Handle(GEOM_Object) theEdge2)
201 if (theEdge1.IsNull() || theEdge2.IsNull()) return NULL;
203 //Add a new Face object
204 Handle(GEOM_Object) aFace = GetEngine()->AddObject(GetDocID(), GEOM_FACE);
206 //Add a new Face function
207 Handle(GEOM_Function) aFunction =
208 aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_TWO_EDGES);
210 //Check if the function is set correctly
211 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
213 GEOMImpl_IBlocks aPI (aFunction);
215 Handle(GEOM_Function) aRef1 = theEdge1->GetLastFunction();
216 Handle(GEOM_Function) aRef2 = theEdge2->GetLastFunction();
217 if (aRef1.IsNull() || aRef2.IsNull()) return NULL;
219 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
220 aShapesSeq->Append(aRef1);
221 aShapesSeq->Append(aRef2);
223 aPI.SetShapes(aShapesSeq);
225 //Compute the Face value
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
291 if (!GetSolver()->ComputeFunction(aFunction)) {
292 SetErrorCode("Block driver failed to compute a face");
296 catch (Standard_Failure) {
297 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
298 SetErrorCode(aFail->GetMessageString());
302 //Make a Python command
303 GEOM::TPythonDump(aFunction) << aFace << " = geompy.MakeQuad4Vertices("
304 << thePnt1 << ", " << thePnt2 << ", " << thePnt3 << ", " << thePnt4 << ")";
310 //=============================================================================
314 //=============================================================================
315 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeHexa
316 (Handle(GEOM_Object) theFace1, Handle(GEOM_Object) theFace2,
317 Handle(GEOM_Object) theFace3, Handle(GEOM_Object) theFace4,
318 Handle(GEOM_Object) theFace5, Handle(GEOM_Object) theFace6)
322 if (theFace1.IsNull() || theFace2.IsNull() ||
323 theFace3.IsNull() || theFace4.IsNull() ||
324 theFace5.IsNull() || theFace6.IsNull()) return NULL;
326 //Add a new Solid object
327 Handle(GEOM_Object) aBlock = GetEngine()->AddObject(GetDocID(), GEOM_BLOCK);
329 //Add a new Block function
330 Handle(GEOM_Function) aFunction =
331 aBlock->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_SIX_FACES);
333 //Check if the function is set correctly
334 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
336 GEOMImpl_IBlocks aPI (aFunction);
338 Handle(GEOM_Function) aRef1 = theFace1->GetLastFunction();
339 Handle(GEOM_Function) aRef2 = theFace2->GetLastFunction();
340 Handle(GEOM_Function) aRef3 = theFace3->GetLastFunction();
341 Handle(GEOM_Function) aRef4 = theFace4->GetLastFunction();
342 Handle(GEOM_Function) aRef5 = theFace5->GetLastFunction();
343 Handle(GEOM_Function) aRef6 = theFace6->GetLastFunction();
344 if (aRef1.IsNull() || aRef2.IsNull() ||
345 aRef3.IsNull() || aRef4.IsNull() ||
346 aRef5.IsNull() || aRef6.IsNull()) return NULL;
348 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
349 aShapesSeq->Append(aRef1);
350 aShapesSeq->Append(aRef2);
351 aShapesSeq->Append(aRef3);
352 aShapesSeq->Append(aRef4);
353 aShapesSeq->Append(aRef5);
354 aShapesSeq->Append(aRef6);
356 aPI.SetShapes(aShapesSeq);
358 //Compute the Block value
361 if (!GetSolver()->ComputeFunction(aFunction)) {
362 SetErrorCode("Block driver failed to compute a block");
366 catch (Standard_Failure) {
367 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
368 SetErrorCode(aFail->GetMessageString());
372 //Make a Python command
373 GEOM::TPythonDump(aFunction) << aBlock << " = geompy.MakeHexa("
374 << theFace1 << ", " << theFace2 << ", " << theFace3 << ", "
375 << theFace4 << ", " << theFace5 << ", " << theFace6 << ")";
381 //=============================================================================
385 //=============================================================================
386 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeHexa2Faces
387 (Handle(GEOM_Object) theFace1, Handle(GEOM_Object) theFace2)
391 if (theFace1.IsNull() || theFace2.IsNull()) return NULL;
393 //Add a new Solid object
394 Handle(GEOM_Object) aBlock = GetEngine()->AddObject(GetDocID(), GEOM_BLOCK);
396 //Add a new Block function
397 Handle(GEOM_Function) aFunction =
398 aBlock->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_TWO_FACES);
400 //Check if the function is set correctly
401 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
403 GEOMImpl_IBlocks aPI (aFunction);
405 Handle(GEOM_Function) aRef1 = theFace1->GetLastFunction();
406 Handle(GEOM_Function) aRef2 = theFace2->GetLastFunction();
407 if (aRef1.IsNull() || aRef2.IsNull()) return NULL;
409 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
410 aShapesSeq->Append(aRef1);
411 aShapesSeq->Append(aRef2);
413 aPI.SetShapes(aShapesSeq);
415 //Compute the Block value
418 if (!GetSolver()->ComputeFunction(aFunction)) {
419 SetErrorCode("Block driver failed to compute a block");
423 catch (Standard_Failure) {
424 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
425 SetErrorCode(aFail->GetMessageString());
429 //Make a Python command
430 GEOM::TPythonDump(aFunction) << aBlock << " = geompy.MakeHexa2Faces("
431 << theFace1 << ", " << theFace2 << ")";
437 //=============================================================================
441 //=============================================================================
442 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeBlockCompound
443 (Handle(GEOM_Object) theCompound)
447 if (theCompound.IsNull()) return NULL;
450 Handle(GEOM_Object) aBlockComp = GetEngine()->AddObject(GetDocID(), GEOM_COMPOUND);
452 //Add a new BlocksComp function
453 Handle(GEOM_Function) aFunction =
454 aBlockComp->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_COMPOUND_GLUE);
456 //Check if the function is set correctly
457 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
459 GEOMImpl_IBlocks aPI (aFunction);
461 Handle(GEOM_Function) aRef1 = theCompound->GetLastFunction();
462 if (aRef1.IsNull()) return NULL;
464 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
465 aShapesSeq->Append(aRef1);
467 aPI.SetShapes(aShapesSeq);
469 //Compute the Blocks Compound value
472 if (!GetSolver()->ComputeFunction(aFunction)) {
473 SetErrorCode("Block driver failed to compute a blocks compound");
477 catch (Standard_Failure) {
478 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
479 SetErrorCode(aFail->GetMessageString());
483 //Make a Python command
484 GEOM::TPythonDump(aFunction) << aBlockComp
485 << " = geompy.MakeBlockCompound(" << theCompound << ")";
491 //=============================================================================
495 //=============================================================================
496 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetPoint
497 (Handle(GEOM_Object) theShape,
498 const Standard_Real theX,
499 const Standard_Real theY,
500 const Standard_Real theZ,
501 const Standard_Real theEpsilon)
506 Handle(GEOM_Object) aResult;
509 if (theShape.IsNull()) return NULL;
511 TopoDS_Shape aBlockOrComp = theShape->GetValue();
512 if (aBlockOrComp.IsNull()) {
513 SetErrorCode("Given shape is null");
517 //Compute the Vertex value
518 gp_Pnt P (theX, theY, theZ);
519 Standard_Real eps = Max(theEpsilon, Precision::Confusion());
522 Standard_Integer isFound = 0;
523 TopTools_MapOfShape mapShape;
524 TopExp_Explorer exp (aBlockOrComp, TopAbs_VERTEX);
526 for (; exp.More(); exp.Next()) {
527 if (mapShape.Add(exp.Current())) {
528 TopoDS_Vertex aVi = TopoDS::Vertex(exp.Current());
529 gp_Pnt aPi = BRep_Tool::Pnt(aVi);
530 if (aPi.Distance(P) < eps) {
538 SetErrorCode("Vertex has not been found");
540 } else if (isFound > 1) {
541 SetErrorCode("Multiple vertices found by the given coordinates and epsilon");
544 TopTools_IndexedMapOfShape anIndices;
545 TopExp::MapShapes(aBlockOrComp, anIndices);
546 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
547 anArray->SetValue(1, anIndices.FindIndex(V));
548 aResult = GetEngine()->AddSubShape(theShape, anArray);
551 //The GetPoint() doesn't change object so no new function is required.
552 Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
554 //Make a Python command
555 GEOM::TPythonDump(aFunction, /*append=*/true)
556 << aResult << " = geompy.GetPoint(" << theShape << ", "
557 << theX << ", " << theY << ", " << theZ << ", " << theEpsilon << ")";
563 //=============================================================================
567 //=============================================================================
568 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetVertexNearPoint
569 (Handle(GEOM_Object) theShape,
570 Handle(GEOM_Object) thePoint)
575 Handle(GEOM_Object) aResult;
578 if (theShape.IsNull() || thePoint.IsNull()) return NULL;
580 TopoDS_Shape aBlockOrComp = theShape->GetValue();
581 TopoDS_Shape aPoint = thePoint->GetValue();
582 if (aBlockOrComp.IsNull() || aPoint.IsNull()) {
583 SetErrorCode("Given shape is null");
587 if (aPoint.ShapeType() != TopAbs_VERTEX) {
588 SetErrorCode("Element for vertex identification is not a vertex");
592 TopoDS_Vertex aVert = TopoDS::Vertex(aPoint);
593 gp_Pnt aP = BRep_Tool::Pnt(aVert);
595 // Compute the Vertex value
597 bool isFound = false;
598 Standard_Real aDist = RealLast();
599 TopTools_MapOfShape mapShape;
601 TopExp_Explorer exp (aBlockOrComp, TopAbs_VERTEX);
602 for (; exp.More(); exp.Next()) {
603 if (mapShape.Add(exp.Current())) {
604 TopoDS_Vertex aVi = TopoDS::Vertex(exp.Current());
605 gp_Pnt aPi = BRep_Tool::Pnt(aVi);
606 Standard_Real aDisti = aPi.Distance(aP);
607 if (aDisti < aDist) {
616 SetErrorCode("Vertex has not been found");
620 TopTools_IndexedMapOfShape anIndices;
621 TopExp::MapShapes(aBlockOrComp, anIndices);
622 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
623 anArray->SetValue(1, anIndices.FindIndex(V));
624 aResult = GetEngine()->AddSubShape(theShape, anArray);
626 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
628 // Make a Python command
629 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetVertexNearPoint("
630 << theShape << ", " << thePoint << ")";
636 //=============================================================================
640 //=============================================================================
641 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetEdge
642 (Handle(GEOM_Object) theShape,
643 Handle(GEOM_Object) thePoint1,
644 Handle(GEOM_Object) thePoint2)
649 Handle(GEOM_Object) aResult;
652 if (theShape.IsNull() || thePoint1.IsNull() || thePoint2.IsNull()) return NULL;
654 TopoDS_Shape aBlockOrComp = theShape->GetValue();
655 if (aBlockOrComp.IsNull()) {
656 SetErrorCode("Given shape is null");
660 TopoDS_Shape anArg1 = thePoint1->GetValue();
661 TopoDS_Shape anArg2 = thePoint2->GetValue();
662 if (anArg1.IsNull() || anArg2.IsNull()) {
663 SetErrorCode("Null shape is given as argument");
666 if (anArg1.ShapeType() != TopAbs_VERTEX ||
667 anArg2.ShapeType() != TopAbs_VERTEX) {
668 SetErrorCode("Element for edge identification is not a vertex");
672 //Compute the Edge value
675 TopTools_IndexedDataMapOfShapeListOfShape MVE;
676 GEOMImpl_Block6Explorer::MapShapesAndAncestors
677 (aBlockOrComp, TopAbs_VERTEX, TopAbs_EDGE, MVE);
680 Standard_Integer ish, ext = MVE.Extent();
682 if (MVE.Contains(anArg1)) {
685 for (ish = 1; ish <= ext; ish++) {
686 TopoDS_Shape aShi = MVE.FindKey(ish);
687 if (BRepTools::Compare(TopoDS::Vertex(anArg1), TopoDS::Vertex(aShi))) {
694 if (MVE.Contains(anArg2)) {
697 for (ish = 1; ish <= ext; ish++) {
698 TopoDS_Shape aShi = MVE.FindKey(ish);
699 if (BRepTools::Compare(TopoDS::Vertex(anArg2), TopoDS::Vertex(aShi))) {
706 if (V1.IsNull() || V2.IsNull()) {
707 SetErrorCode("The given vertex does not belong to the shape");
712 Standard_Integer isFound =
713 GEOMImpl_Block6Explorer::FindEdge(anEdge, V1, V2, MVE, Standard_True);
715 SetErrorCode("The given vertices do not belong to one edge of the given shape");
717 } else if (isFound > 1) {
718 SetErrorCode("Multiple edges found by the given vertices of the shape");
721 TopTools_IndexedMapOfShape anIndices;
722 TopExp::MapShapes(aBlockOrComp, anIndices);
723 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
724 anArray->SetValue(1, anIndices.FindIndex(anEdge));
725 aResult = GetEngine()->AddSubShape(theShape, anArray);
727 } catch (Standard_Failure) {
728 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
729 SetErrorCode(aFail->GetMessageString());
733 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
735 //Make a Python command
736 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetEdge("
737 << theShape << ", " << thePoint1 << ", " << thePoint2 << ")";
743 //=============================================================================
747 //=============================================================================
748 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetEdgeNearPoint
749 (Handle(GEOM_Object) theShape,
750 Handle(GEOM_Object) thePoint)
755 Handle(GEOM_Object) aResult;
758 if (theShape.IsNull() || thePoint.IsNull()) return NULL;
760 TopoDS_Shape aBlockOrComp = theShape->GetValue();
761 if (aBlockOrComp.IsNull()) {
762 SetErrorCode("Given shape is null");
766 TopoDS_Shape anArg = thePoint->GetValue();
767 if (anArg.IsNull()) {
768 SetErrorCode("Null shape is given as argument");
771 if (anArg.ShapeType() != TopAbs_VERTEX) {
772 SetErrorCode("Element for edge identification is not a vertex");
776 //Compute the Edge value
779 TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
780 TopoDS_Shape aShape = GEOMUtils::GetEdgeNearPoint(aBlockOrComp, aVert);
782 TopTools_IndexedMapOfShape anIndices;
783 TopExp::MapShapes(aBlockOrComp, anIndices);
784 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
785 anArray->SetValue(1, anIndices.FindIndex(aShape));
786 aResult = GetEngine()->AddSubShape(theShape, anArray);
788 catch (Standard_Failure) {
789 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
790 SetErrorCode(aFail->GetMessageString());
794 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
796 //Make a Python command
797 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetEdgeNearPoint("
798 << theShape << ", " << thePoint << ")";
804 //=============================================================================
808 //=============================================================================
809 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByPoints
810 (Handle(GEOM_Object) theShape,
811 Handle(GEOM_Object) thePoint1,
812 Handle(GEOM_Object) thePoint2,
813 Handle(GEOM_Object) thePoint3,
814 Handle(GEOM_Object) thePoint4)
819 Handle(GEOM_Object) aResult;
822 if (theShape.IsNull() ||
823 thePoint1.IsNull() || thePoint2.IsNull() ||
824 thePoint3.IsNull() || thePoint4.IsNull()) return NULL;
826 TopoDS_Shape aBlockOrComp = theShape->GetValue();
827 if (aBlockOrComp.IsNull()) {
828 SetErrorCode("Block or compound is null");
832 TopoDS_Shape anArg1 = thePoint1->GetValue();
833 TopoDS_Shape anArg2 = thePoint2->GetValue();
834 TopoDS_Shape anArg3 = thePoint3->GetValue();
835 TopoDS_Shape anArg4 = thePoint4->GetValue();
836 if (anArg1.IsNull() || anArg2.IsNull() ||
837 anArg3.IsNull() || anArg4.IsNull()) {
838 SetErrorCode("Null shape is given as argument");
841 if (anArg1.ShapeType() != TopAbs_VERTEX ||
842 anArg2.ShapeType() != TopAbs_VERTEX ||
843 anArg3.ShapeType() != TopAbs_VERTEX ||
844 anArg4.ShapeType() != TopAbs_VERTEX) {
845 SetErrorCode("Element for face identification is not a vertex");
849 //Compute the Face value
854 TopTools_IndexedDataMapOfShapeListOfShape MVF;
855 GEOMImpl_Block6Explorer::MapShapesAndAncestors(aBlockOrComp, TopAbs_VERTEX, TopAbs_FACE, MVF);
857 TopoDS_Shape V1,V2,V3,V4;
858 Standard_Integer ish, ext = MVF.Extent();
860 if (MVF.Contains(anArg1)) {
863 for (ish = 1; ish <= ext; ish++) {
864 TopoDS_Shape aShi = MVF.FindKey(ish);
865 if (BRepTools::Compare(TopoDS::Vertex(anArg1), TopoDS::Vertex(aShi))) {
872 if (MVF.Contains(anArg2)) {
875 for (ish = 1; ish <= ext; ish++) {
876 TopoDS_Shape aShi = MVF.FindKey(ish);
877 if (BRepTools::Compare(TopoDS::Vertex(anArg2), TopoDS::Vertex(aShi))) {
884 if (MVF.Contains(anArg3)) {
887 for (ish = 1; ish <= ext; ish++) {
888 TopoDS_Shape aShi = MVF.FindKey(ish);
889 if (BRepTools::Compare(TopoDS::Vertex(anArg3), TopoDS::Vertex(aShi))) {
896 if (MVF.Contains(anArg4)) {
899 for (ish = 1; ish <= ext; ish++) {
900 TopoDS_Shape aShi = MVF.FindKey(ish);
901 if (BRepTools::Compare(TopoDS::Vertex(anArg4), TopoDS::Vertex(aShi))) {
908 if (V1.IsNull() || V2.IsNull() || V3.IsNull() || V4.IsNull()) {
909 SetErrorCode("The given vertex does not belong to the shape");
913 Standard_Integer isFound =
914 GEOMImpl_Block6Explorer::FindFace(aShape, V1, V2, V3, V4, MVF, Standard_True);
916 SetErrorCode("The given vertices do not belong to one face of the given shape");
918 } else if (isFound > 1) {
919 SetErrorCode("The given vertices belong to several faces of the given shape");
922 TopTools_IndexedMapOfShape anIndices;
923 TopExp::MapShapes(aBlockOrComp, anIndices);
924 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
925 anArray->SetValue(1, anIndices.FindIndex(aShape));
926 aResult = GetEngine()->AddSubShape(theShape, anArray);
929 catch (Standard_Failure) {
930 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
931 SetErrorCode(aFail->GetMessageString());
935 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
937 //Make a Python command
938 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceByPoints("
939 << theShape << ", " << thePoint1 << ", " << thePoint2
940 << ", " << thePoint3 << ", " << thePoint4 << ")";
946 //=============================================================================
950 //=============================================================================
951 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByEdges
952 (Handle(GEOM_Object) theShape,
953 Handle(GEOM_Object) theEdge1,
954 Handle(GEOM_Object) theEdge2)
959 Handle(GEOM_Object) aResult;
962 if (theShape.IsNull() || theEdge1.IsNull() || theEdge2.IsNull()) return NULL;
964 TopoDS_Shape aBlockOrComp = theShape->GetValue();
965 if (aBlockOrComp.IsNull()) {
966 SetErrorCode("Block or compound is null");
970 TopoDS_Shape anArg1 = theEdge1->GetValue();
971 TopoDS_Shape anArg2 = theEdge2->GetValue();
972 if (anArg1.IsNull() || anArg2.IsNull()) {
973 SetErrorCode("Null shape is given as argument");
976 if (anArg1.ShapeType() != TopAbs_EDGE ||
977 anArg2.ShapeType() != TopAbs_EDGE) {
978 SetErrorCode("Element for face identification is not an edge");
982 //Compute the Face value
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
1108 TopoDS_Shape aShape;
1110 GEOMImpl_Block6Explorer aBlockTool;
1111 aBlockTool.InitByBlockAndFace(aBlockOrComp, anArg);
1112 aShape = aBlockTool.GetFace(2);
1114 TopTools_IndexedMapOfShape anIndices;
1115 TopExp::MapShapes(aBlockOrComp, anIndices);
1116 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1117 anArray->SetValue(1, anIndices.FindIndex(aShape));
1118 aResult = GetEngine()->AddSubShape(theShape, anArray);
1120 catch (Standard_Failure) {
1121 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1122 SetErrorCode(aFail->GetMessageString());
1126 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1128 //Make a Python command
1129 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetOppositeFace("
1130 << theShape << ", " << theFace << ")";
1136 //=============================================================================
1140 //=============================================================================
1141 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceNearPoint
1142 (Handle(GEOM_Object) theShape,
1143 Handle(GEOM_Object) thePoint)
1148 Handle(GEOM_Object) aResult;
1151 if (theShape.IsNull() || thePoint.IsNull()) return NULL;
1153 TopoDS_Shape aBlockOrComp = theShape->GetValue();
1154 if (aBlockOrComp.IsNull()) {
1155 SetErrorCode("Block or compound is null");
1159 TopoDS_Shape anArg = thePoint->GetValue();
1160 if (anArg.IsNull()) {
1161 SetErrorCode("Null shape is given as argument");
1164 if (anArg.ShapeType() != TopAbs_VERTEX) {
1165 SetErrorCode("Element for face identification is not a vertex");
1169 //Compute the Face value
1172 TopoDS_Shape aShape;
1174 TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
1175 gp_Pnt aPnt = BRep_Tool::Pnt(aVert);
1176 Standard_Real PX, PY, PZ;
1177 aPnt.Coord(PX, PY, PZ);
1179 // 1. Classify the point relatively each face
1180 Standard_Integer nearest = 2, nbFound = 0;
1181 TopTools_DataMapOfShapeInteger mapShapeDist;
1182 TopExp_Explorer exp (aBlockOrComp, TopAbs_FACE);
1183 for (; exp.More(); exp.Next()) {
1184 TopoDS_Shape aFace = exp.Current();
1186 if (!mapShapeDist.IsBound(aFace)) {
1187 Standard_Integer aDistance = 2;
1189 // 1.a. Classify relatively Surface
1190 Handle(Geom_Surface) aSurf = BRep_Tool::Surface(TopoDS::Face(aFace));
1191 Handle(ShapeAnalysis_Surface) aSurfAna = new ShapeAnalysis_Surface (aSurf);
1192 gp_Pnt2d p2dOnSurf = aSurfAna->ValueOfUV(aPnt, Precision::Confusion());
1193 gp_Pnt p3dOnSurf = aSurfAna->Value(p2dOnSurf);
1194 Standard_Real aDist = p3dOnSurf.Distance(aPnt);
1195 if (aDist > Precision::Confusion()) {
1199 // 1.b. Classify relatively the face itself
1200 BRepClass_FaceClassifier FC (TopoDS::Face(aFace), p2dOnSurf, Precision::Confusion());
1201 if (FC.State() == TopAbs_IN) {
1203 } else if (FC.State() == TopAbs_ON) {
1210 if (aDistance < nearest) {
1211 nearest = aDistance;
1215 // A first found face, containing the point inside, will be returned.
1216 // It is the solution, if there are no
1217 // coincident or intersecting faces in the compound.
1218 if (nearest == -1) break;
1220 } else if (aDistance == nearest) {
1225 mapShapeDist.Bind(aFace, aDistance);
1226 } // if (!mapShapeDist.IsBound(aFace))
1229 // 2. Define face, containing the point or having minimum distance to it
1232 // The point is on boundary of some faces and there are
1233 // no faces, having the point inside
1234 SetErrorCode("Multiple faces near the given point are found");
1237 } else if (nearest == 1) {
1238 // The point is outside some faces and there are
1239 // no faces, having the point inside or on boundary.
1240 // We will get a nearest face
1241 Standard_Real bigReal = RealLast();
1242 Standard_Real minDist = bigReal;
1243 TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
1244 for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
1245 if (mapShapeDistIter.Value() == 1) {
1246 TopoDS_Shape aFace = mapShapeDistIter.Key();
1247 Standard_Real aDist = bigReal;
1249 // 2.a. Fast check of distance - if point projection on surface is on face
1250 Handle(Geom_Surface) aSurf = BRep_Tool::Surface(TopoDS::Face(aFace));
1251 Handle(ShapeAnalysis_Surface) aSurfAna = new ShapeAnalysis_Surface (aSurf);
1252 gp_Pnt2d p2dOnSurf = aSurfAna->ValueOfUV(aPnt, Precision::Confusion());
1253 gp_Pnt p3dOnSurf = aSurfAna->Value(p2dOnSurf);
1254 aDist = p3dOnSurf.Distance(aPnt);
1256 BRepClass_FaceClassifier FC (TopoDS::Face(aFace), p2dOnSurf, Precision::Confusion());
1257 if (FC.State() == TopAbs_OUT) {
1258 if (aDist < minDist) {
1259 // 2.b. Slow check - if point projection on surface is outside of face
1260 BRepExtrema_DistShapeShape aDistTool (aVert, aFace);
1261 if (!aDistTool.IsDone()) {
1262 SetErrorCode("Can not find a distance from the given point to one of faces");
1265 aDist = aDistTool.Value();
1271 if (aDist < minDist) {
1277 } else { // nearest == -1
1278 // // The point is inside some faces.
1279 // // We will get a face with nearest center
1280 // Standard_Real minDist = RealLast();
1281 // TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
1282 // for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
1283 // if (mapShapeDistIter.Value() == -1) {
1284 // TopoDS_Shape aFace = mapShapeDistIter.Key();
1285 // GProp_GProps aSystem;
1286 // BRepGProp::SurfaceProperties(aFace, aSystem);
1287 // gp_Pnt aCenterMass = aSystem.CentreOfMass();
1289 // Standard_Real aDist = aCenterMass.Distance(aPnt);
1290 // if (aDist < minDist) {
1297 } // if (nbFound > 1)
1300 SetErrorCode("There are no faces near the given point");
1303 TopTools_IndexedMapOfShape anIndices;
1304 TopExp::MapShapes(aBlockOrComp, anIndices);
1305 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1306 anArray->SetValue(1, anIndices.FindIndex(aShape));
1307 aResult = GetEngine()->AddSubShape(theShape, anArray);
1310 catch (Standard_Failure) {
1311 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1312 SetErrorCode(aFail->GetMessageString());
1316 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1318 //Make a Python command
1319 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceNearPoint("
1320 << theShape << ", " << thePoint << ")";
1326 //=============================================================================
1330 //=============================================================================
1331 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByNormale
1332 (Handle(GEOM_Object) theShape,
1333 Handle(GEOM_Object) theVector)
1338 Handle(GEOM_Object) aResult;
1341 if (theShape.IsNull() || theVector.IsNull()) return NULL;
1343 TopoDS_Shape aBlockOrComp = theShape->GetValue();
1344 if (aBlockOrComp.IsNull()) {
1345 SetErrorCode("Block or compound is null");
1349 TopoDS_Shape anArg = theVector->GetValue();
1350 if (anArg.IsNull()) {
1351 SetErrorCode("Null shape is given as argument");
1354 if (anArg.ShapeType() != TopAbs_EDGE) {
1355 SetErrorCode("Element for normale identification is not an edge");
1359 //Compute the Face value
1362 TopoDS_Shape aShape;
1364 TopoDS_Edge anEdge = TopoDS::Edge(anArg);
1365 TopoDS_Vertex V1, V2;
1366 TopExp::Vertices(anEdge, V1, V2, Standard_True);
1367 gp_Pnt P1 = BRep_Tool::Pnt(V1);
1368 gp_Pnt P2 = BRep_Tool::Pnt(V2);
1369 gp_Vec aVec (P1, P2);
1370 if (aVec.Magnitude() < Precision::Confusion()) {
1371 SetErrorCode("Vector with null magnitude is given");
1375 Standard_Real minAngle = RealLast();
1376 TopTools_MapOfShape mapShape;
1377 TopExp_Explorer exp (aBlockOrComp, TopAbs_FACE);
1378 for (; exp.More(); exp.Next()) {
1379 if (mapShape.Add(exp.Current())) {
1380 TopoDS_Face aFace = TopoDS::Face(exp.Current());
1381 BRepAdaptor_Surface SF (aFace);
1383 Standard_Real u, v, x;
1385 // find a point on the surface to get normal direction in
1386 u = SF.FirstUParameter();
1387 x = SF.LastUParameter();
1388 if (Precision::IsInfinite(u)) {
1389 u = (Precision::IsInfinite(x)) ? 0. : x;
1390 } else if (!Precision::IsInfinite(x)) {
1394 v = SF.FirstVParameter();
1395 x = SF.LastVParameter();
1396 if (Precision::IsInfinite(v)) {
1397 v = (Precision::IsInfinite(x)) ? 0. : x;
1398 } else if (!Precision::IsInfinite(x)) {
1402 // compute the normal direction
1404 SF.D1(u,v,P1,Vec1,Vec2);
1405 gp_Vec V = Vec1.Crossed(Vec2);
1407 if (V.Magnitude() < Precision::Confusion()) {
1408 SetErrorCode("Normal vector of a face has null magnitude");
1412 // consider the face orientation
1413 if (aFace.Orientation() == TopAbs_REVERSED ||
1414 aFace.Orientation() == TopAbs_INTERNAL) {
1418 // compute the angle and compare with the minimal one
1419 Standard_Real anAngle = aVec.Angle(V);
1420 if (anAngle < minAngle) {
1427 if (aShape.IsNull()) {
1428 SetErrorCode("Failed to find a face by the given normale");
1431 TopTools_IndexedMapOfShape anIndices;
1432 TopExp::MapShapes(aBlockOrComp, anIndices);
1433 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1434 anArray->SetValue(1, anIndices.FindIndex(aShape));
1435 aResult = GetEngine()->AddSubShape(theShape, anArray);
1438 catch (Standard_Failure) {
1439 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1440 SetErrorCode(aFail->GetMessageString());
1444 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1446 //Make a Python command
1447 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceByNormale("
1448 << theShape << ", " << theVector << ")";
1454 //=============================================================================
1456 * GetShapesNearPoint
1458 //=============================================================================
1459 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetShapesNearPoint
1460 (Handle(GEOM_Object) theShape,
1461 Handle(GEOM_Object) thePoint,
1462 const Standard_Integer theShapeType,
1463 const Standard_Real theConstTolerance)
1468 Handle(GEOM_Object) aResult;
1471 if (theShape.IsNull() || thePoint.IsNull()) return NULL;
1473 TopoDS_Shape aBlockOrComp = theShape->GetValue();
1474 if (aBlockOrComp.IsNull()) {
1475 SetErrorCode("Block or compound is null");
1479 TopoDS_Shape anArg = thePoint->GetValue();
1480 if (anArg.IsNull()) {
1481 SetErrorCode("Null shape is given as argument");
1484 if (anArg.ShapeType() != TopAbs_VERTEX) {
1485 SetErrorCode("Element for face identification is not a vertex");
1489 if (theShapeType < TopAbs_SOLID || TopAbs_VERTEX < theShapeType) {
1490 SetErrorCode("Invalid type of result is requested");
1494 Standard_Real theTolerance = theConstTolerance;
1495 if (theTolerance < Precision::Confusion()) {
1496 theTolerance = Precision::Confusion();
1499 // Compute the result
1502 TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
1504 TopTools_MapOfShape mapShape;
1505 Standard_Integer nbEdges = 0;
1506 TopExp_Explorer exp (aBlockOrComp, TopAbs_ShapeEnum(theShapeType));
1507 for (; exp.More(); exp.Next()) {
1508 if (mapShape.Add(exp.Current())) {
1514 SetErrorCode("Given shape contains no sub-shapes of requested type");
1518 // Calculate distances and find min
1520 Standard_Integer ind = 1;
1521 Standard_Real aMinDist = RealLast();
1522 TopTools_Array1OfShape anEdges (1, nbEdges);
1523 TColStd_Array1OfReal aDistances (1, nbEdges);
1524 for (exp.Init(aBlockOrComp, TopAbs_ShapeEnum(theShapeType)); exp.More(); exp.Next()) {
1525 if (mapShape.Add(exp.Current())) {
1526 TopoDS_Shape anEdge = exp.Current();
1527 anEdges(ind) = anEdge;
1529 BRepExtrema_DistShapeShape aDistTool (aVert, anEdges(ind));
1530 if (!aDistTool.IsDone()) {
1531 SetErrorCode("Can not find a distance from the given point to one of sub-shapes");
1534 aDistances(ind) = aDistTool.Value();
1535 if (aDistances(ind) < aMinDist) {
1536 aMinDist = aDistances(ind);
1542 if (aMinDist < RealLast()) {
1543 // Collect sub-shapes with distance < (aMinDist + theTolerance)
1544 int nbSubShapes = 0;
1545 TopTools_Array1OfShape aNearShapes (1, nbEdges);
1546 for (ind = 1; ind <= nbEdges; ind++) {
1547 if (aDistances(ind) < aMinDist + theTolerance) {
1549 aNearShapes(nbSubShapes) = anEdges(ind);
1554 TopTools_IndexedMapOfShape anIndices;
1555 TopExp::MapShapes(aBlockOrComp, anIndices);
1556 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger (1, nbSubShapes);
1557 for (ind = 1; ind <= nbSubShapes; ind++) {
1558 anArray->SetValue(ind, anIndices.FindIndex(aNearShapes(ind)));
1560 aResult = GetEngine()->AddSubShape(theShape, anArray);
1563 catch (Standard_Failure) {
1564 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1565 SetErrorCode(aFail->GetMessageString());
1569 if (aResult.IsNull())
1572 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1574 //Make a Python command
1575 GEOM::TPythonDump(aFunction)
1576 << aResult << " = geompy.GetShapesNearPoint(" << theShape << ", " << thePoint
1577 << ", " << TopAbs_ShapeEnum(theShapeType) << ", " << theTolerance << ")";
1583 //=============================================================================
1585 * IsCompoundOfBlocks
1587 //=============================================================================
1588 Standard_Boolean GEOMImpl_IBlocksOperations::IsCompoundOfBlocks
1589 (Handle(GEOM_Object) theCompound,
1590 const Standard_Integer theMinNbFaces,
1591 const Standard_Integer theMaxNbFaces,
1592 Standard_Integer& theNbBlocks)
1595 Standard_Boolean isCompOfBlocks = Standard_False;
1598 if (theCompound.IsNull()) return isCompOfBlocks;
1599 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
1602 isCompOfBlocks = Standard_True;
1605 TopTools_MapOfShape mapShape;
1606 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
1607 for (; exp.More(); exp.Next()) {
1608 if (mapShape.Add(exp.Current())) {
1609 TopoDS_Shape aSolid = exp.Current();
1611 TopTools_MapOfShape mapFaces;
1612 TopExp_Explorer expF (aSolid, TopAbs_FACE);
1613 Standard_Integer nbFaces = 0;
1614 for (; expF.More(); expF.Next()) {
1615 if (mapFaces.Add(expF.Current())) {
1617 if (nbFaces > theMaxNbFaces) {
1618 isCompOfBlocks = Standard_False;
1623 if (nbFaces < theMinNbFaces || theMaxNbFaces < nbFaces) {
1624 isCompOfBlocks = Standard_False;
1631 catch (Standard_Failure) {
1632 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1633 SetErrorCode(aFail->GetMessageString());
1634 return isCompOfBlocks;
1638 return isCompOfBlocks;
1641 //=============================================================================
1643 * Set of functions, used by CheckCompoundOfBlocks() method
1645 //=============================================================================
1646 void GEOMImpl_IBlocksOperations::AddBlocksFrom (const TopoDS_Shape& theShape,
1647 TopTools_ListOfShape& BLO,
1648 TopTools_ListOfShape& NOT,
1649 TopTools_ListOfShape& EXT,
1650 TopTools_ListOfShape& NOQ)
1652 TopAbs_ShapeEnum aType = theShape.ShapeType();
1654 case TopAbs_COMPOUND:
1655 case TopAbs_COMPSOLID:
1657 TopoDS_Iterator It (theShape);
1658 for (; It.More(); It.Next()) {
1659 AddBlocksFrom(It.Value(), BLO, NOT, EXT, NOQ);
1665 // Check, if there are seam or degenerated edges
1666 BlockFix_CheckTool aTool;
1667 aTool.SetShape(theShape);
1669 if (aTool.NbPossibleBlocks() > 0) {
1670 EXT.Append(theShape);
1672 // Count faces and edges in each face to recognize blocks
1673 TopTools_MapOfShape mapFaces;
1674 Standard_Integer nbFaces = 0;
1675 Standard_Boolean hasNonQuadr = Standard_False;
1676 TopExp_Explorer expF (theShape, TopAbs_FACE);
1678 for (; expF.More(); expF.Next()) {
1679 if (mapFaces.Add(expF.Current())) {
1681 //0021483//if (nbFaces > 6) break;
1684 TopoDS_Shape aF = expF.Current();
1685 TopExp_Explorer wires (aF, TopAbs_WIRE);
1686 if (!wires.More()) {
1687 // no wire in the face
1688 hasNonQuadr = Standard_True;
1689 NOQ.Append(aF);//0021483
1693 TopoDS_Shape aWire = wires.Current();
1696 // multiple wires in the face
1697 hasNonQuadr = Standard_True;
1698 NOQ.Append(aF);//0021483
1703 // Check number of edges in the face
1704 Standard_Integer nbEdges = 0;
1705 TopTools_MapOfShape mapEdges;
1706 TopExp_Explorer expW (aWire, TopAbs_EDGE);
1707 for (; expW.More(); expW.Next()) {
1708 if (mapEdges.Add(expW.Current())) {
1710 if (nbEdges > 4) break;
1714 hasNonQuadr = Standard_True;
1715 NOQ.Append(aF);//0021483
1720 if (nbFaces == 6 && !hasNonQuadr) {
1721 BLO.Append(theShape);
1723 NOT.Append(theShape);
1728 case TopAbs_SHELL: //0021483
1729 case TopAbs_FACE: //0021483
1731 // Count edges in each face
1732 TopTools_MapOfShape mapFaces;
1733 TopExp_Explorer expF (theShape, TopAbs_FACE);
1734 for (; expF.More(); expF.Next()) {
1735 if (mapFaces.Add(expF.Current())) {
1737 TopoDS_Shape aF = expF.Current();
1738 TopExp_Explorer wires (aF, TopAbs_WIRE);
1739 if (!wires.More()) {
1740 // no wire in the face
1741 NOQ.Append(aF);//0021483
1744 TopoDS_Shape aWire = wires.Current();
1747 // multiple wires in the face
1748 NOQ.Append(aF);//0021483
1752 // Check number of edges in the face
1753 Standard_Integer nbEdges = 0;
1754 TopTools_MapOfShape mapEdges;
1755 TopExp_Explorer expW (aWire, TopAbs_EDGE);
1756 for (; expW.More(); expW.Next()) {
1757 if (mapEdges.Add(expW.Current())) {
1759 if (nbEdges > 4) break;
1763 NOQ.Append(aF);//0021483
1770 NOT.Append(theShape);
1774 void AddBlocksFromOld (const TopoDS_Shape& theShape,
1775 TopTools_ListOfShape& BLO,
1776 TopTools_ListOfShape& NOT,
1777 TopTools_ListOfShape& DEG,
1778 TopTools_ListOfShape& SEA)
1780 TopAbs_ShapeEnum aType = theShape.ShapeType();
1782 case TopAbs_COMPOUND:
1783 case TopAbs_COMPSOLID:
1785 TopoDS_Iterator It (theShape);
1786 for (; It.More(); It.Next()) {
1787 AddBlocksFromOld(It.Value(), BLO, NOT, DEG, SEA);
1793 TopTools_MapOfShape mapFaces;
1794 TopExp_Explorer expF (theShape, TopAbs_FACE);
1795 Standard_Integer nbFaces = 0;
1796 Standard_Boolean hasNonQuadr = Standard_False;
1797 Standard_Boolean hasDegenerated = Standard_False;
1798 Standard_Boolean hasSeam = Standard_False;
1799 for (; expF.More(); expF.Next()) {
1800 if (mapFaces.Add(expF.Current())) {
1802 if (nbFaces > 6) break;
1804 // Check number of edges in the face
1805 Standard_Integer nbEdges = 0;
1806 TopTools_MapOfShape mapEdges;
1809 TopoDS_Shape aF = expF.Current();
1810 TopExp_Explorer wires (aF, TopAbs_WIRE);
1811 if (!wires.More()) {
1812 // no wire in the face
1813 hasNonQuadr = Standard_True;
1816 TopoDS_Shape aWire = wires.Current();
1819 // multiple wires in the face
1820 hasNonQuadr = Standard_True;
1825 BRepTools_WireExplorer aWE (TopoDS::Wire(aWire), TopoDS::Face(aF));
1826 for (; aWE.More(); aWE.Next(), nbEdges++) {
1827 if (BRep_Tool::Degenerated(aWE.Current())) {
1828 // degenerated edge found
1829 hasDegenerated = Standard_True;
1832 if (mapEdges.Contains(aWE.Current())) {
1834 hasSeam = Standard_True;
1837 mapEdges.Add(aWE.Current());
1840 hasNonQuadr = Standard_True;
1845 if (hasDegenerated || hasSeam) {
1846 if (hasDegenerated) {
1847 DEG.Append(theShape);
1850 SEA.Append(theShape);
1852 } else if (hasNonQuadr) {
1853 NOT.Append(theShape);
1855 BLO.Append(theShape);
1858 NOT.Append(theShape);
1863 NOT.Append(theShape);
1867 #define REL_NOT_CONNECTED 0
1869 #define REL_NOT_GLUED 2
1870 #define REL_COLLISION_VV 3
1871 #define REL_COLLISION_FF 4
1872 #define REL_COLLISION_EE 5
1873 #define REL_UNKNOWN 6
1875 Standard_Integer BlocksRelation (const TopoDS_Shape& theBlock1,
1876 const TopoDS_Shape& theBlock2)
1878 // Compare bounding boxes before calling BRepExtrema_DistShapeShape
1879 Standard_Real Xmin1, Ymin1, Zmin1, Xmax1, Ymax1, Zmax1;
1880 Standard_Real Xmin2, Ymin2, Zmin2, Xmax2, Ymax2, Zmax2;
1882 BRepBndLib::Add(theBlock1, B1);
1883 BRepBndLib::Add(theBlock2, B2);
1884 B1.Get(Xmin1, Ymin1, Zmin1, Xmax1, Ymax1, Zmax1);
1885 B2.Get(Xmin2, Ymin2, Zmin2, Xmax2, Ymax2, Zmax2);
1886 if (Xmax2 < Xmin1 || Xmax1 < Xmin2 ||
1887 Ymax2 < Ymin1 || Ymax1 < Ymin2 ||
1888 Zmax2 < Zmin1 || Zmax1 < Zmin2) {
1889 return REL_NOT_CONNECTED;
1892 BRepExtrema_DistShapeShape dst (theBlock1, theBlock2);
1893 if (!dst.IsDone()) {
1897 if (dst.Value() > Precision::Confusion()) {
1898 return REL_NOT_CONNECTED;
1901 if (dst.InnerSolution()) {
1902 return REL_COLLISION_VV;
1905 Standard_Integer nbSol = dst.NbSolution();
1906 Standard_Integer relation = REL_OK;
1907 Standard_Integer nbVerts = 0;
1908 Standard_Integer nbEdges = 0;
1909 Standard_Integer sol = 1;
1910 for (; sol <= nbSol; sol++) {
1911 BRepExtrema_SupportType supp1 = dst.SupportTypeShape1(sol);
1912 BRepExtrema_SupportType supp2 = dst.SupportTypeShape2(sol);
1913 if (supp1 == BRepExtrema_IsVertex && supp2 == BRepExtrema_IsVertex) {
1915 } else if (supp1 == BRepExtrema_IsInFace || supp2 == BRepExtrema_IsInFace) {
1916 return REL_COLLISION_FF;
1917 } else if (supp1 == BRepExtrema_IsOnEdge && supp2 == BRepExtrema_IsOnEdge) {
1919 } else if ((supp1 == BRepExtrema_IsOnEdge && supp2 == BRepExtrema_IsVertex) ||
1920 (supp2 == BRepExtrema_IsOnEdge && supp1 == BRepExtrema_IsVertex)) {
1921 relation = REL_COLLISION_EE;
1926 if (relation != REL_OK) {
1930 TColStd_Array1OfInteger vertSol (1, nbVerts);
1931 TopTools_Array1OfShape V1 (1, nbVerts);
1932 TopTools_Array1OfShape V2 (1, nbVerts);
1933 Standard_Integer ivs = 0;
1934 for (sol = 1; sol <= nbSol; sol++) {
1935 if (dst.SupportTypeShape1(sol) == BRepExtrema_IsVertex &&
1936 dst.SupportTypeShape2(sol) == BRepExtrema_IsVertex) {
1937 TopoDS_Vertex Vcur = TopoDS::Vertex(dst.SupportOnShape1(sol));
1938 // Check, that this vertex is far enough from other solution vertices.
1939 Standard_Integer ii = 1;
1940 for (; ii <= ivs; ii++) {
1941 if (BRepTools::Compare(TopoDS::Vertex(V1(ii)), Vcur)) {
1948 V2(ivs) = dst.SupportOnShape2(sol);
1952 // As we deal only with quadrangles,
1953 // 2, 3 or 4 vertex solutions can be found.
1956 return REL_COLLISION_FF;
1958 return REL_NOT_CONNECTED;
1964 // Check sharing of coincident entities.
1965 if (ivs == 2 || ivs == 3) {
1966 // Map vertices and edges of the blocks
1967 TopTools_IndexedDataMapOfShapeListOfShape MVE1, MVE2;
1968 GEOMImpl_Block6Explorer::MapShapesAndAncestors
1969 (theBlock1, TopAbs_VERTEX, TopAbs_EDGE, MVE1);
1970 GEOMImpl_Block6Explorer::MapShapesAndAncestors
1971 (theBlock2, TopAbs_VERTEX, TopAbs_EDGE, MVE2);
1975 TopoDS_Shape anEdge1, anEdge2;
1976 GEOMImpl_Block6Explorer::FindEdge(anEdge1, V1(1), V1(2), MVE1);
1977 if (anEdge1.IsNull()) return REL_UNKNOWN;
1979 GEOMImpl_Block6Explorer::FindEdge(anEdge2, V2(1), V2(2), MVE2);
1980 if (anEdge2.IsNull()) return REL_UNKNOWN;
1982 if (!anEdge1.IsSame(anEdge2)) return REL_NOT_GLUED;
1984 } else { // ivs == 3
1985 // Find common edges
1986 Standard_Integer e1_v1 = 1;
1987 Standard_Integer e1_v2 = 2;
1988 Standard_Integer e2_v1 = 3;
1989 Standard_Integer e2_v2 = 1;
1991 TopoDS_Shape anEdge11, anEdge12;
1992 GEOMImpl_Block6Explorer::FindEdge(anEdge11, V1(e1_v1), V1(e1_v2), MVE1);
1993 if (anEdge11.IsNull()) {
1996 GEOMImpl_Block6Explorer::FindEdge(anEdge11, V1(e1_v1), V1(e1_v2), MVE1);
1997 if (anEdge11.IsNull()) return REL_UNKNOWN;
1999 GEOMImpl_Block6Explorer::FindEdge(anEdge12, V1(e2_v1), V1(e2_v2), MVE1);
2000 if (anEdge12.IsNull()) {
2002 GEOMImpl_Block6Explorer::FindEdge(anEdge12, V1(e2_v1), V1(e2_v2), MVE1);
2003 if (anEdge12.IsNull()) return REL_UNKNOWN;
2006 TopoDS_Shape anEdge21, anEdge22;
2007 GEOMImpl_Block6Explorer::FindEdge(anEdge21, V2(e1_v1), V2(e1_v2), MVE2);
2008 if (anEdge21.IsNull()) return REL_UNKNOWN;
2009 GEOMImpl_Block6Explorer::FindEdge(anEdge22, V2(e2_v1), V2(e2_v2), MVE2);
2010 if (anEdge22.IsNull()) return REL_UNKNOWN;
2012 // Check of edges coincidence (with some precision) have to be done here
2013 // if (!anEdge11.IsEqual(anEdge21)) return REL_UNKNOWN;
2014 // if (!anEdge12.IsEqual(anEdge22)) return REL_UNKNOWN;
2016 // Check of edges sharing
2017 if (!anEdge11.IsSame(anEdge21)) return REL_NOT_GLUED;
2018 if (!anEdge12.IsSame(anEdge22)) return REL_NOT_GLUED;
2023 // Map vertices and faces of the blocks
2024 TopTools_IndexedDataMapOfShapeListOfShape MVF1, MVF2;
2025 GEOMImpl_Block6Explorer::MapShapesAndAncestors
2026 (theBlock1, TopAbs_VERTEX, TopAbs_FACE, MVF1);
2027 GEOMImpl_Block6Explorer::MapShapesAndAncestors
2028 (theBlock2, TopAbs_VERTEX, TopAbs_FACE, MVF2);
2030 TopoDS_Shape aFace1, aFace2;
2031 GEOMImpl_Block6Explorer::FindFace(aFace1, V1(1), V1(2), V1(3), V1(4), MVF1);
2032 if (aFace1.IsNull()) return REL_UNKNOWN;
2033 GEOMImpl_Block6Explorer::FindFace(aFace2, V2(1), V2(2), V2(3), V2(4), MVF2);
2034 if (aFace2.IsNull()) return REL_UNKNOWN;
2036 // Check of faces coincidence (with some precision) have to be done here
2037 // if (!aFace1.IsEqual(aFace2)) return REL_UNKNOWN;
2039 // Check of faces sharing
2040 if (!aFace1.IsSame(aFace2)) return REL_NOT_GLUED;
2046 void FindConnected (const Standard_Integer theBlockIndex,
2047 const TColStd_Array2OfInteger& theRelations,
2048 TColStd_MapOfInteger& theProcessedMap,
2049 TColStd_MapOfInteger& theConnectedMap)
2051 theConnectedMap.Add(theBlockIndex);
2052 theProcessedMap.Add(theBlockIndex);
2054 Standard_Integer nbBlocks = theRelations.ColLength();
2055 Standard_Integer col = 1;
2056 for (; col <= nbBlocks; col++) {
2057 if (theRelations(theBlockIndex, col) == REL_OK ||
2058 theRelations(theBlockIndex, col) == REL_NOT_GLUED) {
2059 if (!theProcessedMap.Contains(col)) {
2060 FindConnected(col, theRelations, theProcessedMap, theConnectedMap);
2066 Standard_Boolean HasAnyConnection (const Standard_Integer theBlockIndex,
2067 const TColStd_MapOfInteger& theWith,
2068 const TColStd_Array2OfInteger& theRelations,
2069 TColStd_MapOfInteger& theProcessedMap)
2071 theProcessedMap.Add(theBlockIndex);
2073 Standard_Integer nbBlocks = theRelations.ColLength();
2074 Standard_Integer col = 1;
2075 for (; col <= nbBlocks; col++) {
2076 if (theRelations(theBlockIndex, col) != REL_NOT_CONNECTED) {
2077 if (!theProcessedMap.Contains(col)) {
2078 if (theWith.Contains(col))
2079 return Standard_True;
2080 if (HasAnyConnection(col, theWith, theRelations, theProcessedMap))
2081 return Standard_True;
2086 return Standard_False;
2089 //=============================================================================
2091 * CheckCompoundOfBlocksOld
2093 //=============================================================================
2094 Standard_Boolean GEOMImpl_IBlocksOperations::CheckCompoundOfBlocksOld
2095 (Handle(GEOM_Object) theCompound,
2096 std::list<BCError>& theErrors)
2100 if (theCompound.IsNull()) return Standard_False;
2101 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2103 Standard_Boolean isCompOfBlocks = Standard_True;
2105 // Map sub-shapes and their indices
2106 TopTools_IndexedMapOfShape anIndices;
2107 TopExp::MapShapes(aBlockOrComp, anIndices);
2109 // 1. Report non-blocks
2110 TopTools_ListOfShape NOT; // Not blocks
2111 TopTools_ListOfShape DEG; // Hexahedral solids, having degenerated edges
2112 TopTools_ListOfShape SEA; // Hexahedral solids, having seam edges
2113 TopTools_ListOfShape BLO; // All blocks from the given compound
2114 AddBlocksFromOld(aBlockOrComp, BLO, NOT, DEG, SEA);
2116 if (NOT.Extent() > 0) {
2117 isCompOfBlocks = Standard_False;
2119 anErr.error = NOT_BLOCK;
2120 TopTools_ListIteratorOfListOfShape it (NOT);
2121 for (; it.More(); it.Next()) {
2122 anErr.incriminated.push_back(anIndices.FindIndex(it.Value()));
2124 theErrors.push_back(anErr);
2127 if (DEG.Extent() > 0 || SEA.Extent() > 0) {
2128 isCompOfBlocks = Standard_False;
2130 anErr.error = EXTRA_EDGE;
2132 TopTools_ListIteratorOfListOfShape itDEG (DEG);
2133 for (; itDEG.More(); itDEG.Next()) {
2134 anErr.incriminated.push_back(anIndices.FindIndex(itDEG.Value()));
2137 TopTools_ListIteratorOfListOfShape itSEA (SEA);
2138 for (; itSEA.More(); itSEA.Next()) {
2139 anErr.incriminated.push_back(anIndices.FindIndex(itSEA.Value()));
2142 theErrors.push_back(anErr);
2145 Standard_Integer nbBlocks = BLO.Extent();
2146 if (nbBlocks == 0) {
2147 isCompOfBlocks = Standard_False;
2149 return isCompOfBlocks;
2151 if (nbBlocks == 1) {
2153 return isCompOfBlocks;
2156 // Convert list of blocks into array for easy and fast access
2157 Standard_Integer ibl = 1;
2158 TopTools_Array1OfShape aBlocks (1, nbBlocks);
2159 TopTools_ListIteratorOfListOfShape BLOit (BLO);
2160 for (; BLOit.More(); BLOit.Next(), ibl++) {
2161 aBlocks.SetValue(ibl, BLOit.Value());
2164 // 2. Find relations between all blocks,
2165 // report connection errors (NOT_GLUED and INVALID_CONNECTION)
2166 TColStd_Array2OfInteger aRelations (1, nbBlocks, 1, nbBlocks);
2167 aRelations.Init(REL_NOT_CONNECTED);
2169 Standard_Integer row = 1;
2170 for (row = 1; row <= nbBlocks; row++) {
2171 TopoDS_Shape aBlock = aBlocks.Value(row);
2173 Standard_Integer col = row + 1;
2174 for (; col <= nbBlocks; col++) {
2175 Standard_Integer aRel = BlocksRelation(aBlock, aBlocks.Value(col));
2176 if (aRel != REL_NOT_CONNECTED) {
2177 aRelations.SetValue(row, col, aRel);
2178 aRelations.SetValue(col, row, aRel);
2179 if (aRel == REL_NOT_GLUED) {
2180 // report connection error
2181 isCompOfBlocks = Standard_False;
2183 anErr.error = NOT_GLUED;
2184 anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(row)));
2185 anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(col)));
2186 theErrors.push_back(anErr);
2187 } else if (aRel == REL_COLLISION_VV ||
2188 aRel == REL_COLLISION_FF ||
2189 aRel == REL_COLLISION_EE ||
2190 aRel == REL_UNKNOWN) {
2191 // report connection error
2192 isCompOfBlocks = Standard_False;
2194 anErr.error = INVALID_CONNECTION;
2195 anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(row)));
2196 anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(col)));
2197 theErrors.push_back(anErr);
2204 // 3. Find largest set of connected (good connection or not glued) blocks
2205 TColStd_MapOfInteger aProcessedMap;
2206 TColStd_MapOfInteger aLargestSet;
2207 TColStd_MapOfInteger aCurrentSet;
2208 for (ibl = 1; ibl <= nbBlocks; ibl++) {
2209 if (!aProcessedMap.Contains(ibl)) {
2210 aCurrentSet.Clear();
2211 FindConnected(ibl, aRelations, aProcessedMap, aCurrentSet);
2212 if (aCurrentSet.Extent() > aLargestSet.Extent()) {
2213 aLargestSet = aCurrentSet;
2218 // 4. Report all blocks, isolated from <aLargestSet>
2220 anErr.error = NOT_CONNECTED;
2221 Standard_Boolean hasIsolated = Standard_False;
2222 for (ibl = 1; ibl <= nbBlocks; ibl++) {
2223 if (!aLargestSet.Contains(ibl)) {
2224 aProcessedMap.Clear();
2225 if (!HasAnyConnection(ibl, aLargestSet, aRelations, aProcessedMap)) {
2226 // report connection absence
2227 hasIsolated = Standard_True;
2228 anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(ibl)));
2233 isCompOfBlocks = Standard_False;
2234 theErrors.push_back(anErr);
2238 return isCompOfBlocks;
2241 //=============================================================================
2245 //=============================================================================
2246 TCollection_AsciiString GEOMImpl_IBlocksOperations::PrintBCErrors
2247 (Handle(GEOM_Object) theCompound,
2248 const std::list<BCError>& theErrors)
2250 TCollection_AsciiString aDescr;
2252 std::list<BCError>::const_iterator errIt = theErrors.begin();
2254 for (; errIt != theErrors.end(); i++, errIt++) {
2255 BCError errStruct = *errIt;
2257 switch (errStruct.error) {
2259 aDescr += "\n\tNot a Blocks: ";
2262 aDescr += "\n\tHexahedral solids with degenerated and/or seam edges: ";
2264 case INVALID_CONNECTION:
2265 aDescr += "\n\tInvalid connection between two blocks: ";
2268 aDescr += "\n\tBlocks, not connected with main body: ";
2271 aDescr += "\n\tNot glued blocks: ";
2277 std::list<int> sshList = errStruct.incriminated;
2278 std::list<int>::iterator sshIt = sshList.begin();
2280 for (; sshIt != sshList.end(); jj++, sshIt++) {
2283 aDescr += TCollection_AsciiString(*sshIt);
2290 //=============================================================================
2292 * CheckCompoundOfBlocks
2294 //=============================================================================
2295 Standard_Boolean GEOMImpl_IBlocksOperations::CheckCompoundOfBlocks
2296 (Handle(GEOM_Object) theCompound,
2297 std::list<BCError>& theErrors)
2301 if (theCompound.IsNull()) return Standard_False;
2302 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2304 Standard_Boolean isCompOfBlocks = Standard_True;
2306 // Map sub-shapes and their indices
2307 TopTools_IndexedMapOfShape anIndices;
2308 TopExp::MapShapes(aBlockOrComp, anIndices);
2310 // 1. Separate blocks from non-blocks
2311 TopTools_ListOfShape NOT; // Not blocks
2312 TopTools_ListOfShape EXT; // Hexahedral solids, having degenerated and/or seam edges
2313 TopTools_ListOfShape BLO; // All blocks from the given compound
2314 TopTools_ListOfShape NOQ; // All non-quadrangular faces
2315 AddBlocksFrom(aBlockOrComp, BLO, NOT, EXT, NOQ);
2317 // Report non-blocks
2318 if (NOT.Extent() > 0) {
2319 isCompOfBlocks = Standard_False;
2321 anErr.error = NOT_BLOCK;
2322 TopTools_ListIteratorOfListOfShape it (NOT);
2323 for (; it.More(); it.Next()) {
2324 anErr.incriminated.push_back(anIndices.FindIndex(it.Value()));
2326 theErrors.push_back(anErr);
2329 // Report solids, having degenerated and/or seam edges
2330 if (EXT.Extent() > 0) {
2331 isCompOfBlocks = Standard_False;
2333 anErr.error = EXTRA_EDGE;
2334 TopTools_ListIteratorOfListOfShape it (EXT);
2335 for (; it.More(); it.Next()) {
2336 anErr.incriminated.push_back(anIndices.FindIndex(it.Value()));
2338 theErrors.push_back(anErr);
2341 Standard_Integer nbBlocks = BLO.Extent();
2342 if (nbBlocks == 0) {
2343 isCompOfBlocks = Standard_False;
2345 return isCompOfBlocks;
2347 if (nbBlocks == 1) {
2349 return isCompOfBlocks;
2352 // Prepare data for 2. and 3.
2353 TColStd_Array2OfInteger aRelations (1, nbBlocks, 1, nbBlocks);
2354 aRelations.Init(REL_NOT_CONNECTED);
2356 TopTools_IndexedMapOfShape mapBlocks;
2359 TopoDS_Compound aComp;
2360 BB.MakeCompound(aComp);
2362 TopTools_ListIteratorOfListOfShape BLOit (BLO);
2363 for (; BLOit.More(); BLOit.Next()) {
2364 mapBlocks.Add(BLOit.Value());
2365 BB.Add(aComp, BLOit.Value());
2368 // 2. Find glued blocks (having shared faces)
2369 TopTools_IndexedDataMapOfShapeListOfShape mapFaceBlocks;
2370 GEOMImpl_Block6Explorer::MapShapesAndAncestors
2371 (aComp, TopAbs_FACE, TopAbs_SOLID, mapFaceBlocks);
2373 Standard_Integer prevInd = 0, curInd = 0;
2374 Standard_Integer ind = 1, nbFaces = mapFaceBlocks.Extent();
2375 for (; ind <= nbFaces; ind++) {
2376 const TopTools_ListOfShape& aGluedBlocks = mapFaceBlocks.FindFromIndex(ind);
2377 if (aGluedBlocks.Extent() > 1) { // Shared face found
2378 TopTools_ListIteratorOfListOfShape aGluedBlocksIt (aGluedBlocks);
2379 TopoDS_Shape prevBlock, curBlock;
2380 for (; aGluedBlocksIt.More(); aGluedBlocksIt.Next()) {
2381 curBlock = aGluedBlocksIt.Value();
2382 if (!prevBlock.IsNull()) {
2383 prevInd = mapBlocks.FindIndex(prevBlock);
2384 curInd = mapBlocks.FindIndex(curBlock);
2385 aRelations.SetValue(prevInd, curInd, REL_OK);
2386 aRelations.SetValue(curInd, prevInd, REL_OK);
2388 prevBlock = curBlock;
2393 // 3. Find not glued blocks
2394 GEOMAlgo_GlueAnalyser aGD;
2396 aGD.SetShape(aComp);
2397 aGD.SetTolerance(Precision::Confusion());
2398 aGD.SetCheckGeometry(Standard_True);
2401 Standard_Integer iErr, iWrn;
2402 iErr = aGD.ErrorStatus();
2404 SetErrorCode("Error in GEOMAlgo_GlueAnalyser");
2405 return isCompOfBlocks;
2407 iWrn = aGD.WarningStatus();
2409 MESSAGE("Warning in GEOMAlgo_GlueAnalyser");
2412 // Report not glued blocks
2413 if (aGD.HasSolidsToGlue()) {
2414 isCompOfBlocks = Standard_False;
2415 Standard_Integer aSx1Ind, aSx2Ind;
2417 const GEOMAlgo_ListOfCoupleOfShapes& aLCS = aGD.SolidsToGlue();
2418 GEOMAlgo_ListIteratorOfListOfCoupleOfShapes aItCS (aLCS);
2419 for (; aItCS.More(); aItCS.Next()) {
2420 const GEOMAlgo_CoupleOfShapes& aCS = aItCS.Value();
2421 const TopoDS_Shape& aSx1 = aCS.Shape1();
2422 const TopoDS_Shape& aSx2 = aCS.Shape2();
2424 aSx1Ind = mapBlocks.FindIndex(aSx1);
2425 aSx2Ind = mapBlocks.FindIndex(aSx2);
2426 aRelations.SetValue(aSx1Ind, aSx2Ind, NOT_GLUED);
2427 aRelations.SetValue(aSx2Ind, aSx1Ind, NOT_GLUED);
2430 anErr.error = NOT_GLUED;
2431 anErr.incriminated.push_back(anIndices.FindIndex(aSx1));
2432 anErr.incriminated.push_back(anIndices.FindIndex(aSx2));
2433 theErrors.push_back(anErr);
2437 // 4. Find largest set of connected (good connection or not glued) blocks
2438 Standard_Integer ibl = 1;
2439 TColStd_MapOfInteger aProcessedMap;
2440 TColStd_MapOfInteger aLargestSet;
2441 TColStd_MapOfInteger aCurrentSet;
2442 for (ibl = 1; ibl <= nbBlocks; ibl++) {
2443 if (!aProcessedMap.Contains(ibl)) {
2444 aCurrentSet.Clear();
2445 FindConnected(ibl, aRelations, aProcessedMap, aCurrentSet);
2446 if (aCurrentSet.Extent() > aLargestSet.Extent()) {
2447 aLargestSet = aCurrentSet;
2452 // 5. Report all blocks, isolated from <aLargestSet>
2454 anErr.error = NOT_CONNECTED;
2455 Standard_Boolean hasIsolated = Standard_False;
2456 for (ibl = 1; ibl <= nbBlocks; ibl++) {
2457 if (!aLargestSet.Contains(ibl)) {
2458 aProcessedMap.Clear();
2459 if (!HasAnyConnection(ibl, aLargestSet, aRelations, aProcessedMap)) {
2460 // report connection absence
2461 hasIsolated = Standard_True;
2462 anErr.incriminated.push_back(anIndices.FindIndex(mapBlocks.FindKey(ibl)));
2467 isCompOfBlocks = Standard_False;
2468 theErrors.push_back(anErr);
2472 return isCompOfBlocks;
2475 //=============================================================================
2479 //=============================================================================
2480 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetNonBlocks
2481 (Handle(GEOM_Object) theShape,
2482 Handle(GEOM_Object)& theNonQuads)
2486 if (theShape.IsNull()) return NULL;
2487 TopoDS_Shape aShape = theShape->GetValue();
2489 // Separate blocks from non-blocks
2490 TopTools_ListOfShape BLO; // All blocks from the given compound
2491 TopTools_ListOfShape NOT; // Not blocks
2492 TopTools_ListOfShape EXT; // Hexahedral solids, having degenerated and/or seam edges
2493 TopTools_ListOfShape NOQ; // All non-quadrangular faces
2494 AddBlocksFrom(aShape, BLO, NOT, EXT, NOQ);
2496 if (NOT.IsEmpty() && EXT.IsEmpty() && NOQ.IsEmpty()) {
2497 SetErrorCode("NOT_FOUND_ANY");
2501 // Map sub-shapes and their indices
2502 TopTools_IndexedMapOfShape anIndices;
2503 TopExp::MapShapes(aShape, anIndices);
2506 Handle(GEOM_Object) aNonBlocks;
2507 if (NOT.Extent() > 0 || EXT.Extent() > 0) {
2508 Handle(TColStd_HArray1OfInteger) anArray =
2509 new TColStd_HArray1OfInteger (1, NOT.Extent() + EXT.Extent());
2510 Standard_Integer ii = 1;
2511 TopTools_ListIteratorOfListOfShape it1 (NOT);
2512 for (; it1.More(); it1.Next(), ii++) {
2513 anArray->SetValue(ii, anIndices.FindIndex(it1.Value()));
2515 TopTools_ListIteratorOfListOfShape it2 (EXT);
2516 for (; it2.More(); it2.Next(), ii++) {
2517 anArray->SetValue(ii, anIndices.FindIndex(it2.Value()));
2520 aNonBlocks = GetEngine()->AddSubShape(theShape, anArray);
2521 if (aNonBlocks.IsNull()) {
2522 SetErrorCode("Error in algorithm: result found, but cannot be returned.");
2525 aNonBlocks->SetType(GEOM_GROUP);
2526 TDF_Label aFreeLabel = aNonBlocks->GetFreeLabel();
2527 TDataStd_Integer::Set(aFreeLabel, (Standard_Integer)TopAbs_SOLID);
2531 if (NOQ.Extent() > 0) {
2532 Handle(TColStd_HArray1OfInteger) anArray =
2533 new TColStd_HArray1OfInteger (1, NOQ.Extent());
2534 Standard_Integer ii = 1;
2535 TopTools_ListIteratorOfListOfShape it1 (NOQ);
2536 for (; it1.More(); it1.Next(), ii++) {
2537 anArray->SetValue(ii, anIndices.FindIndex(it1.Value()));
2540 theNonQuads = GetEngine()->AddSubShape(theShape, anArray);
2541 if (theNonQuads.IsNull()) {
2542 SetErrorCode("Error in algorithm: result found, but cannot be returned.");
2545 theNonQuads->SetType(GEOM_GROUP);
2546 TDF_Label aFreeLabel = theNonQuads->GetFreeLabel();
2547 TDataStd_Integer::Set(aFreeLabel, (Standard_Integer)TopAbs_FACE);
2550 //Make a Python command
2551 Handle(GEOM_Function) aMainShape = theShape->GetLastFunction();
2552 GEOM::TPythonDump pd (aMainShape, /*append=*/true);
2554 if (aNonBlocks.IsNull())
2555 pd << "no_bad_solids";
2559 if (theNonQuads.IsNull())
2560 pd << "no_bad_faces";
2563 pd << ") = geompy.GetNonBlocks(" << theShape << ")";
2569 //=============================================================================
2573 //=============================================================================
2574 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::RemoveExtraEdges
2575 (Handle(GEOM_Object) theObject,
2576 const Standard_Integer theOptimumNbFaces)
2580 if (theObject.IsNull()) return NULL;
2582 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
2583 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be fixed
2585 //Add a new Copy object
2586 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
2589 Handle(GEOM_Function) aFunction =
2590 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_REMOVE_EXTRA);
2592 //Check if the function is set correctly
2593 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
2595 GEOMImpl_IBlockTrsf aTI (aFunction);
2596 aTI.SetOriginal(aLastFunction);
2597 aTI.SetOptimumNbFaces(theOptimumNbFaces);
2599 //Compute the fixed shape
2602 if (!GetSolver()->ComputeFunction(aFunction)) {
2603 SetErrorCode("Block driver failed to remove extra edges of the given shape");
2607 catch (Standard_Failure) {
2608 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2609 SetErrorCode(aFail->GetMessageString());
2613 //Make a Python command
2614 std::string doUnionFaces = (theOptimumNbFaces < 0) ? "False" : "True";
2615 GEOM::TPythonDump(aFunction) << aCopy << " = geompy.RemoveExtraEdges("
2616 << theObject << ", " << doUnionFaces.data() << ")";
2622 //=============================================================================
2626 //=============================================================================
2627 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::UnionFaces
2628 (Handle(GEOM_Object) theObject)
2632 if (theObject.IsNull()) return NULL;
2634 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
2635 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be fixed
2637 //Add a new Copy object
2638 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
2641 Handle(GEOM_Function) aFunction =
2642 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_UNION_FACES);
2644 //Check if the function is set correctly
2645 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
2647 GEOMImpl_IBlockTrsf aTI (aFunction);
2648 aTI.SetOriginal(aLastFunction);
2650 //Compute the fixed shape
2653 if (!GetSolver()->ComputeFunction(aFunction)) {
2654 SetErrorCode("Block driver failed to remove extra edges of the given shape");
2658 catch (Standard_Failure) {
2659 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2660 SetErrorCode(aFail->GetMessageString());
2664 //Make a Python command
2665 GEOM::TPythonDump(aFunction) << aCopy << " = geompy.UnionFaces("
2666 << theObject << ")";
2672 //=============================================================================
2676 //=============================================================================
2677 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::CheckAndImprove
2678 (Handle(GEOM_Object) theObject)
2682 if (theObject.IsNull()) return NULL;
2684 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
2685 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be fixed
2687 //Add a new Copy object
2688 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
2691 Handle(GEOM_Function) aFunction =
2692 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_COMPOUND_IMPROVE);
2694 //Check if the function is set correctly
2695 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
2697 GEOMImpl_IBlockTrsf aTI (aFunction);
2698 aTI.SetOriginal(aLastFunction);
2700 // -1 means do not unite faces on common surface (?except case of seam edge between them?)
2701 //aTI.SetOptimumNbFaces(-1);
2702 aTI.SetOptimumNbFaces(6);
2704 //Compute the fixed shape
2707 if (!GetSolver()->ComputeFunction(aFunction)) {
2708 SetErrorCode("Block driver failed to improve the given blocks compound");
2712 catch (Standard_Failure) {
2713 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2714 SetErrorCode(aFail->GetMessageString());
2718 //Make a Python command
2719 GEOM::TPythonDump(aFunction) << aCopy
2720 << " = geompy.CheckAndImprove(" << theObject << ")";
2726 //=============================================================================
2728 * ExplodeCompoundOfBlocks
2730 //=============================================================================
2731 Handle(TColStd_HSequenceOfTransient) GEOMImpl_IBlocksOperations::ExplodeCompoundOfBlocks
2732 (Handle(GEOM_Object) theCompound,
2733 const Standard_Integer theMinNbFaces,
2734 const Standard_Integer theMaxNbFaces)
2738 if (theCompound.IsNull()) return NULL;
2739 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2740 if (aBlockOrComp.IsNull()) return NULL;
2742 Handle(TColStd_HSequenceOfTransient) aBlocks = new TColStd_HSequenceOfTransient;
2743 Handle(GEOM_Object) anObj;
2744 Handle(GEOM_Function) aFunction;
2746 TopTools_MapOfShape mapShape;
2747 TCollection_AsciiString anAsciiList, anEntry;
2750 TopTools_IndexedMapOfShape anIndices;
2751 TopExp::MapShapes(aBlockOrComp, anIndices);
2752 Handle(TColStd_HArray1OfInteger) anArray;
2757 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2758 for (; exp.More(); exp.Next()) {
2759 if (mapShape.Add(exp.Current())) {
2760 TopoDS_Shape aSolid = exp.Current();
2762 TopTools_MapOfShape mapFaces;
2763 TopExp_Explorer expF (aSolid, TopAbs_FACE);
2764 Standard_Integer nbFaces = 0;
2765 for (; expF.More(); expF.Next()) {
2766 if (mapFaces.Add(expF.Current())) {
2771 if (theMinNbFaces <= nbFaces && nbFaces <= theMaxNbFaces) {
2772 anArray = new TColStd_HArray1OfInteger(1,1);
2773 anArray->SetValue(1, anIndices.FindIndex(aSolid));
2774 anObj = GetEngine()->AddSubShape(theCompound, anArray);
2775 aBlocks->Append(anObj);
2777 //Make a Python command
2778 TDF_Tool::Entry(anObj->GetEntry(), anEntry);
2779 anAsciiList += anEntry + ", ";
2784 catch (Standard_Failure) {
2785 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2786 SetErrorCode(aFail->GetMessageString());
2790 if (aBlocks->IsEmpty()) {
2791 SetErrorCode("There are no specified blocks in the given shape");
2795 anAsciiList.Trunc(anAsciiList.Length() - 2);
2797 //The explode doesn't change object so no new function is required.
2798 aFunction = theCompound->GetLastFunction();
2800 //Make a Python command
2801 GEOM::TPythonDump(aFunction, /*append=*/true)
2802 << "[" << anAsciiList.ToCString() << "] = geompy.MakeBlockExplode("
2803 << theCompound << ", " << theMinNbFaces << ", " << theMaxNbFaces << ")";
2809 //=============================================================================
2813 //=============================================================================
2814 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetBlockNearPoint
2815 (Handle(GEOM_Object) theCompound,
2816 Handle(GEOM_Object) thePoint)
2821 Handle(GEOM_Object) aResult;
2824 if (theCompound.IsNull() || thePoint.IsNull()) return NULL;
2826 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2827 if (aBlockOrComp.IsNull()) {
2828 SetErrorCode("Compound is null");
2831 if (aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
2832 aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
2833 SetErrorCode("Shape to find block in is not a compound");
2837 TopoDS_Shape anArg = thePoint->GetValue();
2838 if (anArg.IsNull()) {
2839 SetErrorCode("Point is null");
2842 if (anArg.ShapeType() != TopAbs_VERTEX) {
2843 SetErrorCode("Shape for block identification is not a vertex");
2847 //Compute the Block value
2850 TopoDS_Shape aShape;
2852 TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
2853 gp_Pnt aPnt = BRep_Tool::Pnt(aVert);
2854 Standard_Real PX, PY, PZ;
2855 aPnt.Coord(PX, PY, PZ);
2857 // 1. Classify the point relatively each block
2858 Standard_Integer nearest = 2, nbFound = 0;
2859 TopTools_DataMapOfShapeInteger mapShapeDist;
2860 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2861 for (; exp.More(); exp.Next()) {
2862 TopoDS_Shape aSolid = exp.Current();
2864 if (!mapShapeDist.IsBound(aSolid)) {
2865 Standard_Integer aDistance = 2;
2867 // 1.a. Classify relatively Bounding box
2868 Standard_Real Xmin, Ymin, Zmin, Xmax, Ymax, Zmax;
2870 BRepBndLib::Add(aSolid, BB);
2871 BB.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);
2872 if (PX < Xmin || Xmax < PX ||
2873 PY < Ymin || Ymax < PY ||
2874 PZ < Zmin || Zmax < PZ) {
2875 // OUT of bounding box
2878 // 1.b. Classify relatively the solid itself
2879 BRepClass3d_SolidClassifier SC (aSolid, aPnt, Precision::Confusion());
2880 if (SC.State() == TopAbs_IN) {
2882 } else if (SC.State() == TopAbs_ON) {
2889 if (aDistance < nearest) {
2890 nearest = aDistance;
2894 // A first found block, containing the point inside, will be returned.
2895 // It is the solution, if there are no intersecting blocks in the compound.
2896 if (nearest == -1) break;
2898 } else if (aDistance == nearest) {
2903 mapShapeDist.Bind(aSolid, aDistance);
2904 } // if (!mapShapeDist.IsBound(aSolid))
2907 // 2. Define block, containing the point or having minimum distance to it
2910 // The point is on boundary of some blocks and there are
2911 // no blocks, having the point inside their volume
2912 SetErrorCode("Multiple blocks near the given point are found");
2915 } else if (nearest == 1) {
2916 // The point is outside some blocks and there are
2917 // no blocks, having the point inside or on boundary.
2918 // We will get a nearest block
2919 Standard_Real minDist = RealLast();
2920 TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
2921 for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
2922 if (mapShapeDistIter.Value() == 1) {
2923 TopoDS_Shape aSolid = mapShapeDistIter.Key();
2924 BRepExtrema_DistShapeShape aDistTool (aVert, aSolid);
2925 if (!aDistTool.IsDone()) {
2926 SetErrorCode("Can not find a distance from the given point to one of blocks");
2929 Standard_Real aDist = aDistTool.Value();
2930 if (aDist < minDist) {
2936 } else { // nearest == -1
2937 // // The point is inside some blocks.
2938 // // We will get a block with nearest center
2939 // Standard_Real minDist = RealLast();
2940 // TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
2941 // for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
2942 // if (mapShapeDistIter.Value() == -1) {
2943 // TopoDS_Shape aSolid = mapShapeDistIter.Key();
2944 // GProp_GProps aSystem;
2945 // BRepGProp::VolumeProperties(aSolid, aSystem);
2946 // gp_Pnt aCenterMass = aSystem.CentreOfMass();
2948 // Standard_Real aDist = aCenterMass.Distance(aPnt);
2949 // if (aDist < minDist) {
2956 } // if (nbFound > 1)
2959 SetErrorCode("There are no blocks near the given point");
2962 TopTools_IndexedMapOfShape anIndices;
2963 TopExp::MapShapes(aBlockOrComp, anIndices);
2964 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
2965 anArray->SetValue(1, anIndices.FindIndex(aShape));
2966 aResult = GetEngine()->AddSubShape(theCompound, anArray);
2969 catch (Standard_Failure) {
2970 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2971 SetErrorCode(aFail->GetMessageString());
2975 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
2977 //Make a Python command
2978 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetBlockNearPoint("
2979 << theCompound << ", " << thePoint << ")";
2985 //=============================================================================
2989 //=============================================================================
2990 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetBlockByParts
2991 (Handle(GEOM_Object) theCompound,
2992 const Handle(TColStd_HSequenceOfTransient)& theParts)
2996 Handle(GEOM_Object) aResult;
2998 if (theCompound.IsNull() || theParts.IsNull()) return NULL;
2999 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
3000 if (aBlockOrComp.IsNull()) return NULL;
3003 Standard_Integer argi, aLen = theParts->Length();
3004 TopTools_Array1OfShape anArgs (1, aLen);
3005 TCollection_AsciiString anEntry, aPartsDescr;
3006 for (argi = 1; argi <= aLen; argi++) {
3007 Handle(GEOM_Object) anObj = Handle(GEOM_Object)::DownCast(theParts->Value(argi));
3008 Handle(GEOM_Function) aRef = anObj->GetLastFunction();
3009 if (aRef.IsNull()) return NULL;
3011 TopoDS_Shape anArg = aRef->GetValue();
3012 if (anArg.IsNull()) {
3013 SetErrorCode("Null shape is given as argument");
3016 anArgs(argi) = anArg;
3018 // For Python command
3019 TDF_Tool::Entry(anObj->GetEntry(), anEntry);
3020 if (argi > 1) aPartsDescr += ", ";
3021 aPartsDescr += anEntry;
3024 //Compute the Block value
3027 // 1. Explode compound on solids
3028 TopTools_MapOfShape mapShape;
3029 Standard_Integer nbSolids = 0;
3030 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
3031 for (; exp.More(); exp.Next()) {
3032 if (mapShape.Add(exp.Current())) {
3038 Standard_Integer ind = 1;
3039 TopTools_Array1OfShape aSolids (1, nbSolids);
3040 TColStd_Array1OfInteger aNbParts (1, nbSolids);
3041 for (exp.Init(aBlockOrComp, TopAbs_SOLID); exp.More(); exp.Next(), ind++) {
3042 if (mapShape.Add(exp.Current())) {
3043 TopoDS_Shape aSolid = exp.Current();
3044 aSolids(ind) = aSolid;
3047 // 2. Define quantity of parts, contained in each solid
3048 TopTools_IndexedMapOfShape aSubShapes;
3049 TopExp::MapShapes(aSolid, aSubShapes);
3050 for (argi = 1; argi <= aLen; argi++) {
3051 if (aSubShapes.Contains(anArgs(argi))) {
3058 // 3. Define solid, containing maximum quantity of parts
3059 Standard_Integer maxNb = 0, nbFound = 0;
3060 TopoDS_Shape aShape;
3061 for (ind = 1; ind <= nbSolids; ind++) {
3062 if (aNbParts(ind) > maxNb) {
3063 maxNb = aNbParts(ind);
3064 aShape = aSolids(ind);
3066 } else if (aNbParts(ind) == maxNb) {
3072 SetErrorCode("Multiple blocks, containing maximum quantity of the given parts, are found");
3074 } else if (nbFound == 0) {
3075 SetErrorCode("There are no blocks, containing the given parts");
3078 TopTools_IndexedMapOfShape anIndices;
3079 TopExp::MapShapes(aBlockOrComp, anIndices);
3080 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
3081 anArray->SetValue(1, anIndices.FindIndex(aShape));
3082 aResult = GetEngine()->AddSubShape(theCompound, anArray);
3084 } catch (Standard_Failure) {
3085 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
3086 SetErrorCode(aFail->GetMessageString());
3090 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
3092 //Make a Python command
3093 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetBlockByParts("
3094 << theCompound << ", [" << aPartsDescr.ToCString() << "])";
3100 //=============================================================================
3104 //=============================================================================
3105 Handle(TColStd_HSequenceOfTransient) GEOMImpl_IBlocksOperations::GetBlocksByParts
3106 (Handle(GEOM_Object) theCompound,
3107 const Handle(TColStd_HSequenceOfTransient)& theParts)
3111 if (theCompound.IsNull() || theParts.IsNull()) return NULL;
3112 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
3113 if (aBlockOrComp.IsNull()) return NULL;
3115 Handle(TColStd_HSequenceOfTransient) aBlocks = new TColStd_HSequenceOfTransient;
3116 Handle(GEOM_Object) anObj;
3117 Handle(GEOM_Function) aFunction;
3120 Standard_Integer argi, aLen = theParts->Length();
3121 TopTools_Array1OfShape anArgs (1, aLen);
3122 TCollection_AsciiString anEntry, aPartsDescr, anAsciiList;
3124 for (argi = 1; argi <= aLen; argi++) {
3125 Handle(GEOM_Object) anObj = Handle(GEOM_Object)::DownCast(theParts->Value(argi));
3126 Handle(GEOM_Function) aRef = anObj->GetLastFunction();
3127 if (aRef.IsNull()) return NULL;
3129 TopoDS_Shape anArg = aRef->GetValue();
3130 if (anArg.IsNull()) {
3131 SetErrorCode("Null shape is given as argument");
3134 anArgs(argi) = anArg;
3136 // For Python command
3137 TDF_Tool::Entry(anObj->GetEntry(), anEntry);
3138 aPartsDescr += anEntry + ", ";
3144 TopTools_MapOfShape mapShape;
3145 Standard_Integer nbSolids = 0;
3146 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
3147 for (; exp.More(); exp.Next()) {
3148 if (mapShape.Add(exp.Current())) {
3154 Standard_Integer ind = 1;
3155 TopTools_Array1OfShape aSolids (1, nbSolids);
3156 TColStd_Array1OfInteger aNbParts (1, nbSolids);
3157 for (exp.Init(aBlockOrComp, TopAbs_SOLID); exp.More(); exp.Next(), ind++) {
3158 if (mapShape.Add(exp.Current())) {
3159 TopoDS_Shape aSolid = exp.Current();
3160 aSolids(ind) = aSolid;
3163 // 2. Define quantity of parts, contained in each solid
3164 TopTools_IndexedMapOfShape aSubShapes;
3165 TopExp::MapShapes(aSolid, aSubShapes);
3166 for (argi = 1; argi <= aLen; argi++) {
3167 if (aSubShapes.Contains(anArgs(argi))) {
3174 // 3. Define solid, containing maximum quantity of parts
3175 Standard_Integer maxNb = 0, nbFound = 0;
3176 for (ind = 1; ind <= nbSolids; ind++) {
3177 if (aNbParts(ind) > maxNb) {
3178 maxNb = aNbParts(ind);
3180 } else if (aNbParts(ind) == maxNb) {
3186 SetErrorCode("There are no blocks, containing the given parts");
3191 TopTools_IndexedMapOfShape anIndices;
3192 TopExp::MapShapes(aBlockOrComp, anIndices);
3193 Handle(TColStd_HArray1OfInteger) anArray;
3195 for (ind = 1; ind <= nbSolids; ind++) {
3196 if (aNbParts(ind) == maxNb) {
3197 anArray = new TColStd_HArray1OfInteger(1,1);
3198 anArray->SetValue(1, anIndices.FindIndex(aSolids(ind)));
3199 anObj = GetEngine()->AddSubShape(theCompound, anArray);
3200 aBlocks->Append(anObj);
3202 // For Python command
3203 TDF_Tool::Entry(anObj->GetEntry(), anEntry);
3204 anAsciiList += anEntry + ", ";
3205 if (aFunction.IsNull())
3206 aFunction = anObj->GetLastFunction();
3210 catch (Standard_Failure) {
3211 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
3212 SetErrorCode(aFail->GetMessageString());
3216 //Make a Python command
3217 aPartsDescr.Trunc(aPartsDescr.Length() - 2);
3218 anAsciiList.Trunc(anAsciiList.Length() - 2);
3220 GEOM::TPythonDump(aFunction) << "[" << anAsciiList.ToCString()
3221 << "] = geompy.GetBlocksByParts(" << theCompound
3222 << ", [" << aPartsDescr.ToCString() << "])";
3228 //=============================================================================
3230 * MakeMultiTransformation1D
3232 //=============================================================================
3233 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeMultiTransformation1D
3234 (Handle(GEOM_Object) theObject,
3235 const Standard_Integer theDirFace1,
3236 const Standard_Integer theDirFace2,
3237 const Standard_Integer theNbTimes)
3241 if (theObject.IsNull()) return NULL;
3243 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
3244 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be moved
3246 //Add a new Copy object
3247 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
3249 //Add a translate function
3250 Handle(GEOM_Function) aFunction =
3251 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_MULTI_TRANSFORM_1D);
3253 //Check if the function is set correctly
3254 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
3256 GEOMImpl_IBlockTrsf aTI (aFunction);
3257 aTI.SetOriginal(aLastFunction);
3258 aTI.SetFace1U(theDirFace1);
3259 aTI.SetFace2U(theDirFace2);
3260 aTI.SetNbIterU(theNbTimes);
3262 //Compute the transformation
3265 if (!GetSolver()->ComputeFunction(aFunction)) {
3266 SetErrorCode("Block driver failed to make multi-transformation");
3270 catch (Standard_Failure) {
3271 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
3272 SetErrorCode(aFail->GetMessageString());
3276 //Make a Python command
3277 GEOM::TPythonDump(aFunction) << aCopy << " = geompy.MakeMultiTransformation1D("
3278 << theObject << ", " << theDirFace1 << ", " << theDirFace2 << ", " << theNbTimes << ")";
3284 //=============================================================================
3286 * MakeMultiTransformation2D
3288 //=============================================================================
3289 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeMultiTransformation2D
3290 (Handle(GEOM_Object) theObject,
3291 const Standard_Integer theDirFace1U,
3292 const Standard_Integer theDirFace2U,
3293 const Standard_Integer theNbTimesU,
3294 const Standard_Integer theDirFace1V,
3295 const Standard_Integer theDirFace2V,
3296 const Standard_Integer theNbTimesV)
3300 if (theObject.IsNull()) return NULL;
3302 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
3303 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be moved
3305 //Add a new Copy object
3306 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
3308 //Add a translate function
3309 Handle(GEOM_Function) aFunction =
3310 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_MULTI_TRANSFORM_2D);
3312 //Check if the function is set correctly
3313 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
3315 GEOMImpl_IBlockTrsf aTI (aFunction);
3316 aTI.SetOriginal(aLastFunction);
3317 aTI.SetFace1U(theDirFace1U);
3318 aTI.SetFace2U(theDirFace2U);
3319 aTI.SetNbIterU(theNbTimesU);
3320 aTI.SetFace1V(theDirFace1V);
3321 aTI.SetFace2V(theDirFace2V);
3322 aTI.SetNbIterV(theNbTimesV);
3324 //Compute the transformation
3327 if (!GetSolver()->ComputeFunction(aFunction)) {
3328 SetErrorCode("Block driver failed to make multi-transformation");
3332 catch (Standard_Failure) {
3333 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
3334 SetErrorCode(aFail->GetMessageString());
3338 //Make a Python command
3339 GEOM::TPythonDump(aFunction) << aCopy << " = geompy.MakeMultiTransformation2D("
3340 << theObject << ", " << theDirFace1U << ", " << theDirFace2U << ", " << theNbTimesU
3341 << ", " << theDirFace1V << ", " << theDirFace2V << ", " << theNbTimesV << ")";
3347 //=============================================================================
3351 //=============================================================================
3352 Handle(TColStd_HSequenceOfTransient) GEOMImpl_IBlocksOperations::Propagate
3353 (Handle(GEOM_Object) theShape)
3357 if (theShape.IsNull()) return NULL;
3359 TopoDS_Shape aShape = theShape->GetValue();
3360 if (aShape.IsNull()) return NULL;
3362 TopTools_IndexedMapOfShape anIndices;
3363 TopExp::MapShapes(aShape, anIndices);
3365 TopTools_IndexedDataMapOfShapeListOfShape MEW;
3366 GEOMImpl_Block6Explorer::MapShapesAndAncestors
3367 (aShape, TopAbs_EDGE, TopAbs_WIRE, MEW);
3368 Standard_Integer ie, nbEdges = MEW.Extent();
3371 Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
3373 TopTools_MapOfShape mapAcceptedEdges;
3374 TCollection_AsciiString aListRes, anEntry;
3376 // Sort shapes in current chain (Mantis issue 21053)
3377 TopTools_DataMapOfShapeListOfShape aMapChains;
3378 TopTools_ListOfShape aFirstInChains;
3380 for (ie = 1; ie <= nbEdges; ie++) {
3381 TopoDS_Shape curE = MEW.FindKey(ie);
3383 if (mapAcceptedEdges.Contains(curE)) continue;
3386 TopTools_ListOfShape currentChain;
3387 TopTools_ListOfShape listPrevEdges;
3389 currentChain.Append(curE);
3390 listPrevEdges.Append(curE);
3391 mapAcceptedEdges.Add(curE);
3393 // Collect all edges pass by pass
3394 while (listPrevEdges.Extent() > 0) {
3395 // List of edges, added to chain on this cycle pass
3396 TopTools_ListOfShape listCurEdges;
3398 // Find the next portion of edges
3399 TopTools_ListIteratorOfListOfShape itE (listPrevEdges);
3400 for (; itE.More(); itE.Next()) {
3401 TopoDS_Shape anE = itE.Value();
3403 // Iterate on faces, having edge <anE>
3404 TopTools_ListIteratorOfListOfShape itW (MEW.FindFromKey(anE));
3405 for (; itW.More(); itW.Next()) {
3406 TopoDS_Shape aW = itW.Value();
3407 TopoDS_Shape anOppE;
3409 BRepTools_WireExplorer aWE (TopoDS::Wire(aW));
3410 Standard_Integer nb = 1, found = 0;
3411 TopTools_Array1OfShape anEdges (1,4);
3412 for (; aWE.More(); aWE.Next(), nb++) {
3417 anEdges(nb) = aWE.Current();
3418 if (anEdges(nb).IsSame(anE)) found = nb;
3421 if (nb == 5 && found > 0) {
3422 // Quadrangle face found, get an opposite edge
3423 Standard_Integer opp = found + 2;
3424 if (opp > 4) opp -= 4;
3425 anOppE = anEdges(opp);
3427 if (!mapAcceptedEdges.Contains(anOppE)) {
3428 // Add found edge to the chain
3429 currentChain.Append(anOppE);
3430 listCurEdges.Append(anOppE);
3431 mapAcceptedEdges.Add(anOppE);
3433 } // if (nb == 5 && found > 0)
3434 } // for (; itF.More(); itF.Next())
3435 } // for (; itE.More(); itE.Next())
3437 listPrevEdges = listCurEdges;
3438 } // while (listPrevEdges.Extent() > 0)
3440 // Sort shapes in current chain (Mantis issue 21053)
3441 GEOMUtils::SortShapes(currentChain, Standard_False);
3442 aFirstInChains.Append(currentChain.First());
3443 aMapChains.Bind(currentChain.First(), currentChain);
3446 // Sort chains (Mantis issue 21053)
3447 GEOMUtils::SortShapes(aFirstInChains, Standard_False);
3449 // Store sorted chains in the document
3450 TopTools_ListIteratorOfListOfShape aChainsIt (aFirstInChains);
3451 for (; aChainsIt.More(); aChainsIt.Next()) {
3452 TopoDS_Shape aFirstInChain = aChainsIt.Value();
3453 const TopTools_ListOfShape& currentChain = aMapChains.Find(aFirstInChain);
3455 // Store the chain in the document
3456 Handle(TColStd_HArray1OfInteger) anArray =
3457 new TColStd_HArray1OfInteger (1, currentChain.Extent());
3459 // Fill array of sub-shape indices
3460 TopTools_ListIteratorOfListOfShape itSub (currentChain);
3461 for (int index = 1; itSub.More(); itSub.Next(), ++index) {
3462 int id = anIndices.FindIndex(itSub.Value());
3463 anArray->SetValue(index, id);
3466 // Add a new group object
3467 Handle(GEOM_Object) aChain = GetEngine()->AddSubShape(theShape, anArray);
3470 aChain->SetType(GEOM_GROUP);
3472 // Set a sub-shape type
3473 TDF_Label aFreeLabel = aChain->GetFreeLabel();
3474 TDataStd_Integer::Set(aFreeLabel, (Standard_Integer)TopAbs_EDGE);
3476 // Add the chain to the result
3477 aSeq->Append(aChain);
3479 //Make a Python command
3480 TDF_Tool::Entry(aChain->GetEntry(), anEntry);
3481 aListRes += anEntry + ", ";
3484 if (aSeq->IsEmpty()) {
3485 SetErrorCode("There are no quadrangle faces in the shape");
3489 aListRes.Trunc(aListRes.Length() - 2);
3491 // The Propagation doesn't change object so no new function is required.
3492 Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
3494 // Make a Python command
3495 GEOM::TPythonDump(aFunction, /*append=*/true)
3496 << "[" << aListRes.ToCString() << "] = geompy.Propagate(" << theShape << ")";