#include "blobgroup.hpp" #include "blobinvertedrect.hpp" #include "blobshape.hpp" #include namespace { constexpr int k_pumpMs = 16; } // namespace BlobGroup::BlobGroup(QObject* parent) : QObject(parent) { m_physicsPump.setInterval(k_pumpMs); m_physicsPump.setTimerType(Qt::CoarseTimer); connect(&m_physicsPump, &QTimer::timeout, this, &BlobGroup::pumpPhysics); } BlobGroup::~BlobGroup() { for (auto* shape : std::as_const(m_shapes)) shape->m_group = nullptr; if (m_invertedRect) static_cast(m_invertedRect)->m_group = nullptr; } void BlobGroup::setSmoothing(qreal s) { if (s < 0.5) s = 0.5; if (qFuzzyCompare(m_smoothing, s)) return; m_smoothing = s; emit smoothingChanged(); markDirty(); } void BlobGroup::setColor(const QColor& c) { if (m_color == c) return; m_color = c; emit colorChanged(); markDirty(); } void BlobGroup::setCornerFill(bool e) { if (m_cornerFill == e) return; m_cornerFill = e; emit cornerFillChanged(); markDirty(); } void BlobGroup::addShape(BlobShape* shape) { if (!shape || m_shapes.contains(shape)) return; m_shapes.append(shape); markDirty(); } void BlobGroup::removeShape(BlobShape* shape) { m_shapes.removeOne(shape); markDirty(); } void BlobGroup::setInvertedRect(BlobInvertedRect* rect) { if (m_invertedRect == rect) return; m_invertedRect = rect; markDirty(); } void BlobGroup::clearInvertedRect(BlobInvertedRect* rect) { if (m_invertedRect != rect) return; m_invertedRect = nullptr; markDirty(); } void BlobGroup::markDirty() { m_physicsUpdated = false; for (auto* shape : std::as_const(m_shapes)) { shape->polish(); shape->update(); } if (m_invertedRect) { static_cast(m_invertedRect)->polish(); static_cast(m_invertedRect)->update(); } } void BlobGroup::markShapeDirty(BlobShape* source) { m_physicsUpdated = false; source->polish(); source->update(); const float pad = static_cast(m_smoothing) * 2.0f; const QRectF srcRect( static_cast(source->m_cachedPaddedX - pad), static_cast(source->m_cachedPaddedY - pad), static_cast(source->m_cachedPaddedW + pad * 2.0f), static_cast(source->m_cachedPaddedH + pad * 2.0f)); for (auto* shape : std::as_const(m_shapes)) { if (shape == source) continue; const QRectF otherRect( static_cast(shape->m_cachedPaddedX), static_cast(shape->m_cachedPaddedY), static_cast(shape->m_cachedPaddedW), static_cast(shape->m_cachedPaddedH)); if (srcRect.intersects(otherRect)) { shape->polish(); shape->update(); } } if (m_invertedRect && static_cast(m_invertedRect) != source) { static_cast(m_invertedRect)->polish(); static_cast(m_invertedRect)->update(); } } void BlobGroup::ensurePhysicsUpdated() { if (m_physicsUpdated) return; m_physicsUpdated = true; for (auto* shape : std::as_const(m_shapes)) { shape->updatePhysics(); if (shape->needsFrame()) { shape->polish(); shape->update(); } } } void BlobGroup::requestPhysics() { if (!m_physicsPump.isActive()) m_physicsPump.start(); } void BlobGroup::pumpPhysics() { for (auto* shape : std::as_const(m_shapes)) shape->updatePhysics(); const bool anyMoving = std::any_of( m_shapes.cbegin(), m_shapes.cend(), [](const BlobShape* shape) { return shape->needsFrame(); }); if (!anyMoving) { m_physicsPump.stop(); return; } markDirty(); m_physicsUpdated = true; }