mirror of
https://git.salome-platform.org/gitpub/modules/geom.git
synced 2025-05-25 21:50:48 +05:00
1235 lines
40 KiB
C++
1235 lines
40 KiB
C++
// Copyright (C) 2007-2024 CEA, EDF, 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
|
|
//
|
|
|
|
#include <Standard_Stream.hxx>
|
|
|
|
#include <GEOMUtils.hxx>
|
|
|
|
#include <Utils_ExceptHandlers.hxx>
|
|
|
|
#include <Basics_OCCTVersion.hxx>
|
|
|
|
// OCCT Includes
|
|
#include <BRepMesh_IncrementalMesh.hxx>
|
|
|
|
#include <BRepExtrema_DistShapeShape.hxx>
|
|
|
|
#include <BRep_Builder.hxx>
|
|
#include <BRep_Tool.hxx>
|
|
#include <BRepBndLib.hxx>
|
|
#include <BRepGProp.hxx>
|
|
#include <BRepTools.hxx>
|
|
|
|
#include <BRepClass_FaceClassifier.hxx>
|
|
#include <BRepClass3d_SolidClassifier.hxx>
|
|
|
|
#include <BRepBuilderAPI_MakeFace.hxx>
|
|
#include <BRepBuilderAPI_Sewing.hxx>
|
|
|
|
#include <BRepCheck_Analyzer.hxx>
|
|
|
|
#include <Bnd_Box.hxx>
|
|
|
|
#include <BOPAlgo_ArgumentAnalyzer.hxx>
|
|
#include <BOPTools_AlgoTools.hxx>
|
|
|
|
#include <TopAbs.hxx>
|
|
#include <TopExp.hxx>
|
|
#include <TopoDS.hxx>
|
|
#include <TopoDS_Edge.hxx>
|
|
#include <TopoDS_Face.hxx>
|
|
#include <TopoDS_Shape.hxx>
|
|
#include <TopoDS_Vertex.hxx>
|
|
#include <TopoDS_Compound.hxx>
|
|
#include <TopoDS_Iterator.hxx>
|
|
#include <TopExp_Explorer.hxx>
|
|
#include <TopTools_MapOfShape.hxx>
|
|
#include <TopTools_ListOfShape.hxx>
|
|
#include <TopTools_ListIteratorOfListOfShape.hxx>
|
|
#include <TopTools_Array1OfShape.hxx>
|
|
|
|
#include <GeomAPI_ProjectPointOnSurf.hxx>
|
|
|
|
#include <Geom_Circle.hxx>
|
|
#include <Geom_Surface.hxx>
|
|
#include <Geom_Plane.hxx>
|
|
#include <Geom_SphericalSurface.hxx>
|
|
#include <Geom_ToroidalSurface.hxx>
|
|
#include <Geom_RectangularTrimmedSurface.hxx>
|
|
|
|
#include <GeomLProp_CLProps.hxx>
|
|
#include <GeomLProp_SLProps.hxx>
|
|
|
|
#include <GProp_GProps.hxx>
|
|
#include <GProp_PrincipalProps.hxx>
|
|
|
|
#include <TColStd_Array1OfReal.hxx>
|
|
|
|
#include <gp_Pln.hxx>
|
|
#include <gp_Lin.hxx>
|
|
|
|
#include <ShapeFix_Shape.hxx>
|
|
#include <ShapeFix_ShapeTolerance.hxx>
|
|
|
|
#include <ProjLib.hxx>
|
|
#include <ElSLib.hxx>
|
|
|
|
#include <Prs3d.hxx>
|
|
|
|
#include <vector>
|
|
#include <sstream>
|
|
#include <algorithm>
|
|
|
|
#include <Standard_Failure.hxx>
|
|
#include <Standard_NullObject.hxx>
|
|
#include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic : see Lucien PIGNOLONI / OCC
|
|
|
|
#define MAX2(X, Y) (Abs(X) > Abs(Y) ? Abs(X) : Abs(Y))
|
|
#define MAX3(X, Y, Z) (MAX2(MAX2(X,Y), Z))
|
|
|
|
#define STD_SORT_ALGO 1
|
|
|
|
#define DEFAULT_TOLERANCE_TOLERANCE 1.e-02
|
|
#define DEFAULT_MAX_TOLERANCE_TOLERANCE 1.e-06
|
|
|
|
// When the following macro is defined, ShapeFix_ShapeTolerance function is used to set max tolerance of curve
|
|
// in GEOMUtils::FixShapeCurves function; otherwise less restrictive BRep_Builder::UpdateEdge/UpdateVertex
|
|
// approach is used
|
|
// VSR (29/12/2014): macro disabled
|
|
//#define USE_LIMIT_TOLERANCE
|
|
|
|
namespace
|
|
{
|
|
void parseWard( const GEOMUtils::LevelsList &theLevelList, std::string &treeStr )
|
|
{
|
|
treeStr.append( "{" );
|
|
for( GEOMUtils::LevelsList::const_iterator j = theLevelList.begin();
|
|
j != theLevelList.end(); ++j ) {
|
|
if ( j != theLevelList.begin() ) {
|
|
treeStr.append( ";" );
|
|
}
|
|
GEOMUtils::LevelInfo level = (*j);
|
|
GEOMUtils::LevelInfo::iterator upIter;
|
|
for ( upIter = level.begin(); upIter != level.end(); ++upIter ) {
|
|
if ( upIter != level.begin() ) {
|
|
treeStr.append( "," );
|
|
}
|
|
treeStr.append( upIter->first );
|
|
for ( std::vector<std::string>::iterator k = upIter->second.begin(); k != upIter->second.end(); ++k ) {
|
|
treeStr.append( "_" );
|
|
treeStr.append( *k );
|
|
}
|
|
}
|
|
}
|
|
treeStr.append( "}" );
|
|
}
|
|
|
|
GEOMUtils::LevelsList parseWard( const std::string& theData, std::size_t& theCursor )
|
|
{
|
|
std::size_t indexStart = theData.find( "{", theCursor ) + 1;
|
|
std::size_t indexEnd = theData.find( "}", indexStart );
|
|
|
|
std::string ward = theData.substr( indexStart, indexEnd - indexStart );
|
|
std::stringstream ss(ward);
|
|
std::string substr;
|
|
std::vector<std::string> levelsListStr;
|
|
while ( std::getline( ss, substr, ';' ) ) {
|
|
if ( !substr.empty() )
|
|
levelsListStr.push_back( substr );
|
|
}
|
|
GEOMUtils::LevelsList levelsListData;
|
|
for( size_t level = 0; level < levelsListStr.size(); level++ ) {
|
|
std::vector<std::string> namesListStr;
|
|
std::stringstream ss1( levelsListStr[level] );
|
|
while ( std::getline( ss1, substr, ',' ) ) {
|
|
if ( !substr.empty() )
|
|
namesListStr.push_back( substr );
|
|
}
|
|
GEOMUtils::LevelInfo levelInfoData;
|
|
for( size_t node = 0; node < namesListStr.size(); node++ ) {
|
|
std::vector<std::string> linksListStr;
|
|
std::stringstream ss2( namesListStr[node] );
|
|
while ( std::getline( ss2, substr, '_' ) ) {
|
|
if ( !substr.empty() )
|
|
linksListStr.push_back( substr );
|
|
}
|
|
std::string nodeItem = linksListStr[0];
|
|
if( !nodeItem.empty() ) {
|
|
GEOMUtils::NodeLinks linksListData;
|
|
for( size_t link = 1; link < linksListStr.size(); link++ ) {
|
|
std::string linkItem = linksListStr[link];
|
|
linksListData.push_back( linkItem );
|
|
}// Links
|
|
levelInfoData[nodeItem] = linksListData;
|
|
}
|
|
}// Level's objects
|
|
levelsListData.push_back(levelInfoData);
|
|
}// Levels
|
|
|
|
theCursor = indexEnd + 1;
|
|
return levelsListData;
|
|
}
|
|
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : ShapeToDouble
|
|
//purpose : used by CompareShapes::operator()
|
|
//=======================================================================
|
|
std::pair<double, double> GEOMUtils::ShapeToDouble (const TopoDS_Shape& S, bool isOldSorting)
|
|
{
|
|
// Computing of CentreOfMass
|
|
gp_Pnt GPoint;
|
|
double Len;
|
|
|
|
if (S.ShapeType() == TopAbs_VERTEX) {
|
|
GPoint = BRep_Tool::Pnt(TopoDS::Vertex(S));
|
|
Len = (double)S.Orientation();
|
|
}
|
|
else {
|
|
GProp_GProps GPr;
|
|
// BEGIN: fix for Mantis issue 0020842
|
|
if (isOldSorting) {
|
|
BRepGProp::LinearProperties(S, GPr);
|
|
}
|
|
else {
|
|
if (S.ShapeType() == TopAbs_EDGE || S.ShapeType() == TopAbs_WIRE) {
|
|
BRepGProp::LinearProperties(S, GPr);
|
|
}
|
|
else if (S.ShapeType() == TopAbs_FACE || S.ShapeType() == TopAbs_SHELL) {
|
|
BRepGProp::SurfaceProperties(S, GPr);
|
|
}
|
|
else {
|
|
BRepGProp::VolumeProperties(S, GPr);
|
|
}
|
|
}
|
|
// END: fix for Mantis issue 0020842
|
|
GPoint = GPr.CentreOfMass();
|
|
Len = GPr.Mass();
|
|
}
|
|
|
|
double dMidXYZ = GPoint.X() * 999.0 + GPoint.Y() * 99.0 + GPoint.Z() * 0.9;
|
|
return std::make_pair(dMidXYZ, Len);
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : GetPosition
|
|
//purpose :
|
|
//=======================================================================
|
|
gp_Ax3 GEOMUtils::GetPosition (const TopoDS_Shape& theShape)
|
|
{
|
|
gp_Ax3 aResult;
|
|
|
|
if (theShape.IsNull())
|
|
return aResult;
|
|
|
|
// Axes
|
|
aResult.Transform(theShape.Location().Transformation());
|
|
if (theShape.ShapeType() == TopAbs_FACE) {
|
|
Handle(Geom_Surface) aGS = BRep_Tool::Surface(TopoDS::Face(theShape));
|
|
if (!aGS.IsNull() && aGS->IsKind(STANDARD_TYPE(Geom_Plane))) {
|
|
Handle(Geom_Plane) aGPlane = Handle(Geom_Plane)::DownCast(aGS);
|
|
gp_Pln aPln = aGPlane->Pln();
|
|
aResult = aPln.Position();
|
|
// In case of reverse orinetation of the face invert the plane normal
|
|
// (the face's normal does not mathc the plane's normal in this case)
|
|
if(theShape.Orientation() == TopAbs_REVERSED)
|
|
{
|
|
gp_Dir Vx = aResult.XDirection();
|
|
gp_Dir N = aResult.Direction().Mirrored(Vx);
|
|
gp_Pnt P = aResult.Location();
|
|
aResult = gp_Ax3(P, N, Vx);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Origin
|
|
gp_Pnt aPnt;
|
|
|
|
TopAbs_ShapeEnum aShType = theShape.ShapeType();
|
|
|
|
if (aShType == TopAbs_VERTEX) {
|
|
aPnt = BRep_Tool::Pnt(TopoDS::Vertex(theShape));
|
|
}
|
|
else {
|
|
if (aShType == TopAbs_COMPOUND) {
|
|
aShType = GetTypeOfSimplePart(theShape);
|
|
}
|
|
|
|
GProp_GProps aSystem;
|
|
if (aShType == TopAbs_EDGE || aShType == TopAbs_WIRE)
|
|
BRepGProp::LinearProperties(theShape, aSystem);
|
|
else if (aShType == TopAbs_FACE || aShType == TopAbs_SHELL)
|
|
BRepGProp::SurfaceProperties(theShape, aSystem);
|
|
else
|
|
BRepGProp::VolumeProperties(theShape, aSystem);
|
|
|
|
aPnt = aSystem.CentreOfMass();
|
|
}
|
|
|
|
aResult.SetLocation(aPnt);
|
|
|
|
return aResult;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : GetVector
|
|
//purpose :
|
|
//=======================================================================
|
|
gp_Vec GEOMUtils::GetVector (const TopoDS_Shape& theShape,
|
|
Standard_Boolean doConsiderOrientation)
|
|
{
|
|
if (theShape.IsNull())
|
|
Standard_NullObject::Raise("Null shape is given for a vector");
|
|
|
|
if (theShape.ShapeType() != TopAbs_EDGE)
|
|
Standard_TypeMismatch::Raise("Invalid shape is given, must be a vector or an edge");
|
|
|
|
TopoDS_Edge anE = TopoDS::Edge(theShape);
|
|
|
|
TopoDS_Vertex V1, V2;
|
|
TopExp::Vertices(anE, V1, V2, doConsiderOrientation);
|
|
|
|
if (V1.IsNull() || V2.IsNull())
|
|
Standard_NullObject::Raise("Invalid edge is given, it must have two points");
|
|
|
|
gp_Vec aV (BRep_Tool::Pnt(V1), BRep_Tool::Pnt(V2));
|
|
if (aV.Magnitude() < gp::Resolution()) {
|
|
Standard_ConstructionError::Raise("Vector of zero length is given");
|
|
}
|
|
|
|
return aV;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : CompareShapes::operator()
|
|
//purpose : used by std::sort(), called from SortShapes()
|
|
//=======================================================================
|
|
bool GEOMUtils::CompareShapes::operator() (const TopoDS_Shape& theShape1,
|
|
const TopoDS_Shape& theShape2)
|
|
{
|
|
if (!myMap.IsBound(theShape1)) {
|
|
myMap.Bind(theShape1, ShapeToDouble(theShape1, myIsOldSorting));
|
|
}
|
|
|
|
if (!myMap.IsBound(theShape2)) {
|
|
myMap.Bind(theShape2, ShapeToDouble(theShape2, myIsOldSorting));
|
|
}
|
|
|
|
std::pair<double, double> val1 = myMap.Find(theShape1);
|
|
std::pair<double, double> val2 = myMap.Find(theShape2);
|
|
|
|
double tol = Precision::Confusion();
|
|
bool exchange = Standard_False;
|
|
|
|
double dMidXYZ = val1.first - val2.first;
|
|
if (dMidXYZ >= tol) {
|
|
exchange = Standard_True;
|
|
}
|
|
else if (Abs(dMidXYZ) < tol) {
|
|
double dLength = val1.second - val2.second;
|
|
if (dLength >= tol) {
|
|
exchange = Standard_True;
|
|
}
|
|
else if (Abs(dLength) < tol && theShape1.ShapeType() <= TopAbs_FACE) {
|
|
// PAL17233
|
|
// equal values possible on shapes such as two halves of a sphere and
|
|
// a membrane inside the sphere
|
|
Bnd_Box box1,box2;
|
|
BRepBndLib::Add(theShape1, box1);
|
|
if (!box1.IsVoid()) {
|
|
BRepBndLib::Add(theShape2, box2);
|
|
Standard_Real dSquareExtent = box1.SquareExtent() - box2.SquareExtent();
|
|
if (dSquareExtent >= tol) {
|
|
exchange = Standard_True;
|
|
}
|
|
else if (Abs(dSquareExtent) < tol) {
|
|
Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax, val1, val2;
|
|
box1.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
|
|
val1 = (aXmin+aXmax)*999.0 + (aYmin+aYmax)*99.0 + (aZmin+aZmax)*0.9;
|
|
box2.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
|
|
val2 = (aXmin+aXmax)*999.0 + (aYmin+aYmax)*99.0 + (aZmin+aZmax)*0.9;
|
|
if ((val1 - val2) >= tol) {
|
|
exchange = Standard_True;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//return val1 < val2;
|
|
return !exchange;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : SortShapes
|
|
//purpose :
|
|
//=======================================================================
|
|
void GEOMUtils::SortShapes (TopTools_ListOfShape& SL,
|
|
const Standard_Boolean isOldSorting)
|
|
{
|
|
#ifdef STD_SORT_ALGO
|
|
std::vector<TopoDS_Shape> aShapesVec;
|
|
aShapesVec.reserve(SL.Extent());
|
|
|
|
TopTools_ListIteratorOfListOfShape it (SL);
|
|
for (; it.More(); it.Next()) {
|
|
aShapesVec.push_back(it.Value());
|
|
}
|
|
SL.Clear();
|
|
|
|
CompareShapes shComp (isOldSorting);
|
|
std::stable_sort(aShapesVec.begin(), aShapesVec.end(), shComp);
|
|
//std::sort(aShapesVec.begin(), aShapesVec.end(), shComp);
|
|
|
|
std::vector<TopoDS_Shape>::const_iterator anIter = aShapesVec.begin();
|
|
for (; anIter != aShapesVec.end(); ++anIter) {
|
|
SL.Append(*anIter);
|
|
}
|
|
#else
|
|
// old implementation
|
|
Standard_Integer MaxShapes = SL.Extent();
|
|
TopTools_Array1OfShape aShapes (1,MaxShapes);
|
|
TColStd_Array1OfInteger OrderInd(1,MaxShapes);
|
|
TColStd_Array1OfReal MidXYZ (1,MaxShapes); //X,Y,Z;
|
|
TColStd_Array1OfReal Length (1,MaxShapes); //X,Y,Z;
|
|
|
|
// Computing of CentreOfMass
|
|
Standard_Integer Index;
|
|
GProp_GProps GPr;
|
|
gp_Pnt GPoint;
|
|
TopTools_ListIteratorOfListOfShape it(SL);
|
|
for (Index=1; it.More(); Index++)
|
|
{
|
|
TopoDS_Shape S = it.Value();
|
|
SL.Remove( it ); // == it.Next()
|
|
aShapes(Index) = S;
|
|
OrderInd.SetValue (Index, Index);
|
|
if (S.ShapeType() == TopAbs_VERTEX) {
|
|
GPoint = BRep_Tool::Pnt( TopoDS::Vertex( S ));
|
|
Length.SetValue( Index, (Standard_Real) S.Orientation());
|
|
}
|
|
else {
|
|
// BEGIN: fix for Mantis issue 0020842
|
|
if (isOldSorting) {
|
|
BRepGProp::LinearProperties (S, GPr);
|
|
}
|
|
else {
|
|
if (S.ShapeType() == TopAbs_EDGE || S.ShapeType() == TopAbs_WIRE) {
|
|
BRepGProp::LinearProperties (S, GPr);
|
|
}
|
|
else if (S.ShapeType() == TopAbs_FACE || S.ShapeType() == TopAbs_SHELL) {
|
|
BRepGProp::SurfaceProperties(S, GPr);
|
|
}
|
|
else {
|
|
BRepGProp::VolumeProperties(S, GPr);
|
|
}
|
|
}
|
|
// END: fix for Mantis issue 0020842
|
|
GPoint = GPr.CentreOfMass();
|
|
Length.SetValue(Index, GPr.Mass());
|
|
}
|
|
MidXYZ.SetValue(Index, GPoint.X()*999.0 + GPoint.Y()*99.0 + GPoint.Z()*0.9);
|
|
//cout << Index << " L: " << Length(Index) << "CG: " << MidXYZ(Index) << endl;
|
|
}
|
|
|
|
// Sorting
|
|
Standard_Integer aTemp;
|
|
Standard_Boolean exchange, Sort = Standard_True;
|
|
Standard_Real tol = Precision::Confusion();
|
|
while (Sort)
|
|
{
|
|
Sort = Standard_False;
|
|
for (Index=1; Index < MaxShapes; Index++)
|
|
{
|
|
exchange = Standard_False;
|
|
Standard_Real dMidXYZ = MidXYZ(OrderInd(Index)) - MidXYZ(OrderInd(Index+1));
|
|
Standard_Real dLength = Length(OrderInd(Index)) - Length(OrderInd(Index+1));
|
|
if ( dMidXYZ >= tol ) {
|
|
// cout << "MidXYZ: " << MidXYZ(OrderInd(Index))<< " > " <<MidXYZ(OrderInd(Index+1))
|
|
// << " d: " << dMidXYZ << endl;
|
|
exchange = Standard_True;
|
|
}
|
|
else if ( Abs(dMidXYZ) < tol && dLength >= tol ) {
|
|
// cout << "Length: " << Length(OrderInd(Index))<< " > " <<Length(OrderInd(Index+1))
|
|
// << " d: " << dLength << endl;
|
|
exchange = Standard_True;
|
|
}
|
|
else if ( Abs(dMidXYZ) < tol && Abs(dLength) < tol &&
|
|
aShapes(OrderInd(Index)).ShapeType() <= TopAbs_FACE) {
|
|
// PAL17233
|
|
// equal values possible on shapes such as two halves of a sphere and
|
|
// a membrane inside the sphere
|
|
Bnd_Box box1,box2;
|
|
BRepBndLib::Add( aShapes( OrderInd(Index) ), box1 );
|
|
if ( box1.IsVoid() ) continue;
|
|
BRepBndLib::Add( aShapes( OrderInd(Index+1) ), box2 );
|
|
Standard_Real dSquareExtent = box1.SquareExtent() - box2.SquareExtent();
|
|
if ( dSquareExtent >= tol ) {
|
|
// cout << "SquareExtent: " << box1.SquareExtent()<<" > "<<box2.SquareExtent() << endl;
|
|
exchange = Standard_True;
|
|
}
|
|
else if ( Abs(dSquareExtent) < tol ) {
|
|
Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax, val1, val2;
|
|
box1.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
|
|
val1 = (aXmin+aXmax)*999 + (aYmin+aYmax)*99 + (aZmin+aZmax)*0.9;
|
|
box2.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
|
|
val2 = (aXmin+aXmax)*999 + (aYmin+aYmax)*99 + (aZmin+aZmax)*0.9;
|
|
//exchange = val1 > val2;
|
|
if ((val1 - val2) >= tol) {
|
|
exchange = Standard_True;
|
|
}
|
|
//cout << "box: " << val1<<" > "<<val2 << endl;
|
|
}
|
|
}
|
|
|
|
if (exchange)
|
|
{
|
|
// cout << "exchange " << Index << " & " << Index+1 << endl;
|
|
aTemp = OrderInd(Index);
|
|
OrderInd(Index) = OrderInd(Index+1);
|
|
OrderInd(Index+1) = aTemp;
|
|
Sort = Standard_True;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (Index=1; Index <= MaxShapes; Index++)
|
|
SL.Append( aShapes( OrderInd(Index) ));
|
|
#endif
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : CompsolidToCompound
|
|
//purpose :
|
|
//=======================================================================
|
|
TopoDS_Shape GEOMUtils::CompsolidToCompound (const TopoDS_Shape& theCompsolid)
|
|
{
|
|
if (theCompsolid.ShapeType() != TopAbs_COMPSOLID) {
|
|
return theCompsolid;
|
|
}
|
|
|
|
TopoDS_Compound aCompound;
|
|
BRep_Builder B;
|
|
B.MakeCompound(aCompound);
|
|
|
|
TopTools_MapOfShape mapShape;
|
|
TopoDS_Iterator It (theCompsolid, Standard_True, Standard_True);
|
|
|
|
for (; It.More(); It.Next()) {
|
|
TopoDS_Shape aShape_i = It.Value();
|
|
if (mapShape.Add(aShape_i)) {
|
|
B.Add(aCompound, aShape_i);
|
|
}
|
|
}
|
|
|
|
return aCompound;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : AddSimpleShapes
|
|
//purpose :
|
|
//=======================================================================
|
|
void GEOMUtils::AddSimpleShapes (const TopoDS_Shape& theShape, TopTools_ListOfShape& theList)
|
|
{
|
|
if (theShape.ShapeType() != TopAbs_COMPOUND &&
|
|
theShape.ShapeType() != TopAbs_COMPSOLID) {
|
|
theList.Append(theShape);
|
|
return;
|
|
}
|
|
|
|
TopTools_MapOfShape mapShape;
|
|
TopoDS_Iterator It (theShape, Standard_True, Standard_True);
|
|
|
|
for (; It.More(); It.Next()) {
|
|
TopoDS_Shape aShape_i = It.Value();
|
|
if (mapShape.Add(aShape_i)) {
|
|
if (aShape_i.ShapeType() == TopAbs_COMPOUND ||
|
|
aShape_i.ShapeType() == TopAbs_COMPSOLID) {
|
|
AddSimpleShapes(aShape_i, theList);
|
|
} else {
|
|
theList.Append(aShape_i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : GetTypeOfSimplePart
|
|
//purpose :
|
|
//=======================================================================
|
|
TopAbs_ShapeEnum GEOMUtils::GetTypeOfSimplePart (const TopoDS_Shape& theShape)
|
|
{
|
|
TopAbs_ShapeEnum aType = theShape.ShapeType();
|
|
if (aType == TopAbs_VERTEX) return TopAbs_VERTEX;
|
|
else if (aType == TopAbs_EDGE || aType == TopAbs_WIRE) return TopAbs_EDGE;
|
|
else if (aType == TopAbs_FACE || aType == TopAbs_SHELL) return TopAbs_FACE;
|
|
else if (aType == TopAbs_SOLID || aType == TopAbs_COMPSOLID) return TopAbs_SOLID;
|
|
else if (aType == TopAbs_COMPOUND) {
|
|
// Only the iType of the first shape in the compound is taken into account
|
|
TopoDS_Iterator It (theShape, Standard_False, Standard_False);
|
|
if (It.More()) {
|
|
return GetTypeOfSimplePart(It.Value());
|
|
}
|
|
}
|
|
return TopAbs_SHAPE;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : GetEdgeNearPoint
|
|
//purpose :
|
|
//=======================================================================
|
|
TopoDS_Shape GEOMUtils::GetEdgeNearPoint (const TopoDS_Shape& theShape,
|
|
const TopoDS_Vertex& thePoint)
|
|
{
|
|
TopoDS_Shape aResult;
|
|
|
|
// 1. Explode the shape on edges
|
|
TopTools_MapOfShape mapShape;
|
|
Standard_Integer nbEdges = 0;
|
|
TopExp_Explorer exp (theShape, TopAbs_EDGE);
|
|
for (; exp.More(); exp.Next()) {
|
|
if (mapShape.Add(exp.Current())) {
|
|
nbEdges++;
|
|
}
|
|
}
|
|
|
|
if (nbEdges == 0)
|
|
Standard_NullObject::Raise("Given shape contains no edges");
|
|
|
|
mapShape.Clear();
|
|
Standard_Integer ind = 1;
|
|
TopTools_Array1OfShape anEdges (1, nbEdges);
|
|
TColStd_Array1OfReal aDistances (1, nbEdges);
|
|
for (exp.Init(theShape, 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 (thePoint, anEdges(ind));
|
|
if (!aDistTool.IsDone())
|
|
Standard_ConstructionError::Raise("Cannot find a distance from the given point to one of edges");
|
|
|
|
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);
|
|
aResult = anEdges(ind);
|
|
nbFound = 1;
|
|
}
|
|
else {
|
|
}
|
|
}
|
|
if (nbFound > 1) {
|
|
Standard_ConstructionError::Raise("Multiple edges near the given point are found");
|
|
}
|
|
else if (nbFound == 0) {
|
|
Standard_ConstructionError::Raise("There are no edges near the given point");
|
|
}
|
|
else {
|
|
}
|
|
|
|
return aResult;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : PreciseBoundingBox
|
|
//purpose :
|
|
//=======================================================================
|
|
Standard_Boolean GEOMUtils::PreciseBoundingBox
|
|
(const TopoDS_Shape &theShape, Bnd_Box &theBox)
|
|
{
|
|
if ( theBox.IsVoid() ) BRepBndLib::Add( theShape, theBox );
|
|
if ( theBox.IsVoid() ) return Standard_False;
|
|
|
|
Standard_Real aBound[6];
|
|
theBox.Get(aBound[0], aBound[2], aBound[4], aBound[1], aBound[3], aBound[5]);
|
|
|
|
Standard_Integer i;
|
|
const gp_Pnt aMid(0.5*(aBound[1] + aBound[0]), // XMid
|
|
0.5*(aBound[3] + aBound[2]), // YMid
|
|
0.5*(aBound[5] + aBound[4])); // ZMid
|
|
const gp_XYZ aSize(aBound[1] - aBound[0], // DX
|
|
aBound[3] - aBound[2], // DY
|
|
aBound[5] - aBound[4]); // DZ
|
|
const gp_Pnt aPnt[6] =
|
|
{
|
|
gp_Pnt(aBound[0] - (aBound[1] - aBound[0]), aMid.Y(), aMid.Z()), // XMin
|
|
gp_Pnt(aBound[1] + (aBound[1] - aBound[0]), aMid.Y(), aMid.Z()), // XMax
|
|
gp_Pnt(aMid.X(), aBound[2] - (aBound[3] - aBound[2]), aMid.Z()), // YMin
|
|
gp_Pnt(aMid.X(), aBound[3] + (aBound[3] - aBound[2]), aMid.Z()), // YMax
|
|
gp_Pnt(aMid.X(), aMid.Y(), aBound[4] - (aBound[5] - aBound[4])), // ZMin
|
|
gp_Pnt(aMid.X(), aMid.Y(), aBound[5] + (aBound[5] - aBound[4])) // ZMax
|
|
};
|
|
const gp_Dir aDir[3] = { gp::DX(), gp::DY(), gp::DZ() };
|
|
const Standard_Real aPlnSize[3] =
|
|
{
|
|
0.5*Max(aSize.Y(), aSize.Z()), // XMin, XMax planes
|
|
0.5*Max(aSize.X(), aSize.Z()), // YMin, YMax planes
|
|
0.5*Max(aSize.X(), aSize.Y()) // ZMin, ZMax planes
|
|
};
|
|
gp_Pnt aPMin[2];
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
const Standard_Integer iHalf = i/2;
|
|
const gp_Pln aPln(aPnt[i], aDir[iHalf]);
|
|
BRepBuilderAPI_MakeFace aMkFace(aPln, -aPlnSize[iHalf], aPlnSize[iHalf],
|
|
-aPlnSize[iHalf], aPlnSize[iHalf]);
|
|
|
|
if (!aMkFace.IsDone()) {
|
|
return Standard_False;
|
|
}
|
|
|
|
TopoDS_Shape aFace = aMkFace.Shape();
|
|
|
|
// Get minimal distance between planar face and shape.
|
|
Standard_Real aMinDist =
|
|
GEOMUtils::GetMinDistance(aFace, theShape, aPMin[0], aPMin[1]);
|
|
|
|
if (aMinDist < 0.) {
|
|
return Standard_False;
|
|
}
|
|
|
|
aBound[i] = aPMin[1].Coord(iHalf + 1);
|
|
}
|
|
|
|
// Update Bounding box with the new values.
|
|
theBox.SetVoid();
|
|
theBox.Update(aBound[0], aBound[2], aBound[4], aBound[1], aBound[3], aBound[5]);
|
|
|
|
return Standard_True;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : GetMinDistance
|
|
//purpose :
|
|
//=======================================================================
|
|
Standard_Real GEOMUtils::GetMinDistance
|
|
(const TopoDS_Shape& theShape1,
|
|
const TopoDS_Shape& theShape2,
|
|
gp_Pnt& thePnt1, gp_Pnt& thePnt2)
|
|
{
|
|
Standard_Real aResult = -1.0;
|
|
|
|
BRepExtrema_DistShapeShape dst (theShape1, theShape2);
|
|
if (dst.IsDone()) {
|
|
gp_Pnt P1, P2;
|
|
|
|
for (int i = 1; i <= dst.NbSolution(); i++) {
|
|
P1 = dst.PointOnShape1(i);
|
|
P2 = dst.PointOnShape2(i);
|
|
|
|
Standard_Real Dist = P1.Distance(P2);
|
|
if (aResult < 0 || Dist < aResult ) {
|
|
aResult = Dist;
|
|
thePnt1 = P1;
|
|
thePnt2 = P2;
|
|
}
|
|
}
|
|
}
|
|
|
|
return aResult;
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : ProjectPointOnFace()
|
|
// purpose : Returns the projection (3d point) if found, throws an exception otherwise
|
|
//=======================================================================
|
|
gp_Pnt GEOMUtils::ProjectPointOnFace(const gp_Pnt& thePoint,
|
|
const TopoDS_Shape& theFace,
|
|
double& theU, double& theV,
|
|
const double theTol)
|
|
{
|
|
if (theFace.IsNull() || theFace.ShapeType() != TopAbs_FACE)
|
|
Standard_TypeMismatch::Raise
|
|
("Projection aborted : the target shape is not a face");
|
|
|
|
TopoDS_Face aFace = TopoDS::Face(theFace);
|
|
Handle(Geom_Surface) surface = BRep_Tool::Surface(aFace);
|
|
double U1, U2, V1, V2;
|
|
BRepTools::UVBounds(aFace, U1, U2, V1, V2);
|
|
|
|
// projector
|
|
GeomAPI_ProjectPointOnSurf proj;
|
|
proj.Init(surface, U1, U2, V1, V2);
|
|
proj.Perform(thePoint);
|
|
if (!proj.IsDone())
|
|
StdFail_NotDone::Raise("Projection aborted : the algorithm failed");
|
|
int nbPoints = proj.NbPoints();
|
|
if (nbPoints < 1)
|
|
Standard_ConstructionError::Raise("Projection aborted : No solution found");
|
|
proj.LowerDistanceParameters(theU, theV);
|
|
gp_Pnt2d aProjPnt (theU, theV);
|
|
|
|
// classifier
|
|
Standard_Real tol = Max(theTol, 1.e-4);
|
|
BRepClass_FaceClassifier aClsf (aFace, aProjPnt, tol);
|
|
if (aClsf.State() != TopAbs_IN && aClsf.State() != TopAbs_ON) {
|
|
bool isSol = false;
|
|
double minDist = RealLast();
|
|
for (int i = 1; i <= nbPoints; i++) {
|
|
Standard_Real Ui, Vi;
|
|
proj.Parameters(i, Ui, Vi);
|
|
aProjPnt = gp_Pnt2d(Ui, Vi);
|
|
aClsf.Perform(aFace, aProjPnt, tol);
|
|
if (aClsf.State() == TopAbs_IN || aClsf.State() == TopAbs_ON) {
|
|
isSol = true;
|
|
double dist = proj.Distance(i);
|
|
if (dist < minDist) {
|
|
minDist = dist;
|
|
theU = Ui;
|
|
theV = Vi;
|
|
}
|
|
}
|
|
}
|
|
if (!isSol) {
|
|
Standard_ConstructionError::Raise("Projection aborted : No solution found");
|
|
}
|
|
}
|
|
|
|
gp_Pnt surfPnt = surface->Value(theU, theV);
|
|
return surfPnt;
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : ConvertClickToPoint()
|
|
// purpose : Returns the point clicked in 3D view
|
|
//=======================================================================
|
|
gp_Pnt GEOMUtils::ConvertClickToPoint( int x, int y, Handle(V3d_View) aView )
|
|
{
|
|
// We can't rely on Eye and At points to get EyeDir, because they collapse
|
|
// for views with flat bounding boxes. For example if you create a circle and
|
|
// switch to the top view, then both camera's Eye and At points will fall to zero
|
|
// inside V3d_View::FitMinMax() method. It's by occt design.
|
|
// So, we should use camera direction instead.
|
|
|
|
Standard_Real XAt, YAt, ZAt;
|
|
aView->At(XAt, YAt, ZAt);
|
|
gp_Pnt AtPoint(XAt, YAt, ZAt);
|
|
|
|
gp_Pln PlaneOfTheView = gp_Pln( AtPoint, aView->Camera()->Direction() );
|
|
Standard_Real X, Y, Z;
|
|
aView->Convert( x, y, X, Y, Z );
|
|
gp_Pnt ConvertedPoint( X, Y, Z );
|
|
|
|
gp_Pnt2d ConvertedPointOnPlane = ProjLib::Project( PlaneOfTheView, ConvertedPoint );
|
|
gp_Pnt ResultPoint = ElSLib::Value( ConvertedPointOnPlane.X(), ConvertedPointOnPlane.Y(), PlaneOfTheView );
|
|
return ResultPoint;
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : ConvertTreeToString()
|
|
// purpose : Returns the string representation of dependency tree
|
|
//=======================================================================
|
|
void GEOMUtils::ConvertTreeToString( const TreeModel& tree,
|
|
std::string& dependencyStr )
|
|
{
|
|
TreeModel::const_iterator i;
|
|
for ( i = tree.begin(); i != tree.end(); ++i ) {
|
|
dependencyStr.append( i->first );
|
|
dependencyStr.append( "-" );
|
|
std::vector<LevelInfo> upLevelList = i->second.first;
|
|
dependencyStr.append( "upward" );
|
|
parseWard( upLevelList, dependencyStr );
|
|
std::vector<LevelInfo> downLevelList = i->second.second;
|
|
dependencyStr.append( "downward" );
|
|
parseWard( downLevelList, dependencyStr );
|
|
}
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : ConvertStringToTree()
|
|
// purpose : Returns the dependency tree
|
|
//=======================================================================
|
|
void GEOMUtils::ConvertStringToTree( const std::string& dependencyStr,
|
|
TreeModel& tree )
|
|
{
|
|
std::size_t cursor = 0;
|
|
|
|
while( dependencyStr.find('-',cursor) != std::string::npos ) //find next selected object
|
|
{
|
|
std::size_t objectIndex = dependencyStr.find( '-', cursor );
|
|
std::string objectEntry = dependencyStr.substr( cursor, objectIndex - cursor );
|
|
cursor = objectIndex;
|
|
|
|
//std::size_t upwardIndexBegin = dependencyStr.find("{",cursor) + 1;
|
|
//std::size_t upwardIndexFinish = dependencyStr.find("}",upwardIndexBegin);
|
|
LevelsList upwardList = parseWard( dependencyStr, cursor );
|
|
|
|
LevelsList downwardList = parseWard( dependencyStr, cursor );
|
|
|
|
tree[objectEntry] = std::pair<LevelsList,LevelsList>( upwardList, downwardList );
|
|
}
|
|
}
|
|
|
|
bool GEOMUtils::CheckShape( TopoDS_Shape& shape,
|
|
bool checkGeometry )
|
|
{
|
|
BRepCheck_Analyzer analyzer( shape, checkGeometry );
|
|
return analyzer.IsValid();
|
|
}
|
|
|
|
bool GEOMUtils::CheckBOPArguments(const TopoDS_Shape &theShape)
|
|
{
|
|
BOPAlgo_ArgumentAnalyzer aChecker;
|
|
|
|
aChecker.SetShape1(theShape);
|
|
|
|
// Set default options
|
|
aChecker.ArgumentTypeMode() = Standard_True;
|
|
aChecker.SelfInterMode() = Standard_True;
|
|
aChecker.SmallEdgeMode() = Standard_True;
|
|
aChecker.RebuildFaceMode() = Standard_True;
|
|
aChecker.ContinuityMode() = Standard_True;
|
|
aChecker.CurveOnSurfaceMode() = Standard_True;
|
|
|
|
aChecker.StopOnFirstFaulty() = Standard_True;
|
|
aChecker.Perform();
|
|
|
|
// process result of checking
|
|
const bool isValid = !aChecker.HasFaulty();
|
|
|
|
return isValid;
|
|
}
|
|
|
|
bool GEOMUtils::FixShapeTolerance( TopoDS_Shape& shape,
|
|
TopAbs_ShapeEnum type,
|
|
Standard_Real tolerance,
|
|
bool checkGeometry )
|
|
{
|
|
ShapeFix_ShapeTolerance aSft;
|
|
aSft.LimitTolerance( shape, tolerance, tolerance, type );
|
|
Handle(ShapeFix_Shape) aSfs = new ShapeFix_Shape( shape );
|
|
aSfs->Perform();
|
|
shape = aSfs->Shape();
|
|
return CheckShape( shape, checkGeometry );
|
|
}
|
|
|
|
bool GEOMUtils::FixShapeTolerance( TopoDS_Shape& shape,
|
|
Standard_Real tolerance,
|
|
bool checkGeometry )
|
|
{
|
|
return FixShapeTolerance( shape, TopAbs_SHAPE, tolerance, checkGeometry );
|
|
}
|
|
|
|
bool GEOMUtils::FixShapeTolerance( TopoDS_Shape& shape,
|
|
bool checkGeometry )
|
|
{
|
|
return FixShapeTolerance( shape, Precision::Confusion(), checkGeometry );
|
|
}
|
|
|
|
bool GEOMUtils::FixShapeCurves( TopoDS_Shape& shape )
|
|
{
|
|
Standard_Real aT, aTolE, aD, aDMax;
|
|
TopExp_Explorer aExpF, aExpE;
|
|
NCollection_DataMap<TopoDS_Edge, Standard_Real, TopTools_ShapeMapHasher> aDMETol;
|
|
aExpF.Init(shape, TopAbs_FACE);
|
|
for (; aExpF.More(); aExpF.Next()) {
|
|
const TopoDS_Face& aF = *(TopoDS_Face*)&aExpF.Current();
|
|
aExpE.Init(aF, TopAbs_EDGE);
|
|
for (; aExpE.More(); aExpE.Next()) {
|
|
const TopoDS_Edge& aE = *(TopoDS_Edge*)&aExpE.Current();
|
|
try {
|
|
if (!BOPTools_AlgoTools::ComputeTolerance(aF, aE, aDMax, aT)) {
|
|
continue;
|
|
}
|
|
}
|
|
catch(...) {
|
|
continue;
|
|
}
|
|
aTolE = BRep_Tool::Tolerance(aE);
|
|
if (aDMax < aTolE) continue;
|
|
if (aDMETol.IsBound(aE)) {
|
|
aD = aDMETol.Find(aE);
|
|
if (aDMax > aD) {
|
|
aDMETol.UnBind(aE);
|
|
aDMETol.Bind(aE, aDMax);
|
|
}
|
|
}
|
|
else {
|
|
aDMETol.Bind(aE, aDMax);
|
|
}
|
|
}
|
|
}
|
|
NCollection_DataMap<TopoDS_Edge, Standard_Real, TopTools_ShapeMapHasher>::Iterator aDMETolIt(aDMETol);
|
|
#ifdef USE_LIMIT_TOLERANCE
|
|
ShapeFix_ShapeTolerance sat;
|
|
#else
|
|
BRep_Builder b;
|
|
#endif
|
|
for (; aDMETolIt.More(); aDMETolIt.Next()) {
|
|
#ifdef USE_LIMIT_TOLERANCE
|
|
sat.LimitTolerance(aDMETolIt.Key(), aDMETolIt.Value()*1.001);
|
|
#else
|
|
TopoDS_Iterator itv(aDMETolIt.Key());
|
|
for (; itv.More(); itv.Next())
|
|
b.UpdateVertex(TopoDS::Vertex(itv.Value()), aDMETolIt.Value()*1.001);
|
|
b.UpdateEdge(aDMETolIt.Key(), aDMETolIt.Value()*1.001);
|
|
#endif
|
|
}
|
|
return CheckShape( shape );
|
|
}
|
|
|
|
bool GEOMUtils::Write( const TopoDS_Shape& shape, const char* fileName )
|
|
{
|
|
return BRepTools::Write( shape, fileName );
|
|
}
|
|
|
|
TopoDS_Shape GEOMUtils::ReduceCompound( const TopoDS_Shape& shape )
|
|
{
|
|
TopoDS_Shape result = shape;
|
|
|
|
if ( shape.ShapeType() == TopAbs_COMPOUND ||
|
|
shape.ShapeType() == TopAbs_COMPSOLID ) {
|
|
|
|
TopTools_ListOfShape l;
|
|
|
|
TopoDS_Iterator it ( shape );
|
|
for ( ; it.More(); it.Next() )
|
|
l.Append( it.Value() );
|
|
if ( l.Extent() == 1 && l.First() != shape )
|
|
result = ReduceCompound( l.First() );
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : DefaultDeflection
|
|
//purpose :
|
|
//=======================================================================
|
|
double GEOMUtils::DefaultDeflection()
|
|
{
|
|
return 0.001;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : CanBeMeshed
|
|
//purpose :
|
|
//=======================================================================
|
|
static bool GEOMUtils_CanBeMeshed (const TopoDS_Shape& theShape,
|
|
const bool theCheckMesh,
|
|
bool& theHasMesh)
|
|
{
|
|
// Is shape triangulated?
|
|
theHasMesh = true;
|
|
|
|
TopExp_Explorer ex (theShape, TopAbs_FACE);
|
|
TopLoc_Location aLoc;
|
|
if (ex.More()) {
|
|
if (theCheckMesh) {
|
|
for ( ; ex.More() && theHasMesh; ex.Next() ) {
|
|
const TopoDS_Face& aFace = TopoDS::Face( ex.Current() );
|
|
Handle(Poly_Triangulation) aPoly = BRep_Tool::Triangulation( aFace, aLoc );
|
|
theHasMesh = !aPoly.IsNull();
|
|
}
|
|
}
|
|
}
|
|
else { // no faces, try edges
|
|
ex.Init(theShape, TopAbs_EDGE);
|
|
if (!ex.More()) {
|
|
return false; // nothing to mesh
|
|
}
|
|
if (theCheckMesh) {
|
|
for ( ; ex.More() && theHasMesh; ex.Next() ) {
|
|
Handle(Poly_Polygon3D) aPE = BRep_Tool::Polygon3D(TopoDS::Edge(ex.Current()), aLoc);
|
|
theHasMesh = !aPE.IsNull();
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : MeshShape
|
|
//purpose :
|
|
//=======================================================================
|
|
bool GEOMUtils::MeshShape( const TopoDS_Shape theShape,
|
|
const double theDeflection,
|
|
const bool theForced,
|
|
const double theAngleDeflection,
|
|
const bool isRelative,
|
|
const bool doPostCheck)
|
|
{
|
|
Standard_Real aDeflection = (theDeflection <= 0) ? DefaultDeflection() : theDeflection;
|
|
|
|
// Is shape triangulated?
|
|
bool alreadyMeshed = true;
|
|
if (!GEOMUtils_CanBeMeshed (theShape, /*theCheckMesh*/true, alreadyMeshed))
|
|
return false;
|
|
|
|
if (alreadyMeshed && !theForced)
|
|
return true;
|
|
|
|
if (isRelative) {
|
|
// Compute bounding box
|
|
Bnd_Box B;
|
|
BRepBndLib::Add(theShape, B);
|
|
if (B.IsVoid())
|
|
return false; // NPAL15983 (Bug when displaying empty groups)
|
|
|
|
Standard_Real aDeviationCoeff = aDeflection;
|
|
Standard_Real aMaxChordialDeviation = aDeflection;
|
|
aDeflection = Prs3d::GetDeflection(B, aDeviationCoeff, aMaxChordialDeviation);
|
|
}
|
|
|
|
// Clean triangulation before compute incremental mesh
|
|
BRepTools::Clean(theShape);
|
|
|
|
// Compute triangulation
|
|
BRepMesh_IncrementalMesh mesh (theShape, aDeflection, Standard_False, theAngleDeflection);
|
|
|
|
if (!doPostCheck)
|
|
return true;
|
|
|
|
if (!mesh.IsDone())
|
|
return false;
|
|
|
|
GEOMUtils_CanBeMeshed(theShape, /*theCheckMesh*/true, alreadyMeshed);
|
|
return alreadyMeshed;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : CheckTriangulation
|
|
//purpose :
|
|
//=======================================================================
|
|
bool GEOMUtils::CheckTriangulation (const TopoDS_Shape& theShape)
|
|
{
|
|
Standard_Real aHLRAngle = 0.349066;
|
|
return MeshShape(theShape, DefaultDeflection(), false, aHLRAngle);
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : IsOpenPath
|
|
//purpose :
|
|
//=======================================================================
|
|
bool GEOMUtils::IsOpenPath(const TopoDS_Shape &theShape)
|
|
{
|
|
bool isOpen = true;
|
|
|
|
if (theShape.IsNull() == Standard_False) {
|
|
if (theShape.Closed()) {
|
|
// The shape is closed
|
|
isOpen = false;
|
|
} else {
|
|
const TopAbs_ShapeEnum aType = theShape.ShapeType();
|
|
|
|
if (aType == TopAbs_EDGE || aType == TopAbs_WIRE) {
|
|
// Check if path ends are coincident.
|
|
TopoDS_Vertex aV[2];
|
|
|
|
if (aType == TopAbs_EDGE) {
|
|
// Edge
|
|
TopExp::Vertices(TopoDS::Edge(theShape), aV[0], aV[1]);
|
|
} else {
|
|
// Wire
|
|
TopExp::Vertices(TopoDS::Wire(theShape), aV[0], aV[1]);
|
|
}
|
|
|
|
if (aV[0].IsNull() == Standard_False &&
|
|
aV[1].IsNull() == Standard_False) {
|
|
if (aV[0].IsSame(aV[1])) {
|
|
// The shape is closed
|
|
isOpen = false;
|
|
} else {
|
|
const Standard_Real aTol1 = BRep_Tool::Tolerance(aV[0]);
|
|
const Standard_Real aTol2 = BRep_Tool::Tolerance(aV[1]);
|
|
const gp_Pnt aPnt1 = BRep_Tool::Pnt(aV[0]);
|
|
const gp_Pnt aPnt2 = BRep_Tool::Pnt(aV[1]);
|
|
|
|
if (aPnt1.Distance(aPnt2) <= aTol1 + aTol2) {
|
|
// The shape is closed
|
|
isOpen = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return isOpen;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : CompareToleranceValues
|
|
//purpose :
|
|
//=======================================================================
|
|
int GEOMUtils::CompareToleranceValues(const double theTolShape,
|
|
const double theTolRef)
|
|
{
|
|
const double aTolTol = Min(DEFAULT_MAX_TOLERANCE_TOLERANCE,
|
|
theTolRef*DEFAULT_TOLERANCE_TOLERANCE);
|
|
|
|
int aResult = 0;
|
|
|
|
if (theTolShape < theTolRef - aTolTol) {
|
|
aResult = -1;
|
|
} else if (theTolShape > theTolRef + aTolTol) {
|
|
aResult = 1;
|
|
}
|
|
|
|
return aResult;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : IsFitCondition
|
|
//purpose :
|
|
//=======================================================================
|
|
bool GEOMUtils::IsFitCondition(const ComparisonCondition theCondition,
|
|
const double theTolShape,
|
|
const double theTolRef)
|
|
{
|
|
const int aCompValue = CompareToleranceValues(theTolShape, theTolRef);
|
|
bool isFit = false;
|
|
|
|
switch (theCondition) {
|
|
case CC_GT:
|
|
isFit = aCompValue == 1;
|
|
break;
|
|
case GEOMUtils::CC_GE:
|
|
isFit = aCompValue != -1;
|
|
break;
|
|
case GEOMUtils::CC_LT:
|
|
isFit = aCompValue == -1;
|
|
break;
|
|
case GEOMUtils::CC_LE:
|
|
isFit = aCompValue != 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return isFit;
|
|
}
|