mirror of
https://git.salome-platform.org/gitpub/modules/geom.git
synced 2025-01-08 15:50:35 +05:00
3501 lines
111 KiB
C++
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;
|
|
}
|