return aStr.str();
}
-/// Returns true if something in selection is presented in the results list
-static bool isInResults(AttributeSelectionListPtr theSelection,
- const std::list<ResultPtr>& theResults,
- std::set<ResultPtr>& theCashedResults)
-{
- // collect all results into a cashed set
- if (theCashedResults.empty()) {
- std::list<ResultPtr>::const_iterator aRes = theResults.cbegin();
- for(; aRes != theResults.cend(); aRes++) {
- if (theCashedResults.count(*aRes))
- continue;
- else
- theCashedResults.insert(*aRes);
- if ((*aRes)->groupName() == ModelAPI_ResultBody::group()) {
- ResultBodyPtr aResBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aRes);
- std::list<ResultPtr> aResults;
- ModelAPI_Tools::allSubs(aResBody, aResults, false);
- for(std::list<ResultPtr>::iterator aR = aResults.begin(); aR != aResults.end(); aR++) {
- theCashedResults.insert(std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aR));
- }
- } else if ((*aRes)->groupName() == ModelAPI_ResultPart::group()) { // all results of the part
- ResultPartPtr aResPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(*aRes);
- DocumentPtr aPartDoc = aResPart->partDoc();
- if (!aPartDoc.get() || !aPartDoc->isOpened()) { // document is not accessible
- return false;
- }
- int aBodyCount = aPartDoc->size(ModelAPI_ResultBody::group());
- for (int aBodyIndex = 0; aBodyIndex < aBodyCount; ++aBodyIndex) {
- ResultBodyPtr aResBody =
- std::dynamic_pointer_cast<ModelAPI_ResultBody>(
- aPartDoc->object(ModelAPI_ResultBody::group(), aBodyIndex));
- if (aResBody.get()) {
- theCashedResults.insert(aResBody);
- std::list<ResultPtr> aResults;
- ModelAPI_Tools::allSubs(aResBody, aResults, false);
- for(std::list<ResultPtr>::iterator aR = aResults.begin(); aR != aResults.end(); aR++) {
- theCashedResults.insert(std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aR));
- }
- }
- }
- }
- }
- }
- // if context is in results, return true
- for(int a = 0; a < theSelection->size(); a++) {
- AttributeSelectionPtr anAttr = theSelection->value(a);
- ResultPtr aContext = anAttr->context();
- // check is it group selected for groups BOP
- if (aContext.get() && aContext->groupName() == ModelAPI_ResultGroup::group()) {
- // it is impossible by used results check which result is used in this group result,
- // so check the results shapes is it in results of this document or not
- FeaturePtr aSelFeature =
- std::dynamic_pointer_cast<ModelAPI_Feature>(theSelection->owner());
- if (!aSelFeature.get() || aSelFeature->results().empty())
- continue;
- GeomShapePtr aGroupResShape = aSelFeature->firstResult()->shape();
-
- std::set<ResultPtr>::iterator allResultsIter = theCashedResults.begin();
- for(; allResultsIter != theCashedResults.end(); allResultsIter++) {
- GeomShapePtr aResultShape = (*allResultsIter)->shape();
-
- GeomAPI_Shape::ShapeType aType =
- GeomAPI_Shape::shapeTypeByStr(theSelection->selectionType());
- GeomAPI_ShapeExplorer aGroupResExp(aGroupResShape, aType);
- for(; aGroupResExp.more(); aGroupResExp.next()) {
- if (aResultShape->isSubShape(aGroupResExp.current(), false))
- return true; // at least one shape of the group is in the used results
- }
- }
- }
- ResultBodyPtr aSelected = std::dynamic_pointer_cast<ModelAPI_ResultBody>(anAttr->context());
- if (!aSelected.get()) { // try to get selected feature and all its results
- FeaturePtr aContextFeature = anAttr->contextFeature();
- if (aContextFeature.get() && !aContextFeature->results().empty()) {
- const std::list<ResultPtr>& allResluts = aContextFeature->results();
- std::list<ResultPtr>::const_iterator aResIter = allResluts.cbegin();
- for(; aResIter != allResluts.cend(); aResIter++) {
- if (aResIter->get() && theCashedResults.count(*aResIter))
- return true;
- }
- }
- } else if (aSelected.get() && theCashedResults.count(aSelected))
- return true;
- }
- return false;
-}
-
void ExchangePlugin_ExportFeature::exportSTL(const std::string& theFileName)
{
// Get shape.
AttributeSelectionListPtr aSelectionList =
aGroupFeature->selectionList("group_list");
- if (!isInResults(aSelectionList, aResults, allResultsCashed))// skip group not used in result
+ if (!ModelAPI_Tools::isInResults(aSelectionList,
+ aResults,
+ allResultsCashed))// skip group not used in result
continue;
// conversion of dimension
std::string aSelectionType = aSelectionList->selectionType();
bool isWholePart = aSelectionType == "part";
// skip field not used in results
- if (!isWholePart && !isInResults(aSelectionList, aResults, allResultsCashed))
+ if (!isWholePart &&
+ !ModelAPI_Tools::isInResults(aSelectionList, aResults, allResultsCashed))
continue;
// conversion of dimension
AttributeSelectionListPtr anObjects =
aBase->selectionList(FeaturesPlugin_ImportResult::OBJECTS());
+ CompositeFeaturePtr aCompositeFeature =
+ std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aBase);
+ int aNbOfSubs = aCompositeFeature->numberOfSubs();
+ for (int anIndex = 0; anIndex < aNbOfSubs; anIndex++) {
+ FeaturePtr aSubFeature = aCompositeFeature->subFeature(anIndex);
+ theDumper.name(aSubFeature, false, false, true); //mark as not to dump
+ }
+
theDumper << aBase << " = model.addImportResult("
<< aDocName << ", " << anObjects << ")" << std::endl;
}
#include "FeaturesPlugin_ImportResult.h"
#include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_AttributeRefList.h>
#include <ModelAPI_ResultBody.h>
+#include <ModelAPI_ResultGroup.h>
#include <ModelAPI_Session.h>
#include <ModelAPI_ResultPart.h>
+#include <ModelAPI_Tools.h>
#include <Events_InfoMessage.h>
+#include <GeomAPI_ShapeExplorer.h>
void FeaturesPlugin_ImportResult::initAttributes()
{
data()->addAttribute(OBJECTS(), ModelAPI_AttributeSelectionList::typeId());
+
+ AttributePtr aFeaturesAttribute =
+ data()->addAttribute(FEATURES_ID(),
+ ModelAPI_AttributeRefList::typeId());
+ aFeaturesAttribute->setIsArgument(false);
+
+ ModelAPI_Session::get()->validators()->registerNotObligatory(
+ getKind(), FEATURES_ID());
}
void FeaturesPlugin_ImportResult::execute()
{
+ // Process groups/fields
+ std::shared_ptr<ModelAPI_AttributeRefList> aRefListOfGroups =
+ std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(data()->attribute(FEATURES_ID()));
+
+ // Remove previous groups/fields stored in RefList
+ //std::list<ObjectPtr> anGroupList = aRefListOfGroups->list();
+ //std::list<ObjectPtr>::iterator anGroupIt = anGroupList.begin();
+ const std::list<ObjectPtr>& anGroupList = aRefListOfGroups->list();
+ std::list<ObjectPtr>::const_iterator anGroupIt = anGroupList.begin();
+ for (; anGroupIt != anGroupList.end(); ++anGroupIt) {
+ std::shared_ptr<ModelAPI_Feature> aFeature = ModelAPI_Feature::feature(*anGroupIt);
+ if (aFeature)
+ document()->removeFeature(aFeature);
+ }
+
+ aRefListOfGroups->clear();
+
+ std::set<ResultPtr> aGlobalResultsCashed; // cash to speed up searching in all results selected
+ std::list<ResultGroupPtr> aGroups;
+
+ std::list<ResultPtr> aResults;
+
AttributeSelectionListPtr aList = selectionList(OBJECTS());
int aResultIndex = 0;
- for (int aSelIndex = 0; aSelIndex < aList->size(); aSelIndex++) {
+ for (int aSelIndex = 0; aSelIndex < aList->size(); aSelIndex++)
+ {
AttributeSelectionPtr aSel = aList->value(aSelIndex);
+
ResultPtr aContext = aSel->context();
- if (!aContext.get())
- continue;
- GeomShapePtr aShape = aContext->shape();
+ if (aContext.get())
+ aResults.push_back (aContext);
+ else
+ {
+ FeaturePtr aFeature = aSel->contextFeature();
+ if (aFeature.get())
+ {
+ const std::list<ResultPtr>& aResList = aFeature->results();
+ aResults.assign (aResList.begin(), aResList.end());
+ }
+ }
+ }
+
+ std::list<ResultPtr>::iterator aResIter = aResults.begin();
+ for(; aResIter != aResults.end(); aResIter++)
+ {
+ GeomShapePtr aShape = (*aResIter)->shape();
if (!aShape.get() || aShape->isNull())
continue;
+
std::shared_ptr<ModelAPI_ResultBody> aResultBody = document()->createBody(data(), aResultIndex);
aResultBody->store(aShape);
aResultBody->loadFirstLevel(aShape, "ImportResult");
setResult(aResultBody, aResultIndex++);
+
+ std::set<ResultPtr> allResultsCashed; // cash to speed up searching in all results selected
+ std::list<ResultPtr> aLocalResults;
+ aLocalResults.push_back (*aResIter);
+
+ std::list<DocumentPtr> aDocuments; /// documents of Parts
+ aDocuments.push_back ((*aResIter)->document());
+ std::list<DocumentPtr>::iterator aDoc = aDocuments.begin();
+ for(; aDoc != aDocuments.end(); aDoc++)
+ {
+ // groups
+ int aGroupCount = (*aDoc)->size(ModelAPI_ResultGroup::group());
+ for (int aGroupIndex = 0; aGroupIndex < aGroupCount; ++aGroupIndex)
+ {
+ ResultGroupPtr aResultGroup =
+ std::dynamic_pointer_cast<ModelAPI_ResultGroup>((*aDoc)->object(ModelAPI_ResultGroup::group(), aGroupIndex));
+
+ if (!aResultGroup.get() || !aResultGroup->shape().get())
+ continue;
+
+ FeaturePtr aGroupFeature = (*aDoc)->feature(aResultGroup);
+
+ AttributeSelectionListPtr aSelectionList =
+ aGroupFeature->selectionList("group_list");
+
+ if (!ModelAPI_Tools::isInResults(aSelectionList,
+ aLocalResults,
+ allResultsCashed))// skip group not used in result
+ continue;
+
+ aGlobalResultsCashed.insert (allResultsCashed.begin(), allResultsCashed.end());
+
+ //Check: may be this group already exists in the list
+ bool anIsFound = false;
+ std::list<ResultGroupPtr>::iterator anIter = aGroups.begin();
+ for (; anIter != aGroups.end(); anIter++)
+ {
+ if (*anIter == aResultGroup)
+ {
+ anIsFound = true;
+ break;
+ }
+ }
+ if (!anIsFound)
+ aGroups.push_back (aResultGroup);
+ }
+ }
+ }
+
+ std::list<ResultGroupPtr>::iterator anIter = aGroups.begin();
+ for (; anIter != aGroups.end(); anIter++)
+ {
+ DocumentPtr aDoc = (*anIter)->document();
+
+ FeaturePtr aGroupFeature = aDoc->feature(*anIter);
+
+ AttributeSelectionListPtr aSelectionList =
+ aGroupFeature->selectionList("group_list");
+
+ std::shared_ptr<ModelAPI_Feature> aNewGroupFeature = addFeature("Group");
+ aNewGroupFeature->data()->setName(aGroupFeature->name());
+
+ AttributeSelectionListPtr aNewSelectionList = aNewGroupFeature->selectionList("group_list");
+ aNewSelectionList->setSelectionType (aSelectionList->selectionType());
+ GeomAPI_Shape::ShapeType aTypeOfShape = GeomAPI_Shape::shapeTypeByStr (aSelectionList->selectionType());
+
+ for (int aLocalSelIndex = 0; aLocalSelIndex < aSelectionList->size(); aLocalSelIndex++) {
+
+ AttributeSelectionPtr aLocalSel = aSelectionList->value(aLocalSelIndex);
+ ResultPtr aLocalContext = aLocalSel->context();
+ ResultGroupPtr aLocalGroup = std::dynamic_pointer_cast<ModelAPI_ResultGroup> (aLocalContext);
+ if (aLocalGroup.get())
+ {
+ GeomShapePtr aLocalShape = aGroupFeature->firstResult()->shape();
+ GeomAPI_ShapeExplorer anExplo (aLocalShape, aTypeOfShape);
+ for (; anExplo.more(); anExplo.next())
+ {
+ GeomShapePtr anExploredShape = anExplo.current();
+ std::set<ResultPtr>::iterator aResultIter = aGlobalResultsCashed.begin();
+ for (; aResultIter != aGlobalResultsCashed.end(); aResultIter++)
+ {
+ GeomShapePtr aCashedShape = (*aResultIter)->shape();
+ if (aCashedShape->isSubShape(anExploredShape))
+ aNewSelectionList->append((*aResultIter), anExploredShape);
+ }
+ }
+ break;
+ }
+ else
+ {
+ GeomShapePtr aLocalShape = aLocalSel->value();
+
+ if (aLocalContext.get() && aGlobalResultsCashed.count(aLocalContext))
+ aNewSelectionList->append(aLocalContext, aLocalShape);
+ }
+ }
}
+
removeResults(aResultIndex);
}
}
return true;
}
+
+//============================================================================
+std::shared_ptr<ModelAPI_Feature> FeaturesPlugin_ImportResult::addFeature(
+ std::string theID)
+{
+ std::shared_ptr<ModelAPI_Feature> aNew = document()->addFeature(theID, false);
+ if (aNew)
+ data()->reflist(FEATURES_ID())->append(aNew);
+ // set as current also after it becomes sub to set correctly enabled for other subs
+ //document()->setCurrentFeature(aNew, false);
+ return aNew;
+}
+
+//=================================================================================================
+int FeaturesPlugin_ImportResult::numberOfSubs(bool /*forTree*/) const
+{
+ return data()->reflist(FEATURES_ID())->size(true);
+}
+
+//=================================================================================================
+std::shared_ptr<ModelAPI_Feature> FeaturesPlugin_ImportResult::subFeature(const int theIndex,
+ bool /*forTree*/)
+{
+ ObjectPtr anObj = data()->reflist(FEATURES_ID())->object(theIndex, false);
+ FeaturePtr aRes = std::dynamic_pointer_cast<ModelAPI_Feature>(anObj);
+ return aRes;
+}
+
+//=================================================================================================
+int FeaturesPlugin_ImportResult::subFeatureId(const int theIndex) const
+{
+ std::shared_ptr<ModelAPI_AttributeRefList> aRefList = std::dynamic_pointer_cast<
+ ModelAPI_AttributeRefList>(data()->attribute(FEATURES_ID()));
+ std::list<ObjectPtr> aFeatures = aRefList->list();
+ std::list<ObjectPtr>::const_iterator anIt = aFeatures.begin();
+ int aResultIndex = 1; // number of the counted (created) features, started from 1
+ int aFeatureIndex = -1; // number of the not-empty features in the list
+ for (; anIt != aFeatures.end(); anIt++) {
+ if (anIt->get())
+ aFeatureIndex++;
+ if (aFeatureIndex == theIndex)
+ break;
+ aResultIndex++;
+ }
+ return aResultIndex;
+}
+
+//=================================================================================================
+bool FeaturesPlugin_ImportResult::isSub(ObjectPtr theObject) const
+{
+ // check is this feature of result
+ FeaturePtr aFeature = ModelAPI_Feature::feature(theObject);
+ if (aFeature)
+ return data()->reflist(FEATURES_ID())->isInList(aFeature);
+ return false;
+}
+
+//=================================================================================================
+void FeaturesPlugin_ImportResult::removeFeature(
+ std::shared_ptr<ModelAPI_Feature> theFeature)
+{
+ if (!data()->isValid())
+ return;
+ AttributeRefListPtr aList = reflist(FEATURES_ID());
+ aList->remove(theFeature);
+}
#include "FeaturesPlugin.h"
-#include <ModelAPI_Feature.h>
+#include <ModelAPI_CompositeFeature.h>
#include <ModelAPI_AttributeValidator.h>
/// \class FeaturesPlugin_ImportResult
/// \brief The Import Result feature allows the user to import one or several results
/// from another Part.
-class FeaturesPlugin_ImportResult : public ModelAPI_Feature
+class FeaturesPlugin_ImportResult : public ModelAPI_CompositeFeature
{
public:
/// Feature kind.
static const std::string MY_ID("ImportResult");
return MY_ID;
}
+ /// All features (list of references)
+ inline static const std::string& FEATURES_ID()
+ {
+ static const std::string MY_FEATURES_ID("Features");
+ return MY_FEATURES_ID;
+ }
/// \return the kind of a feature.
FEATURESPLUGIN_EXPORT virtual const std::string& getKind()
/// Request for initialization of data model of the feature: adding all attributes.
FEATURESPLUGIN_EXPORT virtual void initAttributes();
+ /// Appends a feature
+ FEATURESPLUGIN_EXPORT virtual std::shared_ptr<ModelAPI_Feature> addFeature(std::string theID);
+
+ /// \return the number of sub-elements.
+ FEATURESPLUGIN_EXPORT virtual int numberOfSubs(bool forTree = false) const;
+
+ /// \return the sub-feature by zero-base index.
+ FEATURESPLUGIN_EXPORT virtual
+ std::shared_ptr<ModelAPI_Feature> subFeature(const int theIndex, bool forTree = false);
+
+ /// \return the sub-feature unique identifier in this composite feature by zero-base index.
+ FEATURESPLUGIN_EXPORT virtual int subFeatureId(const int theIndex) const;
+
+ /// \return true if feature or result belong to this composite feature as subs.
+ FEATURESPLUGIN_EXPORT virtual bool isSub(ObjectPtr theObject) const;
+
+ /// This method to inform that sub-feature is removed and must be removed from the internal data
+ /// structures of the owner (the remove from the document will be done outside just after).
+ FEATURESPLUGIN_EXPORT virtual void removeFeature(std::shared_ptr<ModelAPI_Feature> theFeature);
+
/// Use plugin manager for features creation.
FeaturesPlugin_ImportResult() {}
};
--- /dev/null
+# Copyright (C) 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
+
+model.begin()
+partSet = model.moduleDocument()
+
+### Create Part 1
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+### Create Groups
+Group_1 = model.addGroup(Part_1_doc, "Faces", [model.selection("FACE", "Box_1_1/Left"), model.selection("FACE", "Box_1_1/Top")])
+Group_2 = model.addGroup(Part_1_doc, "Faces", [model.selection("FACE", "Box_1_1/Front"), model.selection("FACE", "Box_1_1/Top")])
+GroupAddition_1 = model.addGroupAddition(Part_1_doc, [model.selection("COMPOUND", "Group_1"), model.selection("COMPOUND", "Group_2")])
+
+model.do()
+
+### Create Part 2
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+ImportResult_1 = model.addImportResult(Part_2_doc, [model.selection("SOLID", "Part_1/Box_1_1")])
+
+model.end()
+
+from GeomAPI import *
+from ModelAPI import *
+import math
+
+TOLERANCE = 1.e-7
+
+assert(ImportResult_1.feature().error() == "")
+model.testNbResults(ImportResult_1, 1)
+model.testNbSubResults(ImportResult_1, [0])
+model.testNbSubShapes(ImportResult_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(ImportResult_1, GeomAPI_Shape.FACE, [6])
+model.testNbSubShapes(ImportResult_1, GeomAPI_Shape.EDGE, [24])
+model.testNbSubShapes(ImportResult_1, GeomAPI_Shape.VERTEX, [48])
+model.testResultsVolumes(ImportResult_1, [1000])
+model.testResultsAreas(ImportResult_1, [600])
+
+# check groups are the same in both parts
+assert(Part_1_doc.size("Groups") == Part_2_doc.size("Groups"))
+for ind in range(0, Part_1_doc.size("Groups")):
+ res1 = objectToResult(Part_1_doc.object("Groups", ind))
+ res2 = objectToResult(Part_2_doc.object("Groups", ind))
+ assert(res1 is not None)
+ assert(res2 is not None)
+ res1It = GeomAPI_ShapeExplorer(res1.shape(), GeomAPI_Shape.FACE)
+ res2It = GeomAPI_ShapeExplorer(res2.shape(), GeomAPI_Shape.FACE)
+ while res1It.more() and res2It.more():
+ shape1 = res1It.current()
+ shape2 = res2It.current()
+ assert(shape1.shapeType() == shape2.shapeType())
+ res1It.next()
+ res2It.next()
+ p1 = res1.shape().middlePoint()
+ p2 = res2.shape().middlePoint()
+ assert(math.fabs(p1.x() - p2.x()) <= TOLERANCE and math.fabs(p1.y() - p2.y()) <= TOLERANCE and math.fabs(p1.z() - p2.z()) <= TOLERANCE), "({}, {}, {}) != ({}, {}, {})".format(p1.x(), p1.y(), p1.z(), p2.x(), p2.y(), p2.z())
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 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
+
+model.begin()
+partSet = model.moduleDocument()
+
+### Create Part 1
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Group_1 = model.addGroup(Part_1_doc, "Faces", [model.selection("FACE", "Box_1_1/Left"), model.selection("FACE", "Box_1_1/Top")])
+
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+Group_2 = model.addGroup(Part_1_doc, "Faces", [model.selection("FACE", "Cylinder_1_1/Face_1"), model.selection("FACE", "Box_1_1/Front")])
+Group_3 = model.addGroup(Part_1_doc, "Faces", [model.selection("FACE", "Cylinder_1_1/Face_1")])
+GroupAddition_1 = model.addGroupAddition(Part_1_doc, [model.selection("COMPOUND", "Group_1"), model.selection("COMPOUND", "Group_2")])
+GroupSubstraction_1 = model.addGroupSubstraction(Part_1_doc, [model.selection("COMPOUND", "GroupAddition_1")], [model.selection("COMPOUND", "Group_3")])
+
+model.do()
+
+### Create Part 2
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+
+### Create ImportResult
+ImportResult_1 = model.addImportResult(Part_2_doc, [model.selection("SOLID", "Part_1/Box_1_1"), model.selection("SOLID", "Part_1/Cylinder_1_1")])
+
+model.end()
+
+from GeomAPI import *
+from ModelAPI import *
+import math
+
+TOLERANCE = 1.e-7
+
+assert(ImportResult_1.feature().error() == "")
+model.testNbResults(ImportResult_1, 2)
+model.testNbSubResults(ImportResult_1, [0, 0])
+model.testNbSubShapes(ImportResult_1, GeomAPI_Shape.SOLID, [1, 1])
+model.testNbSubShapes(ImportResult_1, GeomAPI_Shape.FACE, [6, 3])
+model.testNbSubShapes(ImportResult_1, GeomAPI_Shape.EDGE, [24, 6])
+model.testNbSubShapes(ImportResult_1, GeomAPI_Shape.VERTEX, [48, 12])
+model.testResultsVolumes(ImportResult_1, [1000, 785.3981634])
+model.testResultsAreas(ImportResult_1, [600, 471.238898])
+
+# check groups are the same in both parts
+assert(Part_1_doc.size("Groups") == Part_2_doc.size("Groups"))
+REFIND = [0, 1, 3, 4, 2]
+for ind in range(0, Part_1_doc.size("Groups")):
+ res1 = objectToResult(Part_1_doc.object("Groups", REFIND[ind]))
+ res2 = objectToResult(Part_2_doc.object("Groups", ind))
+ assert(res1 is not None)
+ assert(res2 is not None)
+ res1It = GeomAPI_ShapeExplorer(res1.shape(), GeomAPI_Shape.FACE)
+ res2It = GeomAPI_ShapeExplorer(res2.shape(), GeomAPI_Shape.FACE)
+ while res1It.more() and res2It.more():
+ shape1 = res1It.current()
+ shape2 = res2It.current()
+ assert(shape1.shapeType() == shape2.shapeType())
+ res1It.next()
+ res2It.next()
+ p1 = res1.shape().middlePoint()
+ p2 = res2.shape().middlePoint()
+ assert(math.fabs(p1.x() - p2.x()) <= TOLERANCE and math.fabs(p1.y() - p2.y()) <= TOLERANCE and math.fabs(p1.z() - p2.z()) <= TOLERANCE), "({}, {}, {}) != ({}, {}, {})".format(p1.x(), p1.y(), p1.z(), p2.x(), p2.y(), p2.z())
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 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
+
+model.begin()
+partSet = model.moduleDocument()
+
+### Create Part 1
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Group_1 = model.addGroup(Part_1_doc, "Faces", [model.selection("FACE", "Box_1_1/Left"), model.selection("FACE", "Box_1_1/Top")])
+
+Cylinder_1 = model.addCylinder(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("EDGE", "PartSet/OZ"), 5, 10)
+Group_2 = model.addGroup(Part_1_doc, "Faces", [model.selection("FACE", "Cylinder_1_1/Face_1"), model.selection("FACE", "Box_1_1/Front")])
+Group_3 = model.addGroup(Part_1_doc, "Faces", [model.selection("FACE", "Cylinder_1_1/Face_1")])
+GroupAddition_1 = model.addGroupAddition(Part_1_doc, [model.selection("COMPOUND", "Group_1"), model.selection("COMPOUND", "Group_2")])
+GroupSubstraction_1 = model.addGroupSubstraction(Part_1_doc, [model.selection("COMPOUND", "GroupAddition_1")], [model.selection("COMPOUND", "Group_3")])
+
+model.do()
+
+### Create Part 2
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+
+### Create ImportResult
+ImportResult_1 = model.addImportResult(Part_2_doc, [model.selection("SOLID", "Part_1/Box_1_1")])
+
+model.end()
+
+from GeomAPI import *
+from ModelAPI import *
+import math
+
+TOLERANCE = 1.e-7
+
+assert(ImportResult_1.feature().error() == "")
+model.testNbResults(ImportResult_1, 1)
+model.testNbSubResults(ImportResult_1, [0])
+model.testNbSubShapes(ImportResult_1, GeomAPI_Shape.SOLID, [1])
+model.testNbSubShapes(ImportResult_1, GeomAPI_Shape.FACE, [6])
+model.testNbSubShapes(ImportResult_1, GeomAPI_Shape.EDGE, [24])
+model.testNbSubShapes(ImportResult_1, GeomAPI_Shape.VERTEX, [48])
+model.testResultsVolumes(ImportResult_1, [1000])
+model.testResultsAreas(ImportResult_1, [600])
+
+# check imported groups are correct
+assert(Part_1_doc.size("Groups") == 5)
+assert(Part_2_doc.size("Groups") == 4)
+REFERENCE = [(2, 5.0, 5.0, 5.0),
+ (1, 10.0, 5.0, 5.0),
+ (3, 5.0, 5.0, 5.0),
+ (3, 5.0, 5.0, 5.0)]
+for ind in range(0, Part_2_doc.size("Groups")):
+ res = objectToResult(Part_2_doc.object("Groups", ind))
+ assert(res is not None)
+ nbShapes = 0
+ it = GeomAPI_ShapeExplorer(res.shape(), GeomAPI_Shape.FACE)
+ while it.more():
+ nbShapes += 1
+ it.next()
+ assert(nbShapes == REFERENCE[ind][0])
+ p = res.shape().middlePoint()
+ x = REFERENCE[ind][1]
+ y = REFERENCE[ind][2]
+ z = REFERENCE[ind][3]
+ assert(math.fabs(p.x() - x) <= TOLERANCE and math.fabs(p.y() - y) <= TOLERANCE and math.fabs(p.z() - z) <= TOLERANCE), "({}, {}, {}) != ({}, {}, {})".format(p.x(), p.y(), p.z(), x, y, z)
+
+assert(model.checkPythonDump())
copy-shape, so, even the document was opened and the source-part was not activated (loaded), the part with copy-feature works well
with this result-shape.
+If the source-part contains one or several groups, which refer to sub-shapes of source results, then these groups are mutually imported
+as a sub-features of the Import Result feature. The copied groups contain only the elements referring to the imported results.
+
It may be necessary for the user to load the other parts before using this feature otherwise the content of the **Results** folders will be empty.
To create a Copy in the active part:
Result
""""""
-The Result of the operation will be copy of one or several results selected in another part located in the same place:
+The Result of the operation will be copy of one or several results selected and groups referring to these results in another part located in the same place:
.. figure:: images/CreatedImportResult.png
:align: center
TestCopySubShapes.py
TestCopyWholeFeature.py
TestImportResult.py
+ TestImportResultWithGroups1.py
+ TestImportResultWithGroups2.py
+ TestImportResultWithGroups3.py
TestDefeaturing_ErrorMsg.py
TestDefeaturing_OnSolid1.py
TestDefeaturing_OnSolid2.py
#include <GeomAPI_ShapeHierarchy.h>
#include <GeomAPI_ShapeIterator.h>
+#include <GeomAPI_ShapeExplorer.h>
#include <algorithm>
#include <iostream>
return false;
}
+static void cacheSubresults(const ResultBodyPtr& theTopLevelResult,
+ std::set<ResultPtr>& theCashedResults)
+{
+ std::list<ResultPtr> aResults;
+ ModelAPI_Tools::allSubs(theTopLevelResult, aResults, false);
+ for (std::list<ResultPtr>::iterator aR = aResults.begin(); aR != aResults.end(); ++aR) {
+ theCashedResults.insert(*aR);
+ }
+}
+
+bool isInResults(AttributeSelectionListPtr theSelection,
+ const std::list<ResultPtr>& theResults,
+ std::set<ResultPtr>& theCashedResults)
+{
+ // collect all results into a cashed set
+ if (theCashedResults.empty()) {
+ std::list<ResultPtr>::const_iterator aRes = theResults.cbegin();
+ for(; aRes != theResults.cend(); aRes++) {
+ if (theCashedResults.count(*aRes))
+ continue;
+ else
+ theCashedResults.insert(*aRes);
+
+ if ((*aRes)->groupName() == ModelAPI_ResultBody::group()) {
+ ResultBodyPtr aResBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aRes);
+ cacheSubresults(aResBody, theCashedResults);
+ } else if ((*aRes)->groupName() == ModelAPI_ResultPart::group()) { // all results of the part
+ ResultPartPtr aResPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(*aRes);
+ DocumentPtr aPartDoc = aResPart->partDoc();
+ if (!aPartDoc.get() || !aPartDoc->isOpened()) { // document is not accessible
+ return false;
+ }
+ int aBodyCount = aPartDoc->size(ModelAPI_ResultBody::group());
+ for (int aBodyIndex = 0; aBodyIndex < aBodyCount; ++aBodyIndex) {
+ ResultBodyPtr aResBody =
+ std::dynamic_pointer_cast<ModelAPI_ResultBody>(
+ aPartDoc->object(ModelAPI_ResultBody::group(), aBodyIndex));
+ if (aResBody.get()) {
+ theCashedResults.insert(aResBody);
+ cacheSubresults(aResBody, theCashedResults);
+ }
+ }
+ }
+ }
+ }
+ // if context is in results, return true
+ for(int a = 0; a < theSelection->size(); a++) {
+ AttributeSelectionPtr anAttr = theSelection->value(a);
+ ResultPtr aContext = anAttr->context();
+ // check is it group selected for groups BOP
+ if (aContext.get() && aContext->groupName() == ModelAPI_ResultGroup::group()) {
+ // it is impossible by used results check which result is used in this group result,
+ // so check the results shapes is it in results of this document or not
+ FeaturePtr aSelFeature =
+ std::dynamic_pointer_cast<ModelAPI_Feature>(theSelection->owner());
+ if (!aSelFeature.get() || aSelFeature->results().empty())
+ continue;
+ GeomShapePtr aGroupResShape = aSelFeature->firstResult()->shape();
+
+ std::set<ResultPtr>::iterator allResultsIter = theCashedResults.begin();
+ for(; allResultsIter != theCashedResults.end(); allResultsIter++) {
+ GeomShapePtr aResultShape = (*allResultsIter)->shape();
+
+ GeomAPI_Shape::ShapeType aType =
+ GeomAPI_Shape::shapeTypeByStr(theSelection->selectionType());
+ GeomAPI_ShapeExplorer aGroupResExp(aGroupResShape, aType);
+ for(; aGroupResExp.more(); aGroupResExp.next()) {
+ if (aResultShape->isSubShape(aGroupResExp.current(), false))
+ return true; // at least one shape of the group is in the used results
+ }
+ }
+ }
+ ResultBodyPtr aSelected = std::dynamic_pointer_cast<ModelAPI_ResultBody>(anAttr->context());
+ if (!aSelected.get()) { // try to get selected feature and all its results
+ FeaturePtr aContextFeature = anAttr->contextFeature();
+ if (aContextFeature.get() && !aContextFeature->results().empty()) {
+ const std::list<ResultPtr>& allResluts = aContextFeature->results();
+ std::list<ResultPtr>::const_iterator aResIter = allResluts.cbegin();
+ for(; aResIter != allResluts.cend(); aResIter++) {
+ if (aResIter->get() && theCashedResults.count(*aResIter))
+ return true;
+ }
+ }
+ } else if (aSelected.get() && theCashedResults.count(aSelected))
+ return true;
+ }
+ return false;
+}
+
ResultPtr findPartResult(const DocumentPtr& theMain, const DocumentPtr& theSub)
{
// to optimize and avoid of crash on partset document close
#define ModelAPI_Tools_HeaderFile
#include "ModelAPI.h"
+#include <ModelAPI_AttributeSelectionList.h>
class ModelAPI_CompositeFeature;
class ModelAPI_Document;
std::shared_ptr<ModelAPI_Result> theTarget, const std::string& theFeatureKind,
const bool theSortResults);
+/*!
+ * Returns true if something in selection is presented in the results list
+ */
+MODELAPI_EXPORT bool isInResults(AttributeSelectionListPtr theSelection,
+ const std::list<ResultPtr>& theResults,
+ std::set<ResultPtr>& theCashedResults);
/*! Returns a container with the current color value.
* These are tree int values for RGB definition.
} else if (aObject->document() == aMgr->activeDocument()) {
if (hasParameter || hasFeature) {
- myMenuMgr->action("EDIT_CMD")->setEnabled(true);
- theMenu->addAction(myMenuMgr->action("EDIT_CMD"));
- if (aCurrentOp && aFeature.get()) {
- if (aCurrentOp->id().toStdString() == aFeature->getKind())
+
+ // disable Edit menu for groups under ImportResult feature
+ bool isEnabled = true;
+ if (aFeature.get() && aFeature->getKind() == "Group")
+ {
+ std::shared_ptr<ModelAPI_CompositeFeature> anOwner =
+ ModelAPI_Tools::compositeOwner (aFeature);
+
+ if (anOwner.get() && anOwner->getKind() == "ImportResult")
+ {
myMenuMgr->action("EDIT_CMD")->setEnabled(false);
+ isEnabled = false;
+ }
+ }
+
+ if (isEnabled)
+ {
+ myMenuMgr->action("EDIT_CMD")->setEnabled(true);
+ theMenu->addAction(myMenuMgr->action("EDIT_CMD"));
+ if (aCurrentOp && aFeature.get()) {
+ if (aCurrentOp->id().toStdString() == aFeature->getKind())
+ myMenuMgr->action("EDIT_CMD")->setEnabled(false);
+ }
}
}
}
} else {
DocumentPtr aDoc = myObject->document();
SessionPtr aSession = ModelAPI_Session::get();
+
+ FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(myObject);
+ if (aFeature.get() && aFeature->getKind() == "Group")
+ {
+ std::shared_ptr<ModelAPI_CompositeFeature> anOwner =
+ ModelAPI_Tools::compositeOwner (aFeature);
+
+ if (anOwner.get() && anOwner->getKind() == "ImportResult")
+ return aDefaultFlag;
+ }
+
if (aSession->activeDocument() == aDoc)
return aEditingFlag;
}