working towards gradients

This commit is contained in:
Uwe Rathmann 2024-06-04 13:26:49 +02:00
parent 36f088a263
commit bf7fe7c8f3
2 changed files with 69 additions and 79 deletions

View File

@ -103,7 +103,7 @@ ShadowedArc::ShadowedArc( QQuickItem* parent )
//setFillColor( Qt::darkRed );
const QskGradient gradient( Qt::darkRed, Qt::darkBlue );
const QskGradient gradient( Qt::darkRed, Qt::darkYellow );
setGradientHint( Arc, gradient );
setBorderWidth( 0 );

View File

@ -7,6 +7,7 @@
#include "QskArcMetrics.h"
#include "QskGradient.h"
#include "QskVertex.h"
#include "QskBoxColorMap.h"
#include <qsggeometry.h>
#include <qdebug.h>
@ -40,23 +41,25 @@ namespace
inline void operator++() { increment(); }
void increment();
inline double cos() const { return m_cos; }
inline double sin() const { return m_sin; }
inline qreal cos() const { return m_cos; }
inline qreal sin() const { return m_sin; }
inline int step() const { return m_stepIndex; }
inline int stepCount() const { return m_stepCount; }
inline bool isDone() const { return m_stepIndex >= m_stepCount; }
inline qreal progress() const { return qreal( m_stepIndex ) / m_stepCount; }
private:
double m_cos;
double m_sin;
qreal m_cos;
qreal m_sin;
int m_stepIndex;
int m_stepCount;
const double m_radians1;
const double m_radians2;
const double m_radiansStep;
const qreal m_radians1;
const qreal m_radians2;
const qreal m_radiansStep;
};
inline AngleIterator::AngleIterator( qreal radians1, qreal radians2, int stepCount )
@ -95,16 +98,17 @@ namespace
class EllipseStroker
{
public:
EllipseStroker( const QRectF&, const QskArcMetrics&, qreal borderWidth );
EllipseStroker( const QRectF&, const QskArcMetrics&,
qreal borderWidth, const QskGradient& );
int fillCount() const;
int borderCount() const;
int setBorderLines( QskVertex::ColoredLine*, const QskVertex::Color ) const;
int setFillLines( QskVertex::ColoredLine*, const QskVertex::Color ) const;
int setFillLines( QskVertex::ColoredLine* ) const;
private:
int arcLineCount( qreal radians ) const;
int arcLineCount() const;
// radius
const qreal m_rx;
@ -116,50 +120,39 @@ namespace
const qreal m_radians1;
const qreal m_radians2;
const bool m_inverted;
const qreal m_extent;
const QskGradient& m_gradient;
};
EllipseStroker::EllipseStroker( const QRectF& rect,
const QskArcMetrics& m, qreal borderWidth )
const QskArcMetrics& m, qreal borderWidth, const QskGradient& gradient )
: m_rx( 0.5 * rect.width() )
, m_ry( 0.5 * rect.height() )
, m_cx( rect.x() + m_rx )
, m_cy( rect.y() + m_ry )
, m_radians1( qDegreesToRadians( qMin( m.startAngle(), m.endAngle() ) ) )
, m_radians2( qDegreesToRadians( qMax( m.startAngle(), m.endAngle() ) ) )
, m_inverted( m.spanAngle() >= 0.0 )
, m_radians1( qDegreesToRadians( m.startAngle() ) )
, m_radians2( qDegreesToRadians( m.endAngle() ) )
, m_extent( 0.5 * ( m.thickness() - borderWidth ) )
, m_gradient( gradient )
{
}
int EllipseStroker::fillCount() const
{
int n = 0;
for ( auto r = qFloor( m_radians1 / M_PI_2 ) * M_PI_2;
r < m_radians2; r += M_PI_2 )
{
const auto r1 = qMax( r, m_radians1 );
const auto r2 = qMin( r + M_PI_2, m_radians2 );
n += arcLineCount( r2 - r1 );
return arcLineCount();
}
return n;
}
int EllipseStroker::arcLineCount( qreal radians ) const
int EllipseStroker::arcLineCount() const
{
Q_ASSERT( radians >= 0.0 );
// not very sophisticated - TODO ...
const auto radius = qMax( m_rx, m_ry );
const auto radians = qAbs( m_radians2 - m_radians1 );
const auto count = qCeil( ( radius * radians ) / 3.0 );
return qBound( 3, count, 40 );
return qBound( 3, count, 160 );
}
int EllipseStroker::borderCount() const
@ -176,8 +169,7 @@ namespace
return 0;
}
int EllipseStroker::setFillLines( QskVertex::ColoredLine* lines,
const QskVertex::Color color ) const
int EllipseStroker::setFillLines( QskVertex::ColoredLine* lines ) const
{
const auto w = m_rx - m_extent;
const auto h = m_ry - m_extent;
@ -185,23 +177,29 @@ namespace
auto l = lines;
for ( auto r = qFloor( m_radians1 / M_PI_2 ) * M_PI_2;
r < m_radians2; r += M_PI_2 )
const QskVertex::Color color1 = m_gradient.rgbStart();
const QskVertex::Color color2 = m_gradient.rgbEnd();
for ( AngleIterator it( m_radians1, m_radians2, arcLineCount() ); !it.isDone(); ++it )
{
const auto r1 = qMax( r, m_radians1 );
const auto r2 = qMin( r + M_PI_2, m_radians2 );
const auto lineCount = arcLineCount( r2 - r1 );
for ( AngleIterator it( r1, r2, lineCount ); !it.isDone(); ++it )
{
qreal dx, dy;
/*
The inner/outer points are found by shifting along the
normal vector of the tangent at the ellipse point.
The inner/outer points are found by shifting orthogonally along the
ellipse tangent:
m = w / h * tan( angle )
y = m * x;
x² + y² = dt
=> x = dt / sqrt( 1.0 + m² );
Note: the angle of the orthogonal vector could
also be found ( first quadrant ) by:
atan2( tan( angle ), h / w );
*/
qreal dx, dy;
if ( qFuzzyIsNull( it.cos() ) )
{
dx = 0.0;
@ -209,15 +207,6 @@ namespace
}
else
{
// expanding orthogonally to the ellipse tangent
/*
m = w / h * tan( angle )
y = m * x;
x² + y² = dt
=> x = dt / sqrt( 1.0 + m² );
*/
const qreal m = aspectRatio * ( it.sin() / it.cos() );
const qreal t = m_extent / qSqrt( 1.0 + m * m );
@ -228,9 +217,12 @@ namespace
const auto x = m_cx + w * it.cos();
const auto y = m_cy - h * it.sin();
auto color = color1;
if ( color1 != color2 )
color = color.interpolatedTo( color2, it.progress() );
l++->setLine( x + dx, y - dy, x - dx, y + dy, color );
}
}
return l - lines;
}
@ -250,16 +242,14 @@ void QskArcRenderer::renderFillGeometry( const QRectF& rect,
{
geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip );
EllipseStroker stroker( rect, metrics, borderWidth );
EllipseStroker stroker( rect, metrics, borderWidth, gradient );
const auto lineCount = stroker.fillCount();
const auto lines = qskAllocateColoredLines( geometry, lineCount );
if ( lines )
{
const QskVertex::Color color = gradient.rgbStart();
const auto effectiveCount = stroker.setFillLines( lines, color );
const auto effectiveCount = stroker.setFillLines( lines );
if ( lineCount != effectiveCount )
{
qWarning() << lineCount << effectiveCount;
@ -272,7 +262,7 @@ void QskArcRenderer::renderBorder( const QRectF& rect, const QskArcMetrics& metr
{
geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip );
EllipseStroker stroker( rect, metrics, borderWidth );
EllipseStroker stroker( rect, metrics, borderWidth, QskGradient() );
const auto lineCount = stroker.borderCount();