From 7693827d4a3127ac7e571af418a9fcdd42551ce3 Mon Sep 17 00:00:00 2001 From: nbv Date: Wed, 6 May 2015 16:58:48 +0300 Subject: [PATCH] 0026118: Implement FastSewing algorithm 1. Develop special sewing algorithm. 2. DRAW-command "fastsewing" has been created (see help for detail information). 3. BRepLib::EnsureNormalConsistency() method has been added (see help for detail information). 4. DRAW-command correctnormals has been created (see help for detail information). Test cases for this issue. Correction of elapsed time in test-cases --- src/BRepBuilderAPI/BRepBuilderAPI.cdl | 1 + .../BRepBuilderAPI_FastSewing.cxx | 768 ++++++++++++++++++ .../BRepBuilderAPI_FastSewing.hxx | 306 +++++++ src/BRepBuilderAPI/FILES | 3 +- src/BRepLib/BRepLib.cdl | 11 +- src/BRepLib/BRepLib.cxx | 144 ++++ src/BRepTest/BRepTest_SurfaceCommands.cxx | 65 ++ src/MeshTest/MeshTest.cxx | 28 + tests/sewing/fast/A1 | 49 ++ tests/sewing/fast/A2 | 49 ++ tests/sewing/fast/A3 | 49 ++ tests/sewing/fast/A4 | 49 ++ tests/sewing/fast/A5 | 49 ++ tests/sewing/fast/A6 | 49 ++ tests/sewing/fast/A7 | 49 ++ tests/sewing/grids.list | 1 + 16 files changed, 1668 insertions(+), 2 deletions(-) create mode 100644 src/BRepBuilderAPI/BRepBuilderAPI_FastSewing.cxx create mode 100644 src/BRepBuilderAPI/BRepBuilderAPI_FastSewing.hxx create mode 100644 tests/sewing/fast/A1 create mode 100644 tests/sewing/fast/A2 create mode 100644 tests/sewing/fast/A3 create mode 100644 tests/sewing/fast/A4 create mode 100644 tests/sewing/fast/A5 create mode 100644 tests/sewing/fast/A6 create mode 100644 tests/sewing/fast/A7 diff --git a/src/BRepBuilderAPI/BRepBuilderAPI.cdl b/src/BRepBuilderAPI/BRepBuilderAPI.cdl index 6eabd734a8..a61c6bc20b 100644 --- a/src/BRepBuilderAPI/BRepBuilderAPI.cdl +++ b/src/BRepBuilderAPI/BRepBuilderAPI.cdl @@ -258,6 +258,7 @@ is -- class Sewing; + imported transient class FastSewing; -- -- Construction of composite topologies diff --git a/src/BRepBuilderAPI/BRepBuilderAPI_FastSewing.cxx b/src/BRepBuilderAPI/BRepBuilderAPI_FastSewing.cxx new file mode 100644 index 0000000000..b68b7853b2 --- /dev/null +++ b/src/BRepBuilderAPI/BRepBuilderAPI_FastSewing.cxx @@ -0,0 +1,768 @@ +// Created on: 2015-04-24 +// Created by: NIKOLAI BUKHALOV +// Copyright (c) 2015 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 + +IMPLEMENT_STANDARD_HANDLE(BRepBuilderAPI_FastSewing, Standard_Transient) +IMPLEMENT_STANDARD_RTTIEXT(BRepBuilderAPI_FastSewing, Standard_Transient) + +//======================================================================= +//function : IntersetctionOfSets +//purpose : Returns minimal value of intersection result +//======================================================================= +static Standard_Integer + IntersectionOfSets( const NCollection_List& theSet1, + const NCollection_List& theSet2) +{ + const Standard_Integer anIntMax = IntegerLast(); + Standard_Integer aRetVal = anIntMax; + for(NCollection_List::Iterator + anIt1 = theSet1.begin().Iterator(); + anIt1.More(); anIt1.Next()) + { + const Standard_Integer aVal1 = anIt1.Value(); + for(NCollection_List::Iterator + anIt2 = theSet2.begin().Iterator(); + anIt2.More(); anIt2.Next()) + { + const Standard_Integer aVal2 = anIt2.Value(); + if(aVal1 == aVal2) + { + //theIntersectionResult.Append(aVal1); + if(aVal1 < aRetVal) + aRetVal = aVal1; + } + } + } + + if(aRetVal == anIntMax) + return -1; + + return aRetVal; +} + +//======================================================================= +//function : Get2DCurve +//purpose : +//======================================================================= +static Handle(Geom2d_Curve) + Get2DCurve( const Standard_Integer theIndex, + const Standard_Real theUfirst, + const Standard_Real theUlast, + const Standard_Real theVfirst, + const Standard_Real theVlast, + const Standard_Boolean theIsReverse = Standard_False) +{ + if((theIndex < 0) || (theIndex > 3)) + Standard_OutOfRange::Raise("BRepBuilderAPI_FastSewing.cxx, Get2DCurve(): OUT of Range"); + + Handle(Geom2d_Curve) a2dCurv; + + if(!theIsReverse) + { + switch(theIndex) + { + case 0: + a2dCurv = + new Geom2d_TrimmedCurve(new Geom2d_Line( + gp_Pnt2d(0.0, theVfirst), gp_Dir2d(1.0,0.0)), + theUfirst, theUlast); + break; + case 1: + a2dCurv = + new Geom2d_TrimmedCurve(new Geom2d_Line( + gp_Pnt2d(theUlast, 0.0), gp_Dir2d(0.0,1.0)), + theVfirst, theVlast); + break; + case 2: + a2dCurv = + new Geom2d_TrimmedCurve(new Geom2d_Line( + gp_Pnt2d(0.0, theVlast), gp_Dir2d(1.0,0.0)), + theUfirst, theUlast); + break; + case 3: + a2dCurv = + new Geom2d_TrimmedCurve(new Geom2d_Line( + gp_Pnt2d(theUfirst, 0.0), gp_Dir2d(0.0,1.0)), + theVfirst, theVlast); + break; + default: + break; + } + } + else + { + switch(theIndex) + { + case 0: + a2dCurv = + new Geom2d_TrimmedCurve(new Geom2d_Line( + gp_Pnt2d(theUfirst+theUlast, theVfirst), + gp_Dir2d(-1.0,0.0)), + theUfirst, theUlast); + break; + case 1: + a2dCurv = + new Geom2d_TrimmedCurve(new Geom2d_Line( + gp_Pnt2d(theUlast, theVfirst+theVlast), + gp_Dir2d(0.0,-1.0)), + theVfirst, theVlast); + break; + case 2: + a2dCurv = + new Geom2d_TrimmedCurve(new Geom2d_Line( + gp_Pnt2d(theUfirst+theUlast, theVlast), + gp_Dir2d(-1.0,0.0)), + theUfirst, theUlast); + break; + case 3: + a2dCurv = + new Geom2d_TrimmedCurve(new Geom2d_Line( + gp_Pnt2d(theUfirst, theVfirst+theVlast), + gp_Dir2d(0.0,-1.0)), + theVfirst, theVlast); + break; + default: + break; + } + } + + return a2dCurv; +} + +//======================================================================= +//function : Constructor +//purpose : +//======================================================================= +BRepBuilderAPI_FastSewing:: + BRepBuilderAPI_FastSewing( const Standard_Real theTol): + myTolerance(theTol), + myStatusList(0) +{ +} + +//======================================================================= +//function : Add +//purpose : +//======================================================================= +Standard_Boolean BRepBuilderAPI_FastSewing::Add(const TopoDS_Shape& theShape) +{ + Standard_Boolean aResult = Standard_False; + if(theShape.IsNull()) + { + SetStatus(FS_EmptyInput); + return aResult; + } + + TopTools_MapOfShape aMS; + //aMS.Add(theShape); + TopExp_Explorer aFExp(theShape,TopAbs_FACE); + for (; aFExp.More(); aFExp.Next()) + { + const TopoDS_Face& aFace = TopoDS::Face(aFExp.Current()); + if(aMS.Add(aFace)) + { + Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace); + if(aSurf.IsNull()) + { + SetStatus(FS_FaceWithNullSurface); + continue; + } + + if(aSurf->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface))) + { + SetStatus(FS_NotNaturalBoundsFace); + continue; + } + + Standard_Real aUf = 0.0, aUl = 0.0, aVf = 0.0, aVl = 0.0; + aSurf->Bounds(aUf, aUl, aVf, aVl); + + if(Precision::IsInfinite(aUf) || Precision::IsInfinite(aUl) || + Precision::IsInfinite(aVf) || Precision::IsInfinite(aVl)) + { + SetStatus(FS_InfiniteSurface); + continue; + } + + FS_Face aFFace; + aFFace.mySrcFace = aFace; + aFFace.myID = myFaceVec.Length();//because start index is 0 + myFaceVec.Append(aFFace); + aResult = Standard_True; + } + } + + return aResult; +} + +//======================================================================= +//function : Add +//purpose : +//======================================================================= +Standard_Boolean BRepBuilderAPI_FastSewing::Add(const Handle(Geom_Surface)& theSurface) +{ + if(theSurface.IsNull()) + { + SetStatus(FS_FaceWithNullSurface); + return Standard_False; + } + + if(theSurface->IsKind(STANDARD_TYPE(Geom_RectangularTrimmedSurface))) + { + SetStatus(FS_NotNaturalBoundsFace); + return Standard_False; + } + + Standard_Real aUf = 0.0, aUl = 0.0, aVf = 0.0, aVl = 0.0; + theSurface->Bounds(aUf, aUl, aVf, aVl); + + if(Precision::IsInfinite(aUf) || Precision::IsInfinite(aUl) || + Precision::IsInfinite(aVf) || Precision::IsInfinite(aVl)) + { + SetStatus(FS_InfiniteSurface); + return Standard_False; + } + + FS_Face aFace; + + BRep_Builder aBuilder; + aBuilder.MakeFace(aFace.mySrcFace); + aBuilder.MakeFace(aFace.mySrcFace, theSurface, myTolerance); + aBuilder.NaturalRestriction(aFace.mySrcFace, Standard_True); + + aFace.myID = myFaceVec.Length();//because start index is 0 + myFaceVec.Append(aFace); + + return Standard_True; +} + + +//======================================================================= +//function : Perform +//purpose : +//======================================================================= +void BRepBuilderAPI_FastSewing::Perform(void) +{ + if(myFaceVec.IsEmpty()) + { + SetStatus(FS_EmptyInput); + return; + } + + try + { + { + // create vertices having unique coordinates + Standard_Real aRange = Compute3DRange(); + Handle(NCollection_IncAllocator) anAlloc = new NCollection_IncAllocator; + NCollection_CellFilter + aCells(Max(myTolerance, aRange/IntegerLast()), anAlloc); + + for(Standard_Integer i = myFaceVec.Lower(); i <= myFaceVec.Upper(); i++) + { + FindVertexes(i, aCells); + } + } + + for(Standard_Integer i = myFaceVec.Lower(); i <= myFaceVec.Upper(); i++) + { + FindEdges(i); + } + + //Create topological structures + + for(Standard_Integer i = myVertexVec.Lower(); i <= myVertexVec.Upper(); i++) + { + myVertexVec.ChangeValue(i).CreateTopologicalVertex(myTolerance); + } + + //Edges + for(Standard_Integer i = myEdgeVec.Lower(); i <= myEdgeVec.Upper(); i++) + { + myEdgeVec.ChangeValue(i).CreateTopologicalEdge(myVertexVec, myFaceVec, myTolerance); + } + + //Shell + BRepTools_Quilt aQuilt; + + //Faces + for(Standard_Integer i = myFaceVec.Lower(); i <= myFaceVec.Upper(); i++) + { + FS_Face& aFace = myFaceVec.ChangeValue(i); + aFace.CreateTopologicalWire(myEdgeVec, myTolerance); + aFace.CreateTopologicalFace(); + aQuilt.Add(aFace.myRetFace); + } + + myResShape = aQuilt.Shells(); + } + catch(Standard_Failure) + { + SetStatus(FS_Exception); +#ifdef OCCT_DEBUG + //Standard_Failure::Caught()->Print(cout); +#endif + return; + } +} + +//======================================================================= +//function : UpdateEdgeInfo +//purpose : +//======================================================================= +void BRepBuilderAPI_FastSewing::UpdateEdgeInfo( const Standard_Integer theIDPrevVertex, + const Standard_Integer theIDCurrVertex, + const Standard_Integer theFaceID, + const Standard_Integer theIDCurvOnFace) +{ + //Indeed, two vertices combine into one edge only. + const Standard_Integer anEdgeID = + IntersectionOfSets(myVertexVec.Value(theIDPrevVertex).myEdges, + myVertexVec.Value(theIDCurrVertex).myEdges); + + //For DEBUG mode only + Standard_ProgramError_Raise_if(anEdgeID < 0, + "BRepBuilderAPI_FastSewing::UpdateEdgeInfo: Update not existing edge."); + + FS_Edge& anEdge = myEdgeVec.ChangeValue(anEdgeID); + anEdge.myFaces.Append(theFaceID); + FS_Face& aFace = myFaceVec.ChangeValue(theFaceID); + aFace.SetEdge(theIDCurvOnFace, anEdge.myID); +} + +//======================================================================= +//function : CreateNewEdge +//purpose : Creates FS_Edge +//======================================================================= +void BRepBuilderAPI_FastSewing::CreateNewEdge(const Standard_Integer theIDPrevVertex, + const Standard_Integer theIDCurrVertex, + const Standard_Integer theFaceID, + const Standard_Integer theIDCurvOnFace) +{ + FS_Edge anEdge(theIDPrevVertex, theIDCurrVertex); + anEdge.myID = myEdgeVec.Length(); //because start index is 0 + + + anEdge.myFaces.Append(theFaceID); + FS_Face& aFace = myFaceVec.ChangeValue(theFaceID); + aFace.SetEdge(theIDCurvOnFace, anEdge.myID); + + myVertexVec.ChangeValue(theIDPrevVertex).myEdges.Append(anEdge.myID); + + if(theIDPrevVertex == theIDCurrVertex) + {//the Edge is degenerated + SetStatus(FS_Degenerated); + } + else + { + myVertexVec.ChangeValue(theIDCurrVertex).myEdges.Append(anEdge.myID); + } + + myEdgeVec.Append(anEdge); +} + +//======================================================================= +//function : FindVertexes +//purpose : +//======================================================================= +void BRepBuilderAPI_FastSewing:: + FindVertexes(const Standard_Integer theSurfID, + NCollection_CellFilter& theCells) +{ + const Standard_Integer aNbPoints = 4; + FS_Face& aFace = myFaceVec.ChangeValue(theSurfID); + const Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace.mySrcFace); + Standard_Real aUf = 0.0, aUl = 0.0, aVf = 0.0, aVl = 0.0; + aSurf->Bounds(aUf, aUl, aVf, aVl); + + const gp_Pnt aPnts[aNbPoints] = { aSurf->Value(aUf, aVf), + aSurf->Value(aUl, aVf), + aSurf->Value(aUl, aVl), + aSurf->Value(aUf, aVl)}; + + for(Standard_Integer i = 0; i < aNbPoints; i++) + { + FS_Vertex aVert; + + NodeInspector anInspector(myVertexVec, aPnts[i], myTolerance); + Bnd_Box aBox; + aBox.Add(aPnts[i]); + aBox.Enlarge(myTolerance); + + theCells.Inspect(aBox.CornerMin().XYZ(), aBox.CornerMax().XYZ(), anInspector); + NodeInspector::Target aResID = anInspector.GetResult(); + + if(aResID < 0) + {//Add new Vertex + aVert.myID = myVertexVec.Length(); //because start index is 0 + aVert.myPnt = aPnts[i]; + aVert.myFaces.Append(theSurfID); + myVertexVec.Append(aVert); + aFace.SetVertex(i, aVert.myID); + + theCells.Add(aVert.myID, aBox.CornerMin().XYZ(), aBox.CornerMax().XYZ()); + } + else + {//Change existing vertex + aFace.SetVertex(i, aResID); + myVertexVec.ChangeValue(aResID).myFaces.Append(theSurfID); + } + } +} + +//======================================================================= +//function : FindEdges +//purpose : +//======================================================================= +void BRepBuilderAPI_FastSewing::FindEdges(const Standard_Integer theSurfID) +{ + const Standard_Integer aNbPoints = 4; + FS_Face& aFace = myFaceVec.ChangeValue(theSurfID); + + const Standard_Integer aFirstInd[aNbPoints] = {0, 1, 3, 0}; + const Standard_Integer aLastInd[aNbPoints] = {1, 2, 2, 3}; + + for(Standard_Integer i = 0; i < aNbPoints; i++) + { + const Standard_Integer aFirstVertIndex = aFirstInd[i], + aLastVertIndex = aLastInd[i]; + const Standard_Integer aFirstVertID = aFace.myVertices[aFirstVertIndex], + aLastVertID = aFace.myVertices[aLastVertIndex]; + + if(aFirstVertID == aLastVertID) + {//Edge is degenerated. + CreateNewEdge(aFirstVertID, aLastVertID, theSurfID, i); + continue; + } + + //Must be minimal element from list + const Standard_Integer anIntRes = + IntersectionOfSets(myVertexVec.Value(aFirstVertID).myFaces, + myVertexVec.Value(aLastVertID).myFaces); + + if((anIntRes < 0) || (anIntRes >= theSurfID)) + { + CreateNewEdge(aFirstVertID, aLastVertID, theSurfID, i); + } + else + {//if(theSurfID > anIntRes) => The edge has been processed earlier + UpdateEdgeInfo(aFirstVertID, aLastVertID, theSurfID, i); + } + } +} + +//======================================================================= +//function : GetStatuses +//purpose : +//======================================================================= +BRepBuilderAPI_FastSewing::FS_VARStatuses + BRepBuilderAPI_FastSewing::GetStatuses(Standard_OStream* const theOS) +{ + if(!theOS) + return myStatusList; + + if(!myStatusList) + { + *theOS << "Fast Sewing OK!\n"; + return myStatusList; + } + + //Number of bits + const Standard_Integer aNumMax = 8*sizeof(myStatusList); + FS_Statuses anIDS = static_cast(0x0001); + for(Standard_Integer i = 1; i <= aNumMax; i++, + anIDS = static_cast(anIDS << 1)) + { + if((anIDS & myStatusList) == 0) + continue; + + switch(anIDS) + { + case FS_Degenerated: + *theOS << "Degenerated case. Try to reduce tolerance.\n"; + break; + case FS_FindVertexError: + *theOS << "Error while creating list of vertices.\n"; + break; + case FS_FindEdgeError: + *theOS << "Error while creating list of edges.\n"; + break; + case FS_Exception: + *theOS << "Exception during the operation.\n"; + break; + case FS_FaceWithNullSurface: + *theOS << "Source face has null surface.\n"; + break; + case FS_NotNaturalBoundsFace: + *theOS << "Source face has trimmed surface.\n"; + break; + case FS_InfiniteSurface: + *theOS << "Source face has the surface with infinite boundaries.\n"; + break; + case FS_EmptyInput: + *theOS << "Empty source data.\n"; + break; + + + default: + return myStatusList; + } + } + + return myStatusList; +} + +//======================================================================= +//function : Compute3DRange +//purpose : +//======================================================================= +Standard_Real BRepBuilderAPI_FastSewing::Compute3DRange() +{ + Bnd_Box aBox; + + for(Standard_Integer i = myFaceVec.Lower(); i <= myFaceVec.Upper(); i++) + { + FS_Face& aFace = myFaceVec.ChangeValue(i); + const Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace.mySrcFace); + if(aSurf.IsNull()) + continue; + Standard_Real aUf = 0.0, aUl = 0.0, aVf = 0.0, aVl = 0.0; + aSurf->Bounds(aUf, aUl, aVf, aVl); + + aBox.Add(aSurf->Value(aUf, aVf)); + aBox.Add(aSurf->Value(aUl, aVf)); + aBox.Add(aSurf->Value(aUl, aVl)); + aBox.Add(aSurf->Value(aUf, aVl)); + } + + Standard_Real aXm = 0.0, aYm = 0.0, aZm = 0.0, aXM = 0.0, aYM = 0.0, aZM = 0.0; + aBox.Get(aXm, aYm, aZm, aXM, aYM, aZM); + Standard_Real aDelta = aXM - aXm; + aDelta = Max(aDelta, aYM - aYm); + aDelta = Max(aDelta, aZM - aZm); + + return aDelta; +} + +//======================================================================= +//function : NodeInspector constructor +//purpose : +//======================================================================= +BRepBuilderAPI_FastSewing::NodeInspector:: + NodeInspector(const NCollection_Vector& theVec, + const gp_Pnt& thePnt, + const Standard_Real theTol): +myVecOfVertexes(theVec), myPoint(thePnt), myResID(-1) +{ + mySQToler = theTol*theTol; +} + +//======================================================================= +//function : ::NodeInspector::Inspect +//purpose : +//======================================================================= +NCollection_CellFilter_Action BRepBuilderAPI_FastSewing:: + NodeInspector::Inspect(const Target theID) +{ + const gp_Pnt& aPt = myVecOfVertexes.Value(theID).myPnt; + const Standard_Real aSQDist = aPt.SquareDistance(myPoint); + if(aSQDist < mySQToler) + { + mySQToler = aSQDist; + myResID = theID; + } + + return CellFilter_Keep; +} + +//======================================================================= +//function : ::FS_Edge::CreateTopologicalEdge +//purpose : +//======================================================================= +void BRepBuilderAPI_FastSewing::FS_Edge:: + CreateTopologicalEdge(const NCollection_Vector& theVertexVec, + const NCollection_Vector& theFaceVec, + const Standard_Real theTol) +{ + BRep_Builder aBuilder; + + TopoDS_Vertex aV1 = theVertexVec(myVertices[0]).myTopoVert; + TopoDS_Vertex aV2 = theVertexVec(myVertices[1]).myTopoVert; + + aV1.Orientation(TopAbs_FORWARD); + aV2.Orientation(TopAbs_REVERSED); + + Handle(Geom_Curve) a3dCurv; + TopLoc_Location aLocation; + + const FS_Face& aFace = theFaceVec.Value(myFaces.Value(myFaces.Lower())); + + //3D-curves in 1st and 2nd faces are considered to be in same-range + const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(aFace.mySrcFace, aLocation); + + Standard_Real aUf = 0.0, aUl = 0.0, aVf = 0.0, aVl = 0.0; + aSurf->Bounds(aUf, aUl, aVf, aVl); + + Standard_Integer anEdgeID = -1; + for(Standard_Integer anInd = 0; anInd < 4; anInd++) + { + if(myID == aFace.myEdges[anInd]) + { + anEdgeID = anInd; + break; + } + } + + //For DEBUG mode only + Standard_ProgramError_Raise_if(anEdgeID < 0, + "BRepBuilderAPI_FastSewing::FS_Edge::CreateTopologicalEdge: Single edge."); + + if(IsDegenerated()) + { + Handle(Geom2d_Curve) a2dCurv = Get2DCurve(anEdgeID, aUf, aUl, aVf, aVl); + const Standard_Real aFPar = a2dCurv->FirstParameter(), + aLPar = a2dCurv->LastParameter(); + + aBuilder.MakeEdge(myTopoEdge); + aBuilder.UpdateEdge(myTopoEdge, a2dCurv, aSurf, aLocation, theTol); + aBuilder.Add(myTopoEdge, aV1); + aBuilder.Add(myTopoEdge, aV2); + aBuilder.Range(myTopoEdge, aFPar, aLPar); + aBuilder.Degenerated(myTopoEdge, Standard_True); + return; + } + + switch(anEdgeID) + { + case 0: + a3dCurv = aSurf->VIso(aVf); + break; + case 1: + a3dCurv = aSurf->UIso(aUl); + break; + case 2: + a3dCurv = aSurf->VIso(aVl); + break; + case 3: + a3dCurv = aSurf->UIso(aUf); + break; + default: + Standard_OutOfRange::Raise("FS_Edge::CreateTopologicalEdge()"); + break; + } + + aBuilder.MakeEdge(myTopoEdge, a3dCurv, theTol); + aBuilder.Add(myTopoEdge, aV1); + aBuilder.Add(myTopoEdge, aV2); + aBuilder.Range(myTopoEdge, a3dCurv->FirstParameter(), a3dCurv->LastParameter()); +} + +//======================================================================= +//function : ::FS_Face::CreateTopologicalWire +//purpose : +//======================================================================= +void BRepBuilderAPI_FastSewing::FS_Face:: + CreateTopologicalWire(const NCollection_Vector& theEdgeVec, + const Standard_Real theToler) +{ + TopLoc_Location aLocation; + //3D-curves in 1st and 2nd faces are considered to be in same-range + const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface(mySrcFace, aLocation); + Standard_Real aUf = 0.0, aUl = 0.0, aVf = 0.0, aVl = 0.0; + aSurf->Bounds(aUf, aUl, aVf, aVl); + + BRep_Builder aB; + aB.MakeWire(myWire); + for(Standard_Integer anEdge = 0; anEdge < 4; anEdge++) + { + Standard_ProgramError_Raise_if(myEdges[anEdge] < 0, + "BRepBuilderAPI_FastSewing::FS_Face::CreateTopologicalWire: Wire is not closed."); + + const BRepBuilderAPI_FastSewing::FS_Edge& aFSEdge = theEdgeVec.Value(myEdges[anEdge]); + TopAbs_Orientation anOri = anEdge < 2 ? TopAbs_FORWARD : TopAbs_REVERSED; + TopoDS_Edge anTopE = aFSEdge.myTopoEdge; + + if(aFSEdge.IsDegenerated()) + { + anTopE.Orientation(anOri); + aB.Add(myWire, anTopE); + continue; + } + + //Check if 3D and 2D-curve have same-orientation. + //If it is not, 2d-curve will be reversed. + { + Standard_Real aFirstPar = 0.0, aLastPar = 0.0; + + const Handle(Geom_Curve) a3dCurv = BRep_Tool::Curve(anTopE, aFirstPar, aLastPar); + Handle(Geom2d_Curve) a2dCurv = Get2DCurve(anEdge, aUf, aUl, aVf, aVl); + const gp_Pnt aPref(a3dCurv->Value(aFirstPar)); + const gp_Pnt2d aP2df(a2dCurv->Value(aFirstPar)), aP2dl(a2dCurv->Value(aLastPar)); + gp_Pnt aP3df(aSurf->Value(aP2df.X(), aP2df.Y())); + gp_Pnt aP3dl(aSurf->Value(aP2dl.X(), aP2dl.Y())); + aP3df.Transform(aLocation); + aP3dl.Transform(aLocation); + const Standard_Real aSqD1 = aP3df.SquareDistance(aPref); + const Standard_Real aSqD2 = aP3dl.SquareDistance(aPref); + + if(aSqD2 < aSqD1) + { + a2dCurv = Get2DCurve(anEdge, aUf, aUl, aVf, aVl, Standard_True); + anOri = TopAbs::Reverse(anOri); + } + + aB.UpdateEdge(anTopE, a2dCurv, aSurf, aLocation, theToler); + } + + anTopE.Orientation(anOri); + + aB.Add(myWire, anTopE); + } + + myWire.Closed(Standard_True); +} + +//======================================================================= +//function : ::FS_Face::CreateTopologicalFace +//purpose : +//======================================================================= +void BRepBuilderAPI_FastSewing::FS_Face::CreateTopologicalFace() +{ + Standard_ProgramError_Raise_if(myWire.IsNull(), + "BRepBuilderAPI_FastSewing::FS_Face::CreateTopologicalFace: Cannot create wire."); + + BRep_Builder aBuilder; + myRetFace = TopoDS::Face(mySrcFace.EmptyCopied()); + aBuilder.Add(myRetFace, myWire); + aBuilder.NaturalRestriction(myRetFace, Standard_True); +} diff --git a/src/BRepBuilderAPI/BRepBuilderAPI_FastSewing.hxx b/src/BRepBuilderAPI/BRepBuilderAPI_FastSewing.hxx new file mode 100644 index 0000000000..b0294802dd --- /dev/null +++ b/src/BRepBuilderAPI/BRepBuilderAPI_FastSewing.hxx @@ -0,0 +1,306 @@ +//! Created on: 2015-04-24 +//! Created by: NIKOLAI BUKHALOV +//! Copyright (c) 2015 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. + +#ifndef _BRepBuilderAPI_FastSewing_HeaderFile +#define _BRepBuilderAPI_FastSewing_HeaderFile + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +class Handle(NCollection_IncAllocator); +class Handle(Geom_Surface); + +//! This class performs fast sewing of surfaces (faces). It supposes +//! that all surfaces are finite and are naturally restricted by their bounds. +//! Moreover, it supposes that stitched together surfaces have the same parameterization +//! along common boundaries, therefore it does not perform time-consuming check for +//! SameParameter property of edges. +//! +//! For sewing, use this function as following: +//! - set tolerance value (default tolerance is 1.E-06) +//! - add all necessary surfaces (faces) +//! - check status if adding is correctly completed. +//! - compute -> Perform +//! - retrieve the error status if any +//! - retrieve the resulted shape +class BRepBuilderAPI_FastSewing : public Standard_Transient +{ +public: + typedef unsigned int FS_VARStatuses; + + //! Enumeration of result statuses + //ATTENTION!!! If you add new status, please + // describe it in GetStatuses() method + enum FS_Statuses + { + FS_OK = 0x00000000, + FS_Degenerated = 0x00000001, + FS_FindVertexError = 0x00000002, + FS_FindEdgeError = 0x00000004, + FS_FaceWithNullSurface = 0x00000008, + FS_NotNaturalBoundsFace = 0x00000010, + FS_InfiniteSurface = 0x00000020, + FS_EmptyInput = 0x00000040, + FS_Exception = 0x00000080 + }; + + + //! Creates an object with tolerance of connexity + Standard_EXPORT BRepBuilderAPI_FastSewing(const Standard_Real theTolerance = 1.0e-06); + + //! Adds faces of a shape + Standard_EXPORT Standard_Boolean Add(const TopoDS_Shape& theShape); + + //! Adds a surface + Standard_EXPORT Standard_Boolean Add(const Handle(Geom_Surface)& theSurface); + + //! Compute resulted shape + Standard_EXPORT void Perform (void) ; + + //! Sets tolerance + void SetTolerance (const Standard_Real theToler) + { + myTolerance = theToler; + } + + //! Returns tolerance + Standard_Real GetTolerance() const + { + return myTolerance; + } + + //! Returns resulted shape + const TopoDS_Shape& GetResult() const + { + return myResShape; + } + + //! Returns list of statuses. Print message if theOS != 0 + Standard_EXPORT FS_VARStatuses GetStatuses(Standard_OStream* const theOS = 0); + + DEFINE_STANDARD_RTTI(BRepBuilderAPI_FastSewing) + +protected: + class NodeInspector; + + Standard_EXPORT void FindVertexes(const Standard_Integer theSurfID, + NCollection_CellFilter& theCells); + Standard_EXPORT void FindEdges(const Standard_Integer theSurfID); + Standard_EXPORT void UpdateEdgeInfo(const Standard_Integer theIDPrevVertex, + const Standard_Integer theIDCurrVertex, + const Standard_Integer theFaceID, + const Standard_Integer theIDCurvOnFace); + Standard_EXPORT void CreateNewEdge( const Standard_Integer theIDPrevVertex, + const Standard_Integer theIDCurrVertex, + const Standard_Integer theFaceID, + const Standard_Integer theIDCurvOnFace); + + Standard_EXPORT Standard_Real Compute3DRange(); + + //! Sets status. Returns numeric value of the status set + FS_VARStatuses SetStatus(FS_Statuses theStatus) + { + const FS_VARStatuses aStatusID = (FS_VARStatuses)(theStatus); + myStatusList |= aStatusID; + return aStatusID; + } + + class FS_Edge; + + // Classes FS_Vertex, FS_Face and FS_Edge keep information about + // relations between resulted members (e.g. which faces share this vertex? etc.) + + //! The struct corresponding to a vertex + struct FS_Vertex + { + public: + FS_Vertex(): myID(-1){}; + + //! Creates topological member (vertex) + void CreateTopologicalVertex(const Standard_Real theToler) + { + BRep_Builder aBuilder; + aBuilder.MakeVertex(myTopoVert, myPnt, theToler); + } + + //! Geometry point of this Vertex + gp_Pnt myPnt; + TopoDS_Vertex myTopoVert; + + //! List of faces and edges which share this vertex + NCollection_List myFaces; + NCollection_List myEdges; + + //! Indentifies the place of this Vertex in + //! BRepBuilderAPI_FastSewing::myVertexVec list + Standard_Integer myID; + }; + + //! The struct corresponding to an face + struct FS_Face + { + FS_Face(): myID(-1) + { + for (Standard_Integer i = 0; i < 4; i++) + { + myVertices[i] = -1; + myEdges[i] = -1; + } + }; + //! Creates topological members (wire and face) + void CreateTopologicalWire(const NCollection_Vector& theEdgeVec, + const Standard_Real theToler); + void CreateTopologicalFace(); + + //! Sets vertex + void SetVertex(const Standard_Integer thePlaceID, const Standard_Integer theVertID) + { + Standard_RangeError_Raise_if((thePlaceID < 0) || (thePlaceID > 3), + "FS_Face::SetVertex(): OUT of Range"); + + myVertices[thePlaceID] = theVertID; + } + + //! Sets edge + void SetEdge(const Standard_Integer thePlaceID, const Standard_Integer theEdgeID) + { + Standard_RangeError_Raise_if((thePlaceID < 0) || (thePlaceID > 3), + "FS_Face::SetEdge(): OUT of Range"); + + myEdges[thePlaceID] = theEdgeID; + } + + TopoDS_Face mySrcFace; + TopoDS_Wire myWire; + TopoDS_Face myRetFace; + + //! myEdges[i] number of the edge in myEdgeVec + //! (i==0) <-> (V=Vf); (i==1) <-> (U=Ul); + //! (i==2) <-> (V=Vl); (i==3) <-> (U=Uf) + Standard_Integer myEdges[4]; + //! myVertices[i] is Start point of myEdges[i] + Standard_Integer myVertices[4]; + + //! Indentifies the place of this Face in + //! BRepBuilderAPI_FastSewing::myFaceVec list + Standard_Integer myID; + }; + + //! The struct corresponding to a edge + class FS_Edge + { + public: + FS_Edge(): myID(-1) + { + myVertices[0] = -1; + myVertices[1] = -1; + } + + FS_Edge(const Standard_Integer theIDVert1, const Standard_Integer theIDVert2): myID(-1) + { + myVertices[0] = theIDVert1; + myVertices[1] = theIDVert2; + }; + + //! Creates topological member (TopoDS_Edge) + void CreateTopologicalEdge( const NCollection_Vector& theVertexVec, + const NCollection_Vector& theFaceVec, + const Standard_Real theTol); + + //! Sets vertex + void SetVertex(const Standard_Integer thePlaceID, const Standard_Integer theVertID) + { + Standard_RangeError_Raise_if((thePlaceID < 0) || (thePlaceID > 1), + "FS_Face::SetVertex(): OUT of Range"); + + myVertices[thePlaceID] = theVertID; + } + + Standard_Boolean IsDegenerated() const + { + return (myVertices[0] == myVertices[1]); + } + + //! List of faces which are shared with this edge + //! Value is the index of this shape in myFaceVec array + NCollection_Sequence myFaces; + + //! Indentifies the place of this Edge in + //! BRepBuilderAPI_FastSewing::myEdgeVec list + Standard_Integer myID; + + TopoDS_Edge myTopoEdge; + private: + //! Index of the vertex in myVertexVec array + Standard_Integer myVertices[2]; + }; + + //! This inspector will find a node nearest to the given point + //! not far than on the given tolerance + class NodeInspector: public NCollection_CellFilter_InspectorXYZ + { + public: + typedef Standard_Integer Target; + + NodeInspector(const NCollection_Vector& theVec, + const gp_Pnt& thePnt, const Standard_Real theTol); + + Standard_EXPORT NCollection_CellFilter_Action Inspect (const Target theId); + + Target GetResult() + { + return myResID; + } + + private: + NodeInspector& operator = (const NodeInspector&); + const NCollection_Vector& myVecOfVertexes; + gp_Pnt myPoint; + Standard_Real mySQToler; + Target myResID; + Standard_Boolean myIsFindingEnable; + }; +private: + TopoDS_Shape myResShape; + + // myFaceVec, myVertexVec and myEdgeVec lists are filled only once!!!!! + + //! Vector of faces + NCollection_Vector myFaceVec; + //! Vector of Vertices + NCollection_Vector myVertexVec; + //! Vector of edges + NCollection_Vector myEdgeVec; + + //! Tolerance + Standard_Real myTolerance; + + //! Bits of computation status + FS_VARStatuses myStatusList; +}; + +#endif // _BRepBuilderAPI_FastSewing_HeaderFile + +DEFINE_STANDARD_HANDLE(BRepBuilderAPI_FastSewing, Standard_Transient) diff --git a/src/BRepBuilderAPI/FILES b/src/BRepBuilderAPI/FILES index 73da8c6755..912105931c 100644 --- a/src/BRepBuilderAPI/FILES +++ b/src/BRepBuilderAPI/FILES @@ -1,4 +1,5 @@ BRepBuilderAPI_VertexInspector.hxx BRepBuilderAPI_CellFilter.hxx BRepBuilderAPI_BndBoxTreeSelector.hxx - +BRepBuilderAPI_FastSewing.hxx +BRepBuilderAPI_FastSewing.cxx diff --git a/src/BRepLib/BRepLib.cdl b/src/BRepLib/BRepLib.cdl index cc7935ea9e..ac0bce61a2 100644 --- a/src/BRepLib/BRepLib.cdl +++ b/src/BRepLib/BRepLib.cdl @@ -311,5 +311,14 @@ is ---Purpose: Sorts in LF the Faces of S on the reverse -- complexity of their surfaces -- (other,Torus,Sphere,Cone,Cylinder,Plane) - + + EnsureNormalConsistency (S : Shape from TopoDS; + theAngTol: Real from Standard = 0.001; + ForceComputeNormals: Boolean from Standard = Standard_False) + returns Boolean; + ---Purpose: Corrects the normals in Poly_Triangulation of faces, + -- in such way that normals at nodes lying along smooth + -- edges have the same value on both adjacent triangulations. + -- Returns TRUE if any correction is done. + end BRepLib; diff --git a/src/BRepLib/BRepLib.cxx b/src/BRepLib/BRepLib.cxx index 3cfa3d2605..bb2d97b2df 100644 --- a/src/BRepLib/BRepLib.cxx +++ b/src/BRepLib/BRepLib.cxx @@ -82,6 +82,10 @@ #include #include +#include +#include +#include +#include // TODO - not thread-safe static variables static Standard_Real thePrecision = Precision::Confusion(); @@ -1657,6 +1661,146 @@ void BRepLib::EncodeRegularity(TopoDS_Edge& E, } } +//======================================================================= +// function : EnsureNormalConsistency +// purpose : Corrects the normals in Poly_Triangulation of faces. +// Returns TRUE if any correction is done. +//======================================================================= +Standard_Boolean BRepLib:: + EnsureNormalConsistency(const TopoDS_Shape& theShape, + const Standard_Real theAngTol, + const Standard_Boolean theForceComputeNormals) +{ + const Standard_Real aThresDot = cos(theAngTol); + + Standard_Boolean aRetVal = Standard_False, isNormalsFound = Standard_False; + + // compute normals if they are absent + TopExp_Explorer anExpFace(theShape,TopAbs_FACE); + for (; anExpFace.More(); anExpFace.Next()) + { + const TopoDS_Face& aFace = TopoDS::Face(anExpFace.Current()); + const Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace); + if(aSurf.IsNull()) + continue; + TopLoc_Location aLoc; + const Handle(Poly_Triangulation)& aPT = BRep_Tool::Triangulation(aFace, aLoc); + if(aPT.IsNull()) + continue; + if (!theForceComputeNormals && aPT->HasNormals()) + { + isNormalsFound = Standard_True; + continue; + } + + GeomLProp_SLProps aSLP(aSurf, 2, Precision::Confusion()); + const Standard_Integer anArrDim = 3*aPT->NbNodes(); + Handle(TShort_HArray1OfShortReal) aNormArr = new TShort_HArray1OfShortReal(1, anArrDim); + Standard_Integer anNormInd = aNormArr->Lower(); + for(Standard_Integer i = aPT->UVNodes().Lower(); i <= aPT->UVNodes().Upper(); i++) + { + const gp_Pnt2d &aP2d = aPT->UVNodes().Value(i); + aSLP.SetParameters(aP2d.X(), aP2d.Y()); + + gp_XYZ aNorm(0.,0.,0.); + if(!aSLP.IsNormalDefined()) + { +#ifdef OCCT_DEBUG + cout << "BRepLib::EnsureNormalConsistency(): Cannot find normal!" << endl; +#endif + } + else + { + aNorm = aSLP.Normal().XYZ(); + if (aFace.Orientation() == TopAbs_REVERSED) + aNorm.Reverse(); + } + aNormArr->ChangeValue(anNormInd++) = static_cast(aNorm.X()); + aNormArr->ChangeValue(anNormInd++) = static_cast(aNorm.Y()); + aNormArr->ChangeValue(anNormInd++) = static_cast(aNorm.Z()); + } + + aRetVal = Standard_True; + isNormalsFound = Standard_True; + aPT->SetNormals(aNormArr); + } + + if(!isNormalsFound) + { + return aRetVal; + } + + // loop by edges + TopTools_IndexedDataMapOfShapeListOfShape aMapEF; + TopExp::MapShapesAndAncestors(theShape,TopAbs_EDGE,TopAbs_FACE,aMapEF); + for(Standard_Integer anInd = 1; anInd <= aMapEF.Extent(); anInd++) + { + const TopoDS_Edge& anEdg = TopoDS::Edge(aMapEF.FindKey(anInd)); + const TopTools_ListOfShape& anEdgList = aMapEF.FindFromIndex(anInd); + if (anEdgList.Extent() != 2) + continue; + TopTools_ListIteratorOfListOfShape anItF(anEdgList); + const TopoDS_Face aFace1 = TopoDS::Face(anItF.Value()); + anItF.Next(); + const TopoDS_Face aFace2 = TopoDS::Face(anItF.Value()); + TopLoc_Location aLoc1, aLoc2; + const Handle(Poly_Triangulation)& aPT1 = BRep_Tool::Triangulation(aFace1, aLoc1); + const Handle(Poly_Triangulation)& aPT2 = BRep_Tool::Triangulation(aFace2, aLoc2); + + if(aPT1.IsNull() || aPT2.IsNull()) + continue; + + if(!aPT1->HasNormals() || !aPT2->HasNormals()) + continue; + + const Handle(Poly_PolygonOnTriangulation)& aPTEF1 = + BRep_Tool::PolygonOnTriangulation(anEdg, aPT1, aLoc1); + const Handle(Poly_PolygonOnTriangulation)& aPTEF2 = + BRep_Tool::PolygonOnTriangulation(anEdg, aPT2, aLoc2); + + TShort_Array1OfShortReal& aNormArr1 = aPT1->ChangeNormals(); + TShort_Array1OfShortReal& aNormArr2 = aPT2->ChangeNormals(); + + for(Standard_Integer anEdgNode = aPTEF1->Nodes().Lower(); + anEdgNode <= aPTEF1->Nodes().Upper(); anEdgNode++) + { + //Number of node + const Standard_Integer aFNodF1 = aPTEF1->Nodes().Value(anEdgNode); + const Standard_Integer aFNodF2 = aPTEF2->Nodes().Value(anEdgNode); + + const Standard_Integer aFNorm1FirstIndex = aNormArr1.Lower() + 3* + (aFNodF1 - aPT1->Nodes().Lower()); + const Standard_Integer aFNorm2FirstIndex = aNormArr2.Lower() + 3* + (aFNodF2 - aPT2->Nodes().Lower()); + + gp_XYZ aNorm1(aNormArr1.Value(aFNorm1FirstIndex), + aNormArr1.Value(aFNorm1FirstIndex+1), + aNormArr1.Value(aFNorm1FirstIndex+2)); + gp_XYZ aNorm2(aNormArr2.Value(aFNorm2FirstIndex), + aNormArr2.Value(aFNorm2FirstIndex+1), + aNormArr2.Value(aFNorm2FirstIndex+2)); + const Standard_Real aDot = aNorm1 * aNorm2; + + if(aDot > aThresDot) + { + gp_XYZ aNewNorm = (aNorm1 + aNorm2).Normalized(); + aNormArr1.ChangeValue(aFNorm1FirstIndex) = + aNormArr2.ChangeValue(aFNorm2FirstIndex) = + static_cast(aNewNorm.X()); + aNormArr1.ChangeValue(aFNorm1FirstIndex+1) = + aNormArr2.ChangeValue(aFNorm2FirstIndex+1) = + static_cast(aNewNorm.Y()); + aNormArr1.ChangeValue(aFNorm1FirstIndex+2) = + aNormArr2.ChangeValue(aFNorm2FirstIndex+2) = + static_cast(aNewNorm.Z()); + aRetVal = Standard_True; + } + } + } + + return aRetVal; +} + //======================================================================= //function : SortFaces //purpose : diff --git a/src/BRepTest/BRepTest_SurfaceCommands.cxx b/src/BRepTest/BRepTest_SurfaceCommands.cxx index cf26e9411e..72ec47096c 100644 --- a/src/BRepTest/BRepTest_SurfaceCommands.cxx +++ b/src/BRepTest/BRepTest_SurfaceCommands.cxx @@ -42,6 +42,8 @@ #include #include #include +#include +#include #ifdef _WIN32 //#define strcasecmp strcmp Already defined @@ -404,6 +406,66 @@ static Standard_Integer sewing (Draw_Interpretor& theDi, return 0; } +//======================================================================= +//function : fastsewing +//purpose : +//======================================================================= +Standard_Integer fastsewing (Draw_Interpretor& theDI, + Standard_Integer theNArg, + const char** theArgVal) +{ + if(theNArg < 3) + { + // 0 1 2 3 4 + theDI << "Use: fastsewing result [-tol ] \n"; + return 1; + } + + BRepBuilderAPI_FastSewing aFS; + + Standard_Integer aStartIndex = 2; + + if(!strcmp(theArgVal[aStartIndex], "-tol")) + { + aFS.SetTolerance(Draw::Atof (theArgVal[aStartIndex+1])); + aStartIndex = 4; + } + + for(Standard_Integer i = aStartIndex; i < theNArg; i++) + { + TopoDS_Shape aS = DBRep::Get(theArgVal[i]); + + if(!aFS.Add(aS)) + { + theDI << "Face is not added. See statuses.\n"; + } + } + + BRepBuilderAPI_FastSewing::FS_VARStatuses aStatus = aFS.GetStatuses(); + + if(aStatus) + { + theDI << "Error: There are some problems while adding (" << + (static_cast(aStatus)) << ")\n"; + aFS.GetStatuses(&cout); + } + + aFS.Perform(); + + aStatus = aFS.GetStatuses(); + + if(aStatus) + { + theDI << "Error: There are some problems while performing (" << + (static_cast(aStatus)) << ")\n"; + aFS.GetStatuses(&cout); + } + + DBRep::Set(theArgVal[1], aFS.GetResult()); + + return 0; +} + //======================================================================= // continuity //======================================================================= @@ -508,5 +570,8 @@ void BRepTest::SurfaceCommands(Draw_Interpretor& theCommands) theCommands.Add("encoderegularity", "encoderegularity shape [tolerance (in degree)]", __FILE__,encoderegularity, g); + + theCommands.Add ("fastsewing", "fastsewing result [-tol ] ", + __FILE__, fastsewing, g); } diff --git a/src/MeshTest/MeshTest.cxx b/src/MeshTest/MeshTest.cxx index cb030ebc65..103ffc6988 100644 --- a/src/MeshTest/MeshTest.cxx +++ b/src/MeshTest/MeshTest.cxx @@ -81,6 +81,7 @@ #include #include #include +#include //epa Memory leaks test @@ -1589,6 +1590,31 @@ Standard_Integer triedgepoints(Draw_Interpretor& di, Standard_Integer nbarg, con return 0; } +//======================================================================= +//function : correctnormals +//purpose : Corrects normals in shape triangulation nodes (...) +//======================================================================= +Standard_Integer correctnormals (Draw_Interpretor& theDI, + Standard_Integer /*theNArg*/, + const char** theArgVal) +{ + TopoDS_Shape S = DBRep::Get(theArgVal[1]); + + //Use "correctnormals shape" + + + if(!BRepLib::EnsureNormalConsistency(S)) + { + theDI << "Normals have not been changed!\n"; + } + else + { + theDI << "Some corrections in source shape have been made!\n"; + } + + return 0; +} + //======================================================================= void MeshTest::Commands(Draw_Interpretor& theCommands) //======================================================================= @@ -1623,6 +1649,8 @@ void MeshTest::Commands(Draw_Interpretor& theCommands) theCommands.Add("onetriangulation","onetriangulation name",__FILE__, onetriangulation, g); theCommands.Add("triepoints", "triepoints shape1 [shape2 ...]",__FILE__, triedgepoints, g); + theCommands.Add("correctnormals", "correctnormals shape",__FILE__, correctnormals, g); + #if 0 theCommands.Add("extrema","extrema ",__FILE__, extrema, g); theCommands.Add("vb","vb ",__FILE__, vb, g); diff --git a/tests/sewing/fast/A1 b/tests/sewing/fast/A1 new file mode 100644 index 0000000000..cc0fbf6aa7 --- /dev/null +++ b/tests/sewing/fast/A1 @@ -0,0 +1,49 @@ +if { [regexp {Debug mode} [dversion]] } { + if { [regexp {Windows} [dversion]] } { + set max_time 9 + } else { + set max_time 9 + } +} else { + if { [regexp {Windows} [dversion]] } { + set max_time 3 + } else { + set max_time 3 + } +} + +restore [locate_data_file 5000-12.brep] a + +dchrono ch reset +dchrono ch start +puts [fastsewing result -tol 2.0e-5 a] +dchrono ch stop + +set q [dchrono ch show] + +regexp {CPU user time: ([-0-9.+eE]+) seconds} $q full z +puts "$z" + +if { $z > ${max_time} } { + puts "Elapsed time is more than ${max_time} seconds - Error" +} else { + puts "Elapsed time is less than ${max_time} seconds - OK" +} + +donly result +checkshape result + +set nbshapes_expected " +Number of shapes in shape + VERTEX : 5556 + EDGE : 11118 + WIRE : 5552 + FACE : 5552 + SHELL : 1 + SOLID : 0 + COMPSOLID : 0 + COMPOUND : 1 + SHAPE : 27780 +" + +checknbshapes result -ref "${nbshapes_expected}" -t -m "Partition of 2 shapes" diff --git a/tests/sewing/fast/A2 b/tests/sewing/fast/A2 new file mode 100644 index 0000000000..9fbef2abf7 --- /dev/null +++ b/tests/sewing/fast/A2 @@ -0,0 +1,49 @@ +if { [regexp {Debug mode} [dversion]] } { + if { [regexp {Windows} [dversion]] } { + set max_time 9 + } else { + set max_time 9 + } +} else { + if { [regexp {Windows} [dversion]] } { + set max_time 3 + } else { + set max_time 3 + } +} + +restore [locate_data_file 5000-16.brep] a + +dchrono ch reset +dchrono ch start +puts [fastsewing result -tol 2.0e-5 a] +dchrono ch stop + +set q [dchrono ch show] + +regexp {CPU user time: ([-0-9.+eE]+) seconds} $q full z +puts "$z" + +if { $z > ${max_time} } { + puts "Elapsed time is more than ${max_time} seconds - Error" +} else { + puts "Elapsed time is less than ${max_time} seconds - OK" +} + +donly result +checkshape result + +set nbshapes_expected " +Number of shapes in shape + VERTEX : 5527 + EDGE : 11056 + WIRE : 5520 + FACE : 5520 + SHELL : 1 + SOLID : 0 + COMPSOLID : 0 + COMPOUND : 1 + SHAPE : 27625 +" + +checknbshapes result -ref "${nbshapes_expected}" -t -m "Partition of 2 shapes" diff --git a/tests/sewing/fast/A3 b/tests/sewing/fast/A3 new file mode 100644 index 0000000000..21e26ab458 --- /dev/null +++ b/tests/sewing/fast/A3 @@ -0,0 +1,49 @@ +if { [regexp {Debug mode} [dversion]] } { + if { [regexp {Windows} [dversion]] } { + set max_time 9 + } else { + set max_time 9 + } +} else { + if { [regexp {Windows} [dversion]] } { + set max_time 3 + } else { + set max_time 3 + } +} + +restore [locate_data_file Cover_VXmodel.brep] a + +dchrono ch reset +dchrono ch start +puts [fastsewing result -tol 1.5e-4 a] +dchrono ch stop + +set q [dchrono ch show] + +regexp {CPU user time: ([-0-9.+eE]+) seconds} $q full z +puts "$z" + +if { $z > ${max_time} } { + puts "Elapsed time is more than ${max_time} seconds - Error" +} else { + puts "Elapsed time is less than ${max_time} seconds - OK" +} + +donly result +checkshape result + +set nbshapes_expected " +Number of shapes in shape + VERTEX : 844 + EDGE : 1592 + WIRE : 749 + FACE : 749 + SHELL : 1 + SOLID : 0 + COMPSOLID : 0 + COMPOUND : 1 + SHAPE : 3936 +" + +checknbshapes result -ref "${nbshapes_expected}" -t -m "Partition of 2 shapes" diff --git a/tests/sewing/fast/A4 b/tests/sewing/fast/A4 new file mode 100644 index 0000000000..e85a31e8e6 --- /dev/null +++ b/tests/sewing/fast/A4 @@ -0,0 +1,49 @@ +if { [regexp {Debug mode} [dversion]] } { + if { [regexp {Windows} [dversion]] } { + set max_time 9 + } else { + set max_time 9 + } +} else { + if { [regexp {Windows} [dversion]] } { + set max_time 3 + } else { + set max_time 3 + } +} + +restore [locate_data_file Mustang_250.brep] a + +dchrono ch reset +dchrono ch start +puts [fastsewing result -tol 2.5e-4 a] +dchrono ch stop + +set q [dchrono ch show] + +regexp {CPU user time: ([-0-9.+eE]+) seconds} $q full z +puts "$z" + +if { $z > ${max_time} } { + puts "Elapsed time is more than ${max_time} seconds - Error" +} else { + puts "Elapsed time is less than ${max_time} seconds - OK" +} + +donly result +checkshape result + +set nbshapes_expected " +Number of shapes in shape + VERTEX : 250 + EDGE : 496 + WIRE : 248 + FACE : 248 + SHELL : 1 + SOLID : 0 + COMPSOLID : 0 + COMPOUND : 1 + SHAPE : 1244 +" + +checknbshapes result -ref "${nbshapes_expected}" -t -m "Partition of 2 shapes" diff --git a/tests/sewing/fast/A5 b/tests/sewing/fast/A5 new file mode 100644 index 0000000000..629ff635c0 --- /dev/null +++ b/tests/sewing/fast/A5 @@ -0,0 +1,49 @@ +if { [regexp {Debug mode} [dversion]] } { + if { [regexp {Windows} [dversion]] } { + set max_time 9 + } else { + set max_time 9 + } +} else { + if { [regexp {Windows} [dversion]] } { + set max_time 3 + } else { + set max_time 3 + } +} + +restore [locate_data_file Mustang_500.brep] a + +dchrono ch reset +dchrono ch start +puts [fastsewing result -tol 7.0e-5 a] +dchrono ch stop + +set q [dchrono ch show] + +regexp {CPU user time: ([-0-9.+eE]+) seconds} $q full z +puts "$z" + +if { $z > ${max_time} } { + puts "Elapsed time is more than ${max_time} seconds - Error" +} else { + puts "Elapsed time is less than ${max_time} seconds - OK" +} + +donly result +checkshape result + +set nbshapes_expected " +Number of shapes in shape + VERTEX : 514 + EDGE : 1024 + WIRE : 512 + FACE : 512 + SHELL : 1 + SOLID : 0 + COMPSOLID : 0 + COMPOUND : 1 + SHAPE : 2564 +" + +checknbshapes result -ref "${nbshapes_expected}" -t -m "Partition of 2 shapes" diff --git a/tests/sewing/fast/A6 b/tests/sewing/fast/A6 new file mode 100644 index 0000000000..9de064b496 --- /dev/null +++ b/tests/sewing/fast/A6 @@ -0,0 +1,49 @@ +if { [regexp {Debug mode} [dversion]] } { + if { [regexp {Windows} [dversion]] } { + set max_time 9 + } else { + set max_time 9 + } +} else { + if { [regexp {Windows} [dversion]] } { + set max_time 3 + } else { + set max_time 3 + } +} + +restore [locate_data_file Pipe_Full.brep] a + +dchrono ch reset +dchrono ch start +puts [fastsewing result -tol 5.0e-4 a] +dchrono ch stop + +set q [dchrono ch show] + +regexp {CPU user time: ([-0-9.+eE]+) seconds} $q full z +puts "$z" + +if { $z > ${max_time} } { + puts "Elapsed time is more than ${max_time} seconds - Error" +} else { + puts "Elapsed time is less than ${max_time} seconds - OK" +} + +donly result +checkshape result + +set nbshapes_expected " +Number of shapes in shape + VERTEX : 5327 + EDGE : 10656 + WIRE : 5326 + FACE : 5326 + SHELL : 1 + SOLID : 0 + COMPSOLID : 0 + COMPOUND : 1 + SHAPE : 26637 +" + +checknbshapes result -ref "${nbshapes_expected}" -t -m "Partition of 2 shapes" diff --git a/tests/sewing/fast/A7 b/tests/sewing/fast/A7 new file mode 100644 index 0000000000..7ee885eaad --- /dev/null +++ b/tests/sewing/fast/A7 @@ -0,0 +1,49 @@ +if { [regexp {Debug mode} [dversion]] } { + if { [regexp {Windows} [dversion]] } { + set max_time 9 + } else { + set max_time 9 + } +} else { + if { [regexp {Windows} [dversion]] } { + set max_time 3 + } else { + set max_time 3 + } +} + +restore [locate_data_file Pipe_Partial.brep] a + +dchrono ch reset +dchrono ch start +puts [fastsewing result -tol 5.1e-4 a] +dchrono ch stop + +set q [dchrono ch show] + +regexp {CPU user time: ([-0-9.+eE]+) seconds} $q full z +puts "$z" + +if { $z > ${max_time} } { + puts "Elapsed time is more than ${max_time} seconds - Error" +} else { + puts "Elapsed time is less than ${max_time} seconds - OK" +} + +donly result +checkshape result + +set nbshapes_expected " +Number of shapes in shape + VERTEX : 5994 + EDGE : 11715 + WIRE : 5698 + FACE : 5698 + SHELL : 3 + SOLID : 0 + COMPSOLID : 0 + COMPOUND : 1 + SHAPE : 29109 +" + +checknbshapes result -ref "${nbshapes_expected}" -t -m "Partition of 2 shapes" diff --git a/tests/sewing/grids.list b/tests/sewing/grids.list index ed36e9594b..5df61fab64 100755 --- a/tests/sewing/grids.list +++ b/tests/sewing/grids.list @@ -1,3 +1,4 @@ 001 tol_0_01 002 tol_1 003 tol_100 +004 fast -- 2.20.1