1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-10 18:51:21 +03:00

0024265: Replacing vertices with tolerance that covers lacking edge by two new vertices and lacking edge

ShapeFix_LackingEdgeRecover was introduced
"fixlackingedges" draw command waas introduced
don't process a vertex if it is shared by more than 2 edges placed on one face;
This commit is contained in:
ibs 2013-10-17 15:16:32 +04:00
parent 0fbfbd6029
commit 13be736516
5 changed files with 990 additions and 4 deletions

View File

@ -46,6 +46,7 @@
#include <ShapeFix_Wireframe.hxx>
#include <ShapeFix_Face.hxx>
#include <ShapeFix_Shape.hxx>
#include <ShapeFix_LackingEdgeRecover.hxx>
#include <Precision.hxx>
#include <ShapeExtend_DataMapOfShapeListOfMsg.hxx>
#include <ShapeExtend_MsgRegistrator.hxx>
@ -567,6 +568,52 @@ Standard_Integer fixsmall(Draw_Interpretor& di, Standard_Integer n, const char**
return 0;
}
//=======================================================================
//function : fixlackingedges
//purpose :
//=======================================================================
static Standard_Integer fixlackingedges(Draw_Interpretor& di, Standard_Integer n, const char** a)
{
if( n < 3)
{
di << "\nInvalid number of arguments\n";
return 1;
}
Standard_Integer aCurIndexOfArg = 1;
// result shape
Standard_CString aNameOfModifiedShape = a[aCurIndexOfArg];
// source shape
aCurIndexOfArg++;
TopoDS_Shape aShape = DBRep::Get(a[aCurIndexOfArg]);
if (aShape.IsNull())
{
di << "\nthe shape is null\n";
return 1;
}
// max tolerance
Standard_Real aMaxTol = 0.01;
aCurIndexOfArg++;
if (aCurIndexOfArg < n)
aMaxTol = Draw::Atof(a[aCurIndexOfArg]);
Handle(ShapeFix_LackingEdgeRecover) aLackingEdgeTool =
new ShapeFix_LackingEdgeRecover;
aLackingEdgeTool->SetMaxTolerance(aMaxTol);
aLackingEdgeTool->Init(aShape);
aLackingEdgeTool->Perform();
TopoDS_Shape aModifiedShape = aLackingEdgeTool->Shape();
DBRep::Set ( aNameOfModifiedShape, aModifiedShape );
return 0;
}
//=======================================================================
//function : fixsmalledges
//purpose :
@ -775,8 +822,8 @@ static Standard_Integer connectedges(Draw_Interpretor& di, Standard_Integer n, c
__FILE__,reface,g);
theCommands.Add ("fixshape","res shape [preci [maxpreci]] [{switches}]",
__FILE__,fixshape,g);
// theCommands.Add ("testfill","result edge1 edge2",
// __FILE__,XSHAPE_testfill,g);
theCommands.Add ("fixlackingedges","result shape [toler]",
__FILE__,fixlackingedges,g);
theCommands.Add ("fixwgaps","result shape [toler=0]",
__FILE__,fixgaps,g);
theCommands.Add ("fixsmall","result shape [toler=1.]",

View File

@ -33,6 +33,7 @@ uses
GeomAbs,
Adaptor3d,
TCollection,
TColgp,
TColStd,
TopAbs,
TopLoc,
@ -103,8 +104,11 @@ is
class IntersectionTool;
---Purpose: Tool for fixing selfintersecting wire
-- and intersecting wires
-- and intersecting wires
class LackingEdgeRecover;
---Purpose: Tool for lacking edges recover
class SplitTool;
---Purpose: Tool for splitting and cutting edges; incudes methods
-- used in OverlappingTool and IntersectionTool
@ -142,6 +146,12 @@ is
---Purpose: Removes edges which are less than given tolerance from shape
-- with help of ShapeFix_Wire::FixSmall()
RecoverLackingEdges (theShape: Shape from TopoDS; theMaxTolerance: Real; theContext: in out ReShape from ShapeBuild)
returns Shape from TopoDS;
---Purpose: Recovers lacking edges by replacing of vertices with tolerance
-- greater than max tolerance by couple of vertices with "normal"
-- tolerance and lacking edge between them
FixVertexPosition(theshape: in out Shape from TopoDS;
theTolerance: Real;
thecontext: ReShape from ShapeBuild) returns Boolean;

View File

@ -52,6 +52,7 @@
#include <ShapeFix_Shape.hxx>
#include <ShapeFix_Wire.hxx>
#include <ShapeFix_Face.hxx>
#include <ShapeFix_LackingEdgeRecover.hxx>
#include <TopoDS_Iterator.hxx>
#include <GeomAdaptor_HSurface.hxx>
#include <TopTools_MapOfShape.hxx>
@ -712,3 +713,23 @@ Standard_Real ShapeFix::LeastEdgeSize(TopoDS_Shape& theShape)
aRes = sqrt(aRes);
return aRes;
}
//=======================================================================
//function : RecoverLackingEdges
//purpose :
//=======================================================================
TopoDS_Shape ShapeFix::RecoverLackingEdges(const TopoDS_Shape& theShape,
const Standard_Real theMaxTolerance,
Handle(ShapeBuild_ReShape)& theContext)
{
Handle(ShapeFix_LackingEdgeRecover) aLackingEdgeTool =
new ShapeFix_LackingEdgeRecover;
aLackingEdgeTool->SetContext(theContext);
aLackingEdgeTool->SetMaxTolerance(theMaxTolerance);
aLackingEdgeTool->Init(theShape);
aLackingEdgeTool->Perform();
return aLackingEdgeTool->Shape();
}

View File

@ -0,0 +1,113 @@
-- Created on: 10.10.2013
-- Created by: Briginas Ivan
class LackingEdgeRecover from ShapeFix inherits Root from ShapeFix
---Purpose: Fixing lacking edge
uses
Shape from TopoDS,
Face from TopoDS,
Wire from TopoDS,
Edge from TopoDS,
Vertex from TopoDS,
Pnt from gp,
Pnt2d from gp,
BSplineCurve from Geom2d,
Curve from Geom2d,
WireData from ShapeExtend,
Root from ShapeFix,
SequenceOfPnt from TColgp
is
Create returns LackingEdgeRecover from ShapeFix;
---Purpose: Default constructor set precision and status message
-- and drops all fixing statuses
Create (theShape: Shape from TopoDS)
returns LackingEdgeRecover from ShapeFix;
---Purpose: Constructor call Init method
Init (me: mutable; theShape: Shape from TopoDS);
---Purpose: apply current context to the shape.
Perform (me: mutable);
---Purpose: split vertices with big tolerance covering missed edge,
-- into two new vertices and lacking edge
Shape (me) returns Shape from TopoDS;
---Purpose: Returns resulting shape
ConvertLackingVerticesTo2D(me;
theWire: Wire from TopoDS;
theFace: Face from TopoDS;
theFirstVertex: Vertex from TopoDS;
theSecondVertex: Vertex from TopoDS;
theFirstPnt2D: in out Pnt2d from gp;
theSecondPnt2D: in out Pnt2d from gp);
---Purpose: seek the ends of parametric curves of edges that share
-- input vertices (first and second) update the first and
-- the second points by found results
MakeBSplineLackingCurve2D(me;
theFirstPnt2D: Pnt2d from gp;
theSecondPnt2D: Pnt2d from gp)
returns BSplineCurve from Geom2d;
---Purpose: create and return b-spline in 2D space
IsWireStrip(me;
theWire: Wire from TopoDS;
theFace: Face from TopoDS;
theVertex: Vertex from TopoDS;
theFirstPnt: in out Pnt from gp;
theSecondPnt: in out Pnt from gp) returns Boolean;
---Purpose: 1. build vector between the ends of the parametric curves (of
-- edges belonging to the wire) that share the vertex;
-- 2. project the wire on the built vector
-- 3. return TRUE if the length of the projection is less than
-- the length of the built vector which was multiplied by <br>
-- predefined (2) number
ReplaceVertex(me;
theVertex: Vertex from TopoDS;
theEdge: Edge from TopoDS;
theFace: Face from TopoDS;
theListOfFirstPnt: SequenceOfPnt from TColgp;
theFirstVertex: Vertex from TopoDS;
theSecondVertex: Vertex from TopoDS)
returns Edge from TopoDS;
---Purpose: replace the vertex of the edge by the first or the second vertex
-- before replacing the method choose what vertex should be used for
-- replacing return modified edge (with replaced vertex)
ConvertTo2D(me;
theEdge : Edge from TopoDS;
theVertex : Vertex from TopoDS;
theCurve2D : Curve from Geom2d;
thePFirst : Real;
thePSecond : Real)
returns Pnt2d from gp;
---Purpose: calculate parametric representation the vertex on the curve 2d
-- return this representation
ProjectTo2DVector(me;
theWireData : WireData from ShapeExtend;
theFace : Face from TopoDS;
thePntNbPerEdgeForProj : Real;
thePFirst2D : Pnt2d from gp;
thePSecond2D : Pnt2d from gp)
returns Real;
---Purpose: 1. project the wire (equidistant point of it) on the vector
-- is formed by the first and second parametric points
-- 2. calculate and RETURN length of the projection
fields
myShape : Shape from TopoDS is protected;
myRecoveredShape : Shape from TopoDS is protected;
myStatus : Integer is protected;
end LackingEdgeRecover;

View File

@ -0,0 +1,795 @@
// File: ShapeFix_LackingEdgeRecover.cxx
// Created: 10.10.2013
// Author: Briginas Ivan
#include <ShapeFix_LackingEdgeRecover.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <BRep_Builder.hxx>
#include <BRep_Tool.hxx>
#include <Geom_Curve.hxx>
#include <Geom_Surface.hxx>
#include <BRepLib.hxx>
#include <Geom2d_BSplineCurve.hxx>
#include <gp_Pnt2d.hxx>
#include <gp_Pnt.hxx>
#include <gp_Vec2d.hxx>
#include <TColgp_Array1OfPnt2d.hxx>
#include <TColgp_SequenceOfPnt.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <NCollection_List.hxx>
#include <NCollection_Map.hxx>
#include <NCollection_DataMap.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopTools_IndexedMapOfShape.hxx>
#include <TopTools_ListIteratorOfListOfShape.hxx>
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
#include <ShapeBuild_Edge.hxx>
#include <ShapeExtend.hxx>
#include <ShapeExtend_WireData.hxx>
#include <ShapeBuild_ReShape.hxx>
#include <ShapeFix_Edge.hxx>
#include <Standard_Assert.hxx>
IMPLEMENT_STANDARD_HANDLE (ShapeFix_LackingEdgeRecover, ShapeFix_Root)
IMPLEMENT_STANDARD_RTTIEXT(ShapeFix_LackingEdgeRecover, ShapeFix_Root)
inline Standard_Boolean IsEqual(const TopoDS_Edge& theEdge1,
const TopoDS_Edge& theEdge2)
{
return theEdge1.IsSame(theEdge2);
}
inline Standard_Boolean IsEqual(const TopoDS_Face& theFace1,
const TopoDS_Face& theFace2)
{
return theFace1.IsEqual(theFace2);
}
ShapeFix_LackingEdgeRecover::ShapeFix_LackingEdgeRecover()
{
myStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
SetPrecision(Precision::Confusion());
}
ShapeFix_LackingEdgeRecover::ShapeFix_LackingEdgeRecover(const TopoDS_Shape& theShape)
{
this->Init(theShape);
}
TopoDS_Shape ShapeFix_LackingEdgeRecover::Shape() const
{
return myRecoveredShape;
}
void ShapeFix_LackingEdgeRecover::Init(const TopoDS_Shape& theShape)
{
myShape = theShape;
if ( Context().IsNull() )
SetContext ( new ShapeBuild_ReShape );
myRecoveredShape = theShape;
}
void ShapeFix_LackingEdgeRecover::Perform()
{
myRecoveredShape = Context()->Apply(myShape);
TopTools_IndexedDataMapOfShapeListOfShape aVertexEdgesMap, aVertexWiresMap,
anEdgeFacesMap, aWireFacesMap;
TopExp::MapShapesAndAncestors(myRecoveredShape, TopAbs_VERTEX, TopAbs_EDGE, aVertexEdgesMap);
TopExp::MapShapesAndAncestors(myRecoveredShape, TopAbs_VERTEX, TopAbs_WIRE, aVertexWiresMap);
TopExp::MapShapesAndAncestors(myRecoveredShape, TopAbs_EDGE, TopAbs_FACE, anEdgeFacesMap);
TopExp::MapShapesAndAncestors(myRecoveredShape, TopAbs_WIRE, TopAbs_FACE, aWireFacesMap);
NCollection_List< std::pair<TopoDS_Vertex, TopoDS_Vertex> > aVerticesForLackingEdgesBuilding;
typedef NCollection_DataMap<TopoDS_Face, Standard_Integer> FaceDataMap;
// search vertices with tolerance greater than specified threshold (theMaxTol)
TopTools_IndexedMapOfShape aShapeVertexMap;
TopExp::MapShapes(myRecoveredShape, TopAbs_VERTEX, aShapeVertexMap);
Standard_Integer aVertIter = 1; // start from 1
for (; aVertIter <= aShapeVertexMap.Extent(); ++aVertIter)
{
TopoDS_Vertex aCurVertex = TopoDS::Vertex (aShapeVertexMap.FindKey(aVertIter));
Standard_Real aCurTol = BRep_Tool::Tolerance (aCurVertex);
// skip vertices with tolerance lesser than theMaxTol
if (aCurTol < this->MaxTolerance())
continue;
const TopTools_ListOfShape& aSharingWiresOfCurVertex = aVertexWiresMap.FindFromKey (aCurVertex);
// process each edge
Standard_Boolean anIsVertexReplaced = Standard_False;
gp_Pnt aFirstNewPnt, aSecondNewPnt; // these points will replace vertex with big tolerance
TopTools_ListIteratorOfListOfShape anWireIter(aSharingWiresOfCurVertex);
for (;anWireIter.More() && !anIsVertexReplaced; anWireIter.Next())
{
const TopoDS_Wire& aCurWire = TopoDS::Wire(anWireIter.Value());
const TopTools_ListOfShape& aSharingFacesOfCurWire =
aWireFacesMap.FindFromKey (anWireIter.Value());
// (IMPORTANT) process just first found face
TopTools_ListIteratorOfListOfShape aSharingFacesOfCurWireIter(aSharingFacesOfCurWire);
for (; aSharingFacesOfCurWireIter.More() && !anIsVertexReplaced; aSharingFacesOfCurWireIter.Next())
{
// replace the vertex if sharing wire is strip
anIsVertexReplaced = IsWireStrip(aCurWire, TopoDS::Face(aSharingFacesOfCurWireIter.Value()),
aCurVertex, aFirstNewPnt, aSecondNewPnt);
}
}
//int todo_streach_degenerated_edge;
if (!anIsVertexReplaced)
continue;
const TopTools_ListOfShape& aSharingEdgesOfCurVertex =
aVertexEdgesMap.FindFromKey (aCurVertex);
FaceDataMap aSharingFacesMap;
Standard_Boolean anIsCurVertexSkipped = Standard_False;
// split sharing edges into two groups
TColgp_SequenceOfPnt aFirstPntList, aSecondPntList;
NCollection_Map<TopoDS_Edge> anEdgeMap;
TopTools_ListIteratorOfListOfShape aSharingEdgesOfCurVertexIter(aSharingEdgesOfCurVertex);
for (; aSharingEdgesOfCurVertexIter.More(); aSharingEdgesOfCurVertexIter.Next())
{
const TopoDS_Edge& aCurIntEdge = TopoDS::Edge(aSharingEdgesOfCurVertexIter.Value());
if (!anEdgeMap.Contains(aCurIntEdge))
anEdgeMap.Add(aCurIntEdge);
else
continue;
if (!anEdgeFacesMap.Contains(aCurIntEdge))
continue;
const TopTools_ListOfShape& aSharingFacesOfCurIntEdge = anEdgeFacesMap.FindFromKey (aCurIntEdge);
if (aSharingFacesOfCurIntEdge.IsEmpty())
continue;
// collect all sharing faces
TopTools_ListIteratorOfListOfShape aSharingFacesIter(aSharingFacesOfCurIntEdge);
for(; aSharingFacesIter.More(); aSharingFacesIter.Next())
{
const TopoDS_Face aCurShFace = TopoDS::Face(aSharingFacesIter.Value());
if (!aSharingFacesMap.IsBound(aCurShFace))
aSharingFacesMap.Bind(aCurShFace, 1);
else
aSharingFacesMap(aCurShFace)++;
}
// skip the case when a vertex is being shared by more
// than 2 edges that belong to one face
Standard_Integer aMaxNbEdgesOnOneFace = 2;
for (FaceDataMap::Iterator anIt(aSharingFacesMap);
anIt.More() && !anIsCurVertexSkipped; anIt.Next())
{
if (anIt.Value() > aMaxNbEdgesOnOneFace)
anIsCurVertexSkipped = Standard_True;
}
// break processing of edges that share the cur vertex
if (anIsCurVertexSkipped)
break;
// take first sharing face
const TopoDS_Face& aCurIntFace = TopoDS::Face(aSharingFacesOfCurIntEdge.First());
TopLoc_Location aLocation;
Handle(Geom_Surface) aCurIntSurf = BRep_Tool::Surface (aCurIntFace, aLocation);
Standard_Real aPFirstParamOfCurIntEdge, aPLastParamOfCurIntEdge;
Handle(Geom2d_Curve) aPCurveOfCurIntEdge =
BRep_Tool::CurveOnSurface (aCurIntEdge, aCurIntFace,
aPFirstParamOfCurIntEdge, aPLastParamOfCurIntEdge);
// sort couple of vertices of the current internal edge
TopoDS_Iterator anVerticesIter(aCurIntEdge, TopAbs_VERTEX);
for (; anVerticesIter.More(); anVerticesIter.Next())
{
const TopoDS_Vertex& aCurInternalVertex = TopoDS::Vertex(anVerticesIter.Value());
if(!aCurInternalVertex.IsSame(aCurVertex))
continue;
gp_Pnt2d anAddingPnt2D = ConvertTo2D(aCurIntEdge, aCurInternalVertex, aPCurveOfCurIntEdge,
aPFirstParamOfCurIntEdge, aPLastParamOfCurIntEdge);
gp_Pnt anAddingPnt;
aCurIntSurf->D0(anAddingPnt2D.X(), anAddingPnt2D.Y(), anAddingPnt);
Standard_Real aDist2ToFirstNewPnt = aFirstNewPnt.SquareDistance(anAddingPnt);
Standard_Real aDist2ToSecondNewPnt = aSecondNewPnt.SquareDistance(anAddingPnt);
if (aDist2ToFirstNewPnt < aDist2ToSecondNewPnt)
aFirstPntList.Append(anAddingPnt);
else
aSecondPntList.Append(anAddingPnt);
}
}
if (anIsCurVertexSkipped)
continue;
if (aFirstPntList.IsEmpty() || aSecondPntList.IsEmpty())
continue;
// === process FIRST group
// mean point of first group
gp_XYZ aTotalXYZ;
for (Standard_Integer aCurIndex = 1; aCurIndex <= aFirstPntList.Length(); aCurIndex++)
aTotalXYZ += aFirstPntList.Value(aCurIndex).XYZ();
gp_Pnt aMeanFirstNewPnt(aTotalXYZ/aFirstPntList.Length());
// === END process FIRST group
// === process SECOND group
// mean point of second group
aTotalXYZ = gp_XYZ();
for (Standard_Integer aCurIndex = 1; aCurIndex <= aSecondPntList.Length(); aCurIndex++)
aTotalXYZ += aSecondPntList.Value(aCurIndex).XYZ();
gp_Pnt aMeanSecondNewPnt(aTotalXYZ/aSecondPntList.Length());
// === END process SECOND group
// create new vertices
BRep_Builder aBuilder;
TopoDS_Vertex aFirstNewVertex, aSecondNewVertex;
// tolerance of vertices will be corrected during future edge replacement
aBuilder.MakeVertex (aFirstNewVertex, aMeanFirstNewPnt, Precision::Confusion());
aBuilder.MakeVertex (aSecondNewVertex, aMeanSecondNewPnt, Precision::Confusion());
// fill in for building lacking edges
aVerticesForLackingEdgesBuilding.Append(std::make_pair(aFirstNewVertex, aSecondNewVertex));
// tool for fixing of vertex tolerance
Handle(ShapeFix_Edge) anEdgeFixer = new ShapeFix_Edge;
// update the shape to replace vertex with big tolerance by two new vertices
aSharingEdgesOfCurVertexIter.Initialize(aSharingEdgesOfCurVertex);
for (; aSharingEdgesOfCurVertexIter.More(); aSharingEdgesOfCurVertexIter.Next())
{
const TopoDS_Edge& aCurIntUnUpdatedEdge = TopoDS::Edge(aSharingEdgesOfCurVertexIter.Value());
// current updated edge
TopoDS_Edge aCurIntEdge = TopoDS::Edge(Context()->Apply(aCurIntUnUpdatedEdge));
// the copy of the current internal updated edge
TopoDS_Edge aModifedEdge = TopoDS::Edge(Context()->Apply(aCurIntUnUpdatedEdge));
// take first sharing face
const TopTools_ListOfShape& aSharingFacesOfCurIntEdge = anEdgeFacesMap.FindFromKey (aCurIntUnUpdatedEdge);
const TopoDS_Face& aCurIntFace = TopoDS::Face(aSharingFacesOfCurIntEdge.First());
TopoDS_Iterator aVertIterOfCurIntEdge(aCurIntEdge);
for (; aVertIterOfCurIntEdge.More(); aVertIterOfCurIntEdge.Next())
{
const TopoDS_Vertex& aCurVertexOfCurIntEdge = TopoDS::Vertex(aVertIterOfCurIntEdge.Value());
if (!aCurVertexOfCurIntEdge.IsSame(aCurVertex))
continue;
// replace the current vertex of the current internal edge by couple of new vertices
aModifedEdge = ReplaceVertex(aCurVertexOfCurIntEdge, aModifedEdge,
aCurIntFace, aFirstPntList,
aFirstNewVertex, aSecondNewVertex);
// increase tolerance of vertices of the modified
// edge if the ones don't cover the tolerance
// of the modified edge
anEdgeFixer->FixVertexTolerance(aModifedEdge);
}
// update the context
Context()->Replace(aCurIntEdge, aModifedEdge);
}
}
// apply the changes containing all replacements with vertices
myRecoveredShape = Context()->Apply(myRecoveredShape);
// add lacking edges into the modified shape (it doesn't contain vertices with big tolerance already)
TopTools_IndexedDataMapOfShapeListOfShape anUpdatedVertexWiresMap, anUpdatedWireFacesMap;
TopExp::MapShapesAndAncestors(myRecoveredShape, TopAbs_VERTEX, TopAbs_WIRE, anUpdatedVertexWiresMap);
TopExp::MapShapesAndAncestors(myRecoveredShape, TopAbs_WIRE, TopAbs_FACE, anUpdatedWireFacesMap);
NCollection_List< std::pair<TopoDS_Vertex, TopoDS_Vertex> >::Iterator
aVerticesForLackingEdgesIter(aVerticesForLackingEdgesBuilding);
// run through all pairs of new vertices to add lacking edge between them
for (; aVerticesForLackingEdgesIter.More(); aVerticesForLackingEdgesIter.Next())
{
const TopoDS_Vertex& aFirstNewVertex = aVerticesForLackingEdgesIter.Value().first;
const TopoDS_Vertex& aSecondNewVertex = aVerticesForLackingEdgesIter.Value().second;
// wires share the first new vertex
if (!anUpdatedVertexWiresMap.Contains(aFirstNewVertex))
continue;
const TopTools_ListOfShape& aSharingWiresOfFirstNewVertex =
anUpdatedVertexWiresMap.FindFromKey (aFirstNewVertex);
// wires share the second new vertex
if (!anUpdatedVertexWiresMap.Contains(aSecondNewVertex))
continue;
const TopTools_ListOfShape& aSharingWiresOfSecondNewVertex =
anUpdatedVertexWiresMap.FindFromKey (aSecondNewVertex);
// seek the intersection of two lists of sharing wires
TopTools_ListIteratorOfListOfShape anIterOfFirstWireList(aSharingWiresOfFirstNewVertex);
TopTools_ListOfShape anIntersectOfTwoLists;
for (; anIterOfFirstWireList.More(); anIterOfFirstWireList.Next())
{
TopTools_ListIteratorOfListOfShape anIterOfSecondWireList(aSharingWiresOfSecondNewVertex);
for (; anIterOfSecondWireList.More(); anIterOfSecondWireList.Next())
{
if (anIterOfFirstWireList.Value().IsSame(anIterOfSecondWireList.Value()))
anIntersectOfTwoLists.Append(anIterOfFirstWireList.Value());
}
}
// tool for fixing of vertex tolerance to cover edge tolerance that contains this vertex
Handle(ShapeFix_Edge) anEdgeFixer = new ShapeFix_Edge;
TopoDS_Edge aLackingEdge;
BRep_Builder aBuilder;
// add lacking edge to each intersected wire by replacing one their edge
TopTools_ListIteratorOfListOfShape anIterOfIntersetionList(anIntersectOfTwoLists);
for (; anIterOfIntersetionList.More(); anIterOfIntersetionList.Next())
{
const TopoDS_Wire& aCurWire = TopoDS::Wire(anIterOfIntersetionList.Value());
// faces of doesn't updated wire
const TopTools_ListOfShape& aSharingFacesOfCurWire =
anUpdatedWireFacesMap.FindFromKey (aCurWire);
if (aSharingFacesOfCurWire.Extent() == 0)
continue;
// _first_ found face containing the current wire
const TopoDS_Face& aCurFace = TopoDS::Face(aSharingFacesOfCurWire.First());
TopLoc_Location aLocation;
Handle(Geom_Surface) aCurSurf = BRep_Tool::Surface (aCurFace, aLocation);
TopoDS_Wire anUpdatedCurWire = TopoDS::Wire(Context()->Apply(aCurWire));
// seek 2d points (from doesn't updated wire) for 2d pcurve building
gp_Pnt2d aFirst2D, aSecond2D;
ConvertLackingVerticesTo2D(aCurWire, aCurFace, aFirstNewVertex, aSecondNewVertex, aFirst2D, aSecond2D);
// create 2d pcurve for lacking edge
const Handle(Geom2d_BSplineCurve)& aBSplineLackingCurve2D =
MakeBSplineLackingCurve2D(aFirst2D, aSecond2D);
if (aLackingEdge.IsNull())
aLackingEdge = BRepBuilderAPI_MakeEdge(aBSplineLackingCurve2D, aCurSurf, aFirstNewVertex, aSecondNewVertex);
// add pcurve to the lacking edge
aBuilder.UpdateEdge(aLackingEdge, aBSplineLackingCurve2D, aCurSurf, aLocation,
BRep_Tool::Tolerance(aLackingEdge));
// set orientation of the lacking edge
TopAbs_Orientation anOrientOfLackingEdge = TopAbs_FORWARD;
for (TopoDS_Iterator anEdgeIter(aCurWire); anEdgeIter.More(); anEdgeIter.Next())
{
const TopoDS_Edge& aCurIntEdge = TopoDS::Edge(anEdgeIter.Value());
if (aFirstNewVertex.IsSame(TopExp::FirstVertex(aCurIntEdge)))
{
if (aCurIntEdge.Orientation() == TopAbs_FORWARD)
anOrientOfLackingEdge = TopAbs_REVERSED;
else
anOrientOfLackingEdge = TopAbs_FORWARD;
break;
}
else if (aFirstNewVertex.IsSame(TopExp::LastVertex(aCurIntEdge)))
{
if (aCurIntEdge.Orientation() == TopAbs_FORWARD)
anOrientOfLackingEdge = TopAbs_FORWARD;
else
anOrientOfLackingEdge = TopAbs_REVERSED;
break;
}
}
aLackingEdge = TopoDS::Edge(aLackingEdge.Oriented(anOrientOfLackingEdge));
// add lacking edge to current wire
anUpdatedCurWire.Free(Standard_True);
aBuilder.Add(anUpdatedCurWire, aLackingEdge);
Context()->Replace(aCurWire, anUpdatedCurWire);
}
BRepLib::BuildCurve3d(aLackingEdge);
BRepLib::SameParameter(aLackingEdge, 1.e-5, Standard_True);
}
myRecoveredShape = Context()->Apply(myRecoveredShape);
myStatus = ShapeExtend::EncodeStatus ( ShapeExtend_OK );
}
//=======================================================================
//function : ReplaceVertex
//purpose : replace the input vertex by couple of new ones
//=======================================================================
TopoDS_Edge ShapeFix_LackingEdgeRecover::ReplaceVertex(const TopoDS_Vertex& theVert /*theBeingReplacedVertex*/,
const TopoDS_Edge& theEdge /*theBeingReplacedEdge */,
const TopoDS_Face& theFace,
const TColgp_SequenceOfPnt&
theListOfFirstPnt,
const TopoDS_Vertex& theFirstVertex,
const TopoDS_Vertex& theSecondVertex) const
{
Standard_Real aPFirstParamOfEdge, aPLastParamOfEdge;
Handle(Geom2d_Curve) aPCurveOfCurIntEdge =
BRep_Tool::CurveOnSurface (theEdge, theFace, aPFirstParamOfEdge, aPLastParamOfEdge);
TopAbs_Orientation anOrientOfVert = theVert.Orientation();
// seek the end of pcurve that shares the input vertex
gp_Pnt2d aBeingSoughtPnt2D = ConvertTo2D(theEdge, theVert, aPCurveOfCurIntEdge,
aPFirstParamOfEdge, aPLastParamOfEdge);
TopLoc_Location aLocation;
Handle(Geom_Surface) aSurf = BRep_Tool::Surface (theFace, aLocation);
// convert the found end of pcurve to point in 3D space
gp_Pnt aBeingSoughtPnt;
aSurf->D0(aBeingSoughtPnt2D.X(), aBeingSoughtPnt2D.Y(), aBeingSoughtPnt);
// seek what list contains found 3D point
Standard_Boolean anIsBeingSoughtPntInFirstList = Standard_False;
Standard_Integer aCurIndex = 1;
for (; aCurIndex <= theListOfFirstPnt.Length() && !anIsBeingSoughtPntInFirstList; aCurIndex++)
if (aBeingSoughtPnt.Distance(theListOfFirstPnt.Value(aCurIndex)) <= Precision::Confusion())
anIsBeingSoughtPntInFirstList = Standard_True;
// choose what vertex in the edge will be replaced taking into account found
// list containing this found 3d point
TopoDS_Vertex aBeingSoughtVertex;
if (anIsBeingSoughtPntInFirstList)
aBeingSoughtVertex = TopoDS::Vertex(theFirstVertex.Oriented(anOrientOfVert));
else
aBeingSoughtVertex = TopoDS::Vertex(theSecondVertex.Oriented(anOrientOfVert));
TopoDS_Edge aModifiedEdge;
ShapeBuild_Edge anEdgeBuilder;
// replace the vertex in the edge by chosen vertex
if (anOrientOfVert == TopAbs_FORWARD)
aModifiedEdge = anEdgeBuilder.CopyReplaceVertices(theEdge, aBeingSoughtVertex, TopoDS_Vertex());
else
aModifiedEdge = anEdgeBuilder.CopyReplaceVertices(theEdge, TopoDS_Vertex(), aBeingSoughtVertex);
return aModifiedEdge;
}
//=======================================================================
//function : IsWireStrip
//purpose : find out wire is strip or not
//=======================================================================
Standard_Boolean ShapeFix_LackingEdgeRecover::IsWireStrip(const TopoDS_Wire& theWire,
const TopoDS_Face& theFace,
const TopoDS_Vertex& theVertex,
gp_Pnt& theFirstPnt, gp_Pnt& theSecondPnt) const
{
// if the wide of the wire projection in parametric space of the face
// on vector (which is formed by the first and second input points; theirs analogues in
// parametric space of the face) will be less than this parameter - aStripRation
// then wire is detected as a strip
Standard_Real aStripRatio = 2.0;
// number of equidistant points on each edge for wire projection
// in parametric space on the vector that was described previously
Standard_Integer aPntNbPerEdgeForProj = 10;
// the analogues of the first and second points in parametric space of the face
gp_Pnt2d aPFirst2D, aPSecond2D;
// the wire is explored by BRepTools_WireExplorer and it is
// guaranteed that edges will be SEQUENCIALLY connected
Standard_Boolean isNOTExpByBRepTools_WireExplorer = Standard_False;
Handle(ShapeExtend_WireData) anEdgeExp =
new ShapeExtend_WireData(theWire, isNOTExpByBRepTools_WireExplorer);
Standard_Integer aStartIndex = 1; // start index of ShapeExtend_WireData
Standard_Integer anEndIndex = anEdgeExp->NbEdges();
if (anEndIndex == 0) // the WIRE IS EMPTY
return Standard_False;
// run through all edges and seek couple of edges which share the vertex
Standard_Integer anEdgeIndex, anEdgeIndex_Prev, anEdgeIndex_Next;
for (anEdgeIndex = aStartIndex; anEdgeIndex <= anEndIndex; anEdgeIndex++)
{
// index of previous edge
if (anEdgeIndex == aStartIndex) anEdgeIndex_Prev = anEndIndex;
else anEdgeIndex_Prev = anEdgeIndex-1;
// index of next element
if (anEdgeIndex == anEndIndex) anEdgeIndex_Next = aStartIndex;
else anEdgeIndex_Next = anEdgeIndex+1;
const TopoDS_Edge& aCurEdge = anEdgeExp->Edge(anEdgeIndex);
TopoDS_Vertex aCurFirstVertex = TopExp::FirstVertex(aCurEdge);
TopoDS_Vertex aCurLastVertex = TopExp::LastVertex(aCurEdge);
Standard_Boolean anIsFirstBelong = theVertex.IsSame(aCurFirstVertex);
Standard_Boolean anIsLastBelong = theVertex.IsSame(aCurLastVertex);
if (!anIsFirstBelong && !anIsLastBelong)
continue;
//int todo_investigate_degenerated_edge;
Standard_Real aPFirstParamOfCurEdge, aPLastParamOfCurEdge;
Handle(Geom2d_Curve) aPCurveOfCurEdge =
BRep_Tool::CurveOnSurface (aCurEdge, theFace, aPFirstParamOfCurEdge, aPLastParamOfCurEdge);
if (anIsFirstBelong && anIsLastBelong) // both ends of current edge belong to the vertex
{
aPCurveOfCurEdge->D0(aPFirstParamOfCurEdge, aPFirst2D);
aPCurveOfCurEdge->D0(aPLastParamOfCurEdge, aPSecond2D);
}
else
{
if (anIsFirstBelong) // first end of current edge
aPCurveOfCurEdge->D0(aPFirstParamOfCurEdge, aPFirst2D);
else if (anIsLastBelong) // last end of current edge
aPCurveOfCurEdge->D0(aPLastParamOfCurEdge, aPFirst2D);
// is second edge nether next edge in the sequence or previous?
TopAbs_Orientation aCurEdgeOrient = aCurEdge.Orientation();
Standard_Boolean anIsSecondANextEdge =
(aCurEdgeOrient == TopAbs_FORWARD && anIsLastBelong) ||
(aCurEdgeOrient == TopAbs_REVERSED && anIsFirstBelong);
Standard_Integer anIndexOfEdgeWithSecondPnt =
(anIsSecondANextEdge ? anEdgeIndex_Next : anEdgeIndex_Prev);
//
const TopoDS_Edge& anEdgeWithSecondPnt = anEdgeExp->Edge(anIndexOfEdgeWithSecondPnt);
TopAbs_Orientation anOrientOfEdgeWithSecondPnt = anEdgeWithSecondPnt.Orientation();
Standard_Boolean isFirstVertexOfEdgeWithSecondPnt = Standard_True;
if (anIsSecondANextEdge) // next edge in the edge sequence
{
if (anOrientOfEdgeWithSecondPnt == TopAbs_FORWARD)
isFirstVertexOfEdgeWithSecondPnt = Standard_True;
else
isFirstVertexOfEdgeWithSecondPnt = Standard_False;
}
else // previous edge in sequence in the edge sequence
{
if (anOrientOfEdgeWithSecondPnt == TopAbs_FORWARD)
isFirstVertexOfEdgeWithSecondPnt = Standard_False;
else
isFirstVertexOfEdgeWithSecondPnt = Standard_True;
}
Standard_Real aFirstParamOfEdgeWithSecondPnt, aLastParamOfEdgeWithSecondPnt;
Handle(Geom2d_Curve) aPCurveOfEdgeWithSecondPnt =
BRep_Tool::CurveOnSurface (anEdgeWithSecondPnt, theFace,
aFirstParamOfEdgeWithSecondPnt,
aLastParamOfEdgeWithSecondPnt);
if (isFirstVertexOfEdgeWithSecondPnt)
aPCurveOfEdgeWithSecondPnt->D0(aFirstParamOfEdgeWithSecondPnt, aPSecond2D);
else
aPCurveOfEdgeWithSecondPnt->D0(aLastParamOfEdgeWithSecondPnt, aPSecond2D);
}
if (aPFirst2D.Distance(aPSecond2D) <= Precision::Confusion())
continue;
// project points of edges on aPVec2D
Standard_Real aProjLength = ProjectTo2DVector(anEdgeExp, theFace, aPntNbPerEdgeForProj, aPFirst2D, aPSecond2D);
gp_Vec2d aPVec2D(aPFirst2D, aPSecond2D);
if (aProjLength <= aStripRatio*aPVec2D.Magnitude())
{
TopLoc_Location aLocation;
Handle(Geom_Surface) aSurf = BRep_Tool::Surface (theFace, aLocation);
aSurf->D0(aPFirst2D.X() , aPFirst2D.Y(), theFirstPnt);
aSurf->D0(aPSecond2D.X(), aPSecond2D.Y(), theSecondPnt);
return Standard_True;
}
}
return Standard_False;
}
//=======================================================================
//function : ConvertLackingVerticesTo2D
//purpose :
//=======================================================================
void ShapeFix_LackingEdgeRecover::ConvertLackingVerticesTo2D(const TopoDS_Wire& theWire,
const TopoDS_Face& theFace,
const TopoDS_Vertex& theFirstVertex,
const TopoDS_Vertex& theSecondVertex,
gp_Pnt2d& theFirstPnt2D,
gp_Pnt2d& theSecondPnt2D) const
{
Standard_Boolean aHasFirstBeenFound = Standard_False;
Standard_Boolean aHasSecondBeenFound = Standard_False;
TopoDS_Iterator anEdgeIter(theWire);
for (; anEdgeIter.More(); anEdgeIter.Next())
{
const TopoDS_Edge& aCurEdge = TopoDS::Edge(anEdgeIter.Value());
Standard_Real aPFirstParamOfCurEdge, aPLastParamOfCurEdge;
Handle(Geom2d_Curve) aCurCurve2D =
BRep_Tool::CurveOnSurface(aCurEdge, theFace, aPFirstParamOfCurEdge, aPLastParamOfCurEdge);
TopoDS_Iterator aVertexIter(aCurEdge);
for (; aVertexIter.More(); aVertexIter.Next())
{
const TopoDS_Vertex& aCurVertex = TopoDS::Vertex(aVertexIter.Value());
if (!aHasFirstBeenFound)
{
if (theFirstVertex.IsSame(aCurVertex))
{
aHasFirstBeenFound = Standard_True;
theFirstPnt2D = ConvertTo2D(aCurEdge, aCurVertex, aCurCurve2D,
aPFirstParamOfCurEdge, aPLastParamOfCurEdge);
}
}
if (!aHasSecondBeenFound)
{
if (theSecondVertex.IsSame(aCurVertex))
{
aHasSecondBeenFound = Standard_True;
theSecondPnt2D = ConvertTo2D(aCurEdge, aCurVertex, aCurCurve2D,
aPFirstParamOfCurEdge, aPLastParamOfCurEdge);
}
}
}
if (aHasFirstBeenFound && aHasSecondBeenFound)
break;
}
}
//=======================================================================
//function : MakeBSplineLackingCurve2D
//purpose :
//=======================================================================
Handle(Geom2d_BSplineCurve) ShapeFix_LackingEdgeRecover::MakeBSplineLackingCurve2D(
const gp_Pnt2d& theFirstPnt2D,
const gp_Pnt2d& theSecondPnt2D) const
{
TColgp_Array1OfPnt2d aPolesOfBSplineCurve (1, 2);
aPolesOfBSplineCurve(1).SetCoord(theFirstPnt2D.X(), theFirstPnt2D.Y());
aPolesOfBSplineCurve(2).SetCoord(theSecondPnt2D.X(), theSecondPnt2D.Y());
TColStd_Array1OfReal aKnotesOfBSplineCurve(1, 2);
aKnotesOfBSplineCurve(1) = 0.0;
aKnotesOfBSplineCurve(2) = 1.0;
TColStd_Array1OfInteger aMultiplicities (1, 2);
aMultiplicities(1) = 2;
aMultiplicities(2) = 2;
return new Geom2d_BSplineCurve(aPolesOfBSplineCurve, aKnotesOfBSplineCurve, aMultiplicities, 1, 0);
}
//=======================================================================
//function : ConvertTo2D
//purpose :
//=======================================================================
gp_Pnt2d ShapeFix_LackingEdgeRecover::ConvertTo2D(const TopoDS_Edge& theEdge,
const TopoDS_Vertex& theVertex,
const Handle(Geom2d_Curve)& theCurve2D,
const Standard_Real thePFirst,
const Standard_Real thePLast) const
{
gp_Pnt2d aPnt2d;
if (theEdge.Orientation() == TopAbs_FORWARD)
{
if (theVertex.Orientation() == TopAbs_FORWARD)
theCurve2D->D0(thePFirst, aPnt2d);
else
theCurve2D->D0(thePLast, aPnt2d);
}
else
{
if (theVertex.Orientation() == TopAbs_FORWARD)
theCurve2D->D0(thePLast, aPnt2d);
else
theCurve2D->D0(thePFirst, aPnt2d);
}
return aPnt2d;
}
//=======================================================================
//function : ProjectTo2DVector
//purpose :
//=======================================================================
Standard_Real ShapeFix_LackingEdgeRecover::ProjectTo2DVector(const Handle(ShapeExtend_WireData)& theWireData,
const TopoDS_Face& theFace,
const Standard_Real thePntNbPerEdgeForProj,
const gp_Pnt2d& thePFirst2D,
const gp_Pnt2d& thePSecond2D) const
{
gp_Vec2d aPVec2D(thePFirst2D, thePSecond2D);
Standard_Integer aStartIndex = 1; // start index of ShapeExtend_WireData
Standard_Integer anEndIndex = theWireData->NbEdges();
// project points of edges on aPVec2D
Standard_Real aMaxWireValue = -Precision::Infinite();
Standard_Real aMinWireValue = Precision::Infinite();
Standard_Integer aCurEdgeIndex = aStartIndex;
for (; aCurEdgeIndex <= anEndIndex; aCurEdgeIndex++)
{
Standard_Real aPFirstParamOfIntCurEdge, aPLastParamOfIntCurEdge;
Handle(Geom2d_Curve) aPCurveOfIntCurEdge =
BRep_Tool::CurveOnSurface (theWireData->Edge(aCurEdgeIndex), theFace,
aPFirstParamOfIntCurEdge, aPLastParamOfIntCurEdge);
// split the curve of the current edge on aPntNbPerEdgeForProj parts
Standard_Integer aCurStep = 0;
Standard_Real aPCurParam = aPFirstParamOfIntCurEdge;
Standard_Real aStepSize = (aPLastParamOfIntCurEdge - aPFirstParamOfIntCurEdge)/thePntNbPerEdgeForProj;
while (aPCurParam <= aPLastParamOfIntCurEdge)
{
aPCurParam = aPFirstParamOfIntCurEdge + aCurStep*aStepSize;
gp_Pnt2d aPCur2D;
aPCurveOfIntCurEdge->D0(aPCurParam, aPCur2D);
// project current parametric point on the vector (by scalar product)
Standard_Real aStepFromPFirst2D = aPVec2D*gp_Vec2d(thePFirst2D, aPCur2D) / aPVec2D.Magnitude();
aMaxWireValue = Max(aMaxWireValue, aStepFromPFirst2D);
aMinWireValue = Min(aMinWireValue, aStepFromPFirst2D);
aCurStep++;
}
}
return Abs(aMaxWireValue - aMinWireValue);
}