0026118: Implement FastSewing algorithm
authornbv <nbv@opencascade.com>
Wed, 6 May 2015 13:58:48 +0000 (16:58 +0300)
committerbugmaster <bugmaster@opencascade.com>
Wed, 6 May 2015 13:59:57 +0000 (16:59 +0300)
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

16 files changed:
src/BRepBuilderAPI/BRepBuilderAPI.cdl
src/BRepBuilderAPI/BRepBuilderAPI_FastSewing.cxx [new file with mode: 0644]
src/BRepBuilderAPI/BRepBuilderAPI_FastSewing.hxx [new file with mode: 0644]
src/BRepBuilderAPI/FILES
src/BRepLib/BRepLib.cdl
src/BRepLib/BRepLib.cxx
src/BRepTest/BRepTest_SurfaceCommands.cxx
src/MeshTest/MeshTest.cxx
tests/sewing/fast/A1 [new file with mode: 0644]
tests/sewing/fast/A2 [new file with mode: 0644]
tests/sewing/fast/A3 [new file with mode: 0644]
tests/sewing/fast/A4 [new file with mode: 0644]
tests/sewing/fast/A5 [new file with mode: 0644]
tests/sewing/fast/A6 [new file with mode: 0644]
tests/sewing/fast/A7 [new file with mode: 0644]
tests/sewing/grids.list

index 6eabd73..a61c6bc 100644 (file)
@@ -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 (file)
index 0000000..b68b785
--- /dev/null
@@ -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 <BRepBuilderAPI_FastSewing.hxx>
+
+#include <BRepTools_Quilt.hxx>
+#include <Bnd_Box.hxx>
+
+#include <Geom2d_Line.hxx>
+#include <Geom2d_TrimmedCurve.hxx>
+#include <Geom_Curve.hxx>
+#include <Geom_RectangularTrimmedSurface.hxx>
+#include <Geom_Surface.hxx>
+
+#include <Precision.hxx>
+
+#include <Standard_NullObject.hxx>
+
+#include <TopExp_Explorer.hxx>
+#include <TopoDS.hxx>
+#include <TopTools_MapOfShape.hxx>
+
+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<Standard_Integer>& theSet1,
+                          const NCollection_List<Standard_Integer>& theSet2)
+{
+  const Standard_Integer anIntMax = IntegerLast();
+  Standard_Integer aRetVal = anIntMax;
+  for(NCollection_List<Standard_Integer>::Iterator
+                            anIt1 = theSet1.begin().Iterator();
+                            anIt1.More(); anIt1.Next())
+  {
+    const Standard_Integer aVal1 = anIt1.Value();
+    for(NCollection_List<Standard_Integer>::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<NodeInspector> 
+        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<NodeInspector>& 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<FS_Statuses>(0x0001);
+  for(Standard_Integer i = 1; i <= aNumMax; i++,
+                  anIDS = static_cast<FS_Statuses>(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<FS_Vertex>& 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<FS_Vertex>& theVertexVec,
+                                const NCollection_Vector<FS_Face>& 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<FS_Edge>& 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 (file)
index 0000000..b029480
--- /dev/null
@@ -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 <Standard_Transient.hxx>
+#include <BRep_Builder.hxx>
+
+#include <NCollection_List.hxx>
+#include <NCollection_Sequence.hxx>
+#include <NCollection_Vector.hxx>
+#include <NCollection_CellFilter.hxx>
+
+#include <TopoDS_Edge.hxx>
+#include <TopoDS_Face.hxx>
+#include <TopoDS_Vertex.hxx>
+#include <TopoDS_Wire.hxx>
+
+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<NodeInspector>& 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<Standard_Integer> myFaces;
+    NCollection_List<Standard_Integer> 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<FS_Edge>& 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<FS_Vertex>& theVertexVec,
+                                const NCollection_Vector<FS_Face>& 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<Standard_Integer> 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<FS_Vertex>& 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<FS_Vertex>& 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<FS_Face> myFaceVec;
+  //! Vector of Vertices
+  NCollection_Vector<FS_Vertex> myVertexVec;
+  //! Vector of edges
+  NCollection_Vector<FS_Edge> myEdgeVec;
+
+  //! Tolerance
+  Standard_Real myTolerance;
+
+  //! Bits of computation status
+  FS_VARStatuses myStatusList;
+};
+
+#endif // _BRepBuilderAPI_FastSewing_HeaderFile
+
+DEFINE_STANDARD_HANDLE(BRepBuilderAPI_FastSewing, Standard_Transient)
index 73da8c6..9121059 100644 (file)
@@ -1,4 +1,5 @@
 BRepBuilderAPI_VertexInspector.hxx
 BRepBuilderAPI_CellFilter.hxx
 BRepBuilderAPI_BndBoxTreeSelector.hxx
-
+BRepBuilderAPI_FastSewing.hxx
+BRepBuilderAPI_FastSewing.cxx
index cc7935e..ac0bce6 100644 (file)
@@ -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;
index 3cfa3d2..bb2d97b 100644 (file)
 #include <Approx_CurvilinearParameter.hxx>
 #include <Geom_BSplineSurface.hxx>
 
+#include <Poly_Triangulation.hxx>
+#include <TShort_HArray1OfShortReal.hxx>
+#include <GeomLProp_SLProps.hxx>
+#include <Poly_PolygonOnTriangulation.hxx>
 
 // 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<Standard_ShortReal>(aNorm.X());
+      aNormArr->ChangeValue(anNormInd++) = static_cast<Standard_ShortReal>(aNorm.Y());
+      aNormArr->ChangeValue(anNormInd++) = static_cast<Standard_ShortReal>(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<Standard_ShortReal>(aNewNorm.X());
+        aNormArr1.ChangeValue(aFNorm1FirstIndex+1) =
+          aNormArr2.ChangeValue(aFNorm2FirstIndex+1) =
+          static_cast<Standard_ShortReal>(aNewNorm.Y());
+        aNormArr1.ChangeValue(aFNorm1FirstIndex+2) =
+          aNormArr2.ChangeValue(aFNorm2FirstIndex+2) =
+          static_cast<Standard_ShortReal>(aNewNorm.Z());
+        aRetVal = Standard_True;
+      }
+    }
+  }
+
+  return aRetVal;
+}
+
 //=======================================================================
 //function : SortFaces
 //purpose  : 
index cf26e94..72ec470 100644 (file)
@@ -42,6 +42,8 @@
 #include <TopTools_SequenceOfShape.hxx>
 #include <Precision.hxx>
 #include <Draw_ProgressIndicator.hxx>
+#include <NCollection_Vector.hxx>
+#include <BRepBuilderAPI_FastSewing.hxx>
 
 #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 <value>] <list_of_faces>\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<Standard_Integer>(aStatus)) << ")\n";
+    aFS.GetStatuses(&cout);
+  }
+
+  aFS.Perform();
+
+  aStatus = aFS.GetStatuses();
+
+  if(aStatus)
+  {
+    theDI << "Error: There are some problems while performing (" <<
+                        (static_cast<Standard_Integer>(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 <value>] <list_of_faces>", 
+                                                __FILE__, fastsewing, g);
 }
 
index cb030eb..103ffc6 100644 (file)
@@ -81,6 +81,7 @@
 #include <BRepAdaptor_Surface.hxx>
 #include <Bnd_Box.hxx>
 #include <BRepBndLib.hxx>
+#include <BRepLib.hxx>
 
 
 //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 (file)
index 0000000..cc0fbf6
--- /dev/null
@@ -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 (file)
index 0000000..9fbef2a
--- /dev/null
@@ -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 (file)
index 0000000..21e26ab
--- /dev/null
@@ -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 (file)
index 0000000..e85a31e
--- /dev/null
@@ -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 (file)
index 0000000..629ff63
--- /dev/null
@@ -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 (file)
index 0000000..9de064b
--- /dev/null
@@ -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 (file)
index 0000000..7ee885e
--- /dev/null
@@ -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"
index ed36e95..5df61fa 100755 (executable)
@@ -1,3 +1,4 @@
 001 tol_0_01
 002 tol_1
 003 tol_100
+004 fast