File indexing completed on 2022-09-27 12:21:23

0001 /*************************************************************************************
0002  *  Copyright (C) 2015 by Aleix Pol <aleixpol@kde.org>                               *
0003  *                                                                                   *
0004  *  This program is free software; you can redistribute it and/or                    *
0005  *  modify it under the terms of the GNU General Public License                      *
0006  *  as published by the Free Software Foundation; either version 2                   *
0007  *  of the License, or (at your option) any later version.                           *
0008  *                                                                                   *
0009  *  This program is distributed in the hope that it will be useful,                  *
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of                   *
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                    *
0012  *  GNU General Public License for more details.                                     *
0013  *                                                                                   *
0014  *  You should have received a copy of the GNU General Public License                *
0015  *  along with this program; if not, write to the Free Software                      *
0016  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA   *
0017  *************************************************************************************/
0018 
0019 #include "graph3ditem.h"
0020 #include <QQuickWindow>
0021 #include <QOpenGLFramebufferObject>
0022 #include <analitzaplot/plotsmodel.h>
0023 #include <QTimer>
0024 #include <QQuickItemGrabResult>
0025 #include <QGuiApplication>
0026 #include <QElapsedTimer>
0027 
0028 using namespace Analitza;
0029 
0030 Plotter3DRenderer::Plotter3DRenderer(Graph3DItem* item)
0031     : QObject(item)
0032     , m_item(item)
0033 {}
0034 
0035 void Plotter3DRenderer::renderGL()
0036 {
0037     QTimer::singleShot(0, m_item, &Graph3DItem::update);
0038 }
0039 
0040 QQuickWindow* Plotter3DRenderer::window() const
0041 {
0042     return m_item->window();
0043 }
0044 
0045 Graph3DItem::Graph3DItem(QQuickItem* parent)
0046     : QQuickFramebufferObject(parent)
0047     , m_plotter(new Plotter3DRenderer(this))
0048 {
0049     //FIXME
0050     m_plotter->setUseSimpleRotation(true);
0051     setModel(new PlotsModel(this));
0052 
0053     setMirrorVertically(true);
0054 }
0055 
0056 Graph3DItem::~Graph3DItem()
0057 {}
0058 
0059 QStringList Graph3DItem::addFunction(const QString& expression, const QSharedPointer<Analitza::Variables>& vars)
0060 {
0061     PlotsModel* plotsmodel = qobject_cast<PlotsModel*>(m_plotter->model());
0062     if(!plotsmodel)
0063         qWarning() << "only can add plots to a PlotsModel instance";
0064     else
0065         return plotsmodel->addFunction(expression, Dim3D, vars);
0066     return {};
0067 }
0068 
0069 QAbstractItemModel* Graph3DItem::model() const
0070 {
0071     return m_plotter->model();
0072 }
0073 
0074 void Graph3DItem::setModel(QAbstractItemModel* model)
0075 {
0076     if (m_plotter->model())
0077         disconnect(m_plotter->model(), nullptr, this, nullptr);
0078 
0079     m_plotter->setModel(model);
0080 
0081     connect(model, &QAbstractItemModel::dataChanged, m_plotter, [this](const QModelIndex& start, const QModelIndex& end)
0082         { m_plotter->updatePlots(QModelIndex(), start.row(), end.row()); }
0083     );
0084 
0085     auto updateCount = [this](const QModelIndex &parent, int start, int end) { m_plotter->updatePlots(parent, start, end); };
0086     connect(model, &QAbstractItemModel::rowsInserted, this, updateCount);
0087     connect(model, &QAbstractItemModel::rowsAboutToBeRemoved, this, updateCount);
0088 
0089     Q_EMIT modelChanged(model);
0090 }
0091 
0092 void Graph3DItem::rotate(qreal x, qreal y)
0093 {
0094     m_plotter->rotate(x, y);
0095 }
0096 
0097 void Graph3DItem::scale(qreal s)
0098 {
0099     m_plotter->scale(s);
0100 }
0101 
0102 void Graph3DItem::resetViewport()
0103 {
0104     m_plotter->resetViewport();
0105 }
0106 
0107 bool Graph3DItem::save(const QUrl& url)
0108 {
0109     return m_plotter->save(url);
0110 }
0111 
0112 QStringList Graph3DItem::filters() const
0113 {
0114     return m_plotter->filters();
0115 }
0116 
0117 class Plotter3DFboRenderer : public QQuickFramebufferObject::Renderer
0118 {
0119 public:
0120     Plotter3DFboRenderer(Plotter3DRenderer* plotter)
0121         : m_plotter(plotter)
0122     {
0123         m_plotter->initGL();
0124     }
0125 
0126     void render() override {
0127         m_plotter->drawPlots();
0128 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0129         m_plotter->window()->resetOpenGLState();
0130 #else
0131         m_plotter->window()->endExternalCommands();
0132 #endif
0133     }
0134 
0135     QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) override
0136     {
0137         QOpenGLFramebufferObjectFormat format;
0138         format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
0139         return new QOpenGLFramebufferObject(size, format);
0140     }
0141 
0142 private:
0143     Plotter3DRenderer* m_plotter;
0144 };
0145 
0146 QQuickFramebufferObject::Renderer* Graph3DItem::createRenderer() const
0147 {
0148     m_plotter->setViewport(QRectF({0,0}, QSizeF(width(), height())));
0149     return new Plotter3DFboRenderer(m_plotter);
0150 }
0151 
0152 QImage Plotter3DRenderer::grabImage()
0153 {
0154     QSharedPointer<QQuickItemGrabResult> imgGrab = m_item->grabToImage();
0155     QImage ret;
0156     connect(imgGrab.data(), &QQuickItemGrabResult::ready, this, [imgGrab, &ret]() {
0157         ret = imgGrab->image();
0158     });
0159     QElapsedTimer timer;
0160     timer.start();
0161     while(ret.size().isEmpty() && timer.elapsed()<2000) {
0162         qGuiApp->processEvents();
0163     }
0164     return ret;
0165 }