///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2016 Statoil ASA // // ResInsight is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. // // See the GNU General Public License at // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RimSummaryCurveAppearanceCalculator.h" #include "RiaColorTables.h" #include "RimSummaryCurve.h" #include "RimSummaryCase.h" #include "cvfVector3.h" #include namespace caf { template<> void caf::AppEnum< RimSummaryCurveAppearanceCalculator::CurveAppearanceType >::setUp() { addItem(RimSummaryCurveAppearanceCalculator::NONE, "NONE", "None"); addItem(RimSummaryCurveAppearanceCalculator::COLOR, "COLOR", "Color"); addItem(RimSummaryCurveAppearanceCalculator::SYMBOL, "SYMBOL", "Symbols"); addItem(RimSummaryCurveAppearanceCalculator::LINE_STYLE, "LINE_STYLE", "Line Style"); addItem(RimSummaryCurveAppearanceCalculator::GRADIENT, "GRADIENT", "Gradient"); addItem(RimSummaryCurveAppearanceCalculator::LINE_THICKNESS, "LINE_THICKNESS", "Line Thickness"); setDefault(RimSummaryCurveAppearanceCalculator::NONE); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimSummaryCurveAppearanceCalculator::RimSummaryCurveAppearanceCalculator(const std::set >& curveDefinitions, const std::set allSummaryCaseNames, const std::set allSummaryWellNames) { m_allSummaryCaseNames = allSummaryCaseNames; m_allSummaryWellNames = allSummaryWellNames; for(const std::pair& curveDef : curveDefinitions) { if(curveDef.first) m_caseToAppearanceIdxMap[curveDef.first] = -1; if(!curveDef.second.wellName().empty()) m_welToAppearanceIdxMap[curveDef.second.wellName()] = -1; if(!curveDef.second.wellGroupName().empty()) m_grpToAppearanceIdxMap[curveDef.second.wellGroupName()] = -1; if(!(curveDef.second.regionNumber() == -1)) m_regToAppearanceIdxMap[curveDef.second.regionNumber()] = -1; if(!curveDef.second.quantityName().empty()) { std::string varname = curveDef.second.quantityName(); m_varToAppearanceIdxMap[varname] = -1; // Indexes for sub color ranges char secondChar = 0; if(varname.size() > 1) { secondChar = varname[1]; if ( secondChar != 'W' && secondChar != 'O' && secondChar != 'G' && secondChar != 'V') { secondChar = 0; // Consider all others as one group for coloring } } m_secondCharToVarToAppearanceIdxMap[secondChar][varname] = -1; } } m_caseCount = m_caseToAppearanceIdxMap.size(); m_variableCount = m_varToAppearanceIdxMap .size(); m_wellCount = m_welToAppearanceIdxMap .size(); m_groupCount = m_grpToAppearanceIdxMap .size(); m_regionCount = m_regToAppearanceIdxMap .size(); // Select the default appearance type for each data "dimension" m_caseAppearanceType = NONE; m_varAppearanceType = NONE; m_wellAppearanceType = NONE; m_groupAppearanceType = NONE; m_regionAppearanceType = NONE; std::set unusedAppearTypes; unusedAppearTypes.insert(COLOR); unusedAppearTypes.insert(GRADIENT); unusedAppearTypes.insert(LINE_STYLE); unusedAppearTypes.insert(SYMBOL); unusedAppearTypes.insert(LINE_THICKNESS); m_currentCurveGradient = 0.0f; m_dimensionCount = 0; if(m_variableCount > 1) { m_varAppearanceType = *(unusedAppearTypes.begin()); unusedAppearTypes.erase(unusedAppearTypes.begin()); m_dimensionCount++; } if(m_caseCount > 1) { m_caseAppearanceType = *(unusedAppearTypes.begin()); unusedAppearTypes.erase(unusedAppearTypes.begin()); m_dimensionCount++; } if(m_wellCount > 1) { m_wellAppearanceType = *(unusedAppearTypes.begin()); unusedAppearTypes.erase(unusedAppearTypes.begin()); m_dimensionCount++; } if(m_groupCount > 1) { m_groupAppearanceType = *(unusedAppearTypes.begin()); unusedAppearTypes.erase(unusedAppearTypes.begin()); m_dimensionCount++; } if(m_regionCount > 1) { m_regionAppearanceType = *(unusedAppearTypes.begin()); unusedAppearTypes.erase(unusedAppearTypes.begin()); m_dimensionCount++; } if (m_dimensionCount == 0) m_varAppearanceType = COLOR; // basically one curve updateApperanceIndices(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryCurveAppearanceCalculator::assignDimensions( CurveAppearanceType caseAppearance, CurveAppearanceType variAppearance, CurveAppearanceType wellAppearance, CurveAppearanceType gropAppearance, CurveAppearanceType regiAppearance) { m_caseAppearanceType = caseAppearance; m_varAppearanceType = variAppearance; m_wellAppearanceType = wellAppearance; m_groupAppearanceType = gropAppearance; m_regionAppearanceType = regiAppearance; // Update the dimensionCount m_dimensionCount = 0; if(m_caseAppearanceType != NONE) ++m_dimensionCount; if(m_varAppearanceType != NONE) ++m_dimensionCount; if(m_wellAppearanceType != NONE) ++m_dimensionCount; if(m_groupAppearanceType != NONE) ++m_dimensionCount; if(m_regionAppearanceType != NONE) ++m_dimensionCount; updateApperanceIndices(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryCurveAppearanceCalculator::updateApperanceIndices() { { std::map caseAppearanceIndices = mapNameToAppearanceIndex(m_caseAppearanceType, m_allSummaryCaseNames); int idx = 0; for (auto& pair : m_caseToAppearanceIdxMap) { pair.second = static_cast(caseAppearanceIndices[pair.first->summaryHeaderFilename().toUtf8().constData()]); } } { std::map wellAppearanceIndices = mapNameToAppearanceIndex(m_wellAppearanceType, m_allSummaryWellNames); int idx = 0; for (auto& pair : m_welToAppearanceIdxMap) { pair.second = static_cast(wellAppearanceIndices[pair.first]); } } // Assign increasing indexes { int idx = 0; for(auto& pair : m_varToAppearanceIdxMap) pair.second = idx++; } { int idx = 0; for(auto& pair : m_grpToAppearanceIdxMap) pair.second = idx++; } { int idx = 0; for(auto& pair : m_regToAppearanceIdxMap) pair.second = idx++; } for (auto& charMapPair : m_secondCharToVarToAppearanceIdxMap) { int idx = 0; for (auto& pair : charMapPair.second) pair.second = idx++; } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::map RimSummaryCurveAppearanceCalculator::mapNameToAppearanceIndex(CurveAppearanceType& appearance, const std::set& names) { std::map nameToIndex; size_t numOptions; if (appearance == CurveAppearanceType::COLOR) { numOptions = RiaColorTables::summaryCurveDefaultPaletteColors().size(); } else if (appearance == CurveAppearanceType::SYMBOL) { numOptions = caf::AppEnum::size(); } else if (appearance == CurveAppearanceType::LINE_STYLE) { numOptions = caf::AppEnum::size(); } else { // If none of these styles are used, fall back to a simply incrementing index size_t idx = 0; for (const std::string& name : names) { nameToIndex[name] = idx; ++idx; } return nameToIndex; } std::hash stringHasher; std::vector< std::set > nameIndices; for (const std::string& name : names) { size_t nameHash = stringHasher(name); nameHash = nameHash % numOptions; size_t index = nameHash; while (true) { while (nameIndices.size() <= index) { // Ensure there exists a set at the insertion index nameIndices.push_back(std::set()); } std::set& matches = nameIndices[index]; if (matches.empty()) { // If there are no matches here, the summary case has not been added. matches.insert(name); break; } else if (matches.find(name) != matches.end()) { // Check to see if the summary case exists at this index. break; } else { // Simply increment index to check if the next bucket is available. index = (index + 1) % numOptions; if (index == nameHash) { // If we've reached `caseHash` again, no other slot was available, so add it here. matches.insert(name); break; } } } } size_t index = 0; for (std::set& nameIndex : nameIndices) { for (const std::string& name : nameIndex) { nameToIndex[name] = index; } index++; } return nameToIndex; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryCurveAppearanceCalculator::getDimensions(CurveAppearanceType* caseAppearance, CurveAppearanceType* variAppearance, CurveAppearanceType* wellAppearance, CurveAppearanceType* gropAppearance, CurveAppearanceType* regiAppearance) const { *caseAppearance = m_caseAppearanceType ; *variAppearance = m_varAppearanceType ; *wellAppearance = m_wellAppearanceType ; *gropAppearance = m_groupAppearanceType ; *regiAppearance = m_regionAppearanceType; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryCurveAppearanceCalculator::setupCurveLook(RimSummaryCurve* curve) { m_currentCurveBaseColor = cvf::Color3f(0, 0, 0); m_currentCurveGradient = 0.0f; int caseAppearanceIdx = m_caseToAppearanceIdxMap[curve->summaryCase()]; int varAppearanceIdx = m_varToAppearanceIdxMap[curve->summaryAddress().quantityName()]; int welAppearanceIdx = m_welToAppearanceIdxMap[curve->summaryAddress().wellName()]; int grpAppearanceIdx = m_grpToAppearanceIdxMap[curve->summaryAddress().wellGroupName()]; int regAppearanceIdx = m_regToAppearanceIdxMap[curve->summaryAddress().regionNumber()]; // Remove index for curves without value at the specific dimension if(curve->summaryAddress().wellName().empty()) welAppearanceIdx = -1; if(curve->summaryAddress().wellGroupName().empty()) grpAppearanceIdx = -1; if(curve->summaryAddress().regionNumber() < 0) regAppearanceIdx = -1; setOneCurveAppearance(m_caseAppearanceType, m_caseCount, caseAppearanceIdx, curve); setOneCurveAppearance(m_wellAppearanceType, m_wellCount, welAppearanceIdx, curve); setOneCurveAppearance(m_groupAppearanceType, m_groupCount, grpAppearanceIdx, curve); setOneCurveAppearance(m_regionAppearanceType, m_regionCount, regAppearanceIdx, curve); if (m_varAppearanceType == COLOR && m_secondCharToVarToAppearanceIdxMap.size() > 1) { int subColorIndex = -1; char secondChar = 0; std::string varname = curve->summaryAddress().quantityName(); if (varname.size() > 1) secondChar = varname[1]; subColorIndex = m_secondCharToVarToAppearanceIdxMap[secondChar][varname]; if (secondChar == 'W') { // Pick blue m_currentCurveBaseColor = cycledBlueColor(subColorIndex); } else if (secondChar == 'O') { // Pick Green m_currentCurveBaseColor = cycledGreenColor(subColorIndex); } else if (secondChar == 'G') { // Pick Red m_currentCurveBaseColor = cycledRedColor(subColorIndex); } else if(secondChar == 'V') { // Pick Brown m_currentCurveBaseColor = cycledBrownColor(subColorIndex); } else { m_currentCurveBaseColor = cycledNoneRGBBrColor(subColorIndex); } } else { setOneCurveAppearance(m_varAppearanceType, m_variableCount, varAppearanceIdx, curve); } curve->setColor(gradeColor(m_currentCurveBaseColor, m_currentCurveGradient)); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimSummaryCurveAppearanceCalculator::setOneCurveAppearance(CurveAppearanceType appeaType, size_t totalCount, int appeaIdx, RimSummaryCurve* curve) { switch(appeaType) { case NONE: break; case COLOR: m_currentCurveBaseColor = cycledPaletteColor(appeaIdx); break; case GRADIENT: m_currentCurveGradient = gradient(totalCount, appeaIdx); break; case LINE_STYLE: curve->setLineStyle(cycledLineStyle(appeaIdx)); break; case SYMBOL: curve->setSymbol(cycledSymbol(appeaIdx)); break; case LINE_THICKNESS: curve->setLineThickness(cycledLineThickness(appeaIdx)); break; } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::Color3f RimSummaryCurveAppearanceCalculator::cycledPaletteColor(int colorIndex) { if (colorIndex < 0) return cvf::Color3f::BLACK; return RiaColorTables::summaryCurveDefaultPaletteColors().cycledColor3f(colorIndex); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::Color3f RimSummaryCurveAppearanceCalculator::cycledNoneRGBBrColor(int colorIndex) { if(colorIndex < 0) return cvf::Color3f::BLACK; return RiaColorTables::summaryCurveNoneRedGreenBlueBrownPaletteColors().cycledColor3f(colorIndex); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::Color3f RimSummaryCurveAppearanceCalculator::cycledGreenColor(int colorIndex) { if(colorIndex < 0) return cvf::Color3f::BLACK; return RiaColorTables::summaryCurveGreenPaletteColors().cycledColor3f(colorIndex); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::Color3f RimSummaryCurveAppearanceCalculator::cycledBlueColor(int colorIndex) { if(colorIndex < 0) return cvf::Color3f::BLACK; return RiaColorTables::summaryCurveBluePaletteColors().cycledColor3f(colorIndex); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::Color3f RimSummaryCurveAppearanceCalculator::cycledRedColor(int colorIndex) { if(colorIndex < 0) return cvf::Color3f::BLACK; return RiaColorTables::summaryCurveRedPaletteColors().cycledColor3f(colorIndex); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::Color3f RimSummaryCurveAppearanceCalculator::cycledBrownColor(int colorIndex) { if(colorIndex < 0) return cvf::Color3f::BLACK; return RiaColorTables::summaryCurveBrownPaletteColors().cycledColor3f(colorIndex); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimPlotCurve::LineStyleEnum RimSummaryCurveAppearanceCalculator::cycledLineStyle(int index) { if (index < 0) return RimPlotCurve::STYLE_SOLID; return caf::AppEnum::fromIndex(1 + (index % (caf::AppEnum::size() - 1))); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimPlotCurve::PointSymbolEnum RimSummaryCurveAppearanceCalculator::cycledSymbol(int index) { if (index < 0) return RimPlotCurve::SYMBOL_NONE; return caf::AppEnum::fromIndex(1 + (index % (caf::AppEnum::size() - 1))); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- int RimSummaryCurveAppearanceCalculator::cycledLineThickness(int index) { static const int thicknessCount = 3; static const int thicknesses[] ={ 1, 3, 5 }; if (index < 0) return 1; return (thicknesses[(index) % thicknessCount]); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- float RimSummaryCurveAppearanceCalculator::gradient(size_t totalCount, int index) { if(totalCount == 1 || index < 0) return 0.0f; const float darkLimit = -0.45f; const float lightLimit = 0.7f; float totalSpan = lightLimit - darkLimit; float step = totalSpan / (totalCount -1); return darkLimit + (index * step); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::Color3f RimSummaryCurveAppearanceCalculator::gradeColor(const cvf::Color3f& color, float factor) { CVF_ASSERT(-1.0 <= factor && factor <= 1.0); cvf::Vec3f orgC(color.r(), color.g(), color.b()); cvf::Vec3f targetC; if(factor < 0) { targetC = cvf::Vec3f(0, 0, 0); } else { targetC = cvf::Vec3f(1, 1, 1); } cvf::Vec3f newColor = ((float)fabs(factor)) * (targetC - orgC) + orgC; return cvf::Color3f(newColor[0], newColor[1], newColor[2]); }