Salome HOME
CEA : Lot 2 - Auto Color for Groups
[modules/shaper.git] / src / ModelAPI / ModelAPI_Tools.cpp
index e0da11a2f9490ae9ba3e5bb452a64955ff599bd2..0dd1c1c8eca884b38805aa741acaa4e54f548fd5 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+// Copyright (C) 2014-2021  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
 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 
-#include "ModelAPI_Tools.h"
-#include <ModelAPI_Session.h>
+#include <ModelAPI_AttributeBoolean.h>
+#include <ModelAPI_AttributeDocRef.h>
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeIntArray.h>
+#include <ModelAPI_AttributeSelectionList.h>
 #include <ModelAPI_CompositeFeature.h>
 #include <ModelAPI_Document.h>
+#include <ModelAPI_Events.h>
 #include <ModelAPI_Object.h>
-#include <ModelAPI_AttributeDouble.h>
-#include <ModelAPI_AttributeSelectionList.h>
 #include <ModelAPI_ResultBody.h>
+#include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_ResultGroup.h>
 #include <ModelAPI_ResultParameter.h>
 #include <ModelAPI_ResultPart.h>
-#include <ModelAPI_ResultGroup.h>
-#include <ModelAPI_AttributeDocRef.h>
+#include <ModelAPI_Session.h>
+#include "ModelAPI_Tools.h"
 #include <ModelAPI_Validator.h>
-#include <ModelAPI_AttributeIntArray.h>
-#include <ModelAPI_ResultConstruction.h>
-#include <ModelAPI_AttributeBoolean.h>
-#include <list>
-#include <map>
-#include <iostream>
-#include <sstream>
-
-// To support old types of GCC (less than 5.0), check the wide-string conversion is working
-#if (__cplusplus >= 201103L || _MSVC_LANG >= 201103L)  && \
-    (__cplusplus >= 201402L || !defined(__GLIBCXX__)   || \
-    (defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE > 4))
-#define HAVE_WORKING_WIDESTRING 1
-#else
-#define HAVE_WORKING_WIDESTRING 0
-#endif
-
-#if HAVE_WORKING_WIDESTRING
-#include <codecvt>
-#endif
 
+#include <Config_Translator.h>
 #include <Events_Loop.h>
-#include <ModelAPI_Events.h>
+#include <Locale_Convert.h>
 
 #include <GeomAPI_ShapeHierarchy.h>
 #include <GeomAPI_ShapeIterator.h>
 
+#include <algorithm>
+#include <iostream>
+#include <list>
+#include <map>
+#include <sstream>
+
 #define RECURSE_TOP_LEVEL 50
 
 //#define DEBUG_REMOVE_FEATURES
@@ -165,14 +156,24 @@ std::string getFeatureError(const FeaturePtr& theFeature)
         CompositeFeaturePtr aComposite =
                     std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(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);
+            }
+          }
         }
       }
     }
@@ -183,12 +184,11 @@ 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)
 {
-  std::wstring aName = toWString(theName);
   for (int anIndex = 0; anIndex < theDocument->size(theGroup); ++anIndex) {
     ObjectPtr anObject = theDocument->object(theGroup, anIndex);
-    if (anObject->data()->name() == aName)
+    if (anObject->data()->name() == theName)
       return anObject;
   }
   // not found
@@ -196,7 +196,7 @@ ObjectPtr objectByName(const DocumentPtr& theDocument, const std::string& theGro
 }
 
 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<ModelAPI_ResultParameter>(aParamObj);
@@ -214,7 +214,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();
@@ -373,7 +373,7 @@ bool allDocumentsActivated(std::wstring& theNotActivatedNames)
 }
 
 bool removeFeaturesAndReferences(const std::set<FeaturePtr>& theFeatures,
-                                 const bool theFlushRedisplay,
+                                 const bool /*theFlushRedisplay*/,
                                  const bool theUseComposite,
                                  const bool theUseRecursion)
 {
@@ -483,10 +483,10 @@ void findReferences(const std::set<FeaturePtr>& theFeatures,
       }
       else { // filter references to skip composition features of the current feature
         std::set<FeaturePtr> aFilteredFeatures;
-        std::set<FeaturePtr>::const_iterator anIt = aSelRefFeatures.begin(),
-                                             aLast = aSelRefFeatures.end();
-        for (; anIt != aLast; anIt++) {
-          FeaturePtr aCFeature = *anIt;
+        std::set<FeaturePtr>::const_iterator aRefIt = aSelRefFeatures.begin(),
+                                             aRefLast = aSelRefFeatures.end();
+        for (; aRefIt != aRefLast; aRefIt++) {
+          FeaturePtr aCFeature = *aRefIt;
           CompositeFeaturePtr aComposite =
             std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCFeature);
           if (aComposite.get() && aComposite->isSub(aFeature))
@@ -557,7 +557,7 @@ void findAllReferences(const std::set<FeaturePtr>& 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
@@ -630,7 +630,8 @@ void getConcealedResults(const FeaturePtr& theFeature,
 }
 
 std::pair<std::wstring, bool> getDefaultName(const std::shared_ptr<ModelAPI_Result>& theResult,
-                                            const bool theInherited)
+                                             const bool theInherited,
+                                             const bool theRecursive)
 {
   typedef std::list< std::pair < std::string, std::list<ObjectPtr> > > ListOfReferences;
 
@@ -710,7 +711,7 @@ std::pair<std::wstring, bool> getDefaultName(const std::shared_ptr<ModelAPI_Resu
       }
     }
     // check the result is a Body
-    if ((*anObjIt)->groupName() == ModelAPI_ResultBody::group()) {
+    if (anObjIt->get() && (*anObjIt)->groupName() == ModelAPI_ResultBody::group()) {
       // check the result is part of CompSolid
       ResultPtr anObjRes = std::dynamic_pointer_cast<ModelAPI_Result>(*anObjIt);
       ResultBodyPtr aParentBody = ModelAPI_Tools::bodyOwner(anObjRes);
@@ -719,7 +720,8 @@ std::pair<std::wstring, bool> getDefaultName(const std::shared_ptr<ModelAPI_Resu
 
       // return name of reference result only if it has been renamed by the user,
       // in other case compose a default name
-      if (anObjRes->data()->hasUserDefinedName()) {
+      if (anObjRes->data()->hasUserDefinedName() ||
+          (theRecursive && anObjRes->data()->name() != getDefaultName(anObjRes).first)) {
         std::wstringstream aName;
         aName << anObjRes->data()->name();
         std::map<ResultPtr, int>::iterator aFound = aNbRefToObject.find(anObjRes);
@@ -1058,10 +1060,10 @@ std::list<FeaturePtr> referencedFeatures(
       for(; aResIter != aResSet.end(); aResIter++) {
         std::list<ResultPtr>::const_iterator aGroupRes = (*aResIter)->results().cbegin();
         for(; aGroupRes != (*aResIter)->results().cend(); aGroupRes++) {
-          const std::set<AttributePtr>& aRefs = (*aGroupRes)->data()->refsToMe();
-          std::set<AttributePtr>::const_iterator aRef = aRefs.cbegin();
-          for(; aRef != aRefs.cend(); aRef++) {
-            FeaturePtr aFeat = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRef)->owner());
+          const std::set<AttributePtr>& aGroupRefs = (*aGroupRes)->data()->refsToMe();
+          std::set<AttributePtr>::const_iterator aRefIt = aGroupRefs.cbegin();
+          for(; aRefIt != aGroupRefs.cend(); aRefIt++) {
+            FeaturePtr aFeat = std::dynamic_pointer_cast<ModelAPI_Feature>((*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
@@ -1116,42 +1118,90 @@ std::list<FeaturePtr> referencedFeatures(
   return aResList;
 }
 
-// LCOV_EXCL_STOP
-std::string toString(const std::wstring& theWStr)
+void setValues(std::vector<int>& theRGB, const int theRed, const int theGreen, const int theBlue)
 {
-#if HAVE_WORKING_WIDESTRING
-  static std::wstring_convert<std::codecvt_utf8<wchar_t> > aConvertor;
-  return aConvertor.to_bytes(theWStr);
-#else
-  char* aBuf = new char[2 * (theWStr.size() + 1)];
-  size_t aNbChars = std::wcstombs(aBuf, theWStr.c_str(), theWStr.size());
-  if (aNbChars != (size_t)-1)
-    aBuf[aNbChars] = '\0';
-  std::string aStr(aBuf);
-  delete[] aBuf;
-  return aStr;
-#endif
+  theRGB.push_back(theRed);
+  theRGB.push_back(theGreen);
+  theRGB.push_back(theBlue);
 }
 
-/*! Converts a byte string to an extended string
-*  \param theStr a byte string
-*/
-std::wstring toWString(const std::string& theStr)
+std::vector<int> HSVtoRGB(int theH, int theS, int theV)
 {
-#if HAVE_WORKING_WIDESTRING
-  static std::wstring_convert<std::codecvt_utf8<wchar_t> > aConvertor;
-  return aConvertor.from_bytes(theStr);
-#else
-  wchar_t* aBuf = new wchar_t[theStr.size()];
-  size_t aNbWChars = std::mbstowcs(aBuf, theStr.c_str(), theStr.size());
-  if (aNbWChars != (size_t)-1)
-    aBuf[aNbWChars] = '\0';
-  std::wstring aWStr(aBuf);
-  delete[] aBuf;
-  return aWStr;
-#endif
+  std::vector<int> 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<std::vector<int>, 10> myColorTab = {
+  std::vector<int> {255, 0, 0},
+  std::vector<int> {0, 255, 0},
+  std::vector<int> {0, 0, 255},
+  std::vector<int> {255, 255, 0},
+  std::vector<int> {0, 255, 255},
+  std::vector<int> {255, 0, 255},
+  std::vector<int> {255, 94, 0},
+  std::vector<int> {132, 255, 0},
+  std::vector<int> {132, 0, 255},
+  std::vector<int> {0, 0, 0},
+};
+
+void findRandomColor(std::vector<int>& theValues, bool theReset)
+{
+  static int i = 0;
+  static std::vector<std::vector<int>> 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<int> aHSVColor;
+      std::vector<int> 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
 
 } // namespace ModelAPI_Tools