##
#------ SHAPER ------
-export PATH=${SHAPER_ROOT_DIR}/bin/salome:${PATH}
-export PYTHONPATH=${SHAPER_ROOT_DIR}/bin/salome:${SHAPER_ROOT_DIR}/lib/python3.6/site-packages/salome:${PYTHONPATH}
+export SHAPER_BIN_DIR=${SHAPER_ROOT_DIR}/bin/salome
+export SHAPER_PYTHON_SCRIPTS_DIR=${SHAPER_ROOT_DIR}/lib/python3.6/site-packages/salome
+export PATH=${SHAPER_BIN_DIR}:${PATH}
+export PYTHONPATH=${SHAPER_BIN_DIR}:${SHAPER_PYTHON_SCRIPTS_DIR}:${PYTHONPATH}
export LD_LIBRARY_PATH=${SHAPER_ROOT_DIR}/lib/salome:${LD_LIBRARY_PATH}
tooltip="Create named collection of geometry entities"
icon="icons/Collection/shape_group.png"
apply_continue="true"
- helpfile="groupFeature.html">
+ helpfile="groupFeature.html"
+ hidefaces_panel="true">
<source path="group_widget.xml"/>
</feature>
myModal = false;
myIsTitleInToolbar = true;
myIsApplyContinue = false;
+ myHideFacesPanel = false;
+ myAbortConfirmation = true;
}
Config_FeatureMessage::~Config_FeatureMessage()
{
myIsTitleInToolbar = theValue;
}
+
+bool Config_FeatureMessage::isHideFacesPanel() const
+{
+ return myHideFacesPanel;
+}
+
+
+void Config_FeatureMessage::setHideFacesPanel(bool theValue)
+{
+ myHideFacesPanel = theValue;
+}
+
+bool Config_FeatureMessage::isAbortConfirmation() const
+{
+ return myAbortConfirmation;
+}
+
+void Config_FeatureMessage::setAbortConfirmation(bool theValue)
+{
+ myAbortConfirmation = theValue;
+}
bool myModal; ///<True if the feature has to be represented by modal dialog box
bool myIsAutoPreview; ///< Preview computation is performed automatically
bool myIsTitleInToolbar; ///< False if title should not be displayed in the toolbar
+ bool myHideFacesPanel; ///< Show or Hide HideFaces panel. By default is False
+ bool myAbortConfirmation; ///< Ask confirmation of abort of the feature from user
/// True if the feature can have Apply/Continue button in its property panel
bool myIsApplyContinue;
CONFIG_EXPORT bool isAutoPreview() const;
/// If true - title should normally be displayed in the toolbar
CONFIG_EXPORT bool isTitleInToolbar() const;
+ /// If true - then HideFaces panel has to be shown
+ CONFIG_EXPORT bool isHideFacesPanel() const;
+ CONFIG_EXPORT bool isAbortConfirmation() const;
///Set feature's Id
CONFIG_EXPORT void setId(const std::string& id);
CONFIG_EXPORT void setModal(bool isModal);
///Set flag to display title in toolbar
CONFIG_EXPORT void setTitleInToolbar(bool theValue);
+ ///Set flag to display title in toolbar
+ CONFIG_EXPORT void setHideFacesPanel(bool theValue);
+ ///Set flag to display title in toolbar
+ CONFIG_EXPORT void setAbortConfirmation(bool theValue);
///Set Apply/Continue state;
///If true - the feature can have Apply/Continue button in its property panel
CONFIG_EXPORT void setApplyContinue(bool isModal);
if (!aHelpFile.empty())
outFeatureMessage->setHelpFileName(myLibraryName + "/" + aHelpFile);
- if (isInternal) {
- //Internal feature has no visual representation.
- return;
- }
+ bool isHideFaces = getBooleanAttribute(theFeatureNode, HIDEFACES_PANEL, false);
+ outFeatureMessage->setHideFacesPanel(isHideFaces);
+
+ bool isConfirmAbort = getBooleanAttribute(theFeatureNode, ABORT_CONFIRMATION, true);
+ outFeatureMessage->setAbortConfirmation(isConfirmAbort);
+
+ //if (isInternal) {
+ // //Internal feature has no visual representation.
+ // return;
+ //}
std::string aText = Config_Translator::translate(anId, getProperty(theFeatureNode, FEATURE_TEXT));
outFeatureMessage->setText(aText);
// Widgets
const static char* WDG_INFO = "label";
+const static char* WDG_UNDOLABEL = "undo_label";
const static char* WDG_DOUBLEVALUE = "doublevalue";
const static char* WDG_DOUBLEVALUELABEL = "labelvalue";
const static char* WDG_INTEGERVALUE = "integervalue";
const static char* FEATURE_ICON = "icon";
const static char* FEATURE_TEXT = "title";
const static char* HELP_FILE = "helpfile";
+const static char* ABORT_CONFIRMATION = "abort_confirmation";
+const static char* HIDEFACES_PANEL = "hidefaces_panel";
const static char* FEATURE_KEYSEQUENCE = "keysequence";
const static char* FEATURE_NESTED = "nested";
const static char* FEATURE_WHEN_NESTED = "when_nested";
const static char* ATTR_ICON = FEATURE_ICON;
const static char* ATTR_LABEL = "label";
const static char* ATTR_STYLE_SHEET = "styleSheet";
+const static char* ATTR_HTML_STYLE = "isHTML";
const static char* ATTR_DEFAULT = "default";
const static char* ATTR_INTERNAL = "internal";
const static char* ATTR_OBLIGATORY = "obligatory";
*/
CONFIG_EXPORT bool getBooleanAttribute(const char* theAttributeName, bool theDefault) const;
- protected:
/// These fields are accessible for ModuleBase_WidgetFactory only
CONFIG_EXPORT Config_WidgetAPI(std::string theRawXml);
//! Pass to the next (sibling) node of widget's xml definition. If impossible, returns false
title="Point"
tooltip="Create point"
icon="icons/Construction/point.png"
+ apply_continue="true"
helpfile="pointFeature.html">
<source path="point_widget.xml" />
</feature>
#include "ExchangeAPI_Export.h"
//--------------------------------------------------------------------------------------
+#include <ExchangePlugin_ExportPart.h>
+//--------------------------------------------------------------------------------------
#include <ModelAPI_Document.h>
#include <ModelAPI_Feature.h>
#include <ModelHighAPI_Tools.h>
return ExportPtr(new ExchangeAPI_Export(aFeature, theFilePath, theSelectedShape, "XAO"));
}
+void exportPart(const std::shared_ptr<ModelAPI_Document> & thePart,
+ const std::string & theFilePath,
+ const std::list<ModelHighAPI_Selection> & theSelected)
+{
+ FeaturePtr aFeature = thePart->addFeature(ExchangePlugin_ExportPart::ID());
+ aFeature->string(ExchangePlugin_ExportPart::FILE_PATH_ID())->setValue(theFilePath);
+ if (!theSelected.empty()) {
+ fillAttribute(theSelected,
+ aFeature->selectionList(ExchangePlugin_ExportPart::SELECTION_LIST_ID()));
+ }
+ // restart transaction to execute and delete the macro-feature
+ apply();
+}
//--------------------------------------------------------------------------------------
const std::string & theAuthor = std::string(),
const std::string & theGeometryName = std::string());
+
+/** \ingroup CPPHighAPI
+ * \brief Export selected features or the whole part to the binary file.
+ */
+EXCHANGEAPI_EXPORT void exportPart(
+ const std::shared_ptr<ModelAPI_Document> & thePart,
+ const std::string & theFilePath,
+ const std::list<ModelHighAPI_Selection> & theSelected = std::list<ModelHighAPI_Selection>());
+
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
#endif /* SRC_EXCHANGEAPI_EXCHANGEAPI_EXPORT_H_ */
#include "ExchangeAPI_Import.h"
//--------------------------------------------------------------------------------------
+#include <ExchangePlugin_ImportPart.h>
+//--------------------------------------------------------------------------------------
#include <ModelHighAPI_Dumper.h>
+#include <ModelHighAPI_Services.h>
#include <ModelHighAPI_Tools.h>
//--------------------------------------------------------------------------------------
#include <algorithm>
std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(ExchangeAPI_Import::ID());
return ImportPtr(new ExchangeAPI_Import(aFeature, theFilePath));
}
+
+void importPart(const std::shared_ptr<ModelAPI_Document> & thePart,
+ const std::string & theFilePath,
+ const ModelHighAPI_Reference & theAfterThis)
+{
+ static const bool THE_VISIBLE_FEATURE = false;
+ FeaturePtr aCurrentFeature;
+ if (theAfterThis.feature()) {
+ aCurrentFeature = thePart->currentFeature(THE_VISIBLE_FEATURE);
+ thePart->setCurrentFeature(theAfterThis.feature(), THE_VISIBLE_FEATURE);
+ }
+
+ FeaturePtr aFeature = thePart->addFeature(ExchangePlugin_ImportPart::ID());
+ aFeature->string(ExchangePlugin_ImportPart::FILE_PATH_ID())->setValue(theFilePath);
+ // restart transaction to execute and delete the macro-feature
+ apply();
+
+ // restore current feature
+ if (aCurrentFeature)
+ thePart->setCurrentFeature(aCurrentFeature, THE_VISIBLE_FEATURE);
+}
#include <ModelHighAPI_Interface.h>
#include <ModelHighAPI_Macro.h>
+#include <ModelHighAPI_Reference.h>
+#include <ModelHighAPI_Selection.h>
//--------------------------------------------------------------------------------------
/**\class ExchangeAPI_Import
* \ingroup CPPHighAPI
ImportPtr addImport(const std::shared_ptr<ModelAPI_Document> & thePart,
const std::string & theFilePath);
+/** \ingroup CPPHighAPI
+ * \brief Import features from the file to the document after the current feature (or to the end).
+ */
+EXCHANGEAPI_EXPORT void importPart(
+ const std::shared_ptr<ModelAPI_Document> & thePart,
+ const std::string & theFilePath,
+ const ModelHighAPI_Reference & theAfterThis = ModelHighAPI_Reference());
+
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------
#endif /* SRC_EXCHANGEAPI_EXCHANGEAPI_IMPORT_H_ */
${PROJECT_SOURCE_DIR}/src/GeomAPI
${PROJECT_SOURCE_DIR}/src/GeomAlgoAPI
${PROJECT_SOURCE_DIR}/src/XAO
+ ${PROJECT_SOURCE_DIR}/src/ConstructionPlugin
+ ${PROJECT_SOURCE_DIR}/src/PartSetPlugin
)
SET(PROJECT_HEADERS
ExchangePlugin_Validators.h
ExchangePlugin_Tools.h
ExchangePlugin_Dump.h
+ ExchangePlugin_ImportPart.h
+ ExchangePlugin_ExportPart.h
)
SET(PROJECT_SOURCES
ExchangePlugin_Validators.cpp
ExchangePlugin_Tools.cpp
ExchangePlugin_Dump.cpp
+ ExchangePlugin_ImportPart.cpp
+ ExchangePlugin_ExportPart.cpp
)
SET(XML_RESOURCES
INSTALL(DIRECTORY icons/ DESTINATION ${SHAPER_INSTALL_XML_RESOURCES}/icons/Exchange)
INSTALL(FILES ${TEXT_RESOURCES} DESTINATION ${SHAPER_INSTALL_XML_RESOURCES})
-ADD_UNIT_TESTS(TestImport.py
- TestExport.py
- Test2290.py
- Test2459.py
- TestExportToXAOWithFields.py
- TestExportToXAOWithGroupNotUpdated.py
- TestExport_FiniteValidator.py
+ADD_UNIT_TESTS(
+ TestImport.py
+ TestExport.py
+ Test2290.py
+ Test2459.py
+ TestExportToXAOWithFields.py
+ TestExportToXAOWithGroupNotUpdated.py
+ TestExport_FiniteValidator.py
+ TestExportPart_Failure_1.py
+ TestExportPart_Failure_2.py
+ TestExportPart_Failure_3.py
+ TestExportPart_FullPartSet.py
+ TestExportPart_FullPart_1.py
+ TestExportPart_FullPart_2.py
+ TestExportPart_PartSet.py
+ TestExportPart_Results_1.py
+ TestExportPart_Results_2.py
+ TestExportPart_Results_3.py
+ TestExportPart_Results_4.py
+ TestExportPart_Results_5.py
+ TestExportPart_Results_6.py
+ TestExportPart_Results_7.py
+ TestExportPart_Results_8.py
+ TestImportPart_AfterCurrent_1.py
+ TestImportPart_AfterCurrent_2.py
+ TestImportPart_AfterLast_1.py
+ TestImportPart_AfterLast_2.py
+ TestImportPart_AfterLast_3.py
+ TestImportPart_AfterLast_4.py
+ TestImportPart_AfterLast_5.py
+ TestImportPart_AfterLast_6.py
+ TestImportPart_Construction_1.py
+ TestImportPart_Construction_2.py
+ TestImportPart_Construction_3.py
+ TestImportPart_Construction_4.py
+ TestImportPart_Multiple.py
+ TestImportPart_ToEmptyPart.py
+ TestImportPart_ToEmptyPartSet.py
)
--- /dev/null
+// Copyright (C) 2014-2019 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 <ExchangePlugin_ExportPart.h>
+
+#include <ModelAPI_AttributeSelectionList.h>
+#include <ModelAPI_AttributeString.h>
+#include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+
+#include <ConstructionPlugin_Axis.h>
+#include <ConstructionPlugin_Plane.h>
+#include <ConstructionPlugin_Point.h>
+
+#include <Events_InfoMessage.h>
+
+#include <PartSetPlugin_Part.h>
+
+#include <sstream>
+
+// Obtain all features to be exported to get the list of selected results.
+static void collectFeatures(DocumentPtr theDocument,
+ AttributeSelectionListPtr theSelected,
+ std::list<FeaturePtr>& theExport);
+// Obtain all constuction elements of the document.
+static void collectConstructions(DocumentPtr theDocument, std::list<FeaturePtr>& theExport);
+// Check features could be exported. The following features cannot be exported:
+// * non-construction result (Part) when exporting the PartSet;
+// * features, which refer to objects from another document.
+// Returns true if all features can be exported.
+static bool verifyExport(const std::list<FeaturePtr>& theFeatures,
+ std::list<FeaturePtr>& theExternalReferences,
+ std::list<FeaturePtr>& theExportedParts);
+
+
+ExchangePlugin_ExportPart::ExchangePlugin_ExportPart()
+{
+}
+
+void ExchangePlugin_ExportPart::initAttributes()
+{
+ data()->addAttribute(FILE_PATH_ID(), ModelAPI_AttributeString::typeId());
+ data()->addAttribute(FILE_FORMAT_ID(), ModelAPI_AttributeString::typeId());
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), FILE_FORMAT_ID());
+ data()->addAttribute(SELECTION_LIST_ID(), ModelAPI_AttributeSelectionList::typeId());
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), SELECTION_LIST_ID());
+}
+
+void ExchangePlugin_ExportPart::execute()
+{
+ AttributeStringPtr aFilePathAttr = string(FILE_PATH_ID());
+ std::string aFilename = aFilePathAttr->value();
+ if (aFilename.empty()) {
+ setError("File name is empty.");
+ return;
+ }
+
+ std::list<FeaturePtr> aFeaturesToExport;
+
+ DocumentPtr anExportDoc = document();
+ DocumentPtr aPartSetDoc = ModelAPI_Session::get()->moduleDocument();
+ AttributeSelectionListPtr aSelected = selectionList(SELECTION_LIST_ID());
+ if (aSelected && aSelected->size() == 0 && anExportDoc == aPartSetDoc) {
+ // no result is selected, thus have to export all features of the current document,
+ // but the document is a PartSet; and it is forbidden to copy results of Parts,
+ // thus copy construction elements only
+ collectConstructions(anExportDoc, aFeaturesToExport);
+ }
+ else
+ collectFeatures(anExportDoc, aSelected, aFeaturesToExport);
+
+ if (aFeaturesToExport.empty()) {
+ Events_InfoMessage(getKind(), "Selected features cannot be exported from the document.").send();
+ return;
+ }
+
+ // remove 'ExportPart' feature if any
+ if (aFeaturesToExport.back()->getKind() == ExchangePlugin_ExportPart::ID())
+ aFeaturesToExport.pop_back();
+
+ std::list<FeaturePtr> anExternalLinks, aReferredParts;
+ if (!verifyExport(aFeaturesToExport, anExternalLinks, aReferredParts)) {
+ if (!anExternalLinks.empty()) {
+ // collect names of features as a string
+ std::ostringstream aListOfFeatures;
+ for (std::list<FeaturePtr>::iterator anIt = anExternalLinks.begin();
+ anIt != anExternalLinks.end(); ++anIt) {
+ if (anIt != anExternalLinks.begin())
+ aListOfFeatures << ", ";
+ aListOfFeatures << "'" << (*anIt)->name() << "'";
+ }
+
+ std::string aMessage = "The selected results were created using external references "
+ "outside of this Part from features %1. "
+ "Please, remove these references or select another "
+ "sub-set of results to be able to export.";
+ Events_InfoMessage(getKind(), aMessage).arg(aListOfFeatures.str()).send();
+ }
+ if (!aReferredParts.empty()) {
+ // collect names of parts as a string
+ std::ostringstream aListOfParts;
+ for (std::list<FeaturePtr>::iterator anIt = aReferredParts.begin();
+ anIt != aReferredParts.end(); ++anIt) {
+ if (anIt != aReferredParts.begin())
+ aListOfParts << ", ";
+ aListOfParts << "'" << (*anIt)->name() << "'";
+ }
+
+ std::string aMessage = "The selected results were created using references "
+ "to results of Parts %1. Please, remove these references "
+ "or select another sub-set of results to be able to export.";
+ Events_InfoMessage(getKind(), aMessage).arg(aListOfParts.str()).send();
+ }
+ // should not export anything
+ aFeaturesToExport.clear();
+ }
+
+ if (!aFeaturesToExport.empty()) {
+ // save the document
+ if (!anExportDoc->save(aFilename.c_str(), aFeaturesToExport))
+ setError("Cannot save the document.");
+ }
+}
+
+
+// ================================ Auxiliary functions ===================================
+
+static bool isCoordinate(FeaturePtr theFeature)
+{
+ return !theFeature->isInHistory() &&
+ (theFeature->getKind() == ConstructionPlugin_Point::ID() ||
+ theFeature->getKind() == ConstructionPlugin_Axis::ID() ||
+ theFeature->getKind() == ConstructionPlugin_Plane::ID());
+}
+
+static void allReferencedFeatures(const std::set<FeaturePtr>& theFeatures,
+ std::set<FeaturePtr>& theReferencedFeatures)
+{
+ std::set<FeaturePtr> aReferences;
+ for (std::set<FeaturePtr>::const_iterator anIt = theFeatures.begin();
+ anIt != theFeatures.end(); ++anIt) {
+ theReferencedFeatures.insert(*anIt);
+
+ std::list<std::pair<std::string, std::list<ObjectPtr> > > aRefs;
+ (*anIt)->data()->referencesToObjects(aRefs);
+
+ for (std::list<std::pair<std::string, std::list<ObjectPtr> > >::iterator aRIt = aRefs.begin();
+ aRIt != aRefs.end(); ++aRIt) {
+ for (std::list<ObjectPtr>::iterator anObjIt = aRIt->second.begin();
+ anObjIt != aRIt->second.end(); ++anObjIt) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature(*anObjIt);
+ if (aFeature && !isCoordinate(aFeature) &&
+ theReferencedFeatures.find(aFeature) == theReferencedFeatures.end())
+ aReferences.insert(aFeature);
+ }
+ }
+ }
+
+ if (!aReferences.empty())
+ allReferencedFeatures(aReferences, theReferencedFeatures);
+}
+
+void collectFeatures(DocumentPtr theDocument,
+ AttributeSelectionListPtr theSelected,
+ std::list<FeaturePtr>& theExport)
+{
+ theExport = theDocument->allFeatures();
+
+ // remove all features after the current one
+ FeaturePtr aCurrentFeature = theDocument->currentFeature(false);
+ std::list<FeaturePtr>::iterator anIt = theExport.begin();
+ for (; anIt != theExport.end(); ++anIt)
+ if (*anIt == aCurrentFeature) {
+ theExport.erase(++anIt, theExport.end());
+ break;
+ }
+
+ if (!theSelected || theSelected->size() == 0) {
+ // nothing is selected, return all features of the document
+ return;
+ }
+
+ // collect initial list of features basing on the selected results
+ std::set<FeaturePtr> aFeaturesToExport;
+ for (int anIndex = 0, aSize = theSelected->size(); anIndex < aSize; ++anIndex) {
+ AttributeSelectionPtr aCurrent = theSelected->value(anIndex);
+ FeaturePtr aCurrentFeature = ModelAPI_Feature::feature(aCurrent->context());
+ if (aCurrentFeature)
+ aFeaturesToExport.insert(aCurrentFeature);
+ }
+ // recursively collect all features used for the selected results
+ allReferencedFeatures(aFeaturesToExport, aFeaturesToExport);
+
+ // remove the features which are not affect the selected results
+ anIt = theExport.begin();
+ while (anIt != theExport.end()) {
+ if (aFeaturesToExport.find(*anIt) == aFeaturesToExport.end()) {
+ std::list<FeaturePtr>::iterator aRemoveIt = anIt++;
+ theExport.erase(aRemoveIt);
+ }
+ else
+ ++anIt;
+ }
+}
+
+void collectConstructions(DocumentPtr theDocument, std::list<FeaturePtr>& theExport)
+{
+ theExport = theDocument->allFeatures();
+ // keep constructions only
+ std::list<FeaturePtr>::iterator anIt = theExport.begin();
+ while (anIt != theExport.end()) {
+ FeaturePtr aCurFeature = *anIt;
+ ResultPtr aCurResult = aCurFeature->lastResult();
+
+ bool isApplicable =
+ (!aCurResult || aCurResult->groupName() == ModelAPI_ResultConstruction::group()) &&
+ !isCoordinate(aCurFeature);
+
+ if (isApplicable)
+ ++anIt;
+ else {
+ std::list<FeaturePtr>::iterator aRemoveIt = anIt++;
+ theExport.erase(aRemoveIt);
+ }
+ }
+}
+
+bool verifyExport(const std::list<FeaturePtr>& theFeatures,
+ std::list<FeaturePtr>& theExternalReferences,
+ std::list<FeaturePtr>& theExportedParts)
+{
+ for (std::list<FeaturePtr>::const_iterator anIt = theFeatures.begin();
+ anIt != theFeatures.end(); ++anIt) {
+ // full part should not be exported
+ if ((*anIt)->getKind() == PartSetPlugin_Part::ID())
+ theExportedParts.push_back(*anIt);
+
+ DocumentPtr aDoc = (*anIt)->document();
+
+ std::list<std::pair<std::string, std::list<ObjectPtr> > > aRefs;
+ (*anIt)->data()->referencesToObjects(aRefs);
+ std::list<std::pair<std::string, std::list<ObjectPtr> > >::iterator aRIt = aRefs.begin();
+ for (; aRIt != aRefs.end(); ++aRIt) {
+ for (std::list<ObjectPtr>::iterator anObjIt = aRIt->second.begin();
+ anObjIt != aRIt->second.end(); ++anObjIt) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature(*anObjIt);
+ if (aFeature) {
+ // feature refers to external entity,
+ // which is neither the Origin nor coordinate axis or plane
+ if (aFeature->document() != aDoc && !isCoordinate(aFeature))
+ theExternalReferences.push_back(*anIt);
+ // feature refers to result of a part
+ if (aFeature->getKind() == PartSetPlugin_Part::ID())
+ theExportedParts.push_back(*anIt);
+ }
+ }
+ }
+ }
+
+ return theExternalReferences.empty() && theExportedParts.empty();
+}
--- /dev/null
+// Copyright (C) 2014-2019 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 EXCHANGEPLUGIN_EXPORTPART_H_
+#define EXCHANGEPLUGIN_EXPORTPART_H_
+
+#include <ExchangePlugin.h>
+#include <ModelAPI_Feature.h>
+
+/**
+ * \class ExchangePlugin_ExportPart
+ * \ingroup Plugins
+ * \brief Feature for export some results of a Part to the binary format for the further import.
+ */
+class ExchangePlugin_ExportPart : public ModelAPI_Feature
+{
+public:
+ /// Feature kind
+ inline static const std::string& ID()
+ {
+ static const std::string MY_EXPORT_ID("ExportPart");
+ return MY_EXPORT_ID;
+ }
+ /// attribute name of file path
+ inline static const std::string& FILE_PATH_ID()
+ {
+ static const std::string MY_FILE_PATH_ID("file_path");
+ return MY_FILE_PATH_ID;
+ }
+ /// attribute name of file format
+ inline static const std::string& FILE_FORMAT_ID()
+ {
+ static const std::string MY_FILE_FORMAT_ID("file_format");
+ return MY_FILE_FORMAT_ID;
+ }
+ /// attribute name of selection list
+ inline static const std::string& SELECTION_LIST_ID()
+ {
+ static const std::string MY_SELECTION_LIST_ID("selection_list");
+ return MY_SELECTION_LIST_ID;
+ }
+ /// Default constructor
+ ExchangePlugin_ExportPart();
+
+ /// Returns the unique kind of a feature
+ EXCHANGEPLUGIN_EXPORT virtual const std::string& getKind()
+ {
+ return ExchangePlugin_ExportPart::ID();
+ }
+
+ /// Request for initialization of data model of the feature: adding all attributes
+ EXCHANGEPLUGIN_EXPORT virtual void initAttributes();
+
+ /// Computes or recomputes the results
+ EXCHANGEPLUGIN_EXPORT virtual void execute();
+
+ /// Returns true if this feature is used as macro: creates other features and then removed.
+ EXCHANGEPLUGIN_EXPORT virtual bool isMacro() const { return true; }
+
+ /// Reimplemented from ModelAPI_Feature::isPreviewNeeded(). Returns false.
+ EXCHANGEPLUGIN_EXPORT virtual bool isPreviewNeeded() const { return false; }
+
+ /// Do not put in history.
+ /// Since it is not a macro, it is not deleted, but we don't want to see it.
+ bool isInHistory() { return false; }
+};
+
+#endif /* EXCHANGEPLUGIN_EXPORTPART_H_ */
--- /dev/null
+// Copyright (C) 2014-2019 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 <ExchangePlugin_ImportPart.h>
+
+#include <ModelAPI_AttributeString.h>
+#include <ModelAPI_ResultPart.h>
+#include <ModelAPI_Session.h>
+
+#include <PartSetPlugin_Part.h>
+
+#include <map>
+#include <sstream>
+
+// Update names of imported features/results concurent with existing objects.
+static void correntNonUniqueNames(DocumentPtr theDocument, std::list<FeaturePtr>& theImported);
+
+ExchangePlugin_ImportPart::ExchangePlugin_ImportPart()
+{
+}
+
+void ExchangePlugin_ImportPart::initAttributes()
+{
+ data()->addAttribute(FILE_PATH_ID(), ModelAPI_AttributeString::typeId());
+}
+
+void ExchangePlugin_ImportPart::execute()
+{
+ AttributeStringPtr aFilePathAttr = string(FILE_PATH_ID());
+ std::string aFilename = aFilePathAttr->value();
+ if (aFilename.empty()) {
+ setError("File name is empty.");
+ return;
+ }
+
+ // load the file into the active document
+ SessionPtr aSession = ModelAPI_Session::get();
+ DocumentPtr aDoc = document();
+ bool isPartSet = aDoc == aSession->moduleDocument();
+ std::list<FeaturePtr> anImportedFeatures;
+ bool isOk = aDoc->import(aFilename.c_str(), anImportedFeatures, isPartSet);
+ if (!isOk && isPartSet) {
+ // there are features not appropriate for PartSet,
+ // create new part and load there
+ FeaturePtr aPartFeature = aDoc->addFeature(PartSetPlugin_Part::ID());
+ ResultPartPtr aPartResult;
+ if (aPartFeature) {
+ aPartFeature->execute();
+ aPartResult = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aPartFeature->lastResult());
+ }
+ if (aPartResult) {
+ aDoc = aPartResult->partDoc();
+ isOk = aDoc->import(aFilename.c_str(), anImportedFeatures);
+ }
+ }
+ if (isOk)
+ correntNonUniqueNames(aDoc, anImportedFeatures);
+ else
+ setError("Cannot import the document.");
+}
+
+
+// ================================ Auxiliary functions ===================================
+
+typedef std::map<std::string, std::map<std::string, std::set<int> > > ObjectNameMap;
+
+bool splitName(std::string& theName, int& theIndex)
+{
+ size_t aLastUndercore = theName.find_last_of('_');
+ bool isOk = aLastUndercore != std::string::npos;
+ if (isOk) {
+ char* isNumber;
+ std::string anIndexStr = theName.substr(aLastUndercore + 1);
+ theIndex = std::strtol(anIndexStr.c_str(), &isNumber, 10);
+ isOk = isNumber != 0;
+ if (isOk)
+ theName.erase(aLastUndercore);
+ }
+ return isOk;
+}
+
+void addIndexedName(const ObjectPtr& theObject, ObjectNameMap& theIndexedNames)
+{
+ std::string aName = theObject->data()->name();
+ std::string aGroup = theObject->groupName();
+ int anIndex = 0;
+ bool isIndexed = splitName(aName, anIndex);
+ std::set<int>& anIndices = theIndexedNames[aGroup][aName];
+ if (isIndexed)
+ anIndices.insert(anIndex);
+}
+
+// Collect names of features and results in the document before the import.
+// The name of indexed feature/result will be split to the name and the index. For example ,
+// 'Point_1', 'Point_2' will be placed at the same key with the set of corrsponding indices:
+// 'Point_1', 'Point_2' => {'Point', [1, 2]}.
+// Thus, the new point should have index 3 and therefore the name 'Point_3'.
+static void collectOldNames(DocumentPtr theDocument, std::list<FeaturePtr>& theAvoided,
+ ObjectNameMap& theIndexedNames)
+{
+ std::list<FeaturePtr> anAllFeatures = theDocument->allFeatures();
+ std::list<FeaturePtr>::iterator aFIt = anAllFeatures.begin();
+ std::list<FeaturePtr>::iterator anAvoidIt = theAvoided.begin();
+ for (; aFIt != anAllFeatures.end(); ++aFIt) {
+ if (anAvoidIt != theAvoided.end() && *aFIt == *anAvoidIt) {
+ // skip this feature
+ ++anAvoidIt;
+ continue;
+ }
+
+ // store name of feature
+ addIndexedName(*aFIt, theIndexedNames);
+ // store names of results
+ const std::list<ResultPtr>& aResults = (*aFIt)->results();
+ for (std::list<ResultPtr>::const_iterator aRIt = aResults.begin();
+ aRIt != aResults.end(); ++aRIt)
+ addIndexedName(*aRIt, theIndexedNames);
+ }
+}
+
+static std::string uniqueName(const ObjectPtr& theObject, ObjectNameMap& theExistingNames)
+{
+ std::string aName = theObject->data()->name();
+ std::string aGroup = theObject->groupName();
+ int anIndex = 1;
+ splitName(aName, anIndex);
+
+ ObjectNameMap::iterator aFoundGroup = theExistingNames.find(aGroup);
+ bool isUnique = aFoundGroup == theExistingNames.end();
+
+ std::map<std::string, std::set<int> >::iterator aFound;
+ if (!isUnique) {
+ aFound = aFoundGroup->second.find(aName);
+ isUnique = aFound == aFoundGroup->second.end();
+ }
+
+ if (isUnique) {
+ // name is unique
+ aName = theObject->data()->name();
+ addIndexedName(theObject, theExistingNames);
+ }
+ else {
+ // search the appropriate index
+ std::set<int>::iterator aFoundIndex = aFound->second.find(anIndex);
+ for (; aFoundIndex != aFound->second.end(); ++aFoundIndex, ++anIndex)
+ if (anIndex != *aFoundIndex)
+ break;
+ // compose the new name
+ std::ostringstream aNewName;
+ aNewName << aName << "_" << anIndex;
+ aName = aNewName.str();
+ // add new index
+ aFound->second.insert(anIndex);
+ }
+
+ return aName;
+}
+
+void correntNonUniqueNames(DocumentPtr theDocument, std::list<FeaturePtr>& theImported)
+{
+ ObjectNameMap aNames;
+ collectOldNames(theDocument, theImported, aNames);
+
+ for (std::list<FeaturePtr>::iterator anIt = theImported.begin();
+ anIt != theImported.end(); ++anIt) {
+ // update name of feature
+ std::string aNewName = uniqueName(*anIt, aNames);
+ (*anIt)->data()->setName(aNewName);
+ // update names of results
+ const std::list<ResultPtr>& aResults = (*anIt)->results();
+ for (std::list<ResultPtr>::const_iterator aRIt = aResults.begin();
+ aRIt != aResults.end(); ++aRIt) {
+ aNewName = uniqueName(*aRIt, aNames);
+ (*aRIt)->data()->setName(aNewName);
+ }
+ }
+}
--- /dev/null
+// Copyright (C) 2014-2019 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 EXCHANGEPLUGIN_IMPORTPART_H_
+#define EXCHANGEPLUGIN_IMPORTPART_H_
+
+#include <ExchangePlugin.h>
+#include <ModelAPI_Feature.h>
+
+/**
+ * \class ExchangePlugin_ImportPart
+ * \ingroup Plugins
+ * \brief Feature for import the structure of Part into the current document.
+ */
+class ExchangePlugin_ImportPart : public ModelAPI_Feature
+{
+public:
+ /// Feature kind
+ inline static const std::string& ID()
+ {
+ static const std::string MY_IMPORT_ID("ImportPart");
+ return MY_IMPORT_ID;
+ }
+ /// attribute name of file path
+ inline static const std::string& FILE_PATH_ID()
+ {
+ static const std::string MY_FILE_PATH_ID("file_path");
+ return MY_FILE_PATH_ID;
+ }
+ /// Default constructor
+ ExchangePlugin_ImportPart();
+
+ /// Returns the unique kind of a feature
+ EXCHANGEPLUGIN_EXPORT virtual const std::string& getKind()
+ {
+ return ExchangePlugin_ImportPart::ID();
+ }
+
+ /// Request for initialization of data model of the feature: adding all attributes
+ EXCHANGEPLUGIN_EXPORT virtual void initAttributes();
+
+ /// Computes or recomputes the results
+ EXCHANGEPLUGIN_EXPORT virtual void execute();
+
+ /// Returns true if this feature is used as macro: creates other features and then removed.
+ EXCHANGEPLUGIN_EXPORT virtual bool isMacro() const { return true; }
+
+ /// Reimplemented from ModelAPI_Feature::isPreviewNeeded(). Returns false.
+ EXCHANGEPLUGIN_EXPORT virtual bool isPreviewNeeded() const { return false; }
+};
+
+#endif /* EXCHANGEPLUGIN_IMPORTPART_H_ */
#include <ExchangePlugin_Dump.h>
#include <ExchangePlugin_ImportFeature.h>
#include <ExchangePlugin_ExportFeature.h>
+#include <ExchangePlugin_ImportPart.h>
+#include <ExchangePlugin_ExportPart.h>
#include <ExchangePlugin_Validators.h>
#include <Config_PropManager.h>
if (theFeatureID == ExchangePlugin_ExportFeature::ID()) {
return FeaturePtr(new ExchangePlugin_ExportFeature);
} else
+ if (theFeatureID == ExchangePlugin_ImportPart::ID()) {
+ return FeaturePtr(new ExchangePlugin_ImportPart);
+ } else
+ if (theFeatureID == ExchangePlugin_ExportPart::ID()) {
+ return FeaturePtr(new ExchangePlugin_ExportPart);
+ } else
if (theFeatureID == ExchangePlugin_Dump::ID()) {
return FeaturePtr(new ExchangePlugin_Dump);
}
<translation>Attribute %1 is not a string.</translation>
</message>
</context>
+
+ <context>
+ <name>Export:ExchangePlugin_ExportPart</name>
+ <message>
+ <source>Cannot save the document.</source>
+ <translation>Cannot save the document.</translation>
+ </message>
+ <message>
+ <source>Selected features cannot be exported from the document.</source>
+ <translation>Selected features cannot be exported from the document.</translation>
+ </message>
+ <message>
+ <source>The selected results were created using external references outside of this Part from features %1. Please, remove these references or select another sub-set of results to be able to export.</source>
+ <translation>The selected results were created using external references outside of this Part from features %1. Please, remove these references or select another sub-set of results to be able to export.</translation>
+ </message>
+ <message>
+ <source>The selected results were created using references to results of Parts %1. Please, remove these references or select another sub-set of results to be able to export.</source>
+ <translation>The selected results were created using references to results of Parts %1. Please, remove these references or select another sub-set of results to be able to export.</translation>
+ </message>
+ </context>
+
+ <context>
+ <name>Import:ExchangePlugin_ImportPart</name>
+ <message>
+ <source>Cannot import the document.</source>
+ <translation>Cannot import the document.</translation>
+ </message>
+ </context>
</TS>
--- /dev/null
+# Copyright (C) 2019 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 SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+model.begin()
+model.exportPart(partSet, filename, [Part_1.result()])
+model.end()
+assert not os.path.exists(filename), "ERROR: Exporting result of Part_1 should fail"
--- /dev/null
+# Copyright (C) 2019 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 SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+featureToExport = Box_1
+
+model.begin()
+model.exportPart(Part_1_doc, filename, [featureToExport.result()])
+model.end()
+assert not os.path.exists(filename), "ERROR: Exporting of {} from document {} should fail".format(featureToExport.name(), Part_1.name())
--- /dev/null
+# Copyright (C) 2019 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()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+model.do()
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Part_1/[Box_1_1/Front][Box_1_1/Right][Box_1_1/Top]"))
+Translation_1 = model.addTranslation(partSet, [model.selection("COMPOUND", "Part_1/")], model.selection("EDGE", "Axis_4"), 10)
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+model.begin()
+model.exportPart(partSet, filename)
+model.end()
+assert not os.path.exists(filename), "ERROR: Exporting of PartSet should fail"
--- /dev/null
+# Copyright (C) 2019 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 SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+model.begin()
+model.exportPart(partSet, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Failed to export full PartSet"
--- /dev/null
+# Copyright (C) 2019 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 SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+model.begin()
+model.exportPart(Part_1_doc, filename)
+model.end()
+assert not os.path.exists(filename), "ERROR: Exporting of Part_1 should fail"
--- /dev/null
+# Copyright (C) 2019 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 SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+model.begin()
+model.exportPart(Part_2_doc, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export Part_2 to file {}".format(filename)
--- /dev/null
+# Copyright (C) 2019 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 SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+model.begin()
+model.exportPart(partSet, filename, [Axis_4.result()])
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export construction elements of PartSet"
--- /dev/null
+# Copyright (C) 2019 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 SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+featureToExport = Point_2
+
+model.begin()
+model.exportPart(partSet, filename, [featureToExport.result()])
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export feature {}".format(featureToExport.name())
--- /dev/null
+# Copyright (C) 2019 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 SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+featureToExport = Axis_4
+
+model.begin()
+model.exportPart(partSet, filename, [featureToExport.result()])
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export feature {}".format(featureToExport.name())
--- /dev/null
+# Copyright (C) 2019 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 SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+featureToExport = Sketch_1
+
+model.begin()
+model.exportPart(Part_1_doc, filename, [featureToExport.result()])
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export feature {}".format(featureToExport.name())
--- /dev/null
+# Copyright (C) 2019 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 SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+featureToExport = Extrusion_1
+
+model.begin()
+model.exportPart(Part_1_doc, filename, [featureToExport.result()])
+model.end()
+assert not os.path.exists(filename), "ERROR: Exporting of {} should fail".format(featureToExport.name())
--- /dev/null
+# Copyright (C) 2019 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 SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+featureToExport = Sketch_2
+
+model.begin()
+model.exportPart(Part_1_doc, filename, [featureToExport.result()])
+model.end()
+assert not os.path.exists(filename), "ERROR: Exporting of {} should fail".format(featureToExport.name())
--- /dev/null
+# Copyright (C) 2019 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 SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+featureToExport = Revolution_1
+
+model.begin()
+model.exportPart(Part_1_doc, filename, [featureToExport.result()])
+model.end()
+assert not os.path.exists(filename), "ERROR: Exporting of {} should fail".format(featureToExport.name())
--- /dev/null
+# Copyright (C) 2019 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 SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+featureToExport = Box_1
+
+model.begin()
+model.exportPart(Part_2_doc, filename, [featureToExport.result()])
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export feature {}".format(featureToExport.name())
--- /dev/null
+# Copyright (C) 2019 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 SketchAPI import *
+
+from salome.shaper import model
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+import os
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+featureToExport = Translation_1
+
+model.begin()
+model.exportPart(Part_2_doc, filename, [featureToExport.result()])
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export feature {}".format(featureToExport.name())
--- /dev/null
+# Copyright (C) 2019 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 GeomAlgoAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/YOZ"), model.selection("EDGE", "PartSet/OY"), 45)
+model.do()
+model.end()
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+# store the reference data
+features = Part_1_doc.allFeatures()
+refData = []
+for feat in features:
+ res = []
+ for r in feat.results():
+ res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+ refData.append( (feat.getKind(), res) )
+
+# export all features from Part_1
+model.begin()
+model.exportPart(Part_1_doc, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export features from {}".format(Part_1.name())
+
+# close all documents
+model.reset()
+
+# create new Part
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-20, -40, -50, -40)
+SketchLine_2 = Sketch_1.addLine(-50, -40, -50, -10)
+SketchLine_3 = Sketch_1.addLine(-50, -10, -20, -10)
+SketchLine_4 = Sketch_1.addLine(-20, -10, -20, -40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_2.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 30)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 10)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 30, 0)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Extrusion_1_1")], model.selection("EDGE", "PartSet/OX"), 50)
+model.end()
+
+# store features before the import
+featuresBeforeImportBegin = Part_1_doc.allFeatures()
+featuresBeforeImportBegin.pop_back() # remove Translation_1
+featuresBeforeImportBegin.pop_back() # remove Extrusion_1
+featuresBeforeImportFinish = [Translation_1.feature(), Extrusion_1.feature()]
+
+# import the document after Sketch_1
+model.begin()
+model.importPart(Part_1_doc, filename, Sketch_1)
+model.end()
+
+# compare results with the reference data
+TOLERANCE = 1.e-7
+features = Part_1_doc.allFeatures()
+for feat in featuresBeforeImportBegin:
+ if features.front().getKind() == feat.getKind() and features.front().name() == feat.name():
+ features.pop_front()
+for feat in featuresBeforeImportFinish:
+ if features.back().getKind() == feat.getKind() and features.back().name() == feat.name():
+ features.pop_back()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+ assert(feat.getKind() == ref[0])
+ for fv, rv in zip(feat.results(), ref[1]):
+ assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2019 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 GeomAlgoAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/YOZ"), model.selection("EDGE", "PartSet/OY"), 45)
+model.do()
+model.end()
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+# store the reference data
+features = Part_1_doc.allFeatures()
+refData = []
+for feat in features:
+ res = []
+ for r in feat.results():
+ res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+ refData.append( (feat.getKind(), res) )
+
+# export all features from Part_1
+model.begin()
+model.exportPart(Part_1_doc, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export features from {}".format(Part_1.name())
+
+# close all documents
+model.reset()
+
+# create new Part
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-20, -40, -50, -40)
+SketchLine_2 = Sketch_1.addLine(-50, -40, -50, -10)
+SketchLine_3 = Sketch_1.addLine(-50, -10, -20, -10)
+SketchLine_4 = Sketch_1.addLine(-20, -10, -20, -40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_2.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 30)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 10)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 30, 0)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Extrusion_1_1")], model.selection("EDGE", "PartSet/OX"), 50)
+model.end()
+
+# store features before the import
+featuresBeforeImportBegin = Part_1_doc.allFeatures()
+featuresBeforeImportBegin.pop_back() # remove Translation_1
+featuresBeforeImportFinish = [Translation_1.feature()]
+
+# import the document after Extrusion_1
+model.begin()
+model.importPart(Part_1_doc, filename, Extrusion_1)
+model.end()
+
+# compare results with the reference data
+TOLERANCE = 1.e-7
+features = Part_1_doc.allFeatures()
+for feat in featuresBeforeImportBegin:
+ if features.front().getKind() == feat.getKind() and features.front().name() == feat.name():
+ features.pop_front()
+for feat in featuresBeforeImportFinish:
+ if features.back().getKind() == feat.getKind() and features.back().name() == feat.name():
+ features.pop_back()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+ assert(feat.getKind() == ref[0])
+ for fv, rv in zip(feat.results(), ref[1]):
+ assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2019 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 GeomAlgoAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+# store the reference data
+features = [Point_2.feature(), Axis_4.feature()]
+refData = []
+for feat in features:
+ res = []
+ for r in feat.results():
+ res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+ refData.append( (feat.getKind(), res) )
+
+# export feature from PartSet
+featureToExport = Axis_4
+model.begin()
+model.exportPart(partSet, filename, [featureToExport.result()])
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export feature {}".format(featureToExport.name())
+
+# close all documents
+model.reset()
+
+# create new Part
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-20, -40, -50, -40)
+SketchLine_2 = Sketch_1.addLine(-50, -40, -50, -10)
+SketchLine_3 = Sketch_1.addLine(-50, -10, -20, -10)
+SketchLine_4 = Sketch_1.addLine(-20, -10, -20, -40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_2.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 30)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 10)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 30, 0)
+model.end()
+
+# store features before the import
+featuresBeforeImport = Part_1_doc.allFeatures()
+
+# import the document
+model.begin()
+model.importPart(Part_1_doc, filename)
+model.end()
+
+# compare results with the reference data
+TOLERANCE = 1.e-7
+features = Part_1_doc.allFeatures()
+for feat in featuresBeforeImport:
+ if features.front().getKind() == feat.getKind() and features.front().name() == feat.name():
+ features.pop_front()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+ assert(feat.getKind() == ref[0])
+ for fv, rv in zip(feat.results(), ref[1]):
+ assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2019 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 GeomAlgoAPI import *
+from ModelAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+featureToExport = Sketch_1
+
+# store the reference data
+sketch = featureToCompositeFeature(featureToExport.feature())
+features = [sketch]
+for i in range(0, sketch.numberOfSubs()):
+ features.append(sketch.subFeature(i))
+refData = []
+for feat in features:
+ res = []
+ for r in feat.results():
+ res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+ refData.append( (feat.getKind(), res) )
+
+# export sketch from Part_1
+model.begin()
+model.exportPart(Part_1_doc, filename, [featureToExport.result()])
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export feature {}".format(featureToExport.name())
+
+# close all documents
+model.reset()
+
+# create new Part
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-20, -40, -50, -40)
+SketchLine_2 = Sketch_1.addLine(-50, -40, -50, -10)
+SketchLine_3 = Sketch_1.addLine(-50, -10, -20, -10)
+SketchLine_4 = Sketch_1.addLine(-20, -10, -20, -40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_2.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 30)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 10)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 30, 0)
+model.end()
+
+# store features before the import
+featuresBeforeImport = Part_1_doc.allFeatures()
+
+# import the document
+model.begin()
+model.importPart(Part_1_doc, filename)
+model.end()
+
+# compare results with the reference data
+TOLERANCE = 1.e-7
+features = Part_1_doc.allFeatures()
+for feat in featuresBeforeImport:
+ if features.front().getKind() == feat.getKind() and features.front().name() == feat.name():
+ features.pop_front()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+ assert(feat.getKind() == ref[0])
+ for fv, rv in zip(feat.results(), ref[1]):
+ assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2019 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 GeomAlgoAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+featureToExport = Box_1
+
+# store the reference data
+features = [featureToExport.feature()]
+refData = []
+for feat in features:
+ res = []
+ for r in feat.results():
+ res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+ refData.append( (feat.getKind(), res) )
+
+# export feature from Part_2
+model.begin()
+model.exportPart(Part_2_doc, filename, [featureToExport.result()])
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export feature {}".format(featureToExport.name())
+
+# close all documents
+model.reset()
+
+# create new Part
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-20, -40, -50, -40)
+SketchLine_2 = Sketch_1.addLine(-50, -40, -50, -10)
+SketchLine_3 = Sketch_1.addLine(-50, -10, -20, -10)
+SketchLine_4 = Sketch_1.addLine(-20, -10, -20, -40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_2.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 30)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 10)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 30, 0)
+model.end()
+
+# store features before the import
+featuresBeforeImport = Part_1_doc.allFeatures()
+
+# import the document
+model.begin()
+model.importPart(Part_1_doc, filename)
+model.end()
+
+# compare results with the reference data
+TOLERANCE = 1.e-7
+features = Part_1_doc.allFeatures()
+for feat in featuresBeforeImport:
+ if features.front().getKind() == feat.getKind() and features.front().name() == feat.name():
+ features.pop_front()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+ assert(feat.getKind() == ref[0])
+ for fv, rv in zip(feat.results(), ref[1]):
+ assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2019 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 GeomAlgoAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+model.do()
+
+model.end()
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+featureToExport = Translation_1
+
+# store the reference data
+features = [Box_1.feature(), Translation_1.feature()]
+refData = []
+for feat in features:
+ res = []
+ for r in feat.results():
+ res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+ refData.append( (feat.getKind(), res) )
+
+# export all features from Part_2
+model.begin()
+model.exportPart(Part_2_doc, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export feature {}".format(featureToExport.name())
+
+# close all documents
+model.reset()
+
+# create new Part
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-20, -40, -50, -40)
+SketchLine_2 = Sketch_1.addLine(-50, -40, -50, -10)
+SketchLine_3 = Sketch_1.addLine(-50, -10, -20, -10)
+SketchLine_4 = Sketch_1.addLine(-20, -10, -20, -40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_2.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 30)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 10)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 30, 0)
+model.end()
+
+# store features before the import
+featuresBeforeImport = Part_1_doc.allFeatures()
+
+# import the document
+model.begin()
+model.importPart(Part_1_doc, filename)
+model.end()
+
+# compare results with the reference data
+TOLERANCE = 1.e-7
+features = Part_1_doc.allFeatures()
+for feat in featuresBeforeImport:
+ if features.front().getKind() == feat.getKind() and features.front().name() == feat.name():
+ features.pop_front()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+ assert(feat.getKind() == ref[0])
+ for fv, rv in zip(feat.results(), ref[1]):
+ assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2019 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 GeomAlgoAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+Plane_4 = model.addPlane(Part_2_doc, model.selection("FACE", "PartSet/YOZ"), model.selection("EDGE", "PartSet/OY"), 45)
+model.do()
+
+model.end()
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+# store the reference data
+features = [Box_1.feature(), Plane_4.feature()]
+refData = []
+for feat in features:
+ res = []
+ for r in feat.results():
+ res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+ refData.append( (feat.getKind(), res) )
+
+# export specified features from Part_2
+model.begin()
+model.exportPart(Part_2_doc, filename, [Box_1.result(), Plane_4.result()])
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export features {} and {}".format(feature[0].name(), features[1].name())
+
+# close all documents
+model.reset()
+
+# create new Part
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-20, -40, -50, -40)
+SketchLine_2 = Sketch_1.addLine(-50, -40, -50, -10)
+SketchLine_3 = Sketch_1.addLine(-50, -10, -20, -10)
+SketchLine_4 = Sketch_1.addLine(-20, -10, -20, -40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_2.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 30)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 10)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 30, 0)
+model.end()
+
+# store features before the import
+featuresBeforeImport = Part_1_doc.allFeatures()
+
+# import the document
+model.begin()
+model.importPart(Part_1_doc, filename)
+model.end()
+
+# compare results with the reference data
+TOLERANCE = 1.e-7
+features = Part_1_doc.allFeatures()
+for feat in featuresBeforeImport:
+ if features.front().getKind() == feat.getKind() and features.front().name() == feat.name():
+ features.pop_front()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+ assert(feat.getKind() == ref[0])
+ for fv, rv in zip(feat.results(), ref[1]):
+ assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2019 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 GeomAlgoAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Point_2 = model.addPoint(partSet, 100, 100, 100)
+Axis_4 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "PartSet/Axis_4"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+
+Part_2 = model.addPart(partSet)
+Part_2_doc = Part_2.document()
+Box_1 = model.addBox(Part_2_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_2_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+Plane_4 = model.addPlane(Part_2_doc, model.selection("FACE", "PartSet/YOZ"), model.selection("EDGE", "PartSet/OY"), 45)
+model.do()
+
+model.end()
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+# store the reference data
+features = [Box_1.feature(), Translation_1.feature()]
+refData = []
+for feat in features:
+ res = []
+ for r in feat.results():
+ res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+ refData.append( (feat.getKind(), res) )
+
+# export all features before the history line from Part_2
+model.begin()
+Part_2_doc.setCurrentFeature(Translation_1.feature(), False)
+model.exportPart(Part_2_doc, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export features {} and {}".format(feature[0].name(), features[1].name())
+
+# close all documents
+model.reset()
+
+# create new Part
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-20, -40, -50, -40)
+SketchLine_2 = Sketch_1.addLine(-50, -40, -50, -10)
+SketchLine_3 = Sketch_1.addLine(-50, -10, -20, -10)
+SketchLine_4 = Sketch_1.addLine(-20, -10, -20, -40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_2.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 30)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 10)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 30, 0)
+model.end()
+
+# store features before the import
+featuresBeforeImport = Part_1_doc.allFeatures()
+
+# import the document
+model.begin()
+model.importPart(Part_1_doc, filename)
+model.end()
+
+# compare results with the reference data
+TOLERANCE = 1.e-7
+features = Part_1_doc.allFeatures()
+for feat in featuresBeforeImport:
+ if features.front().getKind() == feat.getKind() and features.front().name() == feat.name():
+ features.pop_front()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+ assert(feat.getKind() == ref[0])
+ for fv, rv in zip(feat.results(), ref[1]):
+ assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2019 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 GeomAlgoAPI import *
+from ModelAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+# PartSet => PartSet
+
+model.begin()
+partSet = model.moduleDocument()
+Point_1 = model.addPoint(partSet, 100, 100, 100)
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Axis_1 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+model.end()
+
+# store the reference data
+features = partSet.allFeatures()
+refData = []
+for feat in features:
+ res = []
+ for r in feat.results():
+ res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+ refData.append( (feat.getKind(), res) )
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+# emport the document
+model.begin()
+model.exportPart(partSet, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export PartSet"
+
+# close all documents
+model.reset()
+
+# import the document
+model.begin()
+partSet = model.moduleDocument()
+model.importPart(partSet, filename)
+model.end()
+
+# Test 1. No Part should be created
+assert(partSet.size(ModelAPI_ResultPart.group()) == 0)
+
+# Test 2. Compare results with the reference data
+TOLERANCE = 1.e-7
+features = partSet.allFeatures()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+ assert(feat.getKind() == ref[0])
+ for fv, rv in zip(feat.results(), ref[1]):
+ assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2019 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 GeomAlgoAPI import *
+from ModelAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+# PartSet => Part
+
+model.begin()
+partSet = model.moduleDocument()
+Point_1 = model.addPoint(partSet, 100, 100, 100)
+Sketch_1 = model.addSketch(partSet, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Axis_1 = model.addAxis(partSet, model.selection("VERTEX", "Origin"), model.selection("VERTEX", "Point_2"))
+model.end()
+
+# store the reference data (without Origin, coordinate axes and planes)
+features = partSet.allFeatures()
+for i in range(0, 7):
+ features.pop_front()
+refData = []
+for feat in features:
+ res = []
+ for r in feat.results():
+ res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+ refData.append( (feat.getKind(), res) )
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+# emport the document
+model.begin()
+model.exportPart(partSet, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export PartSet"
+
+# close all documents
+model.reset()
+
+# import the document
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+model.importPart(Part_1_doc, filename)
+model.end()
+
+# Test 1. No Part should be created
+assert(partSet.size(ModelAPI_ResultPart.group()) == 1)
+
+# Test 2. Compare results with the reference data
+TOLERANCE = 1.e-7
+features = Part_1_doc.allFeatures()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+ assert(feat.getKind() == ref[0])
+ for fv, rv in zip(feat.results(), ref[1]):
+ assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2019 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 GeomAlgoAPI import *
+from ModelAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+# Part => PartSet
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Point_1 = model.addPoint(Part_1_doc, 100, 100, 100)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Axis_1 = model.addAxis(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("VERTEX", "Point_1"))
+model.end()
+
+# store the reference data
+features = Part_1_doc.allFeatures()
+refData = []
+for feat in features:
+ res = []
+ for r in feat.results():
+ res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+ refData.append( (feat.getKind(), res) )
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+# emport the document
+model.begin()
+model.exportPart(Part_1_doc, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export {}".format(Part_1.name())
+
+# close all documents
+model.reset()
+
+# import the document
+model.begin()
+partSet = model.moduleDocument()
+model.importPart(partSet, filename)
+model.end()
+
+# Test 1. No new Part should be created
+assert(partSet.size(ModelAPI_ResultPart.group()) == 0)
+
+# Test 2. Compare results with the reference data
+TOLERANCE = 1.e-7
+features = partSet.allFeatures()
+for i in range(0, 7):
+ # exclude Origin, coordinate axes and planes
+ features.pop_front()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+ assert(feat.getKind() == ref[0])
+ for fv, rv in zip(feat.results(), ref[1]):
+ assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2019 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 GeomAlgoAPI import *
+from ModelAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+# Part => Part
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Point_1 = model.addPoint(Part_1_doc, 100, 100, 100)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Axis_1 = model.addAxis(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("VERTEX", "Point_1"))
+model.end()
+
+# store the reference data
+features = Part_1_doc.allFeatures()
+refData = []
+for feat in features:
+ res = []
+ for r in feat.results():
+ res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+ refData.append( (feat.getKind(), res) )
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+# emport the document
+model.begin()
+model.exportPart(Part_1_doc, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export {}".format(Part_1.name())
+
+# close all documents
+model.reset()
+
+# import the document
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+model.importPart(Part_1_doc, filename)
+model.end()
+
+# Test 1. No new Part should be created
+assert(partSet.size(ModelAPI_ResultPart.group()) == 1)
+
+# Test 2. Compare results with the reference data
+TOLERANCE = 1.e-7
+features = Part_1_doc.allFeatures()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+ assert(feat.getKind() == ref[0])
+ for fv, rv in zip(feat.results(), ref[1]):
+ assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2019 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 GeomAlgoAPI import *
+from ModelAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Box_1 = model.addBox(Part_1_doc, 10, 10, 10)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Box_1_1")], model.selection("EDGE", "PartSet/OX"), 100)
+Translation_1.setName("MovedBox")
+Plane_4 = model.addPlane(Part_1_doc, model.selection("FACE", "PartSet/YOZ"), model.selection("EDGE", "PartSet/OY"), 45)
+model.do()
+model.end()
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+# export all features from Part_1
+model.begin()
+model.exportPart(Part_1_doc, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export features from {}".format(Part_1.name())
+
+# close all documents
+model.reset()
+
+# create new Part
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchLine_1 = Sketch_1.addLine(-20, -40, -50, -40)
+SketchLine_2 = Sketch_1.addLine(-50, -40, -50, -10)
+SketchLine_3 = Sketch_1.addLine(-50, -10, -20, -10)
+SketchLine_4 = Sketch_1.addLine(-20, -10, -20, -40)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchLine_4.endPoint(), SketchLine_1.startPoint())
+SketchConstraintCoincidence_2 = Sketch_1.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchConstraintCoincidence_3 = Sketch_1.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_1.setCoincident(SketchLine_3.endPoint(), SketchLine_4.startPoint())
+SketchConstraintHorizontal_1 = Sketch_1.setHorizontal(SketchLine_1.result())
+SketchConstraintVertical_1 = Sketch_1.setVertical(SketchLine_2.result())
+SketchConstraintHorizontal_2 = Sketch_1.setHorizontal(SketchLine_3.result())
+SketchConstraintVertical_2 = Sketch_1.setVertical(SketchLine_4.result())
+SketchConstraintEqual_1 = Sketch_1.setEqual(SketchLine_1.result(), SketchLine_2.result())
+SketchConstraintLength_1 = Sketch_1.setLength(SketchLine_1.result(), 30)
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchConstraintDistanceHorizontal_1 = Sketch_1.setHorizontalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 20)
+SketchConstraintDistanceVertical_1 = Sketch_1.setVerticalDistance(SketchLine_3.endPoint(), SketchAPI_Point(SketchPoint_1).coordinates(), 10)
+model.do()
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchLine_4r-SketchLine_3r-SketchLine_2r-SketchLine_1r")], model.selection(), 30, 0)
+Translation_1 = model.addTranslation(Part_1_doc, [model.selection("SOLID", "Extrusion_1_1")], model.selection("EDGE", "PartSet/OX"), 50)
+model.end()
+
+
+def checkUniqueNames(theDocument):
+ features = theDocument.allObjects()
+ names = set()
+ for feat in features:
+ name = feat.data().name()
+ if not name == "":
+ assert(not name in names), "'{}' already exists in {}".format(name, names)
+ names.add(name)
+
+
+# import the document at the end
+model.begin()
+model.importPart(Part_1_doc, filename)
+model.end()
+checkUniqueNames(Part_1_doc)
+
+# import the document after Extrusion_1
+model.begin()
+model.importPart(Part_1_doc, filename, Extrusion_1)
+model.end()
+checkUniqueNames(Part_1_doc)
+
+# import the document after Sketch_1
+model.begin()
+model.importPart(Part_1_doc, filename, Sketch_1)
+model.end()
+checkUniqueNames(Part_1_doc)
+
+# import the document after Translation_1
+model.begin()
+model.importPart(Part_1_doc, filename, Translation_1)
+model.end()
+checkUniqueNames(Part_1_doc)
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2019 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 GeomAlgoAPI import *
+from ModelAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Point_1 = model.addPoint(Part_1_doc, 100, 100, 100)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Axis_1 = model.addAxis(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("VERTEX", "Point_1"))
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "Axis_1"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+model.end()
+
+# store the reference data
+features = Part_1_doc.allFeatures()
+refData = []
+for feat in features:
+ res = []
+ for r in feat.results():
+ res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+ refData.append( (feat.getKind(), res) )
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+# emport the document
+model.begin()
+model.exportPart(Part_1_doc, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export {}".format(Part_1.name())
+
+# close all documents
+model.reset()
+
+# import the document
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+model.importPart(Part_1_doc, filename)
+model.end()
+
+# Test 1. No new Part should be created
+assert(partSet.size(ModelAPI_ResultPart.group()) == 1)
+
+# Test 2. Compare results with the reference data
+TOLERANCE = 1.e-7
+features = Part_1_doc.allFeatures()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+ assert(feat.getKind() == ref[0])
+ for fv, rv in zip(feat.results(), ref[1]):
+ assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
--- /dev/null
+# Copyright (C) 2019 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 GeomAlgoAPI import *
+from ModelAPI import *
+from SketchAPI import *
+from salome.shaper import model
+
+import os
+import math
+
+model.begin()
+partSet = model.moduleDocument()
+Part_1 = model.addPart(partSet)
+Part_1_doc = Part_1.document()
+Point_1 = model.addPoint(Part_1_doc, 100, 100, 100)
+Sketch_1 = model.addSketch(Part_1_doc, model.defaultPlane("XOY"))
+SketchProjection_1 = Sketch_1.addProjection(model.selection("VERTEX", "PartSet/Origin"), False)
+SketchPoint_1 = SketchProjection_1.createdFeature()
+SketchCircle_1 = Sketch_1.addCircle(0, 0, 30)
+SketchConstraintCoincidence_1 = Sketch_1.setCoincident(SketchPoint_1.result(), SketchCircle_1.center())
+SketchConstraintRadius_1 = Sketch_1.setRadius(SketchCircle_1.results()[1], 30)
+model.do()
+Axis_1 = model.addAxis(Part_1_doc, model.selection("VERTEX", "PartSet/Origin"), model.selection("VERTEX", "Point_1"))
+Extrusion_1 = model.addExtrusion(Part_1_doc, [model.selection("FACE", "Sketch_1/Face-SketchCircle_1_2f")], model.selection("EDGE", "Axis_1"), 100, 0)
+Sketch_2 = model.addSketch(Part_1_doc, model.selection("FACE", "Extrusion_1_1/To_Face"))
+SketchLine_1 = Sketch_2.addLine(57.73502691896258, 57.73502691896258, 71.87716254269353, 43.59289129523163)
+SketchLine_2 = Sketch_2.addLine(71.87716254269353, 43.59289129523163, 71.87716254269353, 71.87716254269353)
+SketchConstraintCoincidence_2 = Sketch_2.setCoincident(SketchLine_1.endPoint(), SketchLine_2.startPoint())
+SketchLine_3 = Sketch_2.addLine(71.87716254269353, 71.87716254269353, 57.73502691896258, 57.73502691896258)
+SketchConstraintCoincidence_3 = Sketch_2.setCoincident(SketchLine_2.endPoint(), SketchLine_3.startPoint())
+SketchConstraintCoincidence_4 = Sketch_2.setCoincident(SketchLine_1.startPoint(), SketchLine_3.endPoint())
+SketchConstraintPerpendicular_1 = Sketch_2.setPerpendicular(SketchLine_1.result(), SketchLine_3.result())
+SketchConstraintVertical_1 = Sketch_2.setVertical(SketchLine_2.result())
+SketchConstraintEqual_1 = Sketch_2.setEqual(SketchLine_1.result(), SketchLine_3.result())
+SketchProjection_2 = Sketch_2.addProjection(model.selection("VERTEX", "[Extrusion_1_1/Generated_Face&Sketch_1/SketchCircle_1_2][Extrusion_1_1/To_Face]__cc"), False)
+SketchPoint_2 = SketchProjection_2.createdFeature()
+SketchConstraintCoincidence_5 = Sketch_2.setCoincident(SketchAPI_Point(SketchPoint_2).coordinates(), SketchLine_1.startPoint())
+SketchConstraintLength_1 = Sketch_2.setLength(SketchLine_1.result(), 20)
+model.do()
+Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("FACE", "Sketch_2/Face-SketchLine_1r-SketchLine_2f-SketchLine_3f")], model.selection("EDGE", "PartSet/OX"), 180, 0)
+model.do()
+model.end()
+
+# store the reference data
+features = Part_1_doc.allFeatures()
+refData = []
+for feat in features:
+ res = []
+ for r in feat.results():
+ res.append(GeomAlgoAPI_ShapeTools.volume(r.shape()))
+ refData.append( (feat.getKind(), res) )
+
+filename = 'check_export.shaperpart'
+model.removeFile(filename)
+
+# emport the document
+model.begin()
+model.exportPart(Part_1_doc, filename)
+model.end()
+assert os.path.exists(filename), "ERROR: Cannot export {}".format(Part_1.name())
+
+# close all documents
+model.reset()
+
+# import the document
+model.begin()
+partSet = model.moduleDocument()
+model.importPart(partSet, filename)
+model.end()
+
+# Test 1. New Part should be created
+assert(partSet.size(ModelAPI_ResultPart.group()) == 1)
+newPart = modelAPI_ResultPart(objectToResult(partSet.object(ModelAPI_ResultPart.group(), 0)))
+newPart_doc = newPart.partDoc()
+
+# Test 2. Compare results with the reference data
+TOLERANCE = 1.e-7
+features = newPart_doc.allFeatures()
+assert(len(features) == len(refData))
+for feat, ref in zip(features, refData):
+ assert(feat.getKind() == ref[0])
+ for fv, rv in zip(feat.results(), ref[1]):
+ assert(math.fabs(GeomAlgoAPI_ShapeTools.volume(fv.shape()) - rv) < TOLERANCE)
+
+assert(model.checkPythonDump())
<source path="export_widget.xml" />
</feature>
<feature id="Dump" title="Dump" tooltip="Dump Python script" icon="icons/Exchange/dump.png"
- helpfile="dumpFeature.html">
+ helpfile="dumpFeature.html" abort_confirmation="false">
<export_file_selector id="file_path"
type="save"
title="Dump to file"
tooltip="To use geometrical order for identification of selected shapes"
default="false"/> -->
</feature>
+
+ <feature id="ImportPart" title="Import part" tooltip="Import features from file" icon="icons/Exchange/import_part.png"
+ helpfile="importPart.html"
+ internal="1">
+ <file_selector id="file_path" title="Import file" path="">
+ <validator id="ExchangePlugin_ImportFormat" parameters="shaperpart:Part" />
+ </file_selector>
+ </feature>
+ <feature id="ExportPart" title="Export part" tooltip="Export structure of the Part to file" icon="icons/Exchange/export_part.png"
+ helpfile="exportPart.html"
+ internal="1">
+ <export_file_selector id="file_path"
+ type="save"
+ title="Export file"
+ path="">
+ <validator id="ExchangePlugin_ExportFormat"
+ parameters="shaperpart:Part" />
+ </export_file_selector>
+ <multi_selector id="selection_list"
+ tooltip="Select features or results"
+ shape_types="Vertices Edges Faces Solids Compsolids Objects">
+ </multi_selector>
+ </feature>
</group>
</workbench>
</plugin>
\ No newline at end of file
// Collecting solids from compsolids which will not be modified
// in boolean operation and will be added to result.
+ bool isProcessCompsolid = !isSimpleCreation || aFuseVersion >= THE_FUSE_VERSION_1;
ListOfShape aShapesToAdd;
for (ObjectHierarchy::Iterator anObjectsIt = anObjectsHierarchy.Begin();
- !isSimpleCreation && anObjectsIt != anObjectsHierarchy.End();
+ isProcessCompsolid && anObjectsIt != anObjectsHierarchy.End();
++anObjectsIt) {
GeomShapePtr anObject = *anObjectsIt;
GeomShapePtr aParent = anObjectsHierarchy.Parent(anObject, false);
aMakeShapeList->appendAlgo(aCutAlgo);
}
}
- anOriginalShapes.insert(anOriginalShapes.end(), anEdgesAndFaces.begin(),
- anEdgesAndFaces.end());
+
+ if (aShapesToAdd.empty() || !aCuttedEdgesAndFaces) {
+ anOriginalShapes.insert(anOriginalShapes.end(), anEdgesAndFaces.begin(),
+ anEdgesAndFaces.end());
+ }
// If we have compsolids then cut with not used solids all others.
if (!aShapesToAdd.empty()) {
if (anObjectsNb + aToolsNb < 2) {
theError = "Not enough arguments for Fuse operation.";
return false;
- } else if (isAllInSameCompSolid) {
- theError = "Operations only between sub-shapes of the same shape not allowed.";
- return false;
}
return true;
model.testResultsVolumes(Fuse_1, [785.398163397447774514148477465])
Fuse_2 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Extrusion_1_1_3"), model.selection("SOLID", "Extrusion_1_1_1")], [model.selection("FACE", "Fuse_1_1_1")])
-assert(Fuse_2.feature().error() != "")
+model.testNbResults(Fuse_2, 1)
+model.testNbSubResults(Fuse_2, [2])
+model.testNbSubShapes(Fuse_2, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Fuse_2, GeomAPI_Shape.FACE, [19])
+model.testNbSubShapes(Fuse_2, GeomAPI_Shape.EDGE, [82])
+model.testNbSubShapes(Fuse_2, GeomAPI_Shape.VERTEX, [164])
+model.testResultsVolumes(Fuse_2, [25803.607097738855372881516814232])
model.end()
Part_1_doc.removeFeature(Fuse_1.feature())
Fuse_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Partition_1_1_1"), model.selection("SOLID", "Partition_1_1_2")])
-assert(Fuse_1.feature().error() != "")
+# after merging Union and Fuse features, fusing of solids in the same composolid should work (issue #3062)
+assert(Fuse_1.feature().error() == "")
Part_1_doc.removeFeature(Fuse_1.feature())
Fuse_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Partition_1_1_1")], [model.selection("SOLID", "Partition_1_1_2")])
-assert(Fuse_1.feature().error() != "")
+# after merging Union and Fuse features, fusing of solids in the same composolid should work (issue #3062)
+assert(Fuse_1.feature().error() == "")
Part_1_doc.removeFeature(Fuse_1.feature())
model.end()
from GeomAPI import GeomAPI_Shape
model.testNbResults(Fuse_1, 1)
-model.testNbSubResults(Fuse_1, [1])
+model.testNbSubResults(Fuse_1, [0])
model.testNbSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [0])
model.testNbSubShapes(Fuse_1, GeomAPI_Shape.FACE, [1])
model.testNbSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [2])
Fuse_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Compound_1_1_1_1")], [model.selection("SOLID", "LinearCopy_2_1_1_1"), model.selection("FACE", "Compound_1_1_2")], True)
model.end()
-assert(Fuse_1.feature().error() != "")
+from GeomAPI import *
+
+model.testNbResults(Fuse_1, 1)
+model.testNbSubResults(Fuse_1, [2])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [2])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.FACE, [16])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [78])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [156])
+model.testResultsVolumes(Fuse_1, [1589.048622670478835])
from GeomAPI import GeomAPI_Shape
model.testNbResults(Fuse_1, 1)
-model.testNbSubResults(Fuse_1, [2])
-model.testNbSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [6])
-model.testNbSubShapes(Fuse_1, GeomAPI_Shape.FACE, [23])
-model.testNbSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [70])
-model.testNbSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [140])
-model.testResultsVolumes(Fuse_1, [5016.039439659862])
+model.testNbSubResults(Fuse_1, [3])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [7])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.FACE, [31])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [108])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [216])
+model.testResultsVolumes(Fuse_1, [5516.039439659862])
assert(model.checkPythonDump())
Fuse_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Compound_1_1_1_1")], [model.selection("SOLID", "LinearCopy_2_1_1_1"), model.selection("FACE", "Compound_1_1_2")], True, 20190506)
model.end()
-assert(Fuse_1.feature().error() != "")
+from GeomAPI import *
+
+model.testNbResults(Fuse_1, 1)
+model.testNbSubResults(Fuse_1, [5])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.SOLID, [9])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.FACE, [44])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.EDGE, [160])
+model.testNbSubShapes(Fuse_1, GeomAPI_Shape.VERTEX, [320])
+model.testResultsVolumes(Fuse_1, [6516.03943965772123])
# Make union on extrusion
#=========================================================================
aSession.startOperation()
-aUnionFeature = aPart.addFeature("Union")
-aUnionFeature.selectionList("base_objects").append(anExtrusionResult.subResult(0), None);
-aUnionFeature.selectionList("base_objects").append(anExtrusionResult.subResult(1), None);
-aUnionFeature.selectionList("base_objects").append(anExtrusionResult.subResult(2), None);
+aUnionFeature = aPart.addFeature("Fuse")
+aUnionFeature.string("creation_method").setValue("simple")
+aUnionFeature.selectionList("main_objects").append(anExtrusionResult.subResult(0), None);
+aUnionFeature.selectionList("main_objects").append(anExtrusionResult.subResult(1), None);
+aUnionFeature.selectionList("main_objects").append(anExtrusionResult.subResult(2), None);
+aUnionFeature.boolean("remove_intersection_edges").setValue(False)
aSession.finishOperation()
assert (len(aUnionFeature.results()) > 0)
anUnionResult = modelAPI_ResultBody(aUnionFeature.firstResult())
Edge_1 = model.addEdge(Part_1_doc, [model.selection("EDGE", "Sketch_1/SketchArc_1_2")])
Revolution_1 = model.addRevolution(Part_1_doc, [model.selection("EDGE", "Edge_1_1")], model.selection("EDGE", "PartSet/OY"), 200, 0)
Partition_1 = model.addPartition(Part_1_doc, [model.selection("FACE", "PartSet/XOZ"), model.selection("FACE", "Revolution_1_1")])
-Union_1 = model.addUnion(Part_1_doc, [model.selection("FACE", "Partition_1_1_1"), model.selection("FACE", "Partition_1_1_2")])
+Union_1 = model.addFuse(Part_1_doc, [model.selection("FACE", "Partition_1_1_1"), model.selection("FACE", "Partition_1_1_2")], True)
model.do()
model.checkResult(Union_1,model,1,[0],[0],[1],[4],[8])
Partition_1_objects = [model.selection("FACE", "PartSet/YOZ"), model.selection("FACE", "PartSet/XOZ"), model.selection("FACE", "PartSet/XOY"), model.selection("FACE", "Revolution_1_1")]
Partition_1 = model.addPartition(Part_1_doc, Partition_1_objects)
Union_1_objects = [model.selection("FACE", "Partition_1_1_1"), model.selection("FACE", "Partition_1_1_2"), model.selection("FACE", "Partition_1_1_3"), model.selection("FACE", "Partition_1_1_4")]
-Union_1 = model.addUnion(Part_1_doc, Union_1_objects)
+Union_1 = model.addFuse(Part_1_doc, Union_1_objects, True)
model.testHaveNamingSubshapes(Union_1,model,Part_1_doc)
model.do()
model.end()
Partition_1_objects = [model.selection("FACE", "Face_2_1"), model.selection("FACE", "Face_1_1"), model.selection("FACE", "PartSet/YOZ")]
Partition_1 = model.addPartition(Part_1_doc, Partition_1_objects)
Union_1_objects = [model.selection("FACE", "Partition_1_1_1"), model.selection("FACE", "Partition_1_1_3"), model.selection("FACE", "Partition_1_1_4")]
-Union_1 = model.addUnion(Part_1_doc, Union_1_objects)
+Union_1 = model.addFuse(Part_1_doc, Union_1_objects, True, 20190506)
model.do()
model.checkResult(Union_1,model,1,[2],[0],[2],[13],[26])
-#model.testHaveNamingSubshapes(Union_1,model,Part_1_doc)
+model.testHaveNamingSubshapes(Union_1,model,Part_1_doc)
model.end()
Plane_5 = model.addPlane(Part_1_doc, model.selection("FACE", "Box_1_1/Front"), 5, True)
Partition_1_objects = [model.selection("FACE", "Plane_1"), model.selection("FACE", "Plane_2"), model.selection("SOLID", "Box_1_1")]
Partition_1 = model.addPartition(Part_1_doc, Partition_1_objects)
-Union_1 = model.addUnion(Part_1_doc, [model.selection("SOLID", "Partition_1_1_3"), model.selection("SOLID", "Partition_1_1_1")])
-Union_2 = model.addUnion(Part_1_doc, [model.selection("SOLID", "Union_1_1_2"), model.selection("SOLID", "Union_1_1_1")])
+Union_1 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Partition_1_1_3"), model.selection("SOLID", "Partition_1_1_1")], False, 20190506)
+Union_2 = model.addFuse(Part_1_doc, [model.selection("SOLID", "Fuse_1_1_2"), model.selection("SOLID", "Fuse_1_1_1")], False, 20190506)
model.do()
model.end()
<source path="boolean_split_widget.xml"/>
</feature>
<feature id="Union" title="Union" tooltip="Perform union operations with shapes"
- icon="icons/Features/union.png" helpfile="unionFeature.html">
+ icon="icons/Features/union.png" helpfile="unionFeature.html" internal="1">
<source path="union_widget.xml"/>
</feature>
<feature id="Remove_SubShapes" title="Remove Sub-Shapes" tooltip="Allows to remove sub-shapes from wires, shells, compsolids and compounds"
</group>
<group id="Measurement">
<feature id="Measurement" title="Measurement" tooltip="Calculate properties of objects"
- icon="icons/Features/measurement.png" helpfile="measurementFeature.html">
+ icon="icons/Features/measurement.png" helpfile="measurementFeature.html" abort_confirmation="false">
<source path="measurement_widget.xml"/>
</feature>
</group>
#include "GeomAlgoAPI_UnifySameDomain.h"
#include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_DFLoader.h>
#include <GeomAlgoAPI_ShapeTools.h>
#include <ShapeUpgrade_UnifySameDomain.hxx>
if (aResult.IsNull()) {
return;
}
+ // taske off the compound if it consists of single sub-shape
+ if (aResult.ShapeType() == TopAbs_COMPOUND) {
+ aResult = GeomAlgoAPI_DFLoader::refineResult(aResult);
+ }
if (theIsToSimplifyShell && aResult.ShapeType() == TopAbs_SHELL) {
int aNb = 0;
if (!myIsInitialized) {
// create attribute: not initialized by value yet, just zero
myCoords = TDataStd_RealArray::Set(myLab, 0, 2);
+ myIsInitialized = true;
}
}
Model_ResultField.h
Model_ResultGroup.h
Model_ResultParameter.h
+ Model_Tools.h
Model_Update.h
Model_Validator.h
)
Model_ResultField.cpp
Model_ResultGroup.cpp
Model_ResultParameter.cpp
+ Model_Tools.cpp
Model_Update.cpp
Model_Validator.cpp
)
../GeomAlgoAPI
../GeomAPI
../ModelGeomAlgo
+ ../ConstructionPlugin
${OpenCASCADE_INCLUDE_DIR}
)
#include <ModelAPI_Events.h>
+#include <PCDM_RetrievalDriver.hxx>
+
IMPLEMENT_STANDARD_RTTIEXT(Model_Application, TDocStd_Application)
static Handle_Model_Application TheApplication = new Model_Application;
// store handle to the application to avoid nullification
static Handle(Model_Application) TheKeepHandle;
TheKeepHandle = this;
+ // additional file format supported
+ static TCollection_ExtendedString THE_DOC_FORMAT("BinShaperPart");
+ static TCollection_ExtendedString THE_FILE_EXT("shaperpart");
+ Handle(PCDM_RetrievalDriver) aReader =
+ Handle(PCDM_RetrievalDriver)::DownCast(TheKeepHandle->ReaderFromFormat("BinOcaf"));
+ Handle(PCDM_StorageDriver) aWriter = TheKeepHandle->WriterFromFormat("BinOcaf");
+ TheKeepHandle->DefineFormat(THE_DOC_FORMAT, "Shaper Part document", THE_FILE_EXT,
+ aReader, aWriter);
}
//=======================================================================
myIsInitialized = myLab.FindAttribute(TDF_Reference::GetID(), myRef) == Standard_True;
if (!myIsInitialized) {
myRef = TDF_Reference::Set(myLab, myLab); // not initialized references to itself
+ myIsInitialized = true;
} else {
if (owner()) {
std::shared_ptr<Model_Document> aDoc =
std::shared_ptr<GeomAPI_Shape> Model_AttributeSelection::value()
{
- if (!ModelAPI_AttributeSelection::isInitialized() && !myTmpContext.get() && !myTmpSubShape.get())
+ if (!myRef.isInitialized() && !myTmpContext.get() && !myTmpSubShape.get())
return std::shared_ptr<GeomAPI_Shape>();
CenterType aType = NOT_CENTER;
std::shared_ptr<GeomAPI_Shape> aResult = internalValue(aType);
bool Model_AttributeSelection::isInitialized()
{
- if (ModelAPI_AttributeSelection::isInitialized()) { // additional checks if it is initialized
- std::shared_ptr<GeomAPI_Shape> aResult;
- if (myRef.isInitialized()) {
- TDF_Label aSelLab = selectionLabel();
- // it is just reference to shape, not sub-shape
- if (aSelLab.IsAttribute(kSIMPLE_REF_ID) || aSelLab.IsAttribute(kPART_REF_ID)) {
- ResultPtr aContext = context();
- return aContext.get() != NULL;
- }
- Handle(TNaming_NamedShape) aSelection;
- if (selectionLabel().FindAttribute(TNaming_NamedShape::GetID(), aSelection)) {
- return !aSelection->Get().IsNull();
- } else { // for simple construction element: just shape of this construction element
- if (myRef.value().get())
- return true;
- // check that this is on open of document, so, results are not initialized yet
- TDF_Label aRefLab = myRef.myRef->Get();
- if (aRefLab.IsNull() || !owner().get())
- return false;
- std::shared_ptr<Model_Document> aMyDoc =
- std::dynamic_pointer_cast<Model_Document>(owner()->document());
- if (!aMyDoc.get())
- return false;
- // check at least the feature exists
- return aMyDoc->featureByLab(aRefLab).get() != NULL;
- }
+ if (myRef.isInitialized()) {
+ TDF_Label aSelLab = selectionLabel();
+ // it is just reference to shape, not sub-shape
+ if (aSelLab.IsAttribute(kSIMPLE_REF_ID) || aSelLab.IsAttribute(kPART_REF_ID)) {
+ ResultPtr aContext = context();
+ return aContext.get() != NULL;
+ }
+ Handle(TNaming_NamedShape) aSelection;
+ if (selectionLabel().FindAttribute(TNaming_NamedShape::GetID(), aSelection)) {
+ return !aSelection->Get().IsNull();
+ } else { // for simple construction element: just shape of this construction element
+ if (myRef.value().get())
+ return true;
+ // check that this is on open of document, so, results are not initialized yet
+ TDF_Label aRefLab = myRef.myRef->Get();
+ if (aRefLab.IsNull() || !owner().get())
+ return false;
+ std::shared_ptr<Model_Document> aMyDoc =
+ std::dynamic_pointer_cast<Model_Document>(owner()->document());
+ if (!aMyDoc.get())
+ return false;
+ // check at least the feature exists
+ return aMyDoc->featureByLab(aRefLab).get() != NULL;
}
}
return false;
ResultPtr Model_AttributeSelection::context()
{
- if (!ModelAPI_AttributeSelection::isInitialized() && !myTmpContext.get() && !myTmpSubShape.get())
+ if (!myRef.isInitialized() && !myTmpContext.get() && !myTmpSubShape.get())
return ResultPtr();
if (myTmpContext.get() || myTmpSubShape.get()) {
static TDF_Label anEmpty;
return anEmpty;
}
+
+void Model_AttributeSelection::reset()
+{
+ ModelAPI_AttributeSelection::reset();
+ myRef.reset();
+}
/// Makes the current local selection becomes all sub-shapes with same base geometry.
MODEL_EXPORT virtual void combineGeometrical();
+ /// Resets attribute to deafult state
+ MODEL_EXPORT virtual void reset();
+
protected:
/// Objects are created for features automatically
MODEL_EXPORT Model_AttributeSelection(TDF_Label& theLabel);
#include <Model_AttributeTables.h>
#include <Model_Events.h>
#include <Model_Expression.h>
+#include <Model_Tools.h>
+#include <Model_Validator.h>
+
#include <ModelAPI_Feature.h>
#include <ModelAPI_Result.h>
#include <ModelAPI_ResultParameter.h>
#include <ModelAPI_Session.h>
#include <ModelAPI_ResultPart.h>
#include <ModelAPI_Tools.h>
-#include <Model_Validator.h>
#include <GeomDataAPI_Point.h>
#include <GeomDataAPI_Point2D.h>
#include <TDataStd_Name.hxx>
#include <TDataStd_AsciiString.hxx>
-#include <TDataStd_IntegerArray.hxx>
#include <TDataStd_UAttribute.hxx>
-#include <TDF_AttributeIterator.hxx>
-#include <TDF_ChildIterator.hxx>
-#include <TDF_RelocationTable.hxx>
#include <TDF_ChildIDIterator.hxx>
-#include <TColStd_HArray1OfByte.hxx>
#include <string>
}
}
-/// makes copy of all attributes on the given label and all sub-labels
-static void copyAttrs(TDF_Label theSource, TDF_Label theDestination) {
- TDF_AttributeIterator anAttrIter(theSource);
- for(; anAttrIter.More(); anAttrIter.Next()) {
- Handle(TDF_Attribute) aTargetAttr;
- if (!theDestination.FindAttribute(anAttrIter.Value()->ID(), aTargetAttr)) {
- // create a new attribute if not yet exists in the destination
- aTargetAttr = anAttrIter.Value()->NewEmpty();
- theDestination.AddAttribute(aTargetAttr);
- }
- // no special relocation, empty map, but self-relocation is on: copy references w/o changes
- Handle(TDF_RelocationTable) aRelocTable = new TDF_RelocationTable(Standard_True);
- anAttrIter.Value()->Paste(aTargetAttr, aRelocTable);
- // an exception: if a source reference refers itself, a copy must also refer itself
- if (aTargetAttr->ID() == TDF_Reference::GetID()) {
- Handle(TDF_Reference) aTargetRef = Handle(TDF_Reference)::DownCast(aTargetAttr);
- if (aTargetRef->Get().IsEqual(anAttrIter.Value()->Label()))
- aTargetRef->Set(aTargetRef->Label());
- }
- }
- // copy the sub-labels content
- TDF_ChildIterator aSubLabsIter(theSource);
- for(; aSubLabsIter.More(); aSubLabsIter.Next()) {
- copyAttrs(aSubLabsIter.Value(), theDestination.FindChild(aSubLabsIter.Value().Tag()));
- }
-}
-
void Model_Data::copyTo(std::shared_ptr<ModelAPI_Data> theTarget)
{
TDF_Label aTargetRoot = std::dynamic_pointer_cast<Model_Data>(theTarget)->label();
- copyAttrs(myLab, aTargetRoot);
+ Model_Tools::copyAttrs(myLab, aTargetRoot);
// reinitialize Model_Attributes by TDF_Attributes set
std::shared_ptr<Model_Data> aTData = std::dynamic_pointer_cast<Model_Data>(theTarget);
aTData->myAttrs.clear();
friend class Model_SelectionNaming;
friend class Model_ResultConstruction;
friend class Model_ResultBody;
+ friend class Model_Tools;
public:
/// The simplest constructor. "setLabel" must be called just after to initialize correctly.
#include <Model_Application.h>
#include <Model_Session.h>
#include <Model_Events.h>
+#include <Model_Tools.h>
#include <ModelAPI_ResultPart.h>
#include <ModelAPI_Validator.h>
#include <ModelAPI_CompositeFeature.h>
#include <TNaming_Iterator.hxx>
#include <TNaming_NamedShape.hxx>
#include <TNaming_Tool.hxx>
-#include<TNaming_OldShapeIterator.hxx>
+#include <TNaming_OldShapeIterator.hxx>
#include <TopTools_DataMapOfShapeShape.hxx>
#include <TopTools_ListOfShape.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS_Shape.hxx>
+#include <OSD_Directory.hxx>
#include <OSD_File.hxx>
#include <OSD_Path.hxx>
+#include <OSD_Protection.hxx>
#include <CDF_Session.hxx>
#include <CDF_Directory.hxx>
+#include <UTL.hxx>
#include <climits>
#ifndef WIN32
}
// LCOV_EXCL_STOP
-bool Model_Document::load(const char* theDirName, const char* theFileName, DocumentPtr theThis)
+static bool loadDocument(Handle(Model_Application) theApp,
+ Handle(TDocStd_Document)& theDoc,
+ const TCollection_ExtendedString& theFilename)
{
- Handle(Model_Application) anApp = Model_Application::getApplication();
- if (isRoot()) {
- anApp->setLoadPath(theDirName);
- }
- TCollection_ExtendedString aPath(DocFileName(theDirName, theFileName));
- PCDM_ReaderStatus aStatus = (PCDM_ReaderStatus) -1;
- Handle(TDocStd_Document) aLoaded;
+ PCDM_ReaderStatus aStatus = (PCDM_ReaderStatus)-1;
try {
- aStatus = anApp->Open(aPath, aLoaded);
+ aStatus = theApp->Open(theFilename, theDoc);
} catch (Standard_Failure const& anException) {
Events_InfoMessage("Model_Document",
"Exception in opening of document: %1").arg(anException.GetMessageString()).send();
return false;
}
- bool isError = aStatus != PCDM_RS_OK;
- if (isError) {
+ bool isOk = aStatus == PCDM_RS_OK;
+ if (!isOk) {
// LCOV_EXCL_START
switch (aStatus) {
case PCDM_RS_UnknownDocument:
}
// LCOV_EXCL_STOP
}
+ return isOk;
+}
+
+bool Model_Document::load(const char* theDirName, const char* theFileName, DocumentPtr theThis)
+{
+ Handle(Model_Application) anApp = Model_Application::getApplication();
+ if (isRoot()) {
+ anApp->setLoadPath(theDirName);
+ }
+ TCollection_ExtendedString aPath(DocFileName(theDirName, theFileName));
+ Handle(TDocStd_Document) aLoaded;
+ bool isOk = loadDocument(anApp, aLoaded, aPath);
+
std::shared_ptr<Model_Session> aSession =
std::dynamic_pointer_cast<Model_Session>(Model_Session::get());
- if (!isError) {
+ if (isOk) {
myDoc = aLoaded;
myDoc->SetUndoLimit(UNDO_LIMIT);
} else { // open failed, but new document was created to work with it: inform the model
aSession->setActiveDocument(Model_Session::get()->moduleDocument(), false);
}
- return !isError;
+ return isOk;
+}
+
+bool Model_Document::import(const char* theFileName,
+ std::list<std::shared_ptr<ModelAPI_Feature> >& theImported,
+ bool theCheckBefore)
+{
+ Handle(Model_Application) anApp = Model_Application::getApplication();
+ TCollection_ExtendedString aFormat;
+ if (!anApp->Format(theFileName, aFormat))
+ return false;
+
+ Handle(TDocStd_Document) aTempDoc;
+ bool isOk = loadDocument(anApp, aTempDoc, theFileName);
+
+ if (isOk && theCheckBefore) {
+ // verify all features are applicable for the current document type (e.g. PartSet)
+ std::shared_ptr<Model_Session> aSession =
+ std::dynamic_pointer_cast<Model_Session>(ModelAPI_Session::get());
+ for (TDF_ChildIterator anIt(aTempDoc->Main()); anIt.More() && isOk; anIt.Next()) {
+ TDF_Label aCurrentLab = anIt.Value();
+ Handle(TDataStd_Comment) aFeatureID;
+ TDF_Label aNewFeatuerLab;
+ if (aCurrentLab.FindAttribute(TDataStd_Comment::GetID(), aFeatureID)) {
+ TCollection_AsciiString anID(aFeatureID->Get());
+ std::string aFeatureKind(anID.ToCString());
+ if (aSession->myPlugins.find(aFeatureKind) != aSession->myPlugins.end()) {
+ std::string& aDocKind = aSession->myPlugins[aFeatureKind].second;
+ isOk = aDocKind.empty() || aDocKind == kind();
+ }
+ }
+ }
+ }
+
+ if (isOk) {
+ // copy features from the temporary document to the current
+ Handle(TDF_RelocationTable) aRelocTable = new TDF_RelocationTable();
+ TDF_LabelList anAllNewFeatures;
+ // Perform the copying twice for correct references:
+ // 1. copy labels hierarchy and fill the relocation table
+ TDF_Label aMain = myDoc->Main();
+ for (TDF_ChildIterator anIt(aTempDoc->Main()); anIt.More(); anIt.Next()) {
+ TDF_Label aCurrentLab = anIt.Value();
+ Handle(TDataStd_Comment) aFeatureID;
+ TDF_Label aNewFeatuerLab;
+ if (aCurrentLab.FindAttribute(TDataStd_Comment::GetID(), aFeatureID)) {
+ TCollection_AsciiString anID(aFeatureID->Get());
+ FeaturePtr aNewFeature = addFeature(anID.ToCString());
+ std::shared_ptr<Model_Data> aData =
+ std::dynamic_pointer_cast<Model_Data>(aNewFeature->data());
+ aNewFeatuerLab = aData->label().Father();
+ Model_Tools::copyLabels(aCurrentLab, aNewFeatuerLab, aRelocTable);
+ theImported.push_back(aNewFeature);
+ }
+ anAllNewFeatures.Append(aNewFeatuerLab);
+ }
+ // 2. copy attributes
+ std::set<TCollection_AsciiString> aCoordinateLabels;
+ Model_Tools::labelsOfCoordinates(aCoordinateLabels, aRelocTable);
+ TDF_ListIteratorOfLabelList aNewIt(anAllNewFeatures);
+ for (TDF_ChildIterator anIt(aTempDoc->Main()); anIt.More(); anIt.Next()) {
+ TDF_Label aCurrentLab = anIt.Value();
+ TDF_Label aFeatureLab = aNewIt.Value();
+ if (aFeatureLab.IsNull())
+ anAllNewFeatures.Remove(aNewIt);
+ else {
+ Model_Tools::copyAttrsAndKeepRefsToCoordinates(
+ aCurrentLab, aFeatureLab, aCoordinateLabels, aRelocTable);
+ aNewIt.Next();
+ }
+ }
+
+ myObjs->synchronizeFeatures(anAllNewFeatures, true, false, false, true);
+ }
+
+ if (anApp->CanClose(aTempDoc) == CDM_CCS_OK)
+ anApp->Close(aTempDoc);
+ return isOk;
+}
+
+static bool saveDocument(Handle(Model_Application) theApp,
+ Handle(TDocStd_Document) theDoc,
+ const TCollection_ExtendedString& theFilename)
+{
+ PCDM_StoreStatus aStatus;
+ try {
+ // create the directory to save the document
+ OSD_Path aPathToFile = UTL::Path(theFilename);
+ aPathToFile.SetName("");
+ aPathToFile.SetExtension("");
+ OSD_Directory aBaseDir(aPathToFile);
+ if (aPathToFile.TrekLength() != 0 && !aBaseDir.Exists())
+ aBaseDir.Build(OSD_Protection());
+ // save the document
+ aStatus = theApp->SaveAs(theDoc, theFilename);
+ }
+ catch (Standard_Failure const& anException) {
+ Events_InfoMessage("Model_Document",
+ "Exception in saving of document: %1").arg(anException.GetMessageString()).send();
+ return false;
+ }
+ bool isDone = aStatus == PCDM_SS_OK || aStatus == PCDM_SS_No_Obj;
+ if (!isDone) {
+ switch (aStatus) {
+ case PCDM_SS_DriverFailure:
+ Events_InfoMessage("Model_Document",
+ "Can not save document: save driver-library failure").send();
+ break;
+ case PCDM_SS_WriteFailure:
+ Events_InfoMessage("Model_Document", "Can not save document: file writing failure").send();
+ break;
+ case PCDM_SS_Failure:
+ default:
+ Events_InfoMessage("Model_Document", "Can not save document").send();
+ break;
+ }
+ }
+ return isDone;
}
bool Model_Document::save(
}
// filename in the dir is id of document inside of the given directory
TCollection_ExtendedString aPath(DocFileName(theDirName, theFileName));
- PCDM_StoreStatus aStatus;
- try {
- aStatus = anApp->SaveAs(myDoc, aPath);
- } catch (Standard_Failure const& anException) {
- Events_InfoMessage("Model_Document",
- "Exception in saving of document: %1").arg(anException.GetMessageString()).send();
- if (aWasCurrent.get()) { // return the current feature to the initial position
- setCurrentFeature(aWasCurrent, false);
- aSession->setCheckTransactions(true);
- }
- return false;
- }
- bool isDone = aStatus == PCDM_SS_OK || aStatus == PCDM_SS_No_Obj;
- if (!isDone) {
- switch (aStatus) {
- case PCDM_SS_DriverFailure:
- Events_InfoMessage("Model_Document",
- "Can not save document: save driver-library failure").send();
- break;
- case PCDM_SS_WriteFailure:
- Events_InfoMessage("Model_Document", "Can not save document: file writing failure").send();
- break;
- case PCDM_SS_Failure:
- default:
- Events_InfoMessage("Model_Document", "Can not save document").send();
- break;
- }
- }
+ bool isDone = saveDocument(anApp, myDoc, aPath);
if (aWasCurrent.get()) { // return the current feature to the initial position
setCurrentFeature(aWasCurrent, false);
return isDone;
}
+bool Model_Document::save(const char* theFilename,
+ const std::list<FeaturePtr>& theExportFeatures) const
+{
+ Handle(Model_Application) anApp = Model_Application::getApplication();
+ TCollection_ExtendedString aFormat;
+ if (!anApp->Format(theFilename, aFormat))
+ return false;
+
+ Handle(TDocStd_Document) aTempDoc = new TDocStd_Document(aFormat);
+ TDF_Label aMain = aTempDoc->Main();
+
+ Handle(TDF_RelocationTable) aRelocTable = new TDF_RelocationTable();
+ std::list<FeaturePtr>::const_iterator anIt = theExportFeatures.begin();
+ // Perform the copying twice for correct references:
+ // 1. copy labels hierarchy and fill the relocation table
+ for (; anIt != theExportFeatures.end(); ++anIt) {
+ TDF_Label aFeatureLab = aMain.NewChild();
+ std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>((*anIt)->data());
+ Model_Tools::copyLabels(aData->label().Father(), aFeatureLab, aRelocTable);
+ }
+ // 2. copy attributes
+ std::set<TCollection_AsciiString> aCoordinateLabels;
+ Model_Tools::labelsOfCoordinates(aCoordinateLabels, aRelocTable);
+ TDF_ChildIterator aChildIt(aMain);
+ for (anIt = theExportFeatures.begin(); anIt != theExportFeatures.end(); ++anIt) {
+ TDF_Label aFeatureLab = aChildIt.Value();
+ std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>((*anIt)->data());
+ Model_Tools::copyAttrsAndKeepRefsToCoordinates(
+ aData->label().Father(), aFeatureLab, aCoordinateLabels, aRelocTable);
+ aChildIt.Next();
+ }
+
+ bool isDone = saveDocument(anApp, aTempDoc, theFilename);
+ if (aTempDoc->CanClose() == CDM_CCS_OK)
+ aTempDoc->Close();
+ return isDone;
+}
+
void Model_Document::close(const bool theForever)
{
std::shared_ptr<ModelAPI_Session> aPM = Model_Session::get();
MODEL_EXPORT virtual bool load(
const char* theDirName, const char* theFileName, DocumentPtr theThis);
+ //! Loads the OCAF document from the file into the current document.
+ //! All the features are added after the active feature.
+ //! \param theFileName name of the file to import
+ //! \param theImported list of features imported from the file
+ //! \param theCheckBefore verify the document does not contain unappropriate features
+ //! (useful for import to PartSet)
+ //! \returns true if file was loaded successfully
+ MODEL_EXPORT virtual bool import(const char* theFileName,
+ std::list<std::shared_ptr<ModelAPI_Feature> >& theImported,
+ bool theCheckBefore = false);
+
//! Saves the OCAF document to the file.
//! \param theDirName directory where the document will be saved
//! \param theFileName a name of the document file to store
MODEL_EXPORT virtual bool save(
const char* theDirName, const char* theFileName, std::list<std::string>& theResults);
+ //! Export the list of features to the file
+ //! \param theFilename path to save the file
+ //! \param theExportFeatures list of features to export
+ MODEL_EXPORT virtual bool save(const char* theFilename,
+ const std::list<std::shared_ptr<ModelAPI_Feature> >& theExportFeatures) const;
+
//! Removes document data
//! \param theForever if it is false, document is just hidden
//! (to keep possibility make it back on Undo/Redo)
--- /dev/null
+// Copyright (C) 2014-2019 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_Tools.h>
+#include <Model_Data.h>
+
+#include <ModelAPI_Document.h>
+#include <ModelAPI_Feature.h>
+#include <ModelAPI_Result.h>
+#include <ModelAPI_Session.h>
+
+#include <ConstructionPlugin_Axis.h>
+#include <ConstructionPlugin_Plane.h>
+#include <ConstructionPlugin_Point.h>
+
+#include <Standard_GUID.hxx>
+
+#include <TDataStd_Comment.hxx>
+#include <TDataStd_AsciiString.hxx>
+
+#include <TDF_AttributeIterator.hxx>
+#include <TDF_ChildIterator.hxx>
+#include <TDF_Reference.hxx>
+#include <TDF_RelocationTable.hxx>
+#include <TDF_Tool.hxx>
+
+void Model_Tools::copyLabels(TDF_Label theSource, TDF_Label theDestination,
+ Handle(TDF_RelocationTable) theRelocTable)
+{
+ theRelocTable->SetRelocation(theSource, theDestination);
+ // copy the sub-labels hierarchy
+ TDF_ChildIterator aSubLabsIter(theSource);
+ for (; aSubLabsIter.More(); aSubLabsIter.Next()) {
+ copyLabels(aSubLabsIter.Value(),
+ theDestination.FindChild(aSubLabsIter.Value().Tag()),
+ theRelocTable);
+ }
+}
+
+void Model_Tools::copyAttrs(TDF_Label theSource, TDF_Label theDestination,
+ Handle(TDF_RelocationTable) theRelocTable)
+{
+ TDF_AttributeIterator anAttrIter(theSource);
+ for(; anAttrIter.More(); anAttrIter.Next()) {
+ Handle(TDF_Attribute) aTargetAttr;
+ if (!theDestination.FindAttribute(anAttrIter.Value()->ID(), aTargetAttr)) {
+ // create a new attribute if not yet exists in the destination
+ aTargetAttr = anAttrIter.Value()->NewEmpty();
+ theDestination.AddAttribute(aTargetAttr);
+ }
+ // no special relocation, empty map, but self-relocation is on: copy references w/o changes
+ Handle(TDF_RelocationTable) aRelocTable =
+ theRelocTable.IsNull() ? new TDF_RelocationTable(Standard_True) : theRelocTable;
+ anAttrIter.Value()->Paste(aTargetAttr, aRelocTable);
+ // an exception: if a source reference refers itself, a copy must also refer itself
+ if (aTargetAttr->ID() == TDF_Reference::GetID()) {
+ Handle(TDF_Reference) aTargetRef = Handle(TDF_Reference)::DownCast(aTargetAttr);
+ if (aTargetRef->Get().IsEqual(anAttrIter.Value()->Label()))
+ aTargetRef->Set(aTargetRef->Label());
+ }
+ }
+ // copy the sub-labels content
+ TDF_ChildIterator aSubLabsIter(theSource);
+ for(; aSubLabsIter.More(); aSubLabsIter.Next()) {
+ copyAttrs(aSubLabsIter.Value(),
+ theDestination.FindChild(aSubLabsIter.Value().Tag()),
+ theRelocTable);
+ }
+}
+
+static TCollection_AsciiString labelToString(TDF_Label theLabel)
+{
+ TCollection_AsciiString aLabString;
+ TDF_Tool::Entry(theLabel, aLabString);
+ return aLabString;
+}
+
+static void makeExternalReference(TDF_Label theDestination, TDF_Label theReferred)
+{
+ Handle(TDF_Attribute) aReference, aComment, aString;
+ theDestination.FindAttribute(TDF_Reference::GetID(), aReference);
+ // create new attributes if not yet exists in the destination
+ if (!theDestination.FindAttribute(TDataStd_Comment::GetID(), aComment)) {
+ aComment = new TDataStd_Comment;
+ theDestination.AddAttribute(aComment);
+ }
+ if (!theDestination.FindAttribute(TDataStd_AsciiString::GetID(), aString)) {
+ aString = new TDataStd_AsciiString;
+ theDestination.AddAttribute(aString);
+ }
+ // reference to itself
+ Handle(TDF_Reference)::DownCast(aReference)->Set(theDestination, theDestination);
+ // ID of the document
+ std::ostringstream aDocIdStr;
+ aDocIdStr << ModelAPI_Session::get()->moduleDocument()->id();
+ Handle(TDataStd_Comment)::DownCast(aComment)->Set(aDocIdStr.str().c_str());
+ // value of referred label
+ Handle(TDataStd_AsciiString)::DownCast(aString)->Set(labelToString(theReferred));
+}
+
+void Model_Tools::copyAttrsAndKeepRefsToCoordinates(
+ TDF_Label theSource,
+ TDF_Label theDestination,
+ const std::set<TCollection_AsciiString>& theCoordinateLabels,
+ Handle(TDF_RelocationTable) theRelocTable)
+{
+ TDF_AttributeIterator anAttrIter(theSource);
+ for(; anAttrIter.More(); anAttrIter.Next()) {
+ Handle(TDF_Attribute) aTargetAttr;
+ if (!theDestination.FindAttribute(anAttrIter.Value()->ID(), aTargetAttr)) {
+ // create a new attribute if not yet exists in the destination
+ aTargetAttr = anAttrIter.Value()->NewEmpty();
+ theDestination.AddAttribute(aTargetAttr);
+ }
+ anAttrIter.Value()->Paste(aTargetAttr, theRelocTable);
+ if (aTargetAttr->ID() == TDF_Reference::GetID()) {
+ Handle(TDF_Reference) aTargetRef = Handle(TDF_Reference)::DownCast(aTargetAttr);
+ if (aTargetRef->Get().IsNull()) {
+ // may be refer to a cartesian coordinate entity
+ Handle(TDF_Reference) aSourceRef = Handle(TDF_Reference)::DownCast(anAttrIter.Value());
+ if (!aSourceRef.IsNull() && !aSourceRef->Get().IsNull()) {
+ std::set<TCollection_AsciiString>::const_iterator aFound =
+ theCoordinateLabels.find(labelToString(aSourceRef->Get()));
+ if (aFound != theCoordinateLabels.end())
+ makeExternalReference(theDestination, aSourceRef->Get());
+ }
+ }
+ else if (aTargetRef->Get().IsEqual(anAttrIter.Value()->Label())) {
+ // a source reference refers itself, a copy must also refer itself
+ aTargetRef->Set(aTargetRef->Label());
+ }
+ }
+ }
+ // copy the sub-labels content
+ TDF_ChildIterator aSubLabsIter(theSource);
+ for(; aSubLabsIter.More(); aSubLabsIter.Next()) {
+ copyAttrsAndKeepRefsToCoordinates(
+ aSubLabsIter.Value(), theDestination.FindChild(aSubLabsIter.Value().Tag()),
+ theCoordinateLabels, theRelocTable);
+ }
+}
+
+void Model_Tools::labelsOfCoordinates(std::set<TCollection_AsciiString>& theCoordinateLabels,
+ Handle(TDF_RelocationTable) theRelocTable)
+{
+ DocumentPtr aPartSet = ModelAPI_Session::get()->moduleDocument();
+ std::list<FeaturePtr> aFeatures = aPartSet->allFeatures();
+ for (std::list<FeaturePtr>::iterator aFIt = aFeatures.begin(); aFIt != aFeatures.end(); ++aFIt) {
+ FeaturePtr aCurFeat = *aFIt;
+ if (!aCurFeat->isInHistory() &&
+ (aCurFeat->getKind() == ConstructionPlugin_Point::ID() ||
+ aCurFeat->getKind() == ConstructionPlugin_Axis::ID() ||
+ aCurFeat->getKind() == ConstructionPlugin_Plane::ID())) {
+ ResultPtr aResult = aCurFeat->lastResult();
+ if (aResult) {
+ std::shared_ptr<Model_Data> aResData =
+ std::dynamic_pointer_cast<Model_Data>(aResult->data());
+ TDF_Label aLab = aResData->label().Father();
+ theCoordinateLabels.insert(labelToString(aLab));
+ // set relocation to empty, references will be set correctly while copying attributes
+ theRelocTable->SetRelocation(aLab, TDF_Label());
+ }
+ }
+ }
+}
--- /dev/null
+// Copyright (C) 2014-2019 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_Tools_H_
+#define Model_Tools_H_
+
+#include <Model.h>
+
+#include <TDF_Label.hxx>
+#include <TDF_RelocationTable.hxx>
+
+#include <memory>
+#include <set>
+
+/// A collection of methods useful for different parts of data model.
+class Model_Tools
+{
+public:
+ /// makes copy of label and all its sub-labels without copying the attributes;
+ /// and feel the relocation table
+ static void copyLabels(TDF_Label theSource, TDF_Label theDestination,
+ Handle(TDF_RelocationTable) theRelocTable);
+
+ /// makes copy of all attributes on the given label and all sub-labels
+ static void copyAttrs(TDF_Label theSource, TDF_Label theDestination,
+ Handle(TDF_RelocationTable) theRelocTable = Handle(TDF_RelocationTable)());
+
+ /// makes copy of all attributes on the given label and all sub-labels,
+ /// but keep references to the Origin, coordinate axes and coordinate planes
+ static void copyAttrsAndKeepRefsToCoordinates(TDF_Label theSource, TDF_Label theDestination,
+ const std::set<TCollection_AsciiString>& theCoordinateLabels,
+ Handle(TDF_RelocationTable) theRelocTable);
+
+ /// collect labels of coordinate planes, axes, and origin
+ static void labelsOfCoordinates(
+ std::set<TCollection_AsciiString>& theCoordinateLabels,
+ Handle(TDF_RelocationTable) theRelocTable);
+};
+
+#endif
MODELAPI_EXPORT virtual std::shared_ptr<ModelAPI_Feature> nextFeature(
std::shared_ptr<ModelAPI_Feature> theCurrent, const bool theReverse = false) const = 0;
+ /// Loads the OCAF document from the file into the current document.
+ /// All the features are added after the active feature.
+ /// \param theFileName name of the file to import
+ /// \param theImported list of features imported from the file
+ /// \param theCheckBefore verify the document does not contain unappropriate features
+ /// (useful for import to PartSet)
+ /// \returns true if file was loaded successfully
+ MODELAPI_EXPORT virtual bool import(const char* theFileName,
+ std::list<std::shared_ptr<ModelAPI_Feature> >& theImported,
+ bool theCheckBefore = false) = 0;
+
+ /// Export the list of features to the file
+ /// \param theFilename path to save the file
+ /// \param theExportFeatures list of features to export
+ MODELAPI_EXPORT virtual bool save(const char* theFilename,
+ const std::list<std::shared_ptr<ModelAPI_Feature> >& theExportFeatures) const = 0;
+
protected:
//! Only for SWIG wrapping it is here
MODELAPI_EXPORT ModelAPI_Document();
double aValues[3] = {anAttr->x(), anAttr->y(), anAttr->z()};
dumpArray(aResult, aValues, 3);
} else if (aType == GeomDataAPI_Dir::typeId()) {
+ if (theAttr->id() == "DistanceDirection")
+ return "__notcase__";
AttributeDirPtr anAttr = std::dynamic_pointer_cast<GeomDataAPI_Dir>(theAttr);
double aValues[3] = {anAttr->x(), anAttr->y(), anAttr->z()};
dumpArray(aResult, aValues, 3);
ModuleBase_ListView.h
ModuleBase_ModelWidget.h
ModuleBase_Operation.h
- ModuleBase_OperationAction.h
ModuleBase_OperationDescription.h
ModuleBase_OperationFeature.h
ModuleBase_PageBase.h
ModuleBase_WidgetSelectionFilter.h
ModuleBase_IStepPrs.h
ModuleBase_SelectionFilterType.h
+ ModuleBase_WidgetUndoLabel.h
)
SET(PROJECT_MOC_HEADERS
ModuleBase_ModelDialogWidget.h
ModuleBase_ModelWidget.h
ModuleBase_Operation.h
- ModuleBase_OperationAction.h
ModuleBase_OperationFeature.h
ModuleBase_PagedContainer.h
ModuleBase_PageGroupBox.h
ModuleBase_WidgetRadiobox.h
ModuleBase_WidgetPointInput.h
ModuleBase_WidgetSelectionFilter.h
+ ModuleBase_WidgetUndoLabel.h
)
SET(PROJECT_SOURCES
ModuleBase_ListView.cpp
ModuleBase_ModelWidget.cpp
ModuleBase_Operation.cpp
- ModuleBase_OperationAction.cpp
ModuleBase_OperationDescription.cpp
ModuleBase_OperationFeature.cpp
ModuleBase_PageBase.cpp
ModuleBase_WidgetPointInput.cpp
ModuleBase_WidgetSelectionFilter.cpp
ModuleBase_IStepPrs.cpp
+ ModuleBase_WidgetUndoLabel.cpp
)
SET(TEXT_RESOURCES
#include <QRadioButton>
#include <QToolButton>
+const QString AStyle = "QToolButton:checked {border: 1px solid black; background-color:#C0DCF3}";
+
+
ModuleBase_ChoiceCtrl::ModuleBase_ChoiceCtrl(QWidget* theParent,
const QStringList& theChoiceList,
const QStringList& theIconsList,
QPixmap aIcon = ModuleBase_IconFactory::loadPixmap(theIconsList.at(aId));
aBtn->setIcon(aIcon);
aBtn->setIconSize(aIcon.size());
+ aBtn->setStyleSheet(AStyle);
aBtnLayout->addWidget(aBtn);
myButtons->addButton(aBtn, aId++);
/// Have an opportunity to create widgets for the current operation
/// instead of standard creation in workshop
- /// \param theOperation a started operation
+ /// \param theFeature a feature of the started operation
+ /// \param theXmlRepr an XML representation of the operation
/// \param theWidgets a list of created widgets
/// \return boolean result, false by default
- virtual bool createWidgets(ModuleBase_Operation* theOperation,
+ virtual bool createWidgets(const FeaturePtr& theFeature, const QString& theXmlRepr,
QList<ModuleBase_ModelWidget*>& theWidgets) const { return false; }
//! Returns True if there are available Undos and there is not an active operation
}
return aFirstWidget;
}
+
+bool ModuleBase_IPropertyPanel::isModified() const
+{
+ bool isModified = false;
+ QList<ModuleBase_ModelWidget*> aWidgets = modelWidgets();
+ foreach(ModuleBase_ModelWidget* aWgt, aWidgets) {
+ bool aRes = aWgt->isModified();
+ isModified |= aRes;
+ }
+ return isModified;
+}
/// The method is called on accepting of operation
virtual void onAcceptData() = 0;
+ /// Returns True if data of its feature was modified during operation
+ virtual bool isModified() const;
+
/// Returns the first widget, where canAcceptFocus returns true
/// \return a widget or null
static ModuleBase_ModelWidget* findFirstAcceptingValueWidget(
//! \param theAIS the object which has to be activated
virtual void applyCurrentSelectionModes(const AISObjectPtr& theAIS) = 0;
+ //! Undo last command
+ virtual void undo() = 0;
+
+ //! Set enabled state of cancel button in property panel
+ virtual void setCancelEnabled(bool toEnable) = 0;
+
+ //! Returns current state of cancel button
+ virtual bool isCancelEnabled() const = 0;
+
signals:
/// Signal selection changed.
void selectionChanged();
}
}
+//********************************************************************
+void ModuleBase_ListView::selectIndices(const std::set<int>& theIndices)
+{
+ myListControl->clearSelection();
+ for (int i = 0; i < myListControl->count(); i++) {
+ QListWidgetItem* anItem = myListControl->item(i);
+ int aId = anItem->data(ATTRIBUTE_SELECTION_INDEX_ROLE).toInt();
+ if (theIndices.find(aId) != theIndices.end()) {
+ anItem->setSelected(true);
+ }
+ }
+}
+
//********************************************************************
void ModuleBase_ListView::removeSelectedItems()
{
/// \param theIndices an output container for indices
void getSelectedIndices(std::set<int>& theIndices);
+ /// Selects items with indices
+ /// \param theIndices indices
+ void selectIndices(const std::set<int>& theIndices);
+
/// Removes selected items from the list widget
void removeSelectedItems();
//**************************************************************
bool ModuleBase_ModelWidget::restoreValue()
{
+ if (!isEnabled()) {
+ // This code works in inspection panel
+ ModelAPI_ValidatorsFactory* aValidators = ModelAPI_Session::get()->validators();
+ if (!aValidators->isCase(myFeature, attributeID()))
+ return false; // if it is not an active case for the widget
+ }
emit beforeValuesRestored();
bool isDone = restoreValueCustom();
emit afterValuesRestored();
/// By default this slot does nothing
virtual void onFeatureAccepted() {}
+ /// Returns True in case if the widget contains useful information for inspection tool
+ virtual bool isInformative() const { return true; }
+
+ /// If widgets has several panels then this method has to show a page which contains information
+ /// for current feature. By default does nothing
+ virtual void showInformativePage() {}
+
+ /// Returns True if data of its attribute was modified
+ virtual bool isModified() const { return false; }
+
signals:
/// The signal about widget values are to be changed
void beforeValuesChanged();
#include <GeomAPI_Pnt2d.h>
#include <Events_Loop.h>
+#include <Config_WidgetAPI.h>
+#include <Config_Keywords.h>
#include <QTimer>
ModuleBase_Operation::ModuleBase_Operation(const QString& theId, QObject* theParent)
: QObject(theParent),
myIsModified(false),
- myPropertyPanel(NULL)
+ myPropertyPanel(NULL),
+ myHideFacesVisibilityState(false)
{
myDescription = new ModuleBase_OperationDescription(theId);
}
{
return myGrantedIds.contains(theId);
}
+
+bool ModuleBase_Operation::isModified() const
+{
+ if (myDescription->hasXmlRepresentation()) {
+ Config_WidgetAPI aWidgetApi(myDescription->xmlRepresentation().toStdString());
+ if (!aWidgetApi.getBooleanAttribute(ABORT_CONFIRMATION, true))
+ return false;
+ }
+ //if (myPropertyPanel)
+ // return myPropertyPanel->isModified();
+ //return false;
+ // Most of operation causes creation of a feature
+ return true;
+}
virtual bool isGranted(QString theId) const;
/// Returns True if data of its feature was modified during operation
- virtual bool isModified() const { return myIsModified; }
-
- /// Change the modified state of the operation
- void setIsModified(const bool theIsModified) { myIsModified = theIsModified; }
+ virtual bool isModified() const;
/// Returns operations Id from it's description
QString id() const;
myHelpFileName = theName;
}
+ void setHideFacesVisible(bool isVisible) { myHideFacesVisibilityState = isVisible; }
+
+ bool isHideFacesVisible() const { return myHideFacesVisibilityState; }
+
signals:
/// The operation is started
void beforeStarted();
ModuleBase_IPropertyPanel* myPropertyPanel;
QString myHelpFileName;
+
+ /// Visibility state of HideFaces panel before the operation launch
+ bool myHideFacesVisibilityState;
};
#endif
+++ /dev/null
-// Copyright (C) 2014-2019 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 "ModuleBase_OperationAction.h"
-
-ModuleBase_OperationAction::ModuleBase_OperationAction(const QString& theId, QObject* theParent)
- : ModuleBase_Operation(theId, theParent)
-{
-}
-
-ModuleBase_OperationAction::~ModuleBase_OperationAction()
-{
-}
-
-bool ModuleBase_OperationAction::commit()
-{
- // the action is supposed to perform a single modification,
- // so the operation returns modified state
- setIsModified(true);
-
- return ModuleBase_Operation::commit();
-}
+++ /dev/null
-// Copyright (C) 2014-2019 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 ModuleBase_OperationAction_H
-#define ModuleBase_OperationAction_H
-
-#include <ModuleBase.h>
-
-#include <ModuleBase_Operation.h>
-
-/*!
- * \class ModuleBase_OperationAction
- * \ingroup GUI
- * \brief Base class for action operations
- *
- * This is an action-like operation, which modifies the structure of data through
- * starting/comitting transactions in the document. This operations are single stepped,
- * and have no filled property panel, like Delete/Detach.
- */
-
-class MODULEBASE_EXPORT ModuleBase_OperationAction : public ModuleBase_Operation
-{
-Q_OBJECT
-
- public:
- /// Constructor
- /// \param theId the operation identifier
- /// \param theParent the QObject parent
- ModuleBase_OperationAction(const QString& theId = "", QObject* theParent = 0);
- /// Destructor
- virtual ~ModuleBase_OperationAction();
-
- public slots:
- /// Commits the operation. Change is modified state to true value.
- /// \return the result of commit
- virtual bool commit();
-};
-
-#endif
std::shared_ptr<ModelAPI_Document> aDoc = ModelAPI_Session::get()->activeDocument();
myFeature = aDoc->addFeature(getDescription()->operationId().toStdString());
}
- if (myFeature) { // TODO: generate an error if feature was not created
- setIsModified(true);
- // Model update should call "execute" of a feature.
- //myFeature->execute();
- // Init default values
- /*QList<ModuleBase_ModelWidget*> aWidgets = getDescription()->modelWidgets();
- QList<ModuleBase_ModelWidget*>::const_iterator anIt = aWidgets.begin(), aLast = aWidgets.end();
- for (; anIt != aLast; anIt++) {
- (*anIt)->storeValue(aFeature);
- }*/
- }
-
- //if (theFlushMessage) {
- // Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
- // Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
- //}
return myFeature;
}
#ifdef DEBUG_OPERATION_START
qDebug("ModuleBase_OperationFeature::start -- begin");
#endif
- setIsModified(false);
QString anId = getDescription()->operationId();
if (myIsEditing) {
anId = anId.append(EditSuffix());
//********************************************************************
-bool ModuleBase_ResultPrs::setSubShapeHidden(const NCollection_List<TopoDS_Shape>& theShapes)
+void ModuleBase_ResultPrs::setSubShapeHidden(const TopoDS_ListOfShape& theShapes)
{
bool isModified = false;
BRep_Builder aBBuilder;
aBBuilder.MakeCompound (aCompound);
- TopoDS_Compound aShownComp;
- if (myIsSubstituted)
- aShownComp = TopoDS::Compound(Shape());
+ myHiddenSubShapes = theShapes;
+ collectSubShapes(aBBuilder, aCompound, myOriginalShape, myHiddenSubShapes);
+ myVisibleCompound = aCompound;
- // restore hidden shapes if there are not the shapes in parameter container
- NCollection_List<TopoDS_Shape> aVisibleSubShapes;
- NCollection_List<TopoDS_Shape>::Iterator aHiddenIt(myHiddenSubShapes);
- for (; aHiddenIt.More(); aHiddenIt.Next()) {
- if (!theShapes.Contains(aHiddenIt.Value())) {
- aVisibleSubShapes.Append(aHiddenIt.Value());
- }
- else {
- aBBuilder.Add(aCompound, aHiddenIt.Value());
- if (!aShownComp.IsNull())
- aBBuilder.Remove(aShownComp, aHiddenIt.Value());
- }
- }
- isModified = !aVisibleSubShapes.IsEmpty();
- NCollection_List<TopoDS_Shape>::Iterator aVisibleIt(aVisibleSubShapes);
- for (; aVisibleIt.More(); aVisibleIt.Next()) {
- if (myHiddenSubShapes.Contains(aVisibleIt.Value())) {
- myHiddenSubShapes.Remove(aVisibleIt.Value());
- if (!aShownComp.IsNull())
- aBBuilder.Add(aShownComp, aVisibleIt.Value());
- }
- }
- // append hidden shapes into internal container if there are not these shapes
- NCollection_List<TopoDS_Shape>::Iterator aShapeIt(theShapes);
- for (; aShapeIt.More(); aShapeIt.Next()) {
- if (aShapeIt.Value().ShapeType() != TopAbs_FACE) // only face shape can be hidden
- continue;
-
- if (!myHiddenSubShapes.Contains(aShapeIt.Value())) {
- myHiddenSubShapes.Append(aShapeIt.Value());
- aBBuilder.Add (aCompound, aShapeIt.Value());
- if (!aShownComp.IsNull())
- aBBuilder.Remove(aShownComp, aShapeIt.Value());
- isModified = true;
- }
+ aBBuilder.MakeCompound (aCompound);
+ TopoDS_ListOfShape::Iterator aIt(myHiddenSubShapes);
+ for (; aIt.More(); aIt.Next()) {
+ aBBuilder.Add(aCompound, aIt.Value());
}
myHiddenCompound = aCompound;
- return isModified;
}
//********************************************************************
return false;
// orientation of parameter shape(come from selection) may be wrong, check isEqual() to be sure
- for (NCollection_List<TopoDS_Shape>::Iterator aShapeIt(myHiddenSubShapes); aShapeIt.More();
- aShapeIt.Next())
- {
+ TopoDS_ListOfShape::Iterator aShapeIt(myHiddenSubShapes);
+ for (; aShapeIt.More(); aShapeIt.Next()) {
if (theShape.IsSame(aShapeIt.Value()))
return true;
}
//********************************************************************
bool ModuleBase_ResultPrs::hasSubShapeVisible(
- const NCollection_List<TopoDS_Shape>& theShapesToSkip)
+ const TopoDS_ListOfShape& theShapesToSkip)
{
TopoDS_Compound aCompound;
BRep_Builder aBuilder;
aBuilder.MakeCompound (aCompound);
- NCollection_List<TopoDS_Shape> aShapesToSkip;
- aShapesToSkip.Append(myHiddenSubShapes);
- for (NCollection_List<TopoDS_Shape>::Iterator anIt(theShapesToSkip); anIt.More(); anIt.Next())
+ TopoDS_ListOfShape aShapesToSkip;
+ TopoDS_ListOfShape aHiddenCopy(myHiddenSubShapes);
+ aShapesToSkip.Append(aHiddenCopy);
+ for (TopoDS_ListOfShape::Iterator anIt(theShapesToSkip); anIt.More(); anIt.Next())
aShapesToSkip.Append(anIt.Value());
collectSubShapes(aBuilder, aCompound, myOriginalShape, aShapesToSkip);
}
}
else { // convert shape into SHELL
- TopoDS_Compound aCompound;
- if (!myIsSubstituted) {
- BRep_Builder aBuilder;
- aBuilder.MakeCompound(aCompound);
- collectSubShapes(aBuilder, aCompound, myOriginalShape, myHiddenSubShapes);
- }
- else {
- aCompound = TopoDS::Compound(Shape());
- }
- bool isEmptyShape = BOPTools_AlgoTools3D::IsEmptyShape(aCompound);
- Set(aCompound);
+ bool isEmptyShape = BOPTools_AlgoTools3D::IsEmptyShape(myVisibleCompound);
+ Set(myVisibleCompound);
myIsSubstituted = true;
if (isEmptyShape)
aReadyToDisplay = false;
//********************************************************************
void ModuleBase_ResultPrs::collectSubShapes(BRep_Builder& theBuilder,
TopoDS_Shape& theCompound, const TopoDS_Shape& theShape,
- const NCollection_List<TopoDS_Shape>& theHiddenSubShapes)
+ const TopoDS_ListOfShape& theHiddenSubShapes)
{
switch (theShape.ShapeType()) {
case TopAbs_COMPSOLID:
/// Visual state of the face is controlled by the second parameter
/// \param theShapes a container of shape objects
/// \returns true if the presentation is changed, or false (if for example it was hidden)
- Standard_EXPORT bool setSubShapeHidden(const NCollection_List<TopoDS_Shape>& theShapes);
+ Standard_EXPORT void setSubShapeHidden(const TopoDS_ListOfShape& theShapes);
/// Returns true if parameter shape has been hidden
/// \param theShape sub-shape of the presentation shape
/// \return boolean value
Standard_EXPORT bool isSubShapeHidden(const TopoDS_Shape& theShape);
+ /// Returns hidden sub shapes list
+ Standard_EXPORT const TopoDS_ListOfShape& hiddenSubShapes() const
+ { return myHiddenSubShapes; }
+
/// Returns true if there are no hidden sub shapes or original shape has at least one not hidden
/// \param theShapesToSkip container of shape to be hidden in the presentation (faces)
/// \return boolean value
- Standard_EXPORT bool hasSubShapeVisible(const NCollection_List<TopoDS_Shape>& theShapesToSkip);
+ Standard_EXPORT bool hasSubShapeVisible(const TopoDS_ListOfShape& theShapesToSkip);
/// Set transparency of hidden sub shapes: if value is 1, shapes are entirely hidden
/// \param theTransparency transparency value
/// \param theShape the processed shape
/// \param theHiddenSubShapes container of shapes to be skipped (faces)
void collectSubShapes(BRep_Builder& theBuilder, TopoDS_Shape& theCompound,
- const TopoDS_Shape& theShape, const NCollection_List<TopoDS_Shape>& theHiddenSubShapes);
+ const TopoDS_Shape& theShape, const TopoDS_ListOfShape& theHiddenSubShapes);
void setEdgesDefaultColor();
bool myIsSubstituted;
/// Container of original Shape sub shape to be hidden and not selectable
- NCollection_List<TopoDS_Shape> myHiddenSubShapes;
+ TopoDS_ListOfShape myHiddenSubShapes;
+ TopoDS_Compound myVisibleCompound; /// compound of hidden sub shapes
TopoDS_Compound myHiddenCompound; /// compound of hidden sub shapes
double myTransparency; ///< transparency of hidden shapes, where 0 - there is no transparency
Handle(AIS_ColoredDrawer) myHiddenSubShapesDrawer; ///< drawer for hidden sub shapes
#include <ModuleBase_PagedContainer.h>
+const QString AStyle = "QToolButton:checked {border: 1px solid black; background-color:#C0DCF3}";
+
+
ModuleBase_ToolBox::ModuleBase_ToolBox(QWidget* theParent, const bool theUseFrameStyleBox)
: QFrame(theParent)
{
QToolButton* aButton = new QToolButton(myButtonsFrame);
aButton->setFocusPolicy(Qt::StrongFocus);
aButton->setCheckable(true);
+ aButton->setStyleSheet(AStyle);
if (theIcon.isNull())
aButton->setText(theName);
else {
void setSpinValue(ModuleBase_ParamSpinBox* theSpin, double theValue)
{
- if (fabs(theSpin->value() - theValue) < tolerance)
+ if (!theSpin->text().isEmpty() && fabs(theSpin->value() - theValue) < tolerance)
return;
bool isBlocked = theSpin->blockSignals(true);
theSpin->setValue(theValue);
std::string aTextRepr = aRef->text();
if (!aTextRepr.empty()) {
QString aText = QString::fromStdString(aTextRepr);
- //if (aText.endsWith('=')) {
- // if (!myParameter.get()) {
- // QString aName = aText.left(aText.indexOf('=')).trimmed();
- // myParameter = ModuleBase_Tools::findParameter(aName);
- // }
- // /// If myParameter is empty then it was not created because of an error
- // if (!myParameter.get())
- // return false;
-
- // AttributeStringPtr aExprAttr = myParameter->string("expression");
- // aText += aExprAttr->value().c_str();
- //}
ModuleBase_Tools::setSpinText(mySpinBox, aText);
}
else {
}
return isModified;
}
+
+bool ModuleBase_WidgetDoubleValue::isModified() const
+{
+ QString aText = mySpinBox->text();
+ if (aText.isEmpty())
+ return false;
+
+ if (myHasDefault) {
+ bool aOk = false;
+ double aVal = aText.toDouble(&aOk);
+ if (!aOk || aVal == myDefaultVal)
+ return false;
+ }
+ return true;
+}
\ No newline at end of file
/// \return a control list
virtual QList<QWidget*> getControls() const;
+ /// Returns True if data of its feature was modified during operation
+ virtual bool isModified() const;
+
public slots:
// Delayed value chnged: when user starts typing something,
// it gives him a 0,5 second to finish typing, when sends valueChnaged() signal
#include <ModuleBase_WidgetMultiSelector.h>
#include <ModuleBase_WidgetConcealedObjects.h>
#include <ModuleBase_WidgetLabel.h>
+#include <ModuleBase_WidgetUndoLabel.h>
#include <ModuleBase_WidgetToolbox.h>
#include <ModuleBase_WidgetRadiobox.h>
#include <ModuleBase_PageBase.h>
result = new ModuleBase_WidgetLabel(theParent, myWidgetApi);
} else if (theType == WDG_DOUBLEVALUE) {
result = new ModuleBase_WidgetDoubleValue(theParent, myWidgetApi);
+ } else if (theType == WDG_UNDOLABEL) {
+ result = new ModuleBase_WidgetUndoLabel(theParent, myWorkshop, myWidgetApi);
} else if (theType == WDG_DOUBLEVALUELABEL) {
result = new ModuleBase_WidgetLabelValue(theParent, myWidgetApi);
} else if (theType == WDG_INTEGERVALUE) {
}
return isModified;
}
+
+bool ModuleBase_WidgetIntValue::isModified() const
+{
+ QString aText = mySpinBox->text();
+ if (aText.isEmpty())
+ return false;
+
+ if (myHasDefault) {
+ bool aOk = false;
+ int aVal = aText.toInt(&aOk);
+ if (!aOk || aVal == myDefVal)
+ return false;
+ }
+ return true;
+}
\ No newline at end of file
/// \return a control list
virtual QList<QWidget*> getControls() const;
+ /// Returns True if data of its feature was modified during operation
+ virtual bool isModified() const;
+
protected:
/// Returns true if the event is processed.
virtual bool processEnter();
: ModuleBase_ModelWidget(theParent, theData)
{
QString aText = translate(theData->getProperty("title"));
+ bool aIsHtml = theData->getBooleanAttribute(ATTR_HTML_STYLE, false);
+
QString aLabelIcon = QString::fromStdString(theData->getProperty("icon"));
myLabel = new QLabel(aText, theParent);
if (!aLabelIcon.isEmpty()) {
myLabel->setWordWrap(true);
myLabel->setIndent(5);
myLabel->setContentsMargins(0,0,0,4);
+ if (aIsHtml)
+ myLabel->setTextFormat(Qt::RichText);
QVBoxLayout* aLayout = new QVBoxLayout(this);
ModuleBase_Tools::zeroMargins(aLayout);
aLayout->addWidget(myLabel);
setLayout(aLayout);
- std::string aStyleSheet = theData->getProperty(ATTR_STYLE_SHEET).c_str();
+ std::string aStyleSheet = theData->getProperty(ATTR_STYLE_SHEET);
if (!aStyleSheet.empty())
myLabel->setStyleSheet(QString("QLabel {%1}").arg(aStyleSheet.c_str()));
}
}
return isModified;
}
+
+bool ModuleBase_WidgetLineEdit::isModified() const
+{
+ return !myLineEdit->text().isEmpty();
+}
\ No newline at end of file
/// Redefinition of virtual method
virtual QList<QWidget*> getControls() const;
+ /// Returns True if data of its feature was modified during operation
+ virtual bool isModified() const;
+
protected:
/// Returns true if the event is processed.
virtual bool processEnter();
} else
Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY));
}
+
+bool ModuleBase_WidgetMultiSelector::isModified() const
+{
+ return myListView->getControl()->count() > 0;
+}
\ No newline at end of file
/// The slot is called when user press Ok or OkPlus buttons in the parent property panel
virtual void onFeatureAccepted();
+ /// Returns True if data of its feature was modified during operation
+ virtual bool isModified() const;
+
public slots:
/// Slot is called on selection type changed
void onSelectionTypeChanged();
}
}
}
+
+//********************************************************************
+bool ModuleBase_WidgetShapeSelector::isModified() const
+{
+ return !myTextLine->text().isEmpty();
+}
\ No newline at end of file
/// \return a control list
virtual QList<QWidget*> getControls() const;
+ /// Returns True if data of its feature was modified during operation
+ virtual bool isModified() const;
+
protected:
/// Saves the internal parameters to the given feature
/// \return True in success
--- /dev/null
+// Copyright (C) 2014-2019 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 "ModuleBase_WidgetUndoLabel.h"
+#include "ModuleBase_IWorkshop.h"
+
+#include <QPushButton>
+#include <QLayout>
+#include <QString>
+#include <QLabel>
+
+ModuleBase_WidgetUndoLabel::ModuleBase_WidgetUndoLabel(QWidget* theParent,
+ ModuleBase_IWorkshop* theWorkshop,
+ const Config_WidgetAPI* theData)
+ : ModuleBase_WidgetLabel(theParent, theData),
+ myWorkshop(theWorkshop)
+{
+ myUndoBtn = new QPushButton(tr("Undo"), this);
+ myUndoBtn->hide();
+ layout()->addWidget(myUndoBtn);
+ connect(myUndoBtn, SIGNAL(clicked(bool)), SLOT(onUndo()));
+}
+
+
+bool ModuleBase_WidgetUndoLabel::restoreValueCustom()
+{
+ bool aRes = ModuleBase_WidgetLabel::restoreValueCustom();
+ bool aError = myLabel->text().length() > 0;
+ myUndoBtn->setVisible(aError);
+ myWorkshop->setCancelEnabled(!aError);
+ return aRes;
+}
+
+
+void ModuleBase_WidgetUndoLabel::onUndo()
+{
+ myWorkshop->undo();
+}
\ No newline at end of file
--- /dev/null
+// Copyright (C) 2014-2019 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 ModuleBase_WidgetUndoLabel_H
+#define ModuleBase_WidgetUndoLabel_H
+
+#include "ModuleBase.h"
+#include "ModuleBase_WidgetLabel.h"
+
+class QPushButton;
+class ModuleBase_IWorkshop;
+
+/**
+* \ingroup GUI
+* Implementation of model widget for a label control
+*/
+class MODULEBASE_EXPORT ModuleBase_WidgetUndoLabel : public ModuleBase_WidgetLabel
+{
+ Q_OBJECT
+public:
+ /// Constructor
+ /// \param theParent the parent object
+ /// \param theData the widget configuation. The attribute of the model widget is obtained from
+ ModuleBase_WidgetUndoLabel(QWidget* theParent, ModuleBase_IWorkshop* theWorkshop,
+ const Config_WidgetAPI* theData);
+
+ virtual ~ModuleBase_WidgetUndoLabel() {}
+
+ virtual bool restoreValueCustom();
+
+private slots:
+ void onUndo();
+
+private:
+ ModuleBase_IWorkshop* myWorkshop;
+ QPushButton* myUndoBtn;
+};
+
+#endif
\ No newline at end of file
#include <ModuleBase_Tools.h>
#include <Events_Loop.h>
+#include <Config_PropManager.h>
#include <QLayout>
#include <QPushButton>
#include <QEvent>
#include <QKeyEvent>
#include <QDialogButtonBox>
+#include <QShortcut>
enum ColumnType {
Col_Name,
connect(myAddBtn, SIGNAL(clicked(bool)), SLOT(onAdd()));
aBtnLayout->addWidget(myAddBtn);
+ QString aAddStr(Config_PropManager::string("Shortcuts", "add_parameter_shortcut").c_str());
+ if (aAddStr.isEmpty())
+ aAddStr = "Ctrl+A";
+
+ QShortcut* aAddShc = new QShortcut(QKeySequence(aAddStr), myAddBtn);
+ connect(aAddShc, SIGNAL(activated()), SLOT(onAdd()));
+
myInsertBtn = new QPushButton(translate("Insert"), this);
connect(myInsertBtn, SIGNAL(clicked(bool)), SLOT(onInsert()));
aBtnLayout->addWidget(myInsertBtn);
Events_Loop::loop()->eventByName(Config_FeatureMessage::GUI_EVENT())) {
std::shared_ptr<Config_FeatureMessage> aFeatureMsg =
std::dynamic_pointer_cast<Config_FeatureMessage>(theMessage);
- if (!aFeatureMsg->isInternal()) {
- ActionInfo aFeatureInfo;
- aFeatureInfo.initFrom(aFeatureMsg);
- // Remember features icons
- myIcons[QString::fromStdString(aFeatureMsg->id())] = aFeatureInfo.iconFile;
- }
+ ActionInfo aFeatureInfo;
+ aFeatureInfo.initFrom(aFeatureMsg);
+ // Remember features icons
+ myIcons[QString::fromStdString(aFeatureMsg->id())] = aFeatureInfo.iconFile;
}
}
\ No newline at end of file
#include <ModuleBase_ISelection.h>
#include <ModuleBase_Operation.h>
-#include <ModuleBase_OperationAction.h>
#include <ModuleBase_OperationFeature.h>
#include <ModuleBase_ViewerPrs.h>
#include <ModuleBase_Tools.h>
XGUI_Workshop* aWorkshop = aConnector->workshop();
ModuleBase_Operation* anOperation = myModule->workshop()->currentOperation();
- ModuleBase_OperationAction* anOpAction = new ModuleBase_OperationAction(
- tr("Detach %1").arg(aLine->data()->name().c_str()), myModule);
+ ModuleBase_Operation* anOpAction =
+ new ModuleBase_Operation(tr("Detach %1").arg(aLine->data()->name().c_str()), myModule);
bool isSketchOp = PartSet_SketcherMgr::isSketchOperation(anOperation);
XGUI_OperationMgr* anOpMgr = aConnector->workshop()->operationMgr();
// the active nested sketch operation should be aborted unconditionally
QAction* anAction = action("AUXILIARY_CMD");
//SessionPtr aMgr = ModelAPI_Session::get();
- ModuleBase_OperationAction* anOpAction = 0;
+ ModuleBase_Operation* anOpAction = 0;
XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(myModule->workshop());
XGUI_OperationMgr* anOpMgr = aConnector->workshop()->operationMgr();
if (isUseTransaction) {
- anOpAction = new ModuleBase_OperationAction(anAction->text(), myModule);
+ anOpAction = new ModuleBase_Operation(anAction->text(), myModule);
bool isSketchOp = PartSet_SketcherMgr::isSketchOperation(anOperation);
bool isCommitted;
#include <SketchPlugin_ConstraintCoincidence.h>
#include <ModuleBase_Operation.h>
-#include <ModuleBase_OperationAction.h>
#include <ModuleBase_IViewer.h>
#include <ModuleBase_IViewWindow.h>
#include <ModuleBase_IPropertyPanel.h>
Config_PropManager::registerProp("Visualization", "sketch_dimension_color",
"Dimension color",
Config_Prop::Color, SKETCH_DIMENSION_COLOR);
+
+ Config_PropManager::registerProp("Shortcuts", "add_parameter_shortcut",
+ "Add parameter in parameters manager dialog",
+ Config_Prop::Shortcut, "Ctrl+A");
}
//******************************************************
if (PartSet_SketcherMgr::isSketchOperation(theOperation)) {
mySketchMgr->startSketch(theOperation);
}
- else if (sketchMgr()->isNestedSketchOperation(theOperation)) {
- mySketchMgr->startNestedSketch(theOperation);
- }
+ // It is switched off because of
+ // Task #3067: 5.2.2 Drawing in the sketcher: change the mouse cursor arrow
+ //else if (sketchMgr()->isNestedSketchOperation(theOperation)) {
+ // mySketchMgr->startNestedSketch(theOperation);
+ //}
}
//******************************************************
}
//******************************************************
-bool PartSet_Module::createWidgets(ModuleBase_Operation* theOperation,
+bool PartSet_Module::createWidgets(const FeaturePtr& theFeature, const QString& theXmlRepr,
QList<ModuleBase_ModelWidget*>& theWidgets) const
{
bool aProcessed = false;
- ModuleBase_OperationFeature* aFOperation =
- dynamic_cast<ModuleBase_OperationFeature*>(theOperation);
XGUI_Workshop* aWorkshop = getWorkshop();
XGUI_PropertyPanel* aPropertyPanel = aWorkshop->propertyPanel();
- if (mySketchMgr->activeSketch().get() && aFOperation && aPropertyPanel) {
+ if (mySketchMgr->activeSketch().get() && aPropertyPanel) {
ModuleBase_ISelection* aSelection = workshop()->selection();
// click on a point in sketch leads here with the point is highlighted, not yet selected
QList<ModuleBase_ViewerPrsPtr> aPreselection = aSelection->getHighlighted();
ObjectPtr anObject = aSelectedPrs->object();
FeaturePtr aFeature = ModelAPI_Feature::feature(anObject);
- FeaturePtr anOpFeature = aFOperation->feature();
GeomShapePtr aShape = aSelectedPrs->shape();
// click on the digit of dimension constrain comes here
// with an empty shape, so we need the check
- if (aFeature == anOpFeature && aShape.get() && !aShape->isNull()) {
+ if (aFeature == theFeature && aShape.get() && !aShape->isNull()) {
// if feature has only one result and shape of result is equal to selected shape
// this attribute is not processed. It is a case of Sketch Point.
if (aFeature->results().size() == 1) {
AttributePtr anAttribute = PartSet_Tools::findAttributeBy2dPoint(anObject, aTDShape,
mySketchMgr->activeSketch());
if (anAttribute.get()) {
- QString aXmlRepr = aFOperation->getDescription()->xmlRepresentation();
- ModuleBase_WidgetFactory aFactory(aXmlRepr.toStdString(), workshop());
+ ModuleBase_WidgetFactory aFactory(theXmlRepr.toStdString(), workshop());
const std::string anAttributeId = anAttribute->id();
aFactory.createWidget(aPropertyPanel->contentWidget(), anAttributeId);
// 3. start operation
QString aDescription = aWorkshop->contextMenuMgr()->action("DELETE_CMD")->text();
- ModuleBase_OperationAction* anOpAction = new ModuleBase_OperationAction(aDescription, this);
+ ModuleBase_Operation* anOpAction = new ModuleBase_Operation(aDescription, this);
// the active nested sketch operation should be aborted unconditionally
// the Delete action should be additionally granted for the Sketch operation
/// If there is found selected attribute, widgets are created and contains
/// only a widget for the attribute
/// It is important for Property Panel filling by sketch point attribute
- /// \param theOperation a started operation
+ /// \param theFeature a feature of the started operation
+ /// \param theXmlRepr an XML representation of the operation
/// \param theWidgets a list of created widgets
/// \return boolean result, false by default
- virtual bool createWidgets(ModuleBase_Operation* theOperation,
+ virtual bool createWidgets(const FeaturePtr& theFeature, const QString& theXmlRepr,
QList<ModuleBase_ModelWidget*>& theWidgets) const;
/// Launching of a edit operation on the feature
return;
#endif
- if (canChangeCursor(getCurrentOperation())) {
- QCursor* aCurrentCursor = QApplication::overrideCursor();
- if (!aCurrentCursor || aCurrentCursor->shape() != Qt::CrossCursor) {
- QApplication::setOverrideCursor(QCursor(Qt::CrossCursor));
-#ifdef DEBUG_CURSOR
- qDebug("onEnterViewPort() : Qt::CrossCursor");
-#endif
- }
- }
+ // It is switched off because of
+ // Task #3067: 5.2.2 Drawing in the sketcher: change the mouse cursor arrow
+ // if (canChangeCursor(getCurrentOperation())) {
+ // QCursor* aCurrentCursor = QApplication::overrideCursor();
+ // if (!aCurrentCursor || aCurrentCursor->shape() != Qt::CrossCursor) {
+ // QApplication::setOverrideCursor(QCursor(Qt::CrossCursor));
+ //#ifdef DEBUG_CURSOR
+ // qDebug("onEnterViewPort() : Qt::CrossCursor");
+ //#endif
+ // }
+ // }
if (!isNestedCreateOperation(getCurrentOperation(), activeSketch()))
return;
return;
#endif
- if (canChangeCursor(getCurrentOperation())) {
- QApplication::restoreOverrideCursor();
-#ifdef DEBUG_CURSOR
- qDebug("onLeaveViewPort() : None");
-#endif
- }
+// if (canChangeCursor(getCurrentOperation())) {
+// QApplication::restoreOverrideCursor();
+//#ifdef DEBUG_CURSOR
+// qDebug("onLeaveViewPort() : None");
+//#endif
+// }
if (!isNestedCreateOperation(getCurrentOperation(), activeSketch()))
return;
workshop()->viewer()->set2dMode(false);
}
-void PartSet_SketcherMgr::startNestedSketch(ModuleBase_Operation* theOperation)
-{
- if (canChangeCursor(theOperation) && myIsMouseOverWindow) {
- QCursor* aCurrentCursor = QApplication::overrideCursor();
- if (!aCurrentCursor || aCurrentCursor->shape() != Qt::CrossCursor) {
- QApplication::setOverrideCursor(QCursor(Qt::CrossCursor));
-#ifdef DEBUG_CURSOR
- qDebug("startNestedSketch() : Qt::CrossCursor");
-#endif
- }
- }
-}
+//void PartSet_SketcherMgr::startNestedSketch(ModuleBase_Operation* theOperation)
+//{
+// if (canChangeCursor(theOperation) && myIsMouseOverWindow) {
+// QCursor* aCurrentCursor = QApplication::overrideCursor();
+// if (!aCurrentCursor || aCurrentCursor->shape() != Qt::CrossCursor) {
+// QApplication::setOverrideCursor(QCursor(Qt::CrossCursor));
+//#ifdef DEBUG_CURSOR
+// qDebug("startNestedSketch() : Qt::CrossCursor");
+//#endif
+// }
+// }
+//}
void PartSet_SketcherMgr::stopNestedSketch(ModuleBase_Operation* theOperation)
{
operationMgr()->onValidateOperation();
// when sketch nested operation is stopped the cursor should be restored unconditionally
//if (canChangeCursor(theOperation)) {
- QApplication::restoreOverrideCursor();
+ //QApplication::restoreOverrideCursor();
#ifdef DEBUG_CURSOR
qDebug("stopNestedSketch() : None");
#endif
/// Starts sketch operation, connects to the opeation property panel
/// \param theOperation a committed operation
- void startNestedSketch(ModuleBase_Operation* theOperation);
+ //void startNestedSketch(ModuleBase_Operation* theOperation);
/// Stop sketch operation, disconnects from the opeation property panel
/// \param theOperation a stopped operation
/// \return a boolean value
virtual bool isValidSelection(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue);
+ /// Returns True in case if the widget contains useful information for inspection tool
+ virtual bool isInformative() const { return false; }
+
protected:
/// If there is no operation in current session, start operation for modify parameters
/// \return true if the operation was not opened
#include <QCheckBox>
#include <QGroupBox>
#include <QPushButton>
-#include <QStackedWidget>
#include <QLineEdit>
#include <QDoubleValidator>
+#include <QDialog>
#ifndef DBL_MAX
#define DBL_MAX 1.7976931348623158e+308
mySizeOfView->setValidator(aValidator);
aSizeLayout->addWidget(mySizeOfView);
+ myPartSetMessage = new QDialog(this, Qt::ToolTip);
+ myPartSetMessage->setModal(false);
+ myPartSetMessage->setStyleSheet("background-color:lightyellow;");
+ QVBoxLayout* aMsgLay = new QVBoxLayout(myPartSetMessage);
+ QString aMsg = tr("The Sketch is created in PartSet.\n"
+ "It will be necessary to create a Part in order to use this sketch for body creation");
+ aMsgLay->addWidget(new QLabel(aMsg, myPartSetMessage));
+ myPartSetMessage->hide();
+
+ mySizeMessage = new QDialog(mySizeOfView, Qt::ToolTip);
+ mySizeMessage->setModal(false);
+ mySizeMessage->setStyleSheet("background-color:lightyellow;");
+ aMsgLay = new QVBoxLayout(mySizeMessage);
+ aMsg = tr("A size of Sketch view can be defined here.");
+ aMsgLay->addWidget(new QLabel(aMsg, mySizeMessage));
+ mySizeMessage->hide();
+
QString aText = translate(theData->getProperty("title"));
QLabel* aLabel = new QLabel(aText, aFirstWgt);
aLabel->setWordWrap(true);
GeomPlanePtr aPlane = plane();
if (!aPlane.get())
return;
+
+ myPartSetMessage->hide();
+ mySizeMessage->hide();
+
// 1. hide main planes if they have been displayed and display sketch preview plane
myPreviewPlanes->erasePreviewPlanes(myWorkshop);
mySizeOfViewWidget->setVisible(false);
}
+void PartSet_WidgetSketchLabel::showEvent(QShowEvent* theEvent)
+{
+ if (mySizeOfViewWidget->isVisible()) {
+ DocumentPtr aDoc = feature()->document();
+ DocumentPtr aModDoc = ModelAPI_Session::get()->moduleDocument();
+ if (aModDoc == aDoc) {
+ myPartSetMessage->move(mapToGlobal(geometry().bottomLeft()));
+ myPartSetMessage->show();
+ }
+ mySizeMessage->move(mySizeOfView->mapToGlobal(mySizeOfView->geometry().center()));
+ mySizeMessage->show();
+ }
+}
+
+
void PartSet_WidgetSketchLabel::deactivate()
{
ModuleBase_WidgetValidated::deactivate();
#include <TopoDS_Shape.hxx>
+#include <QStackedWidget>
#include <QMap>
class PartSet_PreviewPlanes;
class QStackedWidget;
class QLineEdit;
class QPushButton;
+class QDialog;
/**
* \ingroup Modules
/// \param thePrs a presentation
static bool canFillSketch(const std::shared_ptr<ModuleBase_ViewerPrs>& thePrs);
+ /// If widgets has several panels then this method has to show a page which contains information
+ /// for current feature. By default does nothing
+ virtual void showInformativePage() {
+ if (myStackWidget) myStackWidget->setCurrentIndex(1);
+ }
+
signals:
/// Signal on plane selection
void planeSelected(const std::shared_ptr<GeomAPI_Pln>& thePln);
/// \param thePrs a presentation
bool fillSketchPlaneBySelection(const std::shared_ptr<ModuleBase_ViewerPrs>& thePrs);
+
+ virtual void showEvent(QShowEvent* theEvent);
+
private slots:
/// A slot called on set sketch plane view
void onSetPlaneView();
bool myOpenTransaction;
bool myIsSelection;
+
+ QDialog* myPartSetMessage;
+ QDialog* mySizeMessage;
};
#endif
"""Package for Exchange plugin for the Parametric Geometry API of the Modeler.
"""
-from ExchangeAPI import addImport, exportToFile, exportToXAO
\ No newline at end of file
+from ExchangeAPI import addImport, exportToFile, exportToXAO
+from ExchangeAPI import exportPart, importPart
+
+from .tools import *
--- /dev/null
+# Copyright (C) 2019 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
+
+def removeFile(theFilename):
+ try: os.remove(theFilename)
+ except OSError: pass
+ assert not os.path.exists(theFilename), "Cannot remove file {}".format(theFilename)
XGUI_Displayer* aDisp = myWorkshop->displayer();
QObjectPtrList aObjList = aDisp->displayedObjects();
+ //if (myHighlightPointAspect.IsNull()) {
+ // Handle(AIS_Trihedron) aTrihedron = mySelector->viewer()->getTrihedron();
+ // myHighlightPointAspect =
+ // new Graphic3d_AspectMarker3d(aTrihedron->getHighlightPointAspect()->Aspect().operator*());
+ //}
+ if (myOldSelectionColor.size() == 0)
+ myOldSelectionColor = aDisp->selectionColor();
+
AIS_ListOfInteractive aList;
aContext->DisplayedObjects(aList);
AIS_ListIteratorOfListOfInteractive aLIt;
}
// Delete selector because it has to be redefined on next activation
if (mySelector) {
+ //if (!myHighlightPointAspect.IsNull()) {
+ // Handle(AIS_Trihedron) aTrihedron = mySelector->viewer()->getTrihedron();
+ // aTrihedron->getHighlightPointAspect()->SetAspect(myHighlightPointAspect);
+ // myHighlightPointAspect.Nullify();
+ //}
+ myWorkshop->displayer()->setSelectionColor(myOldSelectionColor);
myProxyViewer->setSelector(0);
delete mySelector;
mySelector = 0;
aResMgr->setValue("Study", "store_positions", myIsStorePositions);
getApp()->setEditEnabled(myIsEditEnabled);
+ myOldSelectionColor.clear();
+
// Post-processing for LoadScriptId to remove created(if it was created) SALOME Object Browser
disconnect(getApp()->action(LightApp_Application::UserID+1), SIGNAL(triggered(bool)),
this, SLOT(onScriptLoaded()));
{
if (theMgr->getType() == OCCViewer_Viewer::Type()) {
OCCViewer_Viewer* aViewer = static_cast<OCCViewer_Viewer*>(theMgr->getViewModel());
+
+ //if (myHighlightPointAspect.IsNull()) {
+ // Handle(AIS_Trihedron) aTrihedron = aViewer->getTrihedron();
+ // myHighlightPointAspect =
+ // new Graphic3d_AspectMarker3d(aTrihedron->getHighlightPointAspect()->Aspect().operator*());
+ //}
SHAPERGUI_OCCSelector* aSelector = new SHAPERGUI_OCCSelector(aViewer,
getApp()->selectionMgr());
#ifdef SALOME_PATCH_FOR_CTRL_WHEEL
aSel->setEnabled(aSel == aSelector);
}
myProxyViewer->setSelector(aSelector);
+
+ if (myOldSelectionColor.size() == 0)
+ myOldSelectionColor = myWorkshop->displayer()->selectionColor();
+
+ std::vector<int> aColor = Config_PropManager::color("Visualization", "selection_color");
+ myWorkshop->displayer()->setSelectionColor(aColor);
return aSelector;
}
return 0;
}
aProp->setValue(aValue);
+ if ((theSection == "Visualization") && (theParam == "selection_color")) {
+ std::vector<int> aColor = Config_PropManager::color("Visualization", "selection_color");
+ myWorkshop->displayer()->setSelectionColor(aColor);
+ }
+
myWorkshop->displayer()->redisplayObjects();
}
QMap<QString, QIntList> myToolbars;
QMap<QString, QIntList> myDefaultToolbars;
bool myIsToolbarsModified;
+
+ std::vector<int> myOldSelectionColor;
+ Handle(Graphic3d_AspectMarker3d) myHighlightPointAspect;
};
#endif
TestConstraintDistanceBehavior.py
TestConstraintDistanceHorizontal.py
TestConstraintDistanceVertical.py
+ TestConstraintDistanceZero.py
+ TestConstraintDistanceHorizontalZero.py
+ TestConstraintDistanceVerticalZero.py
TestConstraintEqual.py
TestConstraintEqualEllipse.py
TestConstraintFixed.py
#include <GeomAPI_Pnt2d.h>
#include <GeomAPI_XY.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Dir.h>
#include <ModelAPI_AttributeDouble.h>
#include <ModelAPI_AttributeInteger.h>
data()->addAttribute(SketchPlugin_ConstraintDistance::LOCATION_TYPE_ID(),
ModelAPI_AttributeInteger::typeId());
ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), LOCATION_TYPE_ID());
+
+ AttributePtr anAttr = data()->addAttribute(SketchPlugin_ConstraintDistance::DIRECTION_ID(),
+ GeomDataAPI_Dir::typeId());
+ anAttr->setIsArgument(false);
+ ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), DIRECTION_ID());
}
void SketchPlugin_ConstraintDistance::colorConfigInfo(std::string& theSection, std::string& theName,
return anAIS;
}
+static std::shared_ptr<GeomAPI_Lin2d> getLine(DataPtr theData, const std::string& theAttrName)
+{
+ FeaturePtr aLineFeature = SketcherPrs_Tools::getFeatureLine(theData, theAttrName);
+ if (!aLineFeature)
+ return GeomLine2dPtr();
+
+ std::shared_ptr<GeomDataAPI_Point2D> aStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aLineFeature->attribute(SketchPlugin_Line::START_ID()));
+ std::shared_ptr<GeomDataAPI_Point2D> aEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+ aLineFeature->attribute(SketchPlugin_Line::END_ID()));
+
+ return GeomLine2dPtr(new GeomAPI_Lin2d(aStart->x(), aStart->y(), aEnd->x(), aEnd->y()));
+}
+
double SketchPlugin_ConstraintDistance::calculateCurrentDistance()
{
double aDistance = -1.;
std::shared_ptr<GeomDataAPI_Point2D> aPointB =
SketcherPrs_Tools::getFeaturePoint(aData, SketchPlugin_Constraint::ENTITY_B(), aPlane);
+ GeomPnt2dPtr aGeomPntA, aGeomPntB;
+ GeomLine2dPtr aLine;
if (aPointA.get() && aPointB.get()) { // both points
- aDistance = aPointA->pnt()->distance(aPointB->pnt());
+ aGeomPntA = aPointA->pnt();
+ aGeomPntB = aPointB->pnt();
} else {
- FeaturePtr aLineFeature;
- std::shared_ptr<SketchPlugin_Line> aLine;
if (!aPointA.get() && aPointB.get()) { //Line and point
- aLineFeature = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_A());
- aLine = std::dynamic_pointer_cast<SketchPlugin_Line>(aLineFeature);
- if (aLine.get()) {
- aDistance = aLine->distanceToPoint(aPointB->pnt());
- }
+ aLine = getLine(aData, SketchPlugin_Constraint::ENTITY_A());
+ aGeomPntB = aPointB->pnt();
+ aGeomPntA = aLine ? aLine->project(aGeomPntB) : GeomPnt2dPtr();
} else if (aPointA.get() && !aPointB.get()) { // Point and line
- aLineFeature = SketcherPrs_Tools::getFeatureLine(aData, SketchPlugin_Constraint::ENTITY_B());
- aLine = std::dynamic_pointer_cast<SketchPlugin_Line>(aLineFeature);
- if (aLine.get()) {
- aDistance = aLine->distanceToPoint(aPointA->pnt());
- }
+ aLine = getLine(aData, SketchPlugin_Constraint::ENTITY_B());
+ aGeomPntA = aPointA->pnt();
+ aGeomPntB = aLine ? aLine->project(aGeomPntA) : GeomPnt2dPtr();
}
}
+
+ if (aGeomPntA.get() && aGeomPntB.get()) {
+ aDistance = aGeomPntA->distance(aGeomPntB);
+ if (aDistance < tolerance)
+ aDistance = 0.0;
+ }
+
+ // keep the direction between arguments for processing of the zero distance
+ std::shared_ptr<GeomDataAPI_Dir> aPointPointDir =
+ std::dynamic_pointer_cast<GeomDataAPI_Dir>(attribute(DIRECTION_ID()));
+ if (aDistance > tolerance)
+ aPointPointDir->setValue(aGeomPntB->x() - aGeomPntA->x(), aGeomPntB->y() - aGeomPntA->y(), 0.0);
+ else if (aLine) {
+ GeomDir2dPtr aLineDir = aLine->direction();
+ aPointPointDir->setValue(-aLineDir->y(), aLineDir->x(), 0.0);
+ }
+
return aDistance;
}
if (!aValueAttr->isInitialized()) {
// only if it is not initialized, try to compute the current value
double aDistance = calculateCurrentDistance();
- if (aDistance > 0) { // set as value the length of updated references
+ if (aDistance >= 0) { // set as value the length of updated references
aValueAttr->setValue(aDistance);
}
}
} else
return;
- if (aEndPnt->distance(aStartPnt) < tolerance)
- return;
-
myFlyoutUpdate = true;
- std::shared_ptr<GeomAPI_Dir2d> aLineDir(new GeomAPI_Dir2d(aEndPnt->decreased(aStartPnt)));
std::shared_ptr<GeomAPI_XY> aFlyoutDir = aFlyoutPnt->xy()->decreased(aStartPnt);
-
- double X = aFlyoutDir->dot(aLineDir->xy());
- double Y = -aFlyoutDir->cross(aLineDir->xy());
- aFlyoutAttr->setValue(X, Y);
+ if (aEndPnt->distance(aStartPnt) >= tolerance) {
+ std::shared_ptr<GeomAPI_Dir2d> aLineDir(new GeomAPI_Dir2d(aEndPnt->decreased(aStartPnt)));
+ double X = aFlyoutDir->dot(aLineDir->xy());
+ double Y = -aFlyoutDir->cross(aLineDir->xy());
+ aFlyoutAttr->setValue(X, Y);
+ }
+ else
+ aFlyoutAttr->setValue(aFlyoutDir->x(), aFlyoutDir->y());
myFlyoutUpdate = false;
}
}
return MY_SIGNED;
}
+ /// \brief The direction from the first object to the second.
+ /// To change distance value from zero to non-zero correctly.
+ inline static const std::string& DIRECTION_ID()
+ {
+ static const std::string MY_DIRECTION_ID("DistanceDirection");
+ return MY_DIRECTION_ID;
+ }
+
/// attribute name of dimension location type
inline static const std::string& LOCATION_TYPE_ID()
{
}
// LCOV_EXCL_STOP
-double SketchPlugin_Line::distanceToPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint)
-{
- double aDelta = 0;
-
- std::shared_ptr<ModelAPI_Data> aData = data();
- std::shared_ptr<GeomDataAPI_Point2D> aPoint1 =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(START_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aPoint2 =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(END_ID()));
-
- GeomAPI_Lin2d aLin2d(aPoint1->x(), aPoint1->y(), aPoint2->x(), aPoint2->y());
-
- if (false/*projection*/) { // TODO: if it has not been necessary, remove this block
- std::shared_ptr<GeomAPI_Pnt2d> aResult = aLin2d.project(thePoint);
- aDelta = aResult->distance(thePoint);
- } else { // distance
- aDelta = aLin2d.distance(thePoint);
- }
-
- return aDelta;
-}
-
const std::string& SketchPlugin_Line::getKind()
{
static std::string MY_KIND = SketchPlugin_Line::ID();
/// if message has selected object
virtual std::string processEvent(const std::shared_ptr<Events_Message>& theMessage);
- /// Return the distance between the feature and the point
- /// \param thePoint the point
- double distanceToPoint(const std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
-
/// Called on change of any argument-attribute of this object
SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
std::shared_ptr<GeomAPI_Dir> aYDir(new GeomAPI_Dir(aNormDir->cross(aTempDir)));
std::shared_ptr<GeomAPI_Dir> aXDir(new GeomAPI_Dir(aYDir->cross(aNormDir)));
+ bool aWasBlocked = data()->blockSendAttributeUpdated(true);
// update position of the sketch
std::shared_ptr<GeomDataAPI_Point> anOrigin = std::dynamic_pointer_cast
<GeomDataAPI_Point>(data()->attribute(SketchPlugin_Sketch::ORIGIN_ID()));
std::shared_ptr<GeomDataAPI_Dir> aDirX = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
data()->attribute(SketchPlugin_Sketch::DIRX_ID()));
aDirX->setValue(aXDir);
- std::shared_ptr<GeomAPI_Dir> aDir = aPlane->direction();
+ data()->blockSendAttributeUpdated(aWasBlocked, true);
}
}
}
model.do()
# changing the parameter
-for param in range(-30, 31, 2):
+for param in range(-31, 30, 2):
if param == 0:
continue
DistanceParam.setValue(param)
model.do()
# changing the parameter
-for param in range(-30, 31, 2):
+for param in range(-31, 30, 2):
if param == 0:
continue
DistanceParam.setValue(param)
for param in range(-30, 31, 2):
DistanceParam.setValue(param)
model.do()
- if param <= 0:
+ if param < 0:
assert SketchConstraintDistance_1.feature().error() != '', "ERROR: Sketch should not be valid due to negative distance value"
+ elif param == 0: # constraint is valid, but lead to degenerated geometry
+ assert Sketch_1.feature().error() != '', "ERROR: Sketch should not be valid due to negative distance value"
else:
dist = model.distancePointPoint(firstPoint, secondPoint)
assert math.fabs(dist - math.fabs(param)) < TOLERANCE, "Incorrect distance {}, expected {}".format(dist, math.fabs(param))
#=========================================================================
# Change a distance value
#=========================================================================
-d = DISTANCE1 + 20.
+d = DISTANCE1 + 21.
dStep = -5.
while d >= -30.:
aSession.startOperation()
DISTANCE1 = d
aDistance.setValue(DISTANCE1)
aSession.finishOperation()
- if DISTANCE1 == 0:
- assert(aHDist1.error() != "")
- else:
- assert math.fabs(horizontalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
+ assert math.fabs(horizontalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
d += dStep
assert (model.dof(aSketchFeature) == 3)
# Change a distance value (check previous constraint is applied too)
#=========================================================================
d = DISTANCE2
-dStep = -5.
+dStep = -7.
while d >= -50.:
aSession.startOperation()
DISTANCE2 = d
aDistance.setValue(DISTANCE2)
aSession.finishOperation()
- if DISTANCE2 == 0:
- assert(aHDist2.error() != "")
- else:
- assert math.fabs(horizontalDistance(anExtCoords, aPoint1Coords) - DISTANCE2) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(anExtCoords, aPoint1Coords), DISTANCE2)
- assert math.fabs(aPoint1Coords.x() - DISTANCE2) < 1.e-5, "Wrong point coordinates ({}, {}), expected x = {}".format(aPoint1Coords.x(), aPoint1Coords.y(), DISTANCE2)
- assert math.fabs(horizontalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
+ assert math.fabs(horizontalDistance(anExtCoords, aPoint1Coords) - DISTANCE2) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(anExtCoords, aPoint1Coords), DISTANCE2)
+ assert math.fabs(aPoint1Coords.x() - DISTANCE2) < 1.e-5, "Wrong point coordinates ({}, {}), expected x = {}".format(aPoint1Coords.x(), aPoint1Coords.y(), DISTANCE2)
+ assert math.fabs(horizontalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
d += dStep
assert (model.dof(aSketchFeature) == 2)
# Change a distance value
#=========================================================================
d = DISTANCE3
-dStep = -5.
+dStep = -7.
while d >= -50.:
aSession.startOperation()
DISTANCE3 = d
aDistance.setValue(DISTANCE3)
aSession.finishOperation()
- if DISTANCE3 == 0:
- assert(aHDist3.error() != "")
- else:
- assert math.fabs(horizontalDistance(aStartPoint, aEndPoint) - DISTANCE3) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(aStartPoint, aEndPoint), DISTANCE3)
+ assert math.fabs(horizontalDistance(aStartPoint, aEndPoint) - DISTANCE3) < 1.e-5, "Distance values are different: {0} != {1}".format(horizontalDistance(aStartPoint, aEndPoint), DISTANCE3)
d += dStep
assert (model.dof(aSketchFeature) == 6)
--- /dev/null
+# Copyright (C) 2019 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
+#
+
+"""
+ Test the zero value of the constraint "DistanceHorizontal"
+"""
+
+import unittest
+import math
+
+from salome.shaper import model
+from SketchAPI import *
+
+__updated__ = "2019-10-22"
+TOLERANCE = 1.e-6
+
+class TestZeroDistanceHorizontal(unittest.TestCase):
+ def setUp(self):
+ model.begin()
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+ self.myLine1 = self.mySketch.addLine(10, 10, 45, 27.5)
+ self.myLine2 = self.mySketch.addLine(20, 15, 30, 40)
+ self.myLine3 = self.mySketch.addLine(10, 0, 10, 10)
+ model.do()
+ self.myDOF = 12
+
+ def tearDown(self):
+ model.end()
+ model.checkSketch(self.mySketch, self.myDOF)
+
+ def assertDistanceHorizontal(self, theObject1, theObject2, theDistance):
+ dist = theObject2.x() - theObject1.x()
+ self.assertTrue(math.fabs(dist - theDistance) < TOLERANCE, "Current distance = {}, reference = {}".format(dist, theDistance))
+ model.checkSketch(self.mySketch, self.myDOF)
+
+
+ def test_distance_positive_nzznz(self):
+ """ Test 1. Change distance from non-zero to zero and back to non-zero
+ """
+ dist = self.mySketch.setHorizontalDistance(self.myLine1.startPoint(), self.myLine2.startPoint(), 10)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine2.startPoint(), 10)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine2.startPoint(), 0)
+
+ SketchAPI_Constraint(dist).setValue(10)
+ model.do()
+ self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine2.startPoint(), 10)
+
+ def test_distance_negative_nzznz(self):
+ """ Test 2. Change distance from non-zero to zero and back to non-zero
+ """
+ dist = self.mySketch.setHorizontalDistance(self.myLine1.endPoint(), self.myLine2.endPoint(), 15)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistanceHorizontal(self.myLine1.endPoint(), self.myLine2.endPoint(), -15)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistanceHorizontal(self.myLine1.endPoint(), self.myLine2.endPoint(), 0)
+
+ SketchAPI_Constraint(dist).setValue(10)
+ model.do()
+ self.assertDistanceHorizontal(self.myLine1.endPoint(), self.myLine2.endPoint(), -10)
+
+ def test_distance_equal_znzz(self):
+ """ Test 3. Change distance from zero to non-zero and back to zero
+ """
+ dist = self.mySketch.setHorizontalDistance(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+
+ SketchAPI_Constraint(dist).setValue(10)
+ model.do()
+ self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine3.endPoint(), 10)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+
+ def test_distance_notequal_znzz(self):
+ """ Test 4. Change distance from zero to non-zero and back to zero
+ """
+ dist = self.mySketch.setHorizontalDistance(self.myLine1.startPoint(), self.myLine3.startPoint(), 0)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine3.startPoint(), 0)
+
+ SketchAPI_Constraint(dist).setValue(10)
+ model.do()
+ self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine3.startPoint(), 10)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistanceHorizontal(self.myLine1.startPoint(), self.myLine3.startPoint(), 0)
+
+
+if __name__ == "__main__":
+ test_program = unittest.main(exit=False)
+ assert test_program.result.wasSuccessful(), "Test failed"
+ assert model.checkPythonDump()
#=========================================================================
# Change a distance value
#=========================================================================
-d = DISTANCE1 + 20.
+d = DISTANCE1 + 21.
dStep = -5.
while d >= -30.:
aSession.startOperation()
DISTANCE1 = d
aDistance.setValue(DISTANCE1)
aSession.finishOperation()
- if DISTANCE1 == 0:
- assert(aVDist1.error() != "")
- else:
- assert math.fabs(verticalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
+ assert math.fabs(verticalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
d += dStep
assert (model.dof(aSketchFeature) == 3)
# Change a distance value (check previous constraint is applied too)
#=========================================================================
d = DISTANCE2
-dStep = -5.
+dStep = -7.
while d >= -50.:
aSession.startOperation()
DISTANCE2 = d
aDistance.setValue(DISTANCE2)
aSession.finishOperation()
- if DISTANCE2 == 0:
- assert(aVDist2.error() != "")
- else:
- assert math.fabs(verticalDistance(anExtCoords, aPoint1Coords) - DISTANCE2) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(anExtCoords, aPoint1Coords), DISTANCE2)
- assert math.fabs(aPoint1Coords.y() - DISTANCE2) < 1.e-5, "Wrong point coordinates ({}, {}), expected y = {}".format(aPoint1Coords.x(), aPoint1Coords.y(), DISTANCE2)
- assert math.fabs(verticalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
+ assert math.fabs(verticalDistance(anExtCoords, aPoint1Coords) - DISTANCE2) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(anExtCoords, aPoint1Coords), DISTANCE2)
+ assert math.fabs(aPoint1Coords.y() - DISTANCE2) < 1.e-5, "Wrong point coordinates ({}, {}), expected y = {}".format(aPoint1Coords.x(), aPoint1Coords.y(), DISTANCE2)
+ assert math.fabs(verticalDistance(aPoint1Coords, aPoint2Coords) - DISTANCE1) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(aPoint1Coords, aPoint2Coords), DISTANCE1)
d += dStep
assert (model.dof(aSketchFeature) == 2)
# Change a distance value
#=========================================================================
d = DISTANCE3
-dStep = -5.
+dStep = -7.
while d >= -50.:
aSession.startOperation()
DISTANCE3 = d
aDistance.setValue(DISTANCE3)
aSession.finishOperation()
- if DISTANCE3 == 0:
- assert(aVDist3.error() != "")
- else:
- assert math.fabs(verticalDistance(aStartPoint, aEndPoint) - DISTANCE3) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(aStartPoint, aEndPoint), DISTANCE3)
+ assert math.fabs(verticalDistance(aStartPoint, aEndPoint) - DISTANCE3) < 1.e-5, "Distance values are different: {0} != {1}".format(verticalDistance(aStartPoint, aEndPoint), DISTANCE3)
d += dStep
assert (model.dof(aSketchFeature) == 6)
--- /dev/null
+# Copyright (C) 2019 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
+#
+
+"""
+ Test the zero value of the constraint "DistanceVertical"
+"""
+
+import unittest
+import math
+
+from salome.shaper import model
+from SketchAPI import *
+
+__updated__ = "2019-10-22"
+TOLERANCE = 1.e-6
+
+class TestZeroDistanceVertical(unittest.TestCase):
+ def setUp(self):
+ model.begin()
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+ self.myLine1 = self.mySketch.addLine(10, 10, 45, 27.5)
+ self.myLine2 = self.mySketch.addLine(20, 15, 30, 40)
+ self.myLine3 = self.mySketch.addLine(0, 10, 10, 10)
+ model.do()
+ self.myDOF = 12
+
+ def tearDown(self):
+ model.end()
+ model.checkSketch(self.mySketch, self.myDOF)
+
+ def assertDistanceVertical(self, theObject1, theObject2, theDistance):
+ dist = theObject2.y() - theObject1.y()
+ self.assertTrue(math.fabs(dist - theDistance) < TOLERANCE, "Current distance = {}, reference = {}".format(dist, theDistance))
+ model.checkSketch(self.mySketch, self.myDOF)
+
+
+ def test_distance_positive_nzznz(self):
+ """ Test 1. Change distance from non-zero to zero and back to non-zero
+ """
+ dist = self.mySketch.setVerticalDistance(self.myLine1.startPoint(), self.myLine2.startPoint(), 5)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine2.startPoint(), 5)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine2.startPoint(), 0)
+
+ SketchAPI_Constraint(dist).setValue(10)
+ model.do()
+ self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine2.startPoint(), 10)
+
+ def test_distance_negative_nzznz(self):
+ """ Test 2. Change distance from non-zero to zero and back to non-zero
+ """
+ dist = self.mySketch.setVerticalDistance(self.myLine1.endPoint(), self.myLine2.startPoint(), 12.5)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistanceVertical(self.myLine1.endPoint(), self.myLine2.startPoint(), -12.5)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistanceVertical(self.myLine1.endPoint(), self.myLine2.startPoint(), 0)
+
+ SketchAPI_Constraint(dist).setValue(12.5)
+ model.do()
+ self.assertDistanceVertical(self.myLine1.endPoint(), self.myLine2.startPoint(), -12.5)
+
+ def test_distance_equal_znzz(self):
+ """ Test 3. Change distance from zero to non-zero and back to zero
+ """
+ dist = self.mySketch.setVerticalDistance(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+
+ SketchAPI_Constraint(dist).setValue(10)
+ model.do()
+ self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine3.endPoint(), 10)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+
+ def test_distance_notequal_znzz(self):
+ """ Test 4. Change distance from zero to non-zero and back to zero
+ """
+ dist = self.mySketch.setVerticalDistance(self.myLine1.startPoint(), self.myLine3.startPoint(), 0)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine3.startPoint(), 0)
+
+ SketchAPI_Constraint(dist).setValue(10)
+ model.do()
+ self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine3.startPoint(), 10)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistanceVertical(self.myLine1.startPoint(), self.myLine3.startPoint(), 0)
+
+
+if __name__ == "__main__":
+ test_program = unittest.main(exit=False)
+ assert test_program.result.wasSuccessful(), "Test failed"
+ assert model.checkPythonDump()
--- /dev/null
+# Copyright (C) 2019 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
+#
+
+"""
+ Test the zero value of the constraint "Distance"
+"""
+
+import unittest
+import math
+
+from salome.shaper import model
+from SketchAPI import *
+
+__updated__ = "2019-10-22"
+TOLERANCE = 1.e-6
+
+class TestZeroDistance(unittest.TestCase):
+ def setUp(self):
+ model.begin()
+ self.myDocument = model.moduleDocument()
+ self.mySketch = model.addSketch(self.myDocument, model.defaultPlane("XOY"))
+ self.myLine1 = self.mySketch.addLine(10, 10, 45, 27.5)
+ self.myLine2 = self.mySketch.addLine(20, 15, 30, 40)
+ self.myLine3 = self.mySketch.addLine(10, 0, 10, 10)
+ model.do()
+ self.myDOF = 12
+
+ def tearDown(self):
+ model.end()
+ model.checkSketch(self.mySketch, self.myDOF)
+
+ def assertDistance(self, theObject1, theObject2, theDistance, isSigned = False):
+ dist = -1.
+ if issubclass(type(theObject1), SketchAPI_SketchEntity):
+ if isSigned:
+ dist = model.signedDistancePointLine(theObject2, theObject1)
+ else:
+ dist = model.distancePointLine(theObject2, theObject1)
+ elif issubclass(type(theObject2), SketchAPI_SketchEntity):
+ if isSigned:
+ dist = model.signedDistancePointLine(theObject1, theObject2)
+ else:
+ dist = model.distancePointLine(theObject1, theObject2)
+ else:
+ dist = model.distancePointPoint(theObject1, theObject2)
+ self.assertTrue(math.fabs(dist - theDistance) < TOLERANCE, "Current distance = {}, reference = {}".format(dist, theDistance))
+ model.checkSketch(self.mySketch, self.myDOF)
+
+
+ def test_distance_points_nzznz(self):
+ """ Test 1. Change point-point distance from non-zero to zero and back to non-zero
+ """
+ dist = self.mySketch.setDistance(self.myLine1.endPoint(), self.myLine2.endPoint(), 20)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistance(self.myLine1.endPoint(), self.myLine2.endPoint(), 20)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistance(self.myLine1.endPoint(), self.myLine2.endPoint(), 0)
+
+ SketchAPI_Constraint(dist).setValue(20)
+ self.myDOF += 1
+ model.do()
+ self.assertDistance(self.myLine1.endPoint(), self.myLine2.endPoint(), 20)
+
+ def test_distance_points_znzz(self):
+ """ Test 2. Change point-point distance from zero to non-zero and back to zero
+ """
+ dist = self.mySketch.setDistance(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+ self.myDOF -= 2
+ model.do()
+ self.assertDistance(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+
+ SketchAPI_Constraint(dist).setValue(10)
+ self.myDOF += 1
+ model.do()
+ self.assertDistance(self.myLine1.startPoint(), self.myLine3.endPoint(), 10)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistance(self.myLine1.startPoint(), self.myLine3.endPoint(), 0)
+
+
+ def test_unsigned_distance_nzznz(self):
+ """ Test 3. Change unsigned point-line distance from non-zero to zero and back to non-zero
+ """
+ dist = self.mySketch.setDistance(self.myLine1.result(), self.myLine2.endPoint(), 20)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistance(self.myLine1, self.myLine2.endPoint(), 20)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistance(self.myLine1, self.myLine2.endPoint(), 0)
+
+ SketchAPI_Constraint(dist).setValue(20)
+ model.do()
+ self.assertDistance(self.myLine1, self.myLine2.endPoint(), 20)
+
+ def test_unsigned_distance_znzz(self):
+ """ Test 4. Change unsigned point-line distance from zero to non-zero and back to zero
+ """
+ dist = self.mySketch.setDistance(self.myLine2.startPoint(), self.myLine1.result(), 0)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistance(self.myLine2.startPoint(), self.myLine1, 0)
+
+ SketchAPI_Constraint(dist).setValue(10)
+ model.do()
+ self.assertDistance(self.myLine2.startPoint(), self.myLine1, 10)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistance(self.myLine2.startPoint(), self.myLine1, 0)
+
+
+ def test_signed_distance_nzznz(self):
+ """ Test 5. Change signed point-line distance from non-zero to zero and back to non-zero
+ """
+ dist = self.mySketch.setDistance(self.myLine1.result(), self.myLine2.endPoint(), 20, True)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistance(self.myLine1, self.myLine2.endPoint(), -20, True)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistance(self.myLine1, self.myLine2.endPoint(), 0, True)
+
+ SketchAPI_Constraint(dist).setValue(20)
+ model.do()
+ self.assertDistance(self.myLine1, self.myLine2.endPoint(), -20, True)
+
+ def test_signed_distance_nzznz_2(self):
+ """ Test 6. Change signed point-line distance from non-zero to zero and back to non-zero
+ """
+ dist = self.mySketch.setDistance(self.myLine3.startPoint(), self.myLine1.result(), 10, True)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistance(self.myLine1, self.myLine3.startPoint(), 10, True)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistance(self.myLine1, self.myLine3.startPoint(), 0, True)
+
+ SketchAPI_Constraint(dist).setValue(20)
+ model.do()
+ self.assertDistance(self.myLine1, self.myLine3.startPoint(), 20, True)
+
+ def test_signed_distance_znzz(self):
+ """ Test 7. Change signed point-line distance from zero to non-zero and back to zero
+ """
+ dist = self.mySketch.setDistance(self.myLine2.startPoint(), self.myLine1.result(), 0, True)
+ self.myDOF -= 1
+ model.do()
+ self.assertDistance(self.myLine2.startPoint(), self.myLine1, 0)
+
+ SketchAPI_Constraint(dist).setValue(10)
+ model.do()
+ self.assertDistance(self.myLine2.startPoint(), self.myLine1, 10)
+
+ SketchAPI_Constraint(dist).setValue(0)
+ model.do()
+ self.assertDistance(self.myLine2.startPoint(), self.myLine1, 0)
+
+
+if __name__ == "__main__":
+ test_program = unittest.main(exit=False)
+ assert test_program.result.wasSuccessful(), "Test failed"
+ assert model.checkPythonDump()
<sketch-start-label id="External" geometrical_selection="true" title="Select a plane on which to create a sketch" tooltip="Select a plane on which to create a sketch">
<validator id="GeomValidators_Face" parameters="plane"/>
</sketch-start-label>
- <!-- <label id="SolverDOF"/> -->
- <label id="SolverError" styleSheet="color : red; font : bold"/>
+ <undo_label id="SolverError" isHTML="true" />
<validator id="SketchPlugin_SolverErrorValidator"/>
</feature>
<validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityB"/>
<validator id="PartSet_DifferentObjects"/>
<validator id="GeomValidators_ShapeType" parameters="vertex,line"/>
- <validator id="PartSet_DifferentPoints" parameters="ConstraintEntityB"/>
</sketch_shape_selector>
<sketch_shape_selector
id="ConstraintEntityB"
<validator id="SketchPlugin_DistanceAttr" parameters="ConstraintEntityA"/>
<validator id="SketchPlugin_ExternalValidator" parameters="ConstraintEntityA"/>
<validator id="GeomValidators_ShapeType" parameters="vertex,line"/>
- <validator id="PartSet_DifferentPoints" parameters="ConstraintEntityA"/>
</sketch_shape_selector>
<sketch-2dpoint_flyout_selector id="ConstraintFlyoutValuePnt" default="computed" internal="1" obligatory="0"/>
<doublevalue_editor label="Value" tooltip="Distance" id="ConstraintValue" default="computed" min="0">
- <validator id="GeomValidators_Positive"/>
+ <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
</doublevalue_editor>
<module_choice id="LocationType"
<sketch-2dpoint_flyout_selector id="ConstraintFlyoutValuePnt" default="computed" internal="1" obligatory="0"/>
<doublevalue_editor label="Value" tooltip="Distance" id="DistanceValue" default="computed" min="0">
- <validator id="GeomValidators_Positive"/>
+ <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
</doublevalue_editor>
<module_choice id="LocationType"
<sketch-2dpoint_flyout_selector id="ConstraintFlyoutValuePnt" default="computed" internal="1" obligatory="0"/>
<doublevalue_editor label="Value" tooltip="Distance" id="DistanceValue" default="computed" min="0">
- <validator id="GeomValidators_Positive"/>
+ <validator id="GeomValidators_Positive" parameters="-1.e-10"/>
</doublevalue_editor>
<module_choice id="LocationType"
double PlaneGCSSolver_ConstraintWrapper::value() const
{
- return myValueParam->value();
+ return myValueParam ? myValueParam->value() : 0.0;
}
#include <PlaneGCSSolver_PointWrapper.h>
#include <PlaneGCSSolver_Storage.h>
#include <PlaneGCSSolver_Tools.h>
+#include <PlaneGCSSolver_UpdateCoincidence.h>
#include <SketchPlugin_ConstraintDistanceHorizontal.h>
#include <SketchPlugin_ConstraintDistanceVertical.h>
*(theOddPoint->y) = aProjectedPnt->y();
}
+static FeaturePtr getFeature(AttributeRefAttrPtr theRefAttr)
+{
+ ObjectPtr anObj;
+ if (theRefAttr->isObject())
+ anObj = theRefAttr->object();
+ else
+ anObj = theRefAttr->attr()->owner();
+ return ModelAPI_Feature::feature(anObj);
+}
+
+static void calculateDistanceDirection(const ConstraintPtr& theConstraint,
+ const StoragePtr& theStorage,
+ double& theDirX, double& theDirY)
+{
+ std::shared_ptr<GeomDataAPI_Dir> aDistDir = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+ theConstraint->attribute(SketchPlugin_ConstraintDistance::DIRECTION_ID()));
+ if (aDistDir && aDistDir->isInitialized()) {
+ theDirX = aDistDir->x();
+ theDirY = aDistDir->y();
+ if (fabs(theDirX) > tolerance || fabs(theDirY) > tolerance)
+ return;
+ }
+
+ AttributeRefAttrPtr aRefAttrA = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
+ AttributeRefAttrPtr aRefAttrB = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_B());
+
+ EntityWrapperPtr aEntityA = theStorage->entity(aRefAttrA);
+ EntityWrapperPtr aEntityB = theStorage->entity(aRefAttrB);
+
+ GCSPointPtr aPoint;
+ if (aEntityA->type() != ENTITY_LINE && aEntityB->type() != ENTITY_LINE) {
+ aPoint = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(aEntityA)->point();
+ theDirX = 1.0;
+ theDirY = 0.0;
+
+ EdgeWrapperPtr anEdgeA = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(
+ theStorage->entity(getFeature(aRefAttrA)));
+ EdgeWrapperPtr anEdgeB = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(
+ theStorage->entity(getFeature(aRefAttrB)));
+
+ if (anEdgeA && anEdgeB) {
+ GCS::DeriVector2 aDirA = anEdgeA->entity()->CalculateNormal(*aPoint);
+ GCS::DeriVector2 aDirB = anEdgeB->entity()->CalculateNormal(*aPoint);
+ double x = -aDirA.x + aDirB.x;
+ double y = -aDirA.y + aDirB.y;
+ double norm = sqrt(x*x + y*y);
+ if (norm > tolerance) {
+ theDirX = x / norm;
+ theDirY = y / norm;
+ }
+ }
+ }
+}
+
+static void moveEntity(const ConstraintPtr& theConstraint,
+ const StoragePtr& theStorage,
+ const double theDX, const double theDY)
+{
+ static const double THE_SHIFT = 1.e-4;
+
+ AttributeRefAttrPtr aRefAttrA = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
+ AttributeRefAttrPtr aRefAttrB = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_B());
+
+ EntityWrapperPtr aEntityA = theStorage->entity(aRefAttrA);
+ EntityWrapperPtr aEntityB = theStorage->entity(aRefAttrB);
+
+ PointWrapperPtr aPointA = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(aEntityA);
+ PointWrapperPtr aPointB = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(aEntityB);
+
+ if (aPointA) {
+ *aPointA->point()->x -= THE_SHIFT * theDX;
+ *aPointA->point()->y -= THE_SHIFT * theDY;
+ }
+ else if (aPointB) {
+ *aPointB->point()->x += THE_SHIFT * theDX;
+ *aPointB->point()->y += THE_SHIFT * theDY;
+ }
+}
+
+
void SketchSolver_ConstraintDistance::getAttributes(
EntityWrapperPtr& theValue,
return;
}
+ ScalarWrapperPtr aValue = std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(theValue);
+ bool isCoincidence = fabs(aValue->value()) < tolerance;
+
if (theAttributes[1]) {
if (myBaseConstraint->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID())
myType = CONSTRAINT_HORIZONTAL_DISTANCE;
else if (myBaseConstraint->getKind() == SketchPlugin_ConstraintDistanceVertical::ID())
myType = CONSTRAINT_VERTICAL_DISTANCE;
else
- myType = CONSTRAINT_PT_PT_DISTANCE;
+ myType = isCoincidence ? CONSTRAINT_PT_PT_COINCIDENT : CONSTRAINT_PT_PT_DISTANCE;
} else if (theAttributes[2] && theAttributes[2]->type() == ENTITY_LINE)
- myType = CONSTRAINT_PT_LINE_DISTANCE;
+ myType = isCoincidence ? CONSTRAINT_PT_ON_CURVE : CONSTRAINT_PT_LINE_DISTANCE;
else
theAttributes.clear();
+ if (myType == CONSTRAINT_HORIZONTAL_DISTANCE || myType == CONSTRAINT_VERTICAL_DISTANCE)
+ mySignValue = aValue->value() < 0.0 ? -1.0 : 1.0;
+
myPrevValue = 0.0;
- myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateFeature::GROUP());
+ if (isCoincidence)
+ myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateCoincidence::GROUP());
+ else
+ myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateFeature::GROUP());
}
void SketchSolver_ConstraintDistance::adjustConstraint()
ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint);
myPrevValue = aConstraint->value();
- SketchSolver_Constraint::update();
+ bool isDistanceAlognDir =
+ myBaseConstraint->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID() ||
+ myBaseConstraint->getKind() == SketchPlugin_ConstraintDistanceVertical::ID();
+
+ AttributeDoublePtr aCurValue = myBaseConstraint->real(SketchPlugin_Constraint::VALUE());
+ bool isZeroSwitch = fabs(myPrevValue) < tolerance && fabs(aCurValue->value()) > tolerance;
+ bool isNonZeroSwitch = fabs(myPrevValue) > tolerance && fabs(aCurValue->value()) < tolerance;
+
+ if (!isDistanceAlognDir && (isZeroSwitch || isNonZeroSwitch)) {
+ // the value is changed from non-zero to zero or vice versa
+ remove();
+ process();
+
+ // move entities to avoid conflicting constraints
+ if (isZeroSwitch) {
+ double aDirX, aDirY;
+ // calculate the direction basing on the distanced objects
+ calculateDistanceDirection(myBaseConstraint, myStorage, aDirX, aDirY);
+ moveEntity(myBaseConstraint, myStorage, aDirX, aDirY);
+
+ if (myOddPoint) {
+ removeConstraintsKeepingSign();
+ addConstraintsToKeepSign();
+ }
+ }
+ }
+ else {
+ SketchSolver_Constraint::update();
+ if (isDistanceAlognDir && mySignValue * aConstraint->value() < 0.0) {
+ if (isZeroSwitch)
+ aConstraint->setValue(-aConstraint->value());
+ else
+ mySignValue *= -1.0;
+ }
+ }
}
bool SketchSolver_ConstraintDistance::remove()
/// The value parameter for the constraint
inline static const std::string& CONSTRAINTS()
{
- static const std::string MY_ERROR_VALUE("The constraint is conflicting with others. "
- "To fix this, you can either undo your operation or remove a conflicting constraint.");
+ static const std::string MY_ERROR_VALUE("<b>The constraint is conflicting with others. "
+ "To fix this, you can either <font color='red'>undo (Ctrl+Z)</font> your operation or "
+ "<font color='red'>remove</font> a conflicting constraint.</b>");
return MY_ERROR_VALUE;
}
/// Cyclic dependency of copied features with their originals
inline static const std::string& INFINITE_LOOP()
{
static const std::string MY_ERROR_VALUE(
- "There is a circular reference between copied sketch entities and their originals. "
- "To fix this, you can either undo your operation or remove wrong constraint.");
+ "<b>There is a circular reference between copied sketch entities and their originals. "
+ "To fix this, you can either <font color='red'>undo (Ctrl+Z)</font> your operation or "
+ "<font color='red'>remove</font> wrong constraint.</b>");
return MY_ERROR_VALUE;
}
/// Constraints should use objects instead of features as attributes
return readyToDisplay(theConstraint, thePlane, aPnt1, aPnt2);
}
+static bool isEqualPoints(ModelAPI_Feature* theConstraint,
+ const gp_Pnt& thePoint1,
+ const gp_Pnt& thePoint2)
+{
+ bool isEqual = false;
+ if (theConstraint->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID())
+ isEqual = Abs(thePoint1.X() - thePoint2.X()) < Precision::Confusion();
+ else if (theConstraint->getKind() == SketchPlugin_ConstraintDistanceVertical::ID())
+ isEqual = Abs(thePoint1.Y() - thePoint2.Y()) < Precision::Confusion();
+ else
+ isEqual = thePoint1.SquareDistance(thePoint2) < Precision::SquareConfusion();
+ return isEqual;
+}
+
void SketcherPrs_LengthDimension::Compute(
const Handle(PrsMgr_PresentationManager3d)& thePresentationManager,
const Handle(Prs3d_Presentation)& thePresentation,
gp_Pnt aPnt1, aPnt2;
bool aReadyToDisplay = readyToDisplay(myConstraint, plane(), aPnt1, aPnt2);
if (aReadyToDisplay) {
+ if (isEqualPoints(myConstraint, aPnt1, aPnt2)) {
+ // adjust points to draw the dimension presentation
+ std::shared_ptr<GeomDataAPI_Dir> aDirAttr = std::dynamic_pointer_cast<GeomDataAPI_Dir>(
+ myConstraint->attribute(SketchPlugin_ConstraintDistance::DIRECTION_ID()));
+ double x = 0.0, y = 0.0;
+ if (aDirAttr && aDirAttr->isInitialized()) {
+ x = aDirAttr->x();
+ y = aDirAttr->y();
+ if (x == 0.0 && y == 0.0)
+ x = 1.0;
+ }
+ else if (myConstraint->getKind() == SketchPlugin_ConstraintDistanceVertical::ID())
+ y = 1.0;
+ else
+ x = 1.0;
+ GeomPointPtr aCoord = plane()->to3D(x, y);
+
+ gp_XYZ aDir(aCoord->x(), aCoord->y(), aCoord->z());
+ aPnt1.ChangeCoord().Add(aDir * (-Precision::Confusion()));
+ aPnt2.ChangeCoord().Add(aDir * Precision::Confusion());
+ }
+
myFirstPoint = aPnt1;
mySecondPoint = aPnt2;
if (!aPnt_A || !aPnt_B) // Objects not found
return false;
- if (theConstraint->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID()) {
+ /*if (theConstraint->getKind() == SketchPlugin_ConstraintDistanceHorizontal::ID()) {
if (fabs(aPnt_A->x() - aPnt_B->x()) < Precision::Confusion())
return false;
}
else if (theConstraint->getKind() == SketchPlugin_ConstraintDistanceVertical::ID()) {
if (fabs(aPnt_A->y() - aPnt_B->y()) < Precision::Confusion())
return false;
- }
+ }*/
// Get points from these object
std::shared_ptr<GeomAPI_Pnt> aPoint1 = thePlane->to3D(aPnt_A->x(), aPnt_A->y());
SET(PROJECT_INCLUDES
${PROJECT_SOURCE_DIR}/src/Events
${PROJECT_SOURCE_DIR}/src/Config
+ ${PROJECT_SOURCE_DIR}/src/ExchangePlugin
${PROJECT_SOURCE_DIR}/src/ModelAPI
${PROJECT_SOURCE_DIR}/src/GeomAPI
${PROJECT_SOURCE_DIR}/src/ModuleBase
#include <ModuleBase_IModule.h>
#include <ModuleBase_Tools.h>
-#include <ModuleBase_OperationAction.h>
+#include <ModuleBase_Operation.h>
#include <ModuleBase_ViewerPrs.h>
#include <QAction>
//**************************************************************
XGUI_Displayer::XGUI_Displayer(XGUI_Workshop* theWorkshop)
: myWorkshop(theWorkshop), myNeedUpdate(false),
- myViewerBlockedRecursiveCount(0), myIsFirstAISContextUse(true)
+ myViewerBlockedRecursiveCount(0), myContextId(0)
{
}
Handle(AIS_InteractiveContext) XGUI_Displayer::AISContext() const
{
Handle(AIS_InteractiveContext) aContext = myWorkshop->viewer()->AISContext();
- if (!aContext.IsNull() && myIsFirstAISContextUse/*&& !aContext->HasOpenedContext()*/) {
- XGUI_Displayer* aDisplayer = (XGUI_Displayer*)this;
- aDisplayer->myIsFirstAISContextUse = false;
+ if (!aContext.IsNull() && (myContextId != aContext.get())) {
+ myContextId = aContext.get();
if (!myWorkshop->selectionActivate()->isTrihedronActive())
selectionActivate()->deactivateTrihedron(true);
aContext->DefaultDrawer()->VIsoAspect()->SetNumber(0);
aContext->DefaultDrawer()->UIsoAspect()->SetNumber(0);
- ModuleBase_IViewer::DefaultHighlightDrawer = aContext->HighlightStyle();
+ //Handle(AIS_Trihedron) aTrihedron = myWorkshop->viewer()->trihedron();
+ //aTrihedron->getHighlightPointAspect()->SetScale(2.0);
+ //aTrihedron->getHighlightPointAspect()->SetTypeOfMarker(Aspect_TOM_O_STAR);
+
// Commented out according to discussion in bug #2825
+ //ModuleBase_IViewer::DefaultHighlightDrawer = aContext->HighlightStyle();
//Handle(Prs3d_Drawer) aSelStyle = aContext->SelectionStyle();
//double aDeflection =
// QString(ModelAPI_ResultConstruction::DEFAULT_DEFLECTION().c_str()).toDouble();
return aContext;
}
+//**************************************************************
+void XGUI_Displayer::setSelectionColor(const std::vector<int>& theColor)
+{
+ Handle(AIS_InteractiveContext) aContext = AISContext();
+ if (!aContext.IsNull()) {
+ Quantity_Color aQColor(theColor[0] / 255.,
+ theColor[1] / 255.,
+ theColor[2] / 255., Quantity_TOC_RGB);
+ aContext->SelectionStyle()->SetColor(aQColor);
+ aContext->HighlightStyle(Prs3d_TypeOfHighlight_LocalSelected)->SetColor(aQColor);
+ }
+}
+
+
+//**************************************************************
+std::vector<int> XGUI_Displayer::selectionColor() const
+{
+ std::vector<int> aColor;
+ Handle(AIS_InteractiveContext) aContext = AISContext();
+ if (!aContext.IsNull()) {
+ Quantity_Color aQColor = aContext->SelectionStyle()->Color();
+ aColor.push_back((int)(aQColor.Red() * 255));
+ aColor.push_back((int)(aQColor.Green() * 255));
+ aColor.push_back((int)(aQColor.Blue() * 255));
+ }
+ return aColor;
+}
+
+
//**************************************************************
Handle(SelectMgr_AndFilter) XGUI_Displayer::GetFilter()
{
/// Returns scale of active view
double getViewScale() const;
+ /// Set color of selection
+ /// \param theColor R,G,B values of color
+ void setSelectionColor(const std::vector<int>& theColor);
+
+ /// Returns current selection color
+ std::vector<int> selectionColor() const;
+
signals:
/// Signal on object display
/// \param theObject a data object
/// Number of blocking of the viewer update. The viewer is updated only if it is zero
int myViewerBlockedRecursiveCount;
- bool myIsFirstAISContextUse; ///< Flag: first asking of AIS context: trihedron activation
+ mutable void* myContextId;
mutable bool myNeedUpdate; ///< A flag that update was requested but not done
};
#include "XGUI_FacesPanel.h"
#include "XGUI_ObjectsBrowser.h"
#include "XGUI_SelectionMgr.h"
+#include "XGUI_Selection.h"
#include "XGUI_Tools.h"
#include "XGUI_Workshop.h"
+#include "XGUI_Displayer.h"
+#include "XGUI_ViewerProxy.h"
#include <ModuleBase_IModule.h>
#include <ModuleBase_ISelection.h>
#include <Config_PropManager.h>
#include <Events_Loop.h>
#include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAPI_Shape.h>
#include <ModelAPI_Events.h>
+#include <ModelAPI_ResultGroup.h>
+#include <ModelAPI_AttributeSelectionList.h>
#include <QAction>
#include <QCheckBox>
static const int LayoutMargin = 3;
//********************************************************************
-XGUI_FacesPanel::XGUI_FacesPanel(QWidget* theParent, ModuleBase_IWorkshop* theWorkshop)
+XGUI_FacesPanel::XGUI_FacesPanel(QWidget* theParent, XGUI_Workshop* theWorkshop)
: QDockWidget(theParent), myIsActive(false), myWorkshop(theWorkshop)
{
setWindowTitle(tr("Hide Faces"));
if (myLastItemIndex == 0) // do nothing because there was no activity in the pane after reset
return;
- // clear internal containers
- myListView->getControl()->clear();
- myItems.clear();
+ std::map<ObjectPtr, TopoDS_ListOfShape> anObjectToShapes;
+ std::map<ObjectPtr, Handle(ModuleBase_ResultPrs) > anObjectToPrs;
+ QMap<int, std::shared_ptr<ModuleBase_ViewerPrs> >::const_iterator aIt;
+ for (aIt = myItems.cbegin(); aIt != myItems.cend(); aIt++) {
+ getObjectsMapFromPrs(aIt.value(), anObjectToShapes, anObjectToPrs);
+ }
- // restore previous view of presentations
- bool isModified = redisplayObjects(myItemObjects);
- std::set<std::shared_ptr<ModelAPI_Object> > aHiddenObjects = myHiddenObjects;
- isModified = displayHiddenObjects(aHiddenObjects, myHiddenObjects) || isModified;
- if (isModified)// && isToFlushRedisplay) // flush signal immediatelly until container is filled
+ std::set<ObjectPtr> aObjects;
+ TopoDS_ListOfShape anEmpty;
+ std::map<ObjectPtr, Handle(ModuleBase_ResultPrs)>::const_iterator aPrsIt;
+ for (aPrsIt = anObjectToPrs.cbegin(); aPrsIt != anObjectToPrs.cend(); aPrsIt++) {
+ aObjects.insert(aPrsIt->first);
+ aPrsIt->second->setSubShapeHidden(anEmpty);
+ }
+ std::set<std::shared_ptr<ModelAPI_Object> >::const_iterator aGrpIt;
+ for (aGrpIt = myHiddenGroups.cbegin(); aGrpIt != myHiddenGroups.cend(); aGrpIt++)
+ (*aGrpIt)->setDisplayed(true);
+ myHiddenGroups.clear();
+
+ if (redisplayObjects(aObjects))
flushRedisplay();
+ // clear internal containers
+ myListView->getControl()->clear();
+ myItems.clear();
updateProcessedObjects(myItems, myItemObjects);
- myHiddenObjects.clear();
myLastItemIndex = 0; // it should be after redisplay as flag used in customize
+ myHiddenObjects.clear();
}
//********************************************************************
ModuleBase_IModule* aModule = myWorkshop->module();
QIntList aModuleSelectionFilters = myWorkshop->module()->selectionFilters();
- theSelectionFilters.Append(aModule->selectionFilter(SF_GlobalFilter));
+ // The global filter makes problem for groups selection when any operation is launched
+ // theSelectionFilters.Append(aModule->selectionFilter(SF_GlobalFilter));
theSelectionFilters.Append(aModule->selectionFilter(SF_FilterInfinite));
theSelectionFilters.Append(aModule->selectionFilter(SF_ResultGroupNameFilter));
}
// selection should be cleared after emit of signal to do not process selection change
// event by the previous selector
// the selection is cleared by activating selection control
- XGUI_Tools::workshop(myWorkshop)->selector()->clearSelection();
+ myWorkshop->selector()->clearSelection();
}
else
emit deactivated();
return myHiddenOrTransparent->isChecked();
}
+//********************************************************************
+double XGUI_FacesPanel::transparency() const
+{
+ return useTransparency() ?
+ Config_PropManager::real("Visualization", "hidden_face_transparency") : 1;
+}
+
+
//********************************************************************
void XGUI_FacesPanel::restoreObjects(const std::set<ObjectPtr>& theHiddenObjects)
{
}
}
+//********************************************************************
+void XGUI_FacesPanel::getObjectsMapFromPrs(ModuleBase_ViewerPrsPtr thePrs,
+ std::map<ObjectPtr, TopoDS_ListOfShape>& theObjectToShapes,
+ std::map<ObjectPtr, Handle(ModuleBase_ResultPrs) >& theObjectToPrs)
+{
+ ObjectPtr anObject = thePrs->object();
+ if (!anObject.get())
+ return;
+
+ XGUI_Displayer* aDisplayer = myWorkshop->displayer();
+ ResultGroupPtr aResGroup = std::dynamic_pointer_cast<ModelAPI_ResultGroup>(anObject);
+ if (aResGroup.get()) {
+ // Process a grouip result
+ FeaturePtr aGroupFeature = ModelAPI_Feature::feature(aResGroup);
+ AttributeSelectionListPtr aSelectionList = aGroupFeature->selectionList("group_list");
+ AISObjectPtr aPrs;
+ for (int i = 0; i < aSelectionList->size(); i++) {
+ AttributeSelectionPtr aSelection = aSelectionList->value(i);
+ ResultPtr aRes = aSelection->context();
+ aPrs = aDisplayer->getAISObject(aRes);
+ if (aPrs.get()) {
+ Handle(ModuleBase_ResultPrs) aResultPrs = Handle(ModuleBase_ResultPrs)::DownCast(
+ aPrs->impl<Handle(AIS_InteractiveObject)>());
+ if (!aResultPrs.IsNull()) {
+ GeomShapePtr aShape = aSelection->value();
+ if (theObjectToShapes.find(aRes) != theObjectToShapes.end())
+ theObjectToShapes.at(aRes).Append(aShape->impl<TopoDS_Shape>());
+ else {
+ TopoDS_ListOfShape aListOfShapes;
+ aListOfShapes.Append(aShape->impl<TopoDS_Shape>());
+ theObjectToShapes[aRes] = aListOfShapes;
+ theObjectToPrs[aRes] = aResultPrs;
+ }
+ }
+ }
+ }
+ }
+ else {
+ // Process bodies
+ Handle(ModuleBase_ResultPrs) aResultPrs = Handle(ModuleBase_ResultPrs)::DownCast(
+ thePrs->interactive());
+ if (aResultPrs.IsNull())
+ return;
+
+ if (theObjectToShapes.find(anObject) != theObjectToShapes.end())
+ theObjectToShapes.at(anObject).Append(ModuleBase_Tools::getSelectedShape(thePrs));
+ else {
+ TopoDS_ListOfShape aListOfShapes;
+ aListOfShapes.Append(ModuleBase_Tools::getSelectedShape(thePrs));
+ theObjectToShapes[anObject] = aListOfShapes;
+ theObjectToPrs[anObject] = aResultPrs;
+ }
+ }
+}
+
//********************************************************************
void XGUI_FacesPanel::processSelection()
{
- QList<ModuleBase_ViewerPrsPtr> aSelected = myWorkshop->selection()->getSelected(
- ModuleBase_ISelection::Viewer);
+ QList<ModuleBase_ViewerPrsPtr> aSelected =
+ myWorkshop->selector()->selection()->getSelected(ModuleBase_ISelection::Viewer);
+
bool isModified = false;
static Events_ID aDispEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
- std::map<ObjectPtr, NCollection_List<TopoDS_Shape> > anObjectToShapes;
+ std::map<ObjectPtr, TopoDS_ListOfShape> anObjectToShapes;
std::map<ObjectPtr, Handle(ModuleBase_ResultPrs) > anObjectToPrs;
+ std::set<int> aToRemove;
+
for (int i = 0; i < aSelected.size(); i++) {
ModuleBase_ViewerPrsPtr aPrs = aSelected[i];
ObjectPtr anObject = aPrs->object();
if (!anObject.get())
continue;
- if (ModuleBase_Tools::getSelectedShape(aPrs).ShapeType() != TopAbs_FACE)
- continue;
- Handle(ModuleBase_ResultPrs) aResultPrs = Handle(ModuleBase_ResultPrs)::DownCast(
- aPrs->interactive());
- if (aResultPrs.IsNull())
- continue;
- QString aItemName = XGUI_Tools::generateName(aPrs);
+ ResultGroupPtr aResGroup = std::dynamic_pointer_cast<ModelAPI_ResultGroup>(anObject);
+ if (!aResGroup.get()) {
+ GeomShapePtr aShapePtr = aPrs->shape();
+ if (!aShapePtr.get() || !aShapePtr->isFace())
+ return;
+ }
+
+ QString aItemName = aResGroup.get()?
+ aResGroup->data()->name().c_str() : XGUI_Tools::generateName(aPrs);
if (myListView->hasItem(aItemName))
return;
+ getObjectsMapFromPrs(aPrs, anObjectToShapes, anObjectToPrs);
+ if (aResGroup.get() && aResGroup->isDisplayed()) {
+ aResGroup->setDisplayed(false);
+ myHiddenGroups.insert(aResGroup);
+ }
+
+ // The code is dedicated to remove already selected items if they are selected twice
+ // It can happen in case of groups selection
+ QMap<int, ModuleBase_ViewerPrsPtr>::const_iterator aIt;
+ for (aIt = myItems.cbegin(); aIt != myItems.cend(); aIt++) {
+ ModuleBase_ViewerPrsPtr aPrs = aIt.value();
+ ObjectPtr aObject = aPrs->object();
+ ResultGroupPtr aResGroup = std::dynamic_pointer_cast<ModelAPI_ResultGroup>(aObject);
+ if (aResGroup.get())
+ continue;
+ if (anObjectToShapes.find(aObject) != anObjectToShapes.end()) {
+ TopoDS_ListOfShape aShapes = anObjectToShapes[aObject];
+ GeomShapePtr aShapePtr = aPrs->shape();
+ if (aShapes.Contains(aShapePtr->impl<TopoDS_Shape>())) {
+ aToRemove.insert(aIt.key());
+ }
+ }
+ }
+
myItems.insert(myLastItemIndex, aPrs);
myListView->addItem(aItemName, myLastItemIndex);
myLastItemIndex++;
isModified = true;
-
- if (anObjectToShapes.find(anObject) != anObjectToShapes.end())
- anObjectToShapes.at(anObject).Append(ModuleBase_Tools::getSelectedShape(aPrs));
- else {
- NCollection_List<TopoDS_Shape> aListOfShapes;
- aListOfShapes.Append(ModuleBase_Tools::getSelectedShape(aPrs));
- anObjectToShapes[anObject] = aListOfShapes;
- anObjectToPrs[anObject] = aResultPrs;
- }
}
- for (std::map<ObjectPtr, NCollection_List<TopoDS_Shape> >::const_iterator
- anIt = anObjectToShapes.begin(); anIt != anObjectToShapes.end(); anIt++) {
+
+ // Hide fully hidden shapes
+ std::map<ObjectPtr, TopoDS_ListOfShape>::const_iterator anIt;
+ for (anIt = anObjectToShapes.begin(); anIt != anObjectToShapes.end(); anIt++) {
ObjectPtr anObject = anIt->first;
if (!anObject.get() || anObjectToPrs.find(anObject) == anObjectToPrs.end())
continue;
}
ModelAPI_EventCreator::get()->sendUpdated(anObject, aDispEvent);
}
+
+ // Process selected presentations
+ double aTransp = transparency();
+ std::map<ObjectPtr, Handle(ModuleBase_ResultPrs)>::iterator aPrsIt;
+ for (aPrsIt = anObjectToPrs.begin(); aPrsIt != anObjectToPrs.end(); aPrsIt++) {
+ ObjectPtr anObject = aPrsIt->first;
+ Handle(ModuleBase_ResultPrs) aPrs = aPrsIt->second;
+ TopoDS_ListOfShape aAlreadyHidden = aPrs->hiddenSubShapes();
+ TopoDS_ListOfShape aListOfShapes = anObjectToShapes[anObject];
+ TopoDS_ListOfShape::Iterator aShapesIt(aListOfShapes);
+ for (; aShapesIt.More(); aShapesIt.Next()) {
+ if (!aAlreadyHidden.Contains(aShapesIt.Value()))
+ aAlreadyHidden.Append(aShapesIt.Value());
+ }
+ aPrs->setSubShapeHidden(aAlreadyHidden);
+ aPrs->setHiddenSubShapeTransparency(aTransp);
+ }
+
+ // Remove duplicate items
+ if (aToRemove.size() > 0) {
+ myListView->removeItems(aToRemove);
+ std::set<int>::const_iterator aIntIt;
+ for (aIntIt = aToRemove.cbegin(); aIntIt != aToRemove.cend(); aIntIt++)
+ myItems.remove(*aIntIt);
+ }
if (isModified) {
updateProcessedObjects(myItems, myItemObjects);
flushRedisplay();
}
- onTransparencyChanged();
}
//********************************************************************
return false;
bool isModified = false;
- std::set<ObjectPtr> aRestoredObjects;
- for (std::set<int>::const_iterator anIt = aSelectedIds.begin(); anIt != aSelectedIds.end();
- anIt++) {
+ std::set<ModuleBase_ViewerPrsPtr> aRestored;
+ std::set<int>::const_iterator anIt;
+ for (anIt = aSelectedIds.begin(); anIt != aSelectedIds.end(); anIt++) {
ModuleBase_ViewerPrsPtr aPrs = myItems[*anIt];
- if (aRestoredObjects.find(aPrs->object()) == aRestoredObjects.end())
- aRestoredObjects.insert(aPrs->object());
- myItems.remove(*anIt);
- isModified = true;
+ if (aRestored.find(aPrs) == aRestored.end()) {
+ aRestored.insert(aPrs);
+ myItems.remove(*anIt);
+ isModified = true;
+ }
}
- if (isModified) {
- bool isRedisplayed = redisplayObjects(aRestoredObjects);
- isRedisplayed = displayHiddenObjects(aRestoredObjects, myHiddenObjects)
- || isRedisplayed;
- if (isRedisplayed) {
- flushRedisplay();
- myWorkshop->viewer()->update();
+ std::map<ObjectPtr, TopoDS_ListOfShape> anObjectToShapes;
+ std::map<ObjectPtr, Handle(ModuleBase_ResultPrs) > anObjectToPrs;
+
+ std::set<ModuleBase_ViewerPrsPtr>::const_iterator aIt;
+ for (aIt = aRestored.cbegin(); aIt != aRestored.cend(); aIt++) {
+ getObjectsMapFromPrs((*aIt), anObjectToShapes, anObjectToPrs);
+ ResultGroupPtr aResGroup = std::dynamic_pointer_cast<ModelAPI_ResultGroup>((*aIt)->object());
+ if (aResGroup.get()) {
+ std::set<std::shared_ptr<ModelAPI_Object> >::iterator aGrpIt = myHiddenGroups.find(aResGroup);
+ if (aGrpIt != myHiddenGroups.end()) {
+ aResGroup->setDisplayed(true);
+ myHiddenGroups.erase(aGrpIt);
+ }
}
- // should be after flush of redisplay to have items object to be updated
- updateProcessedObjects(myItems, myItemObjects);
+ }
+ std::set<ObjectPtr> aRestoredObjects;
+ std::map<ObjectPtr, TopoDS_ListOfShape>::const_iterator aShapesIt;
+ for (aShapesIt = anObjectToShapes.begin(); aShapesIt != anObjectToShapes.end(); aShapesIt++) {
+ TopoDS_ListOfShape aShapes = aShapesIt->second;
+ aRestoredObjects.insert(aShapesIt->first);
+ Handle(ModuleBase_ResultPrs) aPrs = anObjectToPrs[aShapesIt->first];
+ TopoDS_ListOfShape aHiddenShapes = aPrs->hiddenSubShapes();
+ TopoDS_ListOfShape::Iterator aSubShapesIt(aShapes);
+ for (; aSubShapesIt.More(); aSubShapesIt.Next()) {
+ if (aHiddenShapes.Contains(aSubShapesIt.Value()))
+ aHiddenShapes.Remove(aSubShapesIt.Value());
+ }
+ aPrs->setSubShapeHidden(aHiddenShapes);
}
+ if (redisplayObjects(aRestoredObjects))
+ flushRedisplay();
myListView->removeSelectedItems();
- // Restore selection
- myListView->restoreSelection(anIndices);
- //appendSelectionInHistory();
return true;
}
return isModified;
}
-//********************************************************************
-bool XGUI_FacesPanel::displayHiddenObjects(
- const std::set<std::shared_ptr<ModelAPI_Object> >& theObjects,
- std::set<std::shared_ptr<ModelAPI_Object> >& theHiddenObjects)
-{
- if (theObjects.empty())
- return false;
-
- bool isModified = false;
- static Events_ID aDispEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
-
- for (std::set<ObjectPtr>::const_iterator anIt = theObjects.begin(); anIt != theObjects.end();
- anIt++)
- {
- ObjectPtr anObject = *anIt;
- // if the object was hidden by this panel
- if (anObject->isDisplayed() || theHiddenObjects.find(anObject) == theHiddenObjects.end())
- continue;
- theHiddenObjects.erase(anObject);
- anObject->setDisplayed(true); // it means that the object is hidden by hide all faces
- ModelAPI_EventCreator::get()->sendUpdated(anObject, aDispEvent);
- isModified = true;
- }
- return isModified;
-}
-
-//********************************************************************
-bool XGUI_FacesPanel::hideEmptyObjects()
-{
- bool isModified = false;
- static Events_ID aDispEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
- std::map<ObjectPtr, NCollection_List<TopoDS_Shape> > anObjectToShapes;
- std::map<ObjectPtr, Handle(ModuleBase_ResultPrs) > anObjectToPrs;
-
- for (QMap<int, ModuleBase_ViewerPrsPtr>::const_iterator anIt = myItems.begin();
- anIt != myItems.end(); anIt++) {
- ModuleBase_ViewerPrsPtr aPrs = anIt.value();
- ObjectPtr anObject = aPrs->object();
- if (!anObject.get() || !anObject->isDisplayed())
- continue;
-
- Handle(ModuleBase_ResultPrs) aResultPrs = Handle(ModuleBase_ResultPrs)::DownCast(
- aPrs->interactive());
- if (aResultPrs.IsNull())
- continue;
-
- if (anObjectToShapes.find(anObject) != anObjectToShapes.end())
- anObjectToShapes.at(anObject).Append(ModuleBase_Tools::getSelectedShape(aPrs));
- else {
- NCollection_List<TopoDS_Shape> aListOfShapes;
- aListOfShapes.Append(ModuleBase_Tools::getSelectedShape(aPrs));
- anObjectToShapes[anObject] = aListOfShapes;
- anObjectToPrs[anObject] = aResultPrs;
- }
- }
- for (std::map<ObjectPtr, NCollection_List<TopoDS_Shape> >::const_iterator
- anIt = anObjectToShapes.begin(); anIt != anObjectToShapes.end(); anIt++) {
- ObjectPtr anObject = anIt->first;
- if (!anObject.get() || anObjectToPrs.find(anObject) == anObjectToPrs.end())
- continue;
- Handle(ModuleBase_ResultPrs) aResultPrs = anObjectToPrs.at(anObject);
-
- if (!aResultPrs->hasSubShapeVisible(anIt->second)) {
- // erase object because it is entirely hidden
- anObject->setDisplayed(false);
- myHiddenObjects.insert(anObject);
- ModelAPI_EventCreator::get()->sendUpdated(anObject, aDispEvent);
- isModified = true;
- }
- }
- return isModified;
-}
-
//********************************************************************
void XGUI_FacesPanel::updateProcessedObjects(QMap<int, ModuleBase_ViewerPrsPtr> theItems,
std::set<ObjectPtr>& theObjects)
anIt != theItems.end(); anIt++) {
ModuleBase_ViewerPrsPtr aPrs = anIt.value();
ObjectPtr anObject = aPrs.get() ? aPrs->object() : ObjectPtr();
- if (anObject.get() && theObjects.find(anObject) != theObjects.end())
- continue;
- theObjects.insert(anObject);
+ if (anObject.get()) {
+ ResultGroupPtr aResGroup = std::dynamic_pointer_cast<ModelAPI_ResultGroup>(anObject);
+ if (aResGroup.get()) {
+ FeaturePtr aGroupFeature = ModelAPI_Feature::feature(aResGroup);
+ AttributeSelectionListPtr aSelectionList = aGroupFeature->selectionList("group_list");
+ for (int i = 0; i < aSelectionList->size(); i++) {
+ AttributeSelectionPtr aSelection = aSelectionList->value(i);
+ ResultPtr aRes = aSelection->context();
+ if (theObjects.find(aRes) == theObjects.end())
+ theObjects.insert(aRes);
+ }
+ }
+ else {
+ if (theObjects.find(anObject) == theObjects.end())
+ theObjects.insert(anObject);
+ }
+ }
}
}
//********************************************************************
bool XGUI_FacesPanel::customizeObject(const ObjectPtr& theObject,
- const AISObjectPtr& thePresentation)
+ const AISObjectPtr& thePresentation)
{
- if (myLastItemIndex == 0) // do nothing because there was no activity in the pane after reset
- return false;
-
- if (thePresentation.get() == NULL)
- return false;
-
- if (myItemObjects.find(theObject) == myItemObjects.end()) // not found
- return false;
-
- // if the object is displayed, the hidden faces are collected and set to the presentation
- bool isModified = false;
- NCollection_List<TopoDS_Shape> aHiddenSubShapes;
- for (QMap<int, ModuleBase_ViewerPrsPtr>::const_iterator anIt = myItems.begin();
- anIt != myItems.end(); anIt++) {
- ModuleBase_ViewerPrsPtr aPrs = anIt.value();
- if (aPrs.get() && aPrs->object() != theObject)
- continue;
- TopoDS_Shape aShape = ModuleBase_Tools::getSelectedShape(aPrs);
- if (!aHiddenSubShapes.Contains(aShape))
- aHiddenSubShapes.Append(aShape);
- }
-
- Handle(ModuleBase_ResultPrs) aResultPrs = Handle(ModuleBase_ResultPrs)::DownCast(
- thePresentation->impl<Handle(AIS_InteractiveObject)>());
- if (aResultPrs.IsNull())
- return false;
-
- isModified = aResultPrs->setSubShapeHidden(aHiddenSubShapes);
-
- double aTransparency = !useTransparency() ? 1
- : Config_PropManager::real("Visualization", "hidden_face_transparency");
- isModified = aResultPrs->setHiddenSubShapeTransparency(aTransparency) || isModified;
-
- return isModified;
+ return myItems.size() > 0;
}
//********************************************************************
//********************************************************************
void XGUI_FacesPanel::onTransparencyChanged()
{
- bool isModified = false;
- if (useTransparency()) {
- std::set<std::shared_ptr<ModelAPI_Object> > aHiddenObjects = myHiddenObjects;
- isModified = displayHiddenObjects(aHiddenObjects, myHiddenObjects);
+ std::map<ObjectPtr, TopoDS_ListOfShape> anObjectToShapes;
+ std::map<ObjectPtr, Handle(ModuleBase_ResultPrs) > anObjectToPrs;
+ QMap<int, std::shared_ptr<ModuleBase_ViewerPrs> >::const_iterator aIt;
+ for (aIt = myItems.cbegin(); aIt != myItems.cend(); aIt++) {
+ getObjectsMapFromPrs(aIt.value(), anObjectToShapes, anObjectToPrs);
}
- else
- isModified = hideEmptyObjects();
- isModified = redisplayObjects(myItemObjects) || isModified;
- if (isModified)
+ double aTransp = Config_PropManager::real("Visualization", "hidden_face_transparency");
+ std::set<ObjectPtr> aObjects;
+ std::map<ObjectPtr, Handle(ModuleBase_ResultPrs)>::const_iterator aPrsIt;
+ for (aPrsIt = anObjectToPrs.cbegin(); aPrsIt != anObjectToPrs.cend(); aPrsIt++) {
+ aObjects.insert(aPrsIt->first);
+ aPrsIt->second->setHiddenSubShapeTransparency(useTransparency()? aTransp : 1);
+ }
+ if (redisplayObjects(aObjects))
flushRedisplay();
}
{
Events_Loop::loop()->flush(Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY));
// Necessary for update visibility icons in ObjectBrowser
- XGUI_ObjectsBrowser* anObjectBrowser = XGUI_Tools::workshop(myWorkshop)->objectBrowser();
+ XGUI_ObjectsBrowser* anObjectBrowser = myWorkshop->objectBrowser();
if (anObjectBrowser)
anObjectBrowser->updateAllIndexes();
+ myWorkshop->viewer()->update();
}
#include <ModuleBase_ActionType.h>
#include <ModuleBase_Definitions.h>
#include <ModuleBase_ViewerPrs.h>
+#include <ModuleBase_ResultPrs.h>
#include <SelectMgr_ListOfFilter.hxx>
+#include <TopoDS_Shape.hxx>
#include <QDockWidget>
#include <QObject>
class GeomAPI_AISObject;
-class ModuleBase_IWorkshop;
+class XGUI_Workshop;
class ModuleBase_ListView;
class QAction;
public:
/// Constructor
/// \param theParent is a parent of the property panel
- XGUI_FacesPanel(QWidget* theParent, ModuleBase_IWorkshop* theWorkshop);
+ XGUI_FacesPanel(QWidget* theParent, XGUI_Workshop* theWorkshop);
~XGUI_FacesPanel() {}
/// Clear content of list widget
/// \param theIsActive state whether the panel should be activated or deactivated
void setActivePanel(const bool theIsActive);
- /// Returns true if transparency choice is checked
- /// \return boolean value
- bool useTransparency() const;
-
/// Returns true if the object is in internal container of hidden objects by this panel
/// \param theObject a checked object
/// \return boolean value
bool customizeObject(const std::shared_ptr<ModelAPI_Object>& theObject,
const std::shared_ptr<GeomAPI_AISObject>& thePresentation);
+
+ XGUI_Workshop* workshop() const { return myWorkshop; }
+
+
protected:
/// Reimplementation to emit a signal about the panel close
virtual void closeEvent(QCloseEvent* theEvent);
/// \return true if some of objects was redisplayed
static bool redisplayObjects(const std::set<std::shared_ptr<ModelAPI_Object> >& theObjects);
- /// Display objects if the objects are in a container of hidden by this pane.
- /// \param theObjects container of objects
- /// \param theHiddenObjects hidden objects, if object is in the container, it should be removed
- /// \return true if some of objects was redisplayed
- static bool displayHiddenObjects(const std::set<std::shared_ptr<ModelAPI_Object> >& theObjects,
- std::set<std::shared_ptr<ModelAPI_Object> >& theHiddenObjects);
-
- /// Iterates by items and hide objects where all sub-shapes are hidden
- /// \return true if some of objects was redisplayed
- bool hideEmptyObjects();
-
/// Container of objects participating in the panel, it is filled by internal container
/// \param theItems container of selected values
/// \param theObjects [out] container of objects
static void updateProcessedObjects(QMap<int, std::shared_ptr<ModuleBase_ViewerPrs> > theItems,
std::set<std::shared_ptr<ModelAPI_Object> >& theObjects);
+ /// Returns maps of shapes and presentations. If object is a body result then it returns
+ /// its ruslts. If it is a group then it returns result of shapes included into the gropup
+ /// The function doesn't clear content of input maps.
+ /// \param thePrs a selected presintation
+ /// \param theObjectsToShapes map of objects to shapes list
+ /// \param theObjectToPrs map of objects to presentations
+ void getObjectsMapFromPrs(ModuleBase_ViewerPrsPtr thePrs,
+ std::map<ObjectPtr, TopoDS_ListOfShape>& theObjectsToShapes,
+ std::map<ObjectPtr, Handle(ModuleBase_ResultPrs) >& theObjectToPrs);
+
+ /// Returns true if transparency choice is checked
+ /// \return boolean value
+ bool useTransparency() const;
+
+ double transparency() const;
+
protected slots:
/// Deletes element in list of items
void onDeleteItem();
protected:
QCheckBox* myHiddenOrTransparent; ///< if checked - transparent, else hidden
ModuleBase_ListView* myListView; ///< list control of processed faces
- ModuleBase_IWorkshop* myWorkshop; ///< workshop
+ XGUI_Workshop* myWorkshop; ///< workshop
bool myIsActive; ///< current state about the panel is active
int myLastItemIndex; ///< last index to be used in the map of items for the next added item
- QMap<int, std::shared_ptr<ModuleBase_ViewerPrs> > myItems; ///< selected face items
+ QMap<int, ModuleBase_ViewerPrsPtr> myItems; ///< selected face items
std::set<std::shared_ptr<ModelAPI_Object> > myItemObjects; ///< cached objects of myItems
std::set<std::shared_ptr<ModelAPI_Object> > myHiddenObjects; ///< hidden objects
+ std::set<std::shared_ptr<ModelAPI_Object> > myHiddenGroups; ///< hidden objects
};
#endif
\ No newline at end of file
//
#include "XGUI_InspectionPanel.h"
+#include "XGUI_Workshop.h"
#include "XGUI_SelectionMgr.h"
#include "XGUI_Selection.h"
#include "XGUI_Tools.h"
+#include "XGUI_ModuleConnector.h"
#include <ModuleBase_ViewerPrs.h>
#include <ModuleBase_Tools.h>
+#include <ModuleBase_OperationDescription.h>
+#include <ModuleBase_WidgetFactory.h>
+#include <ModuleBase_IModule.h>
+#include <ModuleBase_PageWidget.h>
+
#include <ModelAPI_ResultField.h>
#include <ModelAPI_Result.h>
#include <QTextBrowser>
#include <QResizeEvent>
#include <QSplitter>
+#include <QStackedWidget>
#include <BRepBndLib.hxx>
#include <TopoDS_Iterator.hxx>
#include <TopTools_ListOfShape.hxx>
#include <Standard_ErrorHandler.hxx> // CAREFUL ! position of this file is critic
+
// ================ Auxiliary functions ================
#define TITLE(val) ("<b>" + (val) + "</b>")
// ================ XGUI_InspectionPanel ================
-XGUI_InspectionPanel::XGUI_InspectionPanel(QWidget* theParent, XGUI_SelectionMgr* theMgr)
+XGUI_InspectionPanel::XGUI_InspectionPanel(QWidget* theParent, XGUI_Workshop* theWorkshop)
: QDockWidget(theParent),
- mySelectionMgr(theMgr)
+ myWorkshop(theWorkshop)
{
setWindowTitle(tr("Inspection Panel"));
setObjectName(INSPECTION_PANEL);
setStyleSheet("::title { position: relative; padding-left: 5px; text-align: left center }");
- QSplitter* aSplitter = new QSplitter(Qt::Vertical, this);
+ myStackWgt = new QStackedWidget(this);
+
+ // Create shape selection page
+ QSplitter* aSplitter = new QSplitter(Qt::Vertical, myStackWgt);
// Create an internal widget
QWidget* aNameWgt = new QWidget(aSplitter);
aSizes << 10 << 140 << 10;
aSplitter->setSizes(aSizes);
- setWidget(aSplitter);
+ myShapePanelId = myStackWgt->addWidget(aSplitter);
+
+ // Create feature selection page
+ QScrollArea* aScroll = new QScrollArea(myStackWgt);
+ aScroll->setWidgetResizable(true);
+ aScroll->setFrameStyle(QFrame::NoFrame);
+
+ myFeaturePane = new ModuleBase_PageWidget(aScroll);
+ myFeatureLayout = new QGridLayout(myFeaturePane);
+ myFeatureLayout->setContentsMargins(3, 3, 3, 3);
+ aScroll->setWidget(myFeaturePane);
+ //myFeaturePane->setEnabled(false);
- connect(mySelectionMgr, SIGNAL(selectionChanged()), SLOT(onSelectionChanged()));
+ myFeaturePanelId = myStackWgt->addWidget(aScroll);
+
+ setWidget(myStackWgt);
+ connect(myWorkshop->selector(), SIGNAL(selectionChanged()), SLOT(onSelectionChanged()));
}
//********************************************************************
}
myTypeLbl->setText("");
setParamsText("");
+
+ myFeaturePane->clearPage();
}
//********************************************************************
void XGUI_InspectionPanel::onSelectionChanged()
{
+ if (!isVisible())
+ return;
+
clearContent();
- XGUI_Selection* aSelection = mySelectionMgr->selection();
- QList<ModuleBase_ViewerPrsPtr> aSelectedList =
- aSelection->getSelected(ModuleBase_ISelection::Viewer);
- QList<ModuleBase_ViewerPrsPtr> anOBSelected =
- aSelection->getSelected(ModuleBase_ISelection::Browser);
- if (!anOBSelected.isEmpty())
- ModuleBase_ISelection::appendSelected(anOBSelected, aSelectedList);
+ XGUI_Selection* aSelection = myWorkshop->selector()->selection();
+ QList<ModuleBase_ViewerPrsPtr> aSelectedList =
+ aSelection->getSelected(myWorkshop->selector()->placeOfSelection());
if (aSelectedList.count() > 0) {
ModuleBase_ViewerPrsPtr aPrs = aSelectedList.first();
std::dynamic_pointer_cast<ModelAPI_ResultField::ModelAPI_FieldStep>(aPrs->object());
if (aStep)
return;
- TopoDS_Shape aShape = ModuleBase_Tools::getSelectedShape(aPrs);
- if (aShape.IsNull()) {
- ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(aPrs->object());
- if (aRes.get()) {
- GeomShapePtr aShpPtr = aRes->shape();
- if (aShpPtr.get()) {
- aShape = aShpPtr->impl<TopoDS_Shape>();
+ FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aPrs->object());
+ if (aFeature.get()) {
+ myStackWgt->setCurrentIndex(myFeaturePanelId);
+ buildFeaturePane(aFeature);
+ }
+ else {
+ myStackWgt->setCurrentIndex(myShapePanelId);
+ TopoDS_Shape aShape = ModuleBase_Tools::getSelectedShape(aPrs);
+ if (aShape.IsNull()) {
+ ResultPtr aRes = std::dynamic_pointer_cast<ModelAPI_Result>(aPrs->object());
+ if (aRes.get()) {
+ GeomShapePtr aShpPtr = aRes->shape();
+ if (aShpPtr.get()) {
+ aShape = aShpPtr->impl<TopoDS_Shape>();
+ }
}
}
+ if (aShape.IsNull())
+ return;
+ GeomShapePtr aShapePtr(new GeomAPI_Shape());
+ aShapePtr->setImpl(new TopoDS_Shape(aShape));
+
+ ModuleBase_ViewerPrsPtr aPrsCopy(new ModuleBase_ViewerPrs(aPrs->object(), aShapePtr));
+ setName(XGUI_Tools::generateName(aPrsCopy));
+ setShapeContent(aShape);
+ setShapeParams(aShape);
}
- if (aShape.IsNull())
- return;
- GeomShapePtr aShapePtr(new GeomAPI_Shape());
- aShapePtr->setImpl(new TopoDS_Shape(aShape));
-
- ModuleBase_ViewerPrsPtr aPrsCopy(new ModuleBase_ViewerPrs(aPrs->object(), aShapePtr));
- setName(XGUI_Tools::generateName(aPrsCopy));
- setShapeContent(aShape);
- setShapeParams(aShape);
}
}
appendPointToParameters(tr("Maximal corner"), aMaxPoint, aParams);
}
+//********************************************************************
void XGUI_InspectionPanel::setPlaneType(const QString& theTitle,
const std::shared_ptr<GeomAPI_Pln>& thePlane)
{
setParamsText(aParams);
}
+//********************************************************************
void XGUI_InspectionPanel::setSphereType(const QString& theTitle,
const std::shared_ptr<GeomAPI_Sphere>& theSphere)
{
setParamsText(aParams);
}
+//********************************************************************
void XGUI_InspectionPanel::setCylinderType(const QString& theTitle,
const std::shared_ptr<GeomAPI_Cylinder>& theCyl)
{
setParamsText(aParams);
}
+//********************************************************************
void XGUI_InspectionPanel::setConeType(const QString& theTitle,
const std::shared_ptr<GeomAPI_Cone>& theCone)
{
setParamsText(aParams);
}
+//********************************************************************
void XGUI_InspectionPanel::setTorusType(const QString& theTitle,
const std::shared_ptr<GeomAPI_Torus>& theTorus)
{
setParamsText(aParams);
}
+//********************************************************************
void XGUI_InspectionPanel::setBoxType(const QString& theTitle,
const std::shared_ptr<GeomAPI_Box>& theBox)
{
setParamsText(aParams);
}
+//********************************************************************
void XGUI_InspectionPanel::setRotatedBoxType(const QString& theTitle,
const std::shared_ptr<GeomAPI_Box>& theBox)
{
}
+//********************************************************************
void XGUI_InspectionPanel::setParamsText(const QString& theText)
{
myTypeParams->setText(theText);
}
+
+//********************************************************************
+void XGUI_InspectionPanel::buildFeaturePane(const FeaturePtr& theFeature)
+{
+ std::string aXmlCfg, aDescription;
+ myWorkshop->module()->getXMLRepresentation(theFeature->getKind(), aXmlCfg, aDescription);
+ if (!aXmlCfg.empty()) {
+ QList<ModuleBase_ModelWidget*> aWidgets;
+ if (!myWorkshop->module()->createWidgets(theFeature, aXmlCfg.c_str(), aWidgets)) {
+ ModuleBase_WidgetFactory aFactory(aXmlCfg, myWorkshop->moduleConnector());
+ aFactory.createWidget(myFeaturePane);
+ aWidgets = aFactory.getModelWidgets();
+ }
+ foreach(ModuleBase_ModelWidget* aWgt, aWidgets) {
+ if (aWgt->isInformative()) {
+ aWgt->setEnabled(false);
+ aWgt->setFeature(theFeature, false, false);
+ aWgt->setEditingMode(true);
+ aWgt->restoreValue();
+ aWgt->showInformativePage();
+ }
+ else {
+ aWgt->setFeature(theFeature, false, false);
+ aWgt->setEditingMode(true);
+ aWgt->hide();
+ }
+ }
+ }
+}
+
+void XGUI_InspectionPanel::showEvent(QShowEvent* theEvent)
+{
+ QDockWidget::showEvent(theEvent);
+ onSelectionChanged();
+}
#include "XGUI.h"
+#include <ModelAPI_Feature.h>
+
#include <QDockWidget>
#include <memory>
-class XGUI_SelectionMgr;
+class XGUI_Workshop;
class QLineEdit;
class QTableWidget;
class QLabel;
class QTextBrowser;
class QVBoxLayout;
class QResizeEvent;
+class QStackedWidget;
+class QGridLayout;
class TopoDS_Shape;
class GeomAPI_Cone;
class GeomAPI_Torus;
class GeomAPI_Box;
+class ModuleBase_PageWidget;
/// Internal name of property panel widget
const static char* INSPECTION_PANEL = "inspection_panel_dock";
/// Constructor
/// \param theParent is a parent of the property panel
/// \param theMgr operation manager
- XGUI_InspectionPanel(QWidget* theParent, XGUI_SelectionMgr* theMgr);
+ XGUI_InspectionPanel(QWidget* theParent, XGUI_Workshop* theWorkshop);
// Destructor
virtual ~XGUI_InspectionPanel();
+protected:
+ virtual void showEvent(QShowEvent* theEvent);
private slots:
/// A slot to react on selection changed
/// \param theBox the box
void setRotatedBoxType(const QString& theTitle, const std::shared_ptr<GeomAPI_Box>& theBox);
-
/// Set text into parameters area
/// \param theText the text
void setParamsText(const QString& theText);
+ /// Fills Feature panel with controls specific to the given feature
+ /// \param theFeature the selected feature
+ void buildFeaturePane(const FeaturePtr& theFeature);
+
private:
- XGUI_SelectionMgr* mySelectionMgr; //> selection manager
-
- QLineEdit* myNameEdt; //> Name field
- QTableWidget* mySubShapesTab; //> table of sub-shapes
- QLabel* myTypeLbl; //> label of a type
- QTextBrowser* myTypeParams; //> parameters area
- QVBoxLayout* myMainLayout; //> main layout
- //QWidget* myMainWidget; //> main widget
+ XGUI_Workshop* myWorkshop; //> selection manager
+
+ QLineEdit* myNameEdt; ///> Name field
+ QTableWidget* mySubShapesTab; ///> table of sub-shapes
+ QLabel* myTypeLbl; ///> label of a type
+ QTextBrowser* myTypeParams; ///> parameters area
+ QVBoxLayout* myMainLayout; ///> main layout
+ ModuleBase_PageWidget* myFeaturePane; ///> Content of feature property panel
+ QGridLayout* myFeatureLayout; ///> Layout of feature panel
+ QStackedWidget* myStackWgt; ///> base widget of the panel
+ int myShapePanelId;
+ int myFeaturePanelId;
};
#endif
\ No newline at end of file
{
Handle(AIS_InteractiveObject) anIO = theAIS->impl<Handle(AIS_InteractiveObject)>();
myWorkshop->selectionActivate()->activate(anIO, false);
-}
\ No newline at end of file
+}
+
+
+void XGUI_ModuleConnector::undo()
+{
+ myWorkshop->onUndo();
+}
+
+void XGUI_ModuleConnector::setCancelEnabled(bool toEnable)
+{
+ XGUI_ActionsMgr* anActionsMgr = workshop()->actionsMgr();
+ QAction* aAbortAction = anActionsMgr->operationStateAction(XGUI_ActionsMgr::AbortAll);
+ QAction* aAbortAllAction = anActionsMgr->operationStateAction(XGUI_ActionsMgr::Abort);
+ if (aAbortAction) {
+ aAbortAction->setEnabled(toEnable);
+ }
+ if (aAbortAllAction) {
+ aAbortAllAction->setEnabled(toEnable);
+ }
+}
+
+bool XGUI_ModuleConnector::isCancelEnabled() const
+{
+ XGUI_ActionsMgr* anActionsMgr = workshop()->actionsMgr();
+ QAction* aAbortAction = anActionsMgr->operationStateAction(XGUI_ActionsMgr::AbortAll);
+ QAction* aAbortAllAction = anActionsMgr->operationStateAction(XGUI_ActionsMgr::Abort);
+ bool isEnabled = false;
+ if (aAbortAction) {
+ isEnabled = true;
+ }
+ if (aAbortAllAction) {
+ isEnabled &= true;
+ }
+ return isEnabled;
+}
//! \param theAIS the object which has to be activated
virtual void applyCurrentSelectionModes(const AISObjectPtr& theAIS);
+ //! Undo last command
+ virtual void undo();
+
+ //! Set enabled state of cancel button in property panel
+ virtual void setCancelEnabled(bool toEnable);
+
+ //! Returns current state of cancel button
+ virtual bool isCancelEnabled() const;
+
private:
QObjectPtrList activeObjects(const QObjectPtrList& theObjList) const;
}
}
if (aResultOp) {
- bool isModified = aCurrentOperation->isModified();
- aResultOp->setIsModified(aResultOp->isModified() || isModified);
+ //bool isModified = aCurrentOperation->isModified();
+ //aResultOp->setIsModified(aResultOp->isModified() || isModified);
resumeOperation(aResultOp);
onValidateOperation();
}
//**************************************************************
void XGUI_SelectionMgr::onObjectBrowserSelection()
{
+ myLastSelectionPlace = ModuleBase_ISelection::Browser;
QList<ModuleBase_ViewerPrsPtr> aSelectedPrs =
myWorkshop->selector()->selection()->getSelected(ModuleBase_ISelection::Browser);
XGUI_Displayer* aDisplayer = myWorkshop->displayer();
//**************************************************************
void XGUI_SelectionMgr::onViewerSelection()
{
+ myLastSelectionPlace = ModuleBase_ISelection::Viewer;
QList<ModuleBase_ViewerPrsPtr> aValues;
Handle(AIS_InteractiveContext) aContext = myWorkshop->viewer()->AISContext();
if (!aContext.IsNull())
return mySelection;
}
+ ModuleBase_ISelection::SelectionPlace placeOfSelection() const {
+ return myLastSelectionPlace;
+ }
+
//! Connects the manager to all viewers accessible by Workshop
void connectViewers();
/// Current selection object
XGUI_Selection* mySelection;
+
+ ModuleBase_ISelection::SelectionPlace myLastSelectionPlace;
};
#endif
if (aContext.get()) {
GeomShapePtr aSubShape(new GeomAPI_Shape());
TopoDS_Shape aShape = ModuleBase_Tools::getSelectedShape(thePrs);
- aSubShape->setImpl(new TopoDS_Shape(aShape));
- if (!aSubShape->isEqual(aContext)) {
- QString aTypeName;
- switch (aShape.ShapeType()) {
- case TopAbs_COMPOUND:
- aTypeName = "compound";
- break;
- case TopAbs_COMPSOLID:
- aTypeName = "compsolid";
- break;
- case TopAbs_SOLID:
- aTypeName = "solid";
- break;
- case TopAbs_SHELL:
- aTypeName = "shell";
- break;
- case TopAbs_FACE:
- aTypeName = "face";
- break;
- case TopAbs_WIRE:
- aTypeName = "wire";
- break;
- case TopAbs_EDGE:
- aTypeName = "edge";
- break;
- case TopAbs_VERTEX:
- aTypeName = "vertex";
- break;
- case TopAbs_SHAPE:
- aTypeName = "shape";
- break;
+ if (!aShape.IsNull()) {
+ aSubShape->setImpl(new TopoDS_Shape(aShape));
+ if (!aSubShape->isEqual(aContext)) {
+ QString aTypeName;
+ switch (aShape.ShapeType()) {
+ case TopAbs_COMPOUND:
+ aTypeName = "compound";
+ break;
+ case TopAbs_COMPSOLID:
+ aTypeName = "compsolid";
+ break;
+ case TopAbs_SOLID:
+ aTypeName = "solid";
+ break;
+ case TopAbs_SHELL:
+ aTypeName = "shell";
+ break;
+ case TopAbs_FACE:
+ aTypeName = "face";
+ break;
+ case TopAbs_WIRE:
+ aTypeName = "wire";
+ break;
+ case TopAbs_EDGE:
+ aTypeName = "edge";
+ break;
+ case TopAbs_VERTEX:
+ aTypeName = "vertex";
+ break;
+ case TopAbs_SHAPE:
+ aTypeName = "shape";
+ break;
+ }
+ int aId = GeomAlgoAPI_CompoundBuilder::id(aContext, aSubShape);
+ aName += QString("/%1_%2").arg(aTypeName).arg(aId);
}
- int aId = GeomAlgoAPI_CompoundBuilder::id(aContext, aSubShape);
- aName += QString("/%1_%2").arg(aTypeName).arg(aId);
}
}
return aName;
#include <ModelAPI_AttributeDocRef.h>
#include <ModelAPI_AttributeIntArray.h>
#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeString.h>
#include <ModelAPI_Data.h>
#include <ModelAPI_Events.h>
#include <ModelAPI_Feature.h>
#include <Events_InfoMessage.h>
#include <Events_LongOp.h>
+#include <ExchangePlugin_ExportPart.h>
+#include <ExchangePlugin_ImportPart.h>
+
#include <GeomAPI_Pnt.h>
#include <ModuleBase_IModule.h>
#include <ModuleBase_Tools.h>
#include <ModuleBase_WidgetFactory.h>
#include <ModuleBase_OperationFeature.h>
-#include <ModuleBase_OperationAction.h>
#include <ModuleBase_PagedContainer.h>
#include <ModuleBase_WidgetValidated.h>
#include <ModuleBase_ModelWidget.h>
static QString MyExtension(".cadbld");
#endif
+static QString MyImportPartFilter(QObject::tr("Part files (*.shaperpart);;All files (*.*)"));
+
//******************************************************
XGUI_Workshop::XGUI_Workshop(XGUI_SalomeConnector* theConnector)
connect(myEventsListener, SIGNAL(errorOccurred(std::shared_ptr<Events_InfoMessage>)),
myErrorDlg, SLOT(addError(std::shared_ptr<Events_InfoMessage>)));
+ Config_PropManager::registerProp("Visualization", "selection_color", "Selection color",
+ Config_Prop::Color, "255,255,255");
+
if (ModuleBase_Preferences::resourceMgr()->booleanValue("Viewer", "face-selection", true))
myViewerSelMode.append(TopAbs_FACE);
if (ModuleBase_Preferences::resourceMgr()->booleanValue("Viewer", "edge-selection", true))
// Calling of loadCustomProps before activating module is required
// by Config_PropManger to restore user-defined path to plugins
ModuleBase_Preferences::loadCustomProps();
+ std::vector<int> aColor;
+ try {
+ aColor = Config_PropManager::color("Visualization", "selection_color");
+ }
+ catch (...) {
+ }
+ if (aColor.size() == 3)
+ myDisplayer->setSelectionColor(aColor);
+
createModule();
#ifndef HAVE_SALOME
connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onOpen()));
salomeConnector()->addDesktopMenuSeparator("MEN_DESK_FILE");
+ aAction = salomeConnector()->addDesktopCommand("EXPORT_PART_CMD", tr("Export part..."),
+ tr("Export a part of the current document into a file"),
+ QIcon(), QKeySequence(),
+ false, "MEN_DESK_FILE");
+ connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onExportPart()));
+
+ aAction = salomeConnector()->addDesktopCommand("IMPORT_PART_CMD", tr("Import part..."),
+ tr("Import structure of a part"),
+ QIcon(), QKeySequence(),
+ false, "MEN_DESK_FILE");
+ connect(aAction, SIGNAL(triggered(bool)), this, SLOT(onImportPart()));
+ salomeConnector()->addDesktopMenuSeparator("MEN_DESK_FILE");
+
#else
// File commands group
AppElements_MenuGroupPanel* aGroup = myMainWindow->menuObject()->generalPage();
if (!aFOperation)
return;
- showPanel(myPropertyPanel);
myPropertyPanel->cleanContent();
QList<ModuleBase_ModelWidget*> aWidgets;
- if (!module()->createWidgets(theOperation, aWidgets)) {
- QString aXmlRepr = aFOperation->getDescription()->xmlRepresentation();
+ QString aXmlRepr = aFOperation->getDescription()->xmlRepresentation();
+ if (!module()->createWidgets(aFOperation->feature(), aXmlRepr, aWidgets)) {
ModuleBase_WidgetFactory aFactory(aXmlRepr.toStdString(), myModuleConnector);
aFactory.createWidget(myPropertyPanel->contentWidget());
aWidgets = aFactory.getModelWidgets();
#endif
myErrorMgr->setPropertyPanel(myPropertyPanel);
+ theOperation->setHideFacesVisible(myFacesPanel->isVisible());
+ if (aFeatureInfo->isHideFacesPanel() && !myFacesPanel->isVisible())
+ myFacesPanel->show();
+ showPanel(myPropertyPanel);
}
//******************************************************
}
}
activateObjectsSelection(anObjects);
+
+ if (!theOperation->isHideFacesVisible())
+ myFacesPanel->hide();
}
//******************************************************
ModuleBase_Preferences::editPreferences(aModif);
if (aModif.size() > 0) {
QString aSection;
- foreach (ModuleBase_Pref aPref, aModif)
- {
+ foreach (ModuleBase_Pref aPref, aModif) {
aSection = aPref.first;
if (aSection == ModuleBase_Preferences::VIEWER_SECTION) {
myMainWindow->viewer()->updateFromResources();
myMainWindow->menuObject()->updateFromResources();
}
}
+ std::vector<int> aColor;
+ try {
+ aColor = Config_PropManager::color("Visualization", "selection_color");
+ }
+ catch (...) {
+ }
+ if (aColor.size() == 3)
+ displayer()->setSelectionColor(aColor);
+
displayer()->redisplayObjects();
}
}
myDisplayer->updateViewer();
}
+//******************************************************
+void XGUI_Workshop::onImportPart()
+{
+ if (!abortAllOperations())
+ return;
+
+ //show file dialog, check if readable and open
+ qreal aRatio = ModuleBase_Tools::currentPixelRatio();
+ // If the ratio is > 1 (HD screen) then QT has a bug in
+ // displaying of system open file dialog (too small)
+ QString aFile = QFileDialog::getOpenFileName(desktop(), tr("Import part"), QString(),
+ MyImportPartFilter, Q_NULLPTR,
+ ((aRatio > 1) ? QFileDialog::DontUseNativeDialog : QFileDialog::Options()));
+ if (!aFile.isNull()) {
+ ModuleBase_OperationFeature* anImportPartOp = dynamic_cast<ModuleBase_OperationFeature*>(
+ module()->createOperation(ExchangePlugin_ImportPart::ID()));
+ if (operationMgr()->startOperation(anImportPartOp)) {
+ // initialize the filename to be imported
+ FeaturePtr aFeature = anImportPartOp->feature();
+ aFeature->string(ExchangePlugin_ImportPart::FILE_PATH_ID())->setValue(aFile.toStdString());
+ ModuleBase_Tools::flushUpdated(aFeature);
+ operationMgr()->commitOperation();
+ }
+ }
+}
+
+//******************************************************
+void XGUI_Workshop::onExportPart()
+{
+ if (abortAllOperations()) {
+ ModuleBase_OperationFeature* anExportPartOp = dynamic_cast<ModuleBase_OperationFeature*>(
+ module()->createOperation(ExchangePlugin_ExportPart::ID()));
+ operationMgr()->startOperation(anExportPartOp);
+ }
+}
+
//******************************************************
ModuleBase_IModule* XGUI_Workshop::loadModule(const QString& theModule)
{
hidePanel(myPropertyPanel); ///<! Invisible by default
- myFacesPanel = new XGUI_FacesPanel(aDesktop, myModuleConnector);
+ myFacesPanel = new XGUI_FacesPanel(aDesktop, this);
myActiveControlMgr->addSelector(new XGUI_FacesPanelSelector(myFacesPanel));
myFacesPanel->setAllowedAreas(Qt::LeftDockWidgetArea |
Qt::RightDockWidgetArea |
Qt::BottomDockWidgetArea);
connect(myFacesPanel, SIGNAL(closed()), myFacesPanel, SLOT(onClosed()));
- myInspectionPanel = new XGUI_InspectionPanel(aDesktop, mySelector);
+ myInspectionPanel = new XGUI_InspectionPanel(aDesktop, this);
myInspectionPanel->setAllowedAreas(Qt::LeftDockWidgetArea |
Qt::RightDockWidgetArea);
aDesktop->addDockWidget(Qt::RightDockWidgetArea, myInspectionPanel);
bool aDone = false;
QString aDescription = contextMenuMgr()->action("DELETE_CMD")->text() + " %1";
aDescription = aDescription.arg(XGUI_Tools::unionOfObjectNames(anObjects, ", "));
- ModuleBase_OperationAction* anOpAction = new ModuleBase_OperationAction(aDescription, module());
+ ModuleBase_Operation* anOpAction = new ModuleBase_Operation(aDescription, module());
operationMgr()->startOperation(anOpAction);
// 1. start operation
aDescription += "by deleting of " +
aDescription.arg(XGUI_Tools::unionOfObjectNames(anObjects, ", "));
- ModuleBase_OperationAction* anOpAction = new ModuleBase_OperationAction(aDescription, module());
+ ModuleBase_Operation* anOpAction = new ModuleBase_Operation(aDescription, module());
operationMgr()->startOperation(anOpAction);
// WORKAROUND, should be done before each object remove, if it presents in XGUI_DataModel tree
/// Create a new document
void onNew();
+ /// Import part structure from a file
+ void onImportPart();
+
+ /// Export features to a file
+ void onExportPart();
+
#ifndef HAVE_SALOME
/// Exit application
void onExit();
export DISPLAY="localhost:0.0"
+# check for __init__.py in the SHAPER's Python scripts directory
+# for correct parsing PYTHONPATH and use the actual version of SHAPER
+# instead of distributed with SALOME
+if [[ ! -f ${SHAPER_PYTHON_SCRIPTS_DIR}/salome/__init__.py ]]; then
+ touch ${SHAPER_PYTHON_SCRIPTS_DIR}/salome/__init__.py
+fi
+
if [[ $# > 0 ]]; then
ctest --no-compress-output -T Test "$@" -R $1
else