diff --git a/.github/workflows/setup_environment.yml b/.github/workflows/setup_environment.yml index 7210fa35cc..8974edf1b7 100644 --- a/.github/workflows/setup_environment.yml +++ b/.github/workflows/setup_environment.yml @@ -184,6 +184,14 @@ jobs: if: ${{ inputs.build == true }} timeout-minutes: 25 + - name: Upload compile_commands.json + uses: actions/upload-artifact@v6 + with: + name: compile_commands.json + path: | + build/*.json + if: ${{ inputs.lint_clazy }} + - name: Clazy-standalone uses: MinyazevR/clazy-standalone-action@v0.3.3 with: @@ -209,7 +217,9 @@ jobs: database: 'build' verbosity: 'info' files-changed-only: true - ignore-tidy: '^(buildScripts|thirdparty|installer)$' + ignore-tidy: 'thirdparty|buildScripts|installer' + # Despite having the correct isystem path for googletests in compile_commands.json, it throws [clang-dignostic-error] file "gmock/gmock.h" not found. A temporary solution is to explicitly use these options as command-line arguments for clang-tidy + extra-args: '-isystem${{ github.workspace }}/qrtest/thirdparty/googletest/googletest/googlemock/include/ -isystem${{ github.workspace }}/qrtest/thirdparty/googletest/googletest/googletest/include/' - name: Clang-tidy exit if: ${{ inputs.lint_clazy && steps.linter.outputs.checks-failed > 0 }} diff --git a/plugins/robots/common/twoDModel/src/engine/items/ballItem.cpp b/plugins/robots/common/twoDModel/src/engine/items/ballItem.cpp index 3865a4265f..f0d1e38ee7 100644 --- a/plugins/robots/common/twoDModel/src/engine/items/ballItem.cpp +++ b/plugins/robots/common/twoDModel/src/engine/items/ballItem.cpp @@ -15,9 +15,8 @@ #include "ballItem.h" #include -#include +#include //clazy:exclude=qt6-header-fixes #include - #include using namespace twoDModel::items; @@ -48,13 +47,11 @@ BallItem::BallItem(graphicsUtils::AbstractCoordinateSystem *metricSystem, setTransformOriginPoint(boundingRect().center()); } -BallItem::~BallItem() -{ -} +BallItem::~BallItem() = default; QAction *BallItem::ballTool() { - QAction * const result = new QAction(QIcon(":/icons/2d_ball.svg"), tr("Ball (B)"), nullptr); + auto * const result = new QAction(QIcon(":/icons/2d_ball.svg"), tr("Ball (B)"), nullptr); result->setShortcuts({QKeySequence(Qt::Key_B), QKeySequence(Qt::Key_4)}); result->setCheckable(true); return result; @@ -62,8 +59,7 @@ QAction *BallItem::ballTool() QRectF BallItem::boundingRect() const { - return QRectF({ -mDiameterPx / 2.0, -mDiameterPx / 2.0} - , QSizeF{mDiameterPx, mDiameterPx}); + return {{ -mDiameterPx / 2.0, -mDiameterPx / 2.0}, QSizeF{mDiameterPx, mDiameterPx}}; } void BallItem::drawItem(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) @@ -84,6 +80,26 @@ void BallItem::setPenBrushForExtraction(QPainter *painter, const QStyleOptionGra } } +void BallItem::setStartPosition(QPointF startPosition) +{ + mStartPosition = startPosition; +} + +void BallItem::setStartRotation(qreal startRotation) +{ + mStartRotation = startRotation; +} + +qreal BallItem::startRotation() const +{ + return mStartRotation; +} + +QPointF BallItem::startPosition() const +{ + return mStartPosition; +} + void BallItem::drawExtractionForItem(QPainter *painter) { painter->drawEllipse(boundingRect()); @@ -98,19 +114,11 @@ void BallItem::savePos() QDomElement BallItem::serialize(QDomElement &element) const { QDomElement ballNode = AbstractItem::serialize(element); + Serializer::serialize(ballNode); + SolidItem::serialize(ballNode); + auto *coordSystem = coordinateSystem(); ballNode.setTagName("ball"); - ballNode.setAttribute("x", - QString::number(coordSystem->toUnit(x1() + scenePos().x()))); - ballNode.setAttribute("y", - QString::number(coordSystem->toUnit(y1() + scenePos().y()))); - ballNode.setAttribute("markerX", - QString::number(coordSystem->toUnit(x1() + mStartPosition.x()))); - ballNode.setAttribute("markerY", - QString::number(coordSystem->toUnit(y1() + mStartPosition.y()))); - ballNode.setAttribute("rotation", QString::number(rotation())); - ballNode.setAttribute("startRotation", QString::number(mStartRotation)); - SolidItem::serialize(ballNode); if (mDiameterPx.wasChanged()) { ballNode.setAttribute("diameter", QString::number(coordSystem->toUnit(mDiameterPx))); } @@ -120,24 +128,14 @@ QDomElement BallItem::serialize(QDomElement &element) const void BallItem::deserialize(const QDomElement &element) { AbstractItem::deserialize(element); + SolidItem::deserialize(element); auto *coordSystem = coordinateSystem(); - qreal x = coordSystem->toPx(element.attribute("x", "0").toDouble()); - qreal y = coordSystem->toPx(element.attribute("y", "0").toDouble()); - qreal markerX = coordSystem->toPx(element.attribute("markerX", "0").toDouble()); - qreal markerY = coordSystem->toPx(element.attribute("markerY", "0").toDouble()); - qreal rotation = element.attribute("rotation", "0").toDouble(); - mStartRotation = element.attribute("startRotation", "0").toDouble(); - if (element.hasAttribute("diameter")) { setDiameter(coordSystem->toPx( element.attribute("diameter").toDouble())); } - SolidItem::deserialize(element); - setPos(QPointF(x, y)); - setTransformOriginPoint(boundingRect().center()); - mStartPosition = {markerX, markerY}; - setRotation(rotation); + Serializer::deserialize(element); Q_EMIT x1Changed(x1()); } @@ -166,7 +164,7 @@ void BallItem::returnToStartPosition() QPolygonF BallItem::collidingPolygon() const { - return QPolygonF(boundingRect().adjusted(1, 1, -1, -1).translated(scenePos())); + return boundingRect().adjusted(1, 1, -1, -1).translated(scenePos()); } QPainterPath BallItem::path() const diff --git a/plugins/robots/common/twoDModel/src/engine/items/ballItem.h b/plugins/robots/common/twoDModel/src/engine/items/ballItem.h index 8b6a0d59fb..a5350db1a5 100644 --- a/plugins/robots/common/twoDModel/src/engine/items/ballItem.h +++ b/plugins/robots/common/twoDModel/src/engine/items/ballItem.h @@ -16,6 +16,7 @@ #include #include "src/engine/items/solidItem.h" +#include "details/serializer.h" #include class QSvgRenderer; @@ -23,15 +24,15 @@ class QSvgRenderer; namespace twoDModel { namespace items { -class BallItem final: public graphicsUtils::AbstractItem, public SolidItem +class BallItem final: public graphicsUtils::AbstractItem, public SolidItem, public Serializer { Q_OBJECT Q_DISABLE_COPY(BallItem) public: explicit BallItem(graphicsUtils::AbstractCoordinateSystem *metricSystem, - QPointF position); - ~BallItem(); + QPointF position); + ~BallItem() override; /// Creates and returns ball item for 2D model palette. /// Transfers ownership. @@ -51,6 +52,10 @@ class BallItem final: public graphicsUtils::AbstractItem, public SolidItem void saveStartPosition(); void returnToStartPosition(); + void setStartPosition(QPointF startPosition); + void setStartRotation(qreal startPosition); + qreal startRotation() const; + QPointF startPosition() const; bool isCircle() const override; BodyType bodyType() const override; diff --git a/plugins/robots/common/twoDModel/src/engine/items/cubeItem.cpp b/plugins/robots/common/twoDModel/src/engine/items/cubeItem.cpp index dae804e4f1..62d8739170 100644 --- a/plugins/robots/common/twoDModel/src/engine/items/cubeItem.cpp +++ b/plugins/robots/common/twoDModel/src/engine/items/cubeItem.cpp @@ -100,24 +100,33 @@ void CubeItem::savePos() RotateItem::savePos(); } +void CubeItem::setStartPosition(QPointF startPosition) +{ + mStartPosition = startPosition; +} + +void CubeItem::setStartRotation(qreal startRotation) +{ + mStartRotation = startRotation; +} + +qreal CubeItem::startRotation() const +{ + return mStartRotation; +} + +QPointF CubeItem::startPosition() const +{ + return mStartPosition; +} + QDomElement CubeItem::serialize(QDomElement &element) const { QDomElement cubeNode = AbstractItem::serialize(element); - const auto &coordSystem = coordinateSystem(); - cubeNode.setTagName("cube"); - cubeNode.setAttribute("x", - QString::number(coordSystem->toUnit(scenePos().x()))); - cubeNode.setAttribute("y", - QString::number(coordSystem->toUnit(scenePos().y()))); - cubeNode.setAttribute("markerX", - QString::number(coordSystem->toUnit(mStartPosition.x()))); - cubeNode.setAttribute("markerY", - QString::number(coordSystem->toUnit(mStartPosition.y()))); - cubeNode.setAttribute("rotation", QString::number(rotation())); - cubeNode.setAttribute("startRotation", QString::number(mStartRotation)); - + Serializer::serialize(cubeNode); SolidItem::serialize(cubeNode); - + cubeNode.setTagName("cube"); + auto &&coordSystem = coordinateSystem(); if (mEdgeSizePx.wasChanged()) { cubeNode.setAttribute("edgeSize", QString::number(coordSystem->toUnit(mEdgeSizePx))); } @@ -128,22 +137,18 @@ QDomElement CubeItem::serialize(QDomElement &element) const void CubeItem::deserialize(const QDomElement &element) { AbstractItem::deserialize(element); - const auto &coordSystem = coordinateSystem(); - const auto x = coordSystem->toPx(element.attribute("x", "0").toDouble()); - const auto y = coordSystem->toPx(element.attribute("y", "0").toDouble()); - const auto markerX = coordSystem->toPx(element.attribute("markerX", "0").toDouble()); - const auto markerY = coordSystem->toPx(element.attribute("markerY", "0").toDouble()); - const auto rotation = element.attribute("rotation", "0").toDouble(); - mStartRotation = element.attribute("startRotation", "0").toDouble(); - setPos(QPointF(x, y)); - setTransformOriginPoint(boundingRect().center()); - setRotation(rotation); + SolidItem::deserialize(element); + + auto *coordSystem = coordinateSystem(); if (element.hasAttribute("edgeSize")) { setEdgeSize(coordSystem->toPx( element.attribute("edgeSize").toDouble())); } - SolidItem::deserialize(element); - mStartPosition = {markerX, markerY}; + + Serializer::deserialize(element); + // Update rotater position + RotateItem::init(); + savePos(); Q_EMIT x1Changed(x1()); } @@ -195,10 +200,6 @@ void CubeItem::setEdgeSize(const qreal edge) setY1(-mEdgeSizePx / 2.0f); setX2(x1() + mEdgeSizePx); setY2(y1() + mEdgeSizePx); - setTransformOriginPoint(boundingRect().center()); - // Update rotater position - RotateItem::init(); - savePos(); } SolidItem::BodyType CubeItem::bodyType() const diff --git a/plugins/robots/common/twoDModel/src/engine/items/cubeItem.h b/plugins/robots/common/twoDModel/src/engine/items/cubeItem.h index 9006383ce2..5773c9e853 100644 --- a/plugins/robots/common/twoDModel/src/engine/items/cubeItem.h +++ b/plugins/robots/common/twoDModel/src/engine/items/cubeItem.h @@ -15,7 +15,7 @@ #pragma once #include - +#include "details/serializer.h" #include "src/engine/items/solidItem.h" class QSvgRenderer; @@ -23,7 +23,7 @@ class QSvgRenderer; namespace twoDModel { namespace items { -class CubeItem final: public graphicsUtils::RotateItem, public SolidItem +class CubeItem final: public graphicsUtils::RotateItem, public SolidItem, public Serializer { Q_OBJECT Q_DISABLE_COPY(CubeItem) @@ -31,7 +31,7 @@ class CubeItem final: public graphicsUtils::RotateItem, public SolidItem public: explicit CubeItem(graphicsUtils::AbstractCoordinateSystem *metricSystem, QPointF position); - ~CubeItem(); + ~CubeItem() override; /// Creates and returns cube item for 2D model palette. /// Transfers ownership. @@ -45,6 +45,10 @@ class CubeItem final: public graphicsUtils::RotateItem, public SolidItem void drawFieldForResizeItem(QPainter* painter) override { Q_UNUSED(painter) } void resizeItem(QGraphicsSceneMouseEvent *event) override { Q_UNUSED(event) } void savePos() override; + void setStartPosition(QPointF startPosition); + void setStartRotation(qreal startPosition); + qreal startRotation() const; + QPointF startPosition() const; QDomElement serialize(QDomElement &element) const override; void deserialize(const QDomElement &element) override; diff --git a/plugins/robots/common/twoDModel/src/engine/items/itemProperty.h b/plugins/robots/common/twoDModel/src/engine/items/details/itemProperty.h similarity index 80% rename from plugins/robots/common/twoDModel/src/engine/items/itemProperty.h rename to plugins/robots/common/twoDModel/src/engine/items/details/itemProperty.h index 0679e3a24b..df521c3f15 100644 --- a/plugins/robots/common/twoDModel/src/engine/items/itemProperty.h +++ b/plugins/robots/common/twoDModel/src/engine/items/details/itemProperty.h @@ -15,17 +15,18 @@ #pragma once #include +#include template class ItemProperty final { Q_DISABLE_COPY_MOVE(ItemProperty) public: - explicit ItemProperty(const QString& name, const T& value) - : mName(name), mValue(value), mWasChanged(false) {} + explicit ItemProperty(QString name, const T& value) + : mName(std::move(name)), mValue(value), mWasChanged(false) {} ItemProperty() = default; - operator const T() const & { return mValue; } + operator T() const & { return mValue; } // NOLINT(google-explicit-constructor) QString name() const { return mName; } @@ -41,5 +42,5 @@ class ItemProperty final private: QString mName; T mValue; - bool mWasChanged; + bool mWasChanged {}; }; diff --git a/plugins/robots/common/twoDModel/src/engine/items/details/serializer.h b/plugins/robots/common/twoDModel/src/engine/items/details/serializer.h new file mode 100644 index 0000000000..4f6a537d62 --- /dev/null +++ b/plugins/robots/common/twoDModel/src/engine/items/details/serializer.h @@ -0,0 +1,114 @@ +/* Copyright 2025 CyberTech Labs Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#pragma once + +#include "itemProperty.h" +#include +#include + +namespace twoDModel { +namespace items { + +template +class Serializer +{ + Q_DISABLE_COPY_MOVE(Serializer) +public: + Serializer() = default; + ~Serializer() = default; + void deserialize(const QDomElement &element) + { + auto &&derived = static_cast(this); + auto &&coordSystem = derived->coordinateSystem(); + qreal x {}; + qreal y {}; + + if (element.hasAttribute("begin")) { + const auto &point = deserializePoint(element.attribute("begin")); + x = point.x(); + y = point.y(); + mPreferLeftTopPoint = true; + } else { + x = coordSystem->toPx(element.attribute("x", "0").toDouble()); + y = coordSystem->toPx(element.attribute("y", "0").toDouble()); + mPreferLeftTopPoint = false; + } + + const auto markerX = coordSystem->toPx(element.attribute("markerX", "0").toDouble()); + const auto markerY = coordSystem->toPx(element.attribute("markerY", "0").toDouble()); + + const auto rotation = element.attribute("rotation", "0").toDouble(); + const auto startRotation = element.attribute("startRotation", "0").toDouble(); + auto &&boundingRect = derived->boundingRect(); + derived->setTransformOriginPoint(boundingRect.center()); + derived->setRotation(rotation); + derived->setStartRotation(startRotation); + if (mPreferLeftTopPoint) { + const auto currentTopLeft = derived->mapToScene(boundingRect.topLeft()); + const auto offsetX = x - currentTopLeft.x(); + const auto offsetY = y - currentTopLeft.y(); + derived->moveBy(offsetX, offsetY); + } else { + derived->setPos(QPointF{x, y}); + } + derived->setStartPosition({markerX, markerY}); + } + + void serialize(QDomElement &element) const + { + auto &&derived = static_cast(this); + auto &&coordSystem = derived->coordinateSystem(); + const auto startRotation = derived->startRotation(); + const auto startPosition = derived->startPosition(); + const auto derivedScenePosition = derived->scenePos(); + if (!mPreferLeftTopPoint) { + element.setAttribute("x", + QString::number(coordSystem->toUnit(derivedScenePosition.x()))); + element.setAttribute("y", + QString::number(coordSystem->toUnit(derivedScenePosition.y()))); + } else { + auto &&boundingRectTopLeft = derived->mapToScene(derived->boundingRect().topLeft()); + auto x1InSystem = coordSystem->toUnit(boundingRectTopLeft.x()); + auto y1InSystem = coordSystem->toUnit(boundingRectTopLeft.y()); + element.setAttribute("begin", QString::number(x1InSystem) + ":" + QString::number(y1InSystem)); + } + + element.setAttribute("markerX", + QString::number(coordSystem->toUnit(startPosition.x()))); + element.setAttribute("markerY", + QString::number(coordSystem->toUnit(startPosition.y()))); + element.setAttribute("rotation", QString::number(derived->rotation())); + element.setAttribute("startRotation", QString::number(startRotation)); + } + + QPointF deserializePoint(const QString &string) const + { + auto &&derived = static_cast(this); + auto &&coordSystem = derived->coordinateSystem(); + const auto &splittedStr = string.split(":"); + if (splittedStr.count() == 2) { + const qreal x = splittedStr[0].toDouble(); + const qreal y = splittedStr[1].toDouble(); + return coordSystem->toPx({x, y}); + } + return {}; + } + +private: + bool mPreferLeftTopPoint {}; +}; + +} +} diff --git a/plugins/robots/common/twoDModel/src/engine/items/skittleItem.cpp b/plugins/robots/common/twoDModel/src/engine/items/skittleItem.cpp index a209ee16fa..86226f6db3 100644 --- a/plugins/robots/common/twoDModel/src/engine/items/skittleItem.cpp +++ b/plugins/robots/common/twoDModel/src/engine/items/skittleItem.cpp @@ -15,9 +15,8 @@ #include "skittleItem.h" #include -#include +#include //clazy:exclude=qt6-header-fixes #include - #include using namespace twoDModel::items; @@ -60,8 +59,7 @@ QAction *SkittleItem::skittleTool() QRectF SkittleItem::boundingRect() const { - return {{-mDiameterPx / 2, -mDiameterPx / 2} - , QSizeF{mDiameterPx, mDiameterPx}}; + return {{-mDiameterPx / 2, -mDiameterPx / 2} , QSizeF{mDiameterPx, mDiameterPx}}; } QPainterPath SkittleItem::shape() const @@ -103,19 +101,11 @@ void SkittleItem::savePos() QDomElement SkittleItem::serialize(QDomElement &element) const { QDomElement skittleNode = AbstractItem::serialize(element); - skittleNode.setTagName("skittle"); - auto *coordSystem = coordinateSystem(); - skittleNode.setAttribute("x", - QString::number(coordSystem->toUnit(x1() + scenePos().x()))); - skittleNode.setAttribute("y", - QString::number(coordSystem->toUnit(y1() + scenePos().y()))); - skittleNode.setAttribute("markerX", - QString::number(coordSystem->toUnit(x1() + mStartPosition.x()))); - skittleNode.setAttribute("markerY", - QString::number(coordSystem->toUnit(y1() + mStartPosition.y()))); - skittleNode.setAttribute("rotation", QString::number(rotation())); - skittleNode.setAttribute("startRotation", QString::number(mStartRotation)); + Serializer::serialize(skittleNode); SolidItem::serialize(skittleNode); + skittleNode.setTagName("skittle"); + + auto &&coordSystem = coordinateSystem(); if (mDiameterPx.wasChanged()) { skittleNode.setAttribute("diameter", QString::number(coordSystem->toUnit(mDiameterPx))); } @@ -125,26 +115,38 @@ QDomElement SkittleItem::serialize(QDomElement &element) const void SkittleItem::deserialize(const QDomElement &element) { AbstractItem::deserialize(element); - auto *coordSystem = coordinateSystem(); - qreal x = coordSystem->toPx(element.attribute("x", "0").toDouble()); - qreal y = coordSystem->toPx(element.attribute("y", "0").toDouble()); - qreal markerX = coordSystem->toPx(element.attribute("markerX", "0").toDouble()); - qreal markerY = coordSystem->toPx(element.attribute("markerY", "0").toDouble()); - qreal rotation = element.attribute("rotation", "0").toDouble(); - mStartRotation = element.attribute("startRotation", "0").toDouble(); + SolidItem::deserialize(element); + auto *coordSystem = coordinateSystem(); if (element.hasAttribute("diameter")) { setDiameter(coordSystem->toPx( element.attribute("diameter").toDouble())); } - SolidItem::deserialize(element); - setPos(QPointF(x, y)); - setTransformOriginPoint(boundingRect().center()); - mStartPosition = {markerX, markerY}; - setRotation(rotation); + + Serializer::deserialize(element); Q_EMIT x1Changed(x1()); } +void SkittleItem::setStartPosition(QPointF startPosition) +{ + mStartPosition = startPosition; +} + +void SkittleItem::setStartRotation(qreal startRotation) +{ + mStartRotation = startRotation; +} + +qreal SkittleItem::startRotation() const +{ + return mStartRotation; +} + +QPointF SkittleItem::startPosition() const +{ + return mStartPosition; +} + void SkittleItem::saveStartPosition() { if (this->editable()) { diff --git a/plugins/robots/common/twoDModel/src/engine/items/skittleItem.h b/plugins/robots/common/twoDModel/src/engine/items/skittleItem.h index d9834774e3..36049b21da 100644 --- a/plugins/robots/common/twoDModel/src/engine/items/skittleItem.h +++ b/plugins/robots/common/twoDModel/src/engine/items/skittleItem.h @@ -15,20 +15,21 @@ #pragma once #include "src/engine/items/solidItem.h" #include +#include "details/serializer.h" class QSvgRenderer; namespace twoDModel { namespace items { -class SkittleItem final: public graphicsUtils::AbstractItem, public SolidItem +class SkittleItem final: public graphicsUtils::AbstractItem, public SolidItem, public Serializer { Q_OBJECT Q_DISABLE_COPY(SkittleItem) public: explicit SkittleItem(graphicsUtils::AbstractCoordinateSystem *metricSystem, - QPointF position); + QPointF position); ~SkittleItem() override; @@ -47,7 +48,10 @@ class SkittleItem final: public graphicsUtils::AbstractItem, public SolidItem QDomElement serialize(QDomElement &element) const override; void deserialize(const QDomElement &element) override; - + void setStartPosition(QPointF startPosition); + void setStartRotation(qreal startPosition); + qreal startRotation() const; + QPointF startPosition() const; void saveStartPosition(); void returnToStartPosition(); QPainterPath shape() const override; @@ -61,6 +65,7 @@ class SkittleItem final: public graphicsUtils::AbstractItem, public SolidItem QPointF mStartPosition; qreal mStartRotation {0.0}; ItemProperty mDiameterPx; + // bool mPreferLeftTopPoint {}; std::unique_ptr mSvgRenderer; }; } diff --git a/plugins/robots/common/twoDModel/src/engine/items/solidItem.h b/plugins/robots/common/twoDModel/src/engine/items/solidItem.h index e15482993d..e6ae45a902 100644 --- a/plugins/robots/common/twoDModel/src/engine/items/solidItem.h +++ b/plugins/robots/common/twoDModel/src/engine/items/solidItem.h @@ -17,7 +17,7 @@ #include #include #include -#include "itemProperty.h" +#include "details/itemProperty.h" namespace twoDModel { namespace items { diff --git a/plugins/robots/common/twoDModel/twoDModel.pri b/plugins/robots/common/twoDModel/twoDModel.pri index 524f9e3d72..06a14e66b9 100644 --- a/plugins/robots/common/twoDModel/twoDModel.pri +++ b/plugins/robots/common/twoDModel/twoDModel.pri @@ -66,7 +66,6 @@ HEADERS += \ $$PWD/include/twoDModel/blocks/markerDownBlock.h \ $$PWD/include/twoDModel/blocks/markerUpBlock.h \ $$PWD/src/engine/items/cubeItem.h \ - $$PWD/src/engine/items/itemProperty.h HEADERS += \ $$PWD/src/engine/twoDModelEngineApi.h \ @@ -100,6 +99,8 @@ HEADERS += \ $$PWD/src/engine/model/physics/simplePhysicsEngine.h \ $$PWD/src/engine/model/physics/parts/box2DRobot.h \ $$PWD/src/engine/model/physics/parts/box2DWheel.h \ + $$PWD/src/engine/items/details/itemProperty.h \ + $$PWD/src/engine/items/details/serializer.h \ $$PWD/src/engine/items/solidItem.h \ $$PWD/src/engine/items/wallItem.h \ $$PWD/src/engine/items/stylusItem.h \ diff --git a/qrtest/qrtest.pro b/qrtest/qrtest.pro index 4a3f571fda..5e9890a9f1 100644 --- a/qrtest/qrtest.pro +++ b/qrtest/qrtest.pro @@ -23,5 +23,5 @@ SUBDIRS = \ unitTests.depends = googletest -googletest.file = thirdparty/googletest/googletest.pro +googletest.file = $$PWD/thirdparty/googletest/googletest.pro diff --git a/qrtest/unitTests/common.pri b/qrtest/unitTests/common.pri index 9641788afd..00f6eba2ef 100644 --- a/qrtest/unitTests/common.pri +++ b/qrtest/unitTests/common.pri @@ -44,7 +44,7 @@ CONFIG += c++17 # for GTEST # the line below suppresses warnings generated by google's headers QMAKE_CXXFLAGS += \ - -isystem $$PWD/../thirdparty/googletest/googletest/googletest/include \ - -isystem $$PWD/../thirdparty/googletest/googletest/googlemock/include \ + -isystem $$clean_path($$PWD/../thirdparty/googletest/googletest/googletest/include) \ + -isystem $$clean_path($$PWD/../thirdparty/googletest/googletest/googlemock/include) \ links(googletest) diff --git a/qrtest/unitTests/mocks/plugins/robots/common/kitBase/include/kitBase/robotModel/robotModelInterfaceMock.h b/qrtest/unitTests/mocks/plugins/robots/common/kitBase/include/kitBase/robotModel/robotModelInterfaceMock.h index b06eac23bf..35bc7bdc90 100644 --- a/qrtest/unitTests/mocks/plugins/robots/common/kitBase/include/kitBase/robotModel/robotModelInterfaceMock.h +++ b/qrtest/unitTests/mocks/plugins/robots/common/kitBase/include/kitBase/robotModel/robotModelInterfaceMock.h @@ -29,48 +29,35 @@ class RobotModelInterfaceMock : public kitBase::robotModel::RobotModelInterface Q_OBJECT public: - MOCK_CONST_METHOD0(robotId, QString()); - MOCK_CONST_METHOD0(name, QString()); - MOCK_CONST_METHOD0(friendlyName, QString()); - MOCK_CONST_METHOD0(kitId, QString()); - MOCK_CONST_METHOD0(priority, int()); - MOCK_CONST_METHOD0(interpretedModel, bool()); - - MOCK_METHOD0(init, void()); - - MOCK_METHOD0(connectToRobot, void()); - MOCK_METHOD0(stopRobot, void()); - MOCK_METHOD0(disconnectFromRobot, void()); - - MOCK_CONST_METHOD0(connectionState, ConnectionState()); - - MOCK_CONST_METHOD0(needsConnection, bool()); - - MOCK_CONST_METHOD0(updateSensorsValues, void()); - MOCK_CONST_METHOD0(updateIntervalForInterpretation, int()); - - - MOCK_CONST_METHOD0(configuration - , kitBase::robotModel::ConfigurationInterface const &()); - MOCK_METHOD0(mutableConfiguration, kitBase::robotModel::ConfigurationInterface&()); - - MOCK_CONST_METHOD0(availablePorts, QList< kitBase::robotModel::PortInfo>()); - MOCK_CONST_METHOD1(getPortsBy, QList(const QString &name)); - MOCK_CONST_METHOD0(buttonCodes, StringIntHash()); - MOCK_CONST_METHOD0(configurablePorts, QList< kitBase::robotModel::PortInfo>()); - MOCK_CONST_METHOD1(allowedDevices, QList< kitBase::robotModel::DeviceInfo>( - kitBase::robotModel::PortInfo const &port)); - - MOCK_METHOD2(configureDevice, void( kitBase::robotModel::PortInfo const & port - , kitBase::robotModel::DeviceInfo const &deviceInfo)); - - MOCK_METHOD0(applyConfiguration, void()); - - MOCK_CONST_METHOD0(convertibleBases, QList< kitBase::robotModel::DeviceInfo>()); - - MOCK_METHOD0(timeline, utils::TimelineInterface &()); - - MOCK_METHOD0(onInterpretationStarted, void()); + // clazy:excludeall=function-args-by-value,returning-void-expression + MOCK_METHOD(QString, robotId, (), (const, override)); + MOCK_METHOD(QString, name, (), (const, override)); + MOCK_METHOD(QString, friendlyName, (), (const, override)); + MOCK_METHOD(QString, kitId, (), (const, override)); + MOCK_METHOD(int, priority, (), (const, override)); + MOCK_METHOD(bool, interpretedModel, (), (const, override)); + MOCK_METHOD(void, init, (), (override)); + MOCK_METHOD(void, connectToRobot, (), (override)); + MOCK_METHOD(void, stopRobot, (), (override)); + MOCK_METHOD(void, disconnectFromRobot, (), (override)); + MOCK_METHOD(ConnectionState, connectionState, (), (const, override)); + MOCK_METHOD(bool, needsConnection, (), (const, override)); + MOCK_METHOD(void, updateSensorsValues, (), (const, override)); + MOCK_METHOD(int, updateIntervalForInterpretation, (), (const, override)); + MOCK_METHOD(kitBase::robotModel::ConfigurationInterface const &, configuration, (), (const, override)); + MOCK_METHOD(QList, availablePorts, (), (const, override)); + MOCK_METHOD(QList, getPortsBy, (const QString &), (const, override)); + MOCK_METHOD(StringIntHash, buttonCodes, (), (const, override)); + MOCK_METHOD(QList, configurablePorts, (), (const, override)); + MOCK_METHOD(QList, allowedDevices, + (kitBase::robotModel::PortInfo const &), (const, override)); + MOCK_METHOD(void, configureDevice, (kitBase::robotModel::PortInfo const & + , kitBase::robotModel::DeviceInfo const &), (override)); + MOCK_METHOD(void, applyConfiguration, (), (override)); + MOCK_METHOD(QList< kitBase::robotModel::DeviceInfo>, convertibleBases, (), (const, override)); + MOCK_METHOD(utils::TimelineInterface &, timeline, (), (override)); + MOCK_METHOD(void, onInterpretationStarted, (), (override)); + // clazy:enable }; } diff --git a/qrtest/unitTests/mocks/plugins/robots/common/twoDModel/include/twoDModel/robotModel/physicsEngineMock.h b/qrtest/unitTests/mocks/plugins/robots/common/twoDModel/include/twoDModel/robotModel/physicsEngineMock.h index 4381c1ab91..317fd923f8 100644 --- a/qrtest/unitTests/mocks/plugins/robots/common/twoDModel/include/twoDModel/robotModel/physicsEngineMock.h +++ b/qrtest/unitTests/mocks/plugins/robots/common/twoDModel/include/twoDModel/robotModel/physicsEngineMock.h @@ -21,23 +21,22 @@ namespace qrTest { class PhysicsEngineMock : public twoDModel::model::physics::PhysicsEngineBase + { Q_OBJECT public: + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) PhysicsEngineMock(const twoDModel::model::WorldModel &worldModel, const QList &robots) : PhysicsEngineBase(worldModel, robots) {}; // clazy:excludeall=function-args-by-value,returning-void-expression - MOCK_CONST_METHOD1(positionShift, QVector2D(twoDModel::model::RobotModel &)); - MOCK_CONST_METHOD1(rotation, qreal(twoDModel::model::RobotModel &)); - MOCK_METHOD1(addRobot, void(twoDModel::model::RobotModel * const)); - MOCK_METHOD1(removeRobot, void(twoDModel::model::RobotModel * const)); - MOCK_METHOD1(recalculateParameters, void(qreal)); - MOCK_CONST_METHOD0(isRobotStuck, bool()); - MOCK_METHOD0(wakeUp, void()); - MOCK_METHOD0(clearForcesAndStop, void()); - MOCK_METHOD0(nextFrame, void()); + MOCK_METHOD(void, addRobot, (twoDModel::model::RobotModel * const), (override)); + MOCK_METHOD(QVector2D, positionShift, (twoDModel::model::RobotModel &), (const, override)); + MOCK_METHOD(qreal, rotation, (twoDModel::model::RobotModel &), (const, override)); + MOCK_METHOD(void, removeRobot, (twoDModel::model::RobotModel * const), (override)); + MOCK_METHOD(void, recalculateParameters, (qreal), (override)); + MOCK_METHOD(bool, isRobotStuck, (), (const, override)); // clazy:enable }; } diff --git a/qrtest/unitTests/mocks/plugins/robots/common/twoDModel/include/twoDModel/robotModel/twoDRobotModelMock.h b/qrtest/unitTests/mocks/plugins/robots/common/twoDModel/include/twoDModel/robotModel/twoDRobotModelMock.h index cc4b86cc1f..d24559f7f5 100644 --- a/qrtest/unitTests/mocks/plugins/robots/common/twoDModel/include/twoDModel/robotModel/twoDRobotModelMock.h +++ b/qrtest/unitTests/mocks/plugins/robots/common/twoDModel/include/twoDModel/robotModel/twoDRobotModelMock.h @@ -24,32 +24,32 @@ class TwoDRobotModelMock : public twoDModel::robotModel::TwoDRobotModel Q_OBJECT public: - TwoDRobotModelMock(const RobotModelInterface &realModel): + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) + explicit TwoDRobotModelMock(const RobotModelInterface &realModel): twoDModel::robotModel::TwoDRobotModel(realModel) {}; // clazy:excludeall=function-args-by-value,returning-void-expression - MOCK_CONST_METHOD0(robotId, QString()); - MOCK_CONST_METHOD0(name, QString()); - MOCK_CONST_METHOD0(friendlyName, QString()); - MOCK_CONST_METHOD0(needsConnection, bool()); - MOCK_CONST_METHOD0(updateIntervalForInterpretation, int()); - MOCK_METHOD0(timeline, utils::TimelineInterface &()); - MOCK_CONST_METHOD0(configurablePorts, QList< kitBase::robotModel::PortInfo>()); - MOCK_CONST_METHOD0(convertibleBases, QList< kitBase::robotModel::DeviceInfo>()); - MOCK_CONST_METHOD0(priority, int()); - MOCK_METHOD0(rereadSettings, void()); - MOCK_METHOD1(setEngine, void(twoDModel::engine::TwoDModelEngineInterface &)); - MOCK_CONST_METHOD0(robotImage, QString()); - MOCK_CONST_METHOD0(defaultLeftWheelPort, kitBase::robotModel::PortInfo()); - MOCK_CONST_METHOD0(defaultRightWheelPort, kitBase::robotModel::PortInfo()); - MOCK_CONST_METHOD0(displayWidget, twoDModel::engine::TwoDModelDisplayWidget *()); - MOCK_CONST_METHOD0(collidingPolygon, QPolygonF()); - MOCK_CONST_METHOD0(mass, qreal()); - MOCK_CONST_METHOD0(friction, qreal()); - MOCK_CONST_METHOD0(size, QSizeF()); - MOCK_CONST_METHOD0(rotationCenter, QPointF()); - MOCK_CONST_METHOD0(robotCenter, QPointF()); - MOCK_CONST_METHOD0(wheelsPosition, QList()); - MOCK_CONST_METHOD0(onePercentAngularVelocity, qreal()); + MOCK_METHOD(QString, robotId, (),(const, override)); + MOCK_METHOD(QString, name, (), (const, override)); + MOCK_METHOD(QString, friendlyName, (), (const, override)); + MOCK_METHOD(bool, needsConnection, (), (const, override)); + MOCK_METHOD(int, updateIntervalForInterpretation, (), (const, override)); + MOCK_METHOD(utils::TimelineInterface &, timeline, (), (override)); + MOCK_METHOD(QList< kitBase::robotModel::PortInfo>, configurablePorts, (), (const, override)); + MOCK_METHOD(QList< kitBase::robotModel::DeviceInfo>, convertibleBases, (), (const, override)); + MOCK_METHOD(int, priority, (), (const, override)); + MOCK_METHOD(void, rereadSettings, (), (override)); + MOCK_METHOD(QString, robotImage, (), (const, override)); + MOCK_METHOD(kitBase::robotModel::PortInfo, defaultLeftWheelPort, (), (const, override)); + MOCK_METHOD(kitBase::robotModel::PortInfo, defaultRightWheelPort, (), (const, override)); + MOCK_METHOD(twoDModel::engine::TwoDModelDisplayWidget *, displayWidget,(), (const, override)); + MOCK_METHOD(QPolygonF, collidingPolygon, (), (const, override)); + MOCK_METHOD(qreal, mass, (), (const, override)); + MOCK_METHOD(qreal, friction, (), (const, override)); + MOCK_METHOD(QSizeF, size,(), (const, override)); + MOCK_METHOD(QPointF, rotationCenter, (), (const, override)); + MOCK_METHOD(QPointF, robotCenter, (), (const, override)); + MOCK_METHOD(QList, wheelsPosition, (), (const, override)); + MOCK_METHOD(qreal, onePercentAngularVelocity, (), (const, override)); // clazy:enable }; } diff --git a/qrtest/unitTests/pluginsTests/robotsTests/commonTests/twoDModelTests/data/pixelWorldModel.xml b/qrtest/unitTests/pluginsTests/robotsTests/commonTests/twoDModelTests/data/pixelWorldModel.xml index 5ef06335d7..3798b73266 100644 --- a/qrtest/unitTests/pluginsTests/robotsTests/commonTests/twoDModelTests/data/pixelWorldModel.xml +++ b/qrtest/unitTests/pluginsTests/robotsTests/commonTests/twoDModelTests/data/pixelWorldModel.xml @@ -5,10 +5,15 @@ + + + + + diff --git a/qrtest/unitTests/pluginsTests/robotsTests/commonTests/twoDModelTests/engineTests/modelTests/modelParserTests.cpp b/qrtest/unitTests/pluginsTests/robotsTests/commonTests/twoDModelTests/engineTests/modelTests/modelParserTests.cpp index b13906e51a..3d0f828fdc 100644 --- a/qrtest/unitTests/pluginsTests/robotsTests/commonTests/twoDModelTests/engineTests/modelTests/modelParserTests.cpp +++ b/qrtest/unitTests/pluginsTests/robotsTests/commonTests/twoDModelTests/engineTests/modelTests/modelParserTests.cpp @@ -24,36 +24,21 @@ #include "src/engine/items/skittleItem.h" #include "src/engine/items/lineItem.h" #include "src/engine/items/ballItem.h" +#include "src/engine/items/cubeItem.h" #include "src/engine/items/commentItem.h" #include #include +#include #include using namespace ::testing; using namespace qrTest::robotsTests::commonTwoDModelTests; -namespace { - -static QString readAll(const QString &fileName) { - QFile file(fileName); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - return QString(); - } - - QTextStream input; - input.setDevice(&file); - input.setCodec("UTF-8"); - const QString text = input.readAll(); - return text; -} -} - void ModelParserTests::SetUp() { - mModel.reset( - new twoDModel::model::Model(new PhysicsEngineFactoryMock())); - mRobotModel.reset(new RobotModelInterfaceMock()); - mTwoDRobotModel.reset(new TwoDRobotModelMock(*mRobotModel.data())); + mModel.reset(new twoDModel::model::Model(new testing::NiceMock())); + mRobotModel.reset(new testing::NiceMock()); + mTwoDRobotModel.reset(new testing::NiceMock(*mRobotModel.data())); mModel->addRobotModel(*mTwoDRobotModel.data()); } @@ -72,7 +57,7 @@ TEST_F(ModelParserTests, defaultMetricSystemCustomObjectParametersTest) EXPECT_CALL(*mTwoDRobotModel, robotId()).Times(AtLeast(1)); QDomDocument doc; - const auto xml = readAll("./data/pixelWorldModel.xml"); + const auto xml = utils::InFile::readAll("./data/pixelWorldModel.xml"); doc.setContent(xml); mModel->deserialize(doc); const auto &setting = mModel->settings(); @@ -101,6 +86,12 @@ TEST_F(ModelParserTests, defaultMetricSystemCustomObjectParametersTest) EXPECT_FLOAT_EQ(skittleItem->y(), -25.0f); EXPECT_FLOAT_EQ(skittleItem->rotation(), 10.0f); + const auto skittleWithBeginItem = skittles["skittle_with_begin"]; + const auto skittleWidth = skittleWithBeginItem->boundingRect().width(); + const auto skittleHeight = skittleWithBeginItem->boundingRect().height(); + EXPECT_FLOAT_EQ(skittleWithBeginItem->x(), 250 + skittleWidth / 2); + EXPECT_FLOAT_EQ(skittleWithBeginItem->y(), 300 + skittleHeight / 2); + const auto skittleSolidItem = static_cast(skittleItem.data()); EXPECT_FLOAT_EQ(skittleSolidItem->friction(), 0.5f); EXPECT_FLOAT_EQ(skittleSolidItem->restitution(), 0.2f); @@ -118,6 +109,12 @@ TEST_F(ModelParserTests, defaultMetricSystemCustomObjectParametersTest) EXPECT_FLOAT_EQ(ballItem->y(), -25.0f); EXPECT_FLOAT_EQ(ballItem->rotation(), 10.0f); + const auto ballWithBeginItem = balls["ball_with_begin"]; + const auto ballWidth = ballWithBeginItem->boundingRect().width(); + const auto ballHeight = ballWithBeginItem->boundingRect().height(); + EXPECT_FLOAT_EQ(ballWithBeginItem->x(), 250 + ballWidth / 2); + EXPECT_FLOAT_EQ(ballWithBeginItem->y(), 300 + ballHeight / 2); + const auto ballSolidItem = static_cast(ballItem.data()); EXPECT_FLOAT_EQ(ballSolidItem->friction(), 0.4f); EXPECT_FLOAT_EQ(ballSolidItem->restitution(), 0.7f); @@ -156,6 +153,12 @@ TEST_F(ModelParserTests, defaultMetricSystemCustomObjectParametersTest) EXPECT_FLOAT_EQ(comment->x2(), 481.938f); EXPECT_FLOAT_EQ(comment->y2(), -207.0f); + auto cubes = worldModel.cubes(); + const auto cubeWithBeginItem = cubes["cube_with_begin"]; + const auto worldPoint = cubeWithBeginItem->mapToScene({cubeWithBeginItem->x1(), cubeWithBeginItem->y1()}); + EXPECT_FLOAT_EQ(worldPoint.x(), 250); + EXPECT_FLOAT_EQ(worldPoint.y(), 300); + auto robotModels = mModel->robotModels(); EXPECT_EQ(robotModels.size(), 1); auto robotModel = robotModels[0]; @@ -181,7 +184,7 @@ constexpr auto epsilon = 1e-4; constexpr auto pixelsInCm = 16.0 / 5.6; #define EXPECT_LT_ABS(X, Y) \ - EXPECT_NEAR(X, Y * pixelsInCm, epsilon) + EXPECT_NEAR(X, (Y) * pixelsInCm, epsilon) TEST_F(ModelParserTests, cmConfugurationDefaultParametersTest) { @@ -191,7 +194,7 @@ TEST_F(ModelParserTests, cmConfugurationDefaultParametersTest) EXPECT_CALL(*mTwoDRobotModel, robotId()).Times(AtLeast(1)); QDomDocument doc; - const auto xml = readAll("./data/cmWorldModel.xml"); + const auto xml = utils::InFile::readAll("./data/cmWorldModel.xml"); doc.setContent(xml); mModel->deserialize(doc); const auto &setting = mModel->settings(); diff --git a/qrtranslations/es/plugins/robots/common/twoDModel_es.ts b/qrtranslations/es/plugins/robots/common/twoDModel_es.ts index 84c44241ac..d1c58a4299 100644 --- a/qrtranslations/es/plugins/robots/common/twoDModel_es.ts +++ b/qrtranslations/es/plugins/robots/common/twoDModel_es.ts @@ -350,7 +350,7 @@ twoDModel::items::BallItem - + Ball (B) Pelota (B) @@ -414,7 +414,7 @@ twoDModel::items::SkittleItem - + Can (C) Lata (C) diff --git a/qrtranslations/fr/plugins/robots/common/twoDModel_fr.ts b/qrtranslations/fr/plugins/robots/common/twoDModel_fr.ts index 4d3385d988..32d0415d49 100644 --- a/qrtranslations/fr/plugins/robots/common/twoDModel_fr.ts +++ b/qrtranslations/fr/plugins/robots/common/twoDModel_fr.ts @@ -358,7 +358,7 @@ twoDModel::items::BallItem - + Ball (B) Balle (B) @@ -422,7 +422,7 @@ twoDModel::items::SkittleItem - + Can (C) Boîte (C) diff --git a/qrtranslations/fr/plugins/robots/interpreters/trikV6KitInterpreter_fr.ts b/qrtranslations/fr/plugins/robots/interpreters/trikV6KitInterpreter_fr.ts index 2c5cd8b1f4..02f436c277 100644 --- a/qrtranslations/fr/plugins/robots/interpreters/trikV6KitInterpreter_fr.ts +++ b/qrtranslations/fr/plugins/robots/interpreters/trikV6KitInterpreter_fr.ts @@ -37,7 +37,7 @@ trik::TrikV6KitInterpreterPlugin - + TRIK (model-2014) TRIK (modèle 2014) @@ -52,7 +52,7 @@ trik::robotModel::real::TrikV6RealRobotModel - + Interpretation (Wi-Fi) Interprétation (Wi-Fi) diff --git a/qrtranslations/ru/plugins/robots/common/twoDModel_ru.ts b/qrtranslations/ru/plugins/robots/common/twoDModel_ru.ts index 9c9995652a..27fb35ba7c 100644 --- a/qrtranslations/ru/plugins/robots/common/twoDModel_ru.ts +++ b/qrtranslations/ru/plugins/robots/common/twoDModel_ru.ts @@ -630,7 +630,7 @@ twoDModel::items::BallItem - + Ball (B) Мяч (B) @@ -698,7 +698,7 @@ twoDModel::items::SkittleItem - + Can (C) Банка (C) diff --git a/qrtranslations/ru/plugins/robots/interpreters/trikV6KitInterpreter_ru.ts b/qrtranslations/ru/plugins/robots/interpreters/trikV6KitInterpreter_ru.ts index 61fceb0d64..657adf8a9a 100644 --- a/qrtranslations/ru/plugins/robots/interpreters/trikV6KitInterpreter_ru.ts +++ b/qrtranslations/ru/plugins/robots/interpreters/trikV6KitInterpreter_ru.ts @@ -75,7 +75,7 @@ ТРИК (старый корпус) - + TRIK (model-2014) ТРИК (модель 2014) @@ -97,7 +97,7 @@ trik::robotModel::real::TrikV6RealRobotModel - + Interpretation (Wi-Fi) Интерпретация (Wi-Fi) diff --git a/qrtranslations/vi/plugins/robots/common/twoDModel_vi.ts b/qrtranslations/vi/plugins/robots/common/twoDModel_vi.ts index b8fb9192ce..89dc9e32ce 100644 --- a/qrtranslations/vi/plugins/robots/common/twoDModel_vi.ts +++ b/qrtranslations/vi/plugins/robots/common/twoDModel_vi.ts @@ -350,7 +350,7 @@ twoDModel::items::BallItem - + Ball (B) Bóng (B) @@ -414,7 +414,7 @@ twoDModel::items::SkittleItem - + Can (C) Lon (C)