From 13be7365163355aa8f28e08ba1fadbfa21c1a50f Mon Sep 17 00:00:00 2001 From: ibs Date: Thu, 17 Oct 2013 15:16:32 +0400 Subject: [PATCH] 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; --- src/SWDRAW/SWDRAW_ShapeFix.cxx | 51 +- src/ShapeFix/ShapeFix.cdl | 14 +- src/ShapeFix/ShapeFix.cxx | 21 + src/ShapeFix/ShapeFix_LackingEdgeRecover.cdl | 113 +++ src/ShapeFix/ShapeFix_LackingEdgeRecover.cxx | 795 +++++++++++++++++++ 5 files changed, 990 insertions(+), 4 deletions(-) create mode 100644 src/ShapeFix/ShapeFix_LackingEdgeRecover.cdl create mode 100644 src/ShapeFix/ShapeFix_LackingEdgeRecover.cxx diff --git a/src/SWDRAW/SWDRAW_ShapeFix.cxx b/src/SWDRAW/SWDRAW_ShapeFix.cxx index 8dc75e556c..8947012340 100644 --- a/src/SWDRAW/SWDRAW_ShapeFix.cxx +++ b/src/SWDRAW/SWDRAW_ShapeFix.cxx @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -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.]", diff --git a/src/ShapeFix/ShapeFix.cdl b/src/ShapeFix/ShapeFix.cdl index 87e9f83ddd..fc971d97da 100644 --- a/src/ShapeFix/ShapeFix.cdl +++ b/src/ShapeFix/ShapeFix.cdl @@ -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; diff --git a/src/ShapeFix/ShapeFix.cxx b/src/ShapeFix/ShapeFix.cxx index 816ccc3520..c48d4d5bad 100644 --- a/src/ShapeFix/ShapeFix.cxx +++ b/src/ShapeFix/ShapeFix.cxx @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -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(); +} diff --git a/src/ShapeFix/ShapeFix_LackingEdgeRecover.cdl b/src/ShapeFix/ShapeFix_LackingEdgeRecover.cdl new file mode 100644 index 0000000000..76e6bffe63 --- /dev/null +++ b/src/ShapeFix/ShapeFix_LackingEdgeRecover.cdl @@ -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
+ -- 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; diff --git a/src/ShapeFix/ShapeFix_LackingEdgeRecover.cxx b/src/ShapeFix/ShapeFix_LackingEdgeRecover.cxx new file mode 100644 index 0000000000..787829071b --- /dev/null +++ b/src/ShapeFix/ShapeFix_LackingEdgeRecover.cxx @@ -0,0 +1,795 @@ +// File: ShapeFix_LackingEdgeRecover.cxx +// Created: 10.10.2013 +// Author: Briginas Ivan + +#include + +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include + +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 > aVerticesForLackingEdgesBuilding; + typedef NCollection_DataMap 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 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 >::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); +} \ No newline at end of file