From 77c39cdd05e422705945849f76055e0d9f3ed29a Mon Sep 17 00:00:00 2001 From: "Vogel, Rick" Date: Thu, 20 Jul 2023 12:01:16 +0200 Subject: [PATCH] add rotation per subcontrol --- playground/levelingsensor/SkinFactory.cpp | 44 +- playground/levelingsensor/main.cpp | 37 +- .../LevelingSensor/QskLevelingSensor.cpp | 74 +-- .../LevelingSensor/QskLevelingSensor.h | 21 +- .../QskLevelingSensorSkinlet.cpp | 525 ++++++++++-------- 5 files changed, 405 insertions(+), 296 deletions(-) diff --git a/playground/levelingsensor/SkinFactory.cpp b/playground/levelingsensor/SkinFactory.cpp index 894574f6..12fb02f4 100644 --- a/playground/levelingsensor/SkinFactory.cpp +++ b/playground/levelingsensor/SkinFactory.cpp @@ -96,7 +96,7 @@ namespace } template<> - void style< QskLevelingSensor >( QskSkinHintTableEditor& ed ) + void style< QskLevelingSensor >( QskSkinHintTableEditor& editor ) { using Q = QskLevelingSensor; @@ -111,34 +111,36 @@ namespace } }; gradient.setLinearDirection( Qt::Vertical ); - ed.setColor( Q::Background, "dimgray" ); + editor.setColor( Q::Background, "dimgray" ); - ed.setStrutSize( Q::OuterDisk, { r2, r2 } ); - ed.setColor( Q::OuterDisk, Qt::white ); + editor.setStrutSize( Q::OuterDisk, { r2, r2 } ); + editor.setColor( Q::OuterDisk, Qt::white ); - ed.setGradient( Q::Horizon, gradient ); - ed.setStrutSize( Q::Horizon, { r1, r1 } ); + editor.setGradient( Q::Horizon, gradient ); + editor.setStrutSize( Q::Horizon, { r1, r1 } ); - ed.setColor( Q::TickmarksX, Qt::black ); - ed.setStrutSize( Q::TickmarksX, { r1, 0.2 } ); // w %, h % - ed.setHint( Q::TickmarksX, QVector3D{ 0.50, 0.75, 1.0 } ); // % + editor.setColor( Q::TickmarksX, Qt::black ); + editor.setStrutSize( Q::TickmarksX, { r1, 0.2 } ); // w %, h % + editor.setHint( Q::TickmarksX, QVector3D{ 0.50, 0.75, 1.0 } ); // % + editor.setAlignment(Q::TickmarksX, Qt::AlignCenter); - ed.setStrutSize( Q::TickmarksXLabels, { r1, 0.15 } ); // w %, h % - ed.setAlignment( Q::TickmarksXLabels, Qt::AlignTop | Qt::AlignHCenter ); + editor.setStrutSize( Q::TickmarksXLabels, { r1, 0.15 } ); // w %, h % + editor.setAlignment( Q::TickmarksXLabels, Qt::AlignTop | Qt::AlignHCenter ); - ed.setColor( Q::TickmarksY, Qt::black ); - ed.setStrutSize( Q::TickmarksY, { 0.1, r1 } ); // w %, h % - ed.setHint( Q::TickmarksY, QVector3D{ 0.50, 0.75, 1.00 } ); // % + editor.setColor( Q::TickmarksY, Qt::black ); + editor.setStrutSize( Q::TickmarksY, { 0.1, r1 } ); // w %, h % + editor.setHint( Q::TickmarksY, QVector3D{ 0.50, 0.75, 1.00 } ); // % + editor.setAlignment(Q::TickmarksY, Qt::AlignCenter); - ed.setStrutSize( Q::TickmarksYLabels, { 0.15, r1 } ); // w %, h % - ed.setAlignment( Q::TickmarksYLabels, Qt::AlignCenter ); + editor.setStrutSize( Q::TickmarksYLabels, { 0.15, r1 } ); // w %, h % + editor.setAlignment( Q::TickmarksYLabels, Qt::AlignCenter ); - ed.setColor( Q::TickmarksZ, "silver" ); - ed.setStrutSize( Q::TickmarksZ, { 0.90, 0.95 } ); - ed.setHint( Q::TickmarksZ, QVector3D{ 0.50, 0.75, 1.00 } ); // % + editor.setColor( Q::TickmarksZ, "silver" ); + editor.setStrutSize( Q::TickmarksZ, { 0.90, 0.95 } ); + editor.setHint( Q::TickmarksZ, QVector3D{ 0.50, 0.75, 1.00 } ); // % - ed.setStrutSize( Q::TickmarksZLabels, { 0.9, 0.0 } ); // r1 %, r2 % - ed.setAlignment( Q::TickmarksZLabels, Qt::AlignCenter ); + editor.setStrutSize( Q::TickmarksZLabels, { 0.9, 0.0 } ); // r1 %, r2 % + editor.setAlignment( Q::TickmarksZLabels, Qt::AlignCenter ); } public: diff --git a/playground/levelingsensor/main.cpp b/playground/levelingsensor/main.cpp index 694b1c40..ab93ceb3 100644 --- a/playground/levelingsensor/main.cpp +++ b/playground/levelingsensor/main.cpp @@ -87,17 +87,26 @@ namespace } Q_REQUIRED_RESULT QskSlider* makeRotationSlider( - const Qt::Axis axis, QskLevelingSensor* const sensor, QQuickItem* const parent = nullptr ) + const Qt::Axis axis, QskLevelingSensor* const sensor, const QskAspect::Subcontrol subControl, QQuickItem* const parent = nullptr ) { auto* const slider = new QskSlider( Qt::Horizontal, parent ); slider->setMinimum( -360 ); slider->setMaximum( +360 ); - QObject::connect( sensor, &QskLevelingSensor::rotationChanged, slider, - [ slider, axis ]( const QVector3D& degree ) { slider->setValue( degree[ axis ] ); } ); + QObject::connect( sensor, &QskLevelingSensor::subControlRotationChanged, slider, + [ = ]( const QskAspect::Subcontrol control, const QVector3D& degree ) { + if(control == subControl) + { + slider->setValue( degree[ axis ] ); + } + } ); QObject::connect( slider, &QskSlider::valueChanged, sensor, - [ sensor, axis ]( const qreal degree ) { sensor->setRotation( axis, degree ); } ); + [ = ]( const qreal degree ) { + auto d = sensor->subControlRotation( subControl ); + d[ axis ] = degree; + sensor->setSubControlRotation( subControl, d ); + } ); return slider; } @@ -108,6 +117,8 @@ namespace Window() { auto* const root = new QskLinearBox( Qt::Horizontal, contentItem() ); + root->setSpacing(8); + root->setMargins(8); auto* const left = new QskLinearBox( Qt::Vertical, root ); auto* const right = new QskLinearBox( Qt::Vertical, root ); auto* const sensor = new QskLevelingSensor( left ); @@ -125,12 +136,18 @@ namespace ( void ) new QskTextLabel( "Tickmarks Z", right ); auto* const sliderTickmarksZ = makeTickmarksSlider( Qt::ZAxis, sensor, 0, 90, radialIntervalA, radialIntervalB, right ); - ( void ) new QskTextLabel( "Rotation X", right ); - ( void ) makeRotationSlider( Qt::XAxis, sensor, right ); - ( void ) new QskTextLabel( "Rotation Y", right ); - ( void ) makeRotationSlider( Qt::YAxis, sensor, right ); - ( void ) new QskTextLabel( "Rotation Z", right ); - ( void ) makeRotationSlider( Qt::ZAxis, sensor, right ); + ( void ) new QskTextLabel( "Rotation X Plane", right ); + ( void ) makeRotationSlider( Qt::XAxis, sensor, QskLevelingSensor::TickmarksX, right ); + ( void ) makeRotationSlider( Qt::YAxis, sensor, QskLevelingSensor::TickmarksX, right ); + ( void ) makeRotationSlider( Qt::ZAxis, sensor, QskLevelingSensor::TickmarksX, right ); + ( void ) new QskTextLabel( "Rotation Y Plane", right ); + ( void ) makeRotationSlider( Qt::XAxis, sensor, QskLevelingSensor::TickmarksY, right ); + ( void ) makeRotationSlider( Qt::YAxis, sensor, QskLevelingSensor::TickmarksY, right ); + ( void ) makeRotationSlider( Qt::ZAxis, sensor, QskLevelingSensor::TickmarksY, right ); + ( void ) new QskTextLabel( "Rotation Z Plane", right ); + ( void ) makeRotationSlider( Qt::XAxis, sensor, QskLevelingSensor::TickmarksZ, right ); + ( void ) makeRotationSlider( Qt::YAxis, sensor, QskLevelingSensor::TickmarksZ, right ); + ( void ) makeRotationSlider( Qt::ZAxis, sensor, QskLevelingSensor::TickmarksZ, right ); sliderTickmarksX->setValue(15); sliderTickmarksY->setValue(15); diff --git a/src/controls/LevelingSensor/QskLevelingSensor.cpp b/src/controls/LevelingSensor/QskLevelingSensor.cpp index a04b84af..6295f651 100644 --- a/src/controls/LevelingSensor/QskLevelingSensor.cpp +++ b/src/controls/LevelingSensor/QskLevelingSensor.cpp @@ -42,50 +42,23 @@ QSK_SUBCONTROL(QskLevelingSensor, TickmarksZLabels) #define RETURN_IF_FALSE(expr) if(!(expr)) return; +using Q = QskLevelingSensor; + QskLevelingSensor::QskLevelingSensor(QQuickItem* const parent) : Inherited(parent) { } -void QskLevelingSensor::setRotation(const QVector3D& degree) -{ - if (m_rotation != degree) - { - setRotation(Qt::XAxis, degree.x()); - setRotation(Qt::YAxis, degree.y()); - setRotation(Qt::ZAxis, degree.z()); - } -} - -void QskLevelingSensor::setRotation(const Qt::Axis axis, const float degree) -{ - RETURN_IF_FALSE(isAxis(axis)); - - if (compareExchange(m_rotation[axis], degree)) - { - update(); - switch(axis) - { - case Qt::XAxis: Q_EMIT rotationXChanged(m_rotation[axis]); break; - case Qt::YAxis: Q_EMIT rotationYChanged(m_rotation[axis]); break; - case Qt::ZAxis: Q_EMIT rotationZChanged(m_rotation[axis]); break; - } - Q_EMIT rotationChanged(m_rotation); - } -} - void QskLevelingSensor::setTickmarks(const Qt::Axis axis, QskScaleTickmarks tickmarks) { RETURN_IF_FALSE(isAxis(axis)); - m_tickmarks[axis] = std::move(tickmarks); update(); } void QskLevelingSensor::setTickmarksLabels(const Qt::Axis axis, TickmarksLabels labels) { - RETURN_IF_FALSE(isAxis(axis)); - + RETURN_IF_FALSE(isAxis(axis)); m_tickmarksLabels[axis] = std::move(labels); update(); } @@ -135,9 +108,46 @@ const QVector3D& QskLevelingSensor::angle() const noexcept return m_angle; } -const QVector3D& QskLevelingSensor::rotation() const noexcept +const QVector3D& QskLevelingSensor::subControlRotation(const QskAspect::Subcontrol subControl) const noexcept { - return m_rotation; + static const QVector3D notFound; + const auto found = m_subControlRotation.find(subControl); + if(found == m_subControlRotation.end()) { + return notFound; + } + return found->second; +} + +void QskLevelingSensor::setSubControlRotation(const QskAspect::Subcontrol subControl, const QVector3D& degree) +{ + auto updateSubControlRotation = [this](const QskAspect::Subcontrol subControl, const QVector3D& degree) + { + if ( compareExchange( m_subControlRotation[ subControl ], degree ) ) + { + Q_EMIT subControlRotationChanged(subControl, degree); + update(); + } + }; + + if(subControl == Q::TickmarksX || subControl == Q::TickmarksXLabels) + { + updateSubControlRotation(Q::TickmarksX, degree); + updateSubControlRotation(Q::TickmarksXLabels, degree); + } + else if(subControl == Q::TickmarksY || subControl == Q::TickmarksYLabels) + { + updateSubControlRotation(Q::TickmarksY, degree); + updateSubControlRotation(Q::TickmarksYLabels, degree); + } + else if(subControl == Q::TickmarksZ || subControl == TickmarksZLabels) + { + updateSubControlRotation(TickmarksZ, degree); + updateSubControlRotation(TickmarksZLabels, degree); + } + else + { + updateSubControlRotation(subControl, degree); + } } #include "moc_QskLevelingSensor.cpp" \ No newline at end of file diff --git a/src/controls/LevelingSensor/QskLevelingSensor.h b/src/controls/LevelingSensor/QskLevelingSensor.h index 2b514246..89a05032 100644 --- a/src/controls/LevelingSensor/QskLevelingSensor.h +++ b/src/controls/LevelingSensor/QskLevelingSensor.h @@ -5,6 +5,8 @@ #include #include +#include + class QSK_EXPORT QskLevelingSensor : public QskControl { Q_OBJECT @@ -23,26 +25,31 @@ public: using TickmarksLabels = QVector>; explicit QskLevelingSensor(QQuickItem* parent = nullptr); public Q_SLOTS: - void setRotation(const QVector3D& degree); - void setRotation(Qt::Axis axis, float degree); void setTickmarks(Qt::Axis axis, Tickmarks tickmarks); void setTickmarksLabels(Qt::Axis axis, TickmarksLabels labels); void setAngle(const QVector3D& degree); void setAngle(Qt::Axis axis, float degree); + + void setSubControlRotation(QskAspect::Subcontrol subControl, const QVector3D& degree); + Q_SIGNALS: - void rotationXChanged(qreal degree); - void rotationYChanged(qreal degree); - void rotationZChanged(qreal degree); - void rotationChanged(const QVector3D& degree); void anglesChanged(const QVector3D& degree); + void subControlRotationChanged(QskAspect::Subcontrol subControl, const QVector3D& degree); + public: - Q_REQUIRED_RESULT const QVector3D& rotation() const noexcept; Q_REQUIRED_RESULT const Tickmarks& tickmarks(Qt::Axis axis) const; Q_REQUIRED_RESULT const TickmarksLabels& tickmarkLabels(Qt::Axis axis) const; Q_REQUIRED_RESULT const QVector3D& angle() const noexcept; + Q_REQUIRED_RESULT const QVector3D& subControlRotation(QskAspect::Subcontrol subControl) const noexcept; + private: + + // TODO use pimpl + QVector3D m_rotation; QVector3D m_angle = { 45,45,45 }; Tickmarks m_tickmarks[3]; TickmarksLabels m_tickmarksLabels[3]; + + std::unordered_map m_subControlRotation; }; \ No newline at end of file diff --git a/src/controls/LevelingSensor/QskLevelingSensorSkinlet.cpp b/src/controls/LevelingSensor/QskLevelingSensorSkinlet.cpp index 5e70632f..d904e8ba 100644 --- a/src/controls/LevelingSensor/QskLevelingSensorSkinlet.cpp +++ b/src/controls/LevelingSensor/QskLevelingSensorSkinlet.cpp @@ -1,7 +1,7 @@ #include "QskLevelingSensorSkinlet.h" #include "QskLevelingSensor.h" -#include "QskLevelingSensorUtility.h" #include "QskLevelingSensorNodes.h" +#include "QskLevelingSensorUtility.h" #include "QskSGNodeUtility.h" #include @@ -24,34 +24,86 @@ #include #include +namespace +{ + template< typename T > + struct State; + + template<> + struct State< QskLevelingSensor > + { + qreal r1 = 0.0; + qreal r2 = 0.0; + qreal cX = 0.0; + qreal cY = 0.0; + qreal sX = 0.0; + qreal sY = 0.0; + qreal sZ = 0.0; + + explicit State( const QskLevelingSensor* const sensor ) + : r1( QskLevelingSensorSkinlet::innerRadius( sensor ) ) + , r2( QskLevelingSensorSkinlet::outerRadius( sensor ) ) + , cX( QskLevelingSensorSkinlet::center( sensor ).x() ) + , cY( QskLevelingSensorSkinlet::center( sensor ).y() ) + , sX( r1 / sensor->angle().x() ) + , sY( r1 / sensor->angle().y() ) + , sZ( r1 / sensor->angle().z() ) + { + } + }; + + template<> + struct State< QskAspect::Subcontrol > : State< QskLevelingSensor > + { + qreal rX = 0.0; + qreal rY = 0.0; + qreal rZ = 0.0; + qreal tX = 0.0; + qreal tY = 0.0; + qreal tZ = 0.0; + + State( const QskLevelingSensor* const sensor, QskAspect::Subcontrol subcontrol ) + : State< QskLevelingSensor >( sensor ) + , rX( sensor->subControlRotation( subcontrol ).x() ) + , rY( sensor->subControlRotation( subcontrol ).y() ) + , rZ( sensor->subControlRotation( subcontrol ).z() ) + , tX( rY * sX ) + , tY( rX * sY ) + , tZ( 0.0 ) + { + } + }; + +} + using Q = QskLevelingSensor; using R = QskLevelingSensorSkinlet::NodeRole; using namespace QskSGNode; -float QskLevelingSensorSkinlet::outerRadius(const QskSkinnable* const skinnable) +float QskLevelingSensorSkinlet::outerRadius( const QskSkinnable* const skinnable ) { - const auto* const sensor = static_cast(skinnable); + const auto* const sensor = static_cast< const Q* >( skinnable ); const auto contentsRect = sensor->contentsRect(); - return 0.5f * qMin(contentsRect.width(), contentsRect.height()); + return 0.5f * qMin( contentsRect.width(), contentsRect.height() ); } -float QskLevelingSensorSkinlet::innerRadius(const QskSkinnable* const skinnable) +float QskLevelingSensorSkinlet::innerRadius( const QskSkinnable* const skinnable ) { - const auto scale = skinnable->strutSizeHint(Q::Horizon); - return outerRadius(skinnable) * scale.width(); + const auto scale = skinnable->strutSizeHint( Q::Horizon ); + return outerRadius( skinnable ) * scale.width(); } -QPointF QskLevelingSensorSkinlet::center(const QskSkinnable* const skinnable) +QPointF QskLevelingSensorSkinlet::center( const QskSkinnable* const skinnable ) { - const auto* const sensor = static_cast(skinnable); + const auto* const sensor = static_cast< const Q* >( skinnable ); return sensor->contentsRect().center(); } -QskLevelingSensorSkinlet::QskLevelingSensorSkinlet(QskSkin* skin) - : Inherited(skin) +QskLevelingSensorSkinlet::QskLevelingSensorSkinlet( QskSkin* skin ) + : Inherited( skin ) { - setNodeRoles({ + setNodeRoles( { OuterDisk, Horizon, HorizonClip, @@ -60,19 +112,20 @@ QskLevelingSensorSkinlet::QskLevelingSensorSkinlet(QskSkin* skin) TickmarksY, TickmarksYLabels, TickmarksZ, - TickmarksZLabels, }); + TickmarksZLabels, + } ); } -template -Q_REQUIRED_RESULT QRectF QskLevelingSensorSkinlet::subControlRect(const QskLevelingSensor* const sensor, - const QRectF& contentsRect) const = delete; +template< QskLevelingSensorSkinlet::NodeRole > +Q_REQUIRED_RESULT QRectF QskLevelingSensorSkinlet::subControlRect( + const QskLevelingSensor* const sensor, const QRectF& contentsRect ) const = delete; template<> -Q_REQUIRED_RESULT QRectF QskLevelingSensorSkinlet::subControlRect(const QskLevelingSensor* const sensor, - const QRectF& contentsRect) const +Q_REQUIRED_RESULT QRectF QskLevelingSensorSkinlet::subControlRect< R::OuterDisk >( + const QskLevelingSensor* const sensor, const QRectF& contentsRect ) const { - const auto radius = outerRadius(sensor); - const auto scale = sensor->strutSizeHint(Q::OuterDisk); + const auto radius = outerRadius( sensor ); + const auto scale = sensor->strutSizeHint( Q::OuterDisk ); const auto width = 2 * radius * scale.width(); const auto height = width; const auto x = contentsRect.center().x() - width / 2; @@ -81,333 +134,353 @@ Q_REQUIRED_RESULT QRectF QskLevelingSensorSkinlet::subControlRect( } template<> -Q_REQUIRED_RESULT QRectF QskLevelingSensorSkinlet::subControlRect(const QskLevelingSensor* const sensor, - const QRectF& contentsRect) const +Q_REQUIRED_RESULT QRectF QskLevelingSensorSkinlet::subControlRect< R::Horizon >( + const QskLevelingSensor* const sensor, const QRectF& contentsRect ) const { - const auto scale = sensor->strutSizeHint(Q::Horizon); - const auto width = 2 * innerRadius(sensor) * scale.width(); + const auto scale = sensor->strutSizeHint( Q::Horizon ); + const auto width = 2 * innerRadius( sensor ) * scale.width(); const auto height = width; - return { - center(sensor).x() - width / 2, - center(sensor).y() - height / 2, - width, - height - }; + return { center( sensor ).x() - width / 2, center( sensor ).y() - height / 2, width, height }; } -QRectF QskLevelingSensorSkinlet::subControlRect(const QskSkinnable* skinnable, - const QRectF& contentsRect, QskAspect::Subcontrol subControl) const +QRectF QskLevelingSensorSkinlet::subControlRect( const QskSkinnable* skinnable, + const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const { - const auto* const sensor = static_cast(skinnable); + const auto* const sensor = static_cast< const Q* >( skinnable ); - if (subControl == Q::OuterDisk) + if ( subControl == Q::OuterDisk ) { - return subControlRect(sensor, contentsRect); + return subControlRect< OuterDisk >( sensor, contentsRect ); } - if (subControl == Q::Horizon) + if ( subControl == Q::Horizon ) { - return subControlRect(sensor, contentsRect); + return subControlRect< Horizon >( sensor, contentsRect ); } - return Inherited::subControlRect(skinnable, contentsRect, subControl); + return Inherited::subControlRect( skinnable, contentsRect, subControl ); } -template -QSGNode* QskLevelingSensorSkinlet::updateSubNode(const QskLevelingSensor* const sensor, - const quint8 nodeRole, QSGNode* const node) const = delete; +template< QskLevelingSensorSkinlet::NodeRole > +QSGNode* QskLevelingSensorSkinlet::updateSubNode( const QskLevelingSensor* const sensor, + const quint8 nodeRole, QSGNode* const node ) const = delete; template<> -QSGNode* QskLevelingSensorSkinlet::updateSubNode(const QskLevelingSensor* const sensor, - const quint8 nodeRole, QSGNode* const node) const +QSGNode* QskLevelingSensorSkinlet::updateSubNode< R::OuterDisk >( + const QskLevelingSensor* const sensor, const quint8 nodeRole, QSGNode* const node ) const { const auto subControl = Q::OuterDisk; const auto contentsRect = sensor->contentsRect(); - const auto boxRect = subControlRect(sensor, contentsRect); + const auto boxRect = subControlRect< OuterDisk >( sensor, contentsRect ); const auto boxShapeMetrics = QskBoxShapeMetrics{ boxRect.width() / 2 }; - const auto boxBorderMetrics = sensor->boxBorderMetricsHint(subControl); - const auto boxBorderColors = sensor->boxBorderColorsHint(subControl); - const auto boxGradient = sensor->gradientHint(subControl); + const auto boxBorderMetrics = sensor->boxBorderMetricsHint( subControl ); + const auto boxBorderColors = sensor->boxBorderColorsHint( subControl ); + const auto boxGradient = sensor->gradientHint( subControl ); - auto* const root = ensure>::node(node); - auto* const bNode = static_cast(root->firstChild()); + auto* const root = ensure< QSGTransformNode, par< 1, QskBoxNode > >::node( node ); + auto* const bNode = static_cast< QskBoxNode* >( root->firstChild() ); - const auto size = outerRadius(sensor) * sensor->strutSizeHint(Q::OuterDisk).width(); - updateBoxNode(sensor, bNode, { 0, 0, 2 * size, 2 * size }, boxShapeMetrics, boxBorderMetrics, boxBorderColors, boxGradient); + const auto size = outerRadius( sensor ) * sensor->strutSizeHint( Q::OuterDisk ).width(); + updateBoxNode( sensor, bNode, { 0, 0, 2 * size, 2 * size }, boxShapeMetrics, boxBorderMetrics, + boxBorderColors, boxGradient ); - const auto cX = center(sensor).x(); - const auto cY = center(sensor).y(); + const auto cX = center( sensor ).x(); + const auto cY = center( sensor ).y(); const auto rZ = 0.0; - const auto matrix = - matrix_deg(0.0, 0.0, 0.0, cX, cY, 0) * - matrix_deg(0.0, 0.0, rZ, 0, 0, 0) * - matrix_deg(0.0, 0.0, 0.0, -size, -size, 0); + const auto matrix = matrix_deg( 0.0, 0.0, 0.0, cX, cY, 0 ) * + matrix_deg( 0.0, 0.0, rZ, 0, 0, 0 ) * + matrix_deg( 0.0, 0.0, 0.0, -size, -size, 0 ); - root->setMatrix(matrix); + root->setMatrix( matrix ); return root; } template<> -QSGNode* QskLevelingSensorSkinlet::updateSubNode(const QskLevelingSensor* const sensor, - const quint8 nodeRole, QSGNode* const node) const +QSGNode* QskLevelingSensorSkinlet::updateSubNode< R::Horizon >( + const QskLevelingSensor* const sensor, const quint8 nodeRole, QSGNode* const node ) const { const auto subControl = Q::Horizon; - const auto r1 = innerRadius(sensor); - const auto cX = center(sensor).x(); - const auto cY = center(sensor).y(); - const auto rX = sensor->rotation().x(); + const auto r1 = innerRadius( sensor ); + const auto cX = center( sensor ).x(); + const auto cY = center( sensor ).y(); + const auto rX = sensor->subControlRotation( subControl ).x(); const auto rZ = 0.0; const auto dY = 2 * sensor->angle().y(); - const auto p = qBound(0.0, 0.5 + (-rX / dY), 1.0); + const auto p = qBound( 0.0, 0.5 + ( -rX / dY ), 1.0 ); const auto shape = QskBoxShapeMetrics{ r1 }; - const auto bmetrics = sensor->boxBorderMetricsHint(subControl); - const auto bcolors = sensor->boxBorderColorsHint(subControl); + const auto bmetrics = sensor->boxBorderMetricsHint( subControl ); + const auto bcolors = sensor->boxBorderColorsHint( subControl ); - auto gradient = sensor->gradientHint(Q::Horizon); - gradient.setDirection(QskGradient::Linear); - gradient.setLinearDirection(Qt::Vertical); - gradient.setStops({ - {0.0, gradient.startColor()}, - {p, gradient.startColor()}, - {p, gradient.endColor()}, - {1.0, gradient.endColor()} - }); + auto gradient = sensor->gradientHint( Q::Horizon ); + gradient.setDirection( QskGradient::Linear ); + gradient.setLinearDirection( Qt::Vertical ); + gradient.setStops( { { 0.0, gradient.startColor() }, { p, gradient.startColor() }, + { p, gradient.endColor() }, { 1.0, gradient.endColor() } } ); - auto* const tNode = ensure>::node(node); - auto* const boxNode = static_cast(tNode->firstChild()); - updateBoxNode(sensor, boxNode, { 0, 0, 2 * r1, 2 * r1 }, shape, bmetrics, bcolors, gradient); + auto* const tNode = ensure< QSGTransformNode, par< 1, QskBoxNode > >::node( node ); + auto* const boxNode = static_cast< QskBoxNode* >( tNode->firstChild() ); + updateBoxNode( sensor, boxNode, { 0, 0, 2 * r1, 2 * r1 }, shape, bmetrics, bcolors, gradient ); - const auto matrix = - matrix_deg(0, 0, 0, cX, cY, 0) * - matrix_deg(0, 0, rZ, 0, 0, 0) * - matrix_deg(0, 0, 0, -r1, -r1, 0); + const auto matrix = matrix_deg( 0, 0, 0, cX, cY, 0 ) * matrix_deg( 0, 0, rZ, 0, 0, 0 ) * + matrix_deg( 0, 0, 0, -r1, -r1, 0 ); - tNode->setMatrix(matrix); + tNode->setMatrix( matrix ); return tNode; } template<> -QSGNode* QskLevelingSensorSkinlet::updateSubNode(const QskLevelingSensor* const sensor, - const quint8 nodeRole, QSGNode* const node) const +QSGNode* QskLevelingSensorSkinlet::updateSubNode< R::TickmarksX >( + const QskLevelingSensor* const sensor, const quint8 nodeRole, QSGNode* const node ) const { const auto subControl = Q::TickmarksX; - const auto color = sensor->color(subControl); - const auto scale = sensor->strutSizeHint(subControl); - - const auto cX = center(sensor).x(); - const auto cY = center(sensor).y(); + const auto color = sensor->color( subControl ); + const auto scale = sensor->strutSizeHint( subControl ); - const auto rX = sensor->rotation().x(); - const auto rY = sensor->rotation().y(); - const auto rZ = sensor->arcMetricsHint(subControl).startAngle(); + const auto cX = center( sensor ).x(); + const auto cY = center( sensor ).y(); - const auto r1 = innerRadius(sensor); + const auto rotation = sensor->subControlRotation( subControl ); + + const auto r1 = innerRadius( sensor ); + const auto r2 = outerRadius( sensor ); const auto r3 = r1 * scale.height(); const auto sX = r1 / sensor->angle().x(); const auto sY = r1 / sensor->angle().y(); - const auto tX = static_cast(rY * sX); - const auto tY = 0.0; // static_cast(rX * sY); + const auto tX = static_cast< float >( rotation.y() * sX ); + const auto tY = static_cast< float >( rotation.x() * sY ); - auto* const clipping = ensure>>::node(node); - auto* const transform = static_cast(clipping->firstChild()); - auto* const tickmarks = static_cast(transform->firstChild()); + auto* const clipping = + ensure< PolygonClipNode, par< 1, QSGTransformNode, par< 1, LinearTickmarksNode > > >::node( + node ); + auto* const transform = static_cast< QSGTransformNode* >( clipping->firstChild() ); + auto* const tickmarks = static_cast< LinearTickmarksNode* >( transform->firstChild() ); - auto size = qvariant_cast(sensor->effectiveSkinHint(subControl)) * r3; + auto size = qvariant_cast< QVector3D >( sensor->effectiveSkinHint( subControl ) ) * r3; - clipping->setGeometryProperties(r1, cX, cY); + clipping->setGeometryProperties( r1, cX, cY ); - tickmarks->setMaterialProperties(color); - tickmarks->setGeometryProperties(sensor->tickmarks(Qt::XAxis), size, {sX, 0.0f}, {tX, tY}); + tickmarks->setMaterialProperties( color ); + tickmarks->setGeometryProperties( + sensor->tickmarks( Qt::XAxis ), size, { sX, 0.0f }, { tX, tY } ); - const auto matrix = matrix_deg(0, 0, rZ, cX, cY, 0); - transform->setMatrix(matrix); + const auto matrix = matrix_deg( 0, 0, rotation.z(), cX, cY, 0 ); + transform->setMatrix( matrix ); return clipping; } template<> -QSGNode* QskLevelingSensorSkinlet::updateSubNode(const QskLevelingSensor* const sensor, - const quint8 nodeRole, QSGNode* const node) const +QSGNode* QskLevelingSensorSkinlet::updateSubNode< R::TickmarksY >( + const QskLevelingSensor* const sensor, const quint8 nodeRole, QSGNode* const node ) const { const auto subControl = Q::TickmarksY; - const auto color = sensor->color(subControl); - const auto scale = sensor->strutSizeHint(subControl); + const State< QskAspect::Subcontrol > state( sensor, subControl ); - const auto r1 = innerRadius(sensor); - const auto r3 = r1 * scale.width(); - - const auto rX = 0.00; - const auto rY = 0.00; - const auto rZ = sensor->rotation().z(); + const auto color = sensor->color( subControl ); + const auto scale = sensor->strutSizeHint( subControl ); - const auto tX = center(sensor).x(); - const auto tY = center(sensor).y(); - const auto tZ = 0.0; + const auto r3 = state.r1 * scale.width(); - auto* const cNode = ensure>>::node(node); - auto* const tNode = static_cast(cNode->firstChild()); - auto* const lNode = static_cast(tNode->firstChild()); + const auto rotation = sensor->subControlRotation( subControl ); - auto size = qvariant_cast(sensor->effectiveSkinHint(subControl)) * r3; + auto* const cNode = + ensure< PolygonClipNode, par< 1, QSGTransformNode, par< 1, LinearTickmarksNode > > >::node( + node ); + auto* const tNode = static_cast< QSGTransformNode* >( cNode->firstChild() ); + auto* const lNode = static_cast< LinearTickmarksNode* >( tNode->firstChild() ); - cNode->setGeometryProperties(r1, tX, tY); + auto size = qvariant_cast< QVector3D >( sensor->effectiveSkinHint( subControl ) ) * r3; - const auto sY = static_cast(r1 / sensor->angle().y()); - lNode->setMaterialProperties(color); -#ifdef USE_FILTERING - using TickType = QskScaleTickmarks::TickType; - const auto filter = [=](TickType, qreal v){ return rY - r1 / sY <= v && v <= rY + r1 / sY; }; - lNode->setGeometryProperties(filtered(sensor->tickmarks(Qt::YAxis), filter), size, {0.0f, sY}, {}, 1.0f, true); -#else - lNode->setGeometryProperties(sensor->tickmarks(Qt::YAxis), size, {0.0f, sY}); -#endif + cNode->setGeometryProperties( state.r1, state.cX, state.cY ); - const auto matrix = matrix_deg(rX, rY, rZ, tX, tY, tZ); - tNode->setMatrix(matrix); + const auto sY = static_cast< float >( state.r1 / sensor->angle().y() ); + lNode->setMaterialProperties( color ); + lNode->setGeometryProperties( sensor->tickmarks( Qt::YAxis ), size, { 0.0f, sY }, + { ( float ) state.tX, ( float ) state.tY } ); + + const auto matrix = matrix_deg( 0, 0, state.rZ, state.cX, state.cY ); + tNode->setMatrix( matrix ); return cNode; } template<> -QSGNode* QskLevelingSensorSkinlet::updateSubNode(const QskLevelingSensor* const sensor, - const quint8 nodeRole, QSGNode* const node) const +QSGNode* QskLevelingSensorSkinlet::updateSubNode< R::TickmarksZ >( + const QskLevelingSensor* const sensor, const quint8 nodeRole, QSGNode* const node ) const { const auto subControl = Q::TickmarksZ; - const auto color = sensor->color(subControl); - const auto scale = sensor->strutSizeHint(subControl); - - const auto r1 = innerRadius(sensor); - const auto r2 = outerRadius(sensor); - const auto r3 = qvariant_cast(sensor->effectiveSkinHint(subControl)) * (r2 - r1) + QVector3D{r1, r1, r1}; + const auto color = sensor->color( subControl ); + const auto scale = sensor->strutSizeHint( subControl ); - auto* const transform = ensure>::node(node); - auto* const tickmarksNode = static_cast(transform->firstChild()); - tickmarksNode->setMaterialProperties(color); - tickmarksNode->setGeometryProperties(sensor->tickmarks(Qt::ZAxis), r1, r3); + const auto r1 = innerRadius( sensor ); + const auto r2 = outerRadius( sensor ); + const auto r3 = + qvariant_cast< QVector3D >( sensor->effectiveSkinHint( subControl ) ) * ( r2 - r1 ) + + QVector3D{ r1, r1, r1 }; - const auto rZ = sensor->arcMetricsHint(subControl).startAngle(); - const auto tX = center(sensor).x(); - const auto tY = center(sensor).y(); + auto* const transform = ensure< QSGTransformNode, par< 1, RadialTickmarksNode > >::node( node ); + auto* const tickmarksNode = static_cast< RadialTickmarksNode* >( transform->firstChild() ); + tickmarksNode->setMaterialProperties( color ); + tickmarksNode->setGeometryProperties( sensor->tickmarks( Qt::ZAxis ), r1, r3 ); - const auto matrix = matrix_deg(0.0, 0.0, rZ, tX, tY); - transform->setMatrix(matrix); + const auto rZ = sensor->subControlRotation( subControl ).z(); + const auto tX = center( sensor ).x(); + const auto tY = center( sensor ).y(); + + const auto matrix = matrix_deg( 0.0, 0.0, rZ, tX, tY ); + transform->setMatrix( matrix ); return transform; } template<> -QSGNode* QskLevelingSensorSkinlet::updateSubNode(const QskLevelingSensor* const sensor, - const quint8 nodeRole, QSGNode* const node) const +QSGNode* QskLevelingSensorSkinlet::updateSubNode< R::TickmarksXLabels >( + const QskLevelingSensor* const sensor, const quint8 nodeRole, QSGNode* const node ) const { const auto subControl = Q::TickmarksXLabels; - - const auto r1 = innerRadius(sensor); - const auto r3 = static_cast(r1 * sensor->strutSizeHint(Q::TickmarksX).height()); + + const auto r1 = innerRadius( sensor ); + const auto r3 = static_cast< float >( r1 * sensor->strutSizeHint( Q::TickmarksX ).height() ); const auto sX = r1 / sensor->angle().x(); const auto sY = r1 / sensor->angle().y(); - const auto rZ = sensor->arcMetricsHint(subControl).startAngle(); - const auto cX = center(sensor).x(); - const auto cY = center(sensor).y(); - const auto tX = sensor->rotation().y() * sX; - const auto tY = r3; - auto* const cNode = ensure>>::node(node); - auto* const tNode = static_cast(cNode->firstChild()); - auto* const lNode = static_cast(tNode->firstChild()); - tNode->setMatrix(matrix_deg(0.0, 0.0, rZ, cX, cY)); - cNode->setGeometryProperties(r1, center(sensor).x(), center(sensor).y()); - lNode->update(sensor, subControl, sensor->tickmarkLabels(Qt::XAxis), { sX , 0.0}, {tX, tY}); + const auto rotation = sensor->subControlRotation( subControl ); + + const auto rZ = rotation.z(); + const auto cX = center( sensor ).x(); + const auto cY = center( sensor ).y(); + const auto tX = rotation.y() * sX; + const auto tY = r3 + rotation.x() * sY; + + auto* const cNode = ensure< PolygonClipNode, + par< 1, QSGTransformNode, par< 1, LinearTickmarksLabelsNode > > >::node( node ); + auto* const tNode = static_cast< QSGTransformNode* >( cNode->firstChild() ); + auto* const lNode = static_cast< LinearTickmarksLabelsNode* >( tNode->firstChild() ); + tNode->setMatrix( matrix_deg( 0.0, 0.0, rZ, cX, cY ) ); + cNode->setGeometryProperties( r1, center( sensor ).x(), center( sensor ).y() ); + lNode->update( + sensor, subControl, sensor->tickmarkLabels( Qt::XAxis ), { sX, 0.0 }, { tX, tY } ); return cNode; } template<> -QSGNode* QskLevelingSensorSkinlet::updateSubNode(const QskLevelingSensor* const sensor, - const quint8 nodeRole, QSGNode* const node) const +QSGNode* QskLevelingSensorSkinlet::updateSubNode< R::TickmarksYLabels >( + const QskLevelingSensor* const sensor, const quint8 nodeRole, QSGNode* const node ) const { const auto subControl = Q::TickmarksYLabels; - const auto r1 = innerRadius(sensor); - const auto r3 = static_cast(r1 * sensor->strutSizeHint(Q::TickmarksY).width()); - const auto cX = static_cast(center(sensor).x()); - const auto cY = static_cast(center(sensor).y()); - const auto rZ = sensor->rotation().z(); - - auto* const cNode = ensure>>::node(node); - auto* const tNode = static_cast(cNode->firstChild()); - auto* const lNode = static_cast(tNode->firstChild()); - cNode->setGeometryProperties(r1, cX, cY); - tNode->setMatrix(matrix_deg(0.0, 0.0, 0, cX, cY)); - lNode->update(sensor, subControl, sensor->tickmarkLabels(Qt::YAxis), { 0.0, r1 / sensor->angle().y() }, {r3, 0.0}); + const auto r1 = innerRadius( sensor ); + const auto r3 = static_cast< float >( r1 * sensor->strutSizeHint( Q::TickmarksY ).width() ); + const auto cX = static_cast< float >( center( sensor ).x() ); + const auto cY = static_cast< float >( center( sensor ).y() ); + + const auto scale = sensor->strutSizeHint( subControl ); + const auto angles = sensor->angle(); + const auto rotation = sensor->subControlRotation( subControl ); + const auto sX = r1 / angles.x(); + const auto sY = r1 / angles.y(); + const auto tX = static_cast< float >( rotation.y() * sX ); + const auto tY = static_cast< float >( rotation.x() * sY ); + + auto* const cNode = ensure< PolygonClipNode, + par< 1, QSGTransformNode, par< 1, LinearTickmarksLabelsNode > > >::node( node ); + auto* const tNode = static_cast< QSGTransformNode* >( cNode->firstChild() ); + auto* const lNode = static_cast< LinearTickmarksLabelsNode* >( tNode->firstChild() ); + cNode->setGeometryProperties( r1, cX, cY ); + tNode->setMatrix( matrix_deg( 0.0, 0.0, rotation.z(), cX, cY ) ); + lNode->update( sensor, subControl, sensor->tickmarkLabels( Qt::YAxis ), + { 0.0, r1 / sensor->angle().y() }, { r3 + tX, tY } ); return cNode; } template<> -QSGNode* QskLevelingSensorSkinlet::updateSubNode(const QskLevelingSensor* const sensor, - const quint8 nodeRole, QSGNode* const node) const +QSGNode* QskLevelingSensorSkinlet::updateSubNode< R::TickmarksZLabels >( + const QskLevelingSensor* const sensor, const quint8 nodeRole, QSGNode* const node ) const { const auto subControl = Q::TickmarksZLabels; - auto* const tNode = ensure>::node(node); - auto* const lNode = static_cast(tNode->firstChild()); - const auto r1 = innerRadius(sensor); - const auto r3 = static_cast(r1 * sensor->strutSizeHint(subControl).width()); - const auto cX = static_cast(center(sensor).x()); - const auto cY = static_cast(center(sensor).y()); - const auto rZ = sensor->arcMetricsHint(subControl).startAngle(); - lNode->update(sensor, subControl, sensor->tickmarkLabels(Qt::ZAxis), { r3, r3 }); - tNode->setMatrix(matrix_deg(0.0, 0.0, rZ, cX, cY)); + auto* const tNode = + ensure< QSGTransformNode, par< 1, RadialTickmarksLabelsNode > >::node( node ); + auto* const lNode = static_cast< RadialTickmarksLabelsNode* >( tNode->firstChild() ); + const auto r1 = innerRadius( sensor ); + const auto r3 = static_cast< float >( r1 * sensor->strutSizeHint( subControl ).width() ); + const auto cX = static_cast< float >( center( sensor ).x() ); + const auto cY = static_cast< float >( center( sensor ).y() ); + const auto rZ = sensor->subControlRotation( subControl ).z(); + lNode->update( sensor, subControl, sensor->tickmarkLabels( Qt::ZAxis ), { r3, r3 } ); + tNode->setMatrix( matrix_deg( 0.0, 0.0, rZ, cX, cY ) ); return tNode; } template<> -QSGNode* QskLevelingSensorSkinlet::updateSubNode(const QskLevelingSensor* const sensor, - const quint8 nodeRole, QSGNode* const node) const +QSGNode* QskLevelingSensorSkinlet::updateSubNode< R::HorizonClip >( + const QskLevelingSensor* const sensor, const quint8 nodeRole, QSGNode* const node ) const { - const auto cX = center(sensor).x(); - const auto cY = center(sensor).y(); - const auto r1 = innerRadius(sensor); + const auto cX = center( sensor ).x(); + const auto cY = center( sensor ).y(); + const auto r1 = innerRadius( sensor ); - auto* const clipNode = ensure::node(node); - clipNode->setGeometryProperties(r1, cX, cY); + auto* const clipNode = ensure< PolygonClipNode >::node( node ); + clipNode->setGeometryProperties( r1, cX, cY ); return clipNode; } QSGNode* QskLevelingSensorSkinlet::updateSubNode( - const QskSkinnable* const skinnable, const quint8 nodeRole, QSGNode* const node) const + const QskSkinnable* const skinnable, const quint8 nodeRole, QSGNode* const node ) const { - const auto* const sensor = static_cast(skinnable); + const auto* const sensor = static_cast< const Q* >( skinnable ); - const auto subControl = [nodeRole, sensor](){ - switch(static_cast(nodeRole)) + const auto subControl = [ nodeRole, sensor ]() { + switch ( static_cast< R >( nodeRole ) ) { - case OuterDisk: return Q::OuterDisk; - case Horizon: return Q::Horizon; - case HorizonClip: return Q::Horizon; - case TickmarksX: return Q::TickmarksX; - case TickmarksXLabels: return Q::TickmarksXLabels; - case TickmarksY: return Q::TickmarksY; - case TickmarksYLabels: return Q::TickmarksYLabels; - case TickmarksZ: return Q::TickmarksZ; - case TickmarksZLabels: return Q::TickmarksZLabels; - default: return QskAspect::NoSubcontrol; + case OuterDisk: + return Q::OuterDisk; + case Horizon: + return Q::Horizon; + case HorizonClip: + return Q::Horizon; + case TickmarksX: + return Q::TickmarksX; + case TickmarksXLabels: + return Q::TickmarksXLabels; + case TickmarksY: + return Q::TickmarksY; + case TickmarksYLabels: + return Q::TickmarksYLabels; + case TickmarksZ: + return Q::TickmarksZ; + case TickmarksZLabels: + return Q::TickmarksZLabels; + default: + return QskAspect::NoSubcontrol; } }(); - if (qvariant_cast(sensor->effectiveSkinHint(subControl | QskAspect::Option))) + if ( qvariant_cast< bool >( sensor->effectiveSkinHint( subControl | QskAspect::Option ) ) ) { return nullptr; } - switch(static_cast(nodeRole)) + switch ( static_cast< R >( nodeRole ) ) { - case OuterDisk: return updateSubNode(sensor, nodeRole, node); - case Horizon: return updateSubNode(sensor, nodeRole, node); - case HorizonClip: return updateSubNode(sensor, nodeRole, node); - case TickmarksX: return updateSubNode(sensor, nodeRole, node); - case TickmarksXLabels: return updateSubNode(sensor, nodeRole, node); - case TickmarksY: return updateSubNode(sensor, nodeRole, node); - case TickmarksYLabels: return updateSubNode(sensor, nodeRole, node); - case TickmarksZ: return updateSubNode(sensor, nodeRole, node); - case TickmarksZLabels: return updateSubNode(sensor, nodeRole, node); - default: return Inherited::updateSubNode(sensor, nodeRole, node); + case OuterDisk: + return updateSubNode< OuterDisk >( sensor, nodeRole, node ); + case Horizon: + return updateSubNode< Horizon >( sensor, nodeRole, node ); + case HorizonClip: + return updateSubNode< HorizonClip >( sensor, nodeRole, node ); + case TickmarksX: + return updateSubNode< TickmarksX >( sensor, nodeRole, node ); + case TickmarksXLabels: + return updateSubNode< TickmarksXLabels >( sensor, nodeRole, node ); + case TickmarksY: + return updateSubNode< TickmarksY >( sensor, nodeRole, node ); + case TickmarksYLabels: + return updateSubNode< TickmarksYLabels >( sensor, nodeRole, node ); + case TickmarksZ: + return updateSubNode< TickmarksZ >( sensor, nodeRole, node ); + case TickmarksZLabels: + return updateSubNode< TickmarksZLabels >( sensor, nodeRole, node ); + default: + return Inherited::updateSubNode( sensor, nodeRole, node ); } }