We have accurate panel hit approximation based on trad RM
This commit is contained in:
135
PanelsPanel.cpp
135
PanelsPanel.cpp
@@ -57,12 +57,53 @@ void PanelsPanel::reset()
|
|||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a circle radius multiplier (0.0-1.0) based on 3 power tiers
|
|
||||||
static double bubbleScale(int power)
|
static double bubbleScale(int power)
|
||||||
{
|
{
|
||||||
if (power < 50) return 0.18; // small
|
if (power < 150) return 0.20;
|
||||||
if (power < 100) return 0.30; // medium
|
if (power < 500) return 0.40;
|
||||||
return 0.85; // large
|
return 0.80;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw a radial-gradient bubble at bCentre with radius circR
|
||||||
|
static void drawBubble(QPainter &p, const QPointF &bCentre, double circR,
|
||||||
|
bool isHighest, int power)
|
||||||
|
{
|
||||||
|
const QRectF circRect(bCentre.x() - circR, bCentre.y() - circR,
|
||||||
|
circR * 2, circR * 2);
|
||||||
|
|
||||||
|
// Drop shadow
|
||||||
|
p.setBrush(QColor(0, 0, 0, 55));
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.drawEllipse(circRect.adjusted(2, 3, 2, 3));
|
||||||
|
|
||||||
|
// Colour scheme: red = highest, orange/amber = others
|
||||||
|
QColor bright, dark, rim;
|
||||||
|
if (isHighest) {
|
||||||
|
bright = QColor(255, 100, 100);
|
||||||
|
dark = QColor(160, 10, 10);
|
||||||
|
rim = QColor(255, 200, 200);
|
||||||
|
} else {
|
||||||
|
bright = QColor(255, 210, 60);
|
||||||
|
dark = QColor(200, 100, 0);
|
||||||
|
rim = QColor(255, 240, 180);
|
||||||
|
}
|
||||||
|
|
||||||
|
QRadialGradient grad(bCentre, circR,
|
||||||
|
QPointF(bCentre.x() - circR * 0.3,
|
||||||
|
bCentre.y() - circR * 0.3));
|
||||||
|
grad.setColorAt(0.0, bright);
|
||||||
|
grad.setColorAt(1.0, dark);
|
||||||
|
p.setBrush(grad);
|
||||||
|
p.setPen(QPen(rim, 1.5));
|
||||||
|
p.drawEllipse(circRect);
|
||||||
|
|
||||||
|
// Power text
|
||||||
|
QFont pf = p.font();
|
||||||
|
pf.setBold(true);
|
||||||
|
pf.setPointSize(qMax(5, qMin(11, static_cast<int>(circR * 0.68))));
|
||||||
|
p.setFont(pf);
|
||||||
|
p.setPen(Qt::white);
|
||||||
|
p.drawText(circRect, Qt::AlignCenter, QString::number(power));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PanelsPanel::paintEvent(QPaintEvent *)
|
void PanelsPanel::paintEvent(QPaintEvent *)
|
||||||
@@ -79,6 +120,7 @@ void PanelsPanel::paintEvent(QPaintEvent *)
|
|||||||
const double cy = drawArea.center().y();
|
const double cy = drawArea.center().y();
|
||||||
const double outerR = side / 2.0;
|
const double outerR = side / 2.0;
|
||||||
const double innerR = outerR * 0.44;
|
const double innerR = outerR * 0.44;
|
||||||
|
const double bandW = outerR - innerR;
|
||||||
|
|
||||||
const QRectF outerRect(cx - outerR, cy - outerR, side, side);
|
const QRectF outerRect(cx - outerR, cy - outerR, side, side);
|
||||||
const QRectF innerRect(cx - innerR, cy - innerR, innerR * 2, innerR * 2);
|
const QRectF innerRect(cx - innerR, cy - innerR, innerR * 2, innerR * 2);
|
||||||
@@ -86,19 +128,28 @@ void PanelsPanel::paintEvent(QPaintEvent *)
|
|||||||
const double gapDeg = (m_count > 1) ? 3.0 : 0.0;
|
const double gapDeg = (m_count > 1) ? 3.0 : 0.0;
|
||||||
const double segSpan = (360.0 - m_count * gapDeg) / m_count;
|
const double segSpan = (360.0 - m_count * gapDeg) / m_count;
|
||||||
|
|
||||||
// Max bubble radius constrained to fit inside the segment band
|
const double maxCircR = qMin(
|
||||||
const double maxCircR = qMin((outerR - innerR) * 0.48,
|
bandW * 0.46,
|
||||||
(outerR + innerR) / 2.0 * qSin(qDegreesToRadians(segSpan / 2.0)) * 0.88);
|
outerR * qSin(qDegreesToRadians(segSpan / 2.0)) * 0.82
|
||||||
|
);
|
||||||
|
|
||||||
|
// Find the highest-power panel index among active hits
|
||||||
|
int topIndex = -1;
|
||||||
|
int topPower = -1;
|
||||||
|
for (auto it = m_hits.cbegin(); it != m_hits.cend(); ++it) {
|
||||||
|
if (it.value() > topPower) { topPower = it.value(); topIndex = it.key(); }
|
||||||
|
}
|
||||||
|
|
||||||
static const QColor kDefault(100, 140, 180);
|
static const QColor kDefault(100, 140, 180);
|
||||||
static const QColor kHit(220, 40, 40);
|
static const QColor kHit(200, 50, 50);
|
||||||
|
|
||||||
for (int i = 0; i < m_count; ++i) {
|
for (int i = 0; i < m_count; ++i) {
|
||||||
const bool isHit = m_hits.contains(i);
|
const bool isHit = m_hits.contains(i);
|
||||||
const double startAngle = 90.0 - i * (segSpan + gapDeg);
|
const double startAngle = 90.0 - i * (segSpan + gapDeg);
|
||||||
const double sweep = -segSpan;
|
const double sweep = -segSpan;
|
||||||
|
const double midAngleRad = qDegreesToRadians(startAngle + sweep / 2.0);
|
||||||
|
|
||||||
// --- Segment path ---
|
// --- Segment ---
|
||||||
QPainterPath path;
|
QPainterPath path;
|
||||||
path.arcMoveTo(outerRect, startAngle);
|
path.arcMoveTo(outerRect, startAngle);
|
||||||
path.arcTo(outerRect, startAngle, sweep);
|
path.arcTo(outerRect, startAngle, sweep);
|
||||||
@@ -109,56 +160,36 @@ void PanelsPanel::paintEvent(QPaintEvent *)
|
|||||||
p.setPen(QPen(Qt::white, isHit ? 3 : 2));
|
p.setPen(QPen(Qt::white, isHit ? 3 : 2));
|
||||||
p.drawPath(path);
|
p.drawPath(path);
|
||||||
|
|
||||||
// --- Midpoint for label / hit circle ---
|
// --- Panel index label at midpoint ---
|
||||||
const double midAngle = startAngle + sweep / 2.0;
|
const double midR = (outerR + innerR) / 2.0;
|
||||||
const double midAngleRad = qDegreesToRadians(midAngle);
|
const QPointF labelPt(cx + midR * qCos(midAngleRad),
|
||||||
const double midR = (outerR + innerR) / 2.0;
|
cy - midR * qSin(midAngleRad));
|
||||||
const QPointF mid(cx + midR * qCos(midAngleRad),
|
{
|
||||||
cy - midR * qSin(midAngleRad));
|
|
||||||
|
|
||||||
if (isHit) {
|
|
||||||
const int power = m_hits[i];
|
|
||||||
const double circR = maxCircR * bubbleScale(power);
|
|
||||||
|
|
||||||
// Tier label for legend (small/medium/large)
|
|
||||||
// Glow halo
|
|
||||||
p.setBrush(Qt::NoBrush);
|
|
||||||
p.setPen(QPen(QColor(255, 80, 80, 110), 5));
|
|
||||||
p.drawPath(path);
|
|
||||||
|
|
||||||
// Drop shadow
|
|
||||||
const QRectF circRect(mid.x() - circR, mid.y() - circR, circR * 2, circR * 2);
|
|
||||||
p.setBrush(QColor(0, 0, 0, 55));
|
|
||||||
p.setPen(Qt::NoPen);
|
|
||||||
p.drawEllipse(circRect.adjusted(2, 3, 2, 3));
|
|
||||||
|
|
||||||
// Radial gradient fill
|
|
||||||
QRadialGradient grad(mid, circR,
|
|
||||||
QPointF(mid.x() - circR * 0.3, mid.y() - circR * 0.3));
|
|
||||||
grad.setColorAt(0.0, QColor(255, 100, 100));
|
|
||||||
grad.setColorAt(1.0, QColor(160, 10, 10));
|
|
||||||
p.setBrush(grad);
|
|
||||||
p.setPen(QPen(QColor(255, 200, 200), 1.5));
|
|
||||||
p.drawEllipse(circRect);
|
|
||||||
|
|
||||||
// Power value text — scale font to circle size
|
|
||||||
QFont pf = p.font();
|
|
||||||
pf.setBold(true);
|
|
||||||
pf.setPointSize(qMax(6, qMin(12, static_cast<int>(circR * 0.68))));
|
|
||||||
p.setFont(pf);
|
|
||||||
p.setPen(Qt::white);
|
|
||||||
p.drawText(circRect, Qt::AlignCenter, QString::number(power));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Normal index label
|
|
||||||
QFont font = p.font();
|
QFont font = p.font();
|
||||||
font.setBold(true);
|
font.setBold(true);
|
||||||
font.setPointSize(qMax(7, qMin(12, static_cast<int>(outerR / (m_count * 0.55 + 2)))));
|
font.setPointSize(qMax(7, qMin(12, static_cast<int>(outerR / (m_count * 0.55 + 2)))));
|
||||||
p.setFont(font);
|
p.setFont(font);
|
||||||
p.setPen(Qt::white);
|
p.setPen(Qt::white);
|
||||||
p.drawText(QRectF(mid.x() - 22, mid.y() - 11, 44, 22),
|
p.drawText(QRectF(labelPt.x() - 22, labelPt.y() - 11, 44, 22),
|
||||||
Qt::AlignCenter, QString::number(i));
|
Qt::AlignCenter, QString::number(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isHit) {
|
||||||
|
const int power = m_hits[i];
|
||||||
|
const bool isTop = (i == topIndex);
|
||||||
|
const double circR = maxCircR * bubbleScale(power);
|
||||||
|
const double bCentR = outerR - circR - 2.0;
|
||||||
|
const QPointF bCentre(cx + bCentR * qCos(midAngleRad),
|
||||||
|
cy - bCentR * qSin(midAngleRad));
|
||||||
|
|
||||||
|
// Glow halo on segment
|
||||||
|
p.setBrush(Qt::NoBrush);
|
||||||
|
p.setPen(QPen(isTop ? QColor(255, 80, 80, 120)
|
||||||
|
: QColor(255, 200, 50, 100), 5));
|
||||||
|
p.drawPath(path);
|
||||||
|
|
||||||
|
drawBubble(p, bCentre, circR, isTop, power);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Centre hole: total count ---
|
// --- Centre hole: total count ---
|
||||||
|
|||||||
Reference in New Issue
Block a user