X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModelHighAPI%2FModelHighAPI_Dumper.cpp;h=8bc41417be4434a04555ce2e0e807a020e4416ce;hb=48b3193b3aa7ad3413effc73276ab77d6226d73f;hp=5369fe882b2230db299746e8de384faf7af04e46;hpb=b67410b7e66bb035081015af2245b62223510474;p=modules%2Fshaper.git diff --git a/src/ModelHighAPI/ModelHighAPI_Dumper.cpp b/src/ModelHighAPI/ModelHighAPI_Dumper.cpp index 5369fe882..8bc41417b 100644 --- a/src/ModelHighAPI/ModelHighAPI_Dumper.cpp +++ b/src/ModelHighAPI/ModelHighAPI_Dumper.cpp @@ -1,14 +1,30 @@ -// 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 +// -// File: ModelHighAPI_Dumper.cpp -// Created: 1 August 2016 -// Author: Artem ZHIDKOV - -//-------------------------------------------------------------------------------------- #include "ModelHighAPI_Dumper.h" +#include + #include #include +#include #include #include @@ -16,6 +32,7 @@ #include #include +#include #include #include #include @@ -24,12 +41,17 @@ #include #include #include +#include #include #include #include #include +#include #include +#include +#include #include +#include #include @@ -37,8 +59,6 @@ #include -#define DUMP_USER_DEFINED_NAMES - static int gCompositeStackDepth = 0; ModelHighAPI_Dumper* ModelHighAPI_Dumper::mySelf = 0; @@ -73,7 +93,11 @@ void ModelHighAPI_Dumper::clear(bool bufferOnly) myNames.clear(); myModules.clear(); myFeatureCount.clear(); - myLastEntityWithName = EntityPtr(); + while (!myEntitiesStack.empty()) + myEntitiesStack.pop(); + + myPostponed.clear(); + myDumpPostponedInProgress = false; } } @@ -82,43 +106,91 @@ void ModelHighAPI_Dumper::clearNotDumped() myNotDumpedEntities.clear(); } -const std::string& ModelHighAPI_Dumper::name(const EntityPtr& theEntity, bool theSaveNotDumped) +// 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; - bool isUserDefined = false; + std::string aName, aKind; + bool isDefaultName = false; + bool isSaveNotDumped = theSaveNotDumped; + std::ostringstream aDefaultName; FeaturePtr aFeature = std::dynamic_pointer_cast(theEntity); if (aFeature) { - isUserDefined = true; aName = aFeature->name(); - const std::string& aKind = aFeature->getKind(); - DocumentPtr aDoc = aFeature->document(); - int& aNbFeatures = myFeatureCount[aDoc][aKind]; + aKind = aFeature->getKind(); + } else { + FolderPtr aFolder = std::dynamic_pointer_cast(theEntity); + if (aFolder) { + aName = aFolder->data()->name(); + aKind = ModelAPI_Folder::ID(); + isSaveNotDumped = false; + } + } + + ObjectPtr anObject = std::dynamic_pointer_cast(theEntity); + if (anObject) { + DocumentPtr aDoc = anObject->document(); + std::pair& 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, std::string::npos); - int anId = std::stoi(anIdStr); + std::string anIdStr = aName.substr(aKind.length() + 1); + 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 + 1 == anId) { - isUserDefined = false; - //aNbFeatures = anId - 1; + if (aNbFeatures.first == anId && aNbFeatures.second < anId) { + // name is not user-defined + isDefaultName = true; } + + if (anId > aNbFeatures.second) + aNbFeatures.second = anId; } - aNbFeatures += 1; + // obtain default name for the feature + if (theUseEntityName) + aDefaultName << aName; + else { + int aFullIndex = 0; + NbFeaturesMap::const_iterator aFIt = myFeatureCount.begin(); + for (; aFIt != myFeatureCount.end(); ++aFIt) { + std::map >::const_iterator aFound = + aFIt->second.find(aKind); + if (aFound != aFIt->second.end()) + aFullIndex += aFound->second.first; + } + aDefaultName << aKind << "_" << aFullIndex; + } } - myNames[theEntity] = std::pair(aName, isUserDefined); - if (theSaveNotDumped) + myNames[theEntity] = EntityName(aDefaultName.str(), aName, isDefaultName); + if (isSaveNotDumped) myNotDumpedEntities.insert(theEntity); - return myNames[theEntity].first; + + // store names of results + if (aFeature) + saveResultNames(aFeature); + + return myNames[theEntity].myCurrentName; } const std::string& ModelHighAPI_Dumper::parentName(const FeaturePtr& theEntity) @@ -136,12 +208,31 @@ const std::string& ModelHighAPI_Dumper::parentName(const FeaturePtr& theEntity) return DUMMY; } +void ModelHighAPI_Dumper::saveResultNames(const FeaturePtr& theFeature) +{ + // Default name of the feature + bool isFeatureDefaultName = myNames[theFeature].myIsDefault; + + // Save only names of results which is not correspond to default feature name + const std::list& aResults = theFeature->results(); + std::list allRes; + ModelAPI_Tools::allResults(theFeature, allRes); + for(std::list::iterator aRes = allRes.begin(); aRes != allRes.end(); aRes++) { + std::pair 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); + } +} + bool ModelHighAPI_Dumper::process(const std::shared_ptr& theDoc, const std::string& theFileName) { // dump top level document feature static const std::string aDocName("partSet"); - myNames[theDoc] = std::pair(aDocName, false); + myNames[theDoc] = EntityName(aDocName, std::string(), true); *this << aDocName << " = model.moduleDocument()" << std::endl; // dump subfeatures and store result to file @@ -151,32 +242,51 @@ bool ModelHighAPI_Dumper::process(const std::shared_ptr& theD bool ModelHighAPI_Dumper::process(const std::shared_ptr& theDoc) { bool isOk = true; - std::list aFeatures = theDoc->allFeatures(); - std::list::const_iterator aFeatIt = aFeatures.begin(); + std::list anObjects = theDoc->allObjects(); + std::list::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(*anObjIt); + if (aFeature) + dumpParameter(aFeature); + } // dump all other features - for (aFeatIt = aFeatures.begin(); aFeatIt != aFeatures.end(); ++aFeatIt) { - CompositeFeaturePtr aCompFeat = std::dynamic_pointer_cast(*aFeatIt); + for (anObjIt = anObjects.begin(); anObjIt != anObjects.end(); ++anObjIt) { + CompositeFeaturePtr aCompFeat = std::dynamic_pointer_cast(*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(*anObjIt); + if (aFolder) + dumpFolder(aFolder); + else { + FeaturePtr aFeature = std::dynamic_pointer_cast(*anObjIt); + if (aFeature) // dump common feature + dumpFeature(aFeature); + } + } } + // dump folders if any + dumpPostponed(true); return isOk; } -bool ModelHighAPI_Dumper::process(const std::shared_ptr& theComposite, bool isForce) +bool ModelHighAPI_Dumper::process(const std::shared_ptr& 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; @@ -185,15 +295,19 @@ bool ModelHighAPI_Dumper::process(const std::shared_ptrpartDoc(); + 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(aDocName, false); + 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 @@ -204,20 +318,20 @@ bool ModelHighAPI_Dumper::process(const std::shared_ptr& theComposite, - bool theDumpModelDo) +bool ModelHighAPI_Dumper::processSubs( + const std::shared_ptr& theComposite, + bool theDumpModelDo) { bool isOk = true; // dump all sub-features; + bool isSubDumped = false; int aNbSubs = theComposite->numberOfSubs(); -////////////////////////////////////// - std::list aList = theComposite->reflist("Features")->list(); -////////////////////////////////////// for (int anIndex = 0; anIndex < aNbSubs; ++anIndex) { FeaturePtr aFeature = theComposite->subFeature(anIndex); - if (isDumped(aFeature)) + if (isDumped(EntityPtr(aFeature))) continue; + isSubDumped = true; CompositeFeaturePtr aCompFeat = std::dynamic_pointer_cast(aFeature); if (aCompFeat) // iteratively process composite features isOk = process(aCompFeat) && isOk; @@ -225,15 +339,82 @@ bool ModelHighAPI_Dumper::processSubs(const std::shared_ptr aPostponedCopy = myPostponed; + myPostponed.clear(); + + // iterate over postponed entities and try to dump them + std::list::const_iterator anIt = aPostponedCopy.begin(); + for (; anIt != aPostponedCopy.end(); ++anIt) { + FolderPtr aFolder = std::dynamic_pointer_cast(*anIt); + if (aFolder) { + if (theDumpFolders) + dumpFolder(aFolder); + else + myPostponed.push_back(*anIt); + } + else { + FeaturePtr aFeature = std::dynamic_pointer_cast(*anIt); + if (aFeature) + dumpFeature(aFeature, true); + } + } + myDumpPostponedInProgress = false; +} + +void ModelHighAPI_Dumper::dumpSubFeatureNameAndColor(const std::string theSubFeatureGet, + const FeaturePtr& theSubFeature) +{ + name(theSubFeature, false); + myNames[theSubFeature] = EntityName(theSubFeatureGet, theSubFeature->name(), false); + + // store results if they have user-defined names or colors + std::list aResultsWithNameOrColor; + const std::list& aResults = theSubFeature->results(); + std::list::const_iterator aResIt = aResults.begin(); + for (; aResIt != aResults.end(); ++aResIt) { + std::string aResName = (*aResIt)->data()->name(); + myNames[*aResIt] = EntityName(aResName, aResName, false); + aResultsWithNameOrColor.push_back(*aResIt); + } + + // store just dumped entity to stack + myEntitiesStack.push(LastDumpedEntity(theSubFeature, true, aResultsWithNameOrColor)); + + dumpEntitySetName(); +} + bool ModelHighAPI_Dumper::exportTo(const std::string& theFileName) { std::ofstream aFile; @@ -241,11 +422,12 @@ bool ModelHighAPI_Dumper::exportTo(const std::string& theFileName) 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 { @@ -260,11 +442,12 @@ bool ModelHighAPI_Dumper::exportTo(const std::string& theFileName) 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 aFile << myFullDump.str(); + aFile << myDumpBuffer.str(); // standard footer aFile << "model.end()" << std::endl; @@ -283,25 +466,155 @@ void ModelHighAPI_Dumper::importModule(const std::string& theModuleName, void ModelHighAPI_Dumper::dumpEntitySetName() { - if (!myLastEntityWithName) - return; + const LastDumpedEntity& aLastDumped = myEntitiesStack.top(); + bool isBufferEmpty = myDumpBuffer.str().empty(); + + // dump "setName" for the entity + if (aLastDumped.myUserName) { + 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::const_iterator aResIt = aLastDumped.myResults.begin(); + std::list::const_iterator aResEnd = aLastDumped.myResults.end(); + for (; aResIt != aResEnd; ++aResIt) { + // set result name + EntityName& anEntityNames = myNames[*aResIt]; + if (!anEntityNames.myIsDefault) { + *this << *aResIt; + 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)) { + AttributeIntArrayPtr aColor = (*aResIt)->data()->intArray(ModelAPI_Result::COLOR_ID()); + if (aColor && aColor->isInitialized()) { + *this << *aResIt; + myDumpBuffer << ".setColor(" << aColor->value(0) << ", " << aColor->value(1) + << ", " << 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; + } + } + } -#ifdef DUMP_USER_DEFINED_NAMES - const std::string& aName = name(myLastEntityWithName); - myDumpBuffer << aName; - FeaturePtr aFeature = std::dynamic_pointer_cast(myLastEntityWithName); - if (aFeature) - myDumpBuffer << ".feature()"; - myDumpBuffer << ".data().setName(\"" << aName << "\")" << std::endl; -#endif - myNames[myLastEntityWithName].second = false; // don't dump "setName" for the entity twice - myLastEntityWithName = EntityPtr(); + 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(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 aRefs = theRefList->list(); + std::list::iterator anIt = aRefs.begin(); + for (; anIt != aRefs.end(); ++anIt) { + FeaturePtr aFeature = ModelAPI_Feature::feature(*anIt); + if (aFeature && !isDumped(EntityPtr(aFeature))) + return false; + } + return true; +} + +bool ModelHighAPI_Dumper::isDefaultColor(const ResultPtr& theResult) const +{ + AttributeIntArrayPtr aColor = theResult->data()->intArray(ModelAPI_Result::COLOR_ID()); + if (!aColor || !aColor->isInitialized()) + return true; + + std::string aSection, aName, aDefault; + theResult->colorConfigInfo(aSection, aName, aDefault); + + // dump current color + std::ostringstream aColorInfo; + aColorInfo << aColor->value(0) << "," << aColor->value(1) << "," << aColor->value(2); + + 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) @@ -432,26 +745,80 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( 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); - if (myNames[theEntity].second) - myLastEntityWithName = theEntity; + + if (!myNames[theEntity].myIsDumped) { + bool isUserDefinedName = !myNames[theEntity].myIsDefault; + // store results if they have user-defined names or colors + std::list aResultsWithNameOrColor; + std::list allRes; + ModelAPI_Tools::allResults(theEntity, allRes); + for(std::list::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); return *this; } 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 aResults = aFeature->results(); - for(std::list::const_iterator anIt = aResults.cbegin(); anIt != aResults.cend(); ++anIt, ++anIndex) { - if(theResult->isSame(*anIt)) { - break; + std::list 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::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::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; } @@ -475,7 +842,19 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const ObjectPtr& theObject) 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; } @@ -575,50 +954,120 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( return *this; } - myDumpBuffer << "\"" << aShape->shapeTypeStr() << "\", \"" << theAttrSelect->namingName() << "\")"; + myDumpBuffer << "\"" << aShape->shapeTypeStr() << "\", \"" << + theAttrSelect->namingName() << "\")"; return *this; } ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( const std::shared_ptr& 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; + } + myDumpBuffer << "model.selection(\"" << + aShape->shapeTypeStr() << "\", \"" << anAttribute->namingName() << "\")"; } - 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 aSelLists = + anOwner->data()->attributes(ModelAPI_AttributeSelectionList::typeId()); + if (aSelLists.size() > 1) { + int anIndex = 1; + for (std::list::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& theArray) +{ + myDumpBuffer<<"["; + for(int anIndex = 0; anIndex < theArray->size(); ++anIndex) { + if (anIndex != 0) + myDumpBuffer<<", "; + + myDumpBuffer<<"\""<value(anIndex)<<"\""; + } + + myDumpBuffer<<"]"; return *this; } /// Dump std::endl -MODELHIGHAPI_EXPORT ModelHighAPI_Dumper& operator<<(ModelHighAPI_Dumper& theDumper, std::basic_ostream& (*theEndl)(std::basic_ostream&)) { theDumper.myDumpBuffer << theEndl; - theDumper.dumpEntitySetName(); + + if (!theDumper.myEntitiesStack.empty()) { + 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(aLastDumped.myEntity); + if (!aComposite) { + theDumper.dumpEntitySetName(); + FeaturePtr aFeature = std::dynamic_pointer_cast(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 std::set aNotDumped = theDumper.myNotDumpedEntities; @@ -634,6 +1083,20 @@ ModelHighAPI_Dumper& operator<<(ModelHighAPI_Dumper& theDumper, else { FeaturePtr aFeature = std::dynamic_pointer_cast(*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& aRefs = aFeature->data()->refsToMe(); + std::set::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); + } + } } } @@ -644,5 +1107,8 @@ ModelHighAPI_Dumper& operator<<(ModelHighAPI_Dumper& theDumper, // then store currently dumped string theDumper.myFullDump << aBufCopy; + // now, store all postponed features + theDumper.dumpPostponed(); + return theDumper; }