Initial implementation of the solid creation mode for the new offset creation algorithm.
--- /dev/null
+// 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;
+}
--- /dev/null
+// 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
--- /dev/null
+// 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);
+}
--- /dev/null
+// 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
--- /dev/null
+BRepOffset_MakeSimpleOffset.cxx
+BRepOffset_MakeSimpleOffset.hxx
+BRepOffset_SimpleOffset.cxx
+BRepOffset_SimpleOffset.hxx
\ No newline at end of file
#include <LocOpe_FindEdges.hxx>
#include <LocOpe_FindEdgesInFace.hxx>
+#include <BRepOffset_MakeSimpleOffset.hxx>
#include <BRepOffsetAPI_MakeOffsetShape.hxx>
#include <BRepOffsetAPI_MakeThickSolid.hxx>
#include <BRep_Tool.hxx>
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
" 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);
}