working on arcs
This commit is contained in:
parent
7f2fbc7bd0
commit
73dd618626
@ -25,13 +25,6 @@ static inline qreal qskInterpolated( qreal from, qreal to, qreal ratio )
|
||||
return from + ( to - from ) * ratio;
|
||||
}
|
||||
|
||||
static inline qreal qskAbsoluted( qreal length, qreal percentage )
|
||||
{
|
||||
// 100% means -> 0.5 of length
|
||||
percentage = qBound( 0.0, percentage, 100.0 );
|
||||
return percentage / 100.0 * 0.5 * length;
|
||||
}
|
||||
|
||||
void QskArcMetrics::setThickness( qreal thickness ) noexcept
|
||||
{
|
||||
m_thickness = thickness;
|
||||
@ -93,32 +86,33 @@ QVariant QskArcMetrics::interpolate(
|
||||
return QVariant::fromValue( from.interpolated( to, progress ) );
|
||||
}
|
||||
|
||||
QskArcMetrics QskArcMetrics::toAbsolute( const QSizeF& size ) const noexcept
|
||||
QskArcMetrics QskArcMetrics::toAbsolute( qreal radiusX, qreal radiusY ) const noexcept
|
||||
{
|
||||
if ( size.width() < 0.0 )
|
||||
return toAbsolute( size.height() );
|
||||
if ( radiusX < 0.0 )
|
||||
return toAbsolute( radiusY );
|
||||
|
||||
if ( size.height() < 0.0 )
|
||||
return toAbsolute( size.width() );
|
||||
if ( radiusY < 0.0 )
|
||||
return toAbsolute( radiusX );
|
||||
|
||||
return toAbsolute( qMin( size.width(), size.height() ) );
|
||||
return toAbsolute( qMin( radiusX, radiusY ) );
|
||||
}
|
||||
|
||||
QskArcMetrics QskArcMetrics::toAbsolute( qreal size ) const noexcept
|
||||
QskArcMetrics QskArcMetrics::toAbsolute( qreal radius ) const noexcept
|
||||
{
|
||||
if ( m_sizeMode != Qt::RelativeSize )
|
||||
return *this;
|
||||
|
||||
QskArcMetrics absoluted = *this;
|
||||
QskArcMetrics m = *this;
|
||||
|
||||
if ( size <= 0.0 )
|
||||
absoluted.m_thickness = 0.0;
|
||||
else
|
||||
absoluted.m_thickness = qskAbsoluted( size, absoluted.m_thickness );
|
||||
if ( radius < 0.0 )
|
||||
radius = 0.0;
|
||||
|
||||
absoluted.m_sizeMode = Qt::AbsoluteSize;
|
||||
const auto ratio = qBound( 0.0, m.m_thickness, 100.0 ) / 100.0;
|
||||
|
||||
return absoluted;
|
||||
m.m_thickness = radius * ratio;
|
||||
m.m_sizeMode = Qt::AbsoluteSize;
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
QskHashValue QskArcMetrics::hash( QskHashValue seed ) const noexcept
|
||||
|
@ -56,8 +56,8 @@ class QSK_EXPORT QskArcMetrics
|
||||
QskArcMetrics interpolated( const QskArcMetrics&,
|
||||
qreal value ) const noexcept;
|
||||
|
||||
QskArcMetrics toAbsolute( const QSizeF& ) const noexcept;
|
||||
QskArcMetrics toAbsolute( qreal ) const noexcept;
|
||||
QskArcMetrics toAbsolute( qreal radiusX, qreal radiusY ) const noexcept;
|
||||
QskArcMetrics toAbsolute( qreal radius ) const noexcept;
|
||||
|
||||
QskHashValue hash( QskHashValue seed = 0 ) const noexcept;
|
||||
|
||||
|
@ -210,7 +210,10 @@ static inline QSGNode* qskUpdateArcNode(
|
||||
if ( rect.isEmpty() )
|
||||
return nullptr;
|
||||
|
||||
const auto absoluteMetrics = metrics.toAbsolute( rect.size() );
|
||||
const auto rx = 0.5 * rect.width();
|
||||
const auto ry = 0.5 * rect.height();
|
||||
|
||||
const auto absoluteMetrics = metrics.toAbsolute( rx, ry );
|
||||
|
||||
if ( !qskIsArcVisible( absoluteMetrics, fillGradient ) )
|
||||
return nullptr;
|
||||
|
@ -11,31 +11,29 @@
|
||||
|
||||
#include <qpainterpath.h>
|
||||
|
||||
static inline QskGradient effectiveGradient( const QRectF& rect,
|
||||
const QskArcMetrics& metrics, const QskGradient& gradient )
|
||||
#define LINEAR_GRADIENT_HACK 1
|
||||
|
||||
#if LINEAR_GRADIENT_HACK
|
||||
|
||||
static inline QskGradient buildGradient( QskGradient::Type type,
|
||||
const QRectF& rect, const QskArcMetrics& metrics,
|
||||
const QskGradientStops& stops )
|
||||
{
|
||||
if ( gradient.isMonochrome() )
|
||||
return gradient;
|
||||
|
||||
bool isRadial = false;
|
||||
|
||||
if ( gradient.type() == QskGradient::Linear )
|
||||
{
|
||||
/*
|
||||
Horizontal is interpreted as conic ( in direction of the arc ),
|
||||
while Vertical means radial ( inner to outer border )
|
||||
*/
|
||||
isRadial = gradient.linearDirection().isVertical();
|
||||
}
|
||||
|
||||
auto g = gradient;
|
||||
g.setStretchMode( QskGradient::NoStretch );
|
||||
|
||||
const auto center = rect.center();
|
||||
|
||||
if( isRadial )
|
||||
QskGradient gradient;
|
||||
gradient.setStretchMode( QskGradient::NoStretch );
|
||||
|
||||
if ( type == QskGradient::Conic )
|
||||
{
|
||||
g.setRadialDirection( center.x(), center.y(),
|
||||
gradient.setConicDirection(
|
||||
center.x(), center.y(), metrics.startAngle() );
|
||||
|
||||
gradient.setStops( stops );
|
||||
}
|
||||
else
|
||||
{
|
||||
gradient.setRadialDirection( center.x(), center.y(),
|
||||
rect.width(), rect.height() );
|
||||
|
||||
{
|
||||
@ -47,24 +45,58 @@ static inline QskGradient effectiveGradient( const QRectF& rect,
|
||||
const auto radius = 0.5 * qMin( rect.width(), rect.height() );
|
||||
const auto t = metrics.thickness() / radius;
|
||||
|
||||
QskGradientStops stops;
|
||||
stops.reserve( gradient.stops().size() );
|
||||
QskGradientStops scaledStops;
|
||||
scaledStops.reserve( stops.size() );
|
||||
|
||||
for ( const auto& stop : gradient.stops() )
|
||||
for ( const auto& stop : stops )
|
||||
{
|
||||
const auto pos = 0.5 - t * ( 0.75 - stop.position() );
|
||||
stops += QskGradientStop( pos, stop.color() );
|
||||
scaledStops += QskGradientStop( pos, stop.color() );
|
||||
}
|
||||
|
||||
g.setStops( stops );
|
||||
gradient.setStops( scaledStops );
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
return gradient;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline QskGradient effectiveGradient( const QRectF& rect,
|
||||
const QskArcMetrics& metrics, const QskGradient& gradient )
|
||||
{
|
||||
if ( !gradient.isMonochrome() )
|
||||
{
|
||||
g.setConicDirection( center.x(), center.y(), metrics.startAngle() );
|
||||
if ( gradient.type() == QskGradient::Stops )
|
||||
{
|
||||
const QskConicDirection dir(
|
||||
rect.center(), metrics.startAngle() );
|
||||
#if 0
|
||||
dir.setSpanAngle( metrics.spanAngle() ); // what is "expected" ??
|
||||
#endif
|
||||
|
||||
QskGradient g( gradient.stops() );
|
||||
g.setStretchMode( QskGradient::NoStretch );
|
||||
g.setConicDirection( dir );
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
#if LINEAR_GRADIENT_HACK
|
||||
if ( gradient.type() == QskGradient::Linear )
|
||||
{
|
||||
// to keep the iotdashboard working: to be removed
|
||||
|
||||
const auto type = gradient.linearDirection().isHorizontal()
|
||||
? QskGradient::Conic : QskGradient::Radial;
|
||||
|
||||
return buildGradient( type, rect, metrics, gradient.stops() );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return g;
|
||||
return gradient;
|
||||
}
|
||||
|
||||
QskArcNode::QskArcNode()
|
||||
@ -78,22 +110,8 @@ QskArcNode::~QskArcNode()
|
||||
void QskArcNode::setArcData( const QRectF& rect,
|
||||
const QskArcMetrics& metrics, const QskGradient& gradient )
|
||||
{
|
||||
#if 1
|
||||
/*
|
||||
Translating linear gradients into conic or radial gradients.
|
||||
This code is a leftover from situations, where only linear
|
||||
gradients had been available. Once the iotdashboard example
|
||||
has been adjusted we will remove this code TODO ...
|
||||
*/
|
||||
const auto g = effectiveGradient( rect, metrics, gradient );
|
||||
#endif
|
||||
|
||||
/*
|
||||
For the moment using a QPainterPath/QskShapeNode.
|
||||
But we can do better by creatig vertex lists manually
|
||||
like what is done by the box renderer. TODO ...
|
||||
*/
|
||||
|
||||
const auto path = QskArcRenderer::arcPath( rect, metrics );
|
||||
updateNode( path, QTransform(), rect, g );
|
||||
|
||||
updateNode( path, QTransform(), rect,
|
||||
effectiveGradient( rect, metrics, gradient ) );
|
||||
}
|
||||
|
@ -11,6 +11,11 @@
|
||||
class QskArcMetrics;
|
||||
class QskGradient;
|
||||
|
||||
/*
|
||||
For the moment a QPainterPath/QskShapeNode.
|
||||
But we can do better by creatig vertex lists manually
|
||||
like what is done by the box renderer. TODO ...
|
||||
*/
|
||||
class QSK_EXPORT QskArcNode : public QskShapeNode
|
||||
{
|
||||
public:
|
||||
|
@ -9,10 +9,13 @@
|
||||
#include <qpainterpath.h>
|
||||
#include <qrect.h>
|
||||
|
||||
QPainterPath QskArcRenderer::arcPath(
|
||||
static inline QPainterPath qskArcPath(
|
||||
const QRectF& rect, const QskArcMetrics& metrics )
|
||||
{
|
||||
const auto m = metrics.toAbsolute( rect.size() );
|
||||
const auto rx = 0.5 * rect.width();
|
||||
const auto ry = 0.5 * rect.height();
|
||||
|
||||
const auto m = metrics.toAbsolute( rx, ry );
|
||||
|
||||
const qreal t2 = 0.5 * m.thickness();
|
||||
const auto r = rect.adjusted( t2, t2, -t2, -t2 );
|
||||
@ -27,3 +30,59 @@ QPainterPath QskArcRenderer::arcPath(
|
||||
|
||||
return stroker.createStroke( path );
|
||||
}
|
||||
|
||||
static inline QRectF qskArcRect(
|
||||
const QRectF& rect, const QskArcMetrics& metrics )
|
||||
{
|
||||
return qskArcPath( rect, metrics ).controlPointRect();
|
||||
}
|
||||
|
||||
QPainterPath QskArcRenderer::arcPath(
|
||||
qreal radius, const QskArcMetrics& metrics )
|
||||
{
|
||||
const QRectF r( 0.0, 0.0, 2 * radius, 2 * radius );
|
||||
return qskArcPath( r, metrics );
|
||||
}
|
||||
|
||||
QPainterPath QskArcRenderer::arcPath(
|
||||
const QSizeF& diameters, const QskArcMetrics& metrics )
|
||||
{
|
||||
const QRectF r( 0.0, 0.0, diameters.width(), diameters.height() );
|
||||
return qskArcPath( r, metrics );
|
||||
}
|
||||
|
||||
QPainterPath QskArcRenderer::arcPath(
|
||||
const QRectF& rect, const QskArcMetrics& metrics )
|
||||
{
|
||||
return qskArcPath( rect, metrics );
|
||||
}
|
||||
|
||||
QRectF QskArcRenderer::arcRect( qreal radius, const QskArcMetrics& metrics )
|
||||
{
|
||||
const qreal d = 2.0 * radius;
|
||||
return qskArcRect( QRectF( 0.0, 0.0, d, d ), metrics );
|
||||
}
|
||||
|
||||
QRectF QskArcRenderer::arcRect( const QSizeF& diameters, const QskArcMetrics& metrics )
|
||||
{
|
||||
const QRectF r( 0.0, 0.0, diameters.width(), diameters.height() );
|
||||
return qskArcRect( r, metrics );
|
||||
}
|
||||
|
||||
QRectF QskArcRenderer::arcRect( const QRectF& rect, const QskArcMetrics& metrics )
|
||||
{
|
||||
return qskArcRect( rect, metrics );
|
||||
}
|
||||
|
||||
QSizeF QskArcRenderer::arcSize(
|
||||
const QSizeF& diameters, const QskArcMetrics& metrics )
|
||||
{
|
||||
if ( qFuzzyIsNull( metrics.spanAngle() ) )
|
||||
return QSizeF();
|
||||
|
||||
if ( qAbs( metrics.spanAngle() ) >= 360.0 )
|
||||
return diameters;
|
||||
|
||||
const QRectF r( 0.0, 0.0, diameters.width(), diameters.height() );
|
||||
return qskArcRect( r, metrics ).size();
|
||||
}
|
||||
|
@ -12,10 +12,22 @@ class QskArcMetrics;
|
||||
|
||||
class QPainterPath;
|
||||
class QRectF;
|
||||
class QSizeF;
|
||||
|
||||
namespace QskArcRenderer
|
||||
{
|
||||
// radius
|
||||
QSK_EXPORT QPainterPath arcPath( qreal radius, const QskArcMetrics& );
|
||||
QSK_EXPORT QRectF arcRect( qreal radius, const QskArcMetrics& );
|
||||
|
||||
// diameter
|
||||
QSK_EXPORT QPainterPath arcPath( const QSizeF&, const QskArcMetrics& );
|
||||
QSK_EXPORT QSizeF arcSize( const QSizeF&, const QskArcMetrics& );
|
||||
QSK_EXPORT QRectF arcRect( const QSizeF&, const QskArcMetrics& );
|
||||
|
||||
// bounding rectangle
|
||||
QSK_EXPORT QPainterPath arcPath( const QRectF&, const QskArcMetrics& );
|
||||
QSK_EXPORT QRectF arcRect( const QRectF&, const QskArcMetrics& );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user