]> OCCT Git - occt-copy.git/commitdiff
Initial implementation of the new offset algorithm.
authoraml <aml@opencascade.com>
Tue, 1 Nov 2016 10:54:05 +0000 (13:54 +0300)
committeraml <aml@opencascade.com>
Wed, 9 Nov 2016 10:07:15 +0000 (13:07 +0300)
Initial implementation of the solid creation mode for the new offset creation algorithm.

src/BRepOffset/BRepOffset_MakeSimpleOffset.cxx [new file with mode: 0644]
src/BRepOffset/BRepOffset_MakeSimpleOffset.hxx [new file with mode: 0644]
src/BRepOffset/BRepOffset_SimpleOffset.cxx [new file with mode: 0644]
src/BRepOffset/BRepOffset_SimpleOffset.hxx [new file with mode: 0644]
src/BRepOffset/FILES [new file with mode: 0644]
src/BRepTest/BRepTest_FeatureCommands.cxx

diff --git a/src/BRepOffset/BRepOffset_MakeSimpleOffset.cxx b/src/BRepOffset/BRepOffset_MakeSimpleOffset.cxx
new file mode 100644 (file)
index 0000000..8617ee0
--- /dev/null
@@ -0,0 +1,587 @@
+// Created on: 2016-10-13
+// Created by: Alexander MALYSHEV
+// Copyright (c) 1995-1999 Matra Datavision
+// Copyright (c) 1999-2016 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 self.
+#include <BRepOffset_MakeSimpleOffset.hxx>
+
+#include <Adaptor3d_CurveOnSurface.hxx>
+#include <BRep_Builder.hxx>
+#include <BRep_Tool.hxx>
+#include <BRepLib.hxx>
+#include <BRepLib_MakeEdge.hxx>
+#include <BRepLib_MakeFace.hxx>
+#include <BRepTools_Quilt.hxx>
+#include <BRepAdaptor_HCurve2d.hxx>
+#include <BRepAdaptor_HSurface.hxx>
+#include <BRepAdaptor_Surface.hxx>
+#include <BRepOffset_SimpleOffset.hxx>
+#include <BRepTools_Modifier.hxx>
+#include <Geom_TrimmedCurve.hxx>
+#include <Geom2d_Line.hxx>
+#include <GeomFill_Generator.hxx>
+#include <Extrema_LocateExtPC.hxx>
+#include <NCollection_List.hxx>
+#include <ShapeAnalysis_FreeBounds.hxx>
+#include <ShapeFix_Edge.hxx>
+#include <TopExp.hxx>
+#include <TopExp_Explorer.hxx>
+#include <TopoDS_Edge.hxx>
+#include <TopoDS_Face.hxx>
+#include <TopoDS.hxx>
+#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
+#include <TopTools_ListIteratorOfListOfShape.hxx>
+
+
+//=============================================================================
+//function : BRepOffset_MakeSimpleOffset
+//purpose  : Constructor
+//=============================================================================
+BRepOffset_MakeSimpleOffset::BRepOffset_MakeSimpleOffset(const TopoDS_Shape& theInputShape,
+                                                         const Standard_Real theOffsetValue)
+: myInputShape(theInputShape),
+  myOffsetValue(theOffsetValue),
+  myIsBuildSolid(Standard_False),
+  myMaxAngle(0.0),
+  myError(BRepOffsetSimple_OK),
+  myIsDone(Standard_False)
+{
+}
+
+//=============================================================================
+//function : GetErrorMessage
+//purpose  :
+//=============================================================================
+TCollection_AsciiString BRepOffset_MakeSimpleOffset::GetErrorMessage() const
+{
+  TCollection_AsciiString anError = "";
+
+  if (myError == BRepOffsetSimple_NullInputShape)
+  {
+    anError = "Null input shape";
+    return anError;
+  }
+  else if (myError == BRepOffsetSimple_ErrorOffsetComputation)
+  {
+    anError = "Error during offset construction";
+    return anError;
+  }
+  else if (myError == BRepOffsetSimple_ErrorWallFaceComputation)
+  {
+    anError = "Error during building wall face";
+    return anError;
+  }
+  else if (myError == BRepOffsetSimple_ErrorInvalidNbShells)
+  {
+    anError = "Result contains two or more shells";
+    return anError;
+  }
+  else if (myError == BRepOffsetSimple_ErrorNonClosedShell)
+  {
+    anError = "Result shell is not closed";
+    return anError;
+  }
+
+  return anError;
+}
+
+//=============================================================================
+//function : Clear
+//purpose  : 
+//=============================================================================
+void BRepOffset_MakeSimpleOffset::Clear()
+{
+  myIsDone = Standard_False;
+  myError = BRepOffsetSimple_OK;
+  myMaxAngle = 0.0;
+  myMapVE.Clear();
+}
+
+//=============================================================================
+//function : GetSafeOffset
+//purpose  : 
+//=============================================================================
+Standard_Real BRepOffset_MakeSimpleOffset::GetSafeOffset(const Standard_Real theExpectedToler)
+{
+  // Compute max angle in faces junctions.
+  if (myMaxAngle == 0.0) // Non-initialized.
+    ComputeMaxAngle();
+
+  const Standard_Real anExpOffset = theExpectedToler / (2.0 * myMaxAngle);
+  return anExpOffset;
+}
+
+//=============================================================================
+//function : Perform
+//purpose  : 
+//=============================================================================
+void BRepOffset_MakeSimpleOffset::Perform()
+{
+  // Clear result of previous computations.
+  Clear();
+
+  // Check shape existence.
+  if (myInputShape.IsNull())
+  {
+    myError = BRepOffsetSimple_NullInputShape;
+    return;
+  }
+
+  if (myMaxAngle == 0.0) // Non-initialized.
+    ComputeMaxAngle();
+
+  Handle(BRepOffset_SimpleOffset) aBuilder = new BRepOffset_SimpleOffset(myInputShape, myOffsetValue);
+  BRepTools_Modifier aModifier(myInputShape, aBuilder);
+
+  if (!aModifier.IsDone())
+  {
+    myError = BRepOffsetSimple_ErrorOffsetComputation;
+    return;
+  }
+
+  myResShape = aModifier.ModifiedShape(myInputShape);
+  
+  // Fix degeneracy. Degenerated edge should be mapped to the degenerated.
+  BRep_Builder aBB;
+  TopExp_Explorer anExpSE(myInputShape, TopAbs_EDGE);
+  for(; anExpSE.More(); anExpSE.Next())
+  {
+    const TopoDS_Edge & aCurrEdge = TopoDS::Edge(anExpSE.Current());
+
+    if (!BRep_Tool::Degenerated(aCurrEdge))
+      continue;
+
+    const TopoDS_Edge & anEdge = TopoDS::Edge(aModifier.ModifiedShape(aCurrEdge));
+    aBB.Degenerated(anEdge, Standard_True);
+  }
+
+  // Restore walls for solid.
+  if (myIsBuildSolid && !BuildMissingWalls(aModifier))
+    return;
+
+  myIsDone = Standard_True;
+}
+
+//=============================================================================
+//function : tgtfaces
+//purpose  : check the angle at the border between two squares.
+//           Two shares should have a shared front edge.
+//=============================================================================
+static void tgtfaces(const TopoDS_Edge& Ed,
+                     const TopoDS_Face& F1,
+                     const TopoDS_Face& F2,
+                     const Standard_Boolean couture,
+                     Standard_Real& theResAngle)
+{
+ // Check that pcurves exist on both faces of edge.
+  Standard_Real aFirst,aLast;
+  Handle(Geom2d_Curve) aCurve;
+  aCurve = BRep_Tool::CurveOnSurface(Ed,F1,aFirst,aLast);
+  if(aCurve.IsNull())
+    return;
+  aCurve = BRep_Tool::CurveOnSurface(Ed,F2,aFirst,aLast);
+  if(aCurve.IsNull())
+    return;
+
+  Standard_Real u;
+  TopoDS_Edge E = Ed;
+  BRepAdaptor_Surface aBAS1(F1,Standard_False);
+  BRepAdaptor_Surface aBAS2(F2,Standard_False);
+
+  Handle(BRepAdaptor_HSurface) HS1 = new BRepAdaptor_HSurface (aBAS1);
+  Handle(BRepAdaptor_HSurface) HS2;
+  if(couture) HS2 = HS1;
+  else HS2 = new BRepAdaptor_HSurface(aBAS2);
+  //case when edge lies on the one face
+  
+  E.Orientation(TopAbs_FORWARD);
+  Handle(BRepAdaptor_HCurve2d) HC2d1 = new BRepAdaptor_HCurve2d();
+  HC2d1->ChangeCurve2d().Initialize(E,F1);
+  if(couture) E.Orientation(TopAbs_REVERSED);
+  Handle(BRepAdaptor_HCurve2d) HC2d2 = new BRepAdaptor_HCurve2d();
+  HC2d2->ChangeCurve2d().Initialize(E,F2);
+
+  Standard_Boolean rev1 = (F1.Orientation() == TopAbs_REVERSED);
+  Standard_Boolean rev2 = (F2.Orientation() == TopAbs_REVERSED);
+  Standard_Real f,l,eps;
+  BRep_Tool::Range(E,f,l);
+  Extrema_LocateExtPC ext;
+
+  eps = (l - f) / 100.0;
+  f += eps; // to avoid calculations on  
+  l -= eps; // points of pointed squares.
+  gp_Pnt2d p;
+  gp_Pnt pp1,pp2;//,PP;
+  gp_Vec du1, dv1;
+  gp_Vec du2, dv2;
+  gp_Vec d1,d2;
+  Standard_Real norm;
+
+  const Standard_Integer NBPNT = 23;
+  for(Standard_Integer i = 0; i <= NBPNT; i++)
+  {
+    // First suppose that this is sameParameter
+    u = f + (l - f) * i / NBPNT;
+
+    // take derivatives of surfaces at the same u, and compute normals
+    HC2d1->D0(u,p);
+    HS1->D1 (p.X(), p.Y(), pp1, du1, dv1);
+    d1 = (du1.Crossed(dv1));
+    norm = d1.Magnitude(); 
+    if (norm > 1.e-12) d1 /= norm;
+    else continue; // skip degenerated point
+    if(rev1) d1.Reverse();
+
+    HC2d2->D0(u,p);
+    HS2->D1 (p.X(), p.Y(), pp2, du2, dv2);
+    d2 = (du2.Crossed(dv2));
+    norm = d2.Magnitude();
+    if (norm > 1.e-12) d2 /= norm;
+    else continue; // skip degenerated point
+    if(rev2) d2.Reverse();
+
+    // Compute angle.
+    Standard_Real aCurrentAng = d1.Angle(d2);
+
+    theResAngle = Max(theResAngle, aCurrentAng);
+  }
+}
+
+//=============================================================================
+// function : ComputeMaxAngleOnShape
+// purpose  : Code the regularities on all edges of the shape, boundary of 
+//            two faces that do not have it.
+//=============================================================================
+static void ComputeMaxAngleOnShape(const TopoDS_Shape& S,
+                                   Standard_Real& theResAngle)
+{
+  TopTools_IndexedDataMapOfShapeListOfShape M;
+  TopExp::MapShapesAndAncestors(S,TopAbs_EDGE,TopAbs_FACE,M);
+  TopTools_ListIteratorOfListOfShape It;
+  TopExp_Explorer Ex;
+  TopoDS_Face F1,F2;
+  Standard_Boolean found, couture;
+  for(Standard_Integer i = 1; i <= M.Extent(); i++)
+  {
+    TopoDS_Edge E = TopoDS::Edge(M.FindKey(i));
+    found = Standard_False; couture = Standard_False;
+    F1.Nullify();
+    for(It.Initialize(M.FindFromIndex(i));It.More() && !found;It.Next())
+    {
+      if(F1.IsNull()) { F1 = TopoDS::Face(It.Value()); }
+      else
+      {
+        if(!F1.IsSame(TopoDS::Face(It.Value())))
+        {
+          found = Standard_True;
+          F2 = TopoDS::Face(It.Value());
+        }
+      }
+    }
+    if (!found && !F1.IsNull()){//is it a sewing edge?
+      TopAbs_Orientation orE = E.Orientation();
+      TopoDS_Edge curE;
+      for(Ex.Init(F1,TopAbs_EDGE);Ex.More() && !found;Ex.Next()){
+        curE= TopoDS::Edge(Ex.Current());
+        if(E.IsSame(curE) && orE != curE.Orientation()) 
+        {
+          found = Standard_True;
+          couture = Standard_True;
+          F2 = F1;
+        }
+      }
+    }
+    if(found)
+    {
+      if(BRep_Tool::Continuity(E,F1,F2)<=GeomAbs_C0)
+      {
+        try
+        {
+          tgtfaces(E, F1, F2, couture, theResAngle);
+        }
+        catch(Standard_Failure)
+        {
+        }
+      }
+    }
+  }
+}
+
+//=============================================================================
+//function : ComputeMaxAngle
+//purpose  : Computes max angle in faces junction
+//=============================================================================
+void BRepOffset_MakeSimpleOffset::ComputeMaxAngle()
+{
+  ComputeMaxAngleOnShape(myInputShape, myMaxAngle);
+}
+
+//=============================================================================
+//function : BuildMissingWalls
+//purpose  : Builds walls to the result solid.
+//=============================================================================
+Standard_Boolean BRepOffset_MakeSimpleOffset::BuildMissingWalls(const BRepTools_Modifier& theModifier)
+{
+  // Internal list of new faces.
+  NCollection_List<TopoDS_Face> aListOfNewFaces;
+  BRep_Builder aBB;
+
+  // Compute outer bounds of original shape.
+  ShapeAnalysis_FreeBounds aFB(myInputShape);
+  const TopoDS_Compound& aFreeWires = aFB.GetClosedWires();
+
+  // Build linear faces on each edge and its image.
+  TopExp_Explorer anExpCW(aFreeWires,TopAbs_WIRE);
+  for(; anExpCW.More() ; anExpCW.Next())
+  {
+    const TopoDS_Wire& aCurWire = TopoDS::Wire(anExpCW.Current());
+
+    // Iterate over outer edges in outer wires.
+    TopExp_Explorer anExpWE(aCurWire, TopAbs_EDGE);
+    for(; anExpWE.More() ; anExpWE.Next())
+    {
+      const TopoDS_Edge& aCurEdge = TopoDS::Edge(anExpWE.Current());
+
+      TopoDS_Face aNewFace = BuildWallFace(theModifier, aCurEdge);
+
+      if (aNewFace.IsNull())
+      {
+        myError = BRepOffsetSimple_ErrorWallFaceComputation;
+        return Standard_False;
+      }
+
+      aListOfNewFaces.Append(aNewFace);
+    }
+  }
+
+  // Update result to be compound.
+  TopoDS_Compound aResCompound;
+  aBB.MakeCompound(aResCompound);
+
+  // Add old faces.
+  TopExp_Explorer anExpSF(myInputShape, TopAbs_FACE);
+  for ( ; anExpSF.More() ; anExpSF.Next())
+    aBB.Add(aResCompound, anExpSF.Current());
+
+  // Add new faces.
+  anExpSF.Init(myResShape, TopAbs_FACE);
+  for ( ; anExpSF.More() ; anExpSF.Next())
+    aBB.Add(aResCompound, anExpSF.Current());
+
+  // Add wall faces.
+  NCollection_List<TopoDS_Face>::Iterator anIterF(aListOfNewFaces);
+  for ( ; anIterF.More() ; anIterF.Next())
+  {
+    const TopoDS_Face& aF = anIterF.Value();
+    aBB.Add(aResCompound, aF);
+  }
+
+  // Create result shell.
+  BRepTools_Quilt aQuilt;
+  aQuilt.Add(aResCompound);
+  TopoDS_Shape aShells = aQuilt.Shells();
+
+  TopExp_Explorer anExpSSh(aShells, TopAbs_SHELL);
+  TopoDS_Shell aResShell;
+  for ( ; anExpSSh.More() ; anExpSSh.Next() )
+  {
+    if (!aResShell.IsNull())
+    {
+      // Shell is not null -> explorer contains two or more shells.
+      myError = BRepOffsetSimple_ErrorInvalidNbShells;
+      return Standard_False;
+    }
+    aResShell = TopoDS::Shell(anExpSSh.Current());
+  }
+
+  if (!BRep_Tool::IsClosed(aResShell))
+  {
+    myError = BRepOffsetSimple_ErrorNonClosedShell;
+    return Standard_False;
+  }
+
+  // Create result solid.
+  TopoDS_Solid aResSolid;
+  aBB.MakeSolid(aResSolid);
+  aBB.Add(aResSolid, aResShell);
+  myResShape = aResSolid;
+
+  return Standard_True;
+}
+
+//=============================================================================
+//function : BuildWallFace
+//purpose  :
+//=============================================================================
+TopoDS_Face BRepOffset_MakeSimpleOffset::BuildWallFace(const BRepTools_Modifier& theModifier,
+                                                       const TopoDS_Edge& theOrigEdge)
+{
+  TopoDS_Face aResFace;
+
+  // Get offset edge. offset edge is revered to create correct wire.
+  TopoDS_Edge aNewEdge = TopoDS::Edge(theModifier.ModifiedShape(theOrigEdge));
+  aNewEdge.Orientation(TopAbs_REVERSED);
+
+  TopoDS_Vertex aNewV1, aNewV2;
+  TopExp::Vertices(aNewEdge, aNewV1, aNewV2);
+
+  // Wire contour is:
+  // theOrigEdge (forcible forward) -> wall1 -> aNewEdge (forcible reversed) -> wall2
+  // Firstly it is necessary to create copy of original shape with forward direction.
+  // This simplifies walls creation.
+  TopoDS_Edge anOrigCopy = theOrigEdge;
+  anOrigCopy.Orientation(TopAbs_FORWARD);
+  TopoDS_Vertex aV1, aV2;
+  TopExp::Vertices(anOrigCopy, aV1, aV2);
+
+  // To simplify work with map.
+  TopoDS_Vertex aForwardV1 = TopoDS::Vertex(aV1.Oriented(TopAbs_FORWARD));
+  TopoDS_Vertex aForwardV2 = TopoDS::Vertex(aV2.Oriented(TopAbs_FORWARD));
+
+  // Check existence of edges in stored map: Edge1
+  TopoDS_Edge aWall1;
+  if (myMapVE.IsBound(aForwardV2))
+  {
+    // Edge exists - get it from map.
+    aWall1 = myMapVE(aForwardV2);
+  }
+  else
+  {
+    // Edge does not exist - create it and add to the map.
+    BRepLib_MakeEdge aME1(TopoDS::Vertex(aV2.Oriented(TopAbs_FORWARD)), 
+                          TopoDS::Vertex(aNewV2.Oriented(TopAbs_REVERSED)));
+    if (!aME1.IsDone())
+      return aResFace;
+    aWall1 = aME1.Edge();
+
+    myMapVE.Bind(aForwardV2, aWall1);
+  }
+
+  // Check existence of edges in stored map: Edge2
+  TopoDS_Edge aWall2;
+  if (myMapVE.IsBound(aForwardV1))
+  {
+    // Edge exists - get it from map.
+    aWall2 = TopoDS::Edge(myMapVE(aForwardV1).Oriented(TopAbs_REVERSED));
+  }
+  else
+  {
+    // Edge does not exist - create it and add to the map.
+    BRepLib_MakeEdge aME2(TopoDS::Vertex(aV1.Oriented(TopAbs_FORWARD)), 
+                          TopoDS::Vertex(aNewV1.Oriented(TopAbs_REVERSED)));
+    if (!aME2.IsDone())
+      return aResFace;
+    aWall2 = aME2.Edge();
+
+    myMapVE.Bind(aForwardV1, aWall2);
+
+    // Orient it in reversed direction.
+    aWall2.Orientation(TopAbs_REVERSED);
+  }
+
+  BRep_Builder aBB;
+
+  TopoDS_Wire aWire;
+  aBB.MakeWire(aWire);
+  aBB.Add(aWire, anOrigCopy);
+  aBB.Add(aWire, aWall1);
+  aBB.Add(aWire, aNewEdge);
+  aBB.Add(aWire, aWall2);
+
+  // Build 3d curves on wire
+  BRepLib::BuildCurves3d( aWire );
+
+  // Try to build using simple planar approach.
+  TopoDS_Face aF;
+  try
+  {
+    // Call of face maker is wrapped by try/catch since it generates exceptions sometimes.
+    BRepLib_MakeFace aFM(aWire, Standard_True);
+    if (aFM.IsDone())
+      aF = aFM.Face();
+  }
+  catch(Standard_Failure)
+  {
+  }
+
+  if (aF.IsNull()) // Exception in face maker or result is not computed.
+  {
+    // Build using thrusections.
+    Standard_Boolean ToReverse = Standard_False;
+    Standard_Real fpar, lpar, fparOE, lparOE;
+    Handle(Geom_Curve) EdgeCurve = BRep_Tool::Curve(theOrigEdge, fpar, lpar);
+    Handle(Geom_TrimmedCurve) TrEdgeCurve = new Geom_TrimmedCurve( EdgeCurve, fpar, lpar );
+    Handle(Geom_Curve) OffsetCurve = BRep_Tool::Curve(aNewEdge, fparOE, lparOE);
+    Handle(Geom_TrimmedCurve) TrOffsetCurve = new Geom_TrimmedCurve( OffsetCurve, fparOE, lparOE );
+
+    GeomFill_Generator ThrusecGenerator;
+    ThrusecGenerator.AddCurve( TrEdgeCurve );
+    ThrusecGenerator.AddCurve( TrOffsetCurve );
+    ThrusecGenerator.Perform( Precision::PConfusion() );
+    Handle(Geom_Surface) theSurf = ThrusecGenerator.Surface();
+    //theSurf = new Geom_SurfaceOfLinearExtrusion( TrOffsetCurve, OffsetDir );
+    Standard_Real Uf, Ul, Vf, Vl;
+    theSurf->Bounds(Uf, Ul, Vf, Vl);
+    TopLoc_Location Loc;
+    Handle(Geom2d_Line) EdgeLine2d, OELine2d, aLine2d, aLine2d2;
+    EdgeLine2d = new Geom2d_Line(gp_Pnt2d(0., Vf), gp_Dir2d(1., 0.));
+    aBB.UpdateEdge(theOrigEdge, EdgeLine2d, theSurf, Loc, Precision::Confusion());
+    OELine2d = new Geom2d_Line(gp_Pnt2d(0., Vl), gp_Dir2d(1., 0.));
+    aBB.UpdateEdge(aNewEdge, OELine2d, theSurf, Loc, Precision::Confusion());
+    Standard_Real UonV1 = (ToReverse)? Ul : Uf;
+    Standard_Real UonV2 = (ToReverse)? Uf : Ul;
+    aLine2d  = new Geom2d_Line(gp_Pnt2d(UonV2, 0.), gp_Dir2d(0., 1.));
+    aLine2d2 = new Geom2d_Line(gp_Pnt2d(UonV1, 0.), gp_Dir2d(0., 1.));
+    if (aWall1.IsSame(aWall2))
+    {
+      aBB.UpdateEdge(aWall1, aLine2d, aLine2d2, theSurf, Loc, Precision::Confusion());
+      Handle(Geom_Curve) BSplC34 = theSurf->UIso( Uf );
+      aBB.UpdateEdge(aWall1, BSplC34, Precision::Confusion());
+      aBB.Range(aWall1, Vf, Vl);
+    }
+    else
+    {
+      aBB.SameParameter(aWall1, Standard_False);
+      aBB.SameRange(aWall1, Standard_False);
+      aBB.SameParameter(aWall2, Standard_False);
+      aBB.SameRange(aWall2, Standard_False);
+      aBB.UpdateEdge(aWall1, aLine2d,  theSurf, Loc, Precision::Confusion());
+      aBB.Range(aWall1, theSurf, Loc, Vf, Vl);
+      aBB.UpdateEdge(aWall2, aLine2d2, theSurf, Loc, Precision::Confusion());
+      aBB.Range(aWall2, theSurf, Loc, Vf, Vl);
+      Handle(Geom_Curve) BSplC3 = theSurf->UIso( UonV2 );
+      aBB.UpdateEdge(aWall1, BSplC3, Precision::Confusion());
+      aBB.Range(aWall1, Vf, Vl, Standard_True); //only for 3d curve
+      Handle(Geom_Curve) BSplC4 = theSurf->UIso( UonV1 );
+      aBB.UpdateEdge(aWall2, BSplC4, Precision::Confusion());
+      aBB.Range(aWall2, Vf, Vl, Standard_True); //only for 3d curve
+    }
+
+    aF = BRepLib_MakeFace(theSurf, aWire);
+
+  }
+
+  // Fix same parameter and same range flags.
+  ShapeFix_Edge aSFE;
+  TopExp_Explorer anExpFE(aF, TopAbs_EDGE);
+  for ( ; anExpFE.More() ; anExpFE.Next())
+  {
+    const TopoDS_Edge& aCurrEdge = TopoDS::Edge(anExpFE.Current());
+    aSFE.FixSameParameter(aCurrEdge);
+    //aSFE.FixSameParameter(aCurrEdge, aF);
+  }
+
+  return aF;
+}
diff --git a/src/BRepOffset/BRepOffset_MakeSimpleOffset.hxx b/src/BRepOffset/BRepOffset_MakeSimpleOffset.hxx
new file mode 100644 (file)
index 0000000..5f56f14
--- /dev/null
@@ -0,0 +1,143 @@
+// Created on: 2016-10-13
+// Created by: Alexander MALYSHEV
+// Copyright (c) 1999-2016 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 _BRepOffset_MakeSimpleOffset_HeaderFile
+#define _BRepOffset_MakeSimpleOffset_HeaderFile
+
+#include <NCollection_DataMap.hxx>
+#include <Standard_Macro.hxx>
+#include <Standard_Real.hxx>
+#include <TCollection_AsciiString.hxx>
+#include <TopoDS_Edge.hxx>
+#include <TopoDS_Face.hxx>
+#include <TopoDS_Vertex.hxx>
+#include <TopoDS_Shape.hxx>
+
+class BRepTools_Modifier;
+
+
+enum BRepOffsetSimple_Status
+{
+  BRepOffsetSimple_OK,
+  BRepOffsetSimple_NullInputShape,
+  BRepOffsetSimple_ErrorOffsetComputation,
+  BRepOffsetSimple_ErrorWallFaceComputation,
+  BRepOffsetSimple_ErrorInvalidNbShells,
+  BRepOffsetSimple_ErrorNonClosedShell
+};
+
+//! This class represents simple offset algorithm itself. It builds simple offset without intersection.
+//! Solid can be created using SetBuildSolidFlag method (set flag to true). By default shell will be constructed.
+//!
+//! Algorithm:
+//! 1. Build source-image maps for vertices, edges and faces.BRepTools_Modification class will be used
+//!    to store this information. An image of a shared edge can be constructed from the corresponding edge
+//!    of the first iterated face.
+//! 2. Run BRepTools_Modifier to obtain offset shape.
+//  3. Ensure topological integrity of the output shape.
+//!
+//! Limitations:
+//! According to the algorithm nature result depends on the smoothness of input data. Smooth (G1-continuity) input shape
+//! will lead to the good result.
+class BRepOffset_MakeSimpleOffset
+{
+public:
+
+  //! Constructor.
+  Standard_EXPORT BRepOffset_MakeSimpleOffset(const TopoDS_Shape& theInputShape,
+                                              const Standard_Real theOffsetValue);
+
+  //! Computes offset shape.
+  Standard_EXPORT void Perform();
+
+  //! Gets error message.
+  Standard_EXPORT TCollection_AsciiString GetErrorMessage() const;
+
+  //! Gets error code.
+  const BRepOffsetSimple_Status GetError() const { return myError; }
+
+  // Inline methods.
+  //! Gets solid building flag.
+  const Standard_Boolean GetBuildSolidFlag() const { return myIsBuildSolid; }
+
+  //! Sets solid building flag.
+  void SetBuildSolidFlag(const Standard_Boolean theBuildFlag) { myIsBuildSolid = theBuildFlag; }
+
+  //! Gets offset value.
+  const Standard_Real GetOffsetValue() const { return myOffsetValue; }
+
+  //! Sets offset value.
+  void SetOffsetValue(const Standard_Real theOffsetValue) { myOffsetValue = theOffsetValue; }
+
+  //! Gets done state.
+  const Standard_Boolean IsDone() const { return myIsDone; } 
+
+  //! Returns result shape.
+  const TopoDS_Shape& GetResultShape() const { return myResShape; }
+
+  //! Computes max safe offset value for the given tolerance.
+  Standard_Real GetSafeOffset(const Standard_Real theExpectedToler);
+
+protected:
+
+  //! Computes max angle in faces junction.
+  void ComputeMaxAngle();
+
+  //! Clears previous result.
+  void Clear();
+
+private:
+
+  //! Builds face on specified wall.
+  TopoDS_Face BuildWallFace(const BRepTools_Modifier& theModifier,
+                            const TopoDS_Edge& theOrigEdge);
+
+  //! Builds missing walls.
+  Standard_Boolean BuildMissingWalls(const BRepTools_Modifier& theModifier);
+
+  // Input data.
+
+  //! Input shape.
+  TopoDS_Shape myInputShape;
+
+  //! Offset value.
+  Standard_Real myOffsetValue;
+
+  //! Solid building flag. True means solid construction.
+  Standard_Boolean myIsBuildSolid;
+
+  // Internal data.
+
+  //! Maximal angle in faces junction. This value helps to estimate result tolerance.
+  Standard_Real myMaxAngle;
+
+  //! Error message.
+  BRepOffsetSimple_Status myError;
+
+  //! Done state.
+  Standard_Boolean myIsDone;
+
+  //! Map of vertex - wall edge.
+  //! Used to build shared edge between adjacent wall faces.
+  NCollection_DataMap<TopoDS_Vertex, TopoDS_Edge> myMapVE;
+
+  // Output data.
+
+  //! Result shape.
+  TopoDS_Shape myResShape;
+
+};
+
+#endif // _BRepOffset_MakeSimpleOffset_HeaderFile
diff --git a/src/BRepOffset/BRepOffset_SimpleOffset.cxx b/src/BRepOffset/BRepOffset_SimpleOffset.cxx
new file mode 100644 (file)
index 0000000..359ce2a
--- /dev/null
@@ -0,0 +1,438 @@
+// Created on: 2016-10-14
+// Created by: Alexander MALYSHEV
+// Copyright (c) 1995-1999 Matra Datavision
+// Copyright (c) 1999-2016 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 self.
+#include <BRepOffset_SimpleOffset.hxx>
+
+#include <Adaptor3d_CurveOnSurface.hxx>
+#include <BRepBuilderAPI_MakeEdge.hxx>
+#include <BRepLib.hxx>
+#include <BRep_Tool.hxx>
+#include <Geom_OffsetSurface.hxx>
+#include <GeomAdaptor_Curve.hxx>
+#include <Geom2dAdaptor_HCurve.hxx>
+#include <GeomAdaptor_HSurface.hxx>
+#include <NCollection_Vector.hxx>
+#include <ShapeAnalysis_Edge.hxx>
+#include <TopExp.hxx>
+#include <TopExp_Explorer.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Face.hxx>
+#include <TopoDS_Edge.hxx>
+#include <TopoDS_Vertex.hxx>
+#include <TopTools_ListIteratorOfListOfShape.hxx>
+
+
+static const Standard_Integer NCONTROL=22;
+
+
+IMPLEMENT_STANDARD_RTTIEXT(BRepOffset_SimpleOffset, BRepTools_Modification)
+
+
+//=============================================================================
+//function : BRepOffset_SimpleOffset
+//purpose  : Constructor
+//=============================================================================
+BRepOffset_SimpleOffset::BRepOffset_SimpleOffset(const TopoDS_Shape& theInputShape,
+                                                 const Standard_Real theOffsetValue)
+: myOffsetValue(theOffsetValue)
+{
+  FillOffsetData(theInputShape);
+}
+
+//=============================================================================
+//function : NewSurface
+//purpose  :
+//=============================================================================
+Standard_Boolean BRepOffset_SimpleOffset::NewSurface(const TopoDS_Face& F,
+                                                     Handle(Geom_Surface)& S,
+                                                     TopLoc_Location& L,
+                                                     Standard_Real& Tol,
+                                                     Standard_Boolean& RevWires,
+                                                     Standard_Boolean& RevFace)
+{
+  if (!myFaceInfo.IsBound(TopoDS::Face(F.Oriented(TopAbs_FORWARD))) &&
+      !myFaceInfo.IsBound(TopoDS::Face(F.Oriented(TopAbs_REVERSED))))
+    return Standard_False;
+
+  NewFaceData aNFD;
+  if (myFaceInfo.IsBound(TopoDS::Face(F.Oriented(TopAbs_FORWARD))))
+    aNFD = myFaceInfo.Find(TopoDS::Face(F.Oriented(TopAbs_FORWARD)));
+  if (myFaceInfo.IsBound(TopoDS::Face(F.Oriented(TopAbs_REVERSED))))
+    aNFD = myFaceInfo.Find(TopoDS::Face(F.Oriented(TopAbs_REVERSED)));
+
+  S = aNFD.myOffsetS;
+  L = aNFD.myL;
+  Tol = aNFD.myTol;
+  RevWires = aNFD.myRevWires;
+  RevFace = aNFD.myRevFace;
+
+  return Standard_True;
+}
+
+//=============================================================================
+//function : NewCurve
+//purpose  :
+//=============================================================================
+Standard_Boolean BRepOffset_SimpleOffset::NewCurve(const TopoDS_Edge& E,
+                                                   Handle(Geom_Curve)& C,
+                                                   TopLoc_Location& L,
+                                                   Standard_Real& Tol)
+{
+  if (!myEdgeInfo.IsBound(TopoDS::Edge(E.Oriented(TopAbs_FORWARD))) &&
+      !myEdgeInfo.IsBound(TopoDS::Edge(E.Oriented(TopAbs_REVERSED))))
+    return Standard_False;
+
+  NewEdgeData aNED;
+  if (myEdgeInfo.IsBound(TopoDS::Edge(E.Oriented(TopAbs_FORWARD))))
+    aNED = myEdgeInfo.Find(TopoDS::Edge(E.Oriented(TopAbs_FORWARD)));
+  if (myEdgeInfo.IsBound(TopoDS::Edge(E.Oriented(TopAbs_REVERSED))))
+    aNED = myEdgeInfo.Find(TopoDS::Edge(E.Oriented(TopAbs_REVERSED)));
+
+  C = aNED.myOffsetC;
+  L = aNED.myL;
+  Tol = aNED.myTol;
+
+  return Standard_True;
+}
+
+//=============================================================================
+//function : NewPoint
+//purpose  :
+//=============================================================================
+Standard_Boolean BRepOffset_SimpleOffset::NewPoint (const TopoDS_Vertex& V,
+                                                    gp_Pnt& P,
+                                                    Standard_Real& Tol)
+{
+  if (!myVertexInfo.IsBound(TopoDS::Vertex(V.Oriented(TopAbs_FORWARD))) &&
+      !myVertexInfo.IsBound(TopoDS::Vertex(V.Oriented(TopAbs_REVERSED))))
+    return Standard_False;
+
+  NewVertexData aNVD;
+  if (myVertexInfo.IsBound(TopoDS::Vertex(V.Oriented(TopAbs_FORWARD))))
+    aNVD = myVertexInfo.Find(TopoDS::Vertex(V.Oriented(TopAbs_FORWARD)));
+  if (myVertexInfo.IsBound(TopoDS::Vertex(V.Oriented(TopAbs_REVERSED))))
+    aNVD = myVertexInfo.Find(TopoDS::Vertex(V.Oriented(TopAbs_REVERSED)));
+
+  P = aNVD.myP;
+  Tol = aNVD.myTol;
+
+  return Standard_True;
+}
+
+//=============================================================================
+//function : NewCurve2d
+//purpose  :
+//=============================================================================
+Standard_Boolean BRepOffset_SimpleOffset::NewCurve2d (const TopoDS_Edge& E,
+                                                      const TopoDS_Face& F,
+                                                      const TopoDS_Edge& /*NewE*/,
+                                                      const TopoDS_Face& /*NewF*/,
+                                                      Handle(Geom2d_Curve)& C,
+                                                      Standard_Real& Tol)
+{
+  // Use original pcurve.
+  Standard_Real aF, aL;
+  C = BRep_Tool::CurveOnSurface(E, F, aF, aL);
+  Tol = BRep_Tool::Tolerance(E);
+
+  if (myEdgeInfo.IsBound(E))
+    Tol = myEdgeInfo.Find(E).myTol;
+
+  return Standard_True;
+}
+
+//=============================================================================
+//function : NewParameter
+//purpose  :
+//=============================================================================
+Standard_Boolean BRepOffset_SimpleOffset::NewParameter (const TopoDS_Vertex& V,
+                                                        const TopoDS_Edge& E,
+                                                        Standard_Real& P,
+                                                        Standard_Real& Tol)
+{
+  // Use original parameter.
+  P = BRep_Tool::Parameter(V, E);
+  Tol = BRep_Tool::Tolerance(V);
+
+  if (myVertexInfo.IsBound(V))
+    Tol = myVertexInfo.Find(V).myTol;
+
+  return Standard_True;
+}
+
+//=============================================================================
+//function : NewParameter
+//purpose  :
+//=============================================================================
+GeomAbs_Shape BRepOffset_SimpleOffset::Continuity (const TopoDS_Edge& E,
+                                                   const TopoDS_Face& F1,
+                                                   const TopoDS_Face& F2,
+                                                   const TopoDS_Edge& /*NewE*/,
+                                                   const TopoDS_Face& /*NewF1*/,
+                                                   const TopoDS_Face& /*NewF2*/)
+{
+  // Compute result using original continuity.
+  return BRep_Tool::Continuity(E, F1, F2);
+}
+
+//=============================================================================
+//function : FillOffsetData
+//purpose  : 
+//=============================================================================
+void BRepOffset_SimpleOffset::FillOffsetData(const TopoDS_Shape& theShape)
+{
+  // Clears old data.
+  myFaceInfo.Clear();
+  myEdgeInfo.Clear();
+  myVertexInfo.Clear();
+
+  // Faces loop. Compute offset surface for each face.
+  TopExp_Explorer anExpSF(theShape, TopAbs_FACE);
+  for(; anExpSF.More(); anExpSF.Next())
+  {
+    const TopoDS_Face& aCurrFace = TopoDS::Face(anExpSF.Current());
+    FillFaceData(aCurrFace);
+  }
+
+  // Iterate over edges to compute 3d curve.
+  TopTools_IndexedDataMapOfShapeListOfShape aEdgeFaceMap;
+  TopExp::MapShapesAndAncestors(theShape, TopAbs_EDGE, TopAbs_FACE, aEdgeFaceMap);
+  for (Standard_Integer anIdx = 1; anIdx <= aEdgeFaceMap.Extent(); ++anIdx)
+  {
+    const TopoDS_Edge& aCurrEdge = TopoDS::Edge(aEdgeFaceMap.FindKey(anIdx));
+    FillEdgeData(aCurrEdge, aEdgeFaceMap, anIdx);
+  }
+
+  // Iterate over vertices to compute new vertex.
+  TopTools_IndexedDataMapOfShapeListOfShape aVertexEdgeMap;
+  TopExp::MapShapesAndAncestors(theShape, TopAbs_VERTEX, TopAbs_EDGE, aVertexEdgeMap);
+  for (Standard_Integer anIdx = 1; anIdx <= aVertexEdgeMap.Extent(); ++anIdx)
+  {
+    const TopoDS_Vertex & aCurrVertex = TopoDS::Vertex(aVertexEdgeMap.FindKey(anIdx));
+    FillVertexData(aCurrVertex, aVertexEdgeMap, anIdx);
+  }
+}
+
+//=============================================================================
+//function : FillFaceData
+//purpose  : 
+//=============================================================================
+void BRepOffset_SimpleOffset::FillFaceData(const TopoDS_Face& theFace)
+{
+  NewFaceData aNFD;
+  aNFD.myRevWires = Standard_False;
+  aNFD.myTol = BRep_Tool::Tolerance(theFace);
+
+  // Create offset surface.
+
+  // Any existing transformation is applied to the surface.
+  // New face will have null transformation.
+  Handle(Geom_Surface) aS = BRep_Tool::Surface(theFace);
+
+  // Take into account face orientation.
+  Standard_Real aMult = 1.0;
+  aNFD.myRevFace = Standard_False;
+  if (theFace.Orientation() == TopAbs_REVERSED)
+  {
+    aNFD.myRevFace = Standard_True;
+    aMult = -1.0;
+  }
+  aNFD.myOffsetS = new Geom_OffsetSurface(aS, aMult * myOffsetValue, Standard_True);
+  aNFD.myL = TopLoc_Location(); // Null transformation.
+
+  // Save offset surface in map.
+  myFaceInfo.Bind(theFace, aNFD);
+}
+
+//=============================================================================
+//function : FillEdgeData
+//purpose  : 
+//=============================================================================
+void BRepOffset_SimpleOffset::FillEdgeData(const TopoDS_Edge& theEdge,
+                                           const TopTools_IndexedDataMapOfShapeListOfShape& theEdgeFaceMap,
+                                           const Standard_Integer theIdx)
+{
+  const TopTools_ListOfShape& aFacesList = theEdgeFaceMap(theIdx);
+
+  if (aFacesList.Extent() == 0)
+    return; // Free edges are skipped.
+
+  // Get offset surface.
+  const TopoDS_Face& aCurrFace = TopoDS::Face(aFacesList.First());
+
+  if (!myFaceInfo.IsBound(aCurrFace))
+    return;
+
+  // No need to deal with transformation - it is applied in fill faces data method.
+  const NewFaceData & aNFD = myFaceInfo.Find(aCurrFace);
+  Handle(Geom_Surface) anOffsetSurf = aNFD.myOffsetS;
+
+  // Compute offset 3d curve.
+  Standard_Real aF, aL;
+  Handle(Geom2d_Curve) aC2d = BRep_Tool::CurveOnSurface(theEdge, aCurrFace, aF, aL);
+
+  BRepBuilderAPI_MakeEdge anEdgeMaker(aC2d, anOffsetSurf, aF, aL);
+  TopoDS_Edge aNewEdge = anEdgeMaker.Edge();
+
+  // Compute max tolerance. Vertex tolerance usage is taken from existing offset computation algorithm.
+  // This piece of code significantly influences resulting performance.
+  TopoDS_Vertex aV1, aV2;
+  TopExp::Vertices(theEdge, aV1, aV2);
+  Standard_Real aTol = Max(BRep_Tool::Tolerance(aV1),
+                           BRep_Tool::Tolerance(aV2));
+  BRepLib::BuildCurves3d(aNewEdge, aTol);
+
+  NewEdgeData aNED;
+  aNED.myOffsetC = BRep_Tool::Curve(aNewEdge, aNED.myL, aF, aL);
+
+  // Iterate over adjacent faces for the current edge and compute max deviation.
+  Standard_Real anEdgeTol = 0.0;
+  TopTools_ListIteratorOfListOfShape anIter(aFacesList);
+  for ( ; !aNED.myOffsetC.IsNull() && anIter.More() ; anIter.Next())
+  {
+    const TopoDS_Face& aCurFace = TopoDS::Face(anIter.Value());
+
+    if (!myFaceInfo.IsBound(aCurFace))
+      continue;
+
+    // Create offset curve on surface.
+    Standard_Real aF, aL;
+    const Handle(Geom2d_Curve) aC2d = BRep_Tool::CurveOnSurface(theEdge, aCurFace, aF, aL);
+    const Handle(Adaptor2d_HCurve2d) aHCurve2d = new Geom2dAdaptor_HCurve(aC2d, aF, aL);
+    const Handle(Adaptor3d_HSurface) aHSurface = new GeomAdaptor_HSurface(myFaceInfo.Find(aCurFace).myOffsetS);
+    Adaptor3d_CurveOnSurface aCurveOnSurf(aHCurve2d, aHSurface);
+
+    // Extract 3d-curve (it is not null).
+    const GeomAdaptor_Curve aCurve3d(aNED.myOffsetC, aF, aL);
+
+    // It is necessary to compute maximal deviation (tolerance).
+    Standard_Real aMaxTol = 0.0;
+    ShapeAnalysis_Edge::ComputeDeviation(aCurve3d, aCurveOnSurf, Standard_True, aMaxTol, NCONTROL);
+    anEdgeTol = Max(anEdgeTol, aMaxTol);
+
+  }
+  aNED.myTol = Max(BRep_Tool::Tolerance(aNewEdge), anEdgeTol);
+
+  // Save computed 3d curve in map.
+  myEdgeInfo.Bind(theEdge, aNED);
+}
+
+//=============================================================================
+//function : FillVertexData
+//purpose  : 
+//=============================================================================
+void BRepOffset_SimpleOffset::FillVertexData(const TopoDS_Vertex& theVertex,
+                                             const TopTools_IndexedDataMapOfShapeListOfShape& theVertexEdgeMap,
+                                             const Standard_Integer theIdx)
+{
+  // Algorithm:
+  // Find adjacent edges for the given vertex.
+  // Find corresponding end on the each adjacent edge.
+  // Get offset points for founded end.
+  // Set result vertex position as barycenter of founded points.
+
+  gp_Pnt aCurrPnt = BRep_Tool::Pnt(theVertex);
+
+  const TopTools_ListOfShape& aEdgesList = theVertexEdgeMap(theIdx);
+
+  if (aEdgesList.Extent() == 0)
+    return; // Free vertices are skipped.
+
+  // Array to store offset points.
+  NCollection_Vector<gp_Pnt> anOffsetPointVec;
+
+  Standard_Real aMaxEdgeTol = 0.0;
+
+  // Iterate over adjacent edges.
+  TopTools_ListIteratorOfListOfShape anIterEdges(aEdgesList);
+  for (; anIterEdges.More() ; anIterEdges.Next() )
+  {
+    const TopoDS_Edge& aCurrEdge = TopoDS::Edge(anIterEdges.Value());
+
+    if (!myEdgeInfo.IsBound(aCurrEdge))
+      continue; // Skip shared edges with wrong orientation.
+
+    // Find the closest bound.
+    Standard_Real aF, aL;
+    Handle(Geom_Curve) aC3d = BRep_Tool::Curve(aCurrEdge, aF, aL);
+    // Protection from degenerated edges.
+    if (aC3d.IsNull())
+      continue;
+
+    const gp_Pnt aPntF = aC3d->Value(aF);
+    const gp_Pnt aPntL = aC3d->Value(aL);
+
+    const Standard_Real aSqDistF = aPntF.SquareDistance(aCurrPnt);
+    const Standard_Real aSqDistL = aPntL.SquareDistance(aCurrPnt);
+
+    Standard_Real aMinParam = aF, aMaxParam = aL;
+    if (aSqDistL < aSqDistF)
+    {
+      // Square distance to last point is closer.
+      aMinParam = aL; aMaxParam = aF;
+    }
+
+    // Compute point on offset edge.
+    const NewEdgeData& aNED = myEdgeInfo.Find(aCurrEdge);
+    const Handle(Geom_Curve) &anOffsetCurve = aNED.myOffsetC;
+    const gp_Pnt anOffsetPoint = anOffsetCurve->Value(aMinParam);
+    anOffsetPointVec.Append(anOffsetPoint);
+
+    // Handle situation when edge is closed.
+    TopoDS_Vertex aV1, aV2;
+    TopExp::Vertices(aCurrEdge, aV1, aV2);
+    if (aV1.IsSame(aV2))
+    {
+      const gp_Pnt anOffsetPoint = anOffsetCurve->Value(aMaxParam);
+      anOffsetPointVec.Append(anOffsetPoint);
+    }
+
+    aMaxEdgeTol = Max(aMaxEdgeTol, aNED.myTol);
+  }
+
+  // NCollection_Vector starts from 0 by default.
+  // It's better to use lower() and upper() in this case instead of direct indexes range.
+  gp_Pnt aCenter(0.0, 0.0, 0.0);
+  for(Standard_Integer i  = anOffsetPointVec.Lower();
+                       i <= anOffsetPointVec.Upper();
+                       ++i)
+  {
+    aCenter.SetXYZ(aCenter.XYZ() + anOffsetPointVec.Value(i).XYZ());
+  }
+  aCenter.SetXYZ(aCenter.XYZ() / anOffsetPointVec.Size());
+
+  // Compute max distance.
+  Standard_Real aSqMaxDist = 0.0;
+  for(Standard_Integer i  = anOffsetPointVec.Lower();
+                       i <= anOffsetPointVec.Upper();
+                       ++i)
+  {
+    const Standard_Real aSqDist = aCenter.SquareDistance(anOffsetPointVec.Value(i));
+    if (aSqDist > aSqMaxDist)
+      aSqMaxDist = aSqDist;
+  }
+
+  const Standard_Real aResTol = Max(aMaxEdgeTol, Sqrt(aSqMaxDist));
+
+  const Standard_Real aMultCoeff = 1.001; // Avoid tolerance problems.
+  NewVertexData aNVD;
+  aNVD.myP = aCenter;
+  aNVD.myTol = aResTol * aMultCoeff;
+
+  // Save computed vertex info.
+  myVertexInfo.Bind(theVertex, aNVD);
+}
diff --git a/src/BRepOffset/BRepOffset_SimpleOffset.hxx b/src/BRepOffset/BRepOffset_SimpleOffset.hxx
new file mode 100644 (file)
index 0000000..c2fc360
--- /dev/null
@@ -0,0 +1,177 @@
+// Created on: 2016-10-14
+// Created by: Alexander MALYSHEV
+// Copyright (c) 1999-2016 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 _BRepOffset_SimpleOffset_HeaderFile
+#define _BRepOffset_SimpleOffset_HeaderFile
+
+#include <BRepTools_Modification.hxx>
+#include <GeomAbs_Shape.hxx>
+#include <Geom2d_Curve.hxx>
+#include <Standard_Real.hxx>
+#include <Standard_Macro.hxx>
+#include <Standard_Type.hxx>
+#include <TopoDS_Shape.hxx>
+#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
+#include <NCollection_DataMap.hxx>
+
+
+class BRepOffset_SimpleOffset;
+DEFINE_STANDARD_HANDLE(BRepOffset_SimpleOffset, BRepTools_Modification)
+
+//! This class represents mechanism of simple offset algorithm i. e.
+//! topology-preserve offset without intersection.
+class BRepOffset_SimpleOffset : public BRepTools_Modification
+{
+public:
+
+  DEFINE_STANDARD_RTTI(BRepOffset_SimpleOffset)
+
+  //! Constructor.
+  Standard_EXPORT BRepOffset_SimpleOffset(const TopoDS_Shape& theInputShape,
+                                          const Standard_Real theOffsetValue);
+
+  //! Returns Standard_True  if  the face  <F> has  been
+  //! modified.  In this  case, <S> is the new geometric
+  //! support of  the  face, <L> the  new location,<Tol>
+  //! the new  tolerance.<RevWires> has  to  be set   to
+  //! Standard_True   when the modification reverses the
+  //! normal of  the   surface.(the wires   have  to  be
+  //! reversed).   <RevFace>   has   to   be   set    to
+  //! Standard_True if  the orientation  of the modified
+  //! face changes in the  shells which contain  it.  --
+  //! Here, <RevFace>  will  return Standard_True if the
+  //! -- gp_Trsf is negative.
+  Standard_EXPORT Standard_Boolean NewSurface (const TopoDS_Face& F,
+                                               Handle(Geom_Surface)& S,
+                                               TopLoc_Location& L,
+                                               Standard_Real& Tol,
+                                               Standard_Boolean& RevWires,
+                                               Standard_Boolean& RevFace) Standard_OVERRIDE;
+
+  //! Returns Standard_True  if  the edge  <E> has  been
+  //! modified.  In this case,  <C> is the new geometric
+  //! support of the  edge, <L> the  new location, <Tol>
+  //! the         new    tolerance.   Otherwise, returns
+  //! Standard_False,    and  <C>,  <L>,   <Tol> are not
+  //! significant.
+  Standard_EXPORT Standard_Boolean NewCurve (const TopoDS_Edge& E,
+                                             Handle(Geom_Curve)& C,
+                                             TopLoc_Location& L,
+                                             Standard_Real& Tol) Standard_OVERRIDE;
+
+  //! Returns  Standard_True if the  vertex <V> has been
+  //! modified.  In this  case, <P> is the new geometric
+  //! support of the vertex,   <Tol> the new  tolerance.
+  //! Otherwise, returns Standard_False, and <P>,  <Tol>
+  //! are not significant.
+  Standard_EXPORT Standard_Boolean NewPoint (const TopoDS_Vertex& V,
+                                             gp_Pnt& P,
+                                             Standard_Real& Tol) Standard_OVERRIDE;
+
+  //! Returns Standard_True if  the edge  <E> has a  new
+  //! curve on surface on the face <F>.In this case, <C>
+  //! is the new geometric support of  the edge, <L> the
+  //! new location, <Tol> the new tolerance.
+  //! Otherwise, returns  Standard_False, and <C>,  <L>,
+  //! <Tol> are not significant.
+  Standard_EXPORT Standard_Boolean NewCurve2d (const TopoDS_Edge& E,
+                                               const TopoDS_Face& F,
+                                               const TopoDS_Edge& NewE,
+                                               const TopoDS_Face& NewF,
+                                               Handle(Geom2d_Curve)& C,
+                                               Standard_Real& Tol) Standard_OVERRIDE;
+
+  //! Returns Standard_True if the Vertex  <V> has a new
+  //! parameter on the  edge <E>. In  this case,  <P> is
+  //! the parameter,    <Tol>  the     new    tolerance.
+  //! Otherwise, returns Standard_False, and <P>,  <Tol>
+  //! are not significant.
+  Standard_EXPORT Standard_Boolean NewParameter (const TopoDS_Vertex& V,
+                                                 const TopoDS_Edge& E,
+                                                 Standard_Real& P,
+                                                 Standard_Real& Tol) Standard_OVERRIDE;
+
+  //! Returns the  continuity of  <NewE> between <NewF1>
+  //! and <NewF2>.
+  //!
+  //! <NewE> is the new  edge created from <E>.  <NewF1>
+  //! (resp. <NewF2>) is the new  face created from <F1>
+  //! (resp. <F2>).
+  Standard_EXPORT GeomAbs_Shape Continuity (const TopoDS_Edge& E,
+                                            const TopoDS_Face& F1,
+                                            const TopoDS_Face& F2,
+                                            const TopoDS_Edge& NewE,
+                                            const TopoDS_Face& NewF1,
+                                            const TopoDS_Face& NewF2) Standard_OVERRIDE;
+
+private:
+
+  //! Method to fill new face data for single face.
+  void FillFaceData(const TopoDS_Face& theFace);
+
+  //! Method to fill new edge data for single edge.
+  void FillEdgeData(const TopoDS_Edge& theEdge,
+                    const TopTools_IndexedDataMapOfShapeListOfShape& theEdgeFaceMap,
+                    const Standard_Integer theIdx);
+
+  //! Method to fill new vertex data for single vertex.
+  void FillVertexData(const TopoDS_Vertex& theVertex,
+                      const TopTools_IndexedDataMapOfShapeListOfShape& theVertexEdgeMap,
+                      const Standard_Integer theIdx);
+
+  struct NewFaceData
+  {
+    Handle(Geom_Surface) myOffsetS;
+    TopLoc_Location myL;
+    Standard_Real myTol;
+    Standard_Boolean myRevWires;
+    Standard_Boolean myRevFace;
+  };
+
+  struct NewEdgeData
+  {
+    Handle(Geom_Curve) myOffsetC; // Resulting curve.
+    TopLoc_Location myL;
+    Standard_Real myTol;
+  };
+
+  struct NewVertexData
+  {
+    gp_Pnt myP;
+    Standard_Real myTol;
+  };
+
+  //! Fills offset data.
+  void FillOffsetData(const TopoDS_Shape& theInputShape);
+
+  //! Copy-assignment contsructor and copy constructor are not allowed.
+  void operator=(const BRepOffset_SimpleOffset&);
+  BRepOffset_SimpleOffset(const BRepOffset_SimpleOffset&);
+
+  //! Map of faces to new faces information.
+  NCollection_DataMap<TopoDS_Face, NewFaceData> myFaceInfo;
+
+  //! Map of edges to new edges information.
+  NCollection_DataMap<TopoDS_Edge, NewEdgeData> myEdgeInfo;
+
+  //! Map of vertices to new vertices information.
+  NCollection_DataMap<TopoDS_Vertex, NewVertexData> myVertexInfo;
+
+
+  //! Ofsset value.
+  Standard_Real myOffsetValue;
+};
+
+#endif // _BRepOffset_SimpleOffset_HeaderFile
diff --git a/src/BRepOffset/FILES b/src/BRepOffset/FILES
new file mode 100644 (file)
index 0000000..1a9db5a
--- /dev/null
@@ -0,0 +1,4 @@
+BRepOffset_MakeSimpleOffset.cxx
+BRepOffset_MakeSimpleOffset.hxx
+BRepOffset_SimpleOffset.cxx
+BRepOffset_SimpleOffset.hxx
\ No newline at end of file
index 987ce26f3c6439c0c6c7b4f1b293cf6d2e5e9f23..88282af98f1ee921ce39a05517391dc730e0eb14 100644 (file)
@@ -54,6 +54,7 @@
 #include <LocOpe_FindEdges.hxx>
 #include <LocOpe_FindEdgesInFace.hxx>
 
+#include <BRepOffset_MakeSimpleOffset.hxx>
 #include <BRepOffsetAPI_MakeOffsetShape.hxx>
 #include <BRepOffsetAPI_MakeThickSolid.hxx>
 #include <BRep_Tool.hxx>
@@ -2241,6 +2242,52 @@ static Standard_Integer BOSS(Draw_Interpretor& theCommands,
   return 1;
 }
 
+//=============================================================================
+//function : ComputeSimpleOffset
+//purpose  : Computes simple offset.
+//=============================================================================
+static Standard_Integer ComputeSimpleOffset(Draw_Interpretor& theCommands,
+                                            Standard_Integer narg, 
+                                            const char** a)
+{
+  if (narg != 4)
+  {
+    theCommands << "offsetshapesimple result shape offsetvalue \n";
+    return 1;
+  }
+
+  // Input data.
+  TopoDS_Shape aShape = DBRep::Get(a[2]);
+  if (aShape.IsNull())
+  {
+    theCommands << "Input shape is null";
+    return 0;
+  }
+  const Standard_Real anOffsetValue = Draw::Atof(a[3]);
+  if (Abs(anOffsetValue) < gp::Resolution())
+  {
+    theCommands << "Null offset value";
+    return 0;
+  }
+
+  BRepOffset_MakeSimpleOffset aMaker(aShape, anOffsetValue);
+  if (narg == 5 && !strcasecmp(a[4],"solid") )
+  {
+    aMaker.SetBuildSolidFlag(Standard_True);
+  }
+
+  aMaker.Perform();
+
+  if (!aMaker.IsDone())
+  {
+    theCommands << "ERROR:" << aMaker.GetErrorMessage() << "\n";
+    return 0;
+  }
+
+  DBRep::Set(a[1], aMaker.GetResultShape());
+
+  return 0;
+}
 
 //=======================================================================
 //function : FeatureCommands
@@ -2393,4 +2440,7 @@ void BRepTest::FeatureCommands (Draw_Interpretor& theCommands)
                  " Perform fillet on top and bottom edges of dprism :bossage dprism result radtop radbottom First/LastShape (1/2)",
                  __FILE__,BOSS);
 
+  theCommands.Add("offsetshapesimple", 
+                  "offsetshapesimple result shape offsetvalue [solid]",
+                  __FILE__, ComputeSimpleOffset);
 }