X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModelHighAPI%2FModelHighAPI_Dumper.cpp;h=15d10c6aa7c01e9678042c848c0c4a20021663bc;hb=46c0759fa291dad10b713cf02b341d6e9e60c1a4;hp=4ac4db53a15e30db5c587c65e6fcc90145b84eb7;hpb=9bb3b8b646eb13866a8792ae585ac5df25a16590;p=modules%2Fshaper.git diff --git a/src/ModelHighAPI/ModelHighAPI_Dumper.cpp b/src/ModelHighAPI/ModelHighAPI_Dumper.cpp index 4ac4db53a..15d10c6aa 100644 --- a/src/ModelHighAPI/ModelHighAPI_Dumper.cpp +++ b/src/ModelHighAPI/ModelHighAPI_Dumper.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 CEA/DEN, EDF R&D +// Copyright (C) 2014-2020 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 @@ -12,26 +12,34 @@ // // 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 +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // -// See http://www.salome-platform.org/ or -// email : webmaster.salome@opencascade.com +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // #include "ModelHighAPI_Dumper.h" #include -#include +#include +#include +#include #include +#include +#include #include +#include +#include +#include #include #include #include +#include #include #include +#include #include #include #include @@ -46,27 +54,471 @@ #include #include #include +#include #include #include #include -#include #include +#include #include +#include #include +#include + #include #include #include +// =========== Implementation of storage of dumped data =========== +static const int THE_DUMP_PRECISION = 16; + +class ModelHighAPI_Dumper::DumpStorageBuffer : public ModelHighAPI_Dumper::DumpStorage +{ +public: + void addStorage(const ModelHighAPI_Dumper::DumpStoragePtr& theStorage) + { myStorageArray.push_back(theStorage); } + + void clear() { myStorageArray.clear(); } + + bool isBufferEmpty() + { + return myStorageArray.empty() || myStorageArray.front()->buffer().str().empty(); + } + + void mergeBuffer() + { + std::list::iterator anIt = myStorageArray.begin(); + for (; anIt != myStorageArray.end(); ++anIt) { + // avoid multiple empty lines + std::string aBuf = (*anIt)->buffer().str(); + size_t anInd = std::string::npos; + while ((anInd = aBuf.find("\n\n\n")) != std::string::npos) + aBuf.erase(anInd, 1); + + (*anIt)->fullDump() << aBuf; + (*anIt)->buffer().str(""); + } + } + + void write(const std::string& theValue) + { + if (myStorageArray.empty()) + addStorage(DumpStoragePtr(new DumpStorage)); + + std::list::iterator anIt = myStorageArray.begin(); + for (; anIt != myStorageArray.end(); ++anIt) + (*anIt)->buffer() << theValue; + } + + DumpStorageBuffer& operator<<(const char theChar) + { + std::ostringstream out; + out << theChar; + write(out.str()); + return *this; + } + + DumpStorageBuffer& operator<<(const char* theString) + { + write(theString); + return *this; + } + + DumpStorageBuffer& operator<<(const std::string& theString) + { + write(theString); + return *this; + } + + DumpStorageBuffer& operator<<(const bool theValue) + { + std::ostringstream out; + out << theValue; + write(out.str()); + return *this; + } + + DumpStorageBuffer& operator<<(const int theValue) + { + std::ostringstream out; + out << theValue; + write(out.str()); + return *this; + } + + DumpStorageBuffer& operator<<(const double theValue) + { + std::ostringstream out; + out << std::setprecision(THE_DUMP_PRECISION) << theValue; + write(out.str()); + return *this; + } + /// Dump std::endl + friend + DumpStorageBuffer& operator<<(DumpStorageBuffer& theBuffer, + std::basic_ostream& (*)(std::basic_ostream&)) + { + theBuffer.write("\n"); + return theBuffer; + } + + void dumpArray(int theSize, double* theValues, std::string* theTexts) + { + std::ostringstream anOutput; + anOutput << std::setprecision(THE_DUMP_PRECISION); + for (int i = 0; i < theSize; ++i) { + if (i > 0) + anOutput << ", "; + if (theTexts[i].empty()) + anOutput << theValues[i]; + else + anOutput << "\"" << theTexts[i] << "\""; + } + write(anOutput.str()); + } + + virtual void write(const std::shared_ptr& theAttrSelect) + { + if (myStorageArray.empty()) + addStorage(DumpStoragePtr(new DumpStorage)); + + std::list::iterator anIt = myStorageArray.begin(); + for (; anIt != myStorageArray.end(); ++anIt) + (*anIt)->write(theAttrSelect); + } + + virtual void reserveBuffer() + { + std::list::iterator anIt = myStorageArray.begin(); + for (; anIt != myStorageArray.end(); ++anIt) + (*anIt)->reserveBuffer(); + } + + virtual void restoreReservedBuffer() + { + std::list::iterator anIt = myStorageArray.begin(); + for (; anIt != myStorageArray.end(); ++anIt) + (*anIt)->restoreReservedBuffer(); + } + + virtual bool exportTo(const std::string& theFilename, const ModulesSet& theUsedModules) + { + static const std::string THE_EXT = ".py"; + std::string aFilenameBase = theFilename; + if (aFilenameBase.rfind(THE_EXT) == aFilenameBase.size() - THE_EXT.size()) + aFilenameBase = aFilenameBase.substr(0, aFilenameBase.size() - THE_EXT.size()); + + bool isOk = true; + std::list::iterator anIt = myStorageArray.begin(); + for (; anIt != myStorageArray.end(); ++anIt) { + std::string aFilename = aFilenameBase + (*anIt)->myFilenameSuffix + THE_EXT; + isOk = (*anIt)->exportTo(aFilename, theUsedModules) && isOk; + } + return isOk; + } + +private: + std::list myStorageArray; +}; + + +ModelHighAPI_Dumper::DumpStorage::DumpStorage(const DumpStorage& theOther) + : myFilenameSuffix(theOther.myFilenameSuffix), + myDumpBufferHideout(theOther.myDumpBufferHideout) +{ + myFullDump.str(theOther.myFullDump.str()); + myDumpBuffer.str(theOther.myDumpBuffer.str()); +} + +const ModelHighAPI_Dumper::DumpStorage& +ModelHighAPI_Dumper::DumpStorage::operator=(const ModelHighAPI_Dumper::DumpStorage& theOther) +{ + myFilenameSuffix = theOther.myFilenameSuffix; + myFullDump.str(theOther.myFullDump.str()); + myDumpBuffer.str(theOther.myDumpBuffer.str()); + myDumpBufferHideout = theOther.myDumpBufferHideout; + return *this; +} + +void ModelHighAPI_Dumper::DumpStorage::reserveBuffer() +{ + myDumpBufferHideout.push(myDumpBuffer.str()); + myDumpBuffer.str(""); +} + +void ModelHighAPI_Dumper::DumpStorage::restoreReservedBuffer() +{ + myDumpBuffer << myDumpBufferHideout.top(); + myDumpBufferHideout.pop(); +} + +bool ModelHighAPI_Dumper::DumpStorage::exportTo(const std::string& theFilename, + const ModulesSet& theUsedModules) +{ + std::ofstream aFile; + OSD_OpenStream(aFile, theFilename.c_str(), std::ofstream::out); + if (!aFile.is_open()) + return false; + + // standard header imported modules + for (ModulesSet::const_iterator aModIt = theUsedModules.begin(); + aModIt != theUsedModules.end(); ++aModIt) { + aFile << "from " << *aModIt << " import *" << std::endl; + } + if (!theUsedModules.empty()) + aFile << 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; + aFile.close(); + + return true; +} + +static void getShapeAndContext(const AttributeSelectionPtr& theAttrSelect, + GeomShapePtr& theShape, ResultPtr& theContext) +{ + if (theAttrSelect->isInitialized()) { + theShape = theAttrSelect->value(); + theContext = theAttrSelect->context(); + if (!theShape.get()) + theShape = theContext->shape(); + + if (theAttrSelect->isGeometricalSelection() && + theShape.get() && theShape->shapeType() == GeomAPI_Shape::COMPOUND && + theContext.get() && !theShape->isEqual(theContext->shape()) && + theContext->groupName() != ModelAPI_ResultPart::group() && + theContext->groupName() != ModelAPI_ResultGroup::group()) { + GeomAPI_ShapeIterator anIt(theShape); + theShape = anIt.current(); + } + } +} + +void ModelHighAPI_Dumper::DumpStorage::write(const AttributeSelectionPtr& theAttrSelect) +{ + myDumpBuffer << "model.selection("; + + GeomShapePtr aShape; + ResultPtr aContext; + getShapeAndContext(theAttrSelect, aShape, aContext); + + if (aShape.get()) { + myDumpBuffer << "\"" << aShape->shapeTypeStr() << "\", \"" + << theAttrSelect->namingName() << "\""; + } + + myDumpBuffer << ")"; +} + +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 aFeatures = aDoc1->allFeatures(); + if (aDoc1 != aDoc2) { + // Find the position of the part, where its features should be inserted. + // It will avoid checking of appropriate elements in partSet after the current part. + std::list::iterator aFIt = aFeatures.begin(); + for (; aFIt != aFeatures.end(); ++aFIt) { + ResultPartPtr aPartRes = + std::dynamic_pointer_cast((*aFIt)->lastResult()); + if (aPartRes && aPartRes->partDoc() == aDoc2) + break; + } + + std::list anAdditionalFeatures = aDoc2->allFeatures(); + aFeatures.insert(aFIt, anAdditionalFeatures.begin(), anAdditionalFeatures.end()); + } + + CompositeFeaturePtr aLastCompositeFeature; + + std::list::const_iterator aFIt = aFeatures.begin(); + while (aFIt != aFeatures.end() && *aFIt != theStartFeature) { + CompositeFeaturePtr aCompFeat = std::dynamic_pointer_cast(*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 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(*aFIt); + if (aCompFeat) { + ResultPartPtr aPartRes = + std::dynamic_pointer_cast(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 anApproproate; + if (ModelGeomAlgo_Shape::findSubshapeByPoint(*aFIt, thePoint, theShape->shapeType(), + anApproproate)) { + bool isContinue = true; + std::list > aCenters; + std::list::iterator anApIt = anApproproate.begin(); + for (; anApIt != anApproproate.end() && isContinue; ++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)) { + if (anApIt->myCenterType == (int)ModelAPI_AttributeSelection::NOT_CENTER) + isContinue = !aCurShape->isSame(theShape); + else if (theShape->isVertex() && aCurShape->isEdge()) { + GeomEdgePtr aCurEdge = aCurShape->edge(); + GeomVertexPtr aVertex = theShape->vertex(); + GeomPointPtr aCenter; + switch (anApIt->myCenterType) { + case (int)ModelAPI_AttributeSelection::CIRCLE_CENTER: { + GeomCirclePtr aCirc = aCurEdge->circle(); + if (aCirc) + aCenter = aCirc->center(); + break; + } + case (int)ModelAPI_AttributeSelection::ELLIPSE_FIRST_FOCUS: { + GeomEllipsePtr anEllipse = aCurEdge->ellipse(); + if (anEllipse) + aCenter = anEllipse->firstFocus(); + break; + } + case (int)ModelAPI_AttributeSelection::ELLIPSE_SECOND_FOCUS: { + GeomEllipsePtr anEllipse = aCurEdge->ellipse(); + if (anEllipse) + aCenter = anEllipse->secondFocus(); + break; + } + } + if (aCenter && aCenter->distance(aVertex->point()) < 1.e-7) + aCenters.push_back(std::pair(aCurShape, aNbPossibleSelections)); + } + } + } + // passed till the appropriate shape, check the center of circle + // or a focus of ellipse is selected + if (isContinue && !aCenters.empty()) + aNbPossibleSelections = aCenters.front().second; + } + } + return aNbPossibleSelections; +} + +void ModelHighAPI_Dumper::DumpStorageGeom::write(const AttributeSelectionPtr& theAttrSelect) +{ + GeomShapePtr aShape; + ResultPtr aContext; + getShapeAndContext(theAttrSelect, aShape, aContext); + + // how to dump selection: construction features are dumped by name always + FeaturePtr aSelectedFeature; + FeaturePtr aFeature = theAttrSelect->contextFeature(); + if (aShape && aContext && !aFeature) + aSelectedFeature = ModelAPI_Feature::feature(aContext->data()->owner()); + bool isDumpByGeom = aSelectedFeature && aSelectedFeature->isInHistory(); + + if (isDumpByGeom) { + myDumpBuffer << "model.selection(\"" << aShape->shapeTypeStr(); + // 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(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 << std::setprecision(THE_DUMP_PRECISION) + << anIndex << "\", (" + << aMiddlePoint->x() << ", " + << aMiddlePoint->y() << ", " + << aMiddlePoint->z() << ")"; + myDumpBuffer << ")"; + } + else + DumpStorage::write(theAttrSelect); +} + +void ModelHighAPI_Dumper::DumpStorageWeak::write(const AttributeSelectionPtr& theAttrSelect) +{ + GeomShapePtr aShape; + ResultPtr aContext; + getShapeAndContext(theAttrSelect, aShape, aContext); + + bool aStandardDump = true; + if (aShape.get() && aContext.get() && + aShape != aContext->shape()) { // weak naming for local selection only + GeomAlgoAPI_NExplode aNExplode(aContext->shape(), aShape->shapeType()); + int anIndex = aNExplode.index(aShape); + if (anIndex != 0) { // found a week-naming index, so, export it + myDumpBuffer << "model.selection(\"" << aShape->shapeTypeStr() << "\", \"" + << theAttrSelect->contextName(aContext) << "\", " << anIndex << ")"; + aStandardDump = false; + } + } + if (aStandardDump) + DumpStorage::write(theAttrSelect); +} +// ====================================================================== + + static int gCompositeStackDepth = 0; ModelHighAPI_Dumper* ModelHighAPI_Dumper::mySelf = 0; ModelHighAPI_Dumper::ModelHighAPI_Dumper() + : myDumpStorage(new DumpStorageBuffer), + myDumpPostponedInProgress(false) { - clear(); +} + +ModelHighAPI_Dumper::~ModelHighAPI_Dumper() +{ + delete myDumpStorage; } void ModelHighAPI_Dumper::setInstance(ModelHighAPI_Dumper* theDumper) @@ -80,26 +532,22 @@ ModelHighAPI_Dumper* ModelHighAPI_Dumper::getInstance() return mySelf; } -void ModelHighAPI_Dumper::clear(bool bufferOnly) +void ModelHighAPI_Dumper::addCustomStorage(const ModelHighAPI_Dumper::DumpStoragePtr& theStorage) { - myDumpBuffer.str(""); - myDumpBuffer << std::setprecision(16); - - clearNotDumped(); - - if (!bufferOnly) { - myFullDump.str(""); - myFullDump << std::setprecision(16); + myDumpStorage->addStorage(theStorage); +} - myNames.clear(); - myModules.clear(); - myFeatureCount.clear(); - while (!myEntitiesStack.empty()) - myEntitiesStack.pop(); +void ModelHighAPI_Dumper::clearCustomStorage() +{ + myDumpStorage->clear(); - myPostponed.clear(); - myDumpPostponedInProgress = false; - } + myNames.clear(); + myModules.clear(); + myFeatureCount.clear(); + myPostponed.clear(); + while (!myEntitiesStack.empty()) + myEntitiesStack.pop(); + clearNotDumped(); } void ModelHighAPI_Dumper::clearNotDumped() @@ -148,8 +596,8 @@ const std::string& ModelHighAPI_Dumper::name(const EntityPtr& theEntity, ObjectPtr anObject = std::dynamic_pointer_cast(theEntity); if (anObject) { DocumentPtr aDoc = anObject->document(); - int& aNbFeatures = myFeatureCount[aDoc][aKind]; - aNbFeatures += 1; + 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_" @@ -158,10 +606,24 @@ const std::string& ModelHighAPI_Dumper::name(const EntityPtr& theEntity, // 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 isDefaultName = true; + + // check there are postponed features of this kind, + // dump their names, because the sequence of features may be changed + for (std::list::const_iterator aPpIt = myPostponed.begin(); + aPpIt != myPostponed.end(); ++aPpIt) { + FeaturePtr aCurFeature = std::dynamic_pointer_cast(*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 @@ -171,9 +633,10 @@ const std::string& ModelHighAPI_Dumper::name(const EntityPtr& theEntity, 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; + std::map >::const_iterator aFoundKind = + aFIt->second.find(aKind); + if (aFoundKind != aFIt->second.end()) + aFullIndex += aFoundKind->second.first; } aDefaultName << aKind << "_" << aFullIndex; } @@ -211,33 +674,15 @@ void ModelHighAPI_Dumper::saveResultNames(const FeaturePtr& theFeature) 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::const_iterator aResIt = aResults.begin(); - for (int i = 0; aResIt != aResults.end(); ++aResIt, ++i) { - std::pair aName = ModelAPI_Tools::getDefaultName(*aResIt, i); + 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 = (*aResIt)->data()->name(); - + std::string aResName = (*aRes)->data()->name(); bool isUserDefined = !(isFeatureDefaultName && aDefaultName == aResName); - - myNames[*aResIt] = EntityName(aResName, - (isUserDefined ? aResName : std::string()), !isUserDefined); - - // check names of sub-results for CompSolid - ResultCompSolidPtr aCompSolid = std::dynamic_pointer_cast(*aResIt); - if (aCompSolid) { - int aNbSubs = aCompSolid->numberOfSubs(); - for (int j = 0; j < aNbSubs; ++j) { - ResultPtr aSub = aCompSolid->subResult(j); - std::string aSubName = aSub->data()->name(); - aName = ModelAPI_Tools::getDefaultName(aSub, j); - aDefaultName = aName.first; - - bool isUserDefinedSubName = isUserDefined || aDefaultName != aSubName; - myNames[aSub] = EntityName(aSubName, - (isUserDefinedSubName ? aSubName : std::string()), !isUserDefinedSubName); - } - } + myNames[*aRes] = + EntityName(aResName, (isUserDefined ? aResName : std::string()), !isUserDefined); } } @@ -250,7 +695,8 @@ bool ModelHighAPI_Dumper::process(const std::shared_ptr& theD *this << aDocName << " = model.moduleDocument()" << std::endl; // dump subfeatures and store result to file - return process(theDoc) && exportTo(theFileName); + bool isOk = process(theDoc) && myDumpStorage->exportTo(theFileName, myModules); + return isOk; } bool ModelHighAPI_Dumper::process(const std::shared_ptr& theDoc) @@ -267,8 +713,12 @@ bool ModelHighAPI_Dumper::process(const std::shared_ptr& theD // dump all other features 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; + if (aCompFeat) { + // iteratively process composite features, + // if the composite feature is the last in the document, no need to dump "model.do()" action + std::list::const_iterator aNext = anObjIt; + isOk = process(aCompFeat, false, ++aNext != anObjects.end()) && isOk; + } else if (!isDumped(EntityPtr(*anObjIt))) { // dump folder FolderPtr aFolder = std::dynamic_pointer_cast(*anObjIt); @@ -281,11 +731,13 @@ bool ModelHighAPI_Dumper::process(const std::shared_ptr& theD } } } + // dump folders if any + dumpPostponed(true); return isOk; } bool ModelHighAPI_Dumper::process(const std::shared_ptr& theComposite, - bool isForce) + bool isForce, bool isDumpModelDo) { // increase composite features stack ++gCompositeStackDepth; @@ -318,7 +770,9 @@ bool ModelHighAPI_Dumper::process(const std::shared_ptr::const_iterator anIt = aPostponedCopy.begin(); for (; anIt != aPostponedCopy.end(); ++anIt) { FolderPtr aFolder = std::dynamic_pointer_cast(*anIt); - if (aFolder) - dumpFolder(aFolder); + if (aFolder) { + if (theDumpFolders) + dumpFolder(aFolder); + else + myPostponed.push_back(*anIt); + } else { FeaturePtr aFeature = std::dynamic_pointer_cast(*anIt); if (aFeature) - dumpFeature(aFeature); + dumpFeature(aFeature, true); } } myDumpPostponedInProgress = false; @@ -425,64 +881,22 @@ void ModelHighAPI_Dumper::dumpSubFeatureNameAndColor(const std::string theSubFea dumpEntitySetName(); } -bool ModelHighAPI_Dumper::exportTo(const std::string& theFileName) +void ModelHighAPI_Dumper::importModule(const std::string& theModuleName) { - std::ofstream aFile; - OSD_OpenStream(aFile, theFileName.c_str(), std::ofstream::out); - if (!aFile.is_open()) - return false; - - // standard header - for (ModulesMap::const_iterator aModIt = myModules.begin(); - aModIt != myModules.end(); ++aModIt) { - aFile << "from " << aModIt->first << " import "; - if (aModIt->second.empty() || - aModIt->second.find(std::string()) != aModIt->second.end()) - aFile << "*"; // import whole module - else { - // import specific features - std::set::const_iterator anObjIt = aModIt->second.begin(); - aFile << *anObjIt; - for (++anObjIt; anObjIt != aModIt->second.end(); ++anObjIt) - aFile << ", " << *anObjIt; - } - aFile << std::endl; - } - if (!myModules.empty()) - aFile << 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; - - aFile.close(); - clear(); - - return true; -} - -void ModelHighAPI_Dumper::importModule(const std::string& theModuleName, - const std::string& theObject) -{ - myModules[theModuleName].insert(theObject); + myModules.insert(theModuleName); } void ModelHighAPI_Dumper::dumpEntitySetName() { const LastDumpedEntity& aLastDumped = myEntitiesStack.top(); + bool isBufferEmpty = myDumpStorage->isBufferEmpty(); // dump "setName" for the entity if (aLastDumped.myUserName) { EntityName& anEntityNames = myNames[aLastDumped.myEntity]; if (!anEntityNames.myIsDefault) - myDumpBuffer << anEntityNames.myCurrentName << ".setName(\"" - << anEntityNames.myUserName << "\")" << std::endl; + *myDumpStorage << anEntityNames.myCurrentName << ".setName(\"" + << anEntityNames.myUserName << "\")\n"; // don't dump "setName" for the entity twice anEntityNames.myUserName.clear(); anEntityNames.myIsDefault = true; @@ -495,7 +909,7 @@ void ModelHighAPI_Dumper::dumpEntitySetName() EntityName& anEntityNames = myNames[*aResIt]; if (!anEntityNames.myIsDefault) { *this << *aResIt; - myDumpBuffer << ".setName(\"" << anEntityNames.myUserName << "\")" << std::endl; + *myDumpStorage << ".setName(\"" << anEntityNames.myUserName << "\")\n"; // don't dump "setName" for the entity twice anEntityNames.myUserName.clear(); anEntityNames.myIsDefault = true; @@ -505,8 +919,8 @@ void ModelHighAPI_Dumper::dumpEntitySetName() 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; + *myDumpStorage << ".setColor(" << aColor->value(0) << ", " << aColor->value(1) + << ", " << aColor->value(2) << ")\n"; } } // set result deflection @@ -515,7 +929,7 @@ void ModelHighAPI_Dumper::dumpEntitySetName() (*aResIt)->data()->real(ModelAPI_Result::DEFLECTION_ID()); if(aDeflectionAttr.get() && aDeflectionAttr->isInitialized()) { *this << *aResIt; - myDumpBuffer << ".setDeflection(" << aDeflectionAttr->value() << ")" << std::endl; + *myDumpStorage << ".setDeflection(" << aDeflectionAttr->value() << ")\n"; } } // set result transparency @@ -524,13 +938,17 @@ void ModelHighAPI_Dumper::dumpEntitySetName() (*aResIt)->data()->real(ModelAPI_Result::TRANSPARENCY_ID()); if(aTransparencyAttr.get() && aTransparencyAttr->isInitialized()) { *this << *aResIt; - myDumpBuffer << ".setTransparency(" << aTransparencyAttr->value() << ")" << std::endl; + *myDumpStorage << ".setTransparency(" << aTransparencyAttr->value() << ")\n"; } } } myNames[aLastDumped.myEntity].myIsDumped = true; myEntitiesStack.pop(); + + // clean buffer if it was clear before + if (isBufferEmpty) + myDumpStorage->mergeBuffer(); } bool ModelHighAPI_Dumper::isDumped(const EntityPtr& theEntity) const @@ -563,12 +981,28 @@ bool ModelHighAPI_Dumper::isDumped(const AttributeRefListPtr& theRefList) const 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 { AttributeIntArrayPtr aColor = theResult->data()->intArray(ModelAPI_Result::COLOR_ID()); 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(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); @@ -621,83 +1055,70 @@ bool ModelHighAPI_Dumper::isDefaultTransparency(const ResultPtr& theResult) cons ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const char theChar) { - myDumpBuffer << theChar; + *myDumpStorage << theChar; return *this; } ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const char* theString) { - myDumpBuffer << theString; + *myDumpStorage << theString; return *this; } ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const std::string& theString) { - myDumpBuffer << theString; + *myDumpStorage << theString; return *this; } ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const bool theValue) { - myDumpBuffer << (theValue ? "True" : "False"); + *myDumpStorage << (theValue ? "True" : "False"); return *this; } ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const int theValue) { - myDumpBuffer << theValue; + *myDumpStorage << theValue; return *this; } ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const double theValue) { - myDumpBuffer << theValue; + *myDumpStorage << theValue; return *this; } ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const std::shared_ptr& thePoint) { - importModule("GeomAPI", "GeomAPI_Pnt"); - myDumpBuffer << "GeomAPI_Pnt(" << thePoint->x() << ", " - << thePoint->y() << ", " << thePoint->z() << ")"; + importModule("GeomAPI"); + *myDumpStorage << "GeomAPI_Pnt(" << thePoint->x() << ", " + << thePoint->y() << ", " << thePoint->z() << ")"; return *this; } ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const std::shared_ptr& theDir) { - importModule("GeomAPI", "GeomAPI_Dir"); - myDumpBuffer << "GeomAPI_Dir(" << theDir->x() << ", " - << theDir->y() << ", " << theDir->z() << ")"; + importModule("GeomAPI"); + *myDumpStorage << "GeomAPI_Dir(" << theDir->x() << ", " + << theDir->y() << ", " << theDir->z() << ")"; return *this; } ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( const std::shared_ptr& theDir) { - myDumpBuffer << theDir->x() << ", " << theDir->y() << ", " << theDir->z(); + *myDumpStorage << theDir->x() << ", " << theDir->y() << ", " << theDir->z(); return *this; } -static void dumpArray(std::ostringstream& theOutput, int theSize, - double* theValues, std::string* theTexts) -{ - for (int i = 0; i < theSize; ++i) { - if (i > 0) - theOutput << ", "; - if (theTexts[i].empty()) - theOutput << theValues[i]; - else - theOutput << "\"" << theTexts[i] << "\""; - } -} - ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( const std::shared_ptr& thePoint) { static const int aSize = 3; double aValues[aSize] = {thePoint->x(), thePoint->y(), thePoint->z()}; std::string aTexts[aSize] = {thePoint->textX(), thePoint->textY(), thePoint->textZ()}; - dumpArray(myDumpBuffer, aSize, aValues, aTexts); + myDumpStorage->dumpArray(aSize, aValues, aTexts); return *this; } @@ -707,14 +1128,51 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( static const int aSize = 2; double aValues[aSize] = {thePoint->x(), thePoint->y()}; std::string aTexts[aSize] = {thePoint->textX(), thePoint->textY()}; - dumpArray(myDumpBuffer, aSize, aValues, aTexts); + myDumpStorage->dumpArray(aSize, aValues, aTexts); + return *this; +} + +ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( + const std::shared_ptr& thePointArray) +{ + static const int aThreshold = 4; + static bool aDumpAsIs = false; + static std::string aSeparator = ""; + // if number of elements in the list if greater than a threshold, + // dump it in a separate line with specific name + int aSize = thePointArray->size(); + if (aDumpAsIs || aSize <= aThreshold) { + *myDumpStorage << "["; + GeomPnt2dPtr aPoint = thePointArray->pnt(0); + *myDumpStorage << "(" << aPoint->x() << ", " << aPoint->y() << ")"; + for (int anIndex = 1; anIndex < aSize; ++anIndex) { + aPoint = thePointArray->pnt(anIndex); + *myDumpStorage << "," << aSeparator << " (" << aPoint->x() << ", " << aPoint->y() << ")"; + } + *myDumpStorage << aSeparator << "]"; + } + else { + // name of list + FeaturePtr anOwner = ModelAPI_Feature::feature(thePointArray->owner()); + std::string aListName = name(anOwner) + "_" + thePointArray->id(); + // reserve dumped buffer and store list "as is" + myDumpStorage->reserveBuffer(); + aDumpAsIs = true; + aSeparator = std::string("\n") + std::string(aListName.size() + 3, ' '); + *this << aListName << " = " << thePointArray << "\n"; + aDumpAsIs = false; + aSeparator = ""; + // append reserved data to the end of the current buffer + myDumpStorage->restoreReservedBuffer(); + *myDumpStorage << aListName; + } return *this; } ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( const std::shared_ptr& theAttrBool) { - myDumpBuffer << (theAttrBool->value() ? "True" : "False"); + *myDumpStorage << (theAttrBool->value() ? "True" : "False"); return *this; } @@ -723,9 +1181,23 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( { std::string aText = theAttrInt->text(); if (aText.empty()) - myDumpBuffer << theAttrInt->value(); + *myDumpStorage << theAttrInt->value(); else - myDumpBuffer << "\"" << aText << "\""; + *myDumpStorage << "\"" << aText << "\""; + return *this; +} + +ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( + const std::shared_ptr& theArray) +{ + *myDumpStorage << "["; + int aSize = theArray->size(); + if (aSize > 0) { + *myDumpStorage << theArray->value(0); + for (int anIndex = 1; anIndex < aSize; ++anIndex) + *myDumpStorage << ", " << theArray->value(anIndex); + } + *myDumpStorage << "]"; return *this; } @@ -734,51 +1206,59 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( { std::string aText = theAttrReal->text(); if (aText.empty()) - myDumpBuffer << theAttrReal->value(); + *myDumpStorage << theAttrReal->value(); else - myDumpBuffer << "\"" << aText << "\""; + *myDumpStorage << "\"" << aText << "\""; + return *this; +} + +ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( + const std::shared_ptr& theArray) +{ + *myDumpStorage << "["; + int aSize = theArray->size(); + if (aSize > 0) { + *myDumpStorage << theArray->value(0); + for (int anIndex = 1; anIndex < aSize; ++anIndex) + *myDumpStorage << ", " << theArray->value(anIndex); + } + *myDumpStorage << "]"; return *this; } ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( const std::shared_ptr& theAttrStr) { - myDumpBuffer << "\"" << theAttrStr->value() << "\""; + *myDumpStorage << "\"" << theAttrStr->value() << "\""; return *this; } ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const FolderPtr& theFolder) { - myDumpBuffer << name(theFolder); + *myDumpStorage << 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); + *myDumpStorage << name(theEntity); if (!myNames[theEntity].myIsDumped) { bool isUserDefinedName = !myNames[theEntity].myIsDefault; // store results if they have user-defined names or colors std::list aResultsWithNameOrColor; - const std::list& aResults = theEntity->results(); - std::list::const_iterator aResIt = aResults.begin(); - for (; aResIt != aResults.end(); ++aResIt) { - if (!myNames[*aResIt].myIsDefault || !isDefaultColor(*aResIt) || - !isDefaultDeflection(*aResIt) || !isDefaultTransparency(*aResIt)) - aResultsWithNameOrColor.push_back(*aResIt); - - ResultCompSolidPtr aCompSolid = - std::dynamic_pointer_cast(*aResIt); - if (aCompSolid) { - int aNbSubs = aCompSolid->numberOfSubs(); - for (int i = 0; i < aNbSubs; ++i) { - ResultPtr aCurRes = aCompSolid->subResult(i); - if (!myNames[aCurRes].myIsDefault || !isDefaultColor(aCurRes) || - !isDefaultDeflection(aCurRes) || !isDefaultTransparency(aCurRes)) - aResultsWithNameOrColor.push_back(aCurRes); - } - } + 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) @@ -793,37 +1273,53 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const FeaturePtr& 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; - int aSubIndex = -1; - std::list aResults = aFeature->results(); - for(std::list::const_iterator - anIt = aResults.cbegin(); anIt != aResults.cend(); ++anIt, ++anIndex) { - if(theResult->isSame(*anIt)) { - break; - } - - ResultCompSolidPtr aCompSolid = std::dynamic_pointer_cast(*anIt); - if (aCompSolid) { - int aNbSubs = aCompSolid->numberOfSubs(); - for (aSubIndex = 0; aSubIndex < aNbSubs; ++aSubIndex) - if (theResult->isSame(aCompSolid->subResult(aSubIndex))) + 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; - if (aSubIndex < aNbSubs) - break; - aSubIndex = -1; + } + } } + aCurRes = aParent; } - myDumpBuffer << name(aFeature); - if(anIndex == 0) { - myDumpBuffer << ".result()"; - } else { - myDumpBuffer << ".results()[" << anIndex << "]"; + *myDumpStorage << name(aFeature); + for (std::list::iterator anI = anIndices.begin(); anI != anIndices.end(); anI++) { + if (anI == anIndices.begin()) { + if(*anI == 0) { + *myDumpStorage << ".result()"; + } + else { + *myDumpStorage << ".results()[" << *anI << "]"; + } + } else { + *myDumpStorage << ".subResult(" << *anI << ")"; + } } - if (aSubIndex >= 0) { - myDumpBuffer << ".subResult(" << aSubIndex << ")"; + + return *this; +} + +ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const std::list& theResults) +{ + *this << "["; + for (std::list::const_iterator anIt = theResults.begin(); + anIt != theResults.end(); ++anIt) { + if (anIt != theResults.begin()) + *this << ", "; + *this << *anIt; } + *this << "]"; return *this; } @@ -831,7 +1327,7 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const ObjectPtr& theObject) { FeaturePtr aFeature = std::dynamic_pointer_cast(theObject); if(aFeature.get()) { - myDumpBuffer << name(aFeature); + *myDumpStorage << name(aFeature); return *this; } @@ -852,14 +1348,15 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const AttributePtr& theAttr // 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()) { + AttributeReferencePtr hasParent = anOwner->reference("ParentFeature"); + if ((isCopy.get() && isCopy->value()) || (hasParent && hasParent->value())) { aWrapperPrefix = featureWrapper(anOwner) + "("; aWrapperSuffix = ")"; importModule("SketchAPI"); } - myDumpBuffer << aWrapperPrefix << name(anOwner) << aWrapperSuffix - << "." << attributeGetter(anOwner, theAttr->id()) << "()"; + *myDumpStorage << aWrapperPrefix << name(anOwner) << aWrapperSuffix + << "." << attributeGetter(anOwner, theAttr->id()) << "()"; return *this; } @@ -876,13 +1373,13 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( const std::shared_ptr& theRefAttrList) { - myDumpBuffer << "["; + *myDumpStorage << "["; std::list > aList = theRefAttrList->list(); bool isAdded = false; std::list >::const_iterator anIt = aList.begin(); for (; anIt != aList.end(); ++anIt) { if (isAdded) - myDumpBuffer << ", "; + *myDumpStorage << ", "; else isAdded = true; if (anIt->first) @@ -890,7 +1387,7 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( else if (anIt->second) * this << anIt->second; } - myDumpBuffer << "]"; + *myDumpStorage << "]"; return *this; } @@ -905,36 +1402,35 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( const std::shared_ptr& theRefList) { static const int aThreshold = 2; + static bool aDumpAsIs = false; // 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(); - if (aDumped.empty() || theRefList->size() <= aThreshold) { - myDumpBuffer << "["; + if (aDumpAsIs || theRefList->size() <= aThreshold) { + *myDumpStorage << "["; std::list aList = theRefList->list(); bool isAdded = false; std::list::const_iterator anIt = aList.begin(); for (; anIt != aList.end(); ++anIt) { if (isAdded) - myDumpBuffer << ", "; + *myDumpStorage << ", "; else isAdded = true; *this << *anIt; } - myDumpBuffer << "]"; + *myDumpStorage << "]"; } else { - // clear buffer and store list "as is" - myDumpBuffer.str(""); - *this << theRefList; - // save buffer and clear it again - std::string aDumpedList = myDumpBuffer.str(); - myDumpBuffer.str(""); - // obtain name of list + // name of list FeaturePtr anOwner = ModelAPI_Feature::feature(theRefList->owner()); std::string aListName = name(anOwner) + "_objects"; - // store all previous data - myDumpBuffer << aListName << " = " << aDumpedList << std::endl - << aDumped << aListName; + // reserve dumped buffer and store list "as is" + myDumpStorage->reserveBuffer(); + aDumpAsIs = true; + *this << aListName << " = " << theRefList << "\n"; + aDumpAsIs = false; + // append reserved data to the end of the current buffer + myDumpStorage->restoreReservedBuffer(); + *myDumpStorage << aListName; } return *this; } @@ -942,76 +1438,97 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( const std::shared_ptr& theAttrSelect) { - myDumpBuffer << "model.selection("; - - if(!theAttrSelect->isInitialized()) { - myDumpBuffer << ")"; - return *this; - } - - GeomShapePtr aShape = theAttrSelect->value(); - if(!aShape.get()) { - aShape = theAttrSelect->context()->shape(); - } - - if(!aShape.get()) { - myDumpBuffer << ")"; - return *this; - } - - myDumpBuffer << "\"" << aShape->shapeTypeStr() << "\", \"" << - theAttrSelect->namingName() << "\")"; + myDumpStorage->write(theAttrSelect); return *this; } ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( const std::shared_ptr& theAttrSelList) { - myDumpBuffer << "["; + static const int aThreshold = 2; + static bool aDumpAsIs = false; + // if number of elements in the list if greater than a threshold, + // dump it in a separate line with specific name + if (aDumpAsIs || theAttrSelList->size() <= aThreshold) { + *myDumpStorage << "["; - GeomShapePtr aShape; - std::string aShapeTypeStr; + GeomShapePtr aShape; + std::string aShapeTypeStr; - bool isAdded = false; + bool isAdded = false; + + 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; + } - 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(isAdded) { + *myDumpStorage << ", "; + } else { + isAdded = true; + } + *this << anAttribute; } - if(!aShape.get()) { - continue; + // check selection list is obtained by filters + FiltersFeaturePtr aFilters = theAttrSelList->filters(); + if (aFilters) { + if (theAttrSelList->size() > 0) + *myDumpStorage << ", "; + dumpFeature(aFilters, true); } - if(isAdded) { - myDumpBuffer << ", "; - } else { - isAdded = true; + *myDumpStorage << "]"; + } else { + // 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() << "\")"; + // reserve dumped buffer and store list "as is" + myDumpStorage->reserveBuffer(); + aDumpAsIs = true; + *this << aListName << " = " << theAttrSelList << "\n"; + aDumpAsIs = false; + // append reserved data to the end of the current buffer + myDumpStorage->restoreReservedBuffer(); + *myDumpStorage << aListName; } - - myDumpBuffer << "]"; return *this; } ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( const std::shared_ptr& theArray) { - myDumpBuffer<<"["; + std::ostringstream aBuffer; + aBuffer << "["; for(int anIndex = 0; anIndex < theArray->size(); ++anIndex) { if (anIndex != 0) - myDumpBuffer<<", "; + aBuffer << ", "; - myDumpBuffer<<"\""<value(anIndex)<<"\""; + aBuffer << "\"" << theArray->value(anIndex) << "\""; } + aBuffer << "]"; - myDumpBuffer<<"]"; + myDumpStorage->write(aBuffer.str()); return *this; } @@ -1019,7 +1536,7 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( ModelHighAPI_Dumper& operator<<(ModelHighAPI_Dumper& theDumper, std::basic_ostream& (*theEndl)(std::basic_ostream&)) { - theDumper.myDumpBuffer << theEndl; + *theDumper.myDumpStorage << theEndl; if (!theDumper.myEntitiesStack.empty()) { bool isCopy; @@ -1044,8 +1561,7 @@ ModelHighAPI_Dumper& operator<<(ModelHighAPI_Dumper& theDumper, // store all not-dumped entities first std::set aNotDumped = theDumper.myNotDumpedEntities; - std::string aBufCopy = theDumper.myDumpBuffer.str(); - theDumper.clear(true); + theDumper.myDumpStorage->reserveBuffer(); std::set::const_iterator anIt = aNotDumped.begin(); for (; anIt != aNotDumped.end(); ++anIt) { // if the feature is composite, dump it with all subs @@ -1073,15 +1589,42 @@ ModelHighAPI_Dumper& operator<<(ModelHighAPI_Dumper& theDumper, } } - // avoid multiple empty lines - size_t anInd = std::string::npos; - while ((anInd = aBufCopy.find("\n\n\n")) != std::string::npos) - aBufCopy.erase(anInd, 1); - // then store currently dumped string - theDumper.myFullDump << aBufCopy; + // then store the reserved data + theDumper.myDumpStorage->restoreReservedBuffer(); + theDumper.myDumpStorage->mergeBuffer(); // now, store all postponed features theDumper.dumpPostponed(); return theDumper; } + + +void ModelHighAPI_Dumper::exportVariables() const +{ + DocumentPtr aRoot = ModelAPI_Session::get()->moduleDocument(); + EntityNameMap::const_iterator aNameIter = myNames.cbegin(); + for(; aNameIter != myNames.end(); aNameIter++) { + FeaturePtr aFeature = std::dynamic_pointer_cast(aNameIter->first); + if (aFeature.get() && aFeature->document() != aRoot) { + FeaturePtr aPartFeat = ModelAPI_Tools::findPartFeature(aRoot, aFeature->document()); + if (aPartFeat.get()) { + int aFeatureId = aFeature->data()->featureId(); + int aPartId = aPartFeat->data()->featureId(); + std::ostringstream anEntryStr; + anEntryStr<second.myCurrentName); + size_t aSize = aFeature->results().size(); + if (aSize > 1) { // additional entries for features with more than one result + for(size_t a = 1; a < aSize; a++) { + std::ostringstream aResEntryStr; + aResEntryStr<second.myCurrentName); + } + } + } + } + } +}