diff --git a/.gitmodules b/.gitmodules index 12478201a1..78323b5cbc 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,6 @@ [submodule "ThirdParty/roffcpp"] path = ThirdParty/roffcpp url = https://github.com/CeetronSolutions/roffcpp +[submodule "ThirdParty/openzgy"] + path = ThirdParty/openzgy + url = https://github.com/CeetronSolutions/openzgy.git diff --git a/ApplicationExeCode/CMakeLists.txt b/ApplicationExeCode/CMakeLists.txt index 5714bffb6a..9ca62df5e1 100644 --- a/ApplicationExeCode/CMakeLists.txt +++ b/ApplicationExeCode/CMakeLists.txt @@ -256,8 +256,10 @@ endif() # According to ivarun rt is needed on OpenSuse, and Fedora. See: # https://github.com/OPM/ResInsight/pull/7 +# +# atomic is needed by openzgy library if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") - list(APPEND THIRD_PARTY_LIBRARIES rt) + list(APPEND THIRD_PARTY_LIBRARIES rt atomic) endif() set(LINK_LIBRARIES diff --git a/ApplicationExeCode/Resources/ResInsight.qrc b/ApplicationExeCode/Resources/ResInsight.qrc index 31dd7c6572..c9f8fabc0e 100644 --- a/ApplicationExeCode/Resources/ResInsight.qrc +++ b/ApplicationExeCode/Resources/ResInsight.qrc @@ -274,6 +274,7 @@ DataVector.svg DataVectorCalculated.svg open-text-editor.svg + Seismic16x16.png fs_CellFace.glsl diff --git a/ApplicationExeCode/Resources/Seismic16x16.png b/ApplicationExeCode/Resources/Seismic16x16.png new file mode 100644 index 0000000000..840fc07ec7 Binary files /dev/null and b/ApplicationExeCode/Resources/Seismic16x16.png differ diff --git a/ApplicationLibCode/Application/CMakeLists_files.cmake b/ApplicationLibCode/Application/CMakeLists_files.cmake index 3f908404ad..d32c5e561f 100644 --- a/ApplicationLibCode/Application/CMakeLists_files.cmake +++ b/ApplicationLibCode/Application/CMakeLists_files.cmake @@ -30,6 +30,7 @@ set(SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RiaDateTimeDefines.h ${CMAKE_CURRENT_LIST_DIR}/RiaPlotCollectionScheduler.h ${CMAKE_CURRENT_LIST_DIR}/RiaScheduler.h + ${CMAKE_CURRENT_LIST_DIR}/RiaSeismicDefines.h ${CMAKE_CURRENT_LIST_DIR}/RiaSummaryDefines.h ${CMAKE_CURRENT_LIST_DIR}/RiaLasDefines.h ${CMAKE_CURRENT_LIST_DIR}/RiaWellFlowDefines.h @@ -68,6 +69,7 @@ set(SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RiaPlotCollectionScheduler.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaScheduler.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaSummaryDefines.cpp + ${CMAKE_CURRENT_LIST_DIR}/RiaSeismicDefines.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaLasDefines.cpp ${CMAKE_CURRENT_LIST_DIR}/RiaWellFlowDefines.cpp ) diff --git a/ApplicationLibCode/Application/RiaSeismicDefines.cpp b/ApplicationLibCode/Application/RiaSeismicDefines.cpp new file mode 100644 index 0000000000..8965a053cf --- /dev/null +++ b/ApplicationLibCode/Application/RiaSeismicDefines.cpp @@ -0,0 +1,34 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023 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 "RiaSeismicDefines.h" + +#include "cafAppEnum.h" + +namespace caf +{ +template <> +void caf::AppEnum::setUp() +{ + addItem( RiaDefines::SeismicSectionType::SS_INLINE, "SS_INLINE", "Inline" ); + addItem( RiaDefines::SeismicSectionType::SS_XLINE, "SS_XLINE", "Crossline" ); + addItem( RiaDefines::SeismicSectionType::SS_DEPTHSLICE, "SS_DEPTHSLICE", "Depth Slice" ); + addItem( RiaDefines::SeismicSectionType::SS_POLYLINE, "SS_POLYLINE", "Polyline" ); + setDefault( RiaDefines::SeismicSectionType::SS_INLINE ); +} +} // namespace caf diff --git a/ApplicationLibCode/Application/RiaSeismicDefines.h b/ApplicationLibCode/Application/RiaSeismicDefines.h new file mode 100644 index 0000000000..bb5db22641 --- /dev/null +++ b/ApplicationLibCode/Application/RiaSeismicDefines.h @@ -0,0 +1,38 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023 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. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +namespace RiaDefines +{ +enum class SeismicSliceDirection +{ + INLINE, + XLINE, + DEPTH +}; + +enum class SeismicSectionType +{ + SS_INLINE, + SS_XLINE, + SS_DEPTHSLICE, + SS_POLYLINE +}; + +}; // namespace RiaDefines diff --git a/ApplicationLibCode/CMakeLists.txt b/ApplicationLibCode/CMakeLists.txt index 50027dfc04..9243c99ce1 100644 --- a/ApplicationLibCode/CMakeLists.txt +++ b/ApplicationLibCode/CMakeLists.txt @@ -87,6 +87,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/ModelVisualization ${CMAKE_CURRENT_SOURCE_DIR}/ModelVisualization/GridBox ${CMAKE_CURRENT_SOURCE_DIR}/ModelVisualization/Intersections + ${CMAKE_CURRENT_SOURCE_DIR}/ModelVisualization/Seismic ${CMAKE_CURRENT_SOURCE_DIR}/ModelVisualization/Streamlines ${CMAKE_CURRENT_SOURCE_DIR}/ModelVisualization/Surfaces ${CMAKE_CURRENT_SOURCE_DIR}/UserInterface @@ -109,6 +110,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModel/Surfaces ${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModel/Intersections ${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModel/Streamlines + ${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModel/Seismic ${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModel/CellFilters ${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModel/ProcessControl ${CMAKE_CURRENT_SOURCE_DIR}/ProjectDataModel/WellLog @@ -183,6 +185,7 @@ list( ProjectDataModel/PlotTemplates/CMakeLists_files.cmake ProjectDataModel/StimPlanModel/CMakeLists_files.cmake ProjectDataModel/Streamlines/CMakeLists_files.cmake + ProjectDataModel/Seismic/CMakeLists_files.cmake ProjectDataModel/Surfaces/CMakeLists_files.cmake ProjectDataModel/Intersections/CMakeLists_files.cmake ProjectDataModel/CellFilters/CMakeLists_files.cmake @@ -197,6 +200,7 @@ list( ModelVisualization/CMakeLists_files.cmake ModelVisualization/GridBox/CMakeLists_files.cmake ModelVisualization/Intersections/CMakeLists_files.cmake + ModelVisualization/Seismic/CMakeLists_files.cmake ModelVisualization/Streamlines/CMakeLists_files.cmake ModelVisualization/Surfaces/CMakeLists_files.cmake ModelVisualization/WindowEdgeAxesOverlayItem/CMakeLists_files.cmake diff --git a/ApplicationLibCode/Commands/CMakeLists.txt b/ApplicationLibCode/Commands/CMakeLists.txt index 3f09d8ad99..691badfd00 100644 --- a/ApplicationLibCode/Commands/CMakeLists.txt +++ b/ApplicationLibCode/Commands/CMakeLists.txt @@ -33,6 +33,7 @@ set(COMMAND_REFERENCED_CMAKE_FILES SsiHubImportCommands/CMakeLists_files.cmake StreamlineCommands/CMakeLists_files.cmake SurfaceCommands/CMakeLists_files.cmake + SeismicCommands/CMakeLists_files.cmake ToggleCommands/CMakeLists_files.cmake ViewLink/CMakeLists_files.cmake WellLogCommands/CMakeLists_files.cmake @@ -65,6 +66,7 @@ target_include_directories( ${CMAKE_SOURCE_DIR}/ThirdParty/custom-opm-common/generated-opm-common ${CMAKE_SOURCE_DIR}/ThirdParty/custom-opm-common/opm-common ${CMAKE_SOURCE_DIR}/ThirdParty/qtadvanceddocking/src + ${CMAKE_SOURCE_DIR}/ThirdParty/openzgy/include ) if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") diff --git a/ApplicationLibCode/Commands/SeismicCommands/CMakeLists_files.cmake b/ApplicationLibCode/Commands/SeismicCommands/CMakeLists_files.cmake new file mode 100644 index 0000000000..99990549fe --- /dev/null +++ b/ApplicationLibCode/Commands/SeismicCommands/CMakeLists_files.cmake @@ -0,0 +1,27 @@ +set(SOURCE_GROUP_HEADER_FILES + ${CMAKE_CURRENT_LIST_DIR}/RicImportSeismicFeature.h + ${CMAKE_CURRENT_LIST_DIR}/RicNewInlineSeismicSectionFeature.h + ${CMAKE_CURRENT_LIST_DIR}/RicNewXlineSeismicSectionFeature.h + ${CMAKE_CURRENT_LIST_DIR}/RicNewZSliceSeismicSectionFeature.h + ${CMAKE_CURRENT_LIST_DIR}/RicSeismicSectionFeatureImpl.h + ${CMAKE_CURRENT_LIST_DIR}/RicNewPolylineSeismicSectionFeature.h +) + +set(SOURCE_GROUP_SOURCE_FILES + ${CMAKE_CURRENT_LIST_DIR}/RicImportSeismicFeature.cpp + ${CMAKE_CURRENT_LIST_DIR}/RicNewInlineSeismicSectionFeature.cpp + ${CMAKE_CURRENT_LIST_DIR}/RicNewXlineSeismicSectionFeature.cpp + ${CMAKE_CURRENT_LIST_DIR}/RicNewZSliceSeismicSectionFeature.cpp + ${CMAKE_CURRENT_LIST_DIR}/RicSeismicSectionFeatureImpl.cpp + ${CMAKE_CURRENT_LIST_DIR}/RicNewPolylineSeismicSectionFeature.cpp +) + +list(APPEND COMMAND_CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES}) + +list(APPEND COMMAND_CODE_SOURCE_FILES ${SOURCE_GROUP_SOURCE_FILES}) + +source_group( + "CommandFeature\\SeismicCommands" + FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} + ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake +) diff --git a/ApplicationLibCode/Commands/SeismicCommands/RicImportSeismicFeature.cpp b/ApplicationLibCode/Commands/SeismicCommands/RicImportSeismicFeature.cpp new file mode 100644 index 0000000000..490d9c1fb3 --- /dev/null +++ b/ApplicationLibCode/Commands/SeismicCommands/RicImportSeismicFeature.cpp @@ -0,0 +1,84 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2022 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 "RicImportSeismicFeature.h" + +#include "RiaApplication.h" + +#include "RimOilField.h" +#include "RimProject.h" +#include "RimSeismicData.h" +#include "RimSeismicDataCollection.h" + +#include "Riu3DMainWindowTools.h" +#include "RiuFileDialogTools.h" + +#include "cafSelectionManagerTools.h" +#include "cafUtils.h" + +#include +#include + +CAF_CMD_SOURCE_INIT( RicImportSeismicFeature, "RicImportSeismicFeature" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicImportSeismicFeature::isCommandEnabled() +{ + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicImportSeismicFeature::onActionTriggered( bool isChecked ) +{ + RiaApplication* app = RiaApplication::instance(); + QString defaultDir = app->lastUsedDialogDirectory( "SEISMIC_GRID" ); + QString fileName = RiuFileDialogTools::getOpenFileName( Riu3DMainWindowTools::mainWindowWidget(), + "Import Seismic", + defaultDir, + "Seismic files (*.zgy);;All Files (*.*)" ); + + if ( fileName.isEmpty() ) return; + + // Remember the path to next time + app->setLastUsedDialogDirectory( "SEISMIC_GRID", QFileInfo( fileName ).absolutePath() ); + + auto proj = RimProject::current(); + auto& seisColl = proj->activeOilField()->seismicCollection(); + + if ( !seisColl ) return; + + RimSeismicData* newData = seisColl->importSeismicFromFile( fileName ); + + if ( newData ) + { + Riu3DMainWindowTools::selectAsCurrentItem( newData ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicImportSeismicFeature::setupActionLook( QAction* actionToSetup ) +{ + actionToSetup->setIcon( QIcon( ":/Seismic16x16.png" ) ); + actionToSetup->setText( "Import Seismic" ); +} diff --git a/ApplicationLibCode/Commands/SeismicCommands/RicImportSeismicFeature.h b/ApplicationLibCode/Commands/SeismicCommands/RicImportSeismicFeature.h new file mode 100644 index 0000000000..90159fb3fb --- /dev/null +++ b/ApplicationLibCode/Commands/SeismicCommands/RicImportSeismicFeature.h @@ -0,0 +1,34 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2022 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. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" + +//================================================================================================== +/// +//================================================================================================== +class RicImportSeismicFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + bool isCommandEnabled() override; + void onActionTriggered( bool isChecked ) override; + void setupActionLook( QAction* actionToSetup ) override; +}; diff --git a/ApplicationLibCode/Commands/SeismicCommands/RicNewInlineSeismicSectionFeature.cpp b/ApplicationLibCode/Commands/SeismicCommands/RicNewInlineSeismicSectionFeature.cpp new file mode 100644 index 0000000000..7a8e37119c --- /dev/null +++ b/ApplicationLibCode/Commands/SeismicCommands/RicNewInlineSeismicSectionFeature.cpp @@ -0,0 +1,57 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 "RicNewInlineSeismicSectionFeature.h" +#include "RicSeismicSectionFeatureImpl.h" + +#include "RimGridView.h" +#include "RimSeismicSection.h" +#include "RimSeismicSectionCollection.h" +#include "Riu3DMainWindowTools.h" + +#include "cafSelectionManagerTools.h" +#include "cafUtils.h" + +#include + +CAF_CMD_SOURCE_INIT( RicNewInlineSeismicSectionFeature, "RicNewInlineSeismicSectionFeature" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicNewInlineSeismicSectionFeature::isCommandEnabled() +{ + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewInlineSeismicSectionFeature::onActionTriggered( bool isChecked ) +{ + RicSeismicSectionFeatureImpl::createSeismicSection( "Inline", RiaDefines::SeismicSectionType::SS_INLINE ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewInlineSeismicSectionFeature::setupActionLook( QAction* actionToSetup ) +{ + actionToSetup->setIcon( QIcon( ":/Seismic16x16.png" ) ); + actionToSetup->setText( "New Inline Section" ); +} diff --git a/ApplicationLibCode/Commands/SeismicCommands/RicNewInlineSeismicSectionFeature.h b/ApplicationLibCode/Commands/SeismicCommands/RicNewInlineSeismicSectionFeature.h new file mode 100644 index 0000000000..1a5c4bcf73 --- /dev/null +++ b/ApplicationLibCode/Commands/SeismicCommands/RicNewInlineSeismicSectionFeature.h @@ -0,0 +1,34 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023 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. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" + +//================================================================================================== +/// +//================================================================================================== +class RicNewInlineSeismicSectionFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + bool isCommandEnabled() override; + void onActionTriggered( bool isChecked ) override; + void setupActionLook( QAction* actionToSetup ) override; +}; diff --git a/ApplicationLibCode/Commands/SeismicCommands/RicNewPolylineSeismicSectionFeature.cpp b/ApplicationLibCode/Commands/SeismicCommands/RicNewPolylineSeismicSectionFeature.cpp new file mode 100644 index 0000000000..740c6f7494 --- /dev/null +++ b/ApplicationLibCode/Commands/SeismicCommands/RicNewPolylineSeismicSectionFeature.cpp @@ -0,0 +1,57 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 "RicNewPolylineSeismicSectionFeature.h" +#include "RicSeismicSectionFeatureImpl.h" + +#include "RimGridView.h" +#include "RimSeismicSection.h" +#include "RimSeismicSectionCollection.h" +#include "Riu3DMainWindowTools.h" + +#include "cafSelectionManagerTools.h" +#include "cafUtils.h" + +#include + +CAF_CMD_SOURCE_INIT( RicNewPolylineSeismicSectionFeature, "RicNewPolylineSeismicSectionFeature" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicNewPolylineSeismicSectionFeature::isCommandEnabled() +{ + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewPolylineSeismicSectionFeature::onActionTriggered( bool isChecked ) +{ + RicSeismicSectionFeatureImpl::createSeismicSection( "Polyline Section", RiaDefines::SeismicSectionType::SS_POLYLINE ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewPolylineSeismicSectionFeature::setupActionLook( QAction* actionToSetup ) +{ + actionToSetup->setIcon( QIcon( ":/Seismic16x16.png" ) ); + actionToSetup->setText( "New Polyline Section" ); +} diff --git a/ApplicationLibCode/Commands/SeismicCommands/RicNewPolylineSeismicSectionFeature.h b/ApplicationLibCode/Commands/SeismicCommands/RicNewPolylineSeismicSectionFeature.h new file mode 100644 index 0000000000..9b1d23acba --- /dev/null +++ b/ApplicationLibCode/Commands/SeismicCommands/RicNewPolylineSeismicSectionFeature.h @@ -0,0 +1,34 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023 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. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" + +//================================================================================================== +/// +//================================================================================================== +class RicNewPolylineSeismicSectionFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + bool isCommandEnabled() override; + void onActionTriggered( bool isChecked ) override; + void setupActionLook( QAction* actionToSetup ) override; +}; diff --git a/ApplicationLibCode/Commands/SeismicCommands/RicNewXlineSeismicSectionFeature.cpp b/ApplicationLibCode/Commands/SeismicCommands/RicNewXlineSeismicSectionFeature.cpp new file mode 100644 index 0000000000..250f82ea66 --- /dev/null +++ b/ApplicationLibCode/Commands/SeismicCommands/RicNewXlineSeismicSectionFeature.cpp @@ -0,0 +1,49 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 "RicNewXlineSeismicSectionFeature.h" +#include "RicSeismicSectionFeatureImpl.h" + +#include + +CAF_CMD_SOURCE_INIT( RicNewXlineSeismicSectionFeature, "RicNewXlineSeismicSectionFeature" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicNewXlineSeismicSectionFeature::isCommandEnabled() +{ + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewXlineSeismicSectionFeature::onActionTriggered( bool isChecked ) +{ + RicSeismicSectionFeatureImpl::createSeismicSection( "Xline", RiaDefines::SeismicSectionType::SS_XLINE ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewXlineSeismicSectionFeature::setupActionLook( QAction* actionToSetup ) +{ + actionToSetup->setIcon( QIcon( ":/Seismic16x16.png" ) ); + actionToSetup->setText( "New Xline Section" ); +} diff --git a/ApplicationLibCode/Commands/SeismicCommands/RicNewXlineSeismicSectionFeature.h b/ApplicationLibCode/Commands/SeismicCommands/RicNewXlineSeismicSectionFeature.h new file mode 100644 index 0000000000..d3324cc718 --- /dev/null +++ b/ApplicationLibCode/Commands/SeismicCommands/RicNewXlineSeismicSectionFeature.h @@ -0,0 +1,34 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023 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. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" + +//================================================================================================== +/// +//================================================================================================== +class RicNewXlineSeismicSectionFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + bool isCommandEnabled() override; + void onActionTriggered( bool isChecked ) override; + void setupActionLook( QAction* actionToSetup ) override; +}; diff --git a/ApplicationLibCode/Commands/SeismicCommands/RicNewZSliceSeismicSectionFeature.cpp b/ApplicationLibCode/Commands/SeismicCommands/RicNewZSliceSeismicSectionFeature.cpp new file mode 100644 index 0000000000..9cddd4005e --- /dev/null +++ b/ApplicationLibCode/Commands/SeismicCommands/RicNewZSliceSeismicSectionFeature.cpp @@ -0,0 +1,57 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// 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 "RicNewZSliceSeismicSectionFeature.h" +#include "RicSeismicSectionFeatureImpl.h" + +#include "RimGridView.h" +#include "RimSeismicSection.h" +#include "RimSeismicSectionCollection.h" +#include "Riu3DMainWindowTools.h" + +#include "cafSelectionManagerTools.h" +#include "cafUtils.h" + +#include + +CAF_CMD_SOURCE_INIT( RicNewZSliceSeismicSectionFeature, "RicNewZSliceSeismicSectionFeature" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RicNewZSliceSeismicSectionFeature::isCommandEnabled() +{ + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewZSliceSeismicSectionFeature::onActionTriggered( bool isChecked ) +{ + RicSeismicSectionFeatureImpl::createSeismicSection( "Depth Slice", RiaDefines::SeismicSectionType::SS_DEPTHSLICE ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicNewZSliceSeismicSectionFeature::setupActionLook( QAction* actionToSetup ) +{ + actionToSetup->setIcon( QIcon( ":/Seismic16x16.png" ) ); + actionToSetup->setText( "New Depth Slice" ); +} diff --git a/ApplicationLibCode/Commands/SeismicCommands/RicNewZSliceSeismicSectionFeature.h b/ApplicationLibCode/Commands/SeismicCommands/RicNewZSliceSeismicSectionFeature.h new file mode 100644 index 0000000000..b450d61dad --- /dev/null +++ b/ApplicationLibCode/Commands/SeismicCommands/RicNewZSliceSeismicSectionFeature.h @@ -0,0 +1,34 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023 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. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafCmdFeature.h" + +//================================================================================================== +/// +//================================================================================================== +class RicNewZSliceSeismicSectionFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + bool isCommandEnabled() override; + void onActionTriggered( bool isChecked ) override; + void setupActionLook( QAction* actionToSetup ) override; +}; diff --git a/ApplicationLibCode/Commands/SeismicCommands/RicSeismicSectionFeatureImpl.cpp b/ApplicationLibCode/Commands/SeismicCommands/RicSeismicSectionFeatureImpl.cpp new file mode 100644 index 0000000000..c0875c6654 --- /dev/null +++ b/ApplicationLibCode/Commands/SeismicCommands/RicSeismicSectionFeatureImpl.cpp @@ -0,0 +1,46 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023 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 "RicSeismicSectionFeatureImpl.h" + +#include "RimSeismicSection.h" +#include "RimSeismicSectionCollection.h" +#include "Riu3DMainWindowTools.h" + +#include "cafSelectionManagerTools.h" +#include "cafUtils.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicSeismicSectionFeatureImpl::createSeismicSection( const QString& name, RiaDefines::SeismicSectionType sectionType ) +{ + // Find the selected seismic section collection + std::vector colls = caf::selectedObjectsByTypeStrict(); + if ( colls.empty() ) return; + RimSeismicSectionCollection* seisColl = colls[0]; + + RimSeismicSection* newSection = seisColl->addNewSection(); + if ( newSection ) + { + newSection->setSectionType( sectionType ); + newSection->setUserDescription( name ); + Riu3DMainWindowTools::selectAsCurrentItem( newSection ); + if ( sectionType == RiaDefines::SeismicSectionType::SS_POLYLINE ) newSection->enablePicking( true ); + } +} diff --git a/ApplicationLibCode/Commands/SeismicCommands/RicSeismicSectionFeatureImpl.h b/ApplicationLibCode/Commands/SeismicCommands/RicSeismicSectionFeatureImpl.h new file mode 100644 index 0000000000..729495053a --- /dev/null +++ b/ApplicationLibCode/Commands/SeismicCommands/RicSeismicSectionFeatureImpl.h @@ -0,0 +1,29 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023 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. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RiaSeismicDefines.h" + +class QString; + +class RicSeismicSectionFeatureImpl +{ +public: + static void createSeismicSection( const QString& name, RiaDefines::SeismicSectionType sectionType ); +}; diff --git a/ApplicationLibCode/FileInterface/CMakeLists_files.cmake b/ApplicationLibCode/FileInterface/CMakeLists_files.cmake index 09b160fa89..35b816ba1b 100644 --- a/ApplicationLibCode/FileInterface/CMakeLists_files.cmake +++ b/ApplicationLibCode/FileInterface/CMakeLists_files.cmake @@ -77,6 +77,7 @@ set(SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RifRftSegment.h ${CMAKE_CURRENT_LIST_DIR}/RifPressureDepthTextFileReader.h ${CMAKE_CURRENT_LIST_DIR}/RifReaderPressureDepthData.h + ${CMAKE_CURRENT_LIST_DIR}/RifSeismicZGYReader.h ${CMAKE_CURRENT_LIST_DIR}/RifOpmGridTools.h ${CMAKE_CURRENT_LIST_DIR}/RifCsvSummaryReader.h ${CMAKE_CURRENT_LIST_DIR}/RifRevealSummaryCsvReader.h @@ -160,6 +161,7 @@ set(SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RifRftSegment.cpp ${CMAKE_CURRENT_LIST_DIR}/RifPressureDepthTextFileReader.cpp ${CMAKE_CURRENT_LIST_DIR}/RifReaderPressureDepthData.cpp + ${CMAKE_CURRENT_LIST_DIR}/RifSeismicZGYReader.cpp ${CMAKE_CURRENT_LIST_DIR}/RifOpmGridTools.cpp ${CMAKE_CURRENT_LIST_DIR}/RifCsvSummaryReader.cpp ${CMAKE_CURRENT_LIST_DIR}/RifRevealCsvSummaryReader.cpp diff --git a/ApplicationLibCode/FileInterface/RifSeismicZGYReader.cpp b/ApplicationLibCode/FileInterface/RifSeismicZGYReader.cpp new file mode 100644 index 0000000000..f73871cb7e --- /dev/null +++ b/ApplicationLibCode/FileInterface/RifSeismicZGYReader.cpp @@ -0,0 +1,300 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2022 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 "RifSeismicZGYReader.h" + +#include +#include + +#include "cvfBoundingBox.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RifSeismicZGYReader::RifSeismicZGYReader() + : m_filename( "" ) + , m_reader( nullptr ) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RifSeismicZGYReader::~RifSeismicZGYReader() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RifSeismicZGYReader::open( QString filename ) +{ + if ( isOpen() ) close(); + + m_filename = filename; + + try + { + m_reader = std::make_unique(); + if ( !m_reader->open( filename.toStdString() ) ) + { + m_reader.reset(); + return false; + } + } + catch ( const std::exception& err ) + { + m_reader.reset(); + return false; + } + + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RifSeismicZGYReader::isOpen() const +{ + return m_reader.get() != nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RifSeismicZGYReader::isValid() +{ + if ( !isOpen() ) return false; + + bool valid = ( zStep() > 0.0 ) && ( inlineMinMaxStep()[2] > 0 ) && ( xlineMinMaxStep()[2] > 0 ); + return valid; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RifSeismicZGYReader::close() +{ + if ( !isOpen() ) return; + + try + { + m_reader->close(); + } + catch ( const std::exception& ) + { + } + + m_reader.reset(); + + return; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector> RifSeismicZGYReader::metaData() +{ + std::vector> retValues; + + if ( !isOpen() ) return retValues; + + auto stats = m_reader->metaData(); + + for ( auto& [name, val] : stats ) + { + retValues.push_back( std::make_pair( QString::fromStdString( name ), QString::fromStdString( val ) ) ); + } + + return retValues; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::BoundingBox RifSeismicZGYReader::boundingBox() +{ + cvf::BoundingBox retBox; + + if ( isOpen() ) + { + auto [zmin, zmax] = m_reader->zRange(); + + auto outline = m_reader->seismicWorldOutline(); + + auto corners = outline.points(); + for ( auto p : corners ) + { + retBox.add( cvf::Vec3d( p.x(), p.y(), -zmin ) ); + retBox.add( cvf::Vec3d( p.x(), p.y(), -zmax ) ); + } + } + + return retBox; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RifSeismicZGYReader::histogramData( std::vector& xvals, std::vector& yvals ) +{ + if ( !isOpen() ) return; + + auto histdata = m_reader->histogram(); + + xvals = histdata->Xvalues; + yvals = histdata->Yvalues; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::pair RifSeismicZGYReader::dataRange() +{ + if ( !isOpen() ) return std::make_pair( 0.0, 0.0 ); + + return m_reader->dataRange(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RifSeismicZGYReader::worldCorners() +{ + if ( !isOpen() ) return {}; + + auto [zmin, zmax] = m_reader->zRange(); + auto outline = m_reader->seismicWorldOutline(); + + std::vector retval; + + for ( auto p : outline.points() ) + { + retval.push_back( cvf::Vec3d( p.x(), p.y(), -zmin ) ); + retval.push_back( cvf::Vec3d( p.x(), p.y(), -zmax ) ); + } + + return retval; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RifSeismicZGYReader::zStep() +{ + if ( !isOpen() ) return 0.0; + + return m_reader->zStep(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RifSeismicZGYReader::zSize() +{ + if ( !isOpen() ) return 0; + + return m_reader->zSize(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3i RifSeismicZGYReader::inlineMinMaxStep() +{ + if ( !isOpen() ) return { 0, 0, 0 }; + + auto [minVal, maxVal] = m_reader->inlineRange(); + int step = m_reader->inlineStep(); + + return { minVal, maxVal, step }; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3i RifSeismicZGYReader::xlineMinMaxStep() +{ + if ( !isOpen() ) return { 0, 0, 0 }; + + auto [minVal, maxVal] = m_reader->xlineRange(); + int step = m_reader->xlineStep(); + + return { minVal, maxVal, step }; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3d RifSeismicZGYReader::convertToWorldCoords( int iLine, int xLine, double depth ) +{ + if ( !isOpen() ) return { 0, 0, 0 }; + + auto [x, y] = m_reader->toWorldCoordinate( iLine, xLine ); + + return cvf::Vec3d( x, y, depth ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::pair RifSeismicZGYReader::convertToInlineXline( double worldx, double worldy ) +{ + if ( !isOpen() ) return { 0, 0 }; + + return m_reader->toInlineXline( worldx, worldy ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::shared_ptr + RifSeismicZGYReader::slice( RiaDefines::SeismicSliceDirection direction, int sliceIndex, int zStartIndex, int zSize ) +{ + if ( isOpen() ) + { + switch ( direction ) + { + case RiaDefines::SeismicSliceDirection::INLINE: + if ( zStartIndex < 0 ) return m_reader->inlineSlice( sliceIndex ); + return m_reader->inlineSlice( sliceIndex, zStartIndex, zSize ); + case RiaDefines::SeismicSliceDirection::XLINE: + if ( zStartIndex < 0 ) return m_reader->xlineSlice( sliceIndex ); + return m_reader->xlineSlice( sliceIndex, zStartIndex, zSize ); + case RiaDefines::SeismicSliceDirection::DEPTH: + return m_reader->zSlice( sliceIndex ); + default: + break; + } + } + return nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::shared_ptr RifSeismicZGYReader::trace( int inlineIndex, int xlineIndex, int zStartIndex, int zSize ) +{ + if ( isOpen() ) + { + if ( zStartIndex < 0 ) return m_reader->zTrace( inlineIndex, xlineIndex ); + return m_reader->zTrace( inlineIndex, xlineIndex, zStartIndex, zSize ); + } + + return nullptr; +} diff --git a/ApplicationLibCode/FileInterface/RifSeismicZGYReader.h b/ApplicationLibCode/FileInterface/RifSeismicZGYReader.h new file mode 100644 index 0000000000..d7effe28a5 --- /dev/null +++ b/ApplicationLibCode/FileInterface/RifSeismicZGYReader.h @@ -0,0 +1,81 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2022 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. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cvfVector3.h" + +#include "RiaSeismicDefines.h" + +#include + +#include +#include +#include + +namespace ZGYAccess +{ +class ZGYReader; +class SeismicSliceData; +} // namespace ZGYAccess + +namespace cvf +{ +class BoundingBox; +} // namespace cvf + +class RifSeismicZGYReader +{ +public: + RifSeismicZGYReader(); + ~RifSeismicZGYReader(); + + bool open( QString filename ); + void close(); + + bool isValid(); + + bool isOpen() const; + + std::vector> metaData(); + + cvf::BoundingBox boundingBox(); + + void histogramData( std::vector& xvals, std::vector& yvals ); + + std::pair dataRange(); + + std::vector worldCorners(); + + cvf::Vec3i inlineMinMaxStep(); + cvf::Vec3i xlineMinMaxStep(); + + double zStep(); + int zSize(); + + cvf::Vec3d convertToWorldCoords( int iLine, int xLine, double depth ); + std::pair convertToInlineXline( double worldx, double worldy ); + + std::shared_ptr + slice( RiaDefines::SeismicSliceDirection direction, int sliceIndex, int zStartIndex = -1, int zSize = 0 ); + std::shared_ptr trace( int inlineIndex, int xlineIndex, int zStartIndex = -1, int zSize = 0 ); + +private: + QString m_filename; + std::unique_ptr m_reader; +}; diff --git a/ApplicationLibCode/ModelVisualization/RivPartPriority.h b/ApplicationLibCode/ModelVisualization/RivPartPriority.h index 46ab320779..abbe42fe51 100644 --- a/ApplicationLibCode/ModelVisualization/RivPartPriority.h +++ b/ApplicationLibCode/ModelVisualization/RivPartPriority.h @@ -43,6 +43,7 @@ public: TransparentFault, TransparentNnc, TransparentMeshLines, + TransparentSeismic, Highlight, Text }; diff --git a/ApplicationLibCode/ModelVisualization/RivPolylinePartMgr.cpp b/ApplicationLibCode/ModelVisualization/RivPolylinePartMgr.cpp index d0a56dadb8..9e8a5447bb 100644 --- a/ApplicationLibCode/ModelVisualization/RivPolylinePartMgr.cpp +++ b/ApplicationLibCode/ModelVisualization/RivPolylinePartMgr.cpp @@ -88,7 +88,7 @@ void RivPolylinePartMgr::buildPolylineParts( const caf::DisplayCoordTransform* d return; } - auto linesInDomain = getPolylinesPointsInDomain( polylineDef->lockToZPlane(), polylineDef->lockedZValue() ); + auto linesInDomain = getPolylinesPointsInDomain( polylineDef.p() ); if ( !isPolylinesInBoundingBox( linesInDomain, boundingBox ) ) return; @@ -185,10 +185,12 @@ void RivPolylinePartMgr::buildPolylineParts( const caf::DisplayCoordTransform* d //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -std::vector> RivPolylinePartMgr::getPolylinesPointsInDomain( bool snapToPlaneZ, double planeZ ) +std::vector> RivPolylinePartMgr::getPolylinesPointsInDomain( RigPolyLinesData* lineDef ) { - auto polylines = m_polylineInterface->polyLinesData()->polyLines(); - if ( !snapToPlaneZ ) return polylines; + auto polylines = lineDef->polyLines(); + if ( !lineDef->lockToZPlane() ) return polylines; + + const double planeZ = lineDef->lockedZValue(); std::vector> polylinesInDisplay; for ( const auto& pts : polylines ) diff --git a/ApplicationLibCode/ModelVisualization/RivPolylinePartMgr.h b/ApplicationLibCode/ModelVisualization/RivPolylinePartMgr.h index 669efd1522..b85f8a5a03 100644 --- a/ApplicationLibCode/ModelVisualization/RivPolylinePartMgr.h +++ b/ApplicationLibCode/ModelVisualization/RivPolylinePartMgr.h @@ -43,6 +43,7 @@ class DisplayCoordTransform; class Rim3dView; class RimPolylinesDataInterface; +class RigPolyLinesData; class RivPolylinePartMgr : public cvf::Object { @@ -58,7 +59,7 @@ private: bool isPolylinesInBoundingBox( std::vector> polyline, const cvf::BoundingBox& boundingBox ); void buildPolylineParts( const caf::DisplayCoordTransform* displayXf, const cvf::BoundingBox& boundingBox ); - std::vector> getPolylinesPointsInDomain( bool snapToPlaneZ, double planeZ ); + std::vector> getPolylinesPointsInDomain( RigPolyLinesData* lineDef ); std::vector> transformPolylinesPointsToDisplay( const std::vector>& pointsInDomain, const caf::DisplayCoordTransform* displayXf ); diff --git a/ApplicationLibCode/ModelVisualization/Seismic/CMakeLists_files.cmake b/ApplicationLibCode/ModelVisualization/Seismic/CMakeLists_files.cmake new file mode 100644 index 0000000000..83c9121d58 --- /dev/null +++ b/ApplicationLibCode/ModelVisualization/Seismic/CMakeLists_files.cmake @@ -0,0 +1,17 @@ +set(SOURCE_GROUP_HEADER_FILES + ${CMAKE_CURRENT_LIST_DIR}/RivSeismicSectionPartMgr.h +) + +set(SOURCE_GROUP_SOURCE_FILES + ${CMAKE_CURRENT_LIST_DIR}/RivSeismicSectionPartMgr.cpp +) + +list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES}) + +list(APPEND CODE_SOURCE_FILES ${SOURCE_GROUP_SOURCE_FILES}) + +source_group( + "ModelVisualization\\Seismic" + FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} + ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake +) diff --git a/ApplicationLibCode/ModelVisualization/Seismic/RivSeismicSectionPartMgr.cpp b/ApplicationLibCode/ModelVisualization/Seismic/RivSeismicSectionPartMgr.cpp new file mode 100644 index 0000000000..810942d41c --- /dev/null +++ b/ApplicationLibCode/ModelVisualization/Seismic/RivSeismicSectionPartMgr.cpp @@ -0,0 +1,233 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023 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 "RivSeismicSectionPartMgr.h" + +#include "RiaGuiApplication.h" + +#include "RivPartPriority.h" +#include "RivPolylinePartMgr.h" + +#include "Rim3dView.h" +#include "RimRegularLegendConfig.h" +#include "RimSeismicAlphaMapper.h" +#include "RimSeismicSection.h" +#include "RimSeismicSectionCollection.h" + +#include "RigTexturedSection.h" + +#include "cafDisplayCoordTransform.h" +#include "cafEffectGenerator.h" +#include "cafPdmObject.h" + +#include "cvfLibCore.h" +#include "cvfLibGeometry.h" +#include "cvfLibRender.h" +#include "cvfModelBasicList.h" +#include "cvfPart.h" +#include "cvfScalarMapper.h" + +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivSeismicSectionPartMgr::RivSeismicSectionPartMgr( RimSeismicSection* section ) + : m_section( section ) + , m_canUseShaders( true ) +{ + CVF_ASSERT( section ); + + m_canUseShaders = RiaGuiApplication::instance()->useShaders(); + + cvf::ShaderProgramGenerator gen( "Texturing", cvf::ShaderSourceProvider::instance() ); + gen.addVertexCode( cvf::ShaderSourceRepository::vs_Standard ); + gen.addFragmentCode( cvf::ShaderSourceRepository::src_Texture ); + gen.addFragmentCode( cvf::ShaderSourceRepository::fs_Unlit ); + m_textureShaderProg = gen.generate(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivSeismicSectionPartMgr::appendPolylinePartsToModel( Rim3dView* view, + cvf::ModelBasicList* model, + const caf::DisplayCoordTransform* transform, + const cvf::BoundingBox& boundingBox ) +{ + if ( m_polylinePartMgr.isNull() ) m_polylinePartMgr = new RivPolylinePartMgr( view, m_section.p(), m_section.p() ); + + m_polylinePartMgr->appendDynamicGeometryPartsToModel( model, transform, boundingBox ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RivSeismicSectionPartMgr::appendGeometryPartsToModel( cvf::ModelBasicList* model, + const caf::DisplayCoordTransform* displayCoordTransform, + const cvf::BoundingBox& boundingBox ) +{ + if ( !m_canUseShaders ) return; + + auto texSection = m_section->texturedSection(); + + for ( int i = 0; i < (int)texSection->partsCount(); i++ ) + { + auto& part = texSection->part( i ); + + cvf::Vec3dArray displayPoints; + displayPoints.reserve( part.rect.size() ); + + for ( auto& vOrg : part.rect ) + { + displayPoints.add( displayCoordTransform->transformToDisplayCoord( vOrg ) ); + } + + if ( part.texture.isNull() ) + { + if ( ( part.sliceData == nullptr ) || part.sliceData.get()->isEmpty() ) continue; + + part.texture = createImageFromData( part.sliceData.get() ); + } + + cvf::ref quadPart = createSingleTexturedQuadPart( displayPoints, part.texture ); + model->addPart( quadPart.p() ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref RivSeismicSectionPartMgr::createSingleTexturedQuadPart( const cvf::Vec3dArray& cornerPoints, + cvf::ref image ) +{ + cvf::ref part = new cvf::Part; + + cvf::ref geo = createXYPlaneQuadGeoWithTexCoords( cornerPoints ); + + cvf::ref texture = new cvf::Texture( image.p() ); + cvf::ref sampler = new cvf::Sampler; + sampler->setMinFilter( cvf::Sampler::LINEAR ); + sampler->setMagFilter( cvf::Sampler::NEAREST ); + sampler->setWrapModeS( cvf::Sampler::CLAMP_TO_EDGE ); + sampler->setWrapModeT( cvf::Sampler::CLAMP_TO_EDGE ); + + cvf::ref textureBindings = new cvf::RenderStateTextureBindings; + textureBindings->addBinding( texture.p(), sampler.p(), "u_texture2D" ); + + cvf::ref eff = new cvf::Effect; + eff->setRenderState( textureBindings.p() ); + eff->setShaderProgram( m_textureShaderProg.p() ); + + if ( m_section->isTransparent() ) + { + part->setPriority( RivPartPriority::PartType::TransparentSeismic ); + cvf::ref blending = new cvf::RenderStateBlending; + blending->configureTransparencyBlending(); + eff->setRenderState( blending.p() ); + } + + part->setDrawable( geo.p() ); + part->setEffect( eff.p() ); + + return part; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref RivSeismicSectionPartMgr::createXYPlaneQuadGeoWithTexCoords( const cvf::Vec3dArray& cornerPoints ) +{ + cvf::ref vertices = new cvf::Vec3fArray; + vertices->reserve( 4 ); + + for ( const auto& v : cornerPoints ) + { + vertices->add( cvf::Vec3f( v ) ); + } + + cvf::ref texCoords = new cvf::Vec2fArray; + texCoords->reserve( 4 ); + texCoords->add( cvf::Vec2f( 0, 0 ) ); + texCoords->add( cvf::Vec2f( 1, 0 ) ); + texCoords->add( cvf::Vec2f( 1, 1 ) ); + texCoords->add( cvf::Vec2f( 0, 1 ) ); + + cvf::ref geo = new cvf::DrawableGeo; + geo->setVertexArray( vertices.p() ); + geo->setTextureCoordArray( texCoords.p() ); + + cvf::ref indices = new cvf::UIntArray; + indices->reserve( 6 ); + + for ( uint i : { 0, 1, 2, 0, 2, 3 } ) + { + indices->add( i ); + } + + cvf::ref primSet = new cvf::PrimitiveSetIndexedUInt( cvf::PT_TRIANGLES ); + primSet->setIndices( indices.p() ); + geo->addPrimitiveSet( primSet.p() ); + + geo->computeNormals(); + + return geo; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::TextureImage* RivSeismicSectionPartMgr::createImageFromData( ZGYAccess::SeismicSliceData* data ) +{ + const int width = data->width(); + const int depth = data->depth(); + + cvf::TextureImage* textureImage = new cvf::TextureImage(); + textureImage->allocate( width, depth ); + + auto legend = m_section->legendConfig(); + float* pData = data->values(); + + if ( ( legend == nullptr ) || ( pData == nullptr ) ) + { + textureImage->fill( cvf::Color4ub( 0, 0, 0, 0 ) ); + return textureImage; + } + + const bool isTransparent = m_section->isTransparent(); + + auto alphaMapper = m_section->alphaValueMapper(); + auto colorMapper = legend->scalarMapper(); + + for ( int i = 0; i < width; i++ ) + { + for ( int j = depth - 1; j >= 0; j-- ) + { + auto rgb = colorMapper->mapToColor( *pData ); + + cvf::ubyte uAlpha = 255; + if ( isTransparent ) uAlpha = alphaMapper->alphaValue( *pData ); + + textureImage->setPixel( i, j, cvf::Color4ub( rgb, uAlpha ) ); + + pData++; + } + } + + return textureImage; +} diff --git a/ApplicationLibCode/ModelVisualization/Seismic/RivSeismicSectionPartMgr.h b/ApplicationLibCode/ModelVisualization/Seismic/RivSeismicSectionPartMgr.h new file mode 100644 index 0000000000..37c7a007e8 --- /dev/null +++ b/ApplicationLibCode/ModelVisualization/Seismic/RivSeismicSectionPartMgr.h @@ -0,0 +1,77 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023 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. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "cafPdmPointer.h" +#include "cvfArray.h" +#include "cvfObject.h" + +namespace cvf +{ +class ModelBasicList; +class Transform; +class Part; +class ScalarMapper; +class DrawableGeo; +class BoundingBox; +class ShaderProgram; +class TextureImage; +} // namespace cvf + +namespace caf +{ +class DisplayCoordTransform; +} + +namespace ZGYAccess +{ +class SeismicSliceData; +} + +class RimSeismicSectionCollection; +class RimSeismicSection; +class Rim3dView; +class RivPolylinePartMgr; + +class RivSeismicSectionPartMgr : public cvf::Object +{ +public: + explicit RivSeismicSectionPartMgr( RimSeismicSection* section ); + + void appendGeometryPartsToModel( cvf::ModelBasicList* model, + const caf::DisplayCoordTransform* displayCoordTransform, + const cvf::BoundingBox& boundingBox ); + + void appendPolylinePartsToModel( Rim3dView* view, + cvf::ModelBasicList* model, + const caf::DisplayCoordTransform* displayCoordTransform, + const cvf::BoundingBox& boundingBox ); + +protected: + cvf::ref createXYPlaneQuadGeoWithTexCoords( const cvf::Vec3dArray& cornerPoints ); + cvf::ref createSingleTexturedQuadPart( const cvf::Vec3dArray& cornerPoints, cvf::ref image ); + + cvf::TextureImage* createImageFromData( ZGYAccess::SeismicSliceData* data ); + +private: + caf::PdmPointer m_section; + cvf::ref m_polylinePartMgr; + cvf::ref m_textureShaderProg; + + bool m_canUseShaders; +}; diff --git a/ApplicationLibCode/ProjectDataModel/GeoMech/RimGeoMechView.cpp b/ApplicationLibCode/ProjectDataModel/GeoMech/RimGeoMechView.cpp index e6b69de4c0..77739ac17b 100644 --- a/ApplicationLibCode/ProjectDataModel/GeoMech/RimGeoMechView.cpp +++ b/ApplicationLibCode/ProjectDataModel/GeoMech/RimGeoMechView.cpp @@ -45,6 +45,8 @@ #include "RimIntersectionResultDefinition.h" #include "RimIntersectionResultsDefinitionCollection.h" #include "RimRegularLegendConfig.h" +#include "RimSeismicSection.h" +#include "RimSeismicSectionCollection.h" #include "RimSurfaceInViewCollection.h" #include "RimTensorResults.h" #include "RimTernaryLegendConfig.h" @@ -319,6 +321,13 @@ void RimGeoMechView::onCreateDisplayModel() m_intersectionCollection->appendPartsToModel( *this, m_intersectionVizModel.p(), scaleTransform() ); nativeOrOverrideViewer()->addStaticModelOnce( m_intersectionVizModel.p(), isUsingOverrideViewer() ); + // Seismic sections + + cvf::ref transform = displayCoordTransform(); + m_seismicVizModel->removeAllParts(); + m_seismicSectionCollection->appendPartsToModel( this, m_seismicVizModel.p(), transform.p(), femBBox ); + nativeOrOverrideViewer()->addStaticModelOnce( m_seismicVizModel.p(), isUsingOverrideViewer() ); + // Surfaces m_surfaceVizModel->removeAllParts(); @@ -591,6 +600,11 @@ void RimGeoMechView::onUpdateLegends() { m_surfaceCollection->updateLegendRangesTextAndVisibility( nativeOrOverrideViewer(), isUsingOverrideViewer() ); } + + if ( m_seismicSectionCollection->isChecked() ) + { + m_seismicSectionCollection->updateLegendRangesTextAndVisibility( nativeOrOverrideViewer(), isUsingOverrideViewer() ); + } } } @@ -704,6 +718,11 @@ std::vector RimGeoMechView::legendConfigs() const } } + for ( auto section : seismicSectionCollection()->seismicSections() ) + { + absLegendConfigs.push_back( section->legendConfig() ); + } + absLegendConfigs.erase( std::remove( absLegendConfigs.begin(), absLegendConfigs.end(), nullptr ), absLegendConfigs.end() ); return absLegendConfigs; @@ -1037,6 +1056,7 @@ void RimGeoMechView::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrderin uiTreeOrdering.add( m_intersectionCollection() ); if ( surfaceInViewCollection() ) uiTreeOrdering.add( surfaceInViewCollection() ); + uiTreeOrdering.add( seismicSectionCollection() ); uiTreeOrdering.skipRemainingChildren( true ); } diff --git a/ApplicationLibCode/ProjectDataModel/Rim3dView.cpp b/ApplicationLibCode/ProjectDataModel/Rim3dView.cpp index 3090d928f6..b81aed2232 100644 --- a/ApplicationLibCode/ProjectDataModel/Rim3dView.cpp +++ b/ApplicationLibCode/ProjectDataModel/Rim3dView.cpp @@ -153,6 +153,9 @@ Rim3dView::Rim3dView() m_intersectionVizModel = new cvf::ModelBasicList; m_intersectionVizModel->setName( "CrossSectionModel" ); + m_seismicVizModel = new cvf::ModelBasicList; + m_seismicVizModel->setName( "SeismicSectionModel" ); + m_highlightVizModel = new cvf::ModelBasicList; m_highlightVizModel->setName( "HighlightModel" ); @@ -1142,14 +1145,15 @@ bool Rim3dView::isMasterView() const //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -void Rim3dView::updateGridBoxData() +cvf::BoundingBox Rim3dView::domainBoundingBox() { + cvf::BoundingBox combinedDomainBBox; + if ( viewer() && ownerCase() ) { - using BBox = cvf::BoundingBox; - - BBox masterDomainBBox = isShowingActiveCellsOnly() ? ownerCase()->activeCellsBoundingBox() : ownerCase()->allCellsBoundingBox(); - BBox combinedDomainBBox = masterDomainBBox; + cvf::BoundingBox masterDomainBBox = isShowingActiveCellsOnly() ? ownerCase()->activeCellsBoundingBox() + : ownerCase()->allCellsBoundingBox(); + combinedDomainBBox.add( masterDomainBBox ); if ( Rim3dView* depView = activeComparisonView() ) { @@ -1159,17 +1163,25 @@ void Rim3dView::updateGridBoxData() if ( destinationOwnerCase ) { - BBox depDomainBBox = depView->isShowingActiveCellsOnly() ? destinationOwnerCase->activeCellsBoundingBox() - : destinationOwnerCase->allCellsBoundingBox(); - if ( depDomainBBox.isValid() ) - { - combinedDomainBBox.add( depDomainBBox.min() ); - combinedDomainBBox.add( depDomainBBox.max() ); - } + cvf::BoundingBox depDomainBBox = depView->isShowingActiveCellsOnly() ? destinationOwnerCase->activeCellsBoundingBox() + : destinationOwnerCase->allCellsBoundingBox(); + + combinedDomainBBox.add( depDomainBBox ); } } + } - viewer()->updateGridBoxData( m_scaleZ(), ownerCase()->displayModelOffset(), backgroundColor(), combinedDomainBBox, fontSize() ); + return combinedDomainBBox; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void Rim3dView::updateGridBoxData() +{ + if ( viewer() && ownerCase() ) + { + viewer()->updateGridBoxData( m_scaleZ(), ownerCase()->displayModelOffset(), backgroundColor(), domainBoundingBox(), fontSize() ); } } diff --git a/ApplicationLibCode/ProjectDataModel/Rim3dView.h b/ApplicationLibCode/ProjectDataModel/Rim3dView.h index b33f2cea27..b7baae4074 100644 --- a/ApplicationLibCode/ProjectDataModel/Rim3dView.h +++ b/ApplicationLibCode/ProjectDataModel/Rim3dView.h @@ -169,6 +169,8 @@ public: void updateAnnotationItems(); void resetLegends(); + cvf::BoundingBox domainBoundingBox(); + void setScaleZ( double scaleZ ); void setScaleZAndUpdate( double scaleZ ); void updateScaling(); @@ -256,6 +258,7 @@ protected: // 3D display model data cvf::ref m_wellPathPipeVizModel; cvf::ref m_intersectionVizModel; + cvf::ref m_seismicVizModel; cvf::ref m_wellPathsPartManager; caf::PdmField m_scaleZ; diff --git a/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp b/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp index 8b98018ef4..d3308dfa85 100644 --- a/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimContextCommandBuilder.cpp @@ -112,6 +112,8 @@ #include "RimRftPlotCollection.h" #include "RimSaturationPressurePlotCollection.h" #include "RimScriptCollection.h" +#include "RimSeismicDataCollection.h" +#include "RimSeismicSectionCollection.h" #include "RimSimWellFracture.h" #include "RimSimWellInView.h" #include "RimSimWellInViewCollection.h" @@ -1032,6 +1034,17 @@ caf::CmdFeatureMenuBuilder RimContextCommandBuilder::commandsFromSelection() menuBuilder << "RicNewRangeFilterSliceKFeature"; menuBuilder.subMenuEnd(); } + else if ( dynamic_cast( firstUiItem ) ) + { + menuBuilder << "RicNewInlineSeismicSectionFeature"; + menuBuilder << "RicNewXlineSeismicSectionFeature"; + menuBuilder << "RicNewZSliceSeismicSectionFeature"; + menuBuilder << "RicNewPolylineSeismicSectionFeature"; + } + else if ( dynamic_cast( firstUiItem ) ) + { + menuBuilder << "RicImportSeismicFeature"; + } else if ( dynamic_cast( firstUiItem ) || dynamic_cast( firstUiItem ) ) { menuBuilder << "RicCreateTextAnnotationFeature"; diff --git a/ApplicationLibCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationLibCode/ProjectDataModel/RimEclipseView.cpp index 6e85b80872..b007df4846 100644 --- a/ApplicationLibCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimEclipseView.cpp @@ -71,6 +71,8 @@ #include "RimProject.h" #include "RimRegularLegendConfig.h" #include "RimReservoirCellResultsStorage.h" +#include "RimSeismicSection.h" +#include "RimSeismicSectionCollection.h" #include "RimSimWellFracture.h" #include "RimSimWellInView.h" #include "RimSimWellInViewCollection.h" @@ -591,6 +593,13 @@ void RimEclipseView::onCreateDisplayModel() m_intersectionCollection->appendPartsToModel( *this, m_intersectionVizModel.p(), m_reservoirGridPartManager->scaleTransform() ); nativeOrOverrideViewer()->addStaticModelOnce( m_intersectionVizModel.p(), isUsingOverrideViewer() ); + // Seismic sections + + cvf::ref transform = displayCoordTransform(); + m_seismicVizModel->removeAllParts(); + m_seismicSectionCollection->appendPartsToModel( this, m_seismicVizModel.p(), transform.p(), ownerCase()->allCellsBoundingBox() ); + nativeOrOverrideViewer()->addStaticModelOnce( m_seismicVizModel.p(), isUsingOverrideViewer() ); + // Surfaces m_surfaceVizModel->removeAllParts(); @@ -1468,6 +1477,11 @@ void RimEclipseView::onUpdateLegends() m_surfaceCollection->updateLegendRangesTextAndVisibility( nativeOrOverrideViewer(), isUsingOverrideViewer() ); } + if ( m_seismicSectionCollection->isChecked() ) + { + m_seismicSectionCollection->updateLegendRangesTextAndVisibility( nativeOrOverrideViewer(), isUsingOverrideViewer() ); + } + if ( m_streamlineCollection ) { m_streamlineCollection->updateLegendRangesTextAndVisibility( nativeOrOverrideViewer(), isUsingOverrideViewer() ); @@ -1918,6 +1932,8 @@ void RimEclipseView::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrderin if ( surfaceInViewCollection() ) uiTreeOrdering.add( surfaceInViewCollection() ); + uiTreeOrdering.add( seismicSectionCollection() ); + uiTreeOrdering.skipRemainingChildren( true ); } @@ -2243,6 +2259,11 @@ std::vector RimEclipseView::legendConfigs() const } } + for ( auto section : seismicSectionCollection()->seismicSections() ) + { + absLegends.push_back( section->legendConfig() ); + } + absLegends.erase( std::remove( absLegends.begin(), absLegends.end(), nullptr ), absLegends.end() ); return absLegends; diff --git a/ApplicationLibCode/ProjectDataModel/RimGridView.cpp b/ApplicationLibCode/ProjectDataModel/RimGridView.cpp index 89fe775339..bfe41d0f9d 100644 --- a/ApplicationLibCode/ProjectDataModel/RimGridView.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimGridView.cpp @@ -31,6 +31,7 @@ #include "RimOilField.h" #include "RimProject.h" #include "RimPropertyFilterCollection.h" +#include "RimSeismicSectionCollection.h" #include "RimSurfaceCollection.h" #include "RimSurfaceInView.h" #include "RimSurfaceInViewCollection.h" @@ -100,6 +101,10 @@ RimGridView::RimGridView() CAF_PDM_InitFieldNoDefault( &m_surfaceCollection, "SurfaceInViewCollection", "Surface Collection Field" ); m_surfaceCollection.uiCapability()->setUiTreeHidden( true ); + CAF_PDM_InitFieldNoDefault( &m_seismicSectionCollection, "SeismicSectionCollection", "Seismic Collection Field" ); + m_seismicSectionCollection.uiCapability()->setUiTreeHidden( true ); + m_seismicSectionCollection = new RimSeismicSectionCollection(); + CAF_PDM_InitFieldNoDefault( &m_cellFilterCollection, "RangeFilters", "Cell Filter Collection Field" ); m_cellFilterCollection = new RimCellFilterCollection(); m_cellFilterCollection.uiCapability()->setUiTreeHidden( true ); @@ -154,6 +159,14 @@ RimSurfaceInViewCollection* RimGridView::surfaceInViewCollection() const return m_surfaceCollection(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSeismicSectionCollection* RimGridView::seismicSectionCollection() const +{ + return m_seismicSectionCollection(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModel/RimGridView.h b/ApplicationLibCode/ProjectDataModel/RimGridView.h index 6969ab4e15..be50b6a2ea 100644 --- a/ApplicationLibCode/ProjectDataModel/RimGridView.h +++ b/ApplicationLibCode/ProjectDataModel/RimGridView.h @@ -32,6 +32,7 @@ class RimGridCollection; class RimCellFilterCollection; class RimWellMeasurementInViewCollection; class RimSurfaceInViewCollection; +class RimSeismicSectionCollection; class RimGridView : public Rim3dView { @@ -52,6 +53,7 @@ public: RimIntersectionResultsDefinitionCollection* separateSurfaceResultsCollection() const; RimAnnotationInViewCollection* annotationCollection() const; RimWellMeasurementInViewCollection* measurementCollection() const; + RimSeismicSectionCollection* seismicSectionCollection() const; virtual const RimPropertyFilterCollection* propertyFilterCollection() const = 0; @@ -96,6 +98,7 @@ protected: caf::PdmChildField m_surfaceCollection; caf::PdmChildField m_cellFilterCollection; caf::PdmChildField m_overrideCellFilterCollection; + caf::PdmChildField m_seismicSectionCollection; private: void onCreatePartCollectionFromSelection( cvf::Collection* parts ) override; diff --git a/ApplicationLibCode/ProjectDataModel/RimOilField.cpp b/ApplicationLibCode/ProjectDataModel/RimOilField.cpp index 1b0573211e..230f2dcc0f 100644 --- a/ApplicationLibCode/ProjectDataModel/RimOilField.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimOilField.cpp @@ -29,6 +29,7 @@ #include "RimGeoMechModels.h" #include "RimMeasurement.h" #include "RimObservedDataCollection.h" +#include "RimSeismicDataCollection.h" #include "RimSummaryCaseMainCollection.h" #include "RimSurfaceCollection.h" #include "RimWellPathCollection.h" @@ -64,6 +65,9 @@ RimOilField::RimOilField( void ) surfaceCollection = new RimSurfaceCollection(); surfaceCollection->setAsTopmostFolder(); + CAF_PDM_InitFieldNoDefault( &seismicCollection, "SeismicCollection", "Seismic Data" ); + seismicCollection = new RimSeismicDataCollection(); + completionTemplateCollection = new RimCompletionTemplateCollection; analysisModels = new RimEclipseCaseCollection(); wellPathCollection = new RimWellPathCollection(); diff --git a/ApplicationLibCode/ProjectDataModel/RimOilField.h b/ApplicationLibCode/ProjectDataModel/RimOilField.h index f62f3a6f67..d9196344c9 100644 --- a/ApplicationLibCode/ProjectDataModel/RimOilField.h +++ b/ApplicationLibCode/ProjectDataModel/RimOilField.h @@ -37,6 +37,7 @@ class RimSummaryCaseMainCollection; class RimWellPathCollection; class RimAnnotationCollection; class RimMeasurement; +class RimSeismicDataCollection; class RimSurfaceCollection; class RimEnsembleWellLogsCollection; @@ -68,6 +69,7 @@ public: caf::PdmChildField annotationCollection; caf::PdmChildField measurement; caf::PdmChildField surfaceCollection; + caf::PdmChildField seismicCollection; caf::PdmChildField ensembleWellLogsCollection; protected: diff --git a/ApplicationLibCode/ProjectDataModel/RimProject.cpp b/ApplicationLibCode/ProjectDataModel/RimProject.cpp index 9e72498fce..d0ff871198 100644 --- a/ApplicationLibCode/ProjectDataModel/RimProject.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimProject.cpp @@ -72,6 +72,7 @@ #include "RimRftPlotCollection.h" #include "RimSaturationPressurePlotCollection.h" #include "RimScriptCollection.h" +#include "RimSeismicDataCollection.h" #include "RimStimPlanModelPlotCollection.h" #include "RimSummaryCalculation.h" #include "RimSummaryCalculationCollection.h" @@ -1517,6 +1518,7 @@ void RimProject::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, Q if ( oilField->geoMechModels() ) uiTreeOrdering.add( oilField->geoMechModels() ); if ( oilField->wellPathCollection() ) uiTreeOrdering.add( oilField->wellPathCollection() ); if ( oilField->surfaceCollection() ) uiTreeOrdering.add( oilField->surfaceCollection() ); + if ( oilField->seismicCollection() ) uiTreeOrdering.add( oilField->seismicCollection() ); if ( oilField->formationNamesCollection() ) uiTreeOrdering.add( oilField->formationNamesCollection() ); if ( oilField->completionTemplateCollection() ) uiTreeOrdering.add( oilField->completionTemplateCollection() ); if ( oilField->annotationCollection() ) uiTreeOrdering.add( oilField->annotationCollection() ); diff --git a/ApplicationLibCode/ProjectDataModel/RimRegularLegendConfig.cpp b/ApplicationLibCode/ProjectDataModel/RimRegularLegendConfig.cpp index c65d65ac8a..fc5174c9b4 100644 --- a/ApplicationLibCode/ProjectDataModel/RimRegularLegendConfig.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimRegularLegendConfig.cpp @@ -586,6 +586,17 @@ void RimRegularLegendConfig::setTickNumberFormat( RiaNumberFormat::NumberFormatT m_tickNumberFormat = numberFormat; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimRegularLegendConfig::setUserDefinedRange( double minVal, double maxVal ) +{ + m_userDefinedMinValue = minVal; + m_userDefinedMaxValue = maxVal; + updateLegend(); + sendChangedSignal( &m_userDefinedMaxValue ); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -1265,6 +1276,15 @@ void RimRegularLegendConfig::defineUiOrdering( QString uiConfigName, caf::PdmUiO updateFieldVisibility(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimRegularLegendConfig::defineUiOrderingColorOnly( caf::PdmUiOrdering* colorGroup ) +{ + colorGroup->add( &m_colorLegend, { true, 2, 1 } ); + colorGroup->add( &m_selectColorLegendButton, { false, 1, 0 } ); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModel/RimRegularLegendConfig.h b/ApplicationLibCode/ProjectDataModel/RimRegularLegendConfig.h index 74a0504449..2b7ec192c7 100644 --- a/ApplicationLibCode/ProjectDataModel/RimRegularLegendConfig.h +++ b/ApplicationLibCode/ProjectDataModel/RimRegularLegendConfig.h @@ -130,6 +130,7 @@ public: void setTickNumberFormat( RiaNumberFormat::NumberFormatType numberFormat ); void resetUserDefinedValues(); void setCenterLegendAroundZero( bool enable ); + void setUserDefinedRange( double minVal, double maxVal ); void disableAllTimeStepsRange( bool doDisable ); @@ -171,6 +172,8 @@ public: void setDefaultConfigForResultName( const QString& resultName, bool useDiscreteLogLevels, bool isCategoryResult ); + void defineUiOrderingColorOnly( caf::PdmUiOrdering* colorGroup ); + private: void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; void sendChangedSignal( const caf::PdmFieldHandle* changedField ); diff --git a/ApplicationLibCode/ProjectDataModel/RimTools.cpp b/ApplicationLibCode/ProjectDataModel/RimTools.cpp index a4c2d9fd6b..89bc4cf3a6 100644 --- a/ApplicationLibCode/ProjectDataModel/RimTools.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimTools.cpp @@ -27,6 +27,8 @@ #include "RimGeoMechCase.h" #include "RimOilField.h" #include "RimProject.h" +#include "RimSeismicData.h" +#include "RimSeismicDataCollection.h" #include "RimWellLogFile.h" #include "RimWellPath.h" #include "RimWellPathCollection.h" @@ -371,6 +373,26 @@ void RimTools::geoMechCaseOptionItems( QList* options ) } } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimTools::seismicDataOptionItems( QList* options, cvf::BoundingBox worldBBox ) +{ + if ( !options ) return; + + RimProject* proj = RimProject::current(); + if ( proj ) + { + const auto& coll = proj->activeOilField()->seismicCollection().p(); + + for ( auto* c : coll->seismicData() ) + { + if ( c->boundingBox()->intersects( worldBBox ) ) + options->push_back( caf::PdmOptionItemInfo( c->userDescription(), c, false, c->uiIconProvider() ) ); + } + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/ProjectDataModel/RimTools.h b/ApplicationLibCode/ProjectDataModel/RimTools.h index 50884b3f19..e18e5b0af1 100644 --- a/ApplicationLibCode/ProjectDataModel/RimTools.h +++ b/ApplicationLibCode/ProjectDataModel/RimTools.h @@ -20,6 +20,8 @@ #pragma once +#include "cvfBoundingBox.h" + #include #include @@ -58,6 +60,8 @@ public: static void eclipseCaseOptionItems( QList* options ); static void geoMechCaseOptionItems( QList* options ); static void colorLegendOptionItems( QList* options ); + static void seismicDataOptionItems( QList* options, cvf::BoundingBox worldBBox ); + static RimWellPathCollection* wellPathCollection(); static void timeStepsForCase( RimCase* gridCase, QList* options ); diff --git a/ApplicationLibCode/ProjectDataModel/Seismic/CMakeLists_files.cmake b/ApplicationLibCode/ProjectDataModel/Seismic/CMakeLists_files.cmake new file mode 100644 index 0000000000..813c017603 --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Seismic/CMakeLists_files.cmake @@ -0,0 +1,25 @@ +set(SOURCE_GROUP_HEADER_FILES + ${CMAKE_CURRENT_LIST_DIR}/RimSeismicDataCollection.h + ${CMAKE_CURRENT_LIST_DIR}/RimSeismicData.h + ${CMAKE_CURRENT_LIST_DIR}/RimSeismicSectionCollection.h + ${CMAKE_CURRENT_LIST_DIR}/RimSeismicSection.h + ${CMAKE_CURRENT_LIST_DIR}/RimSeismicAlphaMapper.h +) + +set(SOURCE_GROUP_SOURCE_FILES + ${CMAKE_CURRENT_LIST_DIR}/RimSeismicDataCollection.cpp + ${CMAKE_CURRENT_LIST_DIR}/RimSeismicData.cpp + ${CMAKE_CURRENT_LIST_DIR}/RimSeismicSectionCollection.cpp + ${CMAKE_CURRENT_LIST_DIR}/RimSeismicSection.cpp + ${CMAKE_CURRENT_LIST_DIR}/RimSeismicAlphaMapper.cpp +) + +list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES}) + +list(APPEND CODE_SOURCE_FILES ${SOURCE_GROUP_SOURCE_FILES}) + +source_group( + "ProjectDataModel\\Seismic" + FILES ${SOURCE_GROUP_HEADER_FILES} ${SOURCE_GROUP_SOURCE_FILES} + ${CMAKE_CURRENT_LIST_DIR}/CMakeLists_files.cmake +) diff --git a/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicAlphaMapper.cpp b/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicAlphaMapper.cpp new file mode 100644 index 0000000000..a888f24855 --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicAlphaMapper.cpp @@ -0,0 +1,65 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023 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 "RimSeismicAlphaMapper.h" + +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSeismicAlphaMapper::RimSeismicAlphaMapper() + : m_maxValue( 0.0 ) + , m_minValue( 0.0 ) + , m_dataRange( 0.0 ) + , m_scaleFactor( 0.0 ) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSeismicAlphaMapper::~RimSeismicAlphaMapper() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicAlphaMapper::setDataRangeAndAlphas( double minVal, double maxVal, std::vector alphas ) +{ + m_minValue = minVal; + m_maxValue = maxVal; + m_dataRange = maxVal - minVal; + m_alphavalues = alphas; + + if ( m_dataRange != 0.0 ) + m_scaleFactor = 1.0 * alphas.size() / m_dataRange; + else + m_scaleFactor = 0.0; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ubyte RimSeismicAlphaMapper::alphaValue( double dataValue ) const +{ + int index = (int)( m_scaleFactor * ( dataValue - m_minValue ) ); + + return ( cvf::ubyte )( m_alphavalues[index] * 255 ); +} diff --git a/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicAlphaMapper.h b/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicAlphaMapper.h new file mode 100644 index 0000000000..7e0fe39043 --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicAlphaMapper.h @@ -0,0 +1,40 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023 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. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "cvfBase.h" + +#include + +class RimSeismicAlphaMapper +{ +public: + RimSeismicAlphaMapper(); + ~RimSeismicAlphaMapper(); + + void setDataRangeAndAlphas( double minVal, double maxVal, std::vector alphas ); + + cvf::ubyte alphaValue( double dataValue ) const; + +private: + std::vector m_alphavalues; + double m_maxValue; + double m_minValue; + double m_dataRange; + double m_scaleFactor; +}; diff --git a/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicData.cpp b/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicData.cpp new file mode 100644 index 0000000000..982b15f79b --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicData.cpp @@ -0,0 +1,683 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2022 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 "RimSeismicData.h" + +#include "RiaLogging.h" + +#include "RifSeismicZGYReader.h" + +#include "RimRegularLegendConfig.h" +#include "RimSeismicAlphaMapper.h" +#include "RimStringParameter.h" + +#include "RiuMainWindow.h" +#include "RiuSeismicHistogramPanel.h" + +#include + +#include "cafPdmUiLineEditor.h" +#include "cafPdmUiTableViewEditor.h" +#include "cafPdmUiTreeOrdering.h" +#include "cvfBoundingBox.h" + +#include + +#include +#include +#include +#include + +CAF_PDM_SOURCE_INIT( RimSeismicData, "SeismicData" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSeismicData::RimSeismicData() + : m_zStep( 0 ) + , m_filereader( nullptr ) + , m_nErrorsLogged( 0 ) + , m_fileDataRange( 0, 0 ) + , m_activeDataRange( 0, 0 ) +{ + CAF_PDM_InitObject( "SeismicData", ":/Seismic16x16.png" ); + + CAF_PDM_InitFieldNoDefault( &m_userDescription, "SeismicUserDecription", "Name" ); + + CAF_PDM_InitFieldNoDefault( &m_filename, "SeismicFilePath", "File" ); + m_filename.uiCapability()->setUiReadOnly( true ); + + CAF_PDM_InitFieldNoDefault( &m_legendConfig, "LegendDefinition", "Color Legend" ); + m_legendConfig = new RimRegularLegendConfig(); + m_legendConfig.uiCapability()->setUiTreeHidden( true ); + + CAF_PDM_InitFieldNoDefault( &m_metadata, "Metadata", "Metadata" ); + m_metadata.uiCapability()->setUiEditorTypeName( caf::PdmUiTableViewEditor::uiEditorTypeName() ); + m_metadata.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::HIDDEN ); + m_metadata.uiCapability()->setUiTreeChildrenHidden( true ); + m_metadata.uiCapability()->setUiTreeHidden( true ); + m_metadata.uiCapability()->setUiReadOnly( true ); + m_metadata.xmlCapability()->disableIO(); + + CAF_PDM_InitField( &m_overrideDataRange, "overrideDataRange", false, "Override Data Range" ); + CAF_PDM_InitField( &m_userClipValue, "userClipValue", 0.0, "Clip Value" ); + + setDeletable( true ); + + m_boundingBox = std::make_shared(); + m_alphaValueMapper = std::make_shared(); + + initColorLegend(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSeismicData::~RimSeismicData() +{ + if ( m_filereader != nullptr ) m_filereader->close(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimSeismicData::openFileIfNotOpen() +{ + if ( m_filereader == nullptr ) + { + m_filereader = std::make_shared(); + } + + if ( m_filereader->isOpen() ) return true; + + QString filename = m_filename().path(); + + if ( filename.isEmpty() ) return false; + + if ( QFile::exists( filename ) ) + { + if ( !m_filereader->open( filename ) ) + { + logError( "Unable to open seismic file : " + filename ); + m_filereader.reset(); + return false; + } + if ( !m_filereader->isValid() ) + { + logError( "Seismic file has invalid header values. Cannot import file: " + filename ); + m_filereader->close(); + m_filereader.reset(); + return false; + } + } + else + { + logError( "Seismic file not found: " + filename ); + return false; + } + return true; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicData::logError( QString msg ) +{ + if ( m_nErrorsLogged < 4 ) RiaLogging::error( msg ); + m_nErrorsLogged++; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicData::initAfterRead() +{ + updateMetaData(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicData::setFileName( QString filename ) +{ + if ( filename != m_filename().path() ) + { + if ( m_filereader != nullptr ) m_filereader->close(); + m_nErrorsLogged = 0; + m_filename = filename; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimSeismicData::fileName() const +{ + return m_filename().path(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimSeismicData::userDescription() +{ + return m_userDescription; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicData::setUserDescription( QString description ) +{ + m_userDescription = description; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimSeismicData::userDescriptionField() +{ + return &m_userDescription; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicData::updateMetaData() +{ + m_metadata.deleteChildren(); + m_boundingBox->reset(); + m_worldOutline.clear(); + + if ( !openFileIfNotOpen() ) return; + + auto metadata = m_filereader->metaData(); + + for ( auto& [name, value] : metadata ) + { + auto param = new RimStringParameter(); + param->setLabel( name ); + param->setValue( value ); + m_metadata.push_back( param ); + } + + m_boundingBox->add( m_filereader->boundingBox() ); + + m_zStep = m_filereader->zStep(); + + auto [minDataValue, maxDataValue] = m_filereader->dataRange(); + double maxAbsDataValue = std::max( std::abs( minDataValue ), std::abs( maxDataValue ) ); + + if ( m_userClipValue <= 0.0 ) m_userClipValue = maxAbsDataValue; + + m_userClipValue = std::clamp( m_userClipValue(), 0.0, maxAbsDataValue ); + + m_filereader->histogramData( m_histogramXvalues, m_histogramYvalues ); + + for ( auto& p : m_filereader->worldCorners() ) + { + m_worldOutline.push_back( p ); + } + + m_inlineInfo = m_filereader->inlineMinMaxStep(); + m_xlineInfo = m_filereader->xlineMinMaxStep(); + + m_fileDataRange = m_filereader->dataRange(); + + updateDataRange( false ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimSeismicData::worldOutline() const +{ + return m_worldOutline; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicData::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) +{ + if ( m_metadata.empty() ) + { + updateMetaData(); + } + + auto genGroup = uiOrdering.addNewGroup( "General" ); + genGroup->add( &m_userDescription ); + genGroup->add( &m_filename ); + + auto cmGroup = uiOrdering.addNewGroup( "Color Mapping" ); + m_legendConfig->defineUiOrderingColorOnly( cmGroup ); + cmGroup->add( &m_overrideDataRange ); + if ( m_overrideDataRange() ) + { + cmGroup->add( &m_userClipValue ); + } + + auto metaGroup = uiOrdering.addNewGroup( "File Information" ); + metaGroup->add( &m_metadata ); + metaGroup->setCollapsedByDefault(); + + uiOrdering.skipRemainingFields(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicData::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= "" */ ) +{ + uiTreeOrdering.skipRemainingChildren(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicData::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) +{ + if ( field == &m_metadata ) + { + auto tvAttribute = dynamic_cast( attribute ); + if ( tvAttribute ) + { + tvAttribute->resizePolicy = caf::PdmUiTableViewEditorAttribute::RESIZE_TO_FILL_CONTAINER; + tvAttribute->alwaysEnforceResizePolicy = true; + tvAttribute->minimumHeight = 400; + } + } + else if ( field == &m_userClipValue ) + { + auto myAttr = dynamic_cast( attribute ); + if ( myAttr ) + { + myAttr->validator = new QDoubleValidator( 0.00001, std::numeric_limits::infinity(), 6 ); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::BoundingBox* RimSeismicData::boundingBox() const +{ + return m_boundingBox.get(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimSeismicData::zMin() const +{ + return std::abs( m_boundingBox->max().z() ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimSeismicData::zMax() const +{ + return std::abs( m_boundingBox->min().z() ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +double RimSeismicData::zStep() const +{ + return m_zStep; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimSeismicData::inlineMin() const +{ + return m_inlineInfo[0]; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimSeismicData::inlineMax() const +{ + return m_inlineInfo[1]; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimSeismicData::inlineStep() const +{ + return m_inlineInfo[2]; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimSeismicData::xlineMin() const +{ + return m_xlineInfo[0]; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimSeismicData::xlineMax() const +{ + return m_xlineInfo[1]; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimSeismicData::xlineStep() const +{ + return m_xlineInfo[2]; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimSeismicData::toInlineIndex( int inLine ) const +{ + int iIndex = inLine - inlineMin(); + iIndex /= inlineStep(); + + return iIndex; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimSeismicData::toXlineIndex( int xLine ) const +{ + int xIndex = xLine - xlineMin(); + xIndex /= xlineStep(); + + return xIndex; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimSeismicData::toZIndex( double z ) const +{ + int zIndex = (int)( ( z - zMin() ) / zStep() ); + return zIndex; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimSeismicData::histogramXvalues() const +{ + return m_clippedHistogramXvalues; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimSeismicData::histogramYvalues() const +{ + return m_clippedHistogramYvalues; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimSeismicData::alphaValues() const +{ + return m_clippedAlphaValues; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicData::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) +{ + if ( ( changedField == &m_overrideDataRange ) || ( changedField == &m_userClipValue ) ) + { + updateDataRange( true ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicData::updateDataRange( bool updatePlot ) +{ + m_clippedHistogramXvalues.clear(); + m_clippedHistogramYvalues.clear(); + m_clippedAlphaValues.clear(); + + double clipValue = m_userClipValue; + + if ( m_overrideDataRange() ) + { + m_activeDataRange = std::make_pair( -m_userClipValue, m_userClipValue ); + } + else + { + m_activeDataRange = std::make_pair( m_fileDataRange.first, m_fileDataRange.second ); + clipValue = m_fileDataRange.second; + } + + const int nVals = (int)m_histogramXvalues.size(); + + for ( int i = 0; i < nVals; i++ ) + { + double tmp = std::abs( m_histogramXvalues[i] ); + if ( tmp > clipValue ) continue; + m_clippedHistogramXvalues.push_back( m_histogramXvalues[i] ); + m_clippedHistogramYvalues.push_back( m_histogramYvalues[i] ); + } + + double maxRawValue = *std::max_element( m_clippedHistogramYvalues.begin(), m_clippedHistogramYvalues.end() ); + for ( auto val : m_clippedHistogramYvalues ) + { + m_clippedAlphaValues.push_back( 1.0 - std::clamp( val / maxRawValue, 0.0, 1.0 ) ); + } + + m_alphaValueMapper->setDataRangeAndAlphas( m_activeDataRange.first, m_activeDataRange.second, m_clippedAlphaValues ); + m_legendConfig->setUserDefinedRange( m_activeDataRange.first, m_activeDataRange.second ); + + if ( updatePlot ) RiuMainWindow::instance()->seismicHistogramPanel()->showHistogram( this ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::Vec3d RimSeismicData::convertToWorldCoords( int iLine, int xLine, double depth ) +{ + if ( !openFileIfNotOpen() ) return { 0, 0, 0 }; + + return m_filereader->convertToWorldCoords( iLine, xLine, depth ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::pair RimSeismicData::dataRangeMinMax() const +{ + return m_activeDataRange; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::shared_ptr + RimSeismicData::sliceData( RiaDefines::SeismicSliceDirection direction, int sliceNumber, double zMin, double zMax ) +{ + if ( !openFileIfNotOpen() ) return nullptr; + + int sliceIndex = 0; + int zMinIndex = toZIndex( zMin ); + int zMaxIndex = toZIndex( zMax ); + + switch ( direction ) + { + case RiaDefines::SeismicSliceDirection::INLINE: + sliceIndex = ( sliceNumber - m_inlineInfo[0] ) / m_inlineInfo[2]; + break; + case RiaDefines::SeismicSliceDirection::XLINE: + sliceIndex = ( sliceNumber - m_xlineInfo[0] ) / m_xlineInfo[2]; + break; + case RiaDefines::SeismicSliceDirection::DEPTH: + sliceIndex = (int)( 1.0 * ( sliceNumber - this->zMin() ) / m_zStep ); + break; + default: + return nullptr; + } + + auto data = m_filereader->slice( direction, sliceIndex, zMinIndex, zMaxIndex - zMinIndex ); + + double tmp = 0.0; + float* pValue = data->values(); + const auto [minVal, maxVal] = dataRangeMinMax(); + const int nSize = data->size(); + + for ( int i = 0; i < nSize; i++, pValue++ ) + { + tmp = *pValue; + if ( tmp < minVal ) + *pValue = minVal; + else if ( tmp > maxVal ) + *pValue = maxVal; + } + + return data; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimRegularLegendConfig* RimSeismicData::legendConfig() const +{ + return m_legendConfig(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSeismicAlphaMapper* RimSeismicData::alphaValueMapper() const +{ + return m_alphaValueMapper.get(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicData::initColorLegend() +{ + m_legendConfig->setColorLegend( RimRegularLegendConfig::mapToColorLegend( RimRegularLegendConfig::ColorRangesType::BLUE_WHITE_RED ) ); + m_legendConfig->setMappingMode( RimRegularLegendConfig::MappingType::LINEAR_CONTINUOUS ); + m_legendConfig->setRangeMode( RimLegendConfig::RangeModeType::USER_DEFINED ); + m_legendConfig->setCenterLegendAroundZero( true ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::shared_ptr + RimSeismicData::sliceData( double worldX1, double worldY1, double worldX2, double worldY2, double zMin, double zMax ) +{ + if ( !openFileIfNotOpen() ) return nullptr; + + auto [startInline, startXline] = m_filereader->convertToInlineXline( worldX1, worldY1 ); + auto [stopInline, stopXline] = m_filereader->convertToInlineXline( worldX2, worldY2 ); + + int startInlineIndex = toInlineIndex( startInline ); + int startXlineIndex = toXlineIndex( startXline ); + int stopInlineIndex = toInlineIndex( stopInline ); + int stopXlineIndex = toXlineIndex( stopXline ); + int zMinIndex = toZIndex( zMin ); + int zMaxIndex = toZIndex( zMax ); + + int diffI = std::abs( startInlineIndex - stopInlineIndex ); + int diffX = std::abs( startXlineIndex - stopXlineIndex ); + + int dirI = 1; + if ( startInlineIndex > stopInlineIndex ) dirI = -1; + int dirX = 1; + if ( startXlineIndex > stopXlineIndex ) dirX = -1; + + const int zSize = zMaxIndex - zMinIndex; + + std::shared_ptr retdata; + + if ( diffI > diffX ) + { + double dstepX = 1.0 * dirX * diffX / diffI; + + double xlined = 1.0 * startXlineIndex; + + retdata = std::make_shared( diffI, zSize ); + float* pOut = retdata->values(); + + for ( int iline = startInlineIndex; iline != stopInlineIndex; iline += dirI, xlined += dstepX ) + { + int xline = (int)std::round( xlined ); + + auto trace = m_filereader->trace( iline, xline, zMinIndex, zSize ); + + if ( trace->size() != zSize ) + { + memset( pOut, 0, zSize * sizeof( float ) ); + } + else + { + memcpy( pOut, trace->values(), zSize * sizeof( float ) ); + } + + pOut += zSize; + } + } + else + { + if ( diffX == 0 ) return nullptr; + + double dstepI = 1.0 * dirI * diffI / diffX; + + double ilined = 1.0 * startInlineIndex; + + retdata = std::make_shared( diffX, zSize ); + float* pOut = retdata->values(); + + for ( int xline = startXlineIndex; xline != stopXlineIndex; xline += dirX, ilined += dstepI ) + { + int iline = (int)std::round( ilined ); + + auto trace = m_filereader->trace( iline, xline, zMinIndex, zSize ); + + if ( trace->size() != zSize ) + { + memset( pOut, 0, zSize * sizeof( float ) ); + } + else + { + memcpy( pOut, trace->values(), zSize * sizeof( float ) ); + } + + pOut += zSize; + } + } + + return retdata; +} diff --git a/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicData.h b/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicData.h new file mode 100644 index 0000000000..4f062c6588 --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicData.h @@ -0,0 +1,142 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2022 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. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "RiaSeismicDefines.h" + +#include "cafFilePath.h" +#include "cafPdmChildArrayField.h" +#include "cafPdmChildField.h" +#include "cafPdmField.h" +#include "cafPdmObject.h" + +#include "cvfVector3.h" + +#include + +#include +#include + +class RimGenericParameter; +class RimSeismicAlphaMapper; +class RimRegularLegendConfig; +class RifSeismicZGYReader; + +namespace cvf +{ +class BoundingBox; +} // namespace cvf + +namespace ZGYAccess +{ +class SeismicSliceData; +} + +class RimSeismicData : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + RimSeismicData(); + ~RimSeismicData() override; + + void setFileName( QString filename ); + QString fileName() const; + + QString userDescription(); + void setUserDescription( QString description ); + + void updateMetaData(); + + double zMin() const; + double zMax() const; + double zStep() const; + + int inlineMin() const; + int inlineMax() const; + int inlineStep() const; + + int xlineMin() const; + int xlineMax() const; + int xlineStep() const; + + std::vector histogramXvalues() const; + std::vector histogramYvalues() const; + std::vector alphaValues() const; + + std::vector worldOutline() const; + + cvf::Vec3d convertToWorldCoords( int iLine, int xLine, double depth ); + + std::shared_ptr + sliceData( RiaDefines::SeismicSliceDirection direction, int sliceNumber, double zMin, double zMax ); + std::shared_ptr + sliceData( double worldX1, double worldY1, double worldX2, double worldY2, double zMin, double zMax ); + + std::pair dataRangeMinMax() const; + + RimRegularLegendConfig* legendConfig() const; + RimSeismicAlphaMapper* alphaValueMapper() const; + + cvf::BoundingBox* boundingBox() const; + +protected: + void initAfterRead() override; + caf::PdmFieldHandle* userDescriptionField() override; + void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; + void defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "" ) override; + void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override; + void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; + +private: + void updateDataRange( bool updatePlot ); + bool openFileIfNotOpen(); + void logError( QString msg ); + void initColorLegend(); + + int toInlineIndex( int inLine ) const; + int toXlineIndex( int xLine ) const; + int toZIndex( double z ) const; + +private: + caf::PdmField m_filename; + caf::PdmField m_userDescription; + caf::PdmChildArrayField m_metadata; + caf::PdmChildField m_legendConfig; + + caf::PdmField m_overrideDataRange; + caf::PdmField m_userClipValue; + + double m_zStep; + cvf::Vec3i m_inlineInfo; + cvf::Vec3i m_xlineInfo; + std::shared_ptr m_boundingBox; + std::vector m_histogramXvalues; + std::vector m_histogramYvalues; + std::vector m_clippedHistogramXvalues; + std::vector m_clippedHistogramYvalues; + std::vector m_clippedAlphaValues; + std::vector m_worldOutline; + std::pair m_activeDataRange; + std::pair m_fileDataRange; + + std::shared_ptr m_alphaValueMapper; + + std::shared_ptr m_filereader; + int m_nErrorsLogged; +}; diff --git a/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicDataCollection.cpp b/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicDataCollection.cpp new file mode 100644 index 0000000000..3a8d951a67 --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicDataCollection.cpp @@ -0,0 +1,106 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2022 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 "RimSeismicDataCollection.h" + +#include "RiaLogging.h" + +#include "Rim3dView.h" +#include "RimGridView.h" +#include "RimProject.h" +#include "RimSeismicData.h" + +#include +#include + +CAF_PDM_SOURCE_INIT( RimSeismicDataCollection, "SeismicDataCollection", "SeismicCollection" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSeismicDataCollection::RimSeismicDataCollection() +{ + CAF_PDM_InitObject( "Seismic", ":/Seismic16x16.png" ); + + CAF_PDM_InitFieldNoDefault( &m_seismicData, "SeismicData", "Seismic Data" ); + m_seismicData.uiCapability()->setUiTreeHidden( true ); + + setDeletable( false ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSeismicDataCollection::~RimSeismicDataCollection() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSeismicData* RimSeismicDataCollection::importSeismicFromFile( const QString fileName ) +{ + RimSeismicData* seisData = new RimSeismicData(); + seisData->setFileName( fileName ); + + QFileInfo fi( fileName ); + seisData->setUserDescription( fi.baseName() ); + m_seismicData.push_back( seisData ); + updateAllRequiredEditors(); + + return seisData; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimSeismicDataCollection::seismicData() const +{ + return m_seismicData.children(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimSeismicDataCollection::isEmpty() +{ + return !m_seismicData.hasChildren(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicDataCollection::onChildDeleted( caf::PdmChildArrayFieldHandle* childArray, std::vector& referringObjects ) +{ + updateViews(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicDataCollection::updateViews() +{ + RimProject* proj = RimProject::current(); + std::vector views; + proj->allVisibleGridViews( views ); + + for ( auto view : views ) + { + view->scheduleCreateDisplayModelAndRedraw(); + } +} diff --git a/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicDataCollection.h b/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicDataCollection.h new file mode 100644 index 0000000000..444187985f --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicDataCollection.h @@ -0,0 +1,49 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2022 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. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "cafPdmField.h" + +#include "cafPdmChildArrayField.h" +#include "cafPdmObject.h" + +#include + +class RimSeismicData; + +class RimSeismicDataCollection : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; + +public: + RimSeismicDataCollection(); + ~RimSeismicDataCollection() override; + + RimSeismicData* importSeismicFromFile( const QString file ); + + bool isEmpty(); + + std::vector seismicData() const; + +protected: + void onChildDeleted( caf::PdmChildArrayFieldHandle* childArray, std::vector& referringObjects ) override; + void updateViews(); + +private: + caf::PdmChildArrayField m_seismicData; +}; diff --git a/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicSection.cpp b/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicSection.cpp new file mode 100644 index 0000000000..f982a69ce0 --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicSection.cpp @@ -0,0 +1,900 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023 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 "RimSeismicSection.h" + +#include "RiuMainWindow.h" +#include "RiuSeismicHistogramPanel.h" + +#include "Rim3dView.h" +#include "RimRegularLegendConfig.h" +#include "RimSeismicAlphaMapper.h" +#include "RimSeismicData.h" +#include "RimTools.h" + +#include "WellPathCommands/PointTangentManipulator/RicPolyline3dEditor.h" +#include "WellPathCommands/RicPolylineTargetsPickEventHandler.h" + +#include "RigPolyLinesData.h" +#include "RigTexturedSection.h" + +#include "RivSeismicSectionPartMgr.h" + +#include "cafPdmUiDoubleSliderEditor.h" +#include "cafPdmUiPushButtonEditor.h" +#include "cafPdmUiSliderEditor.h" +#include "cafPdmUiTableViewEditor.h" +#include "cafPdmUiTreeOrdering.h" + +#include "cvfBoundingBox.h" +#include "cvfScalarMapper.h" +#include "cvfTextureImage.h" +#include "cvfVector3.h" + +#include + +#include +#include +#include +#include + +#include + +CAF_PDM_SOURCE_INIT( RimSeismicSection, "SeismicSection" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSeismicSection::RimSeismicSection() + : m_pickTargetsEventHandler( new RicPolylineTargetsPickEventHandler( this ) ) +{ + CAF_PDM_InitObject( "Seismic Section", ":/Seismic16x16.png" ); + + CAF_PDM_InitField( &m_userDescription, "UserDecription", QString( "Seismic Section" ), "Name" ); + + CAF_PDM_InitFieldNoDefault( &m_type, "Type", "Type" ); + + CAF_PDM_InitFieldNoDefault( &m_seismicData, "SeismicData", "Seismic Data" ); + + CAF_PDM_InitField( &m_enablePicking, "EnablePicking", false, "" ); + caf::PdmUiPushButtonEditor::configureEditorForField( &m_enablePicking ); + m_enablePicking.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::LabelPosType::HIDDEN ); + + CAF_PDM_InitField( &m_showImage, "ShowImage", false, "" ); + caf::PdmUiPushButtonEditor::configureEditorForField( &m_showImage ); + m_showImage.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::LabelPosType::HIDDEN ); + + CAF_PDM_InitFieldNoDefault( &m_targets, "Targets", "Targets" ); + m_targets.uiCapability()->setUiEditorTypeName( caf::PdmUiTableViewEditor::uiEditorTypeName() ); + m_targets.uiCapability()->setUiTreeChildrenHidden( true ); + m_targets.uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::TOP ); + m_targets.uiCapability()->setCustomContextMenuEnabled( true ); + + CAF_PDM_InitField( &m_inlineIndex, "InlineIndex", -1, "Inline" ); + m_inlineIndex.uiCapability()->setUiEditorTypeName( caf::PdmUiSliderEditor::uiEditorTypeName() ); + CAF_PDM_InitField( &m_xlineIndex, "CrosslineIndex", -1, "Crossline" ); + m_xlineIndex.uiCapability()->setUiEditorTypeName( caf::PdmUiSliderEditor::uiEditorTypeName() ); + CAF_PDM_InitField( &m_depthIndex, "DepthIndex", -1, "Depth Slice" ); + m_depthIndex.uiCapability()->setUiEditorTypeName( caf::PdmUiSliderEditor::uiEditorTypeName() ); + + CAF_PDM_InitField( &m_lineThickness, "LineThickness", 1, "Line Thickness" ); + CAF_PDM_InitField( &m_lineColor, "LineColor", cvf::Color3f( cvf::Color3f::WHITE ), "Line Color" ); + CAF_PDM_InitField( &m_showSeismicOutline, "ShowSeismicOutline", false, "Show Seismic Data Outline" ); + CAF_PDM_InitField( &m_showSectionLine, "ShowSectionLine", false, "Show Section Polyline" ); + + CAF_PDM_InitField( &m_transparent, "TransperentSection", false, "Transparent (Use on only one section at a time!)" ); + + CAF_PDM_InitFieldNoDefault( &m_zFilterType, "DepthFilter", "Depth Filter" ); + CAF_PDM_InitField( &m_zUpperThreshold, "UpperThreshold", -1, "Upper Threshold" ); + m_zUpperThreshold.uiCapability()->setUiEditorTypeName( caf::PdmUiSliderEditor::uiEditorTypeName() ); + CAF_PDM_InitField( &m_zLowerThreshold, "LowerThreshold", -1, "Lower Threshold" ); + m_zLowerThreshold.uiCapability()->setUiEditorTypeName( caf::PdmUiSliderEditor::uiEditorTypeName() ); + + this->setUi3dEditorTypeName( RicPolyline3dEditor::uiEditorTypeName() ); + + setDeletable( true ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSeismicSection::~RimSeismicSection() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimSeismicSection::userDescription() +{ + return m_userDescription; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicSection::setUserDescription( QString description ) +{ + m_userDescription = description; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimSeismicSection::userDescriptionField() +{ + return &m_userDescription; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicSection::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) +{ + initSliceRanges(); + + auto genGrp = uiOrdering.addNewGroup( "General" ); + + genGrp->add( &m_userDescription ); + genGrp->add( &m_seismicData ); + + if ( m_seismicData() != nullptr ) + { + genGrp->add( &m_type ); + + if ( m_type() == RiaDefines::SeismicSectionType::SS_POLYLINE ) + { + auto polyGrp = uiOrdering.addNewGroup( "Polyline Definition" ); + polyGrp->add( &m_targets ); + polyGrp->add( &m_enablePicking ); + } + else if ( m_type() == RiaDefines::SeismicSectionType::SS_INLINE ) + { + genGrp->add( &m_inlineIndex ); + } + else if ( m_type() == RiaDefines::SeismicSectionType::SS_XLINE ) + { + genGrp->add( &m_xlineIndex ); + } + else if ( m_type() == RiaDefines::SeismicSectionType::SS_DEPTHSLICE ) + { + genGrp->add( &m_depthIndex ); + } + + auto filterGroup = uiOrdering.addNewGroup( "Depth Filter" ); + filterGroup->add( &m_zFilterType ); + + switch ( zFilterType() ) + { + case RimIntersectionFilterEnum::INTERSECT_FILTER_BELOW: + m_zUpperThreshold.uiCapability()->setUiName( "Depth" ); + filterGroup->add( &m_zUpperThreshold ); + break; + + case RimIntersectionFilterEnum::INTERSECT_FILTER_BETWEEN: + m_zUpperThreshold.uiCapability()->setUiName( "Upper Depth" ); + filterGroup->add( &m_zUpperThreshold ); + m_zLowerThreshold.uiCapability()->setUiName( "Lower Depth" ); + filterGroup->add( &m_zLowerThreshold ); + break; + + case RimIntersectionFilterEnum::INTERSECT_FILTER_ABOVE: + m_zLowerThreshold.uiCapability()->setUiName( "Depth" ); + filterGroup->add( &m_zLowerThreshold ); + break; + + case RimIntersectionFilterEnum::INTERSECT_FILTER_NONE: + default: + break; + } + + auto expGrp = uiOrdering.addNewGroup( "Experimental" ); + expGrp->setCollapsedByDefault(); + expGrp->add( &m_transparent ); + + auto outlGrp = uiOrdering.addNewGroup( "Outline" ); + outlGrp->add( &m_lineThickness ); + outlGrp->add( &m_lineColor ); + outlGrp->add( &m_showSeismicOutline ); + if ( m_type() == RiaDefines::SeismicSectionType::SS_POLYLINE ) outlGrp->add( &m_showSectionLine ); + + outlGrp->setCollapsedByDefault(); + } + + if ( m_type() != RiaDefines::SeismicSectionType::SS_POLYLINE ) uiOrdering.add( &m_showImage ); + + uiOrdering.skipRemainingFields(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicSection::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= "" */ ) +{ + uiTreeOrdering.skipRemainingChildren(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicSection::defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) +{ + if ( field == &m_enablePicking ) + { + auto* pbAttribute = dynamic_cast( attribute ); + if ( pbAttribute ) + { + if ( !m_enablePicking ) + { + pbAttribute->m_buttonText = "Start Picking Points"; + } + else + { + pbAttribute->m_buttonText = "Stop Picking Points"; + } + } + } + else if ( field == &m_showImage ) + { + auto* pbAttribute = dynamic_cast( attribute ); + if ( pbAttribute ) + { + pbAttribute->m_buttonText = "Show Image"; + } + } + else if ( field == &m_targets ) + { + auto tvAttribute = dynamic_cast( attribute ); + if ( tvAttribute ) + { + tvAttribute->resizePolicy = caf::PdmUiTableViewEditorAttribute::RESIZE_TO_FIT_CONTENT; + + if ( m_enablePicking ) + { + tvAttribute->baseColor.setRgb( 255, 220, 255 ); + tvAttribute->alwaysEnforceResizePolicy = true; + } + } + } + else if ( ( field == &m_depthIndex ) || ( field == &m_inlineIndex ) || ( field == &m_xlineIndex ) ) + { + if ( m_seismicData() != nullptr ) + { + auto* sliderAttrib = dynamic_cast( attribute ); + if ( sliderAttrib != nullptr ) + { + sliderAttrib->m_showSpinBox = true; + int minVal = m_seismicData()->inlineMin(); + int maxVal = m_seismicData()->inlineMax(); + int stepVal = m_seismicData()->inlineStep(); + + if ( field == &m_xlineIndex ) + { + minVal = m_seismicData()->xlineMin(); + maxVal = m_seismicData()->xlineMax(); + stepVal = m_seismicData()->xlineStep(); + } + else if ( field == &m_depthIndex ) + { + minVal = m_seismicData()->zMin(); + maxVal = m_seismicData()->zMax(); + stepVal = m_seismicData()->zStep(); + } + sliderAttrib->m_maximum = maxVal; + sliderAttrib->m_minimum = minVal; + sliderAttrib->m_step = stepVal; + } + } + } + else if ( ( field == &m_zUpperThreshold ) || ( field == &m_zLowerThreshold ) ) + { + auto* sliderAttrib = dynamic_cast( attribute ); + if ( ( sliderAttrib ) && ( m_seismicData() != nullptr ) ) + { + auto bb = m_seismicData()->boundingBox(); + + sliderAttrib->m_minimum = -1 * bb->max().z(); + sliderAttrib->m_maximum = -1 * bb->min().z(); + sliderAttrib->m_step = (int)m_seismicData->zStep(); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicSection::setSectionType( RiaDefines::SeismicSectionType sectionType ) +{ + m_type = sectionType; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicSection::enablePicking( bool enable ) +{ + m_enablePicking = enable; + updateConnectedEditors(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimSeismicSection::pickingEnabled() const +{ + return m_enablePicking(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PickEventHandler* RimSeismicSection::pickEventHandler() const +{ + return m_pickTargetsEventHandler.get(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimSeismicSection::activeTargets() const +{ + return m_targets.children(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicSection::insertTarget( const RimPolylineTarget* targetToInsertBefore, RimPolylineTarget* targetToInsert ) +{ + size_t index = m_targets.indexOf( targetToInsertBefore ); + if ( index < m_targets.size() ) + m_targets.insert( index, targetToInsert ); + else + m_targets.push_back( targetToInsert ); + + updateVisualization(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicSection::deleteTarget( RimPolylineTarget* targetToDelete ) +{ + m_targets.removeChild( targetToDelete ); + delete targetToDelete; + + updateVisualization(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicSection::updateVisualization() +{ + if ( texturedSection().notNull() ) texturedSection()->setWhatToUpdate( RigTexturedSection::WhatToUpdateEnum::UPDATE_GEOMETRY ); + scheduleViewUpdate(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicSection::initAfterRead() +{ + resolveReferencesRecursively(); + if ( m_seismicData != nullptr ) + { + m_seismicData->legendConfig()->changed.connect( this, &RimSeismicSection::onLegendConfigChanged ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicSection::updateEditorsAndVisualization() +{ + updateConnectedEditors(); + updateVisualization(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicSection::scheduleViewUpdate() +{ + Rim3dView* view = nullptr; + firstAncestorOrThisOfType( view ); + if ( view ) view->scheduleCreateDisplayModelAndRedraw(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref RimSeismicSection::polyLinesData() const +{ + cvf::ref pld = new RigPolyLinesData; + if ( ( m_type() == RiaDefines::SeismicSectionType::SS_POLYLINE ) && m_showSectionLine() ) + { + std::vector line; + for ( const RimPolylineTarget* target : m_targets ) + { + line.push_back( target->targetPointXYZ() ); + } + pld->setPolyLine( line ); + } + + if ( m_showSeismicOutline() && m_seismicData() != nullptr ) + { + std::vector outline = m_seismicData()->worldOutline(); + if ( outline.size() == 8 ) + { + std::vector box; + + for ( auto i : { 4, 0, 1, 3, 2, 0 } ) + box.push_back( outline[i] ); + pld->addPolyLine( box ); + box.clear(); + + for ( auto i : { 1, 5, 4, 6, 7, 5 } ) + box.push_back( outline[i] ); + pld->addPolyLine( box ); + box.clear(); + + box.push_back( outline[2] ); + box.push_back( outline[6] ); + pld->addPolyLine( box ); + box.clear(); + + box.push_back( outline[3] ); + box.push_back( outline[7] ); + pld->addPolyLine( box ); + } + } + + pld->setLineAppearance( m_lineThickness, m_lineColor, false ); + pld->setZPlaneLock( false, 0.0 ); + + if ( isChecked() ) + { + pld->setVisibility( true, false ); + } + else + { + pld->setVisibility( false, false ); + } + + return pld; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RivSeismicSectionPartMgr* RimSeismicSection::partMgr() +{ + if ( m_sectionPartMgr.isNull() ) m_sectionPartMgr = new RivSeismicSectionPartMgr( this ); + + return m_sectionPartMgr.p(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QList RimSeismicSection::calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) +{ + QList options; + + if ( fieldNeedingOptions == &m_seismicData ) + { + Rim3dView* view = nullptr; + firstAncestorOrThisOfType( view ); + + if ( view != nullptr ) RimTools::seismicDataOptionItems( &options, view->domainBoundingBox() ); + } + + return options; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +cvf::ref RimSeismicSection::texturedSection() +{ + if ( m_texturedSection.isNull() ) m_texturedSection = new RigTexturedSection(); + + if ( m_texturedSection->isValid() || ( m_seismicData == nullptr ) ) return m_texturedSection; + + std::vector rects; + std::vector widths; + + double zmin = upperFilterZ( m_seismicData->zMin() ); + double zmax = lowerFilterZ( m_seismicData->zMax() ); + + if ( zmax <= zmin ) return m_texturedSection; + + if ( m_type() == RiaDefines::SeismicSectionType::SS_POLYLINE ) + { + if ( m_targets.size() == 0 ) return m_texturedSection; + + bool valid = m_texturedSection->partsCount() == (int)( m_targets.size() - 1 ); + if ( !valid ) m_texturedSection->resize( m_targets.size() - 1 ); + + for ( int i = 1; i < (int)m_targets.size(); i++ ) + { + cvf::Vec3d p1 = m_targets[i - 1]->targetPointXYZ(); + cvf::Vec3d p2 = m_targets[i]->targetPointXYZ(); + + if ( !m_texturedSection->part( i - 1 ).isRectValid ) + { + cvf::Vec3dArray points; + points.resize( 4 ); + points[0].set( p1.x(), p1.y(), -zmax ); + points[1].set( p2.x(), p2.y(), -zmax ); + points[2].set( p2.x(), p2.y(), -zmin ); + points[3].set( p1.x(), p1.y(), -zmin ); + + m_texturedSection->setSectionPartRect( i - 1, points ); + } + + if ( m_texturedSection->part( i - 1 ).sliceData == nullptr ) + { + m_texturedSection->setSectionPartData( i - 1, m_seismicData->sliceData( p1.x(), p1.y(), p2.x(), p2.y(), zmin, zmax ) ); + } + } + } + else if ( m_type() == RiaDefines::SeismicSectionType::SS_INLINE ) + { + bool valid = m_texturedSection->partsCount() == 1; + if ( valid ) + valid = m_texturedSection->part( 0 ).isRectValid; + else + m_texturedSection->resize( 1 ); + + int ilStart = m_inlineIndex(); + + if ( !valid ) + { + int xlStart = m_seismicData->xlineMin(); + int xlStop = m_seismicData->xlineMax(); + + cvf::Vec3dArray points; + points.resize( 4 ); + points[0] = m_seismicData->convertToWorldCoords( ilStart, xlStart, -zmax ); + points[1] = m_seismicData->convertToWorldCoords( ilStart, xlStop, -zmax ); + points[2] = m_seismicData->convertToWorldCoords( ilStart, xlStop, -zmin ); + points[3] = m_seismicData->convertToWorldCoords( ilStart, xlStart, -zmin ); + + m_texturedSection->setSectionPartRect( 0, points ); + } + + if ( m_texturedSection->part( 0 ).sliceData == nullptr ) + { + m_texturedSection->setSectionPartData( 0, m_seismicData->sliceData( RiaDefines::SeismicSliceDirection::INLINE, ilStart, zmin, zmax ) ); + } + } + else if ( m_type() == RiaDefines::SeismicSectionType::SS_XLINE ) + { + bool valid = m_texturedSection->partsCount() == 1; + if ( valid ) + valid = m_texturedSection->part( 0 ).isRectValid; + else + m_texturedSection->resize( 1 ); + + int xlStart = m_xlineIndex(); + + if ( !valid ) + { + int ilStart = m_seismicData->inlineMin(); + int ilStop = m_seismicData->inlineMax(); + + cvf::Vec3dArray points; + points.resize( 4 ); + points[0] = m_seismicData->convertToWorldCoords( ilStart, xlStart, -zmax ); + points[1] = m_seismicData->convertToWorldCoords( ilStop, xlStart, -zmax ); + points[2] = m_seismicData->convertToWorldCoords( ilStop, xlStart, -zmin ); + points[3] = m_seismicData->convertToWorldCoords( ilStart, xlStart, -zmin ); + + m_texturedSection->setSectionPartRect( 0, points ); + } + + if ( m_texturedSection->part( 0 ).sliceData == nullptr ) + { + m_texturedSection->setSectionPartData( 0, m_seismicData->sliceData( RiaDefines::SeismicSliceDirection::XLINE, xlStart, zmin, zmax ) ); + } + } + else if ( m_type() == RiaDefines::SeismicSectionType::SS_DEPTHSLICE ) + { + bool valid = m_texturedSection->partsCount() == 1; + if ( valid ) + valid = m_texturedSection->part( 0 ).isRectValid; + else + m_texturedSection->resize( 1 ); + + int zIndex = m_depthIndex(); + + if ( !valid ) + { + int ilStart = m_seismicData->inlineMin(); + int ilStop = m_seismicData->inlineMax(); + + int xlStart = m_seismicData->xlineMin(); + int xlStop = m_seismicData->xlineMax(); + + cvf::Vec3dArray points; + points.resize( 4 ); + points[3] = m_seismicData->convertToWorldCoords( ilStart, xlStart, zIndex ); + points[2] = m_seismicData->convertToWorldCoords( ilStop, xlStart, zIndex ); + points[1] = m_seismicData->convertToWorldCoords( ilStop, xlStop, zIndex ); + points[0] = m_seismicData->convertToWorldCoords( ilStart, xlStop, zIndex ); + + for ( int i = 0; i < 4; i++ ) + points[i].z() = -points[i].z(); + + m_texturedSection->setSectionPartRect( 0, points ); + } + + if ( m_texturedSection->part( 0 ).sliceData == nullptr ) + { + m_texturedSection->setSectionPartData( 0, m_seismicData->sliceData( RiaDefines::SeismicSliceDirection::DEPTH, zIndex, zmin, zmax ) ); + } + } + + return m_texturedSection; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicSection::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) +{ + if ( changedField == &m_enablePicking ) + { + this->updateConnectedEditors(); + } + else if ( changedField == &m_showImage ) + { + QDialog w; + QLabel l; + QHBoxLayout layout; + layout.addWidget( &l ); + w.setLayout( &layout ); + QPixmap i = getImage(); + l.setPixmap( i ); + + w.exec(); + + m_showImage = false; + } + else if ( changedField != &m_userDescription ) + { + RigTexturedSection::WhatToUpdateEnum updateType = RigTexturedSection::WhatToUpdateEnum::UPDATE_NONE; + + if ( changedField == &m_seismicData ) + { + RiuMainWindow::instance()->seismicHistogramPanel()->showHistogram( m_seismicData() ); + initSliceRanges(); + + PdmObjectHandle* prevValue = oldValue.value>().rawPtr(); + auto prevSeisData = dynamic_cast( prevValue ); + if ( prevSeisData != nullptr ) + { + prevSeisData->legendConfig()->changed.disconnect( this ); + } + + m_seismicData->legendConfig()->changed.connect( this, &RimSeismicSection::onLegendConfigChanged ); + + updateType = RigTexturedSection::WhatToUpdateEnum::UPDATE_ALL; + } + else if ( ( changedField == &m_type ) || ( changedField == &m_targets ) || ( changedField == &m_depthIndex ) || + ( changedField == &m_inlineIndex ) || ( changedField == &m_xlineIndex ) || changedField == &m_zFilterType || + changedField == &m_zLowerThreshold || changedField == &m_zUpperThreshold ) + { + updateType = RigTexturedSection::WhatToUpdateEnum::UPDATE_GEOMETRY; + } + else if ( changedField == &m_transparent ) + { + updateType = RigTexturedSection::WhatToUpdateEnum::UPDATE_TEXTURE; + } + + texturedSection()->setWhatToUpdate( updateType ); + + scheduleViewUpdate(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSeismicData* RimSeismicSection::seismicData() const +{ + return m_seismicData(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicSection::setSeismicData( RimSeismicData* seisData ) +{ + if ( m_seismicData != nullptr ) m_seismicData->legendConfig()->changed.disconnect( this ); + + m_seismicData = seisData; + + if ( seisData != nullptr ) m_seismicData->legendConfig()->changed.connect( this, &RimSeismicSection::onLegendConfigChanged ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimRegularLegendConfig* RimSeismicSection::legendConfig() const +{ + if ( seismicData() != nullptr ) return seismicData()->legendConfig(); + return nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSeismicAlphaMapper* RimSeismicSection::alphaValueMapper() const +{ + if ( seismicData() != nullptr ) return seismicData()->alphaValueMapper(); + return nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimSeismicSection::isTransparent() const +{ + return m_transparent; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicSection::initSliceRanges() +{ + if ( m_seismicData() == nullptr ) return; + + if ( m_zLowerThreshold < 0 ) m_zLowerThreshold = m_seismicData->zMax(); + if ( m_zUpperThreshold < 0 ) m_zUpperThreshold = m_seismicData->zMin(); + + m_inlineIndex = std::clamp( m_inlineIndex(), m_seismicData->inlineMin(), m_seismicData->inlineMax() ); + m_xlineIndex = std::clamp( m_xlineIndex(), m_seismicData->xlineMin(), m_seismicData->xlineMax() ); + m_depthIndex = std::clamp( m_depthIndex(), (int)m_seismicData->zMin(), (int)m_seismicData->zMax() ); + m_zLowerThreshold = std::clamp( m_zLowerThreshold(), (int)m_seismicData->zMin(), (int)m_seismicData->zMax() ); + m_zUpperThreshold = std::clamp( m_zUpperThreshold(), (int)m_seismicData->zMin(), (int)m_seismicData->zMax() ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QPixmap RimSeismicSection::getImage() +{ + RiaDefines::SeismicSliceDirection sliceDir = RiaDefines::SeismicSliceDirection::INLINE; + int iStart = m_inlineIndex(); + + if ( m_type() == RiaDefines::SeismicSectionType::SS_XLINE ) + { + sliceDir = RiaDefines::SeismicSliceDirection::XLINE; + iStart = m_xlineIndex(); + } + else if ( m_type() == RiaDefines::SeismicSectionType::SS_DEPTHSLICE ) + { + sliceDir = RiaDefines::SeismicSliceDirection::DEPTH; + iStart = m_depthIndex(); + } + + double zmin = upperFilterZ( m_seismicData->zMin() ); + double zmax = lowerFilterZ( m_seismicData->zMax() ); + + auto data = m_seismicData->sliceData( sliceDir, iStart, zmin, zmax ); + + auto mapper = legendConfig()->scalarMapper(); + + float* pData = data->values(); + + QImage img( data->width(), data->depth(), QImage::Format_RGB888 ); + + for ( int i = 0; i < data->width(); i++ ) + { + for ( int j = 0; j < data->depth(); j++ ) + { + auto rgb = mapper->mapToColor( *pData ); + + QColor color( rgb.r(), rgb.g(), rgb.b() ); + img.setPixel( i, j, color.rgb() ); + + pData++; + } + } + + return QPixmap::fromImage( img ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicSection::onLegendConfigChanged( const caf::SignalEmitter* emitter, RimLegendConfigChangeType changeType ) +{ + RigTexturedSection::WhatToUpdateEnum updateType = RigTexturedSection::WhatToUpdateEnum::UPDATE_GEOMETRY; + + switch ( changeType ) + { + case RimLegendConfigChangeType::COLORS: + case RimLegendConfigChangeType::COLOR_MODE: + updateType = RigTexturedSection::WhatToUpdateEnum::UPDATE_TEXTURE; + break; + case RimLegendConfigChangeType::ALL: + case RimLegendConfigChangeType::RANGE: + updateType = RigTexturedSection::WhatToUpdateEnum::UPDATE_DATA; + break; + case RimLegendConfigChangeType::LEVELS: + case RimLegendConfigChangeType::NUMBER_FORMAT: + case RimLegendConfigChangeType::VISIBILITY: + updateType = RigTexturedSection::WhatToUpdateEnum::UPDATE_NONE; + break; + default: + break; + } + + texturedSection()->setWhatToUpdate( updateType ); + + if ( m_isChecked() ) scheduleViewUpdate(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimIntersectionFilterEnum RimSeismicSection::zFilterType() const +{ + return m_zFilterType(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimSeismicSection::upperFilterZ( int upperGridLimit ) const +{ + switch ( zFilterType() ) + { + case RimIntersectionFilterEnum::INTERSECT_FILTER_BELOW: + case RimIntersectionFilterEnum::INTERSECT_FILTER_BETWEEN: + return m_zUpperThreshold; + + case RimIntersectionFilterEnum::INTERSECT_FILTER_ABOVE: + case RimIntersectionFilterEnum::INTERSECT_FILTER_NONE: + default: + return upperGridLimit; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimSeismicSection::lowerFilterZ( int lowerGridLimit ) const +{ + switch ( zFilterType() ) + { + case RimIntersectionFilterEnum::INTERSECT_FILTER_ABOVE: + case RimIntersectionFilterEnum::INTERSECT_FILTER_BETWEEN: + return m_zLowerThreshold; + + case RimIntersectionFilterEnum::INTERSECT_FILTER_BELOW: + case RimIntersectionFilterEnum::INTERSECT_FILTER_NONE: + default: + return lowerGridLimit; + } +} diff --git a/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicSection.h b/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicSection.h new file mode 100644 index 0000000000..956f049b1c --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicSection.h @@ -0,0 +1,137 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023 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. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "RiaSeismicDefines.h" + +#include "RimCheckableNamedObject.h" +#include "RimIntersectionEnums.h" +#include "RimLegendConfigChangeType.h" +#include "RimPolylinePickerInterface.h" +#include "RimPolylinesDataInterface.h" + +#include "cafPdmChildArrayField.h" +#include "cafPdmField.h" +#include "cafPdmFieldCvfColor.h" +#include "cafPdmFieldCvfVec3d.h" +#include "cafPdmPtrField.h" + +#include "cvfArray.h" +#include "cvfColor3.h" +#include "cvfObject.h" + +#include +#include + +class RicPolylineTargetsPickEventHandler; +class RimPolylineTarget; +class RigPolylinesData; +class RigTexturedSection; +class RivSeismicSectionPartMgr; +class Rim3dView; +class RimSeismicData; +class RimRegularLegendConfig; +class RimSeismicAlphaMapper; + +class RimSeismicSection : public RimCheckableNamedObject, public RimPolylinePickerInterface, public RimPolylinesDataInterface +{ + CAF_PDM_HEADER_INIT; + +public: + RimSeismicSection(); + ~RimSeismicSection() override; + + QString userDescription(); + void setUserDescription( QString description ); + + void updateVisualization() override; + void updateEditorsAndVisualization() override; + void insertTarget( const RimPolylineTarget* targetToInsertBefore, RimPolylineTarget* targetToInsert ) override; + void deleteTarget( RimPolylineTarget* targetToDelete ) override; + void enablePicking( bool enable ); + + void setSectionType( RiaDefines::SeismicSectionType sectionType ); + + std::vector activeTargets() const override; + bool pickingEnabled() const override; + caf::PickEventHandler* pickEventHandler() const override; + + cvf::ref polyLinesData() const override; + + cvf::ref texturedSection(); + + RivSeismicSectionPartMgr* partMgr(); + + RimSeismicData* seismicData() const; + void setSeismicData( RimSeismicData* seisData ); + + RimRegularLegendConfig* legendConfig() const; + RimSeismicAlphaMapper* alphaValueMapper() const; + + bool isTransparent() const; + + int upperFilterZ( int upperGridLimit ) const; + int lowerFilterZ( int lowerGridLimit ) const; + RimIntersectionFilterEnum zFilterType() const; + +protected: + void initAfterRead() override; + caf::PdmFieldHandle* userDescriptionField() override; + + QList calculateValueOptions( const caf::PdmFieldHandle* fieldNeedingOptions ) override; + + void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; + void defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "" ) override; + void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; + +private: + void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override; + + void onLegendConfigChanged( const caf::SignalEmitter* emitter, RimLegendConfigChangeType changeType ); + + void initSliceRanges(); + + void scheduleViewUpdate(); + + QPixmap getImage(); + + caf::PdmField m_userDescription; + caf::PdmPtrField m_seismicData; + + caf::PdmField> m_type; + caf::PdmChildArrayField m_targets; + + caf::PdmField m_showSeismicOutline; + caf::PdmField m_enablePicking; + caf::PdmField m_showSectionLine; + caf::PdmField m_lineThickness; + caf::PdmField m_lineColor; + caf::PdmField m_transparent; + caf::PdmField m_showImage; + caf::PdmField m_inlineIndex; + caf::PdmField m_xlineIndex; + caf::PdmField m_depthIndex; + + caf::PdmField> m_zFilterType; + caf::PdmField m_zUpperThreshold; + caf::PdmField m_zLowerThreshold; + + std::shared_ptr m_pickTargetsEventHandler; + cvf::ref m_sectionPartMgr; + cvf::ref m_texturedSection; +}; diff --git a/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicSectionCollection.cpp b/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicSectionCollection.cpp new file mode 100644 index 0000000000..731e6f907a --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicSectionCollection.cpp @@ -0,0 +1,260 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023 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 "RimSeismicSectionCollection.h" + +#include "RiuViewer.h" + +#include "Rim3dView.h" +#include "RimOilField.h" +#include "RimProject.h" +#include "RimRegularLegendConfig.h" +#include "RimSeismicData.h" +#include "RimSeismicDataCollection.h" +#include "RimSeismicSection.h" + +#include "RivSeismicSectionPartMgr.h" + +#include "cvfBoundingBox.h" +#include "cvfModelBasicList.h" + +#include "cafDisplayCoordTransform.h" + +CAF_PDM_SOURCE_INIT( RimSeismicSectionCollection, "SeismicSectionCollection" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSeismicSectionCollection::RimSeismicSectionCollection() +{ + CAF_PDM_InitObject( "Seismic Sections", ":/Seismic16x16.png" ); + + CAF_PDM_InitField( &m_userDescription, "UserDecription", QString( "Seismic Sections" ), "Name" ); + + CAF_PDM_InitFieldNoDefault( &m_seismicSections, "SeismicSections", "SeismicSections" ); + m_seismicSections.uiCapability()->setUiTreeHidden( true ); + + setName( "Seismic Sections" ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSeismicSectionCollection::~RimSeismicSectionCollection() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimSeismicSection* RimSeismicSectionCollection::addNewSection( RiaDefines::SeismicSectionType sectionType ) +{ + Rim3dView* view = nullptr; + firstAncestorOrThisOfType( view ); + if ( view == nullptr ) return nullptr; + + RimSeismicData* defaultSeis = nullptr; + + RimProject* proj = RimProject::current(); + if ( proj ) + { + const auto& coll = proj->activeOilField()->seismicCollection().p(); + for ( auto* c : coll->seismicData() ) + { + if ( c->boundingBox()->intersects( view->domainBoundingBox() ) ) + { + defaultSeis = c; + break; + } + } + } + + RimSeismicSection* newSection = new RimSeismicSection(); + if ( defaultSeis != nullptr ) newSection->setSeismicData( defaultSeis ); + newSection->setSectionType( sectionType ); + m_seismicSections.push_back( newSection ); + updateAllRequiredEditors(); + updateView(); + return newSection; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimSeismicSectionCollection::empty() +{ + return m_seismicSections.empty(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RimSeismicSectionCollection::size() +{ + return static_cast( m_seismicSections.size() ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimSeismicSectionCollection::userDescription() +{ + return m_userDescription; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicSectionCollection::setUserDescription( QString description ) +{ + m_userDescription = description; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +caf::PdmFieldHandle* RimSeismicSectionCollection::userDescriptionField() +{ + return &m_userDescription; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicSectionCollection::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) +{ + uiOrdering.skipRemainingFields( true ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimSeismicSectionCollection::seismicSections() const +{ + return m_seismicSections.children(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicSectionCollection::appendPartsToModel( Rim3dView* view, + cvf::ModelBasicList* model, + caf::DisplayCoordTransform* transform, + const cvf::BoundingBox& boundingBox ) +{ + if ( !isChecked() ) return; + + for ( auto& section : m_seismicSections ) + { + if ( section->isChecked() ) + { + if ( section->seismicData() != nullptr ) + { + section->partMgr()->appendGeometryPartsToModel( model, transform, boundingBox ); + } + section->partMgr()->appendPolylinePartsToModel( view, model, transform, boundingBox ); + } + } + + model->updateBoundingBoxesRecursive(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicSectionCollection::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) +{ + if ( changedField == objectToggleField() ) + { + updateView(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RimSeismicSectionCollection::legendConfigs() +{ + std::vector retVals; + + std::set usedSeisData; + + for ( auto& section : m_seismicSections ) + { + auto seisData = section->seismicData(); + + if ( usedSeisData.contains( seisData ) ) continue; + + retVals.push_back( seisData->legendConfig() ); + usedSeisData.insert( seisData ); + } + + return retVals; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicSectionCollection::updateLegendRangesTextAndVisibility( RiuViewer* nativeOrOverrideViewer, bool isUsingOverrideViewer ) +{ + for ( auto& section : m_seismicSections ) + { + if ( section->legendConfig() ) + { + auto legendConfig = section->legendConfig(); + + QString subtitle; + if ( section->seismicData() ) + { + subtitle = section->seismicData()->userDescription(); + const int maxChar = 20; + if ( subtitle.size() > maxChar ) + { + subtitle = subtitle.left( maxChar - 2 ); + subtitle += ".."; + } + } + + legendConfig->setTitle( QString( "Seismic: \n" ) + subtitle ); + + if ( section->isChecked() && legendConfig->showLegend() ) + { + nativeOrOverrideViewer->addColorLegendToBottomLeftCorner( legendConfig->titledOverlayFrame(), isUsingOverrideViewer ); + } + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicSectionCollection::onChildDeleted( caf::PdmChildArrayFieldHandle* childArray, + std::vector& referringObjects ) +{ + updateView(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimSeismicSectionCollection::updateView() +{ + Rim3dView* view = nullptr; + firstAncestorOrThisOfType( view ); + if ( view ) view->scheduleCreateDisplayModelAndRedraw(); +} diff --git a/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicSectionCollection.h b/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicSectionCollection.h new file mode 100644 index 0000000000..e2c691f759 --- /dev/null +++ b/ApplicationLibCode/ProjectDataModel/Seismic/RimSeismicSectionCollection.h @@ -0,0 +1,84 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023 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. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include "RiaSeismicDefines.h" + +#include "RimCheckableNamedObject.h" + +#include "cafPdmChildArrayField.h" + +#include + +class RimRegularLegendConfig; +class RimSeismicSection; +class Rim3dView; +class RiuViewer; + +namespace cvf +{ +class ModelBasicList; +class Transform; +class BoundingBox; +} // namespace cvf + +namespace caf +{ +class DisplayCoordTransform; +} + +class RimSeismicSectionCollection : public RimCheckableNamedObject +{ + CAF_PDM_HEADER_INIT; + +public: + RimSeismicSectionCollection(); + ~RimSeismicSectionCollection() override; + + RimSeismicSection* addNewSection( RiaDefines::SeismicSectionType sectionType = RiaDefines::SeismicSectionType::SS_INLINE ); + + std::vector seismicSections() const; + + bool empty(); + int size(); + + QString userDescription(); + void setUserDescription( QString description ); + + void appendPartsToModel( Rim3dView* view, + cvf::ModelBasicList* model, + caf::DisplayCoordTransform* scaleTransform, + const cvf::BoundingBox& boundingBox ); + + std::vector legendConfigs(); + void updateLegendRangesTextAndVisibility( RiuViewer* nativeOrOverrideViewer, bool isUsingOverrideViewer ); + +protected: + caf::PdmFieldHandle* userDescriptionField() override; + + void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override; + void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; + + void onChildDeleted( caf::PdmChildArrayFieldHandle* childArray, std::vector& referringObjects ) override; + + void updateView(); + +private: + caf::PdmField m_userDescription; + caf::PdmChildArrayField m_seismicSections; +}; diff --git a/ApplicationLibCode/ReservoirDataModel/CMakeLists_files.cmake b/ApplicationLibCode/ReservoirDataModel/CMakeLists_files.cmake index 7fc313d52a..1158abc83a 100644 --- a/ApplicationLibCode/ReservoirDataModel/CMakeLists_files.cmake +++ b/ApplicationLibCode/ReservoirDataModel/CMakeLists_files.cmake @@ -86,6 +86,7 @@ set(SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RigSurfaceResampler.h ${CMAKE_CURRENT_LIST_DIR}/RigSurfaceStatisticsCalculator.h ${CMAKE_CURRENT_LIST_DIR}/RigWellLogIndexDepthOffset.h + ${CMAKE_CURRENT_LIST_DIR}/RigTexturedSection.h ${CMAKE_CURRENT_LIST_DIR}/RigPressureDepthData.h ${CMAKE_CURRENT_LIST_DIR}/RigMswCenterLineCalculator.h ${CMAKE_CURRENT_LIST_DIR}/RigWellAllocationOverTime.h @@ -172,6 +173,7 @@ set(SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RigSurfaceResampler.cpp ${CMAKE_CURRENT_LIST_DIR}/RigSurfaceStatisticsCalculator.cpp ${CMAKE_CURRENT_LIST_DIR}/RigWellLogIndexDepthOffset.cpp + ${CMAKE_CURRENT_LIST_DIR}/RigTexturedSection.cpp ${CMAKE_CURRENT_LIST_DIR}/RigPressureDepthData.cpp ${CMAKE_CURRENT_LIST_DIR}/RigMswCenterLineCalculator.cpp ${CMAKE_CURRENT_LIST_DIR}/RigWellAllocationOverTime.cpp diff --git a/ApplicationLibCode/ReservoirDataModel/RigPolyLinesData.h b/ApplicationLibCode/ReservoirDataModel/RigPolyLinesData.h index 89eeeb60e1..f6d0a1c32f 100644 --- a/ApplicationLibCode/ReservoirDataModel/RigPolyLinesData.h +++ b/ApplicationLibCode/ReservoirDataModel/RigPolyLinesData.h @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////////// // -// Copyright (C) 2018 equinor ASA +// Copyright (C) 2018 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 diff --git a/ApplicationLibCode/ReservoirDataModel/RigTexturedSection.cpp b/ApplicationLibCode/ReservoirDataModel/RigTexturedSection.cpp new file mode 100644 index 0000000000..2d081606de --- /dev/null +++ b/ApplicationLibCode/ReservoirDataModel/RigTexturedSection.cpp @@ -0,0 +1,141 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023 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 "RigTexturedSection.h" + +#include "cvfTextureImage.h" + +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigTexturedSection::RigTexturedSection() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigTexturedSection::~RigTexturedSection() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigTexturedSection::setWhatToUpdate( WhatToUpdateEnum updateInfo, int index /*=-1*/ ) +{ + int start = index; + int stop = index + 1; + + if ( index < 0 ) + { + start = 0; + stop = m_sectionParts.size(); + } + + for ( int i = start; i < stop; i++ ) + { + switch ( updateInfo ) + { + case RigTexturedSection::WhatToUpdateEnum::UPDATE_ALL: + case RigTexturedSection::WhatToUpdateEnum::UPDATE_GEOMETRY: + m_sectionParts[i].isRectValid = false; + m_sectionParts[i].rect.clear(); + [[fallthrough]]; + case RigTexturedSection::WhatToUpdateEnum::UPDATE_DATA: + m_sectionParts[i].sliceData = nullptr; + [[fallthrough]]; + case RigTexturedSection::WhatToUpdateEnum::UPDATE_TEXTURE: + m_sectionParts[i].texture = nullptr; + [[fallthrough]]; + case RigTexturedSection::WhatToUpdateEnum::UPDATE_NONE: + default: + break; + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RigTexturedSection::isValid() const +{ + if ( m_sectionParts.size() == 0 ) return false; + + bool valid = true; + + for ( int i = 0; i < (int)m_sectionParts.size(); i++ ) + { + valid = valid && m_sectionParts[i].allDataValid(); + } + + return valid; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int RigTexturedSection::partsCount() const +{ + return m_sectionParts.size(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigTexturedSection::resize( int size ) +{ + m_sectionParts.resize( size ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RigTexturedSectionPart& RigTexturedSection::part( int index ) +{ + CVF_ASSERT( index < (int)m_sectionParts.size() ); + return m_sectionParts[index]; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigTexturedSection::setSectionPartRect( int index, cvf::Vec3dArray rect ) +{ + if ( index >= (int)m_sectionParts.size() ) + { + resize( index + 1 ); + } + + m_sectionParts[index].rect = rect; + m_sectionParts[index].isRectValid = true; + m_sectionParts[index].sliceData = nullptr; + m_sectionParts[index].texture = nullptr; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RigTexturedSection::setSectionPartData( int index, std::shared_ptr data ) +{ + if ( index >= (int)m_sectionParts.size() ) return; + m_sectionParts[index].sliceData = data; + m_sectionParts[index].texture = nullptr; +} diff --git a/ApplicationLibCode/ReservoirDataModel/RigTexturedSection.h b/ApplicationLibCode/ReservoirDataModel/RigTexturedSection.h new file mode 100644 index 0000000000..a3c63a4f7f --- /dev/null +++ b/ApplicationLibCode/ReservoirDataModel/RigTexturedSection.h @@ -0,0 +1,88 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023 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. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cvfArray.h" +#include "cvfColor3.h" +#include "cvfObject.h" +#include "cvfVector3.h" + +#include +#include + +namespace ZGYAccess +{ +class SeismicSliceData; +} + +namespace cvf +{ +class TextureImage; +} + +class RigTexturedSectionPart +{ +public: + RigTexturedSectionPart() + : isRectValid( false ){}; + ~RigTexturedSectionPart(){}; + + bool allDataValid() const { return isRectValid && ( sliceData != nullptr ) && texture.notNull(); }; + +public: + cvf::Vec3dArray rect; + bool isRectValid; + std::shared_ptr sliceData; + cvf::ref texture; +}; + +//================================================================================================== +/// +/// +//================================================================================================== +class RigTexturedSection : public cvf::Object +{ +public: + enum class WhatToUpdateEnum + { + UPDATE_NONE = 0, + UPDATE_TEXTURE = 1, + UPDATE_GEOMETRY = 2, + UPDATE_DATA = 3, + UPDATE_ALL = 4 + }; + +public: + RigTexturedSection(); + ~RigTexturedSection() override; + + void setWhatToUpdate( WhatToUpdateEnum updateInfo, int index = -1 ); + bool isValid() const; + + void setSectionPartRect( int index, cvf::Vec3dArray rect ); + void setSectionPartData( int index, std::shared_ptr data ); + + int partsCount() const; + void resize( int size ); + + RigTexturedSectionPart& part( int index ); + +private: + std::vector m_sectionParts; +}; diff --git a/ApplicationLibCode/UserInterface/CMakeLists_files.cmake b/ApplicationLibCode/UserInterface/CMakeLists_files.cmake index 1ce68f8810..4382f0b27f 100644 --- a/ApplicationLibCode/UserInterface/CMakeLists_files.cmake +++ b/ApplicationLibCode/UserInterface/CMakeLists_files.cmake @@ -99,6 +99,7 @@ set(SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RiuAbstractOverlayContentFrame.h ${CMAKE_CURRENT_LIST_DIR}/RiuQwtLegendOverlayContentFrame.h ${CMAKE_CURRENT_LIST_DIR}/RiuAbstractLegendFrame.h + ${CMAKE_CURRENT_LIST_DIR}/RiuSeismicHistogramPanel.h ${CMAKE_CURRENT_LIST_DIR}/RiuCategoryLegendFrame.h ${CMAKE_CURRENT_LIST_DIR}/RiuScalarMapperLegendFrame.h ${CMAKE_CURRENT_LIST_DIR}/RiuFileDialogTools.h @@ -207,6 +208,7 @@ set(SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RiuScalarMapperLegendFrame.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuFileDialogTools.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuGuiTheme.cpp + ${CMAKE_CURRENT_LIST_DIR}/RiuSeismicHistogramPanel.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuQssSyntaxHighlighter.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuTextEditWithCompletion.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuTextContentFrame.cpp @@ -259,6 +261,7 @@ list( ${CMAKE_CURRENT_LIST_DIR}/RiuMdiArea.h ${CMAKE_CURRENT_LIST_DIR}/RiuMdiSubWindow.h ${CMAKE_CURRENT_LIST_DIR}/RiuPvtPlotPanel.h + ${CMAKE_CURRENT_LIST_DIR}/RiuSeismicHistogramPanel.h ${CMAKE_CURRENT_LIST_DIR}/RiuRelativePermeabilityPlotPanel.h ${CMAKE_CURRENT_LIST_DIR}/RiuResultInfoPanel.h ${CMAKE_CURRENT_LIST_DIR}/RiuResultQwtPlot.h diff --git a/ApplicationLibCode/UserInterface/RiuDockWidgetTools.cpp b/ApplicationLibCode/UserInterface/RiuDockWidgetTools.cpp index 46eb9cc33d..a96ace9a25 100644 --- a/ApplicationLibCode/UserInterface/RiuDockWidgetTools.cpp +++ b/ApplicationLibCode/UserInterface/RiuDockWidgetTools.cpp @@ -115,6 +115,14 @@ QString RiuDockWidgetTools::mainWindowPvtPlotName() return "dockPvtPlot_mainWindow"; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RiuDockWidgetTools::mainWindowSeismicHistogramName() +{ + return "dockSeisHist_mainWindow"; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -353,6 +361,8 @@ QIcon RiuDockWidgetTools::dockIcon( const QString dockWidgetName ) return QIcon( ":/window-management.svg" ); else if ( dockWidgetName == main3DWindowName() ) return QIcon( ":/window-management.svg" ); + else if ( dockWidgetName == mainWindowSeismicHistogramName() ) + return QIcon( ":/graph.svg" ); return QIcon( ":/view.svg" ); } @@ -390,33 +400,33 @@ QByteArray RiuDockWidgetTools::defaultEclipseDockState() // start paste static const char stateData[] = - { '\x00', '\x00', '\x06', '\x13', '\x78', '\xda', '\x95', '\x54', '\x4d', '\x6f', '\xc2', '\x30', '\x0c', '\xbd', '\xef', '\x57', - '\x44', '\xbd', '\x33', '\xe8', '\x07', '\x82', '\x03', '\x1f', '\x42', '\x30', '\xa4', '\x1d', '\xd8', '\xd8', '\x0a', '\xe3', - '\x38', '\x65', '\xad', '\x07', '\xd9', '\xd2', '\x04', '\x39', '\x29', '\x1b', '\xd3', '\x7e', '\xfc', '\xd2', '\x16', '\x21', - '\x01', '\x29', '\x5d', '\x0f', '\x55', '\x13', '\xfb', '\x3d', '\xfb', '\xd9', '\x71', '\xd2', '\x1b', '\x7e', '\x27', '\x9c', - '\xec', '\x00', '\x15', '\x93', '\xa2', '\xef', '\xb8', '\xb7', '\x2d', '\x87', '\x80', '\x88', '\x64', '\xcc', '\xc4', '\xba', - '\xef', '\x2c', '\x17', '\xd3', '\x46', '\xd7', '\x19', '\x0e', '\x7a', '\x4f', '\x7a', '\x14', '\xef', '\xa8', '\x88', '\x20', - '\x9e', '\xc8', '\xe8', '\xd3', '\xf8', '\xc2', '\xbd', '\xd2', '\x90', '\x90', '\x97', '\x23', '\xd1', '\x21', '\x4b', '\x05', - '\x78', '\xdc', '\xfb', '\x0e', '\x19', '\x4b', '\xa1', '\x29', '\x13', '\xc6', '\x92', '\xbb', '\xc7', '\x20', '\x34', '\x52', - '\xbe', '\x62', '\xf1', '\x1a', '\x74', '\xdf', '\x89', '\x4d', '\x1c', '\x7f', '\xb2', '\x62', '\x22', '\x96', '\x5f', '\xaf', - '\x89', '\xc1', '\x15', '\x4b', '\x67', '\xd0', '\x3b', '\xf2', '\xc8', '\x94', '\x4b', '\xaa', '\x73', '\x21', '\x2d', '\x63', - '\x0f', '\xb7', '\x9c', '\x69', '\x6d', '\xcc', '\x8f', '\xc8', '\x4c', '\x2c', '\xe3', '\xc9', '\x12', '\xfd', '\x66', '\x89', - '\x52', '\x61', '\x22', '\x7a', '\xa5', '\x98', '\xc6', '\x09', '\x66', '\x84', '\x40', '\xc9', '\x82', '\xbe', '\xa9', '\x42', - '\x65', '\x8a', '\x08', '\xe2', '\x20', '\x68', '\x8e', '\xf2', '\x03', '\x22', '\xbd', '\x40', '\x80', '\x53', '\x4d', '\x85', - '\x6a', '\xf2', '\x40', '\x13', '\xb8', '\x8a', '\x24', '\x63', '\x2e', '\x15', '\xc4', '\x99', '\xe0', '\xa6', '\x85', '\x35', - '\xa1', '\x9a', '\x86', '\x32', '\xc5', '\x08', '\x6a', '\x12', '\xc3', '\x08', '\xd9', '\x56', '\xab', '\xeb', '\xac', '\x66', - '\x56', '\xd9', '\x49', '\x7d', '\xee', '\x65', '\x7d', '\x5b', '\x40', '\xbd', '\xbf', '\x8b', '\x99', '\x96', '\x58', '\x5d', - '\x62', '\x09', '\xd8', '\x9a', '\x36', '\x64', '\x3f', '\xa0', '\x06', '\x9d', '\xc0', '\x27', '\xed', '\x56', '\x87', '\xf4', - '\x9a', '\xc5', '\xde', '\xfc', '\x0f', '\x47', '\x52', '\xfb', '\x70', '\xce', '\xc5', '\xdb', '\xa6', '\xc5', '\x8c', '\x08', - '\x5d', '\xe7', '\x58', '\x4b', '\x01', '\x56', '\x82', '\x55', '\x7a', '\xc5', '\x64', '\xf9', '\xd7', '\x85', '\x3d', '\x83', - '\x4a', '\xb9', '\xbe', '\x17', '\xef', '\xb2', '\xa2', '\xa3', '\x76', '\x60', '\xd5', '\x21', '\xb6', '\xad', '\xe9', '\xe6', - '\x5c', '\xea', '\x7f', '\xa5', '\x3b', '\x07', '\x56', '\x8d', '\x28', '\x6c', '\xf5', '\xa6', '\x26', '\x67', '\x26', '\x37', - '\xa8', '\xc6', '\x0c', '\x23', '\x0e', '\xa5', '\x4c', '\xd7', '\xca', '\x7c', '\x06', '\x3e', '\x07', '\x4c', '\x6a', '\xe6', - '\x9b', '\xef', '\x2a', '\xaa', '\xba', '\x6c', '\xa2', '\x77', '\xd6', '\xc4', '\x19', '\x28', '\x45', '\xd7', '\xa0', '\x2a', - '\x5a', '\x68', '\x83', '\x55', '\x89', '\x43', '\x19', '\x19', '\xd6', '\x4c', '\x8a', '\x1a', '\xd7', '\xa6', '\xed', '\xb9', - '\xc4', '\x75', '\x5b', '\x2e', '\x09', '\xba', '\x25', '\x77', '\x27', '\xb7', '\x74', '\xbd', '\x36', '\x09', '\xcc', '\x57', - '\x8e', '\x08', '\x7c', '\x9f', '\x78', '\xae', '\x89', '\x66', '\x83', '\x34', '\x8f', '\x4f', '\xab', '\x59', '\x97', '\x3c', - '\xe9', '\x83', '\x9b', '\x3f', '\xff', '\x64', '\x15', '\xea' }; + { '\x00', '\x00', '\x06', '\x46', '\x78', '\xda', '\x95', '\x55', '\xcb', '\x4e', '\xc3', '\x30', '\x10', '\xbc', '\xf3', '\x15', + '\x56', '\xee', '\xd0', '\xe6', '\x01', '\xf4', '\x90', '\x16', '\xa1', '\x14', '\x04', '\x87', '\x42', '\x69', '\x5a', '\x7a', + '\x44', '\x26', '\x59', '\x8a', '\xc1', '\xb1', '\xab', '\xf5', '\xb6', '\x3c', '\xc4', '\xc7', '\xe3', '\x3e', '\x14', '\xa9', + '\xc5', '\x69', '\xc8', '\x21', '\x8a', '\xbd', '\x9e', '\xf1', '\xce', '\xac', '\xd7', '\x49', '\x7c', '\xf1', '\x59', '\x48', + '\xb6', '\x04', '\x34', '\x42', '\xab', '\xae', '\xe7', '\x9f', '\xb4', '\x3d', '\x06', '\x2a', '\xd3', '\xb9', '\x50', '\xb3', + '\xae', '\x37', '\x19', '\x5f', '\x1f', '\x77', '\xbc', '\x8b', '\x5e', '\xfc', '\x40', '\x97', '\xf9', '\x92', '\xab', '\x0c', + '\xf2', '\xbe', '\xce', '\xde', '\xed', '\x5a', '\xfa', '\x65', '\x08', '\x0a', '\xf6', '\x58', '\x12', '\x3d', '\x36', '\x31', + '\x80', '\xe5', '\x3c', '\xf4', '\x58', '\xa2', '\x15', '\x71', '\xa1', '\x6c', '\x64', '\xbd', '\x9c', '\x80', '\x22', '\xe4', + '\x72', '\x2a', '\xf2', '\x19', '\x50', '\xd7', '\xcb', '\xed', '\x3e', '\x61', '\x7f', '\x2a', '\x54', '\xae', '\x3f', '\x9e', + '\x0a', '\x8b', '\xdb', '\x0c', '\xbd', '\x5e', '\x5c', '\xf2', '\xd8', '\xb5', '\xd4', '\x9c', '\xd6', '\x42', '\xda', '\x36', + '\x9e', '\xce', '\xa5', '\x20', '\xb2', '\xe1', '\x7b', '\x14', '\x76', '\x2f', '\xbb', '\xb2', '\x4a', '\xf4', '\xb3', '\x4a', + '\xb4', '\x50', '\x76', '\xc7', '\xa0', '\x12', '\x73', '\xbc', '\x83', '\xb9', '\x44', '\xe0', '\x6c', '\xcc', '\x9f', '\xcd', + '\x46', '\xe5', '\x02', '\x11', '\xd4', '\x56', '\xd0', '\x10', '\xf5', '\x1b', '\x64', '\x34', '\x46', '\x80', '\x5d', '\x4d', + '\x1b', '\xd5', '\xec', '\x8e', '\x17', '\x70', '\x10', '\xc9', '\x12', '\xa9', '\x0d', '\xe4', '\x2b', '\xc1', '\x2d', '\x07', + '\xab', '\xcf', '\x89', '\xa7', '\x7a', '\x81', '\x19', '\x34', '\x24', '\xa6', '\x19', '\x8a', '\x39', '\x99', '\xc3', '\xac', + '\xd6', '\xca', '\xd9', '\x8e', '\x3f', '\xff', '\xaf', '\xbf', '\x39', '\x20', '\x7d', '\x5d', '\xe5', '\x82', '\x34', '\xd6', + '\x5b', '\xac', '\x00', '\x3b', '\xd3', '\xa6', '\xe2', '\x1b', '\x4c', '\xef', '\x3c', '\x0a', '\xd9', '\x69', '\xfb', '\x9c', + '\xc5', '\xad', '\xcd', '\xdc', '\xbe', '\xb7', '\x47', '\xd2', '\xf8', '\x70', '\xf6', '\xc5', '\xbb', '\xba', '\xc5', '\xb6', + '\x08', '\x9f', '\xad', '\xb1', '\x0e', '\x03', '\x4e', '\x82', '\x53', '\x7a', '\x4d', '\x67', '\x85', '\x87', '\x85', '\x8d', + '\xc0', '\x2c', '\x24', '\xdd', '\xaa', '\x17', '\x5d', '\x53', '\x51', '\x37', '\xb0', '\xee', '\x10', '\xcf', '\x9c', '\xe9', + '\x86', '\x52', '\xd3', '\xbf', '\xd2', '\xed', '\x03', '\xeb', '\x5a', '\x14', '\xe6', '\xf4', '\xda', '\x90', '\x33', '\xd0', + '\xaf', '\x68', '\x12', '\x81', '\x99', '\x84', '\x4a', '\xa6', '\xef', '\x64', '\x8e', '\x40', '\x0e', '\x01', '\x8b', '\x86', + '\xf9', '\x86', '\xcb', '\xa6', '\xae', '\x52', '\x10', '\xe6', '\x46', '\x18', '\x6a', '\x52', '\xf7', '\x60', '\xaf', '\xee', + '\x03', '\x30', '\x86', '\xcf', '\xc0', '\xd4', '\x54', '\xdd', '\x05', '\xab', '\xf3', '\x83', '\x3a', '\xb3', '\xac', '\x81', + '\x56', '\x0d', '\x6e', '\x5a', '\xd4', '\x69', '\x33', '\xdf', '\x8f', '\x02', '\x16', '\x75', '\x2a', '\xae', '\xdb', '\x3a', + '\xd2', '\x09', '\x4e', '\x59', '\x64', '\x9f', '\x6a', '\x44', '\x14', '\x86', '\x2c', '\xf0', '\x03', '\xdf', '\x09', '\x69', + '\x95', '\x5f', '\x63', '\x3b', '\xae', '\xf8', '\x0b', '\xf4', '\x8e', '\x7e', '\x01', '\xe9', '\x95', '\x27', '\x97' }; // end paste @@ -433,34 +443,34 @@ QByteArray RiuDockWidgetTools::defaultGeoMechDockState() // start paste static const char stateData[] = - { '\x00', '\x00', '\x06', '\x4e', '\x78', '\xda', '\x95', '\x55', '\x5d', '\x4f', '\xc2', '\x30', '\x14', '\x7d', '\xf7', '\x57', - '\x34', '\x7b', '\x47', '\x36', '\x36', '\x44', '\x12', '\x3e', '\x42', '\x40', '\x12', '\x1f', '\x50', '\x64', '\x20', '\x8f', - '\xa6', '\x6e', '\x57', '\xa8', '\x76', '\x2d', '\x69', '\x2f', '\x28', '\xc6', '\x1f', '\x6f', '\xc7', '\xc8', '\x12', '\xa0', - '\x6c', '\xf0', '\xb4', '\xee', '\xf6', '\x9c', '\x9e', '\x73', '\x3f', '\xba', '\xb5', '\xba', '\x3f', '\x09', '\x27', '\x1b', - '\x50', '\x9a', '\x49', '\xd1', '\x76', '\xbc', '\x5b', '\xd7', '\x21', '\x20', '\x22', '\x19', '\x33', '\xb1', '\x68', '\x3b', - '\xb3', '\xe9', '\xb0', '\x72', '\xef', '\x74', '\x3b', '\xad', '\x17', '\xec', '\xc5', '\x1b', '\x2a', '\x22', '\x88', '\x07', - '\x32', '\xfa', '\x32', '\x7b', '\xe1', '\x56', '\x23', '\x24', '\xe4', '\x35', '\x27', '\x3a', '\x64', '\xa6', '\x41', '\xe5', - '\xef', '\xbe', '\x43', '\xfa', '\x52', '\x20', '\x65', '\xc2', '\x44', '\x76', '\xdb', '\x7d', '\x10', '\xa8', '\x28', '\x9f', - '\xb3', '\x78', '\x01', '\xd8', '\x76', '\x62', '\x73', '\x8e', '\x3f', '\x98', '\x33', '\x11', '\xcb', '\xef', '\xb7', '\xc4', - '\xe0', '\xb2', '\xa5', '\xd3', '\x69', '\xe5', '\x3c', '\x32', '\xe4', '\x92', '\xe2', '\xce', '\x88', '\x6b', '\xe2', '\xe1', - '\x8a', '\x33', '\x44', '\x13', '\x7e', '\x56', '\xcc', '\x9c', '\x65', '\x76', '\x52', '\xa1', '\xbf', '\x54', '\x68', '\x2d', - '\x30', '\x95', '\x3c', '\x87', '\xa9', '\xe4', '\x98', '\x9a', '\xc1', '\xf4', '\x14', '\x50', '\x32', '\xa5', '\xef', '\x3a', - '\x73', '\xb9', '\x56', '\x0a', '\xc4', '\xde', '\xd0', '\x58', '\xc9', '\x4f', '\x88', '\x70', '\xaa', '\x00', '\x0e', '\x3d', - '\x65', '\xae', '\xc9', '\x13', '\x4d', '\xa0', '\x10', '\x49', '\xfa', '\x5c', '\x6a', '\x88', '\x53', '\xc3', '\x55', '\x0b', - '\x6b', '\x40', '\x91', '\x86', '\x72', '\xad', '\x22', '\xb8', '\x92', '\x18', '\x46', '\x8a', '\xad', '\x50', '\x17', '\xb3', - '\xaa', '\x69', '\x66', '\x07', '\xf9', '\x79', '\xa7', '\xf9', '\xad', '\x40', '\xe1', '\xf6', '\x21', '\x66', '\x28', '\x55', - '\x79', '\x8a', '\x67', '\xc0', '\x56', '\xd9', '\x90', '\xfd', '\x82', '\xee', '\x34', '\x1a', '\x4d', '\x52', '\xf7', '\x3d', - '\xd2', '\xaa', '\x66', '\xef', '\xe6', '\xb9', '\x6f', '\xc9', '\xd5', '\xcd', '\x39', '\x36', '\x6f', '\x9b', '\x16', '\x33', - '\x22', '\x74', '\xb1', '\xc3', '\x5a', '\x12', '\xb0', '\x12', '\xac', '\xd6', '\x2f', '\x98', '\xac', '\x02', '\x63', '\x13', - '\xd0', '\x6b', '\x8e', '\x8f', '\xe2', '\x43', '\x96', '\x54', '\xd4', '\x0e', '\x2c', '\x6b', '\x62', '\x60', '\x95', '\x1b', - '\x73', '\x89', '\x17', '\xc9', '\x1d', '\x03', '\x4b', '\x26', '\x6d', '\x24', '\x97', '\x4a', '\xf7', '\x99', '\x8a', '\x38', - '\x5c', '\xc9', '\x9c', '\x00', '\x1f', '\x83', '\x4a', '\xce', '\xb2', '\x3c', '\x2b', '\x6b', '\xbc', '\xc1', '\x62', '\xc6', - '\x69', '\x41', '\x6a', '\x47', '\x05', '\x19', '\x81', '\xd6', '\x74', '\x01', '\xba', '\xa4', '\x1c', '\x36', '\x58', '\x49', - '\x4a', '\xe6', '\x0a', '\x44', '\x86', '\x35', '\x92', '\xe2', '\x8a', '\x2b', '\x50', '\xaf', '\x79', '\xc4', '\xf3', '\xea', - '\x2e', '\x09', '\xfc', '\x7b', '\xfb', '\x3d', '\xd8', '\x45', '\x9a', '\x6e', '\x40', '\x02', '\xf7', '\xce', '\x8a', '\x28', - '\x18', '\xb6', '\x01', '\xac', '\x70', '\x79', '\x41', '\xf3', '\xad', '\x38', '\x6b', '\x65', '\x33', '\xf9', '\xc0', '\xf7', - '\x49', '\xcd', '\x33', '\xd6', '\x5d', '\xab', '\xa3', '\x6a', '\xfe', '\x55', '\x36', '\xeb', '\x33', '\x7f', '\x83', '\xce', - '\xcd', '\x3f', '\x00', '\xe7', '\x29', '\xe5' }; + { '\x00', '\x00', '\x06', '\x81', '\x78', '\xda', '\x95', '\x55', '\xc1', '\x52', '\xc2', '\x30', '\x10', '\xbd', '\xfb', '\x15', + '\x99', '\xde', '\x95', '\x96', '\x16', '\xe1', '\x50', '\x70', '\x1c', '\xd0', '\xd1', '\x03', '\x5a', '\x29', '\xca', '\xd1', + '\x89', '\xed', '\x8a', '\xd1', '\x34', '\x61', '\x92', '\x2d', '\x8a', '\xe3', '\xc7', '\x9b', '\x52', '\xa7', '\x33', '\x60', + '\x68', '\xe9', '\xa9', '\xc9', '\xe6', '\xbd', '\xbc', '\xb7', '\x9b', '\x4d', '\x1a', '\x5e', '\x7c', '\x65', '\x9c', '\xac', + '\x41', '\x69', '\x26', '\xc5', '\xd0', '\xf1', '\xce', '\x5c', '\x87', '\x80', '\x48', '\x64', '\xca', '\xc4', '\x72', '\xe8', + '\x3c', '\xce', '\xaf', '\x4f', '\x07', '\xce', '\xc5', '\x28', '\x7c', '\xc0', '\xcb', '\x74', '\x4d', '\x45', '\x02', '\xe9', + '\x44', '\x26', '\x1f', '\x66', '\x2d', '\xde', '\x68', '\x84', '\x8c', '\x3c', '\x55', '\x44', '\x87', '\x3c', '\x6a', '\x50', + '\xd5', '\xdc', '\x77', '\xc8', '\x58', '\x0a', '\xa4', '\x4c', '\x98', '\xc8', '\x76', '\x79', '\x0c', '\x02', '\x15', '\xe5', + '\x0b', '\x96', '\x2e', '\x01', '\x87', '\x4e', '\x6a', '\xf6', '\xf1', '\x27', '\x0b', '\x26', '\x52', '\xf9', '\xf9', '\x9c', + '\x19', '\x5c', '\x39', '\x74', '\x46', '\x61', '\xc5', '\x23', '\xd7', '\x5c', '\x52', '\xdc', '\x1a', '\x71', '\x4d', '\x3c', + '\x5e', '\x71', '\x86', '\x68', '\xc2', '\xf7', '\x8a', '\x99', '\xbd', '\xcc', '\x4a', '\x21', '\xf4', '\x53', '\x08', '\xe5', + '\x02', '\x0b', '\xc9', '\x43', '\x98', '\xd3', '\x0a', '\xd3', '\x35', '\x98', '\x4b', '\x05', '\x94', '\xcc', '\xe9', '\x8b', + '\x2e', '\x5d', '\xe6', '\x4a', '\x81', '\xf8', '\x33', '\x14', '\x29', '\xf9', '\x0e', '\x09', '\xce', '\x15', '\xc0', '\xae', + '\xa7', '\xd2', '\x35', '\xb9', '\xa3', '\x19', '\xd4', '\x22', '\xc9', '\x98', '\x4b', '\x0d', '\x69', '\x61', '\xb8', '\x63', + '\x61', '\x4d', '\x28', '\xd2', '\x58', '\xe6', '\x2a', '\x81', '\x96', '\xc4', '\x38', '\x51', '\x6c', '\x85', '\xba', '\x9e', + '\xd5', '\x29', '\x32', '\xdb', '\xc9', '\xcf', '\xfb', '\x9f', '\xdf', '\x0a', '\x14', '\x6e', '\xae', '\x52', '\x86', '\x52', + '\x35', '\xa7', '\x78', '\x00', '\x6c', '\x95', '\x8d', '\xd9', '\x37', '\xe8', '\x51', '\x3f', '\xf0', '\x49', '\xcf', '\xed', + '\x93', '\xb0', '\x53', '\xce', '\xcd', '\xf7', '\xef', '\x48', '\x5a', '\x1f', '\xce', '\xbe', '\x79', '\x5b', '\xb7', '\x98', + '\x16', '\xa1', '\xcb', '\x2d', '\xd6', '\x92', '\x80', '\x95', '\x60', '\xb5', '\x7e', '\x44', '\x67', '\xd5', '\x18', '\x9b', + '\x81', '\xce', '\x39', '\xde', '\x8a', '\x57', '\xd9', '\x50', '\x51', '\x3b', '\xb0', '\xe9', '\x10', '\x7b', '\x56', '\xb9', + '\x88', '\x4b', '\x3c', '\x4a', '\x6e', '\x1f', '\xd8', '\xd0', '\x69', '\x53', '\xf9', '\xa6', '\xf4', '\x98', '\xa9', '\x84', + '\x43', '\x4b', '\x66', '\x0c', '\x4c', '\xdf', '\x30', '\xdd', '\x86', '\x32', '\x03', '\x1e', '\x81', '\xca', '\x0e', '\x0a', + '\x79', '\x56', '\x56', '\xb4', '\xc6', '\x7a', '\xc6', '\xff', '\x1a', '\x76', '\xf7', '\x6a', '\x38', '\x05', '\xad', '\xe9', + '\x12', '\x74', '\x43', '\x05', '\x6d', '\xb0', '\x86', '\x94', '\xcc', '\xad', '\x49', '\x0c', '\x6b', '\x2a', '\x45', '\x8b', + '\x5b', '\xd3', '\xeb', '\x7a', '\xc4', '\xf3', '\x7a', '\x2e', '\x09', '\xfc', '\x81', '\xfd', '\xea', '\x6c', '\x23', '\x83', + '\x20', '\x20', '\x81', '\x7b', '\x6e', '\x45', '\xd4', '\xf4', '\xe7', '\x04', '\x56', '\xf8', '\x76', '\x44', '\xbf', '\x58', + '\x71', '\xd6', '\xca', '\x96', '\xf2', '\x81', '\xef', '\x93', '\xae', '\x67', '\xac', '\xbb', '\x56', '\x47', '\x9d', '\xea', + '\x21', '\x37', '\xe3', '\x03', '\x3f', '\x90', '\xd1', '\xc9', '\x2f', '\xd6', '\xef', '\x3b', '\x86' }; // end paste diff --git a/ApplicationLibCode/UserInterface/RiuDockWidgetTools.h b/ApplicationLibCode/UserInterface/RiuDockWidgetTools.h index 48a9bc9b8c..1c22356009 100644 --- a/ApplicationLibCode/UserInterface/RiuDockWidgetTools.h +++ b/ApplicationLibCode/UserInterface/RiuDockWidgetTools.h @@ -54,6 +54,7 @@ public: static QString mainWindowDepthPlotName(); static QString mainWindowRelPermPlotName(); static QString mainWindowPvtPlotName(); + static QString mainWindowSeismicHistogramName(); static QString mainWindowMessagesName(); static QString mainWindowMohrsCirclePlotName(); static QString mainWindowUndoStackName(); diff --git a/ApplicationLibCode/UserInterface/RiuMainWindow.cpp b/ApplicationLibCode/UserInterface/RiuMainWindow.cpp index bbf437873e..f0417b8de8 100644 --- a/ApplicationLibCode/UserInterface/RiuMainWindow.cpp +++ b/ApplicationLibCode/UserInterface/RiuMainWindow.cpp @@ -63,6 +63,7 @@ #include "RiuRelativePermeabilityPlotPanel.h" #include "RiuResultInfoPanel.h" #include "RiuResultQwtPlot.h" +#include "RiuSeismicHistogramPanel.h" #include "RiuToolTipMenu.h" #include "RiuTools.h" #include "RiuTreeViewEventFilter.h" @@ -128,6 +129,7 @@ RiuMainWindow::RiuMainWindow() , m_pvtPlotPanel( nullptr ) , m_mohrsCirclePlot( nullptr ) , m_holoLensToolBar( nullptr ) + , m_seismicHistogramPanel( nullptr ) { setAttribute( Qt::WA_DeleteOnClose ); @@ -262,6 +264,7 @@ void RiuMainWindow::cleanupGuiCaseClose() if ( m_relPermPlotPanel ) m_relPermPlotPanel->clearPlot(); if ( m_pvtPlotPanel ) m_pvtPlotPanel->clearPlot(); if ( m_mohrsCirclePlot ) m_mohrsCirclePlot->clearPlot(); + if ( m_seismicHistogramPanel ) m_seismicHistogramPanel->clearPlot(); if ( m_pdmUiPropertyView ) { @@ -481,6 +484,7 @@ void RiuMainWindow::createMenus() importMenu->addAction( cmdFeatureMgr->action( "RicImportPressureDepthDataFeature" ) ); importMenu->addAction( cmdFeatureMgr->action( "RicImportFormationNamesFeature" ) ); importMenu->addAction( cmdFeatureMgr->action( "RicImportSurfacesFeature" ) ); + importMenu->addAction( cmdFeatureMgr->action( "RicImportSeismicFeature" ) ); RiuTools::enableAllActionsOnShow( this, importMenu ); @@ -871,6 +875,15 @@ void RiuMainWindow::createDockPanels() dockManager()->addDockWidgetTabToArea( dockWidget, bottomArea ); } + { + auto dockWidget = + RiuDockWidgetTools::createDockWidget( "Seismic Histogram", RiuDockWidgetTools::mainWindowSeismicHistogramName(), dockManager() ); + + m_seismicHistogramPanel = new RiuSeismicHistogramPanel( dockWidget ); + dockWidget->setWidget( m_seismicHistogramPanel ); + dockManager()->addDockWidgetTabToArea( dockWidget, bottomArea ); + } + // result info { auto dockWidget = RiuDockWidgetTools::createDockWidget( "Result Info", RiuDockWidgetTools::mainWindowResultInfoName(), dockManager() ); @@ -1195,6 +1208,14 @@ RiuMohrsCirclePlot* RiuMainWindow::mohrsCirclePlot() return m_mohrsCirclePlot; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuSeismicHistogramPanel* RiuMainWindow::seismicHistogramPanel() +{ + return m_seismicHistogramPanel; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -1486,6 +1507,8 @@ void RiuMainWindow::selectedObjectsChanged() m_pdmUiPropertyView->showProperties( firstSelectedObject ); + m_seismicHistogramPanel->showHistogram( firstSelectedObject ); + if ( uiItems.size() == 1 && m_allowActiveViewChangeFromSelection ) { // Find the reservoir view or the Plot that the selected item is within @@ -1858,6 +1881,10 @@ void RiuMainWindow::applyFontSizesToDockedPlots() { m_pvtPlotPanel->applyFontSizes( true ); } + if ( m_seismicHistogramPanel ) + { + m_seismicHistogramPanel->applyFontSizes( true ); + } } //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationLibCode/UserInterface/RiuMainWindow.h b/ApplicationLibCode/UserInterface/RiuMainWindow.h index 1383b6e18f..84f7e7bb84 100644 --- a/ApplicationLibCode/UserInterface/RiuMainWindow.h +++ b/ApplicationLibCode/UserInterface/RiuMainWindow.h @@ -54,6 +54,7 @@ class RiuRelativePermeabilityPlotPanel; class RiuPvtPlotPanel; class RiuMohrsCirclePlot; class RiuMdiArea; +class RiuSeismicHistogramPanel; class RicGridCalculatorDialog; @@ -128,6 +129,7 @@ public: RiuRelativePermeabilityPlotPanel* relativePermeabilityPlotPanel(); RiuPvtPlotPanel* pvtPlotPanel(); RiuMohrsCirclePlot* mohrsCirclePlot(); + RiuSeismicHistogramPanel* seismicHistogramPanel(); RiuMessagePanel* messagePanel(); void showProcessMonitorDockPanel(); @@ -189,6 +191,7 @@ private: RiuDepthQwtPlot* m_depthQwtPlot; RiuMohrsCirclePlot* m_mohrsCirclePlot; RiuRelativePermeabilityPlotPanel* m_relPermPlotPanel; + RiuSeismicHistogramPanel* m_seismicHistogramPanel; RiuPvtPlotPanel* m_pvtPlotPanel; std::unique_ptr m_gridCalculatorDialog; diff --git a/ApplicationLibCode/UserInterface/RiuSeismicHistogramPanel.cpp b/ApplicationLibCode/UserInterface/RiuSeismicHistogramPanel.cpp new file mode 100644 index 0000000000..a6d63fbd97 --- /dev/null +++ b/ApplicationLibCode/UserInterface/RiuSeismicHistogramPanel.cpp @@ -0,0 +1,167 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023 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 "RiuSeismicHistogramPanel.h" + +#include "Riu3dSelectionManager.h" +#include "RiuDockedQwtPlot.h" +#include "RiuGuiTheme.h" +#include "RiuPlotCurveSymbol.h" +#include "RiuQwtLinearScaleEngine.h" +#include "RiuQwtPlotCurve.h" +#include "RiuQwtSymbol.h" + +#include "qwt_plot_grid.h" +#include "qwt_text.h" + +#include "RimRegularLegendConfig.h" +#include "RimSeismicData.h" +#include "RimSeismicSection.h" + +#include +#include +#include +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuSeismicHistogramPanel::RiuSeismicHistogramPanel( QWidget* parent ) + : QWidget( parent ) +{ + m_qwtPlot = new RiuDockedQwtPlot( this ); + + QwtPlotGrid* grid = new QwtPlotGrid; + grid->attach( m_qwtPlot ); + RiuGuiTheme::styleQwtItem( grid ); + + QVBoxLayout* mainLayout = new QVBoxLayout(); + mainLayout->addWidget( m_qwtPlot ); + mainLayout->setContentsMargins( 0, 0, 0, 0 ); + + setLayout( mainLayout ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuSeismicHistogramPanel::~RiuSeismicHistogramPanel() +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuSeismicHistogramPanel::setPlotData( QString title, std::vector xvals, std::vector yvals ) +{ + m_qwtPlot->detachItems( QwtPlotItem::Rtti_PlotCurve ); + + RiuQwtPlotCurve* qwtCurve = new RiuQwtPlotCurve( nullptr, "Distribution" ); + + qwtCurve->setSamplesFromXValuesAndYValues( xvals, yvals, false ); + + qwtCurve->setStyle( QwtPlotCurve::Lines ); + + Qt::PenStyle penStyle = Qt::SolidLine; + + QPen curvePen( QBrush(), 1, penStyle ); + curvePen.setColor( QColor( 5, 5, 5, 255 ) ); + qwtCurve->setPen( curvePen ); + + RiuQwtSymbol* curveSymbol = new RiuQwtSymbol( RiuPlotCurveSymbol::SYMBOL_NONE ); + curveSymbol->setBrush( Qt::NoBrush ); + qwtCurve->setSymbol( curveSymbol ); + + qwtCurve->setRenderHint( QwtPlotItem::RenderAntialiased, true ); + qwtCurve->setYAxis( RiuPlotAxis::defaultLeft() ); + + qwtCurve->attach( m_qwtPlot ); + + RiuGuiTheme::styleQwtItem( qwtCurve ); + + m_qwtPlot->setAxisScaleEngine( QwtAxis::YLeft, new QwtLinearScaleEngine ); + m_qwtPlot->setAxisScaleEngine( QwtAxis::XBottom, new QwtLinearScaleEngine ); + m_qwtPlot->setAxisAutoScale( QwtAxis::XBottom, true ); + m_qwtPlot->setAxisAutoScale( QwtAxis::YLeft, true ); + m_qwtPlot->setAxisVisible( QwtAxis::YLeft, false ); + + QwtText plotTitle = m_qwtPlot->title(); + QFont titleFont = plotTitle.font(); + titleFont.setPointSize( 10 ); + plotTitle.setText( title ); + plotTitle.setFont( titleFont ); + m_qwtPlot->setTitle( plotTitle ); + + m_qwtPlot->replot(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuSeismicHistogramPanel::clearPlot() +{ + m_qwtPlot->setTitle( "" ); + m_qwtPlot->detachItems( QwtPlotItem::Rtti_PlotCurve ); + m_qwtPlot->replot(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuSeismicHistogramPanel::applyFontSizes( bool replot ) +{ + if ( m_qwtPlot ) m_qwtPlot->applyFontSizes( replot ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuSeismicHistogramPanel::showHistogram( caf::PdmObjectHandle* selectedObject ) +{ + RimSeismicData* seisData = dynamic_cast( selectedObject ); + if ( seisData == nullptr ) + { + RimSeismicSection* section = dynamic_cast( selectedObject ); + if ( section != nullptr ) + { + seisData = section->seismicData(); + } + } + + if ( seisData == nullptr ) + { + RimRegularLegendConfig* legend = dynamic_cast( selectedObject ); + if ( legend ) + { + RimSeismicSection* section = nullptr; + legend->firstAncestorOfType( section ); + if ( section != nullptr ) + { + seisData = section->seismicData(); + } + } + } + + if ( seisData == nullptr ) + { + clearPlot(); + return; + } + + setPlotData( seisData->userDescription(), seisData->histogramXvalues(), seisData->histogramYvalues() ); +} diff --git a/ApplicationLibCode/UserInterface/RiuSeismicHistogramPanel.h b/ApplicationLibCode/UserInterface/RiuSeismicHistogramPanel.h new file mode 100644 index 0000000000..43cd719093 --- /dev/null +++ b/ApplicationLibCode/UserInterface/RiuSeismicHistogramPanel.h @@ -0,0 +1,52 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2023 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. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include + +#include "cafPdmObject.h" + +#include + +class RiuDockedQwtPlot; +class RiuSelectionItem; + +//================================================================================================== +// +// +// +//================================================================================================== +class RiuSeismicHistogramPanel : public QWidget +{ + Q_OBJECT + +public: + RiuSeismicHistogramPanel( QWidget* parent ); + ~RiuSeismicHistogramPanel() override; + + void setPlotData( QString title, std::vector xvals, std::vector yvals ); + void clearPlot(); + void applyFontSizes( bool replot ); + + void showHistogram( caf::PdmObjectHandle* selectedObject ); + +private: + QPointer m_qwtPlot; +}; diff --git a/ApplicationLibCode/UserInterface/RiuSelectionChangedHandler.cpp b/ApplicationLibCode/UserInterface/RiuSelectionChangedHandler.cpp index 349d5f7372..3bef3cc4a6 100644 --- a/ApplicationLibCode/UserInterface/RiuSelectionChangedHandler.cpp +++ b/ApplicationLibCode/UserInterface/RiuSelectionChangedHandler.cpp @@ -49,6 +49,7 @@ #include "RiuRelativePermeabilityPlotUpdater.h" #include "RiuResultQwtPlot.h" #include "RiuResultTextBuilder.h" +#include "RiuSeismicHistogramPanel.h" #include diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e1d02ef02..0bc5b3d02d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -403,6 +403,15 @@ add_subdirectory(ThirdParty/NRLib) list(APPEND THIRD_PARTY_LIBRARIES NRLib) +# ############################################################################## +# openzgy +# ############################################################################## + +add_definitions(-DOPENZGY_STATIC) +add_subdirectory(ThirdParty/openzgy) + +list(APPEND THIRD_PARTY_LIBRARIES openzgy) + # ############################################################################## # Qt # ############################################################################## diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiSliderEditor.cpp b/Fwk/AppFwk/cafUserInterface/cafPdmUiSliderEditor.cpp index 2223b2bd14..1caf05af05 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiSliderEditor.cpp +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiSliderEditor.cpp @@ -78,6 +78,7 @@ void PdmUiSliderEditor::configureAndUpdateUi( const QString& uiConfigName ) m_spinBox->blockSignals( true ); m_spinBox->setMinimum( m_attributes.m_minimum ); m_spinBox->setMaximum( m_attributes.m_maximum ); + m_spinBox->setSingleStep( m_attributes.m_step ); QString textValue = uiField()->uiValue().toString(); m_spinBox->setValue( textValue.toInt() ); @@ -89,6 +90,7 @@ void PdmUiSliderEditor::configureAndUpdateUi( const QString& uiConfigName ) { m_slider->blockSignals( true ); m_slider->setRange( m_attributes.m_minimum, m_attributes.m_maximum ); + m_slider->setSingleStep( m_attributes.m_step ); updateSliderPosition(); m_slider->blockSignals( false ); } diff --git a/Fwk/AppFwk/cafUserInterface/cafPdmUiSliderEditor.h b/Fwk/AppFwk/cafUserInterface/cafPdmUiSliderEditor.h index 610950d26b..9ff9e53fc4 100644 --- a/Fwk/AppFwk/cafUserInterface/cafPdmUiSliderEditor.h +++ b/Fwk/AppFwk/cafUserInterface/cafPdmUiSliderEditor.h @@ -58,12 +58,14 @@ public: m_minimum = 0; m_maximum = 10; m_showSpinBox = true; + m_step = 1; } public: int m_minimum; int m_maximum; bool m_showSpinBox; + int m_step; }; class PdmUiSliderEditor : public PdmUiFieldEditorHandle diff --git a/Fwk/VizFwk/LibViewing/cvfModelBasicList.cpp b/Fwk/VizFwk/LibViewing/cvfModelBasicList.cpp index c9c56f2c7f..6965b75c03 100644 --- a/Fwk/VizFwk/LibViewing/cvfModelBasicList.cpp +++ b/Fwk/VizFwk/LibViewing/cvfModelBasicList.cpp @@ -211,7 +211,7 @@ bool ModelBasicList::partVisible(cvf::Part* part, const Camera* camera, const Cu if (cullSettings && camera && cullSettings->isViewFrustumCullingEnabled()) { const BoundingBox& bb = part->boundingBox(); - CVF_ASSERT(bb.isValid()); + if (!bb.isValid()) return false; if (camera->frustum().isOutside(bb)) { diff --git a/ThirdParty/openzgy b/ThirdParty/openzgy new file mode 160000 index 0000000000..9629375019 --- /dev/null +++ b/ThirdParty/openzgy @@ -0,0 +1 @@ +Subproject commit 96293750197311582250ac387a1f7db29df290a1