Loading files
f2929057eThis file is pinned to the selected release. Download the original to open it in your design tool.
// Created on: 1995-12-08
// Created by: Jacques GOUSSARD
// Copyright (c) 1995-1999 Matra Datavision
// Copyright (c) 1999-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <BRepCheck_Analyzer.hxx>
#include <BRepCheck_Edge.hxx>
#include <BRepCheck_Face.hxx>
#include <BRepCheck_Status.hxx>
#include <NCollection_List.hxx>
#include <NCollection_Shared.hxx>
#include <BRepCheck_Result.hxx>
#include <BRepCheck_Shell.hxx>
#include <BRepCheck_Solid.hxx>
#include <BRepCheck_Vertex.hxx>
#include <BRepCheck_Wire.hxx>
#include <NCollection_Array1.hxx>
#include <OSD_Parallel.hxx>
#include <Standard_ErrorHandler.hxx>
#include <Standard_Failure.hxx>
#include <Standard_NullObject.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Iterator.hxx>
#include <TopoDS_Shape.hxx>
#include <TopTools_ShapeMapHasher.hxx>
#include <NCollection_Map.hxx>
#include <mutex>
//! Functor for multi-threaded execution.
class BRepCheck_ParallelAnalyzer
{
public:
BRepCheck_ParallelAnalyzer(
NCollection_Array1<NCollection_Array1<TopoDS_Shape>>& theArray,
const NCollection_IndexedDataMap<TopoDS_Shape, occ::handle<BRepCheck_Result>>& theMap)
: myArray(theArray),
myMap(theMap)
{
//
}
void operator()(const int theVectorIndex) const
{
TopExp_Explorer exp;
for (int aShapeIter = myArray[theVectorIndex].Lower();
aShapeIter <= myArray[theVectorIndex].Upper();
++aShapeIter)
{
const TopoDS_Shape& aShape = myArray[theVectorIndex][aShapeIter];
const TopAbs_ShapeEnum aType = aShape.ShapeType();
const occ::handle<BRepCheck_Result>& aResult = myMap.FindFromKey(aShape);
switch (aType)
{
case TopAbs_VERTEX: {
// modified by NIZHNY-MKK Wed May 19 16:56:16 2004.BEGIN
// There is no need to check anything.
// if (aShape.IsSame(S)) {
// myMap(S)->Blind();
// }
// modified by NIZHNY-MKK Wed May 19 16:56:23 2004.END
break;
}
case TopAbs_EDGE: {
try
{
occ::handle<BRepCheck_Edge> aResEdge = occ::down_cast<BRepCheck_Edge>(aResult);
const BRepCheck_Status ste =
aResEdge->CheckPolygonOnTriangulation(TopoDS::Edge(aShape));
if (ste != BRepCheck_NoError)
{
aResEdge->SetStatus(ste);
}
}
catch (Standard_Failure const& anException)
{
(void)anException;
if (!aResult.IsNull())
{
aResult->SetFailStatus(aShape);
}
}
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> MapS;
for (exp.Init(aShape, TopAbs_VERTEX); exp.More(); exp.Next())
{
const TopoDS_Shape& aVertex = exp.Current();
occ::handle<BRepCheck_Result> aResOfVertex = myMap.FindFromKey(aVertex);
try
{
OCC_CATCH_SIGNALS
if (MapS.Add(aVertex))
{
aResOfVertex->InContext(aShape);
}
}
catch (Standard_Failure const& anException)
{
(void)anException;
if (!aResult.IsNull())
{
aResult->SetFailStatus(aShape);
}
if (!aResOfVertex.IsNull())
{
aResOfVertex->SetFailStatus(aVertex);
aResOfVertex->SetFailStatus(aShape);
}
}
}
break;
}
case TopAbs_WIRE: {
break;
}
case TopAbs_FACE: {
NCollection_Map<TopoDS_Shape, TopTools_ShapeMapHasher> MapS;
for (exp.Init(aShape, TopAbs_VERTEX); exp.More(); exp.Next())
{
occ::handle<BRepCheck_Result> aFaceVertexRes = myMap.FindFromKey(exp.Current());
try
{
OCC_CATCH_SIGNALS
if (MapS.Add(exp.Current()))
{
aFaceVertexRes->InContext(aShape);
}
}
catch (Standard_Failure const& anException)
{
(void)anException;
if (!aResult.IsNull())
{
aResult->SetFailStatus(aShape);
}
if (!aFaceVertexRes.IsNull())
{
aFaceVertexRes->SetFailStatus(exp.Current());
aFaceVertexRes->SetFailStatus(aShape);
}
}
}
bool performwire = true;
bool isInvalidTolerance = false;
MapS.Clear();
for (exp.Init(aShape, TopAbs_EDGE); exp.More(); exp.Next())
{
const occ::handle<BRepCheck_Result>& aFaceEdgeRes = myMap.FindFromKey(exp.Current());
try
{
OCC_CATCH_SIGNALS
if (MapS.Add(exp.Current()))
{
aFaceEdgeRes->InContext(aShape);
if (performwire)
{
std::unique_lock<std::mutex> aLock(aFaceEdgeRes->myMutex, std::defer_lock);
if (aFaceEdgeRes->IsParallel())
{
aLock.lock();
}
if (aFaceEdgeRes->IsStatusOnShape(aShape))
{
NCollection_List<BRepCheck_Status>::Iterator itl(
aFaceEdgeRes->StatusOnShape(aShape));
for (; itl.More(); itl.Next())
{
const BRepCheck_Status ste = itl.Value();
if (ste == BRepCheck_NoCurveOnSurface
|| ste == BRepCheck_InvalidCurveOnSurface || ste == BRepCheck_InvalidRange
|| ste == BRepCheck_InvalidCurveOnClosedSurface)
{
performwire = false;
break;
}
}
}
}
}
}
catch (Standard_Failure const& anException)
{
(void)anException;
if (!aResult.IsNull())
{
aResult->SetFailStatus(aShape);
}
if (!aFaceEdgeRes.IsNull())
{
aFaceEdgeRes->SetFailStatus(exp.Current());
aFaceEdgeRes->SetFailStatus(aShape);
}
}
}
bool orientofwires = performwire;
for (exp.Init(aShape, TopAbs_WIRE); exp.More(); exp.Next())
{
const occ::handle<BRepCheck_Result>& aFaceWireRes = myMap.FindFromKey(exp.Current());
try
{
OCC_CATCH_SIGNALS
aFaceWireRes->InContext(aShape);
if (orientofwires)
{
std::unique_lock<std::mutex> aLock(aFaceWireRes->myMutex, std::defer_lock);
if (aFaceWireRes->IsParallel())
{
aLock.lock();
}
if (aFaceWireRes->IsStatusOnShape(aShape))
{
const NCollection_List<BRepCheck_Status>& aStatusList =
aFaceWireRes->StatusOnShape(aShape);
NCollection_List<BRepCheck_Status>::Iterator itl(aStatusList);
for (; itl.More(); itl.Next())
{
BRepCheck_Status ste = itl.Value();
if (ste != BRepCheck_NoError)
{
orientofwires = false;
break;
}
}
}
}
}
catch (Standard_Failure const& anException)
{
(void)anException;
if (!aResult.IsNull())
{
aResult->SetFailStatus(aShape);
}
if (!aFaceWireRes.IsNull())
{
aFaceWireRes->SetFailStatus(exp.Current());
aFaceWireRes->SetFailStatus(aShape);
}
}
}
try
{
OCC_CATCH_SIGNALS
const occ::handle<BRepCheck_Face> aFaceRes = occ::down_cast<BRepCheck_Face>(aResult);
if (isInvalidTolerance)
{
aFaceRes->SetStatus(BRepCheck_InvalidToleranceValue);
}
else if (performwire)
{
if (orientofwires)
{
aFaceRes->OrientationOfWires(true); // on enregistre
}
else
{
aFaceRes->SetUnorientable();
}
}
else
{
aFaceRes->SetUnorientable();
}
}
catch (Standard_Failure const& anException)
{
(void)anException;
if (!aResult.IsNull())
{
aResult->SetFailStatus(aShape);
}
for (exp.Init(aShape, TopAbs_WIRE); exp.More(); exp.Next())
{
occ::handle<BRepCheck_Result> aFaceCatchRes = myMap.FindFromKey(exp.Current());
if (!aFaceCatchRes.IsNull())
{
aFaceCatchRes->SetFailStatus(exp.Current());
aFaceCatchRes->SetFailStatus(aShape);
aResult->SetFailStatus(exp.Current());
}
}
}
break;
}
case TopAbs_SHELL: {
break;
}
case TopAbs_SOLID: {
exp.Init(aShape, TopAbs_SHELL);
for (; exp.More(); exp.Next())
{
const TopoDS_Shape& aShell = exp.Current();
occ::handle<BRepCheck_Result> aSolidRes = myMap.FindFromKey(aShell);
try
{
OCC_CATCH_SIGNALS
aSolidRes->InContext(aShape);
}
catch (Standard_Failure const& anException)
{
(void)anException;
if (!aResult.IsNull())
{
aResult->SetFailStatus(aShape);
}
if (!aSolidRes.IsNull())
{
aSolidRes->SetFailStatus(exp.Current());
aSolidRes->SetFailStatus(aShape);
}
}
}
break;
}
default: {
break;
}
}
}
}
private:
BRepCheck_ParallelAnalyzer& operator=(const BRepCheck_ParallelAnalyzer&) = delete;
private:
NCollection_Array1<NCollection_Array1<TopoDS_Shape>>& myArray;
const NCollection_IndexedDataMap<TopoDS_Shape, occ::handle<BRepCheck_Result>>& myMap;
};
//=================================================================================================
void BRepCheck_Analyzer::Init(const TopoDS_Shape& theShape, const bool B)
{
if (theShape.IsNull())
{
throw Standard_NullObject("BRepCheck_Analyzer::Init() - NULL shape");
}
myShape = theShape;
myMap.Clear();
Put(theShape, B);
Perform();
}
//=================================================================================================
void BRepCheck_Analyzer::Put(const TopoDS_Shape& theShape, const bool B)
{
if (myMap.Contains(theShape))
{
return;
}
occ::handle<BRepCheck_Result> HR;
switch (theShape.ShapeType())
{
case TopAbs_VERTEX:
HR = new BRepCheck_Vertex(TopoDS::Vertex(theShape));
break;
case TopAbs_EDGE:
HR = new BRepCheck_Edge(TopoDS::Edge(theShape));
occ::down_cast<BRepCheck_Edge>(HR)->GeometricControls(B);
occ::down_cast<BRepCheck_Edge>(HR)->SetExactMethod(myIsExact);
break;
case TopAbs_WIRE:
HR = new BRepCheck_Wire(TopoDS::Wire(theShape));
occ::down_cast<BRepCheck_Wire>(HR)->GeometricControls(B);
break;
case TopAbs_FACE:
HR = new BRepCheck_Face(TopoDS::Face(theShape));
occ::down_cast<BRepCheck_Face>(HR)->GeometricControls(B);
break;
case TopAbs_SHELL:
HR = new BRepCheck_Shell(TopoDS::Shell(theShape));
break;
case TopAbs_SOLID:
HR = new BRepCheck_Solid(TopoDS::Solid(theShape));
break;
case TopAbs_COMPSOLID:
case TopAbs_COMPOUND:
break;
default:
break;
}
if (!HR.IsNull())
{
HR->SetParallel(myIsParallel);
}
myMap.Add(theShape, HR);
for (TopoDS_Iterator theIterator(theShape); theIterator.More(); theIterator.Next())
{
Put(theIterator.Value(), B); // performs minimum on each shape
}
}
//=================================================================================================
void BRepCheck_Analyzer::Perform()
{
const int aMapSize = myMap.Length();
const int aMinTaskSize = 10;
const occ::handle<OSD_ThreadPool>& aThreadPool = OSD_ThreadPool::DefaultPool();
const int aNbThreads = aThreadPool->NbThreads();
int aNbTasks = aNbThreads * 10;
int aTaskSize = (int)std::ceil((double)aMapSize / aNbTasks);
if (aTaskSize < aMinTaskSize)
{
aTaskSize = aMinTaskSize;
aNbTasks = (int)std::ceil((double)aMapSize / aTaskSize);
}
NCollection_Array1<NCollection_Array1<TopoDS_Shape>> aArrayOfArray(0, aNbTasks - 1);
for (int anI = 1; anI <= aMapSize; ++anI)
{
int aVectIndex = (anI - 1) / aTaskSize;
int aShapeIndex = (anI - 1) % aTaskSize;
if (aShapeIndex == 0)
{
int aVectorSize = aTaskSize;
int aTailSize = aMapSize - aVectIndex * aTaskSize;
if (aTailSize < aTaskSize)
{
aVectorSize = aTailSize;
}
aArrayOfArray[aVectIndex].Resize(0, aVectorSize - 1, false);
}
aArrayOfArray[aVectIndex][aShapeIndex] = myMap.FindKey(anI);
}
BRepCheck_ParallelAnalyzer aParallelAnalyzer(aArrayOfArray, myMap);
OSD_Parallel::For(0, aArrayOfArray.Length(), aParallelAnalyzer, !myIsParallel);
}
//=================================================================================================
bool BRepCheck_Analyzer::IsValid(const TopoDS_Shape& S) const
{
if (!myMap.FindFromKey(S).IsNull())
{
NCollection_List<BRepCheck_Status>::Iterator itl;
itl.Initialize(myMap.FindFromKey(S)->Status());
if (itl.Value() != BRepCheck_NoError)
{ // a voir
return false;
}
}
for (TopoDS_Iterator theIterator(S); theIterator.More(); theIterator.Next())
{
if (!IsValid(theIterator.Value()))
{
return false;
}
}
switch (S.ShapeType())
{
case TopAbs_EDGE: {
return ValidSub(S, TopAbs_VERTEX);
}
// break;
case TopAbs_FACE: {
bool valid = ValidSub(S, TopAbs_WIRE);
valid = valid && ValidSub(S, TopAbs_EDGE);
valid = valid && ValidSub(S, TopAbs_VERTEX);
return valid;
}
// break;
case TopAbs_SHELL:
// return ValidSub(S,TopAbs_FACE);
break;
case TopAbs_SOLID:
// return ValidSub(S,TopAbs_EDGE);
// break;
return ValidSub(S, TopAbs_SHELL);
break;
default:
break;
}
return true;
}
//=================================================================================================
bool BRepCheck_Analyzer::ValidSub(const TopoDS_Shape& S, const TopAbs_ShapeEnum SubType) const
{
NCollection_List<BRepCheck_Status>::Iterator itl;
TopExp_Explorer exp;
for (exp.Init(S, SubType); exp.More(); exp.Next())
{
// for (TopExp_Explorer exp(S,SubType);exp.More(); exp.Next()) {
const occ::handle<BRepCheck_Result>& RV = myMap.FindFromKey(exp.Current());
for (RV->InitContextIterator(); RV->MoreShapeInContext(); RV->NextShapeInContext())
{
if (RV->ContextualShape().IsSame(S))
{
break;
}
}
if (!RV->MoreShapeInContext())
{
break;
}
for (itl.Initialize(RV->StatusOnShape()); itl.More(); itl.Next())
{
if (itl.Value() != BRepCheck_NoError)
{
return false;
}
}
}
return true;
}