geom/src/GEOMImpl/GEOMImpl_IBlocksOperations.cxx

3501 lines
111 KiB
C++

// Copyright (C) 2007-2014 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 <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 <BRepClass_FaceClassifier.hxx>
#include <BRepClass3d_SolidClassifier.hxx>
#include <BRepExtrema_DistShapeShape.hxx>
#include <TopAbs.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 <GProp_GProps.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
//=============================================================================
/*!
* constructor:
*/
//=============================================================================
GEOMImpl_IBlocksOperations::GEOMImpl_IBlocksOperations (GEOM_Engine* theEngine, int theDocID)
: GEOM_IOperations(theEngine, theDocID)
{
MESSAGE("GEOMImpl_IBlocksOperations::GEOMImpl_IBlocksOperations");
}
//=============================================================================
/*!
* destructor
*/
//=============================================================================
GEOMImpl_IBlocksOperations::~GEOMImpl_IBlocksOperations()
{
MESSAGE("GEOMImpl_IBlocksOperations::~GEOMImpl_IBlocksOperations");
}
//=============================================================================
/*!
* MakeQuad
*/
//=============================================================================
Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuad
(Handle(GEOM_Object) theEdge1, Handle(GEOM_Object) theEdge2,
Handle(GEOM_Object) theEdge3, Handle(GEOM_Object) theEdge4)
{
SetErrorCode(KO);
if (theEdge1.IsNull() || theEdge2.IsNull() ||
theEdge3.IsNull() || theEdge4.IsNull()) return NULL;
//Add a new Face object
Handle(GEOM_Object) aFace = GetEngine()->AddObject(GetDocID(), GEOM_FACE);
//Add a new Face function
Handle(GEOM_Function) aFunction =
aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_FOUR_EDGES);
//Check if the function is set correctly
if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
GEOMImpl_IBlocks aPI (aFunction);
Handle(GEOM_Function) aRef1 = theEdge1->GetLastFunction();
Handle(GEOM_Function) aRef2 = theEdge2->GetLastFunction();
Handle(GEOM_Function) aRef3 = theEdge3->GetLastFunction();
Handle(GEOM_Function) aRef4 = theEdge4->GetLastFunction();
if (aRef1.IsNull() || aRef2.IsNull() ||
aRef3.IsNull() || aRef4.IsNull()) return NULL;
Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
aShapesSeq->Append(aRef1);
aShapesSeq->Append(aRef2);
aShapesSeq->Append(aRef3);
aShapesSeq->Append(aRef4);
aPI.SetShapes(aShapesSeq);
//Compute the Face value
try {
OCC_CATCH_SIGNALS;
if (!GetSolver()->ComputeFunction(aFunction)) {
SetErrorCode("Block driver failed to compute a face");
return NULL;
}
}
catch (Standard_Failure) {
Handle(Standard_Failure) aFail = Standard_Failure::Caught();
SetErrorCode(aFail->GetMessageString());
return NULL;
}
//Make a Python command
GEOM::TPythonDump(aFunction) << aFace << " = geompy.MakeQuad("
<< theEdge1 << ", " << theEdge2 << ", " << theEdge3 << ", " << theEdge4 << ")";
SetErrorCode(OK);
return aFace;
}
//=============================================================================
/*!
* MakeQuad2Edges
*/
//=============================================================================
Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuad2Edges
(Handle(GEOM_Object) theEdge1, Handle(GEOM_Object) theEdge2)
{
SetErrorCode(KO);
if (theEdge1.IsNull() || theEdge2.IsNull()) return NULL;
//Add a new Face object
Handle(GEOM_Object) aFace = GetEngine()->AddObject(GetDocID(), GEOM_FACE);
//Add a new Face function
Handle(GEOM_Function) aFunction =
aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_TWO_EDGES);
//Check if the function is set correctly
if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
GEOMImpl_IBlocks aPI (aFunction);
Handle(GEOM_Function) aRef1 = theEdge1->GetLastFunction();
Handle(GEOM_Function) aRef2 = theEdge2->GetLastFunction();
if (aRef1.IsNull() || aRef2.IsNull()) return NULL;
Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
aShapesSeq->Append(aRef1);
aShapesSeq->Append(aRef2);
aPI.SetShapes(aShapesSeq);
//Compute the Face value
try {
OCC_CATCH_SIGNALS;
if (!GetSolver()->ComputeFunction(aFunction)) {
SetErrorCode("Block driver failed to compute a face");
return NULL;
}
}
catch (Standard_Failure) {
Handle(Standard_Failure) aFail = Standard_Failure::Caught();
SetErrorCode(aFail->GetMessageString());
return NULL;
}
//Make a Python command
GEOM::TPythonDump(aFunction) << aFace << " = geompy.MakeQuad2Edges("
<< theEdge1 << ", " << theEdge2 << ")";
SetErrorCode(OK);
return aFace;
}
//=============================================================================
/*!
* MakeQuad4Vertices
*/
//=============================================================================
Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeQuad4Vertices
(Handle(GEOM_Object) thePnt1, Handle(GEOM_Object) thePnt2,
Handle(GEOM_Object) thePnt3, Handle(GEOM_Object) thePnt4)
{
SetErrorCode(KO);
if (thePnt1.IsNull() || thePnt2.IsNull() ||
thePnt3.IsNull() || thePnt4.IsNull()) return NULL;
//Add a new Face object
Handle(GEOM_Object) aFace = GetEngine()->AddObject(GetDocID(), GEOM_FACE);
//Add a new Face function
Handle(GEOM_Function) aFunction =
aFace->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_FACE_FOUR_PNT);
//Check if the function is set correctly
if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
GEOMImpl_IBlocks aPI (aFunction);
Handle(GEOM_Function) aRef1 = thePnt1->GetLastFunction();
Handle(GEOM_Function) aRef2 = thePnt2->GetLastFunction();
Handle(GEOM_Function) aRef3 = thePnt3->GetLastFunction();
Handle(GEOM_Function) aRef4 = thePnt4->GetLastFunction();
if (aRef1.IsNull() || aRef2.IsNull() ||
aRef3.IsNull() || aRef4.IsNull()) return NULL;
Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
aShapesSeq->Append(aRef1);
aShapesSeq->Append(aRef2);
aShapesSeq->Append(aRef3);
aShapesSeq->Append(aRef4);
aPI.SetShapes(aShapesSeq);
//Compute the Face value
try {
OCC_CATCH_SIGNALS;
if (!GetSolver()->ComputeFunction(aFunction)) {
SetErrorCode("Block driver failed to compute a face");
return NULL;
}
}
catch (Standard_Failure) {
Handle(Standard_Failure) aFail = Standard_Failure::Caught();
SetErrorCode(aFail->GetMessageString());
return NULL;
}
//Make a Python command
GEOM::TPythonDump(aFunction) << aFace << " = geompy.MakeQuad4Vertices("
<< thePnt1 << ", " << thePnt2 << ", " << thePnt3 << ", " << thePnt4 << ")";
SetErrorCode(OK);
return aFace;
}
//=============================================================================
/*!
* MakeHexa
*/
//=============================================================================
Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeHexa
(Handle(GEOM_Object) theFace1, Handle(GEOM_Object) theFace2,
Handle(GEOM_Object) theFace3, Handle(GEOM_Object) theFace4,
Handle(GEOM_Object) theFace5, Handle(GEOM_Object) theFace6)
{
SetErrorCode(KO);
if (theFace1.IsNull() || theFace2.IsNull() ||
theFace3.IsNull() || theFace4.IsNull() ||
theFace5.IsNull() || theFace6.IsNull()) return NULL;
//Add a new Solid object
Handle(GEOM_Object) aBlock = GetEngine()->AddObject(GetDocID(), GEOM_BLOCK);
//Add a new Block function
Handle(GEOM_Function) aFunction =
aBlock->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_SIX_FACES);
//Check if the function is set correctly
if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
GEOMImpl_IBlocks aPI (aFunction);
Handle(GEOM_Function) aRef1 = theFace1->GetLastFunction();
Handle(GEOM_Function) aRef2 = theFace2->GetLastFunction();
Handle(GEOM_Function) aRef3 = theFace3->GetLastFunction();
Handle(GEOM_Function) aRef4 = theFace4->GetLastFunction();
Handle(GEOM_Function) aRef5 = theFace5->GetLastFunction();
Handle(GEOM_Function) aRef6 = theFace6->GetLastFunction();
if (aRef1.IsNull() || aRef2.IsNull() ||
aRef3.IsNull() || aRef4.IsNull() ||
aRef5.IsNull() || aRef6.IsNull()) return NULL;
Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
aShapesSeq->Append(aRef1);
aShapesSeq->Append(aRef2);
aShapesSeq->Append(aRef3);
aShapesSeq->Append(aRef4);
aShapesSeq->Append(aRef5);
aShapesSeq->Append(aRef6);
aPI.SetShapes(aShapesSeq);
//Compute the Block value
try {
OCC_CATCH_SIGNALS;
if (!GetSolver()->ComputeFunction(aFunction)) {
SetErrorCode("Block driver failed to compute a block");
return NULL;
}
}
catch (Standard_Failure) {
Handle(Standard_Failure) aFail = Standard_Failure::Caught();
SetErrorCode(aFail->GetMessageString());
return NULL;
}
//Make a Python command
GEOM::TPythonDump(aFunction) << aBlock << " = geompy.MakeHexa("
<< theFace1 << ", " << theFace2 << ", " << theFace3 << ", "
<< theFace4 << ", " << theFace5 << ", " << theFace6 << ")";
SetErrorCode(OK);
return aBlock;
}
//=============================================================================
/*!
* MakeHexa2Faces
*/
//=============================================================================
Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeHexa2Faces
(Handle(GEOM_Object) theFace1, Handle(GEOM_Object) theFace2)
{
SetErrorCode(KO);
if (theFace1.IsNull() || theFace2.IsNull()) return NULL;
//Add a new Solid object
Handle(GEOM_Object) aBlock = GetEngine()->AddObject(GetDocID(), GEOM_BLOCK);
//Add a new Block function
Handle(GEOM_Function) aFunction =
aBlock->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_TWO_FACES);
//Check if the function is set correctly
if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
GEOMImpl_IBlocks aPI (aFunction);
Handle(GEOM_Function) aRef1 = theFace1->GetLastFunction();
Handle(GEOM_Function) aRef2 = theFace2->GetLastFunction();
if (aRef1.IsNull() || aRef2.IsNull()) return NULL;
Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
aShapesSeq->Append(aRef1);
aShapesSeq->Append(aRef2);
aPI.SetShapes(aShapesSeq);
//Compute the Block value
try {
OCC_CATCH_SIGNALS;
if (!GetSolver()->ComputeFunction(aFunction)) {
SetErrorCode("Block driver failed to compute a block");
return NULL;
}
}
catch (Standard_Failure) {
Handle(Standard_Failure) aFail = Standard_Failure::Caught();
SetErrorCode(aFail->GetMessageString());
return NULL;
}
//Make a Python command
GEOM::TPythonDump(aFunction) << aBlock << " = geompy.MakeHexa2Faces("
<< theFace1 << ", " << theFace2 << ")";
SetErrorCode(OK);
return aBlock;
}
//=============================================================================
/*!
* MakeBlockCompound
*/
//=============================================================================
Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeBlockCompound
(Handle(GEOM_Object) theCompound)
{
SetErrorCode(KO);
if (theCompound.IsNull()) return NULL;
//Add a new object
Handle(GEOM_Object) aBlockComp = GetEngine()->AddObject(GetDocID(), GEOM_COMPOUND);
//Add a new BlocksComp function
Handle(GEOM_Function) aFunction =
aBlockComp->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_COMPOUND_GLUE);
//Check if the function is set correctly
if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
GEOMImpl_IBlocks aPI (aFunction);
Handle(GEOM_Function) aRef1 = theCompound->GetLastFunction();
if (aRef1.IsNull()) return NULL;
Handle(TColStd_HSequenceOfTransient) aShapesSeq = new TColStd_HSequenceOfTransient;
aShapesSeq->Append(aRef1);
aPI.SetShapes(aShapesSeq);
//Compute the Blocks Compound value
try {
OCC_CATCH_SIGNALS;
if (!GetSolver()->ComputeFunction(aFunction)) {
SetErrorCode("Block driver failed to compute a 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) << aBlockComp
<< " = geompy.MakeBlockCompound(" << theCompound << ")";
SetErrorCode(OK);
return aBlockComp;
}
//=============================================================================
/*!
* GetPoint
*/
//=============================================================================
Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetPoint
(Handle(GEOM_Object) theShape,
const Standard_Real theX,
const Standard_Real theY,
const Standard_Real theZ,
const Standard_Real theEpsilon)
{
SetErrorCode(KO);
//New Point object
Handle(GEOM_Object) aResult;
// Arguments
if (theShape.IsNull()) return NULL;
TopoDS_Shape aBlockOrComp = theShape->GetValue();
if (aBlockOrComp.IsNull()) {
SetErrorCode("Given shape is null");
return NULL;
}
//Compute the Vertex value
gp_Pnt P (theX, theY, theZ);
Standard_Real eps = Max(theEpsilon, Precision::Confusion());
TopoDS_Shape V;
Standard_Integer isFound = 0;
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);
if (aPi.Distance(P) < eps) {
V = aVi;
isFound++;
}
}
}
if (isFound == 0) {
SetErrorCode("Vertex has not been found");
return NULL;
} else if (isFound > 1) {
SetErrorCode("Multiple vertices found by the given coordinates and epsilon");
return NULL;
} else {
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);
}
//The GetPoint() 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)
<< 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;
}
//=============================================================================
/*!
* GetEdge
*/
//=============================================================================
Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetEdge
(Handle(GEOM_Object) theShape,
Handle(GEOM_Object) thePoint1,
Handle(GEOM_Object) thePoint2)
{
SetErrorCode(KO);
//New Edge object
Handle(GEOM_Object) aResult;
// Arguments
if (theShape.IsNull() || thePoint1.IsNull() || thePoint2.IsNull()) return NULL;
TopoDS_Shape aBlockOrComp = theShape->GetValue();
if (aBlockOrComp.IsNull()) {
SetErrorCode("Given shape is null");
return NULL;
}
TopoDS_Shape anArg1 = thePoint1->GetValue();
TopoDS_Shape anArg2 = thePoint2->GetValue();
if (anArg1.IsNull() || anArg2.IsNull()) {
SetErrorCode("Null shape is given as argument");
return NULL;
}
if (anArg1.ShapeType() != TopAbs_VERTEX ||
anArg2.ShapeType() != TopAbs_VERTEX) {
SetErrorCode("Element for edge identification is not a vertex");
return NULL;
}
//Compute the Edge value
try {
OCC_CATCH_SIGNALS;
TopTools_IndexedDataMapOfShapeListOfShape MVE;
GEOMImpl_Block6Explorer::MapShapesAndAncestors
(aBlockOrComp, TopAbs_VERTEX, TopAbs_EDGE, MVE);
TopoDS_Shape V1,V2;
Standard_Integer ish, ext = MVE.Extent();
if (MVE.Contains(anArg1)) {
V1 = anArg1;
} else {
for (ish = 1; ish <= ext; ish++) {
TopoDS_Shape aShi = MVE.FindKey(ish);
if (BRepTools::Compare(TopoDS::Vertex(anArg1), TopoDS::Vertex(aShi))) {
V1 = aShi;
break;
}
}
}
if (MVE.Contains(anArg2)) {
V2 = anArg2;
} else {
for (ish = 1; ish <= ext; ish++) {
TopoDS_Shape aShi = MVE.FindKey(ish);
if (BRepTools::Compare(TopoDS::Vertex(anArg2), TopoDS::Vertex(aShi))) {
V2 = aShi;
break;
}
}
}
if (V1.IsNull() || V2.IsNull()) {
SetErrorCode("The given vertex does not belong to the shape");
return NULL;
}
TopoDS_Shape anEdge;
Standard_Integer isFound =
GEOMImpl_Block6Explorer::FindEdge(anEdge, V1, V2, MVE, Standard_True);
if (isFound == 0) {
SetErrorCode("The given vertices do not belong to one edge of the given shape");
return NULL;
} else if (isFound > 1) {
SetErrorCode("Multiple edges found by the given vertices of the shape");
return NULL;
} else {
TopTools_IndexedMapOfShape anIndices;
TopExp::MapShapes(aBlockOrComp, anIndices);
Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
anArray->SetValue(1, anIndices.FindIndex(anEdge));
aResult = GetEngine()->AddSubShape(theShape, anArray);
}
} catch (Standard_Failure) {
Handle(Standard_Failure) aFail = Standard_Failure::Caught();
SetErrorCode(aFail->GetMessageString());
return NULL;
}
Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
//Make a Python command
GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetEdge("
<< theShape << ", " << thePoint1 << ", " << thePoint2 << ")";
SetErrorCode(OK);
return aResult;
}
//=============================================================================
/*!
* GetEdgeNearPoint
*/
//=============================================================================
Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetEdgeNearPoint
(Handle(GEOM_Object) theShape,
Handle(GEOM_Object) thePoint)
{
SetErrorCode(KO);
//New object
Handle(GEOM_Object) aResult;
// Arguments
if (theShape.IsNull() || thePoint.IsNull()) return NULL;
TopoDS_Shape aBlockOrComp = theShape->GetValue();
if (aBlockOrComp.IsNull()) {
SetErrorCode("Given shape 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 edge identification is not a vertex");
return NULL;
}
//Compute the Edge value
try {
OCC_CATCH_SIGNALS;
TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
TopoDS_Shape aShape = GEOMUtils::GetEdgeNearPoint(aBlockOrComp, aVert);
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();
SetErrorCode(aFail->GetMessageString());
return NULL;
}
Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
//Make a Python command
GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetEdgeNearPoint("
<< theShape << ", " << thePoint << ")";
SetErrorCode(OK);
return aResult;
}
//=============================================================================
/*!
* GetFaceByPoints
*/
//=============================================================================
Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByPoints
(Handle(GEOM_Object) theShape,
Handle(GEOM_Object) thePoint1,
Handle(GEOM_Object) thePoint2,
Handle(GEOM_Object) thePoint3,
Handle(GEOM_Object) thePoint4)
{
SetErrorCode(KO);
//New object
Handle(GEOM_Object) aResult;
// Arguments
if (theShape.IsNull() ||
thePoint1.IsNull() || thePoint2.IsNull() ||
thePoint3.IsNull() || thePoint4.IsNull()) return NULL;
TopoDS_Shape aBlockOrComp = theShape->GetValue();
if (aBlockOrComp.IsNull()) {
SetErrorCode("Block or compound is null");
return NULL;
}
TopoDS_Shape anArg1 = thePoint1->GetValue();
TopoDS_Shape anArg2 = thePoint2->GetValue();
TopoDS_Shape anArg3 = thePoint3->GetValue();
TopoDS_Shape anArg4 = thePoint4->GetValue();
if (anArg1.IsNull() || anArg2.IsNull() ||
anArg3.IsNull() || anArg4.IsNull()) {
SetErrorCode("Null shape is given as argument");
return NULL;
}
if (anArg1.ShapeType() != TopAbs_VERTEX ||
anArg2.ShapeType() != TopAbs_VERTEX ||
anArg3.ShapeType() != TopAbs_VERTEX ||
anArg4.ShapeType() != TopAbs_VERTEX) {
SetErrorCode("Element for face identification is not a vertex");
return NULL;
}
//Compute the Face value
try {
OCC_CATCH_SIGNALS;
TopoDS_Shape aShape;
TopTools_IndexedDataMapOfShapeListOfShape MVF;
GEOMImpl_Block6Explorer::MapShapesAndAncestors(aBlockOrComp, TopAbs_VERTEX, TopAbs_FACE, MVF);
TopoDS_Shape V1,V2,V3,V4;
Standard_Integer ish, ext = MVF.Extent();
if (MVF.Contains(anArg1)) {
V1 = anArg1;
} else {
for (ish = 1; ish <= ext; ish++) {
TopoDS_Shape aShi = MVF.FindKey(ish);
if (BRepTools::Compare(TopoDS::Vertex(anArg1), TopoDS::Vertex(aShi))) {
V1 = aShi;
break;
}
}
}
if (MVF.Contains(anArg2)) {
V2 = anArg2;
} else {
for (ish = 1; ish <= ext; ish++) {
TopoDS_Shape aShi = MVF.FindKey(ish);
if (BRepTools::Compare(TopoDS::Vertex(anArg2), TopoDS::Vertex(aShi))) {
V2 = aShi;
break;
}
}
}
if (MVF.Contains(anArg3)) {
V3 = anArg3;
} else {
for (ish = 1; ish <= ext; ish++) {
TopoDS_Shape aShi = MVF.FindKey(ish);
if (BRepTools::Compare(TopoDS::Vertex(anArg3), TopoDS::Vertex(aShi))) {
V3 = aShi;
break;
}
}
}
if (MVF.Contains(anArg4)) {
V4 = anArg4;
} else {
for (ish = 1; ish <= ext; ish++) {
TopoDS_Shape aShi = MVF.FindKey(ish);
if (BRepTools::Compare(TopoDS::Vertex(anArg4), TopoDS::Vertex(aShi))) {
V4 = aShi;
break;
}
}
}
if (V1.IsNull() || V2.IsNull() || V3.IsNull() || V4.IsNull()) {
SetErrorCode("The given vertex does not belong to the shape");
return NULL;
}
Standard_Integer isFound =
GEOMImpl_Block6Explorer::FindFace(aShape, V1, V2, V3, V4, MVF, Standard_True);
if (isFound == 0) {
SetErrorCode("The given vertices do not belong to one face of the given shape");
return NULL;
} else if (isFound > 1) {
SetErrorCode("The given vertices belong to several faces of the given shape");
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);
}
}
catch (Standard_Failure) {
Handle(Standard_Failure) aFail = Standard_Failure::Caught();
SetErrorCode(aFail->GetMessageString());
return NULL;
}
Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
//Make a Python command
GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceByPoints("
<< theShape << ", " << thePoint1 << ", " << thePoint2
<< ", " << thePoint3 << ", " << thePoint4 << ")";
SetErrorCode(OK);
return aResult;
}
//=============================================================================
/*!
* GetFaceByEdges
*/
//=============================================================================
Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByEdges
(Handle(GEOM_Object) theShape,
Handle(GEOM_Object) theEdge1,
Handle(GEOM_Object) theEdge2)
{
SetErrorCode(KO);
//New object
Handle(GEOM_Object) aResult;
// Arguments
if (theShape.IsNull() || theEdge1.IsNull() || theEdge2.IsNull()) return NULL;
TopoDS_Shape aBlockOrComp = theShape->GetValue();
if (aBlockOrComp.IsNull()) {
SetErrorCode("Block or compound is null");
return NULL;
}
TopoDS_Shape anArg1 = theEdge1->GetValue();
TopoDS_Shape anArg2 = theEdge2->GetValue();
if (anArg1.IsNull() || anArg2.IsNull()) {
SetErrorCode("Null shape is given as argument");
return NULL;
}
if (anArg1.ShapeType() != TopAbs_EDGE ||
anArg2.ShapeType() != TopAbs_EDGE) {
SetErrorCode("Element for face identification is not an edge");
return NULL;
}
//Compute the Face value
try {
OCC_CATCH_SIGNALS;
TopoDS_Shape aShape;
TopTools_IndexedDataMapOfShapeListOfShape MEF;
GEOMImpl_Block6Explorer::MapShapesAndAncestors(aBlockOrComp, TopAbs_EDGE, TopAbs_FACE, MEF);
TopoDS_Shape E1,E2;
Standard_Integer ish, ext = MEF.Extent();
if (MEF.Contains(anArg1)) {
E1 = anArg1;
} else {
for (ish = 1; ish <= ext; ish++) {
TopoDS_Shape aShi = MEF.FindKey(ish);
if (GEOMImpl_Block6Explorer::IsSimilarEdges(anArg1, aShi)) {
E1 = aShi;
}
}
}
if (MEF.Contains(anArg2)) {
E2 = anArg2;
} else {
for (ish = 1; ish <= ext; ish++) {
TopoDS_Shape aShi = MEF.FindKey(ish);
if (GEOMImpl_Block6Explorer::IsSimilarEdges(anArg2, aShi)) {
E2 = aShi;
}
}
}
if (E1.IsNull() || E2.IsNull()) {
SetErrorCode("The given edge does not belong to the shape");
return NULL;
}
const TopTools_ListOfShape& aFacesOfE1 = MEF.FindFromKey(E1);
const TopTools_ListOfShape& aFacesOfE2 = MEF.FindFromKey(E2);
Standard_Integer isFound = 0;
TopTools_ListIteratorOfListOfShape anIterF1 (aFacesOfE1);
for (; anIterF1.More(); anIterF1.Next()) {
TopTools_ListIteratorOfListOfShape anIterF2 (aFacesOfE2);
for (; anIterF2.More(); anIterF2.Next()) {
if (anIterF1.Value().IsSame(anIterF2.Value())) {
isFound++;
// Store the face, defined by two edges
aShape = anIterF1.Value();
}
}
}
if (isFound == 0) {
SetErrorCode("The given edges do not belong to one face of the given shape");
return NULL;
} else if (isFound > 1) {
SetErrorCode("The given edges belong to several faces of the given shape");
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);
}
}
catch (Standard_Failure) {
Handle(Standard_Failure) aFail = Standard_Failure::Caught();
SetErrorCode(aFail->GetMessageString());
return NULL;
}
Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
//Make a Python command
GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceByEdges("
<< theShape << ", " << theEdge1 << ", " << theEdge2 << ")";
SetErrorCode(OK);
return aResult;
}
//=============================================================================
/*!
* GetOppositeFace
*/
//=============================================================================
Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetOppositeFace
(Handle(GEOM_Object) theShape,
Handle(GEOM_Object) theFace)
{
SetErrorCode(KO);
//New object
Handle(GEOM_Object) aResult;
// Arguments
if (theShape.IsNull() || theFace.IsNull()) return NULL;
TopoDS_Shape aBlockOrComp = theShape->GetValue();
if (aBlockOrComp.IsNull()) {
SetErrorCode("Block is null");
return NULL;
}
if (aBlockOrComp.ShapeType() != TopAbs_SOLID) {
SetErrorCode("Shape is not a block");
return NULL;
}
TopoDS_Shape anArg = theFace->GetValue();
if (anArg.IsNull()) {
SetErrorCode("Null shape is given as argument");
return NULL;
}
if (anArg.ShapeType() != TopAbs_FACE) {
SetErrorCode("Element for face identification is not a face");
return NULL;
}
//Compute the Face value
try {
OCC_CATCH_SIGNALS;
TopoDS_Shape aShape;
GEOMImpl_Block6Explorer aBlockTool;
aBlockTool.InitByBlockAndFace(aBlockOrComp, anArg);
aShape = aBlockTool.GetFace(2);
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();
SetErrorCode(aFail->GetMessageString());
return NULL;
}
Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
//Make a Python command
GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetOppositeFace("
<< theShape << ", " << theFace << ")";
SetErrorCode(OK);
return aResult;
}
//=============================================================================
/*!
* GetFaceNearPoint
*/
//=============================================================================
Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceNearPoint
(Handle(GEOM_Object) theShape,
Handle(GEOM_Object) thePoint)
{
SetErrorCode(KO);
//New object
Handle(GEOM_Object) aResult;
// Arguments
if (theShape.IsNull() || thePoint.IsNull()) return NULL;
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;
}
//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. 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()) {
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;
}
}
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 {
}
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
// no faces, having the point inside
SetErrorCode("Multiple faces near the given point are found");
return NULL;
} else if (nearest == 1) {
// 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 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;
}
}
if (aDist < minDist) {
minDist = aDist;
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;
} 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);
}
}
catch (Standard_Failure) {
Handle(Standard_Failure) aFail = Standard_Failure::Caught();
SetErrorCode(aFail->GetMessageString());
return NULL;
}
Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
//Make a Python command
GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceNearPoint("
<< theShape << ", " << thePoint << ")";
SetErrorCode(OK);
return aResult;
}
//=============================================================================
/*!
* GetFaceByNormale
*/
//=============================================================================
Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetFaceByNormale
(Handle(GEOM_Object) theShape,
Handle(GEOM_Object) theVector)
{
SetErrorCode(KO);
//New object
Handle(GEOM_Object) aResult;
// Arguments
if (theShape.IsNull() || theVector.IsNull()) return NULL;
TopoDS_Shape aBlockOrComp = theShape->GetValue();
if (aBlockOrComp.IsNull()) {
SetErrorCode("Block or compound is null");
return NULL;
}
TopoDS_Shape anArg = theVector->GetValue();
if (anArg.IsNull()) {
SetErrorCode("Null shape is given as argument");
return NULL;
}
if (anArg.ShapeType() != TopAbs_EDGE) {
SetErrorCode("Element for normale identification is not an edge");
return NULL;
}
//Compute the Face value
try {
OCC_CATCH_SIGNALS;
TopoDS_Shape aShape;
TopoDS_Edge anEdge = TopoDS::Edge(anArg);
TopoDS_Vertex V1, V2;
TopExp::Vertices(anEdge, V1, V2, Standard_True);
gp_Pnt P1 = BRep_Tool::Pnt(V1);
gp_Pnt P2 = BRep_Tool::Pnt(V2);
gp_Vec aVec (P1, P2);
if (aVec.Magnitude() < Precision::Confusion()) {
SetErrorCode("Vector with null magnitude is given");
return NULL;
}
Standard_Real minAngle = RealLast();
TopTools_MapOfShape mapShape;
TopExp_Explorer exp (aBlockOrComp, TopAbs_FACE);
for (; exp.More(); exp.Next()) {
if (mapShape.Add(exp.Current())) {
TopoDS_Face aFace = TopoDS::Face(exp.Current());
BRepAdaptor_Surface SF (aFace);
Standard_Real u, v, x;
// find a point on the surface to get normal direction in
u = SF.FirstUParameter();
x = SF.LastUParameter();
if (Precision::IsInfinite(u)) {
u = (Precision::IsInfinite(x)) ? 0. : x;
} else if (!Precision::IsInfinite(x)) {
u = (u+x) / 2.;
}
v = SF.FirstVParameter();
x = SF.LastVParameter();
if (Precision::IsInfinite(v)) {
v = (Precision::IsInfinite(x)) ? 0. : x;
} else if (!Precision::IsInfinite(x)) {
v = (v+x) / 2.;
}
// compute the normal direction
gp_Vec Vec1,Vec2;
SF.D1(u,v,P1,Vec1,Vec2);
gp_Vec V = Vec1.Crossed(Vec2);
x = V.Magnitude();
if (V.Magnitude() < Precision::Confusion()) {
SetErrorCode("Normal vector of a face has null magnitude");
return NULL;
}
// consider the face orientation
if (aFace.Orientation() == TopAbs_REVERSED ||
aFace.Orientation() == TopAbs_INTERNAL) {
V = - V;
}
// compute the angle and compare with the minimal one
Standard_Real anAngle = aVec.Angle(V);
if (anAngle < minAngle) {
minAngle = anAngle;
aShape = aFace;
}
}
}
if (aShape.IsNull()) {
SetErrorCode("Failed to find a face by the given normale");
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);
}
}
catch (Standard_Failure) {
Handle(Standard_Failure) aFail = Standard_Failure::Caught();
SetErrorCode(aFail->GetMessageString());
return NULL;
}
Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
//Make a Python command
GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetFaceByNormale("
<< theShape << ", " << theVector << ")";
SetErrorCode(OK);
return aResult;
}
//=============================================================================
/*!
* GetShapesNearPoint
*/
//=============================================================================
Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetShapesNearPoint
(Handle(GEOM_Object) theShape,
Handle(GEOM_Object) thePoint,
const Standard_Integer theShapeType,
const Standard_Real theConstTolerance)
{
SetErrorCode(KO);
// New object
Handle(GEOM_Object) aResult;
// Arguments
if (theShape.IsNull() || thePoint.IsNull()) return NULL;
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;
}
}
}
if (nbFaces < theMinNbFaces || theMaxNbFaces < nbFaces) {
isCompOfBlocks = Standard_False;
} else {
theNbBlocks++;
}
}
}
}
catch (Standard_Failure) {
Handle(Standard_Failure) aFail = Standard_Failure::Caught();
SetErrorCode(aFail->GetMessageString());
return isCompOfBlocks;
}
SetErrorCode(OK);
return isCompOfBlocks;
}
//=============================================================================
/*!
* Set of functions, used by CheckCompoundOfBlocks() method
*/
//=============================================================================
void GEOMImpl_IBlocksOperations::AddBlocksFrom (const TopoDS_Shape& theShape,
TopTools_ListOfShape& BLO,
TopTools_ListOfShape& NOT,
TopTools_ListOfShape& EXT,
TopTools_ListOfShape& NOQ)
{
TopAbs_ShapeEnum aType = theShape.ShapeType();
switch (aType) {
case TopAbs_COMPOUND:
case TopAbs_COMPSOLID:
{
TopoDS_Iterator It (theShape);
for (; It.More(); It.Next()) {
AddBlocksFrom(It.Value(), BLO, NOT, EXT, NOQ);
}
}
break;
case TopAbs_SOLID:
{
// Check, if there are seam or degenerated edges
BlockFix_CheckTool aTool;
aTool.SetShape(theShape);
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()) {
if (mapFaces.Add(expF.Current())) {
nbFaces++;
//0021483//if (nbFaces > 6) break;
// get wire
TopoDS_Shape aF = expF.Current();
TopExp_Explorer wires (aF, TopAbs_WIRE);
if (!wires.More()) {
// no wire in the face
hasNonQuadr = Standard_True;
NOQ.Append(aF);//0021483
//0021483//break;
continue;
}
TopoDS_Shape aWire = wires.Current();
wires.Next();
if (wires.More()) {
// multiple wires in the face
hasNonQuadr = Standard_True;
NOQ.Append(aF);//0021483
//0021483//break;
continue;
}
// Check number of edges in the face
Standard_Integer nbEdges = 0;
TopTools_MapOfShape mapEdges;
TopExp_Explorer expW (aWire, TopAbs_EDGE);
for (; expW.More(); expW.Next()) {
if (mapEdges.Add(expW.Current())) {
nbEdges++;
if (nbEdges > 4) break;
}
}
if (nbEdges != 4) {
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);
for (; expF.More(); expF.Next()) {
if (mapFaces.Add(expF.Current())) {
// get wire
TopoDS_Shape aF = expF.Current();
TopExp_Explorer wires (aF, TopAbs_WIRE);
if (!wires.More()) {
// no wire in the face
NOQ.Append(aF);//0021483
continue;
}
TopoDS_Shape aWire = wires.Current();
wires.Next();
if (wires.More()) {
// multiple wires in the face
NOQ.Append(aF);//0021483
continue;
}
// Check number of edges in the face
Standard_Integer nbEdges = 0;
TopTools_MapOfShape mapEdges;
TopExp_Explorer expW (aWire, TopAbs_EDGE);
for (; expW.More(); expW.Next()) {
if (mapEdges.Add(expW.Current())) {
nbEdges++;
if (nbEdges > 4) break;
}
}
if (nbEdges != 4) {
NOQ.Append(aF);//0021483
}
}
}
}
break;
default:
NOT.Append(theShape);
}
}
void AddBlocksFromOld (const TopoDS_Shape& theShape,
TopTools_ListOfShape& BLO,
TopTools_ListOfShape& NOT,
TopTools_ListOfShape& DEG,
TopTools_ListOfShape& SEA)
{
TopAbs_ShapeEnum aType = theShape.ShapeType();
switch (aType) {
case TopAbs_COMPOUND:
case TopAbs_COMPSOLID:
{
TopoDS_Iterator It (theShape);
for (; It.More(); It.Next()) {
AddBlocksFromOld(It.Value(), BLO, NOT, DEG, SEA);
}
}
break;
case TopAbs_SOLID:
{
TopTools_MapOfShape mapFaces;
TopExp_Explorer expF (theShape, TopAbs_FACE);
Standard_Integer nbFaces = 0;
Standard_Boolean hasNonQuadr = Standard_False;
Standard_Boolean hasDegenerated = Standard_False;
Standard_Boolean hasSeam = Standard_False;
for (; expF.More(); expF.Next()) {
if (mapFaces.Add(expF.Current())) {
nbFaces++;
if (nbFaces > 6) break;
// Check number of edges in the face
Standard_Integer nbEdges = 0;
TopTools_MapOfShape mapEdges;
// get wire
TopoDS_Shape aF = expF.Current();
TopExp_Explorer wires (aF, TopAbs_WIRE);
if (!wires.More()) {
// no wire in the face
hasNonQuadr = Standard_True;
break;
}
TopoDS_Shape aWire = wires.Current();
wires.Next();
if (wires.More()) {
// multiple wires in the face
hasNonQuadr = Standard_True;
break;
}
// iterate on wire
BRepTools_WireExplorer aWE (TopoDS::Wire(aWire), TopoDS::Face(aF));
for (; aWE.More(); aWE.Next(), nbEdges++) {
if (BRep_Tool::Degenerated(aWE.Current())) {
// degenerated edge found
hasDegenerated = Standard_True;
// break;
}
if (mapEdges.Contains(aWE.Current())) {
// seam edge found
hasSeam = Standard_True;
// break;
}
mapEdges.Add(aWE.Current());
}
if (nbEdges != 4) {
hasNonQuadr = Standard_True;
}
}
}
if (nbFaces == 6) {
if (hasDegenerated || hasSeam) {
if (hasDegenerated) {
DEG.Append(theShape);
}
if (hasSeam) {
SEA.Append(theShape);
}
} else if (hasNonQuadr) {
NOT.Append(theShape);
} else {
BLO.Append(theShape);
}
} else {
NOT.Append(theShape);
}
}
break;
default:
NOT.Append(theShape);
}
}
#define REL_NOT_CONNECTED 0
#define REL_OK 1
#define REL_NOT_GLUED 2
#define REL_COLLISION_VV 3
#define REL_COLLISION_FF 4
#define REL_COLLISION_EE 5
#define REL_UNKNOWN 6
Standard_Integer BlocksRelation (const TopoDS_Shape& theBlock1,
const TopoDS_Shape& theBlock2)
{
// Compare bounding boxes before calling BRepExtrema_DistShapeShape
Standard_Real Xmin1, Ymin1, Zmin1, Xmax1, Ymax1, Zmax1;
Standard_Real Xmin2, Ymin2, Zmin2, Xmax2, Ymax2, Zmax2;
Bnd_Box B1, B2;
BRepBndLib::Add(theBlock1, B1);
BRepBndLib::Add(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) {
return REL_NOT_CONNECTED;
}
BRepExtrema_DistShapeShape dst (theBlock1, theBlock2);
if (!dst.IsDone()) {
return REL_UNKNOWN;
}
if (dst.Value() > Precision::Confusion()) {
return REL_NOT_CONNECTED;
}
if (dst.InnerSolution()) {
return REL_COLLISION_VV;
}
Standard_Integer nbSol = dst.NbSolution();
Standard_Integer relation = REL_OK;
Standard_Integer nbVerts = 0;
Standard_Integer nbEdges = 0;
Standard_Integer sol = 1;
for (; sol <= nbSol; sol++) {
BRepExtrema_SupportType supp1 = dst.SupportTypeShape1(sol);
BRepExtrema_SupportType supp2 = dst.SupportTypeShape2(sol);
if (supp1 == BRepExtrema_IsVertex && supp2 == BRepExtrema_IsVertex) {
nbVerts++;
} else if (supp1 == BRepExtrema_IsInFace || supp2 == BRepExtrema_IsInFace) {
return REL_COLLISION_FF;
} else if (supp1 == BRepExtrema_IsOnEdge && supp2 == BRepExtrema_IsOnEdge) {
nbEdges++;
} else if ((supp1 == BRepExtrema_IsOnEdge && supp2 == BRepExtrema_IsVertex) ||
(supp2 == BRepExtrema_IsOnEdge && supp1 == BRepExtrema_IsVertex)) {
relation = REL_COLLISION_EE;
} else {
}
}
if (relation != REL_OK) {
return relation;
}
TColStd_Array1OfInteger vertSol (1, nbVerts);
TopTools_Array1OfShape V1 (1, nbVerts);
TopTools_Array1OfShape V2 (1, nbVerts);
Standard_Integer ivs = 0;
for (sol = 1; sol <= nbSol; sol++) {
if (dst.SupportTypeShape1(sol) == BRepExtrema_IsVertex &&
dst.SupportTypeShape2(sol) == BRepExtrema_IsVertex) {
TopoDS_Vertex Vcur = TopoDS::Vertex(dst.SupportOnShape1(sol));
// Check, that this vertex is far enough from other solution vertices.
Standard_Integer ii = 1;
for (; ii <= ivs; ii++) {
if (BRepTools::Compare(TopoDS::Vertex(V1(ii)), Vcur)) {
continue;
}
}
ivs++;
vertSol(ivs) = sol;
V1(ivs) = Vcur;
V2(ivs) = dst.SupportOnShape2(sol);
}
}
// As we deal only with quadrangles,
// 2, 3 or 4 vertex solutions can be found.
if (ivs <= 1) {
if (nbEdges > 0) {
return REL_COLLISION_FF;
}
return REL_NOT_CONNECTED;
}
if (ivs > 4) {
return REL_UNKNOWN;
}
// Check sharing of coincident entities.
if (ivs == 2 || ivs == 3) {
// Map vertices and edges of the blocks
TopTools_IndexedDataMapOfShapeListOfShape MVE1, MVE2;
GEOMImpl_Block6Explorer::MapShapesAndAncestors
(theBlock1, TopAbs_VERTEX, TopAbs_EDGE, MVE1);
GEOMImpl_Block6Explorer::MapShapesAndAncestors
(theBlock2, TopAbs_VERTEX, TopAbs_EDGE, MVE2);
if (ivs == 2) {
// Find common edge
TopoDS_Shape anEdge1, anEdge2;
GEOMImpl_Block6Explorer::FindEdge(anEdge1, V1(1), V1(2), MVE1);
if (anEdge1.IsNull()) return REL_UNKNOWN;
GEOMImpl_Block6Explorer::FindEdge(anEdge2, V2(1), V2(2), MVE2);
if (anEdge2.IsNull()) return REL_UNKNOWN;
if (!anEdge1.IsSame(anEdge2)) return REL_NOT_GLUED;
} else { // ivs == 3
// Find common edges
Standard_Integer e1_v1 = 1;
Standard_Integer e1_v2 = 2;
Standard_Integer e2_v1 = 3;
Standard_Integer e2_v2 = 1;
TopoDS_Shape anEdge11, anEdge12;
GEOMImpl_Block6Explorer::FindEdge(anEdge11, V1(e1_v1), V1(e1_v2), MVE1);
if (anEdge11.IsNull()) {
e1_v2 = 3;
e2_v1 = 2;
GEOMImpl_Block6Explorer::FindEdge(anEdge11, V1(e1_v1), V1(e1_v2), MVE1);
if (anEdge11.IsNull()) return REL_UNKNOWN;
}
GEOMImpl_Block6Explorer::FindEdge(anEdge12, V1(e2_v1), V1(e2_v2), MVE1);
if (anEdge12.IsNull()) {
e2_v2 = 5 - e2_v1;
GEOMImpl_Block6Explorer::FindEdge(anEdge12, V1(e2_v1), V1(e2_v2), MVE1);
if (anEdge12.IsNull()) return REL_UNKNOWN;
}
TopoDS_Shape anEdge21, anEdge22;
GEOMImpl_Block6Explorer::FindEdge(anEdge21, V2(e1_v1), V2(e1_v2), MVE2);
if (anEdge21.IsNull()) return REL_UNKNOWN;
GEOMImpl_Block6Explorer::FindEdge(anEdge22, V2(e2_v1), V2(e2_v2), MVE2);
if (anEdge22.IsNull()) return REL_UNKNOWN;
// Check of edges coincidence (with some precision) have to be done here
// if (!anEdge11.IsEqual(anEdge21)) return REL_UNKNOWN;
// if (!anEdge12.IsEqual(anEdge22)) return REL_UNKNOWN;
// Check of edges sharing
if (!anEdge11.IsSame(anEdge21)) return REL_NOT_GLUED;
if (!anEdge12.IsSame(anEdge22)) return REL_NOT_GLUED;
}
}
if (ivs == 4) {
// Map vertices and faces of the blocks
TopTools_IndexedDataMapOfShapeListOfShape MVF1, MVF2;
GEOMImpl_Block6Explorer::MapShapesAndAncestors
(theBlock1, TopAbs_VERTEX, TopAbs_FACE, MVF1);
GEOMImpl_Block6Explorer::MapShapesAndAncestors
(theBlock2, TopAbs_VERTEX, TopAbs_FACE, MVF2);
TopoDS_Shape aFace1, aFace2;
GEOMImpl_Block6Explorer::FindFace(aFace1, V1(1), V1(2), V1(3), V1(4), MVF1);
if (aFace1.IsNull()) return REL_UNKNOWN;
GEOMImpl_Block6Explorer::FindFace(aFace2, V2(1), V2(2), V2(3), V2(4), MVF2);
if (aFace2.IsNull()) return REL_UNKNOWN;
// Check of faces coincidence (with some precision) have to be done here
// if (!aFace1.IsEqual(aFace2)) return REL_UNKNOWN;
// Check of faces sharing
if (!aFace1.IsSame(aFace2)) return REL_NOT_GLUED;
}
return REL_OK;
}
void FindConnected (const Standard_Integer theBlockIndex,
const TColStd_Array2OfInteger& theRelations,
TColStd_MapOfInteger& theProcessedMap,
TColStd_MapOfInteger& theConnectedMap)
{
theConnectedMap.Add(theBlockIndex);
theProcessedMap.Add(theBlockIndex);
Standard_Integer nbBlocks = theRelations.ColLength();
Standard_Integer col = 1;
for (; col <= nbBlocks; col++) {
if (theRelations(theBlockIndex, col) == REL_OK ||
theRelations(theBlockIndex, col) == REL_NOT_GLUED) {
if (!theProcessedMap.Contains(col)) {
FindConnected(col, theRelations, theProcessedMap, theConnectedMap);
}
}
}
}
Standard_Boolean HasAnyConnection (const Standard_Integer theBlockIndex,
const TColStd_MapOfInteger& theWith,
const TColStd_Array2OfInteger& theRelations,
TColStd_MapOfInteger& theProcessedMap)
{
theProcessedMap.Add(theBlockIndex);
Standard_Integer nbBlocks = theRelations.ColLength();
Standard_Integer col = 1;
for (; col <= nbBlocks; col++) {
if (theRelations(theBlockIndex, col) != REL_NOT_CONNECTED) {
if (!theProcessedMap.Contains(col)) {
if (theWith.Contains(col))
return Standard_True;
if (HasAnyConnection(col, theWith, theRelations, theProcessedMap))
return Standard_True;
}
}
}
return Standard_False;
}
//=============================================================================
/*!
* CheckCompoundOfBlocksOld
*/
//=============================================================================
Standard_Boolean GEOMImpl_IBlocksOperations::CheckCompoundOfBlocksOld
(Handle(GEOM_Object) theCompound,
std::list<BCError>& theErrors)
{
SetErrorCode(KO);
if (theCompound.IsNull()) return Standard_False;
TopoDS_Shape aBlockOrComp = theCompound->GetValue();
Standard_Boolean isCompOfBlocks = Standard_True;
// Map sub-shapes and their indices
TopTools_IndexedMapOfShape anIndices;
TopExp::MapShapes(aBlockOrComp, anIndices);
// 1. Report non-blocks
TopTools_ListOfShape NOT; // Not blocks
TopTools_ListOfShape DEG; // Hexahedral solids, having degenerated edges
TopTools_ListOfShape SEA; // Hexahedral solids, having seam edges
TopTools_ListOfShape BLO; // All blocks from the given compound
AddBlocksFromOld(aBlockOrComp, BLO, NOT, DEG, SEA);
if (NOT.Extent() > 0) {
isCompOfBlocks = Standard_False;
BCError anErr;
anErr.error = NOT_BLOCK;
TopTools_ListIteratorOfListOfShape it (NOT);
for (; it.More(); it.Next()) {
anErr.incriminated.push_back(anIndices.FindIndex(it.Value()));
}
theErrors.push_back(anErr);
}
if (DEG.Extent() > 0 || SEA.Extent() > 0) {
isCompOfBlocks = Standard_False;
BCError anErr;
anErr.error = EXTRA_EDGE;
TopTools_ListIteratorOfListOfShape itDEG (DEG);
for (; itDEG.More(); itDEG.Next()) {
anErr.incriminated.push_back(anIndices.FindIndex(itDEG.Value()));
}
TopTools_ListIteratorOfListOfShape itSEA (SEA);
for (; itSEA.More(); itSEA.Next()) {
anErr.incriminated.push_back(anIndices.FindIndex(itSEA.Value()));
}
theErrors.push_back(anErr);
}
Standard_Integer nbBlocks = BLO.Extent();
if (nbBlocks == 0) {
isCompOfBlocks = Standard_False;
SetErrorCode(OK);
return isCompOfBlocks;
}
if (nbBlocks == 1) {
SetErrorCode(OK);
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)
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 {
}
}
}
}
// 3. Find largest set of connected (good connection or not glued) blocks
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>
BCError anErr;
anErr.error = NOT_CONNECTED;
Standard_Boolean hasIsolated = Standard_False;
for (ibl = 1; ibl <= nbBlocks; ibl++) {
if (!aLargestSet.Contains(ibl)) {
aProcessedMap.Clear();
if (!HasAnyConnection(ibl, aLargestSet, aRelations, aProcessedMap)) {
// report connection absence
hasIsolated = Standard_True;
anErr.incriminated.push_back(anIndices.FindIndex(aBlocks.Value(ibl)));
}
}
}
if (hasIsolated) {
isCompOfBlocks = Standard_False;
theErrors.push_back(anErr);
}
SetErrorCode(OK);
return isCompOfBlocks;
}
//=============================================================================
/*!
* 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,
std::list<BCError>& theErrors)
{
SetErrorCode(KO);
if (theCompound.IsNull()) return Standard_False;
TopoDS_Shape aBlockOrComp = theCompound->GetValue();
Standard_Boolean isCompOfBlocks = Standard_True;
// Map sub-shapes and their indices
TopTools_IndexedMapOfShape anIndices;
TopExp::MapShapes(aBlockOrComp, anIndices);
// 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
TopTools_ListOfShape NOQ; // All non-quadrangular faces
AddBlocksFrom(aBlockOrComp, BLO, NOT, EXT, NOQ);
// Report non-blocks
if (NOT.Extent() > 0) {
isCompOfBlocks = Standard_False;
BCError anErr;
anErr.error = NOT_BLOCK;
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);
}
Standard_Integer nbBlocks = BLO.Extent();
if (nbBlocks == 0) {
isCompOfBlocks = Standard_False;
SetErrorCode(OK);
return isCompOfBlocks;
}
if (nbBlocks == 1) {
SetErrorCode(OK);
return isCompOfBlocks;
}
// Prepare data for 2. and 3.
TColStd_Array2OfInteger aRelations (1, nbBlocks, 1, nbBlocks);
aRelations.Init(REL_NOT_CONNECTED);
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 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;
}
}
}
// 5. Report all blocks, isolated from <aLargestSet>
BCError anErr;
anErr.error = NOT_CONNECTED;
Standard_Boolean hasIsolated = Standard_False;
for (ibl = 1; ibl <= nbBlocks; ibl++) {
if (!aLargestSet.Contains(ibl)) {
aProcessedMap.Clear();
if (!HasAnyConnection(ibl, aLargestSet, aRelations, aProcessedMap)) {
// report connection absence
hasIsolated = Standard_True;
anErr.incriminated.push_back(anIndices.FindIndex(mapBlocks.FindKey(ibl)));
}
}
}
if (hasIsolated) {
isCompOfBlocks = Standard_False;
theErrors.push_back(anErr);
}
SetErrorCode(OK);
return isCompOfBlocks;
}
//=============================================================================
/*!
* GetNonBlocks
*/
//=============================================================================
Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetNonBlocks
(Handle(GEOM_Object) theShape,
Handle(GEOM_Object)& theNonQuads)
{
SetErrorCode(KO);
if (theShape.IsNull()) return NULL;
TopoDS_Shape aShape = theShape->GetValue();
// 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);
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);
}
// 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);
}
//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;
}
//=============================================================================
/*!
* ExplodeCompoundOfBlocks
*/
//=============================================================================
Handle(TColStd_HSequenceOfTransient) GEOMImpl_IBlocksOperations::ExplodeCompoundOfBlocks
(Handle(GEOM_Object) theCompound,
const Standard_Integer theMinNbFaces,
const Standard_Integer theMaxNbFaces)
{
SetErrorCode(KO);
if (theCompound.IsNull()) return NULL;
TopoDS_Shape aBlockOrComp = theCompound->GetValue();
if (aBlockOrComp.IsNull()) return NULL;
Handle(TColStd_HSequenceOfTransient) aBlocks = new TColStd_HSequenceOfTransient;
Handle(GEOM_Object) anObj;
Handle(GEOM_Function) aFunction;
TopTools_MapOfShape mapShape;
TCollection_AsciiString anAsciiList, anEntry;
// Map shapes
TopTools_IndexedMapOfShape anIndices;
TopExp::MapShapes(aBlockOrComp, anIndices);
Handle(TColStd_HArray1OfInteger) anArray;
// Explode
try {
OCC_CATCH_SIGNALS;
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 (theMinNbFaces <= nbFaces && nbFaces <= theMaxNbFaces) {
anArray = new TColStd_HArray1OfInteger(1,1);
anArray->SetValue(1, anIndices.FindIndex(aSolid));
anObj = GetEngine()->AddSubShape(theCompound, anArray);
aBlocks->Append(anObj);
//Make a Python command
TDF_Tool::Entry(anObj->GetEntry(), anEntry);
anAsciiList += anEntry + ", ";
}
}
}
}
catch (Standard_Failure) {
Handle(Standard_Failure) aFail = Standard_Failure::Caught();
SetErrorCode(aFail->GetMessageString());
return aBlocks;
}
if (aBlocks->IsEmpty()) {
SetErrorCode("There are no specified blocks in the given shape");
return aBlocks;
}
anAsciiList.Trunc(anAsciiList.Length() - 2);
//The explode doesn't change object so no new function is required.
aFunction = theCompound->GetLastFunction();
//Make a Python command
GEOM::TPythonDump(aFunction, /*append=*/true)
<< "[" << anAsciiList.ToCString() << "] = geompy.MakeBlockExplode("
<< theCompound << ", " << theMinNbFaces << ", " << theMaxNbFaces << ")";
SetErrorCode(OK);
return aBlocks;
}
//=============================================================================
/*!
* GetBlockNearPoint
*/
//=============================================================================
Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetBlockNearPoint
(Handle(GEOM_Object) theCompound,
Handle(GEOM_Object) thePoint)
{
SetErrorCode(KO);
//New object
Handle(GEOM_Object) aResult;
// Arguments
if (theCompound.IsNull() || thePoint.IsNull()) return NULL;
TopoDS_Shape aBlockOrComp = theCompound->GetValue();
if (aBlockOrComp.IsNull()) {
SetErrorCode("Compound is null");
return NULL;
}
if (aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
SetErrorCode("Shape to find block in is not a compound");
return NULL;
}
TopoDS_Shape anArg = thePoint->GetValue();
if (anArg.IsNull()) {
SetErrorCode("Point is null");
return NULL;
}
if (anArg.ShapeType() != TopAbs_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. 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()) {
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;
}
}
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;
} else if (aDistance == 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 their volume
SetErrorCode("Multiple blocks near the given point are found");
return NULL;
} else if (nearest == 1) {
// The point is outside some blocks and there are
// no blocks, having the point inside or on boundary.
// We will get a nearest block
Standard_Real minDist = RealLast();
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 = aSolid;
}
}
}
} else { // nearest == -1
// // 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;
} 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(theCompound, anArray);
}
}
catch (Standard_Failure) {
Handle(Standard_Failure) aFail = Standard_Failure::Caught();
SetErrorCode(aFail->GetMessageString());
return NULL;
}
Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
//Make a Python command
GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetBlockNearPoint("
<< theCompound << ", " << thePoint << ")";
SetErrorCode(OK);
return aResult;
}
//=============================================================================
/*!
* GetBlockByParts
*/
//=============================================================================
Handle(GEOM_Object) GEOMImpl_IBlocksOperations::GetBlockByParts
(Handle(GEOM_Object) theCompound,
const Handle(TColStd_HSequenceOfTransient)& theParts)
{
SetErrorCode(KO);
Handle(GEOM_Object) aResult;
if (theCompound.IsNull() || theParts.IsNull()) return NULL;
TopoDS_Shape aBlockOrComp = theCompound->GetValue();
if (aBlockOrComp.IsNull()) return NULL;
//Get the parts
Standard_Integer argi, aLen = theParts->Length();
TopTools_Array1OfShape anArgs (1, aLen);
TCollection_AsciiString anEntry, aPartsDescr;
for (argi = 1; argi <= aLen; argi++) {
Handle(GEOM_Object) anObj = Handle(GEOM_Object)::DownCast(theParts->Value(argi));
Handle(GEOM_Function) aRef = anObj->GetLastFunction();
if (aRef.IsNull()) return NULL;
TopoDS_Shape anArg = aRef->GetValue();
if (anArg.IsNull()) {
SetErrorCode("Null shape is given as argument");
return NULL;
}
anArgs(argi) = anArg;
// For Python command
TDF_Tool::Entry(anObj->GetEntry(), anEntry);
if (argi > 1) aPartsDescr += ", ";
aPartsDescr += anEntry;
}
//Compute the Block value
try {
OCC_CATCH_SIGNALS;
// 1. Explode compound on solids
TopTools_MapOfShape mapShape;
Standard_Integer nbSolids = 0;
TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
for (; exp.More(); exp.Next()) {
if (mapShape.Add(exp.Current())) {
nbSolids++;
}
}
mapShape.Clear();
Standard_Integer ind = 1;
TopTools_Array1OfShape aSolids (1, nbSolids);
TColStd_Array1OfInteger aNbParts (1, nbSolids);
for (exp.Init(aBlockOrComp, TopAbs_SOLID); exp.More(); exp.Next(), ind++) {
if (mapShape.Add(exp.Current())) {
TopoDS_Shape aSolid = exp.Current();
aSolids(ind) = aSolid;
aNbParts(ind) = 0;
// 2. Define quantity of parts, contained in each solid
TopTools_IndexedMapOfShape aSubShapes;
TopExp::MapShapes(aSolid, aSubShapes);
for (argi = 1; argi <= aLen; argi++) {
if (aSubShapes.Contains(anArgs(argi))) {
aNbParts(ind)++;
}
}
}
}
// 3. Define solid, containing maximum quantity of parts
Standard_Integer maxNb = 0, nbFound = 0;
TopoDS_Shape aShape;
for (ind = 1; ind <= nbSolids; ind++) {
if (aNbParts(ind) > maxNb) {
maxNb = aNbParts(ind);
aShape = aSolids(ind);
nbFound = 1;
} else if (aNbParts(ind) == maxNb) {
nbFound++;
} else {
}
}
if (nbFound > 1) {
SetErrorCode("Multiple blocks, containing maximum quantity of the given parts, are found");
return NULL;
} else if (nbFound == 0) {
SetErrorCode("There are no blocks, containing the given parts");
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(theCompound, anArray);
}
} catch (Standard_Failure) {
Handle(Standard_Failure) aFail = Standard_Failure::Caught();
SetErrorCode(aFail->GetMessageString());
return NULL;
}
Handle(GEOM_Function) aFunction = aResult->GetLastFunction();
//Make a Python command
GEOM::TPythonDump(aFunction) << aResult << " = geompy.GetBlockByParts("
<< theCompound << ", [" << aPartsDescr.ToCString() << "])";
SetErrorCode(OK);
return aResult;
}
//=============================================================================
/*!
* GetBlocksByParts
*/
//=============================================================================
Handle(TColStd_HSequenceOfTransient) GEOMImpl_IBlocksOperations::GetBlocksByParts
(Handle(GEOM_Object) theCompound,
const Handle(TColStd_HSequenceOfTransient)& theParts)
{
SetErrorCode(KO);
if (theCompound.IsNull() || theParts.IsNull()) return NULL;
TopoDS_Shape aBlockOrComp = theCompound->GetValue();
if (aBlockOrComp.IsNull()) return NULL;
Handle(TColStd_HSequenceOfTransient) aBlocks = new TColStd_HSequenceOfTransient;
Handle(GEOM_Object) anObj;
Handle(GEOM_Function) aFunction;
//Get the parts
Standard_Integer argi, aLen = theParts->Length();
TopTools_Array1OfShape anArgs (1, aLen);
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();
if (aRef.IsNull()) return NULL;
TopoDS_Shape anArg = aRef->GetValue();
if (anArg.IsNull()) {
SetErrorCode("Null shape is given as argument");
return NULL;
}
anArgs(argi) = anArg;
// For Python command
TDF_Tool::Entry(anObj->GetEntry(), anEntry);
aPartsDescr += anEntry + ", ";
}
//Get the Blocks
try {
OCC_CATCH_SIGNALS;
TopTools_MapOfShape mapShape;
Standard_Integer nbSolids = 0;
TopExp_Explorer exp (aBlockOrComp, TopAbs_SOLID);
for (; exp.More(); exp.Next()) {
if (mapShape.Add(exp.Current())) {
nbSolids++;
}
}
mapShape.Clear();
Standard_Integer ind = 1;
TopTools_Array1OfShape aSolids (1, nbSolids);
TColStd_Array1OfInteger aNbParts (1, nbSolids);
for (exp.Init(aBlockOrComp, TopAbs_SOLID); exp.More(); exp.Next(), ind++) {
if (mapShape.Add(exp.Current())) {
TopoDS_Shape aSolid = exp.Current();
aSolids(ind) = aSolid;
aNbParts(ind) = 0;
// 2. Define quantity of parts, contained in each solid
TopTools_IndexedMapOfShape aSubShapes;
TopExp::MapShapes(aSolid, aSubShapes);
for (argi = 1; argi <= aLen; argi++) {
if (aSubShapes.Contains(anArgs(argi))) {
aNbParts(ind)++;
}
}
}
}
// 3. Define solid, containing maximum quantity of parts
Standard_Integer maxNb = 0, nbFound = 0;
for (ind = 1; ind <= nbSolids; ind++) {
if (aNbParts(ind) > maxNb) {
maxNb = aNbParts(ind);
nbFound = 1;
} else if (aNbParts(ind) == maxNb) {
nbFound++;
} else {
}
}
if (nbFound == 0) {
SetErrorCode("There are no blocks, containing the given parts");
return NULL;
}
// Map shapes
TopTools_IndexedMapOfShape anIndices;
TopExp::MapShapes(aBlockOrComp, anIndices);
Handle(TColStd_HArray1OfInteger) anArray;
for (ind = 1; ind <= nbSolids; ind++) {
if (aNbParts(ind) == maxNb) {
anArray = new TColStd_HArray1OfInteger(1,1);
anArray->SetValue(1, anIndices.FindIndex(aSolids(ind)));
anObj = GetEngine()->AddSubShape(theCompound, anArray);
aBlocks->Append(anObj);
// For Python command
TDF_Tool::Entry(anObj->GetEntry(), anEntry);
anAsciiList += anEntry + ", ";
if (aFunction.IsNull())
aFunction = anObj->GetLastFunction();
}
}
}
catch (Standard_Failure) {
Handle(Standard_Failure) aFail = Standard_Failure::Caught();
SetErrorCode(aFail->GetMessageString());
return NULL;
}
//Make a Python command
aPartsDescr.Trunc(aPartsDescr.Length() - 2);
anAsciiList.Trunc(anAsciiList.Length() - 2);
GEOM::TPythonDump(aFunction) << "[" << anAsciiList.ToCString()
<< "] = geompy.GetBlocksByParts(" << theCompound
<< ", [" << aPartsDescr.ToCString() << "])";
SetErrorCode(OK);
return aBlocks;
}
//=============================================================================
/*!
* MakeMultiTransformation1D
*/
//=============================================================================
Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeMultiTransformation1D
(Handle(GEOM_Object) theObject,
const Standard_Integer theDirFace1,
const Standard_Integer theDirFace2,
const Standard_Integer theNbTimes)
{
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 moved
//Add a new Copy object
Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
//Add a translate function
Handle(GEOM_Function) aFunction =
aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_MULTI_TRANSFORM_1D);
//Check if the function is set correctly
if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
GEOMImpl_IBlockTrsf aTI (aFunction);
aTI.SetOriginal(aLastFunction);
aTI.SetFace1U(theDirFace1);
aTI.SetFace2U(theDirFace2);
aTI.SetNbIterU(theNbTimes);
//Compute the transformation
try {
OCC_CATCH_SIGNALS;
if (!GetSolver()->ComputeFunction(aFunction)) {
SetErrorCode("Block driver failed to make multi-transformation");
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.MakeMultiTransformation1D("
<< theObject << ", " << theDirFace1 << ", " << theDirFace2 << ", " << theNbTimes << ")";
SetErrorCode(OK);
return aCopy;
}
//=============================================================================
/*!
* MakeMultiTransformation2D
*/
//=============================================================================
Handle(GEOM_Object) GEOMImpl_IBlocksOperations::MakeMultiTransformation2D
(Handle(GEOM_Object) theObject,
const Standard_Integer theDirFace1U,
const Standard_Integer theDirFace2U,
const Standard_Integer theNbTimesU,
const Standard_Integer theDirFace1V,
const Standard_Integer theDirFace2V,
const Standard_Integer theNbTimesV)
{
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 moved
//Add a new Copy object
Handle(GEOM_Object) aCopy = GetEngine()->AddObject(GetDocID(), GEOM_COPY);
//Add a translate function
Handle(GEOM_Function) aFunction =
aCopy->AddFunction(GEOMImpl_BlockDriver::GetID(), BLOCK_MULTI_TRANSFORM_2D);
//Check if the function is set correctly
if (aFunction->GetDriverGUID() != GEOMImpl_BlockDriver::GetID()) return NULL;
GEOMImpl_IBlockTrsf aTI (aFunction);
aTI.SetOriginal(aLastFunction);
aTI.SetFace1U(theDirFace1U);
aTI.SetFace2U(theDirFace2U);
aTI.SetNbIterU(theNbTimesU);
aTI.SetFace1V(theDirFace1V);
aTI.SetFace2V(theDirFace2V);
aTI.SetNbIterV(theNbTimesV);
//Compute the transformation
try {
OCC_CATCH_SIGNALS;
if (!GetSolver()->ComputeFunction(aFunction)) {
SetErrorCode("Block driver failed to make multi-transformation");
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.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;
}