2023-03-02 13:45:23 +00:00
|
|
|
// Copyright (C) 2023 The Qt Company Ltd.
|
|
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
|
|
|
|
|
2023-05-17 11:41:57 +00:00
|
|
|
#include "private/qquick3drepeater_p.h"
|
2023-03-02 13:45:23 +00:00
|
|
|
#include "qquickgraphssurface_p.h"
|
|
|
|
|
#include <QtCore/QMutexLocker>
|
|
|
|
|
|
|
|
|
|
#include "declarativescene_p.h"
|
|
|
|
|
#include "surface3dcontroller_p.h"
|
|
|
|
|
#include "surfaceselectioninstancing_p.h"
|
|
|
|
|
#include "qvalue3daxis_p.h"
|
|
|
|
|
#include "qcategory3daxis_p.h"
|
2023-03-24 09:57:43 +00:00
|
|
|
#include "quickgraphstexturedata_p.h"
|
2023-03-02 13:45:23 +00:00
|
|
|
|
|
|
|
|
#include <QtQuick3D/private/qquick3dprincipledmaterial_p.h>
|
|
|
|
|
#include <QtQuick3D/private/qquick3ddefaultmaterial_p.h>
|
2023-03-24 09:57:43 +00:00
|
|
|
#include <QtQuick3D/private/qquick3dcustommaterial_p.h>
|
2023-03-02 13:45:23 +00:00
|
|
|
|
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
|
|
|
|
|
|
QQuickGraphsSurface::QQuickGraphsSurface(QQuickItem *parent)
|
|
|
|
|
: QQuickGraphsItem(parent),
|
|
|
|
|
m_surfaceController(0)
|
|
|
|
|
{
|
|
|
|
|
setAcceptedMouseButtons(Qt::AllButtons);
|
|
|
|
|
|
|
|
|
|
// Create the shared component on the main GUI thread.
|
|
|
|
|
m_surfaceController = new Surface3DController(boundingRect().toRect(), new Declarative3DScene);
|
|
|
|
|
setSharedController(m_surfaceController);
|
|
|
|
|
|
|
|
|
|
QObject::connect(m_surfaceController, &Surface3DController::selectedSeriesChanged,
|
|
|
|
|
this, &QQuickGraphsSurface::selectedSeriesChanged);
|
|
|
|
|
QObject::connect(m_surfaceController, &Surface3DController::flipHorizontalGridChanged,
|
2023-05-17 11:41:57 +00:00
|
|
|
this, &QQuickGraphsSurface::handleFlipHorizontalGridChanged);
|
2023-03-02 13:45:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QQuickGraphsSurface::~QQuickGraphsSurface()
|
|
|
|
|
{
|
|
|
|
|
QMutexLocker locker(m_nodeMutex.data());
|
|
|
|
|
const QMutexLocker locker2(mutex());
|
|
|
|
|
delete m_surfaceController;
|
|
|
|
|
for (auto model : m_model)
|
|
|
|
|
delete model;
|
2023-04-11 05:10:15 +00:00
|
|
|
delete m_instancing;
|
|
|
|
|
delete m_sliceInstancing;
|
2023-03-02 13:45:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QValue3DAxis *QQuickGraphsSurface::axisX() const
|
|
|
|
|
{
|
|
|
|
|
return static_cast<QValue3DAxis *>(m_surfaceController->axisX());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QQuickGraphsSurface::setAxisX(QValue3DAxis *axis)
|
|
|
|
|
{
|
|
|
|
|
m_surfaceController->setAxisX(axis);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QValue3DAxis *QQuickGraphsSurface::axisY() const
|
|
|
|
|
{
|
|
|
|
|
return static_cast<QValue3DAxis *>(m_surfaceController->axisY());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QQuickGraphsSurface::setAxisY(QValue3DAxis *axis)
|
|
|
|
|
{
|
|
|
|
|
m_surfaceController->setAxisY(axis);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QValue3DAxis *QQuickGraphsSurface::axisZ() const
|
|
|
|
|
{
|
|
|
|
|
return static_cast<QValue3DAxis *>(m_surfaceController->axisZ());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QQuickGraphsSurface::setAxisZ(QValue3DAxis *axis)
|
|
|
|
|
{
|
|
|
|
|
m_surfaceController->setAxisZ(axis);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QQuickGraphsSurface::handleFlatShadingEnabledChanged()
|
|
|
|
|
{
|
|
|
|
|
auto series = static_cast<QSurface3DSeries *>(sender());
|
|
|
|
|
for (auto model : m_model) {
|
|
|
|
|
if (model->series == series) {
|
|
|
|
|
updateModel(model);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QQuickGraphsSurface::handleWireframeColorChanged()
|
|
|
|
|
{
|
|
|
|
|
for (auto model : m_model) {
|
|
|
|
|
QQmlListReference gridMaterialRef(model->gridModel, "materials");
|
2023-05-05 10:51:27 +00:00
|
|
|
auto gridMaterial = gridMaterialRef.at(0);
|
2023-03-02 13:45:23 +00:00
|
|
|
QColor gridColor = model->series->wireframeColor();
|
2023-05-05 10:51:27 +00:00
|
|
|
gridMaterial->setProperty("gridColor", gridColor);
|
2023-03-02 13:45:23 +00:00
|
|
|
|
|
|
|
|
if (sliceView()) {
|
|
|
|
|
QQmlListReference gridMaterialRef(model->sliceGridModel, "materials");
|
|
|
|
|
auto gridMaterial = static_cast<QQuick3DPrincipledMaterial *>(gridMaterialRef.at(0));
|
|
|
|
|
gridMaterial->setBaseColor(gridColor);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-17 11:41:57 +00:00
|
|
|
void QQuickGraphsSurface::handleFlipHorizontalGridChanged(bool flip)
|
|
|
|
|
{
|
2023-08-01 13:43:24 +00:00
|
|
|
if (!segmentLineRepeaterX()
|
|
|
|
|
|| !segmentLineRepeaterZ()) {
|
2023-05-17 11:41:57 +00:00
|
|
|
return;
|
2023-08-01 13:43:24 +00:00
|
|
|
}
|
2023-05-17 11:41:57 +00:00
|
|
|
int gridLineCountX = segmentLineRepeaterX()->count();
|
|
|
|
|
int subGridLineCountX = subsegmentLineRepeaterX()->count();
|
|
|
|
|
int gridLineCountZ = segmentLineRepeaterZ()->count();
|
|
|
|
|
int subGridLineCountZ = subsegmentLineRepeaterZ()->count();
|
|
|
|
|
|
|
|
|
|
float factor = -1.0f;
|
|
|
|
|
if (isGridUpdated())
|
|
|
|
|
factor = flip ? -1.0f : 1.0f;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < subGridLineCountZ; i++) {
|
|
|
|
|
QQuick3DNode *lineNode = static_cast<QQuick3DNode *>(subsegmentLineRepeaterZ()->objectAt(i));
|
|
|
|
|
QVector3D pos = lineNode->position();
|
|
|
|
|
pos.setY(pos.y() * factor);
|
|
|
|
|
lineNode->setPosition(pos);
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < gridLineCountZ; i++) {
|
|
|
|
|
QQuick3DNode *lineNode = static_cast<QQuick3DNode *>(segmentLineRepeaterZ()->objectAt(i));
|
|
|
|
|
QVector3D pos = lineNode->position();
|
|
|
|
|
pos.setY(pos.y() * factor);
|
|
|
|
|
lineNode->setPosition(pos);
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < subGridLineCountX; i++) {
|
|
|
|
|
QQuick3DNode *lineNode = static_cast<QQuick3DNode *>(subsegmentLineRepeaterX()->objectAt(i));
|
|
|
|
|
QVector3D pos = lineNode->position();
|
|
|
|
|
pos.setY(pos.y() * factor);
|
|
|
|
|
lineNode->setPosition(pos);
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < gridLineCountX; i++) {
|
|
|
|
|
QQuick3DNode *lineNode = static_cast<QQuick3DNode *>(segmentLineRepeaterX()->objectAt(i));
|
|
|
|
|
QVector3D pos = lineNode->position();
|
|
|
|
|
pos.setY(pos.y() * factor);
|
|
|
|
|
lineNode->setPosition(pos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < repeaterX()->count(); i++) {
|
2023-08-01 13:43:24 +00:00
|
|
|
QQuick3DNode *obj = static_cast<QQuick3DNode *>(repeaterX()->objectAt(i));
|
2023-05-17 11:41:57 +00:00
|
|
|
QVector3D pos = obj->position();
|
|
|
|
|
pos.setY(pos.y() * factor);
|
|
|
|
|
obj->setPosition(pos);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < repeaterZ()->count(); i++) {
|
2023-08-01 13:43:24 +00:00
|
|
|
QQuick3DNode *obj = static_cast<QQuick3DNode *>(repeaterZ()->objectAt(i));
|
2023-05-17 11:41:57 +00:00
|
|
|
QVector3D pos = obj->position();
|
|
|
|
|
pos.setY(pos.y() * factor);
|
|
|
|
|
obj->setPosition(pos);
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-01 13:43:24 +00:00
|
|
|
QVector3D pos = titleLabelX()->position();
|
|
|
|
|
pos.setY(pos.y() * factor);
|
|
|
|
|
titleLabelX()->setPosition(pos);
|
|
|
|
|
|
|
|
|
|
pos = titleLabelZ()->position();
|
|
|
|
|
pos.setY(pos.y() * factor);
|
|
|
|
|
titleLabelZ()->setPosition(pos);
|
|
|
|
|
|
2023-05-17 11:41:57 +00:00
|
|
|
setGridUpdated(false);
|
|
|
|
|
emit flipHorizontalGridChanged(flip);
|
|
|
|
|
m_surfaceController->setFlipHorizontalGridChanged(false);
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-02 13:45:23 +00:00
|
|
|
QSurface3DSeries *QQuickGraphsSurface::selectedSeries() const
|
|
|
|
|
{
|
|
|
|
|
return m_surfaceController->selectedSeries();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QQuickGraphsSurface::setFlipHorizontalGrid(bool flip)
|
|
|
|
|
{
|
|
|
|
|
m_surfaceController->setFlipHorizontalGrid(flip);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool QQuickGraphsSurface::flipHorizontalGrid() const
|
|
|
|
|
{
|
|
|
|
|
return m_surfaceController->flipHorizontalGrid();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QQmlListProperty<QSurface3DSeries> QQuickGraphsSurface::seriesList()
|
|
|
|
|
{
|
|
|
|
|
return QQmlListProperty<QSurface3DSeries>(this, this,
|
|
|
|
|
&QQuickGraphsSurface::appendSeriesFunc,
|
|
|
|
|
&QQuickGraphsSurface::countSeriesFunc,
|
|
|
|
|
&QQuickGraphsSurface::atSeriesFunc,
|
|
|
|
|
&QQuickGraphsSurface::clearSeriesFunc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QQuickGraphsSurface::appendSeriesFunc(QQmlListProperty<QSurface3DSeries> *list,
|
|
|
|
|
QSurface3DSeries *series)
|
|
|
|
|
{
|
|
|
|
|
reinterpret_cast<QQuickGraphsSurface *>(list->data)->addSeries(series);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
qsizetype QQuickGraphsSurface::countSeriesFunc(QQmlListProperty<QSurface3DSeries> *list)
|
|
|
|
|
{
|
|
|
|
|
return reinterpret_cast<QQuickGraphsSurface *>(list->data)->m_surfaceController->surfaceSeriesList().size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QSurface3DSeries *QQuickGraphsSurface::atSeriesFunc(QQmlListProperty<QSurface3DSeries> *list,
|
|
|
|
|
qsizetype index)
|
|
|
|
|
{
|
|
|
|
|
return reinterpret_cast<QQuickGraphsSurface *>(list->data)->m_surfaceController->surfaceSeriesList().at(index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QQuickGraphsSurface::clearSeriesFunc(QQmlListProperty<QSurface3DSeries> *list)
|
|
|
|
|
{
|
|
|
|
|
QQuickGraphsSurface *declSurface = reinterpret_cast<QQuickGraphsSurface *>(list->data);
|
|
|
|
|
QList<QSurface3DSeries *> realList = declSurface->m_surfaceController->surfaceSeriesList();
|
|
|
|
|
int count = realList.size();
|
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
|
declSurface->removeSeries(realList.at(i));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QQuickGraphsSurface::addSeries(QSurface3DSeries *series)
|
|
|
|
|
{
|
|
|
|
|
m_surfaceController->addSeries(series);
|
|
|
|
|
if (isReady())
|
|
|
|
|
addModel(series);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QQuickGraphsSurface::removeSeries(QSurface3DSeries *series)
|
|
|
|
|
{
|
|
|
|
|
m_surfaceController->removeSeries(series);
|
|
|
|
|
series->setParent(this); // Reparent as removing will leave series parentless
|
|
|
|
|
for (int i = 0; i < m_model.size();) {
|
|
|
|
|
if (m_model[i]->series == series) {
|
|
|
|
|
m_model[i]->model->deleteLater();
|
|
|
|
|
m_model[i]->gridModel->deleteLater();
|
2023-04-05 10:07:42 +00:00
|
|
|
if (sliceView()) {
|
|
|
|
|
m_model[i]->sliceModel->deleteLater();
|
|
|
|
|
m_model[i]->sliceGridModel->deleteLater();
|
|
|
|
|
}
|
2023-03-02 13:45:23 +00:00
|
|
|
m_model.removeAt(i);
|
|
|
|
|
} else {
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QQuickGraphsSurface::handleAxisXChanged(QAbstract3DAxis *axis)
|
|
|
|
|
{
|
|
|
|
|
emit axisXChanged(static_cast<QValue3DAxis *>(axis));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QQuickGraphsSurface::handleAxisYChanged(QAbstract3DAxis *axis)
|
|
|
|
|
{
|
|
|
|
|
emit axisYChanged(static_cast<QValue3DAxis *>(axis));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QQuickGraphsSurface::handleAxisZChanged(QAbstract3DAxis *axis)
|
|
|
|
|
{
|
|
|
|
|
emit axisZChanged(static_cast<QValue3DAxis *>(axis));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QQuickGraphsSurface::componentComplete()
|
|
|
|
|
{
|
|
|
|
|
QQuickGraphsItem::componentComplete();
|
|
|
|
|
|
|
|
|
|
for (auto series : m_surfaceController->surfaceSeriesList())
|
|
|
|
|
addModel(series);
|
|
|
|
|
|
|
|
|
|
QQuick3DNode *parent = rootNode();
|
|
|
|
|
|
|
|
|
|
m_selectionPointer = new QQuick3DModel();
|
|
|
|
|
m_selectionPointer->setParent(parent);
|
|
|
|
|
m_selectionPointer->setParentItem(parent);
|
|
|
|
|
m_selectionPointer->setSource(QUrl(QStringLiteral("#Sphere")));
|
|
|
|
|
auto pointerMaterial = new QQuick3DPrincipledMaterial();
|
|
|
|
|
pointerMaterial->setParent(this);
|
|
|
|
|
pointerMaterial->setBaseColor(m_surfaceController->activeTheme()->singleHighlightColor());
|
|
|
|
|
QQmlListReference materialRef(m_selectionPointer, "materials");
|
|
|
|
|
materialRef.append(pointerMaterial);
|
|
|
|
|
m_instancing = new SurfaceSelectionInstancing();
|
|
|
|
|
m_instancing->setScale(QVector3D(0.001f, 0.001f, 0.001f));
|
|
|
|
|
m_selectionPointer->setInstancing(m_instancing);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QQuickGraphsSurface::synchData()
|
|
|
|
|
{
|
|
|
|
|
QQuickGraphsItem::synchData();
|
|
|
|
|
|
|
|
|
|
if (m_surfaceController->isSelectedPointChanged()) {
|
|
|
|
|
if (m_surfaceController->selectionMode().testFlag(QAbstract3DGraph::SelectionItem))
|
|
|
|
|
updateSelectedPoint();
|
|
|
|
|
m_surfaceController->setSelectedPointChanged(false);
|
|
|
|
|
}
|
2023-05-17 11:41:57 +00:00
|
|
|
|
|
|
|
|
if (isGridUpdated() || m_surfaceController->isFlipHorizontalGridChanged())
|
|
|
|
|
handleFlipHorizontalGridChanged(m_surfaceController->flipHorizontalGrid());
|
2023-05-23 07:44:55 +00:00
|
|
|
|
|
|
|
|
if (m_surfaceController->isSurfaceTextureChanged()) {
|
|
|
|
|
if (!m_surfaceController->isChangedTexturesEmpty()) {
|
|
|
|
|
for (auto model : m_model) {
|
|
|
|
|
if (m_surfaceController->hasSeriesToChangeTexture(model->series))
|
2023-08-14 08:38:24 +00:00
|
|
|
updateMaterial(model);
|
2023-05-23 07:44:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
m_surfaceController->setSurfaceTextureChanged(false);
|
|
|
|
|
}
|
2023-03-02 13:45:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QQuickGraphsSurface::updateGraph()
|
|
|
|
|
{
|
2023-05-17 11:41:57 +00:00
|
|
|
for (auto model : m_model) {
|
2023-07-24 06:46:49 +00:00
|
|
|
bool seriesVisible = model->series->isVisible();
|
2023-05-17 11:41:57 +00:00
|
|
|
if (m_surfaceController->isSeriesVisibilityDirty()) {
|
2023-03-30 05:23:03 +00:00
|
|
|
bool graphVisible = (model->model->visible() || model->gridModel->visible());
|
2023-07-24 06:46:49 +00:00
|
|
|
|
2023-04-05 10:07:42 +00:00
|
|
|
if (seriesVisible != graphVisible && m_surfaceController->isSlicingActive()) {
|
2023-03-02 13:45:23 +00:00
|
|
|
setSliceActivatedChanged(true);
|
|
|
|
|
}
|
2023-03-30 05:23:03 +00:00
|
|
|
if (!seriesVisible) {
|
|
|
|
|
model->model->setVisible(seriesVisible);
|
|
|
|
|
model->gridModel->setVisible(seriesVisible);
|
2023-03-02 13:45:23 +00:00
|
|
|
if (sliceView()) {
|
2023-03-30 05:23:03 +00:00
|
|
|
model->sliceModel->setVisible(seriesVisible);
|
|
|
|
|
model->sliceGridModel->setVisible(seriesVisible);
|
2023-03-02 13:45:23 +00:00
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-24 06:46:49 +00:00
|
|
|
if (model->gridModel->visible() != seriesVisible)
|
|
|
|
|
model->gridModel->setVisible(seriesVisible);
|
|
|
|
|
if (model->model->visible() != seriesVisible)
|
|
|
|
|
model->model->setVisible(seriesVisible);
|
2023-05-17 11:41:57 +00:00
|
|
|
model->gridModel->setVisible(model->series->drawMode().testFlag(QSurface3DSeries::DrawWireframe));
|
|
|
|
|
if (model->series->drawMode().testFlag(QSurface3DSeries::DrawSurface))
|
|
|
|
|
model->model->setLocalOpacity(1.f);
|
|
|
|
|
else
|
|
|
|
|
model->model->setLocalOpacity(.0f);
|
2023-05-23 07:44:55 +00:00
|
|
|
|
|
|
|
|
if (sliceView() && sliceView()->isVisible()) {
|
|
|
|
|
model->sliceGridModel->setVisible(model->series->drawMode().testFlag(QSurface3DSeries::DrawWireframe));
|
2023-07-25 06:58:01 +00:00
|
|
|
if (model->series->drawMode().testFlag(QSurface3DSeries::DrawSurface))
|
|
|
|
|
model->sliceModel->setLocalOpacity(1.f);
|
|
|
|
|
else
|
|
|
|
|
model->sliceModel->setLocalOpacity(.0f);
|
2023-05-23 07:44:55 +00:00
|
|
|
}
|
2023-08-14 08:38:24 +00:00
|
|
|
updateMaterial(model);
|
2023-03-02 13:45:23 +00:00
|
|
|
}
|
|
|
|
|
|
2023-05-17 11:41:57 +00:00
|
|
|
m_surfaceController->setSeriesVisibilityDirty(false);
|
2023-06-27 13:17:53 +00:00
|
|
|
if (m_surfaceController->isDataDirty() ||
|
|
|
|
|
m_surfaceController->isSeriesVisualsDirty()) {
|
2023-04-05 10:07:42 +00:00
|
|
|
|
|
|
|
|
m_surfaceController->clearSelection();
|
|
|
|
|
|
2023-04-28 08:59:41 +00:00
|
|
|
if (m_surfaceController->hasChangedSeriesList()) {
|
|
|
|
|
handleChangedSeries();
|
|
|
|
|
} else {
|
|
|
|
|
for (auto model : m_model) {
|
|
|
|
|
bool visible = model->series->isVisible();
|
|
|
|
|
if (visible)
|
|
|
|
|
updateModel(model);
|
|
|
|
|
}
|
2023-03-02 13:45:23 +00:00
|
|
|
}
|
2023-04-28 08:59:41 +00:00
|
|
|
|
2023-08-09 06:04:08 +00:00
|
|
|
if (sliceView() && sliceView()->isVisible())
|
|
|
|
|
updateSliceGraph();
|
|
|
|
|
|
2023-04-28 08:59:41 +00:00
|
|
|
m_surfaceController->setDataDirty(false);
|
2023-06-27 13:17:53 +00:00
|
|
|
m_surfaceController->setSeriesVisualsDirty(false);
|
2023-03-02 13:45:23 +00:00
|
|
|
}
|
2023-08-09 06:04:08 +00:00
|
|
|
|
|
|
|
|
if (m_surfaceController->selectionMode().testFlag(QAbstract3DGraph::SelectionItem))
|
|
|
|
|
updateSelectedPoint();
|
2023-03-02 13:45:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QQuickGraphsSurface::handleChangedSeries()
|
|
|
|
|
{
|
|
|
|
|
auto changedSeries = m_surfaceController->changedSeriesList();
|
|
|
|
|
|
|
|
|
|
for (auto series : changedSeries) {
|
|
|
|
|
for (auto model : m_model) {
|
|
|
|
|
if (model->series == series) {
|
|
|
|
|
updateModel(model);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QQuickGraphsSurface::updateModel(SurfaceModel *model)
|
|
|
|
|
{
|
|
|
|
|
const QSurfaceDataArray &array = *(model->series->dataProxy())->array();
|
|
|
|
|
|
2023-08-14 05:34:44 +00:00
|
|
|
if (!array.isEmpty()) {
|
|
|
|
|
int rowCount = array.size();
|
|
|
|
|
int columnCount = array.at(0)->size();
|
2023-05-05 10:51:27 +00:00
|
|
|
|
2023-08-12 21:52:50 +00:00
|
|
|
if (rowCount <= 0 || columnCount <= 0)
|
|
|
|
|
return;
|
|
|
|
|
|
2023-05-05 10:51:27 +00:00
|
|
|
if (model->rowCount != rowCount) {
|
|
|
|
|
model->rowCount = rowCount;
|
|
|
|
|
m_isIndexDirty = true;
|
|
|
|
|
}
|
|
|
|
|
if (model->columnCount != columnCount) {
|
|
|
|
|
model->columnCount = columnCount;
|
|
|
|
|
m_isIndexDirty = true;
|
|
|
|
|
}
|
|
|
|
|
if (m_isIndexDirty) {
|
2023-08-09 06:04:08 +00:00
|
|
|
model->selectedVertex = SurfaceVertex();
|
2023-07-19 08:50:05 +00:00
|
|
|
if (sliceView() && sliceView()->isVisible()) {
|
|
|
|
|
m_surfaceController->setSlicingActive(false);
|
|
|
|
|
setSliceActivatedChanged(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-03-02 13:45:23 +00:00
|
|
|
|
|
|
|
|
int totalSize = rowCount * columnCount * 2;
|
|
|
|
|
float uvX = 1.0f / float(columnCount - 1);
|
|
|
|
|
float uvY = 1.0f / float(rowCount - 1);
|
|
|
|
|
|
|
|
|
|
// checkDirection
|
|
|
|
|
int dataDimensions = Surface3DController::BothAscending;
|
|
|
|
|
if (array.at(0)->at(0).x() > array.at(0)->at(array.at(0)->size() - 1).x())
|
|
|
|
|
dataDimensions |= Surface3DController::XDescending;
|
|
|
|
|
if (static_cast<QValue3DAxis *>(m_surfaceController->axisX())->reversed())
|
|
|
|
|
dataDimensions ^= Surface3DController::XDescending;
|
|
|
|
|
|
|
|
|
|
if (array.at(0)->at(0).z() > array.at(array.size() - 1)-> at(0).z())
|
|
|
|
|
dataDimensions |= Surface3DController::ZDescending;
|
|
|
|
|
if (static_cast<QValue3DAxis *>(m_surfaceController->axisZ())->reversed())
|
|
|
|
|
dataDimensions ^= Surface3DController::ZDescending;
|
|
|
|
|
|
|
|
|
|
m_surfaceController->setDataDimensions(static_cast<Surface3DController::DataDimensions>(dataDimensions));
|
|
|
|
|
|
2023-04-05 10:07:42 +00:00
|
|
|
model->vertices.clear();
|
2023-03-02 13:45:23 +00:00
|
|
|
model->vertices.reserve(totalSize);
|
|
|
|
|
|
|
|
|
|
bool isFlatShadingEnabled = model->series->isFlatShadingEnabled();
|
|
|
|
|
|
2023-05-05 10:51:27 +00:00
|
|
|
QVector3D boundsMin = model->boundsMin;
|
|
|
|
|
QVector3D boundsMax = model->boundsMax;
|
2023-03-02 13:45:23 +00:00
|
|
|
|
2023-05-05 10:51:27 +00:00
|
|
|
QVector<QVector4D> heights;
|
|
|
|
|
heights.reserve(totalSize);
|
|
|
|
|
|
|
|
|
|
QQmlListReference materialRef(model->model, "materials");
|
|
|
|
|
auto material = materialRef.at(0);
|
|
|
|
|
QVariant heightInputAsVariant = material->property("height");
|
|
|
|
|
QQuick3DShaderUtilsTextureInput *heightInput = heightInputAsVariant.value<QQuick3DShaderUtilsTextureInput *>();
|
|
|
|
|
QQuick3DTexture *heightMap = heightInput->texture();
|
|
|
|
|
QQuick3DTextureData *heightMapData = nullptr;
|
|
|
|
|
if (!heightMap) {
|
|
|
|
|
heightMap = new QQuick3DTexture();
|
|
|
|
|
heightMap->setParent(this);
|
|
|
|
|
heightMap->setHorizontalTiling(QQuick3DTexture::ClampToEdge);
|
|
|
|
|
heightMap->setVerticalTiling(QQuick3DTexture::ClampToEdge);
|
|
|
|
|
heightMapData = new QQuick3DTextureData();
|
|
|
|
|
heightMapData->setSize(QSize(columnCount, rowCount));
|
|
|
|
|
heightMapData->setFormat(QQuick3DTextureData::RGBA32F);
|
|
|
|
|
heightMapData->setParent(heightMap);
|
|
|
|
|
heightMapData->setParentItem(heightMap);
|
|
|
|
|
} else {
|
|
|
|
|
heightMapData = heightMap->textureData();
|
|
|
|
|
if (m_isIndexDirty)
|
|
|
|
|
heightMapData->setSize(QSize(columnCount , rowCount ));
|
|
|
|
|
}
|
|
|
|
|
material->setProperty("xDiff", uvX);
|
|
|
|
|
material->setProperty("yDiff", uvY);
|
|
|
|
|
material->setProperty ("flatShading", isFlatShadingEnabled);
|
|
|
|
|
|
2023-08-14 05:34:44 +00:00
|
|
|
QVector2D modelMin = QVector2D(array.at(0)->at(0).x(),array.at(0)->at(0).z());
|
|
|
|
|
QVector2D modelMax = QVector2D(array.at(0)->at(columnCount -1).x(), array.at(rowCount -1)->at(0).z());
|
|
|
|
|
|
|
|
|
|
bool xDesc = dataDimensions == Surface3DController::XDescending
|
|
|
|
|
|| dataDimensions == Surface3DController::BothDescending;
|
|
|
|
|
bool zDesc = dataDimensions == Surface3DController::ZDescending
|
|
|
|
|
|| dataDimensions == Surface3DController::BothDescending;
|
|
|
|
|
|
|
|
|
|
if (xDesc) {
|
|
|
|
|
modelMin.setX(array.at(0)->at(columnCount -1).x());
|
|
|
|
|
modelMax.setX(array.at(0)->at(0).x());
|
|
|
|
|
}
|
|
|
|
|
if (zDesc) {
|
|
|
|
|
modelMin.setY(array.at(rowCount -1)->at(0).z());
|
|
|
|
|
modelMax.setY(array.at(0)->at(0).z());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QAbstract3DAxis *axisX = m_surfaceController->axisX();
|
|
|
|
|
QAbstract3DAxis *axisZ = m_surfaceController->axisZ();
|
|
|
|
|
|
|
|
|
|
auto normalize = [](float x, float min, float max) -> float {
|
|
|
|
|
return (x - min) / (max - min);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
float rangeMinX = normalize(axisX->min(), modelMin.x(), modelMax.x());
|
|
|
|
|
float rangeMinZ = normalize(axisZ->min(), modelMin.y(), modelMax.y());
|
|
|
|
|
float rangeMaxX = normalize(axisX->max(), modelMin.x(), modelMax.x());
|
|
|
|
|
float rangeMaxZ = normalize(axisZ->max(), modelMin.y(), modelMax.y());
|
|
|
|
|
|
|
|
|
|
QVector2D rangeMin = QVector2D(rangeMinX, rangeMinZ);
|
|
|
|
|
QVector2D rangeMax = QVector2D(rangeMaxX, rangeMaxZ);
|
|
|
|
|
material->setProperty("rangeMin", rangeMin);
|
|
|
|
|
material->setProperty("rangeMax", rangeMax);
|
|
|
|
|
material->setProperty("xDesc", xDesc);
|
|
|
|
|
material->setProperty("zDesc", zDesc);
|
|
|
|
|
|
|
|
|
|
model->rangeMin = rangeMin;
|
|
|
|
|
model->rangeMax = rangeMax;
|
|
|
|
|
|
2023-05-17 11:41:57 +00:00
|
|
|
bool isPolar = m_surfaceController->isPolar();
|
2023-08-14 05:34:44 +00:00
|
|
|
for (int i = 0 ; i < rowCount ; i++) {
|
2023-03-02 13:45:23 +00:00
|
|
|
const QSurfaceDataRow &row = *array.at(i);
|
2023-08-14 05:34:44 +00:00
|
|
|
for (int j = 0 ; j < columnCount ; j++) {
|
2023-03-02 13:45:23 +00:00
|
|
|
// getNormalizedVertex
|
2023-05-17 11:41:57 +00:00
|
|
|
QVector3D pos = getNormalizedVertex(row.at(j), isPolar, false);
|
2023-05-05 10:51:27 +00:00
|
|
|
heights.push_back(QVector4D(pos, .0f));
|
2023-06-27 13:17:53 +00:00
|
|
|
SurfaceVertex vertex;
|
2023-03-02 13:45:23 +00:00
|
|
|
vertex.position = pos;
|
2023-08-14 05:34:44 +00:00
|
|
|
vertex.uv = QVector2D(j * uvX, i * uvY);
|
2023-03-02 13:45:23 +00:00
|
|
|
vertex.coord = QPoint(i, j);
|
|
|
|
|
model->vertices.push_back(vertex);
|
|
|
|
|
if (boundsMin.isNull())
|
|
|
|
|
boundsMin = pos;
|
|
|
|
|
else
|
|
|
|
|
boundsMin = QVector3D(qMin(boundsMin.x(), pos.x()), qMin(boundsMin.y(), pos.y()), qMin(boundsMin.z(), pos.z()));
|
|
|
|
|
if (boundsMax.isNull())
|
|
|
|
|
boundsMax = pos;
|
|
|
|
|
else
|
|
|
|
|
boundsMax = QVector3D(qMax(boundsMax.x(), pos.x()), qMax(boundsMax.y(), pos.y()), qMax(boundsMax.z(), pos.z()));
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-05-28 08:39:41 +00:00
|
|
|
model->boundsMin = boundsMin;
|
|
|
|
|
model->boundsMax = boundsMax;
|
|
|
|
|
|
2023-03-02 13:45:23 +00:00
|
|
|
model->indices.clear();
|
2023-05-05 10:51:27 +00:00
|
|
|
QByteArray heightData = QByteArray(reinterpret_cast<char *>(heights.data()), heights.size() * sizeof(QVector4D));
|
|
|
|
|
heightMapData->setTextureData(heightData);
|
|
|
|
|
heightMap->setTextureData(heightMapData);
|
|
|
|
|
heightInput->setTexture(heightMap);
|
|
|
|
|
model->heightTexture = heightMap;
|
2023-03-02 13:45:23 +00:00
|
|
|
|
2023-05-05 10:51:27 +00:00
|
|
|
if (m_isIndexDirty) {
|
2023-08-14 05:34:44 +00:00
|
|
|
createSmoothIndices(model, 0, 0, columnCount, rowCount);
|
2023-03-02 13:45:23 +00:00
|
|
|
|
2023-05-05 10:51:27 +00:00
|
|
|
auto geometry = model->model->geometry();
|
|
|
|
|
geometry->vertexData().clear();
|
2023-03-30 08:01:12 +00:00
|
|
|
QByteArray vertexBuffer(reinterpret_cast<char *>(model->vertices.data()),
|
2023-03-02 13:45:23 +00:00
|
|
|
model->vertices.size() * sizeof(SurfaceVertex));
|
2023-03-30 08:01:12 +00:00
|
|
|
geometry->setVertexData(vertexBuffer);
|
2023-05-05 10:51:27 +00:00
|
|
|
QByteArray indexBuffer(reinterpret_cast<char *>(model->indices.data()),
|
|
|
|
|
model->indices.size() * sizeof(quint32));
|
|
|
|
|
geometry->setIndexData(indexBuffer);
|
|
|
|
|
geometry->setBounds(boundsMin, boundsMax);
|
|
|
|
|
geometry->update();
|
2023-03-30 08:01:12 +00:00
|
|
|
}
|
2023-08-10 23:51:47 +00:00
|
|
|
|
2023-08-14 08:38:24 +00:00
|
|
|
updateMaterial(model);
|
2023-05-05 10:51:27 +00:00
|
|
|
if (m_isIndexDirty) {
|
2023-08-14 05:34:44 +00:00
|
|
|
createGridlineIndices(model, 0, 0, columnCount, rowCount);
|
2023-05-05 10:51:27 +00:00
|
|
|
auto gridGeometry = model->gridModel->geometry();
|
|
|
|
|
gridGeometry->vertexData().clear();
|
|
|
|
|
QByteArray vertexBuffer(reinterpret_cast<char *>(model->vertices.data()),
|
|
|
|
|
model->vertices.size() * sizeof(SurfaceVertex));
|
|
|
|
|
gridGeometry->setVertexData(vertexBuffer);
|
|
|
|
|
QByteArray gridIndexBuffer(reinterpret_cast<char *>(model->gridIndices.data()),
|
|
|
|
|
model->gridIndices.size() * sizeof(quint32));
|
|
|
|
|
gridGeometry->setIndexData(gridIndexBuffer);
|
|
|
|
|
gridGeometry->setBounds(boundsMin, boundsMax);
|
|
|
|
|
gridGeometry->update();
|
|
|
|
|
m_isIndexDirty = false;
|
|
|
|
|
}
|
2023-03-02 13:45:23 +00:00
|
|
|
QQmlListReference gridMaterialRef(model->gridModel, "materials");
|
2023-05-05 10:51:27 +00:00
|
|
|
auto gridMaterial = gridMaterialRef.at(0);
|
|
|
|
|
QVariant gridHeightInputAsVariant = gridMaterial->property("height");
|
|
|
|
|
QQuick3DShaderUtilsTextureInput *gridHeightInput = gridHeightInputAsVariant.value<QQuick3DShaderUtilsTextureInput *>();
|
|
|
|
|
gridHeightInput->setTexture(heightMap);
|
2023-03-02 13:45:23 +00:00
|
|
|
QColor gridColor = model->series->wireframeColor();
|
2023-05-05 10:51:27 +00:00
|
|
|
gridMaterial->setProperty("gridColor", gridColor);
|
2023-08-14 05:34:44 +00:00
|
|
|
gridMaterial->setProperty("rangeMin", rangeMin);
|
|
|
|
|
gridMaterial->setProperty("rangeMax", rangeMax);
|
|
|
|
|
gridMaterial->setProperty("xDesc", xDesc);
|
|
|
|
|
gridMaterial->setProperty("zDesc", zDesc);
|
2023-03-02 13:45:23 +00:00
|
|
|
}
|
2023-05-11 23:38:31 +00:00
|
|
|
updateSelectedPoint();
|
2023-03-02 13:45:23 +00:00
|
|
|
}
|
|
|
|
|
|
2023-08-14 08:38:24 +00:00
|
|
|
void QQuickGraphsSurface::updateMaterial(SurfaceModel *model)
|
2023-03-02 13:45:23 +00:00
|
|
|
{
|
2023-05-23 07:44:55 +00:00
|
|
|
QQmlListReference materialRef(model->model, "materials");
|
2023-08-14 08:38:24 +00:00
|
|
|
|
|
|
|
|
QQuick3DCustomMaterial *material = qobject_cast<QQuick3DCustomMaterial *>(materialRef.at(0));
|
|
|
|
|
|
|
|
|
|
if (!material) {
|
|
|
|
|
material = createQmlCustomMaterial(QStringLiteral(":/materials/SurfaceMaterial"));
|
|
|
|
|
model->customMaterial = material;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool textured = !(model->series->texture().isNull() && model->series->textureFile().isEmpty());
|
|
|
|
|
|
|
|
|
|
if (m_surfaceController->isSeriesVisualsDirty()
|
|
|
|
|
|| !textured) {
|
|
|
|
|
|
|
|
|
|
float xDiff = 1.0f / float(model->columnCount - 1);
|
|
|
|
|
float yDiff = 1.0f / float(model->rowCount - 1);
|
|
|
|
|
float minY = model->boundsMin.y();
|
|
|
|
|
float maxY = model->boundsMax.y();
|
|
|
|
|
float range = maxY - minY;
|
|
|
|
|
|
|
|
|
|
switch (model->series->colorStyle()) {
|
|
|
|
|
case(Q3DTheme::ColorStyleObjectGradient):
|
|
|
|
|
material->setProperty("colorStyle", 0);
|
|
|
|
|
material->setProperty("gradientMin", -(minY / range));
|
|
|
|
|
material->setProperty("gradientHeight", 1.0f / range);
|
|
|
|
|
break;
|
|
|
|
|
case(Q3DTheme::ColorStyleRangeGradient):
|
|
|
|
|
material->setProperty("colorStyle", 1);
|
|
|
|
|
break;
|
|
|
|
|
case(Q3DTheme::ColorStyleUniform):
|
|
|
|
|
material->setProperty("colorStyle", 2);
|
|
|
|
|
material->setProperty("uniformColor",model->series->baseColor());
|
|
|
|
|
break;
|
2023-05-23 07:44:55 +00:00
|
|
|
}
|
2023-08-14 08:38:24 +00:00
|
|
|
|
|
|
|
|
QVariant textureInputAsVariant = material->property("custex");
|
|
|
|
|
QQuick3DShaderUtilsTextureInput *textureInput = textureInputAsVariant.value<QQuick3DShaderUtilsTextureInput *>();
|
|
|
|
|
auto textureData = static_cast<QuickGraphsTextureData *>(model->texture->textureData());
|
|
|
|
|
textureData->createGradient(model->series->baseGradient());
|
|
|
|
|
textureInput->setTexture(model->texture);
|
|
|
|
|
|
|
|
|
|
QVariant heightInputAsVariant = material->property("height");
|
|
|
|
|
QQuick3DShaderUtilsTextureInput *heightInput = heightInputAsVariant.value<QQuick3DShaderUtilsTextureInput *>();
|
|
|
|
|
heightInput->setTexture(model->heightTexture);
|
|
|
|
|
material->setParent(model->model);
|
|
|
|
|
material->setParentItem(model->model);
|
|
|
|
|
material->setCullMode(QQuick3DMaterial::NoCulling);
|
|
|
|
|
material->setProperty("xDiff", xDiff);
|
|
|
|
|
material->setProperty("yDiff", yDiff);
|
|
|
|
|
material->setProperty("flatShading", model->series->isFlatShadingEnabled());
|
2023-08-14 05:34:44 +00:00
|
|
|
material->setProperty("rangeMin", model->rangeMin);
|
|
|
|
|
material->setProperty("rangeMax", model->rangeMax);
|
|
|
|
|
}
|
2023-08-14 08:38:24 +00:00
|
|
|
|
|
|
|
|
if (textured) {
|
|
|
|
|
material->setProperty("colorStyle", 3);
|
|
|
|
|
QQuick3DShaderUtilsTextureInput *texInput = material->property("baseColor").value<QQuick3DShaderUtilsTextureInput *>();
|
2023-05-05 10:51:27 +00:00
|
|
|
if (!texInput->texture()) {
|
|
|
|
|
QQuick3DTexture *texture = new QQuick3DTexture();
|
2023-05-23 07:44:55 +00:00
|
|
|
texture->setParent(model->model);
|
|
|
|
|
texture->setParentItem(model->model);
|
|
|
|
|
texture->setRotationUV(180.0f);
|
|
|
|
|
texture->setFlipU(true);
|
2023-05-05 10:51:27 +00:00
|
|
|
texInput->setTexture(texture);
|
2023-05-23 07:44:55 +00:00
|
|
|
}
|
|
|
|
|
if (!model->series->textureFile().isEmpty()) {
|
2023-05-05 10:51:27 +00:00
|
|
|
texInput->texture()->setSource(QUrl::fromLocalFile(model->series->textureFile()));
|
2023-05-23 07:44:55 +00:00
|
|
|
} else if (!model->series->texture().isNull()) {
|
|
|
|
|
QImage image = model->series->texture();
|
2023-08-11 10:49:31 +00:00
|
|
|
image.convertTo(QImage::Format_RGBA32FPx4);
|
2023-05-23 07:44:55 +00:00
|
|
|
auto textureData = static_cast<QuickGraphsTextureData *>(model->texture->textureData());
|
2023-08-11 10:49:31 +00:00
|
|
|
textureData->setFormat(QQuick3DTextureData::RGBA32F);
|
|
|
|
|
textureData->setSize(image.size());
|
2023-05-28 08:39:41 +00:00
|
|
|
textureData->setTextureData(QByteArray(reinterpret_cast<const char*>(image.bits()),
|
|
|
|
|
image.sizeInBytes()));
|
2023-08-11 10:49:31 +00:00
|
|
|
texInput->texture()->setTextureData(textureData);
|
2023-05-23 07:44:55 +00:00
|
|
|
} else {
|
2023-05-05 10:51:27 +00:00
|
|
|
texInput->texture()->setSource(QUrl());
|
2023-05-23 07:44:55 +00:00
|
|
|
}
|
|
|
|
|
}
|
2023-08-14 08:38:24 +00:00
|
|
|
material->update();
|
2023-03-02 13:45:23 +00:00
|
|
|
}
|
|
|
|
|
|
2023-03-24 09:57:43 +00:00
|
|
|
QVector3D QQuickGraphsSurface::getNormalizedVertex(const QSurfaceDataItem &data, bool polar, bool flipXZ)
|
2023-03-02 13:45:23 +00:00
|
|
|
{
|
|
|
|
|
Q_UNUSED(flipXZ);
|
|
|
|
|
|
|
|
|
|
QValue3DAxis* axisX = static_cast<QValue3DAxis *>(m_surfaceController->axisX());
|
|
|
|
|
QValue3DAxis* axisY = static_cast<QValue3DAxis *>(m_surfaceController->axisY());
|
|
|
|
|
QValue3DAxis* axisZ = static_cast<QValue3DAxis *>(m_surfaceController->axisZ());
|
2023-05-17 11:41:57 +00:00
|
|
|
|
|
|
|
|
float normalizedX = axisX->positionAt(data.x());
|
|
|
|
|
float normalizedY;
|
|
|
|
|
float normalizedZ = axisZ->positionAt(data.z());
|
|
|
|
|
// TODO : Need to handle, flipXZ
|
|
|
|
|
|
2023-03-02 13:45:23 +00:00
|
|
|
float scale, translate;
|
2023-05-17 11:41:57 +00:00
|
|
|
if (polar) {
|
|
|
|
|
float angle = normalizedX * M_PI * 2.0f;
|
|
|
|
|
float radius = normalizedZ;
|
|
|
|
|
normalizedX = radius * qSin(angle) * 1.0f;
|
|
|
|
|
normalizedZ = -(radius * qCos(angle)) * 1.0f;
|
|
|
|
|
} else {
|
2023-06-27 13:17:53 +00:00
|
|
|
scale = translate = this->scaleWithBackground().x();
|
2023-05-17 11:41:57 +00:00
|
|
|
normalizedX = normalizedX * scale * 2.0f - translate;
|
2023-06-27 13:17:53 +00:00
|
|
|
scale = translate = this->scaleWithBackground().z();
|
2023-05-17 11:41:57 +00:00
|
|
|
normalizedZ = normalizedZ * -scale * 2.0f + translate;
|
|
|
|
|
}
|
2023-03-02 13:45:23 +00:00
|
|
|
scale = translate = this->scale().y();
|
|
|
|
|
normalizedY = axisY->positionAt(data.y()) * scale * 2.0f - translate;
|
|
|
|
|
return QVector3D(normalizedX, normalizedY, normalizedZ);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QQuickGraphsSurface::updateSliceGraph()
|
|
|
|
|
{
|
2023-08-24 05:47:20 +00:00
|
|
|
if (!sliceView())
|
|
|
|
|
createSliceView();
|
|
|
|
|
|
2023-03-02 13:45:23 +00:00
|
|
|
QQuickGraphsItem::updateSliceGraph();
|
|
|
|
|
|
2023-06-14 19:40:12 +00:00
|
|
|
m_surfaceController->setSelectedPointChanged(true);
|
|
|
|
|
|
2023-03-02 13:45:23 +00:00
|
|
|
if (!sliceView()->isVisible())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
auto selectionMode = m_surfaceController->selectionMode();
|
|
|
|
|
for (auto model : m_model) {
|
2023-07-25 06:58:01 +00:00
|
|
|
bool visible = model->series->isVisible();
|
|
|
|
|
|
|
|
|
|
model->sliceModel->setVisible(visible);
|
|
|
|
|
model->sliceGridModel->setVisible(visible);
|
|
|
|
|
|
|
|
|
|
if (!selectionMode.testFlag(QAbstract3DGraph::SelectionMultiSeries)
|
|
|
|
|
&& !model->picked) {
|
|
|
|
|
model->sliceModel->setVisible(false);
|
|
|
|
|
model->sliceGridModel->setVisible(false);
|
2023-03-02 13:45:23 +00:00
|
|
|
continue;
|
2023-07-25 06:58:01 +00:00
|
|
|
} else {
|
|
|
|
|
model->sliceGridModel->setVisible(model->series->drawMode().testFlag(QSurface3DSeries::DrawWireframe));
|
|
|
|
|
if (model->series->drawMode().testFlag(QSurface3DSeries::DrawSurface))
|
|
|
|
|
model->sliceModel->setLocalOpacity(1.f);
|
|
|
|
|
else
|
|
|
|
|
model->sliceModel->setLocalOpacity(.0f);
|
|
|
|
|
}
|
2023-03-02 13:45:23 +00:00
|
|
|
|
|
|
|
|
QVector<SurfaceVertex> selectedSeries;
|
|
|
|
|
|
2023-05-11 23:38:31 +00:00
|
|
|
int rowCount = model->rowCount;
|
|
|
|
|
int columnCount = model->columnCount;
|
|
|
|
|
|
|
|
|
|
int indexCount = 0;
|
2023-03-02 13:45:23 +00:00
|
|
|
if (selectionMode.testFlag(QAbstract3DGraph::SelectionRow)) {
|
2023-05-11 23:38:31 +00:00
|
|
|
int selectedRow = model->selectedVertex.coord.x() * columnCount;
|
|
|
|
|
selectedSeries.reserve(columnCount * 2);
|
2023-03-02 13:45:23 +00:00
|
|
|
QVector<SurfaceVertex> list;
|
2023-05-11 23:38:31 +00:00
|
|
|
for (int i = 0; i < columnCount; i++) {
|
2023-03-02 13:45:23 +00:00
|
|
|
SurfaceVertex vertex = model->vertices.at(selectedRow + i);
|
|
|
|
|
vertex.position.setY(vertex.position.y() - .025f);
|
|
|
|
|
vertex.position.setZ(.0f);
|
|
|
|
|
selectedSeries.append(vertex);
|
|
|
|
|
vertex.position.setY(vertex.position.y() + .05f);
|
|
|
|
|
list.append(vertex);
|
|
|
|
|
}
|
|
|
|
|
selectedSeries.append(list);
|
2023-05-11 23:38:31 +00:00
|
|
|
indexCount = columnCount - 1;
|
2023-03-02 13:45:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (selectionMode.testFlag(QAbstract3DGraph::SelectionColumn)) {
|
|
|
|
|
int selectedColumn = model->selectedVertex.coord.y();
|
2023-05-11 23:38:31 +00:00
|
|
|
selectedSeries.reserve(rowCount * 2);
|
2023-03-02 13:45:23 +00:00
|
|
|
QVector<SurfaceVertex> list;
|
2023-05-11 23:38:31 +00:00
|
|
|
for (int i = 0; i < rowCount; i++) {
|
|
|
|
|
SurfaceVertex vertex = model->vertices.at((i * columnCount) + selectedColumn);
|
|
|
|
|
vertex.position.setX(-vertex.position.z());
|
2023-03-02 13:45:23 +00:00
|
|
|
vertex.position.setY(vertex.position.y() - .025f);
|
|
|
|
|
vertex.position.setZ(0);
|
|
|
|
|
selectedSeries.append(vertex);
|
|
|
|
|
vertex.position.setY(vertex.position.y() + .05f);
|
|
|
|
|
list.append(vertex);
|
|
|
|
|
}
|
|
|
|
|
selectedSeries.append(list);
|
2023-05-11 23:38:31 +00:00
|
|
|
indexCount = rowCount - 1;
|
2023-05-05 10:51:27 +00:00
|
|
|
|
|
|
|
|
QQmlListReference materialRef(model->sliceModel, "materials");
|
|
|
|
|
auto material = materialRef.at(0);
|
|
|
|
|
material->setProperty("isColumn", true);
|
2023-03-02 13:45:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QVector<quint32> indices;
|
2023-05-11 23:38:31 +00:00
|
|
|
indices.reserve(indexCount * 6);
|
|
|
|
|
for (int i = 0; i < indexCount; i++) {
|
2023-03-02 13:45:23 +00:00
|
|
|
indices.push_back(i + 1);
|
2023-05-11 23:38:31 +00:00
|
|
|
indices.push_back(i + indexCount + 1);
|
2023-03-02 13:45:23 +00:00
|
|
|
indices.push_back(i);
|
2023-05-11 23:38:31 +00:00
|
|
|
indices.push_back(i + indexCount + 2);
|
|
|
|
|
indices.push_back(i + indexCount + 1);
|
2023-03-02 13:45:23 +00:00
|
|
|
indices.push_back(i + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto geometry = model->sliceModel->geometry();
|
2023-04-05 10:07:42 +00:00
|
|
|
geometry->vertexData().clear();
|
|
|
|
|
geometry->indexData().clear();
|
2023-03-02 13:45:23 +00:00
|
|
|
QByteArray vertexBuffer(reinterpret_cast<char *>(selectedSeries.data()),
|
|
|
|
|
selectedSeries.size() * sizeof(SurfaceVertex));
|
|
|
|
|
geometry->setVertexData(vertexBuffer);
|
|
|
|
|
QByteArray indexBuffer(reinterpret_cast<char *>(indices.data()),
|
|
|
|
|
indices.size() * sizeof(quint32));
|
|
|
|
|
geometry->setIndexData(indexBuffer);
|
|
|
|
|
geometry->update();
|
|
|
|
|
|
|
|
|
|
geometry = model->sliceGridModel->geometry();
|
2023-04-05 10:07:42 +00:00
|
|
|
geometry->vertexData().clear();
|
|
|
|
|
geometry->indexData().clear();
|
2023-03-02 13:45:23 +00:00
|
|
|
geometry->setVertexData(vertexBuffer);
|
|
|
|
|
|
|
|
|
|
QVector<quint32> gridIndices;
|
2023-05-11 23:38:31 +00:00
|
|
|
gridIndices.reserve(indexCount * 4);
|
|
|
|
|
for (int i = 0; i < indexCount; i++) {
|
2023-03-02 13:45:23 +00:00
|
|
|
gridIndices.push_back(i);
|
2023-05-11 23:38:31 +00:00
|
|
|
gridIndices.push_back(i + indexCount + 1);
|
2023-03-02 13:45:23 +00:00
|
|
|
|
|
|
|
|
gridIndices.push_back(i);
|
|
|
|
|
gridIndices.push_back(i + 1);
|
|
|
|
|
}
|
2023-04-05 10:07:42 +00:00
|
|
|
geometry->indexData().clear();
|
2023-03-02 13:45:23 +00:00
|
|
|
QByteArray gridIndexBuffer(reinterpret_cast<char *>(gridIndices.data()),
|
|
|
|
|
gridIndices.size() * sizeof(quint32));
|
|
|
|
|
geometry->setIndexData(gridIndexBuffer);
|
|
|
|
|
geometry->update();
|
|
|
|
|
|
|
|
|
|
QQmlListReference gridMaterialRef(model->sliceGridModel, "materials");
|
|
|
|
|
auto gridMaterial = static_cast<QQuick3DPrincipledMaterial *>(gridMaterialRef.at(0));
|
|
|
|
|
QColor gridColor = model->series->wireframeColor();
|
|
|
|
|
gridMaterial->setBaseColor(gridColor);
|
2023-05-11 23:38:31 +00:00
|
|
|
|
|
|
|
|
updateSelectedPoint();
|
2023-03-02 13:45:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void QQuickGraphsSurface::createSmoothIndices(SurfaceModel *model, int x, int y, int endX, int endY)
|
|
|
|
|
{
|
2023-05-05 10:51:27 +00:00
|
|
|
model->indices.clear();
|
2023-03-02 13:45:23 +00:00
|
|
|
int columnCount = model->columnCount;
|
|
|
|
|
int rowCount = model->rowCount;
|
|
|
|
|
Surface3DController::DataDimensions dataDimensions = m_surfaceController->dataDimensions();
|
|
|
|
|
|
|
|
|
|
if (endX >= columnCount)
|
|
|
|
|
endX = columnCount - 1;
|
|
|
|
|
if (endY >= rowCount)
|
|
|
|
|
endY = rowCount - 1;
|
|
|
|
|
if (x > endX)
|
|
|
|
|
x = endX - 1;
|
|
|
|
|
if (y > endY)
|
|
|
|
|
y = endY - 1;
|
|
|
|
|
|
|
|
|
|
int indexCount = 6 * (endX - x) * (endY - y);
|
|
|
|
|
|
|
|
|
|
QVector<quint32> *indices = &model->indices;
|
|
|
|
|
|
|
|
|
|
indices->clear();
|
|
|
|
|
indices->resize(indexCount);
|
|
|
|
|
|
|
|
|
|
int rowEnd = endY * columnCount;
|
|
|
|
|
for (int row = y * columnCount ; row < rowEnd ; row += columnCount) {
|
|
|
|
|
for (int j = x ; j < endX ; j++) {
|
|
|
|
|
if (dataDimensions == Surface3DController::BothAscending
|
|
|
|
|
|| dataDimensions == Surface3DController::BothDescending) {
|
|
|
|
|
indices->push_back(row + j + 1);
|
|
|
|
|
indices->push_back(row + columnCount + j);
|
|
|
|
|
indices->push_back(row + j);
|
|
|
|
|
|
|
|
|
|
indices->push_back(row + columnCount + j + 1);
|
|
|
|
|
indices->push_back(row + columnCount + j);
|
|
|
|
|
indices->push_back(row + j + 1);
|
|
|
|
|
} else if (dataDimensions == Surface3DController::XDescending) {
|
|
|
|
|
indices->push_back(row + columnCount + j);
|
|
|
|
|
indices->push_back(row + columnCount + j + 1);
|
|
|
|
|
indices->push_back(row + j);
|
|
|
|
|
|
|
|
|
|
indices->push_back(row + j);
|
|
|
|
|
indices->push_back(row + columnCount + j + 1);
|
|
|
|
|
indices->push_back(row + j + 1);
|
|
|
|
|
} else {
|
|
|
|
|
indices->push_back(row + columnCount + j);
|
|
|
|
|
indices->push_back(row + columnCount + j + 1);
|
|
|
|
|
indices->push_back(row + j + 1);
|
|
|
|
|
|
|
|
|
|
indices->push_back(row + j);
|
2023-08-11 10:49:31 +00:00
|
|
|
indices->push_back(row + columnCount + j);
|
2023-03-02 13:45:23 +00:00
|
|
|
indices->push_back(row + j + 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void QQuickGraphsSurface::createGridlineIndices(SurfaceModel *model, int x, int y, int endX, int endY)
|
|
|
|
|
{
|
|
|
|
|
int columnCount = model->columnCount;
|
|
|
|
|
int rowCount = model->rowCount;
|
|
|
|
|
|
|
|
|
|
if (endX >= columnCount)
|
|
|
|
|
endX = columnCount - 1;
|
|
|
|
|
if (endY >= rowCount)
|
|
|
|
|
endY = rowCount - 1;
|
|
|
|
|
if (x > endX)
|
|
|
|
|
x = endX - 1;
|
|
|
|
|
if (y > endY)
|
|
|
|
|
y = endY - 1;
|
|
|
|
|
|
|
|
|
|
int nColumns = endX - x + 1;
|
|
|
|
|
int nRows = endY - y + 1;
|
|
|
|
|
|
|
|
|
|
int gridIndexCount = 2 * nColumns * (nRows - 1) + 2 * nRows * (nColumns - 1);
|
|
|
|
|
model->gridIndices.clear();
|
2023-05-23 07:44:55 +00:00
|
|
|
model->gridIndices.resize(gridIndexCount);
|
2023-03-02 13:45:23 +00:00
|
|
|
|
|
|
|
|
for (int i = y, row = columnCount * y ; i <= endY ; i++, row += columnCount) {
|
|
|
|
|
for (int j = x ; j < endX ; j++) {
|
|
|
|
|
model->gridIndices.push_back(row + j);
|
|
|
|
|
model->gridIndices.push_back(row + j + 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (int i = y, row = columnCount * y ; i < endY ; i++, row += columnCount) {
|
|
|
|
|
for (int j = x ; j <= endX ; j++) {
|
|
|
|
|
model->gridIndices.push_back(row + j);
|
|
|
|
|
model->gridIndices.push_back(row + j + columnCount);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
bool QQuickGraphsSurface::handleMousePressedEvent(QMouseEvent *event)
|
|
|
|
|
{
|
|
|
|
|
if (!QQuickGraphsItem::handleMousePressedEvent(event))
|
|
|
|
|
return true;
|
|
|
|
|
|
2023-05-15 10:00:37 +00:00
|
|
|
if (Qt::LeftButton == event->button())
|
|
|
|
|
doPicking(event->pos());
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool QQuickGraphsSurface::handleTouchEvent(QTouchEvent *event)
|
|
|
|
|
{
|
|
|
|
|
if (!QQuickGraphsItem::handleTouchEvent(event))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if (scene()->selectionQueryPosition() != scene()->invalidSelectionPoint()
|
|
|
|
|
&& !event->isUpdateEvent()) {
|
|
|
|
|
doPicking(event->point(0).position());
|
|
|
|
|
scene()->setSelectionQueryPosition(scene()->invalidSelectionPoint());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-23 07:02:19 +00:00
|
|
|
bool QQuickGraphsSurface::doPicking(const QPointF &position)
|
2023-05-15 10:00:37 +00:00
|
|
|
{
|
2023-05-23 07:02:19 +00:00
|
|
|
if (!QQuickGraphsItem::doPicking(position))
|
|
|
|
|
return false;
|
|
|
|
|
|
2023-05-15 10:00:37 +00:00
|
|
|
auto pickResult = pickAll(position.x(), position.y());
|
|
|
|
|
QVector3D pickedPos(0.0f, 0.0f, 0.0f);
|
|
|
|
|
QQuick3DModel *pickedModel = nullptr;
|
|
|
|
|
|
|
|
|
|
auto selectionMode = m_surfaceController->selectionMode();
|
|
|
|
|
if (!selectionMode.testFlag(QAbstract3DGraph::SelectionNone)) {
|
2023-08-09 22:50:04 +00:00
|
|
|
if (!sliceView() && selectionMode.testFlag(QAbstract3DGraph::SelectionSlice))
|
|
|
|
|
createSliceView();
|
|
|
|
|
|
2023-05-15 10:00:37 +00:00
|
|
|
for (auto picked : pickResult) {
|
2023-05-17 11:41:57 +00:00
|
|
|
if (picked.objectHit()
|
|
|
|
|
&& picked.objectHit()->objectName().contains(QStringLiteral("SurfaceModel"))) {
|
2023-05-15 10:00:37 +00:00
|
|
|
pickedPos = picked.position();
|
|
|
|
|
pickedModel = picked.objectHit();
|
|
|
|
|
if (!pickedPos.isNull())
|
|
|
|
|
break;
|
2023-03-02 13:45:23 +00:00
|
|
|
}
|
2023-05-15 10:00:37 +00:00
|
|
|
}
|
2023-03-02 13:45:23 +00:00
|
|
|
|
2023-05-15 10:00:37 +00:00
|
|
|
if (!pickedPos.isNull()) {
|
|
|
|
|
float min = -1.0f;
|
2023-03-02 13:45:23 +00:00
|
|
|
|
2023-05-15 10:00:37 +00:00
|
|
|
for (auto model : m_model) {
|
|
|
|
|
if (!model->series->isVisible())
|
|
|
|
|
continue;
|
2023-04-17 08:58:45 +00:00
|
|
|
|
2023-05-15 10:00:37 +00:00
|
|
|
model->picked = (model->model == pickedModel);
|
2023-04-17 08:58:45 +00:00
|
|
|
|
2023-05-15 10:00:37 +00:00
|
|
|
SurfaceVertex selectedVertex;
|
|
|
|
|
for (auto vertex : model->vertices) {
|
|
|
|
|
QVector3D pos = vertex.position;
|
|
|
|
|
float dist = pickedPos.distanceToPoint(pos);
|
|
|
|
|
if (selectedVertex.position.isNull() || dist < min) {
|
|
|
|
|
min = dist;
|
|
|
|
|
selectedVertex = vertex;
|
2023-03-02 13:45:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
2023-05-15 10:00:37 +00:00
|
|
|
model->selectedVertex = selectedVertex;
|
|
|
|
|
if (!selectedVertex.position.isNull()
|
|
|
|
|
&& model->picked) {
|
|
|
|
|
model->series->setSelectedPoint(selectedVertex.coord);
|
|
|
|
|
m_surfaceController->setSlicingActive(false);
|
|
|
|
|
if (isSliceEnabled())
|
|
|
|
|
setSliceActivatedChanged(true);
|
|
|
|
|
}
|
2023-03-02 13:45:23 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-05-23 07:02:19 +00:00
|
|
|
return true;
|
2023-03-02 13:45:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QQuickGraphsSurface::updateSelectedPoint()
|
|
|
|
|
{
|
|
|
|
|
bool labelVisible = false;
|
|
|
|
|
m_instancing->resetPositions();
|
2023-04-05 10:07:42 +00:00
|
|
|
if (sliceView() && sliceView()->isVisible())
|
2023-03-02 13:45:23 +00:00
|
|
|
m_sliceInstancing->resetPositions();
|
|
|
|
|
for (auto model : m_model) {
|
2023-08-09 06:04:08 +00:00
|
|
|
if ((!m_surfaceController->selectionMode().testFlag(QAbstract3DGraph::SelectionMultiSeries) &&
|
|
|
|
|
!model->picked)|| model->selectedVertex.position.isNull())
|
2023-05-11 23:38:31 +00:00
|
|
|
continue;
|
|
|
|
|
QPoint selectedCoord = model->selectedVertex.coord;
|
|
|
|
|
int index = selectedCoord.x() * model->columnCount + selectedCoord.y();
|
|
|
|
|
SurfaceVertex selectedVertex = model->vertices.at(index);
|
2023-03-02 13:45:23 +00:00
|
|
|
if (model->series->isVisible() &&
|
2023-07-25 06:58:01 +00:00
|
|
|
!selectedVertex.position.isNull() &&
|
|
|
|
|
m_surfaceController->selectionMode().testFlag(QAbstract3DGraph::SelectionItem)) {
|
2023-03-02 13:45:23 +00:00
|
|
|
m_instancing->addPosition(selectedVertex.position);
|
2023-05-11 23:38:31 +00:00
|
|
|
QVector3D slicePosition = selectedVertex.position;
|
2023-04-05 10:07:42 +00:00
|
|
|
if (sliceView() && sliceView()->isVisible()) {
|
2023-03-02 13:45:23 +00:00
|
|
|
if (m_surfaceController->selectionMode().testFlag(QAbstract3DGraph::SelectionColumn))
|
2023-05-11 23:38:31 +00:00
|
|
|
slicePosition.setX(-slicePosition.z());
|
2023-03-02 13:45:23 +00:00
|
|
|
slicePosition.setZ(.0f);
|
|
|
|
|
m_sliceInstancing->addPosition(slicePosition);
|
|
|
|
|
}
|
|
|
|
|
if (model->picked) {
|
|
|
|
|
QVector3D labelPosition = selectedVertex.position;
|
2023-08-21 07:55:04 +00:00
|
|
|
model->series->setSelectedPoint(selectedVertex.coord);
|
|
|
|
|
QString label = model->series->itemLabel();
|
2023-06-14 19:40:12 +00:00
|
|
|
|
|
|
|
|
updateItemLabel(labelPosition);
|
2023-03-02 13:45:23 +00:00
|
|
|
itemLabel()->setProperty("labelText", label);
|
|
|
|
|
labelVisible = true;
|
|
|
|
|
|
2023-04-05 10:07:42 +00:00
|
|
|
if (sliceView() && sliceView()->isVisible()) {
|
2023-05-11 23:38:31 +00:00
|
|
|
labelPosition = slicePosition;
|
2023-03-02 13:45:23 +00:00
|
|
|
labelPosition.setZ(.1f);
|
|
|
|
|
labelPosition.setY(labelPosition.y() + .05f);
|
|
|
|
|
sliceItemLabel()->setPosition(labelPosition);
|
|
|
|
|
sliceItemLabel()->setProperty("labelText", label);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
itemLabel()->setVisible(labelVisible);
|
2023-04-05 10:07:42 +00:00
|
|
|
if (sliceView() && sliceView()->isVisible())
|
2023-03-02 13:45:23 +00:00
|
|
|
sliceItemLabel()->setVisible(labelVisible);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QQuickGraphsSurface::addModel(QSurface3DSeries *series)
|
|
|
|
|
{
|
2023-03-20 19:36:09 +00:00
|
|
|
auto parent = graphNode();
|
2023-03-02 13:45:23 +00:00
|
|
|
bool visible = series->isVisible();
|
|
|
|
|
|
|
|
|
|
auto model = new QQuick3DModel();
|
2023-03-20 19:36:09 +00:00
|
|
|
model->setParent(parent);
|
|
|
|
|
model->setParentItem(parent);
|
2023-03-02 13:45:23 +00:00
|
|
|
model->setObjectName(QStringLiteral("SurfaceModel"));
|
|
|
|
|
model->setVisible(visible);
|
|
|
|
|
if (m_surfaceController->selectionMode().testFlag(QAbstract3DGraph::SelectionNone))
|
|
|
|
|
model->setPickable(false);
|
|
|
|
|
else
|
|
|
|
|
model->setPickable(true);
|
|
|
|
|
|
|
|
|
|
auto geometry = new QQuick3DGeometry();
|
2023-03-20 19:36:09 +00:00
|
|
|
geometry->setParent(model);
|
2023-03-02 13:45:23 +00:00
|
|
|
geometry->setStride(sizeof(SurfaceVertex));
|
|
|
|
|
geometry->setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles);
|
|
|
|
|
geometry->addAttribute(QQuick3DGeometry::Attribute::PositionSemantic,
|
|
|
|
|
0,
|
|
|
|
|
QQuick3DGeometry::Attribute::F32Type);
|
|
|
|
|
geometry->addAttribute(QQuick3DGeometry::Attribute::TexCoord0Semantic,
|
|
|
|
|
sizeof(QVector3D),
|
|
|
|
|
QQuick3DGeometry::Attribute::F32Type);
|
|
|
|
|
geometry->addAttribute(QQuick3DGeometry::Attribute::IndexSemantic,
|
|
|
|
|
0,
|
|
|
|
|
QQuick3DGeometry::Attribute::U32Type);
|
|
|
|
|
model->setGeometry(geometry);
|
|
|
|
|
|
2023-05-05 10:51:27 +00:00
|
|
|
|
2023-03-02 13:45:23 +00:00
|
|
|
QQuick3DTexture *texture = new QQuick3DTexture();
|
2023-03-24 09:57:43 +00:00
|
|
|
texture->setParent(this);
|
|
|
|
|
texture->setRotationUV(-90.0f);
|
|
|
|
|
texture->setHorizontalTiling(QQuick3DTexture::ClampToEdge);
|
|
|
|
|
texture->setVerticalTiling(QQuick3DTexture::ClampToEdge);
|
|
|
|
|
QuickGraphsTextureData *textureData = new QuickGraphsTextureData();
|
|
|
|
|
textureData->setParent(texture);
|
|
|
|
|
textureData->setParentItem(texture);
|
2023-03-02 13:45:23 +00:00
|
|
|
texture->setTextureData(textureData);
|
2023-05-23 07:44:55 +00:00
|
|
|
|
|
|
|
|
QQmlListReference materialRef(model, "materials");
|
2023-05-05 10:51:27 +00:00
|
|
|
|
2023-08-14 08:38:24 +00:00
|
|
|
QQuick3DCustomMaterial *customMaterial = createQmlCustomMaterial(QStringLiteral(":/materials/SurfaceMaterial"));
|
2023-05-05 10:51:27 +00:00
|
|
|
|
2023-05-23 07:44:55 +00:00
|
|
|
customMaterial->setParent(model);
|
|
|
|
|
customMaterial->setParentItem(model);
|
|
|
|
|
customMaterial->setCullMode(QQuick3DMaterial::NoCulling);
|
|
|
|
|
QVariant textureInputAsVariant = customMaterial->property("custex");
|
|
|
|
|
QQuick3DShaderUtilsTextureInput *textureInput = textureInputAsVariant.value<QQuick3DShaderUtilsTextureInput *>();
|
2023-03-24 09:57:43 +00:00
|
|
|
textureInput->setTexture(texture);
|
2023-05-23 07:44:55 +00:00
|
|
|
|
|
|
|
|
materialRef.append(customMaterial);
|
2023-03-02 13:45:23 +00:00
|
|
|
|
|
|
|
|
auto gridModel = new QQuick3DModel();
|
2023-03-20 19:36:09 +00:00
|
|
|
gridModel->setParent(parent);
|
|
|
|
|
gridModel->setParentItem(parent);
|
2023-03-30 05:23:03 +00:00
|
|
|
gridModel->setObjectName(QStringLiteral("SurfaceModel"));
|
2023-03-02 13:45:23 +00:00
|
|
|
gridModel->setVisible(visible);
|
|
|
|
|
gridModel->setDepthBias(1.0f);
|
|
|
|
|
auto gridGeometry = new QQuick3DGeometry();
|
|
|
|
|
gridGeometry->setParent(this);
|
|
|
|
|
gridGeometry->setStride(sizeof(SurfaceVertex));
|
|
|
|
|
gridGeometry->setPrimitiveType(QQuick3DGeometry::PrimitiveType::Lines);
|
|
|
|
|
gridGeometry->addAttribute(QQuick3DGeometry::Attribute::PositionSemantic,
|
|
|
|
|
0,
|
|
|
|
|
QQuick3DGeometry::Attribute::F32Type);
|
2023-05-05 10:51:27 +00:00
|
|
|
gridGeometry->addAttribute(QQuick3DGeometry::Attribute::TexCoord0Semantic,
|
|
|
|
|
sizeof(QVector3D),
|
|
|
|
|
QQuick3DGeometry::Attribute::F32Type);
|
2023-03-02 13:45:23 +00:00
|
|
|
gridGeometry->addAttribute(QQuick3DGeometry::Attribute::IndexSemantic,
|
|
|
|
|
0,
|
|
|
|
|
QQuick3DGeometry::Attribute::U32Type);
|
|
|
|
|
gridModel->setGeometry(gridGeometry);
|
|
|
|
|
QQmlListReference gridMaterialRef(gridModel, "materials");
|
2023-05-05 10:51:27 +00:00
|
|
|
auto gridMaterial = createQmlCustomMaterial(QStringLiteral(":/materials/GridSurfaceMaterial"));
|
2023-03-20 19:36:09 +00:00
|
|
|
gridMaterial->setParent(gridModel);
|
2023-05-05 10:51:27 +00:00
|
|
|
gridMaterial->setParentItem(gridModel);
|
2023-03-02 13:45:23 +00:00
|
|
|
gridMaterialRef.append(gridMaterial);
|
|
|
|
|
|
|
|
|
|
SurfaceModel *surfaceModel = new SurfaceModel();
|
|
|
|
|
surfaceModel->model = model;
|
|
|
|
|
surfaceModel->gridModel = gridModel;
|
|
|
|
|
surfaceModel->series = series;
|
2023-03-24 09:57:43 +00:00
|
|
|
surfaceModel->texture = texture;
|
2023-05-23 07:44:55 +00:00
|
|
|
surfaceModel->customMaterial = customMaterial;
|
2023-03-02 13:45:23 +00:00
|
|
|
|
|
|
|
|
m_model.push_back(surfaceModel);
|
|
|
|
|
|
|
|
|
|
connect(series,
|
|
|
|
|
&QSurface3DSeries::flatShadingEnabledChanged,
|
|
|
|
|
this,
|
|
|
|
|
&QQuickGraphsSurface::handleFlatShadingEnabledChanged);
|
|
|
|
|
connect(series,
|
|
|
|
|
&QSurface3DSeries::wireframeColorChanged,
|
|
|
|
|
this,
|
|
|
|
|
&QQuickGraphsSurface::handleWireframeColorChanged);
|
2023-04-05 10:07:42 +00:00
|
|
|
|
|
|
|
|
if (sliceView())
|
|
|
|
|
addSliceModel(surfaceModel);
|
2023-03-02 13:45:23 +00:00
|
|
|
}
|
|
|
|
|
|
2023-03-02 13:01:55 +00:00
|
|
|
void QQuickGraphsSurface::createSliceView()
|
|
|
|
|
{
|
|
|
|
|
QQuickGraphsItem::createSliceView();
|
|
|
|
|
|
2023-04-05 10:07:42 +00:00
|
|
|
for (auto surfaceModel : m_model)
|
|
|
|
|
addSliceModel(surfaceModel);
|
|
|
|
|
|
|
|
|
|
QQuick3DViewport *sliceParent = sliceView();
|
2023-03-02 13:01:55 +00:00
|
|
|
|
|
|
|
|
m_sliceSelectionPointer = new QQuick3DModel();
|
|
|
|
|
m_sliceSelectionPointer->setParent(sliceParent->scene());
|
|
|
|
|
m_sliceSelectionPointer->setParentItem(sliceParent->scene());
|
|
|
|
|
m_sliceSelectionPointer->setSource(QUrl(QStringLiteral("#Sphere")));
|
|
|
|
|
QQuick3DPrincipledMaterial *pointerMaterial = new QQuick3DPrincipledMaterial();
|
|
|
|
|
pointerMaterial->setParent(m_sliceSelectionPointer);
|
|
|
|
|
pointerMaterial->setBaseColor(m_surfaceController->activeTheme()->singleHighlightColor());
|
|
|
|
|
QQmlListReference sliceMaterialRef(m_sliceSelectionPointer, "materials");
|
|
|
|
|
sliceMaterialRef.append(pointerMaterial);
|
|
|
|
|
m_sliceInstancing = new SurfaceSelectionInstancing();
|
|
|
|
|
m_sliceInstancing->setScale(QVector3D(0.001f, 0.001f, 0.001f));
|
|
|
|
|
m_sliceSelectionPointer->setInstancing(m_sliceInstancing);
|
|
|
|
|
m_sliceInstancing->setColor(m_surfaceController->activeTheme()->singleHighlightColor());
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-05 10:07:42 +00:00
|
|
|
void QQuickGraphsSurface::addSliceModel(SurfaceModel *model)
|
|
|
|
|
{
|
|
|
|
|
QQuick3DViewport *sliceParent = sliceView();
|
|
|
|
|
|
|
|
|
|
auto surfaceModel = new QQuick3DModel();
|
|
|
|
|
surfaceModel->setParent(sliceParent->scene());
|
|
|
|
|
surfaceModel->setParentItem(sliceParent->scene());
|
|
|
|
|
surfaceModel->setVisible(model->series->isVisible());
|
|
|
|
|
|
|
|
|
|
auto geometry = new QQuick3DGeometry();
|
|
|
|
|
geometry->setParent(surfaceModel);
|
|
|
|
|
geometry->setParentItem(surfaceModel);
|
|
|
|
|
geometry->setStride(sizeof(SurfaceVertex));
|
|
|
|
|
geometry->setPrimitiveType(QQuick3DGeometry::PrimitiveType::Triangles);
|
|
|
|
|
geometry->addAttribute(QQuick3DGeometry::Attribute::PositionSemantic,
|
|
|
|
|
0,
|
|
|
|
|
QQuick3DGeometry::Attribute::F32Type);
|
|
|
|
|
geometry->addAttribute(QQuick3DGeometry::Attribute::TexCoord0Semantic,
|
|
|
|
|
sizeof(QVector3D),
|
|
|
|
|
QQuick3DGeometry::Attribute::F32Type);
|
|
|
|
|
geometry->addAttribute(QQuick3DGeometry::Attribute::IndexSemantic,
|
|
|
|
|
0,
|
|
|
|
|
QQuick3DGeometry::Attribute::U32Type);
|
|
|
|
|
surfaceModel->setGeometry(geometry);
|
|
|
|
|
|
|
|
|
|
QQmlListReference materialRef(surfaceModel, "materials");
|
2023-05-05 10:51:27 +00:00
|
|
|
auto material = createQmlCustomMaterial(QStringLiteral(":/materials/SurfaceSliceMaterial"));
|
2023-04-05 10:07:42 +00:00
|
|
|
material->setCullMode(QQuick3DMaterial::NoCulling);
|
|
|
|
|
QVariant textureInputAsVariant = material->property("custex");
|
|
|
|
|
QQuick3DShaderUtilsTextureInput *textureInput = textureInputAsVariant.value<QQuick3DShaderUtilsTextureInput *>();
|
|
|
|
|
QQuick3DTexture *texture = model->texture;
|
|
|
|
|
textureInput->setTexture(texture);
|
|
|
|
|
materialRef.append(material);
|
|
|
|
|
|
|
|
|
|
model->sliceModel = surfaceModel;
|
|
|
|
|
|
|
|
|
|
QQuick3DModel *gridModel = new QQuick3DModel();
|
|
|
|
|
gridModel->setParent(sliceParent->scene());
|
|
|
|
|
gridModel->setParentItem(sliceParent->scene());
|
|
|
|
|
gridModel->setVisible(model->series->isVisible());
|
|
|
|
|
gridModel->setDepthBias(1.0f);
|
|
|
|
|
QQuick3DGeometry *gridGeometry = new QQuick3DGeometry();
|
|
|
|
|
gridGeometry->setParent(gridModel);
|
|
|
|
|
gridGeometry->setStride(sizeof(SurfaceVertex));
|
|
|
|
|
gridGeometry->setPrimitiveType(QQuick3DGeometry::PrimitiveType::Lines);
|
|
|
|
|
gridGeometry->addAttribute(QQuick3DGeometry::Attribute::PositionSemantic,
|
|
|
|
|
0,
|
|
|
|
|
QQuick3DGeometry::Attribute::F32Type);
|
|
|
|
|
gridGeometry->addAttribute(QQuick3DGeometry::Attribute::IndexSemantic,
|
|
|
|
|
0,
|
|
|
|
|
QQuick3DGeometry::Attribute::U32Type);
|
|
|
|
|
gridModel->setGeometry(gridGeometry);
|
|
|
|
|
QQmlListReference gridMaterialRef(gridModel, "materials");
|
|
|
|
|
QQuick3DPrincipledMaterial *gridMaterial = new QQuick3DPrincipledMaterial();
|
|
|
|
|
gridMaterial->setParent(gridModel);
|
|
|
|
|
gridMaterial->setLighting(QQuick3DPrincipledMaterial::NoLighting);
|
|
|
|
|
gridMaterial->setParent(gridModel);
|
|
|
|
|
gridMaterialRef.append(gridMaterial);
|
|
|
|
|
|
|
|
|
|
model->sliceGridModel = gridModel;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-02 13:45:23 +00:00
|
|
|
void QQuickGraphsSurface::updateSingleHighlightColor()
|
|
|
|
|
{
|
|
|
|
|
m_instancing->setColor(m_surfaceController->activeTheme()->singleHighlightColor());
|
|
|
|
|
if (sliceView())
|
|
|
|
|
m_sliceInstancing->setColor(m_surfaceController->activeTheme()->singleHighlightColor());
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-18 10:40:03 +00:00
|
|
|
void QQuickGraphsSurface::updateLightStrength()
|
|
|
|
|
{
|
|
|
|
|
for (auto model : m_model) {
|
|
|
|
|
QQmlListReference materialRef(model->model, "materials");
|
|
|
|
|
QQuick3DCustomMaterial *material = qobject_cast<QQuick3DCustomMaterial *>(materialRef.at(0));
|
|
|
|
|
material->setProperty("specularBrightness",
|
|
|
|
|
m_surfaceController->activeTheme()->lightStrength() * 0.05);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-02 13:45:23 +00:00
|
|
|
void QQuickGraphsSurface::handleThemeTypeChange()
|
|
|
|
|
{
|
|
|
|
|
for (auto model : m_model)
|
|
|
|
|
updateMaterial(model);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QT_END_NAMESPACE
|