1 // Copyright (C) 2007-2015 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_Curve.hxx>
92 #include <Geom_Surface.hxx>
93 #include <ShapeAnalysis_Surface.hxx>
95 #include <TColStd_MapOfInteger.hxx>
96 #include <TColStd_Array1OfReal.hxx>
97 #include <TColStd_Array1OfInteger.hxx>
98 #include <TColStd_Array2OfInteger.hxx>
100 //#include <OSD_Timer.hxx>
102 #include <Precision.hxx>
104 #include <Standard_Failure.hxx>
105 #include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC
109 * This function returns Standard_True if the face is quadrangular. It means
110 * that it has only 1 wire with 4 edges. If there are more then 4 edges in
111 * the wire and theToleranceC1 is not negative the new implementation is used.
112 * According to it the face is quadrangular if it is quadrangular according to
113 * an old implementation or if it has a single wire with more then 4 edges
114 * that form exactly 4 bounds of C1 continuity with the given tolerance.
116 * \param theFace the face to be checked
117 * \param theToleranceC1 if negative, it is not used; otherwise it is used
118 * to check if two neighbor edges of face have C1 continuity.
119 * \return Standard_True if the face is quadrangular; Standard_False otherwise.
121 static Standard_Boolean IsQuadrangle(const TopoDS_Face &theFace,
122 const Standard_Real theToleranceC1)
124 TopExp_Explorer aFExp (theFace, TopAbs_WIRE);
127 // no wire in the face
128 return Standard_False;
131 TopoDS_Shape aWire = aFExp.Current();
136 // multiple wires in the face
137 return Standard_False;
140 // Check number of edges in the face
141 Standard_Integer aNbEdges = 0;
142 TopTools_MapOfShape aMapEdges;
143 TopExp_Explorer aWExp(aWire, TopAbs_EDGE);
145 for (; aWExp.More(); aWExp.Next()) {
146 if (aMapEdges.Add(aWExp.Current())) {
156 return Standard_False;
160 if (theToleranceC1 < 0.) {
161 return Standard_False;
164 // Check if a wire has 4 bounds of C1 continuity.
165 BRepTools_WireExplorer aWireExp(TopoDS::Wire(aWire), theFace);
166 TopTools_ListOfShape anEdges;
168 for (aNbEdges = 0; aWireExp.More(); aWireExp.Next()) {
169 const TopoDS_Edge &anEdge = aWireExp.Current();
171 // Skip degenerated edges.
172 if (!BRep_Tool::Degenerated(anEdge)) {
173 anEdges.Append(anEdge);
179 return Standard_False;
182 // Compute number of sharp corners.
183 anEdges.Append(anEdges.First()); // To make a loop.
185 TopTools_ListIteratorOfListOfShape anIter(anEdges);
186 Standard_Real aPar[2];
187 Standard_Integer aNbCorners = 0;
188 TopoDS_Edge anEdge1 = TopoDS::Edge(anEdges.First());
189 Handle(Geom_Curve) aCurve1 = BRep_Tool::Curve(anEdge1, aPar[0], aPar[1]);
190 Handle(Geom_Curve) aCurve2;
192 TopoDS_Vertex aCommonVtx;
196 Standard_Boolean isReversed1 = (anEdge1.Orientation() == TopAbs_REVERSED);
197 Standard_Boolean isReversed2;
199 for (anIter.Next(); anIter.More(); anIter.Next()) {
200 TopoDS_Edge anEdge2 = TopoDS::Edge(anIter.Value());
202 if (!TopExp::CommonVertex(anEdge1, anEdge2, aCommonVtx)) {
204 return Standard_False;
207 // Check the angle between tangent vectors of 2 curves at this point.
208 Standard_Real aParam1 = BRep_Tool::Parameter(aCommonVtx, anEdge1);
209 Standard_Real aParam2 = BRep_Tool::Parameter(aCommonVtx, anEdge2);
211 aCurve2 = BRep_Tool::Curve(anEdge2, aPar[0], aPar[1]);
212 isReversed2 = (anEdge2.Orientation() == TopAbs_REVERSED);
213 aCurve1->D1(aParam1, aPnt, aVec1);
214 aCurve2->D1(aParam2, aPnt, aVec2);
223 const Standard_Real anAngle = aVec1.Angle(aVec2);
225 if (anAngle > theToleranceC1) {
228 if (aNbCorners > 4) {
233 // Go to the next couple of edges.
236 isReversed1 = isReversed2;
239 // Check the total number of corners.
240 if (aNbCorners != 4) {
241 return Standard_False;
245 return Standard_True;
248 //=============================================================================
252 //=============================================================================
253 GEOMImpl_IBlocksOperations::GEOMImpl_IBlocksOperations (GEOM_Engine* theEngine, int theDocID)
254 : GEOM_IOperations(theEngine, theDocID)
256 MESSAGE("GEOMImpl_IBlocksOperations::GEOMImpl_IBlocksOperations");
259 //=============================================================================
263 //=============================================================================
264 GEOMImpl_IBlocksOperations::~GEOMImpl_IBlocksOperations()
266 MESSAGE("GEOMImpl_IBlocksOperations::~GEOMImpl_IBlocksOperations");
270 //=============================================================================
274 //=============================================================================
275 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuad
276 (Handle(GEOM_Object) theEdge1, Handle(GEOM_Object) theEdge2,
277 Handle(GEOM_Object) theEdge3, Handle(GEOM_Object) theEdge4)
281 if (theEdge1.IsNull() || theEdge2.IsNull() ||
282 theEdge3.IsNull() || theEdge4.IsNull()) return NULL;
284 //Add a new Face object
285 Handle(GEOM_Object) aFace = GetEngine()->AddObject(GetDocID(), GEOM_FACE);
287 //Add a new Face function
288 Handle(GEOM_Function) aFunction =
289 aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_FOUR_EDGES);
291 //Check if the function is set correctly
292 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
294 GEOMImpl_IBlocks aPI (aFunction);
296 Handle(GEOM_Function) aRef1 = theEdge1->GetLastFunction();
297 Handle(GEOM_Function) aRef2 = theEdge2->GetLastFunction();
298 Handle(GEOM_Function) aRef3 = theEdge3->GetLastFunction();
299 Handle(GEOM_Function) aRef4 = theEdge4->GetLastFunction();
300 if (aRef1.IsNull() || aRef2.IsNull() ||
301 aRef3.IsNull() || aRef4.IsNull()) return NULL;
303 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
304 aShapesSeq->Append(aRef1);
305 aShapesSeq->Append(aRef2);
306 aShapesSeq->Append(aRef3);
307 aShapesSeq->Append(aRef4);
309 aPI.SetShapes(aShapesSeq);
311 //Compute the Face value
314 if (!GetSolver()->ComputeFunction(aFunction)) {
315 SetErrorCode("Block driver failed to compute a face");
319 catch (Standard_Failure) {
320 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
321 SetErrorCode(aFail->GetMessageString());
325 //Make a Python command
326 GEOM::TPythonDump(aFunction) << aFace << " = geompy.MakeQuad("
327 << theEdge1 << ", " << theEdge2 << ", " << theEdge3 << ", " << theEdge4 << ")";
333 //=============================================================================
337 //=============================================================================
338 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuad2Edges
339 (Handle(GEOM_Object) theEdge1, Handle(GEOM_Object) theEdge2)
343 if (theEdge1.IsNull() || theEdge2.IsNull()) return NULL;
345 //Add a new Face object
346 Handle(GEOM_Object) aFace = GetEngine()->AddObject(GetDocID(), GEOM_FACE);
348 //Add a new Face function
349 Handle(GEOM_Function) aFunction =
350 aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_TWO_EDGES);
352 //Check if the function is set correctly
353 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
355 GEOMImpl_IBlocks aPI (aFunction);
357 Handle(GEOM_Function) aRef1 = theEdge1->GetLastFunction();
358 Handle(GEOM_Function) aRef2 = theEdge2->GetLastFunction();
359 if (aRef1.IsNull() || aRef2.IsNull()) return NULL;
361 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
362 aShapesSeq->Append(aRef1);
363 aShapesSeq->Append(aRef2);
365 aPI.SetShapes(aShapesSeq);
367 //Compute the Face value
370 if (!GetSolver()->ComputeFunction(aFunction)) {
371 SetErrorCode("Block driver failed to compute a face");
375 catch (Standard_Failure) {
376 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
377 SetErrorCode(aFail->GetMessageString());
381 //Make a Python command
382 GEOM::TPythonDump(aFunction) << aFace << " = geompy.MakeQuad2Edges("
383 << theEdge1 << ", " << theEdge2 << ")";
389 //=============================================================================
393 //=============================================================================
394 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuad4Vertices
395 (Handle(GEOM_Object) thePnt1, Handle(GEOM_Object) thePnt2,
396 Handle(GEOM_Object) thePnt3, Handle(GEOM_Object) thePnt4)
400 if (thePnt1.IsNull() || thePnt2.IsNull() ||
401 thePnt3.IsNull() || thePnt4.IsNull()) return NULL;
403 //Add a new Face object
404 Handle(GEOM_Object) aFace = GetEngine()->AddObject(GetDocID(), GEOM_FACE);
406 //Add a new Face function
407 Handle(GEOM_Function) aFunction =
408 aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_FOUR_PNT);
410 //Check if the function is set correctly
411 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
413 GEOMImpl_IBlocks aPI (aFunction);
415 Handle(GEOM_Function) aRef1 = thePnt1->GetLastFunction();
416 Handle(GEOM_Function) aRef2 = thePnt2->GetLastFunction();
417 Handle(GEOM_Function) aRef3 = thePnt3->GetLastFunction();
418 Handle(GEOM_Function) aRef4 = thePnt4->GetLastFunction();
419 if (aRef1.IsNull() || aRef2.IsNull() ||
420 aRef3.IsNull() || aRef4.IsNull()) return NULL;
422 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
423 aShapesSeq->Append(aRef1);
424 aShapesSeq->Append(aRef2);
425 aShapesSeq->Append(aRef3);
426 aShapesSeq->Append(aRef4);
428 aPI.SetShapes(aShapesSeq);
430 //Compute the Face value
433 if (!GetSolver()->ComputeFunction(aFunction)) {
434 SetErrorCode("Block driver failed to compute a face");
438 catch (Standard_Failure) {
439 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
440 SetErrorCode(aFail->GetMessageString());
444 //Make a Python command
445 GEOM::TPythonDump(aFunction) << aFace << " = geompy.MakeQuad4Vertices("
446 << thePnt1 << ", " << thePnt2 << ", " << thePnt3 << ", " << thePnt4 << ")";
452 //=============================================================================
456 //=============================================================================
457 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeHexa
458 (Handle(GEOM_Object) theFace1, Handle(GEOM_Object) theFace2,
459 Handle(GEOM_Object) theFace3, Handle(GEOM_Object) theFace4,
460 Handle(GEOM_Object) theFace5, Handle(GEOM_Object) theFace6)
464 if (theFace1.IsNull() || theFace2.IsNull() ||
465 theFace3.IsNull() || theFace4.IsNull() ||
466 theFace5.IsNull() || theFace6.IsNull()) return NULL;
468 //Add a new Solid object
469 Handle(GEOM_Object) aBlock = GetEngine()->AddObject(GetDocID(), GEOM_BLOCK);
471 //Add a new Block function
472 Handle(GEOM_Function) aFunction =
473 aBlock->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_SIX_FACES);
475 //Check if the function is set correctly
476 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
478 GEOMImpl_IBlocks aPI (aFunction);
480 Handle(GEOM_Function) aRef1 = theFace1->GetLastFunction();
481 Handle(GEOM_Function) aRef2 = theFace2->GetLastFunction();
482 Handle(GEOM_Function) aRef3 = theFace3->GetLastFunction();
483 Handle(GEOM_Function) aRef4 = theFace4->GetLastFunction();
484 Handle(GEOM_Function) aRef5 = theFace5->GetLastFunction();
485 Handle(GEOM_Function) aRef6 = theFace6->GetLastFunction();
486 if (aRef1.IsNull() || aRef2.IsNull() ||
487 aRef3.IsNull() || aRef4.IsNull() ||
488 aRef5.IsNull() || aRef6.IsNull()) return NULL;
490 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
491 aShapesSeq->Append(aRef1);
492 aShapesSeq->Append(aRef2);
493 aShapesSeq->Append(aRef3);
494 aShapesSeq->Append(aRef4);
495 aShapesSeq->Append(aRef5);
496 aShapesSeq->Append(aRef6);
498 aPI.SetShapes(aShapesSeq);
500 //Compute the Block value
503 if (!GetSolver()->ComputeFunction(aFunction)) {
504 SetErrorCode("Block driver failed to compute a block");
508 catch (Standard_Failure) {
509 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
510 SetErrorCode(aFail->GetMessageString());
514 //Make a Python command
515 GEOM::TPythonDump(aFunction) << aBlock << " = geompy.MakeHexa("
516 << theFace1 << ", " << theFace2 << ", " << theFace3 << ", "
517 << theFace4 << ", " << theFace5 << ", " << theFace6 << ")";
523 //=============================================================================
527 //=============================================================================
528 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeHexa2Faces
529 (Handle(GEOM_Object) theFace1, Handle(GEOM_Object) theFace2)
533 if (theFace1.IsNull() || theFace2.IsNull()) return NULL;
535 //Add a new Solid object
536 Handle(GEOM_Object) aBlock = GetEngine()->AddObject(GetDocID(), GEOM_BLOCK);
538 //Add a new Block function
539 Handle(GEOM_Function) aFunction =
540 aBlock->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_TWO_FACES);
542 //Check if the function is set correctly
543 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
545 GEOMImpl_IBlocks aPI (aFunction);
547 Handle(GEOM_Function) aRef1 = theFace1->GetLastFunction();
548 Handle(GEOM_Function) aRef2 = theFace2->GetLastFunction();
549 if (aRef1.IsNull() || aRef2.IsNull()) return NULL;
551 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
552 aShapesSeq->Append(aRef1);
553 aShapesSeq->Append(aRef2);
555 aPI.SetShapes(aShapesSeq);
557 //Compute the Block value
560 if (!GetSolver()->ComputeFunction(aFunction)) {
561 SetErrorCode("Block driver failed to compute a block");
565 catch (Standard_Failure) {
566 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
567 SetErrorCode(aFail->GetMessageString());
571 //Make a Python command
572 GEOM::TPythonDump(aFunction) << aBlock << " = geompy.MakeHexa2Faces("
573 << theFace1 << ", " << theFace2 << ")";
579 //=============================================================================
583 //=============================================================================
584 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeBlockCompound
585 (Handle(GEOM_Object) theCompound)
589 if (theCompound.IsNull()) return NULL;
592 Handle(GEOM_Object) aBlockComp = GetEngine()->AddObject(GetDocID(), GEOM_COMPOUND);
594 //Add a new BlocksComp function
595 Handle(GEOM_Function) aFunction =
596 aBlockComp->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_COMPOUND_GLUE);
598 //Check if the function is set correctly
599 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
601 GEOMImpl_IBlocks aPI (aFunction);
603 Handle(GEOM_Function) aRef1 = theCompound->GetLastFunction();
604 if (aRef1.IsNull()) return NULL;
606 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
607 aShapesSeq->Append(aRef1);
609 aPI.SetShapes(aShapesSeq);
611 //Compute the Blocks Compound value
614 if (!GetSolver()->ComputeFunction(aFunction)) {
615 SetErrorCode("Block driver failed to compute a blocks compound");
619 catch (Standard_Failure) {
620 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
621 SetErrorCode(aFail->GetMessageString());
625 //Make a Python command
626 GEOM::TPythonDump(aFunction) << aBlockComp
627 << " = geompy.MakeBlockCompound(" << theCompound << ")";
633 //=============================================================================
637 //=============================================================================
638 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetPoint
639 (Handle(GEOM_Object) theShape,
640 const Standard_Real theX,
641 const Standard_Real theY,
642 const Standard_Real theZ,
643 const Standard_Real theEpsilon)
648 Handle(GEOM_Object) aResult;
651 if (theShape.IsNull()) return NULL;
653 TopoDS_Shape aBlockOrComp = theShape->GetValue();
654 if (aBlockOrComp.IsNull()) {
655 SetErrorCode("Given shape is null");
659 //Compute the Vertex value
660 gp_Pnt P (theX, theY, theZ);
661 Standard_Real eps = Max(theEpsilon, Precision::Confusion());
664 Standard_Integer isFound = 0;
665 TopTools_MapOfShape mapShape;
666 TopExp_Explorer exp (aBlockOrComp, TopAbs_VERTEX);
668 for (; exp.More(); exp.Next()) {
669 if (mapShape.Add(exp.Current())) {
670 TopoDS_Vertex aVi = TopoDS::Vertex(exp.Current());
671 gp_Pnt aPi = BRep_Tool::Pnt(aVi);
672 if (aPi.Distance(P) < eps) {
680 SetErrorCode("Vertex has not been found");
682 } else if (isFound > 1) {
683 SetErrorCode("Multiple vertices found by the given coordinates and epsilon");
686 TopTools_IndexedMapOfShape anIndices;
687 TopExp::MapShapes(aBlockOrComp, anIndices);
688 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
689 anArray->SetValue(1, anIndices.FindIndex(V));
690 aResult = GetEngine()->AddSubShape(theShape, anArray);
693 //The GetPoint() doesn't change object so no new function is required.
694 Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
696 //Make a Python command
697 GEOM::TPythonDump(aFunction, /*append=*/true)
698 << aResult << " = geompy.GetPoint(" << theShape << ", "
699 << theX << ", " << theY << ", " << theZ << ", " << theEpsilon << ")";
705 //=============================================================================
709 //=============================================================================
710 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetVertexNearPoint
711 (Handle(GEOM_Object) theShape,
712 Handle(GEOM_Object) thePoint)
717 Handle(GEOM_Object) aResult;
720 if (theShape.IsNull() || thePoint.IsNull()) return NULL;
722 TopoDS_Shape aBlockOrComp = theShape->GetValue();
723 TopoDS_Shape aPoint = thePoint->GetValue();
724 if (aBlockOrComp.IsNull() || aPoint.IsNull()) {
725 SetErrorCode("Given shape is null");
729 if (aPoint.ShapeType() != TopAbs_VERTEX) {
730 SetErrorCode("Element for vertex identification is not a vertex");
734 TopoDS_Vertex aVert = TopoDS::Vertex(aPoint);
735 gp_Pnt aP = BRep_Tool::Pnt(aVert);
737 // Compute the Vertex value
739 bool isFound = false;
740 Standard_Real aDist = RealLast();
741 TopTools_MapOfShape mapShape;
743 TopExp_Explorer exp (aBlockOrComp, TopAbs_VERTEX);
744 for (; exp.More(); exp.Next()) {
745 if (mapShape.Add(exp.Current())) {
746 TopoDS_Vertex aVi = TopoDS::Vertex(exp.Current());
747 gp_Pnt aPi = BRep_Tool::Pnt(aVi);
748 Standard_Real aDisti = aPi.Distance(aP);
749 if (aDisti < aDist) {
758 SetErrorCode("Vertex has not been found");
762 TopTools_IndexedMapOfShape anIndices;
763 TopExp::MapShapes(aBlockOrComp, anIndices);
764 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
765 anArray->SetValue(1, anIndices.FindIndex(V));
766 aResult = GetEngine()->AddSubShape(theShape, anArray);
768 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
770 // Make a Python command
771 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetVertexNearPoint("
772 << theShape << ", " << thePoint << ")";
778 //=============================================================================
782 //=============================================================================
783 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetEdge
784 (Handle(GEOM_Object) theShape,
785 Handle(GEOM_Object) thePoint1,
786 Handle(GEOM_Object) thePoint2)
791 Handle(GEOM_Object) aResult;
794 if (theShape.IsNull() || thePoint1.IsNull() || thePoint2.IsNull()) return NULL;
796 TopoDS_Shape aBlockOrComp = theShape->GetValue();
797 if (aBlockOrComp.IsNull()) {
798 SetErrorCode("Given shape is null");
802 TopoDS_Shape anArg1 = thePoint1->GetValue();
803 TopoDS_Shape anArg2 = thePoint2->GetValue();
804 if (anArg1.IsNull() || anArg2.IsNull()) {
805 SetErrorCode("Null shape is given as argument");
808 if (anArg1.ShapeType() != TopAbs_VERTEX ||
809 anArg2.ShapeType() != TopAbs_VERTEX) {
810 SetErrorCode("Element for edge identification is not a vertex");
814 //Compute the Edge value
817 TopTools_IndexedDataMapOfShapeListOfShape MVE;
818 GEOMImpl_Block6Explorer::MapShapesAndAncestors
819 (aBlockOrComp, TopAbs_VERTEX, TopAbs_EDGE, MVE);
822 Standard_Integer ish, ext = MVE.Extent();
824 if (MVE.Contains(anArg1)) {
827 for (ish = 1; ish <= ext; ish++) {
828 TopoDS_Shape aShi = MVE.FindKey(ish);
829 if (BRepTools::Compare(TopoDS::Vertex(anArg1), TopoDS::Vertex(aShi))) {
836 if (MVE.Contains(anArg2)) {
839 for (ish = 1; ish <= ext; ish++) {
840 TopoDS_Shape aShi = MVE.FindKey(ish);
841 if (BRepTools::Compare(TopoDS::Vertex(anArg2), TopoDS::Vertex(aShi))) {
848 if (V1.IsNull() || V2.IsNull()) {
849 SetErrorCode("The given vertex does not belong to the shape");
854 Standard_Integer isFound =
855 GEOMImpl_Block6Explorer::FindEdge(anEdge, V1, V2, MVE, Standard_True);
857 SetErrorCode("The given vertices do not belong to one edge of the given shape");
859 } else if (isFound > 1) {
860 SetErrorCode("Multiple edges found by the given vertices of the shape");
863 TopTools_IndexedMapOfShape anIndices;
864 TopExp::MapShapes(aBlockOrComp, anIndices);
865 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
866 anArray->SetValue(1, anIndices.FindIndex(anEdge));
867 aResult = GetEngine()->AddSubShape(theShape, anArray);
869 } catch (Standard_Failure) {
870 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
871 SetErrorCode(aFail->GetMessageString());
875 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
877 //Make a Python command
878 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetEdge("
879 << theShape << ", " << thePoint1 << ", " << thePoint2 << ")";
885 //=============================================================================
889 //=============================================================================
890 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetEdgeNearPoint
891 (Handle(GEOM_Object) theShape,
892 Handle(GEOM_Object) thePoint)
897 Handle(GEOM_Object) aResult;
900 if (theShape.IsNull() || thePoint.IsNull()) return NULL;
902 TopoDS_Shape aBlockOrComp = theShape->GetValue();
903 if (aBlockOrComp.IsNull()) {
904 SetErrorCode("Given shape is null");
908 TopoDS_Shape anArg = thePoint->GetValue();
909 if (anArg.IsNull()) {
910 SetErrorCode("Null shape is given as argument");
913 if (anArg.ShapeType() != TopAbs_VERTEX) {
914 SetErrorCode("Element for edge identification is not a vertex");
918 //Compute the Edge value
921 TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
922 TopoDS_Shape aShape = GEOMUtils::GetEdgeNearPoint(aBlockOrComp, aVert);
924 TopTools_IndexedMapOfShape anIndices;
925 TopExp::MapShapes(aBlockOrComp, anIndices);
926 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
927 anArray->SetValue(1, anIndices.FindIndex(aShape));
928 aResult = GetEngine()->AddSubShape(theShape, anArray);
930 catch (Standard_Failure) {
931 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
932 SetErrorCode(aFail->GetMessageString());
936 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
938 //Make a Python command
939 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetEdgeNearPoint("
940 << theShape << ", " << thePoint << ")";
946 //=============================================================================
950 //=============================================================================
951 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByPoints
952 (Handle(GEOM_Object) theShape,
953 Handle(GEOM_Object) thePoint1,
954 Handle(GEOM_Object) thePoint2,
955 Handle(GEOM_Object) thePoint3,
956 Handle(GEOM_Object) thePoint4)
961 Handle(GEOM_Object) aResult;
964 if (theShape.IsNull() ||
965 thePoint1.IsNull() || thePoint2.IsNull() ||
966 thePoint3.IsNull() || thePoint4.IsNull()) return NULL;
968 TopoDS_Shape aBlockOrComp = theShape->GetValue();
969 if (aBlockOrComp.IsNull()) {
970 SetErrorCode("Block or compound is null");
974 TopoDS_Shape anArg1 = thePoint1->GetValue();
975 TopoDS_Shape anArg2 = thePoint2->GetValue();
976 TopoDS_Shape anArg3 = thePoint3->GetValue();
977 TopoDS_Shape anArg4 = thePoint4->GetValue();
978 if (anArg1.IsNull() || anArg2.IsNull() ||
979 anArg3.IsNull() || anArg4.IsNull()) {
980 SetErrorCode("Null shape is given as argument");
983 if (anArg1.ShapeType() != TopAbs_VERTEX ||
984 anArg2.ShapeType() != TopAbs_VERTEX ||
985 anArg3.ShapeType() != TopAbs_VERTEX ||
986 anArg4.ShapeType() != TopAbs_VERTEX) {
987 SetErrorCode("Element for face identification is not a vertex");
991 //Compute the Face value
996 TopTools_IndexedDataMapOfShapeListOfShape MVF;
997 GEOMImpl_Block6Explorer::MapShapesAndAncestors(aBlockOrComp, TopAbs_VERTEX, TopAbs_FACE, MVF);
999 TopoDS_Shape V1,V2,V3,V4;
1000 Standard_Integer ish, ext = MVF.Extent();
1002 if (MVF.Contains(anArg1)) {
1005 for (ish = 1; ish <= ext; ish++) {
1006 TopoDS_Shape aShi = MVF.FindKey(ish);
1007 if (BRepTools::Compare(TopoDS::Vertex(anArg1), TopoDS::Vertex(aShi))) {
1014 if (MVF.Contains(anArg2)) {
1017 for (ish = 1; ish <= ext; ish++) {
1018 TopoDS_Shape aShi = MVF.FindKey(ish);
1019 if (BRepTools::Compare(TopoDS::Vertex(anArg2), TopoDS::Vertex(aShi))) {
1026 if (MVF.Contains(anArg3)) {
1029 for (ish = 1; ish <= ext; ish++) {
1030 TopoDS_Shape aShi = MVF.FindKey(ish);
1031 if (BRepTools::Compare(TopoDS::Vertex(anArg3), TopoDS::Vertex(aShi))) {
1038 if (MVF.Contains(anArg4)) {
1041 for (ish = 1; ish <= ext; ish++) {
1042 TopoDS_Shape aShi = MVF.FindKey(ish);
1043 if (BRepTools::Compare(TopoDS::Vertex(anArg4), TopoDS::Vertex(aShi))) {
1050 if (V1.IsNull() || V2.IsNull() || V3.IsNull() || V4.IsNull()) {
1051 SetErrorCode("The given vertex does not belong to the shape");
1055 Standard_Integer isFound =
1056 GEOMImpl_Block6Explorer::FindFace(aShape, V1, V2, V3, V4, MVF, Standard_True);
1058 SetErrorCode("The given vertices do not belong to one face of the given shape");
1060 } else if (isFound > 1) {
1061 SetErrorCode("The given vertices belong to several faces of the given shape");
1064 TopTools_IndexedMapOfShape anIndices;
1065 TopExp::MapShapes(aBlockOrComp, anIndices);
1066 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1067 anArray->SetValue(1, anIndices.FindIndex(aShape));
1068 aResult = GetEngine()->AddSubShape(theShape, anArray);
1071 catch (Standard_Failure) {
1072 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1073 SetErrorCode(aFail->GetMessageString());
1077 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1079 //Make a Python command
1080 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceByPoints("
1081 << theShape << ", " << thePoint1 << ", " << thePoint2
1082 << ", " << thePoint3 << ", " << thePoint4 << ")";
1088 //=============================================================================
1092 //=============================================================================
1093 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByEdges
1094 (Handle(GEOM_Object) theShape,
1095 Handle(GEOM_Object) theEdge1,
1096 Handle(GEOM_Object) theEdge2)
1101 Handle(GEOM_Object) aResult;
1104 if (theShape.IsNull() || theEdge1.IsNull() || theEdge2.IsNull()) return NULL;
1106 TopoDS_Shape aBlockOrComp = theShape->GetValue();
1107 if (aBlockOrComp.IsNull()) {
1108 SetErrorCode("Block or compound is null");
1112 TopoDS_Shape anArg1 = theEdge1->GetValue();
1113 TopoDS_Shape anArg2 = theEdge2->GetValue();
1114 if (anArg1.IsNull() || anArg2.IsNull()) {
1115 SetErrorCode("Null shape is given as argument");
1118 if (anArg1.ShapeType() != TopAbs_EDGE ||
1119 anArg2.ShapeType() != TopAbs_EDGE) {
1120 SetErrorCode("Element for face identification is not an edge");
1124 //Compute the Face value
1127 TopoDS_Shape aShape;
1129 TopTools_IndexedDataMapOfShapeListOfShape MEF;
1130 GEOMImpl_Block6Explorer::MapShapesAndAncestors(aBlockOrComp, TopAbs_EDGE, TopAbs_FACE, MEF);
1133 Standard_Integer ish, ext = MEF.Extent();
1135 if (MEF.Contains(anArg1)) {
1138 for (ish = 1; ish <= ext; ish++) {
1139 TopoDS_Shape aShi = MEF.FindKey(ish);
1140 if (GEOMImpl_Block6Explorer::IsSimilarEdges(anArg1, aShi)) {
1146 if (MEF.Contains(anArg2)) {
1149 for (ish = 1; ish <= ext; ish++) {
1150 TopoDS_Shape aShi = MEF.FindKey(ish);
1151 if (GEOMImpl_Block6Explorer::IsSimilarEdges(anArg2, aShi)) {
1157 if (E1.IsNull() || E2.IsNull()) {
1158 SetErrorCode("The given edge does not belong to the shape");
1162 const TopTools_ListOfShape& aFacesOfE1 = MEF.FindFromKey(E1);
1163 const TopTools_ListOfShape& aFacesOfE2 = MEF.FindFromKey(E2);
1165 Standard_Integer isFound = 0;
1166 TopTools_ListIteratorOfListOfShape anIterF1 (aFacesOfE1);
1167 for (; anIterF1.More(); anIterF1.Next()) {
1169 TopTools_ListIteratorOfListOfShape anIterF2 (aFacesOfE2);
1170 for (; anIterF2.More(); anIterF2.Next()) {
1172 if (anIterF1.Value().IsSame(anIterF2.Value())) {
1175 // Store the face, defined by two edges
1176 aShape = anIterF1.Value();
1181 SetErrorCode("The given edges do not belong to one face of the given shape");
1183 } else if (isFound > 1) {
1184 SetErrorCode("The given edges belong to several faces of the given shape");
1187 TopTools_IndexedMapOfShape anIndices;
1188 TopExp::MapShapes(aBlockOrComp, anIndices);
1189 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1190 anArray->SetValue(1, anIndices.FindIndex(aShape));
1191 aResult = GetEngine()->AddSubShape(theShape, anArray);
1194 catch (Standard_Failure) {
1195 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1196 SetErrorCode(aFail->GetMessageString());
1200 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1202 //Make a Python command
1203 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceByEdges("
1204 << theShape << ", " << theEdge1 << ", " << theEdge2 << ")";
1210 //=============================================================================
1214 //=============================================================================
1215 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetOppositeFace
1216 (Handle(GEOM_Object) theShape,
1217 Handle(GEOM_Object) theFace)
1222 Handle(GEOM_Object) aResult;
1225 if (theShape.IsNull() || theFace.IsNull()) return NULL;
1227 TopoDS_Shape aBlockOrComp = theShape->GetValue();
1228 if (aBlockOrComp.IsNull()) {
1229 SetErrorCode("Block is null");
1232 if (aBlockOrComp.ShapeType() != TopAbs_SOLID) {
1233 SetErrorCode("Shape is not a block");
1237 TopoDS_Shape anArg = theFace->GetValue();
1238 if (anArg.IsNull()) {
1239 SetErrorCode("Null shape is given as argument");
1242 if (anArg.ShapeType() != TopAbs_FACE) {
1243 SetErrorCode("Element for face identification is not a face");
1247 //Compute the Face value
1250 TopoDS_Shape aShape;
1252 GEOMImpl_Block6Explorer aBlockTool;
1253 aBlockTool.InitByBlockAndFace(aBlockOrComp, anArg);
1254 aShape = aBlockTool.GetFace(2);
1256 TopTools_IndexedMapOfShape anIndices;
1257 TopExp::MapShapes(aBlockOrComp, anIndices);
1258 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1259 anArray->SetValue(1, anIndices.FindIndex(aShape));
1260 aResult = GetEngine()->AddSubShape(theShape, anArray);
1262 catch (Standard_Failure) {
1263 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1264 SetErrorCode(aFail->GetMessageString());
1268 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1270 //Make a Python command
1271 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetOppositeFace("
1272 << theShape << ", " << theFace << ")";
1278 //=============================================================================
1282 //=============================================================================
1283 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceNearPoint
1284 (Handle(GEOM_Object) theShape,
1285 Handle(GEOM_Object) thePoint)
1290 Handle(GEOM_Object) aResult;
1293 if (theShape.IsNull() || thePoint.IsNull()) return NULL;
1295 TopoDS_Shape aBlockOrComp = theShape->GetValue();
1296 if (aBlockOrComp.IsNull()) {
1297 SetErrorCode("Block or compound is null");
1301 TopoDS_Shape anArg = thePoint->GetValue();
1302 if (anArg.IsNull()) {
1303 SetErrorCode("Null shape is given as argument");
1306 if (anArg.ShapeType() != TopAbs_VERTEX) {
1307 SetErrorCode("Element for face identification is not a vertex");
1311 //Compute the Face value
1314 TopoDS_Shape aShape;
1316 TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
1317 gp_Pnt aPnt = BRep_Tool::Pnt(aVert);
1318 Standard_Real PX, PY, PZ;
1319 aPnt.Coord(PX, PY, PZ);
1321 // 1. Classify the point relatively each face
1322 Standard_Integer nearest = 2, nbFound = 0;
1323 TopTools_DataMapOfShapeInteger mapShapeDist;
1324 TopExp_Explorer exp (aBlockOrComp, TopAbs_FACE);
1325 for (; exp.More(); exp.Next()) {
1326 TopoDS_Shape aFace = exp.Current();
1328 if (!mapShapeDist.IsBound(aFace)) {
1329 Standard_Integer aDistance = 2;
1331 // 1.a. Classify relatively Surface
1332 Handle(Geom_Surface) aSurf = BRep_Tool::Surface(TopoDS::Face(aFace));
1333 Handle(ShapeAnalysis_Surface) aSurfAna = new ShapeAnalysis_Surface (aSurf);
1334 gp_Pnt2d p2dOnSurf = aSurfAna->ValueOfUV(aPnt, Precision::Confusion());
1335 gp_Pnt p3dOnSurf = aSurfAna->Value(p2dOnSurf);
1336 Standard_Real aDist = p3dOnSurf.Distance(aPnt);
1337 if (aDist > Precision::Confusion()) {
1341 // 1.b. Classify relatively the face itself
1342 BRepClass_FaceClassifier FC (TopoDS::Face(aFace), p2dOnSurf, Precision::Confusion());
1343 if (FC.State() == TopAbs_IN) {
1345 } else if (FC.State() == TopAbs_ON) {
1352 if (aDistance < nearest) {
1353 nearest = aDistance;
1357 // A first found face, containing the point inside, will be returned.
1358 // It is the solution, if there are no
1359 // coincident or intersecting faces in the compound.
1360 if (nearest == -1) break;
1362 } else if (aDistance == nearest) {
1367 mapShapeDist.Bind(aFace, aDistance);
1368 } // if (!mapShapeDist.IsBound(aFace))
1371 // 2. Define face, containing the point or having minimum distance to it
1374 // The point is on boundary of some faces and there are
1375 // no faces, having the point inside
1376 SetErrorCode("Multiple faces near the given point are found");
1379 } else if (nearest == 1) {
1380 // The point is outside some faces and there are
1381 // no faces, having the point inside or on boundary.
1382 // We will get a nearest face
1383 Standard_Real bigReal = RealLast();
1384 Standard_Real minDist = bigReal;
1385 TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
1386 for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
1387 if (mapShapeDistIter.Value() == 1) {
1388 TopoDS_Shape aFace = mapShapeDistIter.Key();
1389 Standard_Real aDist = bigReal;
1391 // 2.a. Fast check of distance - if point projection on surface is on face
1392 Handle(Geom_Surface) aSurf = BRep_Tool::Surface(TopoDS::Face(aFace));
1393 Handle(ShapeAnalysis_Surface) aSurfAna = new ShapeAnalysis_Surface (aSurf);
1394 gp_Pnt2d p2dOnSurf = aSurfAna->ValueOfUV(aPnt, Precision::Confusion());
1395 gp_Pnt p3dOnSurf = aSurfAna->Value(p2dOnSurf);
1396 aDist = p3dOnSurf.Distance(aPnt);
1398 BRepClass_FaceClassifier FC (TopoDS::Face(aFace), p2dOnSurf, Precision::Confusion());
1399 if (FC.State() == TopAbs_OUT) {
1400 if (aDist < minDist) {
1401 // 2.b. Slow check - if point projection on surface is outside of face
1402 BRepExtrema_DistShapeShape aDistTool (aVert, aFace);
1403 if (!aDistTool.IsDone()) {
1404 SetErrorCode("Can not find a distance from the given point to one of faces");
1407 aDist = aDistTool.Value();
1413 if (aDist < minDist) {
1419 } else { // nearest == -1
1420 // // The point is inside some faces.
1421 // // We will get a face with nearest center
1422 // Standard_Real minDist = RealLast();
1423 // TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
1424 // for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
1425 // if (mapShapeDistIter.Value() == -1) {
1426 // TopoDS_Shape aFace = mapShapeDistIter.Key();
1427 // GProp_GProps aSystem;
1428 // BRepGProp::SurfaceProperties(aFace, aSystem);
1429 // gp_Pnt aCenterMass = aSystem.CentreOfMass();
1431 // Standard_Real aDist = aCenterMass.Distance(aPnt);
1432 // if (aDist < minDist) {
1439 } // if (nbFound > 1)
1442 SetErrorCode("There are no faces near the given point");
1445 TopTools_IndexedMapOfShape anIndices;
1446 TopExp::MapShapes(aBlockOrComp, anIndices);
1447 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1448 anArray->SetValue(1, anIndices.FindIndex(aShape));
1449 aResult = GetEngine()->AddSubShape(theShape, anArray);
1452 catch (Standard_Failure) {
1453 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1454 SetErrorCode(aFail->GetMessageString());
1458 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1460 //Make a Python command
1461 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceNearPoint("
1462 << theShape << ", " << thePoint << ")";
1468 //=============================================================================
1472 //=============================================================================
1473 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByNormale
1474 (Handle(GEOM_Object) theShape,
1475 Handle(GEOM_Object) theVector)
1480 Handle(GEOM_Object) aResult;
1483 if (theShape.IsNull() || theVector.IsNull()) return NULL;
1485 TopoDS_Shape aBlockOrComp = theShape->GetValue();
1486 if (aBlockOrComp.IsNull()) {
1487 SetErrorCode("Block or compound is null");
1491 TopoDS_Shape anArg = theVector->GetValue();
1492 if (anArg.IsNull()) {
1493 SetErrorCode("Null shape is given as argument");
1496 if (anArg.ShapeType() != TopAbs_EDGE) {
1497 SetErrorCode("Element for normale identification is not an edge");
1501 //Compute the Face value
1504 TopoDS_Shape aShape;
1506 TopoDS_Edge anEdge = TopoDS::Edge(anArg);
1507 TopoDS_Vertex V1, V2;
1508 TopExp::Vertices(anEdge, V1, V2, Standard_True);
1509 gp_Pnt P1 = BRep_Tool::Pnt(V1);
1510 gp_Pnt P2 = BRep_Tool::Pnt(V2);
1511 gp_Vec aVec (P1, P2);
1512 if (aVec.Magnitude() < Precision::Confusion()) {
1513 SetErrorCode("Vector with null magnitude is given");
1517 Standard_Real minAngle = RealLast();
1518 TopTools_MapOfShape mapShape;
1519 TopExp_Explorer exp (aBlockOrComp, TopAbs_FACE);
1520 for (; exp.More(); exp.Next()) {
1521 if (mapShape.Add(exp.Current())) {
1522 TopoDS_Face aFace = TopoDS::Face(exp.Current());
1523 BRepAdaptor_Surface SF (aFace);
1525 Standard_Real u, v, x;
1527 // find a point on the surface to get normal direction in
1528 u = SF.FirstUParameter();
1529 x = SF.LastUParameter();
1530 if (Precision::IsInfinite(u)) {
1531 u = (Precision::IsInfinite(x)) ? 0. : x;
1532 } else if (!Precision::IsInfinite(x)) {
1536 v = SF.FirstVParameter();
1537 x = SF.LastVParameter();
1538 if (Precision::IsInfinite(v)) {
1539 v = (Precision::IsInfinite(x)) ? 0. : x;
1540 } else if (!Precision::IsInfinite(x)) {
1544 // compute the normal direction
1546 SF.D1(u,v,P1,Vec1,Vec2);
1547 gp_Vec V = Vec1.Crossed(Vec2);
1549 if (V.Magnitude() < Precision::Confusion()) {
1550 SetErrorCode("Normal vector of a face has null magnitude");
1554 // consider the face orientation
1555 if (aFace.Orientation() == TopAbs_REVERSED ||
1556 aFace.Orientation() == TopAbs_INTERNAL) {
1560 // compute the angle and compare with the minimal one
1561 Standard_Real anAngle = aVec.Angle(V);
1562 if (anAngle < minAngle) {
1569 if (aShape.IsNull()) {
1570 SetErrorCode("Failed to find a face by the given normale");
1573 TopTools_IndexedMapOfShape anIndices;
1574 TopExp::MapShapes(aBlockOrComp, anIndices);
1575 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1576 anArray->SetValue(1, anIndices.FindIndex(aShape));
1577 aResult = GetEngine()->AddSubShape(theShape, anArray);
1580 catch (Standard_Failure) {
1581 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1582 SetErrorCode(aFail->GetMessageString());
1586 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1588 //Make a Python command
1589 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceByNormale("
1590 << theShape << ", " << theVector << ")";
1596 //=============================================================================
1598 * GetShapesNearPoint
1600 //=============================================================================
1601 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetShapesNearPoint
1602 (Handle(GEOM_Object) theShape,
1603 Handle(GEOM_Object) thePoint,
1604 const Standard_Integer theShapeType,
1605 const Standard_Real theConstTolerance)
1610 Handle(GEOM_Object) aResult;
1613 if (theShape.IsNull() || thePoint.IsNull()) return NULL;
1615 TopoDS_Shape aBlockOrComp = theShape->GetValue();
1616 if (aBlockOrComp.IsNull()) {
1617 SetErrorCode("Block or compound is null");
1621 TopoDS_Shape anArg = thePoint->GetValue();
1622 if (anArg.IsNull()) {
1623 SetErrorCode("Null shape is given as argument");
1626 if (anArg.ShapeType() != TopAbs_VERTEX) {
1627 SetErrorCode("Element for face identification is not a vertex");
1631 if (theShapeType < TopAbs_SOLID || TopAbs_VERTEX < theShapeType) {
1632 SetErrorCode("Invalid type of result is requested");
1636 Standard_Real theTolerance = theConstTolerance;
1637 if (theTolerance < Precision::Confusion()) {
1638 theTolerance = Precision::Confusion();
1641 // Compute the result
1644 TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
1646 TopTools_MapOfShape mapShape;
1647 Standard_Integer nbEdges = 0;
1648 TopExp_Explorer exp (aBlockOrComp, TopAbs_ShapeEnum(theShapeType));
1649 for (; exp.More(); exp.Next()) {
1650 if (mapShape.Add(exp.Current())) {
1656 SetErrorCode("Given shape contains no sub-shapes of requested type");
1660 // Calculate distances and find min
1662 Standard_Integer ind = 1;
1663 Standard_Real aMinDist = RealLast();
1664 TopTools_Array1OfShape anEdges (1, nbEdges);
1665 TColStd_Array1OfReal aDistances (1, nbEdges);
1666 for (exp.Init(aBlockOrComp, TopAbs_ShapeEnum(theShapeType)); exp.More(); exp.Next()) {
1667 if (mapShape.Add(exp.Current())) {
1668 TopoDS_Shape anEdge = exp.Current();
1669 anEdges(ind) = anEdge;
1671 BRepExtrema_DistShapeShape aDistTool (aVert, anEdges(ind));
1672 if (!aDistTool.IsDone()) {
1673 SetErrorCode("Can not find a distance from the given point to one of sub-shapes");
1676 aDistances(ind) = aDistTool.Value();
1677 if (aDistances(ind) < aMinDist) {
1678 aMinDist = aDistances(ind);
1684 if (aMinDist < RealLast()) {
1685 // Collect sub-shapes with distance < (aMinDist + theTolerance)
1686 int nbSubShapes = 0;
1687 TopTools_Array1OfShape aNearShapes (1, nbEdges);
1688 for (ind = 1; ind <= nbEdges; ind++) {
1689 if (aDistances(ind) < aMinDist + theTolerance) {
1691 aNearShapes(nbSubShapes) = anEdges(ind);
1696 TopTools_IndexedMapOfShape anIndices;
1697 TopExp::MapShapes(aBlockOrComp, anIndices);
1698 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger (1, nbSubShapes);
1699 for (ind = 1; ind <= nbSubShapes; ind++) {
1700 anArray->SetValue(ind, anIndices.FindIndex(aNearShapes(ind)));
1702 aResult = GetEngine()->AddSubShape(theShape, anArray);
1705 catch (Standard_Failure) {
1706 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1707 SetErrorCode(aFail->GetMessageString());
1711 if (aResult.IsNull())
1714 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1716 //Make a Python command
1717 GEOM::TPythonDump(aFunction)
1718 << aResult << " = geompy.GetShapesNearPoint(" << theShape << ", " << thePoint
1719 << ", " << TopAbs_ShapeEnum(theShapeType) << ", " << theTolerance << ")";
1725 //=============================================================================
1727 * IsCompoundOfBlocks
1729 //=============================================================================
1730 Standard_Boolean GEOMImpl_IBlocksOperations::IsCompoundOfBlocks
1731 (Handle(GEOM_Object) theCompound,
1732 const Standard_Integer theMinNbFaces,
1733 const Standard_Integer theMaxNbFaces,
1734 Standard_Integer& theNbBlocks)
1737 Standard_Boolean isCompOfBlocks = Standard_False;
1740 if (theCompound.IsNull()) return isCompOfBlocks;
1741 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
1744 isCompOfBlocks = Standard_True;
1747 TopTools_MapOfShape mapShape;
1748 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
1749 for (; exp.More(); exp.Next()) {
1750 if (mapShape.Add(exp.Current())) {
1751 TopoDS_Shape aSolid = exp.Current();
1753 TopTools_MapOfShape mapFaces;
1754 TopExp_Explorer expF (aSolid, TopAbs_FACE);
1755 Standard_Integer nbFaces = 0;
1756 for (; expF.More(); expF.Next()) {
1757 if (mapFaces.Add(expF.Current())) {
1759 if (nbFaces > theMaxNbFaces) {
1760 isCompOfBlocks = Standard_False;
1765 if (nbFaces < theMinNbFaces || theMaxNbFaces < nbFaces) {
1766 isCompOfBlocks = Standard_False;
1773 catch (Standard_Failure) {
1774 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
1775 SetErrorCode(aFail->GetMessageString());
1776 return isCompOfBlocks;
1780 return isCompOfBlocks;
1783 //=============================================================================
1785 * Set of functions, used by CheckCompoundOfBlocks() method
1787 //=============================================================================
1788 void GEOMImpl_IBlocksOperations::AddBlocksFrom (const TopoDS_Shape& theShape,
1789 TopTools_ListOfShape& BLO,
1790 TopTools_ListOfShape& NOT,
1791 TopTools_ListOfShape& EXT,
1792 TopTools_ListOfShape& NOQ,
1793 const Standard_Real theToleranceC1)
1795 TopAbs_ShapeEnum aType = theShape.ShapeType();
1797 case TopAbs_COMPOUND:
1798 case TopAbs_COMPSOLID:
1800 TopoDS_Iterator It (theShape);
1801 for (; It.More(); It.Next()) {
1802 AddBlocksFrom(It.Value(), BLO, NOT, EXT, NOQ, theToleranceC1);
1808 // Check, if there are seam or degenerated edges
1809 BlockFix_CheckTool aTool;
1810 aTool.SetShape(theShape);
1811 aTool.SetAngTolerance(theToleranceC1);
1813 if (aTool.NbPossibleBlocks() > 0) {
1814 EXT.Append(theShape);
1816 // Count faces and edges in each face to recognize blocks
1817 TopTools_MapOfShape mapFaces;
1818 Standard_Integer nbFaces = 0;
1819 Standard_Boolean hasNonQuadr = Standard_False;
1820 TopExp_Explorer expF (theShape, TopAbs_FACE);
1822 for (; expF.More(); expF.Next()) {
1823 TopoDS_Face aF = TopoDS::Face(expF.Current());
1825 if (mapFaces.Add(aF)) {
1828 if (!IsQuadrangle(aF, theToleranceC1)) {
1829 hasNonQuadr = Standard_True;
1830 NOQ.Append(aF);//0021483
1835 if (nbFaces == 6 && !hasNonQuadr) {
1836 BLO.Append(theShape);
1838 NOT.Append(theShape);
1843 case TopAbs_SHELL: //0021483
1844 case TopAbs_FACE: //0021483
1846 // Count edges in each face
1847 TopTools_MapOfShape mapFaces;
1848 TopExp_Explorer expF (theShape, TopAbs_FACE);
1849 for (; expF.More(); expF.Next()) {
1850 TopoDS_Face aF = TopoDS::Face(expF.Current());
1852 if (mapFaces.Add(aF)) {
1853 if (!IsQuadrangle(aF, theToleranceC1)) {
1854 NOQ.Append(aF);//0021483
1861 NOT.Append(theShape);
1865 #define REL_NOT_CONNECTED 0
1867 #define REL_NOT_GLUED 2
1868 #define REL_COLLISION_VV 3
1869 #define REL_COLLISION_FF 4
1870 #define REL_COLLISION_EE 5
1871 #define REL_UNKNOWN 6
1873 Standard_Integer BlocksRelation (const TopoDS_Shape& theBlock1,
1874 const TopoDS_Shape& theBlock2)
1876 // Compare bounding boxes before calling BRepExtrema_DistShapeShape
1877 Standard_Real Xmin1, Ymin1, Zmin1, Xmax1, Ymax1, Zmax1;
1878 Standard_Real Xmin2, Ymin2, Zmin2, Xmax2, Ymax2, Zmax2;
1880 BRepBndLib::Add(theBlock1, B1);
1881 BRepBndLib::Add(theBlock2, B2);
1882 B1.Get(Xmin1, Ymin1, Zmin1, Xmax1, Ymax1, Zmax1);
1883 B2.Get(Xmin2, Ymin2, Zmin2, Xmax2, Ymax2, Zmax2);
1884 if (Xmax2 < Xmin1 || Xmax1 < Xmin2 ||
1885 Ymax2 < Ymin1 || Ymax1 < Ymin2 ||
1886 Zmax2 < Zmin1 || Zmax1 < Zmin2) {
1887 return REL_NOT_CONNECTED;
1890 BRepExtrema_DistShapeShape dst (theBlock1, theBlock2);
1891 if (!dst.IsDone()) {
1895 if (dst.Value() > Precision::Confusion()) {
1896 return REL_NOT_CONNECTED;
1899 if (dst.InnerSolution()) {
1900 return REL_COLLISION_VV;
1903 Standard_Integer nbSol = dst.NbSolution();
1904 Standard_Integer relation = REL_OK;
1905 Standard_Integer nbVerts = 0;
1906 Standard_Integer nbEdges = 0;
1907 Standard_Integer sol = 1;
1908 for (; sol <= nbSol; sol++) {
1909 BRepExtrema_SupportType supp1 = dst.SupportTypeShape1(sol);
1910 BRepExtrema_SupportType supp2 = dst.SupportTypeShape2(sol);
1911 if (supp1 == BRepExtrema_IsVertex && supp2 == BRepExtrema_IsVertex) {
1913 } else if (supp1 == BRepExtrema_IsInFace || supp2 == BRepExtrema_IsInFace) {
1914 return REL_COLLISION_FF;
1915 } else if (supp1 == BRepExtrema_IsOnEdge && supp2 == BRepExtrema_IsOnEdge) {
1917 } else if ((supp1 == BRepExtrema_IsOnEdge && supp2 == BRepExtrema_IsVertex) ||
1918 (supp2 == BRepExtrema_IsOnEdge && supp1 == BRepExtrema_IsVertex)) {
1919 relation = REL_COLLISION_EE;
1924 if (relation != REL_OK) {
1928 TColStd_Array1OfInteger vertSol (1, nbVerts);
1929 TopTools_Array1OfShape V1 (1, nbVerts);
1930 TopTools_Array1OfShape V2 (1, nbVerts);
1931 Standard_Integer ivs = 0;
1932 for (sol = 1; sol <= nbSol; sol++) {
1933 if (dst.SupportTypeShape1(sol) == BRepExtrema_IsVertex &&
1934 dst.SupportTypeShape2(sol) == BRepExtrema_IsVertex) {
1935 TopoDS_Vertex Vcur = TopoDS::Vertex(dst.SupportOnShape1(sol));
1936 // Check, that this vertex is far enough from other solution vertices.
1937 Standard_Integer ii = 1;
1938 for (; ii <= ivs; ii++) {
1939 if (BRepTools::Compare(TopoDS::Vertex(V1(ii)), Vcur)) {
1946 V2(ivs) = dst.SupportOnShape2(sol);
1950 // As we deal only with quadrangles,
1951 // 2, 3 or 4 vertex solutions can be found.
1954 return REL_COLLISION_FF;
1956 return REL_NOT_CONNECTED;
1962 // Check sharing of coincident entities.
1963 if (ivs == 2 || ivs == 3) {
1964 // Map vertices and edges of the blocks
1965 TopTools_IndexedDataMapOfShapeListOfShape MVE1, MVE2;
1966 GEOMImpl_Block6Explorer::MapShapesAndAncestors
1967 (theBlock1, TopAbs_VERTEX, TopAbs_EDGE, MVE1);
1968 GEOMImpl_Block6Explorer::MapShapesAndAncestors
1969 (theBlock2, TopAbs_VERTEX, TopAbs_EDGE, MVE2);
1973 TopoDS_Shape anEdge1, anEdge2;
1974 GEOMImpl_Block6Explorer::FindEdge(anEdge1, V1(1), V1(2), MVE1);
1975 if (anEdge1.IsNull()) return REL_UNKNOWN;
1977 GEOMImpl_Block6Explorer::FindEdge(anEdge2, V2(1), V2(2), MVE2);
1978 if (anEdge2.IsNull()) return REL_UNKNOWN;
1980 if (!anEdge1.IsSame(anEdge2)) return REL_NOT_GLUED;
1982 } else { // ivs == 3
1983 // Find common edges
1984 Standard_Integer e1_v1 = 1;
1985 Standard_Integer e1_v2 = 2;
1986 Standard_Integer e2_v1 = 3;
1987 Standard_Integer e2_v2 = 1;
1989 TopoDS_Shape anEdge11, anEdge12;
1990 GEOMImpl_Block6Explorer::FindEdge(anEdge11, V1(e1_v1), V1(e1_v2), MVE1);
1991 if (anEdge11.IsNull()) {
1994 GEOMImpl_Block6Explorer::FindEdge(anEdge11, V1(e1_v1), V1(e1_v2), MVE1);
1995 if (anEdge11.IsNull()) return REL_UNKNOWN;
1997 GEOMImpl_Block6Explorer::FindEdge(anEdge12, V1(e2_v1), V1(e2_v2), MVE1);
1998 if (anEdge12.IsNull()) {
2000 GEOMImpl_Block6Explorer::FindEdge(anEdge12, V1(e2_v1), V1(e2_v2), MVE1);
2001 if (anEdge12.IsNull()) return REL_UNKNOWN;
2004 TopoDS_Shape anEdge21, anEdge22;
2005 GEOMImpl_Block6Explorer::FindEdge(anEdge21, V2(e1_v1), V2(e1_v2), MVE2);
2006 if (anEdge21.IsNull()) return REL_UNKNOWN;
2007 GEOMImpl_Block6Explorer::FindEdge(anEdge22, V2(e2_v1), V2(e2_v2), MVE2);
2008 if (anEdge22.IsNull()) return REL_UNKNOWN;
2010 // Check of edges coincidence (with some precision) have to be done here
2011 // if (!anEdge11.IsEqual(anEdge21)) return REL_UNKNOWN;
2012 // if (!anEdge12.IsEqual(anEdge22)) return REL_UNKNOWN;
2014 // Check of edges sharing
2015 if (!anEdge11.IsSame(anEdge21)) return REL_NOT_GLUED;
2016 if (!anEdge12.IsSame(anEdge22)) return REL_NOT_GLUED;
2021 // Map vertices and faces of the blocks
2022 TopTools_IndexedDataMapOfShapeListOfShape MVF1, MVF2;
2023 GEOMImpl_Block6Explorer::MapShapesAndAncestors
2024 (theBlock1, TopAbs_VERTEX, TopAbs_FACE, MVF1);
2025 GEOMImpl_Block6Explorer::MapShapesAndAncestors
2026 (theBlock2, TopAbs_VERTEX, TopAbs_FACE, MVF2);
2028 TopoDS_Shape aFace1, aFace2;
2029 GEOMImpl_Block6Explorer::FindFace(aFace1, V1(1), V1(2), V1(3), V1(4), MVF1);
2030 if (aFace1.IsNull()) return REL_UNKNOWN;
2031 GEOMImpl_Block6Explorer::FindFace(aFace2, V2(1), V2(2), V2(3), V2(4), MVF2);
2032 if (aFace2.IsNull()) return REL_UNKNOWN;
2034 // Check of faces coincidence (with some precision) have to be done here
2035 // if (!aFace1.IsEqual(aFace2)) return REL_UNKNOWN;
2037 // Check of faces sharing
2038 if (!aFace1.IsSame(aFace2)) return REL_NOT_GLUED;
2044 void FindConnected (const Standard_Integer theBlockIndex,
2045 const TColStd_Array2OfInteger& theRelations,
2046 TColStd_MapOfInteger& theProcessedMap,
2047 TColStd_MapOfInteger& theConnectedMap)
2049 theConnectedMap.Add(theBlockIndex);
2050 theProcessedMap.Add(theBlockIndex);
2052 Standard_Integer nbBlocks = theRelations.ColLength();
2053 Standard_Integer col = 1;
2054 for (; col <= nbBlocks; col++) {
2055 if (theRelations(theBlockIndex, col) == REL_OK ||
2056 theRelations(theBlockIndex, col) == REL_NOT_GLUED) {
2057 if (!theProcessedMap.Contains(col)) {
2058 FindConnected(col, theRelations, theProcessedMap, theConnectedMap);
2064 Standard_Boolean HasAnyConnection (const Standard_Integer theBlockIndex,
2065 const TColStd_MapOfInteger& theWith,
2066 const TColStd_Array2OfInteger& theRelations,
2067 TColStd_MapOfInteger& theProcessedMap)
2069 theProcessedMap.Add(theBlockIndex);
2071 Standard_Integer nbBlocks = theRelations.ColLength();
2072 Standard_Integer col = 1;
2073 for (; col <= nbBlocks; col++) {
2074 if (theRelations(theBlockIndex, col) != REL_NOT_CONNECTED) {
2075 if (!theProcessedMap.Contains(col)) {
2076 if (theWith.Contains(col))
2077 return Standard_True;
2078 if (HasAnyConnection(col, theWith, theRelations, theProcessedMap))
2079 return Standard_True;
2084 return Standard_False;
2087 //=============================================================================
2091 //=============================================================================
2092 TCollection_AsciiString GEOMImpl_IBlocksOperations::PrintBCErrors
2093 (Handle(GEOM_Object) theCompound,
2094 const std::list<BCError>& theErrors)
2096 TCollection_AsciiString aDescr;
2098 std::list<BCError>::const_iterator errIt = theErrors.begin();
2100 for (; errIt != theErrors.end(); i++, errIt++) {
2101 BCError errStruct = *errIt;
2103 switch (errStruct.error) {
2105 aDescr += "\n\tNot a Blocks: ";
2108 aDescr += "\n\tHexahedral solids with degenerated and/or seam edges: ";
2110 case INVALID_CONNECTION:
2111 aDescr += "\n\tInvalid connection between two blocks: ";
2114 aDescr += "\n\tBlocks, not connected with main body: ";
2117 aDescr += "\n\tNot glued blocks: ";
2123 std::list<int> sshList = errStruct.incriminated;
2124 std::list<int>::iterator sshIt = sshList.begin();
2126 for (; sshIt != sshList.end(); jj++, sshIt++) {
2129 aDescr += TCollection_AsciiString(*sshIt);
2136 //=============================================================================
2138 * CheckCompoundOfBlocks
2140 //=============================================================================
2141 Standard_Boolean GEOMImpl_IBlocksOperations::CheckCompoundOfBlocks
2142 (Handle(GEOM_Object) theCompound,
2143 const Standard_Real theToleranceC1,
2144 std::list<BCError>& theErrors)
2148 if (theCompound.IsNull()) return Standard_False;
2149 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2151 Standard_Boolean isCompOfBlocks = Standard_True;
2153 // Map sub-shapes and their indices
2154 TopTools_IndexedMapOfShape anIndices;
2155 TopExp::MapShapes(aBlockOrComp, anIndices);
2157 // 1. Separate blocks from non-blocks
2158 TopTools_ListOfShape NOT; // Not blocks
2159 TopTools_ListOfShape EXT; // Hexahedral solids, having degenerated and/or seam edges
2160 TopTools_ListOfShape BLO; // All blocks from the given compound
2161 TopTools_ListOfShape NOQ; // All non-quadrangular faces
2162 AddBlocksFrom(aBlockOrComp, BLO, NOT, EXT, NOQ, theToleranceC1);
2164 // Report non-blocks
2165 if (NOT.Extent() > 0) {
2166 isCompOfBlocks = Standard_False;
2168 anErr.error = NOT_BLOCK;
2169 TopTools_ListIteratorOfListOfShape it (NOT);
2170 for (; it.More(); it.Next()) {
2171 anErr.incriminated.push_back(anIndices.FindIndex(it.Value()));
2173 theErrors.push_back(anErr);
2176 // Report solids, having degenerated and/or seam edges
2177 if (EXT.Extent() > 0) {
2178 isCompOfBlocks = Standard_False;
2180 anErr.error = EXTRA_EDGE;
2181 TopTools_ListIteratorOfListOfShape it (EXT);
2182 for (; it.More(); it.Next()) {
2183 anErr.incriminated.push_back(anIndices.FindIndex(it.Value()));
2185 theErrors.push_back(anErr);
2188 Standard_Integer nbBlocks = BLO.Extent();
2189 if (nbBlocks == 0) {
2190 isCompOfBlocks = Standard_False;
2192 return isCompOfBlocks;
2194 if (nbBlocks == 1) {
2196 return isCompOfBlocks;
2199 // Prepare data for 2. and 3.
2200 TColStd_Array2OfInteger aRelations (1, nbBlocks, 1, nbBlocks);
2201 aRelations.Init(REL_NOT_CONNECTED);
2203 TopTools_IndexedMapOfShape mapBlocks;
2206 TopoDS_Compound aComp;
2207 BB.MakeCompound(aComp);
2209 TopTools_ListIteratorOfListOfShape BLOit (BLO);
2210 for (; BLOit.More(); BLOit.Next()) {
2211 mapBlocks.Add(BLOit.Value());
2212 BB.Add(aComp, BLOit.Value());
2215 // 2. Find glued blocks (having shared faces)
2216 TopTools_IndexedDataMapOfShapeListOfShape mapFaceBlocks;
2217 GEOMImpl_Block6Explorer::MapShapesAndAncestors
2218 (aComp, TopAbs_FACE, TopAbs_SOLID, mapFaceBlocks);
2220 Standard_Integer prevInd = 0, curInd = 0;
2221 Standard_Integer ind = 1, nbFaces = mapFaceBlocks.Extent();
2222 for (; ind <= nbFaces; ind++) {
2223 const TopTools_ListOfShape& aGluedBlocks = mapFaceBlocks.FindFromIndex(ind);
2224 if (aGluedBlocks.Extent() > 1) { // Shared face found
2225 TopTools_ListIteratorOfListOfShape aGluedBlocksIt (aGluedBlocks);
2226 TopoDS_Shape prevBlock, curBlock;
2227 for (; aGluedBlocksIt.More(); aGluedBlocksIt.Next()) {
2228 curBlock = aGluedBlocksIt.Value();
2229 if (!prevBlock.IsNull()) {
2230 prevInd = mapBlocks.FindIndex(prevBlock);
2231 curInd = mapBlocks.FindIndex(curBlock);
2232 aRelations.SetValue(prevInd, curInd, REL_OK);
2233 aRelations.SetValue(curInd, prevInd, REL_OK);
2235 prevBlock = curBlock;
2240 // 3. Find not glued blocks
2241 GEOMAlgo_GlueAnalyser aGD;
2243 aGD.SetShape(aComp);
2244 aGD.SetTolerance(Precision::Confusion());
2245 aGD.SetCheckGeometry(Standard_True);
2248 Standard_Integer iErr, iWrn;
2249 iErr = aGD.ErrorStatus();
2251 SetErrorCode("Error in GEOMAlgo_GlueAnalyser");
2252 return isCompOfBlocks;
2254 iWrn = aGD.WarningStatus();
2256 MESSAGE("Warning in GEOMAlgo_GlueAnalyser");
2259 // Report not glued blocks
2260 if (aGD.HasSolidsToGlue()) {
2261 isCompOfBlocks = Standard_False;
2262 Standard_Integer aSx1Ind, aSx2Ind;
2264 const GEOMAlgo_ListOfCoupleOfShapes& aLCS = aGD.SolidsToGlue();
2265 GEOMAlgo_ListIteratorOfListOfCoupleOfShapes aItCS (aLCS);
2266 for (; aItCS.More(); aItCS.Next()) {
2267 const GEOMAlgo_CoupleOfShapes& aCS = aItCS.Value();
2268 const TopoDS_Shape& aSx1 = aCS.Shape1();
2269 const TopoDS_Shape& aSx2 = aCS.Shape2();
2271 aSx1Ind = mapBlocks.FindIndex(aSx1);
2272 aSx2Ind = mapBlocks.FindIndex(aSx2);
2273 aRelations.SetValue(aSx1Ind, aSx2Ind, NOT_GLUED);
2274 aRelations.SetValue(aSx2Ind, aSx1Ind, NOT_GLUED);
2277 anErr.error = NOT_GLUED;
2278 anErr.incriminated.push_back(anIndices.FindIndex(aSx1));
2279 anErr.incriminated.push_back(anIndices.FindIndex(aSx2));
2280 theErrors.push_back(anErr);
2284 // 4. Find largest set of connected (good connection or not glued) blocks
2285 Standard_Integer ibl = 1;
2286 TColStd_MapOfInteger aProcessedMap;
2287 TColStd_MapOfInteger aLargestSet;
2288 TColStd_MapOfInteger aCurrentSet;
2289 for (ibl = 1; ibl <= nbBlocks; ibl++) {
2290 if (!aProcessedMap.Contains(ibl)) {
2291 aCurrentSet.Clear();
2292 FindConnected(ibl, aRelations, aProcessedMap, aCurrentSet);
2293 if (aCurrentSet.Extent() > aLargestSet.Extent()) {
2294 aLargestSet = aCurrentSet;
2299 // 5. Report all blocks, isolated from <aLargestSet>
2301 anErr.error = NOT_CONNECTED;
2302 Standard_Boolean hasIsolated = Standard_False;
2303 for (ibl = 1; ibl <= nbBlocks; ibl++) {
2304 if (!aLargestSet.Contains(ibl)) {
2305 aProcessedMap.Clear();
2306 if (!HasAnyConnection(ibl, aLargestSet, aRelations, aProcessedMap)) {
2307 // report connection absence
2308 hasIsolated = Standard_True;
2309 anErr.incriminated.push_back(anIndices.FindIndex(mapBlocks.FindKey(ibl)));
2314 isCompOfBlocks = Standard_False;
2315 theErrors.push_back(anErr);
2319 return isCompOfBlocks;
2322 //=============================================================================
2326 //=============================================================================
2327 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetNonBlocks
2328 (Handle(GEOM_Object) theShape,
2329 const Standard_Real theToleranceC1,
2330 Handle(GEOM_Object)& theNonQuads)
2334 if (theShape.IsNull()) return NULL;
2335 TopoDS_Shape aShape = theShape->GetValue();
2337 // Separate blocks from non-blocks
2338 TopTools_ListOfShape BLO; // All blocks from the given compound
2339 TopTools_ListOfShape NOT; // Not blocks
2340 TopTools_ListOfShape EXT; // Hexahedral solids, having degenerated and/or seam edges
2341 TopTools_ListOfShape NOQ; // All non-quadrangular faces
2342 AddBlocksFrom(aShape, BLO, NOT, EXT, NOQ, theToleranceC1);
2344 if (NOT.IsEmpty() && EXT.IsEmpty() && NOQ.IsEmpty()) {
2345 SetErrorCode("NOT_FOUND_ANY");
2349 // Map sub-shapes and their indices
2350 TopTools_IndexedMapOfShape anIndices;
2351 TopExp::MapShapes(aShape, anIndices);
2354 Handle(GEOM_Object) aNonBlocks;
2355 if (NOT.Extent() > 0 || EXT.Extent() > 0) {
2356 Handle(TColStd_HArray1OfInteger) anArray =
2357 new TColStd_HArray1OfInteger (1, NOT.Extent() + EXT.Extent());
2358 Standard_Integer ii = 1;
2359 TopTools_ListIteratorOfListOfShape it1 (NOT);
2360 for (; it1.More(); it1.Next(), ii++) {
2361 anArray->SetValue(ii, anIndices.FindIndex(it1.Value()));
2363 TopTools_ListIteratorOfListOfShape it2 (EXT);
2364 for (; it2.More(); it2.Next(), ii++) {
2365 anArray->SetValue(ii, anIndices.FindIndex(it2.Value()));
2368 aNonBlocks = GetEngine()->AddSubShape(theShape, anArray);
2369 if (aNonBlocks.IsNull()) {
2370 SetErrorCode("Error in algorithm: result found, but cannot be returned.");
2373 aNonBlocks->SetType(GEOM_GROUP);
2374 TDF_Label aFreeLabel = aNonBlocks->GetFreeLabel();
2375 TDataStd_Integer::Set(aFreeLabel, (Standard_Integer)TopAbs_SOLID);
2379 if (NOQ.Extent() > 0) {
2380 Handle(TColStd_HArray1OfInteger) anArray =
2381 new TColStd_HArray1OfInteger (1, NOQ.Extent());
2382 Standard_Integer ii = 1;
2383 TopTools_ListIteratorOfListOfShape it1 (NOQ);
2384 for (; it1.More(); it1.Next(), ii++) {
2385 anArray->SetValue(ii, anIndices.FindIndex(it1.Value()));
2388 theNonQuads = GetEngine()->AddSubShape(theShape, anArray);
2389 if (theNonQuads.IsNull()) {
2390 SetErrorCode("Error in algorithm: result found, but cannot be returned.");
2393 theNonQuads->SetType(GEOM_GROUP);
2394 TDF_Label aFreeLabel = theNonQuads->GetFreeLabel();
2395 TDataStd_Integer::Set(aFreeLabel, (Standard_Integer)TopAbs_FACE);
2398 //Make a Python command
2399 Handle(GEOM_Function) aMainShape = theShape->GetLastFunction();
2400 GEOM::TPythonDump pd (aMainShape, /*append=*/true);
2402 if (aNonBlocks.IsNull())
2403 pd << "no_bad_solids";
2407 if (theNonQuads.IsNull())
2408 pd << "no_bad_faces";
2411 pd << ") = geompy.GetNonBlocks(" << theShape << ")";
2417 //=============================================================================
2421 //=============================================================================
2422 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::RemoveExtraEdges
2423 (Handle(GEOM_Object) theObject,
2424 const Standard_Integer theOptimumNbFaces)
2428 if (theObject.IsNull()) return NULL;
2430 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
2431 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be fixed
2433 //Add a new Copy object
2434 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
2437 Handle(GEOM_Function) aFunction =
2438 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_REMOVE_EXTRA);
2440 //Check if the function is set correctly
2441 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
2443 GEOMImpl_IBlockTrsf aTI (aFunction);
2444 aTI.SetOriginal(aLastFunction);
2445 aTI.SetOptimumNbFaces(theOptimumNbFaces);
2447 //Compute the fixed shape
2450 if (!GetSolver()->ComputeFunction(aFunction)) {
2451 SetErrorCode("Block driver failed to remove extra edges of the given shape");
2455 catch (Standard_Failure) {
2456 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2457 SetErrorCode(aFail->GetMessageString());
2461 //Make a Python command
2462 std::string doUnionFaces = (theOptimumNbFaces < 0) ? "False" : "True";
2463 GEOM::TPythonDump(aFunction) << aCopy << " = geompy.RemoveExtraEdges("
2464 << theObject << ", " << doUnionFaces.data() << ")";
2470 //=============================================================================
2474 //=============================================================================
2475 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::UnionFaces
2476 (Handle(GEOM_Object) theObject)
2480 if (theObject.IsNull()) return NULL;
2482 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
2483 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be fixed
2485 //Add a new Copy object
2486 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
2489 Handle(GEOM_Function) aFunction =
2490 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_UNION_FACES);
2492 //Check if the function is set correctly
2493 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
2495 GEOMImpl_IBlockTrsf aTI (aFunction);
2496 aTI.SetOriginal(aLastFunction);
2498 //Compute the fixed shape
2501 if (!GetSolver()->ComputeFunction(aFunction)) {
2502 SetErrorCode("Block driver failed to remove extra edges of the given shape");
2506 catch (Standard_Failure) {
2507 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2508 SetErrorCode(aFail->GetMessageString());
2512 //Make a Python command
2513 GEOM::TPythonDump(aFunction) << aCopy << " = geompy.UnionFaces("
2514 << theObject << ")";
2520 //=============================================================================
2524 //=============================================================================
2525 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::CheckAndImprove
2526 (Handle(GEOM_Object) theObject)
2530 if (theObject.IsNull()) return NULL;
2532 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
2533 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be fixed
2535 //Add a new Copy object
2536 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
2539 Handle(GEOM_Function) aFunction =
2540 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_COMPOUND_IMPROVE);
2542 //Check if the function is set correctly
2543 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
2545 GEOMImpl_IBlockTrsf aTI (aFunction);
2546 aTI.SetOriginal(aLastFunction);
2548 // -1 means do not unite faces on common surface (?except case of seam edge between them?)
2549 //aTI.SetOptimumNbFaces(-1);
2550 aTI.SetOptimumNbFaces(6);
2552 //Compute the fixed shape
2555 if (!GetSolver()->ComputeFunction(aFunction)) {
2556 SetErrorCode("Block driver failed to improve the given blocks compound");
2560 catch (Standard_Failure) {
2561 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2562 SetErrorCode(aFail->GetMessageString());
2566 //Make a Python command
2567 GEOM::TPythonDump(aFunction) << aCopy
2568 << " = geompy.CheckAndImprove(" << theObject << ")";
2574 //=============================================================================
2576 * ExplodeCompoundOfBlocks
2578 //=============================================================================
2579 Handle(TColStd_HSequenceOfTransient) GEOMImpl_IBlocksOperations::ExplodeCompoundOfBlocks
2580 (Handle(GEOM_Object) theCompound,
2581 const Standard_Integer theMinNbFaces,
2582 const Standard_Integer theMaxNbFaces)
2586 if (theCompound.IsNull()) return NULL;
2587 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2588 if (aBlockOrComp.IsNull()) return NULL;
2590 Handle(TColStd_HSequenceOfTransient) aBlocks = new TColStd_HSequenceOfTransient;
2591 Handle(GEOM_Object) anObj;
2592 Handle(GEOM_Function) aFunction;
2594 TopTools_MapOfShape mapShape;
2595 TCollection_AsciiString anAsciiList, anEntry;
2598 TopTools_IndexedMapOfShape anIndices;
2599 TopExp::MapShapes(aBlockOrComp, anIndices);
2600 Handle(TColStd_HArray1OfInteger) anArray;
2605 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2606 for (; exp.More(); exp.Next()) {
2607 if (mapShape.Add(exp.Current())) {
2608 TopoDS_Shape aSolid = exp.Current();
2610 TopTools_MapOfShape mapFaces;
2611 TopExp_Explorer expF (aSolid, TopAbs_FACE);
2612 Standard_Integer nbFaces = 0;
2613 for (; expF.More(); expF.Next()) {
2614 if (mapFaces.Add(expF.Current())) {
2619 if (theMinNbFaces <= nbFaces && nbFaces <= theMaxNbFaces) {
2620 anArray = new TColStd_HArray1OfInteger(1,1);
2621 anArray->SetValue(1, anIndices.FindIndex(aSolid));
2622 anObj = GetEngine()->AddSubShape(theCompound, anArray);
2623 aBlocks->Append(anObj);
2625 //Make a Python command
2626 TDF_Tool::Entry(anObj->GetEntry(), anEntry);
2627 anAsciiList += anEntry + ", ";
2632 catch (Standard_Failure) {
2633 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2634 SetErrorCode(aFail->GetMessageString());
2638 if (aBlocks->IsEmpty()) {
2639 SetErrorCode("There are no specified blocks in the given shape");
2643 anAsciiList.Trunc(anAsciiList.Length() - 2);
2645 //The explode doesn't change object so no new function is required.
2646 aFunction = theCompound->GetLastFunction();
2648 //Make a Python command
2649 GEOM::TPythonDump(aFunction, /*append=*/true)
2650 << "[" << anAsciiList.ToCString() << "] = geompy.MakeBlockExplode("
2651 << theCompound << ", " << theMinNbFaces << ", " << theMaxNbFaces << ")";
2657 //=============================================================================
2661 //=============================================================================
2662 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetBlockNearPoint
2663 (Handle(GEOM_Object) theCompound,
2664 Handle(GEOM_Object) thePoint)
2669 Handle(GEOM_Object) aResult;
2672 if (theCompound.IsNull() || thePoint.IsNull()) return NULL;
2674 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2675 if (aBlockOrComp.IsNull()) {
2676 SetErrorCode("Compound is null");
2679 if (aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
2680 aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
2681 SetErrorCode("Shape to find block in is not a compound");
2685 TopoDS_Shape anArg = thePoint->GetValue();
2686 if (anArg.IsNull()) {
2687 SetErrorCode("Point is null");
2690 if (anArg.ShapeType() != TopAbs_VERTEX) {
2691 SetErrorCode("Shape for block identification is not a vertex");
2695 //Compute the Block value
2698 TopoDS_Shape aShape;
2700 TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
2701 gp_Pnt aPnt = BRep_Tool::Pnt(aVert);
2702 Standard_Real PX, PY, PZ;
2703 aPnt.Coord(PX, PY, PZ);
2705 // 1. Classify the point relatively each block
2706 Standard_Integer nearest = 2, nbFound = 0;
2707 TopTools_DataMapOfShapeInteger mapShapeDist;
2708 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2709 for (; exp.More(); exp.Next()) {
2710 TopoDS_Shape aSolid = exp.Current();
2712 if (!mapShapeDist.IsBound(aSolid)) {
2713 Standard_Integer aDistance = 2;
2715 // 1.a. Classify relatively Bounding box
2716 Standard_Real Xmin, Ymin, Zmin, Xmax, Ymax, Zmax;
2718 BRepBndLib::Add(aSolid, BB);
2719 BB.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);
2720 if (PX < Xmin || Xmax < PX ||
2721 PY < Ymin || Ymax < PY ||
2722 PZ < Zmin || Zmax < PZ) {
2723 // OUT of bounding box
2726 // 1.b. Classify relatively the solid itself
2727 BRepClass3d_SolidClassifier SC (aSolid, aPnt, Precision::Confusion());
2728 if (SC.State() == TopAbs_IN) {
2730 } else if (SC.State() == TopAbs_ON) {
2737 if (aDistance < nearest) {
2738 nearest = aDistance;
2742 // A first found block, containing the point inside, will be returned.
2743 // It is the solution, if there are no intersecting blocks in the compound.
2744 if (nearest == -1) break;
2746 } else if (aDistance == nearest) {
2751 mapShapeDist.Bind(aSolid, aDistance);
2752 } // if (!mapShapeDist.IsBound(aSolid))
2755 // 2. Define block, containing the point or having minimum distance to it
2758 // The point is on boundary of some blocks and there are
2759 // no blocks, having the point inside their volume
2760 SetErrorCode("Multiple blocks near the given point are found");
2763 } else if (nearest == 1) {
2764 // The point is outside some blocks and there are
2765 // no blocks, having the point inside or on boundary.
2766 // We will get a nearest block
2767 Standard_Real minDist = RealLast();
2768 TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
2769 for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
2770 if (mapShapeDistIter.Value() == 1) {
2771 TopoDS_Shape aSolid = mapShapeDistIter.Key();
2772 BRepExtrema_DistShapeShape aDistTool (aVert, aSolid);
2773 if (!aDistTool.IsDone()) {
2774 SetErrorCode("Can not find a distance from the given point to one of blocks");
2777 Standard_Real aDist = aDistTool.Value();
2778 if (aDist < minDist) {
2784 } else { // nearest == -1
2785 // // The point is inside some blocks.
2786 // // We will get a block with nearest center
2787 // Standard_Real minDist = RealLast();
2788 // TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
2789 // for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
2790 // if (mapShapeDistIter.Value() == -1) {
2791 // TopoDS_Shape aSolid = mapShapeDistIter.Key();
2792 // GProp_GProps aSystem;
2793 // BRepGProp::VolumeProperties(aSolid, aSystem);
2794 // gp_Pnt aCenterMass = aSystem.CentreOfMass();
2796 // Standard_Real aDist = aCenterMass.Distance(aPnt);
2797 // if (aDist < minDist) {
2804 } // if (nbFound > 1)
2807 SetErrorCode("There are no blocks near the given point");
2810 TopTools_IndexedMapOfShape anIndices;
2811 TopExp::MapShapes(aBlockOrComp, anIndices);
2812 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
2813 anArray->SetValue(1, anIndices.FindIndex(aShape));
2814 aResult = GetEngine()->AddSubShape(theCompound, anArray);
2817 catch (Standard_Failure) {
2818 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2819 SetErrorCode(aFail->GetMessageString());
2823 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
2825 //Make a Python command
2826 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetBlockNearPoint("
2827 << theCompound << ", " << thePoint << ")";
2833 //=============================================================================
2837 //=============================================================================
2838 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetBlockByParts
2839 (Handle(GEOM_Object) theCompound,
2840 const Handle(TColStd_HSequenceOfTransient)& theParts)
2844 Handle(GEOM_Object) aResult;
2846 if (theCompound.IsNull() || theParts.IsNull()) return NULL;
2847 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2848 if (aBlockOrComp.IsNull()) return NULL;
2851 Standard_Integer argi, aLen = theParts->Length();
2852 TopTools_Array1OfShape anArgs (1, aLen);
2853 TCollection_AsciiString anEntry, aPartsDescr;
2854 for (argi = 1; argi <= aLen; argi++) {
2855 Handle(GEOM_Object) anObj = Handle(GEOM_Object)::DownCast(theParts->Value(argi));
2856 Handle(GEOM_Function) aRef = anObj->GetLastFunction();
2857 if (aRef.IsNull()) return NULL;
2859 TopoDS_Shape anArg = aRef->GetValue();
2860 if (anArg.IsNull()) {
2861 SetErrorCode("Null shape is given as argument");
2864 anArgs(argi) = anArg;
2866 // For Python command
2867 TDF_Tool::Entry(anObj->GetEntry(), anEntry);
2868 if (argi > 1) aPartsDescr += ", ";
2869 aPartsDescr += anEntry;
2872 //Compute the Block value
2875 // 1. Explode compound on solids
2876 TopTools_MapOfShape mapShape;
2877 Standard_Integer nbSolids = 0;
2878 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2879 for (; exp.More(); exp.Next()) {
2880 if (mapShape.Add(exp.Current())) {
2886 Standard_Integer ind = 1;
2887 TopTools_Array1OfShape aSolids (1, nbSolids);
2888 TColStd_Array1OfInteger aNbParts (1, nbSolids);
2889 for (exp.Init(aBlockOrComp, TopAbs_SOLID); exp.More(); exp.Next(), ind++) {
2890 if (mapShape.Add(exp.Current())) {
2891 TopoDS_Shape aSolid = exp.Current();
2892 aSolids(ind) = aSolid;
2895 // 2. Define quantity of parts, contained in each solid
2896 TopTools_IndexedMapOfShape aSubShapes;
2897 TopExp::MapShapes(aSolid, aSubShapes);
2898 for (argi = 1; argi <= aLen; argi++) {
2899 if (aSubShapes.Contains(anArgs(argi))) {
2906 // 3. Define solid, containing maximum quantity of parts
2907 Standard_Integer maxNb = 0, nbFound = 0;
2908 TopoDS_Shape aShape;
2909 for (ind = 1; ind <= nbSolids; ind++) {
2910 if (aNbParts(ind) > maxNb) {
2911 maxNb = aNbParts(ind);
2912 aShape = aSolids(ind);
2914 } else if (aNbParts(ind) == maxNb) {
2920 SetErrorCode("Multiple blocks, containing maximum quantity of the given parts, are found");
2922 } else if (nbFound == 0) {
2923 SetErrorCode("There are no blocks, containing the given parts");
2926 TopTools_IndexedMapOfShape anIndices;
2927 TopExp::MapShapes(aBlockOrComp, anIndices);
2928 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
2929 anArray->SetValue(1, anIndices.FindIndex(aShape));
2930 aResult = GetEngine()->AddSubShape(theCompound, anArray);
2932 } catch (Standard_Failure) {
2933 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
2934 SetErrorCode(aFail->GetMessageString());
2938 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
2940 //Make a Python command
2941 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetBlockByParts("
2942 << theCompound << ", [" << aPartsDescr.ToCString() << "])";
2948 //=============================================================================
2952 //=============================================================================
2953 Handle(TColStd_HSequenceOfTransient) GEOMImpl_IBlocksOperations::GetBlocksByParts
2954 (Handle(GEOM_Object) theCompound,
2955 const Handle(TColStd_HSequenceOfTransient)& theParts)
2959 if (theCompound.IsNull() || theParts.IsNull()) return NULL;
2960 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2961 if (aBlockOrComp.IsNull()) return NULL;
2963 Handle(TColStd_HSequenceOfTransient) aBlocks = new TColStd_HSequenceOfTransient;
2964 Handle(GEOM_Object) anObj;
2965 Handle(GEOM_Function) aFunction;
2968 Standard_Integer argi, aLen = theParts->Length();
2969 TopTools_Array1OfShape anArgs (1, aLen);
2970 TCollection_AsciiString anEntry, aPartsDescr, anAsciiList;
2972 for (argi = 1; argi <= aLen; argi++) {
2973 Handle(GEOM_Object) anObj = Handle(GEOM_Object)::DownCast(theParts->Value(argi));
2974 Handle(GEOM_Function) aRef = anObj->GetLastFunction();
2975 if (aRef.IsNull()) return NULL;
2977 TopoDS_Shape anArg = aRef->GetValue();
2978 if (anArg.IsNull()) {
2979 SetErrorCode("Null shape is given as argument");
2982 anArgs(argi) = anArg;
2984 // For Python command
2985 TDF_Tool::Entry(anObj->GetEntry(), anEntry);
2986 aPartsDescr += anEntry + ", ";
2992 TopTools_MapOfShape mapShape;
2993 Standard_Integer nbSolids = 0;
2994 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2995 for (; exp.More(); exp.Next()) {
2996 if (mapShape.Add(exp.Current())) {
3002 Standard_Integer ind = 1;
3003 TopTools_Array1OfShape aSolids (1, nbSolids);
3004 TColStd_Array1OfInteger aNbParts (1, nbSolids);
3005 for (exp.Init(aBlockOrComp, TopAbs_SOLID); exp.More(); exp.Next(), ind++) {
3006 if (mapShape.Add(exp.Current())) {
3007 TopoDS_Shape aSolid = exp.Current();
3008 aSolids(ind) = aSolid;
3011 // 2. Define quantity of parts, contained in each solid
3012 TopTools_IndexedMapOfShape aSubShapes;
3013 TopExp::MapShapes(aSolid, aSubShapes);
3014 for (argi = 1; argi <= aLen; argi++) {
3015 if (aSubShapes.Contains(anArgs(argi))) {
3022 // 3. Define solid, containing maximum quantity of parts
3023 Standard_Integer maxNb = 0, nbFound = 0;
3024 for (ind = 1; ind <= nbSolids; ind++) {
3025 if (aNbParts(ind) > maxNb) {
3026 maxNb = aNbParts(ind);
3028 } else if (aNbParts(ind) == maxNb) {
3034 SetErrorCode("There are no blocks, containing the given parts");
3039 TopTools_IndexedMapOfShape anIndices;
3040 TopExp::MapShapes(aBlockOrComp, anIndices);
3041 Handle(TColStd_HArray1OfInteger) anArray;
3043 for (ind = 1; ind <= nbSolids; ind++) {
3044 if (aNbParts(ind) == maxNb) {
3045 anArray = new TColStd_HArray1OfInteger(1,1);
3046 anArray->SetValue(1, anIndices.FindIndex(aSolids(ind)));
3047 anObj = GetEngine()->AddSubShape(theCompound, anArray);
3048 aBlocks->Append(anObj);
3050 // For Python command
3051 TDF_Tool::Entry(anObj->GetEntry(), anEntry);
3052 anAsciiList += anEntry + ", ";
3053 if (aFunction.IsNull())
3054 aFunction = anObj->GetLastFunction();
3058 catch (Standard_Failure) {
3059 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
3060 SetErrorCode(aFail->GetMessageString());
3064 //Make a Python command
3065 aPartsDescr.Trunc(aPartsDescr.Length() - 2);
3066 anAsciiList.Trunc(anAsciiList.Length() - 2);
3068 GEOM::TPythonDump(aFunction) << "[" << anAsciiList.ToCString()
3069 << "] = geompy.GetBlocksByParts(" << theCompound
3070 << ", [" << aPartsDescr.ToCString() << "])";
3076 //=============================================================================
3078 * MakeMultiTransformation1D
3080 //=============================================================================
3081 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeMultiTransformation1D
3082 (Handle(GEOM_Object) theObject,
3083 const Standard_Integer theDirFace1,
3084 const Standard_Integer theDirFace2,
3085 const Standard_Integer theNbTimes)
3089 if (theObject.IsNull()) return NULL;
3091 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
3092 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be moved
3094 //Add a new Copy object
3095 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
3097 //Add a translate function
3098 Handle(GEOM_Function) aFunction =
3099 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_MULTI_TRANSFORM_1D);
3101 //Check if the function is set correctly
3102 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
3104 GEOMImpl_IBlockTrsf aTI (aFunction);
3105 aTI.SetOriginal(aLastFunction);
3106 aTI.SetFace1U(theDirFace1);
3107 aTI.SetFace2U(theDirFace2);
3108 aTI.SetNbIterU(theNbTimes);
3110 //Compute the transformation
3113 if (!GetSolver()->ComputeFunction(aFunction)) {
3114 SetErrorCode("Block driver failed to make multi-transformation");
3118 catch (Standard_Failure) {
3119 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
3120 SetErrorCode(aFail->GetMessageString());
3124 //Make a Python command
3125 GEOM::TPythonDump(aFunction) << aCopy << " = geompy.MakeMultiTransformation1D("
3126 << theObject << ", " << theDirFace1 << ", " << theDirFace2 << ", " << theNbTimes << ")";
3132 //=============================================================================
3134 * MakeMultiTransformation2D
3136 //=============================================================================
3137 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeMultiTransformation2D
3138 (Handle(GEOM_Object) theObject,
3139 const Standard_Integer theDirFace1U,
3140 const Standard_Integer theDirFace2U,
3141 const Standard_Integer theNbTimesU,
3142 const Standard_Integer theDirFace1V,
3143 const Standard_Integer theDirFace2V,
3144 const Standard_Integer theNbTimesV)
3148 if (theObject.IsNull()) return NULL;
3150 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
3151 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be moved
3153 //Add a new Copy object
3154 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
3156 //Add a translate function
3157 Handle(GEOM_Function) aFunction =
3158 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_MULTI_TRANSFORM_2D);
3160 //Check if the function is set correctly
3161 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
3163 GEOMImpl_IBlockTrsf aTI (aFunction);
3164 aTI.SetOriginal(aLastFunction);
3165 aTI.SetFace1U(theDirFace1U);
3166 aTI.SetFace2U(theDirFace2U);
3167 aTI.SetNbIterU(theNbTimesU);
3168 aTI.SetFace1V(theDirFace1V);
3169 aTI.SetFace2V(theDirFace2V);
3170 aTI.SetNbIterV(theNbTimesV);
3172 //Compute the transformation
3175 if (!GetSolver()->ComputeFunction(aFunction)) {
3176 SetErrorCode("Block driver failed to make multi-transformation");
3180 catch (Standard_Failure) {
3181 Handle(Standard_Failure) aFail = Standard_Failure::Caught();
3182 SetErrorCode(aFail->GetMessageString());
3186 //Make a Python command
3187 GEOM::TPythonDump(aFunction) << aCopy << " = geompy.MakeMultiTransformation2D("
3188 << theObject << ", " << theDirFace1U << ", " << theDirFace2U << ", " << theNbTimesU
3189 << ", " << theDirFace1V << ", " << theDirFace2V << ", " << theNbTimesV << ")";
3195 //=============================================================================
3199 //=============================================================================
3200 Handle(TColStd_HSequenceOfTransient) GEOMImpl_IBlocksOperations::Propagate
3201 (Handle(GEOM_Object) theShape)
3205 if (theShape.IsNull()) return NULL;
3207 TopoDS_Shape aShape = theShape->GetValue();
3208 if (aShape.IsNull()) return NULL;
3210 TopTools_IndexedMapOfShape anIndices;
3211 TopExp::MapShapes(aShape, anIndices);
3213 TopTools_IndexedDataMapOfShapeListOfShape MEW;
3214 GEOMImpl_Block6Explorer::MapShapesAndAncestors
3215 (aShape, TopAbs_EDGE, TopAbs_WIRE, MEW);
3216 Standard_Integer ie, nbEdges = MEW.Extent();
3219 Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
3221 TopTools_MapOfShape mapAcceptedEdges;
3222 TCollection_AsciiString aListRes, anEntry;
3224 // Sort shapes in current chain (Mantis issue 21053)
3225 TopTools_DataMapOfShapeListOfShape aMapChains;
3226 TopTools_ListOfShape aFirstInChains;
3228 for (ie = 1; ie <= nbEdges; ie++) {
3229 TopoDS_Shape curE = MEW.FindKey(ie);
3231 if (mapAcceptedEdges.Contains(curE)) continue;
3234 TopTools_ListOfShape currentChain;
3235 TopTools_ListOfShape listPrevEdges;
3237 currentChain.Append(curE);
3238 listPrevEdges.Append(curE);
3239 mapAcceptedEdges.Add(curE);
3241 // Collect all edges pass by pass
3242 while (listPrevEdges.Extent() > 0) {
3243 // List of edges, added to chain on this cycle pass
3244 TopTools_ListOfShape listCurEdges;
3246 // Find the next portion of edges
3247 TopTools_ListIteratorOfListOfShape itE (listPrevEdges);
3248 for (; itE.More(); itE.Next()) {
3249 TopoDS_Shape anE = itE.Value();
3251 // Iterate on faces, having edge <anE>
3252 TopTools_ListIteratorOfListOfShape itW (MEW.FindFromKey(anE));
3253 for (; itW.More(); itW.Next()) {
3254 TopoDS_Shape aW = itW.Value();
3255 TopoDS_Shape anOppE;
3257 BRepTools_WireExplorer aWE (TopoDS::Wire(aW));
3258 Standard_Integer nb = 1, found = 0;
3259 TopTools_Array1OfShape anEdges (1,4);
3260 for (; aWE.More(); aWE.Next(), nb++) {
3265 anEdges(nb) = aWE.Current();
3266 if (anEdges(nb).IsSame(anE)) found = nb;
3269 if (nb == 5 && found > 0) {
3270 // Quadrangle face found, get an opposite edge
3271 Standard_Integer opp = found + 2;
3272 if (opp > 4) opp -= 4;
3273 anOppE = anEdges(opp);
3275 if (!mapAcceptedEdges.Contains(anOppE)) {
3276 // Add found edge to the chain
3277 currentChain.Append(anOppE);
3278 listCurEdges.Append(anOppE);
3279 mapAcceptedEdges.Add(anOppE);
3281 } // if (nb == 5 && found > 0)
3282 } // for (; itF.More(); itF.Next())
3283 } // for (; itE.More(); itE.Next())
3285 listPrevEdges = listCurEdges;
3286 } // while (listPrevEdges.Extent() > 0)
3288 // Sort shapes in current chain (Mantis issue 21053)
3289 GEOMUtils::SortShapes(currentChain, Standard_False);
3290 aFirstInChains.Append(currentChain.First());
3291 aMapChains.Bind(currentChain.First(), currentChain);
3294 // Sort chains (Mantis issue 21053)
3295 GEOMUtils::SortShapes(aFirstInChains, Standard_False);
3297 // Store sorted chains in the document
3298 TopTools_ListIteratorOfListOfShape aChainsIt (aFirstInChains);
3299 for (; aChainsIt.More(); aChainsIt.Next()) {
3300 TopoDS_Shape aFirstInChain = aChainsIt.Value();
3301 const TopTools_ListOfShape& currentChain = aMapChains.Find(aFirstInChain);
3303 // Store the chain in the document
3304 Handle(TColStd_HArray1OfInteger) anArray =
3305 new TColStd_HArray1OfInteger (1, currentChain.Extent());
3307 // Fill array of sub-shape indices
3308 TopTools_ListIteratorOfListOfShape itSub (currentChain);
3309 for (int index = 1; itSub.More(); itSub.Next(), ++index) {
3310 int id = anIndices.FindIndex(itSub.Value());
3311 anArray->SetValue(index, id);
3314 // Add a new group object
3315 Handle(GEOM_Object) aChain = GetEngine()->AddSubShape(theShape, anArray);
3318 aChain->SetType(GEOM_GROUP);
3320 // Set a sub-shape type
3321 TDF_Label aFreeLabel = aChain->GetFreeLabel();
3322 TDataStd_Integer::Set(aFreeLabel, (Standard_Integer)TopAbs_EDGE);
3324 // Add the chain to the result
3325 aSeq->Append(aChain);
3327 //Make a Python command
3328 TDF_Tool::Entry(aChain->GetEntry(), anEntry);
3329 aListRes += anEntry + ", ";
3332 if (aSeq->IsEmpty()) {
3333 SetErrorCode("There are no quadrangle faces in the shape");
3337 aListRes.Trunc(aListRes.Length() - 2);
3339 // The Propagation doesn't change object so no new function is required.
3340 Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
3342 // Make a Python command
3343 GEOM::TPythonDump(aFunction, /*append=*/true)
3344 << "[" << aListRes.ToCString() << "] = geompy.Propagate(" << theShape << ")";