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 ];
};
class CornerValues
class Vector1D
{
public:
inline void setCorner( Qt::Orientation orientation, bool increasing,
const QskRoundedRectRenderer::Metrics::Corner& c )
Vector1D() = default;
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;
private:
qreal m_center = 0.0;
qreal m_radius = 0.0;
qreal origin = 0.0;
qreal length = 0.0;
};
}
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
{
public:
HVRectEllipseIterator(
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;
auto v = m_values;
const int* c;
if ( m_vertical )
{
const int c[] = { TopLeft, TopRight, BottomLeft, BottomRight };
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] ] );
static const int cV[] = { TopLeft, TopRight, BottomLeft, BottomRight };
c = cV;
m_pos0 = metrics.innerQuad.top;
m_size = metrics.innerQuad.height;
@ -235,19 +202,8 @@ namespace
}
else
{
const int c[] = { TopLeft, BottomLeft, TopRight, BottomRight };
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] ] );
static const int cH[] = { TopLeft, BottomLeft, TopRight, BottomRight };
c = cH;
m_pos0 = metrics.innerQuad.left;
m_size = metrics.innerQuad.width;
@ -256,19 +212,37 @@ namespace
m_dt = vector.dx() * m_size;
}
m_v1.from = v[0].valueAt( 1.0 );
m_v1.to = v[1].valueAt( 1.0 );
const auto& mc1 = metrics.corner[ c[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_v2 = m_v1;
const auto stepCount = qMax( v[0].stepCount, v[1].stepCount );
m_arcIterator.reset( stepCount, false );
m_arcIterator.reset( m_stepCounts[0], false );
}
inline bool advance()
{
auto v = m_values;
auto v = m_vector;
if ( m_arcIterator.step() == m_arcIterator.stepCount() )
{
@ -278,8 +252,7 @@ namespace
return false;
}
const auto stepCount = qMax( v[3].stepCount, v[4].stepCount );
m_arcIterator.reset( stepCount, true );
m_arcIterator.reset( m_stepCounts[1], true );
const qreal pos1 = v[2].valueAt( 0.0 );
const qreal pos2 = v[5].valueAt( 0.0 );
@ -337,6 +310,37 @@ namespace
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,
Color color, ColoredLine* line )
{
@ -346,13 +350,29 @@ namespace
line->setLine( pos, from, pos, to, color );
}
const QskRoundedRectRenderer::Metrics& m_metrics;
const bool m_vertical;
int m_stepCounts[2];
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_t, m_dt; // to translate into gradient values