-using namespace std;
-
-#include "GEOMImpl_IBlocksOperations.hxx"
-
-#include "GEOMImpl_Types.hxx"
-
-#include "GEOMImpl_BlockDriver.hxx"
-#include "GEOMImpl_IBlocks.hxx"
-#include "GEOMImpl_IBlockTrsf.hxx"
-#include "GEOMImpl_CopyDriver.hxx"
-#include "GEOMImpl_Block6Explorer.hxx"
-
-#include "GEOM_Function.hxx"
+// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE
+//
+// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#ifdef WIN32
+#pragma warning( disable:4786 )
+#endif
+
+#include <Standard_Stream.hxx>
+
+#include <GEOMImpl_IBlocksOperations.hxx>
+
+#include <GEOMImpl_Types.hxx>
+
+#include <GEOMImpl_BlockDriver.hxx>
+#include <GEOMImpl_IBlocks.hxx>
+#include <GEOMImpl_IBlockTrsf.hxx>
+#include <GEOMImpl_Block6Explorer.hxx>
+
+#include <GEOMUtils.hxx>
+
+#include <GEOM_Function.hxx>
+#include <GEOM_PythonDump.hxx>
+
+#include <GEOMAlgo_GlueAnalyser.hxx>
+#include <GEOMAlgo_CoupleOfShapes.hxx>
+#include <GEOMAlgo_ListOfCoupleOfShapes.hxx>
+#include <GEOMAlgo_ListIteratorOfListOfCoupleOfShapes.hxx>
+#include <BlockFix_CheckTool.hxx>
+
+#include <Basics_OCCTVersion.hxx>
#include "utilities.h"
-#include "OpUtil.hxx"
-#include "Utils_ExceptHandlers.hxx"
+#include <OpUtil.hxx>
+#include <Utils_ExceptHandlers.hxx>
#include <TFunction_DriverTable.hxx>
#include <TFunction_Driver.hxx>
#include <TFunction_Logbook.hxx>
+#include <TDataStd_Integer.hxx>
#include <TDF_Tool.hxx>
#include <BRep_Tool.hxx>
+#include <BRep_Builder.hxx>
#include <BRepTools.hxx>
+#include <BRepTools_WireExplorer.hxx>
#include <BRepGProp.hxx>
#include <BRepBndLib.hxx>
#include <BRepAdaptor_Surface.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Vertex.hxx>
+#include <TopoDS_Compound.hxx>
#include <TopoDS_Iterator.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopTools_MapOfShape.hxx>
#include <TopTools_Array1OfShape.hxx>
#include <TopTools_IndexedMapOfShape.hxx>
+#include <TopTools_DataMapOfShapeInteger.hxx>
#include <TopTools_ListIteratorOfListOfShape.hxx>
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
+#include <TopTools_DataMapIteratorOfDataMapOfShapeInteger.hxx>
#include <Bnd_Box.hxx>
-#include <Precision.hxx>
#include <GProp_GProps.hxx>
+
+#include <Geom_Curve.hxx>
+#include <Geom_Surface.hxx>
+#include <ShapeAnalysis_Surface.hxx>
+
#include <TColStd_MapOfInteger.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <TColStd_Array2OfInteger.hxx>
+//#include <OSD_Timer.hxx>
+
+#include <Precision.hxx>
+
+#include <Standard_Failure.hxx>
#include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC
+
+/**
+ * This function returns Standard_True if the face is quadrangular. It means
+ * that it has only 1 wire with 4 edges. If there are more then 4 edges in
+ * the wire and theToleranceC1 is not negative the new implementation is used.
+ * According to it the face is quadrangular if it is quadrangular according to
+ * an old implementation or if it has a single wire with more then 4 edges
+ * that form exactly 4 bounds of C1 continuity with the given tolerance.
+ *
+ * \param theFace the face to be checked
+ * \param theToleranceC1 if negative, it is not used; otherwise it is used
+ * to check if two neighbor edges of face have C1 continuity.
+ * \return Standard_True if the face is quadrangular; Standard_False otherwise.
+ */
+static Standard_Boolean IsQuadrangle(const TopoDS_Face &theFace,
+ const Standard_Real theToleranceC1)
+{
+ TopExp_Explorer aFExp (theFace, TopAbs_WIRE);
+
+ if (!aFExp.More()) {
+ // no wire in the face
+ return Standard_False;
+ }
+
+ TopoDS_Shape aWire = aFExp.Current();
+
+ aFExp.Next();
+
+ if (aFExp.More()) {
+ // multiple wires in the face
+ return Standard_False;
+ }
+
+ // Check number of edges in the face
+ Standard_Integer aNbEdges = 0;
+ TopTools_MapOfShape aMapEdges;
+ TopExp_Explorer aWExp(aWire, TopAbs_EDGE);
+
+ for (; aWExp.More(); aWExp.Next()) {
+ if (aMapEdges.Add(aWExp.Current())) {
+ aNbEdges++;
+
+ if (aNbEdges > 4) {
+ break;
+ }
+ }
+ }
+
+ if (aNbEdges < 4) {
+ return Standard_False;
+ }
+
+ if (aNbEdges > 4) {
+ if (theToleranceC1 < 0.) {
+ return Standard_False;
+ }
+
+ // Check if a wire has 4 bounds of C1 continuity.
+ BRepTools_WireExplorer aWireExp(TopoDS::Wire(aWire), theFace);
+ TopTools_ListOfShape anEdges;
+
+ for (aNbEdges = 0; aWireExp.More(); aWireExp.Next()) {
+ const TopoDS_Edge &anEdge = aWireExp.Current();
+
+ // Skip degenerated edges.
+ if (!BRep_Tool::Degenerated(anEdge)) {
+ anEdges.Append(anEdge);
+ ++aNbEdges;
+ }
+ }
+
+ if (aNbEdges < 4) {
+ return Standard_False;
+ }
+
+ // Compute number of sharp corners.
+ anEdges.Append(anEdges.First()); // To make a loop.
+
+ TopTools_ListIteratorOfListOfShape anIter(anEdges);
+ Standard_Real aPar[2];
+ Standard_Integer aNbCorners = 0;
+ TopoDS_Edge anEdge1 = TopoDS::Edge(anEdges.First());
+ Handle(Geom_Curve) aCurve1 = BRep_Tool::Curve(anEdge1, aPar[0], aPar[1]);
+ Handle(Geom_Curve) aCurve2;
+ TopoDS_Edge anEdge2;
+ TopoDS_Vertex aCommonVtx;
+ gp_Pnt aPnt;
+ gp_Vec aVec1;
+ gp_Vec aVec2;
+ Standard_Boolean isReversed1 = (anEdge1.Orientation() == TopAbs_REVERSED);
+ Standard_Boolean isReversed2;
+
+ for (anIter.Next(); anIter.More(); anIter.Next()) {
+ TopoDS_Edge anEdge2 = TopoDS::Edge(anIter.Value());
+
+ if (!TopExp::CommonVertex(anEdge1, anEdge2, aCommonVtx)) {
+ // NEVERREACHED
+ return Standard_False;
+ }
+
+ // Check the angle between tangent vectors of 2 curves at this point.
+ Standard_Real aParam1 = BRep_Tool::Parameter(aCommonVtx, anEdge1);
+ Standard_Real aParam2 = BRep_Tool::Parameter(aCommonVtx, anEdge2);
+
+ aCurve2 = BRep_Tool::Curve(anEdge2, aPar[0], aPar[1]);
+ isReversed2 = (anEdge2.Orientation() == TopAbs_REVERSED);
+ aCurve1->D1(aParam1, aPnt, aVec1);
+ aCurve2->D1(aParam2, aPnt, aVec2);
+
+ if (isReversed1) {
+ aVec1.Reverse();
+ }
+
+ if (isReversed2) {
+ aVec2.Reverse();
+ }
+ const Standard_Real anAngle = aVec1.Angle(aVec2);
+
+ if (anAngle > theToleranceC1) {
+ ++aNbCorners;
+
+ if (aNbCorners > 4) {
+ break;
+ }
+ }
+
+ // Go to the next couple of edges.
+ anEdge1 = anEdge2;
+ aCurve1 = aCurve2;
+ isReversed1 = isReversed2;
+ }
+
+ // Check the total number of corners.
+ if (aNbCorners != 4) {
+ return Standard_False;
+ }
+ }
+
+ return Standard_True;
+}
+
//=============================================================================
/*!
* constructor:
//Compute the Face value
try {
+ OCC_CATCH_SIGNALS;
if (!GetSolver()->ComputeFunction(aFunction)) {
SetErrorCode("Block driver failed to compute a face");
return NULL;
}
//Make a Python command
- TCollection_AsciiString anEntry, aDescr;
- TDF_Tool::Entry(aFace->GetEntry(), anEntry);
- aDescr += anEntry + " = IBlocksOperations.MakeQuad(";
- TDF_Tool::Entry(theEdge1->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(theEdge2->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(theEdge3->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(theEdge4->GetEntry(), anEntry);
- aDescr += anEntry + ")";
-
- aFunction->SetDescription(aDescr);
+ GEOM::TPythonDump(aFunction) << aFace << " = geompy.MakeQuad("
+ << theEdge1 << ", " << theEdge2 << ", " << theEdge3 << ", " << theEdge4 << ")";
SetErrorCode(OK);
return aFace;
//Compute the Face value
try {
+ OCC_CATCH_SIGNALS;
if (!GetSolver()->ComputeFunction(aFunction)) {
SetErrorCode("Block driver failed to compute a face");
return NULL;
}
//Make a Python command
- TCollection_AsciiString anEntry, aDescr;
- TDF_Tool::Entry(aFace->GetEntry(), anEntry);
- aDescr += anEntry + " = IBlocksOperations.MakeQuad2Edges(";
- TDF_Tool::Entry(theEdge1->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(theEdge2->GetEntry(), anEntry);
- aDescr += anEntry + ")";
-
- aFunction->SetDescription(aDescr);
+ GEOM::TPythonDump(aFunction) << aFace << " = geompy.MakeQuad2Edges("
+ << theEdge1 << ", " << theEdge2 << ")";
SetErrorCode(OK);
return aFace;
//Compute the Face value
try {
+ OCC_CATCH_SIGNALS;
if (!GetSolver()->ComputeFunction(aFunction)) {
SetErrorCode("Block driver failed to compute a face");
return NULL;
}
//Make a Python command
- TCollection_AsciiString anEntry, aDescr;
- TDF_Tool::Entry(aFace->GetEntry(), anEntry);
- aDescr += anEntry + " = IBlocksOperations.MakeQuad4Vertices(";
- TDF_Tool::Entry(thePnt1->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(thePnt2->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(thePnt3->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(thePnt4->GetEntry(), anEntry);
- aDescr += anEntry + ")";
-
- aFunction->SetDescription(aDescr);
+ GEOM::TPythonDump(aFunction) << aFace << " = geompy.MakeQuad4Vertices("
+ << thePnt1 << ", " << thePnt2 << ", " << thePnt3 << ", " << thePnt4 << ")";
SetErrorCode(OK);
return aFace;
//Compute the Block value
try {
+ OCC_CATCH_SIGNALS;
if (!GetSolver()->ComputeFunction(aFunction)) {
SetErrorCode("Block driver failed to compute a block");
return NULL;
}
//Make a Python command
- TCollection_AsciiString anEntry, aDescr;
- TDF_Tool::Entry(aBlock->GetEntry(), anEntry);
- aDescr += anEntry + " = IBlocksOperations.MakeHexa(";
- TDF_Tool::Entry(theFace1->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(theFace2->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(theFace3->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(theFace4->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(theFace5->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(theFace6->GetEntry(), anEntry);
- aDescr += anEntry + ")";
-
- aFunction->SetDescription(aDescr);
+ GEOM::TPythonDump(aFunction) << aBlock << " = geompy.MakeHexa("
+ << theFace1 << ", " << theFace2 << ", " << theFace3 << ", "
+ << theFace4 << ", " << theFace5 << ", " << theFace6 << ")";
SetErrorCode(OK);
return aBlock;
//Compute the Block value
try {
+ OCC_CATCH_SIGNALS;
if (!GetSolver()->ComputeFunction(aFunction)) {
SetErrorCode("Block driver failed to compute a block");
return NULL;
}
//Make a Python command
- TCollection_AsciiString anEntry, aDescr;
- TDF_Tool::Entry(aBlock->GetEntry(), anEntry);
- aDescr += anEntry + " = IBlocksOperations.MakeHexa2Faces(";
- TDF_Tool::Entry(theFace1->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(theFace2->GetEntry(), anEntry);
- aDescr += anEntry + ")";
-
- aFunction->SetDescription(aDescr);
+ GEOM::TPythonDump(aFunction) << aBlock << " = geompy.MakeHexa2Faces("
+ << theFace1 << ", " << theFace2 << ")";
SetErrorCode(OK);
return aBlock;
//Compute the Blocks Compound value
try {
+ OCC_CATCH_SIGNALS;
if (!GetSolver()->ComputeFunction(aFunction)) {
SetErrorCode("Block driver failed to compute a blocks compound");
return NULL;
}
//Make a Python command
- TCollection_AsciiString anEntry, aDescr;
- TDF_Tool::Entry(aBlockComp->GetEntry(), anEntry);
- aDescr += anEntry + " = IBlocksOperations.MakeBlockCompound(";
- TDF_Tool::Entry(theCompound->GetEntry(), anEntry);
- aDescr += anEntry + ")";
-
- aFunction->SetDescription(aDescr);
+ GEOM::TPythonDump(aFunction) << aBlockComp
+ << " = geompy.MakeBlockCompound(" << theCompound << ")";
SetErrorCode(OK);
return aBlockComp;
//=============================================================================
/*!
- * GetEdge
+ * GetPoint
*/
//=============================================================================
Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetPoint
TopoDS_Shape aBlockOrComp = theShape->GetValue();
if (aBlockOrComp.IsNull()) {
- SetErrorCode("Block or compound is null");
- return NULL;
- }
- if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
- aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
- aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
- SetErrorCode("Shape is neither a block, nor a compound of blocks");
+ SetErrorCode("Given shape is null");
return NULL;
}
Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
//Make a Python command
- TCollection_AsciiString anEntry, aDescr;
- TDF_Tool::Entry(aResult->GetEntry(), anEntry);
- aDescr += anEntry + " = IBlocksOperations.GetPoint(";
- TDF_Tool::Entry(theShape->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- aDescr += TCollection_AsciiString(theX) + ", ";
- aDescr += TCollection_AsciiString(theY) + ", ";
- aDescr += TCollection_AsciiString(theZ) + ", ";
- aDescr += TCollection_AsciiString(theEpsilon) + ")";
-
- TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
- aNewDescr += aDescr;
- aFunction->SetDescription(aNewDescr);
+ GEOM::TPythonDump(aFunction, /*append=*/true)
+ << aResult << " = geompy.GetPoint(" << theShape << ", "
+ << theX << ", " << theY << ", " << theZ << ", " << theEpsilon << ")";
+
+ SetErrorCode(OK);
+ return aResult;
+}
+
+//=============================================================================
+/*!
+ * GetVertexNearPoint
+ */
+//=============================================================================
+Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetVertexNearPoint
+ (Handle(GEOM_Object) theShape,
+ Handle(GEOM_Object) thePoint)
+{
+ SetErrorCode(KO);
+
+ // New Point object
+ Handle(GEOM_Object) aResult;
+
+ // Arguments
+ if (theShape.IsNull() || thePoint.IsNull()) return NULL;
+
+ TopoDS_Shape aBlockOrComp = theShape->GetValue();
+ TopoDS_Shape aPoint = thePoint->GetValue();
+ if (aBlockOrComp.IsNull() || aPoint.IsNull()) {
+ SetErrorCode("Given shape is null");
+ return NULL;
+ }
+
+ if (aPoint.ShapeType() != TopAbs_VERTEX) {
+ SetErrorCode("Element for vertex identification is not a vertex");
+ return NULL;
+ }
+
+ TopoDS_Vertex aVert = TopoDS::Vertex(aPoint);
+ gp_Pnt aP = BRep_Tool::Pnt(aVert);
+
+ // Compute the Vertex value
+ TopoDS_Shape V;
+ bool isFound = false;
+ Standard_Real aDist = RealLast();
+ TopTools_MapOfShape mapShape;
+
+ TopExp_Explorer exp (aBlockOrComp, TopAbs_VERTEX);
+ for (; exp.More(); exp.Next()) {
+ if (mapShape.Add(exp.Current())) {
+ TopoDS_Vertex aVi = TopoDS::Vertex(exp.Current());
+ gp_Pnt aPi = BRep_Tool::Pnt(aVi);
+ Standard_Real aDisti = aPi.Distance(aP);
+ if (aDisti < aDist) {
+ V = aVi;
+ aDist = aDisti;
+ isFound = true;
+ }
+ }
+ }
+
+ if (!isFound) {
+ SetErrorCode("Vertex has not been found");
+ return NULL;
+ }
+
+ TopTools_IndexedMapOfShape anIndices;
+ TopExp::MapShapes(aBlockOrComp, anIndices);
+ Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
+ anArray->SetValue(1, anIndices.FindIndex(V));
+ aResult = GetEngine()->AddSubShape(theShape, anArray);
+
+ Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
+
+ // Make a Python command
+ GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetVertexNearPoint("
+ << theShape << ", " << thePoint << ")";
SetErrorCode(OK);
return aResult;
TopoDS_Shape aBlockOrComp = theShape->GetValue();
if (aBlockOrComp.IsNull()) {
- SetErrorCode("Block or compound is null");
- return NULL;
- }
- if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
- aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
- aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
- SetErrorCode("Shape is neither a block, nor a compound of blocks");
+ SetErrorCode("Given shape is null");
return NULL;
}
//Compute the Edge value
try {
+ OCC_CATCH_SIGNALS;
TopTools_IndexedDataMapOfShapeListOfShape MVE;
GEOMImpl_Block6Explorer::MapShapesAndAncestors
(aBlockOrComp, TopAbs_VERTEX, TopAbs_EDGE, MVE);
return NULL;
}
- //The GetEdge() doesn't change object so no new function is required.
- Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
+ Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
//Make a Python command
- TCollection_AsciiString anEntry, aDescr;
- TDF_Tool::Entry(aResult->GetEntry(), anEntry);
- aDescr += anEntry + " = IBlocksOperations.GetEdge(";
- TDF_Tool::Entry(theShape->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(thePoint1->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(thePoint2->GetEntry(), anEntry);
- aDescr += anEntry + ")";
-
- TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
- aNewDescr += aDescr;
- aFunction->SetDescription(aNewDescr);
+ GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetEdge("
+ << theShape << ", " << thePoint1 << ", " << thePoint2 << ")";
SetErrorCode(OK);
return aResult;
TopoDS_Shape aBlockOrComp = theShape->GetValue();
if (aBlockOrComp.IsNull()) {
- SetErrorCode("Block or compound is null");
- return NULL;
- }
- if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
- aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
- aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
- SetErrorCode("Shape is neither a block, nor a compound of blocks");
+ SetErrorCode("Given shape is null");
return NULL;
}
//Compute the Edge value
try {
- TopoDS_Shape aShape;
-
+ OCC_CATCH_SIGNALS;
TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
+ TopoDS_Shape aShape = GEOMUtils::GetEdgeNearPoint(aBlockOrComp, aVert);
- // 1. Explode blocks on edges
- TopTools_MapOfShape mapShape;
- Standard_Integer nbEdges = 0;
- TopExp_Explorer exp (aBlockOrComp, TopAbs_EDGE);
- for (; exp.More(); exp.Next()) {
- if (mapShape.Add(exp.Current())) {
- nbEdges++;
- }
- }
-
- mapShape.Clear();
- Standard_Integer ind = 1;
- TopTools_Array1OfShape anEdges (1, nbEdges);
- TColStd_Array1OfReal aDistances (1, nbEdges);
- for (exp.Init(aBlockOrComp, TopAbs_EDGE); exp.More(); exp.Next()) {
- if (mapShape.Add(exp.Current())) {
- TopoDS_Shape anEdge = exp.Current();
- anEdges(ind) = anEdge;
-
- // 2. Classify the point relatively each edge
- BRepExtrema_DistShapeShape aDistTool (aVert, anEdges(ind));
- if (!aDistTool.IsDone()) {
- SetErrorCode("Can not find a distance from the given point to one of edges");
- return NULL;
- }
- aDistances(ind) = aDistTool.Value();
- ind++;
- }
- }
-
- // 3. Define edge, having minimum distance to the point
- Standard_Real nearest = RealLast(), nbFound = 0;
- Standard_Real prec = Precision::Confusion();
- for (ind = 1; ind <= nbEdges; ind++) {
- if (Abs(aDistances(ind) - nearest) < prec) {
- nbFound++;
- } else if (aDistances(ind) < nearest) {
- nearest = aDistances(ind);
- aShape = anEdges(ind);
- nbFound = 1;
- } else {
- }
- }
- if (nbFound > 1) {
- SetErrorCode("Multiple edges near the given point are found");
- return NULL;
- } else if (nbFound == 0) {
- SetErrorCode("There are no edges near the given point");
- return NULL;
- } else {
- TopTools_IndexedMapOfShape anIndices;
- TopExp::MapShapes(aBlockOrComp, anIndices);
- Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
- anArray->SetValue(1, anIndices.FindIndex(aShape));
- aResult = GetEngine()->AddSubShape(theShape, anArray);
- }
+ TopTools_IndexedMapOfShape anIndices;
+ TopExp::MapShapes(aBlockOrComp, anIndices);
+ Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
+ anArray->SetValue(1, anIndices.FindIndex(aShape));
+ aResult = GetEngine()->AddSubShape(theShape, anArray);
}
catch (Standard_Failure) {
Handle(Standard_Failure) aFail = Standard_Failure::Caught();
return NULL;
}
- //The GetEdgeNearPoint() doesn't change object so no new function is required.
- Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
+ Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
//Make a Python command
- TCollection_AsciiString anEntry, aDescr;
- TDF_Tool::Entry(aResult->GetEntry(), anEntry);
- aDescr += anEntry + " = IBlocksOperations.GetEdgeNearPoint(";
- TDF_Tool::Entry(theShape->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(thePoint->GetEntry(), anEntry);
- aDescr += anEntry + ")";
-
- TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
- aNewDescr += aDescr;
- aFunction->SetDescription(aNewDescr);
+ GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetEdgeNearPoint("
+ << theShape << ", " << thePoint << ")";
SetErrorCode(OK);
return aResult;
SetErrorCode("Block or compound is null");
return NULL;
}
- if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
- aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
- aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
- SetErrorCode("Shape is neither a block, nor a compound of blocks");
- return NULL;
- }
TopoDS_Shape anArg1 = thePoint1->GetValue();
TopoDS_Shape anArg2 = thePoint2->GetValue();
//Compute the Face value
try {
+ OCC_CATCH_SIGNALS;
TopoDS_Shape aShape;
TopTools_IndexedDataMapOfShapeListOfShape MVF;
return NULL;
}
- //The GetFaceByPoints() doesn't change object so no new function is required.
- Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
+ Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
//Make a Python command
- TCollection_AsciiString anEntry, aDescr;
- TDF_Tool::Entry(aResult->GetEntry(), anEntry);
- aDescr += anEntry + " = IBlocksOperations.GetFaceByPoints(";
- TDF_Tool::Entry(theShape->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(thePoint1->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(thePoint2->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(thePoint3->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(thePoint4->GetEntry(), anEntry);
- aDescr += anEntry + ")";
-
- TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
- aNewDescr += aDescr;
- aFunction->SetDescription(aNewDescr);
+ GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceByPoints("
+ << theShape << ", " << thePoint1 << ", " << thePoint2
+ << ", " << thePoint3 << ", " << thePoint4 << ")";
SetErrorCode(OK);
return aResult;
SetErrorCode("Block or compound is null");
return NULL;
}
- if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
- aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
- aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
- SetErrorCode("Shape is neither a block, nor a compound of blocks");
- return NULL;
- }
TopoDS_Shape anArg1 = theEdge1->GetValue();
TopoDS_Shape anArg2 = theEdge2->GetValue();
//Compute the Face value
try {
+ OCC_CATCH_SIGNALS;
TopoDS_Shape aShape;
TopTools_IndexedDataMapOfShapeListOfShape MEF;
return NULL;
}
- //The GetFaceByEdges() doesn't change object so no new function is required.
- Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
+ Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
//Make a Python command
- TCollection_AsciiString anEntry, aDescr;
- TDF_Tool::Entry(aResult->GetEntry(), anEntry);
- aDescr += anEntry + " = IBlocksOperations.GetFaceByEdges(";
- TDF_Tool::Entry(theShape->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(theEdge1->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(theEdge2->GetEntry(), anEntry);
- aDescr += anEntry + ")";
-
- TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
- aNewDescr += aDescr;
- aFunction->SetDescription(aNewDescr);
+ GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceByEdges("
+ << theShape << ", " << theEdge1 << ", " << theEdge2 << ")";
SetErrorCode(OK);
return aResult;
//Compute the Face value
try {
+ OCC_CATCH_SIGNALS;
TopoDS_Shape aShape;
GEOMImpl_Block6Explorer aBlockTool;
return NULL;
}
- //The GetOppositeFace() doesn't change object so no new function is required.
- Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
+ Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
//Make a Python command
- TCollection_AsciiString anEntry, aDescr;
- TDF_Tool::Entry(aResult->GetEntry(), anEntry);
- aDescr += anEntry + " = IBlocksOperations.GetOppositeFace(";
- TDF_Tool::Entry(theShape->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(theFace->GetEntry(), anEntry);
- aDescr += anEntry + ")";
-
- TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
- aNewDescr += aDescr;
- aFunction->SetDescription(aNewDescr);
+ GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetOppositeFace("
+ << theShape << ", " << theFace << ")";
SetErrorCode(OK);
return aResult;
SetErrorCode("Block or compound is null");
return NULL;
}
- if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
- aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
- aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
- SetErrorCode("Shape is neither a block, nor a compound of blocks");
- return NULL;
- }
TopoDS_Shape anArg = thePoint->GetValue();
if (anArg.IsNull()) {
//Compute the Face value
try {
+ OCC_CATCH_SIGNALS;
TopoDS_Shape aShape;
TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
gp_Pnt aPnt = BRep_Tool::Pnt(aVert);
+ Standard_Real PX, PY, PZ;
+ aPnt.Coord(PX, PY, PZ);
- // 1. Explode blocks on faces
- TopTools_MapOfShape mapShape;
- Standard_Integer nbFaces = 0;
+ // 1. Classify the point relatively each face
+ Standard_Integer nearest = 2, nbFound = 0;
+ TopTools_DataMapOfShapeInteger mapShapeDist;
TopExp_Explorer exp (aBlockOrComp, TopAbs_FACE);
for (; exp.More(); exp.Next()) {
- if (mapShape.Add(exp.Current())) {
- nbFaces++;
- }
- }
+ TopoDS_Shape aFace = exp.Current();
+
+ if (!mapShapeDist.IsBound(aFace)) {
+ Standard_Integer aDistance = 2;
+
+ // 1.a. Classify relatively Surface
+ Handle(Geom_Surface) aSurf = BRep_Tool::Surface(TopoDS::Face(aFace));
+ Handle(ShapeAnalysis_Surface) aSurfAna = new ShapeAnalysis_Surface (aSurf);
+ gp_Pnt2d p2dOnSurf = aSurfAna->ValueOfUV(aPnt, Precision::Confusion());
+ gp_Pnt p3dOnSurf = aSurfAna->Value(p2dOnSurf);
+ Standard_Real aDist = p3dOnSurf.Distance(aPnt);
+ if (aDist > Precision::Confusion()) {
+ // OUT of Surface
+ aDistance = 1;
+ } else {
+ // 1.b. Classify relatively the face itself
+ BRepClass_FaceClassifier FC (TopoDS::Face(aFace), p2dOnSurf, Precision::Confusion());
+ if (FC.State() == TopAbs_IN) {
+ aDistance = -1;
+ } else if (FC.State() == TopAbs_ON) {
+ aDistance = 0;
+ } else { // OUT
+ aDistance = 1;
+ }
+ }
- mapShape.Clear();
- Standard_Integer ind = 1;
- TopTools_Array1OfShape aFaces (1, nbFaces);
- TColStd_Array1OfInteger aDistances (1, nbFaces);
- for (exp.Init(aBlockOrComp, TopAbs_FACE); exp.More(); exp.Next()) {
- if (mapShape.Add(exp.Current())) {
- TopoDS_Shape aFace = exp.Current();
- aFaces(ind) = aFace;
-
- // 2. Classify the point relatively each face
- BRepClass_FaceClassifier FC (TopoDS::Face(aFace), aPnt, Precision::Confusion());
- if (FC.State() == TopAbs_IN) {
- aDistances(ind) = -1;
- } else if (FC.State() == TopAbs_ON) {
- aDistances(ind) = 0;
- } else { // OUT
- aDistances(ind) = 1;
+ if (aDistance < nearest) {
+ nearest = aDistance;
+ aShape = aFace;
+ nbFound = 1;
+
+ // A first found face, containing the point inside, will be returned.
+ // It is the solution, if there are no
+ // coincident or intersecting faces in the compound.
+ if (nearest == -1) break;
+
+ } else if (aDistance == nearest) {
+ nbFound++;
+ } else {
}
- ind++;
- }
- }
- // 3. Define face, containing the point or having minimum distance to it
- Standard_Integer nearest = 2, nbFound = 0;
- for (ind = 1; ind <= nbFaces; ind++) {
- if (aDistances(ind) < nearest) {
- nearest = aDistances(ind);
- aShape = aFaces(ind);
- nbFound = 1;
- } else if (aDistances(ind) == nearest) {
- nbFound++;
- } else {
- }
+ mapShapeDist.Bind(aFace, aDistance);
+ } // if (!mapShapeDist.IsBound(aFace))
}
+
+ // 2. Define face, containing the point or having minimum distance to it
if (nbFound > 1) {
if (nearest == 0) {
// The point is on boundary of some faces and there are
// The point is outside some faces and there are
// no faces, having the point inside or on boundary.
// We will get a nearest face
- Standard_Real minDist = RealLast();
- for (ind = 1; ind <= nbFaces; ind++) {
- if (aDistances(ind) == 1) {
- BRepExtrema_DistShapeShape aDistTool (aVert, aFaces(ind));
- if (!aDistTool.IsDone()) {
- SetErrorCode("Can not find a distance from the given point to one of faces");
- return NULL;
- }
- Standard_Real aDist = aDistTool.Value();
- if (aDist < minDist) {
- minDist = aDist;
- aShape = aFaces(ind);
+ Standard_Real bigReal = RealLast();
+ Standard_Real minDist = bigReal;
+ TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
+ for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
+ if (mapShapeDistIter.Value() == 1) {
+ TopoDS_Shape aFace = mapShapeDistIter.Key();
+ Standard_Real aDist = bigReal;
+
+ // 2.a. Fast check of distance - if point projection on surface is on face
+ Handle(Geom_Surface) aSurf = BRep_Tool::Surface(TopoDS::Face(aFace));
+ Handle(ShapeAnalysis_Surface) aSurfAna = new ShapeAnalysis_Surface (aSurf);
+ gp_Pnt2d p2dOnSurf = aSurfAna->ValueOfUV(aPnt, Precision::Confusion());
+ gp_Pnt p3dOnSurf = aSurfAna->Value(p2dOnSurf);
+ aDist = p3dOnSurf.Distance(aPnt);
+
+ BRepClass_FaceClassifier FC (TopoDS::Face(aFace), p2dOnSurf, Precision::Confusion());
+ if (FC.State() == TopAbs_OUT) {
+ if (aDist < minDist) {
+ // 2.b. Slow check - if point projection on surface is outside of face
+ BRepExtrema_DistShapeShape aDistTool (aVert, aFace);
+ if (!aDistTool.IsDone()) {
+ SetErrorCode("Can not find a distance from the given point to one of faces");
+ return NULL;
+ }
+ aDist = aDistTool.Value();
+ } else {
+ aDist = bigReal;
+ }
}
- }
- }
- } else { // nearest == -1
- // The point is inside some faces.
- // We will get a face with nearest center
- Standard_Real minDist = RealLast();
- for (ind = 1; ind <= nbFaces; ind++) {
- if (aDistances(ind) == -1) {
- GProp_GProps aSystem;
- BRepGProp::SurfaceProperties(aFaces(ind), aSystem);
- gp_Pnt aCenterMass = aSystem.CentreOfMass();
- Standard_Real aDist = aCenterMass.Distance(aPnt);
if (aDist < minDist) {
minDist = aDist;
- aShape = aFaces(ind);
+ aShape = aFace;
}
}
}
+ } else { // nearest == -1
+// // The point is inside some faces.
+// // We will get a face with nearest center
+// Standard_Real minDist = RealLast();
+// TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
+// for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
+// if (mapShapeDistIter.Value() == -1) {
+// TopoDS_Shape aFace = mapShapeDistIter.Key();
+// GProp_GProps aSystem;
+// BRepGProp::SurfaceProperties(aFace, aSystem);
+// gp_Pnt aCenterMass = aSystem.CentreOfMass();
+//
+// Standard_Real aDist = aCenterMass.Distance(aPnt);
+// if (aDist < minDist) {
+// minDist = aDist;
+// aShape = aFace;
+// }
+// }
+// }
}
- }
+ } // if (nbFound > 1)
if (nbFound == 0) {
SetErrorCode("There are no faces near the given point");
return NULL;
}
- //The GetFaceNearPoint() doesn't change object so no new function is required.
- Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
+ Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
//Make a Python command
- TCollection_AsciiString anEntry, aDescr;
- TDF_Tool::Entry(aResult->GetEntry(), anEntry);
- aDescr += anEntry + " = IBlocksOperations.GetFaceNearPoint(";
- TDF_Tool::Entry(theShape->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(thePoint->GetEntry(), anEntry);
- aDescr += anEntry + ")";
-
- TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
- aNewDescr += aDescr;
- aFunction->SetDescription(aNewDescr);
+ GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceNearPoint("
+ << theShape << ", " << thePoint << ")";
SetErrorCode(OK);
return aResult;
SetErrorCode("Block or compound is null");
return NULL;
}
- if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
- aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
- aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
- SetErrorCode("Shape is neither a block, nor a compound of blocks");
- return NULL;
- }
TopoDS_Shape anArg = theVector->GetValue();
if (anArg.IsNull()) {
//Compute the Face value
try {
+ OCC_CATCH_SIGNALS;
TopoDS_Shape aShape;
TopoDS_Edge anEdge = TopoDS::Edge(anArg);
return NULL;
}
- //The GetFaceByNormale() doesn't change object so no new function is required.
- Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
+ Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
//Make a Python command
- TCollection_AsciiString anEntry, aDescr;
- TDF_Tool::Entry(aResult->GetEntry(), anEntry);
- aDescr += anEntry + " = IBlocksOperations.GetFaceByNormale(";
- TDF_Tool::Entry(theShape->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(theVector->GetEntry(), anEntry);
- aDescr += anEntry + ")";
-
- TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
- aNewDescr += aDescr;
- aFunction->SetDescription(aNewDescr);
+ GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceByNormale("
+ << theShape << ", " << theVector << ")";
SetErrorCode(OK);
return aResult;
//=============================================================================
/*!
- * IsCompoundOfBlocks
+ * GetShapesNearPoint
*/
//=============================================================================
-Standard_Boolean GEOMImpl_IBlocksOperations::IsCompoundOfBlocks
- (Handle(GEOM_Object) theCompound,
- const Standard_Integer theMinNbFaces,
- const Standard_Integer theMaxNbFaces,
- Standard_Integer& theNbBlocks)
+Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetShapesNearPoint
+ (Handle(GEOM_Object) theShape,
+ Handle(GEOM_Object) thePoint,
+ const Standard_Integer theShapeType,
+ const Standard_Real theConstTolerance)
{
SetErrorCode(KO);
- Standard_Boolean isCompOfBlocks = Standard_False;
- theNbBlocks = 0;
- if (theCompound.IsNull()) return isCompOfBlocks;
- TopoDS_Shape aBlockOrComp = theCompound->GetValue();
+ // New object
+ Handle(GEOM_Object) aResult;
- //Check
- isCompOfBlocks = Standard_True;
- try {
- TopTools_MapOfShape mapShape;
- TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
- for (; exp.More(); exp.Next()) {
- if (mapShape.Add(exp.Current())) {
- TopoDS_Shape aSolid = exp.Current();
+ // Arguments
+ if (theShape.IsNull() || thePoint.IsNull()) return NULL;
- TopTools_MapOfShape mapFaces;
- TopExp_Explorer expF (aSolid, TopAbs_FACE);
- Standard_Integer nbFaces = 0;
- for (; expF.More(); expF.Next()) {
- if (mapFaces.Add(expF.Current())) {
- nbFaces++;
- if (nbFaces > theMaxNbFaces) {
- isCompOfBlocks = Standard_False;
+ TopoDS_Shape aBlockOrComp = theShape->GetValue();
+ if (aBlockOrComp.IsNull()) {
+ SetErrorCode("Block or compound is null");
+ return NULL;
+ }
+
+ TopoDS_Shape anArg = thePoint->GetValue();
+ if (anArg.IsNull()) {
+ SetErrorCode("Null shape is given as argument");
+ return NULL;
+ }
+ if (anArg.ShapeType() != TopAbs_VERTEX) {
+ SetErrorCode("Element for face identification is not a vertex");
+ return NULL;
+ }
+
+ if (theShapeType < TopAbs_SOLID || TopAbs_VERTEX < theShapeType) {
+ SetErrorCode("Invalid type of result is requested");
+ return NULL;
+ }
+
+ Standard_Real theTolerance = theConstTolerance;
+ if (theTolerance < Precision::Confusion()) {
+ theTolerance = Precision::Confusion();
+ }
+
+ // Compute the result
+ try {
+ OCC_CATCH_SIGNALS;
+ TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
+
+ TopTools_MapOfShape mapShape;
+ Standard_Integer nbEdges = 0;
+ TopExp_Explorer exp (aBlockOrComp, TopAbs_ShapeEnum(theShapeType));
+ for (; exp.More(); exp.Next()) {
+ if (mapShape.Add(exp.Current())) {
+ nbEdges++;
+ }
+ }
+
+ if (nbEdges == 0) {
+ SetErrorCode("Given shape contains no sub-shapes of requested type");
+ return NULL;
+ }
+
+ // Calculate distances and find min
+ mapShape.Clear();
+ Standard_Integer ind = 1;
+ Standard_Real aMinDist = RealLast();
+ TopTools_Array1OfShape anEdges (1, nbEdges);
+ TColStd_Array1OfReal aDistances (1, nbEdges);
+ for (exp.Init(aBlockOrComp, TopAbs_ShapeEnum(theShapeType)); exp.More(); exp.Next()) {
+ if (mapShape.Add(exp.Current())) {
+ TopoDS_Shape anEdge = exp.Current();
+ anEdges(ind) = anEdge;
+
+ BRepExtrema_DistShapeShape aDistTool (aVert, anEdges(ind));
+ if (!aDistTool.IsDone()) {
+ SetErrorCode("Can not find a distance from the given point to one of sub-shapes");
+ return NULL;
+ }
+ aDistances(ind) = aDistTool.Value();
+ if (aDistances(ind) < aMinDist) {
+ aMinDist = aDistances(ind);
+ }
+ ind++;
+ }
+ }
+
+ if (aMinDist < RealLast()) {
+ // Collect sub-shapes with distance < (aMinDist + theTolerance)
+ int nbSubShapes = 0;
+ TopTools_Array1OfShape aNearShapes (1, nbEdges);
+ for (ind = 1; ind <= nbEdges; ind++) {
+ if (aDistances(ind) < aMinDist + theTolerance) {
+ nbSubShapes++;
+ aNearShapes(nbSubShapes) = anEdges(ind);
+ }
+ }
+
+ // Add sub-shape
+ TopTools_IndexedMapOfShape anIndices;
+ TopExp::MapShapes(aBlockOrComp, anIndices);
+ Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger (1, nbSubShapes);
+ for (ind = 1; ind <= nbSubShapes; ind++) {
+ anArray->SetValue(ind, anIndices.FindIndex(aNearShapes(ind)));
+ }
+ aResult = GetEngine()->AddSubShape(theShape, anArray);
+ }
+ }
+ catch (Standard_Failure) {
+ Handle(Standard_Failure) aFail = Standard_Failure::Caught();
+ SetErrorCode(aFail->GetMessageString());
+ return NULL;
+ }
+
+ if (aResult.IsNull())
+ return NULL;
+
+ Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
+
+ //Make a Python command
+ GEOM::TPythonDump(aFunction)
+ << aResult << " = geompy.GetShapesNearPoint(" << theShape << ", " << thePoint
+ << ", " << TopAbs_ShapeEnum(theShapeType) << ", " << theTolerance << ")";
+
+ SetErrorCode(OK);
+ return aResult;
+}
+
+//=============================================================================
+/*!
+ * IsCompoundOfBlocks
+ */
+//=============================================================================
+Standard_Boolean GEOMImpl_IBlocksOperations::IsCompoundOfBlocks
+ (Handle(GEOM_Object) theCompound,
+ const Standard_Integer theMinNbFaces,
+ const Standard_Integer theMaxNbFaces,
+ Standard_Integer& theNbBlocks)
+{
+ SetErrorCode(KO);
+ Standard_Boolean isCompOfBlocks = Standard_False;
+ theNbBlocks = 0;
+
+ if (theCompound.IsNull()) return isCompOfBlocks;
+ TopoDS_Shape aBlockOrComp = theCompound->GetValue();
+
+ //Check
+ isCompOfBlocks = Standard_True;
+ try {
+ OCC_CATCH_SIGNALS;
+ TopTools_MapOfShape mapShape;
+ TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
+ for (; exp.More(); exp.Next()) {
+ if (mapShape.Add(exp.Current())) {
+ TopoDS_Shape aSolid = exp.Current();
+
+ TopTools_MapOfShape mapFaces;
+ TopExp_Explorer expF (aSolid, TopAbs_FACE);
+ Standard_Integer nbFaces = 0;
+ for (; expF.More(); expF.Next()) {
+ if (mapFaces.Add(expF.Current())) {
+ nbFaces++;
+ if (nbFaces > theMaxNbFaces) {
+ isCompOfBlocks = Standard_False;
break;
}
}
* Set of functions, used by CheckCompoundOfBlocks() method
*/
//=============================================================================
-void AddBlocksFrom (const TopoDS_Shape& theShape,
- TopTools_ListOfShape& BLO,
- TopTools_ListOfShape& NOT)
+void GEOMImpl_IBlocksOperations::AddBlocksFrom (const TopoDS_Shape& theShape,
+ TopTools_ListOfShape& BLO,
+ TopTools_ListOfShape& NOT,
+ TopTools_ListOfShape& EXT,
+ TopTools_ListOfShape& NOQ,
+ const Standard_Real theToleranceC1)
{
TopAbs_ShapeEnum aType = theShape.ShapeType();
switch (aType) {
{
TopoDS_Iterator It (theShape);
for (; It.More(); It.Next()) {
- AddBlocksFrom(It.Value(), BLO, NOT);
+ AddBlocksFrom(It.Value(), BLO, NOT, EXT, NOQ, theToleranceC1);
}
}
break;
case TopAbs_SOLID:
{
+ // Check, if there are seam or degenerated edges
+ BlockFix_CheckTool aTool;
+ aTool.SetShape(theShape);
+ aTool.SetAngTolerance(theToleranceC1);
+ aTool.Perform();
+ if (aTool.NbPossibleBlocks() > 0) {
+ EXT.Append(theShape);
+ } else {
+ // Count faces and edges in each face to recognize blocks
+ TopTools_MapOfShape mapFaces;
+ Standard_Integer nbFaces = 0;
+ Standard_Boolean hasNonQuadr = Standard_False;
+ TopExp_Explorer expF (theShape, TopAbs_FACE);
+
+ for (; expF.More(); expF.Next()) {
+ TopoDS_Face aF = TopoDS::Face(expF.Current());
+
+ if (mapFaces.Add(aF)) {
+ nbFaces++;
+
+ if (!IsQuadrangle(aF, theToleranceC1)) {
+ hasNonQuadr = Standard_True;
+ NOQ.Append(aF);//0021483
+ }
+ }
+ }
+
+ if (nbFaces == 6 && !hasNonQuadr) {
+ BLO.Append(theShape);
+ } else {
+ NOT.Append(theShape);
+ }
+ }
+ }
+ break;
+ case TopAbs_SHELL: //0021483
+ case TopAbs_FACE: //0021483
+ {
+ // Count edges in each face
TopTools_MapOfShape mapFaces;
TopExp_Explorer expF (theShape, TopAbs_FACE);
- Standard_Integer nbFaces = 0;
- Standard_Integer nbEdges = 0;
for (; expF.More(); expF.Next()) {
- if (mapFaces.Add(expF.Current())) {
- nbFaces++;
- if (nbFaces > 6) break;
-
- // Check number of edges in the face
- TopoDS_Shape aF = expF.Current();
- TopExp_Explorer expE (aF, TopAbs_EDGE);
- nbEdges = 0;
- for (; expE.More(); expE.Next()) {
- nbEdges++;
- if (nbEdges > 4) break;
+ TopoDS_Face aF = TopoDS::Face(expF.Current());
+
+ if (mapFaces.Add(aF)) {
+ if (!IsQuadrangle(aF, theToleranceC1)) {
+ NOQ.Append(aF);//0021483
}
- if (nbEdges != 4) break;
}
}
- if (nbFaces == 6 && nbEdges == 4) {
- BLO.Append(theShape);
- } else {
- NOT.Append(theShape);
- }
}
break;
default:
Bnd_Box B1, B2;
BRepBndLib::Add(theBlock1, B1);
BRepBndLib::Add(theBlock2, B2);
-// BRepBndLib::AddClose(theBlock1, B1);
-// BRepBndLib::AddClose(theBlock2, B2);
B1.Get(Xmin1, Ymin1, Zmin1, Xmax1, Ymax1, Zmax1);
B2.Get(Xmin2, Ymin2, Zmin2, Xmax2, Ymax2, Zmax2);
if (Xmax2 < Xmin1 || Xmax1 < Xmin2 ||
Ymax2 < Ymin1 || Ymax1 < Ymin2 ||
Zmax2 < Zmin1 || Zmax1 < Zmin2) {
-// Standard_Real prec = Precision::Confusion();
-// if (prec < Xmin1 - Xmax2 || prec < Xmin2 - Xmax1 ||
-// prec < Ymin1 - Ymax2 || prec < Ymin2 - Ymax1 ||
-// prec < Zmin1 - Zmax2 || prec < Zmin2 - Zmax1) {
return REL_NOT_CONNECTED;
}
- // to be done
BRepExtrema_DistShapeShape dst (theBlock1, theBlock2);
if (!dst.IsDone()) {
return Standard_False;
}
+//=============================================================================
+/*!
+ * PrintBCErrors
+ */
+//=============================================================================
+TCollection_AsciiString GEOMImpl_IBlocksOperations::PrintBCErrors
+ (Handle(GEOM_Object) theCompound,
+ const std::list<BCError>& theErrors)
+{
+ TCollection_AsciiString aDescr;
+
+ std::list<BCError>::const_iterator errIt = theErrors.begin();
+ int i = 0;
+ for (; errIt != theErrors.end(); i++, errIt++) {
+ BCError errStruct = *errIt;
+
+ switch (errStruct.error) {
+ case NOT_BLOCK:
+ aDescr += "\n\tNot a Blocks: ";
+ break;
+ case EXTRA_EDGE:
+ aDescr += "\n\tHexahedral solids with degenerated and/or seam edges: ";
+ break;
+ case INVALID_CONNECTION:
+ aDescr += "\n\tInvalid connection between two blocks: ";
+ break;
+ case NOT_CONNECTED:
+ aDescr += "\n\tBlocks, not connected with main body: ";
+ break;
+ case NOT_GLUED:
+ aDescr += "\n\tNot glued blocks: ";
+ break;
+ default:
+ break;
+ }
+
+ std::list<int> sshList = errStruct.incriminated;
+ std::list<int>::iterator sshIt = sshList.begin();
+ int jj = 0;
+ for (; sshIt != sshList.end(); jj++, sshIt++) {
+ if (jj > 0)
+ aDescr += ", ";
+ aDescr += TCollection_AsciiString(*sshIt);
+ }
+ }
+
+ return aDescr;
+}
+
//=============================================================================
/*!
* CheckCompoundOfBlocks
*/
//=============================================================================
Standard_Boolean GEOMImpl_IBlocksOperations::CheckCompoundOfBlocks
- (Handle(GEOM_Object) theCompound,
- list<BCError>& theErrors)
+ (Handle(GEOM_Object) theCompound,
+ const Standard_Real theToleranceC1,
+ std::list<BCError>& theErrors)
{
SetErrorCode(KO);
TopTools_IndexedMapOfShape anIndices;
TopExp::MapShapes(aBlockOrComp, anIndices);
- // 1. Report non-blocks
+ // 1. Separate blocks from non-blocks
TopTools_ListOfShape NOT; // Not blocks
+ TopTools_ListOfShape EXT; // Hexahedral solids, having degenerated and/or seam edges
TopTools_ListOfShape BLO; // All blocks from the given compound
- AddBlocksFrom(aBlockOrComp, BLO, NOT);
+ TopTools_ListOfShape NOQ; // All non-quadrangular faces
+ AddBlocksFrom(aBlockOrComp, BLO, NOT, EXT, NOQ, theToleranceC1);
+ // Report non-blocks
if (NOT.Extent() > 0) {
isCompOfBlocks = Standard_False;
BCError anErr;
anErr.error = NOT_BLOCK;
- TopTools_ListIteratorOfListOfShape NOTit (NOT);
- for (; NOTit.More(); NOTit.Next()) {
- anErr.incriminated.push_back(anIndices.FindIndex(NOTit.Value()));
+ TopTools_ListIteratorOfListOfShape it (NOT);
+ for (; it.More(); it.Next()) {
+ anErr.incriminated.push_back(anIndices.FindIndex(it.Value()));
+ }
+ theErrors.push_back(anErr);
+ }
+
+ // Report solids, having degenerated and/or seam edges
+ if (EXT.Extent() > 0) {
+ isCompOfBlocks = Standard_False;
+ BCError anErr;
+ anErr.error = EXTRA_EDGE;
+ TopTools_ListIteratorOfListOfShape it (EXT);
+ for (; it.More(); it.Next()) {
+ anErr.incriminated.push_back(anIndices.FindIndex(it.Value()));
}
theErrors.push_back(anErr);
}
return isCompOfBlocks;
}
- // Convert list of blocks into array for easy and fast access
- Standard_Integer ibl = 1;
- TopTools_Array1OfShape aBlocks (1, nbBlocks);
- TopTools_ListIteratorOfListOfShape BLOit (BLO);
- for (; BLOit.More(); BLOit.Next(), ibl++) {
- aBlocks.SetValue(ibl, BLOit.Value());
- }
-
- // 2. Find relations between all blocks,
- // report connection errors (NOT_GLUED and INVALID_CONNECTION)
+ // Prepare data for 2. and 3.
TColStd_Array2OfInteger aRelations (1, nbBlocks, 1, nbBlocks);
aRelations.Init(REL_NOT_CONNECTED);
- Standard_Integer row = 1;
- for (row = 1; row <= nbBlocks; row++) {
- TopoDS_Shape aBlock = aBlocks.Value(row);
-
- Standard_Integer col = row + 1;
- for (; col <= nbBlocks; col++) {
- Standard_Integer aRel = BlocksRelation(aBlock, aBlocks.Value(col));
- if (aRel != REL_NOT_CONNECTED) {
- aRelations.SetValue(row, col, aRel);
- aRelations.SetValue(col, row, aRel);
- if (aRel == REL_NOT_GLUED) {
- // report connection error
- isCompOfBlocks = Standard_False;
- BCError anErr;
- anErr.error = NOT_GLUED;
- anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(row)));
- anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(col)));
- theErrors.push_back(anErr);
- } else if (aRel == REL_COLLISION_VV ||
- aRel == REL_COLLISION_FF ||
- aRel == REL_COLLISION_EE ||
- aRel == REL_UNKNOWN) {
- // report connection error
- isCompOfBlocks = Standard_False;
- BCError anErr;
- anErr.error = INVALID_CONNECTION;
- anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(row)));
- anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(col)));
- theErrors.push_back(anErr);
- } else {
+ TopTools_IndexedMapOfShape mapBlocks;
+
+ BRep_Builder BB;
+ TopoDS_Compound aComp;
+ BB.MakeCompound(aComp);
+
+ TopTools_ListIteratorOfListOfShape BLOit (BLO);
+ for (; BLOit.More(); BLOit.Next()) {
+ mapBlocks.Add(BLOit.Value());
+ BB.Add(aComp, BLOit.Value());
+ }
+
+ // 2. Find glued blocks (having shared faces)
+ TopTools_IndexedDataMapOfShapeListOfShape mapFaceBlocks;
+ GEOMImpl_Block6Explorer::MapShapesAndAncestors
+ (aComp, TopAbs_FACE, TopAbs_SOLID, mapFaceBlocks);
+
+ Standard_Integer prevInd = 0, curInd = 0;
+ Standard_Integer ind = 1, nbFaces = mapFaceBlocks.Extent();
+ for (; ind <= nbFaces; ind++) {
+ const TopTools_ListOfShape& aGluedBlocks = mapFaceBlocks.FindFromIndex(ind);
+ if (aGluedBlocks.Extent() > 1) { // Shared face found
+ TopTools_ListIteratorOfListOfShape aGluedBlocksIt (aGluedBlocks);
+ TopoDS_Shape prevBlock, curBlock;
+ for (; aGluedBlocksIt.More(); aGluedBlocksIt.Next()) {
+ curBlock = aGluedBlocksIt.Value();
+ if (!prevBlock.IsNull()) {
+ prevInd = mapBlocks.FindIndex(prevBlock);
+ curInd = mapBlocks.FindIndex(curBlock);
+ aRelations.SetValue(prevInd, curInd, REL_OK);
+ aRelations.SetValue(curInd, prevInd, REL_OK);
}
+ prevBlock = curBlock;
}
}
}
- // 3. Find largest set of connected (good connection or not glued) blocks
+ // 3. Find not glued blocks
+ GEOMAlgo_GlueAnalyser aGD;
+
+ aGD.SetShape(aComp);
+ aGD.SetTolerance(Precision::Confusion());
+ aGD.SetCheckGeometry(Standard_True);
+ aGD.Perform();
+
+ Standard_Integer iErr, iWrn;
+ iErr = aGD.ErrorStatus();
+ if (iErr) {
+ SetErrorCode("Error in GEOMAlgo_GlueAnalyser");
+ return isCompOfBlocks;
+ }
+ iWrn = aGD.WarningStatus();
+ if (iWrn) {
+ MESSAGE("Warning in GEOMAlgo_GlueAnalyser");
+ }
+
+ // Report not glued blocks
+ if (aGD.HasSolidsToGlue()) {
+ isCompOfBlocks = Standard_False;
+ Standard_Integer aSx1Ind, aSx2Ind;
+
+ const GEOMAlgo_ListOfCoupleOfShapes& aLCS = aGD.SolidsToGlue();
+ GEOMAlgo_ListIteratorOfListOfCoupleOfShapes aItCS (aLCS);
+ for (; aItCS.More(); aItCS.Next()) {
+ const GEOMAlgo_CoupleOfShapes& aCS = aItCS.Value();
+ const TopoDS_Shape& aSx1 = aCS.Shape1();
+ const TopoDS_Shape& aSx2 = aCS.Shape2();
+
+ aSx1Ind = mapBlocks.FindIndex(aSx1);
+ aSx2Ind = mapBlocks.FindIndex(aSx2);
+ aRelations.SetValue(aSx1Ind, aSx2Ind, NOT_GLUED);
+ aRelations.SetValue(aSx2Ind, aSx1Ind, NOT_GLUED);
+
+ BCError anErr;
+ anErr.error = NOT_GLUED;
+ anErr.incriminated.push_back(anIndices.FindIndex(aSx1));
+ anErr.incriminated.push_back(anIndices.FindIndex(aSx2));
+ theErrors.push_back(anErr);
+ }
+ }
+
+ // 4. Find largest set of connected (good connection or not glued) blocks
+ Standard_Integer ibl = 1;
TColStd_MapOfInteger aProcessedMap;
TColStd_MapOfInteger aLargestSet;
TColStd_MapOfInteger aCurrentSet;
for (ibl = 1; ibl <= nbBlocks; ibl++) {
if (!aProcessedMap.Contains(ibl)) {
+ aCurrentSet.Clear();
FindConnected(ibl, aRelations, aProcessedMap, aCurrentSet);
if (aCurrentSet.Extent() > aLargestSet.Extent()) {
aLargestSet = aCurrentSet;
}
}
- // 4. Report all blocks, isolated from <aLargestSet>
+ // 5. Report all blocks, isolated from <aLargestSet>
BCError anErr;
anErr.error = NOT_CONNECTED;
Standard_Boolean hasIsolated = Standard_False;
if (!HasAnyConnection(ibl, aLargestSet, aRelations, aProcessedMap)) {
// report connection absence
hasIsolated = Standard_True;
- anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(ibl)));
+ anErr.incriminated.push_back(anIndices.FindIndex(mapBlocks.FindKey(ibl)));
}
}
}
//=============================================================================
/*!
- * PrintBCErrors
+ * GetNonBlocks
*/
//=============================================================================
-TCollection_AsciiString GEOMImpl_IBlocksOperations::PrintBCErrors
- (Handle(GEOM_Object) theCompound,
- const list<BCError>& theErrors)
+Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetNonBlocks
+ (Handle(GEOM_Object) theShape,
+ const Standard_Real theToleranceC1,
+ Handle(GEOM_Object)& theNonQuads)
{
- TCollection_AsciiString aDescr;
+ SetErrorCode(KO);
- list<BCError>::const_iterator errIt = theErrors.begin();
- int i = 0;
- for (; errIt != theErrors.end(); i++, errIt++) {
- BCError errStruct = *errIt;
+ if (theShape.IsNull()) return NULL;
+ TopoDS_Shape aShape = theShape->GetValue();
- switch (errStruct.error) {
- case NOT_BLOCK:
- aDescr += "\nNot a Blocks: ";
- break;
- case INVALID_CONNECTION:
- aDescr += "\nInvalid connection between two blocks: ";
- break;
- case NOT_CONNECTED:
- aDescr += "\nBlocks, not connected with main body: ";
- break;
- case NOT_GLUED:
- aDescr += "\nNot glued blocks: ";
- break;
- default:
- break;
+ // Separate blocks from non-blocks
+ TopTools_ListOfShape BLO; // All blocks from the given compound
+ TopTools_ListOfShape NOT; // Not blocks
+ TopTools_ListOfShape EXT; // Hexahedral solids, having degenerated and/or seam edges
+ TopTools_ListOfShape NOQ; // All non-quadrangular faces
+ AddBlocksFrom(aShape, BLO, NOT, EXT, NOQ, theToleranceC1);
+
+ if (NOT.IsEmpty() && EXT.IsEmpty() && NOQ.IsEmpty()) {
+ SetErrorCode("NOT_FOUND_ANY");
+ return NULL;
+ }
+
+ // Map sub-shapes and their indices
+ TopTools_IndexedMapOfShape anIndices;
+ TopExp::MapShapes(aShape, anIndices);
+
+ // Non-blocks
+ Handle(GEOM_Object) aNonBlocks;
+ if (NOT.Extent() > 0 || EXT.Extent() > 0) {
+ Handle(TColStd_HArray1OfInteger) anArray =
+ new TColStd_HArray1OfInteger (1, NOT.Extent() + EXT.Extent());
+ Standard_Integer ii = 1;
+ TopTools_ListIteratorOfListOfShape it1 (NOT);
+ for (; it1.More(); it1.Next(), ii++) {
+ anArray->SetValue(ii, anIndices.FindIndex(it1.Value()));
+ }
+ TopTools_ListIteratorOfListOfShape it2 (EXT);
+ for (; it2.More(); it2.Next(), ii++) {
+ anArray->SetValue(ii, anIndices.FindIndex(it2.Value()));
+ }
+
+ aNonBlocks = GetEngine()->AddSubShape(theShape, anArray);
+ if (aNonBlocks.IsNull()) {
+ SetErrorCode("Error in algorithm: result found, but cannot be returned.");
+ return NULL;
}
+ aNonBlocks->SetType(GEOM_GROUP);
+ TDF_Label aFreeLabel = aNonBlocks->GetFreeLabel();
+ TDataStd_Integer::Set(aFreeLabel, (Standard_Integer)TopAbs_SOLID);
+ }
- list<int> sshList = errStruct.incriminated;
- list<int>::iterator sshIt = sshList.begin();
- int jj = 0;
- for (; sshIt != sshList.end(); jj++, sshIt++) {
- if (jj > 0)
- aDescr += ", ";
- aDescr += TCollection_AsciiString(*sshIt);
+ // Non-quadrangles
+ if (NOQ.Extent() > 0) {
+ Handle(TColStd_HArray1OfInteger) anArray =
+ new TColStd_HArray1OfInteger (1, NOQ.Extent());
+ Standard_Integer ii = 1;
+ TopTools_ListIteratorOfListOfShape it1 (NOQ);
+ for (; it1.More(); it1.Next(), ii++) {
+ anArray->SetValue(ii, anIndices.FindIndex(it1.Value()));
+ }
+
+ theNonQuads = GetEngine()->AddSubShape(theShape, anArray);
+ if (theNonQuads.IsNull()) {
+ SetErrorCode("Error in algorithm: result found, but cannot be returned.");
+ return NULL;
}
+ theNonQuads->SetType(GEOM_GROUP);
+ TDF_Label aFreeLabel = theNonQuads->GetFreeLabel();
+ TDataStd_Integer::Set(aFreeLabel, (Standard_Integer)TopAbs_FACE);
}
- return aDescr;
+ //Make a Python command
+ Handle(GEOM_Function) aMainShape = theShape->GetLastFunction();
+ GEOM::TPythonDump pd (aMainShape, /*append=*/true);
+ pd << "(";
+ if (aNonBlocks.IsNull())
+ pd << "no_bad_solids";
+ else
+ pd << aNonBlocks;
+ pd << ", ";
+ if (theNonQuads.IsNull())
+ pd << "no_bad_faces";
+ else
+ pd << theNonQuads;
+ pd << ") = geompy.GetNonBlocks(" << theShape << ")";
+
+ SetErrorCode(OK);
+ return aNonBlocks;
+}
+
+//=============================================================================
+/*!
+ * RemoveExtraEdges
+ */
+//=============================================================================
+Handle(GEOM_Object) GEOMImpl_IBlocksOperations::RemoveExtraEdges
+ (Handle(GEOM_Object) theObject,
+ const Standard_Integer theOptimumNbFaces)
+{
+ SetErrorCode(KO);
+
+ if (theObject.IsNull()) return NULL;
+
+ Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
+ if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be fixed
+
+ //Add a new Copy object
+ Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
+
+ //Add a function
+ Handle(GEOM_Function) aFunction =
+ aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_REMOVE_EXTRA);
+
+ //Check if the function is set correctly
+ if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
+
+ GEOMImpl_IBlockTrsf aTI (aFunction);
+ aTI.SetOriginal(aLastFunction);
+ aTI.SetOptimumNbFaces(theOptimumNbFaces);
+
+ //Compute the fixed shape
+ try {
+ OCC_CATCH_SIGNALS;
+ if (!GetSolver()->ComputeFunction(aFunction)) {
+ SetErrorCode("Block driver failed to remove extra edges of the given shape");
+ return NULL;
+ }
+ }
+ catch (Standard_Failure) {
+ Handle(Standard_Failure) aFail = Standard_Failure::Caught();
+ SetErrorCode(aFail->GetMessageString());
+ return NULL;
+ }
+
+ //Make a Python command
+ std::string doUnionFaces = (theOptimumNbFaces < 0) ? "False" : "True";
+ GEOM::TPythonDump(aFunction) << aCopy << " = geompy.RemoveExtraEdges("
+ << theObject << ", " << doUnionFaces.data() << ")";
+
+ SetErrorCode(OK);
+ return aCopy;
+}
+
+//=============================================================================
+/*!
+ * UnionFaces
+ */
+//=============================================================================
+Handle(GEOM_Object) GEOMImpl_IBlocksOperations::UnionFaces
+ (Handle(GEOM_Object) theObject)
+{
+ SetErrorCode(KO);
+
+ if (theObject.IsNull()) return NULL;
+
+ Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
+ if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be fixed
+
+ //Add a new Copy object
+ Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
+
+ //Add a function
+ Handle(GEOM_Function) aFunction =
+ aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_UNION_FACES);
+
+ //Check if the function is set correctly
+ if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
+
+ GEOMImpl_IBlockTrsf aTI (aFunction);
+ aTI.SetOriginal(aLastFunction);
+
+ //Compute the fixed shape
+ try {
+ OCC_CATCH_SIGNALS;
+ if (!GetSolver()->ComputeFunction(aFunction)) {
+ SetErrorCode("Block driver failed to remove extra edges of the given shape");
+ return NULL;
+ }
+ }
+ catch (Standard_Failure) {
+ Handle(Standard_Failure) aFail = Standard_Failure::Caught();
+ SetErrorCode(aFail->GetMessageString());
+ return NULL;
+ }
+
+ //Make a Python command
+ GEOM::TPythonDump(aFunction) << aCopy << " = geompy.UnionFaces("
+ << theObject << ")";
+
+ SetErrorCode(OK);
+ return aCopy;
+}
+
+//=============================================================================
+/*!
+ * CheckAndImprove
+ */
+//=============================================================================
+Handle(GEOM_Object) GEOMImpl_IBlocksOperations::CheckAndImprove
+ (Handle(GEOM_Object) theObject)
+{
+ SetErrorCode(KO);
+
+ if (theObject.IsNull()) return NULL;
+
+ Handle(GEOM_Function) aLastFunction = theObject->GetLastFunction();
+ if (aLastFunction.IsNull()) return NULL; //There is no function which creates an object to be fixed
+
+ //Add a new Copy object
+ Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
+
+ //Add a function
+ Handle(GEOM_Function) aFunction =
+ aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_COMPOUND_IMPROVE);
+
+ //Check if the function is set correctly
+ if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
+
+ GEOMImpl_IBlockTrsf aTI (aFunction);
+ aTI.SetOriginal(aLastFunction);
+
+ // -1 means do not unite faces on common surface (?except case of seam edge between them?)
+ //aTI.SetOptimumNbFaces(-1);
+ aTI.SetOptimumNbFaces(6);
+
+ //Compute the fixed shape
+ try {
+ OCC_CATCH_SIGNALS;
+ if (!GetSolver()->ComputeFunction(aFunction)) {
+ SetErrorCode("Block driver failed to improve the given blocks compound");
+ return NULL;
+ }
+ }
+ catch (Standard_Failure) {
+ Handle(Standard_Failure) aFail = Standard_Failure::Caught();
+ SetErrorCode(aFail->GetMessageString());
+ return NULL;
+ }
+
+ //Make a Python command
+ GEOM::TPythonDump(aFunction) << aCopy
+ << " = geompy.CheckAndImprove(" << theObject << ")";
+
+ SetErrorCode(OK);
+ return aCopy;
}
//=============================================================================
Handle(GEOM_Function) aFunction;
TopTools_MapOfShape mapShape;
- TCollection_AsciiString anAsciiList = "[", anEntry;
+ TCollection_AsciiString anAsciiList, anEntry;
// Map shapes
TopTools_IndexedMapOfShape anIndices;
// Explode
try {
+ OCC_CATCH_SIGNALS;
TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
for (; exp.More(); exp.Next()) {
if (mapShape.Add(exp.Current())) {
//Make a Python command
TDF_Tool::Entry(anObj->GetEntry(), anEntry);
- anAsciiList += anEntry;
- anAsciiList += ",";
+ anAsciiList += anEntry + ", ";
}
}
}
return aBlocks;
}
- anAsciiList.Trunc(anAsciiList.Length() - 1);
- anAsciiList += "]";
+ anAsciiList.Trunc(anAsciiList.Length() - 2);
//The explode doesn't change object so no new function is required.
aFunction = theCompound->GetLastFunction();
//Make a Python command
- TCollection_AsciiString aDescr (anAsciiList);
- aDescr += " = IBlocksOperations.ExplodeCompoundOfBlocks(";
- TDF_Tool::Entry(theCompound->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- aDescr += TCollection_AsciiString(theMinNbFaces) + ", ";
- aDescr += TCollection_AsciiString(theMaxNbFaces) + ")";
-
- TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
- aNewDescr += aDescr;
- aFunction->SetDescription(aNewDescr);
+ GEOM::TPythonDump(aFunction, /*append=*/true)
+ << "[" << anAsciiList.ToCString() << "] = geompy.MakeBlockExplode("
+ << theCompound << ", " << theMinNbFaces << ", " << theMaxNbFaces << ")";
SetErrorCode(OK);
return aBlocks;
}
if (aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
- SetErrorCode("Shape is neither a block, nor a compound of blocks");
+ SetErrorCode("Shape to find block in is not a compound");
return NULL;
}
TopoDS_Shape anArg = thePoint->GetValue();
if (anArg.IsNull()) {
- SetErrorCode("Null shape is given as argument");
+ SetErrorCode("Point is null");
return NULL;
}
if (anArg.ShapeType() != TopAbs_VERTEX) {
- SetErrorCode("Element for block identification is not a vertex");
+ SetErrorCode("Shape for block identification is not a vertex");
return NULL;
}
//Compute the Block value
try {
+ OCC_CATCH_SIGNALS;
TopoDS_Shape aShape;
+
TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
gp_Pnt aPnt = BRep_Tool::Pnt(aVert);
+ Standard_Real PX, PY, PZ;
+ aPnt.Coord(PX, PY, PZ);
- // 1. Explode compound on blocks
- TopTools_MapOfShape mapShape;
- Standard_Integer nbSolids = 0;
+ // 1. Classify the point relatively each block
+ Standard_Integer nearest = 2, nbFound = 0;
+ TopTools_DataMapOfShapeInteger mapShapeDist;
TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
for (; exp.More(); exp.Next()) {
- if (mapShape.Add(exp.Current())) {
- nbSolids++;
- }
- }
+ TopoDS_Shape aSolid = exp.Current();
+
+ if (!mapShapeDist.IsBound(aSolid)) {
+ Standard_Integer aDistance = 2;
+
+ // 1.a. Classify relatively Bounding box
+ Standard_Real Xmin, Ymin, Zmin, Xmax, Ymax, Zmax;
+ Bnd_Box BB;
+ BRepBndLib::Add(aSolid, BB);
+ BB.Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);
+ if (PX < Xmin || Xmax < PX ||
+ PY < Ymin || Ymax < PY ||
+ PZ < Zmin || Zmax < PZ) {
+ // OUT of bounding box
+ aDistance = 1;
+ } else {
+ // 1.b. Classify relatively the solid itself
+ BRepClass3d_SolidClassifier SC (aSolid, aPnt, Precision::Confusion());
+ if (SC.State() == TopAbs_IN) {
+ aDistance = -1;
+ } else if (SC.State() == TopAbs_ON) {
+ aDistance = 0;
+ } else { // OUT
+ aDistance = 1;
+ }
+ }
- mapShape.Clear();
- Standard_Integer ind = 1;
- TopTools_Array1OfShape aSolids (1, nbSolids);
- TColStd_Array1OfInteger aDistances (1, nbSolids);
- for (exp.Init(aBlockOrComp, TopAbs_SOLID); exp.More(); exp.Next()) {
- if (mapShape.Add(exp.Current())) {
- TopoDS_Shape aSolid = exp.Current();
- aSolids(ind) = aSolid;
+ if (aDistance < nearest) {
+ nearest = aDistance;
+ aShape = aSolid;
+ nbFound = 1;
+
+ // A first found block, containing the point inside, will be returned.
+ // It is the solution, if there are no intersecting blocks in the compound.
+ if (nearest == -1) break;
- // 2. Classify the point relatively each block
- BRepClass3d_SolidClassifier SC (aSolid, aPnt, Precision::Confusion());
- if (SC.State() == TopAbs_IN) {
- aDistances(ind) = -1;
- } else if (SC.State() == TopAbs_ON) {
- aDistances(ind) = 0;
- } else { // OUT
- aDistances(ind) = 1;
+ } else if (aDistance == nearest) {
+ nbFound++;
+ } else {
}
- ind++;
- }
- }
- // 3. Define block, containing the point or having minimum distance to it
- Standard_Integer nearest = 2, nbFound = 0;
- for (ind = 1; ind <= nbSolids; ind++) {
- if (aDistances(ind) < nearest) {
- nearest = aDistances(ind);
- aShape = aSolids(ind);
- nbFound = 1;
- } else if (aDistances(ind) == nearest) {
- nbFound++;
- } else {
- }
+ mapShapeDist.Bind(aSolid, aDistance);
+ } // if (!mapShapeDist.IsBound(aSolid))
}
+
+ // 2. Define block, containing the point or having minimum distance to it
if (nbFound > 1) {
if (nearest == 0) {
// The point is on boundary of some blocks and there are
// no blocks, having the point inside or on boundary.
// We will get a nearest block
Standard_Real minDist = RealLast();
- for (ind = 1; ind <= nbSolids; ind++) {
- if (aDistances(ind) == 1) {
- BRepExtrema_DistShapeShape aDistTool (aVert, aSolids(ind));
+ TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
+ for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
+ if (mapShapeDistIter.Value() == 1) {
+ TopoDS_Shape aSolid = mapShapeDistIter.Key();
+ BRepExtrema_DistShapeShape aDistTool (aVert, aSolid);
if (!aDistTool.IsDone()) {
SetErrorCode("Can not find a distance from the given point to one of blocks");
return NULL;
Standard_Real aDist = aDistTool.Value();
if (aDist < minDist) {
minDist = aDist;
- aShape = aSolids(ind);
+ aShape = aSolid;
}
}
}
} else { // nearest == -1
- // The point is inside some blocks.
- // We will get a block with nearest center
- Standard_Real minDist = RealLast();
- for (ind = 1; ind <= nbSolids; ind++) {
- if (aDistances(ind) == -1) {
- GProp_GProps aSystem;
- BRepGProp::VolumeProperties(aSolids(ind), aSystem);
- gp_Pnt aCenterMass = aSystem.CentreOfMass();
-
- Standard_Real aDist = aCenterMass.Distance(aPnt);
- if (aDist < minDist) {
- minDist = aDist;
- aShape = aSolids(ind);
- }
- }
- }
+// // The point is inside some blocks.
+// // We will get a block with nearest center
+// Standard_Real minDist = RealLast();
+// TopTools_DataMapIteratorOfDataMapOfShapeInteger mapShapeDistIter (mapShapeDist);
+// for (; mapShapeDistIter.More(); mapShapeDistIter.Next()) {
+// if (mapShapeDistIter.Value() == -1) {
+// TopoDS_Shape aSolid = mapShapeDistIter.Key();
+// GProp_GProps aSystem;
+// BRepGProp::VolumeProperties(aSolid, aSystem);
+// gp_Pnt aCenterMass = aSystem.CentreOfMass();
+//
+// Standard_Real aDist = aCenterMass.Distance(aPnt);
+// if (aDist < minDist) {
+// minDist = aDist;
+// aShape = aSolid;
+// }
+// }
+// }
}
- }
+ } // if (nbFound > 1)
if (nbFound == 0) {
SetErrorCode("There are no blocks near the given point");
return NULL;
}
- //The GetBlockNearPoint() doesn't change object so no new function is required.
- Handle(GEOM_Function) aFunction = theCompound->GetLastFunction();
+ Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
//Make a Python command
- TCollection_AsciiString anEntry, aDescr;
- TDF_Tool::Entry(aResult->GetEntry(), anEntry);
- aDescr += anEntry + " = IBlocksOperations.GetBlockNearPoint(";
- TDF_Tool::Entry(theCompound->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- TDF_Tool::Entry(thePoint->GetEntry(), anEntry);
- aDescr += anEntry + ")";
-
- TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
- aNewDescr += aDescr;
- aFunction->SetDescription(aNewDescr);
+ GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetBlockNearPoint("
+ << theCompound << ", " << thePoint << ")";
SetErrorCode(OK);
return aResult;
//Compute the Block value
try {
+ OCC_CATCH_SIGNALS;
// 1. Explode compound on solids
TopTools_MapOfShape mapShape;
Standard_Integer nbSolids = 0;
return NULL;
}
- //The GetBlockByParts() doesn't change object so no new function is required.
- Handle(GEOM_Function) aFunction = theCompound->GetLastFunction();
+ Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
//Make a Python command
- TDF_Tool::Entry(aResult->GetEntry(), anEntry);
- TCollection_AsciiString aDescr (anEntry);
- aDescr += " = IBlocksOperations.GetBlockByParts(";
- TDF_Tool::Entry(theCompound->GetEntry(), anEntry);
- aDescr += anEntry + ", [";
- aDescr += aPartsDescr + "])";
-
- TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
- aNewDescr += aDescr;
- aFunction->SetDescription(aNewDescr);
+ GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetBlockByParts("
+ << theCompound << ", [" << aPartsDescr.ToCString() << "])";
SetErrorCode(OK);
return aResult;
//Get the parts
Standard_Integer argi, aLen = theParts->Length();
TopTools_Array1OfShape anArgs (1, aLen);
- TCollection_AsciiString anEntry, aPartsDescr, anAsciiList = "[";
+ TCollection_AsciiString anEntry, aPartsDescr, anAsciiList;
+
for (argi = 1; argi <= aLen; argi++) {
Handle(GEOM_Object) anObj = Handle(GEOM_Object)::DownCast(theParts->Value(argi));
Handle(GEOM_Function) aRef = anObj->GetLastFunction();
// For Python command
TDF_Tool::Entry(anObj->GetEntry(), anEntry);
- if (argi > 1) aPartsDescr += ", ";
- aPartsDescr += anEntry;
+ aPartsDescr += anEntry + ", ";
}
//Get the Blocks
try {
+ OCC_CATCH_SIGNALS;
TopTools_MapOfShape mapShape;
Standard_Integer nbSolids = 0;
TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
anObj = GetEngine()->AddSubShape(theCompound, anArray);
aBlocks->Append(anObj);
- //Make a Python command
+ // For Python command
TDF_Tool::Entry(anObj->GetEntry(), anEntry);
- anAsciiList += anEntry;
- anAsciiList += ",";
+ anAsciiList += anEntry + ", ";
+ if (aFunction.IsNull())
+ aFunction = anObj->GetLastFunction();
}
}
}
return NULL;
}
- anAsciiList.Trunc(anAsciiList.Length() - 1);
- anAsciiList += "]";
-
- //The GetBlocksByParts() doesn't change object so no new function is required.
- aFunction = theCompound->GetLastFunction();
-
//Make a Python command
- TCollection_AsciiString aDescr (anAsciiList);
- aDescr += " = IBlocksOperations.GetBlocksByParts(";
- TDF_Tool::Entry(theCompound->GetEntry(), anEntry);
- aDescr += anEntry + ", [";
- aDescr += aPartsDescr + "])";
+ aPartsDescr.Trunc(aPartsDescr.Length() - 2);
+ anAsciiList.Trunc(anAsciiList.Length() - 2);
- TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
- aNewDescr += aDescr;
- aFunction->SetDescription(aNewDescr);
+ GEOM::TPythonDump(aFunction) << "[" << anAsciiList.ToCString()
+ << "] = geompy.GetBlocksByParts(" << theCompound
+ << ", [" << aPartsDescr.ToCString() << "])";
SetErrorCode(OK);
return aBlocks;
//Compute the transformation
try {
+ OCC_CATCH_SIGNALS;
if (!GetSolver()->ComputeFunction(aFunction)) {
SetErrorCode("Block driver failed to make multi-transformation");
return NULL;
}
//Make a Python command
- TCollection_AsciiString anEntry, aDescr;
- TDF_Tool::Entry(aCopy->GetEntry(), anEntry);
- aDescr += anEntry + " = IBlocksOperations.MakeMultiTransformation1D(";
- TDF_Tool::Entry(theObject->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- aDescr += TCollection_AsciiString(theDirFace1) + ", ";
- aDescr += TCollection_AsciiString(theDirFace2) + ", ";
- aDescr += TCollection_AsciiString(theNbTimes) + ") ";
-
- aFunction->SetDescription(aDescr);
+ GEOM::TPythonDump(aFunction) << aCopy << " = geompy.MakeMultiTransformation1D("
+ << theObject << ", " << theDirFace1 << ", " << theDirFace2 << ", " << theNbTimes << ")";
SetErrorCode(OK);
return aCopy;
//Compute the transformation
try {
+ OCC_CATCH_SIGNALS;
if (!GetSolver()->ComputeFunction(aFunction)) {
SetErrorCode("Block driver failed to make multi-transformation");
return NULL;
}
//Make a Python command
- TCollection_AsciiString anEntry, aDescr;
- TDF_Tool::Entry(aCopy->GetEntry(), anEntry);
- aDescr += anEntry + " = IBlocksOperations.MakeMultiTransformation2D(";
- TDF_Tool::Entry(theObject->GetEntry(), anEntry);
- aDescr += anEntry + ", ";
- aDescr += TCollection_AsciiString(theDirFace1U) + ", ";
- aDescr += TCollection_AsciiString(theDirFace2U) + ", ";
- aDescr += TCollection_AsciiString(theNbTimesU) + ", ";
- aDescr += TCollection_AsciiString(theDirFace1V) + ", ";
- aDescr += TCollection_AsciiString(theDirFace2V) + ", ";
- aDescr += TCollection_AsciiString(theNbTimesV) + ") ";
-
- aFunction->SetDescription(aDescr);
+ GEOM::TPythonDump(aFunction) << aCopy << " = geompy.MakeMultiTransformation2D("
+ << theObject << ", " << theDirFace1U << ", " << theDirFace2U << ", " << theNbTimesU
+ << ", " << theDirFace1V << ", " << theDirFace2V << ", " << theNbTimesV << ")";
SetErrorCode(OK);
return aCopy;
}
+
+//=============================================================================
+/*!
+ * Propagate
+ */
+//=============================================================================
+Handle(TColStd_HSequenceOfTransient) GEOMImpl_IBlocksOperations::Propagate
+ (Handle(GEOM_Object) theShape)
+{
+ SetErrorCode(KO);
+
+ if (theShape.IsNull()) return NULL;
+
+ TopoDS_Shape aShape = theShape->GetValue();
+ if (aShape.IsNull()) return NULL;
+
+ TopTools_IndexedMapOfShape anIndices;
+ TopExp::MapShapes(aShape, anIndices);
+
+ TopTools_IndexedDataMapOfShapeListOfShape MEW;
+ GEOMImpl_Block6Explorer::MapShapesAndAncestors
+ (aShape, TopAbs_EDGE, TopAbs_WIRE, MEW);
+ Standard_Integer ie, nbEdges = MEW.Extent();
+
+ // Result
+ Handle(TColStd_HSequenceOfTransient) aSeq = new TColStd_HSequenceOfTransient;
+
+ TopTools_MapOfShape mapAcceptedEdges;
+ TCollection_AsciiString aListRes, anEntry;
+
+ // Sort shapes in current chain (Mantis issue 21053)
+ TopTools_DataMapOfShapeListOfShape aMapChains;
+ TopTools_ListOfShape aFirstInChains;
+
+ for (ie = 1; ie <= nbEdges; ie++) {
+ TopoDS_Shape curE = MEW.FindKey(ie);
+
+ if (mapAcceptedEdges.Contains(curE)) continue;
+
+ // Build the chain
+ TopTools_ListOfShape currentChain;
+ TopTools_ListOfShape listPrevEdges;
+
+ currentChain.Append(curE);
+ listPrevEdges.Append(curE);
+ mapAcceptedEdges.Add(curE);
+
+ // Collect all edges pass by pass
+ while (listPrevEdges.Extent() > 0) {
+ // List of edges, added to chain on this cycle pass
+ TopTools_ListOfShape listCurEdges;
+
+ // Find the next portion of edges
+ TopTools_ListIteratorOfListOfShape itE (listPrevEdges);
+ for (; itE.More(); itE.Next()) {
+ TopoDS_Shape anE = itE.Value();
+
+ // Iterate on faces, having edge <anE>
+ TopTools_ListIteratorOfListOfShape itW (MEW.FindFromKey(anE));
+ for (; itW.More(); itW.Next()) {
+ TopoDS_Shape aW = itW.Value();
+ TopoDS_Shape anOppE;
+
+ BRepTools_WireExplorer aWE (TopoDS::Wire(aW));
+ Standard_Integer nb = 1, found = 0;
+ TopTools_Array1OfShape anEdges (1,4);
+ for (; aWE.More(); aWE.Next(), nb++) {
+ if (nb > 4) {
+ found = 0;
+ break;
+ }
+ anEdges(nb) = aWE.Current();
+ if (anEdges(nb).IsSame(anE)) found = nb;
+ }
+
+ if (nb == 5 && found > 0) {
+ // Quadrangle face found, get an opposite edge
+ Standard_Integer opp = found + 2;
+ if (opp > 4) opp -= 4;
+ anOppE = anEdges(opp);
+
+ if (!mapAcceptedEdges.Contains(anOppE)) {
+ // Add found edge to the chain
+ currentChain.Append(anOppE);
+ listCurEdges.Append(anOppE);
+ mapAcceptedEdges.Add(anOppE);
+ }
+ } // if (nb == 5 && found > 0)
+ } // for (; itF.More(); itF.Next())
+ } // for (; itE.More(); itE.Next())
+
+ listPrevEdges = listCurEdges;
+ } // while (listPrevEdges.Extent() > 0)
+
+ // Sort shapes in current chain (Mantis issue 21053)
+ GEOMUtils::SortShapes(currentChain, Standard_False);
+ aFirstInChains.Append(currentChain.First());
+ aMapChains.Bind(currentChain.First(), currentChain);
+ }
+
+ // Sort chains (Mantis issue 21053)
+ GEOMUtils::SortShapes(aFirstInChains, Standard_False);
+
+ // Store sorted chains in the document
+ TopTools_ListIteratorOfListOfShape aChainsIt (aFirstInChains);
+ for (; aChainsIt.More(); aChainsIt.Next()) {
+ TopoDS_Shape aFirstInChain = aChainsIt.Value();
+ const TopTools_ListOfShape& currentChain = aMapChains.Find(aFirstInChain);
+
+ // Store the chain in the document
+ Handle(TColStd_HArray1OfInteger) anArray =
+ new TColStd_HArray1OfInteger (1, currentChain.Extent());
+
+ // Fill array of sub-shape indices
+ TopTools_ListIteratorOfListOfShape itSub (currentChain);
+ for (int index = 1; itSub.More(); itSub.Next(), ++index) {
+ int id = anIndices.FindIndex(itSub.Value());
+ anArray->SetValue(index, id);
+ }
+
+ // Add a new group object
+ Handle(GEOM_Object) aChain = GetEngine()->AddSubShape(theShape, anArray);
+
+ // Set a GROUP type
+ aChain->SetType(GEOM_GROUP);
+
+ // Set a sub-shape type
+ TDF_Label aFreeLabel = aChain->GetFreeLabel();
+ TDataStd_Integer::Set(aFreeLabel, (Standard_Integer)TopAbs_EDGE);
+
+ // Add the chain to the result
+ aSeq->Append(aChain);
+
+ //Make a Python command
+ TDF_Tool::Entry(aChain->GetEntry(), anEntry);
+ aListRes += anEntry + ", ";
+ }
+
+ if (aSeq->IsEmpty()) {
+ SetErrorCode("There are no quadrangle faces in the shape");
+ return aSeq;
+ }
+
+ aListRes.Trunc(aListRes.Length() - 2);
+
+ // The Propagation doesn't change object so no new function is required.
+ Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
+
+ // Make a Python command
+ GEOM::TPythonDump(aFunction, /*append=*/true)
+ << "[" << aListRes.ToCString() << "] = geompy.Propagate(" << theShape << ")";
+
+ SetErrorCode(OK);
+ return aSeq;
+}