diff --git a/ApplicationLibCode/Commands/CMakeLists_files.cmake b/ApplicationLibCode/Commands/CMakeLists_files.cmake index a9316b1a07..3e583991ac 100644 --- a/ApplicationLibCode/Commands/CMakeLists_files.cmake +++ b/ApplicationLibCode/Commands/CMakeLists_files.cmake @@ -99,6 +99,9 @@ set(SOURCE_GROUP_HEADER_FILES ${CMAKE_CURRENT_LIST_DIR}/RicNewWellTargetCandidatesGeneratorFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicNewStatisticsContourMapFeature.h ${CMAKE_CURRENT_LIST_DIR}/RicNewStatisticsContourMapViewFeature.h + ${CMAKE_CURRENT_LIST_DIR}/RicCreateContourMapPolygonFeature.h + ${CMAKE_CURRENT_LIST_DIR}/RicCreateContourMapPolygonTools.h + ${CMAKE_CURRENT_LIST_DIR}/RicPolygonFromImageDialog.h ) set(SOURCE_GROUP_SOURCE_FILES @@ -202,6 +205,9 @@ set(SOURCE_GROUP_SOURCE_FILES ${CMAKE_CURRENT_LIST_DIR}/RicNewWellTargetCandidatesGeneratorFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicNewStatisticsContourMapFeature.cpp ${CMAKE_CURRENT_LIST_DIR}/RicNewStatisticsContourMapViewFeature.cpp + ${CMAKE_CURRENT_LIST_DIR}/RicCreateContourMapPolygonFeature.cpp + ${CMAKE_CURRENT_LIST_DIR}/RicCreateContourMapPolygonTools.cpp + ${CMAKE_CURRENT_LIST_DIR}/RicPolygonFromImageDialog.cpp ) if(RESINSIGHT_USE_QT_CHARTS) diff --git a/ApplicationLibCode/Commands/RicCreateContourMapPolygonFeature.cpp b/ApplicationLibCode/Commands/RicCreateContourMapPolygonFeature.cpp new file mode 100644 index 0000000000..3a96add9b3 --- /dev/null +++ b/ApplicationLibCode/Commands/RicCreateContourMapPolygonFeature.cpp @@ -0,0 +1,132 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2024- 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 "RicCreateContourMapPolygonFeature.h" + +#include "RiaLogging.h" + +#include "RicExportContourMapToTextFeature.h" +#include "RicPolygonFromImageDialog.h" + +#include "Polygons/RimPolygon.h" +#include "Polygons/RimPolygonCollection.h" +#include "RimContourMapProjection.h" +#include "RimEclipseContourMapView.h" +#include "RimGeoMechContourMapView.h" +#include "RimTools.h" + +#include "RigContourMapProjection.h" +#include "RigPolygonTools.h" + +#include "cafSelectionManager.h" + +#include + +CAF_CMD_SOURCE_INIT( RicCreateContourMapPolygonFeature, "RicCreateContourMapPolygonFeature" ); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateContourMapPolygonFeature::onActionTriggered( bool isChecked ) +{ + RimContourMapProjection* contourMapProjection = nullptr; + + auto [existingEclipseContourMap, existingGeoMechContourMap] = RicExportContourMapToTextFeature::findContourMapView(); + if ( existingEclipseContourMap ) contourMapProjection = existingEclipseContourMap->contourMapProjection(); + if ( existingGeoMechContourMap ) contourMapProjection = existingGeoMechContourMap->contourMapProjection(); + + if ( !contourMapProjection ) return; + + auto rigContourMapProjection = contourMapProjection->mapProjection(); + if ( !rigContourMapProjection ) return; + + auto vertexSizeIJ = rigContourMapProjection->numberOfVerticesIJ(); + + std::vector> image( vertexSizeIJ.x(), std::vector( vertexSizeIJ.y(), 0 ) ); + + for ( cvf::uint i = 0; i < vertexSizeIJ.x(); i++ ) + { + for ( cvf::uint j = 0; j < vertexSizeIJ.y(); j++ ) + { + double valueAtVertex = rigContourMapProjection->valueAtVertex( i, j ); + + if ( !std::isinf( valueAtVertex ) ) + { + image[i][j] = 1; + } + else + { + image[i][j] = 0; + } + } + } + + ImageProcessingDialog dlg; + dlg.show(); + dlg.setImageData( image ); + dlg.updateAndShowImages(); + + if ( dlg.exec() == QDialog::Rejected ) return; + + auto finalImage = dlg.finalImageData(); + if ( finalImage.empty() ) return; + + auto boundaryPoints = RigPolygonTools::boundary( finalImage ); + + std::vector polygonDomainCoords; + { + auto xVertexPositions = rigContourMapProjection->xVertexPositions(); + auto yVertexPositions = rigContourMapProjection->yVertexPositions(); + auto origin3d = rigContourMapProjection->origin3d(); + + for ( auto [i, j] : boundaryPoints ) + { + double xDomain = xVertexPositions.at( i ) + origin3d.x(); + double yDomain = yVertexPositions.at( j ) + origin3d.y(); + + polygonDomainCoords.emplace_back( cvf::Vec3d( xDomain, yDomain, origin3d.z() ) ); + } + + // Epsilon used to simplify polygon. Useful range typical value in [5..30] + const double defaultEpsilon = 20.0; + RigPolygonTools::simplifyPolygon( polygonDomainCoords, defaultEpsilon ); + } + + if ( polygonDomainCoords.size() >= 3 ) + { + auto polygonCollection = RimTools::polygonCollection(); + + auto newPolygon = polygonCollection->appendUserDefinedPolygon(); + + newPolygon->setPointsInDomainCoords( polygonDomainCoords ); + newPolygon->coordinatesChanged.send(); + + polygonCollection->uiCapability()->updateAllRequiredEditors(); + } +} + +//-------------------------------------------------------------------------------------------------- + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateContourMapPolygonFeature::setupActionLook( QAction* actionToSetup ) +{ + actionToSetup->setIcon( QIcon( ":/PolylinesFromFile16x16.png" ) ); + actionToSetup->setText( "Create Polygon From Contour Map" ); +} diff --git a/ApplicationLibCode/Commands/RicCreateContourMapPolygonFeature.h b/ApplicationLibCode/Commands/RicCreateContourMapPolygonFeature.h new file mode 100644 index 0000000000..8dc0be1a9e --- /dev/null +++ b/ApplicationLibCode/Commands/RicCreateContourMapPolygonFeature.h @@ -0,0 +1,33 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2024- 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 RicCreateContourMapPolygonFeature : public caf::CmdFeature +{ + CAF_CMD_HEADER_INIT; + +protected: + void onActionTriggered( bool isChecked ) override; + void setupActionLook( QAction* actionToSetup ) override; +}; diff --git a/ApplicationLibCode/Commands/RicCreateContourMapPolygonTools.cpp b/ApplicationLibCode/Commands/RicCreateContourMapPolygonTools.cpp new file mode 100644 index 0000000000..68aab2fb21 --- /dev/null +++ b/ApplicationLibCode/Commands/RicCreateContourMapPolygonTools.cpp @@ -0,0 +1,144 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2024- 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 "RicCreateContourMapPolygonTools.h" + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QImage RicCreateContourMapPolygonTools::convertBinaryToImage( const std::vector>& data, QColor color, int transparency ) +{ + if ( data.empty() || data[0].empty() ) + { + qWarning( "Data is empty. Cannot export an image." ); + return {}; + } + + // Get dimensions + int height = static_cast( data[0].size() ); + int width = static_cast( data.size() ); + + // Create a QImage + QImage image( width, height, QImage::Format_ARGB32 ); + + // Fill QImage with data + for ( int y = 0; y < height; ++y ) + { + for ( int x = 0; x < width; ++x ) + { + int value = std::clamp( data[x][y], 0, 255 ); + if ( value > 0 ) + image.setPixel( x, height - y - 1, qRgba( color.red(), color.green(), color.blue(), transparency ) ); // Grayscale + else + { + image.setPixel( x, height - y - 1, qRgba( 0, 0, 0, transparency ) ); + } + } + } + + return image; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QImage RicCreateContourMapPolygonTools::convertBinaryToGrayscaleImage( const std::vector>& data, int colorValue ) +{ + if ( data.empty() || data[0].empty() ) + { + qWarning( "Data is empty. Cannot export an image." ); + return {}; + } + + // Get dimensions + int height = static_cast( data[0].size() ); + int width = static_cast( data.size() ); + + // Create a QImage + QImage image( width, height, QImage::Format_Grayscale8 ); + + // Fill QImage with data + for ( int y = 0; y < height; ++y ) + { + for ( int x = 0; x < width; ++x ) + { + int value = std::clamp( data[x][y] * colorValue, 0, 255 ); // Ensure value is in [0, 255] + image.setPixel( x, height - y - 1, qRgb( value, value, value ) ); // Grayscale + } + } + + return image; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateContourMapPolygonTools::exportVectorAsImage( const std::vector>& data, int transparency, const QString& filename ) +{ + if ( data.empty() || data[0].empty() ) + { + qWarning( "Data is empty. Cannot export an image." ); + return; + } + + auto image = convertBinaryToImage( data, QColorConstants::Green, transparency ); + + if ( !image.save( filename, "PNG" ) ) + { + qWarning( "Failed to save image as PNG." ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RicCreateContourMapPolygonTools::exportVectorAsGrayscaleImage( const std::vector>& data, const QString& filename ) +{ + if ( data.empty() || data[0].empty() ) + { + qWarning( "Data is empty. Cannot export an image." ); + return; + } + + auto image = convertBinaryToGrayscaleImage( data, 255 ); + + // Save the QImage as a PNG file + if ( !image.save( filename, "PNG" ) ) + { + qWarning( "Failed to save image as PNG." ); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector> RicCreateContourMapPolygonTools::convertImageToBinary( QImage image ) +{ + std::vector> binaryImage( image.width(), std::vector( image.height(), 0 ) ); + for ( int i = 0; i < image.width(); ++i ) + { + for ( int j = 0; j < image.height(); ++j ) + { + auto pixelColor = image.pixel( i, j ); + auto gray = qGray( pixelColor ); + + binaryImage[i][image.height() - j - 1] = gray > 0 ? 1 : 0; + } + } + return binaryImage; +} diff --git a/ApplicationLibCode/Commands/RicCreateContourMapPolygonTools.h b/ApplicationLibCode/Commands/RicCreateContourMapPolygonTools.h new file mode 100644 index 0000000000..9fc0aa1174 --- /dev/null +++ b/ApplicationLibCode/Commands/RicCreateContourMapPolygonTools.h @@ -0,0 +1,38 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2024- Equinor ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include +#include + +//================================================================================================== +/// +//================================================================================================== +namespace RicCreateContourMapPolygonTools +{ +QImage convertBinaryToImage( const std::vector>& data, QColor color, int transparency ); +QImage convertBinaryToGrayscaleImage( const std::vector>& data, int colorValue ); + +void exportVectorAsImage( const std::vector>& data, int transparency, const QString& filename ); +void exportVectorAsGrayscaleImage( const std::vector>& data, const QString& filename ); + +std::vector> convertImageToBinary( QImage image ); + +}; // namespace RicCreateContourMapPolygonTools diff --git a/ApplicationLibCode/Commands/RicPolygonFromImageDialog.cpp b/ApplicationLibCode/Commands/RicPolygonFromImageDialog.cpp new file mode 100644 index 0000000000..16074a3413 --- /dev/null +++ b/ApplicationLibCode/Commands/RicPolygonFromImageDialog.cpp @@ -0,0 +1,280 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2024- 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 "RicPolygonFromImageDialog.h" + +#include "RicCreateContourMapPolygonTools.h" +#include "RigPolygonTools.h" + +#include +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +ImageProcessingDialog::ImageProcessingDialog( QWidget* parent /*= nullptr */ ) + : QDialog( parent ) +{ + setWindowTitle( "Image Morphology Tool" ); + + // Layout and widgets + QVBoxLayout* mainLayout = new QVBoxLayout( this ); + + QHBoxLayout* centerLayout = new QHBoxLayout( this ); + mainLayout->addLayout( centerLayout ); + + QVBoxLayout* settingsLayout = new QVBoxLayout( this ); + centerLayout->addLayout( settingsLayout ); + + QLabel* kernelLabel = new QLabel( "Kernel Size:", this ); + settingsLayout->addWidget( kernelLabel ); + + kernelSpinBox = new QSpinBox( this ); + kernelSpinBox->setRange( 1, 31 ); + kernelSpinBox->setValue( 3 ); + settingsLayout->addWidget( kernelSpinBox ); + + QLabel* transparencyLabel = new QLabel( "Transparency (0-100):", this ); + settingsLayout->addWidget( transparencyLabel ); + + transparencySlider = new QSlider( Qt::Horizontal, this ); + transparencySlider->setRange( 0, 100 ); + transparencySlider->setValue( 90 ); + settingsLayout->addWidget( transparencySlider ); + + showInput = new QCheckBox( "Show Input Image", this ); + showInput->setChecked( true ); + settingsLayout->addWidget( showInput ); + + showDilated = new QCheckBox( "Show Dilated Image", this ); + showDilated->setChecked( false ); + settingsLayout->addWidget( showDilated ); + + showEroded = new QCheckBox( "Show Eroded Image", this ); + showEroded->setChecked( false ); + settingsLayout->addWidget( showEroded ); + + showFinal = new QCheckBox( "Show Final Image", this ); + showFinal->setChecked( true ); + settingsLayout->addWidget( showFinal ); + + QPushButton* showButton = new QPushButton( "Show Images", this ); + settingsLayout->addWidget( showButton ); + settingsLayout->addStretch(); + + graphicsView = new QGraphicsView( this ); + graphicsScene = new QGraphicsScene( this ); + graphicsView->setScene( graphicsScene ); + centerLayout->addWidget( graphicsView ); + + // Give more space to graphics view + centerLayout->setStretch( 0, 3 ); + centerLayout->setStretch( 1, 7 ); + + // Create a button box + QDialogButtonBox* buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this ); + mainLayout->addWidget( buttonBox ); + + // Connect the button box signals + connect( buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept ); + connect( buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject ); + + // Connect signals and slots + connect( showButton, &QPushButton::clicked, this, &ImageProcessingDialog::showImages ); + connect( showInput, &QCheckBox::clicked, this, &ImageProcessingDialog::showImages ); + connect( showEroded, &QCheckBox::clicked, this, &ImageProcessingDialog::showImages ); + connect( showDilated, &QCheckBox::clicked, this, &ImageProcessingDialog::showImages ); + connect( showFinal, &QCheckBox::clicked, this, &ImageProcessingDialog::showImages ); + + connect( kernelSpinBox, &QSpinBox::valueChanged, this, &ImageProcessingDialog::updateAndShowImages ); + connect( transparencySlider, &QSlider::valueChanged, this, &ImageProcessingDialog::updateAndShowImages ); + + resizeAndCenterDialog( 0.8 ); // 80% of screen size +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void ImageProcessingDialog::performDilation() +{ + if ( inputData.empty() ) + { + QMessageBox::warning( this, "Error", "No image loaded." ); + return; + } + + int kernelSize = kernelAdjustedSize(); + dilatedData = RigPolygonTools::dilate( inputData, kernelSize ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void ImageProcessingDialog::performErosion() +{ + if ( inputData.empty() ) + { + QMessageBox::warning( this, "Error", "No image loaded." ); + return; + } + + int kernelSize = kernelAdjustedSize(); + erodedData = RigPolygonTools::erode( inputData, kernelSize ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void ImageProcessingDialog::updateAndShowImages() +{ + performErosion(); + performDilation(); + computeFinal(); + showImages(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void ImageProcessingDialog::showImages() +{ + if ( inputData.empty() ) + { + QMessageBox::warning( this, "Error", "No image loaded." ); + return; + } + + const auto transparency = 180; + auto original = RicCreateContourMapPolygonTools::convertBinaryToGrayscaleImage( inputData, transparency ); + auto dilatedImage = RicCreateContourMapPolygonTools::convertBinaryToImage( dilatedData, QColorConstants::Green, transparency ); + auto erodedImage = RicCreateContourMapPolygonTools::convertBinaryToImage( erodedData, QColorConstants::Red, transparency ); + auto finalImage = RicCreateContourMapPolygonTools::convertBinaryToImage( finalData, QColorConstants::Yellow, transparency ); + + graphicsScene->clear(); + + // Add a black background image + if ( !original.isNull() ) + { + QImage blackImage( original.size(), QImage::Format_RGB32 ); + blackImage.fill( Qt::black ); + QPixmap basePixmap = QPixmap::fromImage( blackImage ); + QGraphicsPixmapItem* baseItem = new QGraphicsPixmapItem( basePixmap ); + graphicsScene->addItem( baseItem ); + } + + double alpha = transparencySlider->value() / 100.0; + + if ( showInput->isChecked() ) + { + QPixmap basePixmap = QPixmap::fromImage( original ); + QGraphicsPixmapItem* baseItem = new QGraphicsPixmapItem( basePixmap ); + baseItem->setOpacity( alpha ); + graphicsScene->addItem( baseItem ); + } + + if ( showDilated->isChecked() && !dilatedImage.isNull() ) + { + QPixmap dilatePixmap = QPixmap::fromImage( dilatedImage ); + QGraphicsPixmapItem* dilateItem = new QGraphicsPixmapItem( dilatePixmap ); + dilateItem->setOpacity( alpha ); + graphicsScene->addItem( dilateItem ); + } + + if ( showEroded->isChecked() && !erodedImage.isNull() ) + { + QPixmap erodePixmap = QPixmap::fromImage( erodedImage ); + QGraphicsPixmapItem* erodeItem = new QGraphicsPixmapItem( erodePixmap ); + erodeItem->setOpacity( alpha ); + graphicsScene->addItem( erodeItem ); + } + + if ( showFinal->isChecked() && !finalImage.isNull() ) + { + QPixmap erodePixmap = QPixmap::fromImage( finalImage ); + QGraphicsPixmapItem* erodeItem = new QGraphicsPixmapItem( erodePixmap ); + erodeItem->setOpacity( alpha ); + graphicsScene->addItem( erodeItem ); + } + + graphicsView->fitInView( graphicsScene->sceneRect(), Qt::KeepAspectRatio ); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector> ImageProcessingDialog::finalImageData() const +{ + return finalData; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void ImageProcessingDialog::setImageData( std::vector> imageData ) +{ + inputData = imageData; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +int ImageProcessingDialog::kernelAdjustedSize() const +{ + // The kernel size should be odd and positive + return kernelSpinBox->value() * 2 - 1; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void ImageProcessingDialog::computeFinal() +{ + if ( inputData.empty() ) + { + QMessageBox::warning( this, "Error", "No image loaded." ); + return; + } + + auto floodFilled = RigPolygonTools::fillInterior( inputData ); + + int kernelSize = kernelAdjustedSize(); + auto eroded = RigPolygonTools::erode( floodFilled, kernelSize ); + auto dilated = RigPolygonTools::dilate( eroded, kernelSize ); + finalData = dilated; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void ImageProcessingDialog::resizeAndCenterDialog( double scale ) +{ + QScreen* screen = QGuiApplication::primaryScreen(); + if ( !screen ) return; + + QRect screenGeometry = screen->geometry(); + + int width = static_cast( screenGeometry.width() * scale ); + int height = static_cast( screenGeometry.height() * scale ); + + resize( width, height ); + + int x = screenGeometry.x() + ( screenGeometry.width() - width ) / 2; + int y = screenGeometry.y() + ( screenGeometry.height() - height ) / 2; + + move( x, y ); +} diff --git a/ApplicationLibCode/Commands/RicPolygonFromImageDialog.h b/ApplicationLibCode/Commands/RicPolygonFromImageDialog.h new file mode 100644 index 0000000000..2a33204058 --- /dev/null +++ b/ApplicationLibCode/Commands/RicPolygonFromImageDialog.h @@ -0,0 +1,71 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2024- Equinor ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class ImageProcessingDialog : public QDialog +{ + Q_OBJECT + +public: + ImageProcessingDialog( QWidget* parent = nullptr ); + + std::vector> finalImageData() const; + void setImageData( std::vector> imageData ); + +public slots: + void updateAndShowImages(); + +private slots: + void performDilation(); + void performErosion(); + void showImages(); + +private: + int kernelAdjustedSize() const; + void computeFinal(); + void resizeAndCenterDialog( double scale ); + +private: + QSpinBox* kernelSpinBox; + QSlider* transparencySlider; + QGraphicsView* graphicsView; + QGraphicsScene* graphicsScene; + + QCheckBox* showInput; + QCheckBox* showDilated; + QCheckBox* showEroded; + QCheckBox* showFinal; + + std::vector> inputData, dilatedData, erodedData, finalData; +}; diff --git a/ApplicationLibCode/ProjectDataModel/Polygons/RimPolygonCollection.cpp b/ApplicationLibCode/ProjectDataModel/Polygons/RimPolygonCollection.cpp index 6298db2e68..d61a608734 100644 --- a/ApplicationLibCode/ProjectDataModel/Polygons/RimPolygonCollection.cpp +++ b/ApplicationLibCode/ProjectDataModel/Polygons/RimPolygonCollection.cpp @@ -18,6 +18,8 @@ #include "RimPolygonCollection.h" +#include "RiaColorTables.h" + #include "Rim3dView.h" #include "RimPolygon.h" #include "RimPolygonFile.h" @@ -57,6 +59,9 @@ RimPolygon* RimPolygonCollection::createUserDefinedPolygon() auto newPolygon = new RimPolygon(); newPolygon->setName( "Polygon " + QString::number( userDefinedPolygons().size() + 1 ) ); + auto colorCandidates = RiaColorTables::summaryCurveDefaultPaletteColors(); + newPolygon->setColor( colorCandidates.cycledColor3f( userDefinedPolygons().size() ) ); + return newPolygon; } diff --git a/ApplicationLibCode/UserInterface/RiuViewerCommands.cpp b/ApplicationLibCode/UserInterface/RiuViewerCommands.cpp index b95584dbd0..57208b957f 100644 --- a/ApplicationLibCode/UserInterface/RiuViewerCommands.cpp +++ b/ApplicationLibCode/UserInterface/RiuViewerCommands.cpp @@ -20,6 +20,7 @@ #include "RiuViewerCommands.h" #include "RiaDefines.h" +#include "RiaOptionItemFactory.h" #include "GeoMechCommands/RicGeoMechPropertyFilterNewExec.h" #include "MeasurementCommands/RicMeasurementPickEventHandler.h" @@ -39,13 +40,13 @@ #include "RigMainGrid.h" #include "RigVirtualPerforationTransmissibilities.h" -#include "RiaOptionItemFactory.h" #include "Rim2dIntersectionView.h" #include "RimBoxIntersection.h" #include "RimCellEdgeColors.h" #include "RimContextCommandBuilder.h" #include "RimEclipseCase.h" #include "RimEclipseCellColors.h" +#include "RimEclipseContourMapView.h" #include "RimEclipseFaultColors.h" #include "RimEclipseView.h" #include "RimEllipseFractureTemplate.h" @@ -55,6 +56,7 @@ #include "RimFracture.h" #include "RimGeoMechCase.h" #include "RimGeoMechCellColors.h" +#include "RimGeoMechContourMapView.h" #include "RimGeoMechView.h" #include "RimIntersectionResultDefinition.h" #include "RimLegendConfig.h" @@ -593,28 +595,36 @@ void RiuViewerCommands::displayContextMenu( QMouseEvent* event ) if ( gridView ) { - menuBuilder.addSeparator(); - menuBuilder << "RicNewGridTimeHistoryCurveFeature"; - menuBuilder << "RicShowFlowCharacteristicsPlotFeature"; - if ( dynamic_cast( gridView ) ) + bool isContourView = dynamic_cast( gridView ) || dynamic_cast( gridView ); + if ( isContourView ) { - menuBuilder << "RicCreateGridCrossPlotFeature"; + menuBuilder << "RicExportContourMapToTextFeature"; + menuBuilder << "RicCreateContourMapPolygonFeature"; } - menuBuilder.addSeparator(); - menuBuilder.subMenuStart( "Export" ); - menuBuilder << "RicExportEclipseInputGridFeature"; - menuBuilder << "RicSaveEclipseInputActiveVisibleCellsFeature"; - menuBuilder << "RicSaveEclipseResultAsInputPropertyFeature"; - menuBuilder << "RicExportContourMapToTextFeature"; - menuBuilder.subMenuEnd(); - menuBuilder.addSeparator(); + else + { + menuBuilder.addSeparator(); + menuBuilder << "RicNewGridTimeHistoryCurveFeature"; + menuBuilder << "RicShowFlowCharacteristicsPlotFeature"; + if ( dynamic_cast( gridView ) ) + { + menuBuilder << "RicCreateGridCrossPlotFeature"; + } + menuBuilder.addSeparator(); + menuBuilder.subMenuStart( "Export" ); + menuBuilder << "RicExportEclipseInputGridFeature"; + menuBuilder << "RicSaveEclipseInputActiveVisibleCellsFeature"; + menuBuilder << "RicSaveEclipseResultAsInputPropertyFeature"; + menuBuilder.subMenuEnd(); + menuBuilder.addSeparator(); #ifdef USE_QTCHARTS - menuBuilder << "RicCreateGridStatisticsPlotFeature"; + menuBuilder << "RicCreateGridStatisticsPlotFeature"; #endif - menuBuilder << "RicShowGridStatisticsFeature"; - menuBuilder << "RicCopyGridStatisticsToClipboardFeature"; - menuBuilder << "RicSelectColorResult"; + menuBuilder << "RicShowGridStatisticsFeature"; + menuBuilder << "RicCopyGridStatisticsToClipboardFeature"; + menuBuilder << "RicSelectColorResult"; + } } if ( firstHitPart )