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