-// Copyright (C) 2014-2019 CEA/DEN, EDF R&D
+// Copyright (C) 2014-2023 CEA, EDF
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
#include <Config_PropManager.h>
-#include <GeomAPI_Pnt.h>
+#include <GeomAPI_Circ.h>
+#include <GeomAPI_Edge.h>
+#include <GeomAPI_Ellipse.h>
#include <GeomAPI_Dir.h>
+#include <GeomAPI_Pnt.h>
+#include <GeomAPI_Pnt2d.h>
#include <GeomAPI_ShapeExplorer.h>
#include <GeomAPI_ShapeIterator.h>
+#include <GeomAPI_Vertex.h>
#include <GeomAlgoAPI_NExplode.h>
#include <GeomDataAPI_Dir.h>
#include <GeomDataAPI_Point.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <Locale_Convert.h>
#include <ModelAPI_AttributeBoolean.h>
#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeDoubleArray.h>
#include <ModelAPI_AttributeIntArray.h>
#include <ModelAPI_AttributeInteger.h>
#include <ModelAPI_AttributeRefAttr.h>
#include <PartSetPlugin_Part.h>
-#include <OSD_OpenFile.hxx>
-
#include <fstream>
+#include <iomanip>
+#include <cctype>
+#include <cmath>
// =========== Implementation of storage of dumped data ===========
static const int THE_DUMP_PRECISION = 16;
/// Dump std::endl
friend
DumpStorageBuffer& operator<<(DumpStorageBuffer& theBuffer,
- std::basic_ostream<char>& (*theEndl)(std::basic_ostream<char>&))
+ std::basic_ostream<char>& (*)(std::basic_ostream<char>&))
{
theBuffer.write("\n");
return theBuffer;
bool ModelHighAPI_Dumper::DumpStorage::exportTo(const std::string& theFilename,
const ModulesSet& theUsedModules)
{
- std::ofstream aFile;
- OSD_OpenStream(aFile, theFilename.c_str(), std::ofstream::out);
+ std::ofstream aFile(theFilename.c_str(), std::ofstream::out);
if (!aFile.is_open())
return false;
if (aShape.get()) {
myDumpBuffer << "\"" << aShape->shapeTypeStr() << "\", \""
- << theAttrSelect->namingName() << "\"";
+ << Locale::Convert::toString(theAttrSelect->namingName()) << "\"";
}
myDumpBuffer << ")";
std::list<FeaturePtr> 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<FeaturePtr>::iterator aFIt = aFeatures.begin();
+ for (; aFIt != aFeatures.end(); ++aFIt) {
+ ResultPartPtr aPartRes =
+ std::dynamic_pointer_cast<ModelAPI_ResultPart>((*aFIt)->lastResult());
+ if (aPartRes && aPartRes->partDoc() == aDoc2)
+ break;
+ }
+
std::list<FeaturePtr> anAdditionalFeatures = aDoc2->allFeatures();
- aFeatures.insert(aFeatures.end(), anAdditionalFeatures.begin(), anAdditionalFeatures.end());
+ aFeatures.insert(aFIt, anAdditionalFeatures.begin(), anAdditionalFeatures.end());
}
CompositeFeaturePtr aLastCompositeFeature;
std::list<ModelGeomAlgo_Shape::SubshapeOfResult> anApproproate;
if (ModelGeomAlgo_Shape::findSubshapeByPoint(*aFIt, thePoint, theShape->shapeType(),
anApproproate)) {
+ bool isContinue = true;
+ std::list<std::pair<GeomShapePtr, int> > aCenters;
std::list<ModelGeomAlgo_Shape::SubshapeOfResult>::iterator anApIt = anApproproate.begin();
- for (; anApIt != anApproproate.end(); ++anApIt) {
+ for (; anApIt != anApproproate.end() && isContinue; ++anApIt) {
++aNbPossibleSelections;
// stop if the target shape and result are found
if (!aCurShape)
aCurShape = anApIt->myResult->shape();
- if (anApIt->myResult->isSame(theResult) && aCurShape->isSame(theShape))
- break;
+ 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<GeomShapePtr, int>(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;
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 << ")";
+ << Locale::Convert::toString(theAttrSelect->contextName(aContext))
+ << "\", " << anIndex << ")";
aStandardDump = false;
}
}
const std::string& ModelHighAPI_Dumper::name(const EntityPtr& theEntity,
bool theSaveNotDumped,
- bool theUseEntityName)
-{
- EntityNameMap::const_iterator aFound = myNames.find(theEntity);
- if (aFound != myNames.end())
+ bool theUseEntityName,
+ bool theSetIsDumped)
+{
+ EntityNameMap::iterator aFound = myNames.find(theEntity);
+ if (aFound != myNames.end()) {
+ // Set dumped flag for postponed constraints which are without names
+ if (!aFound->second.myIsDumped)
+ aFound->second.myIsDumped = theSetIsDumped;
return aFound->second.myCurrentName;
-
+ }
// entity is not found, store it
- std::string aName, aKind;
+ std::string aName;
+ std::string aKind;
bool isDefaultName = false;
bool isSaveNotDumped = theSaveNotDumped;
std::ostringstream aDefaultName;
FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theEntity);
if (aFeature) {
- aName = aFeature->name();
+ aName = Locale::Convert::toString(aFeature->name());
aKind = aFeature->getKind();
} else {
FolderPtr aFolder = std::dynamic_pointer_cast<ModelAPI_Folder>(theEntity);
if (aFolder) {
- aName = aFolder->data()->name();
+ aName = Locale::Convert::toString(aFolder->data()->name());
aKind = ModelAPI_Folder::ID();
isSaveNotDumped = false;
}
int aFullIndex = 0;
NbFeaturesMap::const_iterator aFIt = myFeatureCount.begin();
for (; aFIt != myFeatureCount.end(); ++aFIt) {
- std::map<std::string, std::pair<int, int> >::const_iterator aFound =
+ std::map<std::string, std::pair<int, int> >::const_iterator aFoundKind =
aFIt->second.find(aKind);
- if (aFound != aFIt->second.end())
- aFullIndex += aFound->second.first;
+ if (aFoundKind != aFIt->second.end())
+ aFullIndex += aFoundKind->second.first;
}
aDefaultName << aKind << "_" << aFullIndex;
}
if (aFeature)
saveResultNames(aFeature);
+ myNames[theEntity].myIsDumped = theSetIsDumped;
+
return myNames[theEntity].myCurrentName;
}
bool isFeatureDefaultName = myNames[theFeature].myIsDefault;
// 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();
+ std::pair<std::wstring, bool> aName = ModelAPI_Tools::getDefaultName(*aRes, true, true);
+ std::string aDefaultName = Locale::Convert::toString(aName.first);
+ std::string aResName = Locale::Convert::toString((*aRes)->data()->name());
bool isUserDefined = !(isFeatureDefaultName && aDefaultName == aResName);
myNames[*aRes] =
EntityName(aResName, (isUserDefined ? aResName : std::string()), !isUserDefined);
// dump subfeatures and store result to file
bool isOk = process(theDoc) && myDumpStorage->exportTo(theFileName, myModules);
- clearCustomStorage();
return isOk;
}
// dump all other features
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;
+ 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<ObjectPtr>::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<ModelAPI_Folder>(*anObjIt);
}
bool ModelHighAPI_Dumper::process(const std::shared_ptr<ModelAPI_CompositeFeature>& theComposite,
- bool isForce)
+ bool isForce, bool isDumpModelDo)
{
// increase composite features stack
++gCompositeStackDepth;
*this << aDocName << " = " << aPartName << ".document()" << std::endl;
// dump features in the document
bool aRes = process(aSubDoc);
- *this << "model.do()" << std::endl;
+ if (isDumpModelDo)
+ *this << "\nmodel.do()\n";
+ *this << std::endl;
return aRes;
}
const FeaturePtr& theSubFeature)
{
name(theSubFeature, false);
- myNames[theSubFeature] = EntityName(theSubFeatureGet, theSubFeature->name(), false);
+ myNames[theSubFeature] =
+ EntityName(theSubFeatureGet, Locale::Convert::toString(theSubFeature->name()), false);
// store results if they have user-defined names or colors
std::list<ResultPtr> aResultsWithNameOrColor;
const std::list<ResultPtr>& aResults = theSubFeature->results();
std::list<ResultPtr>::const_iterator aResIt = aResults.begin();
for (; aResIt != aResults.end(); ++aResIt) {
- std::string aResName = (*aResIt)->data()->name();
+ std::string aResName = Locale::Convert::toString((*aResIt)->data()->name());
myNames[*aResIt] = EntityName(aResName, aResName, false);
aResultsWithNameOrColor.push_back(*aResIt);
}
return true;
}
+size_t ModelHighAPI_Dumper::indexOfFirstNotDumped(
+ const std::shared_ptr<ModelAPI_AttributeRefList>& theRefList) const
+{
+ size_t anIndex = 0;
+ std::list<ObjectPtr> anObjects = theRefList->list();
+ for (std::list<ObjectPtr>::const_iterator anIt = anObjects.begin();
+ anIt != anObjects.end(); ++anIt, ++anIndex)
+ if (!isDumped(ModelAPI_Feature::feature(*anIt)))
+ break;
+ return anIndex;
+}
+
static bool isSketchSub(const FeaturePtr& theFeature)
{
static const std::string SKETCH("Sketch");
return fabs(anAttribute->value()) < 1.e-12;
}
+bool ModelHighAPI_Dumper::dumpCommentBeforeFeature(const FeaturePtr& theFeature) const
+{
+ // currently, the comment should not be dumped only before the filters
+ FiltersFeaturePtr aFilters = std::dynamic_pointer_cast<ModelAPI_FiltersFeature>(theFeature);
+ if (aFilters)
+ return false;
+ // all other features should be commented before the dump
+ return !isDumped(theFeature);
+}
+
ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const char theChar)
{
*myDumpStorage << theChar;
return *this;
}
+ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const std::wstring& theString)
+{
+ *myDumpStorage << Locale::Convert::toString(theString);
+ return *this;
+}
+
ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(const bool theValue)
{
*myDumpStorage << (theValue ? "True" : "False");
{
static const int aSize = 3;
double aValues[aSize] = {thePoint->x(), thePoint->y(), thePoint->z()};
- std::string aTexts[aSize] = {thePoint->textX(), thePoint->textY(), thePoint->textZ()};
+ std::string aTexts[aSize] = {
+ Locale::Convert::toString(thePoint->textX()),
+ Locale::Convert::toString(thePoint->textY()),
+ Locale::Convert::toString(thePoint->textZ())
+ };
myDumpStorage->dumpArray(aSize, aValues, aTexts);
return *this;
}
{
static const int aSize = 2;
double aValues[aSize] = {thePoint->x(), thePoint->y()};
- std::string aTexts[aSize] = {thePoint->textX(), thePoint->textY()};
+ std::string aTexts[aSize] = {
+ Locale::Convert::toString(thePoint->textX()),
+ Locale::Convert::toString(thePoint->textY())
+ };
myDumpStorage->dumpArray(aSize, aValues, aTexts);
return *this;
}
+ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
+ const std::shared_ptr<GeomDataAPI_Point2DArray>& 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<ModelAPI_AttributeBoolean>& theAttrBool)
{
ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
const std::shared_ptr<ModelAPI_AttributeInteger>& theAttrInt)
{
- std::string aText = theAttrInt->text();
+ std::string aText = Locale::Convert::toString(theAttrInt->text());
if (aText.empty())
*myDumpStorage << theAttrInt->value();
else
return *this;
}
+ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
+ const std::shared_ptr<ModelAPI_AttributeIntArray>& 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<ModelAPI_AttributeDouble>& theAttrReal)
{
- std::string aText = theAttrReal->text();
+ std::string aText = Locale::Convert::toString(theAttrReal->text());
if (aText.empty())
*myDumpStorage << theAttrReal->value();
else
return *this;
}
+ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<(
+ const std::shared_ptr<ModelAPI_AttributeDoubleArray>& 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<ModelAPI_AttributeString>& theAttrStr)
{
- *myDumpStorage << "\"" << theAttrStr->value() << "\"";
+ // escaping the quote signs in the string under dumping
+ std::string aStr = theAttrStr->value();
+ /*
+ size_t aPos = aStr.find("\"");
+ while (aPos != std::string::npos) {
+ aStr.insert(aPos, "\\");
+ aPos = aStr.find("\"", aPos + 2);
+ }
+ aPos = aStr.find("\'");
+ while (aPos != std::string::npos) {
+ aStr.insert(aPos, "\\");
+ aPos = aStr.find("\'", aPos + 2);
+ }
+ */
+ size_t aPos = aStr.find_first_of("\"\'");
+ while (aPos != std::string::npos) {
+ aStr.insert(aPos, "\\");
+ aPos = aStr.find_first_of("\"\'", aPos + 2);
+ }
+ *myDumpStorage << "'" << aStr << "'";
return *this;
}
// 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");
bool isAdded = false;
std::list<ObjectPtr>::const_iterator anIt = aList.begin();
for (; anIt != aList.end(); ++anIt) {
+ if (!(*anIt))
+ continue;
+ if (!isDumped(ModelAPI_Feature::feature(*anIt)))
+ break; // stop if the object is not dumped yet (parent feature should be postponed)
+
if (isAdded)
*myDumpStorage << ", ";
else
const std::shared_ptr<ModelAPI_AttributeSelectionList>& theAttrSelList)
{
static const int aThreshold = 2;
- static bool aDumpAsIs = false;
+ static int aNbSpaces = 0;
// 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) {
+ if (aNbSpaces > 0 || theAttrSelList->size() <= aThreshold) {
*myDumpStorage << "[";
GeomShapePtr aShape;
}
if(isAdded) {
- *myDumpStorage << ", ";
+ // print each attribute on separate line with the appropriate shift
+ if (aNbSpaces > 0) {
+ std::string aSpaces(aNbSpaces + 1, ' ');
+ *myDumpStorage << ",\n" << aSpaces;
+ } else
+ *myDumpStorage << ", ";
} else {
isAdded = true;
}
}
// reserve dumped buffer and store list "as is"
myDumpStorage->reserveBuffer();
- aDumpAsIs = true;
+ aNbSpaces = (int)aListName.size() + 3;
*this << aListName << " = " << theAttrSelList << "\n";
- aDumpAsIs = false;
+ aNbSpaces = 0;
// append reserved data to the end of the current buffer
myDumpStorage->restoreReservedBuffer();
*myDumpStorage << aListName;
return *this;
}
+void ModelHighAPI_Dumper::newline()
+{
+ *this << std::endl;
+}
+
/// Dump std::endl
ModelHighAPI_Dumper& operator<<(ModelHighAPI_Dumper& theDumper,
std::basic_ostream<char>& (*theEndl)(std::basic_ostream<char>&))
// store all not-dumped entities first
std::set<EntityPtr> aNotDumped = theDumper.myNotDumpedEntities;
+ theDumper.clearNotDumped();
theDumper.myDumpStorage->reserveBuffer();
std::set<EntityPtr>::const_iterator anIt = aNotDumped.begin();
for (; anIt != aNotDumped.end(); ++anIt) {
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<ModelAPI_Feature>(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<<aPartId<<":"<<aFeatureId;
+ std::string anEntry = anEntryStr.str();
+ exportVariable(anEntry, aNameIter->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<<anEntry<<":"<<a;
+ std::string aResEntry = aResEntryStr.str();
+ exportVariable(aResEntry, aNameIter->second.myCurrentName);
+ }
+ }
+ }
+ }
+ }
+}