]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Merge branch 'cadbld'
authormpv <mpv@opencascade.com>
Wed, 29 Dec 2021 14:14:45 +0000 (17:14 +0300)
committermpv <mpv@opencascade.com>
Wed, 29 Dec 2021 14:14:45 +0000 (17:14 +0300)
# Conflicts:
# src/FeaturesPlugin/FeaturesPlugin_MultiRotation.cpp
# src/FeaturesPlugin/FeaturesPlugin_MultiTranslation.cpp
# src/FeaturesPlugin/FeaturesPlugin_Placement.cpp
# src/FeaturesPlugin/FeaturesPlugin_Rotation.cpp
# src/FeaturesPlugin/FeaturesPlugin_Scale.cpp
# src/FeaturesPlugin/FeaturesPlugin_Symmetry.cpp
# src/FeaturesPlugin/FeaturesPlugin_Translation.cpp

86 files changed:
CMakeLists.txt
doc/gui/General/Introduction.rst
doc/gui/images/general_preferences.png [new file with mode: 0644]
src/Config/Config_ModuleReader.cpp
src/ConnectorPlugin/ConnectorPlugin_ExportFeature.py
src/ConnectorPlugin/ConnectorPlugin_PublishToStudyFeature.py
src/ConstructionAPI/ConstructionAPI_Plane.cpp
src/ExchangeAPI/CMakeLists.txt
src/ExchangeAPI/ExchangeAPI_Import.cpp
src/ExchangePlugin/CMakeLists.txt
src/ExchangePlugin/ExchangePlugin_Dump.cpp
src/ExchangePlugin/ExchangePlugin_Dump.h
src/ExchangePlugin/ExchangePlugin_ExportFeature.cpp
src/ExchangePlugin/ExchangePlugin_Import.cpp
src/ExchangePlugin/ExchangePlugin_ImportFeature.cpp
src/ExchangePlugin/Test/TestImportImage_1.py
src/ExchangePlugin/Test/TestImportImage_2.py
src/ExchangePlugin/Test/TestImportImage_3.py [new file with mode: 0755]
src/ExchangePlugin/Test/tests_gui.set
src/FeaturesAPI/FeaturesAPI_ImportResult.cpp
src/FeaturesPlugin/FeaturesPlugin_ImportResult.cpp
src/FeaturesPlugin/FeaturesPlugin_ImportResult.h
src/FeaturesPlugin/FeaturesPlugin_MultiRotation.cpp
src/FeaturesPlugin/FeaturesPlugin_MultiTranslation.cpp
src/FeaturesPlugin/FeaturesPlugin_Placement.cpp
src/FeaturesPlugin/FeaturesPlugin_Rotation.cpp
src/FeaturesPlugin/FeaturesPlugin_Scale.cpp
src/FeaturesPlugin/FeaturesPlugin_Symmetry.cpp
src/FeaturesPlugin/FeaturesPlugin_Symmetry.h
src/FeaturesPlugin/FeaturesPlugin_Tools.cpp
src/FeaturesPlugin/FeaturesPlugin_Tools.h
src/FeaturesPlugin/FeaturesPlugin_Translation.cpp
src/FeaturesPlugin/FeaturesPlugin_Validators.cpp
src/FeaturesPlugin/Test/TestImportResultWithGroups1.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestImportResultWithGroups2.py [new file with mode: 0644]
src/FeaturesPlugin/Test/TestImportResultWithGroups3.py [new file with mode: 0644]
src/FeaturesPlugin/doc/importResultFeature.rst
src/FeaturesPlugin/tests.set
src/GeomAPI/GeomAPI_Shape.cpp
src/GeomAPI/GeomAPI_Shape.h
src/GeomAlgoAPI/CMakeLists.txt
src/GeomAlgoAPI/GeomAlgoAPI_ImageImport.cpp
src/GeomAlgoAPI/GeomAlgoAPI_ImageImport.h
src/GeomAlgoAPI/GeomAlgoAPI_Tools.cpp
src/GeomAlgoAPI/GeomAlgoAPI_Tools.h
src/Model/CMakeLists.txt
src/Model/Model_AttributeImage.cpp [new file with mode: 0644]
src/Model/Model_AttributeImage.h [new file with mode: 0644]
src/Model/Model_Data.cpp
src/Model/Model_Data.h
src/Model/Model_ResultBody.cpp
src/Model/Model_ResultBody.h
src/ModelAPI/CMakeLists.txt
src/ModelAPI/ModelAPI_AttributeImage.cpp [new file with mode: 0644]
src/ModelAPI/ModelAPI_AttributeImage.h [new file with mode: 0644]
src/ModelAPI/ModelAPI_Data.h
src/ModelAPI/ModelAPI_Events.cpp
src/ModelAPI/ModelAPI_Events.h
src/ModelAPI/ModelAPI_Object.h
src/ModelAPI/ModelAPI_Result.h
src/ModelAPI/ModelAPI_ResultBody.h
src/ModelAPI/ModelAPI_Tools.cpp
src/ModelAPI/ModelAPI_Tools.h
src/ModelHighAPI/CMakeLists.txt
src/ModelHighAPI/ModelHighAPI_Dumper.h
src/ModelHighAPI/ModelHighAPI_FeatureStore.cpp
src/ModelHighAPI/ModelHighAPI_Interface.cpp
src/ModelHighAPI/ModelHighAPI_Selection.cpp
src/ModelHighAPI/ModelHighAPI_Services.cpp
src/ModelHighAPI/ModelHighAPI_Tools.cpp
src/ModuleBase/ModuleBase_Preferences.cpp
src/ModuleBase/ModuleBase_Preferences.h
src/ModuleBase/ModuleBase_Tools.cpp
src/ModuleBase/ModuleBase_Tools.h
src/ModuleBase/ModuleBase_msg_fr.ts
src/PartSet/PartSet_CustomPrs.cpp
src/PartSet/PartSet_MenuMgr.cpp
src/PartSet/PartSet_Module.cpp
src/PartSet/PartSet_Module.h
src/PartSet/PartSet_TreeNodes.cpp
src/SHAPERGUI/SHAPERGUI_DataModel.cpp
src/SHAPERGUI/resources/LightApp.xml.in
src/XGUI/SHAPER.xml
src/XGUI/XGUI_Workshop.cpp
src/XGUI/XGUI_WorkshopListener.cpp
src/XGUI/XGUI_WorkshopListener.h

index c9579f425f8d7afd16cbd8e9d249e7a88d2cc9bf..f9f60ac1ecc76919d4b4ffbe7c60b48886c730ee 100644 (file)
@@ -50,7 +50,7 @@ ENDIF()
 
 # Versioning
 # ===========
-SALOME_SETUP_VERSION(9.8.0)
+SALOME_SETUP_VERSION(9.8.0 DEVELOPMENT)
 MESSAGE(STATUS "Building ${PROJECT_NAME} ${${PROJECT_NAME}_VERSION} from \"${${PROJECT_NAME}_GIT_SHA1}\"")
 SET(COMPONENT_NAME SHAPER)
 
index 35e17284c3f8df4180ac7fb4ebe704862081b62a..3cb1c45b2098d74de2805449301855a62836a0d1 100644 (file)
@@ -451,6 +451,7 @@ To call **Preferences** dialog box:
 
 SHAPER preferences contains the following tabs:
 
+- :ref:`general_preferences`;
 - :ref:`visualization_preferences`;
 - :ref:`plugins_preferences`;
 - :ref:`shortcuts_preferences`;
@@ -458,10 +459,43 @@ SHAPER preferences contains the following tabs:
 - :ref:`sketch_preferences`.
 - :ref:`viewer_preferences`.
 
-Visualization tab is activated by default when **Preferences** dialog box is opened in the active SHAPER module.
+General tab is activated by default when **Preferences** dialog box is opened in the active SHAPER module.
 
 Other tabs are activated by click on tab header.
 
+.. _general_preferences:
+
+General tab
+^^^^^^^^^^^
+
+This tab defines what parts to be activated and what elements to be visible after opening a study or a script.
+
+.. figure:: /images/general_preferences.png
+   :align: center
+
+   **Preferences**: General tab
+
+**Input fields**:
+
+- **Activate** relates to activation of part when opening a HDF document. Its could be one of the following:
+
+  - "Last part" - activate last part in the document (**default value**);
+  - "All parts" - activate all parts within the document;
+  - "No activation" - do not activate any part.
+
+- **Display** in "Opening a study". It specifies the shapes, which should be visualized when activating a part. It could be one of the following:
+
+  - "As stored in HDF" - display only the shapes visible before the document is saved (**default value**);
+  - "Last item in each folder" - show only the last result in each folder of the part: Constructions, Results, Groups, Fields;
+  - "All items" - show all shapes from each folder;
+  - "No visualization" - do not display any shape.
+
+- **Display** in "Launching a python script". It specifies the shapes, which should be visualized when loading a script using "File -> Load Script..." menu. It could be one of the following:
+
+  - "Last item in each folder" - show only the last result in each folder of the part: Constructions, Results, Groups, Fields;
+  - "All items" - show all shapes from each folder(**default value**);
+  - "No visualization" - do not display any shape.
+
 .. _visualization_preferences:
 
 Visualization tab
diff --git a/doc/gui/images/general_preferences.png b/doc/gui/images/general_preferences.png
new file mode 100644 (file)
index 0000000..e7eee17
Binary files /dev/null and b/doc/gui/images/general_preferences.png differ
index 83ea39d23d87815e6b72ede593cb36ee91feb438..de4db1a3b491ddb4db2d3be31a6ef4136ee4c3f9 100644 (file)
@@ -242,7 +242,6 @@ namespace
 {
   // Handle Python exception
   // Reuse code from KERNEL module
-  
   typedef struct
   {
     PyObject_HEAD
index 3a714b066d443d01ca33e216296a148929b35ca0..da88d6c2a8fd0998b37fac8a8b4f9063c0e68b04 100644 (file)
@@ -68,8 +68,8 @@ class ExportFeature(ModelAPI.ModelAPI_Feature):
           for aResIndex in range(self.Part.size(aResultType)):
             anObject = self.Part.object(aResultType, aResIndex)
             aResult = model.objectToResult(anObject)
-            # do nt export picture
-            if aResult.hasTextureFile() is True:
+            # do not export picture
+            if aResult.hasTexture() is True:
               continue
             if not aResult is None:
               if (not aResult.shape() or aResult.shape().isNull()) and isPart:
index 8da67a31e500acbca80415d537c4c02ffd7e82ec..a721ad73b2a039e88d4bc82a731d2136b262ebeb 100644 (file)
@@ -93,7 +93,7 @@ class PublishToStudyFeature(ModelAPI.ModelAPI_Feature):
             aResObject = aPartDoc.object(model.ModelAPI_ResultBody_group(), aResId)
             aRes = model.objectToResult(aResObject)
             #do not export images
-            if aRes.hasTextureFile() is True:
+            if aRes.hasTexture() is True:
               continue
             aResFeatureId = str(aPartDoc.feature(aRes).data().featureId())
             if aResFeatureId in aFeaturesIndices:
index 3933b16230288c625690c37df6dc91d67bf7aba2..5318cb90b53a27fde4fd5d69550b20f832b12338 100644 (file)
@@ -294,7 +294,8 @@ PlanePtr addPlane(const std::shared_ptr<ModelAPI_Document>& thePart,
 {
   // TODO(spo): check that thePart is not empty
   std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(ConstructionAPI_Plane::ID());
-  return PlanePtr(new ConstructionAPI_Plane(aFeature, theFace, theDistance, theIsReverse, theNbCopies));
+  return PlanePtr(new ConstructionAPI_Plane(aFeature, theFace, theDistance,
+                                            theIsReverse, theNbCopies));
 }
 
 //==================================================================================================
index d241e7fcb89b0ad3ab7668afadd0a304b62671a0..33ac73255bf55bb3ff8d82507af4d3eaa6abcb58 100644 (file)
@@ -18,6 +18,7 @@
 #
 
 INCLUDE(Common)
+INCLUDE(UseQtExt)
 
 SET(PROJECT_HEADERS
   ExchangeAPI.h
@@ -34,6 +35,7 @@ SET(PROJECT_LIBRARIES
   ModelAPI
   ModelHighAPI
   GeomAlgoAPI
+  ${QT_LIBRARIES}
 )
 
 INCLUDE_DIRECTORIES(
@@ -41,6 +43,7 @@ INCLUDE_DIRECTORIES(
   ${PROJECT_SOURCE_DIR}/src/ModelAPI
   ${PROJECT_SOURCE_DIR}/src/ModelHighAPI
   ${PROJECT_SOURCE_DIR}/src/GeomAlgoAPI
+  ${QT_INCLUDES}
 )
 
 # Plugin headers dependency
@@ -51,6 +54,9 @@ INCLUDE_DIRECTORIES(
   ${PROJECT_SOURCE_DIR}/src/ExchangePlugin
 )
 
+# additional preprocessor / compiler flags
+ADD_DEFINITIONS(${QT_DEFINITIONS})
+
 #TODO(spo): is ${OpenCASCADE_DEFINITIONS} necessary?
 ADD_DEFINITIONS(-DEXCHANGEAPI_EXPORTS ${OpenCASCADE_DEFINITIONS})
 ADD_LIBRARY(ExchangeAPI SHARED ${PROJECT_SOURCES} ${PROJECT_HEADERS})
index cee25a91a359be46e5c3cf43256676ac8ac71d40..eae6524341fdbecd5fc2c1f929cc17779222f1e7 100644 (file)
 #include <ModelHighAPI_Tools.h>
 //--------------------------------------------------------------------------------------
 #include <ModelAPI_AttributeStringArray.h>
+#include <ModelAPI_AttributeImage.h>
 #include <ModelAPI_Session.h>
 #include <ModelAPI_Tools.h>
 #include <GeomAlgoAPI_Tools.h>
 //--------------------------------------------------------------------------------------
 #include <algorithm>
+//--------------------------------------------------------------------------------------
+#include <QPixmap>
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
 
 ExchangeAPI_Import::ExchangeAPI_Import(
     const std::shared_ptr<ModelAPI_Feature> & theFeature)
@@ -245,7 +251,44 @@ void ExchangeAPI_Import_Image::dump(ModelHighAPI_Dumper& theDumper) const
   std::string aPartName = theDumper.name(aBase->document());
 
   std::string aFilePath =
-      aBase->string(ExchangePlugin_Import_ImageFeature::FILE_PATH_ID())->value();
+    aBase->string(ExchangePlugin_Import_ImageFeature::FILE_PATH_ID())->value();
+
+  // store image into a new file near the dumped python script
+  ResultPtr aResult = aBase->firstResult();
+  std::string aNewImageDir = theDumper.getDumpDir();
+  if (aResult.get() && aResult->hasTexture()) {
+    // get image data
+    int aWidth, aHeight;
+    std::string aFormat;
+    std::list<unsigned char> aByteList;
+    AttributeImagePtr anImageAttr =
+      aResult->data()->image(ModelAPI_ResultBody::IMAGE_ID());
+    anImageAttr->texture(aWidth, aHeight, aByteList, aFormat);
+
+    // convert image data to QPixmap
+    uchar* arr = new uchar[aByteList.size()];
+    std::copy(aByteList.begin(), aByteList.end(), arr);
+    QImage image (arr, aWidth, aHeight, QImage::Format_ARGB32);
+    QPixmap pixmap = QPixmap::fromImage( image );
+
+    // get new file name
+    std::wstring aName = aBase->name();
+    std::string anImageName (aName.begin(), aName.end());
+    std::string aNewImageFile = anImageName + "." + aFormat;
+    QFileInfo aNewFileInfo (QDir(aNewImageDir.c_str()), aNewImageFile.c_str());
+    for (int ii = 1; QFile::exists(aNewFileInfo.absoluteFilePath()); ii++) {
+      // construct the new file name by adding the unique number
+      aNewImageFile = anImageName + "_" + std::to_string(ii) + "." + aFormat;
+      aNewFileInfo.setFile(QDir(aNewImageDir.c_str()), aNewImageFile.c_str());
+    }
+
+    // write image to a new file
+    if (pixmap.save(aNewFileInfo.absoluteFilePath())) {
+      // to dump new file name
+      aFilePath = aNewFileInfo.absoluteFilePath().toStdString();
+    }
+    delete [] arr;
+  }
 
   theDumper << aBase << " = model.addImportImage(" << aPartName << ", \""
             << aFilePath << "\")" << std::endl;
index 7efb757ffd1e0f5f6febf13d7b71f72e68d83ce4..9ffa2d4089da5eb64a8a39ce41763efd266f5e34 100755 (executable)
@@ -19,6 +19,7 @@
 
 INCLUDE(Common)
 INCLUDE(UnitTest)
+INCLUDE(UseQtExt)
 
 INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/Events
                     ${PROJECT_SOURCE_DIR}/src/Config
@@ -32,8 +33,12 @@ INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/src/Events
                     ${PROJECT_SOURCE_DIR}/src/ConstructionPlugin
                     ${PROJECT_SOURCE_DIR}/src/PartSetPlugin
                     ${OpenCASCADE_INCLUDE_DIR}
+                    ${QT_INCLUDES}
 )
 
+# additional preprocessor / compiler flags
+ADD_DEFINITIONS(${QT_DEFINITIONS})
+
 SET(PROJECT_HEADERS
     ExchangePlugin.h
     ExchangePlugin_Plugin.h
@@ -82,6 +87,7 @@ SET(PROJECT_LIBRARIES
     GeomAlgoAPI
     GeomValidators
     XAOShaper
+    ${QT_LIBRARIES}
 )
 
 # default dump approaches (will be set if not initialized)
index 418ab137021da7e20a04b4559af537c1feb399db..43680ab74453040b1bae9737f42855fff5829209 100644 (file)
 #include <ModelAPI_Document.h>
 #include <ModelAPI_Session.h>
 #include <ModelAPI_ResultPart.h>
+#include <ModelAPI_Validator.h>
 
 #include <ModelHighAPI_Dumper.h>
 
 #include <Config_ModuleReader.h>
 
+#include <GeomAlgoAPI_Tools.h>
+
 #ifdef EXCHANGEPLUGIN_DUMP_NAMING
 static const bool THE_DUMP_NAMING = true;
 #else
@@ -67,11 +70,15 @@ void ExchangePlugin_Dump::initAttributes()
 
   data()->addAttribute(EXPORT_VARIABLES_ID(), ModelAPI_AttributeBoolean::typeId());
 
+  data()->addAttribute(DUMP_DIR_ID(), ModelAPI_AttributeString::typeId());
+
   // default values
   boolean(TOPOLOGICAL_NAMING_DUMP_ID())->setValue(THE_DUMP_NAMING);
   boolean(GEOMETRIC_DUMP_ID())->setValue(THE_DUMP_GEO);
   boolean(WEAK_NAMING_DUMP_ID())->setValue(THE_DUMP_WEAK);
   boolean(EXPORT_VARIABLES_ID())->setValue(false);
+
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), DUMP_DIR_ID());
 }
 
 void ExchangePlugin_Dump::execute()
@@ -162,6 +169,16 @@ void ExchangePlugin_Dump::dump(const std::string& theFileName)
     aDumper->addCustomStorage(aWeakNamingStorage);
   }
 
+  // pass dump directory to the dumper
+  AttributeStringPtr aDumpDirAttr =
+    this->string(ExchangePlugin_Dump::DUMP_DIR_ID());
+  std::string aDumpDir;
+  if (aDumpDirAttr.get() && aDumpDirAttr->isInitialized())
+    aDumpDir = aDumpDirAttr->value();
+  else
+    aDumpDir = GeomAlgoAPI_Tools::File_Tools::path(theFileName);
+  aDumper->setDumpDir(aDumpDir);
+
   if (!aDumper->process(aDoc, theFileName)) {
     setError("An error occurred while dumping to " + theFileName);
   } else {
index 1fa72d984f6d424617b7c59d817666aa334374a9..e9858a7f9de515034506578a77f6a82ffc4eedc9 100644 (file)
@@ -38,6 +38,12 @@ public:
     static const std::string MY_DUMP_ID("Dump");
     return MY_DUMP_ID;
   }
+  /// attribute name of true dumping directory
+  inline static const std::string& DUMP_DIR_ID()
+  {
+    static const std::string MY_DUMP_DIR_ID("dump_dir");
+    return MY_DUMP_DIR_ID;
+  }
   /// attribute name of file path
   inline static const std::string& FILE_PATH_ID()
   {
index 6ae4199ec4da72ef2a973b569165cd84c4181210..fcb3c56e126dbd2e95a5ec6970b289a1bc13b6d2 100644 (file)
@@ -211,7 +211,7 @@ void ExchangePlugin_ExportFeature::exportFile(const std::string& theFileName,
     /// do not export pictures
     ResultPtr aBodyContext =
       std::dynamic_pointer_cast<ModelAPI_Result>(anAttrSelection->context());
-    if(aBodyContext->hasTextureFile())
+    if (aBodyContext.get() && aBodyContext->hasTexture())
       continue;
 
     std::shared_ptr<GeomAPI_Shape> aCurShape = anAttrSelection->value();
@@ -265,93 +265,6 @@ static std::string valToString(const ModelAPI_AttributeTables::Value& theVal,
   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.
@@ -416,13 +329,13 @@ void ExchangePlugin_ExportFeature::exportXAO(const std::string& theFileName)
   AttributeSelectionListPtr aSelection = selectionList(XAO_SELECTION_LIST_ID());
   bool aIsSelection = aSelection->isInitialized() && aSelection->size() > 0;
   if (aIsSelection) { // a mode for export to geom result by result
-    for(int a = 0; a < aSelection->size(); a++) {
+    for (int a = 0; a < aSelection->size(); a++) {
       AttributeSelectionPtr anAttr = aSelection->value(a);
       ResultPtr aBodyContext =
         std::dynamic_pointer_cast<ModelAPI_Result>(anAttr->context());
       if (aBodyContext.get() && !aBodyContext->isDisabled() && aBodyContext->shape().get()) {
           /// do not export pictures
-          if(aBodyContext->hasTextureFile()){
+          if (aBodyContext->hasTexture()){
             anExCludedIsImage = true;
             continue;
           }
@@ -504,7 +417,9 @@ void ExchangePlugin_ExportFeature::exportXAO(const std::string& theFileName)
 
       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
@@ -558,7 +473,8 @@ void ExchangePlugin_ExportFeature::exportXAO(const std::string& theFileName)
       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
index 86114578992431b62c6d1eab10b3f823a64d238d..ef4b3b5605ee5fcef963a95f0cb4d2efeedd753c 100644 (file)
@@ -174,7 +174,7 @@ void ExchangePlugin_Import::execute()
 
 void ExchangePlugin_Import_Image::execute()
 {
- AttributeStringPtr aFilePathAttr = string(ExchangePlugin_ImportBase::FILE_PATH_ID());
 AttributeStringPtr aFilePathAttr = string(ExchangePlugin_ImportBase::FILE_PATH_ID());
   std::string aFilePath = aFilePathAttr->value();
   if (aFilePath.empty()) {
     setError("File path is empty.");
index 65045f2283880243a962b3b394532cf6ce527949..e077e4ca78a81465938ea4da770a33147170b212 100644 (file)
@@ -45,6 +45,7 @@
 #include <ModelAPI_AttributeString.h>
 #include <ModelAPI_AttributeStringArray.h>
 #include <ModelAPI_AttributeIntArray.h>
+#include <ModelAPI_AttributeImage.h>
 #include <ModelAPI_AttributeTables.h>
 #include <ModelAPI_AttributeBoolean.h>
 #include <ModelAPI_AttributeInteger.h>
@@ -66,6 +67,7 @@
 
 #include <ExchangePlugin_Tools.h>
 
+#include <QPixmap>
 
 /*
  * Request for initialization of data model of the feature: adding all attributes
@@ -635,35 +637,50 @@ void ExchangePlugin_ImportFeatureBase::loadNamingDS(
 
 void ExchangePlugin_Import_ImageFeature::importFile(const std::string& theFileName)
 {
-
   std::string anExtension = GeomAlgoAPI_Tools::File_Tools::extension(theFileName);
-  std::string theTextureFileName = "";
-  // Perform the import
   std::string anError;
-  std::shared_ptr<GeomAPI_Shape> aGeomShape;
-   if (anExtension == "PNG" || anExtension == "GIF" ||
-             anExtension == "TIFF" || anExtension == "JPE" ||
-             anExtension == "JPG" || anExtension == "JPEG" ||
-             anExtension == "BMP"|| anExtension == "PPM"
-             ) {
-     aGeomShape = ImageImport(theFileName, anError);
-     if(anError == "")
-       theTextureFileName = theFileName;
-    } else {
-    anError = "Unsupported format: " + anExtension;
-  }
 
-  // Check if shape is valid
-  if (!anError.empty()) {
-    setError("An error occurred while importing " + theFileName + ": " + anError);
-    return;
-  }
+  if (anExtension == "PNG"  || anExtension == "GIF" ||
+      anExtension == "TIFF" || anExtension == "JPE" ||
+      anExtension == "JPEG" || anExtension == "JPG" ||
+      anExtension == "BMP"  || anExtension == "PPM"
+      ) {
+    // Perform the import
+    QPixmap px (theFileName.c_str());
+    int aWidth  = px.width();
+    int aHeight = px.height();
+    if (aWidth < 1 || aHeight < 1) {
+      setError("An error occurred while importing " + theFileName + ": invalid image");
+      return;
+    }
 
-  // Pass the results into the model
-  std::string anObjectName = GeomAlgoAPI_Tools::File_Tools::name(theFileName);
-  data()->setName(Locale::Convert::toWString(anObjectName));
+    std::shared_ptr<GeomAPI_Shape> aGeomShape = ImageImport(aWidth, aHeight, anError);
+
+    // Check if shape is valid
+    if (!anError.empty()) {
+      setError("An error occurred while importing " + theFileName + ": " + anError);
+      return;
+    }
+
+    // Pass the results into the model
+    std::string anObjectName = GeomAlgoAPI_Tools::File_Tools::name(theFileName);
+    data()->setName(Locale::Convert::toWString(anObjectName));
+
+    auto resultBody = createResultBody(aGeomShape);
 
-  auto resultBody = createResultBody(aGeomShape);
-  resultBody->setTextureFile(theTextureFileName);
-  setResult(resultBody);
+    // Store image in result body attribute
+    AttributeImagePtr anImageAttr = resultBody->data()->image(ModelAPI_ResultBody::IMAGE_ID());
+    if (anImageAttr.get() != NULL) {
+      QImage aQImage = px.toImage();
+      const uchar* aImageBytes = aQImage.bits();
+      std::list<unsigned char> aByteArray (aImageBytes, aImageBytes + aQImage.sizeInBytes());
+      anImageAttr->setTexture(aWidth, aHeight, aByteArray, anExtension);
+    }
+
+    setResult(resultBody);
+  }
+  else {
+    anError = "Unsupported format: " + anExtension;
+    setError("An error occurred while importing " + theFileName + ": " + anError);
+  }
 }
index 327caf623e2756ff506cb3254a2900e51c847c81..b26dcf5cdb709d0bd93f473edb0d8be5adab93d4 100755 (executable)
@@ -66,6 +66,9 @@ tol=1e-06
 assert(abs(dx-400) <= tol)
 assert(abs(dy-258.5) <= tol)
 assert(abs(dz-0) <= tol)
+assert(ImportImage_1.result().resultSubShapePair()[0].hasTexture())
+assert(Translation_1.result().resultSubShapePair()[0].hasTexture())
+assert(Scale_1.result().resultSubShapePair()[0].hasTexture())
 
 #=============================================================================
 # Change the image :
@@ -95,7 +98,11 @@ tol=1e-06
 assert(abs(dx-448) <= tol)
 assert(abs(dy-296.8) <= tol)
 assert(abs(dz-0) <= tol)
+assert(ImportImage_1.result().resultSubShapePair()[0].hasTexture())
+assert(Translation_1.result().resultSubShapePair()[0].hasTexture())
+assert(Scale_1.result().resultSubShapePair()[0].hasTexture())
 
+assert(model.checkPythonDump())
 
 # Close SALOME GUI
 import salome_utils
index fa214c76bd038620329a28633b41d76f92e75309..9a4230f93920f4a26681d8e5e38846b7966f5486 100755 (executable)
@@ -74,6 +74,9 @@ tol=1e-06
 assert(abs(dx-400) <= tol)
 assert(abs(dy-258.5) <= tol)
 assert(abs(dz-0) <= tol)
+assert(ImportImage_1.result().resultSubShapePair()[0].hasTexture())
+assert(Translation_1.result().resultSubShapePair()[0].hasTexture())
+assert(Scale_1.result().resultSubShapePair()[0].hasTexture())
 
 #=============================================================================
 # Change the image :
@@ -101,6 +104,9 @@ tol=1e-06
 assert(abs(dx-560) <= tol)
 assert(abs(dy-361.9) <= tol)
 assert(abs(dz-0) <= tol)
+assert(ImportImage_1.result().resultSubShapePair()[0].hasTexture())
+assert(Translation_1.result().resultSubShapePair()[0].hasTexture())
+assert(Scale_1.result().resultSubShapePair()[0].hasTexture())
 
 
 # Close SALOME GUI
diff --git a/src/ExchangePlugin/Test/TestImportImage_3.py b/src/ExchangePlugin/Test/TestImportImage_3.py
new file mode 100755 (executable)
index 0000000..221768b
--- /dev/null
@@ -0,0 +1,108 @@
+# 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
+#
+
+import os, inspect
+from salome.shaper import model
+
+from PyQt5.Qt import QApplication
+
+import salome
+salome.salome_init_without_session()
+salome.salome_init(1)
+if QApplication.instance() is None:
+  app = QApplication([])
+
+from tempfile import TemporaryDirectory
+from ModelAPI import *
+
+data_dir = os.path.join(os.path.dirname(inspect.getfile(lambda: None)), "data")
+
+model.begin()
+partSet = model.moduleDocument()
+
+### Create Part
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+
+### Create ImportImage
+ImportImage_1 = model.addImportImage(Part_1_doc, os.path.join(data_dir, "1.jpg"))
+model.do()
+ImportImage_1.setName("drawing")
+ImportImage_1.result().setName("drawing")
+
+### Create Translation
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("FACE", "drawing")], startPoint = model.selection("VERTEX", "[drawing/Shape_1]e[drawing/Shape_4]e"), endPoint = model.selection("VERTEX", "PartSet/Origin"), keepSubResults = True)
+Translation_1.setName("translation")
+
+### Create Scale
+Scale_1 = model.addScale(Part_1_doc, [model.selection("FACE", "drawing")] , model.selection("VERTEX", "PartSet/Origin"), 0.5, keepSubResults = True)
+Scale_1.setName("scale")
+
+model.end()
+
+#=============================================================================
+# Tests :
+#=============================================================================
+model.checkResult(Scale_1, model, 1, [0], [0], [1], [4], [8])
+r=Scale_1.defaultResult()
+s=r.shape()
+dim=s.computeSize()
+dim=dim[1:]
+dx=abs(dim[3]-dim[0])
+dy=abs(dim[4]-dim[1])
+dz=abs(dim[5]-dim[2])
+tol=1e-06
+assert(abs(dx-400) <= tol)
+assert(abs(dy-258.5) <= tol)
+assert(abs(dz-0) <= tol)
+assert(ImportImage_1.result().resultSubShapePair()[0].hasTexture())
+assert(Translation_1.result().resultSubShapePair()[0].hasTexture())
+assert(Scale_1.result().resultSubShapePair()[0].hasTexture())
+
+aDr = objectToFeature(Part_1_doc.objectByName("Features", "drawing"))
+assert(aDr.firstResult().hasTexture())
+
+# check save/load document with an image
+with TemporaryDirectory() as tmp_dir:
+  aSession = ModelAPI_Session.get()
+  aFiles = StringList()
+  aSession.save(tmp_dir, aFiles)
+  aSession.closeAll()
+  assert(aSession.load(tmp_dir))
+  model.begin()
+  partSet = model.moduleDocument()
+  assert(partSet.size("Features") == 1)
+  aPart = objectToFeature(partSet.object("Features", 0))
+  aPartResult = modelAPI_ResultPart(aPart.results()[0])
+  aPartResult.activate()
+  aPartDoc = aPartResult.partDoc()
+  aSession.setActiveDocument(aPartDoc, True)
+  model.end()
+  aDr = objectToFeature(aPartDoc.objectByName("Features", "drawing"))
+  aTr = objectToFeature(aPartDoc.objectByName("Features", "translation"))
+  aSc = objectToFeature(aPartDoc.objectByName("Features", "scale"))
+  assert(aDr.firstResult().hasTexture())
+  assert(aTr.firstResult().hasTexture())
+  assert(aSc.firstResult().hasTexture())
+
+# Close SALOME GUI
+import salome_utils
+import subprocess
+port = salome_utils.getPortNumber()
+proc = subprocess.Popen(["killSalomeWithPort.py", "{}".format(port)])
index 0464ada42e3dfe1191729dfc5af7bc07c9eb422d..b4cc706cf08db7e9eec79b9e961559f6966863de 100755 (executable)
@@ -20,4 +20,5 @@
 SET(TEST_WITH_GUI_NAMES
   TestImportImage_1.py
   TestImportImage_2.py
+  TestImportImage_3.py
 )
\ No newline at end of file
index 22e93b7182bfcb875679e4b5ae22faff8cfa0634..fff4a917bde19106e932e70f838fea50b86e0357 100644 (file)
@@ -57,6 +57,14 @@ void FeaturesAPI_ImportResult::dump(ModelHighAPI_Dumper& theDumper) const
   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;
 }
index a49ef0fb480529c1edb95e640f8386493804400f..9e6a14c4844df1f522e4fcaac1b33b5aa1194a83 100644 (file)
 #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);
 }
 
@@ -115,3 +263,69 @@ bool FeaturesPlugin_ValidatorImportResults::isValid(const AttributePtr& theAttri
   }
   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);
+}
index 9b946ab18fb3982dd427841494cd3e260472c93a..69aef3aa2a5c1639591084d9493553b37c674745 100644 (file)
@@ -22,7 +22,7 @@
 
 #include "FeaturesPlugin.h"
 
-#include <ModelAPI_Feature.h>
+#include <ModelAPI_CompositeFeature.h>
 #include <ModelAPI_AttributeValidator.h>
 
 /// \class FeaturesPlugin_ImportResult
@@ -30,7 +30,7 @@
 /// \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.
@@ -39,6 +39,12 @@ public:
     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()
@@ -60,6 +66,26 @@ public:
   /// 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() {}
 };
index adb0c81f0b97ba739e3d53aa5f203c63043139c7..4e3d05ba23f41abe7458901cd29e9c10c768062e 100644 (file)
@@ -167,9 +167,9 @@ void FeaturesPlugin_MultiRotation::performRotation1D()
 
   GeomAPI_ShapeHierarchy anObjects;
   std::list<ResultPtr> aParts;
-  std::string theTextureFile;
-  if (!FeaturesPlugin_Tools::shapesFromSelectionList(
-       anObjectsSelList, isKeepSubShapes, anObjects, aParts, theTextureFile))
+  ResultPtr aTextureSource;
+  if (!FeaturesPlugin_Tools::shapesFromSelectionList
+      (anObjectsSelList, isKeepSubShapes, anObjects, aParts, aTextureSource))
     return;
 
   // Parameters of rotation.
@@ -226,7 +226,8 @@ void FeaturesPlugin_MultiRotation::performRotation1D()
     ResultBodyPtr aResultBody = document()->createBody(data(), aResultIndex);
     ModelAPI_Tools::loadModifiedShapes(aResultBody, anOriginalShapes, ListOfShape(),
                                        aMakeShapeList, *anIt, "Rotated");
-    aResultBody->setTextureFile(theTextureFile);
+    // Copy image data, if any
+    ModelAPI_Tools::copyImageAttribute(aTextureSource, aResultBody);
     setResult(aResultBody, aResultIndex++);
   }
 
index 637fcfa31904ed3ff378e1c2f113f4ac2c5f4e6e..8ee89a08f6003f9e18344ecb939cb1a6b5e3624a 100644 (file)
@@ -92,9 +92,9 @@ void FeaturesPlugin_MultiTranslation::execute()
 
   GeomAPI_ShapeHierarchy anObjects;
   std::list<ResultPtr> aParts;
-  std::string theTextureFile;
-  if (!FeaturesPlugin_Tools::shapesFromSelectionList(
-       anObjectsSelList, isKeepSubShapes, anObjects, aParts, theTextureFile))
+  ResultPtr aTextureSource;
+  if (!FeaturesPlugin_Tools::shapesFromSelectionList
+      (anObjectsSelList, isKeepSubShapes, anObjects, aParts, aTextureSource))
     return;
 
   std::shared_ptr<GeomAPI_Dir> aFirstDir, aSecondDir;
@@ -172,7 +172,8 @@ void FeaturesPlugin_MultiTranslation::execute()
     ResultBodyPtr aResultBody = document()->createBody(data(), aResultIndex);
     ModelAPI_Tools::loadModifiedShapes(aResultBody, anOriginalShapes, ListOfShape(),
                                        aMakeShapeList, *anIt, "Translated");
-    aResultBody->setTextureFile(theTextureFile);
+    // Copy image data, if any
+    ModelAPI_Tools::copyImageAttribute(aTextureSource, aResultBody);
     setResult(aResultBody, aResultIndex++);
   }
 
index 7a21c667a38a5e1ddc6792734ef6db1a7df68b4c..a357658f5cae9cfa316f4aa7e2215ba10ca56952 100644 (file)
@@ -71,10 +71,10 @@ void FeaturesPlugin_Placement::execute()
   // Getting objects.
   GeomAPI_ShapeHierarchy anObjects;
   std::list<ResultPtr> aParts;
-  std::string theTextureFile;
+  ResultPtr aTextureSource;
   AttributeSelectionListPtr anObjectsSelList = selectionList(OBJECTS_LIST_ID());
-  if (!FeaturesPlugin_Tools::shapesFromSelectionList(
-       anObjectsSelList, isKeepSubShapes, anObjects, aParts, theTextureFile))
+  if (!FeaturesPlugin_Tools::shapesFromSelectionList
+      (anObjectsSelList, isKeepSubShapes, anObjects, aParts, aTextureSource))
     return;
 
   // Verify the start shape
@@ -181,7 +181,8 @@ void FeaturesPlugin_Placement::execute()
     ResultBodyPtr aResultBody = document()->createBody(data(), aResultIndex);
     ModelAPI_Tools::loadModifiedShapes(aResultBody, anOriginalShapes, ListOfShape(),
                                        aMakeShapeList, *anIt, "Placed");
-    aResultBody->setTextureFile(theTextureFile);
+    // Copy image data, if any
+    ModelAPI_Tools::copyImageAttribute(aTextureSource, aResultBody);
     setResult(aResultBody, aResultIndex++);
   }
 
index 144e57ef23e9a5b8fc389f6a3ff9d6855f78c44a..473d5964a3cedece2e8b960c44fbc0155dfe64f9 100644 (file)
@@ -185,10 +185,10 @@ void FeaturesPlugin_Rotation::performRotation(const GeomTrsfPtr& theTrsf)
   // Getting objects.
   GeomAPI_ShapeHierarchy anObjects;
   std::list<ResultPtr> aParts;
-  std::string theTextureFile;
+  ResultPtr aTextureSource;
   AttributeSelectionListPtr anObjSelList = selectionList(OBJECTS_LIST_ID());
   if (!FeaturesPlugin_Tools::shapesFromSelectionList(
-       anObjSelList, isKeepSubShapes, anObjects, aParts, theTextureFile))
+       anObjSelList, isKeepSubShapes, anObjects, aParts, aTextureSource))
     return;
 
   std::string anError;
@@ -227,7 +227,8 @@ void FeaturesPlugin_Rotation::performRotation(const GeomTrsfPtr& theTrsf)
     ResultBodyPtr aResultBody = document()->createBody(data(), aResultIndex);
     ModelAPI_Tools::loadModifiedShapes(aResultBody, anOriginalShapes, ListOfShape(),
                                        aMakeShapeList, *anIt, "Rotated");
-    aResultBody->setTextureFile(theTextureFile);
+    // Copy image data, if any
+    ModelAPI_Tools::copyImageAttribute(aTextureSource, aResultBody);
     setResult(aResultBody, aResultIndex++);
   }
 
index 6c92629c8d09df873234d844fc71f4a791291c66..f53834fc5ba0507ef52f0a57055083b487ecc614 100644 (file)
@@ -93,10 +93,10 @@ void FeaturesPlugin_Scale::performScaleByFactor()
   // Getting objects.
   GeomAPI_ShapeHierarchy anObjects;
   std::list<ResultPtr> aParts;
-  std::string theTextureFile;
+  ResultPtr aTextureSource;
   AttributeSelectionListPtr anObjSelList = selectionList(OBJECTS_LIST_ID());
   if (!FeaturesPlugin_Tools::shapesFromSelectionList(
-       anObjSelList, isKeepSubShapes, anObjects, aParts, theTextureFile))
+       anObjSelList, isKeepSubShapes, anObjects, aParts, aTextureSource))
     return;
 
   // Getting the center point
@@ -144,7 +144,8 @@ void FeaturesPlugin_Scale::performScaleByFactor()
     ResultBodyPtr aResultBody = document()->createBody(data(), aResultIndex);
     ModelAPI_Tools::loadModifiedShapes(aResultBody, anOriginalShapes, ListOfShape(),
                                        aMakeShapeList, *anIt, "Scaled");
-    aResultBody->setTextureFile(theTextureFile);
+    // Copy image data, if any
+    ModelAPI_Tools::copyImageAttribute(aTextureSource, aResultBody);
     setResult(aResultBody, aResultIndex++);
   }
 
@@ -160,10 +161,10 @@ void FeaturesPlugin_Scale::performScaleByDimensions()
   // Getting objects.
   GeomAPI_ShapeHierarchy anObjects;
   std::list<ResultPtr> aParts;
-  std::string theTextureFile;
+  ResultPtr aTextureSource;
   AttributeSelectionListPtr anObjSelList = selectionList(OBJECTS_LIST_ID());
   if (!FeaturesPlugin_Tools::shapesFromSelectionList(
-       anObjSelList, isKeepSubShapes, anObjects, aParts, theTextureFile))
+       anObjSelList, isKeepSubShapes, anObjects, aParts, aTextureSource))
     return;
 
   // Getting the center point
@@ -216,7 +217,8 @@ void FeaturesPlugin_Scale::performScaleByDimensions()
     ResultBodyPtr aResultBody = document()->createBody(data(), aResultIndex);
     ModelAPI_Tools::loadModifiedShapes(aResultBody, anOriginalShapes, ListOfShape(),
                                        aMakeShapeList, *anIt, "Scaled");
-    aResultBody->setTextureFile(theTextureFile);
+    // Copy image data, if any
+    ModelAPI_Tools::copyImageAttribute(aTextureSource, aResultBody);
     setResult(aResultBody, aResultIndex++);
   }
 
index d007306fcff36dd4b16670945f5039ba6c788168..5ad5d61a2d7e4460ce430a5fc7135f4254bc5a07 100644 (file)
@@ -205,13 +205,14 @@ void FeaturesPlugin_Symmetry::buildResult(
     const std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theAlgo,
     const std::list<std::shared_ptr<GeomAPI_Shape> >& theOriginalShapes,
     std::shared_ptr<GeomAPI_Shape> theTargetShape, int& theResultIndex,
-    std::string & theTextureFile)
+    const ResultPtr& theTextureSource)
 {
   // Store and name the result.
   ResultBodyPtr aResultBody = document()->createBody(data(), theResultIndex);
   ModelAPI_Tools::loadModifiedShapes(aResultBody, theOriginalShapes, ListOfShape(),
                                      theAlgo, theTargetShape, "Symmetried");
-  aResultBody->setTextureFile(theTextureFile);
+  // Copy image data, if any
+  ModelAPI_Tools::copyImageAttribute(theTextureSource, aResultBody);
   setResult(aResultBody, theResultIndex++);
 }
 
@@ -282,10 +283,10 @@ void FeaturesPlugin_Symmetry::performSymmetry(GeomTrsfPtr theTrsf)
   // Getting objects.
   GeomAPI_ShapeHierarchy anObjects;
   std::list<ResultPtr> aParts;
-  std::string theTextureFile;
+  ResultPtr aTextureSource;
   AttributeSelectionListPtr anObjSelList = selectionList(OBJECTS_LIST_ID());
   if (!FeaturesPlugin_Tools::shapesFromSelectionList(
-       anObjSelList, isKeepSubShapes, anObjects, aParts, theTextureFile))
+       anObjSelList, isKeepSubShapes, anObjects, aParts, aTextureSource))
     return;
 
   std::string anError;
@@ -313,7 +314,7 @@ void FeaturesPlugin_Symmetry::performSymmetry(GeomTrsfPtr theTrsf)
   ListOfShape aTopLevel;
   anObjects.topLevelObjects(aTopLevel);
   for (ListOfShape::iterator anIt = aTopLevel.begin(); anIt != aTopLevel.end(); ++anIt)
-    buildResult(aMakeShapeList, anOriginalShapes, *anIt, aResultIndex, theTextureFile);
+    buildResult(aMakeShapeList, anOriginalShapes, *anIt, aResultIndex, aTextureSource);
 
   // Remove the rest results if there were produced in the previous pass.
   removeResults(aResultIndex);
index 5d73f9ec8b9ff94888d58e0535f4140518107d50..814dcdb7b4b7f1978e898819aa4ed62a7fdd4708 100644 (file)
@@ -23,6 +23,7 @@
 #include <FeaturesPlugin.h>
 
 #include <ModelAPI_Feature.h>
+#include <ModelAPI_Result.h>
 
 class GeomAPI_Trsf;
 class GeomAlgoAPI_MakeShapeList;
@@ -137,7 +138,8 @@ private:
   void buildResult(const std::shared_ptr<GeomAlgoAPI_MakeShapeList>& theAlgo,
                    const std::list<std::shared_ptr<GeomAPI_Shape> >& theOriginalShapes,
                    std::shared_ptr<GeomAPI_Shape> theTargetShape,
-                   int& theResultIndex, std::string &theTextureFile);
+                   int& theResultIndex,
+                   const ResultPtr& theTextureSource);
 
   /// Create new result for the given part and transformation
   void buildResult(std::shared_ptr<ModelAPI_ResultPart> theOriginal,
index a6dc9169fed7462c4eea49cbf2b24425ddab0ae9..a777af3b594e83200626979cbb82db53b0e14980 100644 (file)
@@ -143,27 +143,21 @@ bool FeaturesPlugin_Tools::shapesFromSelectionList(
     const std::shared_ptr<ModelAPI_AttributeSelectionList> theSelectionList,
     const bool theStoreFullHierarchy,
     GeomAPI_ShapeHierarchy& theHierarchy,
-    std::list<ResultPtr>& theParts, std::string &theTextureFile)
+    std::list<ResultPtr>& theParts, ResultPtr& theTextureSource)
 {
   int aSize = theSelectionList->size();
-  if(aSize == 1)
-  {
+  if (aSize == 1) {
     auto anObjectAttr = theSelectionList->value(0);
-    if(anObjectAttr.get())
-    {
+    if (anObjectAttr.get()) {
       FeaturePtr aFeature = anObjectAttr->contextFeature();
-      if(aFeature.get() &&  aFeature->results().size() == 1)
-      {
-        theTextureFile = aFeature->firstResult()->getTextureFile();
+      if (aFeature.get() && aFeature->results().size() == 1) {
+        theTextureSource = aFeature->firstResult();
       }
-      else
-      {
-        if(!aFeature.get())
-        {
-          auto aResult =  anObjectAttr->context();
-          if(aResult.get())
-          {
-            theTextureFile = aResult->getTextureFile();
+      else {
+        if (!aFeature.get()) {
+          auto aResult = anObjectAttr->context();
+          if (aResult.get()) {
+            theTextureSource = aResult;
           }
         }
       }
index 92cfe2f47e811dae19f97836aa9e737ba7308241..306d00db8ecffe30164b59c82e30a07dff39f118 100644 (file)
@@ -39,7 +39,8 @@ public:
       const std::shared_ptr<ModelAPI_AttributeSelectionList> theSelectionList,
       const bool theStoreFullHierarchy,
       GeomAPI_ShapeHierarchy& theHierarchy,
-      std::list<ResultPtr>& theParts, std::string& theTextureFile);
+      std::list<ResultPtr>& theParts,
+      ResultPtr& theTextureSource);
 };
 
 #endif /* FeaturesPlugin_Tools_H_ */
index ca8039765473a21a2035af356ffbd2a69bbfa3cf..93aa595ede7ce85efe36bed1a960925cc58119eb 100644 (file)
@@ -198,10 +198,10 @@ void FeaturesPlugin_Translation::performTranslation(const GeomTrsfPtr& theTrsf)
   // Getting objects.
   GeomAPI_ShapeHierarchy anObjects;
   std::list<ResultPtr> aParts;
-  std::string theTextureFile;
+  ResultPtr aTextureSource;
   AttributeSelectionListPtr anObjectsSelList = selectionList(OBJECTS_LIST_ID());
-  if (!FeaturesPlugin_Tools::shapesFromSelectionList(
-       anObjectsSelList, isKeepSubShapes, anObjects, aParts, theTextureFile))
+  if (!FeaturesPlugin_Tools::shapesFromSelectionList
+      (anObjectsSelList, isKeepSubShapes, anObjects, aParts, aTextureSource))
     return;
 
   std::string anError;
@@ -242,7 +242,8 @@ void FeaturesPlugin_Translation::performTranslation(const GeomTrsfPtr& theTrsf)
     ResultBodyPtr aResultBody = document()->createBody(data(), aResultIndex);
     ModelAPI_Tools::loadModifiedShapes(aResultBody, anOriginalShapes, ListOfShape(),
                                        aMakeShapeList, *anIt, "Translated");
-    aResultBody->setTextureFile(theTextureFile);
+    // Copy image data, if any
+    ModelAPI_Tools::copyImageAttribute(aTextureSource, aResultBody);
     setResult(aResultBody, aResultIndex++);
   }
 
index 828b4bdd8be11a16e42b47681b24bc382442d431..b5aa56afed87a137bedd12518c300f045c37f966 100644 (file)
@@ -2019,6 +2019,14 @@ bool FeaturesPlugin_ValidatorDefeaturingSelection::isValid(
       theError = "Error: Not all selected shapes are sub-shapes of solids.";
       return false;
     }
+
+    ResultBodyPtr aResRootPtr = ModelAPI_Tools::bodyOwner(aContext, true);
+    if (aResRootPtr.get() && aResRootPtr->shape().get()) {
+      if (!aResRootPtr->shape()->isCollectionOfSolids()) {
+        theError = "Error: The main shape should be a collection of solids";
+        return false;
+      }
+    }
   }
 
   return true;
diff --git a/src/FeaturesPlugin/Test/TestImportResultWithGroups1.py b/src/FeaturesPlugin/Test/TestImportResultWithGroups1.py
new file mode 100644 (file)
index 0000000..29c7ec9
--- /dev/null
@@ -0,0 +1,78 @@
+# 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())
diff --git a/src/FeaturesPlugin/Test/TestImportResultWithGroups2.py b/src/FeaturesPlugin/Test/TestImportResultWithGroups2.py
new file mode 100644 (file)
index 0000000..38f93ae
--- /dev/null
@@ -0,0 +1,85 @@
+# 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())
diff --git a/src/FeaturesPlugin/Test/TestImportResultWithGroups3.py b/src/FeaturesPlugin/Test/TestImportResultWithGroups3.py
new file mode 100644 (file)
index 0000000..8702339
--- /dev/null
@@ -0,0 +1,87 @@
+# 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())
index b2349e635190fd0086b64a1cd9414d57efe52848..a25cb09f31a40181fd1efc8404d4f4f714cfe219 100644 (file)
@@ -8,6 +8,9 @@ changed, the part and part result that contains the copy-results will be updated
 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:
@@ -42,7 +45,7 @@ current Part where the import is done. Only results from the **Results** folder
 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
index 7e5e58612fc4a1a9278d70448ccc74d38c87c133..b1d33e64d97ed043c29d36ffa9ac34b6a2744e51 100644 (file)
@@ -393,6 +393,9 @@ SET(TEST_NAMES
                TestCopySubShapes.py
                TestCopyWholeFeature.py
                TestImportResult.py
+               TestImportResultWithGroups1.py
+               TestImportResultWithGroups2.py
+               TestImportResultWithGroups3.py
                TestDefeaturing_ErrorMsg.py
                TestDefeaturing_OnSolid1.py
                TestDefeaturing_OnSolid2.py
index 1d3f99fcb203147736a42229c9756ecb9e609a5c..7168ccdb5ac04c8bfc87a3aec94ac45d3a7b6a2b 100644 (file)
@@ -55,6 +55,7 @@
 
 #include <BOPAlgo_CheckerSI.hxx>
 #include <BOPDS_DS.hxx>
+#include <BOPTools_AlgoTools.hxx>
 
 #include <sstream>
 #include <algorithm> // for std::transform
@@ -148,6 +149,32 @@ bool GeomAPI_Shape::isCompound() const
   return !aShape.IsNull() && aShape.ShapeType() == TopAbs_COMPOUND;
 }
 
+bool GeomAPI_Shape::isCollectionOfSolids() const
+{
+  const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
+  if (aShape.IsNull())
+    return false;
+
+  if (aShape.ShapeType() == TopAbs_SOLID ||
+      aShape.ShapeType() == TopAbs_COMPSOLID)
+    return true;
+
+  if (aShape.ShapeType() != TopAbs_COMPOUND)
+    return false;
+
+  TopTools_ListOfShape aLS;
+  TopTools_MapOfShape aMFence;
+  BOPTools_AlgoTools::TreatCompound(aShape, aLS, &aMFence);
+  TopTools_ListOfShape::Iterator it(aLS);
+  for (; it.More(); it.Next()) {
+    const TopoDS_Shape& aSx = it.Value();
+    if (aSx.ShapeType() != TopAbs_SOLID &&
+        aSx.ShapeType() != TopAbs_COMPSOLID)
+      return false;
+  }
+  return true;
+}
+
 bool GeomAPI_Shape::isCompoundOfSolids() const
 {
   const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
index 3dfed0f86756fb8394b8b3d78ecefe2600f67712..fad3425c05e15990e474458e8ac76494d1e075be 100644 (file)
@@ -110,6 +110,11 @@ public:
   GEOMAPI_EXPORT
   virtual bool isCompoundOfSolids() const;
 
+  /// Returns true, if the shape contains only solids, compsolids
+  /// and compounds of solids and compsolids of any nesting depth
+  GEOMAPI_EXPORT
+  virtual bool isCollectionOfSolids() const;
+
   /// Returns whether the shape is a compound where all elements are topologically connected
   GEOMAPI_EXPORT
   virtual bool isConnectedTopology() const;
index 2fa736470c59886d68f3ae9501d5f89e31764976..19ace76ed583fa94ea0ad1f2edf14ed861b63a24 100644 (file)
@@ -173,7 +173,6 @@ SET(PROJECT_LIBRARIES
     ${OpenCASCADE_DataExchange_LIBRARIES}
     ${OpenCASCADE_ModelingAlgorithms_LIBRARIES}
     ${OpenCASCADE_ApplicationFramework_LIBRARIES}
-    ${QT_LIBRARIES}
 )
 
 ADD_DEFINITIONS(-DGEOMALGOAPI_EXPORTS ${OpenCASCADE_DEFINITIONS})
@@ -184,10 +183,7 @@ SET(CMAKE_SWIG_FLAGS -w325,321,362,383,302)
 SET_SOURCE_FILES_PROPERTIES(GeomAlgoAPI.i PROPERTIES CPLUSPLUS ON)
 SET_SOURCE_FILES_PROPERTIES(GeomAlgoAPI.i PROPERTIES SWIG_DEFINITIONS "-shadow")
 
-INCLUDE(UseQtExt)
 # additional include directories
-INCLUDE_DIRECTORIES(${QT_INCLUDES})
-
 INCLUDE_DIRECTORIES(
   ../GeomAPI
   ../GeomAlgoImpl
index 1f73aeef182a91096f0de92794b10244874069f1..d0077871a1102f76dcf1d91e74616fcddda61cf0 100644 (file)
@@ -19,7 +19,6 @@
 
 #include <GeomAlgoAPI_ImageImport.h>
 
-#include <QPixmap>
 #include <BRep_Builder.hxx>
 #include <BRepBuilderAPI_MakeFace.hxx>
 #include <BRepBuilderAPI_MakePolygon.hxx>
 #include <TopoDS_Vertex.hxx>
 #include <TopoDS_Wire.hxx>
 
-std::shared_ptr<GeomAPI_Shape> ImageImport(const std::string& theFileName,
-                                         std::string& theError)
+std::shared_ptr<GeomAPI_Shape> ImageImport(const int width,
+                                           const int height,
+                                           std::string& theError)
 {
   TopoDS_Shape aResShape;
   try
   {
-    QPixmap* pixmap = new QPixmap(theFileName.c_str());
-    int height            =  pixmap->height();
-    int width             =  pixmap->width();
-
-    delete pixmap;
-
     TopoDS_Vertex aTriVertexes[4];
     gp_Pnt aPnt1( -0.5*width, -0.5*height, 0);
     gp_Pnt aPnt2( 0.5*width, -0.5*height, 0);
index 4f9573b480638dd58deb12e121d4cdaef927168d..5a29f8fbfa4c72783c0114fa7239da679fb74085 100644 (file)
 #include <GeomAPI_Shape.h>
 
 #include <string>
-#include <QPixmap>
+
 /// Implementation of the import STL files algorithms
 GEOMALGOAPI_EXPORT
-std::shared_ptr<GeomAPI_Shape>  ImageImport(const std::string& theFileName,
-                                          std::string& theError);
+std::shared_ptr<GeomAPI_Shape> ImageImport(const int theWidth,
+                                           const int theHeight,
+                                           std::string& theError);
 
 #endif /* GEOMALGOAPI_IMAGEIMPORT_H_ */
index 3bdecb71dbe2f8b02283869f95f5cb9664d81843..a26b7257e92247735e7670f0e277fb5195d0dabd 100644 (file)
@@ -61,6 +61,14 @@ std::string File_Tools::name(const std::string& theFileName)
   return aPath.Name().ToCString();
 }
 
+std::string File_Tools::path(const std::string& theFileName)
+{
+  OSD_Path aPath (theFileName.c_str());
+  Standard_Integer aTrekLen =
+    theFileName.size() - aPath.Extension().Length() - aPath.Name().Length();
+  return theFileName.substr(0, aTrekLen);
+}
+
 bool AlgoError::isAlgorithmFailed(const GeomMakeShapePtr& theAlgorithm,
                                   const std::string& theFeature,
                                   std::string& theError)
index d7020e68e26b633499c58a5d74e65df37146f20d..39081890a17e03dda09b31455a288a496b395f65 100644 (file)
@@ -63,6 +63,10 @@ public:
    * Returns a name of theFileName
    */
   GEOMALGOAPI_EXPORT static std::string name(const std::string& theFileName);
+  /**
+   * Returns a directory path of theFileName
+   */
+  GEOMALGOAPI_EXPORT static std::string path(const std::string& theFileName);
 };
 
 /** \class AlgoError
index 2f349c1939b9c8b96ef5c7d63cc82bebda7a02ca..c270a9c13be990850c4170c38e460e0bcf144249 100644 (file)
@@ -34,6 +34,7 @@ SET(PROJECT_HEADERS
     Model_AttributeRefList.h
     Model_AttributeRefAttrList.h
     Model_AttributeBoolean.h
+    Model_AttributeImage.h
     Model_AttributeIntArray.h
     Model_AttributeString.h
     Model_AttributeStringArray.h
@@ -72,6 +73,7 @@ SET(PROJECT_SOURCES
     Model_AttributeRefList.cpp
     Model_AttributeRefAttrList.cpp
     Model_AttributeBoolean.cpp
+    Model_AttributeImage.cpp
     Model_AttributeIntArray.cpp
     Model_AttributeString.cpp
     Model_AttributeStringArray.cpp
diff --git a/src/Model/Model_AttributeImage.cpp b/src/Model/Model_AttributeImage.cpp
new file mode 100644 (file)
index 0000000..c74e429
--- /dev/null
@@ -0,0 +1,147 @@
+// Copyright (C) 2014-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
+//
+
+#include <Model_AttributeImage.h>
+#include <ModelAPI_AttributeString.h>
+#include <ModelAPI_Attribute.h>
+#include <ModelAPI_Data.h>
+#include <ModelAPI_Object.h>
+
+#include <Standard_TypeDef.hxx>
+#include <TCollection_AsciiString.hxx>
+#include <TCollection_ExtendedString.hxx>
+
+#include <TDataStd_IntegerArray.hxx>
+#include <TDataStd_ByteArray.hxx>
+#include <TDataStd_Comment.hxx>
+#include <TDF_CopyLabel.hxx>
+
+void Model_AttributeImage::setTexture(const int theWidth,
+                                      const int theHeight,
+                                      const std::list<unsigned char>& theByteArray,
+                                      const std::string& theFormat,
+                                      const bool sendUpdated)
+{
+  if (theWidth > 0 && theHeight > 0 && theByteArray.size() > 0) { // set new data
+    // Find or create attributes
+    Handle_TDataStd_ByteArray aByteArray =
+      TDataStd_ByteArray::Set(myLab, 0, theByteArray.size() - 1);
+    Handle_TDataStd_IntegerArray aDimensions =
+      TDataStd_IntegerArray::Set(myLab, 0, 1);
+    Handle_TDataStd_Comment aFormat = TDataStd_Comment::Set(myLab, theFormat.c_str());
+
+    // Dimensions
+    aDimensions->SetValue(0, theWidth);
+    aDimensions->SetValue(1, theHeight);
+
+    // Texture
+    Handle(TColStd_HArray1OfByte) aNewArray =
+      new TColStd_HArray1OfByte(0, theByteArray.size() - 1);
+    std::list<unsigned char>::const_iterator itBA = theByteArray.begin();
+    for (int j = 0; itBA != theByteArray.end(); ++itBA, ++j) {
+      aNewArray->SetValue(j, (Standard_Byte)(*itBA));
+    }
+    aByteArray->ChangeArray(aNewArray);
+
+    if (sendUpdated)
+      owner()->data()->sendAttributeUpdated(this);
+  }
+  else { // size is zero => arrays must be erased
+    bool isForgotten1 = myLab.ForgetAttribute(TDataStd_ByteArray::GetID());
+    bool isForgotten2 = myLab.ForgetAttribute(TDataStd_IntegerArray::GetID());
+    bool isForgotten3 = myLab.ForgetAttribute(TDataStd_Comment::GetID());
+
+    if (sendUpdated && (isForgotten1 || isForgotten2 || isForgotten3))
+      owner()->data()->sendAttributeUpdated(this);
+  }
+}
+
+bool Model_AttributeImage::hasTexture()
+{
+  Handle_TDataStd_ByteArray aByteArray;
+  Handle_TDataStd_IntegerArray aDimensions;
+  if (myLab.FindAttribute(TDataStd_ByteArray::GetID(), aByteArray) == Standard_True &&
+      myLab.FindAttribute(TDataStd_IntegerArray::GetID(), aDimensions) == Standard_True) {
+
+    // Dimensions
+    if (aDimensions->Value(0) > 0 && aDimensions->Value(1) > 0)
+      // Byte array
+      return aByteArray->Length() > 0;
+  }
+  return false;
+}
+
+bool Model_AttributeImage::texture(int& theWidth,
+                                   int& theHeight,
+                                   std::list<unsigned char>& theByteArray,
+                                   std::string& theFormat)
+{
+  // Init return values
+  theWidth = 0;
+  theHeight = 0;
+  theByteArray.clear();
+  theFormat = "";
+
+  Handle_TDataStd_ByteArray aByteArray;
+  Handle_TDataStd_IntegerArray aDimensions;
+  Handle_TDataStd_Comment aFormat;
+  if (myLab.FindAttribute(TDataStd_ByteArray::GetID(), aByteArray) == Standard_True &&
+      myLab.FindAttribute(TDataStd_IntegerArray::GetID(), aDimensions) == Standard_True &&
+      myLab.FindAttribute(TDataStd_Comment::GetID(), aFormat) == Standard_True) {
+
+    // Dimensions
+    theWidth  = aDimensions->Value(0);
+    theHeight = aDimensions->Value(1);
+
+    // Texture
+    const Handle(TColStd_HArray1OfByte) byteArray = aByteArray->InternalArray();
+    for (int j = byteArray->Lower(); j <= byteArray->Upper(); j++) {
+      theByteArray.push_back((unsigned char)byteArray->Value( j ));
+    }
+
+    // Format
+    theFormat = TCollection_AsciiString(aFormat->Get()).ToCString();
+    return true;
+  }
+
+  return false;
+}
+
+void Model_AttributeImage::copyTo(AttributeImagePtr theTarget) const
+{
+  std::shared_ptr<Model_AttributeImage> aTarget =
+    std::dynamic_pointer_cast<Model_AttributeImage>(theTarget);
+  if (aTarget) {
+    //Model_AttributeSelectionList::copyAttrs(myLab, aTarget->myLab);
+    TDF_CopyLabel aCopyAlgo (myLab, aTarget->myLab);
+    aCopyAlgo.Perform();
+    aTarget->reinit();
+  }
+}
+
+Model_AttributeImage::Model_AttributeImage(TDF_Label& theLabel)
+{
+  myLab = theLabel;
+  reinit();
+}
+
+void Model_AttributeImage::reinit()
+{
+  myIsInitialized = myLab.IsAttribute(TDataStd_ByteArray::GetID());
+}
diff --git a/src/Model/Model_AttributeImage.h b/src/Model/Model_AttributeImage.h
new file mode 100644 (file)
index 0000000..c4827c3
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright (C) 2014-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
+//
+
+#ifndef MODEL_ATTRIBUTEIMAGE_H_
+#define MODEL_ATTRIBUTEIMAGE_H_
+
+#include <Model.h>
+#include <ModelAPI_AttributeImage.h>
+
+#include <TDF_Label.hxx>
+
+#include <string>
+
+/**\class Model_AttributeImage
+ * \ingroup DataModel
+ * \brief API for the attribute that contains image inside.
+ * Represented as the following OCCT attributes:
+ *   TDataStd_ByteArray for the pixmap texture data,
+ *   TDataStd_IntArray(2) for image dimensions (widht and height),
+ *   TDataStd_String for image format.
+ */
+
+class Model_AttributeImage : public ModelAPI_AttributeImage
+{
+  /// Stores the label as the only reference to all data
+  TDF_Label myLab;
+
+ public:
+  /// Defines the value of the image attribute
+  MODEL_EXPORT virtual void setTexture(const int theWidth,
+                                       const int theHeight,
+                                       const std::list<unsigned char>& theByteArray,
+                                       const std::string& theFormat,
+                                       const bool sendUpdated = true);
+
+  /// Returns true, if texture width and height are non-zero
+  MODEL_EXPORT virtual bool hasTexture();
+
+  /// Returns the value of the image attribute
+  MODEL_EXPORT virtual bool texture(int& theWidth,
+                                    int& theHeight,
+                                    std::list<unsigned char>& theByteArray,
+                                    std::string& theFormat);
+
+  /// Copy the image data to the destination attribute
+  virtual void copyTo(std::shared_ptr<ModelAPI_AttributeImage> theTarget) const;
+
+ protected:
+  /// Initializes attibutes
+  Model_AttributeImage(TDF_Label& theLabel);
+  /// Reinitializes the internal state of the attribute (may be needed on undo/redo, abort, etc)
+  virtual void reinit();
+
+  friend class Model_Data;
+};
+
+#endif
index 817a9e40748f4980aef590fc39720b5c909720b4..599c65086de002cf852adf1a1cfbbabb7747bca0 100644 (file)
@@ -32,6 +32,7 @@
 #include <Model_AttributeSelection.h>
 #include <Model_AttributeSelectionList.h>
 #include <Model_AttributeIntArray.h>
+#include <Model_AttributeImage.h>
 #include <Model_AttributeTables.h>
 #include <Model_Events.h>
 #include <Model_Expression.h>
@@ -218,6 +219,8 @@ AttributePtr Model_Data::addAttribute(
     anAttr = new Model_AttributeDoubleArray(anAttrLab);
   } else if (theAttrType == ModelAPI_AttributeTables::typeId()) {
     anAttr = new Model_AttributeTables(anAttrLab);
+  } else if (theAttrType == ModelAPI_AttributeImage::typeId()) {
+    anAttr = new Model_AttributeImage(anAttrLab);
   }
   // create also GeomData attributes here because only here the OCAF structure is known
   else if (theAttrType == GeomData_Point::typeId()) {
@@ -375,6 +378,7 @@ GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeRefAttrList, refattrlist);
 GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeIntArray, intArray);
 GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeDoubleArray, realArray);
 GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeTables, tables);
+GET_ATTRIBUTE_BY_ID(ModelAPI_AttributeImage, image);
 
 std::shared_ptr<ModelAPI_Attribute> Model_Data::attribute(const std::string& theID)
 {
index df833acc0398bf38b4d7b034c999f37988d02859..bb073eb11670639296035f1e1ed7c34628c90071 100644 (file)
@@ -33,6 +33,7 @@
 #include <ModelAPI_AttributeString.h>
 #include <ModelAPI_AttributeStringArray.h>
 #include <ModelAPI_AttributeIntArray.h>
+#include <ModelAPI_AttributeImage.h>
 #include <ModelAPI_Data.h>
 #include <ModelAPI_Feature.h>
 #include <ModelAPI_Folder.h>
@@ -155,6 +156,9 @@ class Model_Data : public ModelAPI_Data
   /// Returns the attribute that contains string values array
   MODEL_EXPORT virtual std::shared_ptr<ModelAPI_AttributeTables>
     tables(const std::string& theID);
+  /// Returns the attribute that contains image
+  MODEL_EXPORT virtual std::shared_ptr<ModelAPI_AttributeImage>
+    image(const std::string& theID);
 
   /// Returns the generic attribute by identifier
   /// \param theID identifier of the attribute
index 65b6875199c997886a06a605ee861c22e17bae7b..32f439df6eb855bfaf734af293e3bcb85b68331d 100644 (file)
@@ -26,6 +26,7 @@
 #include <ModelAPI_Object.h>
 #include <ModelAPI_Events.h>
 #include <ModelAPI_Tools.h>
+#include <ModelAPI_AttributeImage.h>
 #include <Model_Data.h>
 #include <Events_Loop.h>
 #include <GeomAPI_ShapeIterator.h>
@@ -56,6 +57,13 @@ Model_ResultBody::~Model_ResultBody()
   delete myBuilder;
 }
 
+void Model_ResultBody::initAttributes()
+{
+  ModelAPI_Result::initAttributes();
+  // append the image attribute. It is empty, the attribute will be filled by a request
+  data()->addAttribute(IMAGE_ID(), ModelAPI_AttributeImage::typeId())->setIsArgument(false);
+}
+
 bool Model_ResultBody::generated(const GeomShapePtr& theNewShape,
   const std::string& theName, const bool theCheckIsInResult)
 {
@@ -408,17 +416,6 @@ void Model_ResultBody::updateSubs(
   myHistoryCash.Clear();
 }
 
-void  Model_ResultBody::setTextureFile(const std::string & theTextureFile)
-{
-  ModelAPI_Result::setTextureFile(theTextureFile);
-  for( auto sub : mySubs){
-    sub->setTextureFile(theTextureFile);
-  }
-  for(auto map : mySubsMap){
-    map.first->setTextureFile(theTextureFile);
-  }
-}
-
 bool Model_ResultBody::isConnectedTopology()
 {
   TDF_Label aDataLab = std::dynamic_pointer_cast<Model_Data>(data())->label();
@@ -448,6 +445,16 @@ void Model_ResultBody::cleanCash()
   }
 }
 
+bool Model_ResultBody::hasTexture()
+{
+  AttributeImagePtr anImageAttr =
+    data()->image(ModelAPI_ResultBody::IMAGE_ID());
+  if (anImageAttr.get()) {
+    return anImageAttr->hasTexture();
+  }
+  return false;
+}
+
 // adds to the theSubSubs map all sub-shapes of theSub if it is compound of compsolid
 static void collectSubs(
   const GeomShapePtr theSub, TopTools_MapOfShape& theSubSubs, const bool theOneLevelMore)
index 721312c3aa9e8b4d7e6fe2e7a1c5a2139fa8972a..4a8479af50ad1610cb8d9e5b1c64951b576134c4 100644 (file)
@@ -58,6 +58,9 @@ public:
   /// Removes the stored builders
   MODEL_EXPORT virtual ~Model_ResultBody();
 
+  /// Request for initialization of data model of the result body: adding all attributes
+  virtual void initAttributes();
+
   /// Records the subshape newShape which was generated during a topological construction.
   /// As an example, consider the case of a face generated in construction of a box.
   MODEL_EXPORT virtual bool generated(const GeomShapePtr& theNewShape,
@@ -114,7 +117,7 @@ public:
   MODEL_EXPORT virtual void cleanCash() override;
 
   /// sets the texture file
-  MODEL_EXPORT virtual void  setTextureFile(const std::string & theTextureFile) override;
+  MODEL_EXPORT virtual bool hasTexture() override;
 
 
 protected:
index d2d565eee5fcf6aede037889cb2cbc3906c8c5de..bbef9d3e562ad4390e368ce668b93c7ef8edb3e0 100644 (file)
@@ -26,6 +26,7 @@ SET(PROJECT_HEADERS
     ModelAPI.h
     ModelAPI_Attribute.h
     ModelAPI_AttributeBoolean.h
+    ModelAPI_AttributeImage.h
     ModelAPI_AttributeIntArray.h
     ModelAPI_AttributeDocRef.h
     ModelAPI_AttributeDouble.h
@@ -74,6 +75,7 @@ SET(PROJECT_HEADERS
 SET(PROJECT_SOURCES
     ModelAPI_Attribute.cpp
     ModelAPI_AttributeBoolean.cpp
+    ModelAPI_AttributeImage.cpp
     ModelAPI_AttributeIntArray.cpp
     ModelAPI_AttributeDocRef.cpp
     ModelAPI_AttributeDouble.cpp
diff --git a/src/ModelAPI/ModelAPI_AttributeImage.cpp b/src/ModelAPI/ModelAPI_AttributeImage.cpp
new file mode 100644 (file)
index 0000000..4caea45
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright (C) 2014-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
+//
+
+#include <ModelAPI_AttributeImage.h>
+
+
+std::string ModelAPI_AttributeImage::attributeType()
+{
+  return typeId();
+}
+
+/// To virtually destroy the fields of successors
+ModelAPI_AttributeImage::~ModelAPI_AttributeImage()
+{
+}
+
+ModelAPI_AttributeImage::ModelAPI_AttributeImage()
+{
+}
diff --git a/src/ModelAPI/ModelAPI_AttributeImage.h b/src/ModelAPI/ModelAPI_AttributeImage.h
new file mode 100644 (file)
index 0000000..14fc1e7
--- /dev/null
@@ -0,0 +1,78 @@
+// Copyright (C) 2014-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
+//
+
+#ifndef ModelAPI_AttributeImage_H_
+#define ModelAPI_AttributeImage_H_
+
+#include <ModelAPI.h>
+#include <ModelAPI_Attribute.h>
+
+#include <string>
+#include <list>
+
+
+/**\class ModelAPI_AttributeImage
+ * \ingroup DataModel
+ * \brief API for the attribute that contains binary data.
+ * Used for images storage for an example. By default size is one, zero-based.
+ */
+
+class ModelAPI_AttributeImage : public ModelAPI_Attribute
+{
+ public:
+  /// Defines the value of the image attribute
+  MODELAPI_EXPORT virtual void setTexture(const int theWidth,
+                                          const int theHeight,
+                                          const std::list<unsigned char>& theByteArray,
+                                          const std::string& theFormat,
+                                          const bool sendUpdated = true) = 0;
+
+  /// Returns true, if texture width and height are non-zero
+  MODELAPI_EXPORT virtual bool hasTexture() = 0;
+
+  /// Returns the value of the image attribute
+  MODELAPI_EXPORT virtual bool texture(int& theWidth,
+                                       int& theHeight,
+                                       std::list<unsigned char>& theByteArray,
+                                       std::string& theFormat) = 0;
+
+  /// Copy the image data to the destination attribute
+  virtual void copyTo(std::shared_ptr<ModelAPI_AttributeImage> theTarget) const = 0;
+
+  /// Returns the type of this class of attributes
+  MODELAPI_EXPORT static std::string typeId()
+  {
+    return "Image";
+  }
+
+  /// Returns the type of this class of attributes, not static method
+  MODELAPI_EXPORT virtual std::string attributeType();
+
+  /// To virtually destroy the fields of successors
+  MODELAPI_EXPORT virtual ~ModelAPI_AttributeImage();
+
+ protected:
+  /// Objects are created for features automatically
+  MODELAPI_EXPORT ModelAPI_AttributeImage();
+};
+
+//! Pointer on image attribute
+typedef std::shared_ptr<ModelAPI_AttributeImage> AttributeImagePtr;
+
+#endif
index a8f22355ed18314af7bfb3191c2cc0e4b65fbe0b..a5907974a5f38de9440768be773e660aa9bd3b0e 100644 (file)
@@ -48,6 +48,7 @@ class ModelAPI_Feature;
 class ModelAPI_AttributeSelection;
 class ModelAPI_AttributeSelectionList;
 class ModelAPI_AttributeIntArray;
+class ModelAPI_AttributeImage;
 class ModelAPI_AttributeTables;
 class ModelAPI_Object;
 class GeomAPI_Shape;
@@ -113,6 +114,8 @@ class MODELAPI_EXPORT ModelAPI_Data
   virtual std::shared_ptr<ModelAPI_AttributeIntArray> intArray(const std::string& theID) = 0;
   /// Returns the attribute that contains string values array
   virtual std::shared_ptr<ModelAPI_AttributeStringArray> stringArray(const std::string& theID) = 0;
+  /// Returns the attribute that contains image
+  virtual std::shared_ptr<ModelAPI_AttributeImage> image(const std::string& theID) = 0;
   /// Returns the attribute that contains tables
   virtual std::shared_ptr<ModelAPI_AttributeTables> tables(const std::string& theID) = 0;
 
index a340738947572f535e9d55289a1a4535796a38d6..82d4c8e22b51c624ad164f7085c5678c384efd5d 100644 (file)
@@ -189,7 +189,8 @@ const std::string& ModelAPI_ParameterEvalMessage::error() const
 }
 
 /// Creates an empty message
-ModelAPI_ImportParametersMessage::ModelAPI_ImportParametersMessage(const Events_ID theID, const void* theSender)
+ModelAPI_ImportParametersMessage::ModelAPI_ImportParametersMessage(const Events_ID theID,
+                                                                   const void* theSender)
   :Events_Message(theID, theSender)
 {
 
index b32ef747ff9b53c812fb4fde4392db28b9ca209e..247f51bc3cb1422429b60b19077425c8d8a4d466 100644 (file)
@@ -382,7 +382,8 @@ public:
   }
 
   /// Creates an empty message
-  MODELAPI_EXPORT ModelAPI_ImportParametersMessage(const Events_ID theID, const void* theSender = 0);
+  MODELAPI_EXPORT ModelAPI_ImportParametersMessage(const Events_ID theID,
+                                                   const void* theSender = 0);
   /// The virtual destructor
   MODELAPI_EXPORT virtual ~ModelAPI_ImportParametersMessage();
 
index 5710af6f9839546320416ab988dd4c14f19be69b..32e48bc40307cfd422788805c9af036950e41d10 100644 (file)
@@ -45,7 +45,6 @@ class ModelAPI_Object: public ModelAPI_Entity
 {
   std::shared_ptr<ModelAPI_Data> myData;  ///< manager of the data model of a feature
   std::shared_ptr<ModelAPI_Document> myDoc;  ///< document this object belongs to
-  std::string textureFile = "";
  public:
 #ifdef DEBUG_NAMES
   std::wstring myName; // name of this object
@@ -101,19 +100,9 @@ class ModelAPI_Object: public ModelAPI_Entity
   /// signal.
   MODELAPI_EXPORT virtual void setDisplayed(const bool theDisplay);
 
-  MODELAPI_EXPORT bool hasTextureFile()
+  MODELAPI_EXPORT virtual bool hasTexture()
   {
-    return (textureFile != "");
-  }
-
-  MODELAPI_EXPORT virtual void setTextureFile(const std::string & theTextureFile)
-  {
-    textureFile = theTextureFile;
-  }
-
-  MODELAPI_EXPORT const std::string & getTextureFile()
-  {
-    return  textureFile;
+    return false;
   }
 
  protected:
index 05e48d1deb66feed0542ffc4effa3b13c2b84b55..1fc3c1ab8aa0721211db278fbe322f111255ec33 100644 (file)
@@ -39,7 +39,7 @@ class ModelAPI_Result : public ModelAPI_Object
  public:
 
   /// Reference to the color of the result.
-  /// The integer array is used. It contains tree values for red green and blue values.
+  /// The integer array is used. It contains three values for red, green and blue values.
   /// The values are in [0, 255] range
   inline static const std::string& COLOR_ID()
   {
index 5c19f711ccd2c2f7ec8c8e7f163cec4aa87b8ab9..ec323ac28d3cc32c090cfa2912f2ba6ce833c6da 100644 (file)
@@ -58,6 +58,13 @@ protected:
 public:
   MODELAPI_EXPORT virtual ~ModelAPI_ResultBody();
 
+  /// Reference to the image attribute of the result body.
+  inline static const std::string& IMAGE_ID()
+  {
+    static const std::string MY_IMAGE_ID("Image");
+    return MY_IMAGE_ID;
+  }
+
   /// Returns the group identifier of this result
   MODELAPI_EXPORT virtual std::string groupName();
 
index 5db4588bbc9c4f8bed20a6cb8b81cf701567d112..282a40de4e74c423ab8ba172ca5c74005c9c1706 100644 (file)
@@ -20,6 +20,7 @@
 #include <ModelAPI_AttributeBoolean.h>
 #include <ModelAPI_AttributeDocRef.h>
 #include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeImage.h>
 #include <ModelAPI_AttributeIntArray.h>
 #include <ModelAPI_AttributeSelectionList.h>
 #include <ModelAPI_CompositeFeature.h>
@@ -42,6 +43,7 @@
 #include <GeomAlgoAPI_MakeShape.h>
 #include <GeomAPI_ShapeHierarchy.h>
 #include <GeomAPI_ShapeIterator.h>
+#include <GeomAPI_ShapeExplorer.h>
 
 #include <algorithm>
 #include <iostream>
@@ -353,6 +355,95 @@ bool findVariable(FeaturePtr theSearcher, const std::wstring& theName, double& o
   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
@@ -1145,6 +1236,30 @@ void copyVisualizationAttrs(
   }
 }
 
+
+void copyImageAttribute (std::shared_ptr<ModelAPI_Result> theSource,
+                         std::shared_ptr<ModelAPI_Result> theDest)
+{
+  if (!theSource.get() || !theDest.get())
+    return;
+
+  // images allowed only for ResultBody
+  ResultBodyPtr aSourceBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(theSource);
+  ResultBodyPtr aDestBody   = std::dynamic_pointer_cast<ModelAPI_ResultBody>(theDest);
+  if (!aSourceBody.get() || !aDestBody.get())
+    return;
+
+  AttributeImagePtr aSourceImage =
+    theSource->data()->image(ModelAPI_ResultBody::IMAGE_ID());
+  if (aSourceImage.get() && aSourceImage->hasTexture()) {
+    AttributeImagePtr aDestImage =
+      theDest->data()->image(ModelAPI_ResultBody::IMAGE_ID());
+    if (aDestImage.get()) {
+      aSourceImage->copyTo(aDestImage);
+    }
+  }
+}
+
 std::list<FeaturePtr> referencedFeatures(
   std::shared_ptr<ModelAPI_Result> theTarget, const std::string& theFeatureKind,
   const bool theSortResults)
index 29f6554845cfe8a9b6bda6dea97a4756d95992d2..904b82132671fdd1dc329b2ed8d697ff6fcf7f40 100644 (file)
@@ -21,6 +21,7 @@
 #define ModelAPI_Tools_HeaderFile
 
 #include "ModelAPI.h"
+#include <ModelAPI_AttributeSelectionList.h>
 
 class ModelAPI_CompositeFeature;
 class ModelAPI_Document;
@@ -324,6 +325,13 @@ MODELAPI_EXPORT void setTransparency(std::shared_ptr<ModelAPI_Result> theResult,
 MODELAPI_EXPORT void copyVisualizationAttrs(std::shared_ptr<ModelAPI_Result> theSource,
                                             std::shared_ptr<ModelAPI_Result> theDest);
 
+/*! Copies image attribute from one result to another.
+* \param theSource a result that contains the image data
+* \param theDest a destination result that takes the image data
+*/
+MODELAPI_EXPORT void copyImageAttribute(std::shared_ptr<ModelAPI_Result> theSource,
+                                        std::shared_ptr<ModelAPI_Result> theDest);
+
 /*! Produces list of features that reference to the given target (directly or through sub-results)
 * \param theTarget the referenced result
 * \param theFeatureKind the resulting features filter: the feature kind or all for the empty string
@@ -333,6 +341,12 @@ MODELAPI_EXPORT std::list<std::shared_ptr<ModelAPI_Feature> > referencedFeatures
   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.
index 2d7a4917f409303906b8799b958bb677e1280eaf..07adac9db8d19c84f9c7306795022b79a9b61202 100644 (file)
@@ -58,6 +58,7 @@ SET(PROJECT_LIBRARIES
   Locale
   ModelAPI
   ModelGeomAlgo
+  ModuleBase
 )
 
 ADD_DEFINITIONS(-DMODELHIGHAPI_EXPORTS -DWNT)
@@ -87,6 +88,7 @@ INCLUDE_DIRECTORIES(
   ${PROJECT_SOURCE_DIR}/src/Locale
   ${PROJECT_SOURCE_DIR}/src/ModelAPI
   ${PROJECT_SOURCE_DIR}/src/ModelGeomAlgo
+  ${PROJECT_SOURCE_DIR}/src/ModuleBase
   ${PROJECT_SOURCE_DIR}/src/PartSetPlugin
   ${OpenCASCADE_INCLUDE_DIR}
 )
index a75680380e72cca06af2ee71beb62b0662960ab5..f4dca43a2b0379cdd4337ebe892f8fc07484a1f6 100644 (file)
@@ -169,6 +169,14 @@ public:
   MODELHIGHAPI_EXPORT
   bool process(const std::shared_ptr<ModelAPI_Document>& theDoc, const std::string& theFileName);
 
+  /// Keep path to the true dumping directory.
+  /// It is used to store image files or any other external files
+  /// \param theDumpDir path to the true dumping directory
+  MODELHIGHAPI_EXPORT
+  void setDumpDir(const std::string& theDumpDir) { myDumpDir = theDumpDir; }
+  /// Return path to the true dumping directory
+  MODELHIGHAPI_EXPORT std::string getDumpDir() const { return myDumpDir; }
+
   /// Add module to list of imported modules
   /// \param theModuleName  name of the module to be imported
   MODELHIGHAPI_EXPORT
@@ -455,6 +463,8 @@ private:
   std::list<EntityPtr> myPostponed; ///< list of postponed entities (sketch constraints or folders)
   bool myDumpPostponedInProgress; ///< processing postponed is in progress
 
+  std::string myDumpDir;
+
 protected:
   /// list of entities, used by other features but not dumped yet
   std::set<EntityPtr> myNotDumpedEntities;
index 330e61fe192eafd8ba630c2cdce03760d4d2a70c..993defc44076672bb40dffde4f813df98ca6d827 100644 (file)
@@ -241,7 +241,12 @@ std::string ModelHighAPI_FeatureStore::dumpAttr(const AttributePtr& theAttr) {
   } else if (aType == ModelAPI_AttributeString::typeId()) {
     AttributeStringPtr anAttr = std::dynamic_pointer_cast<ModelAPI_AttributeString>(theAttr);
     // do not dump solver DOF for sketch as it may be changed unexpectedly
-    if(anAttr->id() == "SolverDOF") {
+    if (anAttr->id() == "SolverDOF") {
+      return "";
+    }
+    // do not dump file path for Image as it is changed after DumpPython
+    if (aFeatOwner->getKind() == "ImportImage" &&
+        anAttr->id() == "file_path") {
       return "";
     }
     aResult<<anAttr->value();
index 82423fb0b0a73b1a0015897120366c0c0de82c4d..bd87cd0e40ac30231357e3966ce5ba932d4b6f11 100644 (file)
@@ -82,7 +82,7 @@ void ModelHighAPI_Interface::execute(bool isForce)
   Events_Loop* aLoop = Events_Loop::loop();
   aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
   aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
-  //aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
+  aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
   //aLoop->flush(Events_Loop::eventByName(EVENT_OBJECT_DELETED));
 }
 
index 3b45898cdc9cbef594502ea371f7e3193bff3abd..6c80257386eede809c6bb64829b64d2278d031e4 100644 (file)
@@ -235,7 +235,7 @@ void ModelHighAPI_Selection::setColor(int theRed, int theGreen, int theBlue, boo
 
 void ModelHighAPI_Selection::setDeflection(double theValue)
 {
-  if (myVariantType != VT_ResultSubShapePair)
+  if (myVariantType != VT_ResultSubShapePair || !myResultSubShapePair.first.get())
     return;
 
   AttributeDoublePtr aDeflectionAttr =
@@ -247,7 +247,7 @@ void ModelHighAPI_Selection::setDeflection(double theValue)
 // LCOV_EXCL_START
 void ModelHighAPI_Selection::setTransparency(double theValue)
 {
-  if (myVariantType != VT_ResultSubShapePair)
+  if (myVariantType != VT_ResultSubShapePair || !myResultSubShapePair.first.get())
     return;
 
   AttributeDoublePtr aTransparencyAttr =
index 09dea983c9743077e5e0a2631f7588b8d54b8e49..763798c8b72bb35dcdc2f8b60b64ba5f24112ece 100644 (file)
@@ -26,6 +26,8 @@
 #include <ModelAPI_ResultConstruction.h>
 #include <ModelAPI_Events.h>
 
+#include <ModuleBase_Tools.h>
+
 #include <cmath>
 #include <sstream>
 
@@ -106,8 +108,9 @@ void begin()
     aNbTransactions = aNbUndo;
     ++aTransactionID;
   }
+  static std::string anOperationPrefix(ModuleBase_Tools::translate("", "Operation").toStdString());
   std::ostringstream aTransactionName;
-  aTransactionName << "Operation_" << aTransactionID;
+  aTransactionName << anOperationPrefix << "_" << aTransactionID;
   ModelAPI_Session::get()->startOperation(aTransactionName.str());
 }
 
index 14ab9887894f1c487822341e04a9d81b46a10bc9..89f61b480228a57056086ce65d2cf058bf440204 100644 (file)
@@ -29,6 +29,8 @@
 #include <GeomDataAPI_Point2D.h>
 #include <GeomDataAPI_Point2DArray.h>
 //--------------------------------------------------------------------------------------
+#include <GeomAlgoAPI_Tools.h>
+//--------------------------------------------------------------------------------------
 #include <Locale_Convert.h>
 //--------------------------------------------------------------------------------------
 #include <ModelAPI_AttributeBoolean.h>
@@ -529,6 +531,8 @@ static bool dumpToPython(SessionPtr theSession,
   if (aDump.get()) {
     aDump->string("file_path")->setValue(theFilename);
     aDump->string("file_format")->setValue("py");
+    std::string aTrek = GeomAlgoAPI_Tools::File_Tools::path(theFilename);
+    aDump->string("dump_dir")->setValue(aTrek);
     aDump->boolean("topological_naming")->setValue((theSelectionType & CHECK_NAMING) != 0);
     aDump->boolean("geometric_selection")->setValue((theSelectionType & CHECK_GEOMETRICAL) != 0);
     aDump->boolean("weak_naming")->setValue((theSelectionType & CHECK_WEAK) != 0);
index c651c7d46f36cc16d515bef47f77f074df6091a6..229603f834503abe506ae7dbab73070b643a1c3c 100644 (file)
@@ -35,6 +35,7 @@
 
 const QString ModuleBase_Preferences::VIEWER_SECTION = "Viewer";
 const QString ModuleBase_Preferences::MENU_SECTION = "Menu";
+const QString ModuleBase_Preferences::GENERAL_SECTION = "General";
 
 SUIT_ResourceMgr* ModuleBase_Preferences::myResourceMgr = 0;
 
@@ -115,6 +116,7 @@ void ModuleBase_Preferences::loadCustomProps()
 void ModuleBase_Preferences::createEditContent(ModuleBase_IPrefMgr* thePref, int thePage)
 {
   thePref->prefMgr()->setItemIcon(thePage, QIcon(":pictures/module.png"));
+  createGeneralTab(thePref, thePage);
   createCustomPage(thePref, thePage);
 }
 
@@ -150,6 +152,64 @@ void ModuleBase_Preferences::resetConfigPropPreferences(SUIT_PreferenceMgr* theP
   }
 }
 
+void ModuleBase_Preferences::createGeneralTab(ModuleBase_IPrefMgr* thePref, int thePageId)
+{
+  int generalTab = thePref->addPreference(QObject::tr("General"), thePageId,
+                                          SUIT_PreferenceMgr::Auto, QString(), QString());
+  thePref->setItemProperty("columns", 2, generalTab);
+
+  QStringList actItemList;
+  actItemList << QObject::tr("Last part")
+              << QObject::tr("All parts")
+              << QObject::tr("No activation");
+
+  QList<QVariant> actIdList;
+  actIdList << 0 << 1 << 2;
+
+  // Group related to opening a study
+  int group = thePref->addPreference(QObject::tr("Opening a study"), generalTab,
+                                     SUIT_PreferenceMgr::Auto, QString(), QString());
+
+  int actId = thePref->addPreference(QObject::tr("Activate"), group, SUIT_PreferenceMgr::Selector,
+                                     ModuleBase_Preferences::GENERAL_SECTION,
+                                     "part_activation_study");
+  thePref->setItemProperty("strings", actItemList, actId);
+  thePref->setItemProperty("indexes", actIdList, actId);
+
+  QStringList visuItemList;
+  visuItemList << QObject::tr("As stored in HDF")
+               << QObject::tr("Last item in each folder")
+               << QObject::tr("All items")
+               << QObject::tr("No visualization");
+
+  QList<QVariant> visuIdList;
+  visuIdList << 0 << 1 << 2 << 3;
+
+  int visuId = thePref->addPreference(QObject::tr("Display"), group, SUIT_PreferenceMgr::Selector,
+                                      ModuleBase_Preferences::GENERAL_SECTION,
+                                      "part_visualization_study");
+  thePref->setItemProperty("strings", visuItemList, visuId);
+  thePref->setItemProperty("indexes", visuIdList, visuId);
+
+  // Group related to running a python script
+  group = thePref->addPreference(QObject::tr("Launching a python script"), generalTab,
+                                 SUIT_PreferenceMgr::Auto, QString(), QString());
+
+  visuItemList.clear();
+  visuItemList << QObject::tr("Last item in each folder")
+               << QObject::tr("All items")
+               << QObject::tr("No visualization");
+
+  visuIdList.clear();
+  visuIdList << 0 << 1 << 2;
+
+  visuId = thePref->addPreference(QObject::tr("Display"), group, SUIT_PreferenceMgr::Selector,
+                                  ModuleBase_Preferences::GENERAL_SECTION,
+                                  "part_visualization_script");
+  thePref->setItemProperty("strings", visuItemList, visuId);
+  thePref->setItemProperty("indexes", visuIdList, visuId);
+}
+
 void ModuleBase_Preferences::createCustomPage(ModuleBase_IPrefMgr* thePref, int thePageId)
 {
   SUIT_ResourceMgr* aResMgr = ModuleBase_Preferences::resourceMgr();
index 9852625692d79526381c222bd0382a0d074d739f..65b2a2d7a748c3428e8fe708514061b9fd919588 100644 (file)
@@ -47,6 +47,9 @@ class MODULEBASE_EXPORT ModuleBase_Preferences
    /// Name of preferences of menu section
   static const QString MENU_SECTION;
 
+  /// Name of preferences of general section
+  static const QString GENERAL_SECTION;
+
   /// Shows a dialog box to edit preferences
   /// \param theModified a list of modified preferences
   static bool editPreferences(ModuleBase_Prefs& theModified);
@@ -83,6 +86,9 @@ private:
   /// Set default values to the Config_PropManager properties
   static void resetConfig();
 
+  /// Creates a content for General tab, which defines behavior of loading parts and displaying shapes
+  static void createGeneralTab(ModuleBase_IPrefMgr* thePref, int thePageId);
+
   /// Creates content of preferences editing widget
   static void createCustomPage(ModuleBase_IPrefMgr* thePref, int thePageId);
 
index b014d60deff7189df0f53bbd2d824ffcc4dd917c..15b389749ff588f6b9326a0e539b46308c99203a 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <ModuleBase_ParamIntSpinBox.h>
 #include <ModuleBase_ParamSpinBox.h>
+#include <ModuleBase_Preferences.h>
 #include <ModuleBase_WidgetFactory.h>
 #include <ModuleBase_IWorkshop.h>
 #include <ModuleBase_IModule.h>
@@ -36,6 +37,7 @@
 #include <ModelAPI_AttributeSelectionList.h>
 #include <ModelAPI_AttributeRefList.h>
 #include <ModelAPI_AttributeRefAttrList.h>
+#include <ModelAPI_ResultGroup.h>
 #include <ModelAPI_ResultPart.h>
 #include <ModelAPI_ResultConstruction.h>
 #include <ModelAPI_AttributeString.h>
 
 #include <ModelGeomAlgo_Point2D.h>
 
+#ifdef HAVE_SALOME
+#include <SUIT_Application.h>
+#include <SUIT_ResourceMgr.h>
+#include <SUIT_Session.h>
+#endif
+
 #include <StdSelect_BRepOwner.hxx>
 #include <TopoDS_Iterator.hxx>
 #include <AIS_InteractiveContext.hxx>
@@ -108,6 +116,56 @@ namespace ModuleBase_Tools {
 
 //******************************************************************
 
+  //! Waits for REDISPLAY message and set the Visible flag to the entities
+  //! according to Preferences choice.
+  class ModuleBase_RedisplayListener : public Events_Listener
+  {
+  public:
+    static std::shared_ptr<ModuleBase_RedisplayListener> instance()
+    {
+      static std::shared_ptr<ModuleBase_RedisplayListener>
+          anInstance(new ModuleBase_RedisplayListener);
+      return anInstance;
+    }
+
+    void processEvent(const std::shared_ptr<Events_Message>& theMessage)
+    {
+      if (theMessage->eventID() == Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY))
+      {
+#if HAVE_SALOME
+        // If the python script is being loaded now, the preferences should be used
+        // to display the required object
+        SUIT_Session* aSession = SUIT_Session::session();
+        if (!aSession)
+          return;
+        SUIT_Application * anApp = aSession->activeApplication();
+        if (!anApp)
+          return;
+        QVariant aVar = anApp->property("IsLoadedScript");
+        if (!aVar.isNull() && aVar.toBool()) {
+          DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
+          int aSize = aRootDoc->size(ModelAPI_ResultPart::group());
+          if (aSize > 0) {
+            ObjectPtr anPartObject = aRootDoc->object(ModelAPI_ResultPart::group(), aSize - 1);
+            ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(anPartObject);
+            ModuleBase_Tools::setDisplaying(aPart, true);
+          }
+        }
+#endif
+      }
+    }
+
+  private:
+    ModuleBase_RedisplayListener()
+    {
+      Events_Loop::loop()->registerListener(this,
+          Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
+    }
+  };
+
+  static std::shared_ptr<ModuleBase_RedisplayListener>
+      RL = ModuleBase_RedisplayListener::instance();
+
 //******************************************************************
 
 void adjustMargins(QWidget* theWidget)
@@ -1342,6 +1400,46 @@ qreal currentPixelRatio()
 }
 
 
+// Set displaying status to every element on group
+static void setDisplayingByLoop(DocumentPtr theDoc, int theSize,
+  std::string theGroup, bool theDisplayFromScript)
+{
+  int aDisplayingId = -1;
+  if (theDisplayFromScript) {
+    aDisplayingId = ModuleBase_Preferences::resourceMgr()->integerValue("General",
+      "part_visualization_script", -1);
+    // Increase ID to prevert using "As stored in HDF"
+    ++aDisplayingId;
+  }
+  else {
+    aDisplayingId = ModuleBase_Preferences::resourceMgr()->integerValue("General",
+      "part_visualization_study", -1);
+
+    // if chosen "As stored in HDF" then don't change displaying
+    if (aDisplayingId == 0)
+      return;
+  }
+
+  for (int anIndex = theSize - 1; anIndex >= 0; --anIndex) {
+    ObjectPtr anObject = theDoc->object(theGroup, anIndex);
+    anObject->setDisplayed((aDisplayingId == 1 && anIndex == theSize - 1) || aDisplayingId == 2);
+  }
+}
+
+void setDisplaying(ResultPartPtr thePart, bool theDisplayFromScript)
+{
+  DocumentPtr aDoc = thePart->partDoc();
+  int aConstructionSize = aDoc->size(ModelAPI_ResultConstruction::group());
+  int aGroupSize = aDoc->size(ModelAPI_ResultGroup::group());
+  int aFieldSize = aDoc->size(ModelAPI_ResultField::group());
+  int aResultSize = aDoc->size(ModelAPI_ResultBody::group());
+  setDisplayingByLoop(aDoc, aConstructionSize,
+    ModelAPI_ResultConstruction::group(), theDisplayFromScript);
+  setDisplayingByLoop(aDoc, aGroupSize, ModelAPI_ResultGroup::group(), theDisplayFromScript);
+  setDisplayingByLoop(aDoc, aFieldSize, ModelAPI_ResultField::group(), theDisplayFromScript);
+  setDisplayingByLoop(aDoc, aResultSize, ModelAPI_ResultBody::group(), theDisplayFromScript);
+}
+
 } // namespace ModuleBase_Tools
 
 
index a68f2ee9e7f645360400b15ad5a2c7cb545b1135..cae27a1d92115896c1f223a498b840234e95a1fa 100644 (file)
@@ -406,6 +406,11 @@ std::wstring MODULEBASE_EXPORT generateName(const AttributePtr& theAttribute,
 
 /// Returns pixel ratio of a screen where main window is displayed
 qreal MODULEBASE_EXPORT currentPixelRatio();
+
+/// Set displaying status for elements from part depending on the settings
+/// \param thePart a pointer of part
+void MODULEBASE_EXPORT setDisplaying(std::shared_ptr<ModelAPI_ResultPart> thePart,
+                                     bool theDisplayFromScript = false);
 }
 
 #endif
index 050f6abb6e3cc9c6e43c98bf4061b56abd1a208b..39de141b138820c2ccda7a1cc011e7fa68faed32 100644 (file)
         <source>Replace</source>
         <translation>Remplacer</translation>
     </message>
-  <message>
-    <source>Trihedron arrows constant size</source>
-    <translation>Flèche trièdre de taille constante</translation>
-  </message>
+    <message>
+        <source>Trihedron arrows constant size</source>
+        <translation>Flèche trièdre de taille constante</translation>
+    </message>
     <message>
         <source>Keep trihedron arrows view size constant</source>
         <translation>Maintenir la taille de la vue des flèches trièdres constante</translation>
     </message>
+    <message>
+        <source>General</source>
+        <translation>Général</translation>
+    </message>
+    <message>
+        <source>Opening a study</source>
+        <translation>Ouverture d&apos;une étude</translation>
+    </message>
+    <message>
+        <source>Launching a python script</source>
+        <translation>Lancement d&apos;un script python</translation>
+    </message>
+    <message>
+        <source>Activate</source>
+        <translation>Activation</translation>
+    </message>
+    <message>
+        <source>Display</source>
+        <translation>Visualisation</translation>
+    </message>
+    <message>
+        <source>Last part</source>
+        <translation>Dernière pièce</translation>
+    </message>
+    <message>
+        <source>All parts</source>
+        <translation>Toutes les pièces</translation>
+    </message>
+    <message>
+        <source>No activation</source>
+        <translation>Aucune</translation>
+    </message>
+    <message>
+        <source>As stored in HDF</source>
+        <translation>Comme dans le HDF</translation>
+    </message>
+    <message>
+        <source>Last item in each folder</source>
+        <translation>Le dernier élément de chaque dossier</translation>
+    </message>
+    <message>
+        <source>All items</source>
+        <translation>Tous les éléments</translation>
+    </message>
+    <message>
+        <source>No visualization</source>
+        <translation>Aucune visualisation</translation>
+    </message>
 </context>
 </TS>
index 05f8d9b725e8cf81fc65da83fd4ffc3865865a1d..3da462996c5643e5b570556a05de3048e6ea63d4 100644 (file)
@@ -171,9 +171,8 @@ bool PartSet_CustomPrs::displayPresentation(
       isModified = true;
     }
     else {
-      if (myFeature->firstResult().get() && myFeature->firstResult()->hasTextureFile())
-      {
-        PartSet_Module::setTexture( myFeature->firstResult()->getTextureFile(), aPresentation);
+      if (myFeature->firstResult().get()) {
+        PartSet_Module::setTexture(aPresentation, myFeature->firstResult());
       }
       anOperationPrs->Redisplay();
       isModified = true;
index ce5f478a3d2568c9c1c740897ec72f592193c65e..b0cf3a6dc6369eb8dd15b4ed6b5ee3fe171dc09e 100644 (file)
@@ -46,6 +46,7 @@
 #include <XGUI_DataModel.h>
 #include <XGUI_OperationMgr.h>
 #include <XGUI_ObjectsBrowser.h>
+#include <XGUI_Tools.h>
 #include <XGUI_ViewerProxy.h>
 
 #include <Events_Loop.h>
@@ -495,15 +496,20 @@ void PartSet_MenuMgr::onActivatePart(bool)
 void PartSet_MenuMgr::activatePart(ResultPartPtr thePart) const
 {
   bool isFirstLoad = !thePart->partDoc().get();
+  ModuleBase_Tools::blockUpdateViewer(true);
   thePart->activate();
   if (isFirstLoad) {
     XGUI_Workshop* aWorkshop = myModule->getWorkshop();
     XGUI_ObjectsBrowser* aObjBrowser = aWorkshop->objectBrowser();
+    ModuleBase_Tools::setDisplaying(thePart);
+    Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
+    aObjBrowser->onSelectionChanged();
     DocumentPtr aDoc = thePart->partDoc();
     std::list<bool> aStates;
     aDoc->restoreNodesState(aStates);
     aObjBrowser->setStateForDoc(aDoc, aStates);
   }
+  ModuleBase_Tools::blockUpdateViewer(false);
 }
 
 void PartSet_MenuMgr::onActivateAllParts()
index 8a703fa0fd813e926275e89c47715180c84035d0..70935fa37dcf2b7ada4632aaeeb8182c8d87bebf 100644 (file)
@@ -82,6 +82,7 @@
 #include <ModelAPI_Tools.h>
 #include <ModelAPI_ResultConstruction.h>
 #include <ModelAPI_AttributeIntArray.h>
+#include <ModelAPI_AttributeImage.h>
 #include <ModelAPI_ResultGroup.h>
 #include <ModelAPI_ResultParameter.h>
 
 #include <SelectMgr_ListIteratorOfListOfFilter.hxx>
 #include <Graphic3d_Texture2Dmanual.hxx>
 
-#ifdef HAVE_SALOME
-#include <OCCViewer_Utilities.h>
-#endif
 
 #define FEATURE_ITEM_COLOR "0,0,225"
 
@@ -1408,13 +1406,46 @@ double getResultTransparency(const ResultPtr& theResult)
   return aTransparency;
 }
 
+static AttributeImagePtr findImage(const ObjectPtr& theResult)
+{
+  AttributeImagePtr anImageAttr;
+
+  if (theResult.get()) {
+    ResultBodyPtr aResultBody =
+      std::dynamic_pointer_cast<ModelAPI_ResultBody>(theResult);
+    if (aResultBody.get()) {
+      anImageAttr = aResultBody->data()->image(ModelAPI_ResultBody::IMAGE_ID());
+      if (!anImageAttr.get() || !anImageAttr->hasTexture()) {
+        // try to find an image attribute in parents
+        ObjectPtr aParent = theResult->document()->parent(theResult);
+        anImageAttr = findImage(aParent);
+      }
+    }
+  }
+
+  return anImageAttr;
+}
+
 //******************************************************
-void PartSet_Module::setTexture(const std::string & theTextureFile, const AISObjectPtr& thePrs)
+void PartSet_Module::setTexture(const AISObjectPtr& thePrs,
+                                const ResultPtr& theResult)
 {
-#ifdef HAVE_SALOME
+  ResultBodyPtr aResultBody =
+    std::dynamic_pointer_cast<ModelAPI_ResultBody>(theResult);
+  if (!aResultBody.get())
+    return;
+
+  AttributeImagePtr anImageAttr = findImage(theResult);
+  if (!anImageAttr.get() || !anImageAttr->hasTexture())
+    return;
+
+  int aWidth, aHeight;
+  std::string aFormat;
+  std::list<unsigned char> aByteList;
+  anImageAttr->texture(aWidth, aHeight, aByteList, aFormat);
+
   Handle(AIS_InteractiveObject) anAIS = thePrs->impl<Handle(AIS_InteractiveObject)>();
-  if (!anAIS.IsNull())
-  {
+  if (!anAIS.IsNull()) {
     /// set color to white and change material aspect,
     /// in order to keep a natural apect of the image.
     thePrs->setColor(255, 255, 255);
@@ -1431,11 +1462,21 @@ void PartSet_Module::setTexture(const std::string & theTextureFile, const AISObj
       myDrawer->ShadingAspect()->Aspect()->SetFrontMaterial(aMatAspect);
       myDrawer->ShadingAspect()->Aspect()->SetBackMaterial(aMatAspect);
 
-      Handle(Image_PixMap) aPixmap;
-      QPixmap px(theTextureFile.c_str());
-
-      if (!px.isNull() )
-        aPixmap = OCCViewer_Utilities::imageToPixmap( px.toImage());
+      //aPixmap = OCCViewer_Utilities::imageToPixmap( px.toImage());
+      Handle(Image_PixMap) aPixmap = new Image_PixMap();
+      aPixmap->InitTrash(Image_PixMap::ImgBGRA, aWidth, aHeight);
+      std::list<unsigned char>::iterator aByteIter = aByteList.begin();
+      for (int aLine = 0; aLine < aHeight; ++aLine) {
+        // convert pixels from ARGB to renderer-compatible RGBA
+        for (int aByte = 0; aByte < aWidth; ++aByte) {
+          Image_ColorBGRA& aPixmapBytes = aPixmap->ChangeValue<Image_ColorBGRA>(aLine, aByte);
+
+          aPixmapBytes.b() = (Standard_Byte) *aByteIter++;
+          aPixmapBytes.g() = (Standard_Byte) *aByteIter++;
+          aPixmapBytes.r() = (Standard_Byte) *aByteIter++;
+          aPixmapBytes.a() = (Standard_Byte) *aByteIter++;
+        }
+      }
 
       anAISShape->Attributes()->ShadingAspect()->Aspect()->SetTextureMap
           (new Graphic3d_Texture2Dmanual(aPixmap));
@@ -1444,7 +1485,6 @@ void PartSet_Module::setTexture(const std::string & theTextureFile, const AISObj
       anAISShape->SetDisplayMode(AIS_Shaded);
     }
   }
-#endif
 }
 
 //******************************************************
@@ -1489,10 +1529,8 @@ void PartSet_Module::customizePresentation(const ObjectPtr& theObject,
       thePrs->setDeflection(getResultDeflection(aResult));
       thePrs->setTransparency(getResultTransparency(aResult));
 
-      /// set texture  parameters
-      if(aResult->hasTextureFile()) {
-        setTexture(aResult->getTextureFile(), thePrs);
-      }
+      /// set texture parameters, if any
+      setTexture(thePrs, aResult);
     }
     if (aFeature.get() && (aFeature->getKind() == SketchPlugin_Sketch::ID())) {
         thePrs->setWidth(2);
@@ -1574,11 +1612,29 @@ void PartSet_Module::addObjectBrowserMenu(QMenu* theMenu) const
 
       } 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);
+            }
           }
         }
       }
index e47fabe9df15cb788ec4132df554431d32b3e77c..7a39b899847fb6306959c1e2b1d6873e2638b8b4 100644 (file)
@@ -400,7 +400,7 @@ public:
   virtual void createFeatures();
 
   /// add texture
-  static void setTexture(const std::string &theTextureFile, const AISObjectPtr& thePrs);
+  static void setTexture(const AISObjectPtr& thePrs, const ResultPtr& theResult);
 
 public slots:
   /// Slolt called on object display
index dab8161792d418f6694d4951da9faea858ae1b52..f8166269c8fe4051cc549c9afd937f94fa2dc547 100644 (file)
@@ -158,6 +158,17 @@ Qt::ItemFlags PartSet_ObjectNode::flags(int theColumn) const
   } 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;
   }
index 98977191721ce81398f2975809d27f9c95d57c5a..17bbb19a96f44462287d56477622a868ac862830 100644 (file)
@@ -184,6 +184,14 @@ bool SHAPERGUI_DataModel::dumpPython(const QString& thePath, CAM_Study* theStudy
   ModelAPI_Session::get()->startOperation(ExchangePlugin_Dump::ID());
   FeaturePtr aFeature = aDoc->addFeature(ExchangePlugin_Dump::ID());
   if (aFeature.get()) {
+    // keep path to the true dumping directory for external files dumping
+    AttributeStringPtr aAttr = aFeature->string(ExchangePlugin_Dump::DUMP_DIR_ID());
+    if (aAttr.get()) {
+      QString aDirPath = QFileInfo(thePath).path();
+      aAttr->setValue(aDirPath.toStdString());
+    }
+
+    // tmp path to write the script
     std::string aTmpDir = aStudy->GetTmpDir(thePath.toStdString().c_str(), isMultiFile);
     std::string aFileName = aTmpDir + DUMP_NAME;
 
@@ -191,7 +199,7 @@ bool SHAPERGUI_DataModel::dumpPython(const QString& thePath, CAM_Study* theStudy
       QFile::remove(aFileName.c_str());
     }
 
-    AttributeStringPtr aAttr = aFeature->string(ExchangePlugin_Dump::FILE_PATH_ID());
+    aAttr = aFeature->string(ExchangePlugin_Dump::FILE_PATH_ID());
     if (aAttr.get())
       aAttr->setValue(aFileName);
 
@@ -206,7 +214,7 @@ bool SHAPERGUI_DataModel::dumpPython(const QString& thePath, CAM_Study* theStudy
     ModelAPI_Session::get()->finishOperation();
 
     if (QFile::exists(aFileName.c_str())) {
-        QFile aInFile(aFileName.c_str());
+      QFile aInFile(aFileName.c_str());
       if (!aInFile.open(QIODevice::ReadOnly | QIODevice::Text))
         return false;
       QTextStream aText(&aInFile);
index 33908724f1de83403969f09bfd6e7ce62a43e555..0a0028ab87e15d8f8f2664b16057aba2e44caabc 100644 (file)
     <parameter name="PartSet" value="%SHAPER_ROOT_DIR%/share/salome/resources/shaper"/>
     <parameter name="XGUI" value="%SHAPER_ROOT_DIR%/share/salome/resources/shaper"/>
   </section>
+  <section name="General">
+    <!-- Common settings of part's activation and visualization -->
+    <parameter name="part_activation_study" value="0"/>
+    <parameter name="part_visualization_study" value="0"/>
+    <parameter name="part_visualization_script" value="1"/>
+  </section>
   <section name="Viewer" >
     <!-- Viewer preferences -->
     <parameter name="face-selection" value="true" />
index 879498824de975c3d7122204266dd0ccf6031883..94ff4fcc67ccd25b3ed3aab3eee02339243ac1aa 100644 (file)
@@ -4,6 +4,12 @@
     <parameter name="language"    value="en"/>
     <parameter name="locale"      value="true"/>
   </section>
+  <section name="General">
+    <!-- Common settings of part's activation and visualization -->
+    <parameter name="part_activation_study" value="0"/>
+    <parameter name="part_visualization_study" value="0"/>
+    <parameter name="part_visualization_script" value="1"/>
+  </section>
   <section name="Viewer" >
     <!-- Viewer preferences -->
     <parameter name="background" value="bt=2;fn=;tm=0;ts=false;c1=#cddbff;c2=#698fff;gt=1;gr=" />
index 4342023ae4653ec085b1b1636606393714314c04..f95053cbdbb8ae9961f31c07d4303b22433c2432 100644 (file)
@@ -1067,6 +1067,37 @@ void XGUI_Workshop::openFile(const QString& theDirectory)
   }
 #endif
 
+  int anActivationId =
+    ModuleBase_Preferences::resourceMgr()->integerValue("General", "part_activation_study", -1);
+  int aSize = aRootDoc->size(ModelAPI_ResultPart::group());
+
+  if (anActivationId == 0 && aSize > 0) {
+    ObjectPtr anObject = aRootDoc->object(ModelAPI_ResultPart::group(), aSize - 1);
+    ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(anObject);
+    if (aPart.get()) {
+      aPart->activate();
+      ModuleBase_Tools::setDisplaying(aPart);
+    }
+  }
+  else if (anActivationId == 1) {
+    for (int anIndex = 0; anIndex < aSize; ++anIndex) {
+      ObjectPtr anObject = aRootDoc->object(ModelAPI_ResultPart::group(), anIndex);
+      ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(anObject);
+      if (aPart.get()) {
+        aPart->activate();
+        ModuleBase_Tools::setDisplaying(aPart);
+
+        if (anIndex < aSize - 1) {
+          SessionPtr aMgr = ModelAPI_Session::get();
+          aMgr->startOperation("Activation");
+          aMgr->setActiveDocument(aMgr->moduleDocument());
+          aMgr->finishOperation();
+          updateCommandStatus();
+          viewer()->update();
+        }
+      }
+    }
+  }
   QApplication::restoreOverrideCursor();
 }
 
index b1092af83136403d6777998c1cffde2e88b4909a..34b87d99a97e4603d1f51e05ce7e9634158eb341 100644 (file)
 #include <ModuleBase_Tools.h>
 #include <ModuleBase_WidgetSelector.h>
 
+#ifdef HAVE_SALOME
+#include <SUIT_Application.h>
+#include <SUIT_Session.h>
+#endif
+
 #include "XGUI_ActionsMgr.h"
 #include "XGUI_Displayer.h"
 #include "XGUI_ErrorMgr.h"
@@ -57,7 +62,6 @@
 #include "XGUI_OperationMgr.h"
 #include "XGUI_ModuleConnector.h"
 #include "XGUI_PropertyPanel.h"
-
 #include "XGUI_QtEvents.h"
 #include "XGUI_SalomeConnector.h"
 #include "XGUI_SelectionMgr.h"
@@ -373,6 +377,7 @@ void XGUI_WorkshopListener::
       }
     }
   }
+
   // this processing should be moved in another place in order to do not cause problems in
   // flush messages chain
   //if (aHiddenObjects.size() > 0)
@@ -392,6 +397,10 @@ void XGUI_WorkshopListener::
 void XGUI_WorkshopListener::
   onFeatureCreatedMsg(const std::shared_ptr<ModelAPI_ObjectUpdatedMessage>& theMsg)
 {
+  SUIT_Application * app = SUIT_Session::session()->activeApplication();
+
+  QVariant aVar = app->property("IsLoadedScript");
+
   std::set<ObjectPtr> anObjects = theMsg->objects();
   std::set<ObjectPtr>::const_iterator aIt;
 #ifdef DEBUG_FEATURE_CREATED
@@ -406,46 +415,32 @@ void XGUI_WorkshopListener::
 
   //bool aHasPart = false;
   bool aDisplayed = false;
-  for (aIt = anObjects.begin(); aIt != anObjects.end(); ++aIt) {
-    ObjectPtr anObject = *aIt;
+  if (aVar.isNull() || !aVar.toBool()) {
+    for (aIt = anObjects.begin(); aIt != anObjects.end(); ++aIt) {
+      ObjectPtr anObject = *aIt;
 
 #ifdef DEBUG_RESULT_COMPSOLID
-    ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
-    if (aRes.get()) {
-      ResultCompSolidPtr aCompSolidRes = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(aRes);
-      if (aCompSolidRes.get()) {
-          qDebug(QString("COMPSOLID, numberOfSubs = %1")
-            .arg(aCompSolidRes->numberOfSubs()).toStdString().c_str());
+      ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
+      if (aRes.get()) {
+        ResultCompSolidPtr aCompSolidRes = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(aRes);
+        if (aCompSolidRes.get()) {
+            qDebug(QString("COMPSOLID, numberOfSubs = %1")
+              .arg(aCompSolidRes->numberOfSubs()).toStdString().c_str());
+        }
+        if (ModelAPI_Tools::compSolidOwner(aRes))
+          qDebug("COMPSOLID sub-object");
       }
-      if (ModelAPI_Tools::compSolidOwner(aRes))
-        qDebug("COMPSOLID sub-object");
-    }
 #endif
-    // the validity of the data should be checked here in order to avoid display of the objects,
-    // which were created, then deleted, but flush for the creation event happens after that
-    // we should not display disabled objects
-    bool aHide = !anObject->data()->isValid() ||
-                 anObject->isDisabled() ||
-                 !anObject->isDisplayed();
-    if (!aHide) { // check that this is not hidden result
-      ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(anObject);
-      aHide = aRes && aRes->isConcealed();
-      // Hide the presentation with an empty shape. But isDisplayed state of the object should not
-      // be changed to the object becomes visible when the shape becomes not empty
-      if (!aHide && aRes.get())
-        aHide = !aRes->shape().get() || aRes->shape()->isNull();
-    }
-    if (!aHide) {
-      // setDisplayed has to be called in order to synchronize internal state of the object
-      // with list of displayed objects
-      if (myWorkshop->module()->canDisplayObject(anObject)) {
-        anObject->setDisplayed(true);
-        aDisplayed = displayObject(anObject);
-      } else
-        anObject->setDisplayed(false);
+
+      ResultBodyPtr aRes = std::dynamic_pointer_cast<ModelAPI_ResultBody>(anObject);
+
+      if (aRes.get() && aRes->numberOfSubs() > 0)
+        for (int anIndex = 0; anIndex < aRes->numberOfSubs(); ++anIndex)
+          setDisplayed(aRes->subResult(anIndex), aDisplayed);
+      else
+        setDisplayed(anObject, aDisplayed);
     }
   }
-
   MAYBE_UNUSED bool isCustomized = customizeFeature(anObjects, aDisplayed);
 
   //if (myObjectBrowser)
@@ -558,3 +553,32 @@ XGUI_Workshop* XGUI_WorkshopListener::workshop() const
 {
   return myWorkshop;
 }
+
+
+void XGUI_WorkshopListener::setDisplayed(ObjectPtr theObject, bool& theDisplayed)
+{
+  // the validity of the data should be checked here in order to avoid display of the objects,
+  // which were created, then deleted, but flush for the creation event happens after that
+  // we should not display disabled objects
+  bool aHide = !theObject->data()->isValid() ||
+                theObject->isDisabled() ||
+               !theObject->isDisplayed();
+  if (!aHide) { // check that this is not hidden result
+    ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
+    aHide = aRes && aRes->isConcealed();
+    // Hide the presentation with an empty shape. But isDisplayed state of the object should not
+    // be changed to the object becomes visible when the shape becomes not empty
+    if (!aHide && aRes.get())
+      aHide = !aRes->shape().get() || aRes->shape()->isNull();
+  }
+  if (!aHide) {
+    // setDisplayed has to be called in order to synchronize internal state of the object
+    // with list of displayed objects
+    if (myWorkshop->module()->canDisplayObject(theObject)) {
+      theObject->setDisplayed(true);
+      theDisplayed = displayObject(theObject);
+    }
+    else
+      theObject->setDisplayed(false);
+  }
+}
index d8827d57b05f9778d333547576b13afa3b0ff36f..dcedeb713f8ab6c12a8755e602547b7db090c0a8 100644 (file)
@@ -103,6 +103,9 @@ protected:
   XGUI_Workshop* workshop() const;
 
 private:
+
+  void setDisplayed(ObjectPtr theObject, bool& theDisplayed);
+
   XGUI_Workshop* myWorkshop; // the current workshop
 
   bool myUpdatePrefs;