From: jfa Date: Wed, 11 May 2022 10:57:50 +0000 (+0300) Subject: [bos #29476] [EDF] (2022-T1) SHAPER: Offset in sketch X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=6f336b61aab7eee1256f38e9922381b0b62693ba;p=modules%2Fshaper.git [bos #29476] [EDF] (2022-T1) SHAPER: Offset in sketch --- diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Offset.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_Offset.cpp index 176c569ba..c9c0e48c1 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_Offset.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_Offset.cpp @@ -64,7 +64,8 @@ void GeomAlgoAPI_Offset::generated(const GeomShapePtr theOldShape, GeomAlgoAPI_Offset::GeomAlgoAPI_Offset(const GeomPlanePtr& thePlane, const GeomShapePtr& theEdgeOrWire, - const double theOffsetValue) + const double theOffsetValue, + const GeomAlgoAPI_OffsetJoint theJoint) { // 1. Make wire from edge, if need TopoDS_Wire aWire; @@ -92,11 +93,23 @@ GeomAlgoAPI_Offset::GeomAlgoAPI_Offset(const GeomPlanePtr& thePlane, setImpl(aParal); setBuilderType(OCCT_BRepBuilderAPI_MakeShape); + // Joint type + GeomAbs_JoinType aJoin = GeomAbs_Arc; // default mode, corresponding to KeepDistance + if (theJoint == GeomAlgoAPI_OffsetJoint::Lines) + aJoin = GeomAbs_Intersection; + // for GeomAlgoAPI_OffsetJoint::Arcs do the same as for KeepDistance + Standard_Boolean isOpenResult = !aWire.Closed(); - aParal->Init(aFace, GeomAbs_Arc, isOpenResult); + aParal->Init(aFace, aJoin, isOpenResult); aParal->Perform(theOffsetValue, 0.); if (aParal->IsDone()) { TopoDS_Shape anOffset = aParal->Shape(); + + if (theJoint == GeomAlgoAPI_OffsetJoint::Arcs) { + // TODO: process Arcs case - make fillets on straight + // edges intersections, except too short edges + } + GeomShapePtr aResult(new GeomAPI_Shape()); aResult->setImpl(new TopoDS_Shape(anOffset)); setShape(aResult); diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_Offset.h b/src/GeomAlgoAPI/GeomAlgoAPI_Offset.h index 1afa7ddcf..d175237fe 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_Offset.h +++ b/src/GeomAlgoAPI/GeomAlgoAPI_Offset.h @@ -25,6 +25,16 @@ class GeomAPI_Pln; +/// \enum GeomAlgoAPI_OffsetJoint +/// \brief Type of joint of straight edges in 2D offset +/// \a KeepDistance Keep the distance from initial contour to the resulting one, +/// creating contour from lines and arcs where it is needed +/// \a Arcs On connection of straight edges, tangent arcs are created, +/// except the case of too short edges. Radius of arcs equals to the offset value. +/// \a Lines No arcs is created on the connection of the resulting lines, +/// adjacent lines are prolonged to the point of their intersection. +enum class GeomAlgoAPI_OffsetJoint { KeepDistance, Arcs, Lines }; + /// \class GeomAlgoAPI_Offset /// \ingroup DataAlgo /// \brief Perform 3D offset for the shape @@ -39,9 +49,12 @@ public: /// \param[in] thePlane base plane for all offsets /// \param[in] theEdgesOrWire base shapes /// \param[in] theOffsetValue offset distance, it can be negative - GEOMALGOAPI_EXPORT GeomAlgoAPI_Offset(const std::shared_ptr& thePlane, - const GeomShapePtr& theEdgeOrWire, - const double theOffsetValue); + /// \param[in] theJointType type of joint of straight edges + GEOMALGOAPI_EXPORT GeomAlgoAPI_Offset + (const std::shared_ptr& thePlane, + const GeomShapePtr& theEdgeOrWire, + const double theOffsetValue, + const GeomAlgoAPI_OffsetJoint theJoint = GeomAlgoAPI_OffsetJoint::KeepDistance); /// \return the list of shapes generated from the shape \a theShape. /// \param[in] theOldShape base shape. diff --git a/src/SketchAPI/SketchAPI_Offset.cpp b/src/SketchAPI/SketchAPI_Offset.cpp index 3aa00e729..e7d6d0715 100644 --- a/src/SketchAPI/SketchAPI_Offset.cpp +++ b/src/SketchAPI/SketchAPI_Offset.cpp @@ -34,13 +34,15 @@ SketchAPI_Offset::SketchAPI_Offset (const std::shared_ptr & th SketchAPI_Offset::SketchAPI_Offset (const std::shared_ptr & theFeature, const std::list > & theObjects, const ModelHighAPI_Double & theOffsetValue, - bool theIsReversed) + const bool theIsReversed, + const std::string & theJointType) : ModelHighAPI_Interface(theFeature) { if (initialize()) { fillAttribute(theObjects, edgesList()); fillAttribute(theOffsetValue, value()); fillAttribute(theIsReversed, reversed()); + fillAttribute(theJointType, joint()); execute(); } @@ -72,6 +74,7 @@ void SketchAPI_Offset::dump (ModelHighAPI_Dumper& theDumper) const AttributeRefListPtr aOffsetObjects = edgesList(); AttributeDoublePtr aValue = value(); AttributeBooleanPtr aReversed = reversed(); + AttributeStringPtr aJoint = joint(); // Check all attributes are already dumped. If not, store the feature as postponed. if (!theDumper.isDumped(aOffsetObjects)) { @@ -80,7 +83,7 @@ void SketchAPI_Offset::dump (ModelHighAPI_Dumper& theDumper) const } theDumper << aBase << " = " << aSketchName << ".addOffset(" << aOffsetObjects << ", " - << aValue << ", " << aReversed << ")" << std::endl; + << aValue << ", " << aReversed << ", " << aJoint << ")" << std::endl; // Dump variables for a list of created features theDumper << "["; diff --git a/src/SketchAPI/SketchAPI_Offset.h b/src/SketchAPI/SketchAPI_Offset.h index 13e105686..a6d8c2906 100644 --- a/src/SketchAPI/SketchAPI_Offset.h +++ b/src/SketchAPI/SketchAPI_Offset.h @@ -50,12 +50,13 @@ public: SketchAPI_Offset(const std::shared_ptr & theFeature, const std::list > & theObjects, const ModelHighAPI_Double & theOffsetValue, - bool theIsReversed); + const bool theIsReversed = false, + const std::string & theJointType = SketchPlugin_Offset::JOINT_KEEP_DISTANCE()); /// Destructor SKETCHAPI_EXPORT virtual ~SketchAPI_Offset(); - INTERFACE_3(SketchPlugin_Offset::ID(), + INTERFACE_4(SketchPlugin_Offset::ID(), edgesList, SketchPlugin_Offset::EDGES_ID(), ModelAPI_AttributeRefList, /** Offset edges list */, @@ -64,7 +65,10 @@ public: ModelAPI_AttributeDouble, /** Value */, reversed, SketchPlugin_Offset::REVERSED_ID(), - ModelAPI_AttributeBoolean, /** Negative value */ + ModelAPI_AttributeBoolean, /** Negative value */, + + joint, SketchPlugin_Offset::JOINT_ID(), + ModelAPI_AttributeString, /** Joint type */ ) /// List of created objects diff --git a/src/SketchAPI/SketchAPI_Sketch.cpp b/src/SketchAPI/SketchAPI_Sketch.cpp index 838a558bb..fbb5814af 100644 --- a/src/SketchAPI/SketchAPI_Sketch.cpp +++ b/src/SketchAPI/SketchAPI_Sketch.cpp @@ -930,11 +930,12 @@ std::shared_ptr SketchAPI_Sketch::addMirror( std::shared_ptr SketchAPI_Sketch::addOffset( const std::list > & theObjects, const ModelHighAPI_Double & theValue, - const bool theReversed) + const bool theReversed, + const std::string & theJointType) { std::shared_ptr aFeature = compositeFeature()->addFeature(SketchPlugin_Offset::ID()); - return OffsetPtr(new SketchAPI_Offset(aFeature, theObjects, theValue, theReversed)); + return OffsetPtr(new SketchAPI_Offset(aFeature, theObjects, theValue, theReversed, theJointType)); } //-------------------------------------------------------------------------------------- diff --git a/src/SketchAPI/SketchAPI_Sketch.h b/src/SketchAPI/SketchAPI_Sketch.h index bb83b1887..7b84cebfd 100644 --- a/src/SketchAPI/SketchAPI_Sketch.h +++ b/src/SketchAPI/SketchAPI_Sketch.h @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -378,7 +379,8 @@ public: std::shared_ptr addOffset( const std::list > & theObjects, const ModelHighAPI_Double & theValue, - const bool theReversed); + const bool theReversed = false, + const std::string & theJointType = SketchPlugin_Offset::JOINT_KEEP_DISTANCE()); /// Add translation SKETCHAPI_EXPORT diff --git a/src/SketchPlugin/SketchPlugin_Offset.cpp b/src/SketchPlugin/SketchPlugin_Offset.cpp index 258fdbb80..84a77e964 100644 --- a/src/SketchPlugin/SketchPlugin_Offset.cpp +++ b/src/SketchPlugin/SketchPlugin_Offset.cpp @@ -40,15 +40,19 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include +#include +#include #include #include @@ -61,6 +65,8 @@ #include #include +#include + static const double tolerance = 1.e-7; SketchPlugin_Offset::SketchPlugin_Offset() @@ -86,6 +92,11 @@ void SketchPlugin_Offset::initAttributes() registerNotObligatory(getKind(), SketchPlugin_Constraint::ENTITY_B()); ModelAPI_Session::get()->validators()-> registerNotObligatory(getKind(), SketchPlugin_Constraint::ENTITY_C()); + + AttributeStringPtr aJointAttr = std::dynamic_pointer_cast + (data()->addAttribute(JOINT_ID(), ModelAPI_AttributeString::typeId())); + if (!aJointAttr->isInitialized()) + aJointAttr->setValue(JOINT_KEEP_DISTANCE()); } void SketchPlugin_Offset::execute() @@ -93,6 +104,20 @@ void SketchPlugin_Offset::execute() SketchPlugin_Sketch* aSketch = sketch(); if (!aSketch) return; + // 0. Joint type + AttributeStringPtr aJointAttr = string(JOINT_ID()); + std::string aType = JOINT_KEEP_DISTANCE(); + if (aJointAttr->isInitialized()) + aType = aJointAttr->value(); + + GeomAlgoAPI_OffsetJoint aJoint; + if (aType == JOINT_ARCS()) + aJoint = GeomAlgoAPI_OffsetJoint::Arcs; + else if (aType == JOINT_LINES()) + aJoint = GeomAlgoAPI_OffsetJoint::Lines; + else // Default mode + aJoint = GeomAlgoAPI_OffsetJoint::KeepDistance; + // 1. Sketch plane std::shared_ptr aPlane = aSketch->plane(); @@ -189,14 +214,21 @@ void SketchPlugin_Offset::execute() } // 5.d. Make offset for the wire - std::shared_ptr anOffsetShape( - new GeomAlgoAPI_Offset(aPlane, aWireShape, aValue*aSign)); + std::shared_ptr anOffsetShape + (new GeomAlgoAPI_Offset(aPlane, aWireShape, aValue*aSign, aJoint)); if (anOffsetShape->isDone()) { - std::shared_ptr aMakeList(new GeomAlgoAPI_MakeShapeList); - aMakeList->appendAlgo(aWireBuilder); - aMakeList->appendAlgo(anOffsetShape); - anOffsetAlgos.push_back(aMakeList); + if (aJoint == GeomAlgoAPI_OffsetJoint::Arcs) { + // For Arcs joint make fillet at all straight edges intersections + // of the wire, resulting from GeomAlgoAPI_Offset algorithm + makeFillet(fabs(aValue), aWireBuilder, anOffsetShape, anOffsetAlgos); + } + else { + std::shared_ptr aMakeList (new GeomAlgoAPI_MakeShapeList); + aMakeList->appendAlgo(aWireBuilder); + aMakeList->appendAlgo(anOffsetShape); + anOffsetAlgos.push_back(aMakeList); + } } else { setError("Offset algorithm failed"); @@ -753,7 +785,6 @@ bool SketchPlugin_Offset::findWires() } } } - // TODO: hilight selection in the viewer data()->blockSendAttributeUpdated(aWasBlocked); return true; @@ -769,3 +800,125 @@ AISObjectPtr SketchPlugin_Offset::getAISObject(AISObjectPtr thePrevious) thePrevious); return anAIS; } + + +void SketchPlugin_Offset::makeFillet + (const double theValue, + const std::shared_ptr& theWireBuilder, + const std::shared_ptr& theOffsetShape, + ListOfMakeShape& theOffsetAlgos) +{ + std::shared_ptr aMakeList (new GeomAlgoAPI_MakeShapeList); + aMakeList->appendAlgo(theWireBuilder); + aMakeList->appendAlgo(theOffsetShape); + + bool isOK = true; + + GeomShapePtr aResWire = theOffsetShape->shape(); + GeomAlgoAPI_MapShapesAndAncestors aMapVE + (aResWire, GeomAPI_Shape::VERTEX, GeomAPI_Shape::EDGE); + const MapShapeToShapes& aSubshapes = aMapVE.map(); + + // find vertices for fillet + std::set aFilletVertices; + // ??? TODO: if aResWire is a compound of wires - process each wire ??? + if (aResWire->isWire()) { + for (MapShapeToShapes::const_iterator anIt = aSubshapes.begin(); + anIt != aSubshapes.end(); ++anIt) { + // vertex should have 2 adjacent edges + if (anIt->second.size() != 2) + continue; + + // both edges should be linear + ListOfShape anEdges; + anEdges.insert(anEdges.end(), anIt->second.begin(), anIt->second.end()); + GeomEdgePtr anEdge1 (new GeomAPI_Edge(anEdges.front())); + GeomEdgePtr anEdge2 (new GeomAPI_Edge(anEdges.back())); + if (!anEdge1->isLine() || !anEdge2->isLine()) + continue; + + // skip vertices, which smoothly connect adjacent edges + GeomVertexPtr aSharedVertex(new GeomAPI_Vertex(anIt->first)); + if (GeomAlgoAPI_ShapeTools::isTangent(anEdge1, anEdge2, aSharedVertex)) + continue; + + aFilletVertices.insert(anIt->first); + } + } + + if (!aFilletVertices.empty()) { + isOK = false; // the wire needs correction + ListOfShape aVerticesList; + for (GeomAPI_WireExplorer anExp (aResWire->wire()); anExp.more(); anExp.next()) { + GeomShapePtr aVertex = anExp.currentVertex(); + if (aFilletVertices.find(aVertex) != aFilletVertices.end()) + aVerticesList.push_back(aVertex); + } + + // Fillet1D on all linear edges intersections + std::shared_ptr aFilletBuilder + (new GeomAlgoAPI_Fillet1D(aResWire, aVerticesList, theValue)); + + std::string anError; + if (!GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed + (aFilletBuilder, getKind(), anError)) { + aMakeList->appendAlgo(aFilletBuilder); + isOK = true; + } + else { + ListOfShape aFailedVertices = aFilletBuilder->failedVertices(); + if (aFailedVertices.size() != 0 && + aFailedVertices.size() != aVerticesList.size()) { + // Exclude failed vertices and also vertices, joined + // with failed by one edge, and run algorithm once again + ListOfShape::iterator itVertices = aFailedVertices.begin(); + for (; itVertices != aFailedVertices.end(); itVertices++) { + GeomShapePtr aFailedVertex = *itVertices; + aFilletVertices.erase(aFailedVertex); + // remove also neighbour vertices + MapShapeToShapes::const_iterator anIt = aSubshapes.find(aFailedVertex); + if (anIt != aSubshapes.end()) { // should be always true + ListOfShape anEdges; + anEdges.insert(anEdges.end(), anIt->second.begin(), anIt->second.end()); + GeomEdgePtr anEdge1 (new GeomAPI_Edge(anEdges.front())); + GeomEdgePtr anEdge2 (new GeomAPI_Edge(anEdges.back())); + GeomVertexPtr V1, V2; + anEdge1->vertices(V1, V2); + if (V1->isEqual(aFailedVertex)) V1 = V2; + aFilletVertices.erase(V1); + anEdge2->vertices(V1, V2); + if (V1->isEqual(aFailedVertex)) V1 = V2; + aFilletVertices.erase(V1); + } + } + if (aFilletVertices.size() == 0) { + // there are no suitable vertices for fillet + isOK = true; + } + else { + // Fillet1D one more try + ListOfShape aVerticesList1; + for (GeomAPI_WireExplorer anExp (aResWire->wire()); anExp.more(); anExp.next()) { + GeomShapePtr aVertex = anExp.currentVertex(); + if (aFilletVertices.find(aVertex) != aFilletVertices.end()) + aVerticesList1.push_back(aVertex); + } + + std::shared_ptr aFilletBuilder1 + (new GeomAlgoAPI_Fillet1D(aResWire, aVerticesList1, theValue)); + + if (!GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed + (aFilletBuilder1, getKind(), anError)) { + aMakeList->appendAlgo(aFilletBuilder1); + isOK = true; + } + } + } + } + } + + if (isOK) + theOffsetAlgos.push_back(aMakeList); + else + setError("Offset algorithm failed"); +} diff --git a/src/SketchPlugin/SketchPlugin_Offset.h b/src/SketchPlugin/SketchPlugin_Offset.h index c18efdae3..09c388440 100644 --- a/src/SketchPlugin/SketchPlugin_Offset.h +++ b/src/SketchPlugin/SketchPlugin_Offset.h @@ -28,6 +28,8 @@ #include class GeomAlgoAPI_MakeShape; +class GeomAlgoAPI_Offset; +class GeomAlgoAPI_WireBuilder; /**\class SketchPlugin_Offset * \ingroup Plugins @@ -50,6 +52,34 @@ public: return MY_KIND; } + /// Type of joint + inline static const std::string& JOINT_ID() + { + static const std::string ID("offset_joint"); + return ID; + } + + /// Keep distance joint (add arcs where needed) + inline static const std::string& JOINT_KEEP_DISTANCE() + { + static const std::string ID("KeepDistance"); + return ID; + } + + /// Arcs joint (make fillets on all straight lines intersections) + inline static const std::string& JOINT_ARCS() + { + static const std::string ID("Arcs"); + return ID; + } + + /// Lines joint (do not add new arcs, prolongate and intersect adjacent lines) + inline static const std::string& JOINT_LINES() + { + static const std::string ID("Lines"); + return ID; + } + /// list of offset edges inline static const std::string& EDGES_ID() { @@ -140,6 +170,11 @@ private: std::set& theProcessedEdgesSet, std::list& theChain, const bool isPrepend = false); + + void makeFillet (const double theValue, + const std::shared_ptr&, + const std::shared_ptr&, + std::list< std::shared_ptr >& theOffsetAlgos); }; #endif diff --git a/src/SketchPlugin/Test/TestOffset3.py b/src/SketchPlugin/Test/TestOffset3.py new file mode 100644 index 000000000..f5e1f422d --- /dev/null +++ b/src/SketchPlugin/Test/TestOffset3.py @@ -0,0 +1,106 @@ +# Copyright (C) 2020-2021 CEA/DEN, EDF R&D +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +# + +from salome.shaper import model +from SketchAPI import * + +model.begin() +partSet = model.moduleDocument() + +### Create Sketch +Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY")) + +### Create SketchLine +SketchLine_1 = Sketch_1.addLine(0, 0, 0, 130) + +### Create SketchProjection +SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "Origin"), False) +SketchPoint_1 = SketchProjection_1.createdFeature() +Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchAPI_Point(SketchPoint_1).coordinates()) +Sketch_1.setVertical(SketchLine_1.result()) +Sketch_1.setLength(SketchLine_1.result(), 130) + +### Create SketchLine +SketchLine_2 = Sketch_1.addLine(0, 130, 52.63824701112046, 101.2039073554021) +Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint()) +Sketch_1.setLength(SketchLine_2.result(), 60) + +### Create SketchLine +SketchLine_3 = Sketch_1.addLine(52.63824701112046, 101.2039073554021, 199.7207674554361, 130.6442229064876) +Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint()) +Sketch_1.setLength(SketchLine_3.result(), 150) + +### Create SketchConstraintAngle +Sketch_1.setAngle(SketchLine_3.result(), SketchLine_2.result(), 140, type = "Direct") + +### Create SketchLine +SketchLine_4 = Sketch_1.addLine(158.0815949372134, 7.493180231252017, 199.7207674554361, 130.6442229064876) +Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.endPoint()) +Sketch_1.setLength(SketchLine_4.result(), 130) + +### Create SketchConstraintAngle +Sketch_1.setAngle(SketchLine_3.result(), SketchLine_4.result(), 60, type = "Direct") + +### Create SketchLine +SketchLine_5 = Sketch_1.addLine(158.0815949372134, 7.493180231252017, 106.6596776583922, 54.98830022657437) +Sketch_1.setCoincident(SketchLine_4.startPoint(), SketchLine_5.startPoint()) +Sketch_1.setLength(SketchLine_5.result(), 70) + +### Create SketchLine +SketchLine_6 = Sketch_1.addLine(106.6596776583922, 54.98830022657437, 0, 0) +Sketch_1.setCoincident(SketchLine_5.endPoint(), SketchLine_6.startPoint()) +Sketch_1.setCoincident(SketchLine_6.endPoint(), SketchLine_1.startPoint()) +Sketch_1.setLength(SketchLine_6.result(), 120) + +### Create SketchConstraintAngle +Sketch_1.setAngle(SketchLine_6.result(), SketchLine_5.result(), 110, type = "Direct") + +### SketchOffset objects +SketchOffset_objects = [SketchLine_1.result(), SketchLine_2.result(), SketchLine_3.result(), SketchLine_4.result(), SketchLine_5.result(), SketchLine_6.result()] + +### 1. "KeepDistance" mode + +SketchOffset_1 = Sketch_1.addOffset(SketchOffset_objects, 8, False, "KeepDistance") # outside +SketchOffset_2 = Sketch_1.addOffset(SketchOffset_objects, 8, True, "KeepDistance") # inside +model.do() + +assert(len(SketchOffset_1.offset()) == 10) +assert(len(SketchOffset_2.offset()) == 8) + +### 2. "Arcs" mode + +SketchOffset_3 = Sketch_1.addOffset(SketchOffset_objects, 16, False, "Arcs") # outside +SketchOffset_4 = Sketch_1.addOffset(SketchOffset_objects, 16, True, "Arcs") # inside +model.do() + +assert(len(SketchOffset_3.offset()) == 12) +assert(len(SketchOffset_4.offset()) == 12) + +### 3. "Lines" mode + +SketchOffset_5 = Sketch_1.addOffset(SketchOffset_objects, 24, False, "Lines") # outside +SketchOffset_6 = Sketch_1.addOffset(SketchOffset_objects, 24, True, "Lines") # inside +model.do() + +assert(len(SketchOffset_5.offset()) == 6) +assert(len(SketchOffset_6.offset()) == 6) + +model.end() + +assert(model.checkPythonDump()) diff --git a/src/SketchPlugin/doc/examples/offset.py b/src/SketchPlugin/doc/examples/offset.py index 881db9a40..79e8ae9e1 100644 --- a/src/SketchPlugin/doc/examples/offset.py +++ b/src/SketchPlugin/doc/examples/offset.py @@ -16,7 +16,18 @@ Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.endPoint()) Sketch_1.setCoincident(SketchLine_1.startPoint(), SketchLine_4.startPoint()) SketchOffset_1_objects = [SketchLine_1.result(), SketchLine_2.result(), SketchLine_3.result(), SketchLine_4.result()] + +### KeepDistance (default) mode, not reversed (outside) SketchOffset_1 = Sketch_1.addOffset(SketchOffset_1_objects, 10.0, False) +### KeepDistance mode, reversed (inside) +SketchOffset_2 = Sketch_1.addOffset(SketchOffset_1_objects, 25.0, True, "KeepDistance") + +### Arcs mode, reversed (inside) +SketchOffset_3 = Sketch_1.addOffset(SketchOffset_1_objects, 15.0, True, "Arcs") + +### Lines mode, not reversed (outside) +SketchOffset_4 = Sketch_1.addOffset(SketchOffset_1_objects, 20.0, False, "Lines") + model.do() model.end() diff --git a/src/SketchPlugin/doc/images/Offset_panel.png b/src/SketchPlugin/doc/images/Offset_panel.png index d34ad6c3c..de9741e54 100644 Binary files a/src/SketchPlugin/doc/images/Offset_panel.png and b/src/SketchPlugin/doc/images/Offset_panel.png differ diff --git a/src/SketchPlugin/doc/offsetFeature.rst b/src/SketchPlugin/doc/offsetFeature.rst index ce42254df..65af062c9 100644 --- a/src/SketchPlugin/doc/offsetFeature.rst +++ b/src/SketchPlugin/doc/offsetFeature.rst @@ -4,10 +4,24 @@ Offset ====== Offset operation offsets sketch entities on a given distance. -Gaps are filled by arcs. Offset is performed outside a closed contour or to the right of an open one, unless the **Reversed** flag is not set. +Edges junctions are filled in accordance with selected offset mode. +The following modes are implemented: + - **Keep distance** mode, enabled by default. It keeps the distance from initial + contour to the resulting one, creating additional arcs where it is needed. + - **Arcs mode**, where on connection of straight segments, tangent arcs are created. + Only connection of straight lines is supported; with other types of curves, + offset will work as in **Keep distance** mode. Radius of arcs equals to the offset value. + These arcs cut off the initially connected lines, so, if in result at least one + such line becomes invalid (removed from the result), the arc is not created + in this connection, the line is created in this point as in the **Lines** mode. + - **Lines** mode, where no arcs is created on the connection of the resulting lines. + Adjacent lines are prolonged to the point of their intersection. If the offset + arguments are not straigh lines (arcs, bspline, etc), the offset will work + as in the **Keep distance** mode in these locations. + To create an Offset in the active Sketch: #. select in the Main Menu *Sketch - > Offset* item or @@ -23,6 +37,7 @@ Property panel: Input fields: +- Offset mode can be **Keep distance**, **Arcs** or **Lines** - **Edges** is the list of segments (lines, circles, arcs) selected in the view. - **Offset value** is the offset distance. - **Reversed** sets the reversed offset side (inside a closed contour or to the left of an open one). @@ -35,11 +50,12 @@ Button: **TUI Command**: -.. py:function:: Sketch_1.addOffset(Objects, Distance, isReversed) +.. py:function:: Sketch_1.addOffset(Objects, Distance, isReversed, Mode) :param list: A list of objects. :param real: An offset distance. :param boolean: Reversed flag. + :param string: Offset mode. Can be "KeepDistance", "Arcs" or "Lines". :return: Result object. Result diff --git a/src/SketchPlugin/icons/offset_arcs_32x32.png b/src/SketchPlugin/icons/offset_arcs_32x32.png new file mode 100644 index 000000000..046c60a57 Binary files /dev/null and b/src/SketchPlugin/icons/offset_arcs_32x32.png differ diff --git a/src/SketchPlugin/icons/offset_keep_distance_32x32.png b/src/SketchPlugin/icons/offset_keep_distance_32x32.png new file mode 100644 index 000000000..ae7dd5bbe Binary files /dev/null and b/src/SketchPlugin/icons/offset_keep_distance_32x32.png differ diff --git a/src/SketchPlugin/icons/offset_lines_32x32.png b/src/SketchPlugin/icons/offset_lines_32x32.png new file mode 100644 index 000000000..486f6e93c Binary files /dev/null and b/src/SketchPlugin/icons/offset_lines_32x32.png differ diff --git a/src/SketchPlugin/plugin-Sketch.xml b/src/SketchPlugin/plugin-Sketch.xml index 824e6281b..86b234c51 100644 --- a/src/SketchPlugin/plugin-Sketch.xml +++ b/src/SketchPlugin/plugin-Sketch.xml @@ -1020,6 +1020,17 @@ tooltip="Offset a curve to a distance" icon="icons/Sketch/offset.png" helpfile="offsetFeature.html"> + + + + +