diff --git a/playground/charts/CircularChart.cpp b/playground/charts/CircularChart.cpp index 8ec289c5..c7f3b485 100644 --- a/playground/charts/CircularChart.cpp +++ b/playground/charts/CircularChart.cpp @@ -27,7 +27,7 @@ CircularChart::CircularChart( QQuickItem* parentItem ) setGradientHint( Panel, QskGradient() ); setBoxBorderMetricsHint( Panel, 0 ); - setArcMetricsHint( Arc, { 90.0, -360.0, 100.0, Qt::RelativeSize, true } ); + setArcMetricsHint( Arc, { 90.0, -360.0, 100.0, Qt::RelativeSize } ); setGradientHint( Arc, QskRgb::toTransparent( QskRgb::LightGray, 100 ) ); setColor( Arc | QskAspect::Border, QskRgb::LightGray ); diff --git a/playground/shadows/ShadowedArc.cpp b/playground/shadows/ShadowedArc.cpp index bb209f3f..c237065d 100644 --- a/playground/shadows/ShadowedArc.cpp +++ b/playground/shadows/ShadowedArc.cpp @@ -106,7 +106,7 @@ ShadowedArc::ShadowedArc( QQuickItem* parent ) setBorderWidth( 0 ); setBorderColor( Qt::gray ); - setShadowColor( Qt::black ); + setShadowColor( QColor() ); setShadowMetrics( { 0, 0, QPointF( 0, 0 ), Qt::AbsoluteSize } ); } diff --git a/src/common/QskArcMetrics.cpp b/src/common/QskArcMetrics.cpp index 26904c81..2b3dcaf9 100644 --- a/src/common/QskArcMetrics.cpp +++ b/src/common/QskArcMetrics.cpp @@ -51,11 +51,6 @@ void QskArcMetrics::setSizeMode( Qt::SizeMode sizeMode ) noexcept m_relativeSize = ( sizeMode == Qt::RelativeSize ); } -void QskArcMetrics::setProportional( bool on ) noexcept -{ - m_proportional = on; -} - bool QskArcMetrics::isClosed() const { return qAbs( m_spanAngle ) >= 360.0; @@ -92,7 +87,7 @@ QskArcMetrics QskArcMetrics::interpolated( const qreal s1 = qskInterpolated( m_startAngle, to.m_startAngle, ratio ); const qreal s2 = qskInterpolated( endAngle(), to.endAngle(), ratio ); - return QskArcMetrics( s1, s2 - s1, thickness, sizeMode(), to.isProportional() ); + return QskArcMetrics( s1, s2 - s1, thickness, sizeMode() ); } QVariant QskArcMetrics::interpolate( @@ -119,8 +114,7 @@ QskArcMetrics QskArcMetrics::toAbsolute( qreal radius ) const noexcept return *this; const qreal t = qskEffectiveThickness( radius, m_thickness ); - return QskArcMetrics( m_startAngle, m_spanAngle, t, - Qt::AbsoluteSize, m_proportional ); + return QskArcMetrics( m_startAngle, m_spanAngle, t, Qt::AbsoluteSize ); } QPainterPath QskArcMetrics::painterPath( const QRectF& ellipseRect ) const @@ -136,18 +130,7 @@ QPainterPath QskArcMetrics::painterPath( const QRectF& ellipseRect ) const if ( t <= 0.0 || qFuzzyIsNull( m_spanAngle ) ) return QPainterPath(); - auto tx = t; - auto ty = t; - - if ( m_proportional ) - { - const auto sz = qMin( ellipseRect.width(), ellipseRect.height() ); - - tx *= ellipseRect.width() / sz; - ty *= ellipseRect.height() / sz; - } - - const auto innerRect = ellipseRect.adjusted( tx, ty, -tx, -ty ); + const auto innerRect = ellipseRect.adjusted( t, t, -t, -t ); QPainterPath path; @@ -168,32 +151,18 @@ QPainterPath QskArcMetrics::painterPath( const QRectF& ellipseRect ) const } else { - if ( qAbs( m_spanAngle ) >= 360.0 ) - { - path.addEllipse( ellipseRect ); + const auto t2 = 0.5 * t; + const auto r = ellipseRect.adjusted( t2, t2, -t2, -t2 ); - QPainterPath innerPath; - innerPath.addEllipse( innerRect ); - path -= innerPath; - } - else - { - /* - We need the end point of the inner arc to add the line that connects - the inner/outer arcs. As QPainterPath does not offer such a method - we insert a dummy arcMoveTo and grab the calculated position. - */ - path.arcMoveTo( innerRect, m_startAngle + m_spanAngle ); - const auto pos = path.currentPosition(); + QPainterPath arcPath; + arcPath.arcMoveTo( r, m_startAngle ); // replaces the dummy arcMoveTo above + arcPath.arcTo( r, m_startAngle, m_spanAngle ); - path.arcMoveTo( ellipseRect, m_startAngle ); // replaces the dummy arcMoveTo above - path.arcTo( ellipseRect, m_startAngle, m_spanAngle ); + QPainterPathStroker stroker; + stroker.setCapStyle( Qt::FlatCap ); + stroker.setWidth( t ); - path.lineTo( pos ); - path.arcTo( innerRect, m_startAngle + m_spanAngle, -m_spanAngle ); - - path.closeSubpath(); - } + path = stroker.createStroke( arcPath ); } return path; @@ -227,9 +196,8 @@ QskHashValue QskArcMetrics::hash( QskHashValue seed ) const noexcept auto hash = qHash( m_thickness, seed ); hash = qHash( m_startAngle, hash ); hash = qHash( m_spanAngle, hash ); - hash = qHash( m_relativeSize, hash ); - return qHash( m_proportional, hash ); + return qHash( m_relativeSize, hash ); } #ifndef QT_NO_DEBUG_STREAM @@ -242,8 +210,7 @@ QDebug operator<<( QDebug debug, const QskArcMetrics& metrics ) debug.nospace(); debug << "QskArcMetrics" << '('; - debug << metrics.thickness() << ',' << metrics.sizeMode() << ',' - << metrics.isProportional(); + debug << metrics.thickness() << ',' << metrics.sizeMode(); debug << ",[" << metrics.startAngle() << ',' << metrics.spanAngle() << ']'; debug << ')'; diff --git a/src/common/QskArcMetrics.h b/src/common/QskArcMetrics.h index 0ee551b1..9e04eedc 100644 --- a/src/common/QskArcMetrics.h +++ b/src/common/QskArcMetrics.h @@ -22,16 +22,15 @@ class QSK_EXPORT QskArcMetrics Q_PROPERTY( qreal thickness READ thickness WRITE setThickness ) Q_PROPERTY( Qt::SizeMode sizeMode READ sizeMode WRITE setSizeMode ) - Q_PROPERTY( bool proportional READ isProportional WRITE setProportional ) public: constexpr QskArcMetrics() noexcept = default; constexpr QskArcMetrics( qreal thickness, - Qt::SizeMode = Qt::AbsoluteSize, bool proportional = false ) noexcept; + Qt::SizeMode = Qt::AbsoluteSize ) noexcept; constexpr QskArcMetrics( qreal startAngle, qreal spanAngle, qreal thickness, - Qt::SizeMode = Qt::AbsoluteSize, bool proportional = false ) noexcept; + Qt::SizeMode = Qt::AbsoluteSize ) noexcept; bool operator==( const QskArcMetrics& ) const noexcept; bool operator!=( const QskArcMetrics& ) const noexcept; @@ -53,19 +52,6 @@ class QSK_EXPORT QskArcMetrics void setThickness( qreal ) noexcept; constexpr qreal thickness() const noexcept; - /* - A proportional arc scales the thickness of the arc according to the - aspect ratio of the target rectangle. F.e when having a 20x10 rectangle - the thickness in west/east direction is doubled, while for a - 10x20 rectangle the thickness in north/south direction is doubled. - This matches the lines that result from a filling with a conic gradient. - - A non proportional arc will have a fixed thickness regardless of - the aspect ratio. - */ - void setProportional( bool ) noexcept; - constexpr bool isProportional() const noexcept; - void setSizeMode( Qt::SizeMode ) noexcept; constexpr Qt::SizeMode sizeMode() const noexcept; @@ -92,22 +78,20 @@ class QSK_EXPORT QskArcMetrics qreal m_thickness = 0.0; bool m_relativeSize = false; - bool m_proportional = false; }; inline constexpr QskArcMetrics::QskArcMetrics( - qreal thickness, Qt::SizeMode sizeMode, bool proportional ) noexcept - : QskArcMetrics( 0.0, 360.0, thickness, sizeMode, proportional ) + qreal thickness, Qt::SizeMode sizeMode ) noexcept + : QskArcMetrics( 0.0, 360.0, thickness, sizeMode ) { } inline constexpr QskArcMetrics::QskArcMetrics( qreal startAngle, qreal spanAngle, - qreal thickness, Qt::SizeMode sizeMode, bool proportional ) noexcept + qreal thickness, Qt::SizeMode sizeMode ) noexcept : m_startAngle( startAngle ) , m_spanAngle( spanAngle ) , m_thickness( thickness ) , m_relativeSize( sizeMode == Qt::RelativeSize ) - , m_proportional( proportional ) { } @@ -117,8 +101,7 @@ inline bool QskArcMetrics::operator==( return qskFuzzyCompare( m_thickness, other.m_thickness ) && qskFuzzyCompare( m_startAngle, other.m_startAngle ) && qskFuzzyCompare( m_spanAngle, other.m_spanAngle ) - && ( m_relativeSize == other.m_relativeSize ) - && ( m_proportional == other.m_proportional ); + && ( m_relativeSize == other.m_relativeSize ); } inline bool QskArcMetrics::operator!=( @@ -162,11 +145,6 @@ inline constexpr Qt::SizeMode QskArcMetrics::sizeMode() const noexcept return m_relativeSize ? Qt::RelativeSize : Qt::AbsoluteSize; } -inline constexpr bool QskArcMetrics::isProportional() const noexcept -{ - return m_proportional; -} - #ifndef QT_NO_DEBUG_STREAM class QDebug; diff --git a/src/nodes/QskArcNode.cpp b/src/nodes/QskArcNode.cpp index eb9c8284..dc84e8fd 100644 --- a/src/nodes/QskArcNode.cpp +++ b/src/nodes/QskArcNode.cpp @@ -16,15 +16,21 @@ #include -#define ARC_RENDERER +// #define ARC_BORDER_NODE +#define ARC_FILL_NODE -#ifdef ARC_RENDERER +#ifdef ARC_BORDER_NODE using BorderNode = QskArcRenderNode; #else #include using BorderNode = QskStrokeNode; #endif +#ifdef ARC_FILL_NODE + using FillNode = QskArcRenderNode; +#else + using FillNode = QskShapeNode; +#endif namespace { @@ -114,7 +120,7 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics auto shadowNode = static_cast< QskArcShadowNode* >( QskSGNode::findChildNode( this, ShadowRole ) ); - auto fillNode = static_cast< QskShapeNode* >( + auto fillNode = static_cast< FillNode* >( QskSGNode::findChildNode( this, FillRole ) ); auto borderNode = static_cast< BorderNode* >( @@ -168,11 +174,15 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics { if ( fillNode == nullptr ) { - fillNode = new QskShapeNode; + fillNode = new FillNode; QskSGNode::setNodeRole( fillNode, FillRole ); } +#ifdef ARC_FILL_NODE + fillNode->updateNode( arcRect, metricsArc, gradient ); +#else fillNode->updateNode( path, QTransform(), arcRect, gradient ); +#endif } else { @@ -188,9 +198,8 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics QskSGNode::setNodeRole( borderNode, BorderRole ); } -#ifdef ARC_RENDERER - borderNode->updateNode( arcRect, metricsArc, borderWidth, - borderColor, gradient ); +#ifdef ARC_BORDER_NODE + borderNode->updateNode( arcRect, metricsArc, borderWidth, borderColor ); #else QPen pen( borderColor, borderWidth ); pen.setCapStyle( Qt::FlatCap ); diff --git a/src/nodes/QskArcRenderNode.cpp b/src/nodes/QskArcRenderNode.cpp index b84cb92a..e29dee39 100644 --- a/src/nodes/QskArcRenderNode.cpp +++ b/src/nodes/QskArcRenderNode.cpp @@ -49,6 +49,18 @@ QskArcRenderNode::QskArcRenderNode() setFlag( QSGNode::OwnsMaterial, false ); } +void QskArcRenderNode::updateNode( const QRectF& rect, + const QskArcMetrics& metrics, const QskGradient& gradient ) +{ + updateNode( rect, metrics, 0.0, QColor(), gradient ); +} + +void QskArcRenderNode::updateNode( const QRectF& rect, + const QskArcMetrics& metrics, qreal borderWidth, const QColor& borderColor ) +{ + updateNode( rect, metrics, borderWidth, borderColor, QskGradient() ); +} + void QskArcRenderNode::updateNode( const QRectF& rect, const QskArcMetrics& metrics, qreal borderWidth, const QColor& borderColor, const QskGradient& gradient ) @@ -86,8 +98,16 @@ void QskArcRenderNode::updateNode( { d->hash = hash; - QskArcRenderer::renderBorder( - rect, metrics, borderWidth, borderColor, *geometry() ); + if ( borderWidth > 0.0 ) + { + QskArcRenderer::renderBorder( + rect, metrics, borderWidth, borderColor, *geometry() ); + } + else + { + QskArcRenderer::renderFillGeometry( + rect, metrics, *geometry() ); + } markDirty( QSGNode::DirtyGeometry ); markDirty( QSGNode::DirtyMaterial ); diff --git a/src/nodes/QskArcRenderNode.h b/src/nodes/QskArcRenderNode.h index c47879a0..70a06e89 100644 --- a/src/nodes/QskArcRenderNode.h +++ b/src/nodes/QskArcRenderNode.h @@ -21,6 +21,10 @@ class QSK_EXPORT QskArcRenderNode : public QSGGeometryNode public: QskArcRenderNode(); + void updateNode( const QRectF&, const QskArcMetrics&, const QskGradient& ); + void updateNode( const QRectF&, const QskArcMetrics&, qreal borderWidth, + const QColor& borderColor ); + void updateNode( const QRectF&, const QskArcMetrics&, qreal borderWidth, const QColor& borderColor, const QskGradient& ); diff --git a/src/nodes/QskArcRenderer.cpp b/src/nodes/QskArcRenderer.cpp index e80c5275..ae0f276b 100644 --- a/src/nodes/QskArcRenderer.cpp +++ b/src/nodes/QskArcRenderer.cpp @@ -9,10 +9,7 @@ #include "QskVertex.h" #include - -#if 1 #include -#endif static inline QskVertex::Line* qskAllocateLines( QSGGeometry& geometry, int lineCount ) @@ -28,36 +25,6 @@ static inline QskVertex::ColoredLine* qskAllocateColoredLines( return reinterpret_cast< QskVertex::ColoredLine* >( geometry.vertexData() ); } -static inline int qskApproximatedCircumference( const QRectF& rect ) -{ - const qreal a = rect.width(); - const qreal b = rect.height(); - - const auto ratio = a / b; - if ( ratio > 0.9 || ratio < 1.1 ) - return std::max( a, b ) * 2.0 * M_PI; // circle - - // Srinivasa Ramanujan: https://en.wikipedia.org/wiki/Ellipse#Circumference - - const qreal d1 = ( a - b ); - const qreal d2 = ( a + b ); - const qreal h = ( d1 * d1 ) / ( d2 * d2 ); - - return M_PI * d2 * ( 1.0 + ( 3 * h / ( 10 + sqrt( 4 - 3 * h ) ) ) ); -} - -static inline int qskStepCount( const QRectF& rect ) -{ -#if 0 - const auto dist = 3.0; -#else - const auto dist = 20.0; -#endif - - const int length = qskApproximatedCircumference( rect ); - return std::max( 3, qCeil( length / dist ) ); -} - namespace { class AngleIterator @@ -73,14 +40,13 @@ namespace inline int step() const { return m_stepIndex; } inline int stepCount() const { return m_stepCount; } - inline bool isDone() const { return m_stepIndex > m_stepCount; } + inline bool isDone() const { return m_stepIndex >= m_stepCount; } private: double m_cos; double m_sin; int m_stepIndex; - int m_stepCount; const double m_radians1; @@ -93,7 +59,7 @@ namespace , m_stepCount( stepCount ) , m_radians1( radians1 ) , m_radians2( radians2 ) - , m_radiansStep( ( radians2 - radians1 ) / stepCount ) + , m_radiansStep( ( radians2 - radians1 ) / ( stepCount - 1 ) ) { m_cos = qFastCos( radians1 ); m_sin = qFastSin( radians1 ); @@ -130,15 +96,11 @@ namespace int borderCount() const; int setBorderLines( QskVertex::ColoredLine*, const QskVertex::Color ) const; - int setBorderLines( QskVertex::Line* ) const; + int setFillLines( QskVertex::ColoredLine*, const QskVertex::Color ) const; private: - int arcLineCount() const; - - void setArcLines( QskVertex::ColoredLine*, int lineCount, - const QPointF&, const QSizeF&, - const qreal radians1, const qreal radians2, - qreal arcWidth, const QskVertex::Color ) const; + int arcLineCount( qreal radians = 2.0 * M_PI ) const; + QLineF fillLineAt( qreal x, qreal y, qreal sin, qreal cos ) const; const QRectF& m_rect; const QskArcMetrics& m_metrics; @@ -156,17 +118,35 @@ namespace int Stroker::fillCount() const { - return 0; // TODO + int n = 0; + + qreal radians1 = qDegreesToRadians( m_metrics.startAngle() ); + qreal radians2 = qDegreesToRadians( m_metrics.endAngle() ); + + if ( radians2 < radians1 ) + qSwap( radians1, radians2 ); + + for ( auto r = qFloor( radians1 / M_PI_2 ) * M_PI_2; + r < radians2; r += M_PI_2 ) + { + const auto r1 = qMax( r, radians1 ); + const auto r2 = qMin( r + M_PI_2, radians2 ); + + n += arcLineCount( r2 - r1 ); + } + + return n; } - int Stroker::arcLineCount() const + int Stroker::arcLineCount( const qreal radians ) const { - if ( m_metrics.isNull() ) - return 0; + // not very sophisticated - TODO ... - int n = qskStepCount( m_rect ); - if ( !m_metrics.isClosed() ) - n = qCeil( n * qAbs( m_metrics.spanAngle() ) / 360.0 ); + const auto ratio = qAbs( radians ) / ( 2.0 * M_PI ); + + int n = ( m_rect.width() + m_rect.height() ) * M_PI_2; + n = qBound( 3, n, 80 ); + n = qCeil( n * ratio ); return n; } @@ -176,122 +156,115 @@ namespace if ( m_metrics.isNull() ) return 0; - return 2 * arcLineCount() + 1; - } - - void Stroker::setArcLines( QskVertex::ColoredLine* lines, int lineCount, - const QPointF& center, const QSizeF& size, - const qreal radians1, const qreal radians2, - qreal arcWidth, const QskVertex::Color color ) const - { - const auto w1 = size.width(); - const auto h1 = size.height(); - - const auto w2 = w1 - arcWidth; - const auto h2 = h1 - arcWidth; - - auto l = lines; - - for ( AngleIterator it( radians1, radians2, lineCount - 1 ); !it.isDone(); ++it ) - { - const auto x1 = center.x() + w1 * it.cos(); - const auto x2 = center.x() + w2 * it.cos(); - - const auto y1 = center.y() + h1 * it.sin(); - const auto y2 = center.y() + h2 * it.sin(); - - l++->setLine( x1, y1, x2, y2, color ); - } - - if ( l - lines != lineCount ) - qWarning() << lineCount << "->" << l - lines; - Q_ASSERT( l - lines == lineCount ); - } - - int Stroker::setBorderLines( QskVertex::Line* ) const - { return 0; } int Stroker::setBorderLines( QskVertex::ColoredLine* lines, const QskVertex::Color color ) const { + Q_UNUSED( lines ); + Q_UNUSED( color ); + + return 0; + } + + int Stroker::setFillLines( QskVertex::ColoredLine* lines, + const QskVertex::Color color ) const + { + qreal radians1 = qDegreesToRadians( m_metrics.startAngle() ); + qreal radians2 = qDegreesToRadians( m_metrics.endAngle() ); + + if ( m_metrics.spanAngle() < 0.0 ) + std::swap( radians1, radians2 ); + + const qreal w = 0.5 * ( m_rect.width() - m_metrics.thickness() ); + const qreal h = 0.5 * ( m_rect.height() - m_metrics.thickness() ); + const auto center = m_rect.center(); - const qreal radians1 = qDegreesToRadians( m_metrics.startAngle() ); - const qreal radians2 = qDegreesToRadians( m_metrics.endAngle() ); + auto l = lines; - const int n = arcLineCount(); - - auto size = 0.5 * m_rect.size(); - - setArcLines( lines, n, center, size, - radians1, radians2, m_borderWidth, color ); - - const bool stretched = true; - - if ( !stretched ) + for ( auto r = qFloor( radians1 / M_PI_2 ) * M_PI_2; + r < radians2; r += M_PI_2 ) { - size.rwidth() -= m_metrics.thickness() - m_borderWidth; - size.rheight() -= m_metrics.thickness() - m_borderWidth; - } - else - { - qreal tx = m_metrics.thickness(); - qreal ty = m_metrics.thickness(); + const auto r1 = qMax( r, radians1 ); + const auto r2 = qMin( r + M_PI_2, radians2 ); - const qreal ratio = m_rect.width() / m_rect.height(); + const auto lineCount = arcLineCount( r2 - r1 ); - if ( ratio >= 1.0 ) - tx *= ratio; - else - ty /= ratio; + for ( AngleIterator it( r1, r2, lineCount ); !it.isDone(); ++it ) + { + const auto line = fillLineAt( w, h, it.cos(), it.sin() ); - size.rwidth() -= tx; - size.rheight() -= ty; + l++->setLine( center.x() + line.x1(), center.y() - line.y1(), + center.x() + line.x2(), center.y() - line.y2(), color ); + } } - setArcLines( lines + n + 1, n, center, size, - radians2, radians1, m_borderWidth, color ); - - lines[n] = { lines[n - 1].p2, lines[n + 1].p1 }; - - return 2 * n + 1; + return l - lines; } -} -void QskArcRenderer::renderBorderGeometry( const QRectF& rect, - const QskArcMetrics& metrics, qreal borderWidth, QSGGeometry& geometry ) -{ - geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip ); - - Stroker stroker( rect, metrics, borderWidth ); - - const auto lineCount = stroker.borderCount(); - - const auto lines = qskAllocateLines( geometry, lineCount ); - if ( lines ) + inline qreal sqr( qreal x ) { - const auto effectiveCount = stroker.setBorderLines( lines ); - if ( lineCount != effectiveCount ) + return x * x; + } + + QLineF Stroker::fillLineAt( qreal w, qreal h, qreal cos, qreal sin ) const + { + const auto x = w * cos; + const auto y = h * sin; + + /* + The inner/outer points are found by shifting along the + normal vector of the tangent at the ellipse point. + */ + + const auto t = 0.5 * m_metrics.thickness(); + + if ( qFuzzyIsNull( sin ) ) { - qWarning() << lineCount << effectiveCount; + const qreal dx = cos * t; + return QLineF( x + dx, y, x - dx, y ); } + else if ( qFuzzyIsNull( cos ) ) + { + const qreal dy = sin * t; + return QLineF( x, y + dy, x, y - dy ); + } + + const qreal m = qSqrt( w * w - x * x ) * ( w / h ) / x; + const auto dt = t * qSqrt( ( 1.0 / ( 1.0 + m * m ) ) ); + + const qreal dx = ( x >= 0 ) ? dt : -dt; + const qreal dy = m * ( ( y >= 0 ) ? dx : -dx ); + + const auto x1 = x + dx; + const auto y1 = y + dy; + + const auto x2 = x - dx; + const auto y2 = y - dy; + + return QLineF( x1, y1, x2, y2 ); } } void QskArcRenderer::renderFillGeometry( const QRectF& rect, const QskArcMetrics& metrics, qreal borderWidth, QSGGeometry& geometry ) { - Q_UNUSED( rect ); - Q_UNUSED( geometry ); + geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip ); Stroker stroker( rect, metrics, borderWidth ); - const auto lines = qskAllocateColoredLines( geometry, stroker.fillCount() ); + const auto lineCount = stroker.fillCount(); + + const auto lines = qskAllocateColoredLines( geometry, lineCount ); if ( lines ) { - // TODO + const auto effectiveCount = stroker.setFillLines( lines, QColor( Qt::darkRed ) ); + if ( lineCount != effectiveCount ) + { + qWarning() << lineCount << effectiveCount; + } } }