1 // Copyright (C) 2007-2020 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 "utilities.h"
51 #include <Utils_ExceptHandlers.hxx>
53 #include <TFunction_DriverTable.hxx>
54 #include <TFunction_Driver.hxx>
55 #include <TDataStd_Integer.hxx>
56 #include <TDF_Tool.hxx>
58 #include <BRep_Tool.hxx>
59 #include <BRep_Builder.hxx>
60 #include <BRepTools.hxx>
61 #include <BRepTools_WireExplorer.hxx>
62 #include <BRepGProp.hxx>
63 #include <BRepBndLib.hxx>
64 #include <BRepAdaptor_Surface.hxx>
65 #include <BRepClass_FaceClassifier.hxx>
66 #include <BRepClass3d_SolidClassifier.hxx>
67 #include <BRepExtrema_DistShapeShape.hxx>
71 #include <TopoDS_Edge.hxx>
72 #include <TopoDS_Vertex.hxx>
73 #include <TopoDS_Compound.hxx>
74 #include <TopoDS_Iterator.hxx>
76 #include <TopExp_Explorer.hxx>
77 #include <TopTools_MapOfShape.hxx>
78 #include <TopTools_Array1OfShape.hxx>
79 #include <TopTools_IndexedMapOfShape.hxx>
80 #include <TopTools_DataMapOfShapeInteger.hxx>
81 #include <TopTools_ListIteratorOfListOfShape.hxx>
82 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
83 #include <TopTools_DataMapIteratorOfDataMapOfShapeInteger.hxx>
85 #include <Bnd_Box.hxx>
86 #include <GProp_GProps.hxx>
88 #include <Geom_Curve.hxx>
89 #include <Geom_Surface.hxx>
90 #include <ShapeAnalysis_Surface.hxx>
92 #include <TColStd_MapOfInteger.hxx>
93 #include <TColStd_Array1OfReal.hxx>
94 #include <TColStd_Array1OfInteger.hxx>
95 #include <TColStd_Array2OfInteger.hxx>
97 //#include <OSD_Timer.hxx>
99 #include <Precision.hxx>
101 #include <Standard_Failure.hxx>
102 #include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC
106 * This function returns Standard_True if the face is quadrangular. It means
107 * that it has only 1 wire with 4 edges. If there are more then 4 edges in
108 * the wire and theToleranceC1 is not negative the new implementation is used.
109 * According to it the face is quadrangular if it is quadrangular according to
110 * an old implementation or if it has a single wire with more then 4 edges
111 * that form exactly 4 bounds of C1 continuity with the given tolerance.
113 * \param theFace the face to be checked
114 * \param theToleranceC1 if negative, it is not used; otherwise it is used
115 * to check if two neighbor edges of face have C1 continuity.
116 * \return Standard_True if the face is quadrangular; Standard_False otherwise.
118 static Standard_Boolean IsQuadrangle(const TopoDS_Face &theFace,
119 const Standard_Real theToleranceC1)
121 TopExp_Explorer aFExp (theFace, TopAbs_WIRE);
124 // no wire in the face
125 return Standard_False;
128 TopoDS_Shape aWire = aFExp.Current();
133 // multiple wires in the face
134 return Standard_False;
137 // Check number of edges in the face
138 Standard_Integer aNbEdges = 0;
139 TopTools_MapOfShape aMapEdges;
140 TopExp_Explorer aWExp(aWire, TopAbs_EDGE);
142 for (; aWExp.More(); aWExp.Next()) {
143 if (aMapEdges.Add(aWExp.Current())) {
153 return Standard_False;
157 if (theToleranceC1 < 0.) {
158 return Standard_False;
161 // Check if a wire has 4 bounds of C1 continuity.
162 BRepTools_WireExplorer aWireExp(TopoDS::Wire(aWire), theFace);
163 TopTools_ListOfShape anEdges;
165 for (aNbEdges = 0; aWireExp.More(); aWireExp.Next()) {
166 const TopoDS_Edge &anEdge = aWireExp.Current();
168 // Skip degenerated edges.
169 if (!BRep_Tool::Degenerated(anEdge)) {
170 anEdges.Append(anEdge);
176 return Standard_False;
179 // Compute number of sharp corners.
180 anEdges.Append(anEdges.First()); // To make a loop.
182 TopTools_ListIteratorOfListOfShape anIter(anEdges);
183 Standard_Real aPar[2];
184 Standard_Integer aNbCorners = 0;
185 TopoDS_Edge anEdge1 = TopoDS::Edge(anEdges.First());
186 Handle(Geom_Curve) aCurve1 = BRep_Tool::Curve(anEdge1, aPar[0], aPar[1]);
187 Handle(Geom_Curve) aCurve2;
189 TopoDS_Vertex aCommonVtx;
193 Standard_Boolean isReversed1 = (anEdge1.Orientation() == TopAbs_REVERSED);
194 Standard_Boolean isReversed2;
196 for (anIter.Next(); anIter.More(); anIter.Next()) {
197 TopoDS_Edge anEdge2 = TopoDS::Edge(anIter.Value());
199 if (!TopExp::CommonVertex(anEdge1, anEdge2, aCommonVtx)) {
201 return Standard_False;
204 // Check the angle between tangent vectors of 2 curves at this point.
205 Standard_Real aParam1 = BRep_Tool::Parameter(aCommonVtx, anEdge1);
206 Standard_Real aParam2 = BRep_Tool::Parameter(aCommonVtx, anEdge2);
208 aCurve2 = BRep_Tool::Curve(anEdge2, aPar[0], aPar[1]);
209 isReversed2 = (anEdge2.Orientation() == TopAbs_REVERSED);
210 aCurve1->D1(aParam1, aPnt, aVec1);
211 aCurve2->D1(aParam2, aPnt, aVec2);
220 const Standard_Real anAngle = aVec1.Angle(aVec2);
222 if (anAngle > theToleranceC1) {
225 if (aNbCorners > 4) {
230 // Go to the next couple of edges.
233 isReversed1 = isReversed2;
236 // Check the total number of corners.
237 if (aNbCorners != 4) {
238 return Standard_False;
242 return Standard_True;
245 //=============================================================================
249 //=============================================================================
250 GEOMImpl_IBlocksOperations::GEOMImpl_IBlocksOperations (GEOM_Engine* theEngine)
251 : GEOM_IOperations(theEngine)
253 MESSAGE("GEOMImpl_IBlocksOperations::GEOMImpl_IBlocksOperations");
256 //=============================================================================
260 //=============================================================================
261 GEOMImpl_IBlocksOperations::~GEOMImpl_IBlocksOperations()
263 MESSAGE("GEOMImpl_IBlocksOperations::~GEOMImpl_IBlocksOperations");
267 //=============================================================================
271 //=============================================================================
272 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuad
273 (Handle(GEOM_Object) theEdge1, Handle(GEOM_Object) theEdge2,
274 Handle(GEOM_Object) theEdge3, Handle(GEOM_Object) theEdge4)
278 if (theEdge1.IsNull() || theEdge2.IsNull() ||
279 theEdge3.IsNull() || theEdge4.IsNull()) return NULL;
281 //Add a new Face object
282 Handle(GEOM_Object) aFace = GetEngine()->AddObject(GEOM_FACE);
284 //Add a new Face function
285 Handle(GEOM_Function) aFunction =
286 aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_FOUR_EDGES);
288 //Check if the function is set correctly
289 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
291 GEOMImpl_IBlocks aPI (aFunction);
293 Handle(GEOM_Function) aRef1 = theEdge1->GetLastFunction();
294 Handle(GEOM_Function) aRef2 = theEdge2->GetLastFunction();
295 Handle(GEOM_Function) aRef3 = theEdge3->GetLastFunction();
296 Handle(GEOM_Function) aRef4 = theEdge4->GetLastFunction();
297 if (aRef1.IsNull() || aRef2.IsNull() ||
298 aRef3.IsNull() || aRef4.IsNull()) return NULL;
300 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
301 aShapesSeq->Append(aRef1);
302 aShapesSeq->Append(aRef2);
303 aShapesSeq->Append(aRef3);
304 aShapesSeq->Append(aRef4);
306 aPI.SetShapes(aShapesSeq);
308 //Compute the Face value
311 if (!GetSolver()->ComputeFunction(aFunction)) {
312 SetErrorCode("Block driver failed to compute a face");
316 catch (Standard_Failure& aFail) {
317 SetErrorCode(aFail.GetMessageString());
321 //Make a Python command
322 GEOM::TPythonDump(aFunction) << aFace << " = geompy.MakeQuad("
323 << theEdge1 << ", " << theEdge2 << ", " << theEdge3 << ", " << theEdge4 << ")";
329 //=============================================================================
333 //=============================================================================
334 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuad2Edges
335 (Handle(GEOM_Object) theEdge1, Handle(GEOM_Object) theEdge2)
339 if (theEdge1.IsNull() || theEdge2.IsNull()) return NULL;
341 //Add a new Face object
342 Handle(GEOM_Object) aFace = GetEngine()->AddObject(GEOM_FACE);
344 //Add a new Face function
345 Handle(GEOM_Function) aFunction =
346 aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_TWO_EDGES);
348 //Check if the function is set correctly
349 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
351 GEOMImpl_IBlocks aPI (aFunction);
353 Handle(GEOM_Function) aRef1 = theEdge1->GetLastFunction();
354 Handle(GEOM_Function) aRef2 = theEdge2->GetLastFunction();
355 if (aRef1.IsNull() || aRef2.IsNull()) return NULL;
357 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
358 aShapesSeq->Append(aRef1);
359 aShapesSeq->Append(aRef2);
361 aPI.SetShapes(aShapesSeq);
363 //Compute the Face value
366 if (!GetSolver()->ComputeFunction(aFunction)) {
367 SetErrorCode("Block driver failed to compute a face");
371 catch (Standard_Failure& aFail) {
372 SetErrorCode(aFail.GetMessageString());
376 //Make a Python command
377 GEOM::TPythonDump(aFunction) << aFace << " = geompy.MakeQuad2Edges("
378 << theEdge1 << ", " << theEdge2 << ")";
384 //=============================================================================
388 //=============================================================================
389 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuad4Vertices
390 (Handle(GEOM_Object) thePnt1, Handle(GEOM_Object) thePnt2,
391 Handle(GEOM_Object) thePnt3, Handle(GEOM_Object) thePnt4)
395 if (thePnt1.IsNull() || thePnt2.IsNull() ||
396 thePnt3.IsNull() || thePnt4.IsNull()) return NULL;
398 //Add a new Face object
399 Handle(GEOM_Object) aFace = GetEngine()->AddObject(GEOM_FACE);
401 //Add a new Face function
402 Handle(GEOM_Function) aFunction =
403 aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_FOUR_PNT);
405 //Check if the function is set correctly
406 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
408 GEOMImpl_IBlocks aPI (aFunction);
410 Handle(GEOM_Function) aRef1 = thePnt1->GetLastFunction();
411 Handle(GEOM_Function) aRef2 = thePnt2->GetLastFunction();
412 Handle(GEOM_Function) aRef3 = thePnt3->GetLastFunction();
413 Handle(GEOM_Function) aRef4 = thePnt4->GetLastFunction();
414 if (aRef1.IsNull() || aRef2.IsNull() ||
415 aRef3.IsNull() || aRef4.IsNull()) return NULL;
417 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
418 aShapesSeq->Append(aRef1);
419 aShapesSeq->Append(aRef2);
420 aShapesSeq->Append(aRef3);
421 aShapesSeq->Append(aRef4);
423 aPI.SetShapes(aShapesSeq);
425 //Compute the Face value
428 if (!GetSolver()->ComputeFunction(aFunction)) {
429 SetErrorCode("Block driver failed to compute a face");
433 catch (Standard_Failure& aFail) {
434 SetErrorCode(aFail.GetMessageString());
438 //Make a Python command
439 GEOM::TPythonDump(aFunction) << aFace << " = geompy.MakeQuad4Vertices("
440 << thePnt1 << ", " << thePnt2 << ", " << thePnt3 << ", " << thePnt4 << ")";
446 //=============================================================================
450 //=============================================================================
451 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeHexa
452 (Handle(GEOM_Object) theFace1, Handle(GEOM_Object) theFace2,
453 Handle(GEOM_Object) theFace3, Handle(GEOM_Object) theFace4,
454 Handle(GEOM_Object) theFace5, Handle(GEOM_Object) theFace6)
458 if (theFace1.IsNull() || theFace2.IsNull() ||
459 theFace3.IsNull() || theFace4.IsNull() ||
460 theFace5.IsNull() || theFace6.IsNull()) return NULL;
462 //Add a new Solid object
463 Handle(GEOM_Object) aBlock = GetEngine()->AddObject(GEOM_BLOCK);
465 //Add a new Block function
466 Handle(GEOM_Function) aFunction =
467 aBlock->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_SIX_FACES);
469 //Check if the function is set correctly
470 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
472 GEOMImpl_IBlocks aPI (aFunction);
474 Handle(GEOM_Function) aRef1 = theFace1->GetLastFunction();
475 Handle(GEOM_Function) aRef2 = theFace2->GetLastFunction();
476 Handle(GEOM_Function) aRef3 = theFace3->GetLastFunction();
477 Handle(GEOM_Function) aRef4 = theFace4->GetLastFunction();
478 Handle(GEOM_Function) aRef5 = theFace5->GetLastFunction();
479 Handle(GEOM_Function) aRef6 = theFace6->GetLastFunction();
480 if (aRef1.IsNull() || aRef2.IsNull() ||
481 aRef3.IsNull() || aRef4.IsNull() ||
482 aRef5.IsNull() || aRef6.IsNull()) return NULL;
484 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
485 aShapesSeq->Append(aRef1);
486 aShapesSeq->Append(aRef2);
487 aShapesSeq->Append(aRef3);
488 aShapesSeq->Append(aRef4);
489 aShapesSeq->Append(aRef5);
490 aShapesSeq->Append(aRef6);
492 aPI.SetShapes(aShapesSeq);
494 //Compute the Block value
497 if (!GetSolver()->ComputeFunction(aFunction)) {
498 SetErrorCode("Block driver failed to compute a block");
502 catch (Standard_Failure& aFail) {
503 SetErrorCode(aFail.GetMessageString());
507 //Make a Python command
508 GEOM::TPythonDump(aFunction) << aBlock << " = geompy.MakeHexa("
509 << theFace1 << ", " << theFace2 << ", " << theFace3 << ", "
510 << theFace4 << ", " << theFace5 << ", " << theFace6 << ")";
516 //=============================================================================
520 //=============================================================================
521 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeHexa2Faces
522 (Handle(GEOM_Object) theFace1, Handle(GEOM_Object) theFace2)
526 if (theFace1.IsNull() || theFace2.IsNull()) return NULL;
528 //Add a new Solid object
529 Handle(GEOM_Object) aBlock = GetEngine()->AddObject(GEOM_BLOCK);
531 //Add a new Block function
532 Handle(GEOM_Function) aFunction =
533 aBlock->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_TWO_FACES);
535 //Check if the function is set correctly
536 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
538 GEOMImpl_IBlocks aPI (aFunction);
540 Handle(GEOM_Function) aRef1 = theFace1->GetLastFunction();
541 Handle(GEOM_Function) aRef2 = theFace2->GetLastFunction();
542 if (aRef1.IsNull() || aRef2.IsNull()) return NULL;
544 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
545 aShapesSeq->Append(aRef1);
546 aShapesSeq->Append(aRef2);
548 aPI.SetShapes(aShapesSeq);
550 //Compute the Block value
553 if (!GetSolver()->ComputeFunction(aFunction)) {
554 SetErrorCode("Block driver failed to compute a block");
558 catch (Standard_Failure& aFail) {
559 SetErrorCode(aFail.GetMessageString());
563 //Make a Python command
564 GEOM::TPythonDump(aFunction) << aBlock << " = geompy.MakeHexa2Faces("
565 << theFace1 << ", " << theFace2 << ")";
571 //=============================================================================
575 //=============================================================================
576 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeBlockCompound
577 (Handle(GEOM_Object) theCompound)
581 if (theCompound.IsNull()) return NULL;
584 Handle(GEOM_Object) aBlockComp = GetEngine()->AddObject(GEOM_COMPOUND);
586 //Add a new BlocksComp function
587 Handle(GEOM_Function) aFunction =
588 aBlockComp->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_COMPOUND_GLUE);
590 //Check if the function is set correctly
591 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
593 GEOMImpl_IBlocks aPI (aFunction);
595 Handle(GEOM_Function) aRef1 = theCompound->GetLastFunction();
596 if (aRef1.IsNull()) return NULL;
598 Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
599 aShapesSeq->Append(aRef1);
601 aPI.SetShapes(aShapesSeq);
603 //Compute the Blocks Compound value
606 if (!GetSolver()->ComputeFunction(aFunction)) {
607 SetErrorCode("Block driver failed to compute a blocks compound");
611 catch (Standard_Failure& aFail) {
612 SetErrorCode(aFail.GetMessageString());
616 //Make a Python command
617 GEOM::TPythonDump(aFunction) << aBlockComp
618 << " = geompy.MakeBlockCompound(" << theCompound << ")";
624 //=============================================================================
628 //=============================================================================
629 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetPoint
630 (Handle(GEOM_Object) theShape,
631 const Standard_Real theX,
632 const Standard_Real theY,
633 const Standard_Real theZ,
634 const Standard_Real theEpsilon)
639 Handle(GEOM_Object) aResult;
642 if (theShape.IsNull()) return NULL;
644 TopoDS_Shape aBlockOrComp = theShape->GetValue();
645 if (aBlockOrComp.IsNull()) {
646 SetErrorCode("Given shape is null");
650 //Compute the Vertex value
651 gp_Pnt P (theX, theY, theZ);
652 Standard_Real eps = Max(theEpsilon, Precision::Confusion());
655 Standard_Integer isFound = 0;
656 TopTools_MapOfShape mapShape;
657 TopExp_Explorer exp (aBlockOrComp, TopAbs_VERTEX);
659 for (; exp.More(); exp.Next()) {
660 if (mapShape.Add(exp.Current())) {
661 TopoDS_Vertex aVi = TopoDS::Vertex(exp.Current());
662 gp_Pnt aPi = BRep_Tool::Pnt(aVi);
663 if (aPi.Distance(P) < eps) {
671 SetErrorCode("Vertex has not been found");
673 } else if (isFound > 1) {
674 SetErrorCode("Multiple vertices found by the given coordinates and epsilon");
677 TopTools_IndexedMapOfShape anIndices;
678 TopExp::MapShapes(aBlockOrComp, anIndices);
679 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
680 anArray->SetValue(1, anIndices.FindIndex(V));
681 aResult = GetEngine()->AddSubShape(theShape, anArray);
684 //The GetPoint() doesn't change object so no new function is required.
685 Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
687 //Make a Python command
688 GEOM::TPythonDump(aFunction, /*append=*/true)
689 << aResult << " = geompy.GetPoint(" << theShape << ", "
690 << theX << ", " << theY << ", " << theZ << ", " << theEpsilon << ")";
696 //=============================================================================
700 //=============================================================================
701 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetVertexNearPoint
702 (Handle(GEOM_Object) theShape,
703 Handle(GEOM_Object) thePoint)
708 Handle(GEOM_Object) aResult;
711 if (theShape.IsNull() || thePoint.IsNull()) return NULL;
713 TopoDS_Shape aBlockOrComp = theShape->GetValue();
714 TopoDS_Shape aPoint = thePoint->GetValue();
715 if (aBlockOrComp.IsNull() || aPoint.IsNull()) {
716 SetErrorCode("Given shape is null");
720 if (aPoint.ShapeType() != TopAbs_VERTEX) {
721 SetErrorCode("Element for vertex identification is not a vertex");
725 TopoDS_Vertex aVert = TopoDS::Vertex(aPoint);
726 gp_Pnt aP = BRep_Tool::Pnt(aVert);
728 // Compute the Vertex value
730 bool isFound = false;
731 Standard_Real aDist = RealLast();
732 TopTools_MapOfShape mapShape;
734 TopExp_Explorer exp (aBlockOrComp, TopAbs_VERTEX);
735 for (; exp.More(); exp.Next()) {
736 if (mapShape.Add(exp.Current())) {
737 TopoDS_Vertex aVi = TopoDS::Vertex(exp.Current());
738 gp_Pnt aPi = BRep_Tool::Pnt(aVi);
739 Standard_Real aDisti = aPi.Distance(aP);
740 if (aDisti < aDist) {
749 SetErrorCode("Vertex has not been found");
753 TopTools_IndexedMapOfShape anIndices;
754 TopExp::MapShapes(aBlockOrComp, anIndices);
755 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
756 anArray->SetValue(1, anIndices.FindIndex(V));
757 aResult = GetEngine()->AddSubShape(theShape, anArray);
759 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
761 // Make a Python command
762 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetVertexNearPoint("
763 << theShape << ", " << thePoint << ")";
769 //=============================================================================
773 //=============================================================================
774 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetEdge
775 (Handle(GEOM_Object) theShape,
776 Handle(GEOM_Object) thePoint1,
777 Handle(GEOM_Object) thePoint2)
782 Handle(GEOM_Object) aResult;
785 if (theShape.IsNull() || thePoint1.IsNull() || thePoint2.IsNull()) return NULL;
787 TopoDS_Shape aBlockOrComp = theShape->GetValue();
788 if (aBlockOrComp.IsNull()) {
789 SetErrorCode("Given shape is null");
793 TopoDS_Shape anArg1 = thePoint1->GetValue();
794 TopoDS_Shape anArg2 = thePoint2->GetValue();
795 if (anArg1.IsNull() || anArg2.IsNull()) {
796 SetErrorCode("Null shape is given as argument");
799 if (anArg1.ShapeType() != TopAbs_VERTEX ||
800 anArg2.ShapeType() != TopAbs_VERTEX) {
801 SetErrorCode("Element for edge identification is not a vertex");
805 //Compute the Edge value
808 TopTools_IndexedDataMapOfShapeListOfShape MVE;
809 GEOMImpl_Block6Explorer::MapShapesAndAncestors
810 (aBlockOrComp, TopAbs_VERTEX, TopAbs_EDGE, MVE);
813 Standard_Integer ish, ext = MVE.Extent();
815 if (MVE.Contains(anArg1)) {
818 for (ish = 1; ish <= ext; ish++) {
819 TopoDS_Shape aShi = MVE.FindKey(ish);
820 if (BRepTools::Compare(TopoDS::Vertex(anArg1), TopoDS::Vertex(aShi))) {
827 if (MVE.Contains(anArg2)) {
830 for (ish = 1; ish <= ext; ish++) {
831 TopoDS_Shape aShi = MVE.FindKey(ish);
832 if (BRepTools::Compare(TopoDS::Vertex(anArg2), TopoDS::Vertex(aShi))) {
839 if (V1.IsNull() || V2.IsNull()) {
840 SetErrorCode("The given vertex does not belong to the shape");
845 Standard_Integer isFound =
846 GEOMImpl_Block6Explorer::FindEdge(anEdge, V1, V2, MVE, Standard_True);
848 SetErrorCode("The given vertices do not belong to one edge of the given shape");
850 } else if (isFound > 1) {
851 SetErrorCode("Multiple edges found by the given vertices of the shape");
854 TopTools_IndexedMapOfShape anIndices;
855 TopExp::MapShapes(aBlockOrComp, anIndices);
856 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
857 anArray->SetValue(1, anIndices.FindIndex(anEdge));
858 aResult = GetEngine()->AddSubShape(theShape, anArray);
860 } catch (Standard_Failure& aFail) {
861 SetErrorCode(aFail.GetMessageString());
865 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
867 //Make a Python command
868 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetEdge("
869 << theShape << ", " << thePoint1 << ", " << thePoint2 << ")";
875 //=============================================================================
879 //=============================================================================
880 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetEdgeNearPoint
881 (Handle(GEOM_Object) theShape,
882 Handle(GEOM_Object) thePoint)
887 Handle(GEOM_Object) aResult;
890 if (theShape.IsNull() || thePoint.IsNull()) return NULL;
892 TopoDS_Shape aBlockOrComp = theShape->GetValue();
893 if (aBlockOrComp.IsNull()) {
894 SetErrorCode("Given shape is null");
898 TopoDS_Shape anArg = thePoint->GetValue();
899 if (anArg.IsNull()) {
900 SetErrorCode("Null shape is given as argument");
903 if (anArg.ShapeType() != TopAbs_VERTEX) {
904 SetErrorCode("Element for edge identification is not a vertex");
908 //Compute the Edge value
911 TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
912 TopoDS_Shape aShape = GEOMUtils::GetEdgeNearPoint(aBlockOrComp, aVert);
914 TopTools_IndexedMapOfShape anIndices;
915 TopExp::MapShapes(aBlockOrComp, anIndices);
916 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
917 anArray->SetValue(1, anIndices.FindIndex(aShape));
918 aResult = GetEngine()->AddSubShape(theShape, anArray);
920 catch (Standard_Failure& aFail) {
921 SetErrorCode(aFail.GetMessageString());
925 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
927 //Make a Python command
928 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetEdgeNearPoint("
929 << theShape << ", " << thePoint << ")";
935 //=============================================================================
939 //=============================================================================
940 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByPoints
941 (Handle(GEOM_Object) theShape,
942 Handle(GEOM_Object) thePoint1,
943 Handle(GEOM_Object) thePoint2,
944 Handle(GEOM_Object) thePoint3,
945 Handle(GEOM_Object) thePoint4)
950 Handle(GEOM_Object) aResult;
953 if (theShape.IsNull() ||
954 thePoint1.IsNull() || thePoint2.IsNull() ||
955 thePoint3.IsNull() || thePoint4.IsNull()) return NULL;
957 TopoDS_Shape aBlockOrComp = theShape->GetValue();
958 if (aBlockOrComp.IsNull()) {
959 SetErrorCode("Block or compound is null");
963 TopoDS_Shape anArg1 = thePoint1->GetValue();
964 TopoDS_Shape anArg2 = thePoint2->GetValue();
965 TopoDS_Shape anArg3 = thePoint3->GetValue();
966 TopoDS_Shape anArg4 = thePoint4->GetValue();
967 if (anArg1.IsNull() || anArg2.IsNull() ||
968 anArg3.IsNull() || anArg4.IsNull()) {
969 SetErrorCode("Null shape is given as argument");
972 if (anArg1.ShapeType() != TopAbs_VERTEX ||
973 anArg2.ShapeType() != TopAbs_VERTEX ||
974 anArg3.ShapeType() != TopAbs_VERTEX ||
975 anArg4.ShapeType() != TopAbs_VERTEX) {
976 SetErrorCode("Element for face identification is not a vertex");
980 //Compute the Face value
985 TopTools_IndexedDataMapOfShapeListOfShape MVF;
986 GEOMImpl_Block6Explorer::MapShapesAndAncestors(aBlockOrComp, TopAbs_VERTEX, TopAbs_FACE, MVF);
988 TopoDS_Shape V1,V2,V3,V4;
989 Standard_Integer ish, ext = MVF.Extent();
991 if (MVF.Contains(anArg1)) {
994 for (ish = 1; ish <= ext; ish++) {
995 TopoDS_Shape aShi = MVF.FindKey(ish);
996 if (BRepTools::Compare(TopoDS::Vertex(anArg1), TopoDS::Vertex(aShi))) {
1003 if (MVF.Contains(anArg2)) {
1006 for (ish = 1; ish <= ext; ish++) {
1007 TopoDS_Shape aShi = MVF.FindKey(ish);
1008 if (BRepTools::Compare(TopoDS::Vertex(anArg2), TopoDS::Vertex(aShi))) {
1015 if (MVF.Contains(anArg3)) {
1018 for (ish = 1; ish <= ext; ish++) {
1019 TopoDS_Shape aShi = MVF.FindKey(ish);
1020 if (BRepTools::Compare(TopoDS::Vertex(anArg3), TopoDS::Vertex(aShi))) {
1027 if (MVF.Contains(anArg4)) {
1030 for (ish = 1; ish <= ext; ish++) {
1031 TopoDS_Shape aShi = MVF.FindKey(ish);
1032 if (BRepTools::Compare(TopoDS::Vertex(anArg4), TopoDS::Vertex(aShi))) {
1039 if (V1.IsNull() || V2.IsNull() || V3.IsNull() || V4.IsNull()) {
1040 SetErrorCode("The given vertex does not belong to the shape");
1044 Standard_Integer isFound =
1045 GEOMImpl_Block6Explorer::FindFace(aShape, V1, V2, V3, V4, MVF, Standard_True);
1047 SetErrorCode("The given vertices do not belong to one face of the given shape");
1049 } else if (isFound > 1) {
1050 SetErrorCode("The given vertices belong to several faces of the given shape");
1053 TopTools_IndexedMapOfShape anIndices;
1054 TopExp::MapShapes(aBlockOrComp, anIndices);
1055 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1056 anArray->SetValue(1, anIndices.FindIndex(aShape));
1057 aResult = GetEngine()->AddSubShape(theShape, anArray);
1060 catch (Standard_Failure& aFail) {
1061 SetErrorCode(aFail.GetMessageString());
1065 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1067 //Make a Python command
1068 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceByPoints("
1069 << theShape << ", " << thePoint1 << ", " << thePoint2
1070 << ", " << thePoint3 << ", " << thePoint4 << ")";
1076 //=============================================================================
1080 //=============================================================================
1081 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByEdges
1082 (Handle(GEOM_Object) theShape,
1083 Handle(GEOM_Object) theEdge1,
1084 Handle(GEOM_Object) theEdge2)
1089 Handle(GEOM_Object) aResult;
1092 if (theShape.IsNull() || theEdge1.IsNull() || theEdge2.IsNull()) return NULL;
1094 TopoDS_Shape aBlockOrComp = theShape->GetValue();
1095 if (aBlockOrComp.IsNull()) {
1096 SetErrorCode("Block or compound is null");
1100 TopoDS_Shape anArg1 = theEdge1->GetValue();
1101 TopoDS_Shape anArg2 = theEdge2->GetValue();
1102 if (anArg1.IsNull() || anArg2.IsNull()) {
1103 SetErrorCode("Null shape is given as argument");
1106 if (anArg1.ShapeType() != TopAbs_EDGE ||
1107 anArg2.ShapeType() != TopAbs_EDGE) {
1108 SetErrorCode("Element for face identification is not an edge");
1112 //Compute the Face value
1115 TopoDS_Shape aShape;
1117 TopTools_IndexedDataMapOfShapeListOfShape MEF;
1118 GEOMImpl_Block6Explorer::MapShapesAndAncestors(aBlockOrComp, TopAbs_EDGE, TopAbs_FACE, MEF);
1121 Standard_Integer ish, ext = MEF.Extent();
1123 if (MEF.Contains(anArg1)) {
1126 for (ish = 1; ish <= ext; ish++) {
1127 TopoDS_Shape aShi = MEF.FindKey(ish);
1128 if (GEOMImpl_Block6Explorer::IsSimilarEdges(anArg1, aShi)) {
1134 if (MEF.Contains(anArg2)) {
1137 for (ish = 1; ish <= ext; ish++) {
1138 TopoDS_Shape aShi = MEF.FindKey(ish);
1139 if (GEOMImpl_Block6Explorer::IsSimilarEdges(anArg2, aShi)) {
1145 if (E1.IsNull() || E2.IsNull()) {
1146 SetErrorCode("The given edge does not belong to the shape");
1150 const TopTools_ListOfShape& aFacesOfE1 = MEF.FindFromKey(E1);
1151 const TopTools_ListOfShape& aFacesOfE2 = MEF.FindFromKey(E2);
1153 Standard_Integer isFound = 0;
1154 TopTools_ListIteratorOfListOfShape anIterF1 (aFacesOfE1);
1155 for (; anIterF1.More(); anIterF1.Next()) {
1157 TopTools_ListIteratorOfListOfShape anIterF2 (aFacesOfE2);
1158 for (; anIterF2.More(); anIterF2.Next()) {
1160 if (anIterF1.Value().IsSame(anIterF2.Value())) {
1163 // Store the face, defined by two edges
1164 aShape = anIterF1.Value();
1169 SetErrorCode("The given edges do not belong to one face of the given shape");
1171 } else if (isFound > 1) {
1172 SetErrorCode("The given edges belong to several faces of the given shape");
1175 TopTools_IndexedMapOfShape anIndices;
1176 TopExp::MapShapes(aBlockOrComp, anIndices);
1177 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1178 anArray->SetValue(1, anIndices.FindIndex(aShape));
1179 aResult = GetEngine()->AddSubShape(theShape, anArray);
1182 catch (Standard_Failure& aFail) {
1183 SetErrorCode(aFail.GetMessageString());
1187 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1189 //Make a Python command
1190 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceByEdges("
1191 << theShape << ", " << theEdge1 << ", " << theEdge2 << ")";
1197 //=============================================================================
1201 //=============================================================================
1202 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetOppositeFace
1203 (Handle(GEOM_Object) theShape,
1204 Handle(GEOM_Object) theFace)
1209 Handle(GEOM_Object) aResult;
1212 if (theShape.IsNull() || theFace.IsNull()) return NULL;
1214 TopoDS_Shape aBlockOrComp = theShape->GetValue();
1215 if (aBlockOrComp.IsNull()) {
1216 SetErrorCode("Block is null");
1219 if (aBlockOrComp.ShapeType() != TopAbs_SOLID) {
1220 SetErrorCode("Shape is not a block");
1224 TopoDS_Shape anArg = theFace->GetValue();
1225 if (anArg.IsNull()) {
1226 SetErrorCode("Null shape is given as argument");
1229 if (anArg.ShapeType() != TopAbs_FACE) {
1230 SetErrorCode("Element for face identification is not a face");
1234 //Compute the Face value
1237 TopoDS_Shape aShape;
1239 GEOMImpl_Block6Explorer aBlockTool;
1240 aBlockTool.InitByBlockAndFace(aBlockOrComp, anArg);
1241 aShape = aBlockTool.GetFace(2);
1243 TopTools_IndexedMapOfShape anIndices;
1244 TopExp::MapShapes(aBlockOrComp, anIndices);
1245 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1246 anArray->SetValue(1, anIndices.FindIndex(aShape));
1247 aResult = GetEngine()->AddSubShape(theShape, anArray);
1249 catch (Standard_Failure& aFail) {
1250 SetErrorCode(aFail.GetMessageString());
1254 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1256 //Make a Python command
1257 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetOppositeFace("
1258 << theShape << ", " << theFace << ")";
1264 //=============================================================================
1268 //=============================================================================
1269 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceNearPoint
1270 (Handle(GEOM_Object) theShape,
1271 Handle(GEOM_Object) thePoint)
1276 Handle(GEOM_Object) aResult;
1279 if (theShape.IsNull() || thePoint.IsNull()) return NULL;
1281 TopoDS_Shape aBlockOrComp = theShape->GetValue();
1282 if (aBlockOrComp.IsNull()) {
1283 SetErrorCode("Block or compound is null");
1287 TopoDS_Shape anArg = thePoint->GetValue();
1288 if (anArg.IsNull()) {
1289 SetErrorCode("Null shape is given as argument");
1292 if (anArg.ShapeType() != TopAbs_VERTEX) {
1293 SetErrorCode("Element for face identification is not a vertex");
1297 //Compute the Face value
1300 TopoDS_Shape aShape;
1302 TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
1303 gp_Pnt aPnt = BRep_Tool::Pnt(aVert);
1304 Standard_Real PX, PY, PZ;
1305 aPnt.Coord(PX, PY, PZ);
1307 // 1. Classify the point relatively each face
1308 Standard_Integer nearest = 2, nbFound = 0;
1309 TopTools_DataMapOfShapeInteger mapShapeDist;
1310 TopExp_Explorer exp (aBlockOrComp, TopAbs_FACE);
1311 for (; exp.More(); exp.Next()) {
1312 TopoDS_Shape aFace = exp.Current();
1314 if (!mapShapeDist.IsBound(aFace)) {
1315 Standard_Integer aDistance = 2;
1317 // 1.a. Classify relatively Surface
1318 Handle(Geom_Surface) aSurf = BRep_Tool::Surface(TopoDS::Face(aFace));
1319 Handle(ShapeAnalysis_Surface) aSurfAna = new ShapeAnalysis_Surface (aSurf);
1320 gp_Pnt2d p2dOnSurf = aSurfAna->ValueOfUV(aPnt, Precision::Confusion());
1321 gp_Pnt p3dOnSurf = aSurfAna->Value(p2dOnSurf);
1322 Standard_Real aDist = p3dOnSurf.Distance(aPnt);
1323 if (aDist > Precision::Confusion()) {
1327 // 1.b. Classify relatively the face itself
1328 BRepClass_FaceClassifier FC (TopoDS::Face(aFace), p2dOnSurf, Precision::Confusion());
1329 if (FC.State() == TopAbs_IN) {
1331 } else if (FC.State() == TopAbs_ON) {
1338 if (aDistance < nearest) {
1339 nearest = aDistance;
1343 // A first found face, containing the point inside, will be returned.
1344 // It is the solution, if there are no
1345 // coincident or intersecting faces in the compound.
1346 if (nearest == -1) break;
1348 } else if (aDistance == nearest) {
1353 mapShapeDist.Bind(aFace, aDistance);
1354 } // if (!mapShapeDist.IsBound(aFace))
1357 // 2. Define face, containing the point or having minimum distance to it
1360 // The point is on boundary of some faces and there are
1361 // no faces, having the point inside
1362 SetErrorCode("Multiple faces near the given point are found");
1365 } else if (nearest == 1) {
1366 // The point is outside some faces and there are
1367 // no faces, having the point inside or on boundary.
1368 // We will get a nearest face
1369 Standard_Real bigReal = RealLast();
1370 Standard_Real minDist = bigReal;
1371 TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
1372 for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
1373 if (mapShapeDistIter.Value() == 1) {
1374 TopoDS_Shape aFace = mapShapeDistIter.Key();
1375 Standard_Real aDist = bigReal;
1377 // 2.a. Fast check of distance - if point projection on surface is on face
1378 Handle(Geom_Surface) aSurf = BRep_Tool::Surface(TopoDS::Face(aFace));
1379 Handle(ShapeAnalysis_Surface) aSurfAna = new ShapeAnalysis_Surface (aSurf);
1380 gp_Pnt2d p2dOnSurf = aSurfAna->ValueOfUV(aPnt, Precision::Confusion());
1381 gp_Pnt p3dOnSurf = aSurfAna->Value(p2dOnSurf);
1382 aDist = p3dOnSurf.Distance(aPnt);
1384 BRepClass_FaceClassifier FC (TopoDS::Face(aFace), p2dOnSurf, Precision::Confusion());
1385 if (FC.State() == TopAbs_OUT) {
1386 if (aDist < minDist) {
1387 // 2.b. Slow check - if point projection on surface is outside of face
1388 BRepExtrema_DistShapeShape aDistTool (aVert, aFace);
1389 if (!aDistTool.IsDone()) {
1390 SetErrorCode("Can not find a distance from the given point to one of faces");
1393 aDist = aDistTool.Value();
1399 if (aDist < minDist) {
1405 } else { // nearest == -1
1406 // // The point is inside some faces.
1407 // // We will get a face with nearest center
1408 // Standard_Real minDist = RealLast();
1409 // TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
1410 // for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
1411 // if (mapShapeDistIter.Value() == -1) {
1412 // TopoDS_Shape aFace = mapShapeDistIter.Key();
1413 // GProp_GProps aSystem;
1414 // BRepGProp::SurfaceProperties(aFace, aSystem);
1415 // gp_Pnt aCenterMass = aSystem.CentreOfMass();
1417 // Standard_Real aDist = aCenterMass.Distance(aPnt);
1418 // if (aDist < minDist) {
1425 } // if (nbFound > 1)
1428 SetErrorCode("There are no faces near the given point");
1431 TopTools_IndexedMapOfShape anIndices;
1432 TopExp::MapShapes(aBlockOrComp, anIndices);
1433 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1434 anArray->SetValue(1, anIndices.FindIndex(aShape));
1435 aResult = GetEngine()->AddSubShape(theShape, anArray);
1438 catch (Standard_Failure& aFail) {
1439 SetErrorCode(aFail.GetMessageString());
1443 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1445 //Make a Python command
1446 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceNearPoint("
1447 << theShape << ", " << thePoint << ")";
1453 //=============================================================================
1457 //=============================================================================
1458 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByNormale
1459 (Handle(GEOM_Object) theShape,
1460 Handle(GEOM_Object) theVector)
1465 Handle(GEOM_Object) aResult;
1468 if (theShape.IsNull() || theVector.IsNull()) return NULL;
1470 TopoDS_Shape aBlockOrComp = theShape->GetValue();
1471 if (aBlockOrComp.IsNull()) {
1472 SetErrorCode("Block or compound is null");
1476 TopoDS_Shape anArg = theVector->GetValue();
1477 if (anArg.IsNull()) {
1478 SetErrorCode("Null shape is given as argument");
1481 if (anArg.ShapeType() != TopAbs_EDGE) {
1482 SetErrorCode("Element for normale identification is not an edge");
1486 //Compute the Face value
1489 TopoDS_Shape aShape;
1491 TopoDS_Edge anEdge = TopoDS::Edge(anArg);
1492 TopoDS_Vertex V1, V2;
1493 TopExp::Vertices(anEdge, V1, V2, Standard_True);
1494 gp_Pnt P1 = BRep_Tool::Pnt(V1);
1495 gp_Pnt P2 = BRep_Tool::Pnt(V2);
1496 gp_Vec aVec (P1, P2);
1497 if (aVec.Magnitude() < Precision::Confusion()) {
1498 SetErrorCode("Vector with null magnitude is given");
1502 Standard_Real minAngle = RealLast();
1503 TopTools_MapOfShape mapShape;
1504 TopExp_Explorer exp (aBlockOrComp, TopAbs_FACE);
1505 for (; exp.More(); exp.Next()) {
1506 if (mapShape.Add(exp.Current())) {
1507 TopoDS_Face aFace = TopoDS::Face(exp.Current());
1508 BRepAdaptor_Surface SF (aFace);
1510 Standard_Real u, v, x;
1512 // find a point on the surface to get normal direction in
1513 u = SF.FirstUParameter();
1514 x = SF.LastUParameter();
1515 if (Precision::IsInfinite(u)) {
1516 u = (Precision::IsInfinite(x)) ? 0. : x;
1517 } else if (!Precision::IsInfinite(x)) {
1521 v = SF.FirstVParameter();
1522 x = SF.LastVParameter();
1523 if (Precision::IsInfinite(v)) {
1524 v = (Precision::IsInfinite(x)) ? 0. : x;
1525 } else if (!Precision::IsInfinite(x)) {
1529 // compute the normal direction
1531 SF.D1(u,v,P1,Vec1,Vec2);
1532 gp_Vec V = Vec1.Crossed(Vec2);
1534 if (V.Magnitude() < Precision::Confusion()) {
1535 SetErrorCode("Normal vector of a face has null magnitude");
1539 // consider the face orientation
1540 if (aFace.Orientation() == TopAbs_REVERSED ||
1541 aFace.Orientation() == TopAbs_INTERNAL) {
1545 // compute the angle and compare with the minimal one
1546 Standard_Real anAngle = aVec.Angle(V);
1547 if (anAngle < minAngle) {
1554 if (aShape.IsNull()) {
1555 SetErrorCode("Failed to find a face by the given normale");
1558 TopTools_IndexedMapOfShape anIndices;
1559 TopExp::MapShapes(aBlockOrComp, anIndices);
1560 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
1561 anArray->SetValue(1, anIndices.FindIndex(aShape));
1562 aResult = GetEngine()->AddSubShape(theShape, anArray);
1565 catch (Standard_Failure& aFail) {
1566 SetErrorCode(aFail.GetMessageString());
1570 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1572 //Make a Python command
1573 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceByNormale("
1574 << theShape << ", " << theVector << ")";
1580 //=============================================================================
1582 * GetShapesNearPoint
1584 //=============================================================================
1585 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetShapesNearPoint
1586 (Handle(GEOM_Object) theShape,
1587 Handle(GEOM_Object) thePoint,
1588 const Standard_Integer theShapeType,
1589 const Standard_Real theConstTolerance)
1594 Handle(GEOM_Object) aResult;
1597 if (theShape.IsNull() || thePoint.IsNull()) return NULL;
1599 TopoDS_Shape aBlockOrComp = theShape->GetValue();
1600 if (aBlockOrComp.IsNull()) {
1601 SetErrorCode("Block or compound is null");
1605 TopoDS_Shape anArg = thePoint->GetValue();
1606 if (anArg.IsNull()) {
1607 SetErrorCode("Null shape is given as argument");
1610 if (anArg.ShapeType() != TopAbs_VERTEX) {
1611 SetErrorCode("Element for face identification is not a vertex");
1615 if (theShapeType < TopAbs_SOLID || TopAbs_VERTEX < theShapeType) {
1616 SetErrorCode("Invalid type of result is requested");
1620 Standard_Real theTolerance = theConstTolerance;
1621 if (theTolerance < Precision::Confusion()) {
1622 theTolerance = Precision::Confusion();
1625 // Compute the result
1628 TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
1630 TopTools_MapOfShape mapShape;
1631 Standard_Integer nbEdges = 0;
1632 TopExp_Explorer exp (aBlockOrComp, TopAbs_ShapeEnum(theShapeType));
1633 for (; exp.More(); exp.Next()) {
1634 if (mapShape.Add(exp.Current())) {
1640 SetErrorCode("Given shape contains no sub-shapes of requested type");
1644 // Calculate distances and find min
1646 Standard_Integer ind = 1;
1647 Standard_Real aMinDist = RealLast();
1648 TopTools_Array1OfShape anEdges (1, nbEdges);
1649 TColStd_Array1OfReal aDistances (1, nbEdges);
1650 for (exp.Init(aBlockOrComp, TopAbs_ShapeEnum(theShapeType)); exp.More(); exp.Next()) {
1651 if (mapShape.Add(exp.Current())) {
1652 TopoDS_Shape anEdge = exp.Current();
1653 anEdges(ind) = anEdge;
1655 BRepExtrema_DistShapeShape aDistTool (aVert, anEdges(ind));
1656 if (!aDistTool.IsDone()) {
1657 SetErrorCode("Can not find a distance from the given point to one of sub-shapes");
1660 aDistances(ind) = aDistTool.Value();
1661 if (aDistances(ind) < aMinDist) {
1662 aMinDist = aDistances(ind);
1668 if (aMinDist < RealLast()) {
1669 // Collect sub-shapes with distance < (aMinDist + theTolerance)
1670 int nbSubShapes = 0;
1671 TopTools_Array1OfShape aNearShapes (1, nbEdges);
1672 for (ind = 1; ind <= nbEdges; ind++) {
1673 if (aDistances(ind) < aMinDist + theTolerance) {
1675 aNearShapes(nbSubShapes) = anEdges(ind);
1680 TopTools_IndexedMapOfShape anIndices;
1681 TopExp::MapShapes(aBlockOrComp, anIndices);
1682 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger (1, nbSubShapes);
1683 for (ind = 1; ind <= nbSubShapes; ind++) {
1684 anArray->SetValue(ind, anIndices.FindIndex(aNearShapes(ind)));
1686 aResult = GetEngine()->AddSubShape(theShape, anArray);
1689 catch (Standard_Failure& aFail) {
1690 SetErrorCode(aFail.GetMessageString());
1694 if (aResult.IsNull())
1697 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
1699 //Make a Python command
1700 GEOM::TPythonDump(aFunction)
1701 << aResult << " = geompy.GetShapesNearPoint(" << theShape << ", " << thePoint
1702 << ", " << TopAbs_ShapeEnum(theShapeType) << ", " << theTolerance << ")";
1708 //=============================================================================
1710 * IsCompoundOfBlocks
1712 //=============================================================================
1713 Standard_Boolean GEOMImpl_IBlocksOperations::IsCompoundOfBlocks
1714 (Handle(GEOM_Object) theCompound,
1715 const Standard_Integer theMinNbFaces,
1716 const Standard_Integer theMaxNbFaces,
1717 Standard_Integer& theNbBlocks)
1720 Standard_Boolean isCompOfBlocks = Standard_False;
1723 if (theCompound.IsNull()) return isCompOfBlocks;
1724 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
1727 isCompOfBlocks = Standard_True;
1730 TopTools_MapOfShape mapShape;
1731 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
1732 for (; exp.More(); exp.Next()) {
1733 if (mapShape.Add(exp.Current())) {
1734 TopoDS_Shape aSolid = exp.Current();
1736 TopTools_MapOfShape mapFaces;
1737 TopExp_Explorer expF (aSolid, TopAbs_FACE);
1738 Standard_Integer nbFaces = 0;
1739 for (; expF.More(); expF.Next()) {
1740 if (mapFaces.Add(expF.Current())) {
1742 if (nbFaces > theMaxNbFaces) {
1743 isCompOfBlocks = Standard_False;
1748 if (nbFaces < theMinNbFaces || theMaxNbFaces < nbFaces) {
1749 isCompOfBlocks = Standard_False;
1756 catch (Standard_Failure& aFail) {
1757 SetErrorCode(aFail.GetMessageString());
1758 return isCompOfBlocks;
1762 return isCompOfBlocks;
1765 //=============================================================================
1767 * Set of functions, used by CheckCompoundOfBlocks() method
1769 //=============================================================================
1770 void GEOMImpl_IBlocksOperations::AddBlocksFrom (const TopoDS_Shape& theShape,
1771 TopTools_ListOfShape& BLO,
1772 TopTools_ListOfShape& NOT,
1773 TopTools_ListOfShape& EXT,
1774 TopTools_ListOfShape& NOQ,
1775 const Standard_Real theToleranceC1)
1777 TopAbs_ShapeEnum aType = theShape.ShapeType();
1779 case TopAbs_COMPOUND:
1780 case TopAbs_COMPSOLID:
1782 TopoDS_Iterator It (theShape);
1783 for (; It.More(); It.Next()) {
1784 AddBlocksFrom(It.Value(), BLO, NOT, EXT, NOQ, theToleranceC1);
1790 // Check, if there are seam or degenerated edges
1791 BlockFix_CheckTool aTool;
1792 aTool.SetShape(theShape);
1793 aTool.SetAngTolerance(theToleranceC1);
1795 if (aTool.NbPossibleBlocks() > 0) {
1796 EXT.Append(theShape);
1798 // Count faces and edges in each face to recognize blocks
1799 TopTools_MapOfShape mapFaces;
1800 Standard_Integer nbFaces = 0;
1801 Standard_Boolean hasNonQuadr = Standard_False;
1802 TopExp_Explorer expF (theShape, TopAbs_FACE);
1804 for (; expF.More(); expF.Next()) {
1805 TopoDS_Face aF = TopoDS::Face(expF.Current());
1807 if (mapFaces.Add(aF)) {
1810 if (!IsQuadrangle(aF, theToleranceC1)) {
1811 hasNonQuadr = Standard_True;
1812 NOQ.Append(aF);//0021483
1817 if (nbFaces == 6 && !hasNonQuadr) {
1818 BLO.Append(theShape);
1820 NOT.Append(theShape);
1825 case TopAbs_SHELL: //0021483
1826 case TopAbs_FACE: //0021483
1828 // Count edges in each face
1829 TopTools_MapOfShape mapFaces;
1830 TopExp_Explorer expF (theShape, TopAbs_FACE);
1831 for (; expF.More(); expF.Next()) {
1832 TopoDS_Face aF = TopoDS::Face(expF.Current());
1834 if (mapFaces.Add(aF)) {
1835 if (!IsQuadrangle(aF, theToleranceC1)) {
1836 NOQ.Append(aF);//0021483
1843 NOT.Append(theShape);
1847 #define REL_NOT_CONNECTED 0
1849 #define REL_NOT_GLUED 2
1850 #define REL_COLLISION_VV 3
1851 #define REL_COLLISION_FF 4
1852 #define REL_COLLISION_EE 5
1853 #define REL_UNKNOWN 6
1855 Standard_Integer BlocksRelation (const TopoDS_Shape& theBlock1,
1856 const TopoDS_Shape& theBlock2)
1858 // Compare bounding boxes before calling BRepExtrema_DistShapeShape
1859 Standard_Real Xmin1, Ymin1, Zmin1, Xmax1, Ymax1, Zmax1;
1860 Standard_Real Xmin2, Ymin2, Zmin2, Xmax2, Ymax2, Zmax2;
1862 BRepBndLib::Add(theBlock1, B1);
1863 BRepBndLib::Add(theBlock2, B2);
1864 B1.Get(Xmin1, Ymin1, Zmin1, Xmax1, Ymax1, Zmax1);
1865 B2.Get(Xmin2, Ymin2, Zmin2, Xmax2, Ymax2, Zmax2);
1866 if (Xmax2 < Xmin1 || Xmax1 < Xmin2 ||
1867 Ymax2 < Ymin1 || Ymax1 < Ymin2 ||
1868 Zmax2 < Zmin1 || Zmax1 < Zmin2) {
1869 return REL_NOT_CONNECTED;
1872 BRepExtrema_DistShapeShape dst (theBlock1, theBlock2);
1873 if (!dst.IsDone()) {
1877 if (dst.Value() > Precision::Confusion()) {
1878 return REL_NOT_CONNECTED;
1881 if (dst.InnerSolution()) {
1882 return REL_COLLISION_VV;
1885 Standard_Integer nbSol = dst.NbSolution();
1886 Standard_Integer relation = REL_OK;
1887 Standard_Integer nbVerts = 0;
1888 Standard_Integer nbEdges = 0;
1889 Standard_Integer sol = 1;
1890 for (; sol <= nbSol; sol++) {
1891 BRepExtrema_SupportType supp1 = dst.SupportTypeShape1(sol);
1892 BRepExtrema_SupportType supp2 = dst.SupportTypeShape2(sol);
1893 if (supp1 == BRepExtrema_IsVertex && supp2 == BRepExtrema_IsVertex) {
1895 } else if (supp1 == BRepExtrema_IsInFace || supp2 == BRepExtrema_IsInFace) {
1896 return REL_COLLISION_FF;
1897 } else if (supp1 == BRepExtrema_IsOnEdge && supp2 == BRepExtrema_IsOnEdge) {
1899 } else if ((supp1 == BRepExtrema_IsOnEdge && supp2 == BRepExtrema_IsVertex) ||
1900 (supp2 == BRepExtrema_IsOnEdge && supp1 == BRepExtrema_IsVertex)) {
1901 relation = REL_COLLISION_EE;
1906 if (relation != REL_OK) {
1910 TColStd_Array1OfInteger vertSol (1, nbVerts);
1911 TopTools_Array1OfShape V1 (1, nbVerts);
1912 TopTools_Array1OfShape V2 (1, nbVerts);
1913 Standard_Integer ivs = 0;
1914 for (sol = 1; sol <= nbSol; sol++) {
1915 if (dst.SupportTypeShape1(sol) == BRepExtrema_IsVertex &&
1916 dst.SupportTypeShape2(sol) == BRepExtrema_IsVertex) {
1917 TopoDS_Vertex Vcur = TopoDS::Vertex(dst.SupportOnShape1(sol));
1918 // Check, that this vertex is far enough from other solution vertices.
1919 Standard_Integer ii = 1;
1920 for (; ii <= ivs; ii++) {
1921 if (BRepTools::Compare(TopoDS::Vertex(V1(ii)), Vcur)) {
1928 V2(ivs) = dst.SupportOnShape2(sol);
1932 // As we deal only with quadrangles,
1933 // 2, 3 or 4 vertex solutions can be found.
1936 return REL_COLLISION_FF;
1938 return REL_NOT_CONNECTED;
1944 // Check sharing of coincident entities.
1945 if (ivs == 2 || ivs == 3) {
1946 // Map vertices and edges of the blocks
1947 TopTools_IndexedDataMapOfShapeListOfShape MVE1, MVE2;
1948 GEOMImpl_Block6Explorer::MapShapesAndAncestors
1949 (theBlock1, TopAbs_VERTEX, TopAbs_EDGE, MVE1);
1950 GEOMImpl_Block6Explorer::MapShapesAndAncestors
1951 (theBlock2, TopAbs_VERTEX, TopAbs_EDGE, MVE2);
1955 TopoDS_Shape anEdge1, anEdge2;
1956 GEOMImpl_Block6Explorer::FindEdge(anEdge1, V1(1), V1(2), MVE1);
1957 if (anEdge1.IsNull()) return REL_UNKNOWN;
1959 GEOMImpl_Block6Explorer::FindEdge(anEdge2, V2(1), V2(2), MVE2);
1960 if (anEdge2.IsNull()) return REL_UNKNOWN;
1962 if (!anEdge1.IsSame(anEdge2)) return REL_NOT_GLUED;
1964 } else { // ivs == 3
1965 // Find common edges
1966 Standard_Integer e1_v1 = 1;
1967 Standard_Integer e1_v2 = 2;
1968 Standard_Integer e2_v1 = 3;
1969 Standard_Integer e2_v2 = 1;
1971 TopoDS_Shape anEdge11, anEdge12;
1972 GEOMImpl_Block6Explorer::FindEdge(anEdge11, V1(e1_v1), V1(e1_v2), MVE1);
1973 if (anEdge11.IsNull()) {
1976 GEOMImpl_Block6Explorer::FindEdge(anEdge11, V1(e1_v1), V1(e1_v2), MVE1);
1977 if (anEdge11.IsNull()) return REL_UNKNOWN;
1979 GEOMImpl_Block6Explorer::FindEdge(anEdge12, V1(e2_v1), V1(e2_v2), MVE1);
1980 if (anEdge12.IsNull()) {
1982 GEOMImpl_Block6Explorer::FindEdge(anEdge12, V1(e2_v1), V1(e2_v2), MVE1);
1983 if (anEdge12.IsNull()) return REL_UNKNOWN;
1986 TopoDS_Shape anEdge21, anEdge22;
1987 GEOMImpl_Block6Explorer::FindEdge(anEdge21, V2(e1_v1), V2(e1_v2), MVE2);
1988 if (anEdge21.IsNull()) return REL_UNKNOWN;
1989 GEOMImpl_Block6Explorer::FindEdge(anEdge22, V2(e2_v1), V2(e2_v2), MVE2);
1990 if (anEdge22.IsNull()) return REL_UNKNOWN;
1992 // Check of edges coincidence (with some precision) have to be done here
1993 // if (!anEdge11.IsEqual(anEdge21)) return REL_UNKNOWN;
1994 // if (!anEdge12.IsEqual(anEdge22)) return REL_UNKNOWN;
1996 // Check of edges sharing
1997 if (!anEdge11.IsSame(anEdge21)) return REL_NOT_GLUED;
1998 if (!anEdge12.IsSame(anEdge22)) return REL_NOT_GLUED;
2003 // Map vertices and faces of the blocks
2004 TopTools_IndexedDataMapOfShapeListOfShape MVF1, MVF2;
2005 GEOMImpl_Block6Explorer::MapShapesAndAncestors
2006 (theBlock1, TopAbs_VERTEX, TopAbs_FACE, MVF1);
2007 GEOMImpl_Block6Explorer::MapShapesAndAncestors
2008 (theBlock2, TopAbs_VERTEX, TopAbs_FACE, MVF2);
2010 TopoDS_Shape aFace1, aFace2;
2011 GEOMImpl_Block6Explorer::FindFace(aFace1, V1(1), V1(2), V1(3), V1(4), MVF1);
2012 if (aFace1.IsNull()) return REL_UNKNOWN;
2013 GEOMImpl_Block6Explorer::FindFace(aFace2, V2(1), V2(2), V2(3), V2(4), MVF2);
2014 if (aFace2.IsNull()) return REL_UNKNOWN;
2016 // Check of faces coincidence (with some precision) have to be done here
2017 // if (!aFace1.IsEqual(aFace2)) return REL_UNKNOWN;
2019 // Check of faces sharing
2020 if (!aFace1.IsSame(aFace2)) return REL_NOT_GLUED;
2026 void FindConnected (const Standard_Integer theBlockIndex,
2027 const TColStd_Array2OfInteger& theRelations,
2028 TColStd_MapOfInteger& theProcessedMap,
2029 TColStd_MapOfInteger& theConnectedMap)
2031 theConnectedMap.Add(theBlockIndex);
2032 theProcessedMap.Add(theBlockIndex);
2034 Standard_Integer nbBlocks = theRelations.ColLength();
2035 Standard_Integer col = 1;
2036 for (; col <= nbBlocks; col++) {
2037 if (theRelations(theBlockIndex, col) == REL_OK ||
2038 theRelations(theBlockIndex, col) == REL_NOT_GLUED) {
2039 if (!theProcessedMap.Contains(col)) {
2040 FindConnected(col, theRelations, theProcessedMap, theConnectedMap);
2046 Standard_Boolean HasAnyConnection (const Standard_Integer theBlockIndex,
2047 const TColStd_MapOfInteger& theWith,
2048 const TColStd_Array2OfInteger& theRelations,
2049 TColStd_MapOfInteger& theProcessedMap)
2051 theProcessedMap.Add(theBlockIndex);
2053 Standard_Integer nbBlocks = theRelations.ColLength();
2054 Standard_Integer col = 1;
2055 for (; col <= nbBlocks; col++) {
2056 if (theRelations(theBlockIndex, col) != REL_NOT_CONNECTED) {
2057 if (!theProcessedMap.Contains(col)) {
2058 if (theWith.Contains(col))
2059 return Standard_True;
2060 if (HasAnyConnection(col, theWith, theRelations, theProcessedMap))
2061 return Standard_True;
2066 return Standard_False;
2069 //=============================================================================
2073 //=============================================================================
2074 TCollection_AsciiString GEOMImpl_IBlocksOperations::PrintBCErrors
2075 (Handle(GEOM_Object) /*theCompound*/,
2076 const std::list<BCError>& theErrors)
2078 TCollection_AsciiString aDescr;
2080 std::list<BCError>::const_iterator errIt = theErrors.begin();
2082 for (; errIt != theErrors.end(); i++, errIt++) {
2083 BCError errStruct = *errIt;
2085 switch (errStruct.error) {
2087 aDescr += "\n\tNot a Blocks: ";
2090 aDescr += "\n\tHexahedral solids with degenerated and/or seam edges: ";
2092 case INVALID_CONNECTION:
2093 aDescr += "\n\tInvalid connection between two blocks: ";
2096 aDescr += "\n\tBlocks, not connected with main body: ";
2099 aDescr += "\n\tNot glued blocks: ";
2105 std::list<int> sshList = errStruct.incriminated;
2106 std::list<int>::iterator sshIt = sshList.begin();
2108 for (; sshIt != sshList.end(); jj++, sshIt++) {
2111 aDescr += TCollection_AsciiString(*sshIt);
2118 //=============================================================================
2120 * CheckCompoundOfBlocks
2122 //=============================================================================
2123 Standard_Boolean GEOMImpl_IBlocksOperations::CheckCompoundOfBlocks
2124 (Handle(GEOM_Object) theCompound,
2125 const Standard_Real theToleranceC1,
2126 std::list<BCError>& theErrors)
2130 if (theCompound.IsNull()) return Standard_False;
2131 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2133 Standard_Boolean isCompOfBlocks = Standard_True;
2135 // Map sub-shapes and their indices
2136 TopTools_IndexedMapOfShape anIndices;
2137 TopExp::MapShapes(aBlockOrComp, anIndices);
2139 // 1. Separate blocks from non-blocks
2140 TopTools_ListOfShape NOT; // Not blocks
2141 TopTools_ListOfShape EXT; // Hexahedral solids, having degenerated and/or seam edges
2142 TopTools_ListOfShape BLO; // All blocks from the given compound
2143 TopTools_ListOfShape NOQ; // All non-quadrangular faces
2144 AddBlocksFrom(aBlockOrComp, BLO, NOT, EXT, NOQ, theToleranceC1);
2146 // Report non-blocks
2147 if (NOT.Extent() > 0) {
2148 isCompOfBlocks = Standard_False;
2150 anErr.error = NOT_BLOCK;
2151 TopTools_ListIteratorOfListOfShape it (NOT);
2152 for (; it.More(); it.Next()) {
2153 anErr.incriminated.push_back(anIndices.FindIndex(it.Value()));
2155 theErrors.push_back(anErr);
2158 // Report solids, having degenerated and/or seam edges
2159 if (EXT.Extent() > 0) {
2160 isCompOfBlocks = Standard_False;
2162 anErr.error = EXTRA_EDGE;
2163 TopTools_ListIteratorOfListOfShape it (EXT);
2164 for (; it.More(); it.Next()) {
2165 anErr.incriminated.push_back(anIndices.FindIndex(it.Value()));
2167 theErrors.push_back(anErr);
2170 Standard_Integer nbBlocks = BLO.Extent();
2171 if (nbBlocks == 0) {
2172 isCompOfBlocks = Standard_False;
2174 return isCompOfBlocks;
2176 if (nbBlocks == 1) {
2178 return isCompOfBlocks;
2181 // Prepare data for 2. and 3.
2182 TColStd_Array2OfInteger aRelations (1, nbBlocks, 1, nbBlocks);
2183 aRelations.Init(REL_NOT_CONNECTED);
2185 TopTools_IndexedMapOfShape mapBlocks;
2188 TopoDS_Compound aComp;
2189 BB.MakeCompound(aComp);
2191 TopTools_ListIteratorOfListOfShape BLOit (BLO);
2192 for (; BLOit.More(); BLOit.Next()) {
2193 mapBlocks.Add(BLOit.Value());
2194 BB.Add(aComp, BLOit.Value());
2197 // 2. Find glued blocks (having shared faces)
2198 TopTools_IndexedDataMapOfShapeListOfShape mapFaceBlocks;
2199 GEOMImpl_Block6Explorer::MapShapesAndAncestors
2200 (aComp, TopAbs_FACE, TopAbs_SOLID, mapFaceBlocks);
2202 Standard_Integer prevInd = 0, curInd = 0;
2203 Standard_Integer ind = 1, nbFaces = mapFaceBlocks.Extent();
2204 for (; ind <= nbFaces; ind++) {
2205 const TopTools_ListOfShape& aGluedBlocks = mapFaceBlocks.FindFromIndex(ind);
2206 if (aGluedBlocks.Extent() > 1) { // Shared face found
2207 TopTools_ListIteratorOfListOfShape aGluedBlocksIt (aGluedBlocks);
2208 TopoDS_Shape prevBlock, curBlock;
2209 for (; aGluedBlocksIt.More(); aGluedBlocksIt.Next()) {
2210 curBlock = aGluedBlocksIt.Value();
2211 if (!prevBlock.IsNull()) {
2212 prevInd = mapBlocks.FindIndex(prevBlock);
2213 curInd = mapBlocks.FindIndex(curBlock);
2214 aRelations.SetValue(prevInd, curInd, REL_OK);
2215 aRelations.SetValue(curInd, prevInd, REL_OK);
2217 prevBlock = curBlock;
2222 // 3. Find not glued blocks
2223 GEOMAlgo_GlueAnalyser aGD;
2225 aGD.SetShape(aComp);
2226 aGD.SetTolerance(Precision::Confusion());
2227 aGD.SetCheckGeometry(Standard_True);
2230 Standard_Integer iErr, iWrn;
2231 iErr = aGD.ErrorStatus();
2233 SetErrorCode("Error in GEOMAlgo_GlueAnalyser");
2234 return isCompOfBlocks;
2236 iWrn = aGD.WarningStatus();
2238 MESSAGE("Warning in GEOMAlgo_GlueAnalyser");
2241 // Report not glued blocks
2242 if (aGD.HasSolidsToGlue()) {
2243 isCompOfBlocks = Standard_False;
2244 Standard_Integer aSx1Ind, aSx2Ind;
2246 const GEOMAlgo_ListOfCoupleOfShapes& aLCS = aGD.SolidsToGlue();
2247 GEOMAlgo_ListIteratorOfListOfCoupleOfShapes aItCS (aLCS);
2248 for (; aItCS.More(); aItCS.Next()) {
2249 const GEOMAlgo_CoupleOfShapes& aCS = aItCS.Value();
2250 const TopoDS_Shape& aSx1 = aCS.Shape1();
2251 const TopoDS_Shape& aSx2 = aCS.Shape2();
2253 aSx1Ind = mapBlocks.FindIndex(aSx1);
2254 aSx2Ind = mapBlocks.FindIndex(aSx2);
2255 aRelations.SetValue(aSx1Ind, aSx2Ind, NOT_GLUED);
2256 aRelations.SetValue(aSx2Ind, aSx1Ind, NOT_GLUED);
2259 anErr.error = NOT_GLUED;
2260 anErr.incriminated.push_back(anIndices.FindIndex(aSx1));
2261 anErr.incriminated.push_back(anIndices.FindIndex(aSx2));
2262 theErrors.push_back(anErr);
2266 // 4. Find largest set of connected (good connection or not glued) blocks
2267 Standard_Integer ibl = 1;
2268 TColStd_MapOfInteger aProcessedMap;
2269 TColStd_MapOfInteger aLargestSet;
2270 TColStd_MapOfInteger aCurrentSet;
2271 for (ibl = 1; ibl <= nbBlocks; ibl++) {
2272 if (!aProcessedMap.Contains(ibl)) {
2273 aCurrentSet.Clear();
2274 FindConnected(ibl, aRelations, aProcessedMap, aCurrentSet);
2275 if (aCurrentSet.Extent() > aLargestSet.Extent()) {
2276 aLargestSet = aCurrentSet;
2281 // 5. Report all blocks, isolated from <aLargestSet>
2283 anErr.error = NOT_CONNECTED;
2284 Standard_Boolean hasIsolated = Standard_False;
2285 for (ibl = 1; ibl <= nbBlocks; ibl++) {
2286 if (!aLargestSet.Contains(ibl)) {
2287 aProcessedMap.Clear();
2288 if (!HasAnyConnection(ibl, aLargestSet, aRelations, aProcessedMap)) {
2289 // report connection absence
2290 hasIsolated = Standard_True;
2291 anErr.incriminated.push_back(anIndices.FindIndex(mapBlocks.FindKey(ibl)));
2296 isCompOfBlocks = Standard_False;
2297 theErrors.push_back(anErr);
2301 return isCompOfBlocks;
2304 //=============================================================================
2308 //=============================================================================
2309 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetNonBlocks
2310 (Handle(GEOM_Object) theShape,
2311 const Standard_Real theToleranceC1,
2312 Handle(GEOM_Object)& theNonQuads)
2316 if (theShape.IsNull()) return NULL;
2317 TopoDS_Shape aShape = theShape->GetValue();
2319 // Separate blocks from non-blocks
2320 TopTools_ListOfShape BLO; // All blocks from the given compound
2321 TopTools_ListOfShape NOT; // Not blocks
2322 TopTools_ListOfShape EXT; // Hexahedral solids, having degenerated and/or seam edges
2323 TopTools_ListOfShape NOQ; // All non-quadrangular faces
2324 AddBlocksFrom(aShape, BLO, NOT, EXT, NOQ, theToleranceC1);
2326 if (NOT.IsEmpty() && EXT.IsEmpty() && NOQ.IsEmpty()) {
2327 SetErrorCode("NOT_FOUND_ANY");
2331 // Map sub-shapes and their indices
2332 TopTools_IndexedMapOfShape anIndices;
2333 TopExp::MapShapes(aShape, anIndices);
2336 Handle(GEOM_Object) aNonBlocks;
2337 if (NOT.Extent() > 0 || EXT.Extent() > 0) {
2338 Handle(TColStd_HArray1OfInteger) anArray =
2339 new TColStd_HArray1OfInteger (1, NOT.Extent() + EXT.Extent());
2340 Standard_Integer ii = 1;
2341 TopTools_ListIteratorOfListOfShape it1 (NOT);
2342 for (; it1.More(); it1.Next(), ii++) {
2343 anArray->SetValue(ii, anIndices.FindIndex(it1.Value()));
2345 TopTools_ListIteratorOfListOfShape it2 (EXT);
2346 for (; it2.More(); it2.Next(), ii++) {
2347 anArray->SetValue(ii, anIndices.FindIndex(it2.Value()));
2350 aNonBlocks = GetEngine()->AddSubShape(theShape, anArray);
2351 if (aNonBlocks.IsNull()) {
2352 SetErrorCode("Error in algorithm: result found, but cannot be returned.");
2355 aNonBlocks->SetType(GEOM_GROUP);
2356 TDF_Label aFreeLabel = aNonBlocks->GetFreeLabel();
2357 TDataStd_Integer::Set(aFreeLabel, (Standard_Integer)TopAbs_SOLID);
2361 if (NOQ.Extent() > 0) {
2362 Handle(TColStd_HArray1OfInteger) anArray =
2363 new TColStd_HArray1OfInteger (1, NOQ.Extent());
2364 Standard_Integer ii = 1;
2365 TopTools_ListIteratorOfListOfShape it1 (NOQ);
2366 for (; it1.More(); it1.Next(), ii++) {
2367 anArray->SetValue(ii, anIndices.FindIndex(it1.Value()));
2370 theNonQuads = GetEngine()->AddSubShape(theShape, anArray);
2371 if (theNonQuads.IsNull()) {
2372 SetErrorCode("Error in algorithm: result found, but cannot be returned.");
2375 theNonQuads->SetType(GEOM_GROUP);
2376 TDF_Label aFreeLabel = theNonQuads->GetFreeLabel();
2377 TDataStd_Integer::Set(aFreeLabel, (Standard_Integer)TopAbs_FACE);
2380 //Make a Python command
2381 Handle(GEOM_Function) aMainShape = theShape->GetLastFunction();
2382 GEOM::TPythonDump pd (aMainShape, /*append=*/true);
2384 if (aNonBlocks.IsNull())
2385 pd << "no_bad_solids";
2389 if (theNonQuads.IsNull())
2390 pd << "no_bad_faces";
2393 pd << ") = geompy.GetNonBlocks(" << theShape << ")";
2399 //=============================================================================
2403 //=============================================================================
2404 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::RemoveExtraEdges
2405 (Handle(GEOM_Object) theObject,
2406 const Standard_Integer theOptimumNbFaces)
2410 if (theObject.IsNull()) return NULL;
2412 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
2413 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be fixed
2415 //Add a new Copy object
2416 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GEOM_COPY);
2419 Handle(GEOM_Function) aFunction =
2420 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_REMOVE_EXTRA);
2422 //Check if the function is set correctly
2423 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
2425 GEOMImpl_IBlockTrsf aTI (aFunction);
2426 aTI.SetOriginal(aLastFunction);
2427 aTI.SetOptimumNbFaces(theOptimumNbFaces);
2429 //Compute the fixed shape
2432 if (!GetSolver()->ComputeFunction(aFunction)) {
2433 SetErrorCode("Block driver failed to remove extra edges of the given shape");
2437 catch (Standard_Failure& aFail) {
2438 SetErrorCode(aFail.GetMessageString());
2442 //Make a Python command
2443 std::string doUnionFaces = (theOptimumNbFaces < 0) ? "False" : "True";
2444 GEOM::TPythonDump(aFunction) << aCopy << " = geompy.RemoveExtraEdges("
2445 << theObject << ", " << doUnionFaces.data() << ")";
2451 //=============================================================================
2455 //=============================================================================
2456 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::UnionFaces
2457 (Handle(GEOM_Object) theObject)
2461 if (theObject.IsNull()) return NULL;
2463 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
2464 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be fixed
2466 //Add a new Copy object
2467 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GEOM_COPY);
2470 Handle(GEOM_Function) aFunction =
2471 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_UNION_FACES);
2473 //Check if the function is set correctly
2474 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
2476 GEOMImpl_IBlockTrsf aTI (aFunction);
2477 aTI.SetOriginal(aLastFunction);
2479 //Compute the fixed shape
2482 if (!GetSolver()->ComputeFunction(aFunction)) {
2483 SetErrorCode("Block driver failed to remove extra edges of the given shape");
2487 catch (Standard_Failure& aFail) {
2488 SetErrorCode(aFail.GetMessageString());
2492 //Make a Python command
2493 GEOM::TPythonDump(aFunction) << aCopy << " = geompy.UnionFaces("
2494 << theObject << ")";
2500 //=============================================================================
2504 //=============================================================================
2505 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::CheckAndImprove
2506 (Handle(GEOM_Object) theObject)
2510 if (theObject.IsNull()) return NULL;
2512 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
2513 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be fixed
2515 //Add a new Copy object
2516 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GEOM_COPY);
2519 Handle(GEOM_Function) aFunction =
2520 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_COMPOUND_IMPROVE);
2522 //Check if the function is set correctly
2523 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
2525 GEOMImpl_IBlockTrsf aTI (aFunction);
2526 aTI.SetOriginal(aLastFunction);
2528 // -1 means do not unite faces on common surface (?except case of seam edge between them?)
2529 //aTI.SetOptimumNbFaces(-1);
2530 aTI.SetOptimumNbFaces(6);
2532 //Compute the fixed shape
2535 if (!GetSolver()->ComputeFunction(aFunction)) {
2536 SetErrorCode("Block driver failed to improve the given blocks compound");
2540 catch (Standard_Failure& aFail) {
2541 SetErrorCode(aFail.GetMessageString());
2545 //Make a Python command
2546 GEOM::TPythonDump(aFunction) << aCopy
2547 << " = geompy.CheckAndImprove(" << theObject << ")";
2553 //=============================================================================
2555 * ExplodeCompoundOfBlocks
2557 //=============================================================================
2558 Handle(TColStd_HSequenceOfTransient) GEOMImpl_IBlocksOperations::ExplodeCompoundOfBlocks
2559 (Handle(GEOM_Object) theCompound,
2560 const Standard_Integer theMinNbFaces,
2561 const Standard_Integer theMaxNbFaces)
2565 if (theCompound.IsNull()) return NULL;
2566 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2567 if (aBlockOrComp.IsNull()) return NULL;
2569 Handle(TColStd_HSequenceOfTransient) aBlocks = new TColStd_HSequenceOfTransient;
2570 Handle(GEOM_Object) anObj;
2571 Handle(GEOM_Function) aFunction;
2573 TopTools_MapOfShape mapShape;
2574 TCollection_AsciiString anAsciiList, anEntry;
2577 TopTools_IndexedMapOfShape anIndices;
2578 TopExp::MapShapes(aBlockOrComp, anIndices);
2579 Handle(TColStd_HArray1OfInteger) anArray;
2584 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2585 for (; exp.More(); exp.Next()) {
2586 if (mapShape.Add(exp.Current())) {
2587 TopoDS_Shape aSolid = exp.Current();
2589 TopTools_MapOfShape mapFaces;
2590 TopExp_Explorer expF (aSolid, TopAbs_FACE);
2591 Standard_Integer nbFaces = 0;
2592 for (; expF.More(); expF.Next()) {
2593 if (mapFaces.Add(expF.Current())) {
2598 if (theMinNbFaces <= nbFaces && nbFaces <= theMaxNbFaces) {
2599 anArray = new TColStd_HArray1OfInteger(1,1);
2600 anArray->SetValue(1, anIndices.FindIndex(aSolid));
2601 anObj = GetEngine()->AddSubShape(theCompound, anArray);
2602 aBlocks->Append(anObj);
2604 //Make a Python command
2605 TDF_Tool::Entry(anObj->GetEntry(), anEntry);
2606 anAsciiList += anEntry + ", ";
2611 catch (Standard_Failure& aFail) {
2612 SetErrorCode(aFail.GetMessageString());
2616 if (aBlocks->IsEmpty()) {
2617 SetErrorCode("There are no specified blocks in the given shape");
2621 anAsciiList.Trunc(anAsciiList.Length() - 2);
2623 //The explode doesn't change object so no new function is required.
2624 aFunction = theCompound->GetLastFunction();
2626 //Make a Python command
2627 GEOM::TPythonDump(aFunction, /*append=*/true)
2628 << "[" << anAsciiList.ToCString() << "] = geompy.MakeBlockExplode("
2629 << theCompound << ", " << theMinNbFaces << ", " << theMaxNbFaces << ")";
2635 //=============================================================================
2639 //=============================================================================
2640 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetBlockNearPoint
2641 (Handle(GEOM_Object) theCompound,
2642 Handle(GEOM_Object) thePoint)
2647 Handle(GEOM_Object) aResult;
2650 if (theCompound.IsNull() || thePoint.IsNull()) return NULL;
2652 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2653 if (aBlockOrComp.IsNull()) {
2654 SetErrorCode("Compound is null");
2657 if (aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
2658 aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
2659 SetErrorCode("Shape to find block in is not a compound");
2663 TopoDS_Shape anArg = thePoint->GetValue();
2664 if (anArg.IsNull()) {
2665 SetErrorCode("Point is null");
2668 if (anArg.ShapeType() != TopAbs_VERTEX) {
2669 SetErrorCode("Shape for block identification is not a vertex");
2673 //Compute the Block value
2676 TopoDS_Shape aShape;
2678 TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
2679 gp_Pnt aPnt = BRep_Tool::Pnt(aVert);
2680 Standard_Real PX, PY, PZ;
2681 aPnt.Coord(PX, PY, PZ);
2683 // 1. Classify the point relatively each block
2684 Standard_Integer nearest = 2, nbFound = 0;
2685 TopTools_DataMapOfShapeInteger mapShapeDist;
2686 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2687 for (; exp.More(); exp.Next()) {
2688 TopoDS_Shape aSolid = exp.Current();
2690 if (!mapShapeDist.IsBound(aSolid)) {
2691 Standard_Integer aDistance = 2;
2693 // 1.a. Classify relatively Bounding box
2694 Standard_Real Xmin, Ymin, Zmin, Xmax, Ymax, Zmax;
2696 BRepBndLib::Add(aSolid, BB);
2697 BB.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);
2698 if (PX < Xmin || Xmax < PX ||
2699 PY < Ymin || Ymax < PY ||
2700 PZ < Zmin || Zmax < PZ) {
2701 // OUT of bounding box
2704 // 1.b. Classify relatively the solid itself
2705 BRepClass3d_SolidClassifier SC (aSolid, aPnt, Precision::Confusion());
2706 if (SC.State() == TopAbs_IN) {
2708 } else if (SC.State() == TopAbs_ON) {
2715 if (aDistance < nearest) {
2716 nearest = aDistance;
2720 // A first found block, containing the point inside, will be returned.
2721 // It is the solution, if there are no intersecting blocks in the compound.
2722 if (nearest == -1) break;
2724 } else if (aDistance == nearest) {
2729 mapShapeDist.Bind(aSolid, aDistance);
2730 } // if (!mapShapeDist.IsBound(aSolid))
2733 // 2. Define block, containing the point or having minimum distance to it
2736 // The point is on boundary of some blocks and there are
2737 // no blocks, having the point inside their volume
2738 SetErrorCode("Multiple blocks near the given point are found");
2741 } else if (nearest == 1) {
2742 // The point is outside some blocks and there are
2743 // no blocks, having the point inside or on boundary.
2744 // We will get a nearest block
2745 Standard_Real minDist = RealLast();
2746 TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
2747 for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
2748 if (mapShapeDistIter.Value() == 1) {
2749 TopoDS_Shape aSolid = mapShapeDistIter.Key();
2750 BRepExtrema_DistShapeShape aDistTool (aVert, aSolid);
2751 if (!aDistTool.IsDone()) {
2752 SetErrorCode("Can not find a distance from the given point to one of blocks");
2755 Standard_Real aDist = aDistTool.Value();
2756 if (aDist < minDist) {
2762 } else { // nearest == -1
2763 // // The point is inside some blocks.
2764 // // We will get a block with nearest center
2765 // Standard_Real minDist = RealLast();
2766 // TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
2767 // for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
2768 // if (mapShapeDistIter.Value() == -1) {
2769 // TopoDS_Shape aSolid = mapShapeDistIter.Key();
2770 // GProp_GProps aSystem;
2771 // BRepGProp::VolumeProperties(aSolid, aSystem);
2772 // gp_Pnt aCenterMass = aSystem.CentreOfMass();
2774 // Standard_Real aDist = aCenterMass.Distance(aPnt);
2775 // if (aDist < minDist) {
2782 } // if (nbFound > 1)
2785 SetErrorCode("There are no blocks near the given point");
2788 TopTools_IndexedMapOfShape anIndices;
2789 TopExp::MapShapes(aBlockOrComp, anIndices);
2790 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
2791 anArray->SetValue(1, anIndices.FindIndex(aShape));
2792 aResult = GetEngine()->AddSubShape(theCompound, anArray);
2795 catch (Standard_Failure& aFail) {
2796 SetErrorCode(aFail.GetMessageString());
2800 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
2802 //Make a Python command
2803 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetBlockNearPoint("
2804 << theCompound << ", " << thePoint << ")";
2810 //=============================================================================
2814 //=============================================================================
2815 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetBlockByParts
2816 (Handle(GEOM_Object) theCompound,
2817 const Handle(TColStd_HSequenceOfTransient)& theParts)
2821 Handle(GEOM_Object) aResult;
2823 if (theCompound.IsNull() || theParts.IsNull()) return NULL;
2824 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2825 if (aBlockOrComp.IsNull()) return NULL;
2828 Standard_Integer argi, aLen = theParts->Length();
2829 TopTools_Array1OfShape anArgs (1, aLen);
2830 TCollection_AsciiString anEntry, aPartsDescr;
2831 for (argi = 1; argi <= aLen; argi++) {
2832 Handle(GEOM_Object) anObj = Handle(GEOM_Object)::DownCast(theParts->Value(argi));
2833 Handle(GEOM_Function) aRef = anObj->GetLastFunction();
2834 if (aRef.IsNull()) return NULL;
2836 TopoDS_Shape anArg = aRef->GetValue();
2837 if (anArg.IsNull()) {
2838 SetErrorCode("Null shape is given as argument");
2841 anArgs(argi) = anArg;
2843 // For Python command
2844 TDF_Tool::Entry(anObj->GetEntry(), anEntry);
2845 if (argi > 1) aPartsDescr += ", ";
2846 aPartsDescr += anEntry;
2849 //Compute the Block value
2852 // 1. Explode compound on solids
2853 TopTools_MapOfShape mapShape;
2854 Standard_Integer nbSolids = 0;
2855 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2856 for (; exp.More(); exp.Next()) {
2857 if (mapShape.Add(exp.Current())) {
2863 Standard_Integer ind = 1;
2864 TopTools_Array1OfShape aSolids (1, nbSolids);
2865 TColStd_Array1OfInteger aNbParts (1, nbSolids);
2866 for (exp.Init(aBlockOrComp, TopAbs_SOLID); exp.More(); exp.Next(), ind++) {
2867 if (mapShape.Add(exp.Current())) {
2868 TopoDS_Shape aSolid = exp.Current();
2869 aSolids(ind) = aSolid;
2872 // 2. Define quantity of parts, contained in each solid
2873 TopTools_IndexedMapOfShape aSubShapes;
2874 TopExp::MapShapes(aSolid, aSubShapes);
2875 for (argi = 1; argi <= aLen; argi++) {
2876 if (aSubShapes.Contains(anArgs(argi))) {
2883 // 3. Define solid, containing maximum quantity of parts
2884 Standard_Integer maxNb = 0, nbFound = 0;
2885 TopoDS_Shape aShape;
2886 for (ind = 1; ind <= nbSolids; ind++) {
2887 if (aNbParts(ind) > maxNb) {
2888 maxNb = aNbParts(ind);
2889 aShape = aSolids(ind);
2891 } else if (aNbParts(ind) == maxNb) {
2897 SetErrorCode("Multiple blocks, containing maximum quantity of the given parts, are found");
2899 } else if (nbFound == 0) {
2900 SetErrorCode("There are no blocks, containing the given parts");
2903 TopTools_IndexedMapOfShape anIndices;
2904 TopExp::MapShapes(aBlockOrComp, anIndices);
2905 Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
2906 anArray->SetValue(1, anIndices.FindIndex(aShape));
2907 aResult = GetEngine()->AddSubShape(theCompound, anArray);
2909 } catch (Standard_Failure& aFail) {
2910 SetErrorCode(aFail.GetMessageString());
2914 Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
2916 //Make a Python command
2917 GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetBlockByParts("
2918 << theCompound << ", [" << aPartsDescr.ToCString() << "])";
2924 //=============================================================================
2928 //=============================================================================
2929 Handle(TColStd_HSequenceOfTransient) GEOMImpl_IBlocksOperations::GetBlocksByParts
2930 (Handle(GEOM_Object) theCompound,
2931 const Handle(TColStd_HSequenceOfTransient)& theParts)
2935 if (theCompound.IsNull() || theParts.IsNull()) return NULL;
2936 TopoDS_Shape aBlockOrComp = theCompound->GetValue();
2937 if (aBlockOrComp.IsNull()) return NULL;
2939 Handle(TColStd_HSequenceOfTransient) aBlocks = new TColStd_HSequenceOfTransient;
2940 Handle(GEOM_Object) anObj;
2941 Handle(GEOM_Function) aFunction;
2944 Standard_Integer argi, aLen = theParts->Length();
2945 TopTools_Array1OfShape anArgs (1, aLen);
2946 TCollection_AsciiString anEntry, aPartsDescr, anAsciiList;
2948 for (argi = 1; argi <= aLen; argi++) {
2949 Handle(GEOM_Object) anObj = Handle(GEOM_Object)::DownCast(theParts->Value(argi));
2950 Handle(GEOM_Function) aRef = anObj->GetLastFunction();
2951 if (aRef.IsNull()) return NULL;
2953 TopoDS_Shape anArg = aRef->GetValue();
2954 if (anArg.IsNull()) {
2955 SetErrorCode("Null shape is given as argument");
2958 anArgs(argi) = anArg;
2960 // For Python command
2961 TDF_Tool::Entry(anObj->GetEntry(), anEntry);
2962 aPartsDescr += anEntry + ", ";
2968 TopTools_MapOfShape mapShape;
2969 Standard_Integer nbSolids = 0;
2970 TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
2971 for (; exp.More(); exp.Next()) {
2972 if (mapShape.Add(exp.Current())) {
2978 Standard_Integer ind = 1;
2979 TopTools_Array1OfShape aSolids (1, nbSolids);
2980 TColStd_Array1OfInteger aNbParts (1, nbSolids);
2981 for (exp.Init(aBlockOrComp, TopAbs_SOLID); exp.More(); exp.Next(), ind++) {
2982 if (mapShape.Add(exp.Current())) {
2983 TopoDS_Shape aSolid = exp.Current();
2984 aSolids(ind) = aSolid;
2987 // 2. Define quantity of parts, contained in each solid
2988 TopTools_IndexedMapOfShape aSubShapes;
2989 TopExp::MapShapes(aSolid, aSubShapes);
2990 for (argi = 1; argi <= aLen; argi++) {
2991 if (aSubShapes.Contains(anArgs(argi))) {
2998 // 3. Define solid, containing maximum quantity of parts
2999 Standard_Integer maxNb = 0, nbFound = 0;
3000 for (ind = 1; ind <= nbSolids; ind++) {
3001 if (aNbParts(ind) > maxNb) {
3002 maxNb = aNbParts(ind);
3004 } else if (aNbParts(ind) == maxNb) {
3010 SetErrorCode("There are no blocks, containing the given parts");
3015 TopTools_IndexedMapOfShape anIndices;
3016 TopExp::MapShapes(aBlockOrComp, anIndices);
3017 Handle(TColStd_HArray1OfInteger) anArray;
3019 for (ind = 1; ind <= nbSolids; ind++) {
3020 if (aNbParts(ind) == maxNb) {
3021 anArray = new TColStd_HArray1OfInteger(1,1);
3022 anArray->SetValue(1, anIndices.FindIndex(aSolids(ind)));
3023 anObj = GetEngine()->AddSubShape(theCompound, anArray);
3024 aBlocks->Append(anObj);
3026 // For Python command
3027 TDF_Tool::Entry(anObj->GetEntry(), anEntry);
3028 anAsciiList += anEntry + ", ";
3029 if (aFunction.IsNull())
3030 aFunction = anObj->GetLastFunction();
3034 catch (Standard_Failure& aFail) {
3035 SetErrorCode(aFail.GetMessageString());
3039 //Make a Python command
3040 aPartsDescr.Trunc(aPartsDescr.Length() - 2);
3041 anAsciiList.Trunc(anAsciiList.Length() - 2);
3043 GEOM::TPythonDump(aFunction) << "[" << anAsciiList.ToCString()
3044 << "] = geompy.GetBlocksByParts(" << theCompound
3045 << ", [" << aPartsDescr.ToCString() << "])";
3051 //=============================================================================
3053 * MakeMultiTransformation1D
3055 //=============================================================================
3056 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeMultiTransformation1D
3057 (Handle(GEOM_Object) theObject,
3058 const Standard_Integer theDirFace1,
3059 const Standard_Integer theDirFace2,
3060 const Standard_Integer theNbTimes)
3064 if (theObject.IsNull()) return NULL;
3066 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
3067 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be moved
3069 //Add a new Copy object
3070 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GEOM_COPY);
3072 //Add a translate function
3073 Handle(GEOM_Function) aFunction =
3074 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_MULTI_TRANSFORM_1D);
3076 //Check if the function is set correctly
3077 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
3079 GEOMImpl_IBlockTrsf aTI (aFunction);
3080 aTI.SetOriginal(aLastFunction);
3081 aTI.SetFace1U(theDirFace1);
3082 aTI.SetFace2U(theDirFace2);
3083 aTI.SetNbIterU(theNbTimes);
3085 //Compute the transformation
3088 if (!GetSolver()->ComputeFunction(aFunction)) {
3089 SetErrorCode("Block driver failed to make multi-transformation");
3093 catch (Standard_Failure& aFail) {
3094 SetErrorCode(aFail.GetMessageString());
3098 //Make a Python command
3099 GEOM::TPythonDump(aFunction) << aCopy << " = geompy.MakeMultiTransformation1D("
3100 << theObject << ", " << theDirFace1 << ", " << theDirFace2 << ", " << theNbTimes << ")";
3106 //=============================================================================
3108 * MakeMultiTransformation2D
3110 //=============================================================================
3111 Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeMultiTransformation2D
3112 (Handle(GEOM_Object) theObject,
3113 const Standard_Integer theDirFace1U,
3114 const Standard_Integer theDirFace2U,
3115 const Standard_Integer theNbTimesU,
3116 const Standard_Integer theDirFace1V,
3117 const Standard_Integer theDirFace2V,
3118 const Standard_Integer theNbTimesV)
3122 if (theObject.IsNull()) return NULL;
3124 Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
3125 if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be moved
3127 //Add a new Copy object
3128 Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GEOM_COPY);
3130 //Add a translate function
3131 Handle(GEOM_Function) aFunction =
3132 aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_MULTI_TRANSFORM_2D);
3134 //Check if the function is set correctly
3135 if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
3137 GEOMImpl_IBlockTrsf aTI (aFunction);
3138 aTI.SetOriginal(aLastFunction);
3139 aTI.SetFace1U(theDirFace1U);
3140 aTI.SetFace2U(theDirFace2U);
3141 aTI.SetNbIterU(theNbTimesU);
3142 aTI.SetFace1V(theDirFace1V);
3143 aTI.SetFace2V(theDirFace2V);
3144 aTI.SetNbIterV(theNbTimesV);
3146 //Compute the transformation
3149 if (!GetSolver()->ComputeFunction(aFunction)) {
3150 SetErrorCode("Block driver failed to make multi-transformation");
3154 catch (Standard_Failure& aFail) {
3155 SetErrorCode(aFail.GetMessageString());
3159 //Make a Python command
3160 GEOM::TPythonDump(aFunction) << aCopy << " = geompy.MakeMultiTransformation2D("
3161 << theObject << ", " << theDirFace1U << ", " << theDirFace2U << ", " << theNbTimesU
3162 << ", " << theDirFace1V << ", " << theDirFace2V << ", " << theNbTimesV << ")";
3168 //=============================================================================
3172 //=============================================================================
3173 Handle(TColStd_HSequenceOfTransient) GEOMImpl_IBlocksOperations::Propagate
3174 (Handle(GEOM_Object) theShape)
3178 if (theShape.IsNull()) return NULL;
3180 TopoDS_Shape aShape = theShape->GetValue();
3181 if (aShape.IsNull()) return NULL;
3183 TopTools_IndexedMapOfShape anIndices;
3184 TopExp::MapShapes(aShape, anIndices);
3186 TopTools_IndexedDataMapOfShapeListOfShape MEW;
3187 GEOMImpl_Block6Explorer::MapShapesAndAncestors
3188 (aShape, TopAbs_EDGE, TopAbs_WIRE, MEW);
3189 Standard_Integer ie, nbEdges = MEW.Extent();
3192 Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
3194 TopTools_MapOfShape mapAcceptedEdges;
3195 TCollection_AsciiString aListRes, anEntry;
3197 // Sort shapes in current chain (Mantis issue 21053)
3198 TopTools_DataMapOfShapeListOfShape aMapChains;
3199 TopTools_ListOfShape aFirstInChains;
3201 for (ie = 1; ie <= nbEdges; ie++) {
3202 TopoDS_Shape curE = MEW.FindKey(ie);
3204 if (mapAcceptedEdges.Contains(curE)) continue;
3207 TopTools_ListOfShape currentChain;
3208 TopTools_ListOfShape listPrevEdges;
3210 currentChain.Append(curE);
3211 listPrevEdges.Append(curE);
3212 mapAcceptedEdges.Add(curE);
3214 // Collect all edges pass by pass
3215 while (listPrevEdges.Extent() > 0) {
3216 // List of edges, added to chain on this cycle pass
3217 TopTools_ListOfShape listCurEdges;
3219 // Find the next portion of edges
3220 TopTools_ListIteratorOfListOfShape itE (listPrevEdges);
3221 for (; itE.More(); itE.Next()) {
3222 TopoDS_Shape anE = itE.Value();
3224 // Iterate on faces, having edge <anE>
3225 TopTools_ListIteratorOfListOfShape itW (MEW.FindFromKey(anE));
3226 for (; itW.More(); itW.Next()) {
3227 TopoDS_Shape aW = itW.Value();
3228 TopoDS_Shape anOppE;
3230 BRepTools_WireExplorer aWE (TopoDS::Wire(aW));
3231 Standard_Integer nb = 1, found = 0;
3232 TopTools_Array1OfShape anEdges (1,4);
3233 for (; aWE.More(); aWE.Next(), nb++) {
3238 anEdges(nb) = aWE.Current();
3239 if (anEdges(nb).IsSame(anE)) found = nb;
3242 if (nb == 5 && found > 0) {
3243 // Quadrangle face found, get an opposite edge
3244 Standard_Integer opp = found + 2;
3245 if (opp > 4) opp -= 4;
3246 anOppE = anEdges(opp);
3248 if (!mapAcceptedEdges.Contains(anOppE)) {
3249 // Add found edge to the chain
3250 currentChain.Append(anOppE);
3251 listCurEdges.Append(anOppE);
3252 mapAcceptedEdges.Add(anOppE);
3254 } // if (nb == 5 && found > 0)
3255 } // for (; itF.More(); itF.Next())
3256 } // for (; itE.More(); itE.Next())
3258 listPrevEdges = listCurEdges;
3259 } // while (listPrevEdges.Extent() > 0)
3261 // Sort shapes in current chain (Mantis issue 21053)
3262 GEOMUtils::SortShapes(currentChain, Standard_False);
3263 aFirstInChains.Append(currentChain.First());
3264 aMapChains.Bind(currentChain.First(), currentChain);
3267 // Sort chains (Mantis issue 21053)
3268 GEOMUtils::SortShapes(aFirstInChains, Standard_False);
3270 // Store sorted chains in the document
3271 TopTools_ListIteratorOfListOfShape aChainsIt (aFirstInChains);
3272 for (; aChainsIt.More(); aChainsIt.Next()) {
3273 TopoDS_Shape aFirstInChain = aChainsIt.Value();
3274 const TopTools_ListOfShape& currentChain = aMapChains.Find(aFirstInChain);
3276 // Store the chain in the document
3277 Handle(TColStd_HArray1OfInteger) anArray =
3278 new TColStd_HArray1OfInteger (1, currentChain.Extent());
3280 // Fill array of sub-shape indices
3281 TopTools_ListIteratorOfListOfShape itSub (currentChain);
3282 for (int index = 1; itSub.More(); itSub.Next(), ++index) {
3283 int id = anIndices.FindIndex(itSub.Value());
3284 anArray->SetValue(index, id);
3287 // Add a new group object
3288 Handle(GEOM_Object) aChain = GetEngine()->AddSubShape(theShape, anArray);
3291 aChain->SetType(GEOM_GROUP);
3293 // Set a sub-shape type
3294 TDF_Label aFreeLabel = aChain->GetFreeLabel();
3295 TDataStd_Integer::Set(aFreeLabel, (Standard_Integer)TopAbs_EDGE);
3297 // Add the chain to the result
3298 aSeq->Append(aChain);
3300 //Make a Python command
3301 TDF_Tool::Entry(aChain->GetEntry(), anEntry);
3302 aListRes += anEntry + ", ";
3305 if (aSeq->IsEmpty()) {
3306 SetErrorCode("There are no quadrangle faces in the shape");
3310 aListRes.Trunc(aListRes.Length() - 2);
3312 // The Propagation doesn't change object so no new function is required.
3313 Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
3315 // Make a Python command
3316 GEOM::TPythonDump(aFunction, /*append=*/true)
3317 << "[" << aListRes.ToCString() << "] = geompy.Propagate(" << theShape << ")";