QskArcRenderer: orthogonal mode completed, radial mode almost completed

( closing lines are missing )
This commit is contained in:
Uwe Rathmann 2024-07-18 18:13:28 +02:00
parent 55b3f0c556
commit ca38a1e46a
3 changed files with 130 additions and 76 deletions

View File

@ -60,9 +60,9 @@ namespace
setStartAngle( 45.0 ); setStartAngle( 45.0 );
setSpanAngle( 270.0 ); setSpanAngle( 270.0 );
setThickness( 10.0 ); setThickness( 30.0 );
setBorderWidth( 2.0 ); setBorderWidth( 5.0 );
setBorderColor( QColor( 0, 0, 0, 150 ) ); setBorderColor( QColor( 0, 0, 0, 150 ) );
#if 0 #if 0

View File

@ -99,7 +99,7 @@ ShadowedArc::ShadowedArc( QQuickItem* parent )
// initial settings // initial settings
setArcMetrics( { 0.0, 360.0, 1.0, Qt::RelativeSize } ); setArcMetrics( { 0.0, 360.0, 1.0, Qt::AbsoluteSize } );
setFillGradient( Qt::darkRed ); setFillGradient( Qt::darkRed );

View File

@ -31,10 +31,13 @@ namespace
class OrthogonalStroker class OrthogonalStroker
{ {
public: public:
OrthogonalStroker( const QRectF& rect, qreal length ) OrthogonalStroker( const QRectF& rect, qreal thickness, qreal border )
: m_l2( 0.5 * length ) : m_thickness( thickness )
, m_rx( 0.5 * ( rect.width() - length ) ) , m_border( border )
, m_ry( 0.5 * ( rect.height() - length ) ) , m_rx( 0.5 * ( rect.width() - m_thickness ) )
, m_ry( 0.5 * ( rect.height() - m_thickness ) )
, m_offsetOut( 0.5 * m_thickness )
, m_offsetIn( m_offsetOut - border )
, m_aspectRatio( m_rx / m_ry ) , m_aspectRatio( m_rx / m_ry )
, m_cx( rect.x() + 0.5 * rect.width() ) , m_cx( rect.x() + 0.5 * rect.width() )
, m_cy( rect.y() + 0.5 * rect.height() ) , m_cy( rect.y() + 0.5 * rect.height() )
@ -49,11 +52,46 @@ namespace
const auto x = m_cx + m_rx * cos; const auto x = m_cx + m_rx * cos;
const auto y = m_cy - m_ry * sin; const auto y = m_cy - m_ry * sin;
const auto v = normalVector( cos, sin ) * m_l2;
const auto v = normalVector( cos, sin ) * m_offsetIn;
line.setLine( x + v.x(), y - v.y(), x - v.x(), y + v.y(), color ); line.setLine( x + v.x(), y - v.y(), x - v.x(), y + v.y(), color );
} }
inline void setBorderLines( const qreal radians,
const QskVertex::Color color, QskVertex::ColoredLine& outer,
QskVertex::ColoredLine& inner ) const
{
const auto cos = qFastCos( radians );
const auto sin = qFastSin( radians );
const auto x = m_cx + m_rx * cos;
const auto y = m_cy - m_ry * sin;
const auto v = normalVector( cos, sin );
const auto v1 = v * m_offsetOut;
const auto v2 = v * m_offsetIn;
outer.setLine( x + v1.x(), y - v1.y(), x + v2.x(), y - v2.y(), color );
inner.setLine( x - v1.x(), y + v1.y(), x - v2.x(), y + v2.y(), color );
}
inline void setClosingBorderLines( const QSGGeometry::ColoredPoint2D& pos,
QskVertex::ColoredLine* lines, qreal sign, const QskVertex::Color color ) const
{
const auto& l0 = lines[0];
const auto dx = sign * l0.dy();
const auto dy = sign * l0.dx();
lines[-3].setLine( pos.x, pos.y, pos.x, pos.y, color );
lines[-2].setLine( pos.x + dx, pos.y - dy, pos.x, pos.y, color );
lines[-1].setLine( l0.x1() + dx, l0.y1() - dy, l0.x1(), l0.y1(), color );
}
private:
inline QPointF normalVector( const qreal radians ) const inline QPointF normalVector( const qreal radians ) const
{ {
return normalVector( qFastCos( radians ), qFastSin( radians ) ); return normalVector( qFastCos( radians ), qFastSin( radians ) );
@ -87,45 +125,34 @@ namespace
return { dx, m * dx }; return { dx, m * dx };
} }
inline void setBorderLines( const qreal radians, qreal border, const qreal m_thickness;
const QskVertex::Color color, QskVertex::ColoredLine& outer, const qreal m_border;
QskVertex::ColoredLine& inner ) const
{
const auto cos = qFastCos( radians );
const auto sin = qFastSin( radians );
const auto x = m_cx + m_rx * cos; // radii t the middle of the arc
const auto y = m_cy - m_ry * sin; const qreal m_rx, m_ry;
const auto v = normalVector( cos, sin );
const auto v1 = v * m_l2; // distances between the middle and inner/outer of the border
const auto v2 = v * ( m_l2 - border ); const qreal m_offsetOut, m_offsetIn;
outer.setLine( x + v1.x(), y - v1.y(), x + v2.x(), y - v2.y(), color );
inner.setLine( x - v1.x(), y + v1.y(), x - v2.x(), y + v2.y(), color );
}
const qreal m_l2; // half of the length
// radius
const qreal m_rx;
const qreal m_ry;
const qreal m_aspectRatio; // m_rx / m_ry const qreal m_aspectRatio; // m_rx / m_ry
// center // center
const qreal m_cx; const qreal m_cx, m_cy;
const qreal m_cy;
}; };
class RadialStroker class RadialStroker
{ {
public: public:
RadialStroker( const QRectF& rect, qreal length ) RadialStroker( const QRectF& rect, qreal thickness, qreal border )
: m_length( length ) : m_inner( thickness - 2 * border )
, m_rx1( 0.5 * rect.width() ) , m_rx1( 0.5 * rect.width() )
, m_ry1( 0.5 * rect.height() ) , m_ry1( 0.5 * rect.height() )
, m_rx2( m_rx1 - ( ( m_rx1 > m_ry1 ) ? length * m_rx1 / m_ry1 : length ) ) , m_rx2( m_rx1 - border )
, m_ry2( m_ry1 - ( ( m_ry1 > m_rx1 ) ? length * m_ry1 / m_rx1 : length ) ) , m_ry2( m_ry1 - border )
, m_rx3( m_rx2 - ( ( m_rx1 > m_ry1 ) ? m_inner * m_rx1 / m_ry1 : m_inner ) )
, m_ry3( m_ry2 - ( ( m_rx1 < m_ry1 ) ? m_inner * m_ry1 / m_rx1 : m_inner ) )
, m_rx4( m_rx3 - border )
, m_ry4( m_ry3 - border )
, m_cx( rect.x() + m_rx1 ) , m_cx( rect.x() + m_rx1 )
, m_cy( rect.y() + m_ry1 ) , m_cy( rect.y() + m_ry1 )
{ {
@ -137,24 +164,50 @@ namespace
const auto cos = qFastCos( radians ); const auto cos = qFastCos( radians );
const auto sin = qFastSin( radians ); const auto sin = qFastSin( radians );
line.setLine( m_cx + m_rx1 * cos, m_cy - m_ry1 * sin, line.setLine( m_cx + m_rx2 * cos, m_cy - m_ry2 * sin,
m_cx + m_rx3 * cos, m_cy - m_ry3 * sin, color );
}
inline void setBorderLines( const qreal radians,
const QskVertex::Color color, QskVertex::ColoredLine& outer,
QskVertex::ColoredLine& inner ) const
{
const auto cos = qFastCos( radians );
const auto sin = qFastSin( radians );
outer.setLine( m_cx + m_rx1 * cos, m_cy - m_ry1 * sin,
m_cx + m_rx2 * cos, m_cy - m_ry2 * sin, color ); m_cx + m_rx2 * cos, m_cy - m_ry2 * sin, color );
inner.setLine( m_cx + m_rx3 * cos, m_cy - m_ry3 * sin,
m_cx + m_rx4 * cos, m_cy - m_ry4 * sin, color );
}
inline void setClosingBorderLines( const QSGGeometry::ColoredPoint2D& pos,
QskVertex::ColoredLine* lines, qreal sign, const QskVertex::Color color ) const
{
// TODO ...
#if 1
Q_UNUSED( pos );
Q_UNUSED( sign );
const auto& l0 = lines[0];
const qreal dx = 0.0;
const qreal dy = 0.0;
lines[-3].setLine( l0.x1() + dx, l0.y1() - dy, l0.x1(), l0.y1(), color );
lines[-2].setLine( l0.x1() + dx, l0.y1() - dy, l0.x1(), l0.y1(), color );
lines[-1].setLine( l0.x1() + dx, l0.y1() - dy, l0.x1(), l0.y1(), color );
#endif
} }
private: private:
const qreal m_length; const qreal m_inner;
// outer radii // radii: out->in
const qreal m_rx1; const qreal m_rx1, m_ry1, m_rx2, m_ry2, m_rx3, m_ry3, m_rx4, m_ry4;
const qreal m_ry1;
// inner radii
const qreal m_rx2;
const qreal m_ry2;
// center point // center point
const qreal m_cx; const qreal m_cx, m_cy;
const qreal m_cy;
}; };
} }
@ -207,7 +260,7 @@ namespace
bool radial, const QskGradient& ); bool radial, const QskGradient& );
int lineCount() const; int lineCount() const;
int setLines( qreal length, QskVertex::ColoredLine* ) const; int setLines( qreal thickness, qreal border, QskVertex::ColoredLine* ) const;
private: private:
template< class LineStroker > template< class LineStroker >
@ -228,17 +281,17 @@ namespace
return arcLineCount() + m_gradient.stepCount() - 1; return arcLineCount() + m_gradient.stepCount() - 1;
} }
inline int FillStroker::setLines( inline int FillStroker::setLines( const qreal thickness,
const qreal length, QskVertex::ColoredLine* lines ) const const qreal border, QskVertex::ColoredLine* lines ) const
{ {
if ( m_radial ) if ( m_radial )
{ {
const RadialStroker lineStroker( m_rect, length ); const RadialStroker lineStroker( m_rect, thickness, border );
return renderLines( lineStroker, lines ); return renderLines( lineStroker, lines );
} }
else else
{ {
const OrthogonalStroker lineStroker( m_rect, length ); const OrthogonalStroker lineStroker( m_rect, thickness, border );
return renderLines( lineStroker, lines ); return renderLines( lineStroker, lines );
} }
} }
@ -292,11 +345,11 @@ namespace
bool radial, const QColor& color ); bool radial, const QColor& color );
int lineCount() const; int lineCount() const;
int setLines( qreal length, qreal border, QskVertex::ColoredLine* ) const; int setLines( qreal thickness, qreal border, QskVertex::ColoredLine* ) const;
private: private:
void setClosingLines( const QSGGeometry::ColoredPoint2D&, template< class LineStroker >
QskVertex::ColoredLine* ) const; int renderLines( const LineStroker&, QskVertex::ColoredLine* ) const;
const QskVertex::Color m_color; const QskVertex::Color m_color;
}; };
@ -317,7 +370,23 @@ namespace
return count; return count;
} }
int BorderStroker::setLines( qreal length, qreal border, int BorderStroker::setLines( const qreal thickness, const qreal border,
QskVertex::ColoredLine* lines ) const
{
if ( m_radial )
{
const RadialStroker stroker( m_rect, thickness, border );
return renderLines( stroker, lines );
}
else
{
const OrthogonalStroker stroker( m_rect, thickness, border );
return renderLines( stroker, lines );
}
}
template< class LineStroker >
inline int BorderStroker::renderLines( const LineStroker& stroker,
QskVertex::ColoredLine* lines ) const QskVertex::ColoredLine* lines ) const
{ {
const auto count = arcLineCount(); const auto count = arcLineCount();
@ -333,35 +402,22 @@ namespace
if ( !m_closed ) if ( !m_closed )
inner += 3; inner += 3;
OrthogonalStroker stroker( m_rect, length );
for ( int i = 0; i < count; i++ ) for ( int i = 0; i < count; i++ )
{ {
stroker.setBorderLines( m_radians1 + i * stepSize, stroker.setBorderLines( m_radians1 + i * stepSize,
border, m_color, outer[i], inner[count - 1 - i] ); m_color, outer[i], inner[count - 1 - i] );
} }
if ( !m_closed ) if ( !m_closed )
{ {
setClosingLines( inner[count - 1].p1, outer ); const auto sign = ( stepSize > 0.0 ) ? 1.0 : -1.0;
setClosingLines( outer[count - 1].p1, inner );
stroker.setClosingBorderLines( inner[count - 1].p1, outer, sign, m_color );
stroker.setClosingBorderLines( outer[count - 1].p1, inner, sign, m_color );
} }
return 2 * ( count + ( m_closed ? 0 : 3 ) ); return 2 * ( count + ( m_closed ? 0 : 3 ) );
} }
void BorderStroker::setClosingLines( const QSGGeometry::ColoredPoint2D& pos,
QskVertex::ColoredLine* lines ) const
{
const auto& l0 = lines[0];
const auto sign = ( m_radians1 <= m_radians2 ) ? 1.0 : -1.0;
const auto dx = sign * l0.dy();
const auto dy = sign * l0.dx();
lines[-3].setLine( pos.x, pos.y, pos.x, pos.y, m_color );
lines[-2].setLine( pos.x + dx, pos.y - dy, pos.x, pos.y, m_color );
lines[-1].setLine( l0.x1() + dx, l0.y1() - dy, l0.x1(), l0.y1(), m_color );
}
} }
bool QskArcRenderer::isGradientSupported( const QskGradient& gradient ) bool QskArcRenderer::isGradientSupported( const QskGradient& gradient )
@ -378,9 +434,7 @@ void QskArcRenderer::renderFillGeometry( const QRectF& rect,
{ {
geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip ); geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip );
const auto r = rect.adjusted( borderWidth, borderWidth, -borderWidth, -borderWidth ); FillStroker stroker( rect, metrics, radial, gradient );
FillStroker stroker( r, metrics, radial, gradient );
const auto lineCount = stroker.lineCount(); const auto lineCount = stroker.lineCount();
@ -389,7 +443,7 @@ void QskArcRenderer::renderFillGeometry( const QRectF& rect,
return; return;
const auto effectiveCount = stroker.setLines( const auto effectiveCount = stroker.setLines(
metrics.thickness() - 2 * borderWidth, lines ); metrics.thickness(), borderWidth, lines );
if ( effectiveCount > lineCount ) if ( effectiveCount > lineCount )
{ {