geom/src/GEOMImpl/GEOMImpl_IBlocksOperations.cxx

2695 lines
86 KiB
C++
Raw Normal View History

2004-12-01 15:39:14 +05:00
using namespace std;
#include "GEOMImpl_IBlocksOperations.hxx"
#include "GEOMImpl_Types.hxx"
#include "GEOMImpl_BlockDriver.hxx"
#include "GEOMImpl_IBlocks.hxx"
#include "GEOMImpl_IBlockTrsf.hxx"
#include "GEOMImpl_CopyDriver.hxx"
#include "GEOMImpl_Block6Explorer.hxx"
#include "GEOM_Function.hxx"
#include "utilities.h"
#include "OpUtil.hxx"
#include "Utils_ExceptHandlers.hxx"
#include <TFunction_DriverTable.hxx>
#include <TFunction_Driver.hxx>
#include <TFunction_Logbook.hxx>
#include <TDF_Tool.hxx>
#include <BRep_Tool.hxx>
#include <BRepTools.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_Iterator.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopTools_MapOfShape.hxx>
#include <TopTools_Array1OfShape.hxx>
#include <TopTools_IndexedMapOfShape.hxx>
#include <TopTools_ListIteratorOfListOfShape.hxx>
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
#include <Bnd_Box.hxx>
#include <Precision.hxx>
#include <GProp_GProps.hxx>
#include <TColStd_MapOfInteger.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <TColStd_Array2OfInteger.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 {
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
TCollection_AsciiString anEntry, aDescr;
TDF_Tool::Entry(aFace->GetEntry(), anEntry);
aDescr += anEntry + " = IBlocksOperations.MakeQuad(";
TDF_Tool::Entry(theEdge1->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(theEdge2->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(theEdge3->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(theEdge4->GetEntry(), anEntry);
aDescr += anEntry + ")";
aFunction->SetDescription(aDescr);
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 {
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
TCollection_AsciiString anEntry, aDescr;
TDF_Tool::Entry(aFace->GetEntry(), anEntry);
aDescr += anEntry + " = IBlocksOperations.MakeQuad2Edges(";
TDF_Tool::Entry(theEdge1->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(theEdge2->GetEntry(), anEntry);
aDescr += anEntry + ")";
aFunction->SetDescription(aDescr);
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 {
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
TCollection_AsciiString anEntry, aDescr;
TDF_Tool::Entry(aFace->GetEntry(), anEntry);
aDescr += anEntry + " = IBlocksOperations.MakeQuad4Vertices(";
TDF_Tool::Entry(thePnt1->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(thePnt2->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(thePnt3->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(thePnt4->GetEntry(), anEntry);
aDescr += anEntry + ")";
aFunction->SetDescription(aDescr);
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 {
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
TCollection_AsciiString anEntry, aDescr;
TDF_Tool::Entry(aBlock->GetEntry(), anEntry);
aDescr += anEntry + " = IBlocksOperations.MakeHexa(";
TDF_Tool::Entry(theFace1->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(theFace2->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(theFace3->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(theFace4->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(theFace5->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(theFace6->GetEntry(), anEntry);
aDescr += anEntry + ")";
aFunction->SetDescription(aDescr);
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 {
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
TCollection_AsciiString anEntry, aDescr;
TDF_Tool::Entry(aBlock->GetEntry(), anEntry);
aDescr += anEntry + " = IBlocksOperations.MakeHexa2Faces(";
TDF_Tool::Entry(theFace1->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(theFace2->GetEntry(), anEntry);
aDescr += anEntry + ")";
aFunction->SetDescription(aDescr);
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 {
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
TCollection_AsciiString anEntry, aDescr;
TDF_Tool::Entry(aBlockComp->GetEntry(), anEntry);
aDescr += anEntry + " = IBlocksOperations.MakeBlockCompound(";
TDF_Tool::Entry(theCompound->GetEntry(), anEntry);
aDescr += anEntry + ")";
aFunction->SetDescription(aDescr);
SetErrorCode(OK);
return aBlockComp;
}
//=============================================================================
/*!
* GetEdge
*/
//=============================================================================
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("Block or compound is null");
return NULL;
}
if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
SetErrorCode("Shape is neither a block, nor a compound of blocks");
return NULL;
}
//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
TCollection_AsciiString anEntry, aDescr;
TDF_Tool::Entry(aResult->GetEntry(), anEntry);
aDescr += anEntry + " = IBlocksOperations.GetPoint(";
TDF_Tool::Entry(theShape->GetEntry(), anEntry);
aDescr += anEntry + ", ";
aDescr += TCollection_AsciiString(theX) + ", ";
aDescr += TCollection_AsciiString(theY) + ", ";
aDescr += TCollection_AsciiString(theZ) + ", ";
aDescr += TCollection_AsciiString(theEpsilon) + ")";
TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
aNewDescr += aDescr;
aFunction->SetDescription(aNewDescr);
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("Block or compound is null");
return NULL;
}
if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
SetErrorCode("Shape is neither a block, nor a compound of blocks");
return NULL;
}
TopoDS_Shape anArg1 = thePoint1->GetValue();
TopoDS_Shape anArg2 = thePoint2->GetValue();
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 {
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;
}
//The GetEdge() doesn't change object so no new function is required.
Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
//Make a Python command
TCollection_AsciiString anEntry, aDescr;
TDF_Tool::Entry(aResult->GetEntry(), anEntry);
aDescr += anEntry + " = IBlocksOperations.GetEdge(";
TDF_Tool::Entry(theShape->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(thePoint1->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(thePoint2->GetEntry(), anEntry);
aDescr += anEntry + ")";
TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
aNewDescr += aDescr;
aFunction->SetDescription(aNewDescr);
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("Block or compound is null");
return NULL;
}
if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
SetErrorCode("Shape is neither a block, nor a compound of blocks");
return NULL;
}
TopoDS_Shape anArg = thePoint->GetValue();
if (anArg.IsNull()) {
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 {
TopoDS_Shape aShape;
TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
// 1. Explode blocks on edges
TopTools_MapOfShape mapShape;
Standard_Integer nbEdges = 0;
TopExp_Explorer exp (aBlockOrComp, TopAbs_EDGE);
for (; exp.More(); exp.Next()) {
if (mapShape.Add(exp.Current())) {
nbEdges++;
}
}
mapShape.Clear();
Standard_Integer ind = 1;
TopTools_Array1OfShape anEdges (1, nbEdges);
TColStd_Array1OfReal aDistances (1, nbEdges);
for (exp.Init(aBlockOrComp, TopAbs_EDGE); exp.More(); exp.Next()) {
if (mapShape.Add(exp.Current())) {
TopoDS_Shape anEdge = exp.Current();
anEdges(ind) = anEdge;
// 2. Classify the point relatively each edge
BRepExtrema_DistShapeShape aDistTool (aVert, anEdges(ind));
if (!aDistTool.IsDone()) {
SetErrorCode("Can not find a distance from the given point to one of edges");
return NULL;
}
aDistances(ind) = aDistTool.Value();
ind++;
}
}
// 3. Define edge, having minimum distance to the point
Standard_Real nearest = RealLast(), nbFound = 0;
Standard_Real prec = Precision::Confusion();
for (ind = 1; ind <= nbEdges; ind++) {
if (Abs(aDistances(ind) - nearest) < prec) {
nbFound++;
} else if (aDistances(ind) < nearest) {
nearest = aDistances(ind);
aShape = anEdges(ind);
nbFound = 1;
} else {
}
}
if (nbFound > 1) {
SetErrorCode("Multiple edges near the given point are found");
return NULL;
} else if (nbFound == 0) {
SetErrorCode("There are no edges near the given point");
return NULL;
} else {
TopTools_IndexedMapOfShape anIndices;
TopExp::MapShapes(aBlockOrComp, anIndices);
Handle(TColStd_HArray1OfInteger) anArray = new TColStd_HArray1OfInteger(1,1);
anArray->SetValue(1, anIndices.FindIndex(aShape));
aResult = GetEngine()->AddSubShape(theShape, anArray);
}
}
catch (Standard_Failure) {
Handle(Standard_Failure) aFail = Standard_Failure::Caught();
SetErrorCode(aFail->GetMessageString());
return NULL;
}
//The GetEdgeNearPoint() doesn't change object so no new function is required.
Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
//Make a Python command
TCollection_AsciiString anEntry, aDescr;
TDF_Tool::Entry(aResult->GetEntry(), anEntry);
aDescr += anEntry + " = IBlocksOperations.GetEdgeNearPoint(";
TDF_Tool::Entry(theShape->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(thePoint->GetEntry(), anEntry);
aDescr += anEntry + ")";
TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
aNewDescr += aDescr;
aFunction->SetDescription(aNewDescr);
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;
}
if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
SetErrorCode("Shape is neither a block, nor a compound of blocks");
return NULL;
}
TopoDS_Shape anArg1 = thePoint1->GetValue();
TopoDS_Shape anArg2 = thePoint2->GetValue();
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 {
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;
}
//The GetFaceByPoints() doesn't change object so no new function is required.
Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
//Make a Python command
TCollection_AsciiString anEntry, aDescr;
TDF_Tool::Entry(aResult->GetEntry(), anEntry);
aDescr += anEntry + " = IBlocksOperations.GetFaceByPoints(";
TDF_Tool::Entry(theShape->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(thePoint1->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(thePoint2->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(thePoint3->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(thePoint4->GetEntry(), anEntry);
aDescr += anEntry + ")";
TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
aNewDescr += aDescr;
aFunction->SetDescription(aNewDescr);
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;
}
if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
SetErrorCode("Shape is neither a block, nor a compound of blocks");
return NULL;
}
TopoDS_Shape anArg1 = theEdge1->GetValue();
TopoDS_Shape anArg2 = theEdge2->GetValue();
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 {
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;
}
//The GetFaceByEdges() doesn't change object so no new function is required.
Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
//Make a Python command
TCollection_AsciiString anEntry, aDescr;
TDF_Tool::Entry(aResult->GetEntry(), anEntry);
aDescr += anEntry + " = IBlocksOperations.GetFaceByEdges(";
TDF_Tool::Entry(theShape->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(theEdge1->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(theEdge2->GetEntry(), anEntry);
aDescr += anEntry + ")";
TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
aNewDescr += aDescr;
aFunction->SetDescription(aNewDescr);
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 {
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;
}
//The GetOppositeFace() doesn't change object so no new function is required.
Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
//Make a Python command
TCollection_AsciiString anEntry, aDescr;
TDF_Tool::Entry(aResult->GetEntry(), anEntry);
aDescr += anEntry + " = IBlocksOperations.GetOppositeFace(";
TDF_Tool::Entry(theShape->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(theFace->GetEntry(), anEntry);
aDescr += anEntry + ")";
TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
aNewDescr += aDescr;
aFunction->SetDescription(aNewDescr);
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;
}
if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
SetErrorCode("Shape is neither a block, nor a compound of blocks");
return NULL;
}
TopoDS_Shape anArg = thePoint->GetValue();
if (anArg.IsNull()) {
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 {
TopoDS_Shape aShape;
TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
gp_Pnt aPnt = BRep_Tool::Pnt(aVert);
// 1. Explode blocks on faces
TopTools_MapOfShape mapShape;
Standard_Integer nbFaces = 0;
TopExp_Explorer exp (aBlockOrComp, TopAbs_FACE);
for (; exp.More(); exp.Next()) {
if (mapShape.Add(exp.Current())) {
nbFaces++;
}
}
mapShape.Clear();
Standard_Integer ind = 1;
TopTools_Array1OfShape aFaces (1, nbFaces);
TColStd_Array1OfInteger aDistances (1, nbFaces);
for (exp.Init(aBlockOrComp, TopAbs_FACE); exp.More(); exp.Next()) {
if (mapShape.Add(exp.Current())) {
TopoDS_Shape aFace = exp.Current();
aFaces(ind) = aFace;
// 2. Classify the point relatively each face
BRepClass_FaceClassifier FC (TopoDS::Face(aFace), aPnt, Precision::Confusion());
if (FC.State() == TopAbs_IN) {
aDistances(ind) = -1;
} else if (FC.State() == TopAbs_ON) {
aDistances(ind) = 0;
} else { // OUT
aDistances(ind) = 1;
}
ind++;
}
}
// 3. Define face, containing the point or having minimum distance to it
Standard_Integer nearest = 2, nbFound = 0;
for (ind = 1; ind <= nbFaces; ind++) {
if (aDistances(ind) < nearest) {
nearest = aDistances(ind);
aShape = aFaces(ind);
nbFound = 1;
} else if (aDistances(ind) == nearest) {
nbFound++;
} else {
}
}
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 minDist = RealLast();
for (ind = 1; ind <= nbFaces; ind++) {
if (aDistances(ind) == 1) {
BRepExtrema_DistShapeShape aDistTool (aVert, aFaces(ind));
if (!aDistTool.IsDone()) {
SetErrorCode("Can not find a distance from the given point to one of faces");
return NULL;
}
Standard_Real aDist = aDistTool.Value();
if (aDist < minDist) {
minDist = aDist;
aShape = aFaces(ind);
}
}
}
} else { // nearest == -1
// The point is inside some faces.
// We will get a face with nearest center
Standard_Real minDist = RealLast();
for (ind = 1; ind <= nbFaces; ind++) {
if (aDistances(ind) == -1) {
GProp_GProps aSystem;
BRepGProp::SurfaceProperties(aFaces(ind), aSystem);
gp_Pnt aCenterMass = aSystem.CentreOfMass();
Standard_Real aDist = aCenterMass.Distance(aPnt);
if (aDist < minDist) {
minDist = aDist;
aShape = aFaces(ind);
}
}
}
}
}
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;
}
//The GetFaceNearPoint() doesn't change object so no new function is required.
Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
//Make a Python command
TCollection_AsciiString anEntry, aDescr;
TDF_Tool::Entry(aResult->GetEntry(), anEntry);
aDescr += anEntry + " = IBlocksOperations.GetFaceNearPoint(";
TDF_Tool::Entry(theShape->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(thePoint->GetEntry(), anEntry);
aDescr += anEntry + ")";
TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
aNewDescr += aDescr;
aFunction->SetDescription(aNewDescr);
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;
}
if (aBlockOrComp.ShapeType() != TopAbs_SOLID &&
aBlockOrComp.ShapeType() != TopAbs_COMPOUND &&
aBlockOrComp.ShapeType() != TopAbs_COMPSOLID) {
SetErrorCode("Shape is neither a block, nor a compound of blocks");
return NULL;
}
TopoDS_Shape anArg = theVector->GetValue();
if (anArg.IsNull()) {
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 {
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;
}
//The GetFaceByNormale() doesn't change object so no new function is required.
Handle(GEOM_Function) aFunction = theShape->GetLastFunction();
//Make a Python command
TCollection_AsciiString anEntry, aDescr;
TDF_Tool::Entry(aResult->GetEntry(), anEntry);
aDescr += anEntry + " = IBlocksOperations.GetFaceByNormale(";
TDF_Tool::Entry(theShape->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(theVector->GetEntry(), anEntry);
aDescr += anEntry + ")";
TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
aNewDescr += aDescr;
aFunction->SetDescription(aNewDescr);
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 {
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 AddBlocksFrom (const TopoDS_Shape& theShape,
TopTools_ListOfShape& BLO,
TopTools_ListOfShape& NOT)
{
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);
}
}
break;
case TopAbs_SOLID:
{
TopTools_MapOfShape mapFaces;
TopExp_Explorer expF (theShape, TopAbs_FACE);
Standard_Integer nbFaces = 0;
Standard_Integer nbEdges = 0;
for (; expF.More(); expF.Next()) {
if (mapFaces.Add(expF.Current())) {
nbFaces++;
if (nbFaces > 6) break;
// Check number of edges in the face
TopoDS_Shape aF = expF.Current();
TopExp_Explorer expE (aF, TopAbs_EDGE);
nbEdges = 0;
for (; expE.More(); expE.Next()) {
nbEdges++;
if (nbEdges > 4) break;
}
if (nbEdges != 4) break;
}
}
if (nbFaces == 6 && nbEdges == 4) {
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);
// BRepBndLib::AddClose(theBlock1, B1);
// BRepBndLib::AddClose(theBlock2, B2);
B1.Get(Xmin1, Ymin1, Zmin1, Xmax1, Ymax1, Zmax1);
B2.Get(Xmin2, Ymin2, Zmin2, Xmax2, Ymax2, Zmax2);
if (Xmax2 < Xmin1 || Xmax1 < Xmin2 ||
Ymax2 < Ymin1 || Ymax1 < Ymin2 ||
Zmax2 < Zmin1 || Zmax1 < Zmin2) {
// Standard_Real prec = Precision::Confusion();
// if (prec < Xmin1 - Xmax2 || prec < Xmin2 - Xmax1 ||
// prec < Ymin1 - Ymax2 || prec < Ymin2 - Ymax1 ||
// prec < Zmin1 - Zmax2 || prec < Zmin2 - Zmax1) {
return REL_NOT_CONNECTED;
}
// to be done
BRepExtrema_DistShapeShape dst (theBlock1, theBlock2);
if (!dst.IsDone()) {
return 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;
}
//=============================================================================
/*!
* CheckCompoundOfBlocks
*/
//=============================================================================
Standard_Boolean GEOMImpl_IBlocksOperations::CheckCompoundOfBlocks
(Handle(GEOM_Object) theCompound,
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 BLO; // All blocks from the given compound
AddBlocksFrom(aBlockOrComp, BLO, NOT);
if (NOT.Extent() > 0) {
isCompOfBlocks = Standard_False;
BCError anErr;
anErr.error = NOT_BLOCK;
TopTools_ListIteratorOfListOfShape NOTit (NOT);
for (; NOTit.More(); NOTit.Next()) {
anErr.incriminated.push_back(anIndices.FindIndex(NOTit.Value()));
}
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)) {
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 list<BCError>& theErrors)
{
TCollection_AsciiString aDescr;
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 += "\nNot a Blocks: ";
break;
case INVALID_CONNECTION:
aDescr += "\nInvalid connection between two blocks: ";
break;
case NOT_CONNECTED:
aDescr += "\nBlocks, not connected with main body: ";
break;
case NOT_GLUED:
aDescr += "\nNot glued blocks: ";
break;
default:
break;
}
list<int> sshList = errStruct.incriminated;
list<int>::iterator sshIt = sshList.begin();
int jj = 0;
for (; sshIt != sshList.end(); jj++, sshIt++) {
if (jj > 0)
aDescr += ", ";
aDescr += TCollection_AsciiString(*sshIt);
}
}
return aDescr;
}
//=============================================================================
/*!
* 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 {
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;
anAsciiList += ",";
}
}
}
}
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() - 1);
anAsciiList += "]";
//The explode doesn't change object so no new function is required.
aFunction = theCompound->GetLastFunction();
//Make a Python command
TCollection_AsciiString aDescr (anAsciiList);
aDescr += " = IBlocksOperations.ExplodeCompoundOfBlocks(";
TDF_Tool::Entry(theCompound->GetEntry(), anEntry);
aDescr += anEntry + ", ";
aDescr += TCollection_AsciiString(theMinNbFaces) + ", ";
aDescr += TCollection_AsciiString(theMaxNbFaces) + ")";
TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
aNewDescr += aDescr;
aFunction->SetDescription(aNewDescr);
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 is neither a block, nor a compound of blocks");
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 block identification is not a vertex");
return NULL;
}
//Compute the Block value
try {
TopoDS_Shape aShape;
TopoDS_Vertex aVert = TopoDS::Vertex(anArg);
gp_Pnt aPnt = BRep_Tool::Pnt(aVert);
// 1. Explode compound on blocks
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 aDistances (1, nbSolids);
for (exp.Init(aBlockOrComp, TopAbs_SOLID); exp.More(); exp.Next()) {
if (mapShape.Add(exp.Current())) {
TopoDS_Shape aSolid = exp.Current();
aSolids(ind) = aSolid;
// 2. Classify the point relatively each block
BRepClass3d_SolidClassifier SC (aSolid, aPnt, Precision::Confusion());
if (SC.State() == TopAbs_IN) {
aDistances(ind) = -1;
} else if (SC.State() == TopAbs_ON) {
aDistances(ind) = 0;
} else { // OUT
aDistances(ind) = 1;
}
ind++;
}
}
// 3. Define block, containing the point or having minimum distance to it
Standard_Integer nearest = 2, nbFound = 0;
for (ind = 1; ind <= nbSolids; ind++) {
if (aDistances(ind) < nearest) {
nearest = aDistances(ind);
aShape = aSolids(ind);
nbFound = 1;
} else if (aDistances(ind) == nearest) {
nbFound++;
} else {
}
}
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();
for (ind = 1; ind <= nbSolids; ind++) {
if (aDistances(ind) == 1) {
BRepExtrema_DistShapeShape aDistTool (aVert, aSolids(ind));
if (!aDistTool.IsDone()) {
SetErrorCode("Can not find a distance from the given point to one of blocks");
return NULL;
}
Standard_Real aDist = aDistTool.Value();
if (aDist < minDist) {
minDist = aDist;
aShape = aSolids(ind);
}
}
}
} else { // nearest == -1
// The point is inside some blocks.
// We will get a block with nearest center
Standard_Real minDist = RealLast();
for (ind = 1; ind <= nbSolids; ind++) {
if (aDistances(ind) == -1) {
GProp_GProps aSystem;
BRepGProp::VolumeProperties(aSolids(ind), aSystem);
gp_Pnt aCenterMass = aSystem.CentreOfMass();
Standard_Real aDist = aCenterMass.Distance(aPnt);
if (aDist < minDist) {
minDist = aDist;
aShape = aSolids(ind);
}
}
}
}
}
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;
}
//The GetBlockNearPoint() doesn't change object so no new function is required.
Handle(GEOM_Function) aFunction = theCompound->GetLastFunction();
//Make a Python command
TCollection_AsciiString anEntry, aDescr;
TDF_Tool::Entry(aResult->GetEntry(), anEntry);
aDescr += anEntry + " = IBlocksOperations.GetBlockNearPoint(";
TDF_Tool::Entry(theCompound->GetEntry(), anEntry);
aDescr += anEntry + ", ";
TDF_Tool::Entry(thePoint->GetEntry(), anEntry);
aDescr += anEntry + ")";
TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
aNewDescr += aDescr;
aFunction->SetDescription(aNewDescr);
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 {
// 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;
}
//The GetBlockByParts() doesn't change object so no new function is required.
Handle(GEOM_Function) aFunction = theCompound->GetLastFunction();
//Make a Python command
TDF_Tool::Entry(aResult->GetEntry(), anEntry);
TCollection_AsciiString aDescr (anEntry);
aDescr += " = IBlocksOperations.GetBlockByParts(";
TDF_Tool::Entry(theCompound->GetEntry(), anEntry);
aDescr += anEntry + ", [";
aDescr += aPartsDescr + "])";
TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
aNewDescr += aDescr;
aFunction->SetDescription(aNewDescr);
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);
if (argi > 1) aPartsDescr += ", ";
aPartsDescr += anEntry;
}
//Get the Blocks
try {
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);
//Make a Python command
TDF_Tool::Entry(anObj->GetEntry(), anEntry);
anAsciiList += anEntry;
anAsciiList += ",";
}
}
}
catch (Standard_Failure) {
Handle(Standard_Failure) aFail = Standard_Failure::Caught();
SetErrorCode(aFail->GetMessageString());
return NULL;
}
anAsciiList.Trunc(anAsciiList.Length() - 1);
anAsciiList += "]";
//The GetBlocksByParts() doesn't change object so no new function is required.
aFunction = theCompound->GetLastFunction();
//Make a Python command
TCollection_AsciiString aDescr (anAsciiList);
aDescr += " = IBlocksOperations.GetBlocksByParts(";
TDF_Tool::Entry(theCompound->GetEntry(), anEntry);
aDescr += anEntry + ", [";
aDescr += aPartsDescr + "])";
TCollection_AsciiString aNewDescr = aFunction->GetDescription() + "\n";
aNewDescr += aDescr;
aFunction->SetDescription(aNewDescr);
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 {
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
TCollection_AsciiString anEntry, aDescr;
TDF_Tool::Entry(aCopy->GetEntry(), anEntry);
aDescr += anEntry + " = IBlocksOperations.MakeMultiTransformation1D(";
TDF_Tool::Entry(theObject->GetEntry(), anEntry);
aDescr += anEntry + ", ";
aDescr += TCollection_AsciiString(theDirFace1) + ", ";
aDescr += TCollection_AsciiString(theDirFace2) + ", ";
aDescr += TCollection_AsciiString(theNbTimes) + ") ";
aFunction->SetDescription(aDescr);
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 {
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
TCollection_AsciiString anEntry, aDescr;
TDF_Tool::Entry(aCopy->GetEntry(), anEntry);
aDescr += anEntry + " = IBlocksOperations.MakeMultiTransformation2D(";
TDF_Tool::Entry(theObject->GetEntry(), anEntry);
aDescr += anEntry + ", ";
aDescr += TCollection_AsciiString(theDirFace1U) + ", ";
aDescr += TCollection_AsciiString(theDirFace2U) + ", ";
aDescr += TCollection_AsciiString(theNbTimesU) + ", ";
aDescr += TCollection_AsciiString(theDirFace1V) + ", ";
aDescr += TCollection_AsciiString(theDirFace2V) + ", ";
aDescr += TCollection_AsciiString(theNbTimesV) + ") ";
aFunction->SetDescription(aDescr);
SetErrorCode(OK);
return aCopy;
}