1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-09 13:22:24 +03:00

0026261: Create a tool to remove tails from any wire

A tool to remove tails from the wires of a shape was created.
The tool is based on mechanism 'ShapeFix',
is located in types 'ShapeFix_Wire' and 'ShapeAnalysis_Wire',
is enabled through method 'ShapeFix_Wire::FixTailMode' and
is initialized by methods 'ShapeFix_Wire::SetMaxTailAngle' and 'ShapeFix_Wire::SetMaxTailWidth' and
is called through method 'ShapeFix_Wire::FixTails'.
The status of any performing of the last method is accessible through method 'ShapeFix_Wire::StatusFixTails'.
The tail angle is checked only at the tail start.

Mechanism 'ShapeFix' was modified:
- the tool is disabled by default;
- algorithm 'Fix notched edges' is disabled then the tool is enabled;
- the tool and the last algorithm work in turns then the tool works on the request.

'Draw' command 'fixshape' was extended by options '-maxtaila' and '-maxtailw' to test the tool.

'Draw' tests to test the tool were created.

Algorithm 'fixshape' was changed in type 'ShapeProcess_OperLibrary' to
- use new parameters named 'FixTailMode', 'MaxTailAngle' (in degrees) and 'MaxTailWidth' from the algorithm context;
- apply the tool after the shape will be fully fixed if the tool was enabled.

Place holders for the new parameters were created in the resource file of mechsnism 'STEPControl_Reader'.

Test cases for issue CR26261
This commit is contained in:
abk
2015-05-19 20:03:11 +03:00
committed by bugmaster
parent 70fd50ec90
commit fbf3becf65
38 changed files with 852 additions and 21 deletions

View File

@@ -64,6 +64,7 @@ uses
Shape from TopoDS,
Wire from TopoDS,
Face from TopoDS,
Edge from TopoDS,
SequenceOfIntersectionPoint from IntRes2d,
SequenceOfPnt from TColgp,
SequenceOfReal from TColStd,
@@ -545,6 +546,17 @@ is
aMapSeemEdges : out MapOfShape from TopTools) returns Boolean;
---Purpose: Checks existance of loop on wire and return vertices wich are loop vertices
-- (vertices belonging to a few pairs of edges)
CheckTail(me : mutable;
theEdge1: in Edge from TopoDS;
theEdge2: in Edge from TopoDS;
theMaxSine: in Real;
theMaxWidth: in Real;
theMaxTolerance: in Real;
theEdge11: out Edge from TopoDS;
theEdge12: out Edge from TopoDS;
theEdge21: out Edge from TopoDS;
theEdge22: out Edge from TopoDS) returns Boolean;
---Status after checking :

View File

@@ -69,12 +69,18 @@
#include <Bnd_Box2d.hxx>
//szvsh addition
#include <BRepGProp.hxx>
#include <GCPnts_AbscissaPoint.hxx>
#include <Geom2dAdaptor_HCurve.hxx>
#include <GeomAdaptor_Curve.hxx>
#include <GProp_GProps.hxx>
#include <Adaptor3d_CurveOnSurface.hxx>
#include <TColgp_SequenceOfPnt.hxx>
#include <ShapeAnalysis_Surface.hxx>
#include <TopoDS_Wire.hxx>
#include <ShapeAnalysis.hxx>
#include <ShapeAnalysis_TransferParametersProj.hxx>
#include <ShapeBuild_Edge.hxx>
#include <Geom_Plane.hxx>
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
#include <TopoDS_Iterator.hxx>
@@ -1964,3 +1970,283 @@ Standard_Boolean isMultiVertex(const TopTools_ListOfShape& alshape,
}
return Standard_False;
}
//=======================================================================
//function : Project
//purpose :
//=======================================================================
static Standard_Real Project(
const Handle(Geom_Curve)& theCurve,
const Standard_Real theFirstParameter,
const Standard_Real theLastParameter,
const gp_Pnt& thePoint,
const Standard_Real thePrecision,
Standard_Real& theParameter,
gp_Pnt& theProjection)
{
const Standard_Real aDist = ShapeAnalysis_Curve().Project(theCurve, thePoint,
thePrecision, theProjection, theParameter, theFirstParameter,
theLastParameter);
if (theParameter >= theFirstParameter && theParameter <= theLastParameter)
{
return aDist;
}
const Standard_Real aParams[] = {theFirstParameter, theLastParameter};
const gp_Pnt aPrjs[] =
{theCurve->Value(aParams[0]), theCurve->Value(aParams[1])};
const Standard_Real aDists[] =
{thePoint.Distance(aPrjs[0]), thePoint.Distance(aPrjs[1])};
const Standard_Integer aPI = (aDists[0] <= aDists[1]) ? 0 : 1;
theParameter = aParams[aPI];
theProjection = aPrjs[aPI];
return aDists[aPI];
}
//=======================================================================
//function : CheckTail
//purpose :
//=======================================================================
Standard_Boolean ShapeAnalysis_Wire::CheckTail(
const TopoDS_Edge& theEdge1,
const TopoDS_Edge& theEdge2,
const Standard_Real theMaxSine,
const Standard_Real theMaxWidth,
const Standard_Real theMaxTolerance,
TopoDS_Edge& theEdge11,
TopoDS_Edge& theEdge12,
TopoDS_Edge& theEdge21,
TopoDS_Edge& theEdge22)
{
const TopoDS_Edge aEs[] = {theEdge1, theEdge2};
if (!IsReady() || BRep_Tool::Degenerated(aEs[0]) ||
BRep_Tool::Degenerated(aEs[1]))
{
return Standard_False;
}
// Check the distance between the edge common ends.
const Standard_Real aTol2 = theMaxWidth + 0.5 * Precision::Confusion();
const Standard_Real aTol3 = theMaxWidth + Precision::Confusion();
const Standard_Real aTol4 = theMaxWidth + 1.5 * Precision::Confusion();
const Standard_Real aSqTol2 = aTol2 * aTol2;
const Standard_Real aSqTol3 = aTol3 * aTol3;
Handle(Geom_Curve) aCs[2];
Standard_Real aLs[2][2];
Standard_Integer aVIs[2];
gp_Pnt aVPs[2];
{
for (Standard_Integer aEI = 0; aEI < 2; ++aEI)
{
if (!ShapeAnalysis_Edge().Curve3d(
aEs[aEI], aCs[aEI], aLs[aEI][0], aLs[aEI][1], Standard_False))
{
return Standard_False;
}
aVIs[aEI] = (aEs[aEI].Orientation() == TopAbs_REVERSED) ? aEI : 1 - aEI;
aVPs[aEI] = aCs[aEI]->Value(aLs[aEI][aVIs[aEI]]);
}
if (aVPs[0].SquareDistance(aVPs[1]) > aSqTol2)
{
return Standard_False;
}
}
// Check the angle between the edges.
if (theMaxSine >= 0)
{
const Standard_Real aSqMaxSine = theMaxSine * theMaxSine;
gp_XYZ aDs[2];
Standard_Integer aReverse = 0;
for (Standard_Integer aEI = 0; aEI < 2; ++aEI)
{
GeomAdaptor_Curve aCA(aCs[aEI]);
if (GCPnts_AbscissaPoint::Length(aCA, aLs[aEI][0], aLs[aEI][1],
0.25 * Precision::Confusion()) < 0.5 * Precision::Confusion())
{
return Standard_False;
}
GCPnts_AbscissaPoint aAP(0.25 * Precision::Confusion(), aCA,
0.5 * Precision::Confusion() * (1 - 2 * aVIs[aEI]),
aLs[aEI][aVIs[aEI]]);
if (!aAP.IsDone())
{
return Standard_False;
}
gp_XYZ aPs[2];
aPs[aVIs[aEI]] = aVPs[aEI].XYZ();
aPs[1 - aVIs[aEI]] = aCs[aEI]->Value(aAP.Parameter()).XYZ();
aDs[aEI] = aPs[1] - aPs[0];
const Standard_Real aDN = aDs[aEI].Modulus();
if (aDN < 0.1 * Precision::Confusion())
{
return Standard_False;
}
aDs[aEI] *= 1 / aDN;
aReverse ^= aVIs[aEI];
}
if (aReverse)
{
aDs[0].Reverse();
}
if (aDs[0] * aDs[1] < 0 || aDs[0].CrossSquareMagnitude(aDs[1]) > aSqMaxSine)
{
return Standard_False;
}
}
// Calculate the tail bounds.
gp_Pnt aPs[2], aPrjs[2];
Standard_Real aParams1[2], aParams2[2];
Standard_Real aDists[2];
Standard_Boolean isWholes[] = {Standard_True, Standard_True};
for (Standard_Integer aEI = 0; aEI < 2; ++aEI)
{
Standard_Real aParam1 = aLs[aEI][aVIs[aEI]];
aParams1[aEI] = aLs[aEI][1 - aVIs[aEI]];
aCs[aEI]->D0(aParams1[aEI], aPs[aEI]);
aDists[aEI] = Project(aCs[1 - aEI], aLs[1 - aEI][0], aLs[1 - aEI][1],
aPs[aEI], 0.25 * Precision::Confusion(), aParams2[aEI], aPrjs[aEI]);
if (aDists[aEI] <= aTol2)
{
continue;
}
isWholes[aEI] = Standard_False;
for (;;)
{
const Standard_Real aParam = (aParam1 + aParams1[aEI]) * 0.5;
aCs[aEI]->D0(aParam, aPs[aEI]);
const Standard_Real aDist = Project(aCs[1 - aEI], aLs[1 - aEI][0],
aLs[1 - aEI][1], aPs[aEI], 0.25 * Precision::Confusion(), aParams2[aEI],
aPrjs[aEI]);
if (aDist <= aTol2)
{
aParam1 = aParam;
}
else
{
aParams1[aEI] = aParam;
if (aDist <= aTol3)
{
break;
}
}
}
}
// Check the tail bounds.
for (Standard_Integer aEI = 0; aEI < 2; ++aEI)
{
const Standard_Real aParam1 = aLs[aEI][aVIs[aEI]];
const Standard_Real aParam2 = aParams1[aEI];
const Standard_Real aStepL = (aParam2 - aParam1) / 23;
for (Standard_Integer aStepN = 1; aStepN < 23; ++aStepN)
{
Standard_Real aParam = aParam1 + aStepN * aStepL;
gp_Pnt aP = aCs[aEI]->Value(aParam), aPrj;
if (Project(aCs[1 - aEI], aLs[1 - aEI][0], aLs[1 - aEI][1], aP,
0.25 * Precision::Confusion(), aParam, aPrj) > aTol4)
{
return Standard_False;
}
}
}
// Check whether both edges must be removed.
if (isWholes[0] && isWholes[1] && aPs[0].SquareDistance(aPs[1]) <= aSqTol3)
{
theEdge11 = theEdge1;
theEdge21 = theEdge2;
return Standard_True;
}
// Cut and remove the edges.
Standard_Integer aFI = 0;
if (isWholes[0] || isWholes[1])
{
// Determine an edge to remove and the other one to cut.
aFI = isWholes[0] ? 0 : 1;
if (aDists[1 - aFI] < aDists[aFI] && isWholes[1 - aFI])
{
aFI = 1 - aFI;
}
}
Standard_Real aParams[2];
aParams[aFI] = aParams1[aFI];
aParams[1 - aFI] = aParams2[aFI];
// Correct the cut for the parametrization tolerance.
TopoDS_Edge* aEParts[][2] =
{{&theEdge11, &theEdge12}, {&theEdge21, &theEdge22}};
Standard_Integer aResults[] = {1, 1};
for (Standard_Integer aEI = 0; aEI < 2; ++aEI)
{
if (Abs(aParams[aEI] - aLs[aEI][1 - aVIs[aEI]]) <= Precision::PConfusion())
{
aResults[aEI] = 2;
*aEParts[aEI][0] = aEs[aEI];
}
else if (Abs(aParams[aEI] - aLs[aEI][aVIs[aEI]]) <= Precision::PConfusion())
{
aResults[aEI] = 0;
}
}
// Correct the cut for the distance tolerance.
for (Standard_Integer aEI = 0; aEI < 2; ++aEI)
{
if (aResults[aEI] != 1)
{
continue;
}
// Create the parts of the edge.
TopoDS_Edge aFE = TopoDS::Edge(aEs[aEI].Oriented(TopAbs_FORWARD));
ShapeAnalysis_TransferParametersProj aSATPP(aFE, TopoDS_Face());
aSATPP.SetMaxTolerance(theMaxTolerance);
TopoDS_Vertex aSplitV;
BRep_Builder().MakeVertex(
aSplitV, aCs[aEI]->Value(aParams[aEI]), Precision::Confusion());
TopoDS_Edge aEParts2[] = {
ShapeBuild_Edge().CopyReplaceVertices(aFE, TopoDS_Vertex(),
TopoDS::Vertex(aSplitV.Oriented(TopAbs_REVERSED))),
ShapeBuild_Edge().CopyReplaceVertices(aFE, aSplitV, TopoDS_Vertex())};
ShapeBuild_Edge().CopyPCurves(aEParts2[0], aFE);
ShapeBuild_Edge().CopyPCurves(aEParts2[1], aFE);
BRep_Builder().SameRange(aEParts2[0], Standard_False);
BRep_Builder().SameRange(aEParts2[1], Standard_False);
BRep_Builder().SameParameter(aEParts2[0], Standard_False);
BRep_Builder().SameParameter(aEParts2[1], Standard_False);
aSATPP.TransferRange(
aEParts2[0], aLs[aEI][0], aParams[aEI], Standard_False);
aSATPP.TransferRange(
aEParts2[1], aParams[aEI], aLs[aEI][1], Standard_False);
GProp_GProps aLinProps;
BRepGProp::LinearProperties(aEParts2[1 - aVIs[aEI]], aLinProps);
if (aLinProps.Mass() <= Precision::Confusion())
{
aResults[aEI] = 2;
*aEParts[aEI][0] = aEs[aEI];
}
else
{
BRepGProp::LinearProperties(aEParts2[aVIs[aEI]], aLinProps);
if (aLinProps.Mass() <= Precision::Confusion())
{
aResults[aEI] = 0;
}
else
{
*aEParts[aEI][0] = aEParts2[0];
*aEParts[aEI][1] = aEParts2[1];
}
}
}
return aResults[0] + aResults[1] != 0;
}