-// Copyright (C) 2016-20xx CEA/DEN, EDF R&D -->
+// Copyright (C) 2014-2017 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<mailto:webmaster.salome@opencascade.com>
+//
-// File: ModelHighAPI_Dumper.cpp
-// Created: 1 August 2016
-// Author: Artem ZHIDKOV
-
-//--------------------------------------------------------------------------------------
#include "ModelHighAPI_Dumper.h"
+#include <Config_PropManager.h>
+
#include <GeomAPI_Pnt.h>
#include <GeomAPI_Dir.h>
+#include <GeomAPI_ShapeExplorer.h>
+#include <GeomAlgoAPI_NExplode.h>
#include <GeomDataAPI_Dir.h>
#include <GeomDataAPI_Point.h>
#include <ModelAPI_AttributeSelection.h>
#include <ModelAPI_AttributeSelectionList.h>
#include <ModelAPI_AttributeString.h>
+#include <ModelAPI_AttributeStringArray.h>
#include <ModelAPI_CompositeFeature.h>
#include <ModelAPI_Document.h>
#include <ModelAPI_Entity.h>
#include <ModelAPI_Feature.h>
+#include <ModelAPI_Folder.h>
#include <ModelAPI_Result.h>
+#include <ModelAPI_ResultBody.h>
+#include <ModelAPI_ResultConstruction.h>
#include <ModelAPI_ResultPart.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Tools.h>
+
+#include <ModelGeomAlgo_Shape.h>
#include <PartSetPlugin_Part.h>
ModelHighAPI_Dumper* ModelHighAPI_Dumper::mySelf = 0;
ModelHighAPI_Dumper::ModelHighAPI_Dumper()
+ : myGeometricalSelection(false)
{
clear();
}
myFeatureCount.clear();
while (!myEntitiesStack.empty())
myEntitiesStack.pop();
+
+ myPostponed.clear();
+ myDumpPostponedInProgress = false;
}
}
myNotDumpedEntities.clear();
}
+// Convert string to integer. If the string is not a number, return -1
+static int toInt(const std::string& theString)
+{
+ std::string::const_iterator aChar = theString.begin();
+ for (; aChar != theString.end(); ++aChar)
+ if (!std::isdigit(*aChar))
+ break;
+ if (aChar != theString.end())
+ return -1; // not a number
+ return std::stoi(theString);
+}
+
const std::string& ModelHighAPI_Dumper::name(const EntityPtr& theEntity,
bool theSaveNotDumped,
bool theUseEntityName)
{
EntityNameMap::const_iterator aFound = myNames.find(theEntity);
if (aFound != myNames.end())
- return aFound->second.first;
+ return aFound->second.myCurrentName;
// entity is not found, store it
- std::string aName;
+ std::string aName, aKind;
+ bool isDefaultName = false;
+ bool isSaveNotDumped = theSaveNotDumped;
std::ostringstream aDefaultName;
FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theEntity);
if (aFeature) {
aName = aFeature->name();
- const std::string& aKind = aFeature->getKind();
- DocumentPtr aDoc = aFeature->document();
- int& aNbFeatures = myFeatureCount[aDoc][aKind];
- aNbFeatures += 1;
+ aKind = aFeature->getKind();
+ } else {
+ FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(theEntity);
+ if (aFolder) {
+ aName = aFolder->data()->name();
+ aKind = ModelAPI_Folder::ID();
+ isSaveNotDumped = false;
+ }
+ }
+
+ ObjectPtr anObject = std::dynamic_pointer_cast<ModelAPI_Object>(theEntity);
+ if (anObject) {
+ DocumentPtr aDoc = anObject->document();
+ std::pair<int, int>& aNbFeatures = myFeatureCount[aDoc][aKind];
+ aNbFeatures.first += 1;
size_t anIndex = aName.find(aKind);
if (anIndex == 0 && aName[aKind.length()] == '_') { // name starts with "FeatureKind_"
std::string anIdStr = aName.substr(aKind.length() + 1);
- int anId = std::stoi(anIdStr);
+ int anId = toInt(anIdStr);
// Check number of already registered objects of such kind. Index of current object
// should be the same to identify feature's name as automatically generated.
- if (aNbFeatures == anId) {
+ if (aNbFeatures.first == anId && aNbFeatures.second < anId) {
// name is not user-defined
- aName.clear();
+ isDefaultName = true;
+
+ // check there are postponed features of this kind,
+ // dump their names, because the sequence of features may be changed
+ for (std::list<EntityPtr>::const_iterator aPpIt = myPostponed.begin();
+ aPpIt != myPostponed.end(); ++aPpIt) {
+ FeaturePtr aCurFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*aPpIt);
+ if (aCurFeature && aCurFeature->getKind() == aKind) {
+ myNames[*aPpIt].myIsDefault = false;
+ isDefaultName = false;
+ }
+ }
}
+
+ if (anId > aNbFeatures.second)
+ aNbFeatures.second = anId;
}
// obtain default name for the feature
int aFullIndex = 0;
NbFeaturesMap::const_iterator aFIt = myFeatureCount.begin();
for (; aFIt != myFeatureCount.end(); ++aFIt) {
- std::map<std::string, int>::const_iterator aFound = aFIt->second.find(aKind);
+ std::map<std::string, std::pair<int, int> >::const_iterator aFound =
+ aFIt->second.find(aKind);
if (aFound != aFIt->second.end())
- aFullIndex += aFound->second;
+ aFullIndex += aFound->second.first;
}
aDefaultName << aKind << "_" << aFullIndex;
}
}
- myNames[theEntity] = std::pair<std::string, std::string>(aDefaultName.str(), aName);
- if (theSaveNotDumped)
+ myNames[theEntity] = EntityName(aDefaultName.str(), aName, isDefaultName);
+ if (isSaveNotDumped)
myNotDumpedEntities.insert(theEntity);
// store names of results
if (aFeature)
saveResultNames(aFeature);
- return myNames[theEntity].first;
+ return myNames[theEntity].myCurrentName;
}
const std::string& ModelHighAPI_Dumper::parentName(const FeaturePtr& theEntity)
void ModelHighAPI_Dumper::saveResultNames(const FeaturePtr& theFeature)
{
- const std::string& aFeatureName = myNames[theFeature].first;
- const std::list<ResultPtr>& aResults = theFeature->results();
- std::list<ResultPtr>::const_iterator aResIt = aResults.begin();
- for (int i = 1; aResIt != aResults.end(); ++aResIt, ++i) {
- bool isUserDefined = true;
- std::string aResName = (*aResIt)->data()->name();
- size_t anIndex = aResName.find(aFeatureName);
- if (anIndex == 0) {
- std::string aSuffix = aResName.substr(aFeatureName.length());
- if (aSuffix.empty() && i == 1) // first result may not constain index in the name
- isUserDefined = false;
- else {
- if (aSuffix[0] == '_' && std::stoi(aSuffix.substr(1)) == i)
- isUserDefined = false;
- }
- }
+ // Default name of the feature
+ bool isFeatureDefaultName = myNames[theFeature].myIsDefault;
- myNames[*aResIt] = std::pair<std::string, std::string>(aResName,
- isUserDefined ? aResName : std::string());
+ // Save only names of results which is not correspond to default feature name
+ const std::list<ResultPtr>& aResults = theFeature->results();
+ std::list<ResultPtr> allRes;
+ ModelAPI_Tools::allResults(theFeature, allRes);
+ for(std::list<ResultPtr>::iterator aRes = allRes.begin(); aRes != allRes.end(); aRes++) {
+ std::pair<std::string, bool> aName = ModelAPI_Tools::getDefaultName(*aRes);
+ std::string aDefaultName = aName.first;
+ std::string aResName = (*aRes)->data()->name();
+ bool isUserDefined = !(isFeatureDefaultName && aDefaultName == aResName);
+ myNames[*aRes] =
+ EntityName(aResName, (isUserDefined ? aResName : std::string()), !isUserDefined);
}
}
{
// dump top level document feature
static const std::string aDocName("partSet");
- myNames[theDoc] = std::pair<std::string, std::string>(aDocName, std::string());
+ myNames[theDoc] = EntityName(aDocName, std::string(), true);
*this << aDocName << " = model.moduleDocument()" << std::endl;
// dump subfeatures and store result to file
bool ModelHighAPI_Dumper::process(const std::shared_ptr<ModelAPI_Document>& theDoc)
{
bool isOk = true;
- std::list<FeaturePtr> aFeatures = theDoc->allFeatures();
- std::list<FeaturePtr>::const_iterator aFeatIt = aFeatures.begin();
+ std::list<ObjectPtr> anObjects = theDoc->allObjects();
+ std::list<ObjectPtr>::const_iterator anObjIt = anObjects.begin();
// firstly, dump all parameters
- for (; aFeatIt != aFeatures.end(); ++ aFeatIt)
- dumpParameter(*aFeatIt);
+ for (; anObjIt != anObjects.end(); ++ anObjIt) {
+ FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anObjIt);
+ if (aFeature)
+ dumpParameter(aFeature);
+ }
// dump all other features
- for (aFeatIt = aFeatures.begin(); aFeatIt != aFeatures.end(); ++aFeatIt) {
- CompositeFeaturePtr aCompFeat = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*aFeatIt);
+ for (anObjIt = anObjects.begin(); anObjIt != anObjects.end(); ++anObjIt) {
+ CompositeFeaturePtr aCompFeat = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*anObjIt);
if (aCompFeat) // iteratively process composite features
isOk = process(aCompFeat) && isOk;
- else if (!isDumped(*aFeatIt)) // dump common feature
- dumpFeature(*aFeatIt);
+ else if (!isDumped(EntityPtr(*anObjIt))) {
+ // dump folder
+ FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(*anObjIt);
+ if (aFolder)
+ dumpFolder(aFolder);
+ else {
+ FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anObjIt);
+ if (aFeature) // dump common feature
+ dumpFeature(aFeature);
+ }
+ }
}
+ // dump folders if any
+ dumpPostponed(true);
return isOk;
}
-bool ModelHighAPI_Dumper::process(const std::shared_ptr<ModelAPI_CompositeFeature>& theComposite, bool isForce)
+bool ModelHighAPI_Dumper::process(const std::shared_ptr<ModelAPI_CompositeFeature>& theComposite,
+ bool isForce)
{
// increase composite features stack
++gCompositeStackDepth;
// dump composite itself
- if (!isDumped(theComposite) || isForce)
- dumpFeature(theComposite, isForce);
+ if (!isDumped(EntityPtr(theComposite)) || isForce)
+ dumpFeature(FeaturePtr(theComposite), isForce);
// sub-part is processed independently, because it provides separate document
if (theComposite->getKind() == PartSetPlugin_Part::ID()) {
+ // dump name of the part if it is different from default
+ if (!myEntitiesStack.empty())
+ dumpEntitySetName();
+
// decrease composite features stack because we run into separate document
--gCompositeStackDepth;
if (!aSubDoc)
return false;
// set name of document
- const std::string& aPartName = myNames[theComposite].first;
+ const std::string& aPartName = myNames[theComposite].myCurrentName;
std::string aDocName = aPartName + "_doc";
- myNames[aSubDoc] = std::pair<std::string, std::string>(aDocName, std::string());
+ myNames[aSubDoc] = EntityName(aDocName, std::string(), true);
// dump document in a separate line
*this << aDocName << " = " << aPartName << ".document()" << std::endl;
// dump features in the document
- return process(aSubDoc);
+ bool aRes = process(aSubDoc);
+ *this << "model.do()" << std::endl;
+ return aRes;
}
// dump sub-features
return isOk;
}
-bool ModelHighAPI_Dumper::processSubs(const std::shared_ptr<ModelAPI_CompositeFeature>& theComposite,
- bool theDumpModelDo)
+bool ModelHighAPI_Dumper::processSubs(
+ const std::shared_ptr<ModelAPI_CompositeFeature>& theComposite,
+ bool theDumpModelDo)
{
bool isOk = true;
// dump all sub-features;
int aNbSubs = theComposite->numberOfSubs();
for (int anIndex = 0; anIndex < aNbSubs; ++anIndex) {
FeaturePtr aFeature = theComposite->subFeature(anIndex);
- if (isDumped(aFeature))
+ if (isDumped(EntityPtr(aFeature)))
continue;
isSubDumped = true;
return isOk;
}
+void ModelHighAPI_Dumper::postpone(const EntityPtr& theEntity)
+{
+ // keep the name
+ name(theEntity, false);
+ myPostponed.push_back(theEntity);
+}
+
+void ModelHighAPI_Dumper::dumpPostponed(bool theDumpFolders)
+{
+ if (myDumpPostponedInProgress)
+ return;
+
+ myDumpPostponedInProgress = true;
+ // make a copy of postponed entities, because the list will be updated
+ // if some features are not able to be dumped
+ std::list<EntityPtr> aPostponedCopy = myPostponed;
+ myPostponed.clear();
+
+ // iterate over postponed entities and try to dump them
+ std::list<EntityPtr>::const_iterator anIt = aPostponedCopy.begin();
+ for (; anIt != aPostponedCopy.end(); ++anIt) {
+ FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(*anIt);
+ if (aFolder) {
+ if (theDumpFolders)
+ dumpFolder(aFolder);
+ else
+ myPostponed.push_back(*anIt);
+ }
+ else {
+ FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
+ if (aFeature)
+ dumpFeature(aFeature, true);
+ }
+ }
+ myDumpPostponedInProgress = false;
+}
+
void ModelHighAPI_Dumper::dumpSubFeatureNameAndColor(const std::string theSubFeatureGet,
const FeaturePtr& theSubFeature)
{
name(theSubFeature, false);
- myNames[theSubFeature] = std::pair<std::string, std::string>(theSubFeatureGet, theSubFeature->name());
+ myNames[theSubFeature] = EntityName(theSubFeatureGet, theSubFeature->name(), false);
// store results if they have user-defined names or colors
std::list<ResultPtr> aResultsWithNameOrColor;
std::list<ResultPtr>::const_iterator aResIt = aResults.begin();
for (; aResIt != aResults.end(); ++aResIt) {
std::string aResName = (*aResIt)->data()->name();
- myNames[*aResIt] = std::pair<std::string, std::string>(aResName, aResName);
+ myNames[*aResIt] = EntityName(aResName, aResName, false);
aResultsWithNameOrColor.push_back(*aResIt);
}
if (!aFile.is_open())
return false;
- // standard header
+ // standard header (encoding + imported modules)
+ aFile << "# -*- coding: utf-8 -*-" << std::endl << std::endl;
for (ModulesMap::const_iterator aModIt = myModules.begin();
aModIt != myModules.end(); ++aModIt) {
aFile << "from " << aModIt->first << " import ";
- if (aModIt->second.empty() ||
+ if (aModIt->second.empty() ||
aModIt->second.find(std::string()) != aModIt->second.end())
aFile << "*"; // import whole module
else {
if (!myModules.empty())
aFile << std::endl;
- aFile << "import model" << std::endl << std::endl;
+ aFile << "from salome.shaper import model" << std::endl << std::endl;
aFile << "model.begin()" << std::endl;
// dump collected data
void ModelHighAPI_Dumper::dumpEntitySetName()
{
const LastDumpedEntity& aLastDumped = myEntitiesStack.top();
+ bool isBufferEmpty = myDumpBuffer.str().empty();
// dump "setName" for the entity
if (aLastDumped.myUserName) {
- std::pair<std::string, std::string> anEntityNames = myNames[aLastDumped.myEntity];
- if (!anEntityNames.second.empty())
- myDumpBuffer << anEntityNames.first << ".setName(\"" << anEntityNames.second << "\")" << std::endl;
- anEntityNames.second.clear(); // don't dump "setName" for the entity twice
+ EntityName& anEntityNames = myNames[aLastDumped.myEntity];
+ if (!anEntityNames.myIsDefault)
+ myDumpBuffer << anEntityNames.myCurrentName << ".setName(\""
+ << anEntityNames.myUserName << "\")" << std::endl;
+ // don't dump "setName" for the entity twice
+ anEntityNames.myUserName.clear();
+ anEntityNames.myIsDefault = true;
}
// dump "setName" for results
std::list<ResultPtr>::const_iterator aResIt = aLastDumped.myResults.begin();
std::list<ResultPtr>::const_iterator aResEnd = aLastDumped.myResults.end();
for (; aResIt != aResEnd; ++aResIt) {
// set result name
- std::pair<std::string, std::string> anEntityNames = myNames[*aResIt];
- if (!anEntityNames.second.empty()) {
+ EntityName& anEntityNames = myNames[*aResIt];
+ if (!anEntityNames.myIsDefault) {
*this << *aResIt;
- myDumpBuffer << ".setName(\"" << anEntityNames.second << "\")" << std::endl;
- anEntityNames.second.clear(); // don't dump "setName" for the entity twice
+ myDumpBuffer << ".setName(\"" << anEntityNames.myUserName << "\")" << std::endl;
+ // don't dump "setName" for the entity twice
+ anEntityNames.myUserName.clear();
+ anEntityNames.myIsDefault = true;
}
// set result color
if (!isDefaultColor(*aResIt)) {
<< ", " << aColor->value(2) << ")" << std::endl;
}
}
+ // set result deflection
+ if (!isDefaultDeflection(*aResIt)) {
+ AttributeDoublePtr aDeflectionAttr =
+ (*aResIt)->data()->real(ModelAPI_Result::DEFLECTION_ID());
+ if(aDeflectionAttr.get() && aDeflectionAttr->isInitialized()) {
+ *this << *aResIt;
+ myDumpBuffer << ".setDeflection(" << aDeflectionAttr->value() << ")" << std::endl;
+ }
+ }
+ // set result transparency
+ if (!isDefaultTransparency(*aResIt)) {
+ AttributeDoublePtr aTransparencyAttr =
+ (*aResIt)->data()->real(ModelAPI_Result::TRANSPARENCY_ID());
+ if(aTransparencyAttr.get() && aTransparencyAttr->isInitialized()) {
+ *this << *aResIt;
+ myDumpBuffer << ".setTransparency(" << aTransparencyAttr->value() << ")" << std::endl;
+ }
+ }
}
+ myNames[aLastDumped.myEntity].myIsDumped = true;
myEntitiesStack.pop();
+
+ // clean buffer if it was clear before
+ if (isBufferEmpty) {
+ myFullDump << myDumpBuffer.str();
+ myDumpBuffer.str("");
+ }
}
bool ModelHighAPI_Dumper::isDumped(const EntityPtr& theEntity) const
{
EntityNameMap::const_iterator aFound = myNames.find(theEntity);
- return aFound != myNames.end();
+ FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theEntity);
+ return (aFound != myNames.end() && aFound->second.myIsDumped) ||
+ myFeaturesToSkip.find(aFeature) != myFeaturesToSkip.end();
+}
+
+bool ModelHighAPI_Dumper::isDumped(const AttributeRefAttrPtr& theRefAttr) const
+{
+ FeaturePtr aFeature;
+ if (theRefAttr->isObject())
+ aFeature = ModelAPI_Feature::feature(theRefAttr->object());
+ else
+ aFeature = ModelAPI_Feature::feature(theRefAttr->attr()->owner());
+ return aFeature && isDumped(EntityPtr(aFeature));
+}
+
+bool ModelHighAPI_Dumper::isDumped(const AttributeRefListPtr& theRefList) const
+{
+ std::list<ObjectPtr> aRefs = theRefList->list();
+ std::list<ObjectPtr>::iterator anIt = aRefs.begin();
+ for (; anIt != aRefs.end(); ++anIt) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt);
+ if (aFeature && !isDumped(EntityPtr(aFeature)))
+ return false;
+ }
+ return true;
+}
+
+static bool isSketchSub(const FeaturePtr& theFeature)
+{
+ static const std::string SKETCH("Sketch");
+ CompositeFeaturePtr anOwner = ModelAPI_Tools::compositeOwner(theFeature);
+ return anOwner && anOwner->getKind() == SKETCH;
}
bool ModelHighAPI_Dumper::isDefaultColor(const ResultPtr& theResult) const
if (!aColor || !aColor->isInitialized())
return true;
+ // check the result belongs to sketch entity, do not dump color in this way
+ ResultConstructionPtr aResConstr =
+ std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(theResult);
+ if (aResConstr) {
+ FeaturePtr aFeature = ModelAPI_Feature::feature(theResult->data()->owner());
+ if (isSketchSub(aFeature))
+ return true;
+ }
+
std::string aSection, aName, aDefault;
theResult->colorConfigInfo(aSection, aName, aDefault);
return aDefault == aColorInfo.str();
}
+bool ModelHighAPI_Dumper::isDefaultDeflection(const ResultPtr& theResult) const
+{
+ AttributeDoublePtr aDeflectionAttr = theResult->data()->real(ModelAPI_Result::DEFLECTION_ID());
+ if(!aDeflectionAttr || !aDeflectionAttr->isInitialized()) {
+ return true;
+ }
+
+ double aCurrent = aDeflectionAttr->value();
+ double aDefault = -1;
+
+ bool isConstruction = false;
+ std::string aResultGroup = theResult->groupName();
+ if (aResultGroup == ModelAPI_ResultConstruction::group())
+ isConstruction = true;
+ else if (aResultGroup == ModelAPI_ResultBody::group()) {
+ GeomShapePtr aGeomShape = theResult->shape();
+ if (aGeomShape.get()) {
+ // if the shape could not be exploded on faces, it contains only wires, edges, and vertices
+ // correction of deviation for them should not influence to the application performance
+ GeomAPI_ShapeExplorer anExp(aGeomShape, GeomAPI_Shape::FACE);
+ isConstruction = !anExp.more();
+ }
+ }
+ if (isConstruction)
+ aDefault = Config_PropManager::real("Visualization", "construction_deflection");
+ else
+ aDefault = Config_PropManager::real("Visualization", "body_deflection");
+
+ return fabs(aCurrent - aDefault) < 1.e-12;
+}
+
+bool ModelHighAPI_Dumper::isDefaultTransparency(const ResultPtr& theResult) const
+{
+ AttributeDoublePtr anAttribute = theResult->data()->real(ModelAPI_Result::TRANSPARENCY_ID());
+ if(!anAttribute || !anAttribute->isInitialized()) {
+ return true;
+ }
+ return fabs(anAttribute->value()) < 1.e-12;
+}
+
ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const char theChar)
{
myDumpBuffer << theChar;
return *this;
}
+ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const FolderPtr& theFolder)
+{
+ myDumpBuffer << name(theFolder);
+
+ // add dumped folder to a stack
+ if (!myNames[theFolder].myIsDumped &&
+ (myEntitiesStack.empty() || myEntitiesStack.top().myEntity != theFolder))
+ myEntitiesStack.push(LastDumpedEntity(theFolder, !myNames[theFolder].myIsDefault));
+
+ return *this;
+}
+
ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const FeaturePtr& theEntity)
{
myDumpBuffer << name(theEntity);
- bool isUserDefinedName = !myNames[theEntity].second.empty();
- // store results if they have user-defined names or colors
- std::list<ResultPtr> aResultsWithNameOrColor;
- const std::list<ResultPtr>& aResults = theEntity->results();
- std::list<ResultPtr>::const_iterator aResIt = aResults.begin();
- for (; aResIt != aResults.end(); ++aResIt)
- if (!myNames[*aResIt].second.empty() || !isDefaultColor(*aResIt))
- aResultsWithNameOrColor.push_back(*aResIt);
- // store just dumped entity to stack
- myEntitiesStack.push(LastDumpedEntity(theEntity, isUserDefinedName, aResultsWithNameOrColor));
+ if (!myNames[theEntity].myIsDumped) {
+ bool isUserDefinedName = !myNames[theEntity].myIsDefault;
+ // store results if they have user-defined names or colors
+ std::list<ResultPtr> aResultsWithNameOrColor;
+ std::list<ResultPtr> allRes;
+ ModelAPI_Tools::allResults(theEntity, allRes);
+ for(std::list<ResultPtr>::iterator aRes = allRes.begin(); aRes != allRes.end(); aRes++) {
+ if(!myNames[*aRes].myIsDefault || !isDefaultColor(*aRes) ||
+ !isDefaultDeflection(*aRes) || !isDefaultTransparency(*aRes))
+ aResultsWithNameOrColor.push_back(*aRes);
+ }
+ // store just dumped entity to stack
+ if (myEntitiesStack.empty() || myEntitiesStack.top().myEntity != theEntity)
+ myEntitiesStack.push(
+ LastDumpedEntity(theEntity, isUserDefinedName, aResultsWithNameOrColor));
+ }
// remove entity from the list of not dumped items
myNotDumpedEntities.erase(theEntity);
ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const ResultPtr& theResult)
{
+ // iterate in the structure of sub-results to the parent
+ ResultPtr aCurRes = theResult;
FeaturePtr aFeature = ModelAPI_Feature::feature(theResult);
- int anIndex = 0;
- std::list<ResultPtr> aResults = aFeature->results();
- for(std::list<ResultPtr>::const_iterator anIt = aResults.cbegin(); anIt != aResults.cend(); ++anIt, ++anIndex) {
- if(theResult->isSame(*anIt)) {
- break;
+ std::list<int> anIndices; // indexes of results in the parent result, starting from topmost
+ while(aCurRes.get()) {
+ ResultBodyPtr aParent = ModelAPI_Tools::bodyOwner(aCurRes);
+ if (aParent) {
+ anIndices.push_front(ModelAPI_Tools::bodyIndex(aCurRes));
+ } else { // index of the result in the feature
+ std::list<ResultPtr>::const_iterator aRes = aFeature->results().cbegin();
+ for(int anIndex = 0; aRes != aFeature->results().cend(); aRes++, anIndex++) {
+ if (*aRes == aCurRes) {
+ anIndices.push_front(anIndex);
+ break;
+ }
+ }
+ }
+ aCurRes = aParent;
+ }
+
+ myDumpBuffer << name(aFeature);
+ for (std::list<int>::iterator anI = anIndices.begin(); anI != anIndices.end(); anI++) {
+ if (anI == anIndices.begin()) {
+ if(*anI == 0) {
+ myDumpBuffer << ".result()";
+ }
+ else {
+ myDumpBuffer << ".results()[" << *anI << "]";
+ }
+ } else {
+ myDumpBuffer << ".subResult(" << *anI << ")";
}
}
- myDumpBuffer << name(aFeature) << ".result()[" << anIndex << "]";
+
return *this;
}
ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const AttributePtr& theAttr)
{
FeaturePtr anOwner = ModelAPI_Feature::feature(theAttr->owner());
- myDumpBuffer << name(anOwner) << "." << attributeGetter(anOwner, theAttr->id()) << "()";
+
+ std::string aWrapperPrefix, aWrapperSuffix;
+ // Check the attribute belongs to copied (in multi-translation or multi-rotation) feature.
+ // In this case we need to cast explicitly feature to appropriate type.
+ AttributeBooleanPtr isCopy = anOwner->boolean("Copy");
+ if (isCopy.get() && isCopy->value()) {
+ aWrapperPrefix = featureWrapper(anOwner) + "(";
+ aWrapperSuffix = ")";
+ importModule("SketchAPI");
+ }
+
+ myDumpBuffer << aWrapperPrefix << name(anOwner) << aWrapperSuffix
+ << "." << attributeGetter(anOwner, theAttr->id()) << "()";
return *this;
}
return *this;
}
+static int possibleSelectionsByPoint(const GeomPointPtr& thePoint,
+ const ResultPtr& theResult,
+ const GeomShapePtr& theShape,
+ const FeaturePtr& theStartFeature,
+ const FeaturePtr& theEndFeature)
+{
+ DocumentPtr aDoc1 = theStartFeature->document();
+ DocumentPtr aDoc2 = theEndFeature->document();
+
+ std::list<FeaturePtr> aFeatures = aDoc1->allFeatures();
+ if (aDoc1 != aDoc2) {
+ std::list<FeaturePtr> anAdditionalFeatures = aDoc2->allFeatures();
+ aFeatures.insert(aFeatures.end(), anAdditionalFeatures.begin(), anAdditionalFeatures.end());
+ }
+
+ CompositeFeaturePtr aLastCompositeFeature;
+
+ std::list<FeaturePtr>::const_iterator aFIt = aFeatures.begin();
+ while (aFIt != aFeatures.end() && *aFIt != theStartFeature) {
+ CompositeFeaturePtr aCompFeat = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*aFIt);
+ if (aCompFeat)
+ aLastCompositeFeature = aCompFeat;
+ ++aFIt;
+ }
+
+ // collect the list of composite features, containing the last feature;
+ // these features should be excluded from searching,
+ // because the feature cannot select sub-shapes from its parent
+ std::set<FeaturePtr> aEndFeatureParents = ModelAPI_Tools::getParents(theEndFeature);
+
+ int aNbPossibleSelections = 0;
+ for (; aFIt != aFeatures.end() && *aFIt != theEndFeature; ++aFIt) {
+ bool isSkipFeature = false;
+ if (aLastCompositeFeature && aLastCompositeFeature->isSub(*aFIt))
+ isSkipFeature = true;
+ CompositeFeaturePtr aCompFeat = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*aFIt);
+ if (aCompFeat) {
+ ResultPartPtr aPartRes =
+ std::dynamic_pointer_cast<ModelAPI_ResultPart>(aCompFeat->firstResult());
+ if (!aPartRes)
+ aLastCompositeFeature = aCompFeat;
+ if (aEndFeatureParents.find(aCompFeat) != aEndFeatureParents.end()) {
+ // do not process the parent for the last feature,
+ // because it cannot select objects from its parent
+ isSkipFeature = true;
+ }
+ }
+ if (isSkipFeature)
+ continue;
+
+ std::list<ModelGeomAlgo_Shape::SubshapeOfResult> anApproproate;
+ if (ModelGeomAlgo_Shape::findSubshapeByPoint(*aFIt, thePoint, theShape->shapeType(),
+ anApproproate)) {
+ std::list<ModelGeomAlgo_Shape::SubshapeOfResult>::iterator anApIt = anApproproate.begin();
+ for (; anApIt != anApproproate.end(); ++anApIt) {
+ ++aNbPossibleSelections;
+
+ // stop if the target shape and result are found
+ GeomShapePtr aCurShape = anApIt->mySubshape;
+ if (!aCurShape)
+ aCurShape = anApIt->myResult->shape();
+
+ if (anApIt->myResult->isSame(theResult) && aCurShape->isSame(theShape))
+ break;
+ }
+ }
+ }
+ return aNbPossibleSelections;
+}
+
ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
const std::shared_ptr<ModelAPI_AttributeSelection>& theAttrSelect)
{
return *this;
}
- myDumpBuffer << "\"" << aShape->shapeTypeStr() << "\", \"" << theAttrSelect->namingName() << "\")";
+ // how to dump selection: construction features are dumped by name always
+ bool isDumpByGeom = myGeometricalSelection;
+ FeaturePtr aSelectedFeature;
+ if (isDumpByGeom) {
+ ResultPtr aRes = theAttrSelect->context();
+ FeaturePtr aFeature = theAttrSelect->contextFeature();
+ if (aRes && !aFeature)
+ aSelectedFeature = ModelAPI_Feature::feature(aRes->data()->owner());
+ isDumpByGeom = aSelectedFeature && aSelectedFeature->isInHistory();
+ }
+
+ myDumpBuffer << "\"" << aShape->shapeTypeStr();
+ bool aStandardDump = true;
+ if (isDumpByGeom) {
+ // check the selected item is a ResultPart;
+ // in this case it is necessary to get shape with full transformation
+ // for correct calculation of the middle point
+ ResultPartPtr aResPart =
+ std::dynamic_pointer_cast<ModelAPI_ResultPart>(theAttrSelect->context());
+ if (aResPart && aShape->shapeType() == GeomAPI_Shape::COMPOUND)
+ aShape = aResPart->shape();
+ GeomPointPtr aMiddlePoint = aShape->middlePoint();
+ // calculate number of features, which could be selected by the same point
+ FeaturePtr anOwner = ModelAPI_Feature::feature(theAttrSelect->owner());
+ int aNbPossibleSelections = possibleSelectionsByPoint(aMiddlePoint,
+ theAttrSelect->context(), aShape, aSelectedFeature, anOwner);
+
+ // produce the index if the number of applicable features is greater than 1
+ std::string anIndex;
+ if (aNbPossibleSelections > 1) {
+ std::ostringstream anOutput;
+ anOutput << "_" << aNbPossibleSelections;
+ anIndex = anOutput.str();
+ }
+
+ myDumpBuffer << anIndex << "\", ";
+ *this << aMiddlePoint;
+ aStandardDump = false;
+ } if (theAttrSelect->isWeakNaming() ||
+ (myWeakNamingSelection && aShape.get() && theAttrSelect->context().get() &&
+ aShape != theAttrSelect->context()->shape())) { // weak naming for local selection only
+ GeomAlgoAPI_NExplode aNExplode(theAttrSelect->context()->shape(), aShape->shapeType());
+ int anIndex = aNExplode.index(aShape);
+ if (anIndex != 0) { // found a week-naming index, so, export it
+ myDumpBuffer<<"\", \""<<theAttrSelect->context()->data()->name()<<"\", "<<anIndex;
+ aStandardDump = false;
+ }
+ }
+ if (aStandardDump)
+ myDumpBuffer << "\", \"" << theAttrSelect->namingName() << "\"";
+ myDumpBuffer << ")";
return *this;
}
ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
const std::shared_ptr<ModelAPI_AttributeSelectionList>& theAttrSelList)
{
- myDumpBuffer << "[";
+ static const int aThreshold = 2;
+ // if number of elements in the list if greater than a threshold,
+ // dump it in a separate line with specific name
+ std::string aDumped = myDumpBuffer.str();
- GeomShapePtr aShape;
- std::string aShapeTypeStr;
+ if (aDumped.empty() || theAttrSelList->size() <= aThreshold) {
+ myDumpBuffer << "[";
- bool isAdded = false;
+ GeomShapePtr aShape;
+ std::string aShapeTypeStr;
- for(int anIndex = 0; anIndex < theAttrSelList->size(); ++anIndex) {
- AttributeSelectionPtr anAttribute = theAttrSelList->value(anIndex);
- aShape = anAttribute->value();
- if(!aShape.get()) {
- aShape = anAttribute->context()->shape();
- }
+ bool isAdded = false;
- if(!aShape.get()) {
- continue;
+ for(int anIndex = 0; anIndex < theAttrSelList->size(); ++anIndex) {
+ AttributeSelectionPtr anAttribute = theAttrSelList->value(anIndex);
+ aShape = anAttribute->value();
+ if(!aShape.get()) {
+ ResultPtr aContext = anAttribute->context();
+ if (aContext.get())
+ aShape = aContext->shape();
+ }
+
+ if(!aShape.get()) {
+ continue;
+ }
+
+ if(isAdded) {
+ myDumpBuffer << ", ";
+ } else {
+ isAdded = true;
+ }
+ *this << anAttribute;
}
- if(isAdded) {
- myDumpBuffer << ", ";
- } else {
- isAdded = true;
+ myDumpBuffer << "]";
+ } else {
+ // clear buffer and store list "as is"
+ myDumpBuffer.str("");
+ *this << theAttrSelList;
+ // save buffer and clear it again
+ std::string aDumpedList = myDumpBuffer.str();
+ myDumpBuffer.str("");
+ // obtain name of list (the feature may contain several selection lists)
+ FeaturePtr anOwner = ModelAPI_Feature::feature(theAttrSelList->owner());
+ std::string aListName = name(anOwner) + "_objects";
+ std::list<AttributePtr> aSelLists =
+ anOwner->data()->attributes(ModelAPI_AttributeSelectionList::typeId());
+ if (aSelLists.size() > 1) {
+ int anIndex = 1;
+ for (std::list<AttributePtr>::iterator aSIt = aSelLists.begin();
+ aSIt != aSelLists.end(); ++aSIt, ++anIndex)
+ if ((*aSIt).get() == theAttrSelList.get())
+ break;
+ std::ostringstream aSStream;
+ aSStream << aListName << "_" << anIndex;
+ aListName = aSStream.str();
}
- myDumpBuffer << "model.selection(\"" << aShape->shapeTypeStr() << "\", \"" << anAttribute->namingName() << "\")";
+ // store all previous data
+ myDumpBuffer << aListName << " = " << aDumpedList << std::endl
+ << aDumped << aListName;
}
+ return *this;
+}
- myDumpBuffer << "]";
+ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
+ const std::shared_ptr<ModelAPI_AttributeStringArray>& theArray)
+{
+ myDumpBuffer<<"[";
+ for(int anIndex = 0; anIndex < theArray->size(); ++anIndex) {
+ if (anIndex != 0)
+ myDumpBuffer<<", ";
+
+ myDumpBuffer<<"\""<<theArray->value(anIndex)<<"\"";
+ }
+
+ myDumpBuffer<<"]";
return *this;
}
/// Dump std::endl
-MODELHIGHAPI_EXPORT
ModelHighAPI_Dumper& operator<<(ModelHighAPI_Dumper& theDumper,
std::basic_ostream<char>& (*theEndl)(std::basic_ostream<char>&))
{
theDumper.myDumpBuffer << theEndl;
if (!theDumper.myEntitiesStack.empty()) {
- // Name for composite feature is dumped when all sub-entities are dumped
- // (see method ModelHighAPI_Dumper::processSubs).
- const ModelHighAPI_Dumper::LastDumpedEntity& aLastDumped = theDumper.myEntitiesStack.top();
- CompositeFeaturePtr aComposite =
- std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aLastDumped.myEntity);
- if (!aComposite)
- theDumper.dumpEntitySetName();
+ bool isCopy;
+ // all copies have been stored into stack, pop them all
+ do {
+ isCopy = false;
+ // Name for composite feature is dumped when all sub-entities are dumped
+ // (see method ModelHighAPI_Dumper::processSubs).
+ const ModelHighAPI_Dumper::LastDumpedEntity& aLastDumped = theDumper.myEntitiesStack.top();
+ CompositeFeaturePtr aComposite =
+ std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aLastDumped.myEntity);
+ if (!aComposite) {
+ theDumper.dumpEntitySetName();
+ FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aLastDumped.myEntity);
+ if (aFeature) {
+ AttributeBooleanPtr aCopyAttr = aFeature->boolean("Copy");
+ isCopy = aCopyAttr.get() && aCopyAttr->value();
+ }
+ }
+ } while (isCopy && !theDumper.myEntitiesStack.empty());
}
// store all not-dumped entities first
else {
FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anIt);
theDumper.dumpFeature(aFeature, true);
+ // dump the Projection feature which produces this "Copy" entity
+ AttributeBooleanPtr aCopyAttr = aFeature->boolean("Copy");
+ if (aCopyAttr.get() && aCopyAttr->value())
+ {
+ const std::set<AttributePtr>& aRefs = aFeature->data()->refsToMe();
+ std::set<AttributePtr>::iterator aRefIt = aRefs.begin();
+ for (; aRefIt != aRefs.end(); ++aRefIt)
+ if ((*aRefIt)->id() == "ProjectedFeature")
+ { // process projection only
+ FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner());
+ if (anOwner && !theDumper.isDumped(EntityPtr(anOwner)))
+ theDumper.dumpFeature(anOwner, true);
+ }
+ }
}
}
// then store currently dumped string
theDumper.myFullDump << aBufCopy;
+ // now, store all postponed features
+ theDumper.dumpPostponed();
+
return theDumper;
}