///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2020 Equinor 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 "RimColorLegendCollection.h" #include "RiaColorTables.h" #include "RiaFractureDefines.h" #include "RigFormationNames.h" #include "Formations/RimFormationNames.h" #include "RimCase.h" #include "RimColorLegend.h" #include "RimColorLegendItem.h" #include "RimProject.h" #include "RimRegularLegendConfig.h" #include "cafPdmFieldScriptingCapability.h" #include "cafPdmObjectScriptingCapability.h" #include CAF_PDM_SOURCE_INIT( RimColorLegendCollection, "ColorLegendCollection" ); //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimColorLegendCollection::RimColorLegendCollection() { CAF_PDM_InitScriptableObject( "Color Legends", ":/Legend.png" ); CAF_PDM_InitFieldNoDefault( &m_standardColorLegends, "StandardColorLegends", "Standard Color Legends", ":/Legend.png" ); m_standardColorLegends.xmlCapability()->disableIO(); CAF_PDM_InitScriptableFieldNoDefault( &m_customColorLegends, "CustomColorLegends", "Custom Color Legends", ":/Legend.png" ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimColorLegendCollection::~RimColorLegendCollection() { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimColorLegendCollection::appendCustomColorLegend( RimColorLegend* colorLegend ) { colorLegend->addReorderCapability(); m_customColorLegends.push_back( colorLegend ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- bool RimColorLegendCollection::isStandardColorLegend( RimColorLegend* legend ) { for ( const auto& standardLegend : m_standardColorLegends ) { if ( legend == standardLegend ) return true; } return false; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimColorLegendCollection::deleteCustomColorLegends() { m_defaultColorLegendNameForResult.clear(); m_customColorLegends.deleteChildren(); } //-------------------------------------------------------------------------------------------------- /// Update the custom color legend registered as default for the given result in place, so that /// objects referring to the legend keep their binding. Creates and registers a new custom legend /// if none exists or the registered legend is a standard legend. If colors is empty, palette /// colors are assigned automatically. //-------------------------------------------------------------------------------------------------- RimColorLegend* RimColorLegendCollection::updateColorLegend( const RimCase* rimCase, const QString& resultName, const QString& colorLegendName, const std::vector& categoryValues, const std::vector& categoryNames, const std::vector& colors ) { CAF_ASSERT( categoryValues.size() == categoryNames.size() ); CAF_ASSERT( colors.empty() || colors.size() == categoryValues.size() ); auto legend = findDefaultLegendForResult( rimCase, resultName ); if ( !legend || isStandardColorLegend( legend ) ) { legend = new RimColorLegend(); appendCustomColorLegend( legend ); } legend->setColorLegendName( colorLegendName ); auto paletteColors = RiaColorTables::categoryPaletteColors().color3ubArray(); std::vector items; for ( size_t i = 0; i < categoryValues.size(); i++ ) { cvf::Color3f color = colors.empty() ? cvf::Color3f( paletteColors[i % paletteColors.size()] ) : colors[i]; auto item = new RimColorLegendItem(); item->setValues( categoryNames[i], categoryValues[i], color ); items.push_back( item ); } legend->setColorLegendItems( items ); setDefaultColorLegendForResult( rimCase, resultName, legend ); return legend; } //-------------------------------------------------------------------------------------------------- /// Overload taking values and names as a map, with optional colors ordered by ascending value. //-------------------------------------------------------------------------------------------------- RimColorLegend* RimColorLegendCollection::updateColorLegend( const RimCase* rimCase, const QString& resultName, const QString& colorLegendName, const std::map& valuesAndNames, const std::vector& colors ) { std::vector categoryValues; std::vector categoryNames; for ( const auto& [value, name] : valuesAndNames ) { categoryValues.push_back( value ); categoryNames.push_back( name ); } return updateColorLegend( rimCase, resultName, colorLegendName, categoryValues, categoryNames, colors ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimColorLegendCollection::deleteColorLegend( const RimCase* rimCase, const QString& resultName ) { auto legend = findDefaultLegendForResult( rimCase, resultName ); m_defaultColorLegendNameForResult.erase( createLookupKey( rimCase, resultName ) ); if ( !legend || isStandardColorLegend( legend ) ) return; m_customColorLegends.removeChild( legend ); delete legend; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimColorLegendCollection::setDefaultColorLegendForResult( const RimCase* rimCase, const QString& resultName, RimColorLegend* colorLegend ) { auto key = createLookupKey( rimCase, resultName ); m_defaultColorLegendNameForResult[key] = colorLegend; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimColorLegendCollection::createStandardColorLegends() { using ColorRangeEnum = caf::AppEnum; for ( size_t typeIdx = 0; typeIdx < ColorRangeEnum::size(); typeIdx++ ) { auto colorType = ColorRangeEnum::fromIndex( typeIdx ); if ( colorType != RimRegularLegendConfig::ColorRangesType::UNDEFINED ) { QString legendName = ColorRangeEnum::uiTextFromIndex( typeIdx ); cvf::Color3ubArray colorArray = RimRegularLegendConfig::colorArrayFromColorType( colorType ); if ( colorType == RimRegularLegendConfig::ColorRangesType::CATEGORY ) { // Reverse the ordering of the category items in the category legend to match the changes // for fixing issue https://github.com/OPM/ResInsight/issues/6252 auto other = colorArray; for ( size_t i = 0; i < colorArray.size(); i++ ) { colorArray[i] = other[colorArray.size() - 1 - i]; } } auto* colorLegend = new RimColorLegend; colorLegend->setColorLegendName( legendName ); for ( size_t i = 0; i < colorArray.size(); i++ ) { cvf::Color3f color3f( colorArray[i] ); auto* colorLegendItem = new RimColorLegendItem; // Set empty text for color legend items // The text defined is used in RimEclipseResultDefinitionTools::updateCellResultLegend() colorLegendItem->setValues( "", static_cast( i ), color3f ); colorLegend->appendColorLegendItem( colorLegendItem ); colorLegend->setReadOnly( true ); } m_standardColorLegends.push_back( colorLegend ); } } m_standardColorLegends.push_back( createRockTypeColorLegend() ); updateConnectedEditors(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimColorLegendCollection::allColorLegends() const { std::vector allLegends; auto standardLegends = m_standardColorLegends.childrenByType(); for ( auto l : standardLegends ) { allLegends.push_back( l ); } auto customLegends = m_customColorLegends.childrenByType(); for ( auto l : customLegends ) { allLegends.push_back( l ); } return allLegends; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimColorLegendCollection::createColorLegendFromFormationNames( RimFormationNames* rimFormationNames ) { if ( !rimFormationNames ) return; auto rigFormationNames = rimFormationNames->formationNamesData(); if ( !rigFormationNames ) return; const std::vector& formationNames = rigFormationNames->formationNames(); const std::vector& formationColors = rigFormationNames->formationColors(); if ( formationNames.empty() || formationColors.empty() ) return; if ( formationNames.size() != formationColors.size() ) return; bool anyValidColor = std::any_of( formationColors.begin(), formationColors.end(), []( const auto& color ) { return color.isValid(); } ); if ( !anyValidColor ) return; QString legendName = rimFormationNames->shortName(); // Do not create duplicate legends if ( findByName( legendName ) != nullptr ) return; auto* colorLegend = new RimColorLegend; colorLegend->setColorLegendName( legendName ); for ( size_t i = 0; i < formationColors.size(); i++ ) { auto* item = new RimColorLegendItem; item->setValues( formationNames[i], (int)i, formationColors[i] ); colorLegend->appendColorLegendItem( item ); } appendCustomColorLegend( colorLegend ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimColorLegend* RimColorLegendCollection::findByName( const QString& name ) const { std::vector allLegends = allColorLegends(); for ( auto legend : allLegends ) { if ( legend->colorLegendName() == name ) { return legend; } } return nullptr; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimColorLegend* RimColorLegendCollection::findDefaultLegendForResult( const RimCase* rimCase, const QString& resultName ) const { auto key = createLookupKey( rimCase, resultName ); auto it = m_defaultColorLegendNameForResult.find( key ); if ( it != m_defaultColorLegendNameForResult.end() ) { return it->second; } return nullptr; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimColorLegendItem* RimColorLegendCollection::createColorLegendItem( const QString& name, int r, int g, int b ) const { auto* item = new RimColorLegendItem; item->setValues( name, 0, cvf::Color3f::fromByteColor( r, g, b ) ); return item; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimColorLegend* RimColorLegendCollection::createRockTypeColorLegend() const { auto* colorLegend = new RimColorLegend; colorLegend->setColorLegendName( RiaDefines::rockTypeColorLegendName() ); // Rock types colors taken from "Equinor GeoStandard - May 2020" document. // 6.3.1 Epiclastic rocks colorLegend->appendColorLegendItem( createColorLegendItem( "Conglomerate", 255, 193, 0 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Sedimentary breccia", 255, 193, 0 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Sandstone", 255, 247, 143 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Siltstone", 179, 212, 84 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Mudstone", 31, 180, 108 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Claystone", 101, 167, 64 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Fissile siltstone", 179, 212, 84 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Fissil mudstone", 31, 180, 108 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Shale", 136, 112, 0 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Grey silty clay", 197, 179, 115 ) ); // 6.3.2 Carbonate rocks colorLegend->appendColorLegendItem( createColorLegendItem( "Limestone", 0, 165, 203 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Dolomitic limestone", 0, 155, 219 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Dolostone", 54, 17, 99 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Calcareous dolostone", 115, 173, 222 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Chalk", 0, 181, 214 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Marl", 98, 200, 206 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Spiculities", 214, 133, 137 ) ); // 6.3.3 Evaporitic rocks colorLegend->appendColorLegendItem( createColorLegendItem( "Gypsum", 241, 119, 170 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Anhydrite", 241, 119, 170 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Gypsum / Anhydrite", 241, 119, 170 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Halite", 246, 160, 169 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Salt", 246, 160, 169 ) ); // 6.3.4 Coal colorLegend->appendColorLegendItem( createColorLegendItem( "Coal", 0, 0, 0 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Brown coal", 76, 75, 57 ) ); // 6.3.5 Magmatic rocks colorLegend->appendColorLegendItem( createColorLegendItem( "Volcanic rocks", 255, 50, 50 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Intrusive (plutonic) rocks", 251, 184, 141 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Silicic plutonic rocks", 240, 81, 70 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Mafic plutonic rocks", 128, 69, 0 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Ooze", 119, 110, 85 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Dykes and sills", 75, 57, 0 ) ); // 6.3.6 Metamorphic rocks colorLegend->appendColorLegendItem( createColorLegendItem( "Metamorphic rocks", 245, 127, 51 ) ); // 6.3.6 Combined symbols colorLegend->appendColorLegendItem( createColorLegendItem( "Tuffitt", 211, 128, 181 ) ); colorLegend->appendColorLegendItem( createColorLegendItem( "Bitumenious", 235, 220, 175 ) ); int index = 0; for ( auto item : colorLegend->colorLegendItems() ) { item->setCategoryValue( index ); index++; } return colorLegend; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- QString RimColorLegendCollection::createLookupKey( const RimCase* rimCase, const QString& resultName ) { const int caseId = rimCase ? rimCase->caseId() : -1; return QString( "%1 (case %2)" ).arg( resultName ).arg( caseId ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimColorLegendCollection::initAfterRead() { for ( const auto& legend : m_customColorLegends ) { legend->addReorderCapability(); } }