minor adjustments

This commit is contained in:
Uwe Rathmann 2023-01-10 10:20:30 +01:00
parent 9afabe0e92
commit e50fb269c3

View File

@ -152,80 +152,47 @@ namespace
Values m_outer[ 4 ]; Values m_outer[ 4 ];
}; };
class CornerValues class Vector1D
{ {
public: public:
inline void setCorner( Qt::Orientation orientation, bool increasing, Vector1D() = default;
const QskRoundedRectRenderer::Metrics::Corner& c )
inline constexpr Vector1D( qreal origin, qreal length )
: origin( origin )
, length( length )
{ {
if ( orientation == Qt::Horizontal )
{
m_center = c.centerX;
m_radius = c.radiusInnerX;
}
else
{
m_center = c.centerY;
m_radius = c.radiusInnerY;
}
const qreal f = increasing ? 1.0 : -1.0;
if ( m_radius < 0.0 )
{
m_center += m_radius * f;
m_radius = 0.0;
}
else
{
m_radius *= f;
}
stepCount = c.stepCount;
} }
qreal valueAt( qreal fv ) const inline qreal valueAt( qreal t ) const
{ {
return m_center + fv * m_radius; return origin + t * length;
} }
int stepCount; qreal origin = 0.0;
qreal length = 0.0;
private:
qreal m_center = 0.0;
qreal m_radius = 0.0;
}; };
} }
namespace namespace
{ {
/*
A contour iterator for vertical and horizontal linear gradients.
The radii in direction of the gradient need to match at the
opening and at the closing sides,
*/
class HVRectEllipseIterator class HVRectEllipseIterator
{ {
public: public:
HVRectEllipseIterator( HVRectEllipseIterator(
const QskRoundedRectRenderer::Metrics& metrics, const QLineF& vector ) const QskRoundedRectRenderer::Metrics& metrics, const QLineF& vector )
: m_metrics( metrics ) : m_vertical( vector.x1() == vector.x2() )
, m_vertical( vector.x1() == vector.x2() )
{ {
const auto& mc = metrics.corner; const int* c;
auto v = m_values;
if ( m_vertical ) if ( m_vertical )
{ {
const int c[] = { TopLeft, TopRight, BottomLeft, BottomRight }; static const int cV[] = { TopLeft, TopRight, BottomLeft, BottomRight };
c = cV;
v[0].setCorner( Qt::Horizontal, false, mc[ c[0] ] );
v[1].setCorner( Qt::Horizontal, true, mc[ c[1] ] );
const int idx1 = ( v[0].stepCount >= v[1].stepCount ) ? 0 : 1;
v[2].setCorner( Qt::Vertical, false, mc[ c[idx1] ] );
v[3].setCorner( Qt::Horizontal, false, mc[ c[2] ] );
v[4].setCorner( Qt::Horizontal, true, mc[ c[3] ] );
const int idx2 = ( v[3].stepCount >= v[4].stepCount ) ? 2 : 3;
v[5].setCorner( Qt::Vertical, true, mc[ c[idx2] ] );
m_pos0 = metrics.innerQuad.top; m_pos0 = metrics.innerQuad.top;
m_size = metrics.innerQuad.height; m_size = metrics.innerQuad.height;
@ -235,19 +202,8 @@ namespace
} }
else else
{ {
const int c[] = { TopLeft, BottomLeft, TopRight, BottomRight }; static const int cH[] = { TopLeft, BottomLeft, TopRight, BottomRight };
c = cH;
v[0].setCorner( Qt::Vertical, false, mc[ c[0] ] );
v[1].setCorner( Qt::Vertical, true, mc[ c[1] ] );
const int idx1 = ( v[0].stepCount >= v[1].stepCount ) ? 0 : 1;
v[2].setCorner( Qt::Horizontal, false, mc[ c[idx1] ] );
v[3].setCorner( Qt::Vertical, false, mc[ c[2] ] );
v[4].setCorner( Qt::Vertical, true, mc[ c[3] ] );
const int idx2 = ( v[3].stepCount >= v[4].stepCount ) ? 2 : 3;
v[5].setCorner( Qt::Horizontal, true, mc[ c[idx2] ] );
m_pos0 = metrics.innerQuad.left; m_pos0 = metrics.innerQuad.left;
m_size = metrics.innerQuad.width; m_size = metrics.innerQuad.width;
@ -256,19 +212,37 @@ namespace
m_dt = vector.dx() * m_size; m_dt = vector.dx() * m_size;
} }
m_v1.from = v[0].valueAt( 1.0 ); const auto& mc1 = metrics.corner[ c[0] ];
m_v1.to = v[1].valueAt( 1.0 ); const auto& mc2 = metrics.corner[ c[1] ];
const auto& mc3 = ( mc1.stepCount >= mc2.stepCount ) ? mc1 : mc2;
const auto& mc4 = metrics.corner[ c[2] ];
const auto& mc5 = metrics.corner[ c[3] ];
const auto& mc6 = ( mc4.stepCount >= mc5.stepCount ) ? mc4 : mc5;
m_vector[0] = vectorAt( !m_vertical, false, mc1 );
m_vector[1] = vectorAt( !m_vertical, true, mc2 );
m_vector[2] = vectorAt( m_vertical, false, mc3 );
m_vector[3] = vectorAt( !m_vertical, false, mc4 );
m_vector[4] = vectorAt( !m_vertical, true, mc5 );
m_vector[5] = vectorAt( m_vertical, true, mc6 );
m_stepCounts[0] = mc3.stepCount;
m_stepCounts[1] = mc6.stepCount;
m_v1.from = m_vector[0].valueAt( 1.0 );
m_v1.to = m_vector[1].valueAt( 1.0 );
m_v1.pos = m_pos0; m_v1.pos = m_pos0;
m_v2 = m_v1; m_v2 = m_v1;
const auto stepCount = qMax( v[0].stepCount, v[1].stepCount ); m_arcIterator.reset( m_stepCounts[0], false );
m_arcIterator.reset( stepCount, false );
} }
inline bool advance() inline bool advance()
{ {
auto v = m_values; auto v = m_vector;
if ( m_arcIterator.step() == m_arcIterator.stepCount() ) if ( m_arcIterator.step() == m_arcIterator.stepCount() )
{ {
@ -278,8 +252,7 @@ namespace
return false; return false;
} }
const auto stepCount = qMax( v[3].stepCount, v[4].stepCount ); m_arcIterator.reset( m_stepCounts[1], true );
m_arcIterator.reset( stepCount, true );
const qreal pos1 = v[2].valueAt( 0.0 ); const qreal pos1 = v[2].valueAt( 0.0 );
const qreal pos2 = v[5].valueAt( 0.0 ); const qreal pos2 = v[5].valueAt( 0.0 );
@ -337,6 +310,37 @@ namespace
private: private:
inline Vector1D vectorAt( bool vertical, bool increasing,
const QskRoundedRectRenderer::Metrics::Corner& c ) const
{
qreal center, radius;
if ( vertical )
{
center = c.centerY;
radius = c.radiusInnerY;
}
else
{
center = c.centerX;
radius = c.radiusInnerX;
}
const qreal f = increasing ? 1.0 : -1.0;
if ( radius < 0.0 )
{
center += radius * f;
radius = 0.0;
}
else
{
radius *= f;
}
return { center, radius };
}
inline void setLine( qreal from, qreal to, qreal pos, inline void setLine( qreal from, qreal to, qreal pos,
Color color, ColoredLine* line ) Color color, ColoredLine* line )
{ {
@ -346,13 +350,29 @@ namespace
line->setLine( pos, from, pos, to, color ); line->setLine( pos, from, pos, to, color );
} }
const QskRoundedRectRenderer::Metrics& m_metrics;
const bool m_vertical; const bool m_vertical;
int m_stepCounts[2];
ArcIterator m_arcIterator; ArcIterator m_arcIterator;
CornerValues m_values[6]; /*
struct { qreal from, to, pos; } m_v1, m_v2; This iterator supports shapes, where we have the same radius in
direction of the gradient ( exception: one corner is not rounded ).
However we allow having different radii opposite to the direction
of the gradient. So we have 3 center/radius pairs to calculate the
interpolating contour lines at both ends ( opening/closing ).
*/
Vector1D m_vector[6];
/*
position of the previous and following contour line, so that
the positions of the gradiet lines in between can be calculated.
*/
struct
{
qreal from, to; // opposite to the direction of the gradient
qreal pos; // in direction of the gradient
} m_v1, m_v2;
qreal m_pos0, m_size; qreal m_pos0, m_size;
qreal m_t, m_dt; // to translate into gradient values qreal m_t, m_dt; // to translate into gradient values