code reorganized

This commit is contained in:
Uwe Rathmann 2024-06-13 12:26:38 +02:00
parent 04d46b52fb
commit 3157acc4ae
2 changed files with 162 additions and 123 deletions

View File

@ -98,6 +98,8 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics
const qreal borderWidth, const QColor& borderColor, const QskGradient& gradient, const qreal borderWidth, const QColor& borderColor, const QskGradient& gradient,
const QColor& shadowColor, const QskShadowMetrics& shadowMetrics ) const QColor& shadowColor, const QskShadowMetrics& shadowMetrics )
{ {
const bool radial = false;
const auto metricsArc = arcMetrics.toAbsolute( rect.size() ); const auto metricsArc = arcMetrics.toAbsolute( rect.size() );
auto shadowNode = static_cast< QskArcShadowNode* >( auto shadowNode = static_cast< QskArcShadowNode* >(
@ -127,7 +129,7 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics
const auto isShadowNodeVisible = isFillNodeVisible && const auto isShadowNodeVisible = isFillNodeVisible &&
shadowColor.isValid() && ( shadowColor.alpha() > 0.0 ); shadowColor.isValid() && ( shadowColor.alpha() > 0.0 );
const auto path = metricsArc.painterPath( arcRect ); const auto path = metricsArc.painterPath( arcRect, radial );
if ( isShadowNodeVisible ) if ( isShadowNodeVisible )
{ {
@ -170,7 +172,7 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics
QskSGNode::setNodeRole( arcNode, ArcRole ); QskSGNode::setNodeRole( arcNode, ArcRole );
} }
arcNode->updateNode( arcRect, metricsArc, false, arcNode->updateNode( arcRect, metricsArc, radial,
borderWidth, QColor(), gradient ); borderWidth, QColor(), gradient );
} }
else else

View File

@ -28,56 +28,151 @@ static inline QskVertex::ColoredLine* qskAllocateColoredLines(
namespace namespace
{ {
class OrthogonalStroker
{
public:
OrthogonalStroker( const QRectF& rect, qreal length )
: m_l2( 0.5 * length )
, m_rx( 0.5 * ( rect.width() - length ) )
, m_ry( 0.5 * ( rect.height() - length ) )
, m_aspectRatio( m_rx / m_ry )
, m_cx( rect.x() + 0.5 * rect.width() )
, m_cy( rect.y() + 0.5 * rect.height() )
{
}
inline void setLine( const qreal radians,
const QskVertex::Color color, QskVertex::ColoredLine& line ) const
{
const auto cos = qFastCos( radians );
const auto sin = qFastSin( radians );
/*
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( cos ) )
{
dx = 0.0;
dy = ( sin > 0.0 ) ? m_l2 : -m_l2;
}
else
{
const qreal m = m_aspectRatio * ( sin / cos );
const qreal t = m_l2 / qSqrt( 1.0 + m * m );
dx = ( cos >= 0.0 ) ? t : -t;
dy = m * dx;
}
const auto x = m_cx + m_rx * cos;
const auto y = m_cy - m_ry * sin;
line.setLine( x + dx, y - dy, x - dx, y + dy, 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
// center
const qreal m_cx;
const qreal m_cy;
};
class RadialStroker
{
public:
RadialStroker( const QRectF& rect, qreal length )
: m_length( length )
, m_rx1( 0.5 * rect.width() )
, m_ry1( 0.5 * rect.height() )
, m_rx2( m_rx1 - ( ( m_rx1 > m_ry1 ) ? length * m_rx1 / m_ry1 : length ) )
, m_ry2( m_ry1 - ( ( m_ry1 > m_rx1 ) ? length * m_ry1 / m_rx1 : length ) )
, m_cx( rect.x() + m_rx1 )
, m_cy( rect.y() + m_ry1 )
{
}
inline void setLine( const qreal radians,
const QskVertex::Color color, QskVertex::ColoredLine& line ) const
{
const auto cos = qFastCos( radians );
const auto sin = qFastSin( radians );
line.setLine( m_cx + m_rx1 * cos, m_cy - m_ry1 * sin,
m_cx + m_rx2 * cos, m_cy - m_ry2 * sin, color );
}
private:
const qreal m_length;
// outer radii
const qreal m_rx1;
const qreal m_ry1;
// inner radii
const qreal m_rx2;
const qreal m_ry2;
// center point
const qreal m_cx;
const qreal m_cy;
};
class EllipseStroker class EllipseStroker
{ {
public: public:
EllipseStroker( const QRectF&, const QskArcMetrics&, bool orthogonal, EllipseStroker( const QRectF&, const QskArcMetrics&,
qreal borderWidth, const QskGradient& ); bool radial, const QskGradient& );
int fillCount() const; int fillCount() const;
int borderCount() const; int borderCount() const;
int setBorderLines( QskVertex::ColoredLine*, const QskVertex::Color ) const; int setBorderLines( QskVertex::ColoredLine*, const QskVertex::Color ) const;
int setFillLines( QskVertex::ColoredLine* ) const; int setFillLines( int length, QskVertex::ColoredLine* ) const;
private: private:
int arcLineCount() const; int arcLineCount() const;
qreal radiansAt( qreal progress ) const; qreal radiansAt( qreal progress ) const;
void setOrthogonalLine( const qreal radians, template< class LineStroker >
const QskVertex::Color, QskVertex::ColoredLine& ) const; int renderFillLines( const LineStroker&, QskVertex::ColoredLine* ) const;
void setRadialLine( const qreal radians,
const QskVertex::Color, QskVertex::ColoredLine& ) const;
const qreal m_extent;
const bool m_orthogonal;
// radius // radius
const qreal m_rx; const QRectF& m_rect;
const qreal m_ry;
// center
const qreal m_cx;
const qreal m_cy;
const qreal m_radians1; const qreal m_radians1;
const qreal m_radians2; const qreal m_radians2;
const bool m_radial;
const QskGradient& m_gradient; const QskGradient& m_gradient;
}; };
EllipseStroker::EllipseStroker( const QRectF& rect, EllipseStroker::EllipseStroker( const QRectF& rect,
const QskArcMetrics& m, bool orthogonal, qreal borderWidth, const QskArcMetrics& metrics, bool radial, const QskGradient& gradient )
const QskGradient& gradient ) : m_rect( rect )
: m_extent( 0.5 * ( m.thickness() - borderWidth ) ) , m_radians1( qDegreesToRadians( metrics.startAngle() ) )
, m_orthogonal( orthogonal ) , m_radians2( qDegreesToRadians( metrics.endAngle() ) )
, m_rx( 0.5 * rect.width() - m_extent ) , m_radial( radial )
, m_ry( 0.5 * rect.height() - m_extent )
, m_cx( rect.center().x() )
, m_cy( rect.center().y() )
, m_radians1( qDegreesToRadians( m.startAngle() ) )
, m_radians2( qDegreesToRadians( m.endAngle() ) )
, m_gradient( gradient ) , m_gradient( gradient )
{ {
} }
@ -91,7 +186,7 @@ namespace
{ {
// not very sophisticated - TODO ... // not very sophisticated - TODO ...
const auto radius = qMax( m_rx, m_ry ) + m_extent; // outer border const auto radius = 0.5 * qMax( m_rect.width(), m_rect.height() );
const auto radians = qAbs( m_radians2 - m_radians1 ); const auto radians = qAbs( m_radians2 - m_radians1 );
const auto count = qCeil( ( radius * radians ) / 3.0 ); const auto count = qCeil( ( radius * radians ) / 3.0 );
@ -112,79 +207,24 @@ namespace
return 0; return 0;
} }
inline void EllipseStroker::setOrthogonalLine( const qreal radians, inline int EllipseStroker::setFillLines(
const QskVertex::Color color, QskVertex::ColoredLine& line ) const const int length, QskVertex::ColoredLine* lines ) const
{ {
const auto cos = qFastCos( radians ); if ( m_radial )
const auto sin = qFastSin( radians );
/*
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( cos ) )
{ {
dx = 0.0; const RadialStroker lineStroker( m_rect, length );
dy = ( sin > 0.0 ) ? m_extent : -m_extent; return renderFillLines( lineStroker, lines );
} }
else else
{ {
const qreal m = ( m_rx / m_ry ) * ( sin / cos ); const OrthogonalStroker lineStroker( m_rect, length );
const qreal t = m_extent / qSqrt( 1.0 + m * m ); return renderFillLines( lineStroker, lines );
dx = ( cos >= 0.0 ) ? t : -t;
dy = m * dx;
} }
const auto x = m_cx + m_rx * cos;
const auto y = m_cy - m_ry * sin;
line.setLine( x + dx, y - dy, x - dx, y + dy, color );
} }
inline void EllipseStroker::setRadialLine( const qreal radians, template< class LineStroker >
const QskVertex::Color color, QskVertex::ColoredLine& line ) const inline int EllipseStroker::renderFillLines(
{ const LineStroker& stroker, QskVertex::ColoredLine* lines ) const
const auto cos = qFastCos( radians );
const auto sin = qFastSin( radians );
const auto t = 2.0 * m_extent;
const auto w = 2.0 * m_rx + t;
const auto h = 2.0 * m_ry + t;
const auto x1 = 0.5 * w * cos;
const auto y1 = 0.5 * h * sin;
const auto sz = qMin( w, h );
const auto tx = t * w / sz;
const auto ty = t * h / sz;
const auto w2 = w - 2 * tx;
const auto h2 = h - 2 * ty;
const auto x2 = 0.5 * w2 * cos;
const auto y2 = 0.5 * h2 * sin;
line.setLine( m_cx + x1, m_cy - y1, m_cx + x2, m_cy - y2, color );
}
int EllipseStroker::setFillLines( QskVertex::ColoredLine* lines ) const
{ {
auto l = lines; auto l = lines;
@ -210,20 +250,12 @@ namespace
while( !it.isDone() && ( it.position() < progress ) ) while( !it.isDone() && ( it.position() < progress ) )
{ {
if ( m_orthogonal ) stroker.setLine( radiansAt( it.position() ), it.color(), *l++ );
setOrthogonalLine( radiansAt( it.position() ), it.color(), *l++ );
else
setRadialLine( radiansAt( it.position() ), it.color(), *l++ );
it.advance(); it.advance();
} }
const auto color = it.colorAt( progress ); const auto color = it.colorAt( progress );
stroker.setLine( m_radians1 + i * stepSize, color, *l++ );
if ( m_orthogonal )
setOrthogonalLine( m_radians1 + i * stepSize, color, *l++ );
else
setRadialLine( m_radians1 + i * stepSize, color, *l++ );
} }
return l - lines; return l - lines;
@ -253,39 +285,44 @@ void QskArcRenderer::renderFillGeometry( const QRectF& rect,
#endif #endif
geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip ); geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip );
EllipseStroker stroker( rect, metrics, !radial, borderWidth, gradient ); EllipseStroker stroker( rect, metrics, radial, gradient );
const auto lineCount = stroker.fillCount(); const auto lineCount = stroker.fillCount();
const auto lines = qskAllocateColoredLines( geometry, lineCount ); const auto lines = qskAllocateColoredLines( geometry, lineCount );
if ( lines ) if ( lines == nullptr )
return;
const auto effectiveCount = stroker.setFillLines(
metrics.thickness() - borderWidth, lines );
if ( effectiveCount > lineCount )
{ {
const auto effectiveCount = stroker.setFillLines( lines ); qFatal( "geometry: allocated memory exceeded: %d vs. %d",
if ( effectiveCount > lineCount ) effectiveCount, lineCount );
{ }
qFatal( "geometry: allocated memory exceeded: %d vs. %d",
effectiveCount, lineCount );
}
if ( effectiveCount < lineCount ) if ( effectiveCount < lineCount )
{ {
/* /*
Gradient or contour lines might be at the same position Gradient or contour lines might be at the same position
and we end up with less lines, than expected. and we end up with less lines, than expected.
*/ */
for ( int i = effectiveCount; i < lineCount; i++ ) for ( int i = effectiveCount; i < lineCount; i++ )
lines[i] = lines[i - 1]; lines[i] = lines[i - 1];
}
} }
} }
void QskArcRenderer::renderBorder( const QRectF& rect, const QskArcMetrics& metrics, void QskArcRenderer::renderBorder( const QRectF& rect, const QskArcMetrics& metrics,
bool radial, qreal borderWidth, const QColor& borderColor, QSGGeometry& geometry ) bool radial, qreal borderWidth, const QColor& borderColor, QSGGeometry& geometry )
{ {
Q_UNUSED( borderWidth );
Q_UNUSED( radial );
geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip ); geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip );
EllipseStroker stroker( rect, metrics, !radial, borderWidth, QskGradient() ); EllipseStroker stroker( rect, metrics, radial, QskGradient() );
const auto lineCount = stroker.borderCount(); const auto lineCount = stroker.borderCount();