X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FModelAPI%2FModelAPI_Tools.cpp;h=84c5de685d83c7cbd6a5c7ba02dbd1f12639865b;hb=9270adddc12db9661c676544537b0e8eb78c1624;hp=074b903d55cc28d42615493e3d6633772fb19201;hpb=c4eab94a20a0d93100549a210582d46409fec1cc;p=modules%2Fshaper.git diff --git a/src/ModelAPI/ModelAPI_Tools.cpp b/src/ModelAPI/ModelAPI_Tools.cpp index 074b903d5..84c5de685 100644 --- a/src/ModelAPI/ModelAPI_Tools.cpp +++ b/src/ModelAPI/ModelAPI_Tools.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2019 CEA/DEN, EDF R&D +// Copyright (C) 2014-2022 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 @@ -17,24 +17,41 @@ // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // -#include "ModelAPI_Tools.h" -#include +#include +#include +#include +#include +#include +#include #include #include +#include #include -#include #include +#include +#include #include #include -#include +#include +#include "ModelAPI_Tools.h" #include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include #include #include -#include #include - -#include -#include +#include +#include #define RECURSE_TOP_LEVEL 50 @@ -106,6 +123,7 @@ std::shared_ptr shape(const ResultPtr& theResult) return theResult->shape(); } +// LCOV_EXCL_START const char* toString(ModelAPI_ExecState theExecState) { switch (theExecState) { @@ -118,7 +136,6 @@ const char* toString(ModelAPI_ExecState theExecState) } } -// LCOV_EXCL_START std::string getFeatureError(const FeaturePtr& theFeature) { std::string anError; @@ -144,14 +161,24 @@ std::string getFeatureError(const FeaturePtr& theFeature) CompositeFeaturePtr aComposite = std::dynamic_pointer_cast(theFeature); if (aComposite) { + bool aHasSubError = false; for (int i = 0, aSize = aComposite->numberOfSubs(); i < aSize; i++) { FeaturePtr aSubFeature = aComposite->subFeature(i); std::string aSubFeatureError = getFeatureError(aSubFeature); if (!aSubFeatureError.empty()) { anError = anError + " in " + aSubFeature->getKind() + ".\n" + aSubFeatureError; + aHasSubError = true; break; } } + if (!aHasSubError) { // #24260: error not in the sub-features, but in the argument + if (aComposite->getKind() == "Sketch" && + aComposite->selection("External")->isInvalid()) { + std::string aMsg = "The sketch base plane is invalid, "; + aMsg += "please push 'Change sketch plane' button to reselect it."; + anError = Config_Translator::translate(aComposite->getKind(), aMsg); + } + } } } } @@ -162,7 +189,7 @@ std::string getFeatureError(const FeaturePtr& theFeature) // LCOV_EXCL_STOP ObjectPtr objectByName(const DocumentPtr& theDocument, const std::string& theGroup, - const std::string& theName) + const std::wstring& theName) { for (int anIndex = 0; anIndex < theDocument->size(theGroup); ++anIndex) { ObjectPtr anObject = theDocument->object(theGroup, anIndex); @@ -173,8 +200,127 @@ ObjectPtr objectByName(const DocumentPtr& theDocument, const std::string& theGro return ObjectPtr(); } +//================================================================================================== +void loadModifiedShapes(ResultBodyPtr theResultBody, + const ListOfShape& theBaseShapes, + const ListOfShape& theTools, + const GeomMakeShapePtr& theMakeShape, + const GeomShapePtr theResultShape, + const std::string& theNamePrefix) +{ + theResultBody->storeModified(theBaseShapes, theResultShape, theMakeShape); + + ListOfShape aShapes = theBaseShapes; + ListOfShape::const_iterator aToolIter = theTools.cbegin(); + for (; aToolIter != theTools.cend(); aToolIter++) + aShapes.push_back(*aToolIter); + + for (ListOfShape::const_iterator anIter = aShapes.begin(); anIter != aShapes.end(); ++anIter) + { + theResultBody->loadModifiedShapes(theMakeShape, *anIter, GeomAPI_Shape::VERTEX, theNamePrefix); + theResultBody->loadModifiedShapes(theMakeShape, *anIter, GeomAPI_Shape::EDGE, theNamePrefix); + theResultBody->loadModifiedShapes(theMakeShape, *anIter, GeomAPI_Shape::FACE, theNamePrefix); + } +} + +//================================================================================================== +void loadModifiedShapes(ResultBodyPtr theResultBody, + const GeomShapePtr& theBaseShape, + const GeomMakeShapePtr& theMakeShape, + const std::string theName) +{ + switch (theBaseShape->shapeType()) { + case GeomAPI_Shape::COMPOUND: { + for (GeomAPI_ShapeIterator anIt(theBaseShape); anIt.more(); anIt.next()) + { + loadModifiedShapes(theResultBody, + anIt.current(), + theMakeShape, + theName); + } + break; + } + case GeomAPI_Shape::COMPSOLID: + case GeomAPI_Shape::SOLID: + case GeomAPI_Shape::SHELL: { + theResultBody->loadModifiedShapes(theMakeShape, + theBaseShape, + GeomAPI_Shape::FACE, + theName); + } + case GeomAPI_Shape::FACE: + case GeomAPI_Shape::WIRE: { + theResultBody->loadModifiedShapes(theMakeShape, + theBaseShape, + GeomAPI_Shape::EDGE, + theName); + } + case GeomAPI_Shape::EDGE: { + theResultBody->loadModifiedShapes(theMakeShape, + theBaseShape, + GeomAPI_Shape::VERTEX, + theName); + } + default: // [to avoid compilation warning] + break; + } +} + +//================================================================================================== +void loadDeletedShapes(ResultBodyPtr theResultBody, + const GeomShapePtr theBaseShape, + const ListOfShape& theTools, + const GeomMakeShapePtr& theMakeShape, + const GeomShapePtr theResultShapesCompound) +{ + ListOfShape aShapes = theTools; + if (theBaseShape.get()) + aShapes.push_front(theBaseShape); + + for (ListOfShape::const_iterator anIter = aShapes.begin(); anIter != aShapes.end(); anIter++) + { + theResultBody->loadDeletedShapes(theMakeShape, + *anIter, + GeomAPI_Shape::VERTEX, + theResultShapesCompound); + theResultBody->loadDeletedShapes(theMakeShape, + *anIter, + GeomAPI_Shape::EDGE, + theResultShapesCompound); + theResultBody->loadDeletedShapes(theMakeShape, + *anIter, + GeomAPI_Shape::FACE, + theResultShapesCompound); + // store information about deleted solids because of unittest TestBooleanCommon_SolidsHistory + // on OCCT 7.4.0 : common produces modified compsolid, so, move to the end for removed solids + // starts to produce whole compsolid + theResultBody->loadDeletedShapes(theMakeShape, + *anIter, + GeomAPI_Shape::SOLID, + theResultShapesCompound); + } +} + +//================================================================================================== +void loadDeletedShapes(std::vector& theResultBaseAlgoList, + const ListOfShape& theTools, + const GeomShapePtr theResultShapesCompound) +{ + for (std::vector::iterator anIt = theResultBaseAlgoList.begin(); + anIt != theResultBaseAlgoList.end(); + ++anIt) + { + ResultBaseAlgo& aRCA = *anIt; + loadDeletedShapes(aRCA.resultBody, + aRCA.baseShape, + theTools, + aRCA.makeShape, + theResultShapesCompound); + } +} + bool findVariable(const DocumentPtr& theDocument, FeaturePtr theSearcher, - const std::string& theName, double& outValue, ResultParameterPtr& theParam) + const std::wstring& theName, double& outValue, ResultParameterPtr& theParam) { ObjectPtr aParamObj = objectByName(theDocument, ModelAPI_ResultParameter::group(), theName); theParam = std::dynamic_pointer_cast(aParamObj); @@ -192,7 +338,7 @@ bool findVariable(const DocumentPtr& theDocument, FeaturePtr theSearcher, return true; } -bool findVariable(FeaturePtr theSearcher, const std::string& theName, double& outValue, +bool findVariable(FeaturePtr theSearcher, const std::wstring& theName, double& outValue, ResultParameterPtr& theParam, const DocumentPtr& theDocument) { SessionPtr aSession = ModelAPI_Session::get(); @@ -209,6 +355,95 @@ bool findVariable(FeaturePtr theSearcher, const std::string& theName, double& ou return false; } +static void cacheSubresults(const ResultBodyPtr& theTopLevelResult, + std::set& theCashedResults) +{ + std::list aResults; + ModelAPI_Tools::allSubs(theTopLevelResult, aResults, false); + for (std::list::iterator aR = aResults.begin(); aR != aResults.end(); ++aR) { + theCashedResults.insert(*aR); + } +} + +bool isInResults(AttributeSelectionListPtr theSelection, + const std::list& theResults, + std::set& theCashedResults) +{ + // collect all results into a cashed set + if (theCashedResults.empty()) { + std::list::const_iterator aRes = theResults.cbegin(); + for(; aRes != theResults.cend(); aRes++) { + if (theCashedResults.count(*aRes)) + continue; + else + theCashedResults.insert(*aRes); + + if ((*aRes)->groupName() == ModelAPI_ResultBody::group()) { + ResultBodyPtr aResBody = std::dynamic_pointer_cast(*aRes); + cacheSubresults(aResBody, theCashedResults); + } else if ((*aRes)->groupName() == ModelAPI_ResultPart::group()) { // all results of the part + ResultPartPtr aResPart = std::dynamic_pointer_cast(*aRes); + DocumentPtr aPartDoc = aResPart->partDoc(); + if (!aPartDoc.get() || !aPartDoc->isOpened()) { // document is not accessible + return false; + } + int aBodyCount = aPartDoc->size(ModelAPI_ResultBody::group()); + for (int aBodyIndex = 0; aBodyIndex < aBodyCount; ++aBodyIndex) { + ResultBodyPtr aResBody = + std::dynamic_pointer_cast( + aPartDoc->object(ModelAPI_ResultBody::group(), aBodyIndex)); + if (aResBody.get()) { + theCashedResults.insert(aResBody); + cacheSubresults(aResBody, theCashedResults); + } + } + } + } + } + // if context is in results, return true + for(int a = 0; a < theSelection->size(); a++) { + AttributeSelectionPtr anAttr = theSelection->value(a); + ResultPtr aContext = anAttr->context(); + // check is it group selected for groups BOP + if (aContext.get() && aContext->groupName() == ModelAPI_ResultGroup::group()) { + // it is impossible by used results check which result is used in this group result, + // so check the results shapes is it in results of this document or not + FeaturePtr aSelFeature = + std::dynamic_pointer_cast(theSelection->owner()); + if (!aSelFeature.get() || aSelFeature->results().empty()) + continue; + GeomShapePtr aGroupResShape = aSelFeature->firstResult()->shape(); + + std::set::iterator allResultsIter = theCashedResults.begin(); + for(; allResultsIter != theCashedResults.end(); allResultsIter++) { + GeomShapePtr aResultShape = (*allResultsIter)->shape(); + + GeomAPI_Shape::ShapeType aType = + GeomAPI_Shape::shapeTypeByStr(theSelection->selectionType()); + GeomAPI_ShapeExplorer aGroupResExp(aGroupResShape, aType); + for(; aGroupResExp.more(); aGroupResExp.next()) { + if (aResultShape->isSubShape(aGroupResExp.current(), false)) + return true; // at least one shape of the group is in the used results + } + } + } + ResultBodyPtr aSelected = std::dynamic_pointer_cast(anAttr->context()); + if (!aSelected.get()) { // try to get selected feature and all its results + FeaturePtr aContextFeature = anAttr->contextFeature(); + if (aContextFeature.get() && !aContextFeature->results().empty()) { + const std::list& allResluts = aContextFeature->results(); + std::list::const_iterator aResIter = allResluts.cbegin(); + for(; aResIter != allResluts.cend(); aResIter++) { + if (aResIter->get() && theCashedResults.count(*aResIter)) + return true; + } + } + } else if (aSelected.get() && theCashedResults.count(aSelected)) + return true; + } + return false; +} + ResultPtr findPartResult(const DocumentPtr& theMain, const DocumentPtr& theSub) { // to optimize and avoid of crash on partset document close @@ -301,14 +536,16 @@ bool hasSubResults(const ResultPtr& theResult) return aCompSolid.get() && aCompSolid->numberOfSubs() > 0; } -void allSubs(const ResultBodyPtr& theResult, std::list& theResults) { +void allSubs(const ResultBodyPtr& theResult, std::list& theResults, + const bool theLowerOnly) { // iterate sub-bodies of compsolid ResultBodyPtr aComp = std::dynamic_pointer_cast(theResult); if (aComp.get()) { int aNumSub = aComp->numberOfSubs(); for (int a = 0; a < aNumSub; a++) { ResultBodyPtr aSub = aComp->subResult(a); - theResults.push_back(aSub); + if (!theLowerOnly || aSub->numberOfSubs() == 0) + theResults.push_back(aSub); allSubs(aSub, theResults); } } @@ -328,9 +565,9 @@ void allResults(const FeaturePtr& theFeature, std::list& theResults) } //****************************************************************** -bool allDocumentsActivated(std::string& theNotActivatedNames) +bool allDocumentsActivated(std::wstring& theNotActivatedNames) { - theNotActivatedNames = ""; + theNotActivatedNames = L""; bool anAllPartActivated = true; DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument(); @@ -341,7 +578,7 @@ bool allDocumentsActivated(std::string& theNotActivatedNames) if (!aPart->isActivated()) { anAllPartActivated = false; if (!theNotActivatedNames.empty()) - theNotActivatedNames += ", "; + theNotActivatedNames += L", "; theNotActivatedNames += aObject->data()->name().c_str(); } } @@ -349,7 +586,7 @@ bool allDocumentsActivated(std::string& theNotActivatedNames) } bool removeFeaturesAndReferences(const std::set& theFeatures, - const bool theFlushRedisplay, + const bool /*theFlushRedisplay*/, const bool theUseComposite, const bool theUseRecursion) { @@ -459,10 +696,10 @@ void findReferences(const std::set& theFeatures, } else { // filter references to skip composition features of the current feature std::set aFilteredFeatures; - std::set::const_iterator anIt = aSelRefFeatures.begin(), - aLast = aSelRefFeatures.end(); - for (; anIt != aLast; anIt++) { - FeaturePtr aCFeature = *anIt; + std::set::const_iterator aRefIt = aSelRefFeatures.begin(), + aRefLast = aSelRefFeatures.end(); + for (; aRefIt != aRefLast; aRefIt++) { + FeaturePtr aCFeature = *aRefIt; CompositeFeaturePtr aComposite = std::dynamic_pointer_cast(aCFeature); if (aComposite.get() && aComposite->isSub(aFeature)) @@ -533,7 +770,7 @@ void findAllReferences(const std::set& theFeatures, aResultRefList.insert(aMainRefList.begin(), aMainRefList.end()); for (; anIt != aLast; anIt++) { FeaturePtr aFeature = *anIt; - int aRecLevel = 0; + aRecLevel = 0; #ifdef DEBUG_REMOVE_FEATURES_RECURSE std::cout << " Ref: " << getFeatureInfo(aFeature) << std::endl; #endif @@ -605,8 +842,9 @@ void getConcealedResults(const FeaturePtr& theFeature, } } -std::pair getDefaultName(const std::shared_ptr& theResult, - const bool theInherited) +std::pair getDefaultName(const std::shared_ptr& theResult, + const bool theInherited, + const bool theRecursive) { typedef std::list< std::pair < std::string, std::list > > ListOfReferences; @@ -617,10 +855,10 @@ std::pair getDefaultName(const std::shared_ptr(aDefaultName.str(), false); + return std::pair(aDefaultName.str(), false); } FeaturePtr anOwner = ModelAPI_Feature::feature(theResult->data()->owner()); @@ -641,6 +879,7 @@ std::pair getDefaultName(const std::shared_ptrsecond.size() > 1 || (aRefIt->second.size() == 1 && + aRefIt->second.front().get() && aRefIt->second.front()->groupName() == ModelAPI_ResultBody::group()); if (isBody && (isMainArg || aFoundRef == aReferences.end() || aData->isPrecedingAttribute(aRefIt->first, aFoundRef->first))) @@ -685,7 +924,7 @@ std::pair getDefaultName(const std::shared_ptrgroupName() == ModelAPI_ResultBody::group()) { + if (anObjIt->get() && (*anObjIt)->groupName() == ModelAPI_ResultBody::group()) { // check the result is part of CompSolid ResultPtr anObjRes = std::dynamic_pointer_cast(*anObjIt); ResultBodyPtr aParentBody = ModelAPI_Tools::bodyOwner(anObjRes); @@ -694,8 +933,9 @@ std::pair getDefaultName(const std::shared_ptrdata()->hasUserDefinedName()) { - std::stringstream aName; + if (anObjRes->data()->hasUserDefinedName() || + (theRecursive && anObjRes->data()->name() != getDefaultName(anObjRes).first)) { + std::wstringstream aName; aName << anObjRes->data()->name(); std::map::iterator aFound = aNbRefToObject.find(anObjRes); if (aFound != aNbRefToObject.end()) { @@ -703,19 +943,19 @@ std::pair getDefaultName(const std::shared_ptrsecond + 1; } - return std::pair(aName.str(), true); + return std::pair(aName.str(), true); } } } // compose default name by the name of the feature and the index of result - std::stringstream aDefaultName; + std::wstringstream aDefaultName; aDefaultName << anOwner->name(); // if there are several results (issue #899: any number of result), // add unique prefix starting from second if (anIndexInOwner > 0 || theResult->groupName() == ModelAPI_ResultBody::group()) aDefaultName << "_" << anIndexInOwner + 1; - return std::pair(aDefaultName.str(), false); + return std::pair(aDefaultName.str(), false); } std::set getParents(const FeaturePtr& theFeature) @@ -758,4 +998,595 @@ std::set getParents(const FeaturePtr& theFeature) return aParents; } +void fillShapeHierarchy(const GeomShapePtr& theShape, + const ResultPtr& theContext, + GeomAPI_ShapeHierarchy& theHierarchy) +{ + ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(theContext); + if (aResCompSolidPtr.get()) { + std::shared_ptr aContextShape = aResCompSolidPtr->shape(); + if (aContextShape->shapeType() <= GeomAPI_Shape::COMPSOLID) { + theHierarchy.addParent(theShape, aContextShape); + fillShapeHierarchy(aContextShape, aResCompSolidPtr, theHierarchy); + } + } +} + + +void removeResults(const std::list& theResults) +{ + // collect all documents where the results must be removed + std::map > aDocs; + + std::list::const_iterator aResIter = theResults.cbegin(); + for(; aResIter != theResults.cend(); aResIter++) { + DocumentPtr aDoc = (*aResIter)->document(); + if (!aDocs.count(aDoc)) + aDocs[aDoc] = std::list(); + aDocs[aDoc].push_back(*aResIter); + } + // create a "remove" feature in each doc + std::map >::iterator aDoc = aDocs.begin(); + for(; aDoc != aDocs.end(); aDoc++) { + FeaturePtr aRemove = aDoc->first->addFeature("RemoveResults"); + if (aRemove) { + for(aResIter = aDoc->second.cbegin(); aResIter != aDoc->second.cend(); aResIter++) + aRemove->selectionList("results")->append(*aResIter, GeomShapePtr()); + } + } +} + +// used by GUI only +// LCOV_EXCL_START + +//************************************************************** +void setDeflection(ResultPtr theResult, const double theDeflection) +{ + if (!theResult.get()) + return; + + AttributeDoublePtr aDeflectionAttr = theResult->data()->real(ModelAPI_Result::DEFLECTION_ID()); + if (aDeflectionAttr.get() != NULL) { + aDeflectionAttr->setValue(theDeflection); + } +} + +double getDeflection(const std::shared_ptr& theResult) +{ + double aDeflection = -1; + // get deflection from the attribute of the result + if (theResult.get() != NULL && + theResult->data()->attribute(ModelAPI_Result::DEFLECTION_ID()).get() != NULL) { + AttributeDoublePtr aDoubleAttr = theResult->data()->real(ModelAPI_Result::DEFLECTION_ID()); + if (aDoubleAttr.get() && aDoubleAttr->isInitialized()) { + double aValue = aDoubleAttr->value(); + if (aValue > 0) /// zero value should not be used as a deflection(previous studies) + aDeflection = aDoubleAttr->value(); + } + } + return aDeflection; +} + +//****************************************************** +void setColor(ResultPtr theResult, const std::vector& theColor) +{ + if (!theResult.get()) + return; + + AttributeIntArrayPtr aColorAttr = theResult->data()->intArray(ModelAPI_Result::COLOR_ID()); + if (aColorAttr.get() != NULL) { + if (!aColorAttr->size()) { + aColorAttr->setSize(3); + } + aColorAttr->setValue(0, theColor[0]); + aColorAttr->setValue(1, theColor[1]); + aColorAttr->setValue(2, theColor[2]); + } +} + +void getColor(const std::shared_ptr& theResult, std::vector& theColor) +{ + theColor.clear(); + // get color from the attribute of the result + if (theResult.get() != NULL && + theResult->data()->attribute(ModelAPI_Result::COLOR_ID()).get() != NULL) { + AttributeIntArrayPtr aColorAttr = theResult->data()->intArray(ModelAPI_Result::COLOR_ID()); + if (aColorAttr.get() && aColorAttr->size()) { + theColor.push_back(aColorAttr->value(0)); + theColor.push_back(aColorAttr->value(1)); + theColor.push_back(aColorAttr->value(2)); + } + } +} + +//****************************************************** +void getIsoLines(const std::shared_ptr& theResult, + bool& isVisible, std::vector& theNbLines) +{ + theNbLines.clear(); + isVisible = false; + if (!theResult.get()) + return; + if (theResult->groupName() == ModelAPI_ResultConstruction::group()) { + theNbLines.push_back(0); + theNbLines.push_back(0); + } + else { + // get color from the attribute of the result + AttributeIntArrayPtr aAttr = theResult->data()->intArray(ModelAPI_Result::ISO_LINES_ID()); + if (aAttr.get()) { + if (aAttr->size()) { + theNbLines.push_back(aAttr->value(0)); + theNbLines.push_back(aAttr->value(1)); + } + } + AttributeBooleanPtr aBoolAttr = + theResult->data()->boolean(ModelAPI_Result::SHOW_ISO_LINES_ID()); + if (aBoolAttr.get()) { + isVisible = aBoolAttr->value(); + } + } +} + +//****************************************************** +void setIsoLines(ResultPtr theResult, const std::vector& theIso) +{ + if (!theResult.get()) + return; + + AttributeIntArrayPtr aAttr = theResult->data()->intArray(ModelAPI_Result::ISO_LINES_ID()); + if (aAttr.get() != NULL) { + if (!aAttr->size()) { + aAttr->setSize(2); + } + aAttr->setValue(0, theIso[0]); + aAttr->setValue(1, theIso[1]); + } +} + +//****************************************************** +void showIsoLines(std::shared_ptr theResult, bool theShow) +{ + if (!theResult.get()) + return; + + AttributeBooleanPtr aAttr = theResult->data()->boolean(ModelAPI_Result::SHOW_ISO_LINES_ID()); + if (aAttr.get() != NULL) { + aAttr->setValue(theShow); + } +} + +//****************************************************** +bool isShownIsoLines(std::shared_ptr theResult) +{ + if (!theResult.get()) + return false; + + AttributeBooleanPtr aAttr = theResult->data()->boolean(ModelAPI_Result::SHOW_ISO_LINES_ID()); + if (aAttr.get() != NULL) { + return aAttr->value(); + } + return false; +} + +//****************************************************** +void showEdgesDirection(std::shared_ptr theResult, bool theShow) +{ + if (!theResult.get()) + return; + + AttributeBooleanPtr aAttr = theResult->data()->boolean(ModelAPI_Result::SHOW_EDGES_DIRECTION_ID()); + if (aAttr.get() != NULL) { + aAttr->setValue(theShow); + } +} + +//****************************************************** +bool isShowEdgesDirection(std::shared_ptr theResult) +{ + if (!theResult.get()) + return false; + + AttributeBooleanPtr aAttr = theResult->data()->boolean(ModelAPI_Result::SHOW_EDGES_DIRECTION_ID()); + if (aAttr.get() != NULL) { + return aAttr->value(); + } + return false; +} + +//************************************************************** +void setTransparency(ResultPtr theResult, double theTransparency) +{ + if (!theResult.get()) + return; + + AttributeDoublePtr anAttribute = theResult->data()->real(ModelAPI_Result::TRANSPARENCY_ID()); + if (anAttribute.get() != NULL) { + anAttribute->setValue(theTransparency); + } +} + +double getTransparency(const std::shared_ptr& theResult) +{ + double aTransparency = -1; + // get transparency from the attribute of the result + if (theResult.get() != NULL && + theResult->data()->attribute(ModelAPI_Result::TRANSPARENCY_ID()).get() != NULL) { + AttributeDoublePtr aDoubleAttr = theResult->data()->real(ModelAPI_Result::TRANSPARENCY_ID()); + if (aDoubleAttr.get() && aDoubleAttr->isInitialized()) { + aTransparency = aDoubleAttr->value(); + } + } + return aTransparency; +} + +void copyVisualizationAttrs( + std::shared_ptr theSource, std::shared_ptr theDest) +{ + // color + AttributeIntArrayPtr aSourceColor = theSource->data()->intArray(ModelAPI_Result::COLOR_ID()); + if (aSourceColor.get() && aSourceColor->isInitialized() && aSourceColor->size()) { + AttributeIntArrayPtr aDestColor = theDest->data()->intArray(ModelAPI_Result::COLOR_ID()); + if (aDestColor.get()) { + aDestColor->setSize(aSourceColor->size()); + for(int a = 0; a < aSourceColor->size(); a++) + aDestColor->setValue(a, aSourceColor->value(a)); + } + } + // Iso-lines + AttributeIntArrayPtr aSource = theSource->data()->intArray(ModelAPI_Result::ISO_LINES_ID()); + if (aSource.get() && aSource->isInitialized() && aSource->size()) { + AttributeIntArrayPtr aDest = theDest->data()->intArray(ModelAPI_Result::ISO_LINES_ID()); + if (aDest.get()) { + aDest->setSize(aSource->size()); + for(int a = 0; a < aSource->size(); a++) + aDest->setValue(a, aSource->value(a)); + } + } + // deflection + AttributeDoublePtr aSourceDefl = theSource->data()->real(ModelAPI_Result::DEFLECTION_ID()); + if (aSourceDefl.get() && aSourceDefl->isInitialized()) { + AttributeDoublePtr aDestDefl = theDest->data()->real(ModelAPI_Result::DEFLECTION_ID()); + if (aDestDefl.get()) { + aDestDefl->setValue(aSourceDefl->value()); + } + } + // transparency + AttributeDoublePtr aSourceTransp = theSource->data()->real(ModelAPI_Result::TRANSPARENCY_ID()); + if (aSourceTransp.get() && aSourceTransp->isInitialized()) { + AttributeDoublePtr aDestTransp = theDest->data()->real(ModelAPI_Result::TRANSPARENCY_ID()); + if (aDestTransp.get()) { + aDestTransp->setValue(aSourceTransp->value()); + } + } +} + + +void copyImageAttribute (std::shared_ptr theSource, + std::shared_ptr theDest) +{ + if (!theSource.get() || !theDest.get()) + return; + + // images allowed only for ResultBody + ResultBodyPtr aSourceBody = std::dynamic_pointer_cast(theSource); + ResultBodyPtr aDestBody = std::dynamic_pointer_cast(theDest); + if (!aSourceBody.get() || !aDestBody.get()) + return; + + AttributeImagePtr aSourceImage = + theSource->data()->image(ModelAPI_ResultBody::IMAGE_ID()); + if (aSourceImage.get() && aSourceImage->hasTexture()) { + AttributeImagePtr aDestImage = + theDest->data()->image(ModelAPI_ResultBody::IMAGE_ID()); + if (aDestImage.get()) { + aSourceImage->copyTo(aDestImage); + } + } +} + +std::list referencedFeatures( + std::shared_ptr theTarget, const std::string& theFeatureKind, + const bool theSortResults) +{ + std::set aResSet; // collect in the set initially to avoid duplicates + std::list allSubRes; + allSubRes.push_back(theTarget); + ResultBodyPtr aBody = std::dynamic_pointer_cast(theTarget); + if (aBody.get()) + allSubs(aBody, allSubRes); + std::list::iterator aSub = allSubRes.begin(); + for(; aSub != allSubRes.end(); aSub++) { + const std::set& aRefs = (*aSub)->data()->refsToMe(); + std::set::const_iterator aRef = aRefs.cbegin(); + for(; aRef != aRefs.cend(); aRef++) { + FeaturePtr aFeat = std::dynamic_pointer_cast((*aRef)->owner()); + if (aFeat.get() && (theFeatureKind.empty() || aFeat->getKind() == theFeatureKind)) + aResSet.insert(aFeat); + } + } + // add also feature of the target that may be referenced as a whole + FeaturePtr aTargetFeature = theTarget->document()->feature(theTarget); + const std::set& aRefs = aTargetFeature->data()->refsToMe(); + std::set::const_iterator aRef = aRefs.cbegin(); + for(; aRef != aRefs.cend(); aRef++) { + FeaturePtr aFeat = std::dynamic_pointer_cast((*aRef)->owner()); + if (aFeat.get() && (theFeatureKind.empty() || aFeat->getKind() == theFeatureKind)) + aResSet.insert(aFeat); + } + // check also Group-operations that may refer to groups - add them for theFeatureKind "Group" + if (theFeatureKind == "Group") { + std::set aGroupOperations; + for(bool aNeedIterate = true; aNeedIterate; ) { + std::set::iterator aResIter = aResSet.begin(); + for(; aResIter != aResSet.end(); aResIter++) { + std::list::const_iterator aGroupRes = (*aResIter)->results().cbegin(); + for(; aGroupRes != (*aResIter)->results().cend(); aGroupRes++) { + const std::set& aGroupRefs = (*aGroupRes)->data()->refsToMe(); + std::set::const_iterator aRefIt = aGroupRefs.cbegin(); + for(; aRefIt != aGroupRefs.cend(); aRefIt++) { + FeaturePtr aFeat = std::dynamic_pointer_cast((*aRefIt)->owner()); + if (aFeat.get() && !aGroupOperations.count(aFeat) && !aFeat->results().empty() && + aFeat->firstResult()->groupName() == ModelAPI_ResultGroup::group()) { + // iterate results of this group operation because it may be without theTarget shape + GeomShapePtr aTargetShape = theTarget->shape(); + bool anIsIn = false; + std::list::const_iterator anOpRes = aFeat->results().cbegin(); + for(; anOpRes != aFeat->results().cend() && !anIsIn; anOpRes++) { + GeomShapePtr anOpShape = (*anOpRes)->shape(); + if (!anOpShape.get() || anOpShape->isNull()) + continue; + for(GeomAPI_ShapeIterator aSubIt(anOpShape); aSubIt.more(); aSubIt.next()) { + if (aTargetShape->isSubShape(aSubIt.current(), false)) { + anIsIn = true; + break; + } + } + } + if (anIsIn) + aGroupOperations.insert(aFeat); + } + } + } + } + // insert all new group operations into result and if they are, check for next dependencies + aNeedIterate = false; + std::set::iterator aGroupOpIter = aGroupOperations.begin(); + for(; aGroupOpIter != aGroupOperations.end(); aGroupOpIter++) { + if (aResSet.find(*aGroupOpIter) == aResSet.end()) { + aResSet.insert(*aGroupOpIter); + aNeedIterate = true; + } + } + } + } + + std::list aResList; + std::set::iterator aResIter = aResSet.begin(); + for(; aResIter != aResSet.end(); aResIter++) { + if (theSortResults) { // sort results by creation-order + std::list::iterator aListIter = aResList.begin(); + for(; aListIter != aResList.end(); aListIter++) { + if ((*aResIter)->document()->isLater(*aListIter, *aResIter)) + break; + } + if (aListIter == aResList.end()) // goes to the end + aResList.push_back(*aResIter); + else + aResList.insert(aListIter, *aResIter); + } else //just push to the end unsorted + aResList.push_back(*aResIter); + } + return aResList; +} + +void setValues(std::vector& theRGB, const int theRed, const int theGreen, const int theBlue) +{ + theRGB.push_back(theRed); + theRGB.push_back(theGreen); + theRGB.push_back(theBlue); +} + +std::vector HSVtoRGB(int theH, int theS, int theV) +{ + std::vector aRGB; + if (theH < 0 || theH > 360 || + theS < 0 || theS > 100 || + theV < 0 || theV > 100) + return aRGB; + + int aHi = (int)theH/60; + double aV = theV; + double aVmin = (100 - theS)*theV/100; + double anA = (theV - aVmin)* (theH % 60) / 60; + double aVinc = aVmin + anA; + double aVdec = theV - anA; + double aPercentToValue = 255./100; + int aV_int = (int)(aV*aPercentToValue); + int aVinc_int = (int)(aVinc*aPercentToValue); + int aVmin_int = (int)(aVmin*aPercentToValue); + int aVdec_int = (int)(aVdec*aPercentToValue); + + switch(aHi) { + case 0: setValues(aRGB, aV_int, aVinc_int, aVmin_int); break; + case 1: setValues(aRGB, aVdec_int, aV_int, aVmin_int); break; + case 2: setValues(aRGB, aVmin_int, aV_int, aVinc_int); break; + case 3: setValues(aRGB, aVmin_int, aVdec_int, aV_int); break; + case 4: setValues(aRGB, aVinc_int, aVmin_int, aV_int); break; + case 5: setValues(aRGB, aV_int, aVmin_int, aVdec_int); break; + default: break; + } + return aRGB; +} + +std::array, 10> myColorTab = { + std::vector {255, 0, 0}, + std::vector {0, 255, 0}, + std::vector {0, 0, 255}, + std::vector {255, 255, 0}, + std::vector {0, 255, 255}, + std::vector {255, 0, 255}, + std::vector {255, 94, 0}, + std::vector {132, 255, 0}, + std::vector {132, 0, 255}, + std::vector {0, 0, 0}, +}; + +void findRandomColor(std::vector& theValues, bool theReset) +{ + static size_t i = 0; + static std::vector> usedGeneratedColor; + + // True when disabling auto-color + if ( theReset ) { + i = 0; + return; + } + + theValues.clear(); + if (i < myColorTab.size()) { + theValues = myColorTab[i++]; + } else { + int timeout = 0; + std::vector aHSVColor; + std::vector aRGBColor; + do { + aHSVColor = {rand() % 360 , rand() % (100 - 50 + 1) + 50, rand() % (100 - 50 + 1) + 50}; + aRGBColor = HSVtoRGB(aHSVColor[0], aHSVColor[1], aHSVColor[2]); + timeout++; + } while ( + timeout < 20 && + std::find(usedGeneratedColor.begin(), usedGeneratedColor.end(), aHSVColor) + != usedGeneratedColor.end() && + std::find(myColorTab.begin(), myColorTab.end(), aRGBColor) != myColorTab.end()); + usedGeneratedColor.push_back(aHSVColor); + theValues = aRGBColor; + } +} + +// LCOV_EXCL_STOP + +/// Returns name of the higher level feature (Part or feature of PartSet). +static FeaturePtr topOwner(const FeaturePtr& theFeature) +{ + FeaturePtr anOwner = theFeature; + while (anOwner.get()) + { + FeaturePtr aNextOwner = compositeOwner(anOwner); + if (aNextOwner.get()) + anOwner = aNextOwner; + else + break; + } + if (anOwner->document() != ModelAPI_Session::get()->moduleDocument()) // the part-owner name + anOwner = findPartFeature(ModelAPI_Session::get()->moduleDocument(), anOwner->document()); + return anOwner; +} + +std::wstring validateMovement(const FeaturePtr& theAfter, const std::list theMoved) +{ + std::wstring aResult; + if (theMoved.empty()) + return aResult; // nothing to move, nothing to check, ok + DocumentPtr aDoc = theAfter.get() ? theAfter->document() : (*(theMoved.cbegin()))->document(); + std::set aMoved(theMoved.begin(), theMoved.end()); // fast access to moved + std::set aPassed, aPassedMoved; // all features and all moved before the current one + std::set aPassedAfter; // all passed features after theAfter + bool anAfterIsPassed = theAfter.get() == 0; // flag that iterator already passed theAfter + std::list allFeat = aDoc->allFeatures(); + for (std::list::iterator aFeat = allFeat.begin(); aFeat != allFeat.end(); aFeat++) + { + if (!anAfterIsPassed) + { + if (aMoved.count(*aFeat)) + aPassedMoved.insert(*aFeat); + else // check aPassedMoved are not referenced by the current feature + aPassed.insert(*aFeat); + + anAfterIsPassed = *aFeat == theAfter; + if (anAfterIsPassed && !aPassedMoved.empty()) + { // check dependencies of moved relatively to the passed + std::map > aReferences; + findAllReferences(aPassedMoved, aReferences); + std::map >::iterator aRefIter = aReferences.begin(); + for (; aRefIter != aReferences.end(); aRefIter++) + { + if (aPassed.count(aRefIter->first)) + { + aResult += topOwner(aRefIter->first)->name() + L" -> "; + // iterate all passed moved to check is it referenced by described feature or not + std::set::iterator aMovedIter = aPassedMoved.begin(); + for (; aMovedIter != aPassedMoved.end(); aMovedIter++) + { + std::map > aPassedRefs; + std::set aMovedOne; + aMovedOne.insert(*aMovedIter); + findAllReferences(aMovedOne, aPassedRefs); + if (aPassedRefs.count(aRefIter->first)) + aResult += topOwner(*aMovedIter)->name() + L" "; + } + aResult += L"\n"; + } + } + } + } + else // iteration after theAfter + { + if (aMoved.count(*aFeat)) { // check dependencies of moved relatively to ones after theAfter + std::map > aReferences; + findAllReferences(aPassedAfter, aReferences); + bool aFoundRef = aReferences.find(*aFeat) != aReferences.end(); + if (!aFoundRef && !(*aFeat)->results().empty()) // reference may be a feature in moved part + { + ResultPartPtr aFeatPart = + std::dynamic_pointer_cast((*aFeat)->firstResult()); + if (aFeatPart.get() && aFeatPart->partDoc().get()) + { + std::map >::iterator aRef = aReferences.begin(); + for (; aRef != aReferences.end() && !aFoundRef; aRef++) + aFoundRef = aRef->first->document() == aFeatPart->partDoc(); + } + } + + if (aFoundRef) + { + aResult += topOwner(*aFeat)->name() + L" -> "; + std::set aReferencedCount; // to avoid duplicates in the displayed references + // iterate all passed after theAfter to check refers it described feature or not + FeaturePtr aFeatTop = topOwner(*aFeat); + std::set::iterator aPassedIter = aPassedAfter.begin(); + for (; aPassedIter != aPassedAfter.end(); aPassedIter++) + { + FeaturePtr aPassedTop = topOwner(*aPassedIter); + if (aReferencedCount.count(aPassedTop)) + continue; + std::map > aPassedRefs; + std::set aPassedOne; + aPassedOne.insert(*aPassedIter); + findAllReferences(aPassedOne, aPassedRefs); + std::map >::iterator aPRIter = aPassedRefs.begin(); + for (; aPRIter != aPassedRefs.end(); aPRIter++) + { + FeaturePtr aPRTop = topOwner(aPRIter->first); + if (aPRIter->first == *aFeat || aPRIter->first == aFeatTop || + aPRTop == *aFeat || aPRTop == aFeatTop) + { + aResult += aPassedTop->name() + L" "; + aReferencedCount.insert(aPassedTop); + break; + } + } + } + aResult += L"\n"; + } + } + else { + aPassedAfter.insert(*aFeat); + } + } + + } + return aResult; +} + } // namespace ModelAPI_Tools