From: jgv Date: Mon, 14 Aug 2017 11:48:07 +0000 (+0300) Subject: Implementation of the algorithm for replacing faces in shape with new faces based... X-Git-Url: http://git.dev.opencascade.org/gitweb/?a=commitdiff_plain;h=refs%2Fheads%2FCR0-winwerth_5;p=occt-copy.git Implementation of the algorithm for replacing faces in shape with new faces based on other surfaces - BRepOffsetAPI_PatchFaces. The algorithm runs the steps similar to 3d Offset algorithm for Join type Intersection (intersection of the faces with neighbors for trimming of the faces by the adjacent faces). Test cases for new functionality. --- diff --git a/src/BRepOffset/BRepOffset_Tool.cxx b/src/BRepOffset/BRepOffset_Tool.cxx index 638b476ae6..da2d9b0a11 100644 --- a/src/BRepOffset/BRepOffset_Tool.cxx +++ b/src/BRepOffset/BRepOffset_Tool.cxx @@ -2817,7 +2817,7 @@ static Standard_Boolean EnlargeGeometry(Handle(Geom_Surface)& S, const Standard_Boolean GlobalEnlargeVfirst, const Standard_Boolean GlobalEnlargeVlast) { - const Standard_Real coeff = 4.; + const Standard_Real coeff = 2.; const Standard_Real TolApex = 1.e-5; Standard_Boolean SurfaceChange = Standard_False; @@ -3200,7 +3200,8 @@ Standard_Boolean BRepOffset_Tool::EnLargeFace const Standard_Boolean UpdatePCurve, const Standard_Boolean enlargeU, const Standard_Boolean enlargeVfirst, - const Standard_Boolean enlargeVlast) + const Standard_Boolean enlargeVlast, + const Standard_Boolean UseInfini) { //--------------------------- // extension de la geometrie. @@ -3223,8 +3224,20 @@ Standard_Boolean BRepOffset_Tool::EnLargeFace } S->Bounds (US1,US2,VS1,VS2); - UU1 = VV1 = - infini; - UU2 = VV2 = infini; + if (UseInfini) + { + UU1 = VV1 = - infini; + UU2 = VV2 = infini; + } + else + { + Standard_Real FaceDU = UF2 - UF1; + Standard_Real FaceDV = VF2 - VF1; + UU1 = UF1 - FaceDU; + UU2 = UF2 + FaceDU; + VV1 = VF1 - FaceDV; + VV2 = VF2 + FaceDV; + } if (CanExtentSurface) { SurfaceChange = EnlargeGeometry( S, UU1, UU2, VV1, VV2, isVV1degen, isVV2degen, UF1, UF2, VF1, VF2, diff --git a/src/BRepOffset/BRepOffset_Tool.hxx b/src/BRepOffset/BRepOffset_Tool.hxx index b0609d5506..67e764a012 100644 --- a/src/BRepOffset/BRepOffset_Tool.hxx +++ b/src/BRepOffset/BRepOffset_Tool.hxx @@ -92,8 +92,15 @@ public: //! if is TRUE, update the pcurves of the //! edges of on the new surface.if the surface has been changed, //! Returns True if The Surface of has changed. - Standard_EXPORT static Standard_Boolean EnLargeFace (const TopoDS_Face& F, TopoDS_Face& NF, const Standard_Boolean ChangeGeom, const Standard_Boolean UpDatePCurve = Standard_False, const Standard_Boolean enlargeU = Standard_True, const Standard_Boolean enlargeVfirst = Standard_True, const Standard_Boolean enlargeVlast = Standard_True); - + Standard_EXPORT static Standard_Boolean EnLargeFace (const TopoDS_Face& F, + TopoDS_Face& NF, + const Standard_Boolean ChangeGeom, + const Standard_Boolean UpDatePCurve = Standard_False, + const Standard_Boolean enlargeU = Standard_True, + const Standard_Boolean enlargeVfirst = Standard_True, + const Standard_Boolean enlargeVlast = Standard_True, + const Standard_Boolean UseInfini = Standard_True); + Standard_EXPORT static void ExtentFace (const TopoDS_Face& F, TopTools_DataMapOfShapeShape& ConstShapes, TopTools_DataMapOfShapeShape& ToBuild, const TopAbs_State Side, const Standard_Real TolConf, TopoDS_Face& NF); //! Via the wire explorer store in for diff --git a/src/BRepOffsetAPI/BRepOffsetAPI_PatchFaces.cxx b/src/BRepOffsetAPI/BRepOffsetAPI_PatchFaces.cxx new file mode 100644 index 0000000000..cf1be4cd4e --- /dev/null +++ b/src/BRepOffsetAPI/BRepOffsetAPI_PatchFaces.cxx @@ -0,0 +1,781 @@ +// Created on: 2012-08-06 +// Created by: jgv@ROLEX +// Copyright (c) 2012-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 +#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 + + +static TopoDS_Edge MakeNewEdgeWithOldPcurvesOnNewSurfaces(const TopoDS_Edge& theEdge, + const TopoDS_Face& theOldFace1, + const TopoDS_Face& theNewFace1, + const TopoDS_Face& theOldFace2, + const TopoDS_Face& theNewFace2) +{ + TopoDS_Edge aNewEdge; + Standard_Real fpar, lpar; + BRep_Builder BB; + + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(theEdge, fpar, lpar); + aNewEdge = BRepLib_MakeEdge(aCurve, aCurve->FirstParameter(), aCurve->LastParameter()); //??? + TopoDS_Vertex V1, V2; + TopExp::Vertices(aNewEdge, V1, V2); + aNewEdge.Free(Standard_True); + BB.Remove(aNewEdge, V1); + BB.Remove(aNewEdge, V2); + + Standard_Real Etol = BRep_Tool::Tolerance(theEdge); + Handle(Geom2d_Curve) aPCurve1 = BRep_Tool::CurveOnSurface(theEdge, theOldFace1, fpar, lpar); + BB.UpdateEdge(aNewEdge, aPCurve1, theNewFace1, Etol); + Handle(Geom2d_Curve) aPCurve2 = BRep_Tool::CurveOnSurface(theEdge, theOldFace2, fpar, lpar); + BB.UpdateEdge(aNewEdge, aPCurve2, theNewFace2, Etol); + + return aNewEdge; +} + +static void UpdateEdgeByProjectionOfPCurve(TopoDS_Edge& anEdge, + const TopoDS_Face& aNewFace, + const TopoDS_Face& aBoundedNewFace) +{ + BRep_Builder BB; + Standard_Real fpar, lpar; + + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge,fpar,lpar); + + Handle(Geom_Surface) NewSurf = BRep_Tool::Surface(aNewFace); + Handle(ShapeAnalysis_Surface) SAS = new ShapeAnalysis_Surface(NewSurf); + ShapeConstruct_ProjectCurveOnSurface aToolProj; + aToolProj.Init(SAS, Precision::Confusion()); + Handle(Geom2d_Curve) NewPCurve; + aToolProj.Perform(aCurve,fpar,lpar,NewPCurve); + Standard_Real TolReached = SAS->Gap(); + //BB.UpdateEdge(anEdge, NullPCurve, aFace, 0.); + BB.UpdateEdge(anEdge, NewPCurve, aBoundedNewFace, TolReached); + TopoDS_Vertex V1, V2; + TopExp::Vertices(anEdge, V1, V2); + BB.UpdateVertex(V1, TolReached); + BB.UpdateVertex(V2, TolReached); +} + +static void ProjectVertexOnNewEdge(const TopoDS_Vertex& theVertex, + const TopoDS_Edge& theEdge, + const TopoDS_Edge& theNewEdge, + Standard_Real& theParam, + gp_Pnt& thePnt, + Standard_Real& theTolReached) +{ + Standard_Real ParamOnEdge = BRep_Tool::Parameter(theVertex, theEdge); + BRepAdaptor_Curve BAcurve(theEdge); + BRepAdaptor_Curve BAnewcurve(theNewEdge); + gp_Pnt PointOnEdge = BAcurve.Value(ParamOnEdge); + Extrema_ExtPC Projector(PointOnEdge, BAnewcurve); + Standard_Real Param[4], dist[4]; + gp_Pnt Pnt[4]; + Param[1] = BAnewcurve.FirstParameter(); + Param[2] = BAnewcurve.LastParameter(); + Projector.TrimmedSquareDistances(dist[1], dist[2], Pnt[1], Pnt[2]); + dist[3] = RealLast(); + if (Projector.IsDone() && Projector.NbExt() > 0) + { + Standard_Integer imin = 1; + for (Standard_Integer i = 2; i <= Projector.NbExt(); i++) + if (Projector.SquareDistance(i) < Projector.SquareDistance(imin)) + imin = i; + Param[3] = Projector.Point(imin).Parameter(); + dist[3] = Projector.SquareDistance(imin); + Pnt[3] = Projector.Point(imin).Value(); + } + + Standard_Integer imin = 1; + for (Standard_Integer i = 2; i <= 3; i++) + if (dist[i] < dist[imin]) + imin = i; + + theParam = Param[imin]; + thePnt = Pnt[imin]; + theTolReached = sqrt(dist[imin]); +} + +static TopoDS_Edge GetGeneratedEdge(const TopoDS_Edge& anEdge, + const TopoDS_Face& aFace, + const TopoDS_Face& aNewFace) +{ + TopoDS_Edge aNewEdge; + + TopExp_Explorer Explo(aFace, TopAbs_EDGE); + TopExp_Explorer ExploNew(aNewFace, TopAbs_EDGE); + for (; Explo.More(); Explo.Next(),ExploNew.Next()) + { + const TopoDS_Shape& EdgeInFace = Explo.Current(); + //const TopoDS_Shape& EdgeInNewFace = ExploNew.Current(); + if (anEdge == EdgeInFace) + { + aNewEdge = TopoDS::Edge(ExploNew.Current()); + break; + } + } + + TopoDS_Vertex V1, V2; + TopExp::Vertices(aNewEdge, V1, V2); + BRep_Builder BB; + aNewEdge.Free(Standard_True); + BB.Remove(aNewEdge, V1); + BB.Remove(aNewEdge, V2); + return aNewEdge; +} + +static TopAbs_Orientation OrientationInEdge(const TopoDS_Vertex& theVertex, + const TopoDS_Edge& theEdge) +{ + TopoDS_Vertex V1, V2; + TopExp::Vertices(theEdge, V1, V2); + if (theVertex.IsSame(V1)) + return TopAbs_FORWARD; + + return TopAbs_REVERSED; +} + +static Standard_Boolean EdgeContains(const TopoDS_Edge& theEdge, + const TopoDS_Vertex& theVertex) +{ + TopoDS_Iterator ite(theEdge); + for (; ite.More(); ite.Next()) + if (theVertex.IsSame(ite.Value())) + return Standard_True; + + return Standard_False; +} + + +static Standard_Boolean IsTangentFaces(const TopoDS_Edge& theEdge, + const TopoDS_Face& theFace1, + const TopoDS_Face& theFace2, + const GeomAbs_Shape Order) +{ + if (Order == GeomAbs_G1 && + BRep_Tool::Continuity( theEdge, theFace1, theFace2 ) != GeomAbs_C0) + return Standard_True; + + Standard_Real TolC0 = Max(0.001, 1.5*BRep_Tool::Tolerance(theEdge)); + + Standard_Real aFirst; + Standard_Real aLast; + +// Obtaining of pcurves of edge on two faces. + const Handle(Geom2d_Curve) aC2d1 = BRep_Tool::CurveOnSurface + (theEdge, theFace1, aFirst, aLast); + const Handle(Geom2d_Curve) aC2d2 = BRep_Tool::CurveOnSurface + (theEdge, theFace2, aFirst, aLast); + if (aC2d1.IsNull() || aC2d2.IsNull()) + return Standard_False; + +// Obtaining of two surfaces from adjacent faces. + Handle(Geom_Surface) aSurf1 = BRep_Tool::Surface(theFace1); + Handle(Geom_Surface) aSurf2 = BRep_Tool::Surface(theFace2); + + if (aSurf1.IsNull() || aSurf2.IsNull()) + return Standard_False; + +// Computation of the number of samples on the edge. + BRepAdaptor_Surface aBAS1(theFace1); + BRepAdaptor_Surface aBAS2(theFace2); + Handle(BRepAdaptor_HSurface) aBAHS1 = new BRepAdaptor_HSurface(aBAS1); + Handle(BRepAdaptor_HSurface) aBAHS2 = new BRepAdaptor_HSurface(aBAS2); + Handle(BRepTopAdaptor_TopolTool) aTool1 = new BRepTopAdaptor_TopolTool(aBAHS1); + Handle(BRepTopAdaptor_TopolTool) aTool2 = new BRepTopAdaptor_TopolTool(aBAHS2); + Standard_Integer aNbSamples1 = aTool1->NbSamples(); + Standard_Integer aNbSamples2 = aTool2->NbSamples(); + const Standard_Integer aNbSamplesMax = 23; + Standard_Integer aNbSamples = Min(aNbSamplesMax, Max(aNbSamples1, aNbSamples2)); + const Standard_Real aTolAngle = M_PI/18; + + +// Computation of the continuity. + Standard_Real aPar; + Standard_Real aDelta = (aLast - aFirst)/(aNbSamples - 1); + Standard_Integer i, nbNotDone = 0; + + for (i = 1, aPar = aFirst; i <= aNbSamples; i++, aPar += aDelta) { + if (i == aNbSamples) aPar = aLast; + + LocalAnalysis_SurfaceContinuity aCont(aC2d1, aC2d2, aPar, + aSurf1, aSurf2, Order, + 0.001, TolC0, aTolAngle, 0.1, 0.1); + if (!aCont.IsDone()) + { + nbNotDone++; + continue; + } + + if (Order == GeomAbs_G1) + { + if (!aCont.IsG1()) + return Standard_False; + } + else if (!aCont.IsG2()) + return Standard_False; + } + + if (nbNotDone == aNbSamples) + return Standard_False; + + return Standard_True; +} + +//======================================================================= +//function : BRepOffsetAPI_PatchFaces +//purpose : Constructor +//======================================================================= + +BRepOffsetAPI_PatchFaces::BRepOffsetAPI_PatchFaces(const TopoDS_Shape& theShape) +{ + myInitialShape = theShape; +} + +//======================================================================= +//function : SetOffsetFace +//purpose : +//======================================================================= +void BRepOffsetAPI_PatchFaces::AddPatchFace(const TopoDS_Face& theFace, + const TopoDS_Face& thePatchFace) +{ + // Check the orientation of the patch face and make + // it oriented the same way as original + TopoDS_Face aFace = TopoDS::Face(theFace.Oriented(TopAbs_FORWARD)); + TopoDS_Face aPatchFace = TopoDS::Face(thePatchFace.Oriented(TopAbs_FORWARD)); + + Handle(IntTools_Context) aCtx = new IntTools_Context; + Standard_Boolean bToReverse = BOPTools_AlgoTools::IsSplitToReverse(aFace, aPatchFace, aCtx); + TopoDS_Face anOrientedPatchFace = bToReverse ? TopoDS::Face(aPatchFace.Reversed()) : aPatchFace; + myFacePatchFace.Add(aFace, anOrientedPatchFace); +} + +//======================================================================= +//function : Build +//purpose : +//======================================================================= + +void BRepOffsetAPI_PatchFaces::Build() +{ + TopExp::MapShapesAndUniqueAncestors(myInitialShape, TopAbs_EDGE, TopAbs_FACE, myEFmap); + + //Draft filling of + for (Standard_Integer i = 1; i <= myFacePatchFace.Extent(); i++) + { + const TopoDS_Face& aFace = TopoDS::Face(myFacePatchFace.FindKey(i)); + const TopoDS_Shape& aPatchFace = myFacePatchFace(i); + myFaceNewFace.Add(aFace, aPatchFace); + TopExp_Explorer Explo(aFace, TopAbs_EDGE); + for (; Explo.More(); Explo.Next()) + { + const TopoDS_Edge& anEdge = TopoDS::Edge(Explo.Current()); + const TopTools_ListOfShape& Lfaces = myEFmap.FindFromKey(anEdge); + TopoDS_Face aNeighborFace = (aFace.IsSame(Lfaces.First()))? + TopoDS::Face(Lfaces.Last()) : TopoDS::Face(Lfaces.First()); + if (myFacePatchFace.Contains(aNeighborFace)) + continue; + if (myFaceNewFace.Contains(aNeighborFace)) + continue; + Standard_Boolean IsTangentEdge = IsTangentFaces(anEdge, aFace, aNeighborFace, GeomAbs_G1); + if (IsTangentEdge) + { + myTangentEdges.Add(anEdge); + continue; + } + + aNeighborFace.Orientation(TopAbs_FORWARD); + TopoDS_Face aNewFace; + BRepOffset_Tool::EnLargeFace(aNeighborFace, aNewFace, + Standard_True,Standard_True,Standard_True,Standard_True,Standard_True, + Standard_False); //not too big + myFaceNewFace.Add(aNeighborFace, aNewFace); + } + } + + //Make draft intersection edges: draft filling of + BRep_Builder BB; + TopTools_MapOfShape UpdatedConstEdges; + for (Standard_Integer i = 1; i <= myFaceNewFace.Extent(); i++) + { + TopoDS_Face aFace = TopoDS::Face(myFaceNewFace.FindKey(i)); + TopoDS_Face aNewFace = TopoDS::Face(myFaceNewFace(i)); + TopoDS_Face aBoundedNewFace; + if (myNewFaceBoundedFace.IsBound(aNewFace)) + aBoundedNewFace = TopoDS::Face(myNewFaceBoundedFace(aNewFace)); + else + { + aBoundedNewFace = TopoDS::Face(aNewFace.EmptyCopied()); + myNewFaceBoundedFace.Bind(aNewFace, aBoundedNewFace); + } + + TopoDS_Iterator itf(aFace); + for (; itf.More(); itf.Next()) + { + const TopoDS_Wire& aWire = TopoDS::Wire(itf.Value()); + TopoDS_Wire F_Wire = TopoDS::Wire(aWire.Oriented(TopAbs_FORWARD)); + BRepTools_WireExplorer wexp(F_Wire, aFace); + for (; wexp.More(); wexp.Next()) + { + TopoDS_Edge anEdge = wexp.Current(); + Standard_Boolean ToReverse = Standard_False; + TopoDS_Edge aNewEdge; + if (myEdgeNewEdge.IsBound(anEdge)) + //aNewEdge = TopoDS::Edge(myEdgeNewEdge(anEdge)); + continue; + + Handle(Geom2d_Curve) NullPCurve; + Standard_Real fpar, lpar; + + const TopTools_ListOfShape& Lfaces = myEFmap.FindFromKey(anEdge); + if (Lfaces.Extent() == 1) //seam edge + { + cout< smooth edge"< smooth edge"< + myFaceNewFace.Swap(myFaceNewFace.FindIndex(aNeighborFace), myFaceNewFace.Extent()); + myFaceNewFace.RemoveLast(); + + myTangentEdges.Add(anEdge); + UpdatedConstEdges.Add(anEdge); + } + else + { + aNewEdge = MakeNewEdgeWithOldPcurvesOnNewSurfaces(anEdge, + aFace, aBoundedNewFace, + aNeighborFace, aBoundedNewNeighborFace); + myEdgeNewEdge.Bind(anEdge.Oriented(TopAbs_FORWARD), aNewEdge); + } + continue; + } + TopoDS_Vertex V1, V2; + TopExp::Vertices(aNewEdge, V1, V2); + aNewEdge.Free(Standard_True); + BB.Remove(aNewEdge, V1); + BB.Remove(aNewEdge, V2); + aNewEdge.Orientation(TopAbs_FORWARD); + + //Make pcurves on new surfaces + Handle(Geom2d_Curve) PCurve1 = BRep_Tool::CurveOnSurface(aNewEdge, aNewFace, fpar, lpar); + BB.UpdateEdge(aNewEdge, NullPCurve, aNewFace, 0.); + BB.UpdateEdge(aNewEdge, PCurve1, aBoundedNewFace, 0.); + Handle(Geom2d_Curve) PCurve2 = BRep_Tool::CurveOnSurface(aNewEdge, aNewNeighborFace, fpar, lpar); + BB.UpdateEdge(aNewEdge, NullPCurve, aNewNeighborFace, 0.); + BB.UpdateEdge(aNewEdge, PCurve2, aBoundedNewNeighborFace, 0.); + + //Check orientation of new edge + BRepAdaptor_Curve BAcurve(anEdge); + BRepAdaptor_Curve BAnewcurve(aNewEdge); + gp_Pnt FirstPnt, FirstNewPnt; + gp_Vec DirOnCurve, DirOnNewCurve; + BAcurve.D1(BAcurve.FirstParameter(), FirstPnt, DirOnCurve); + Standard_Real ParamOnNewEdge = BAnewcurve.FirstParameter(); + Extrema_ExtPC Projector(FirstPnt, BAnewcurve); + if (!Projector.IsDone() || Projector.NbExt() == 0) + { + cout< 0) + { + Standard_Integer indmin = 1; + for (Standard_Integer ind = 2; ind <= Projector.NbExt(); ind++) + if (Projector.SquareDistance(ind) < Projector.SquareDistance(indmin)) + indmin = ind; + ParamOnNewEdge = Projector.Point(indmin).Parameter(); + } + BAnewcurve.D1(ParamOnNewEdge, FirstNewPnt, DirOnNewCurve); + Standard_Real ScalProd = DirOnCurve * DirOnNewCurve; + if (ScalProd < 0.) + ToReverse = Standard_True; + + myEdgeNewEdge.Bind(anEdge.Oriented(TopAbs_FORWARD), + (ToReverse)? aNewEdge.Oriented(TopAbs_REVERSED) : aNewEdge); + } //intersect + else //borders on constant face: change surface of pcurve on existing edge + { + Handle(Geom2d_Curve) aPCurve = BRep_Tool::CurveOnSurface(anEdge, aFace, fpar, lpar); + //BB.UpdateEdge(anEdge, NullPCurve, aFace, 0.); + BB.UpdateEdge(anEdge, aPCurve, aBoundedNewFace, 0.); + + aNewEdge = anEdge; + } + } //for (; wexp.More(); wexp.Next()) + } //for (; itf.More(); itf.Next()) + } //for (Standard_Integer i = 1; i <= myFaceNewFace.Extent(); i++) + + //Intersect edges and make new wires + for (Standard_Integer i = 1; i <= myFaceNewFace.Extent(); i++) + { + TopoDS_Face aFace = TopoDS::Face(myFaceNewFace.FindKey(i)); + TopoDS_Shape aNewFace = myFaceNewFace(i); + TopoDS_Face aBoundedNewFace = TopoDS::Face(myNewFaceBoundedFace(aNewFace)); + + TopoDS_Iterator itf(aFace); + for (; itf.More(); itf.Next()) + { + const TopoDS_Wire& aWire = TopoDS::Wire(itf.Value()); + TopAbs_Orientation aWireOr = aWire.Orientation(); + + TopoDS_Wire aNewWire; + BB.MakeWire(aNewWire); + + TopoDS_Wire F_Wire = TopoDS::Wire(aWire.Oriented(TopAbs_FORWARD)); + BRepTools_WireExplorer wexp(F_Wire, aFace); + TopoDS_Vertex CurVertex = wexp.CurrentVertex(); + TopoDS_Edge FirstEdge = wexp.Current(); + TopoDS_Edge FirstNewEdge = FirstEdge; + if (myOrientedEdgeNewEdge.IsBound(FirstEdge)) + FirstNewEdge = TopoDS::Edge(myOrientedEdgeNewEdge(FirstEdge)); + else if (myEdgeNewEdge.IsBound(FirstEdge)) + FirstNewEdge = TopoDS::Edge(myEdgeNewEdge(FirstEdge)); + TopoDS_Edge CurEdge, PrevEdge = FirstEdge; + TopoDS_Edge CurNewEdge, PrevNewEdge = FirstNewEdge; + wexp.Next(); + if (!wexp.More() && //only one edge in wire + !myVertexNewVertex.IsBound(CurVertex)) + { + TopoDS_Vertex CurNewVertex; + if (myVertexNewVertex.IsBound(CurVertex)) + CurNewVertex = TopoDS::Vertex(myVertexNewVertex(CurVertex)); + + if (myEdgeNewEdge.IsBound(FirstEdge))//new edge: update + { + Standard_Real fpar, lpar; + BRep_Tool::Range(FirstEdge, fpar, lpar); + BB.Range(FirstNewEdge, fpar, lpar); + BRepAdaptor_Curve BAcurve(FirstNewEdge); + gp_Pnt FirstPnt = BAcurve.Value(BAcurve.FirstParameter()); + if (CurNewVertex.IsNull()) + CurNewVertex = BRepLib_MakeVertex(FirstPnt); + BB.Add(FirstNewEdge, CurNewVertex); + BB.Add(FirstNewEdge, CurNewVertex.Oriented(TopAbs_REVERSED)); + myVertexNewVertex.Bind(CurVertex, CurNewVertex); + } + } + for (; wexp.More(); wexp.Next()) + { + CurEdge = wexp.Current(); + if (myOrientedEdgeNewEdge.IsBound(CurEdge)) + CurNewEdge = TopoDS::Edge(myOrientedEdgeNewEdge(CurEdge)); + else if (myEdgeNewEdge.IsBound(CurEdge)) + CurNewEdge = TopoDS::Edge(myEdgeNewEdge(CurEdge)); + else + CurNewEdge = CurEdge; + CurVertex = wexp.CurrentVertex(); + UpdateEdgesAndVertex(PrevEdge, PrevNewEdge, + CurEdge, CurNewEdge, + CurVertex); + if (!PrevEdge.IsSame(PrevNewEdge) && + PrevEdge.Orientation() == TopAbs_REVERSED) + PrevNewEdge.Reverse(); + BB.Add(aNewWire, PrevNewEdge); + + PrevEdge = CurEdge; + PrevNewEdge = CurNewEdge; + } + CurEdge = FirstEdge; + CurNewEdge = FirstNewEdge; + CurVertex = wexp.CurrentVertex(); + UpdateEdgesAndVertex(PrevEdge, PrevNewEdge, + CurEdge, CurNewEdge, + CurVertex); + if (!PrevEdge.IsSame(PrevNewEdge) && + PrevEdge.Orientation() == TopAbs_REVERSED) + PrevNewEdge.Reverse(); + BB.Add(aNewWire, PrevNewEdge); + + aNewWire.Orientation(aWireOr); + BB.Add(aBoundedNewFace, aNewWire); + } //for (; itf.More(); itf.Next()) (iterator on face) + } + + //Assemble resulting shape + TopoDS_Solid aSolid; + BB.MakeSolid(aSolid); + TopoDS_Shell aShell; + BB.MakeShell(aShell); + TopExp_Explorer Explo(myInitialShape, TopAbs_FACE); + for (; Explo.More(); Explo.Next()) + { + const TopoDS_Shape& aFace = Explo.Current(); + TopoDS_Shape aBoundedNewFace; + if (myFaceNewFace.Contains(aFace)) + { + const TopoDS_Shape& aNewFace = myFaceNewFace.FindFromKey(aFace); + aBoundedNewFace = myNewFaceBoundedFace(aNewFace); + if (aFace.Orientation() == TopAbs_REVERSED) + aBoundedNewFace.Reverse(); + } + else + aBoundedNewFace = aFace; + BB.Add(aShell, aBoundedNewFace); + } + BB.Add(aSolid, aShell); + + ShapeFix_Shape Fixer(aSolid); + Fixer.Perform(); + + myShape = Fixer.Shape(); + //myShape = aSolid; + + Done(); +} + +void BRepOffsetAPI_PatchFaces::UpdateEdgesAndVertex(const TopoDS_Edge& thePrevEdge, + TopoDS_Edge& thePrevNewEdge, + const TopoDS_Edge& theCurEdge, + TopoDS_Edge& theCurNewEdge, + TopoDS_Vertex& theCurVertex) +{ + BRep_Builder BB; + + TopoDS_Vertex CurNewVertex; + if (myVertexNewVertex.IsBound(theCurVertex)) + CurNewVertex = TopoDS::Vertex(myVertexNewVertex(theCurVertex)); + else + { + Standard_Boolean IsConstVertex = (!(myEdgeNewEdge.IsBound(thePrevEdge) || myOrientedEdgeNewEdge.IsBound(thePrevEdge)) || + !(myEdgeNewEdge.IsBound(theCurEdge) || myOrientedEdgeNewEdge.IsBound(theCurEdge))); + if (IsConstVertex) + CurNewVertex = theCurVertex; + } + + Standard_Boolean IsSeamPrev = (myOrientedEdgeNewEdge.IsBound(thePrevEdge)); + Standard_Boolean IsSeamCur = (myOrientedEdgeNewEdge.IsBound(theCurEdge)); + + if ((myEdgeNewEdge.IsBound(thePrevEdge) || myOrientedEdgeNewEdge.IsBound(thePrevEdge)) && + (myEdgeNewEdge.IsBound(theCurEdge) || myOrientedEdgeNewEdge.IsBound(theCurEdge))) //two new edges: intersect + { + Standard_Real ParamOnPrev, ParamOnCur, TolProj; + gp_Pnt PntOnPrev, PntOnCur; + ProjectVertexOnNewEdge(theCurVertex, thePrevEdge, thePrevNewEdge, + ParamOnPrev, PntOnPrev, TolProj); + ProjectVertexOnNewEdge(theCurVertex, theCurEdge, theCurNewEdge, + ParamOnCur, PntOnCur, TolProj); + + Standard_Real TolReached; + gp_Pnt PntVtx = (CurNewVertex.IsNull())? + BRep_Tool::Pnt(theCurVertex) : BRep_Tool::Pnt(CurNewVertex); + TolReached = PntOnPrev.Distance(PntOnCur); + Standard_Real DistVtoPrev = PntVtx.Distance(PntOnPrev); + Standard_Real DistVtoCur = PntVtx.Distance(PntOnCur); + TolReached = Max(TolReached, DistVtoPrev); + TolReached = Max(TolReached, DistVtoCur); + + BRepExtrema_ExtCC ExtrEE(thePrevNewEdge, theCurNewEdge); + if (!ExtrEE.IsDone() || ExtrEE.NbExt() == 0) + { + cout< +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +class TopoDS_Shape; + + +//! Describes functions to replace some faces in a shape +//! by patches +class BRepOffsetAPI_PatchFaces : public BRepBuilderAPI_MakeShape +{ +public: + + DEFINE_STANDARD_ALLOC + + + //! General constructor. + Standard_EXPORT BRepOffsetAPI_PatchFaces(const TopoDS_Shape& aShape); + + //! Adds the patch face for the face in the shape. + Standard_EXPORT void AddPatchFace (const TopoDS_Face& theFace, const TopoDS_Face& thePatchFace); + + Standard_EXPORT virtual void Build() Standard_OVERRIDE; + + + + +protected: + + + + + +private: + + + Standard_EXPORT void UpdateEdgesAndVertex(const TopoDS_Edge& thePrevEdge, + TopoDS_Edge& thePrevNewEdge, + const TopoDS_Edge& theCurEdge, + TopoDS_Edge& theCurNewEdge, + TopoDS_Vertex& theCurVertex); + + Standard_EXPORT void PutVertexToEdge(const TopoDS_Vertex& theVertex, + const TopoDS_Vertex& theProVertex, + TopoDS_Edge& theEdge, + const TopoDS_Edge& theProEdge, + const Standard_Real theParamOnEdge); + + + TopoDS_Shape myInitialShape; + + TopTools_IndexedDataMapOfShapeShape myFacePatchFace; + TopTools_IndexedDataMapOfShapeShape myFaceNewFace; + TopTools_DataMapOfShapeShape myNewFaceBoundedFace; + TopTools_DataMapOfShapeShape myEdgeNewEdge; + TopTools_DataMapOfOrientedShapeShape myOrientedEdgeNewEdge; + TopTools_DataMapOfShapeShape myVertexNewVertex; + TopTools_MapOfShape myTangentEdges; + + TopTools_IndexedDataMapOfShapeListOfShape myEFmap; + +}; + + + + + + + +#endif // _BRepOffsetAPI_PatchFaces_HeaderFile diff --git a/src/BRepOffsetAPI/FILES b/src/BRepOffsetAPI/FILES index 4680ffd109..0d84a8f527 100644 --- a/src/BRepOffsetAPI/FILES +++ b/src/BRepOffsetAPI/FILES @@ -27,3 +27,5 @@ BRepOffsetAPI_SequenceOfSequenceOfShape.hxx BRepOffsetAPI_Sewing.hxx BRepOffsetAPI_ThruSections.cxx BRepOffsetAPI_ThruSections.hxx +BRepOffsetAPI_PatchFaces.cxx +BRepOffsetAPI_PatchFaces.hxx diff --git a/src/BRepTest/BRepTest_FeatureCommands.cxx b/src/BRepTest/BRepTest_FeatureCommands.cxx index a7431744c2..d27354fe39 100644 --- a/src/BRepTest/BRepTest_FeatureCommands.cxx +++ b/src/BRepTest/BRepTest_FeatureCommands.cxx @@ -54,6 +54,8 @@ #include #include +#include + #include #include #include @@ -2249,6 +2251,35 @@ static Standard_Integer BOSS(Draw_Interpretor& theCommands, return 1; } +//======================================================================= +//function : patchfaces +//purpose : +//======================================================================= +static Standard_Integer patchfaces(Draw_Interpretor& /*di*/, + Standard_Integer n, const char** a) +{ + if (n < 5) return 1; + + TopoDS_Shape aShape = DBRep::Get(a[2]); + if (aShape.IsNull()) return 1; + + TopoDS_Shape aLocalFace = DBRep::Get(a[3], TopAbs_FACE); + if (aLocalFace.IsNull()) return 1; + TopoDS_Face aFace = TopoDS::Face(aLocalFace); + + TopoDS_Shape aLocalNewFace = DBRep::Get(a[4], TopAbs_FACE); + if (aLocalNewFace.IsNull()) return 1; + TopoDS_Face aNewFace = TopoDS::Face(aLocalNewFace); + + BRepOffsetAPI_PatchFaces Builder(aShape); + Builder.AddPatchFace(aFace, aNewFace); + Builder.Build(); + + TopoDS_Shape Result = Builder.Shape(); + DBRep::Set(a[1], Result); + + return 0; +} //======================================================================= //function : FeatureCommands @@ -2395,4 +2426,6 @@ void BRepTest::FeatureCommands (Draw_Interpretor& theCommands) " Perform fillet on top and bottom edges of dprism :bossage dprism result radtop radbottom First/LastShape (1/2)", __FILE__,BOSS); + theCommands.Add("patchfaces", "patchfaces res shape face newface", + __FILE__,patchfaces,g); } diff --git a/src/TopExp/TopExp.cxx b/src/TopExp/TopExp.cxx index ff63bbe973..b011b50c7c 100644 --- a/src/TopExp/TopExp.cxx +++ b/src/TopExp/TopExp.cxx @@ -99,7 +99,55 @@ void TopExp::MapShapesAndAncestors } } +//======================================================================= +//function : MapShapesAndUniqueAncestors +//purpose : +//======================================================================= +void TopExp::MapShapesAndUniqueAncestors + (const TopoDS_Shape& S, + const TopAbs_ShapeEnum TS, + const TopAbs_ShapeEnum TA, + TopTools_IndexedDataMapOfShapeListOfShape& M, + const Standard_Boolean useOrientation) +{ + TopTools_ListOfShape empty; + + // visit ancestors + TopExp_Explorer exa(S,TA); + while (exa.More()) + { + // visit shapes + const TopoDS_Shape& anc = exa.Current(); + TopExp_Explorer exs(anc,TS); + while (exs.More()) + { + Standard_Integer index = M.FindIndex(exs.Current()); + if (index == 0) + index = M.Add(exs.Current(),empty); + TopTools_ListOfShape& aList = M(index); + // check if anc already exists in a list + TopTools_ListIteratorOfListOfShape it(aList); + for (; it.More(); it.Next()) + if (useOrientation? anc.IsEqual(it.Value()) : anc.IsSame(it.Value())) + break; + if (!it.More()) + aList.Append(anc); + exs.Next(); + } + exa.Next(); + } + + // visit shapes not under ancestors + TopExp_Explorer ex(S,TS,TA); + while (ex.More()) + { + Standard_Integer index = M.FindIndex(ex.Current()); + if (index == 0) + M.Add(ex.Current(),empty); + ex.Next(); + } +} //======================================================================= //function : FirstVertex diff --git a/src/TopExp/TopExp.hxx b/src/TopExp/TopExp.hxx index 25ccde43b8..34e45eee4a 100644 --- a/src/TopExp/TopExp.hxx +++ b/src/TopExp/TopExp.hxx @@ -66,6 +66,18 @@ public: //! Warning: The map is not cleared at first. Standard_EXPORT static void MapShapesAndAncestors (const TopoDS_Shape& S, const TopAbs_ShapeEnum TS, const TopAbs_ShapeEnum TA, TopTools_IndexedDataMapOfShapeListOfShape& M); + //! Stores in the map all the subshape of of + //! type for each one append to the list all + //! unique ancestors of type . For example map all + //! the edges and bind the list of faces. + //! useOrientation = True : taking account the ancestor orientation + //! Warning: The map is not cleared at first. + Standard_EXPORT static void MapShapesAndUniqueAncestors (const TopoDS_Shape& S, + const TopAbs_ShapeEnum TS, + const TopAbs_ShapeEnum TA, + TopTools_IndexedDataMapOfShapeListOfShape& M, + const Standard_Boolean useOrientation = Standard_False); + //! Returns the Vertex of orientation FORWARD in E. If //! there is none returns a Null Shape. //! CumOri = True : taking account the edge orientation diff --git a/tests/patchfaces/begin b/tests/patchfaces/begin new file mode 100644 index 0000000000..ed01a4a269 --- /dev/null +++ b/tests/patchfaces/begin @@ -0,0 +1,23 @@ +# To prevent loops limit to 10 minutes +cpulimit 100 +if { [array get Draw_Groups "TOPOLOGY Feature commands"] == "" } { + pload TOPTEST +} +if { [array get Draw_Groups "Shape Healing"] == "" } { + pload XSDRAW +} +if { [info exists imagedir] == 0 } { + set imagedir . +} +if { [info exists test_image ] == 0 } { + set test_image photo +} +proc PATCHFACES {i} { + uplevel #0 binrestore [locate_data_file shape_3_$i.bin] s + uplevel #0 tclean s + uplevel #0 removeloc s s + uplevel #0 explode s + uplevel #0 tcopy s_1 InitShape + + uplevel #0 patchfaces result s_1 s_2 s_3 +} diff --git a/tests/patchfaces/end b/tests/patchfaces/end new file mode 100644 index 0000000000..73b3acd4ea --- /dev/null +++ b/tests/patchfaces/end @@ -0,0 +1 @@ +puts "TEST COMPLETED" diff --git a/tests/patchfaces/grids.list b/tests/patchfaces/grids.list new file mode 100644 index 0000000000..55dee65f67 --- /dev/null +++ b/tests/patchfaces/grids.list @@ -0,0 +1 @@ +001 replace diff --git a/tests/patchfaces/parse.rules b/tests/patchfaces/parse.rules new file mode 100644 index 0000000000..95a93927e0 --- /dev/null +++ b/tests/patchfaces/parse.rules @@ -0,0 +1,2 @@ +FAILED /\bFaulty\b/ bad shape +OK /Relative error of mass computation/ message from vprops \ No newline at end of file diff --git a/tests/patchfaces/replace/end b/tests/patchfaces/replace/end new file mode 100644 index 0000000000..4e1132da15 --- /dev/null +++ b/tests/patchfaces/replace/end @@ -0,0 +1,2 @@ +checkshape result +checkview -display result -2d -path ${imagedir}/${test_image}.png \ No newline at end of file diff --git a/tests/patchfaces/replace/test_1 b/tests/patchfaces/replace/test_1 new file mode 100644 index 0000000000..9fc4b85992 --- /dev/null +++ b/tests/patchfaces/replace/test_1 @@ -0,0 +1 @@ +PATCHFACES 1 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_10 b/tests/patchfaces/replace/test_10 new file mode 100644 index 0000000000..4089cf808b --- /dev/null +++ b/tests/patchfaces/replace/test_10 @@ -0,0 +1 @@ +PATCHFACES 10 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_11 b/tests/patchfaces/replace/test_11 new file mode 100644 index 0000000000..a40a9b3cf3 --- /dev/null +++ b/tests/patchfaces/replace/test_11 @@ -0,0 +1 @@ +PATCHFACES 11 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_12 b/tests/patchfaces/replace/test_12 new file mode 100644 index 0000000000..0b094e3c01 --- /dev/null +++ b/tests/patchfaces/replace/test_12 @@ -0,0 +1 @@ +PATCHFACES 12 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_13 b/tests/patchfaces/replace/test_13 new file mode 100644 index 0000000000..8fcfcd37af --- /dev/null +++ b/tests/patchfaces/replace/test_13 @@ -0,0 +1 @@ +PATCHFACES 13 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_14 b/tests/patchfaces/replace/test_14 new file mode 100644 index 0000000000..247d4915a0 --- /dev/null +++ b/tests/patchfaces/replace/test_14 @@ -0,0 +1 @@ +PATCHFACES 14 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_15 b/tests/patchfaces/replace/test_15 new file mode 100644 index 0000000000..75b75d0657 --- /dev/null +++ b/tests/patchfaces/replace/test_15 @@ -0,0 +1 @@ +PATCHFACES 15 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_16 b/tests/patchfaces/replace/test_16 new file mode 100644 index 0000000000..2e9d2ae11a --- /dev/null +++ b/tests/patchfaces/replace/test_16 @@ -0,0 +1 @@ +PATCHFACES 16 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_17 b/tests/patchfaces/replace/test_17 new file mode 100644 index 0000000000..53762739db --- /dev/null +++ b/tests/patchfaces/replace/test_17 @@ -0,0 +1 @@ +PATCHFACES 17 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_18 b/tests/patchfaces/replace/test_18 new file mode 100644 index 0000000000..d15b5ab431 --- /dev/null +++ b/tests/patchfaces/replace/test_18 @@ -0,0 +1 @@ +PATCHFACES 18 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_19 b/tests/patchfaces/replace/test_19 new file mode 100644 index 0000000000..58b5d2c72f --- /dev/null +++ b/tests/patchfaces/replace/test_19 @@ -0,0 +1 @@ +PATCHFACES 19 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_2 b/tests/patchfaces/replace/test_2 new file mode 100644 index 0000000000..7c6e6e6876 --- /dev/null +++ b/tests/patchfaces/replace/test_2 @@ -0,0 +1 @@ +PATCHFACES 2 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_20 b/tests/patchfaces/replace/test_20 new file mode 100644 index 0000000000..4c8a8baa47 --- /dev/null +++ b/tests/patchfaces/replace/test_20 @@ -0,0 +1 @@ +PATCHFACES 20 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_21 b/tests/patchfaces/replace/test_21 new file mode 100644 index 0000000000..31ff03b3fc --- /dev/null +++ b/tests/patchfaces/replace/test_21 @@ -0,0 +1 @@ +PATCHFACES 21 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_22 b/tests/patchfaces/replace/test_22 new file mode 100644 index 0000000000..1472cf0d63 --- /dev/null +++ b/tests/patchfaces/replace/test_22 @@ -0,0 +1 @@ +PATCHFACES 22 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_23 b/tests/patchfaces/replace/test_23 new file mode 100644 index 0000000000..43e9544e53 --- /dev/null +++ b/tests/patchfaces/replace/test_23 @@ -0,0 +1 @@ +PATCHFACES 23 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_24 b/tests/patchfaces/replace/test_24 new file mode 100644 index 0000000000..bab81082a6 --- /dev/null +++ b/tests/patchfaces/replace/test_24 @@ -0,0 +1 @@ +PATCHFACES 24 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_25 b/tests/patchfaces/replace/test_25 new file mode 100644 index 0000000000..d11d3b564d --- /dev/null +++ b/tests/patchfaces/replace/test_25 @@ -0,0 +1 @@ +PATCHFACES 25 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_26 b/tests/patchfaces/replace/test_26 new file mode 100644 index 0000000000..0af9759422 --- /dev/null +++ b/tests/patchfaces/replace/test_26 @@ -0,0 +1 @@ +PATCHFACES 26 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_27 b/tests/patchfaces/replace/test_27 new file mode 100644 index 0000000000..defa2b09df --- /dev/null +++ b/tests/patchfaces/replace/test_27 @@ -0,0 +1 @@ +PATCHFACES 27 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_28 b/tests/patchfaces/replace/test_28 new file mode 100644 index 0000000000..7da11d2301 --- /dev/null +++ b/tests/patchfaces/replace/test_28 @@ -0,0 +1 @@ +PATCHFACES 28 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_29 b/tests/patchfaces/replace/test_29 new file mode 100644 index 0000000000..f16ed03dcd --- /dev/null +++ b/tests/patchfaces/replace/test_29 @@ -0,0 +1 @@ +PATCHFACES 29 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_3 b/tests/patchfaces/replace/test_3 new file mode 100644 index 0000000000..2db0a20cf0 --- /dev/null +++ b/tests/patchfaces/replace/test_3 @@ -0,0 +1 @@ +PATCHFACES 3 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_30 b/tests/patchfaces/replace/test_30 new file mode 100644 index 0000000000..d07f306628 --- /dev/null +++ b/tests/patchfaces/replace/test_30 @@ -0,0 +1 @@ +PATCHFACES 30 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_31 b/tests/patchfaces/replace/test_31 new file mode 100644 index 0000000000..b8ef5b5d17 --- /dev/null +++ b/tests/patchfaces/replace/test_31 @@ -0,0 +1 @@ +PATCHFACES 31 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_32 b/tests/patchfaces/replace/test_32 new file mode 100644 index 0000000000..c531a687e0 --- /dev/null +++ b/tests/patchfaces/replace/test_32 @@ -0,0 +1 @@ +PATCHFACES 32 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_33 b/tests/patchfaces/replace/test_33 new file mode 100644 index 0000000000..5ddf9519ce --- /dev/null +++ b/tests/patchfaces/replace/test_33 @@ -0,0 +1 @@ +PATCHFACES 33 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_34 b/tests/patchfaces/replace/test_34 new file mode 100644 index 0000000000..8f81bc0f47 --- /dev/null +++ b/tests/patchfaces/replace/test_34 @@ -0,0 +1 @@ +PATCHFACES 34 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_35 b/tests/patchfaces/replace/test_35 new file mode 100644 index 0000000000..cc9e8b6f7c --- /dev/null +++ b/tests/patchfaces/replace/test_35 @@ -0,0 +1 @@ +PATCHFACES 35 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_4 b/tests/patchfaces/replace/test_4 new file mode 100644 index 0000000000..4cf50d24b1 --- /dev/null +++ b/tests/patchfaces/replace/test_4 @@ -0,0 +1 @@ +PATCHFACES 4 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_5 b/tests/patchfaces/replace/test_5 new file mode 100644 index 0000000000..9436e03c4d --- /dev/null +++ b/tests/patchfaces/replace/test_5 @@ -0,0 +1 @@ +PATCHFACES 5 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_6 b/tests/patchfaces/replace/test_6 new file mode 100644 index 0000000000..447f5d0859 --- /dev/null +++ b/tests/patchfaces/replace/test_6 @@ -0,0 +1 @@ +PATCHFACES 6 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_7 b/tests/patchfaces/replace/test_7 new file mode 100644 index 0000000000..19d943456b --- /dev/null +++ b/tests/patchfaces/replace/test_7 @@ -0,0 +1 @@ +PATCHFACES 7 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_8 b/tests/patchfaces/replace/test_8 new file mode 100644 index 0000000000..8386ba18ca --- /dev/null +++ b/tests/patchfaces/replace/test_8 @@ -0,0 +1 @@ +PATCHFACES 8 \ No newline at end of file diff --git a/tests/patchfaces/replace/test_9 b/tests/patchfaces/replace/test_9 new file mode 100644 index 0000000000..75af863bad --- /dev/null +++ b/tests/patchfaces/replace/test_9 @@ -0,0 +1 @@ +PATCHFACES 9 \ No newline at end of file