diff --git a/ApplicationCode/ProjectDataModel/Flow/CMakeLists_files.cmake b/ApplicationCode/ProjectDataModel/Flow/CMakeLists_files.cmake index 4f15cd5729..286b794cda 100644 --- a/ApplicationCode/ProjectDataModel/Flow/CMakeLists_files.cmake +++ b/ApplicationCode/ProjectDataModel/Flow/CMakeLists_files.cmake @@ -6,10 +6,14 @@ endif() set (SOURCE_GROUP_HEADER_FILES ${CEE_CURRENT_LIST_DIR}RimFlowDiagSolution.h +${CEE_CURRENT_LIST_DIR}RimFlowPlotCollection.h +${CEE_CURRENT_LIST_DIR}RimWellAllocationPlot.h ) set (SOURCE_GROUP_SOURCE_FILES ${CEE_CURRENT_LIST_DIR}RimFlowDiagSolution.cpp +${CEE_CURRENT_LIST_DIR}RimFlowPlotCollection.cpp +${CEE_CURRENT_LIST_DIR}RimWellAllocationPlot.cpp ) list(APPEND CODE_HEADER_FILES diff --git a/ApplicationCode/ProjectDataModel/Flow/RimFlowPlotCollection.cpp b/ApplicationCode/ProjectDataModel/Flow/RimFlowPlotCollection.cpp new file mode 100644 index 0000000000..e6b4a84ca8 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Flow/RimFlowPlotCollection.cpp @@ -0,0 +1,45 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017 Statoil ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimFlowPlotCollection.h" + +#include "RimWellAllocationPlot.h" + + +#include "cvfAssert.h" + +CAF_PDM_SOURCE_INIT(RimFlowPlotCollection, "FlowPlotCollection"); + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimFlowPlotCollection::RimFlowPlotCollection() +{ + CAF_PDM_InitObject("Flow Diagnosis Plots", ":/WellLogPlots16x16.png", "", ""); + + CAF_PDM_InitFieldNoDefault(&flowPlots, "WellLogPlots", "", "", "", ""); + flowPlots.uiCapability()->setUiHidden(true); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimFlowPlotCollection::~RimFlowPlotCollection() +{ + flowPlots.deleteAllChildObjects(); +} diff --git a/ApplicationCode/ProjectDataModel/Flow/RimFlowPlotCollection.h b/ApplicationCode/ProjectDataModel/Flow/RimFlowPlotCollection.h new file mode 100644 index 0000000000..df0808eeb2 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Flow/RimFlowPlotCollection.h @@ -0,0 +1,38 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017 Statoil ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafPdmObject.h" +#include "cafPdmChildArrayField.h" + +class RimWellAllocationPlot; + +//================================================================================================== +/// +/// +//================================================================================================== +class RimFlowPlotCollection : public caf::PdmObject +{ + CAF_PDM_HEADER_INIT; +public: + RimFlowPlotCollection(); + virtual ~RimFlowPlotCollection(); + + caf::PdmChildArrayField flowPlots; +}; diff --git a/ApplicationCode/ProjectDataModel/Flow/RimWellAllocationPlot.cpp b/ApplicationCode/ProjectDataModel/Flow/RimWellAllocationPlot.cpp new file mode 100644 index 0000000000..391ff970a9 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Flow/RimWellAllocationPlot.cpp @@ -0,0 +1,307 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017 Statoil ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RimWellAllocationPlot.h" + +#include "RiaApplication.h" +#include "RiuMainPlotWindow.h" + +#include "RiuWellAllocationPlot.h" +#include "qwt_plot_renderer.h" + + + +CAF_PDM_SOURCE_INIT(RimWellAllocationPlot, "WellAllocationPlot"); + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimWellAllocationPlot::RimWellAllocationPlot() +{ + CAF_PDM_InitObject("Well Allocation Plot", ":/SummaryPlot16x16.png", "", ""); + CAF_PDM_InitField(&m_showWindow, "ShowWindow", true, "Show Summary Plot", "", "", ""); + m_showWindow.uiCapability()->setUiHidden(true); + + CAF_PDM_InitField(&m_userName, "PlotDescription", QString("Summary Plot"), "Name", "", "", ""); + CAF_PDM_InitField(&m_showPlotTitle, "ShowPlotTitle", true, "Show Plot Title", "", "", ""); + +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimWellAllocationPlot::~RimWellAllocationPlot() +{ + if (RiaApplication::instance()->mainPlotWindow()) + { + RiaApplication::instance()->mainPlotWindow()->removeViewer(m_qwtPlot); + } + + deletePlotWidget(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellAllocationPlot::deletePlotWidget() +{ + if (m_qwtPlot) + { + m_qwtPlot->deleteLater(); + m_qwtPlot = NULL; + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellAllocationPlot::updateAxes() +{ + updateZoomInQwt(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QWidget* RimWellAllocationPlot::viewWidget() +{ + return m_qwtPlot; +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellAllocationPlot::handleViewerDeletion() +{ + m_showWindow = false; + + if (m_qwtPlot) + { + detachAllCurves(); + } + + uiCapability()->updateUiIconFromToggleField(); + updateConnectedEditors(); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellAllocationPlot::zoomAll() +{ + + +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellAllocationPlot::fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) +{ + if (changedField == &m_showWindow) + { + if (m_showWindow) + { + loadDataAndUpdate(); + } + else + { + updateViewerWidget(); + } + + uiCapability()->updateUiIconFromToggleField(); + } + else if (changedField == &m_userName || + changedField == &m_showPlotTitle) + { + updateViewerWidgetWindowTitle(); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellAllocationPlot::setupBeforeSave() +{ + if (m_qwtPlot && RiaApplication::instance()->mainPlotWindow()) + { + this->setMdiWindowGeometry(RiaApplication::instance()->mainPlotWindow()->windowGeometryForViewer(m_qwtPlot)); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QImage RimWellAllocationPlot::snapshotWindowContent() +{ + QImage image; + + if (m_qwtPlot) + { + image = QImage(m_qwtPlot->size(), QImage::Format_ARGB32); + image.fill(QColor(Qt::white).rgb()); + + QPainter painter(&image); + QRectF rect(0, 0, m_qwtPlot->size().width(), m_qwtPlot->size().height()); + + QwtPlotRenderer plotRenderer; + plotRenderer.render(m_qwtPlot, &painter, rect); + } + + return image; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellAllocationPlot::defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName /*= ""*/) +{ +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellAllocationPlot::loadDataAndUpdate() +{ + updateViewerWidget(); + +// for (RimSummaryCurveFilter* curveFilter : m_curveFilters) +// { +// curveFilter->loadDataAndUpdate(); +// } +// +// for (RimSummaryCurve* curve : m_curves) +// { +// curve->loadDataAndUpdate(); +// } + + this->updateAxes(); + + updateZoomInQwt(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellAllocationPlot::updateZoomInQwt() +{ + if (!m_qwtPlot) return; + + zoomAll(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellAllocationPlot::setDescription(const QString& description) +{ + m_userName = description; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimWellAllocationPlot::description() const +{ + return m_userName(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellAllocationPlot::updateViewerWidget() +{ + RiuMainPlotWindow* mainPlotWindow = RiaApplication::instance()->mainPlotWindow(); + if (!mainPlotWindow) return; + + if (m_showWindow()) + { + if (!m_qwtPlot) + { + m_qwtPlot = new RiuWellAllocationPlot(this, mainPlotWindow); + +// for (RimSummaryCurveFilter* curveFilter : m_curveFilters) +// { +// curveFilter->setParentQwtPlot(m_qwtPlot); +// } +// +// for (RimSummaryCurve* curve : m_curves) +// { +// curve->setParentQwtPlot(m_qwtPlot); +// } + + mainPlotWindow->addViewer(m_qwtPlot, this->mdiWindowGeometry()); + mainPlotWindow->setActiveViewer(m_qwtPlot); + } + + updateViewerWidgetWindowTitle(); + } + else + { + if (m_qwtPlot) + { + this->setMdiWindowGeometry(mainPlotWindow->windowGeometryForViewer(m_qwtPlot)); + + mainPlotWindow->removeViewer(m_qwtPlot); + detachAllCurves(); + + deletePlotWidget(); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellAllocationPlot::updateViewerWidgetWindowTitle() +{ + if (m_qwtPlot) + { + m_qwtPlot->setWindowTitle(m_userName); + + if (m_showPlotTitle) + { + m_qwtPlot->setTitle(m_userName); + } + else + { + m_qwtPlot->setTitle(""); + } + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RimWellAllocationPlot::detachAllCurves() +{ +// for (RimSummaryCurveFilter* curveFilter : m_curveFilters) +// { +// curveFilter->detachQwtCurves(); +// } +// +// for (RimSummaryCurve* curve : m_curves) +// { +// curve->detachQwtCurve(); +// } +} + diff --git a/ApplicationCode/ProjectDataModel/Flow/RimWellAllocationPlot.h b/ApplicationCode/ProjectDataModel/Flow/RimWellAllocationPlot.h new file mode 100644 index 0000000000..e3a8d9bb62 --- /dev/null +++ b/ApplicationCode/ProjectDataModel/Flow/RimWellAllocationPlot.h @@ -0,0 +1,85 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017 Statoil ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "cafPdmObject.h" +#include "cafPdmField.h" + +#include "RimViewWindow.h" + +#include + +class RiuWellAllocationPlot; +class QwtInterval; + + +//================================================================================================== +/// +/// +//================================================================================================== +class RimWellAllocationPlot : public RimViewWindow +{ + CAF_PDM_HEADER_INIT; + +public: + RimWellAllocationPlot(); + virtual ~RimWellAllocationPlot(); + + void setDescription(const QString& description); + QString description() const; + + void loadDataAndUpdate(); + + void handleViewerDeletion(); + void updateCaseNameHasChanged(); + + void updateAxes(); + virtual void zoomAll() override; + + void updateZoomInQwt(); + void disableAutoZoom(); + + virtual QWidget* viewWidget() override; + +protected: + // Overridden PDM methods + virtual caf::PdmFieldHandle* objectToggleField() { return &m_showWindow; } + virtual caf::PdmFieldHandle* userDescriptionField() { return &m_userName; } + virtual void fieldChangedByUi(const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue) override; + virtual void setupBeforeSave() override; + virtual void defineUiTreeOrdering(caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName = "") override; + + virtual QImage snapshotWindowContent() override; + +private: + void updateViewerWidget(); + void updateViewerWidgetWindowTitle(); + void detachAllCurves(); + void deletePlotWidget(); + + +private: + caf::PdmField m_showWindow; + + caf::PdmField m_showPlotTitle; + caf::PdmField m_userName; + + QPointer m_qwtPlot; + +}; diff --git a/ApplicationCode/UserInterface/CMakeLists_files.cmake b/ApplicationCode/UserInterface/CMakeLists_files.cmake index 8db7cf883e..baf8b7aa0a 100644 --- a/ApplicationCode/UserInterface/CMakeLists_files.cmake +++ b/ApplicationCode/UserInterface/CMakeLists_files.cmake @@ -39,6 +39,7 @@ ${CEE_CURRENT_LIST_DIR}RiuWellLogTrack.h ${CEE_CURRENT_LIST_DIR}RiuGeoMechXfTensorResultAccessor.h ${CEE_CURRENT_LIST_DIR}RiuFemTimeHistoryResultAccessor.h ${CEE_CURRENT_LIST_DIR}RiuExportMultipleSnapshotsWidget.h +${CEE_CURRENT_LIST_DIR}RiuWellAllocationPlot.h ) set (SOURCE_GROUP_SOURCE_FILES @@ -76,6 +77,7 @@ ${CEE_CURRENT_LIST_DIR}RiuWellLogTrack.cpp ${CEE_CURRENT_LIST_DIR}RiuGeoMechXfTensorResultAccessor.cpp ${CEE_CURRENT_LIST_DIR}RiuFemTimeHistoryResultAccessor.cpp ${CEE_CURRENT_LIST_DIR}RiuExportMultipleSnapshotsWidget.cpp +${CEE_CURRENT_LIST_DIR}RiuWellAllocationPlot.cpp ) list(APPEND CODE_HEADER_FILES @@ -102,6 +104,7 @@ ${CEE_CURRENT_LIST_DIR}RiuRecentFileActionProvider.h ${CEE_CURRENT_LIST_DIR}RiuSummaryQwtPlot.h ${CEE_CURRENT_LIST_DIR}RiuQwtScalePicker.h ${CEE_CURRENT_LIST_DIR}RiuExportMultipleSnapshotsWidget.h +${CEE_CURRENT_LIST_DIR}RiuWellAllocationPlot.h ) list(APPEND QT_UI_FILES diff --git a/ApplicationCode/UserInterface/RiuWellAllocationPlot.cpp b/ApplicationCode/UserInterface/RiuWellAllocationPlot.cpp new file mode 100644 index 0000000000..b288159828 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuWellAllocationPlot.cpp @@ -0,0 +1,443 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017 Statoil ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#include "RiuWellAllocationPlot.h" + + +#include "RiaApplication.h" + +#include "RimWellAllocationPlot.h" + +#include "RiuMainPlotWindow.h" +#include "RiuQwtScalePicker.h" + +#include "qwt_date_scale_draw.h" +#include "qwt_date_scale_engine.h" +#include "qwt_legend.h" +#include "qwt_plot_curve.h" +#include "qwt_plot_grid.h" +#include "qwt_plot_layout.h" +#include "qwt_plot_marker.h" +#include "qwt_plot_panner.h" +#include "qwt_plot_picker.h" +#include "qwt_plot_zoomer.h" +#include "qwt_scale_engine.h" +#include "qwt_symbol.h" + +#include +#include + +#include + + + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuWellAllocationPlot::RiuWellAllocationPlot(RimWellAllocationPlot* plotDefinition, QWidget* parent) : QwtPlot(parent) +{ + Q_ASSERT(plotDefinition); + m_plotDefinition = plotDefinition; + + m_grid = new QwtPlotGrid; + m_grid->attach(this); + + setDefaults(); + + // LeftButton for the zooming + m_zoomerLeft = new QwtPlotZoomer(canvas()); + m_zoomerLeft->setRubberBandPen(QColor(Qt::black)); + m_zoomerLeft->setTrackerMode(QwtPicker::AlwaysOff); + m_zoomerLeft->setTrackerPen(QColor(Qt::black)); + m_zoomerLeft->initMousePattern(1); + + // MidButton for the panning + QwtPlotPanner* panner = new QwtPlotPanner(canvas()); + panner->setMouseButton(Qt::MidButton); + + connect(m_zoomerLeft, SIGNAL(zoomed(const QRectF &)), SLOT(onZoomedSlot())); + connect(panner, SIGNAL(panned(int, int)), SLOT(onZoomedSlot())); + + // Attach a zoomer for the right axis + m_zoomerRight = new QwtPlotZoomer(canvas()); + m_zoomerRight->setAxis(xTop, yRight); + m_zoomerRight->setTrackerMode(QwtPicker::AlwaysOff); + m_zoomerRight->initMousePattern(1); + + + RiuQwtScalePicker* scalePicker = new RiuQwtScalePicker(this); + connect(scalePicker, SIGNAL(clicked(int, double)), this, SLOT(onAxisClicked(int, double))); + + // Create a plot picker to display values next to mouse cursor +// m_plotPicker = new RiuQwtPlotPicker(this->canvas()); +// m_plotPicker->setTrackerMode(QwtPicker::AlwaysOn); +// +// m_plotMarker = new QwtPlotMarker; +// +// // QwtPlotMarker takes ownership of the symbol, it is deleted in destructor of QwtPlotMarker +// QwtSymbol* mySymbol = new QwtSymbol(QwtSymbol::Ellipse, Qt::NoBrush, QPen(Qt::black, 2.0), QSize(12, 12)); +// m_plotMarker->setSymbol(mySymbol); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuWellAllocationPlot::~RiuWellAllocationPlot() +{ + m_grid->detach(); + delete m_grid; + + if (m_plotDefinition) + { + m_plotDefinition->handleViewerDeletion(); + } + +// m_plotMarker->detach(); +// delete m_plotMarker; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RimWellAllocationPlot* RiuWellAllocationPlot::ownerPlotDefinition() +{ + return m_plotDefinition; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuWellAllocationPlot::currentVisibleWindow(QwtInterval* leftAxis, QwtInterval* rightAxis, QwtInterval* timeAxis) const +{ + *leftAxis = axisScaleDiv(yLeft).interval(); + *rightAxis = axisScaleDiv(yRight).interval(); + *timeAxis = axisScaleDiv(xBottom).interval(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuWellAllocationPlot::setZoomWindow(const QwtInterval& leftAxis, const QwtInterval& rightAxis, const QwtInterval& timeAxis) +{ + { + QRectF zoomWindow; + zoomWindow.setLeft(timeAxis.minValue()); + zoomWindow.setRight(timeAxis.maxValue()); + zoomWindow.setTop(leftAxis.maxValue()); + zoomWindow.setBottom(leftAxis.minValue()); + + m_zoomerLeft->zoom(zoomWindow); + } + + { + QRectF zoomWindow; + zoomWindow.setLeft(timeAxis.minValue()); + zoomWindow.setRight(timeAxis.maxValue()); + zoomWindow.setTop(rightAxis.maxValue()); + zoomWindow.setBottom(rightAxis.minValue()); + + m_zoomerRight->zoom(zoomWindow); + } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QSize RiuWellAllocationPlot::minimumSizeHint() const +{ + return QSize(0, 100); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QSize RiuWellAllocationPlot::sizeHint() const +{ + return QSize(0, 0); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QPointF RiuWellAllocationPlot::closestCurvePoint(const QPoint& cursorPosition, QString* valueString, QString* timeString, int* yAxis) const +{ + QPointF samplePoint; + + QwtPlotCurve* closestCurve = nullptr; + double distMin = DBL_MAX; + int closestPointSampleIndex = -1; + + const QwtPlotItemList& itmList = itemList(); + for (QwtPlotItemIterator it = itmList.begin(); it != itmList.end(); it++) + { + if ((*it)->rtti() == QwtPlotItem::Rtti_PlotCurve) + { + QwtPlotCurve* candidateCurve = static_cast(*it); + double dist = DBL_MAX; + int candidateSampleIndex = candidateCurve->closestPoint(cursorPosition, &dist); + if (dist < distMin) + { + closestCurve = candidateCurve; + distMin = dist; + closestPointSampleIndex = candidateSampleIndex; + } + } + } + + if (closestCurve && distMin < 50) + { + samplePoint = closestCurve->sample(closestPointSampleIndex); + + if (yAxis) *yAxis = closestCurve->yAxis(); + } + + + if (timeString) + { + const QwtScaleDraw* timeAxisScaleDraw = axisScaleDraw(QwtPlot::xBottom); + if (timeAxisScaleDraw) + { + *timeString = timeAxisScaleDraw->label(samplePoint.x()).text(); + } + } + + if (valueString && closestCurve) + { + const QwtScaleDraw* yAxisScaleDraw = axisScaleDraw(closestCurve->yAxis()); + if (yAxisScaleDraw) + { + *valueString = yAxisScaleDraw->label(samplePoint.y()).text(); + } + } + + return samplePoint; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuWellAllocationPlot::updateClosestCurvePointMarker(const QPointF& closestPoint, int yAxis) +{ +// bool replotRequired = false; +// +// if (!closestPoint.isNull()) +// { +// if (!m_plotMarker->plot()) +// { +// m_plotMarker->attach(this); +// +// replotRequired = true; +// } +// +// if (m_plotMarker->value() != closestPoint) +// { +// m_plotMarker->setValue(closestPoint.x(), closestPoint.y()); +// +// // Set y-axis to be able to support more than one y-axis. Default y-axis is left axis. +// // TODO : Should use a color or other visual indicator to show what axis the curve relates to +// m_plotMarker->setYAxis(yAxis); +// +// replotRequired = true; +// } +// } +// else +// { +// if (m_plotMarker->plot()) +// { +// m_plotMarker->detach(); +// +// replotRequired = true; +// } +// } +// +// if (replotRequired) this->replot(); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuWellAllocationPlot::setDefaults() +{ + QPalette newPalette(palette()); + newPalette.setColor(QPalette::Background, Qt::white); + setPalette(newPalette); + + setAutoFillBackground(true); + setCanvasBackground(Qt::white); + + QFrame* canvasFrame = dynamic_cast(canvas()); + if (canvasFrame) + { + canvasFrame->setFrameShape(QFrame::NoFrame); + } + + canvas()->setMouseTracking(true); + canvas()->installEventFilter(this); + + QPen gridPen(Qt::SolidLine); + gridPen.setColor(Qt::lightGray); + m_grid->setPen(gridPen); + + enableAxis(QwtPlot::xBottom, true); + enableAxis(QwtPlot::yLeft, true); + enableAxis(QwtPlot::xTop, false); + enableAxis(QwtPlot::yRight, false); + + plotLayout()->setAlignCanvasToScales(true); + + useDateBasedTimeAxis(); + + QFont xAxisFont = axisFont(QwtPlot::xBottom); + xAxisFont.setPixelSize(11); + setAxisFont(QwtPlot::xBottom, xAxisFont); + setAxisMaxMinor(QwtPlot::xBottom, 2); + + QFont yAxisFont = axisFont(QwtPlot::yLeft); + yAxisFont.setPixelSize(11); + setAxisFont(QwtPlot::yLeft, yAxisFont); + + setAxisMaxMinor(QwtPlot::yLeft, 3); + + QwtText axisTitleY = axisTitle(QwtPlot::yLeft); + QFont yAxisTitleFont = axisTitleY.font(); + yAxisTitleFont.setPixelSize(11); + yAxisTitleFont.setBold(false); + axisTitleY.setFont(yAxisTitleFont); + axisTitleY.setRenderFlags(Qt::AlignRight); + setAxisTitle(QwtPlot::yLeft, axisTitleY); + + + QwtLegend* legend = new QwtLegend(this); + // The legend will be deleted in the destructor of the plot or when + // another legend is inserted. + this->insertLegend(legend, BottomLegend); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuWellAllocationPlot::useDateBasedTimeAxis() +{ + QwtDateScaleDraw* scaleDraw = new QwtDateScaleDraw(Qt::UTC); + scaleDraw->setDateFormat(QwtDate::Year, QString("dd-MM-yyyy")); + + QwtDateScaleEngine* scaleEngine = new QwtDateScaleEngine(Qt::UTC); + setAxisScaleEngine(QwtPlot::xBottom, scaleEngine); + setAxisScaleDraw(QwtPlot::xBottom, scaleDraw); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuWellAllocationPlot::useTimeBasedTimeAxis() +{ + setAxisScaleEngine(QwtPlot::xBottom, new QwtLinearScaleEngine()); + setAxisScaleDraw(QwtPlot::xBottom, new QwtScaleDraw()); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RiuWellAllocationPlot::eventFilter(QObject* watched, QEvent* event) +{ + if (watched == canvas()) + { + QMouseEvent* mouseEvent = dynamic_cast(event); + if (mouseEvent) + { + if (mouseEvent->button() == Qt::LeftButton && mouseEvent->type() == QMouseEvent::MouseButtonRelease) + { + selectClosestCurve(mouseEvent->pos()); + } + } + } + + return QwtPlot::eventFilter(watched, event); +} + + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuWellAllocationPlot::leaveEvent(QEvent *) +{ +// if (m_plotMarker->plot()) +// { +// m_plotMarker->detach(); +// +// replot(); +// } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuWellAllocationPlot::selectClosestCurve(const QPoint& pos) +{ +// QwtPlotCurve* closestCurve = NULL; +// double distMin = DBL_MAX; +// +// const QwtPlotItemList& itmList = itemList(); +// for (QwtPlotItemIterator it = itmList.begin(); it != itmList.end(); it++) +// { +// if ((*it)->rtti() == QwtPlotItem::Rtti_PlotCurve) +// { +// QwtPlotCurve* candidateCurve = static_cast(*it); +// double dist = DBL_MAX; +// candidateCurve->closestPoint(pos, &dist); +// if (dist < distMin) +// { +// closestCurve = candidateCurve; +// distMin = dist; +// } +// } +// } +// +// if (closestCurve && distMin < 20) +// { +// RimSummaryCurve* selectedCurve = m_plotDefinition->findRimCurveFromQwtCurve(closestCurve); +// if (selectedCurve) +// { +// RiaApplication::instance()->getOrCreateAndShowMainPlotWindow()->selectAsCurrentItem(selectedCurve); +// } +// } +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuWellAllocationPlot::onZoomedSlot() +{ + QwtInterval left, right, time; + currentVisibleWindow(&left, &right, &time); + + this->setZoomWindow(left, right, time); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuWellAllocationPlot::onAxisClicked(int axis, double value) +{ + if (!m_plotDefinition) return; + +// m_plotDefinition->selectAxisInPropertyEditor(axis); +} diff --git a/ApplicationCode/UserInterface/RiuWellAllocationPlot.h b/ApplicationCode/UserInterface/RiuWellAllocationPlot.h new file mode 100644 index 0000000000..84bc22c11a --- /dev/null +++ b/ApplicationCode/UserInterface/RiuWellAllocationPlot.h @@ -0,0 +1,90 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2017 Statoil ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "qwt_plot.h" +#include "cafPdmPointer.h" + +#include + +class QwtPlotCurve; +class QwtPlotGrid; +class QwtPlotZoomer; +class QwtInterval; +class QwtPicker; +class QwtPlotMarker; + +class RimWellAllocationPlot; + +//================================================================================================== +// +// +// +//================================================================================================== +class RiuWellAllocationPlot : public QwtPlot +{ + Q_OBJECT; +public: + RiuWellAllocationPlot(RimWellAllocationPlot* plotDefinition, QWidget* parent = NULL); + virtual ~RiuWellAllocationPlot(); + + RimWellAllocationPlot* ownerPlotDefinition(); + + void useDateBasedTimeAxis(); + void useTimeBasedTimeAxis(); + + void currentVisibleWindow(QwtInterval* leftAxis, + QwtInterval* rightAxis, + QwtInterval* timeAxis) const; + + void setZoomWindow(const QwtInterval& leftAxis, + const QwtInterval& rightAxis, + const QwtInterval& timeAxis); + +protected: + virtual bool eventFilter(QObject* watched, QEvent* event) override; + virtual void leaveEvent(QEvent *) override; + + virtual QSize sizeHint() const override; + virtual QSize minimumSizeHint() const override; + +private: + friend class RiuQwtPlotPicker; + QPointF closestCurvePoint(const QPoint& pos, QString* valueString, QString* timeString, int* yAxis) const; + void updateClosestCurvePointMarker(const QPointF& pos, int yAxis); + + void setDefaults(); + void selectClosestCurve(const QPoint& pos); + void showToolTip(const QPoint& pos); + + private slots: + void onZoomedSlot(); + void onAxisClicked(int axis, double value); + +private: + QwtPlotGrid* m_grid; +// QwtPicker* m_plotPicker; +// QwtPlotMarker* m_plotMarker; + + caf::PdmPointer m_plotDefinition; + + QPointer m_zoomerLeft; + QPointer m_zoomerRight; +}; +