mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-06-10 11:34:06 +03:00
Implementation of Fuzzy Boolean operations. Such operations allow to perform Boolean operations on the shapes with near-coincidence between the entities of these shapes, i.e. between shapes in which some entities from one shape are intended to be coincide with some entities from the other, but the coincidence is not precise. API for Boolean operations has been improved to have a possibility to add new options. Modified entities: 1. New option of setting additional tolerance have been added to the following classes: class BOPAlgo_ArgumentAnalyzer class BOPAlgo_BOP class BOPAlgo_Builder class BOPAlgo_MakerVolume class BOPAlgo_PaveFiller class BOPDS_DS class BRepAlgoAPI_BooleanOperation class BRepAlgoAPI_Check class BRepAlgoAPI_Common class BRepAlgoAPI_Cut class BRepAlgoAPI_Fuse class BRepAlgoAPI_Section 2. Following draw commands have been modified to support new functionality: BOP commands: bop b1 b2 [tol] bcommon r b1 b2 [tol] bcut r b1 b2 [tol] bfuse r b1 b2 [tol] bsection r s1 s2 [-n2d/-n2d1/-n2d2] [-na] [tol] mkvolume r b1 b2 ... [-c] [-ni] [-s] [tol] bfillds [-s -t] [tol] Check commands: bopcheck Shape [level of check: 0 - 9] [-t -s] [-tol tol] bopargcheck [-F/O/C/T/S/U] [/R|F|T|V|E|I|P|C|S]] [#BF] [-tol tol] 3. Two new classes have been added to API to provide the root interface for algorithms class BRepAlgoAPI_Algo class BRepAlgoAPI_BuilderAlgo Fix to eliminate the warning. Test-cases for issue #25477
1049 lines
29 KiB
C++
1049 lines
29 KiB
C++
// Created on: 2004-09-02
|
|
// Copyright (c) 2004-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 <BOPAlgo_ArgumentAnalyzer.ixx>
|
|
|
|
#include <Standard_ErrorHandler.hxx>
|
|
#include <Standard_Failure.hxx>
|
|
|
|
#include <TColStd_Array2OfBoolean.hxx>
|
|
|
|
#include <gp_Pnt.hxx>
|
|
|
|
#include <Geom_Surface.hxx>
|
|
|
|
#include <TopoDS_Iterator.hxx>
|
|
#include <TopoDS.hxx>
|
|
#include <TopoDS_Vertex.hxx>
|
|
#include <TopoDS_Edge.hxx>
|
|
#include <TopoDS_Wire.hxx>
|
|
#include <TopoDS_Shell.hxx>
|
|
#include <TopoDS_Solid.hxx>
|
|
|
|
#include <BRep_TVertex.hxx>
|
|
#include <BRep_TEdge.hxx>
|
|
#include <BRep_TFace.hxx>
|
|
#include <BRep_Builder.hxx>
|
|
#include <BRep_Tool.hxx>
|
|
|
|
#include <TopExp.hxx>
|
|
#include <TopExp_Explorer.hxx>
|
|
|
|
#include <BRepExtrema_DistShapeShape.hxx>
|
|
//
|
|
#include <BOPCol_ListOfShape.hxx>
|
|
#include <BOPCol_SequenceOfShape.hxx>
|
|
#include <BOPCol_MapOfShape.hxx>
|
|
|
|
#include <IntTools_Range.hxx>
|
|
#include <IntTools_EdgeEdge.hxx>
|
|
#include <IntTools_CommonPrt.hxx>
|
|
|
|
#include <IntTools_Context.hxx>
|
|
|
|
#include <BOPTools.hxx>
|
|
#include <BOPTools_AlgoTools3D.hxx>
|
|
#include <BOPTools_AlgoTools.hxx>
|
|
|
|
#include <BOPDS_DS.hxx>
|
|
#include <BOPDS_MapOfPassKey.hxx>
|
|
|
|
#include <BOPAlgo_Operation.hxx>
|
|
#include <BOPAlgo_CheckerSI.hxx>
|
|
#include <BOPAlgo_BuilderFace.hxx>
|
|
|
|
// ================================================================================
|
|
// function: Constructor
|
|
// purpose:
|
|
// ================================================================================
|
|
BOPAlgo_ArgumentAnalyzer::BOPAlgo_ArgumentAnalyzer() :
|
|
BOPAlgo_Algo(),
|
|
myStopOnFirst(Standard_False),
|
|
myOperation(BOPAlgo_UNKNOWN),
|
|
myArgumentTypeMode(Standard_False),
|
|
mySelfInterMode(Standard_False),
|
|
mySmallEdgeMode(Standard_False),
|
|
myRebuildFaceMode(Standard_False),
|
|
myTangentMode(Standard_False),
|
|
myMergeVertexMode(Standard_False),
|
|
myMergeEdgeMode(Standard_False),
|
|
myContinuityMode(Standard_False),
|
|
myCurveOnSurfaceMode(Standard_False),
|
|
myEmpty1(Standard_False),
|
|
myEmpty2(Standard_False),
|
|
myFuzzyValue(0.)
|
|
{
|
|
}
|
|
//=======================================================================
|
|
// function: ~
|
|
// purpose:
|
|
//=======================================================================
|
|
BOPAlgo_ArgumentAnalyzer::~BOPAlgo_ArgumentAnalyzer()
|
|
{
|
|
myResult.Clear();
|
|
myToleranceMap.Clear();
|
|
}
|
|
|
|
// ================================================================================
|
|
// function: SetShape1
|
|
// purpose:
|
|
// ================================================================================
|
|
void BOPAlgo_ArgumentAnalyzer::SetShape1(const TopoDS_Shape & TheShape)
|
|
{
|
|
myShape1 = TheShape;
|
|
}
|
|
|
|
// ================================================================================
|
|
// function: SetShape2
|
|
// purpose:
|
|
// ================================================================================
|
|
void BOPAlgo_ArgumentAnalyzer::SetShape2(const TopoDS_Shape & TheShape)
|
|
{
|
|
myShape2 = TheShape;
|
|
}
|
|
|
|
// ================================================================================
|
|
// function: GetShape1
|
|
// purpose:
|
|
// ================================================================================
|
|
const TopoDS_Shape & BOPAlgo_ArgumentAnalyzer::GetShape1() const
|
|
{
|
|
return myShape1;
|
|
}
|
|
|
|
// ================================================================================
|
|
// function: GetShape2
|
|
// purpose:
|
|
// ================================================================================
|
|
const TopoDS_Shape & BOPAlgo_ArgumentAnalyzer::GetShape2() const
|
|
{
|
|
return myShape2;
|
|
}
|
|
|
|
// ================================================================================
|
|
// function: OperationType
|
|
// purpose:
|
|
// ================================================================================
|
|
BOPAlgo_Operation& BOPAlgo_ArgumentAnalyzer::OperationType()
|
|
{
|
|
return myOperation;
|
|
}
|
|
|
|
// ================================================================================
|
|
// function: StopOnFirstFaulty
|
|
// purpose:
|
|
// ================================================================================
|
|
Standard_Boolean & BOPAlgo_ArgumentAnalyzer::StopOnFirstFaulty()
|
|
{
|
|
return myStopOnFirst;
|
|
}
|
|
|
|
// ================================================================================
|
|
// function: Prepare
|
|
// purpose:
|
|
// ================================================================================
|
|
void BOPAlgo_ArgumentAnalyzer::Prepare()
|
|
{
|
|
Standard_Boolean isS1 = myShape1.IsNull(), isS2 = myShape2.IsNull();
|
|
if (!isS1) {
|
|
myEmpty1 = BOPTools_AlgoTools3D::IsEmptyShape(myShape1);
|
|
}
|
|
if (!isS2) {
|
|
myEmpty2 = BOPTools_AlgoTools3D::IsEmptyShape(myShape2);
|
|
}
|
|
}
|
|
// ================================================================================
|
|
// function: Perform
|
|
// purpose:
|
|
// ================================================================================
|
|
void BOPAlgo_ArgumentAnalyzer::Perform()
|
|
{
|
|
try {
|
|
OCC_CATCH_SIGNALS
|
|
myResult.Clear();
|
|
//
|
|
UserBreak();
|
|
//
|
|
// 1. Prepare
|
|
Prepare();
|
|
//
|
|
UserBreak();
|
|
//
|
|
// 2. Update Tolerances according to myFuzzyValue
|
|
UpdateTolerances();
|
|
//
|
|
UserBreak();
|
|
//
|
|
// 3. Test types
|
|
if(myArgumentTypeMode) {
|
|
TestTypes();
|
|
}
|
|
//
|
|
UserBreak();
|
|
//
|
|
// 4. Test self-interference
|
|
if(mySelfInterMode) {
|
|
TestSelfInterferences();
|
|
}
|
|
//
|
|
UserBreak();
|
|
//
|
|
// 5. Test small edges
|
|
if(mySmallEdgeMode) {
|
|
if(!(!myResult.IsEmpty() && myStopOnFirst))
|
|
TestSmallEdge();
|
|
}
|
|
//
|
|
UserBreak();
|
|
//
|
|
// 6. Test possibility to rebuild faces
|
|
if(myRebuildFaceMode) {
|
|
if(!(!myResult.IsEmpty() && myStopOnFirst))
|
|
TestRebuildFace();
|
|
}
|
|
//
|
|
UserBreak();
|
|
//
|
|
// 7. Test tangent
|
|
if(myTangentMode) {
|
|
if(!(!myResult.IsEmpty() && myStopOnFirst))
|
|
TestTangent();
|
|
}
|
|
//
|
|
UserBreak();
|
|
//
|
|
// 8. Test merge vertices
|
|
if(myMergeVertexMode) {
|
|
if(!(!myResult.IsEmpty() && myStopOnFirst))
|
|
TestMergeVertex();
|
|
}
|
|
//
|
|
UserBreak();
|
|
//
|
|
// 9. Test merge edges
|
|
if(myMergeEdgeMode) {
|
|
if(!(!myResult.IsEmpty() && myStopOnFirst))
|
|
TestMergeEdge();
|
|
}
|
|
//
|
|
UserBreak();
|
|
//
|
|
// 10. Test shapes continuity
|
|
if(myContinuityMode) {
|
|
if(!(!myResult.IsEmpty() && myStopOnFirst))
|
|
TestContinuity();
|
|
}
|
|
//
|
|
UserBreak();
|
|
//
|
|
// 11. Test validity of the curves on the surfaces
|
|
if(myCurveOnSurfaceMode) {
|
|
if(!(!myResult.IsEmpty() && myStopOnFirst))
|
|
TestCurveOnSurface();
|
|
}
|
|
}
|
|
catch(Standard_Failure) {
|
|
BOPAlgo_CheckResult aResult;
|
|
aResult.SetCheckStatus(BOPAlgo_CheckUnknown);
|
|
myResult.Append(aResult);
|
|
}
|
|
//
|
|
SetDefaultTolerances();
|
|
}
|
|
|
|
// ================================================================================
|
|
// function: HasFaulty
|
|
// purpose:
|
|
// ================================================================================
|
|
Standard_Boolean BOPAlgo_ArgumentAnalyzer::HasFaulty() const
|
|
{
|
|
return ( !myResult.IsEmpty());
|
|
}
|
|
|
|
// ================================================================================
|
|
// function: GetCheckResult
|
|
// purpose:
|
|
// ================================================================================
|
|
const BOPAlgo_ListOfCheckResult& BOPAlgo_ArgumentAnalyzer::GetCheckResult() const
|
|
{
|
|
return myResult;
|
|
}
|
|
|
|
// ================================================================================
|
|
// function: TestTypes
|
|
// purpose:
|
|
// ================================================================================
|
|
void BOPAlgo_ArgumentAnalyzer::TestTypes()
|
|
{
|
|
Standard_Boolean isS1 = myShape1.IsNull(), isS2 = myShape2.IsNull();
|
|
|
|
if(isS1 && isS2) {
|
|
BOPAlgo_CheckResult aResult;
|
|
aResult.SetCheckStatus(BOPAlgo_BadType);
|
|
myResult.Append(aResult);
|
|
return;
|
|
}
|
|
|
|
//single shape check
|
|
if((isS1 && !isS2) || (!isS1 && isS2)) {
|
|
Standard_Boolean bIsEmpty = (isS1) ? myEmpty2 : myEmpty1;
|
|
|
|
if(bIsEmpty || myOperation!=BOPAlgo_UNKNOWN) {
|
|
const TopoDS_Shape & aS = (isS1) ? myShape2 : myShape1;
|
|
BOPAlgo_CheckResult aResult;
|
|
aResult.SetShape1(aS);
|
|
aResult.SetCheckStatus(BOPAlgo_BadType);
|
|
myResult.Append(aResult);
|
|
return;
|
|
}
|
|
}
|
|
// two shapes check (begin)
|
|
else {
|
|
if(myEmpty1 || myEmpty2) {
|
|
BOPAlgo_CheckResult aResult;
|
|
if(myEmpty1 && myEmpty2) {
|
|
aResult.SetShape1(myShape1);
|
|
aResult.SetShape2(myShape2);
|
|
}
|
|
else {
|
|
const TopoDS_Shape & aS = myEmpty1 ? myShape1 : myShape2;
|
|
if(myEmpty1)
|
|
aResult.SetShape1(aS);
|
|
else
|
|
aResult.SetShape2(aS);
|
|
}
|
|
aResult.SetCheckStatus(BOPAlgo_BadType);
|
|
myResult.Append(aResult);
|
|
return;
|
|
}
|
|
//
|
|
Standard_Integer aDim1, aDim2;
|
|
Standard_Boolean bBadTypes = Standard_False;
|
|
//
|
|
aDim1 = BOPTools_AlgoTools::Dimension(myShape1);
|
|
aDim2 = BOPTools_AlgoTools::Dimension(myShape2);
|
|
if (aDim1 < aDim2) {
|
|
if (myOperation == BOPAlgo_FUSE ||
|
|
myOperation == BOPAlgo_CUT21) {
|
|
bBadTypes = Standard_True;
|
|
}
|
|
}
|
|
else if (aDim1 > aDim2) {
|
|
if (myOperation == BOPAlgo_FUSE ||
|
|
myOperation == BOPAlgo_CUT) {
|
|
bBadTypes = Standard_True;
|
|
}
|
|
}
|
|
if (bBadTypes) {
|
|
BOPAlgo_CheckResult aResult;
|
|
aResult.SetShape1(myShape1);
|
|
aResult.SetShape2(myShape2);
|
|
aResult.SetCheckStatus(BOPAlgo_BadType);
|
|
myResult.Append(aResult);
|
|
}
|
|
}
|
|
}
|
|
//=======================================================================
|
|
//function : TestSelfInterferences
|
|
//purpose :
|
|
//=======================================================================
|
|
void BOPAlgo_ArgumentAnalyzer::TestSelfInterferences()
|
|
{
|
|
Standard_Integer ii;
|
|
//
|
|
for(ii = 0; ii < 2; ii++) {
|
|
const TopoDS_Shape& aS = (ii == 0) ? myShape1 : myShape2;
|
|
if(aS.IsNull()) {
|
|
continue;
|
|
}
|
|
//
|
|
Standard_Boolean bIsEmpty = (ii == 0) ? myEmpty1 : myEmpty2;
|
|
if (bIsEmpty) {
|
|
continue;
|
|
}
|
|
//
|
|
Standard_Integer iErr, n1, n2;
|
|
BOPDS_MapIteratorMapOfPassKey aItMPK;
|
|
BOPCol_ListOfShape anArgs;
|
|
BOPAlgo_CheckerSI aChecker;
|
|
//
|
|
anArgs.Append(aS);
|
|
aChecker.SetArguments(anArgs);
|
|
aChecker.SetNonDestructive(Standard_True);
|
|
aChecker.SetRunParallel(myRunParallel);
|
|
aChecker.SetProgressIndicator(myProgressIndicator);
|
|
//
|
|
aChecker.Perform();
|
|
iErr=aChecker.ErrorStatus();
|
|
//
|
|
const BOPDS_DS& aDS=*(aChecker.PDS());
|
|
const BOPDS_MapOfPassKey& aMPK=aDS.Interferences();
|
|
//
|
|
aItMPK.Initialize(aMPK);
|
|
for (; aItMPK.More(); aItMPK.Next()) {
|
|
const BOPDS_PassKey& aPK=aItMPK.Value();
|
|
aPK.Ids(n1, n2);
|
|
if(aDS.IsNewShape(n1) || aDS.IsNewShape(n2)) {
|
|
continue;
|
|
}
|
|
//
|
|
const TopoDS_Shape& aS1=aDS.Shape(n1);
|
|
const TopoDS_Shape& aS2=aDS.Shape(n2);
|
|
//
|
|
BOPAlgo_CheckResult aResult;
|
|
if(ii == 0) {
|
|
aResult.SetShape1(myShape1);
|
|
aResult.AddFaultyShape1(aS1);
|
|
aResult.AddFaultyShape1(aS2);
|
|
}
|
|
else {
|
|
aResult.SetShape2(myShape2);
|
|
aResult.AddFaultyShape2(aS1);
|
|
aResult.AddFaultyShape2(aS2);
|
|
}
|
|
aResult.SetCheckStatus(BOPAlgo_SelfIntersect);
|
|
myResult.Append(aResult);
|
|
}
|
|
//
|
|
if (iErr) {
|
|
BOPAlgo_CheckResult aResult;
|
|
if(ii == 0) {
|
|
aResult.SetShape1(myShape1);
|
|
aResult.AddFaultyShape1(myShape1);
|
|
}
|
|
else {
|
|
aResult.SetShape2(myShape2);
|
|
aResult.AddFaultyShape2(myShape2);
|
|
}
|
|
aResult.SetCheckStatus(BOPAlgo_OperationAborted);
|
|
myResult.Append(aResult);
|
|
}
|
|
}// for(ii = 0; ii < 2; ii++) {
|
|
}
|
|
// ================================================================================
|
|
// function: TestSmallEdge
|
|
// purpose:
|
|
// ================================================================================
|
|
void BOPAlgo_ArgumentAnalyzer::TestSmallEdge()
|
|
{
|
|
Standard_Integer i = 0;
|
|
BRepExtrema_DistShapeShape aDist;
|
|
Handle(IntTools_Context) aCtx;
|
|
//
|
|
aCtx = new IntTools_Context;
|
|
|
|
for(i = 0; i < 2; i++) {
|
|
const TopoDS_Shape& aS = (i == 0) ? myShape1 : myShape2;
|
|
|
|
if(aS.IsNull())
|
|
continue;
|
|
|
|
TopExp_Explorer anExp(aS, TopAbs_EDGE);
|
|
|
|
for(; anExp.More(); anExp.Next()) {
|
|
const TopoDS_Edge& anEdge = *(TopoDS_Edge*)&anExp.Current();
|
|
if (BRep_Tool::Degenerated(anEdge)) {
|
|
continue;
|
|
}
|
|
|
|
if(BOPTools_AlgoTools::IsMicroEdge(anEdge, aCtx)) {
|
|
Standard_Boolean bKeepResult = Standard_True;
|
|
|
|
if(myOperation == BOPAlgo_SECTION) {
|
|
const TopoDS_Shape& anOtherS = (i == 0) ? myShape2 : myShape1;
|
|
|
|
if(!anOtherS.IsNull()) {
|
|
aDist.LoadS2(anOtherS);
|
|
|
|
Standard_Boolean bVertexIsOnShape = Standard_False;
|
|
Standard_Integer ii = 0;
|
|
TopExp_Explorer anExpV(anEdge, TopAbs_VERTEX);
|
|
|
|
for(; anExpV.More(); anExpV.Next()) {
|
|
const TopoDS_Shape& aV = anExpV.Current();
|
|
|
|
aDist.LoadS1(aV);
|
|
aDist.Perform();
|
|
|
|
if(aDist.IsDone()) {
|
|
|
|
for(ii = 1; ii <= aDist.NbSolution(); ii++) {
|
|
Standard_Real aTolerance = BRep_Tool::Tolerance(*(TopoDS_Vertex*)&aV);
|
|
const TopoDS_Shape& aSupportShape = aDist.SupportOnShape2(ii);
|
|
|
|
switch(aSupportShape.ShapeType()) {
|
|
case TopAbs_VERTEX: {
|
|
aTolerance += BRep_Tool::Tolerance(*(TopoDS_Vertex*)&(aSupportShape));
|
|
break;
|
|
}
|
|
case TopAbs_EDGE: {
|
|
aTolerance += BRep_Tool::Tolerance(*(TopoDS_Edge*)&(aSupportShape));
|
|
break;
|
|
}
|
|
case TopAbs_FACE: {
|
|
aTolerance += BRep_Tool::Tolerance(*(TopoDS_Face*)&(aSupportShape));
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if(aDist.Value() < aTolerance) {
|
|
bVertexIsOnShape = Standard_True;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!bVertexIsOnShape) {
|
|
bKeepResult = Standard_False;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(bKeepResult) {
|
|
BOPAlgo_CheckResult aResult;
|
|
|
|
if(i == 0) {
|
|
aResult.SetShape1(myShape1);
|
|
aResult.AddFaultyShape1(anEdge);
|
|
}
|
|
else {
|
|
aResult.SetShape2(myShape2);
|
|
aResult.AddFaultyShape2(anEdge);
|
|
}
|
|
|
|
aResult.SetCheckStatus(BOPAlgo_TooSmallEdge);
|
|
myResult.Append(aResult);
|
|
|
|
if(myStopOnFirst) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// ================================================================================
|
|
// function: TestRebuildFace
|
|
// purpose:
|
|
// ================================================================================
|
|
void BOPAlgo_ArgumentAnalyzer::TestRebuildFace()
|
|
{
|
|
if((myOperation == BOPAlgo_SECTION) ||
|
|
(myOperation == BOPAlgo_UNKNOWN))
|
|
return;
|
|
Standard_Integer i = 0;
|
|
|
|
for(i = 0; i < 2; i++) {
|
|
const TopoDS_Shape& aS = (i == 0) ? myShape1 : myShape2;
|
|
|
|
if(aS.IsNull())
|
|
continue;
|
|
|
|
TopExp_Explorer anExp(aS, TopAbs_FACE);
|
|
BOPCol_ListOfShape aLS;
|
|
|
|
for(; anExp.More(); anExp.Next()) {
|
|
const TopoDS_Face& aFace = *(TopoDS_Face*)&(anExp.Current());
|
|
|
|
TopoDS_Face aFF = aFace;
|
|
aFF.Orientation(TopAbs_FORWARD);
|
|
TopExp_Explorer anExpE(aFF, TopAbs_EDGE);
|
|
Standard_Integer nbstartedges = 0;
|
|
aLS.Clear();
|
|
//
|
|
for(; anExpE.More(); anExpE.Next()) {
|
|
const TopoDS_Edge& aE=(*(TopoDS_Edge*)(&anExpE.Current()));
|
|
TopAbs_Orientation anOriE=aE.Orientation();
|
|
//
|
|
if (anOriE==TopAbs_INTERNAL) {
|
|
TopoDS_Edge aEE=aE;
|
|
aEE.Orientation(TopAbs_FORWARD);
|
|
aLS.Append(aEE);
|
|
aEE.Orientation(TopAbs_REVERSED);
|
|
aLS.Append(aEE);
|
|
}
|
|
else {
|
|
aLS.Append(aE);
|
|
}
|
|
nbstartedges++;
|
|
}
|
|
BOPAlgo_BuilderFace aBF;
|
|
aBF.SetFace(aFace);
|
|
aBF.SetShapes(aLS);
|
|
aBF.Perform();
|
|
const BOPCol_ListOfShape& aLF = aBF.Areas();
|
|
Standard_Boolean bBadFace = Standard_False;
|
|
|
|
if(aLF.Extent() != 1) {
|
|
bBadFace = Standard_True;
|
|
}
|
|
else {
|
|
Standard_Integer nbedgeused = 0;
|
|
anExpE.Init(aLF.First(), TopAbs_EDGE);
|
|
|
|
for(; anExpE.More(); anExpE.Next(), nbedgeused++);
|
|
|
|
if(nbstartedges != nbedgeused) {
|
|
bBadFace = Standard_True;
|
|
}
|
|
}
|
|
|
|
if(bBadFace) {
|
|
BOPAlgo_CheckResult aResult;
|
|
|
|
if(i == 0) {
|
|
aResult.SetShape1(myShape1);
|
|
aResult.AddFaultyShape1(aFace);
|
|
}
|
|
else {
|
|
aResult.SetShape2(myShape2);
|
|
aResult.AddFaultyShape2(aFace);
|
|
}
|
|
|
|
aResult.SetCheckStatus(BOPAlgo_NonRecoverableFace);
|
|
myResult.Append(aResult);
|
|
|
|
if(myStopOnFirst) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ================================================================================
|
|
// function: TestTangent
|
|
// purpose:
|
|
// ================================================================================
|
|
void BOPAlgo_ArgumentAnalyzer::TestTangent()
|
|
{
|
|
// not implemented
|
|
}
|
|
|
|
// ================================================================================
|
|
// function: TestMergeSubShapes
|
|
// purpose:
|
|
// ================================================================================
|
|
void BOPAlgo_ArgumentAnalyzer::TestMergeSubShapes(const TopAbs_ShapeEnum theType)
|
|
{
|
|
if(myShape1.IsNull() || myShape2.IsNull())
|
|
return;
|
|
|
|
if (myEmpty1 || myEmpty2)
|
|
return;
|
|
|
|
BOPAlgo_CheckStatus aStatus = BOPAlgo_CheckUnknown;
|
|
|
|
switch(theType) {
|
|
case TopAbs_VERTEX: {
|
|
aStatus = BOPAlgo_IncompatibilityOfVertex;
|
|
break;
|
|
}
|
|
case TopAbs_EDGE: {
|
|
aStatus = BOPAlgo_IncompatibilityOfEdge;
|
|
break;
|
|
}
|
|
case TopAbs_FACE: {
|
|
aStatus = BOPAlgo_IncompatibilityOfFace;
|
|
break;
|
|
}
|
|
default:
|
|
return;
|
|
}
|
|
TopExp_Explorer anExp1(myShape1, theType);
|
|
TopExp_Explorer anExp2(myShape2, theType);
|
|
BOPCol_SequenceOfShape aSeq1, aSeq2;
|
|
BOPCol_MapOfShape aMap1, aMap2;
|
|
|
|
for(; anExp1.More(); anExp1.Next()) {
|
|
const TopoDS_Shape& aS1 = anExp1.Current();
|
|
|
|
if(aMap1.Contains(aS1))
|
|
continue;
|
|
aSeq1.Append(aS1);
|
|
aMap1.Add(aS1);
|
|
}
|
|
|
|
for(; anExp2.More(); anExp2.Next()) {
|
|
const TopoDS_Shape& aS2 = anExp2.Current();
|
|
if(aMap2.Contains(aS2))
|
|
continue;
|
|
aSeq2.Append(aS2);
|
|
aMap2.Add(aS2);
|
|
}
|
|
|
|
TColStd_Array2OfBoolean anArrayOfFlag(1, aSeq1.Length(), 1, aSeq2.Length());
|
|
Standard_Integer i = 0, j = 0;
|
|
for(i = 1; i <= aSeq1.Length(); i++)
|
|
for(j = 1; j <= aSeq2.Length(); j++)
|
|
anArrayOfFlag.SetValue(i, j, Standard_False);
|
|
|
|
for(i = 1; i <= aSeq1.Length(); i++) {
|
|
const TopoDS_Shape& aS1 = aSeq1.Value(i);
|
|
BOPCol_ListOfShape aListOfS2;
|
|
Standard_Integer nbs = 0;
|
|
|
|
for(j = 1; j <= aSeq2.Length(); j++) {
|
|
const TopoDS_Shape& aS2 = aSeq2.Value(j);
|
|
Standard_Boolean bIsEqual = Standard_False;
|
|
|
|
if(theType == TopAbs_VERTEX) {
|
|
|
|
const TopoDS_Vertex& aV1 = *(TopoDS_Vertex*)&(aS1);
|
|
const TopoDS_Vertex& aV2 = *(TopoDS_Vertex*)&(aS2);
|
|
gp_Pnt aP1 = BRep_Tool::Pnt(aV1);
|
|
gp_Pnt aP2 = BRep_Tool::Pnt(aV2);
|
|
Standard_Real aDist = aP1.Distance(aP2);
|
|
|
|
if(aDist <= (BRep_Tool::Tolerance(aV1) + BRep_Tool::Tolerance(aV2))) {
|
|
bIsEqual = Standard_True;
|
|
}
|
|
}
|
|
else if(theType == TopAbs_EDGE) {
|
|
const TopoDS_Edge& aE1 = *(TopoDS_Edge*)&(aS1);
|
|
const TopoDS_Edge& aE2 = *(TopoDS_Edge*)&(aS2);
|
|
//
|
|
IntTools_EdgeEdge aEE(aE1, aE2);
|
|
//
|
|
aEE.Perform();
|
|
if (aEE.IsDone()) {
|
|
const IntTools_SequenceOfCommonPrts& aCPrts = aEE.CommonParts();
|
|
Standard_Integer ii = 0;
|
|
|
|
for (ii = 1; ii <= aCPrts.Length(); ii++) {
|
|
const IntTools_CommonPrt& aCPart = aCPrts(ii);
|
|
|
|
if (aCPart.Type() == TopAbs_EDGE) {
|
|
bIsEqual = Standard_True;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(theType == TopAbs_FACE) {
|
|
// not yet implemented!
|
|
}
|
|
|
|
if(bIsEqual) {
|
|
anArrayOfFlag.SetValue(i, j, Standard_True );
|
|
aListOfS2.Append(aS2);
|
|
nbs++;
|
|
}
|
|
}
|
|
|
|
if(nbs > 1) {
|
|
BOPAlgo_CheckResult aResult;
|
|
|
|
aResult.SetShape1(myShape1);
|
|
aResult.SetShape2(myShape2);
|
|
aResult.AddFaultyShape1(aS1);
|
|
BOPCol_ListIteratorOfListOfShape anIt(aListOfS2);
|
|
|
|
for(; anIt.More(); anIt.Next()) {
|
|
aResult.AddFaultyShape2(anIt.Value());
|
|
}
|
|
|
|
aResult.SetCheckStatus(aStatus);
|
|
myResult.Append(aResult);
|
|
|
|
if(myStopOnFirst) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
for(i = 1; i <= aSeq2.Length(); i++) {
|
|
const TopoDS_Shape& aS2 = aSeq2.Value(i);
|
|
BOPCol_ListOfShape aListOfS1;
|
|
Standard_Integer nbs = 0;
|
|
|
|
for(j = 1; j <= aSeq1.Length(); j++) {
|
|
const TopoDS_Shape& aS1 = aSeq1.Value(j);
|
|
|
|
if(anArrayOfFlag.Value(j, i)) {
|
|
aListOfS1.Append(aS1);
|
|
nbs++;
|
|
}
|
|
}
|
|
|
|
if(nbs > 1) {
|
|
BOPAlgo_CheckResult aResult;
|
|
|
|
aResult.SetShape1(myShape1);
|
|
aResult.SetShape2(myShape2);
|
|
BOPCol_ListIteratorOfListOfShape anIt(aListOfS1);
|
|
|
|
for(; anIt.More(); anIt.Next()) {
|
|
aResult.AddFaultyShape1(anIt.Value());
|
|
}
|
|
aResult.AddFaultyShape2(aS2);
|
|
|
|
aResult.SetCheckStatus(aStatus);
|
|
myResult.Append(aResult);
|
|
|
|
if(myStopOnFirst) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ================================================================================
|
|
// function: TestMergeVertex
|
|
// purpose:
|
|
// ================================================================================
|
|
void BOPAlgo_ArgumentAnalyzer::TestMergeVertex()
|
|
{
|
|
TestMergeSubShapes(TopAbs_VERTEX);
|
|
}
|
|
|
|
// ================================================================================
|
|
// function: TestMergeEdge
|
|
// purpose:
|
|
// ================================================================================
|
|
void BOPAlgo_ArgumentAnalyzer::TestMergeEdge()
|
|
{
|
|
TestMergeSubShapes(TopAbs_EDGE);
|
|
}
|
|
|
|
// ================================================================================
|
|
// function: TestContinuity
|
|
// purpose:
|
|
// ================================================================================
|
|
void BOPAlgo_ArgumentAnalyzer::TestContinuity()
|
|
{
|
|
Standard_Integer i;
|
|
Standard_Real f, l;
|
|
TopExp_Explorer aExp;
|
|
BOPCol_MapIteratorOfMapOfShape aIt;
|
|
//
|
|
for (i = 0; i < 2; ++i) {
|
|
const TopoDS_Shape& aS = !i ? myShape1 : myShape2;
|
|
if(aS.IsNull()) {
|
|
continue;
|
|
}
|
|
//
|
|
BOPCol_MapOfShape aMS;
|
|
//Edges
|
|
aExp.Init(aS, TopAbs_EDGE);
|
|
for (; aExp.More(); aExp.Next()) {
|
|
const TopoDS_Edge& aE = *(TopoDS_Edge*)&aExp.Current();
|
|
if (BRep_Tool::Degenerated(aE)) {
|
|
continue;
|
|
}
|
|
const Handle(Geom_Curve)& aC = BRep_Tool::Curve(aE, f, l);
|
|
if (aC->Continuity() == GeomAbs_C0) {
|
|
aMS.Add(aE);
|
|
}
|
|
}
|
|
//Faces
|
|
aExp.Init(aS, TopAbs_FACE);
|
|
for (; aExp.More(); aExp.Next()) {
|
|
const TopoDS_Face& aF = *(TopoDS_Face*)&aExp.Current();
|
|
const Handle(Geom_Surface)& aS = BRep_Tool::Surface(aF);
|
|
if (aS->Continuity() == GeomAbs_C0) {
|
|
aMS.Add(aF);
|
|
}
|
|
}
|
|
//
|
|
//add shapes with continuity C0 to result
|
|
aIt.Initialize(aMS);
|
|
for (; aIt.More(); aIt.Next()) {
|
|
const TopoDS_Shape& aFS = aIt.Value();
|
|
BOPAlgo_CheckResult aResult;
|
|
if(i == 0) {
|
|
aResult.SetShape1(myShape1);
|
|
aResult.AddFaultyShape1(aFS);
|
|
} else {
|
|
aResult.SetShape2(myShape2);
|
|
aResult.AddFaultyShape2(aFS);
|
|
}
|
|
aResult.SetCheckStatus(BOPAlgo_GeomAbs_C0);
|
|
myResult.Append(aResult);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ================================================================================
|
|
// function: TestCurveOnSurface
|
|
// purpose:
|
|
// ================================================================================
|
|
void BOPAlgo_ArgumentAnalyzer::TestCurveOnSurface()
|
|
{
|
|
Standard_Integer i;
|
|
Standard_Real aT, aD, aTolE;
|
|
TopExp_Explorer aExpF, aExpE;
|
|
//
|
|
for(i = 0; i < 2; i++) {
|
|
const TopoDS_Shape& aS = (i == 0) ? myShape1 : myShape2;
|
|
if(aS.IsNull()) {
|
|
continue;
|
|
}
|
|
//
|
|
aExpF.Init(aS, 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();
|
|
//
|
|
if (BOPTools_AlgoTools::ComputeTolerance(aF, aE, aD, aT)) {
|
|
aTolE = BRep_Tool::Tolerance(aE);
|
|
if (aD > aTolE) {
|
|
BOPAlgo_CheckResult aResult;
|
|
aResult.SetCheckStatus(BOPAlgo_InvalidCurveOnSurface);
|
|
if(i == 0) {
|
|
aResult.SetShape1(myShape1);
|
|
aResult.AddFaultyShape1(aE);
|
|
aResult.AddFaultyShape1(aF);
|
|
aResult.SetMaxDistance1(aD);
|
|
aResult.SetMaxParameter1(aT);
|
|
}
|
|
else {
|
|
aResult.SetShape2(myShape2);
|
|
aResult.AddFaultyShape2(aE);
|
|
aResult.AddFaultyShape2(aF);
|
|
aResult.SetMaxDistance2(aD);
|
|
aResult.SetMaxParameter2(aT);
|
|
}
|
|
myResult.Append(aResult);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ================================================================================
|
|
// function: UpdateTolerances
|
|
// purpose:
|
|
// ================================================================================
|
|
void BOPAlgo_ArgumentAnalyzer::UpdateTolerances()
|
|
{
|
|
if (myFuzzyValue == 0.) {
|
|
return;
|
|
}
|
|
//
|
|
BOPCol_MapOfShape aMapShapes;
|
|
//
|
|
if (!myShape1.IsNull()) {
|
|
BOPTools::MapShapes(myShape1, aMapShapes);
|
|
}
|
|
if (!myShape2.IsNull()) {
|
|
BOPTools::MapShapes(myShape2, aMapShapes);
|
|
}
|
|
//
|
|
if (aMapShapes.IsEmpty()) {
|
|
return;
|
|
}
|
|
//
|
|
Standard_Real aTol, aFuzz;
|
|
TopAbs_ShapeEnum aType;
|
|
BOPCol_MapIteratorOfMapOfShape aIt;
|
|
//
|
|
aFuzz = myFuzzyValue / 2.;
|
|
aIt.Initialize(aMapShapes);
|
|
for (; aIt.More(); aIt.Next()) {
|
|
const TopoDS_Shape& aS = aIt.Value();
|
|
aType = aS.ShapeType();
|
|
//
|
|
switch (aType) {
|
|
case TopAbs_VERTEX: {
|
|
const TopoDS_Vertex& aV = *(TopoDS_Vertex*)&aS;
|
|
const Handle(BRep_TVertex)& TV =
|
|
*((Handle(BRep_TVertex)*)&aV.TShape());
|
|
aTol = TV->Tolerance();
|
|
myToleranceMap.Bind(aS, aTol);
|
|
TV->Tolerance(aTol + aFuzz);
|
|
break;
|
|
}
|
|
case TopAbs_EDGE: {
|
|
const TopoDS_Edge& aE = *(TopoDS_Edge*)&aS;
|
|
const Handle(BRep_TEdge)& TE =
|
|
*((Handle(BRep_TEdge)*)&aE.TShape());
|
|
aTol = TE->Tolerance();
|
|
myToleranceMap.Bind(aS, aTol);
|
|
TE->Tolerance(aTol + aFuzz);
|
|
break;
|
|
}
|
|
case TopAbs_FACE: {
|
|
const TopoDS_Face& aF = *(TopoDS_Face*)&aS;
|
|
const Handle(BRep_TFace)& TF =
|
|
*((Handle(BRep_TFace)*)&aF.TShape());
|
|
aTol = TF->Tolerance();
|
|
myToleranceMap.Bind(aS, aTol);
|
|
TF->Tolerance(aTol + aFuzz);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
} // switch (aType) {
|
|
} // for (; aIt.More(); aIt.Next()) {
|
|
}
|
|
|
|
// ================================================================================
|
|
// function: SetDefaultTolerances
|
|
// purpose:
|
|
// ================================================================================
|
|
void BOPAlgo_ArgumentAnalyzer::SetDefaultTolerances()
|
|
{
|
|
if (myFuzzyValue == 0.) {
|
|
return;
|
|
}
|
|
//
|
|
if (myToleranceMap.IsEmpty()) {
|
|
return;
|
|
}
|
|
//
|
|
Standard_Real aTol;
|
|
TopAbs_ShapeEnum aType;
|
|
BOPCol_DataMapIteratorOfDataMapOfShapeReal aIt;
|
|
//
|
|
aIt.Initialize(myToleranceMap);
|
|
for (; aIt.More(); aIt.Next()) {
|
|
const TopoDS_Shape& aS = aIt.Key();
|
|
aTol = aIt.Value();
|
|
aType = aS.ShapeType();
|
|
//
|
|
switch (aType) {
|
|
case TopAbs_VERTEX: {
|
|
const TopoDS_Vertex& aV = *(TopoDS_Vertex*)&aS;
|
|
const Handle(BRep_TVertex)& TV =
|
|
*((Handle(BRep_TVertex)*)&aV.TShape());
|
|
TV->Tolerance(aTol);
|
|
break;
|
|
}
|
|
case TopAbs_EDGE: {
|
|
const TopoDS_Edge& aE = *(TopoDS_Edge*)&aS;
|
|
const Handle(BRep_TEdge)& TE =
|
|
*((Handle(BRep_TEdge)*)&aE.TShape());
|
|
TE->Tolerance(aTol);
|
|
break;
|
|
}
|
|
case TopAbs_FACE: {
|
|
const TopoDS_Face& aF = *(TopoDS_Face*)&aS;
|
|
const Handle(BRep_TFace)& TF =
|
|
*((Handle(BRep_TFace)*)&aF.TShape());
|
|
TF->Tolerance(aTol);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
} // switch (aType) {
|
|
} // for (; aIt.More(); aIt.Next()) {
|
|
}
|