From 10f21d0cd6ce43b0af22c6e9ee436bc6a08ea5fa Mon Sep 17 00:00:00 2001 From: jfa Date: Fri, 15 Nov 2019 15:43:33 +0300 Subject: [PATCH] Task #3079 3.5 Build/Vertex on a whole Sketch --- src/BuildAPI/BuildAPI_Vertex.cpp | 25 +- src/BuildAPI/BuildAPI_Vertex.h | 19 +- src/BuildPlugin/BuildPlugin_Plugin.cpp | 2 + src/BuildPlugin/BuildPlugin_Validators.cpp | 60 ++++- src/BuildPlugin/BuildPlugin_Validators.h | 15 ++ src/BuildPlugin/BuildPlugin_Vertex.cpp | 258 ++++++++++++++++++--- src/BuildPlugin/BuildPlugin_Vertex.h | 17 ++ src/BuildPlugin/Test/TestVertex.py | 13 +- src/BuildPlugin/vertex_widget.xml | 8 +- 9 files changed, 370 insertions(+), 47 deletions(-) diff --git a/src/BuildAPI/BuildAPI_Vertex.cpp b/src/BuildAPI/BuildAPI_Vertex.cpp index 327a2d290..f94b230f1 100644 --- a/src/BuildAPI/BuildAPI_Vertex.cpp +++ b/src/BuildAPI/BuildAPI_Vertex.cpp @@ -35,6 +35,19 @@ BuildAPI_Vertex::BuildAPI_Vertex(const std::shared_ptr& theFea : ModelHighAPI_Interface(theFeature) { if(initialize()) { + fillAttribute(false, mydoIntersect); + setBase(theBaseObjects); + } +} + +//================================================================================================== +BuildAPI_Vertex::BuildAPI_Vertex(const std::shared_ptr& theFeature, + const std::list& theBaseObjects, + const bool theDoIntersect) +: ModelHighAPI_Interface(theFeature) +{ + if(initialize()) { + fillAttribute(theDoIntersect, mydoIntersect); setBase(theBaseObjects); } } @@ -61,6 +74,15 @@ VertexPtr addVertex(const std::shared_ptr& thePart, return VertexPtr(new BuildAPI_Vertex(aFeature, theBaseObjects)); } +//================================================================================================== +VertexPtr addVertex(const std::shared_ptr& thePart, + const std::list& theBaseObjects, + const bool theDoIntersect) +{ + std::shared_ptr aFeature = thePart->addFeature(BuildAPI_Vertex::ID()); + return VertexPtr(new BuildAPI_Vertex(aFeature, theBaseObjects, theDoIntersect)); +} + //================================================================================================== void BuildAPI_Vertex::dump(ModelHighAPI_Dumper& theDumper) const { @@ -68,5 +90,6 @@ void BuildAPI_Vertex::dump(ModelHighAPI_Dumper& theDumper) const std::string aPartName = theDumper.name(aBase->document()); theDumper << aBase << " = model.addVertex(" << aPartName << ", " - << aBase->selectionList(BuildPlugin_Vertex::BASE_OBJECTS_ID()) << ")" << std::endl; + << aBase->selectionList(BuildPlugin_Vertex::BASE_OBJECTS_ID()) << ", " + << aBase->boolean(BuildPlugin_Vertex::INTERSECT_ID()) << ")" << std::endl; } diff --git a/src/BuildAPI/BuildAPI_Vertex.h b/src/BuildAPI/BuildAPI_Vertex.h index 6a96640a4..77ba77e95 100644 --- a/src/BuildAPI/BuildAPI_Vertex.h +++ b/src/BuildAPI/BuildAPI_Vertex.h @@ -44,13 +44,21 @@ public: explicit BuildAPI_Vertex(const std::shared_ptr& theFeature, const std::list& theBaseObjects); + /// Constructor with values. + BUILDAPI_EXPORT + explicit BuildAPI_Vertex(const std::shared_ptr& theFeature, + const std::list& theBaseObjects, + const bool theDoIntersect); + /// Destructor. BUILDAPI_EXPORT virtual ~BuildAPI_Vertex(); - INTERFACE_1(BuildPlugin_Vertex::ID(), + INTERFACE_2(BuildPlugin_Vertex::ID(), baseObjects, BuildPlugin_Vertex::BASE_OBJECTS_ID(), - ModelAPI_AttributeSelectionList, /** Base objects */) + ModelAPI_AttributeSelectionList, /** Base objects */, + doIntersect, BuildPlugin_Vertex::INTERSECT_ID(), + ModelAPI_AttributeBoolean, /** Compute intersections */) /// Modify base attribute of the feature. BUILDAPI_EXPORT @@ -70,4 +78,11 @@ BUILDAPI_EXPORT VertexPtr addVertex(const std::shared_ptr& thePart, const std::list& theBaseObjects); +/// \ingroup CPPHighAPI +/// \brief Create Vertex feature. +BUILDAPI_EXPORT +VertexPtr addVertex(const std::shared_ptr& thePart, + const std::list& theBaseObjects, + const bool theDoIntersect); + #endif // BuildAPI_Vertex_H_ diff --git a/src/BuildPlugin/BuildPlugin_Plugin.cpp b/src/BuildPlugin/BuildPlugin_Plugin.cpp index 5d37e3299..4c20e54dd 100644 --- a/src/BuildPlugin/BuildPlugin_Plugin.cpp +++ b/src/BuildPlugin/BuildPlugin_Plugin.cpp @@ -57,6 +57,8 @@ BuildPlugin_Plugin::BuildPlugin_Plugin() new BuildPlugin_ValidatorSubShapesSelection()); aFactory->registerValidator("BuildPlugin_ValidatorFillingSelection", new BuildPlugin_ValidatorFillingSelection()); + aFactory->registerValidator("BuildPlugin_ValidatorBaseForVertex", + new BuildPlugin_ValidatorBaseForVertex()); // Register this plugin. ModelAPI_Session::get()->registerPlugin(this); diff --git a/src/BuildPlugin/BuildPlugin_Validators.cpp b/src/BuildPlugin/BuildPlugin_Validators.cpp index 65be34119..6b44423f8 100644 --- a/src/BuildPlugin/BuildPlugin_Validators.cpp +++ b/src/BuildPlugin/BuildPlugin_Validators.cpp @@ -464,7 +464,7 @@ bool BuildPlugin_ValidatorFillingSelection::isValid(const AttributePtr& theAttri return false; } - FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner()); + //FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner()); // Check selected shapes. for (int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) { @@ -491,3 +491,61 @@ bool BuildPlugin_ValidatorFillingSelection::isValid(const AttributePtr& theAttri return true; } + + +//================================================================================================= +bool BuildPlugin_ValidatorBaseForVertex::isValid(const AttributePtr& theAttribute, + const std::list& /*theArguments*/, + Events_InfoMessage& theError) const +{ + if (!theAttribute.get()) { + theError = "Error: empty selection."; + return false; + } + + AttributeSelectionListPtr aSelectionList = + std::dynamic_pointer_cast(theAttribute); + if (!aSelectionList.get()) { + theError = "Could not get selection list."; + return false; + } + + for (int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) { + AttributeSelectionPtr aSelectionAttr = aSelectionList->value(anIndex); + if (!aSelectionAttr.get()) { + theError = "Empty attribute in list."; + return false; + } + + // Vertex? + bool isVertex = false; + GeomShapePtr aShapeInList = aSelectionAttr->value(); + if (aShapeInList.get()) { + isVertex = (aShapeInList->shapeType() == GeomAPI_Shape::VERTEX); + } + + if (!isVertex) { + // Sketch? + FeaturePtr aFeature = aSelectionAttr->contextFeature(); + if (!aFeature.get()) { + ResultPtr aContext = aSelectionAttr->context(); + if (aContext.get()) { + aFeature = ModelAPI_Feature::feature(aContext); + } + } + + if (aFeature.get()) { + std::string aFeatureKind = aFeature->getKind(); + if (aFeatureKind != "Sketch" && + aFeatureKind != "Point" && + aFeatureKind != "Vertex") { + theError = "Error: %1 shape is not allowed for selection."; + theError.arg(aFeatureKind); + return false; + } + } + } + } + + return true; +} diff --git a/src/BuildPlugin/BuildPlugin_Validators.h b/src/BuildPlugin/BuildPlugin_Validators.h index 4c54b6b7b..116d44afc 100644 --- a/src/BuildPlugin/BuildPlugin_Validators.h +++ b/src/BuildPlugin/BuildPlugin_Validators.h @@ -118,4 +118,19 @@ public: Events_InfoMessage& theError) const; }; +/// \class BuildPlugin_ValidatorBaseForVertex +/// \ingroup Validators +/// \brief A validator for selection of Vertex feature. +class BuildPlugin_ValidatorBaseForVertex: public ModelAPI_AttributeValidator +{ +public: + //! Returns true if attribute is ok. + //! \param[in] theAttribute the checked attribute. + //! \param[in] theArguments arguments of the attribute. + //! \param[out] theError error message. + virtual bool isValid(const AttributePtr& theAttribute, + const std::list& theArguments, + Events_InfoMessage& theError) const; +}; + #endif diff --git a/src/BuildPlugin/BuildPlugin_Vertex.cpp b/src/BuildPlugin/BuildPlugin_Vertex.cpp index 82f3521ed..cd14766ed 100644 --- a/src/BuildPlugin/BuildPlugin_Vertex.cpp +++ b/src/BuildPlugin/BuildPlugin_Vertex.cpp @@ -20,10 +20,18 @@ #include "BuildPlugin_Vertex.h" #include +#include +#include #include +#include +#include #include #include +#include +#include + +#include //================================================================================================= BuildPlugin_Vertex::BuildPlugin_Vertex() @@ -34,62 +42,242 @@ BuildPlugin_Vertex::BuildPlugin_Vertex() void BuildPlugin_Vertex::initAttributes() { data()->addAttribute(BASE_OBJECTS_ID(), ModelAPI_AttributeSelectionList::typeId()); + + data()->addAttribute(INTERSECT_ID(), ModelAPI_AttributeBoolean::typeId()); + ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), INTERSECT_ID()); +} + +//================================================================================================= +bool BuildPlugin_Vertex::buildVertices(GeomShapePtr theShape, + bool isIntersect, + int& theResultIndex) +{ + if (!theShape.get()) { + setError("Error: Empty shape selected."); + return false; + } + + if (theShape->shapeType() == GeomAPI_Shape::VERTEX) { + // Copy shape. + std::shared_ptr aCopyAlgo(new GeomAlgoAPI_Copy(theShape)); + + std::string anError; + if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aCopyAlgo, getKind(), anError)) { + setError(anError); + return false; + } + + // Store result. + ResultBodyPtr aResultBody = document()->createBody(data(), theResultIndex); + aResultBody->storeModified(theShape, aCopyAlgo->shape()); + setResult(aResultBody, theResultIndex); + ++theResultIndex; + } else { + // Sketch + GeomAPI_DataMapOfShapeShape alreadyProcessed; + + // 1. Explode on Vertices + for (GeomAPI_ShapeExplorer anExp (theShape, GeomAPI_Shape::VERTEX); anExp.more(); anExp.next()) { + GeomShapePtr aSubShape = anExp.current(); + + if (alreadyProcessed.bind(aSubShape, aSubShape)) { + // Store result. + ResultBodyPtr aResultBody = document()->createBody(data(), theResultIndex); + aResultBody->storeModified(theShape, aSubShape); + setResult(aResultBody, theResultIndex); + ++theResultIndex; + } + } + + // 2. If need intersection points, perform Partition + if (isIntersect) { + // Partition + ListOfShape anObjList, aTools; + anObjList.push_back(theShape); + std::shared_ptr aPartitionAlgo (new GeomAlgoAPI_Partition(anObjList, aTools)); + + std::string anError; + if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aPartitionAlgo, getKind(), anError)) { + setError(anError); + return false; + } + GeomShapePtr aSplittedSketch = aPartitionAlgo->shape(); + + // Explode on Vertices, skip vertices of initial sketch + for (GeomAPI_ShapeExplorer anExp (aSplittedSketch, GeomAPI_Shape::VERTEX); anExp.more(); anExp.next()) { + GeomShapePtr aSubShape = anExp.current(); + + //if (!theShape->isSubShape(aSubShape)) { // skip vertices of initial sketch + if (alreadyProcessed.bind(aSubShape, aSubShape)) { + // Store result. + ResultBodyPtr aResultBody = document()->createBody(data(), theResultIndex); + aResultBody->storeGenerated(anObjList, aSubShape, aPartitionAlgo); + setResult(aResultBody, theResultIndex); + ++theResultIndex; + } + } + } + } + + return true; } //================================================================================================= +bool BuildPlugin_Vertex::buildVertices(FeaturePtr theFeature, + bool isIntersect, + int& theResultIndex) +{ + if (theFeature->getKind() != "Sketch") return false; + + // Sub-features + CompositeFeaturePtr aComposite = + std::dynamic_pointer_cast(theFeature); + if (!aComposite) return false; + int nbSubs = aComposite->numberOfSubs(); + if (nbSubs < 1) return false; + + // The whole sketch shape + ResultPtr aContext = theFeature->firstResult(); + GeomShapePtr theShape = aContext->shape(); + + GeomAPI_DataMapOfShapeShape alreadyProcessed; + + // 1. Explode on Vertices + for (GeomAPI_ShapeExplorer anExp (theShape, GeomAPI_Shape::VERTEX); anExp.more(); anExp.next()) { + GeomShapePtr aSubShape = anExp.current(); + + if (alreadyProcessed.bind(aSubShape, aSubShape)) { + // Store result. + ResultBodyPtr aResultBody = document()->createBody(data(), theResultIndex); + aResultBody->storeModified(theShape, aSubShape); + setResult(aResultBody, theResultIndex); + ++theResultIndex; + } + } + + // 2. If need intersection points, perform Partition + if (isIntersect) { + // Partition + ListOfShape anObjList, aTools; + anObjList.push_back(theShape); + std::shared_ptr aPartitionAlgo (new GeomAlgoAPI_Partition(anObjList, aTools)); + + std::string anError; + if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aPartitionAlgo, getKind(), anError)) { + setError(anError); + return false; + } + GeomShapePtr aSplittedSketch = aPartitionAlgo->shape(); + + // Explode on Vertices, skip vertices of initial sketch + for (GeomAPI_ShapeExplorer anExp (aSplittedSketch, GeomAPI_Shape::VERTEX); anExp.more(); anExp.next()) { + GeomShapePtr aSubShape = anExp.current(); + + //if (!theShape->isSubShape(aSubShape)) { // skip vertices of initial sketch + if (alreadyProcessed.bind(aSubShape, aSubShape)) { + // Store result. + ResultBodyPtr aResultBody = document()->createBody(data(), theResultIndex); + aResultBody->storeGenerated(anObjList, aSubShape, aPartitionAlgo); + setResult(aResultBody, theResultIndex); + ++theResultIndex; + } + } + } + + // 3. Add construction points (centers of circles, etc.) + for (int i = 0; i < nbSubs; i++) { + FeaturePtr aSubFeature = aComposite->subFeature(i); + const std::list& aSubResults = aSubFeature->results(); + std::list::const_iterator anItRes = aSubResults.cbegin(); + // Iterate on all sub-results + for (; anItRes != aSubResults.cend(); anItRes++) { + ResultPtr aRes = *anItRes; + if (aRes.get()) { + // Sub-result i + GeomShapePtr aSubResShape = aRes->shape(); + + for (GeomAPI_ShapeExplorer anExp (aSubResShape, GeomAPI_Shape::VERTEX); anExp.more(); anExp.next()) { + GeomShapePtr aSubShape = anExp.current(); + + if (alreadyProcessed.bind(aSubShape, aSubShape)) { + // Store result. + ResultBodyPtr aResultBody = document()->createBody(data(), theResultIndex); + aResultBody->storeModified(theShape, aSubShape); + setResult(aResultBody, theResultIndex); + ++theResultIndex; + } + } + } + } + } + + return true; +} + void BuildPlugin_Vertex::execute() { // Get base objects list. AttributeSelectionListPtr aSelectionList = selectionList(BASE_OBJECTS_ID()); - if(!aSelectionList.get()) { + if (!aSelectionList.get()) { setError("Error: Could not get selection list."); return; } - if(aSelectionList->size() == 0) { + if (aSelectionList->size() == 0) { setError("Error: Empty selection list."); return; } - // Collect base shapes. - ListOfShape aListOfShapes; + // Get "Compute intersections" flag value + bool isIntersect = false; + if (boolean(INTERSECT_ID()).get() && boolean(INTERSECT_ID())->isInitialized()) { + isIntersect = boolean(INTERSECT_ID())->value(); + } + + // Iterate arguments and build results int aResultIndex = 0; - for(int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) { + for (int anIndex = 0; anIndex < aSelectionList->size(); ++anIndex) { AttributeSelectionPtr aSelection = aSelectionList->value(anIndex); GeomShapePtr aShape = aSelection->value(); - if(!aShape.get()) { + if (aShape.get()) { + // A shape selected + if (!buildVertices(aShape, isIntersect, aResultIndex)) return; + } else { ResultPtr aContext = aSelection->context(); - if(!aContext.get()) { - setError("Error: Attribute has empty context."); - return; + if (aContext.get()) { // Result selected + FeaturePtr aFeature = ModelAPI_Feature::feature(aContext); + if (aFeature.get()) { + if (aFeature->getKind() == "Sketch") { + // Special processing for sketch to build center vertices etc. + if (!buildVertices(aFeature, isIntersect, aResultIndex)) return; + } else { + aShape = aContext->shape(); + if (!buildVertices(aShape, isIntersect, aResultIndex)) return; + } + } + } else { + FeaturePtr aFeature = aSelection->contextFeature(); + if (aFeature.get()) { // Feature selected + if (aFeature->getKind() == "Sketch") { + // Special processing for sketch to build center vertices etc. + if (!buildVertices(aFeature, isIntersect, aResultIndex)) return; + } else { + const std::list& anArgResults = aFeature->results(); + std::list::const_iterator anItRes = anArgResults.cbegin(); + // Iterate on all its results + for (; anItRes != anArgResults.cend(); anItRes++) { + ResultPtr aRes = *anItRes; + if (aRes.get()) { + // Result i + aShape = aRes->shape(); + if (!buildVertices(aShape, isIntersect, aResultIndex)) return; + } + } + } + } } - - aShape = aContext->shape(); } - if(!aShape.get()) { - setError("Error: Empty shape selected."); - return; - } - - if(aShape->shapeType() != GeomAPI_Shape::VERTEX) { - setError("Error: Selected shape has wrong type. Only vertices acceptable."); - return; - } - - // Copy shape. - std::shared_ptr aCopyAlgo(new GeomAlgoAPI_Copy(aShape)); - - std::string anError; - if (GeomAlgoAPI_Tools::AlgoError::isAlgorithmFailed(aCopyAlgo, getKind(), anError)) { - setError(anError); - return; - } - - // Store result. - ResultBodyPtr aResultBody = document()->createBody(data(), aResultIndex); - aResultBody->storeModified(aShape, aCopyAlgo->shape()); - setResult(aResultBody, aResultIndex); - ++aResultIndex; } + // Remove extra results from previous execution removeResults(aResultIndex); } diff --git a/src/BuildPlugin/BuildPlugin_Vertex.h b/src/BuildPlugin/BuildPlugin_Vertex.h index 62852d5e3..d6dfa9c78 100644 --- a/src/BuildPlugin/BuildPlugin_Vertex.h +++ b/src/BuildPlugin/BuildPlugin_Vertex.h @@ -23,6 +23,7 @@ #include "BuildPlugin.h" #include +#include /// \class BuildPlugin_Vertex /// \ingroup Plugins @@ -47,6 +48,13 @@ public: return MY_BASE_OBJECTS_ID; } + /// Attribute name of "Compute intersections" checkbox. + inline static const std::string& INTERSECT_ID() + { + static const std::string MY_INTERSECT_ID("intersect"); + return MY_INTERSECT_ID; + } + /// \return the kind of a feature. BUILDPLUGIN_EXPORT virtual const std::string& getKind() { @@ -59,6 +67,15 @@ public: /// Creates a new part document if needed. BUILDPLUGIN_EXPORT virtual void execute(); + + protected: + bool buildVertices(GeomShapePtr theShape, + bool isIntersect, + int& theResultIndex); + + bool buildVertices(FeaturePtr theFeature, + bool isIntersect, + int& theResultIndex); }; #endif diff --git a/src/BuildPlugin/Test/TestVertex.py b/src/BuildPlugin/Test/TestVertex.py index c9fcd9544..e2b936990 100644 --- a/src/BuildPlugin/Test/TestVertex.py +++ b/src/BuildPlugin/Test/TestVertex.py @@ -81,7 +81,7 @@ aVertexFeature2 = aPart.addFeature("Vertex") aBaseObjectsList = aVertexFeature2.selectionList("base_objects") aBaseObjectsList.append(aSketchResult, None) aSession.finishOperation() -assert (len(aVertexFeature2.results()) == 0) +assert (len(aVertexFeature2.results()) == 10) aSession.startOperation() aLine = aSketchFeature.addFeature("SketchLine") @@ -94,11 +94,14 @@ aBaseObjectsList.append(aSketchResult, aLine.lastResult().shape()) aSession.finishOperation() assert (len(aVertexFeature2.results()) == 0) +# Check Vertex feature failed on incorrect input +# TODO + # remove failed feature -aSession.startOperation() -aPart.removeFeature(aVertexFeature2) -aPart.setCurrentFeature(aVertexFeature, True) -aSession.finishOperation() +#aSession.startOperation() +#aPart.removeFeature(aVertexFeature2) +#aPart.setCurrentFeature(aVertexFeature, True) +#aSession.finishOperation() from salome.shaper import model assert(model.checkPythonDump()) diff --git a/src/BuildPlugin/vertex_widget.xml b/src/BuildPlugin/vertex_widget.xml index 77af0a18f..14ef22749 100644 --- a/src/BuildPlugin/vertex_widget.xml +++ b/src/BuildPlugin/vertex_widget.xml @@ -1,8 +1,10 @@ + + -- 2.39.2