C
Qt Cluster: Rendering and Recovery from Main UI Failure
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
// This file is part of the Qt Safe Renderer module
#include "gaugenode.h"
#include <QtQuick/qsgnode.h>
#include <QtQuick/qsgflatcolormaterial.h>
#include <QtMath>
#define EXTRAVERTICES 3
GaugeNode::GaugeNode(const int &numVertices, const QColor &color = QColor(255, 0, 0),
const bool &doNotFill = false)
: QSGGeometryNode()
, m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), numVertices+EXTRAVERTICES)
, m_material(nullptr)
, m_numVertices(numVertices)
, m_doNotFill(doNotFill)
, m_color(color)
, m_cutRad(0.0)
, m_lefttoright(true)
{
initGeometry();
}
GaugeNode::~GaugeNode()
{
if (m_material)
delete m_material;
}
void GaugeNode::setColor(const QColor &color)
{
if (m_color == color)
return;
m_color = color;
m_dirtyBits |= QSGNode::DirtyMaterial;
}
void GaugeNode::setCutRad(const float &cutRad)
{
if (m_cutRad == cutRad)
return;
m_cutRad = cutRad;
}
void GaugeNode::setDoNotFill(const bool &doNotFill)
{
if (m_doNotFill == doNotFill)
return;
m_doNotFill = doNotFill;
if (m_doNotFill)
m_geometry.setDrawingMode(QSGGeometry::DrawLineStrip);
else
m_geometry.setDrawingMode(QSGGeometry::DrawTriangleStrip);
m_dirtyBits |= QSGNode::DirtyGeometry;
}
void GaugeNode::setBackCutRad(const double &backCutRad)
{
if (backCutRad == m_backCutRad)
return;
m_backCutRad = backCutRad;
m_dirtyBits |= QSGNode::DirtyGeometry;
}
void GaugeNode::setRadius(const double &radius)
{
if (m_radius == radius)
return;
m_radius = radius;
m_dirtyBits |= QSGNode::DirtyGeometry;
}
void GaugeNode::setArcDistPerVert(const double &dist)
{
if (dist == m_arc_dist_per_vertices)
return;
m_arc_dist_per_vertices = dist;
m_dirtyBits |= QSGNode::DirtyGeometry;
}
void GaugeNode::setNumVertices(const int &numVertices)
{
if (numVertices == m_numVertices)
return;
m_numVertices = numVertices;
m_geometry.allocate(m_numVertices + 3);
m_dirtyBits |= QSGNode::DirtyGeometry;
}
void GaugeNode::setFillWidth(const double &fillWidth)
{
if (m_fillWidth == fillWidth)
return;
m_fillWidth = fillWidth;
m_dirtyBits |= QSGNode::DirtyGeometry;
}
void GaugeNode::setBoundingRect(const QRectF &rect)
{
if (rect.width() == m_width && rect.height() == m_height)
return;
m_height = rect.height();
m_width = rect.width();
setCenterPoint(rect.center());
m_dirtyBits |= QSGNode::DirtyGeometry;
}
void GaugeNode::setCenterPoint(const QPointF ¢er)
{
m_center_x = center.x();
m_center_y = center.y();
}
void GaugeNode::setLeftToRight(const bool <r)
{
if (m_lefttoright == ltr)
return;
m_lefttoright = ltr;
m_dirtyBits |= QSGNode::DirtyMaterial;
}
void GaugeNode::drawGeometryTexturePoint2D()
{
QSGGeometry::TexturedPoint2D *vertices = m_geometry.vertexDataAsTexturedPoint2D();
double current_angle_rad = 0.0;
double currentRadius = m_radius;
double d_arc_point_x = m_center_x + (currentRadius - m_fillWidth) * qCos(m_backCutRad);
double d_arc_point_y = m_center_y + (currentRadius - m_fillWidth) * qSin(m_backCutRad);
vertices[0].set(d_arc_point_x, d_arc_point_y,
d_arc_point_x / m_width, d_arc_point_y / m_height);
d_arc_point_x = m_center_x + currentRadius * qCos(m_backCutRad);
d_arc_point_y = m_center_y + currentRadius * qSin(m_backCutRad);
vertices[1].set(d_arc_point_x, d_arc_point_y,
d_arc_point_x / m_width, d_arc_point_y / m_height);
d_arc_point_x = 0;
d_arc_point_y = 0;
for (int i = 0; i < m_numVertices; ++i) {
current_angle_rad = m_backCutRad + i * m_arc_dist_per_vertices + m_arc_dist_per_vertices;
if (i % 2 == 0)
currentRadius -= m_fillWidth;
else
currentRadius += m_fillWidth;
d_arc_point_x = m_center_x + currentRadius * qCos(current_angle_rad);
d_arc_point_y = m_center_y + currentRadius * qSin(current_angle_rad);
vertices[i + 2].set(d_arc_point_x, d_arc_point_y,
d_arc_point_x / m_width, d_arc_point_y / m_height);
}
d_arc_point_x = m_center_x + (currentRadius - m_fillWidth) * qCos(current_angle_rad);
d_arc_point_y = m_center_y + (currentRadius - m_fillWidth) * qSin(current_angle_rad);
vertices[m_numVertices + 2].set(d_arc_point_x, d_arc_point_y,
d_arc_point_x / m_width, d_arc_point_y / m_height);
}
void GaugeNode::drawMaterial()
{
static_cast<QSGFlatColorMaterial *>(m_material)->setColor(m_color);
}
void GaugeNode::draw()
{
if (m_dirtyBits == 0)
return;
if (m_dirtyBits.testFlag(QSGNode::DirtyGeometry))
drawGeometryTexturePoint2D();
if (m_dirtyBits.testFlag(QSGNode::DirtyMaterial))
drawMaterial();
markDirty(m_dirtyBits);
m_dirtyBits = DirtyState();
}
//Could be used to optimize vertices if only geometry is changed
void GaugeNode::drawGeometry()
{
QSGGeometry::Point2D *vertices = m_geometry.vertexDataAsPoint2D();
double d_arc_point_x = 0.0;
double d_arc_point_y = 0.0;
double current_angle_rad = 0.0;
double currentRadius = m_radius;
vertices[0].set(m_center_x + (currentRadius - m_fillWidth) * qCos(m_backCutRad), m_center_y
+ (currentRadius - m_fillWidth) * qSin(m_backCutRad));
vertices[1].set(m_center_x + currentRadius * qCos(m_backCutRad), m_center_y
+ currentRadius * qSin(m_backCutRad));
for (int i = 0; i < m_numVertices; ++i) {
current_angle_rad = m_backCutRad + i * m_arc_dist_per_vertices + m_arc_dist_per_vertices;
if (i % 2 == 0)
currentRadius -= m_fillWidth;
else
currentRadius += m_fillWidth;
d_arc_point_x = m_center_x + currentRadius * qCos(current_angle_rad);
d_arc_point_y = m_center_y + currentRadius * qSin(current_angle_rad);
vertices[i + 2].set(d_arc_point_x, d_arc_point_y);
}
vertices[m_numVertices + 2].set(m_center_x + (currentRadius - m_fillWidth)
* qCos(current_angle_rad), m_center_y
+ (currentRadius - m_fillWidth) * qSin(current_angle_rad));
markDirty(QSGNode::DirtyGeometry | QSGNode::DirtyMaterial);
}
void GaugeNode::initGeometry()
{
m_geometry.setLineWidth(1);
if (m_doNotFill)
m_geometry.setDrawingMode(QSGGeometry::DrawLineStrip);
else
m_geometry.setDrawingMode(QSGGeometry::DrawTriangleStrip);
setGeometry(&m_geometry);
QSGFlatColorMaterial *material = new QSGFlatColorMaterial;
material->setColor(m_color);
m_material = static_cast<QSGMaterial *>(material);
setMaterial(m_material);
}