From f99f17ab1d21db46a479f4ba954c34a1f6308e35 Mon Sep 17 00:00:00 2001 From: aml Date: Tue, 1 Nov 2016 13:54:05 +0300 Subject: [PATCH] Initial implementation of the new offset algorithm. Initial implementation of the solid creation mode for the new offset creation algorithm. --- .../BRepOffset_MakeSimpleOffset.cxx | 587 ++++++++++++++++++ .../BRepOffset_MakeSimpleOffset.hxx | 143 +++++ src/BRepOffset/BRepOffset_SimpleOffset.cxx | 438 +++++++++++++ src/BRepOffset/BRepOffset_SimpleOffset.hxx | 177 ++++++ src/BRepOffset/FILES | 4 + src/BRepTest/BRepTest_FeatureCommands.cxx | 50 ++ 6 files changed, 1399 insertions(+) create mode 100644 src/BRepOffset/BRepOffset_MakeSimpleOffset.cxx create mode 100644 src/BRepOffset/BRepOffset_MakeSimpleOffset.hxx create mode 100644 src/BRepOffset/BRepOffset_SimpleOffset.cxx create mode 100644 src/BRepOffset/BRepOffset_SimpleOffset.hxx create mode 100644 src/BRepOffset/FILES diff --git a/src/BRepOffset/BRepOffset_MakeSimpleOffset.cxx b/src/BRepOffset/BRepOffset_MakeSimpleOffset.cxx new file mode 100644 index 0000000000..8617ee072f --- /dev/null +++ b/src/BRepOffset/BRepOffset_MakeSimpleOffset.cxx @@ -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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +//============================================================================= +//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 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::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 index 0000000000..5f56f14353 --- /dev/null +++ b/src/BRepOffset/BRepOffset_MakeSimpleOffset.hxx @@ -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 +#include +#include +#include +#include +#include +#include +#include + +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 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 index 0000000000..359ce2a10a --- /dev/null +++ b/src/BRepOffset/BRepOffset_SimpleOffset.cxx @@ -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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +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 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 index 0000000000..c2fc360a0f --- /dev/null +++ b/src/BRepOffset/BRepOffset_SimpleOffset.hxx @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + + +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 has been + //! modified. In this case, is the new geometric + //! support of the face, the new location, + //! the new tolerance. has to be set to + //! Standard_True when the modification reverses the + //! normal of the surface.(the wires have to be + //! reversed). has to be set to + //! Standard_True if the orientation of the modified + //! face changes in the shells which contain it. -- + //! Here, 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 has been + //! modified. In this case, is the new geometric + //! support of the edge, the new location, + //! the new tolerance. Otherwise, returns + //! Standard_False, and , , 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 has been + //! modified. In this case,

is the new geometric + //! support of the vertex, the new tolerance. + //! Otherwise, returns Standard_False, and

, + //! 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 has a new + //! curve on surface on the face .In this case, + //! is the new geometric support of the edge, the + //! new location, the new tolerance. + //! Otherwise, returns Standard_False, and , , + //! 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 has a new + //! parameter on the edge . In this case,

is + //! the parameter, the new tolerance. + //! Otherwise, returns Standard_False, and

, + //! 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 between + //! and . + //! + //! is the new edge created from . + //! (resp. ) is the new face created from + //! (resp. ). + 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 myFaceInfo; + + //! Map of edges to new edges information. + NCollection_DataMap myEdgeInfo; + + //! Map of vertices to new vertices information. + NCollection_DataMap myVertexInfo; + + + //! Ofsset value. + Standard_Real myOffsetValue; +}; + +#endif // _BRepOffset_SimpleOffset_HeaderFile diff --git a/src/BRepOffset/FILES b/src/BRepOffset/FILES new file mode 100644 index 0000000000..1a9db5a664 --- /dev/null +++ b/src/BRepOffset/FILES @@ -0,0 +1,4 @@ +BRepOffset_MakeSimpleOffset.cxx +BRepOffset_MakeSimpleOffset.hxx +BRepOffset_SimpleOffset.cxx +BRepOffset_SimpleOffset.hxx \ No newline at end of file diff --git a/src/BRepTest/BRepTest_FeatureCommands.cxx b/src/BRepTest/BRepTest_FeatureCommands.cxx index 987ce26f3c..88282af98f 100644 --- a/src/BRepTest/BRepTest_FeatureCommands.cxx +++ b/src/BRepTest/BRepTest_FeatureCommands.cxx @@ -54,6 +54,7 @@ #include #include +#include #include #include #include @@ -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); } -- 2.39.5