* @brief Rebuilds the fill from the per-column envelopes: one O(points) accumulation * pass, then O(item width) vertex emission, so geometry cost is independent of * data density. The per-vertex alpha ramps from kMaxAlpha at the largest * per-sign deviation down to kMinAlpha at the baseline, anchoring the gradient * to the data instead of the axis range. */
| 451 | * to the data instead of the axis range. |
| 452 | */ |
| 453 | QSGNode* Widgets::PlotAreaFill::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData* data) |
| 454 | { |
| 455 | Q_UNUSED(data) |
| 456 | |
| 457 | const double w = width(); |
| 458 | const double h = height(); |
| 459 | const double xRange = m_xMax - m_xMin; |
| 460 | const double yRange = m_yMax - m_yMin; |
| 461 | |
| 462 | const QList<QPointF> points = m_source ? m_source->points() : QList<QPointF>(); |
| 463 | |
| 464 | const bool valid = |
| 465 | points.size() >= 2 && std::isfinite(m_baseline) && xRange > 0 && yRange > 0 && w > 0 && h > 0; |
| 466 | if (!valid) { |
| 467 | delete oldNode; |
| 468 | return nullptr; |
| 469 | } |
| 470 | |
| 471 | const int cols = std::min(kMaxColumns, static_cast<int>(std::ceil(w))); |
| 472 | accumulateColumns(points, cols, w); |
| 473 | |
| 474 | double refPositive = 0; |
| 475 | double refNegative = 0; |
| 476 | const int filled = scanColumns(refPositive, refNegative); |
| 477 | if (filled == 0) { |
| 478 | delete oldNode; |
| 479 | return nullptr; |
| 480 | } |
| 481 | |
| 482 | auto* node = static_cast<QSGGeometryNode*>(oldNode); |
| 483 | if (!node) { |
| 484 | node = new QSGGeometryNode; |
| 485 | auto* geometry = new QSGGeometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), 0); |
| 486 | geometry->setDrawingMode(QSGGeometry::DrawTriangleStrip); |
| 487 | node->setGeometry(geometry); |
| 488 | node->setFlag(QSGNode::OwnsGeometry); |
| 489 | node->setMaterial(new QSGVertexColorMaterial); |
| 490 | node->setFlag(QSGNode::OwnsMaterial); |
| 491 | } |
| 492 | |
| 493 | const int vertexCount = 8 * filled - 2; |
| 494 | auto* geometry = node->geometry(); |
| 495 | Q_ASSERT(geometry != nullptr); |
| 496 | if (geometry->vertexCount() != vertexCount) |
| 497 | geometry->allocate(vertexCount); |
| 498 | |
| 499 | emitColumns(geometry->vertexDataAsColoredPoint2D(), vertexCount, w, h, refPositive, refNegative); |
| 500 | |
| 501 | node->markDirty(QSGNode::DirtyGeometry); |
| 502 | return node; |
| 503 | } |