From dbc09e3a2342af8784045d3d0ae3565ec869bef6 Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 26 Jan 2019 22:51:29 +0100 Subject: [PATCH] fixes 0003020: 2D offset of circle are not in the right place --- .../Part/App/BRepOffsetAPI_MakeOffsetFix.cpp | 198 ++++++++++++++++++ .../Part/App/BRepOffsetAPI_MakeOffsetFix.h | 85 ++++++++ src/Mod/Part/App/CMakeLists.txt | 2 + src/Mod/Part/App/TopoShape.cpp | 12 +- 4 files changed, 289 insertions(+), 8 deletions(-) create mode 100644 src/Mod/Part/App/BRepOffsetAPI_MakeOffsetFix.cpp create mode 100644 src/Mod/Part/App/BRepOffsetAPI_MakeOffsetFix.h diff --git a/src/Mod/Part/App/BRepOffsetAPI_MakeOffsetFix.cpp b/src/Mod/Part/App/BRepOffsetAPI_MakeOffsetFix.cpp new file mode 100644 index 0000000000..ecc85405e1 --- /dev/null +++ b/src/Mod/Part/App/BRepOffsetAPI_MakeOffsetFix.cpp @@ -0,0 +1,198 @@ +/*************************************************************************** + * Copyright (c) 2019 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" +#ifndef _PreComp_ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif +#include "BRepOffsetAPI_MakeOffsetFix.h" + +using namespace Part; + +BRepOffsetAPI_MakeOffsetFix::BRepOffsetAPI_MakeOffsetFix() +{ +} + +BRepOffsetAPI_MakeOffsetFix::BRepOffsetAPI_MakeOffsetFix(const GeomAbs_JoinType Join, const Standard_Boolean IsOpenResult) +{ +#if OCC_VERSION_HEX >= 0x060900 + mkOffset.Init(Join, IsOpenResult); +#else + (void)IsOpenResult; + mkOffset.Init(Join); +#endif +} + +BRepOffsetAPI_MakeOffsetFix::~BRepOffsetAPI_MakeOffsetFix() +{ +} + +void BRepOffsetAPI_MakeOffsetFix::AddWire(const TopoDS_Wire& Spine) +{ + TopoDS_Wire wire = Spine; + int numEdges = 0; + TopExp_Explorer xp(wire, TopAbs_EDGE); + while (xp.More()) { + numEdges++; + xp.Next(); + } + if (numEdges == 1) { + TopLoc_Location edgeLocation; + + BRepBuilderAPI_MakeWire mkWire; + TopExp_Explorer xp(wire, TopAbs_EDGE); + while (xp.More()) { + // The trick is to reset the placement of an edge before + // passing it to BRepOffsetAPI_MakeOffset because then it + // will create the expected result. + // Afterwards apply the placement again on the result shape. + // See the method MakeWire() + TopoDS_Edge edge = TopoDS::Edge(xp.Current()); + edgeLocation = edge.Location(); + edge.Location(TopLoc_Location()); + mkWire.Add(edge); + myLocations.push_back(std::make_pair(edge, edgeLocation)); + xp.Next(); + } + + wire = mkWire.Wire(); + } + mkOffset.AddWire(wire); + myResult.Nullify(); +} + +void BRepOffsetAPI_MakeOffsetFix::Perform (const Standard_Real Offset, const Standard_Real Alt) +{ + mkOffset.Perform(Offset, Alt); +} + +void BRepOffsetAPI_MakeOffsetFix::Build() +{ + mkOffset.Build(); +} + +Standard_Boolean BRepOffsetAPI_MakeOffsetFix::IsDone() const +{ + return mkOffset.IsDone(); +} + +void BRepOffsetAPI_MakeOffsetFix::MakeWire(TopoDS_Shape& wire) +{ + // get the edges of the wire and check which of the stored edges + // serve as input of the wire + TopTools_MapOfShape aMap; + TopExp_Explorer xp(wire, TopAbs_EDGE); + while (xp.More()) { + aMap.Add(xp.Current()); + xp.Next(); + } + + std::list edgeList; + for (auto itLoc : myLocations) { + const TopTools_ListOfShape& newShapes = mkOffset.Generated(itLoc.first); + for (TopTools_ListIteratorOfListOfShape it(newShapes); it.More(); it.Next()) { + TopoDS_Shape newShape = it.Value(); + + if (aMap.Contains(newShape)) { + newShape.Move(itLoc.second); + edgeList.push_back(TopoDS::Edge(newShape)); + } + } + } + + if (!edgeList.empty()) { + BRepBuilderAPI_MakeWire mkWire; + mkWire.Add(edgeList.front()); + edgeList.pop_front(); + wire = mkWire.Wire(); + + bool found = false; + do { + found = false; + for (std::list::iterator pE = edgeList.begin(); pE != edgeList.end(); ++pE) { + mkWire.Add(*pE); + if (mkWire.Error() != BRepBuilderAPI_DisconnectedWire) { + // edge added ==> remove it from list + found = true; + edgeList.erase(pE); + wire = mkWire.Wire(); + break; + } + } + } + while (found); + } +} + +const TopoDS_Shape& BRepOffsetAPI_MakeOffsetFix::Shape() +{ + if (myResult.IsNull()) { + TopoDS_Shape result = mkOffset.Shape(); + if (result.ShapeType() == TopAbs_WIRE) { + MakeWire(result); + } + else if (result.ShapeType() == TopAbs_COMPOUND) { + BRep_Builder builder; + TopoDS_Compound comp; + builder.MakeCompound(comp); + + TopExp_Explorer xp(result, TopAbs_WIRE); + while (xp.More()) { + TopoDS_Wire wire = TopoDS::Wire(xp.Current()); + MakeWire(wire); + builder.Add(comp, wire); + xp.Next(); + } + + result = comp; + } + + myResult = result; + } + return myResult; +} + +const TopTools_ListOfShape& BRepOffsetAPI_MakeOffsetFix::Generated(const TopoDS_Shape& S) +{ + return mkOffset.Generated(S); +} + +const TopTools_ListOfShape& BRepOffsetAPI_MakeOffsetFix::Modified (const TopoDS_Shape& S) +{ + return mkOffset.Modified(S); +} + +Standard_Boolean BRepOffsetAPI_MakeOffsetFix::IsDeleted (const TopoDS_Shape& S) +{ + return mkOffset.IsDeleted(S); +} diff --git a/src/Mod/Part/App/BRepOffsetAPI_MakeOffsetFix.h b/src/Mod/Part/App/BRepOffsetAPI_MakeOffsetFix.h new file mode 100644 index 0000000000..56f91a5a34 --- /dev/null +++ b/src/Mod/Part/App/BRepOffsetAPI_MakeOffsetFix.h @@ -0,0 +1,85 @@ +/*************************************************************************** + * Copyright (c) 2019 Werner Mayer * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef PART_BREPOFFSETAPI_MAKEOFFSETFIX_H +#define PART_BREPOFFSETAPI_MAKEOFFSETFIX_H + +#include +#include +#include + +namespace Part { +/*! + * \brief The BRepOffsetAPI_MakeOffsetFix class + * This class works around a limitation of the BRepOffsetAPI_MakeOffset which + * returns unexpected results when an input wire has set a placement and consists + * of a single edge only. + */ +class PartExport BRepOffsetAPI_MakeOffsetFix : public BRepBuilderAPI_MakeShape +{ +public: + BRepOffsetAPI_MakeOffsetFix(); + BRepOffsetAPI_MakeOffsetFix(const GeomAbs_JoinType Join, const Standard_Boolean IsOpenResult); + virtual ~BRepOffsetAPI_MakeOffsetFix(); + + //! Initializes the algorithm to construct parallels to the wire Spine. + void AddWire (const TopoDS_Wire& Spine); + + //! Computes a parallel to the spine at distance Offset and + //! at an altitude Alt from the plane of the spine in relation + //! to the normal to the spine. + //! Exceptions: StdFail_NotDone if the offset is not built. + void Perform (const Standard_Real Offset, const Standard_Real Alt = 0.0); + + //! Builds the resulting shape (redefined from MakeShape). + void Build(); + + virtual Standard_Boolean IsDone() const; + + //! Returns a shape built by the shape construction algorithm. + //! Raises exception StdFail_NotDone if the shape was not built. + virtual const TopoDS_Shape& Shape(); + + //! returns a list of the created shapes + //! from the shape . + virtual const TopTools_ListOfShape& Generated (const TopoDS_Shape& S) Standard_OVERRIDE; + + //! Returns the list of shapes modified from the shape + //! . + virtual const TopTools_ListOfShape& Modified (const TopoDS_Shape& S); + + //! Returns true if the shape S has been deleted. + virtual Standard_Boolean IsDeleted (const TopoDS_Shape& S); + +private: + void MakeWire(TopoDS_Shape&); + +private: + BRepOffsetAPI_MakeOffset mkOffset; + std::list > myLocations; + TopoDS_Shape myResult; +}; + +} + +#endif // PART_BREPOFFSETAPI_MAKEOFFSETFIX_H diff --git a/src/Mod/Part/App/CMakeLists.txt b/src/Mod/Part/App/CMakeLists.txt index 43b75e20a9..0c731fedd8 100644 --- a/src/Mod/Part/App/CMakeLists.txt +++ b/src/Mod/Part/App/CMakeLists.txt @@ -329,6 +329,8 @@ SET(Part_SRCS Attacher.h AppPart.cpp AppPartPy.cpp + BRepOffsetAPI_MakeOffsetFix.cpp + BRepOffsetAPI_MakeOffsetFix.h BSplineCurveBiArcs.cpp CrossSection.cpp CrossSection.h diff --git a/src/Mod/Part/App/TopoShape.cpp b/src/Mod/Part/App/TopoShape.cpp index 3ef74866c8..a430bfdfdd 100644 --- a/src/Mod/Part/App/TopoShape.cpp +++ b/src/Mod/Part/App/TopoShape.cpp @@ -196,6 +196,7 @@ #include "Tools.h" #include "encodeFilename.h" #include "FaceMakerBullseye.h" +#include "BRepOffsetAPI_MakeOffsetFix.h" using namespace Part; @@ -2618,14 +2619,9 @@ TopoDS_Shape TopoShape::makeOffset2D(double offset, short joinType, bool fill, b //do the offset.. TopoDS_Shape offsetShape; - BRepOffsetAPI_MakeOffset mkOffset(sourceWires[0], GeomAbs_JoinType(joinType) -#if OCC_VERSION_HEX >= 0x060900 - , allowOpenResult -#endif - ); + BRepOffsetAPI_MakeOffsetFix mkOffset(GeomAbs_JoinType(joinType), allowOpenResult); for (TopoDS_Wire &w : sourceWires) { - if (&w != &(sourceWires[0])) //filter out first wire - it's already added - mkOffset.AddWire(w); + mkOffset.AddWire(w); } if (fabs(offset) > Precision::Confusion()) { @@ -2643,7 +2639,7 @@ TopoDS_Shape TopoShape::makeOffset2D(double offset, short joinType, bool fill, b } offsetShape = mkOffset.Shape(); - if(offsetShape.IsNull()) + if (offsetShape.IsNull()) throw Base::CADKernelError("makeOffset2D: result of offsetting is null!"); //Copying shape to fix strange orientation behavior, OCC7.0.0. See bug #2699