#include "wavylinerenderer.hpp" #include "wavyline.hpp" #include namespace ZShell::controls { void WavyLineRenderer::synchronizeData(QCanvasPainterItem* item) { auto* wavyLine = static_cast(item); m_lineWidth = wavyLine->m_lineWidth; m_amplitudeMultiplier = wavyLine->m_amplitudeMultiplier; m_frequency = wavyLine->m_frequency; m_startX = wavyLine->m_startX; m_fullLength = wavyLine->m_fullLength; m_color = wavyLine->m_color; m_waveProgress = wavyLine->m_waveProgress; m_pathType = wavyLine->m_pathType; m_startAngle = wavyLine->m_startAngle; m_fullAngle = wavyLine->m_fullAngle; m_radius = wavyLine->m_radius; m_value = wavyLine->m_value; } void WavyLineRenderer::paint(QCanvasPainter* painter) { painter->clearRect(0, 0, width(), height()); painter->setStrokeStyle(m_color); painter->setLineWidth(m_lineWidth); painter->setLineCap(QCanvasPainter::LineCap::Round); if (m_pathType == WavyLine::Arc) { paintArc(painter); } else { paintLinear(painter); } } void WavyLineRenderer::paintLinear(QCanvasPainter* painter) { const auto amplitude = m_lineWidth * m_amplitudeMultiplier; const auto phase = m_waveProgress * 2 * M_PI; const auto centerY = height() / 2; const auto len = m_fullLength > 0 ? m_fullLength : 1; const auto start = m_lineWidth / 2.0; const auto fullEnd = width() - m_lineWidth / 2.0; const auto drawEnd = start + (fullEnd - start) * m_value; painter->beginPath(); bool first = true; for (int x = m_lineWidth / 2; x <= drawEnd; ++x) { const auto theta = m_frequency * 2 * M_PI * (x + m_startX) / len + phase; const auto waveY = centerY + amplitude * qSin(theta); if (first) { painter->moveTo(x, waveY); first = false; } else { painter->lineTo(x, waveY); } } painter->stroke(); } void WavyLineRenderer::paintArc(QCanvasPainter* painter) { if (m_fullAngle <= 0) { return; } const auto startAngleRad = m_startAngle * M_PI / 180.0; const auto fullAngleRad = m_fullAngle * M_PI / 180.0; const auto amplitude = m_lineWidth * m_amplitudeMultiplier; const auto cx = width() / 2.0; const auto cy = height() / 2.0; const auto radius = m_radius > 0 ? m_radius : (qMin(width(), height()) - m_lineWidth - 2 * amplitude) / 2.0; if (radius <= 0) { return; } const auto phase = m_waveProgress * 2 * M_PI; const auto arcLen = radius * fullAngleRad; const auto len = m_fullLength > 0 ? m_fullLength : arcLen; const auto drawAngleRad = fullAngleRad * m_value; if (drawAngleRad <= 0) { return; } const auto N = qMax(64, qCeil(radius * drawAngleRad)); const auto dTheta = drawAngleRad / N; painter->beginPath(); for (int i = 0; i <= N; ++i) { const auto theta = startAngleRad + i * dTheta; const auto s = i * dTheta * radius; const auto phi = m_frequency * 2 * M_PI * (s + m_startX) / len + phase; const auto r = radius + amplitude * qSin(phi); const auto px = cx + r * qCos(theta); const auto py = cy + r * qSin(theta); if (i == 0) { painter->moveTo(px, py); } else { painter->lineTo(px, py); } } painter->stroke(); } } // namespace ZShell::controls