From 59a0ab09e4c41969b0e8b0af46d7fc3b9a9bc63b Mon Sep 17 00:00:00 2001 From: jfa Date: Thu, 18 Jun 2020 14:54:19 +0300 Subject: [PATCH] Offset feature (partially working version) --- src/SketchPlugin/SketchPlugin_Offset.cpp | 277 ++++++++++++++++++++++- src/SketchPlugin/SketchPlugin_Offset.h | 26 ++- src/SketchPlugin/plugin-Sketch.xml | 10 +- 3 files changed, 308 insertions(+), 5 deletions(-) diff --git a/src/SketchPlugin/SketchPlugin_Offset.cpp b/src/SketchPlugin/SketchPlugin_Offset.cpp index 269c25980..aadc85824 100644 --- a/src/SketchPlugin/SketchPlugin_Offset.cpp +++ b/src/SketchPlugin/SketchPlugin_Offset.cpp @@ -19,12 +19,31 @@ #include +#include +#include +#include +#include +#include +#include + #include #include #include #include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include SketchPlugin_Offset::SketchPlugin_Offset() : SketchPlugin_SketchEntity() @@ -33,6 +52,7 @@ SketchPlugin_Offset::SketchPlugin_Offset() void SketchPlugin_Offset::initDerivedClassAttributes() { + std::cout << " !!! *** SketchPlugin_Offset::initDerivedClassAttributes()" << std::endl; data()->addAttribute(EDGES_ID(), ModelAPI_AttributeRefList::typeId()); data()->addAttribute(VALUE_ID(), ModelAPI_AttributeDouble::typeId()); data()->addAttribute(REVERSED_ID(), ModelAPI_AttributeBoolean::typeId()); @@ -40,14 +60,219 @@ void SketchPlugin_Offset::initDerivedClassAttributes() void SketchPlugin_Offset::execute() { + std::cout << " !!! *** SketchPlugin_Offset::execute()" << std::endl; + + ModelAPI_Tools::removeFeaturesAndReferences(myCreatedFeatures); + + SketchPlugin_Sketch* aSketch = sketch(); + if (!aSketch) return; + + // 1. Sketch plane + std::shared_ptr aPlane = aSketch->plane(); + + // 2. Offset value + AttributeDoublePtr aValueAttr = real(VALUE_ID()); + if (!aValueAttr->isInitialized()) return; + double aValue = aValueAttr->value(); + const double tolerance = 1.e-7; + if (aValue < tolerance) return; + + // 2.a. Reversed? + AttributeBooleanPtr aReversedAttr = boolean(REVERSED_ID()); + if (!aReversedAttr->isInitialized()) return; + if (aReversedAttr->value()) aValue = -aValue; // reverse offset direction + + // 3. List of all selected edges + AttributeRefListPtr aSelectedEdges = reflist(EDGES_ID()); + std::list anEdgesList = aSelectedEdges->list(); + + // 4. Put all selected edges in a set to pass them into findWireOneWay() below + std::set anEdgesSet; + std::list::const_iterator anEdgesIt = anEdgesList.begin(); + for (; anEdgesIt != anEdgesList.end(); anEdgesIt++) { + FeaturePtr aFeature = ModelAPI_Feature::feature(*anEdgesIt); + if (aFeature) { + anEdgesSet.insert(aFeature); + } + } + + // 5. Gather chains of edges + for (anEdgesIt = anEdgesList.begin(); anEdgesIt != anEdgesList.end(); anEdgesIt++) { + FeaturePtr aFeature = ModelAPI_Feature::feature(*anEdgesIt); + if (aFeature.get()) { + if (anEdgesSet.find(aFeature) == anEdgesSet.end()) + continue; + + // End points (if any) + std::shared_ptr aStartPoint, anEndPoint; + SketchPlugin_SegmentationTools::getFeaturePoints(aFeature, aStartPoint, anEndPoint); + + std::list aChain; + aChain.push_back(aFeature); + bool isClosed = findWireOneWay(aFeature, aFeature, aStartPoint, anEdgesSet, aChain); + if (!isClosed) + findWireOneWay(aFeature, aFeature, anEndPoint, anEdgesSet, aChain); + std::set::iterator aPos = anEdgesSet.find(aFeature); + if (aPos != anEdgesSet.end()) + anEdgesSet.erase(aPos); + + ListOfShape aTopoChain; + std::list::iterator aChainIt = aChain.begin(); + for (; aChainIt != aChain.end(); ++aChainIt) { + FeaturePtr aChainFeature = (*aChainIt); + GeomShapePtr aTopoEdge = aChainFeature->lastResult()->shape(); + if (aTopoEdge->shapeType() == GeomAPI_Shape::EDGE) { + aTopoChain.push_back(aTopoEdge); + } + } + GeomShapePtr anEdgeOrWire = GeomAlgoAPI_WireBuilder::wire(aTopoChain); + + // 6. Make offset for each wire or edge + std::shared_ptr anOffsetShape = + GeomAlgoAPI_Offset::OffsetInPlane(aPlane, anEdgeOrWire, aValue); + + // 7. Store offset results + // Create sketch feature for each edge of anOffsetShape, + // and also store created features in list to remove them on next execute() + addToSketch(anOffsetShape); + } + } +} + +bool SketchPlugin_Offset::findWireOneWay (const FeaturePtr& theFirstEdge, + const FeaturePtr& theEdge, + const std::shared_ptr& theEndPoint, + std::set& theEdgesSet, + std::list& theChain) +{ + // Find coincident edges at Start Point + if (!theEndPoint) return false; + + FeaturePtr aNextEdgeFeature; + std::set aCoincFeatures = + SketchPlugin_Tools::findFeaturesCoincidentToPoint(theEndPoint); + + int nbFound = 0; + std::set::iterator aCoincIt; + for (aCoincIt = aCoincFeatures.begin(); aCoincIt != aCoincFeatures.end(); ++aCoincIt) { + FeaturePtr aCoincFeature = (*aCoincIt); + if (aCoincFeature->getKind() != SketchPlugin_Point::ID()) { + if (aCoincFeature != theEdge) { + bool isInSet = true; // empty set means all sketch edges + if (theEdgesSet.size()) { + isInSet = (theEdgesSet.find(aCoincFeature) != theEdgesSet.end()); + } + if (isInSet) { + aNextEdgeFeature = aCoincFeature; + nbFound++; + } + } + } + } + + if (nbFound == 1) { + if (aNextEdgeFeature == theFirstEdge) + // Closed chain found + return true; + + // continue the chain + theChain.push_back(aNextEdgeFeature); + // remove from the set, if the set is used + if (theEdgesSet.size()) { + std::set::iterator aPos = theEdgesSet.find(aNextEdgeFeature); + if (aPos != theEdgesSet.end()) + theEdgesSet.erase(aPos); + } + + std::shared_ptr aNextStartPoint, aNextEndPoint; + SketchPlugin_SegmentationTools::getFeaturePoints(aNextEdgeFeature, aNextStartPoint, aNextEndPoint); + if (aNextStartPoint && aNextEndPoint) { + if (aNextEndPoint == theEndPoint) + aNextEndPoint = aNextStartPoint; + + return findWireOneWay (theFirstEdge, aNextEdgeFeature, aNextEndPoint, theEdgesSet, theChain); + } + } + + return false; +} + +void SketchPlugin_Offset::addToSketch(const std::shared_ptr& anOffsetShape) +{ + //GeomAPI_ShapeExplorer::GeomAPI_ShapeExplorer + ListOfShape aResEdges = GeomAlgoAPI_ShapeTools::getLowLevelSubShapes(anOffsetShape); + std::list::const_iterator aResEdgesIt = aResEdges.begin(); + for (; aResEdgesIt != aResEdges.end(); aResEdgesIt++) { + GeomShapePtr aResShape = (*aResEdgesIt); + if (aResShape->shapeType() == GeomAPI_Shape::EDGE) { + // Add new feature + FeaturePtr aResFeature; + std::shared_ptr aResEdge (new GeomAPI_Edge(aResShape)); + + std::shared_ptr aFP, aLP; + std::shared_ptr aFP3d = aResEdge->firstPoint(); + std::shared_ptr aLP3d = aResEdge->lastPoint(); + if (aFP3d.get() && aLP3d.get()) { + aFP = sketch()->to2D(aFP3d); + aLP = sketch()->to2D(aLP3d); + } + + if (aResEdge->isLine()) { + aResFeature = sketch()->addFeature(SketchPlugin_Line::ID()); + + std::dynamic_pointer_cast + (aResFeature->attribute(SketchPlugin_Line::START_ID()))->setValue(aFP); + std::dynamic_pointer_cast + (aResFeature->attribute(SketchPlugin_Line::END_ID()))->setValue(aLP); + } + else if (aResEdge->isArc()) { + std::shared_ptr aCircEdge = aResEdge->circle(); + std::shared_ptr aCP3d = aCircEdge->center(); + std::shared_ptr aCP = sketch()->to2D(aCP3d); + + aResFeature = sketch()->addFeature(SketchPlugin_Arc::ID()); + + bool aWasBlocked = aResFeature->data()->blockSendAttributeUpdated(true); + std::dynamic_pointer_cast + (aResFeature->attribute(SketchPlugin_Arc::CENTER_ID()))->setValue(aCP); + std::dynamic_pointer_cast + (aResFeature->attribute(SketchPlugin_Arc::START_ID()))->setValue(aFP); + std::dynamic_pointer_cast + (aResFeature->attribute(SketchPlugin_Arc::END_ID()))->setValue(aLP); + aResFeature->data()->blockSendAttributeUpdated(aWasBlocked); + } + else if (aResEdge->isCircle()) { + std::shared_ptr aCircEdge = aResEdge->circle(); + std::shared_ptr aCP3d = aCircEdge->center(); + std::shared_ptr aCP = sketch()->to2D(aCP3d); + + aResFeature = sketch()->addFeature(SketchPlugin_Circle::ID()); + std::dynamic_pointer_cast + (aResFeature->attribute(SketchPlugin_Circle::CENTER_ID()))->setValue(aCP); + aResFeature->real(SketchPlugin_Circle::RADIUS_ID())->setValue(aCircEdge->radius()); + } + else { + } + + if (aResFeature.get()) { + myCreatedFeatures.insert(aResFeature); + + aResFeature->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue + (boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->value()); + aResFeature->execute(); + } + } + } } void SketchPlugin_Offset::attributeChanged(const std::string& theID) { + std::cout << " !!! *** SketchPlugin_Offset::attributeChanged()" << std::endl; } bool SketchPlugin_Offset::customAction(const std::string& theActionId) { + std::cout << " !!! *** SketchPlugin_Offset::customAction()" << std::endl; bool isOk = false; if (theActionId == ADD_WIRE_ACTION_ID()) { isOk = findWires(); @@ -61,5 +286,55 @@ bool SketchPlugin_Offset::customAction(const std::string& theActionId) bool SketchPlugin_Offset::findWires() { - return false; + AttributeRefListPtr aSelectedEdges = reflist(EDGES_ID()); + std::list anEdgesList = aSelectedEdges->list(); + + // Empty set + std::set anEdgesSet; + + // Processed set + std::set anEdgesSet1; + + // Put all selected edges in a set to pass them into findWireOneWay() below + std::set aSelectedSet; + std::list::const_iterator anEdgesIt = anEdgesList.begin(); + for (; anEdgesIt != anEdgesList.end(); anEdgesIt++) { + FeaturePtr aFeature = ModelAPI_Feature::feature(*anEdgesIt); + if (aFeature) { + aSelectedSet.insert(aFeature); + } + } + + // Gather chains of edges + for (anEdgesIt = anEdgesList.begin(); anEdgesIt != anEdgesList.end(); anEdgesIt++) { + FeaturePtr aFeature = ModelAPI_Feature::feature(*anEdgesIt); + if (aFeature.get()) { + if (anEdgesSet1.find(aFeature) != anEdgesSet1.end()) + continue; + anEdgesSet1.insert(aFeature); + + // End points (if any) + std::shared_ptr aStartPoint, anEndPoint; + SketchPlugin_SegmentationTools::getFeaturePoints(aFeature, aStartPoint, anEndPoint); + + std::list aChain; + aChain.push_back(aFeature); + bool isClosed = findWireOneWay(aFeature, aFeature, aStartPoint, anEdgesSet, aChain); + if (!isClosed) + findWireOneWay(aFeature, aFeature, anEndPoint, anEdgesSet, aChain); + + std::list::iterator aChainIt = aChain.begin(); + for (; aChainIt != aChain.end(); ++aChainIt) { + FeaturePtr aChainFeature = (*aChainIt); + anEdgesSet1.insert(aChainFeature); + if (aSelectedSet.find(aChainFeature) == aSelectedSet.end()) { + // TODO: add in reflist(EDGES_ID()), update viewer + // ?? ModelHighAPI_Tools::fillAttribute() + std::cout << " !!! *** SketchPlugin_Offset::findWires() - Add an edge" << std::endl; + } + } + } + } + + return true; } diff --git a/src/SketchPlugin/SketchPlugin_Offset.h b/src/SketchPlugin/SketchPlugin_Offset.h index 19fff782a..678bb4c4c 100644 --- a/src/SketchPlugin/SketchPlugin_Offset.h +++ b/src/SketchPlugin/SketchPlugin_Offset.h @@ -22,6 +22,7 @@ #include #include +#include /**\class SketchPlugin_Offset * \ingroup Plugins @@ -82,7 +83,8 @@ public: /// \returns true SKETCHPLUGIN_EXPORT virtual bool isMacro() const { return true; } - SKETCHPLUGIN_EXPORT virtual bool isPreviesNeeded() const { return false; } + //SKETCHPLUGIN_EXPORT virtual bool isPreviewNeeded() const { return false; } + SKETCHPLUGIN_EXPORT virtual bool isPreviewNeeded() const { return true; } /// Find edges connected by coincident boundary constraint and composing a wire with /// the already selected segments. It means that not more than 2 edges can be connected @@ -91,7 +93,7 @@ public: /// \return \c false in case the action not performed. SKETCHPLUGIN_EXPORT virtual bool customAction(const std::string& theActionId); - /// Use plugin manager for features creatio + /// Use plugin manager for features creation. SketchPlugin_Offset(); protected: @@ -101,6 +103,26 @@ protected: private: /// Find all wires connected with the selected edges bool findWires(); + + // Create sketch feature for each edge of theOffsetResult, + // and store it in myCreatedFeatures to remove on next execute() + void addToSketch (const std::shared_ptr& theOffsetResult); + + // Find edges that prolongate theEdgeFeature (in a chain) at theEndPoint + // Recursive method. + // \param[in] theEdgeFeature + // \param[in] theEndPoint + // \param[in/out] theAllEdges + // \param[in/out] theChain + /// \return \c true if the chain is closed + bool findWireOneWay (const FeaturePtr& theFirstEdge, + const FeaturePtr& theEdge, + const std::shared_ptr& theEndPoint, + std::set& theEdgesSet, + std::list& theChain); + + // tmp + std::set myCreatedFeatures; }; #endif diff --git a/src/SketchPlugin/plugin-Sketch.xml b/src/SketchPlugin/plugin-Sketch.xml index e7cb83553..5bfeb303d 100644 --- a/src/SketchPlugin/plugin-Sketch.xml +++ b/src/SketchPlugin/plugin-Sketch.xml @@ -958,16 +958,22 @@ tooltip="Offset value" default="1" min="0.000001" use_reset="false"> - + + + tooltip="Add the list of segments composing a wire with the selected items through the coincidence by boundary points"/> -- 2.39.2