From 05af1cc356f2801ba447edcb67d04fbe38a52faf Mon Sep 17 00:00:00 2001 From: MinyazevR Date: Sun, 18 Jan 2026 09:48:15 +0300 Subject: [PATCH 1/6] Add resizing to grids in different metric systems --- .../engine/model/metricCoordinateSystem.h | 8 +- .../twoDModel/engine/model/metricSystem.h | 17 +- .../include/twoDModel/engine/model/settings.h | 17 +- .../twoDModel/engine/view/twoDModelWidget.h | 4 +- .../src/engine/items/colorFieldItem.h | 4 - .../twoDModel/src/engine/items/imageItem.cpp | 14 +- .../twoDModel/src/engine/items/imageItem.h | 4 +- .../twoDModel/src/engine/items/wallItem.cpp | 32 ++-- .../twoDModel/src/engine/items/wallItem.h | 8 +- .../engine/model/metricCoordinateSystem.cpp | 10 +- .../src/engine/model/metricSystem.cpp | 86 ++++++----- .../twoDModel/src/engine/model/settings.cpp | 33 ++-- .../src/engine/view/parts/gridParameters.cpp | 65 ++++++-- .../src/engine/view/parts/gridParameters.h | 8 +- .../src/engine/view/parts/gridSizeWidget.cpp | 126 +++++++++++++++ .../src/engine/view/parts/gridSizeWidget.h | 49 ++++++ .../twoDModel/src/engine/view/parts/ruler.cpp | 72 +++++---- .../twoDModel/src/engine/view/parts/ruler.h | 13 +- .../src/engine/view/scene/twoDModelScene.cpp | 16 +- .../src/engine/view/twoDModelWidget.cpp | 75 +++++---- .../src/engine/view/twoDModelWidget.ui | 36 ++--- plugins/robots/common/twoDModel/twoDModel.pri | 2 + .../interpreterCoreDefaultSettings.ini | 3 +- .../es/plugins/robots/common/twoDModel_es.ts | 145 +++++++++++------- qrtranslations/es/qrutils_es.ts | 2 +- .../fr/plugins/robots/common/twoDModel_fr.ts | 93 +++++++---- qrtranslations/fr/qrutils_fr.ts | 2 +- .../ru/plugins/robots/common/twoDModel_ru.ts | 93 +++++++---- qrtranslations/ru/qrutils_ru.ts | 2 +- .../vi/plugins/robots/common/twoDModel_vi.ts | 145 +++++++++++------- qrtranslations/vi/qrutils_vi.ts | 2 +- qrutils/graphicsUtils/abstractItem.cpp | 14 +- qrutils/graphicsUtils/abstractItem.h | 2 +- qrutils/graphicsUtils/gridDrawer.cpp | 32 ++-- qrutils/graphicsUtils/gridDrawer.h | 2 +- 35 files changed, 796 insertions(+), 440 deletions(-) create mode 100644 plugins/robots/common/twoDModel/src/engine/view/parts/gridSizeWidget.cpp create mode 100644 plugins/robots/common/twoDModel/src/engine/view/parts/gridSizeWidget.h diff --git a/plugins/robots/common/twoDModel/include/twoDModel/engine/model/metricCoordinateSystem.h b/plugins/robots/common/twoDModel/include/twoDModel/engine/model/metricCoordinateSystem.h index 3782836170..3ece58158c 100644 --- a/plugins/robots/common/twoDModel/include/twoDModel/engine/model/metricCoordinateSystem.h +++ b/plugins/robots/common/twoDModel/include/twoDModel/engine/model/metricCoordinateSystem.h @@ -29,10 +29,10 @@ class MetricCoordinateSystem: public graphicsUtils::AbstractCoordinateSystem { Q_OBJECT public: - explicit MetricCoordinateSystem(twoDModel::model::SizeUnit *metricSystem, + explicit MetricCoordinateSystem(const QSharedPointer &metricSystem, QObject* parent = nullptr); - ~MetricCoordinateSystem(); + ~MetricCoordinateSystem() override; /// Conversе of units of measurement into pixels qreal toPx(const qreal size) const override; @@ -46,9 +46,7 @@ class MetricCoordinateSystem: public graphicsUtils::AbstractCoordinateSystem /// Converting pixels to QPointF QPointF toUnit(const QPointF &size) const override; private: - // Doesn't take ownership, ownership is twoDModel::model::Settings. - // The lifetime of this object is greater than MetricCoordinateSystem (see Model.h) - QPointer mMetricSystem; + QSharedPointer mMetricSystem; }; } diff --git a/plugins/robots/common/twoDModel/include/twoDModel/engine/model/metricSystem.h b/plugins/robots/common/twoDModel/include/twoDModel/engine/model/metricSystem.h index ea86e900ef..1f500a8e23 100644 --- a/plugins/robots/common/twoDModel/include/twoDModel/engine/model/metricSystem.h +++ b/plugins/robots/common/twoDModel/include/twoDModel/engine/model/metricSystem.h @@ -24,10 +24,8 @@ namespace twoDModel { namespace model { /// Incapsulates size unit settings used by 2D model. -class TWO_D_MODEL_EXPORT SizeUnit : public QObject +class TWO_D_MODEL_EXPORT SizeUnit { - Q_OBJECT - public: /// Possible units of measurement enum class Unit { @@ -42,6 +40,8 @@ class TWO_D_MODEL_EXPORT SizeUnit : public QObject /// The current pixel value in centimeters qreal pixelsInCm() const; + twoDModel::model::SizeUnit::Unit unit() const; + /// Serialize the sizeUnit in the WorldModel void serialize(QDomElement &parent) const; @@ -49,7 +49,7 @@ class TWO_D_MODEL_EXPORT SizeUnit : public QObject void deserialize(const QDomElement &parent); /// Set the current unit of measurement - void setUnit(twoDModel::model::SizeUnit::Unit unit); + void setSizeUnit(twoDModel::model::SizeUnit::Unit unit); /// Multiplier for conversion to pixels qreal countFactor() const; @@ -60,14 +60,9 @@ class TWO_D_MODEL_EXPORT SizeUnit : public QObject /// Get current unit string representation QString toStr() const; - std::map currentValues() const; - - Unit defaultUnit() const; - -Q_SIGNALS: - /// Emit when the sizeUnit is serialized - void sizeUnitChanged(const twoDModel::model::SizeUnit::Unit &unit); + static std::map currentValues(); + static Unit defaultUnit(); private: Unit mSizeUnit { Unit::Pixels }; qreal mPixelsInCm { twoDModel::pixelsInCm }; diff --git a/plugins/robots/common/twoDModel/include/twoDModel/engine/model/settings.h b/plugins/robots/common/twoDModel/include/twoDModel/engine/model/settings.h index f08662852c..10ee45062d 100644 --- a/plugins/robots/common/twoDModel/include/twoDModel/engine/model/settings.h +++ b/plugins/robots/common/twoDModel/include/twoDModel/engine/model/settings.h @@ -15,7 +15,7 @@ #pragma once #include -#include "metricSystem.h" +#include #include "twoDModel/twoDModelDeclSpec.h" class QDomElement; @@ -23,6 +23,8 @@ class QDomElement; namespace twoDModel { namespace model { +class SizeUnit; + /// Incapsulates settings used by 2D model. class TWO_D_MODEL_EXPORT Settings : public QObject { @@ -37,10 +39,6 @@ class TWO_D_MODEL_EXPORT Settings : public QObject /// Returns true is user wants to add some noise to sensors values. bool realisticSensors() const; - /// To simplify the already overloaded WorldModel xml, - /// it was decided to use a tag in the existing tag - SizeUnit *sizeUnit(); - qreal pixelsInCm() const; /// Returns true is user wants to add some noise to motors work. @@ -56,17 +54,22 @@ class TWO_D_MODEL_EXPORT Settings : public QObject void setRealisticMotors(bool set); - SizeUnit *sizeUnit() const; + QSharedPointer sizeUnit() const; Q_SIGNALS: /// Emitted each time when user modifies physical preferences. void physicsChanged(bool isRealistic); + /// Emit when the sizeUnit is serialized + void sizeUnitChanged(const QSharedPointer &unit); + + void gridSizeChanged(qreal size); + private: bool mRealisticPhysics { false }; bool mRealisticSensors { false }; bool mRealisticMotors { false }; - QScopedPointer mSizeUnitSystem; + QSharedPointer mSizeUnitSystem; }; } diff --git a/plugins/robots/common/twoDModel/include/twoDModel/engine/view/twoDModelWidget.h b/plugins/robots/common/twoDModel/include/twoDModel/engine/view/twoDModelWidget.h index 65cda9b327..04c1ff1d5e 100644 --- a/plugins/robots/common/twoDModel/include/twoDModel/engine/view/twoDModelWidget.h +++ b/plugins/robots/common/twoDModel/include/twoDModel/engine/view/twoDModelWidget.h @@ -50,6 +50,7 @@ namespace twoDModel { namespace model { class Model; class RobotModel; +class SizeUnit; } namespace view { @@ -172,8 +173,7 @@ private Q_SLOTS: void trainingModeChanged(bool enabled); void updateUIPhysicsSettings(); - void updateRobotInfoWidget(const qreal factor, const QString& unitString); - + void updateRobotInfoWidget(const QSharedPointer &sizeUnit); private: enum CursorType { diff --git a/plugins/robots/common/twoDModel/src/engine/items/colorFieldItem.h b/plugins/robots/common/twoDModel/src/engine/items/colorFieldItem.h index fbe89313ca..74355f9a50 100644 --- a/plugins/robots/common/twoDModel/src/engine/items/colorFieldItem.h +++ b/plugins/robots/common/twoDModel/src/engine/items/colorFieldItem.h @@ -17,10 +17,6 @@ namespace twoDModel { -namespace model { -class SizeUnit; -} - namespace items { class ColorFieldItem: public view::TwoDSceneItem diff --git a/plugins/robots/common/twoDModel/src/engine/items/imageItem.cpp b/plugins/robots/common/twoDModel/src/engine/items/imageItem.cpp index 9345ccfd3f..b5ab8e11f4 100644 --- a/plugins/robots/common/twoDModel/src/engine/items/imageItem.cpp +++ b/plugins/robots/common/twoDModel/src/engine/items/imageItem.cpp @@ -25,7 +25,7 @@ using namespace qReal; using namespace graphicsUtils; ImageItem::ImageItem(graphicsUtils::AbstractCoordinateSystem *metricSystem, - const QSharedPointer &image, QRect geometry) + const QSharedPointer &image, const QRectF &geometry) : mImage(image) { setCoordinateSystem(metricSystem); @@ -44,7 +44,7 @@ ImageItem::ImageItem(graphicsUtils::AbstractCoordinateSystem *metricSystem, AbstractItem *ImageItem::clone() const { - const auto cloned = new ImageItem(coordinateSystem(), mImage, QRect(x1(), y1(), x2() - x1(), y2() - y1())); + const auto cloned = new ImageItem(coordinateSystem(), mImage, QRectF(x1(), y1(), x2() - x1(), y2() - y1())); AbstractItem::copyTo(cloned); return cloned; } @@ -90,7 +90,7 @@ QRectF ImageItem::boundingRect() const QRectF ImageItem::calcNecessaryBoundingRect() const { - return QRectF(qMin(x1(), x2()), qMin(y1(), y2()), qAbs(x2() - x1()), qAbs(y2() - y1())); + return {qMin(x1(), x2()), qMin(y1(), y2()), qAbs(x2() - x1()), qAbs(y2() - y1())}; } void ImageItem::drawItem(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) @@ -232,10 +232,10 @@ QRectF ImageItem::deserializeRect(const QString &string) const const auto y = splittedStr[1].toDouble(); const auto w = splittedStr[2].toDouble(); const auto h = splittedStr[3].toDouble(); - return QRectF(x, y, w, h); + return {x, y, w, h}; } - return QRectF(); + return {}; } void ImageItem::resizeItem(QGraphicsSceneMouseEvent *event) @@ -250,7 +250,7 @@ void ImageItem::resizeItem(QGraphicsSceneMouseEvent *event) } } else if (dragState() != None) { setFlag(QGraphicsItem::ItemIsMovable, false); - const auto gridSize = SettingsManager::value("2dGridCellSize").toInt(); + const auto gridSize = SettingsManager::value("2dDoubleGridCellSize").toReal(); const auto x = alignedCoordinate(event->scenePos().x(), gridSize); const auto y = alignedCoordinate(event->scenePos().y(), gridSize); setXYWithDragState(mapFromScene(x, y)); @@ -261,7 +261,7 @@ void ImageItem::resizeItem(QGraphicsSceneMouseEvent *event) // and align top left corner to grid QRectF itemBoundingRect = calcNecessaryBoundingRect(); const auto topLeft = mapToScene(QPointF(itemBoundingRect.left(), itemBoundingRect.top())); - const auto gridSize = SettingsManager::value("2dGridCellSize").toInt(); + const auto gridSize = SettingsManager::value("2dDoubleGridCellSize").toReal(); const auto x = alignedCoordinate(topLeft.x(), gridSize); const auto y = alignedCoordinate(topLeft.y(), gridSize); auto delta = QPointF(x, y) - topLeft; diff --git a/plugins/robots/common/twoDModel/src/engine/items/imageItem.h b/plugins/robots/common/twoDModel/src/engine/items/imageItem.h index 40544c4528..8565b6d7d9 100644 --- a/plugins/robots/common/twoDModel/src/engine/items/imageItem.h +++ b/plugins/robots/common/twoDModel/src/engine/items/imageItem.h @@ -33,7 +33,7 @@ class ImageItem : public graphicsUtils::AbstractItem public: ImageItem(graphicsUtils::AbstractCoordinateSystem *metricSystem, - const QSharedPointer &image, QRect geometry); + const QSharedPointer &image, const QRectF &geometry); AbstractItem *clone() const; @@ -45,7 +45,7 @@ class ImageItem : public graphicsUtils::AbstractItem QRectF boundingRect() const override; QRectF calcNecessaryBoundingRect() const override; - void drawItem(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override; + void drawItem(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; void drawExtractionForItem(QPainter* painter) override; QPainterPath resizeArea() const override; void resizeItem(QGraphicsSceneMouseEvent *event) override; diff --git a/plugins/robots/common/twoDModel/src/engine/items/wallItem.cpp b/plugins/robots/common/twoDModel/src/engine/items/wallItem.cpp index 97262da765..970e462aec 100644 --- a/plugins/robots/common/twoDModel/src/engine/items/wallItem.cpp +++ b/plugins/robots/common/twoDModel/src/engine/items/wallItem.cpp @@ -190,7 +190,8 @@ QPainterPath WallItem::path() const void WallItem::recalculateBorders() { - mPath = mLineImpl.shape(mWallWidth, begin().x(), begin().y(), end().x(), end().y()); + /// TODO: Fix narrowing conversion + mPath = mLineImpl.shape(static_cast(mWallWidth), begin().x(), begin().y(), end().x(), end().y()); } void WallItem::resizeItem(QGraphicsSceneMouseEvent *event) @@ -202,7 +203,7 @@ void WallItem::resizeItem(QGraphicsSceneMouseEvent *event) reshapeRectWithShift(); } else { if (SettingsManager::value("2dShowGrid").toBool() && event->modifiers() != Qt::ControlModifier) { - resizeWithGrid(event, SettingsManager::value("2dGridCellSize").toInt()); + resizeWithGrid(event, SettingsManager::value("2dDoubleGridCellSize").toReal()); } else { if (dragState() == TopLeft || dragState() == BottomRight) { calcResizeItem(event); @@ -220,7 +221,8 @@ void WallItem::reshapeRectWithShift() const qreal differenceY = qAbs(y2() - y1()); const qreal differenceXY = qAbs(differenceX - differenceY); const qreal size = qMax(differenceX, differenceY); - const int delta = size / 2; + /// TODO: Fix narrowing conversion + const int delta = static_cast(size / 2); if (differenceXY > delta) { const qreal corner1X = dragState() == TopLeft ? x2() : x1(); const qreal corner1Y = dragState() == TopLeft ? y2() : y1(); @@ -247,7 +249,7 @@ void WallItem::reshapeRectWithShift() } } -void WallItem::resizeWithGrid(QGraphicsSceneMouseEvent *event, int indexGrid) +void WallItem::resizeWithGrid(QGraphicsSceneMouseEvent *event, qreal gridSize) { const qreal x = mapFromScene(event->scenePos()).x(); const qreal y = mapFromScene(event->scenePos()).y(); @@ -257,31 +259,31 @@ void WallItem::resizeWithGrid(QGraphicsSceneMouseEvent *event, int indexGrid) if (dragState() == TopLeft) { setX1(x); setY1(y); - reshapeBeginWithGrid(indexGrid); + reshapeBeginWithGrid(gridSize); } else if (dragState() == BottomRight) { setX2(x); setY2(y); - reshapeEndWithGrid(indexGrid); + reshapeEndWithGrid(gridSize); } else { setPos(mEstimatedPos); - moveBy(alignedCoordinate(begin().x(), indexGrid) - begin().x() - , alignedCoordinate(begin().y(), indexGrid) - begin().y()); + moveBy(alignedCoordinate(begin().x(), gridSize) - begin().x() + , alignedCoordinate(begin().y(), gridSize) - begin().y()); } } -void WallItem::reshapeEndWithGrid(int indexGrid) +void WallItem::reshapeEndWithGrid(qreal gridSize) { - setX2(alignedCoordinate(end().x(), indexGrid) - pos().x()); - setY2(alignedCoordinate(end().y(), indexGrid) - pos().y()); + setX2(alignedCoordinate(end().x(), gridSize) - pos().x()); + setY2(alignedCoordinate(end().y(), gridSize) - pos().y()); } -void WallItem::reshapeBeginWithGrid(int indexGrid) +void WallItem::reshapeBeginWithGrid(qreal gridSize) { - setX1(alignedCoordinate(begin().x(), indexGrid) - pos().x()); - setY1(alignedCoordinate(begin().y(), indexGrid) - pos().y()); + setX1(alignedCoordinate(begin().x(), gridSize) - pos().x()); + setY1(alignedCoordinate(begin().y(), gridSize) - pos().y()); } -void WallItem::alignTheWall(int indexGrid) +void WallItem::alignTheWall(qreal indexGrid) { reshapeBeginWithGrid(indexGrid); reshapeEndWithGrid(indexGrid); diff --git a/plugins/robots/common/twoDModel/src/engine/items/wallItem.h b/plugins/robots/common/twoDModel/src/engine/items/wallItem.h index e71c20e0e0..37c0c9a145 100644 --- a/plugins/robots/common/twoDModel/src/engine/items/wallItem.h +++ b/plugins/robots/common/twoDModel/src/engine/items/wallItem.h @@ -58,12 +58,12 @@ class WallItem : public graphicsUtils::AbstractItem, public SolidItem QPainterPath path() const; - void resizeWithGrid(QGraphicsSceneMouseEvent *event, int indexGrid); + void resizeWithGrid(QGraphicsSceneMouseEvent *event, qreal gridSize); - void reshapeEndWithGrid(int indexGrid); - void reshapeBeginWithGrid(int indexGrid); + void reshapeEndWithGrid(qreal indexGrid); + void reshapeBeginWithGrid(qreal indexGrid); void setDraggedEnd(qreal x, qreal y); - void alignTheWall(int indexGrid); + void alignTheWall(qreal indexGrid); QPolygonF collidingPolygon() const override; BodyType bodyType() const override; diff --git a/plugins/robots/common/twoDModel/src/engine/model/metricCoordinateSystem.cpp b/plugins/robots/common/twoDModel/src/engine/model/metricCoordinateSystem.cpp index 833baa490a..5c7408b1bb 100644 --- a/plugins/robots/common/twoDModel/src/engine/model/metricCoordinateSystem.cpp +++ b/plugins/robots/common/twoDModel/src/engine/model/metricCoordinateSystem.cpp @@ -19,20 +19,18 @@ using namespace twoDModel::model; MetricCoordinateSystem::MetricCoordinateSystem( - twoDModel::model::SizeUnit *metricSystem, + const QSharedPointer &metricSystem, QObject* parent) : graphicsUtils::AbstractCoordinateSystem(parent) , mMetricSystem(metricSystem) { } -MetricCoordinateSystem::~MetricCoordinateSystem() -{ -} +MetricCoordinateSystem::~MetricCoordinateSystem() = default; qreal MetricCoordinateSystem::toPx(const qreal size) const { - if (mMetricSystem.isNull()) { + if (!mMetricSystem) { return size; } @@ -41,7 +39,7 @@ qreal MetricCoordinateSystem::toPx(const qreal size) const qreal MetricCoordinateSystem::toUnit(const qreal size) const { - if (mMetricSystem.isNull()) { + if (!mMetricSystem) { return size; } diff --git a/plugins/robots/common/twoDModel/src/engine/model/metricSystem.cpp b/plugins/robots/common/twoDModel/src/engine/model/metricSystem.cpp index 9b3923fe02..96fdccdc63 100644 --- a/plugins/robots/common/twoDModel/src/engine/model/metricSystem.cpp +++ b/plugins/robots/common/twoDModel/src/engine/model/metricSystem.cpp @@ -13,42 +13,46 @@ * limitations under the License. */ #include - #include "twoDModel/engine/model/metricSystem.h" using namespace twoDModel::model; namespace { - /// Translation of a string representation into a unit - static SizeUnit::Unit stringToUnit(const QString &unit) { - if (unit.isEmpty()) { - return SizeUnit::Unit::Pixels; - } - if (unit == "cm") { - return SizeUnit::Unit::Centimeters; - } - if (unit == "mm") { - return SizeUnit::Unit::Millimeters; - } - if (unit == "m") { - return SizeUnit::Unit::Meters; - } +/// Translation of a string representation into a unit +SizeUnit::Unit stringToUnit(const QString &unit) { + if (unit.isEmpty()) { return SizeUnit::Unit::Pixels; } + if (unit == "cm") { + return SizeUnit::Unit::Centimeters; + } + if (unit == "mm") { + return SizeUnit::Unit::Millimeters; + } + if (unit == "m") { + return SizeUnit::Unit::Meters; + } + return SizeUnit::Unit::Pixels; +} - /// Translation of a unit into a string representation - static QString unitToString(SizeUnit::Unit unit) { - if (unit == SizeUnit::Unit::Centimeters) { - return "cm"; - } - if (unit == SizeUnit::Unit::Millimeters) { - return "mm"; - } - if (unit == SizeUnit::Unit::Meters) { - return "m"; - } - return {}; +/// Translation of a unit into a string representation +QString unitToString(SizeUnit::Unit unit) { + if (unit == SizeUnit::Unit::Centimeters) { + return "cm"; + } + if (unit == SizeUnit::Unit::Millimeters) { + return "mm"; } + if (unit == SizeUnit::Unit::Meters) { + return "m"; + } + return {}; +} +} + +SizeUnit::Unit SizeUnit::unit() const +{ + return mSizeUnit; } qreal SizeUnit::pixelsInCm() const @@ -67,14 +71,13 @@ void SizeUnit::serialize(QDomElement &parent) const void SizeUnit::deserialize(const QDomElement &parent) { if (!parent.isNull()) { - setUnit(stringToUnit(parent.attribute("sizeUnit", ""))); + setSizeUnit(stringToUnit(parent.attribute("sizeUnit", ""))); } else { - setUnit(defaultUnit()); + setSizeUnit(defaultUnit()); } - Q_EMIT sizeUnitChanged(mSizeUnit); } -void SizeUnit::setUnit(twoDModel::model::SizeUnit::Unit unit) +void SizeUnit::setSizeUnit(twoDModel::model::SizeUnit::Unit unit) { mSizeUnit = unit; } @@ -110,27 +113,28 @@ qreal SizeUnit::toPx(const qreal size) const QString SizeUnit::toStr() const { if (mSizeUnit == SizeUnit::Unit::Centimeters) { - return tr("cm"); + return QObject::tr("cm"); } if (mSizeUnit == SizeUnit::Unit::Millimeters) { - return tr("mm"); + return QObject::tr("mm"); } if (mSizeUnit == SizeUnit::Unit::Meters) { - return tr("m"); + return QObject::tr("m"); } - return tr("px"); + return QObject::tr("px"); } -std::map SizeUnit::currentValues() const +std::map SizeUnit::currentValues() { return { - {tr("Pixels"), Unit::Pixels } - , {tr("Centimeters"), Unit::Centimeters} - , {tr("Meters"), Unit::Meters} - , {tr("Millimeters"), Unit::Millimeters} + {QObject::tr("Pixels"), Unit::Pixels } + , {QObject::tr("Centimeters"), Unit::Centimeters} + , {QObject::tr("Meters"), Unit::Meters} + , {QObject::tr("Millimeters"), Unit::Millimeters} }; } -SizeUnit::Unit SizeUnit::defaultUnit() const { +SizeUnit::Unit SizeUnit::defaultUnit() +{ return Unit::Pixels; } diff --git a/plugins/robots/common/twoDModel/src/engine/model/settings.cpp b/plugins/robots/common/twoDModel/src/engine/model/settings.cpp index add10634a1..075f549aeb 100644 --- a/plugins/robots/common/twoDModel/src/engine/model/settings.cpp +++ b/plugins/robots/common/twoDModel/src/engine/model/settings.cpp @@ -13,16 +13,15 @@ * limitations under the License. */ #include - -#include "twoDModel/engine/model/settings.h" - #include +#include "twoDModel/engine/model/settings.h" +#include "twoDModel/engine/model/metricSystem.h" using namespace twoDModel::model; Settings::Settings(QObject *parent) : QObject(parent) - , mSizeUnitSystem(new SizeUnit()) + , mSizeUnitSystem(new SizeUnit()) {} bool Settings::realisticPhysics() const @@ -40,11 +39,6 @@ qreal Settings::pixelsInCm() const return mSizeUnitSystem->pixelsInCm(); } -SizeUnit *Settings::sizeUnit() -{ - return mSizeUnitSystem.data(); -} - bool Settings::realisticMotors() const { return mRealisticMotors; @@ -58,6 +52,9 @@ void Settings::serialize(QDomElement &parent) const result.setAttribute("realisticSensors", mRealisticSensors ? "true" : "false"); result.setAttribute("realisticMotors", mRealisticMotors ? "true" : "false"); mSizeUnitSystem->serialize(result); + const auto currentGridSize = qReal::SettingsManager::value("2dDoubleGridCellSize") + .toReal() / mSizeUnitSystem->countFactor(); + result.setAttribute("gridCellSize", QString::number(currentGridSize)); } void Settings::deserialize(const QDomElement &parent) @@ -67,6 +64,20 @@ void Settings::deserialize(const QDomElement &parent) mRealisticMotors = parent.attribute("realisticMotors") == "true"; mSizeUnitSystem->deserialize(parent); Q_EMIT physicsChanged(mRealisticPhysics); + Q_EMIT sizeUnitChanged(mSizeUnitSystem); + if (parent.hasAttribute("gridCellSize")) { + const auto gridSize = parent.attribute("gridCellSize").toDouble(); + // TODO: Synchronize with GridParamters.h + constexpr auto minimalSize = 10; + constexpr auto maximumSize = 150; + if (mSizeUnitSystem->toPx(gridSize) >= minimalSize + && mSizeUnitSystem->toPx(gridSize) <= maximumSize) { + Q_EMIT gridSizeChanged(gridSize); + return; + } + } + const auto gridSize = qReal::SettingsManager::value("2dDefaultGridCellSize", "50").toReal(); + Q_EMIT gridSizeChanged(gridSize); } void Settings::setRealisticPhysics(bool set) @@ -85,7 +96,7 @@ void Settings::setRealisticMotors(bool set) mRealisticMotors = set; } -SizeUnit *Settings::sizeUnit() const +QSharedPointer Settings::sizeUnit() const { - return mSizeUnitSystem.data(); + return mSizeUnitSystem; } diff --git a/plugins/robots/common/twoDModel/src/engine/view/parts/gridParameters.cpp b/plugins/robots/common/twoDModel/src/engine/view/parts/gridParameters.cpp index 3b14eec2d8..0d65cceaf4 100644 --- a/plugins/robots/common/twoDModel/src/engine/view/parts/gridParameters.cpp +++ b/plugins/robots/common/twoDModel/src/engine/view/parts/gridParameters.cpp @@ -13,51 +13,82 @@ * limitations under the License. */ #include "gridParameters.h" - #include #include - +#include "twoDModel/engine/model/metricSystem.h" #include using namespace twoDModel::view; +namespace { + constexpr auto minLE = 10; + constexpr auto maxLE = 150; + constexpr auto scale = 10000.0f; +} + GridParameters::GridParameters(QWidget *parent) : QFrame(parent) { - QHBoxLayout *layout = new QHBoxLayout(this); - + auto *layout = new QHBoxLayout(this); mShowGridCheckBox = new QCheckBox(this); mShowGridCheckBox->setText(tr("Grid")); mShowGridCheckBox->setTristate(false); - mCellSize = new QSlider(this); mCellSize->setOrientation(Qt::Horizontal); - mCellSize->setMinimum(50); - mCellSize->setMaximum(200); - mCellSize->setTickInterval(10); + mCellSize->setMinimum(minLE * scale); + mCellSize->setMaximum(maxLE * scale); + mCellSize->setSingleStep(0.1 * scale); + mCellSize->setPageStep(scale); mCellSize->setEnabled(false); layout->addWidget(mShowGridCheckBox); layout->addWidget(mCellSize); layout->setContentsMargins(5, 5, 5, 5); - connect(mShowGridCheckBox, SIGNAL(toggled(bool)), mCellSize, SLOT(setEnabled(bool))); - connect(mShowGridCheckBox, SIGNAL(toggled(bool)), this, SLOT(showGrid(bool))); - connect(mCellSize, SIGNAL(valueChanged(int)), this, SLOT(setCellSize(int))); + connect(mShowGridCheckBox, &QAbstractButton::toggled, mCellSize, &QWidget::setEnabled); + connect(mShowGridCheckBox, &QAbstractButton::toggled, this, &GridParameters::showGrid); + connect(mCellSize, &QAbstractSlider::valueChanged, this, &GridParameters::setCellSize); const bool showGrid = qReal::SettingsManager::value("2dShowGrid").toBool(); - const int gridSize = qReal::SettingsManager::value("2dGridCellSize").toInt(); + const qreal gridSize = qReal::SettingsManager::value("2dDefaultGridCellSize").toReal(); mShowGridCheckBox->setChecked(showGrid); - mCellSize->setValue(gridSize); - + mCellSize->setValue(qRound(gridSize * scale)); setLayout(layout); + // Bring the slider values closer to the step values (which should ideally be 0.1 of the unit of measurement) + connect(mCellSize, &QSlider::sliderMoved, this, [this](int rawValue) { + const auto step = mCellSize->singleStep(); + const auto snapped = qRound(static_cast(rawValue) / step) * step; + if (snapped != rawValue) { + mCellSize->setValue(snapped); + } + }); } -GridParameters::~GridParameters() +void GridParameters::onSizeUnitChanged(const QSharedPointer &unit) { + mSizeUnit = unit; + mCellSize->blockSignals(true); + const auto factor = unit->countFactor(); + // We adapt the slider to the coordinate system in such a way as to cover the desired range of values. + // Thus, with the selected millimeters, the range will be from 35000 to 525000, which corresponds + // to the size of the cell from 35 mm to 525 and allows you to set its size with an accuracy + // of a thousandth of a millimeter. mCellSize->setSingleStep(0.1 * scale) means that for the selected system, + // the step will be 1000 units. In other words, 0.1 of the selected measurement system + mCellSize->setMinimum(qRound((minLE / factor) * scale)); + mCellSize->setMaximum(qRound((maxLE / factor) * scale)); + const qreal currentGlobal = qReal::SettingsManager::value("2dDoubleGridCellSize").toReal(); + mCellSize->setValue(qRound((currentGlobal / factor) * scale)); + mCellSize->blockSignals(false); } +void GridParameters::onGridParametersChangedOutside(qreal newCellSize) +{ + mCellSize->setValue(qRound(newCellSize * scale)); +} + +GridParameters::~GridParameters() = default; + void GridParameters::showGrid(bool isGridEnabled) { qReal::SettingsManager::setValue("2dShowGrid", isGridEnabled); @@ -66,6 +97,8 @@ void GridParameters::showGrid(bool isGridEnabled) void GridParameters::setCellSize(int cellSizeValue) { - qReal::SettingsManager::setValue("2dGridCellSize", cellSizeValue); + const auto factor = mSizeUnit ? mSizeUnit->countFactor() : 1.0; + const auto unitsValue = static_cast(cellSizeValue) * factor / scale; + qReal::SettingsManager::setValue("2dDoubleGridCellSize", unitsValue); Q_EMIT parametersChanged(); } diff --git a/plugins/robots/common/twoDModel/src/engine/view/parts/gridParameters.h b/plugins/robots/common/twoDModel/src/engine/view/parts/gridParameters.h index 0eb8b5515d..c5ce6c0641 100644 --- a/plugins/robots/common/twoDModel/src/engine/view/parts/gridParameters.h +++ b/plugins/robots/common/twoDModel/src/engine/view/parts/gridParameters.h @@ -19,6 +19,9 @@ #include namespace twoDModel { +namespace model { +class SizeUnit; +} namespace view { class GridParameters : public QFrame @@ -27,11 +30,13 @@ class GridParameters : public QFrame public: explicit GridParameters(QWidget *parent = nullptr); - ~GridParameters(); + ~GridParameters() override; public Q_SLOTS: void showGrid(bool isGridEnabled); void setCellSize(int cellSizeValue); + void onGridParametersChangedOutside(qreal newCellSize); + void onSizeUnitChanged(const QSharedPointer &unit); Q_SIGNALS: void parametersChanged(); @@ -39,6 +44,7 @@ public Q_SLOTS: private: QSlider *mCellSize; QCheckBox *mShowGridCheckBox; + QSharedPointer mSizeUnit; }; } diff --git a/plugins/robots/common/twoDModel/src/engine/view/parts/gridSizeWidget.cpp b/plugins/robots/common/twoDModel/src/engine/view/parts/gridSizeWidget.cpp new file mode 100644 index 0000000000..bc1612dfda --- /dev/null +++ b/plugins/robots/common/twoDModel/src/engine/view/parts/gridSizeWidget.cpp @@ -0,0 +1,126 @@ +/* Copyright 2026 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. */ + +#include +#include +#include +#include +#include +#include +#include "gridSizeWidget.h" +#include + +using namespace twoDModel::view; + +namespace { +constexpr auto pixelMinimalValue = 10.0; +constexpr auto pixelMaximumValue = 150.0; +} + +GridSizeWidget::~GridSizeWidget() = default; + +GridSizeWidget::GridSizeWidget(QWidget *parent) + : QWidget(parent) + , mUnit(nullptr) + , mStackedWidget(new QStackedWidget(this)) +{ + setupUI(); + createSpinBoxes(); +} + +void GridSizeWidget::createSpinBoxes() +{ + auto onValueChangedLambda = [this](QObject *abstractSpinBox) { + if (auto * spinBox = qobject_cast(abstractSpinBox)) { + connect(spinBox, QOverload::of(&QDoubleSpinBox::valueChanged), + this, [this](qreal value) { + Q_EMIT gridSizeChanged(value); + }); + } + }; + + auto createSpinBoxLambda = [this, onValueChangedLambda](qreal step, int decimals, + twoDModel::model::SizeUnit::Unit unit) { + twoDModel::model::SizeUnit sizeUnit {}; + sizeUnit.setSizeUnit(unit); + auto *spinBox = new QDoubleSpinBox(this); + updateValues(spinBox, sizeUnit, step); + spinBox->setDecimals(decimals); + mSlubSpinBoxes.emplace(unit, spinBox); + mStackedWidget->addWidget(spinBox); + onValueChangedLambda(spinBox); + }; + + // Create custom Pixels SpinBox + createSpinBoxLambda(0.1, 3, twoDModel::model::SizeUnit::Unit::Pixels); + // Create custom Millimiter SpinBox + createSpinBoxLambda(0.1, 3, twoDModel::model::SizeUnit::Unit::Millimeters); + // Create custom Centimeter SpinBox + createSpinBoxLambda(0.1, 3, twoDModel::model::SizeUnit::Unit::Centimeters); + // Create custom Meter SpinBox + createSpinBoxLambda(0.05, 3, twoDModel::model::SizeUnit::Unit::Meters); + + mStackedWidget->setCurrentWidget(mSlubSpinBoxes[twoDModel::model::SizeUnit::defaultUnit()]); +} + +void GridSizeWidget::updateValues(QObject *spinBox, + twoDModel::model::SizeUnit sizeUnit, + qreal step) { + const auto displayMin = pixelMinimalValue / sizeUnit.countFactor(); + const auto displayMax = pixelMaximumValue / sizeUnit.countFactor(); + spinBox->setProperty("minimum", displayMin); + spinBox->setProperty("maximum", displayMax); + spinBox->setProperty("suffix", " " +sizeUnit.toStr()); + spinBox->setProperty("singleStep", step); +} + +void GridSizeWidget::setupUI() +{ + auto *layout = new QHBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(mStackedWidget); +} + +qreal GridSizeWidget::countFactor() +{ + return mUnit ? mUnit->countFactor() : 1.0f; +} + +void GridSizeWidget::onSizeUnitChanged(const QSharedPointer &unit) +{ + blockSignals(true); + mUnit = unit; + const auto it = mSlubSpinBoxes.find(mUnit->unit()); + if (it != mSlubSpinBoxes.end() && it->second != mStackedWidget->currentWidget()) { + mStackedWidget->setCurrentWidget(it->second); + setValue(it->second); + } + blockSignals(false); +} + +void GridSizeWidget::onGridParameterChanged() +{ + blockSignals(true); + setValue(mStackedWidget->currentWidget()); + blockSignals(false); +} + +void GridSizeWidget::setValue(QObject *currentSpinBox) +{ + if (!currentSpinBox) { + return; + } + const auto gridSize = qReal::SettingsManager::value("2dDoubleGridCellSize").toReal(); + currentSpinBox->setProperty("value", gridSize / countFactor()); +} diff --git a/plugins/robots/common/twoDModel/src/engine/view/parts/gridSizeWidget.h b/plugins/robots/common/twoDModel/src/engine/view/parts/gridSizeWidget.h new file mode 100644 index 0000000000..6bd0debab6 --- /dev/null +++ b/plugins/robots/common/twoDModel/src/engine/view/parts/gridSizeWidget.h @@ -0,0 +1,49 @@ +/* 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. */ + +#include +#include +#include "twoDModel/engine/model/metricSystem.h" +#include + +class QStackedWidget; + +namespace twoDModel { +namespace view { + +/// A class that represents a set of QDoubleSpinBox's for different units of measurement, +/// as they may require different sinlgeSterp, suffix, and other parameters. +class GridSizeWidget : public QWidget { + Q_OBJECT +public: + explicit GridSizeWidget(QWidget *parent = nullptr); + ~GridSizeWidget() override; +public Q_SLOTS: + void onSizeUnitChanged(const QSharedPointer &unit); + void onGridParameterChanged(); +Q_SIGNALS: + void gridSizeChanged(qreal size); +private: + void setupUI(); + qreal countFactor(); + static void updateValues(QObject *spinBox, twoDModel::model::SizeUnit sizeUnit, qreal step); + void setValue(QObject *currentSpinBox); + void createSpinBoxes(); + QSharedPointer mUnit; + QStackedWidget *mStackedWidget; + std::unordered_map mSlubSpinBoxes; +}; + +} +} diff --git a/plugins/robots/common/twoDModel/src/engine/view/parts/ruler.cpp b/plugins/robots/common/twoDModel/src/engine/view/parts/ruler.cpp index 000a85a4eb..29b876e6df 100644 --- a/plugins/robots/common/twoDModel/src/engine/view/parts/ruler.cpp +++ b/plugins/robots/common/twoDModel/src/engine/view/parts/ruler.cpp @@ -13,38 +13,36 @@ * limitations under the License. */ #include "ruler.h" - #include #include #include #include +#include "twoDModel/engine/model/metricSystem.h" using namespace twoDModel::view; const qreal gap = 5; // The gap between the ruler borders and text on it. -const int frequency = 150; // The text on the ruler will not be met more often than once per this number of pixels. +const int frequency = 50; // The text on the ruler will not be met more often than once per this number of pixels. Ruler::Ruler(QWidget *parent) : QFrame(parent) , mOrientation(Qt::Horizontal) - , mMetricFactor(1.0) + , mSizeUnit(nullptr) { mFont.setPixelSize(8); } -Ruler::~Ruler() -{ -} +Ruler::~Ruler() = default; Qt::Orientation Ruler::orientation() const { return mOrientation; } -void Ruler::setMetricFactor(const qreal factor) +void Ruler::onSizeUnitChanged(const QSharedPointer &unit) { - mMetricFactor = factor; + mSizeUnit = unit; } void Ruler::setOrientation(Qt::Orientation orientation) @@ -65,25 +63,37 @@ void Ruler::paintEvent(QPaintEvent *event) QFrame::paintEvent(event); QPainter painter(this); painter.setFont(mFont); - const int gridSize = qReal::SettingsManager::value("2dGridCellSize").toInt(); - const int shift = qMax(frequency / gridSize, 1); - const QRectF sceneRect = mView->mapToScene(mView->viewport()->geometry()).boundingRect(); - const int firstCell = qCeil(relevantCoordinate(sceneRect.topLeft())) / gridSize; - // This will let us always draw 0 near zero line for more persistent coordinates scrolling. - // Without making first cell being multiple of shift the first marker will be always upon the first - // line and that looks horrible when user scrolls the scene. - const int realFirstCell = firstCell / shift * shift * gridSize; - for (int coordinate = realFirstCell - ; coordinate < relevantCoordinate(sceneRect.bottomRight()) - ; coordinate += shift * gridSize) - { - const QString text = QString::number(coordinate / mMetricFactor); - const QRectF boundingRect = textBoundingRect(text); - const qreal relevantPosition = relevantCoordinate(mView->mapFromScene(makePoint(coordinate, 0))); - const QPointF position = drawingPoint(relevantPosition, boundingRect.size()); - const QPointF alignment = makePoint(relevantDimension(boundingRect.size()) / 2, 0); - - painter.drawText(position - boundingRect.topLeft() - alignment, text); + + const auto gridSize = qReal::SettingsManager::value("2dDoubleGridCellSize").toReal(); + const auto currentCountFactor = countFactor(); + const auto sceneRect = mView->mapToScene(mView->viewport()->geometry()).boundingRect(); + const auto startPos = relevantCoordinate(sceneRect.topLeft()); + const auto endPos = relevantCoordinate(sceneRect.bottomRight()); + + const auto zoom = mView->transform().m11(); + const auto skipCells = qMax(1, qCeil((frequency / zoom) / gridSize)); + const auto effectiveStep = skipCells * gridSize; + const auto startIdx = static_cast(std::floor(startPos / effectiveStep)); + const auto endIdx = static_cast(std::ceil(endPos / effectiveStep)); + + for (int i = startIdx; i <= endIdx; ++i) { + const qreal coordinate = i * effectiveStep; + QString text = QString::number(coordinate / currentCountFactor, 'f', 3); + if (text.contains('.')) { + while (text.endsWith('0')) { + text.chop(1); + } + if (text.endsWith('.')) { + text.chop(1); + } + } + const auto &boundingRect = textBoundingRect(text); + const auto relevantPosition = relevantCoordinate(mView->mapFromScene(makePoint(coordinate, 0))); + const auto position = drawingPoint(relevantPosition, boundingRect.size()); + const auto alignment = makePoint(relevantDimension(boundingRect.size()) / 2, 0); + if (relevantPosition >= 0 && relevantPosition <= relevantDimension(this->size())) { + painter.drawText(position - boundingRect.topLeft() - alignment, text); + } } } @@ -92,6 +102,14 @@ qreal Ruler::relevantCoordinate(QPointF point) const return orientation() == Qt::Horizontal ? point.x() : point.y(); } +qreal Ruler::countFactor() const +{ + if (mSizeUnit) { + return mSizeUnit->countFactor(); + } + return 1.0f; +} + qreal Ruler::relevantDimension(QSizeF size) const { return orientation() == Qt::Horizontal ? size.width() : size.height(); diff --git a/plugins/robots/common/twoDModel/src/engine/view/parts/ruler.h b/plugins/robots/common/twoDModel/src/engine/view/parts/ruler.h index b2fc53f3f8..36222aa773 100644 --- a/plugins/robots/common/twoDModel/src/engine/view/parts/ruler.h +++ b/plugins/robots/common/twoDModel/src/engine/view/parts/ruler.h @@ -19,6 +19,9 @@ class QGraphicsView; namespace twoDModel { +namespace model { +class SizeUnit; +} namespace view { /// A widget for displaying distances on grid in centimeters. @@ -30,7 +33,7 @@ class Ruler : public QFrame public: explicit Ruler(QWidget *parent = nullptr); - ~Ruler(); + ~Ruler() override; /// Returns the orientation of this ruler. Qt::Orientation orientation() const; @@ -39,24 +42,22 @@ public Q_SLOTS: /// Returns the orientation of this ruler. void setOrientation(Qt::Orientation orientation); - /// Reconfigures ruller to calculate distances in other metrics. The distance between grid lines in pixels - /// stays the same, but values in centimeters modified - void setMetricFactor(const qreal factor); + void onSizeUnitChanged(const QSharedPointer &unit); /// Configures this ruller to work with the given graphics view. void setScene(QGraphicsView *scene); - private: void paintEvent(QPaintEvent *event) override; qreal relevantCoordinate(QPointF point) const; + qreal countFactor() const; qreal relevantDimension(QSizeF size) const; qreal irrelevantDimension(QSizeF size) const; QPointF makePoint(qreal relevantCoordinate, qreal irrelevantCoordinate) const; QPointF drawingPoint(qreal relevantCoordinate, QSizeF textSize) const; QRectF textBoundingRect(const QString &text) const; Qt::Orientation mOrientation; - qreal mMetricFactor; + QSharedPointer mSizeUnit; QGraphicsView *mView {}; // Doesn`t take owership QFont mFont; }; diff --git a/plugins/robots/common/twoDModel/src/engine/view/scene/twoDModelScene.cpp b/plugins/robots/common/twoDModel/src/engine/view/scene/twoDModelScene.cpp index f08c83e411..1bfb45f4c5 100644 --- a/plugins/robots/common/twoDModel/src/engine/view/scene/twoDModelScene.cpp +++ b/plugins/robots/common/twoDModel/src/engine/view/scene/twoDModelScene.cpp @@ -818,7 +818,7 @@ void TwoDModelScene::drawBackground(QPainter *painter, const QRectF &rect) mWidthOfGrid = SettingsManager::value("GridWidth").toReal() / 100; painter->setPen(QPen(Qt::black, mWidthOfGrid)); QGraphicsScene::drawBackground(painter, rect); - const int cellSize = SettingsManager::value("2dGridCellSize").toInt(); + const qreal cellSize = SettingsManager::value("2dDoubleGridCellSize").toReal(); mGridDrawer.drawGrid(painter, rect, cellSize); drawAxes(painter); } @@ -883,9 +883,9 @@ void TwoDModelScene::addImage() , tr("Graphics (*.*)")); - const auto gridSize = SettingsManager::value("2dGridCellSize").toInt(); - const QPoint step(gridSize, gridSize); - QPoint topLeft = mainView()->mapToScene(0,0).toPoint() + step; + const auto gridSize = SettingsManager::value("2dDoubleGridCellSize").toReal(); + const QPointF step(gridSize, gridSize); + QPointF topLeft = mainView()->mapToScene(0,0).toPoint() + step; for (auto &&loadFileName : loadImages) { if (loadFileName.isEmpty()) { @@ -910,7 +910,7 @@ void TwoDModelScene::addImage() continue; } mDrawingAction = image; - const QRect rect(topLeft, size); + const QRectF rect(topLeft, size); QSharedPointer result(new twoDModel::items::ImageItem( &mModel.coordinateMetricSystem(), newImage, rect)); result->setMemorize(true); @@ -1014,8 +1014,8 @@ void TwoDModelScene::reshapeWall(QGraphicsSceneMouseEvent *event) mCurrentWall->setX2(pos.x()); mCurrentWall->setY2(pos.y()); if (SettingsManager::value("2dShowGrid").toBool()) { - mCurrentWall->reshapeBeginWithGrid(SettingsManager::value("2dGridCellSize").toInt()); - mCurrentWall->reshapeEndWithGrid(SettingsManager::value("2dGridCellSize").toInt()); + mCurrentWall->reshapeBeginWithGrid(SettingsManager::value("2dDoubleGridCellSize").toReal()); + mCurrentWall->reshapeEndWithGrid(SettingsManager::value("2dDoubleGridCellSize").toReal()); } else { if (event->modifiers() & Qt::ShiftModifier) { mCurrentWall->reshapeRectWithShift(); @@ -1143,7 +1143,7 @@ void TwoDModelScene::alignWalls() if (SettingsManager::value("2dShowGrid").toBool()) { for (auto &&wall : mModel.worldModel().walls()) { if (items().contains(wall.data())) { - wall->alignTheWall(SettingsManager::value("2dGridCellSize").toInt()); + wall->alignTheWall(SettingsManager::value("2dDoubleGridCellSize").toReal()); } } } diff --git a/plugins/robots/common/twoDModel/src/engine/view/twoDModelWidget.cpp b/plugins/robots/common/twoDModel/src/engine/view/twoDModelWidget.cpp index d9373ac9b7..2e004fae88 100644 --- a/plugins/robots/common/twoDModel/src/engine/view/twoDModelWidget.cpp +++ b/plugins/robots/common/twoDModel/src/engine/view/twoDModelWidget.cpp @@ -57,6 +57,7 @@ #include "twoDModel/engine/model/constants.h" #include "twoDModel/engine/model/twoDModelRobotParameters.h" #include "twoDModel/engine/model/model.h" +#include "twoDModel/engine/model/metricSystem.h" #include "nullTwoDModelDisplayWidget.h" #include @@ -145,13 +146,13 @@ TwoDModelWidget::TwoDModelWidget(Model &model, QWidget *parent) mUi->horizontalRuler->setScene(mUi->graphicsView); mUi->verticalRuler->setScene(mUi->graphicsView); + mUi->detailsTab->setParamsSettings(mUi->physicsParamsFrame); + mUi->detailsTab->setMetricSettings(mUi->metricFrame); - auto pixelsInCm = mModel.settings().pixelsInCm(); /// @todo: make some values editable + auto pixelsInCm = mModel.settings().pixelsInCm(); + connectMetricComboBoxes(); - mUi->detailsTab->setParamsSettings(mUi->physicsParamsFrame); - - updateRobotInfoWidget(pixelsInCm, tr("cm")); connect(&mModel, &model::Model::robotAdded, this, [this, pixelsInCm](){ auto robotModels = mModel.robotModels(); auto robotTrack = robotModels.isEmpty() || @@ -169,8 +170,10 @@ TwoDModelWidget::~TwoDModelWidget() delete mUi; } -void TwoDModelWidget::updateRobotInfoWidget(const qreal factor, const QString& unitString) +void TwoDModelWidget::updateRobotInfoWidget(const QSharedPointer &sizeUnit) { + const auto unitString = sizeUnit->toStr(); + const auto factor = sizeUnit->countFactor(); mUi->wheelDiamInCm->setValue(robotWheelDiameterInPx / factor); mUi->wheelDiameterUnit->setText(unitString); mUi->wheelDiamInCm->setButtonSymbols(QAbstractSpinBox::NoButtons); @@ -269,6 +272,12 @@ void TwoDModelWidget::initWidget() connect(mUi->editorModeButton, &QPushButton::toggled, &*mScene, &TwoDModelScene::onEditorModeToggled); connect(mUi->gridParametersBox, &twoDModel::view::GridParameters::parametersChanged , &*mScene, [&]() { mScene->update(); }); + connect(&mModel.settings(), &Settings::gridSizeChanged, + mUi->gridParametersBox, &GridParameters::onGridParametersChangedOutside); + connect(mUi->gridSizeWidget, &GridSizeWidget::gridSizeChanged, + mUi->gridParametersBox, &GridParameters::onGridParametersChangedOutside); + connect(mUi->gridParametersBox, &twoDModel::view::GridParameters::parametersChanged, + mUi->gridSizeWidget, &GridSizeWidget::onGridParameterChanged); connect(mUi->gridParametersBox, &GridParameters::parametersChanged, this, toggleRulers); connect(mUi->gridParametersBox, &twoDModel::view::GridParameters::parametersChanged , mUi->horizontalRuler, [&]() {mUi->horizontalRuler->update(); }); @@ -821,6 +830,7 @@ void TwoDModelWidget::setInteractivityFlags(ReadOnlyFlags flags) mRobotPositionReadOnly = flags.testFlag(ReadOnly::RobotPosition); if (mRobotPositionReadOnly) returnToStartMarker(); + mUi->metricComboBox->setVisible(!worldReadOnly); mScene->setInteractivityFlags(flags); } @@ -1053,31 +1063,34 @@ bool TwoDModelWidget::setSelectedValue(QComboBox * const comboBox, const T &port void TwoDModelWidget::connectMetricComboBoxes() { - connect(mModel.settings().sizeUnit(), &SizeUnit::sizeUnitChanged - , this, [=](SizeUnit::Unit unit) { - setSelectedValue(mUi->metricComboBox, unit); - }); - - connect(mUi->metricComboBox, QOverload::of(&QComboBox::currentIndexChanged) - , this, [this](int index) { - const auto unitValue = mUi->metricComboBox->itemData(index) - .value(); - const auto sizeUnit = mModel.settings().sizeUnit(); - sizeUnit->setUnit(unitValue); - const auto realValue = sizeUnit->countFactor(); - mUi->horizontalRuler->setMetricFactor(realValue); - mUi->verticalRuler->setMetricFactor(realValue); - updateRobotInfoWidget(realValue, sizeUnit->toStr()); - Q_EMIT mUi->gridParametersBox->parametersChanged(); + connect(&mModel.settings(), &Settings::sizeUnitChanged, this, [this] + (const QSharedPointer &unit) { + setSelectedValue(mUi->metricComboBox, unit->unit()); }); const auto sizeUnit = mModel.settings().sizeUnit(); const auto availableUnits = sizeUnit->currentValues(); for (auto &&availableUnit : availableUnits) { - mUi->metricComboBox->addItem(availableUnit.first, - QVariant::fromValue(availableUnit.second)); + mUi->metricComboBox->addItem(availableUnit.first, QVariant::fromValue(availableUnit.second)); } + auto lambdaOnUnitChanged = [this](const QSharedPointer &unit) { + mUi->gridParametersBox->onSizeUnitChanged(unit); + mUi->gridSizeWidget->onSizeUnitChanged(unit); + mUi->horizontalRuler->onSizeUnitChanged(unit); + mUi->verticalRuler->onSizeUnitChanged(unit); + updateRobotInfoWidget(unit); + }; + + connect(mUi->metricComboBox,QOverload::of(&QComboBox::currentIndexChanged), + this, [this, lambdaOnUnitChanged](int index) { + const auto unitValue = mUi->metricComboBox->itemData(index).value(); + auto sizeUnit = mModel.settings().sizeUnit(); + sizeUnit->setSizeUnit(unitValue); + lambdaOnUnitChanged(sizeUnit); + Q_EMIT mUi->gridParametersBox->parametersChanged(); + }); + setSelectedValue(mUi->metricComboBox, sizeUnit->defaultUnit()); } @@ -1179,12 +1192,6 @@ void TwoDModelWidget::onRobotListChange(RobotItem *robotItem) } } -namespace { - bool isTrikModel(const QString &name) { - return name.contains("TrikV62"); - } -} - void TwoDModelWidget::setSelectedRobotItem(RobotItem *robotItem) { mSelectedRobotItem = robotItem; @@ -1195,16 +1202,6 @@ void TwoDModelWidget::setSelectedRobotItem(RobotItem *robotItem) setPortsGroupBoxAndWheelComboBoxes(); updateWheelComboBoxes(); - if (isTrikModel(mSelectedRobotItem->robotModel().info().name())) { - mUi->detailsTab->setMetricSettings(mUi->metricFrame); - connectMetricComboBoxes(); - mUi->pixelsInCmDoubleSpinBox->setValue( - mModel.settings().pixelsInCm()); - } else { - mUi->detailsTab->setMetricSectionsVisible(false); - mUi->metricFrame->hide(); - } - mUi->detailsTab->setDisplay(nullptr); mDisplay = mSelectedRobotItem->robotModel().info().displayWidget(); mDisplay->setParent(this); diff --git a/plugins/robots/common/twoDModel/src/engine/view/twoDModelWidget.ui b/plugins/robots/common/twoDModel/src/engine/view/twoDModelWidget.ui index 25e178b5f4..3082e0cb8e 100644 --- a/plugins/robots/common/twoDModel/src/engine/view/twoDModelWidget.ui +++ b/plugins/robots/common/twoDModel/src/engine/view/twoDModelWidget.ui @@ -7,7 +7,7 @@ 0 0 988 - 669 + 687 @@ -434,36 +434,14 @@ - - - - 0 - 0 - - + - Pixels in cm: + Grid size: - - - true - - - true - - - 4 - - - 1000.000000000000000 - - - 1.000000000000000 - - + @@ -1006,6 +984,12 @@ QDoubleSpinBox
src/engine/view/parts/robotInfoSpinBox.h
+ + twoDModel::view::GridSizeWidget + QWidget +
src/engine/view/parts/gridSizeWidget.h
+ 1 +
diff --git a/plugins/robots/common/twoDModel/twoDModel.pri b/plugins/robots/common/twoDModel/twoDModel.pri index a86628f48e..1df80b11c5 100644 --- a/plugins/robots/common/twoDModel/twoDModel.pri +++ b/plugins/robots/common/twoDModel/twoDModel.pri @@ -87,6 +87,7 @@ HEADERS += \ $$PWD/src/engine/view/parts/robotItemPopup.h \ $$PWD/src/engine/view/parts/speedPopup.h \ $$PWD/src/engine/view/parts/ruler.h \ + $$PWD/src/engine/view/parts/gridSizeWidget.h \ $$PWD/src/engine/constraints/constraintsChecker.h \ $$PWD/src/engine/constraints/details/defines.h \ $$PWD/src/engine/constraints/details/constraintsParser.h \ @@ -162,6 +163,7 @@ SOURCES += \ $$PWD/src/engine/view/parts/robotItemPopup.cpp \ $$PWD/src/engine/view/parts/speedPopup.cpp \ $$PWD/src/engine/view/parts/ruler.cpp \ + $$PWD/src/engine/view/parts/gridSizeWidget.cpp \ $$PWD/src/engine/model/model.cpp \ $$PWD/src/engine/model/metricSystem.cpp \ $$PWD/src/engine/model/metricCoordinateSystem.cpp \ diff --git a/plugins/robots/interpreters/interpreterCore/interpreterCoreDefaultSettings.ini b/plugins/robots/interpreters/interpreterCore/interpreterCoreDefaultSettings.ini index bbf3e4c072..35ab47d1d5 100644 --- a/plugins/robots/interpreters/interpreterCore/interpreterCoreDefaultSettings.ini +++ b/plugins/robots/interpreters/interpreterCore/interpreterCoreDefaultSettings.ini @@ -9,7 +9,8 @@ SelectedRobotKit=trikV62Kit 2dFollowingRobot=true 2dCursorType=1 2dShowGrid=true -2dGridCellSize=50 +2dDoubleGridCellSize=50 +2dDefaultGridCellSize=50 2dEditorModeEnable=false approximationLevel=12 diff --git a/qrtranslations/es/plugins/robots/common/twoDModel_es.ts b/qrtranslations/es/plugins/robots/common/twoDModel_es.ts index 9573c6b44d..00fd5edb37 100644 --- a/qrtranslations/es/plugins/robots/common/twoDModel_es.ts +++ b/qrtranslations/es/plugins/robots/common/twoDModel_es.ts @@ -209,6 +209,46 @@ Object "%1" has no property "%2" El objeto "%1" no tiene la propiedad "%2" + + + cm + cm + + + + mm + mm + + + + m + m + + + + px + px + + + + Pixels + Píxeles + + + + Centimeters + Centímetros + + + + Meters + Metros + + + + Millimeters + Milímetros + TwoDModelWidget @@ -243,85 +283,89 @@ Unidades del sistema métrico: - Pixels in cm: - Píxeles por cm: + Píxeles por cm: + + + + Grid size: + Tamaño de cuadrícula: - + Realistic physics Física realista - + Realistic sensors Sensores realistas - + Realistic engines Motores realistas - + Robot height: Altura del robot: - + Robot mass: Masa del robot: - + Wheel diameter: Diámetro de la rueda: - + Robot track: Separación entre ruedas: - + Robot width: Ancho del robot: - - - - + + + + cm cm - + kg kg - + Decrease speed Disminuir velocidad - + Time in 2D model Tiempo en el modelo 2D - + sec. seg. - + Increase speed Aumentar velocidad - + px px @@ -466,44 +510,36 @@ twoDModel::model::SizeUnit - cm - cm + cm - mm - mm + mm - m - m + m - px - px + px - Pixels - Píxeles + Píxeles - Centimeters - Centímetros + Centímetros - Meters - Metros + Metros - Millimeters - Milímetros + Milímetros @@ -709,7 +745,7 @@ twoDModel::view::GridParameters - + Grid Cuadrícula @@ -837,75 +873,74 @@ twoDModel::view::TwoDModelWidget - cm - cm + cm - + kg kg - + Warning Advertencia - + Do you really want to clear scene? ¿Realmente desea limpiar la escena? - + Training mode: solution will not be checked Modo entrenamiento: la solución no será verificada - + Checking mode: solution will be checked, errors will be reported Modo verificación: la solución será comprobada, se informará de errores - + Saving world and robot model Guardando modelo del mundo y del robot - - - + + + 2D model saves (*.xml) Guardados del modelo 2D (*.xml) - + Loading world and robot model Cargando modelo del mundo y del robot - + Loading world without robot model Cargando modelo del mundo sin modelo de robot - + Hide details Ocultar detalles - + Show details Mostrar detalles - - + + No wheel Ausente - + %1 (port %2) %1 (puerto %2) diff --git a/qrtranslations/es/qrutils_es.ts b/qrtranslations/es/qrutils_es.ts index 98ceaa23f5..9f9f1a8c37 100644 --- a/qrtranslations/es/qrutils_es.ts +++ b/qrtranslations/es/qrutils_es.ts @@ -69,7 +69,7 @@ División entera por cero - + Remove Eliminar diff --git a/qrtranslations/fr/plugins/robots/common/twoDModel_fr.ts b/qrtranslations/fr/plugins/robots/common/twoDModel_fr.ts index e9826b3085..4b48f3f441 100644 --- a/qrtranslations/fr/plugins/robots/common/twoDModel_fr.ts +++ b/qrtranslations/fr/plugins/robots/common/twoDModel_fr.ts @@ -209,6 +209,46 @@ Cancel Annuler + + + cm + cm + + + + mm + mm + + + + m + m + + + + px + px + + + + Pixels + Pixels + + + + Centimeters + Centimètres + + + + Meters + Mètres + + + + Millimeters + Millimètres + TwoDModelWidget @@ -236,7 +276,12 @@ Arrêter le programme - + + Grid size: + Taille de la grille: + + + @@ -274,7 +319,7 @@ px - + Left wheel: Roue gauche : @@ -289,12 +334,11 @@ Unités du système métrique : - Pixels in cm: - Nombre de pixels par cm : + Nombre de pixels par cm : - + Realistic physics Physique réaliste @@ -474,44 +518,36 @@ twoDModel::model::SizeUnit - cm - cm + cm - mm - mm + mm - m - m + m - px - px + px - Pixels - Pixels + Pixels - Centimeters - Centimètres + Centimètres - Meters - Mètres + Mètres - Millimeters - Millimètres + Millimètres @@ -717,7 +753,7 @@ twoDModel::view::GridParameters - + Grid Grille @@ -845,7 +881,7 @@ twoDModel::view::TwoDModelWidget - + Warning Attention @@ -863,17 +899,16 @@ Annuler - cm - cm + cm - + kg kg - + Training mode: solution will not be checked Mode entraînement : la solution ne sera pas vérifiée @@ -905,7 +940,7 @@ Chargement du monde sans modèle de robot - + Hide details Masquer les détails @@ -915,7 +950,7 @@ Afficher les détails - + No wheel Pas de roue diff --git a/qrtranslations/fr/qrutils_fr.ts b/qrtranslations/fr/qrutils_fr.ts index d0a7f0677d..0693d7e9f8 100644 --- a/qrtranslations/fr/qrutils_fr.ts +++ b/qrtranslations/fr/qrutils_fr.ts @@ -88,7 +88,7 @@ Division entière par zéro - + Remove Supprimer diff --git a/qrtranslations/ru/plugins/robots/common/twoDModel_ru.ts b/qrtranslations/ru/plugins/robots/common/twoDModel_ru.ts index 536ca535fe..178b2763a0 100644 --- a/qrtranslations/ru/plugins/robots/common/twoDModel_ru.ts +++ b/qrtranslations/ru/plugins/robots/common/twoDModel_ru.ts @@ -415,6 +415,46 @@ Cancel Отмена + + + cm + см + + + + mm + мм + + + + m + м + + + + px + пикс + + + + Pixels + Пиксели + + + + Centimeters + Сантиметры + + + + Meters + Метры + + + + Millimeters + Миллиметры + TwoDModelWidget @@ -446,7 +486,12 @@ Остановить программу - + + Grid size: + Шаг сетки: + + + @@ -484,7 +529,7 @@ пикс - + Left wheel: Левое колесо: @@ -499,12 +544,11 @@ Единицы измерения - Pixels in cm: - Кол-во пикселей в см + Кол-во пикселей в см - + Realistic physics Реалистичная физика @@ -750,44 +794,36 @@ twoDModel::model::SizeUnit - cm - см + см - mm - мм + мм - m - м + м - px - пикс + пикс - Pixels - Пиксели + Пиксели - Centimeters - Сантиметры + Сантиметры - Meters - Метры + Метры - Millimeters - Миллиметры + Миллиметры @@ -1056,7 +1092,7 @@ twoDModel::view::GridParameters - + Grid Сетка @@ -1188,7 +1224,7 @@ twoDModel::view::TwoDModelWidget - + Warning Предупреждение @@ -1206,17 +1242,16 @@ Отмена - cm - см + см - + kg кг - + Training mode: solution will not be checked Режим тренировки: решение не будет проверяться @@ -1260,7 +1295,7 @@ Попытка загрузить слишком большое изображение может заморозить выполнение на некоторое время. Продолжить? - + Hide details Скрыть детали @@ -1270,7 +1305,7 @@ Показать детали - + No wheel Отсутствует diff --git a/qrtranslations/ru/qrutils_ru.ts b/qrtranslations/ru/qrutils_ru.ts index 1fc89472de..4b1b1bfc16 100644 --- a/qrtranslations/ru/qrutils_ru.ts +++ b/qrtranslations/ru/qrutils_ru.ts @@ -92,7 +92,7 @@ Целичисленное деление на ноль - + Remove Удалить diff --git a/qrtranslations/vi/plugins/robots/common/twoDModel_vi.ts b/qrtranslations/vi/plugins/robots/common/twoDModel_vi.ts index f43a690b07..f70d8f2792 100644 --- a/qrtranslations/vi/plugins/robots/common/twoDModel_vi.ts +++ b/qrtranslations/vi/plugins/robots/common/twoDModel_vi.ts @@ -209,6 +209,46 @@ Object "%1" has no property "%2" Đối tượng "%1" không có thuộc tính "%2" + + + cm + cm + + + + mm + mm + + + + m + m + + + + px + px + + + + Pixels + Điểm ảnh + + + + Centimeters + Xentimét + + + + Meters + Mét + + + + Millimeters + Milimét + TwoDModelWidget @@ -243,85 +283,89 @@ Đơn vị hệ mét: - Pixels in cm: - Số pixel trên 1 cm: + Số pixel trên 1 cm: + + + + Grid size: + Kích thước lưới: - + Realistic physics Vật lý thực tế - + Realistic sensors Cảm biến thực tế - + Realistic engines Động cơ thực tế - + Robot height: Chiều cao robot: - + Robot mass: Khối lượng robot: - + Wheel diameter: Đường kính bánh xe: - + Robot track: Chiều rộng cơ sở robot: - + Robot width: Chiều rộng robot: - - - - + + + + cm cm - + kg kg - + Decrease speed Giảm tốc độ - + Time in 2D model Thời gian trong mô hình 2D - + sec. giây. - + Increase speed Tăng tốc độ - + px px @@ -466,44 +510,36 @@ twoDModel::model::SizeUnit - cm - cm + cm - mm - mm + mm - m - m + m - px - px + px - Pixels - Điểm ảnh + Điểm ảnh - Centimeters - Xentimét + Xentimét - Meters - Mét + Mét - Millimeters - Milimét + Milimét @@ -709,7 +745,7 @@ twoDModel::view::GridParameters - + Grid Lưới @@ -837,75 +873,74 @@ twoDModel::view::TwoDModelWidget - cm - cm + cm - + kg kg - + Warning Cảnh báo - + Do you really want to clear scene? Bạn có thực sự muốn xóa toàn bộ cảnh? - + Training mode: solution will not be checked Chế độ luyện tập: lời giải sẽ không được kiểm tra - + Checking mode: solution will be checked, errors will be reported Chế độ kiểm tra: lời giải sẽ được kiểm tra, các lỗi sẽ được báo cáo - + Saving world and robot model Đang lưu mô hình thế giới và robot - - - + + + 2D model saves (*.xml) Tệp lưu mô hình 2D (*.xml) - + Loading world and robot model Đang tải mô hình thế giới và robot - + Loading world without robot model Đang tải mô hình thế giới mà không có mô hình robot - + Hide details Ẩn chi tiết - + Show details Hiển thị chi tiết - - + + No wheel Không có bánh xe - + %1 (port %2) %1 (cổng %2) diff --git a/qrtranslations/vi/qrutils_vi.ts b/qrtranslations/vi/qrutils_vi.ts index efd34b7a88..ea31c950ed 100644 --- a/qrtranslations/vi/qrutils_vi.ts +++ b/qrtranslations/vi/qrutils_vi.ts @@ -69,7 +69,7 @@ Chia số nguyên cho 0 - + Remove Xóa diff --git a/qrutils/graphicsUtils/abstractItem.cpp b/qrutils/graphicsUtils/abstractItem.cpp index e627e83efb..a101a0f53f 100644 --- a/qrutils/graphicsUtils/abstractItem.cpp +++ b/qrutils/graphicsUtils/abstractItem.cpp @@ -14,6 +14,7 @@ #include "abstractItem.h" +#include #include #include #include @@ -686,16 +687,7 @@ void AbstractItem::copyTo(AbstractItem * const other) const , QOverload::of(&AbstractItem::setBrush)); } -qreal AbstractItem::alignedCoordinate(qreal coord, const int indexGrid) const +qreal AbstractItem::alignedCoordinate(qreal coord, const qreal gridSize) const { - const int coef = static_cast(coord) / indexGrid; - const int coefSign = coef ? coef / qAbs(coef) : 0; - - if (qAbs(qAbs(coord) - qAbs(coef) * indexGrid) <= indexGrid / 2.0) { - return coef * indexGrid; - } else if (qAbs(qAbs(coord) - (qAbs(coef) + 1) * indexGrid) <= indexGrid / 2.0) { - return (coef + coefSign) * indexGrid; - } - - return coord; + return std::round(coord / gridSize) * gridSize; } diff --git a/qrutils/graphicsUtils/abstractItem.h b/qrutils/graphicsUtils/abstractItem.h index 78bcad5af7..1a991df017 100644 --- a/qrutils/graphicsUtils/abstractItem.h +++ b/qrutils/graphicsUtils/abstractItem.h @@ -192,7 +192,7 @@ class QRUTILS_EXPORT AbstractItem : public QGraphicsObject virtual void updateCursor(QGraphicsSceneHoverEvent *event); void copyTo(AbstractItem * const other) const; - qreal alignedCoordinate(qreal coord, const int indexGrid) const; + qreal alignedCoordinate(qreal coord, const qreal gridSize) const; void setXYWithDragState(const QPointF pos); private: diff --git a/qrutils/graphicsUtils/gridDrawer.cpp b/qrutils/graphicsUtils/gridDrawer.cpp index 2c86fab201..d6e0d64ed5 100644 --- a/qrutils/graphicsUtils/gridDrawer.cpp +++ b/qrutils/graphicsUtils/gridDrawer.cpp @@ -13,30 +13,30 @@ * limitations under the License. */ #include - +#include #include "gridDrawer.h" using namespace graphicsUtils; -GridDrawer::GridDrawer() -{ -} +GridDrawer::GridDrawer() = default; -void GridDrawer::drawGrid(QPainter *painter, const QRectF &rect, const int indexGrid) +void GridDrawer::drawGrid(QPainter *painter, const QRectF &rect, const qreal gridSize) { - const int left = static_cast(rect.left()); - const int right = static_cast(rect.right()); - const int top = static_cast(rect.top()); - const int bottom = static_cast(rect.bottom()); + const auto firstVerticalLineIndex = static_cast(std::floor(rect.left() / gridSize)); + const auto lastVerticalLineIndex = static_cast(std::ceil(rect.right() / gridSize)); - const int startX = left / indexGrid * indexGrid; - const int startY = top / indexGrid * indexGrid; - - for (int i = startX; i <= right; i += indexGrid) { - painter->drawLine(i, top, i, bottom); + for (auto i = firstVerticalLineIndex; i <= lastVerticalLineIndex; ++i) { + const auto currentVerticalLineX = i * gridSize; + painter->drawLine(QPointF(currentVerticalLineX, rect.top()), + QPointF(currentVerticalLineX, rect.bottom())); } - for (int i = startY; i <= bottom; i += indexGrid) { - painter->drawLine(left, i, right, i); + const auto firstHorizontalLineIndex = static_cast(std::floor(rect.top() / gridSize)); + const auto lastHorizontalLineIndex = static_cast(std::floor(rect.bottom() / gridSize)); + + for (auto i = firstHorizontalLineIndex; i <= lastHorizontalLineIndex; ++i) { + const auto currentHorizontalLineY = i * gridSize; + painter->drawLine(QPointF(rect.left(), currentHorizontalLineY), + QPointF(rect.right(), currentHorizontalLineY)); } } diff --git a/qrutils/graphicsUtils/gridDrawer.h b/qrutils/graphicsUtils/gridDrawer.h index 543102636e..63b1d641c4 100644 --- a/qrutils/graphicsUtils/gridDrawer.h +++ b/qrutils/graphicsUtils/gridDrawer.h @@ -24,7 +24,7 @@ class QRUTILS_EXPORT GridDrawer { public: GridDrawer(); - void drawGrid(QPainter *painter, const QRectF &rect, const int indexGrid); + void drawGrid(QPainter *painter, const QRectF &rect, const qreal indexGrid); }; } From af305bf07c7d843ccf96d97433a5fc0ce6f31eea Mon Sep 17 00:00:00 2001 From: MinyazevR Date: Sun, 18 Jan 2026 09:51:47 +0300 Subject: [PATCH 2/6] Fix Vera++ warnings --- .../common/twoDModel/src/engine/view/parts/gridSizeWidget.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/robots/common/twoDModel/src/engine/view/parts/gridSizeWidget.h b/plugins/robots/common/twoDModel/src/engine/view/parts/gridSizeWidget.h index 6bd0debab6..cbdaf16c1e 100644 --- a/plugins/robots/common/twoDModel/src/engine/view/parts/gridSizeWidget.h +++ b/plugins/robots/common/twoDModel/src/engine/view/parts/gridSizeWidget.h @@ -12,6 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#pragma once #include #include #include "twoDModel/engine/model/metricSystem.h" @@ -24,7 +25,8 @@ namespace view { /// A class that represents a set of QDoubleSpinBox's for different units of measurement, /// as they may require different sinlgeSterp, suffix, and other parameters. -class GridSizeWidget : public QWidget { +class GridSizeWidget : public QWidget +{ Q_OBJECT public: explicit GridSizeWidget(QWidget *parent = nullptr); From d56fd10290d3c3d38a529339f32877a2e6710594 Mon Sep 17 00:00:00 2001 From: MinyazevR Date: Mon, 19 Jan 2026 07:45:53 +0300 Subject: [PATCH 3/6] Fix Clang-Tidy warnings --- .../robots/common/twoDModel/src/engine/items/wallItem.cpp | 8 ++++---- .../robots/common/twoDModel/src/engine/items/wallItem.h | 2 +- .../twoDModel/src/engine/view/parts/gridSizeWidget.cpp | 1 - 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/plugins/robots/common/twoDModel/src/engine/items/wallItem.cpp b/plugins/robots/common/twoDModel/src/engine/items/wallItem.cpp index 970e462aec..ab24afeefb 100644 --- a/plugins/robots/common/twoDModel/src/engine/items/wallItem.cpp +++ b/plugins/robots/common/twoDModel/src/engine/items/wallItem.cpp @@ -51,7 +51,7 @@ WallItem::WallItem(graphicsUtils::AbstractCoordinateSystem *metricSystem, WallItem *WallItem::clone() const { - WallItem * const cloned = new WallItem(coordinateSystem(), {x1(), y1()}, {x2(), y2()}); + auto * const cloned = new WallItem(coordinateSystem(), {x1(), y1()}, {x2(), y2()}); AbstractItem::copyTo(cloned); connect(this, &AbstractItem::positionChanged, cloned, &WallItem::recalculateBorders); connect(this, &AbstractItem::x1Changed, cloned, &WallItem::recalculateBorders); @@ -65,7 +65,7 @@ WallItem *WallItem::clone() const QAction *WallItem::wallTool() { - QAction * const result = new QAction(QIcon(":/icons/2d_wall.png"), tr("Wall (W)"), nullptr); + auto * const result = new QAction(QIcon(":/icons/2d_wall.png"), tr("Wall (W)"), nullptr); result->setShortcuts({QKeySequence(Qt::Key_W), QKeySequence(Qt::Key_2)}); result->setCheckable(true); return result; @@ -175,8 +175,8 @@ void WallItem::deserialize(const QDomElement &element) setY2(end.y()); readPenBrush(element); - if (pen().widthF()) { - mWallWidth = pen().widthF(); + if (pen().width()) { + mWallWidth = pen().width(); } SolidItem::deserialize(element); diff --git a/plugins/robots/common/twoDModel/src/engine/items/wallItem.h b/plugins/robots/common/twoDModel/src/engine/items/wallItem.h index 37c0c9a145..6775d4ae51 100644 --- a/plugins/robots/common/twoDModel/src/engine/items/wallItem.h +++ b/plugins/robots/common/twoDModel/src/engine/items/wallItem.h @@ -79,7 +79,7 @@ class WallItem : public graphicsUtils::AbstractItem, public SolidItem const QImage mImage; QPainterPath mPath; - qreal mWallWidth {10}; + int mWallWidth {10}; QPointF mEstimatedPos; }; diff --git a/plugins/robots/common/twoDModel/src/engine/view/parts/gridSizeWidget.cpp b/plugins/robots/common/twoDModel/src/engine/view/parts/gridSizeWidget.cpp index bc1612dfda..31cb606a3a 100644 --- a/plugins/robots/common/twoDModel/src/engine/view/parts/gridSizeWidget.cpp +++ b/plugins/robots/common/twoDModel/src/engine/view/parts/gridSizeWidget.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include "gridSizeWidget.h" #include From 9d29495c9adddc935c8f8c3394c80a67488a356a Mon Sep 17 00:00:00 2001 From: MinyazevR Date: Mon, 19 Jan 2026 13:08:05 +0300 Subject: [PATCH 4/6] Fix CLang-Tidy warnings --- .../robots/common/twoDModel/src/engine/view/parts/ruler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/robots/common/twoDModel/src/engine/view/parts/ruler.cpp b/plugins/robots/common/twoDModel/src/engine/view/parts/ruler.cpp index 29b876e6df..a8b0fd4787 100644 --- a/plugins/robots/common/twoDModel/src/engine/view/parts/ruler.cpp +++ b/plugins/robots/common/twoDModel/src/engine/view/parts/ruler.cpp @@ -52,9 +52,9 @@ void Ruler::setOrientation(Qt::Orientation orientation) const QString theLongestText = "-123.45"; // The longest text that ruler must place into itself. const QSizeF theLargestSize = textBoundingRect(theLongestText).size(); if (orientation == Qt::Horizontal) { - setFixedHeight(theLargestSize.height() + 2 * gap); + setFixedHeight(static_cast(theLargestSize.height() + 2 * gap)); } else { - setFixedWidth(theLargestSize.width() + 2 * gap); + setFixedWidth(static_cast(theLargestSize.width() + 2 * gap)); } } From 528b31bf3504fb55830a818c199e1bc76cf99987 Mon Sep 17 00:00:00 2001 From: MinyazevR Date: Mon, 19 Jan 2026 16:32:27 +0300 Subject: [PATCH 5/6] Lupdate --- .../es/plugins/robots/common/twoDModel_es.ts | 141 ++++++++++++++++-- .../fr/plugins/robots/common/twoDModel_fr.ts | 119 ++++++++++++++- .../ru/plugins/robots/common/twoDModel_ru.ts | 119 ++++++++++++++- .../vi/plugins/robots/common/twoDModel_vi.ts | 141 ++++++++++++++++-- 4 files changed, 482 insertions(+), 38 deletions(-) diff --git a/qrtranslations/es/plugins/robots/common/twoDModel_es.ts b/qrtranslations/es/plugins/robots/common/twoDModel_es.ts index a4f75bcdf4..4ea4f572db 100644 --- a/qrtranslations/es/plugins/robots/common/twoDModel_es.ts +++ b/qrtranslations/es/plugins/robots/common/twoDModel_es.ts @@ -249,6 +249,117 @@ Millimeters Milímetros + + + The &lt;template&gt; tag was provided, but the required "name" attribute was missing. + + + + + Redefinition a template %1 that already exists + + + + + the &lt;templates&gt; tag can only contain the &lt;template&gt; tag as a child tag, actual %1 + + + + + The &lt;use&gt; tag must contain a "template" attribute + + + + + Recursive template expansion detected: %1 -> %2 + + + + + The &lt;use&gt; tag contains a template=%1 attribute that is not the name of a declared template + + + + + After substituting the parameters for the template %1, it did not become a valid xml node + + + + + + line %1 + + + + + template %1 + + + + + relative the beginning of the &lt;constraints&gt; tag + + + + + relative to the beginning of the %1 template body + + + + + Substitution chain: %1. + + + + + Currently, this method of setting &lt;content&gt; tag for the template %1 is not supported. + + + + + When defining the template %1, the syntax %2 was used to substitute an offset %3 for an undeclared parameter %4. + + + + + the &lt;params&gt; tag can only contain the &lt;param&gt; tag as a child tag for template %1, actual tag is &lt;%2&gt; + + + + + The &lt;param&gt; tag of template %1 was provided, but the required "name" attribute was missing. + + + + + The &lt;template&gt; of template %1 tag was provided, but the required child tag &lt;content&gt; was missing + + + + + The using an undeclared parameter %1 for template %2 + + + + + The &lt;use&gt; tag can only contain a child tag &lt;with&gt; + + + + + The parameter %1 of template %2 has no default value and was not explicitly specified by the user + + + + + Error while template substitution: %1 + + + + + Error while parsing template: %1 + + TwoDModelWidget @@ -887,65 +998,65 @@ kg - + Warning Advertencia - + Do you really want to clear scene? ¿Realmente desea limpiar la escena? - + Training mode: solution will not be checked Modo entrenamiento: la solución no será verificada - + Checking mode: solution will be checked, errors will be reported Modo verificación: la solución será comprobada, se informará de errores - + Saving world and robot model Guardando modelo del mundo y del robot - - - + + + 2D model saves (*.xml) Guardados del modelo 2D (*.xml) - + Loading world and robot model Cargando modelo del mundo y del robot - + Loading world without robot model Cargando modelo del mundo sin modelo de robot - + Hide details Ocultar detalles - + Show details Mostrar detalles - - + + No wheel Ausente - + %1 (port %2) %1 (puerto %2) diff --git a/qrtranslations/fr/plugins/robots/common/twoDModel_fr.ts b/qrtranslations/fr/plugins/robots/common/twoDModel_fr.ts index 894e2f4540..2918ca8020 100644 --- a/qrtranslations/fr/plugins/robots/common/twoDModel_fr.ts +++ b/qrtranslations/fr/plugins/robots/common/twoDModel_fr.ts @@ -249,6 +249,117 @@ Millimeters Millimètres + + + The &lt;template&gt; tag was provided, but the required "name" attribute was missing. + + + + + Redefinition a template %1 that already exists + + + + + the &lt;templates&gt; tag can only contain the &lt;template&gt; tag as a child tag, actual %1 + + + + + The &lt;use&gt; tag must contain a "template" attribute + + + + + Recursive template expansion detected: %1 -> %2 + + + + + The &lt;use&gt; tag contains a template=%1 attribute that is not the name of a declared template + + + + + After substituting the parameters for the template %1, it did not become a valid xml node + + + + + + line %1 + + + + + template %1 + + + + + relative the beginning of the &lt;constraints&gt; tag + + + + + relative to the beginning of the %1 template body + + + + + Substitution chain: %1. + + + + + Currently, this method of setting &lt;content&gt; tag for the template %1 is not supported. + + + + + When defining the template %1, the syntax %2 was used to substitute an offset %3 for an undeclared parameter %4. + + + + + the &lt;params&gt; tag can only contain the &lt;param&gt; tag as a child tag for template %1, actual tag is &lt;%2&gt; + + + + + The &lt;param&gt; tag of template %1 was provided, but the required "name" attribute was missing. + + + + + The &lt;template&gt; of template %1 tag was provided, but the required child tag &lt;content&gt; was missing + + + + + The using an undeclared parameter %1 for template %2 + + + + + The &lt;use&gt; tag can only contain a child tag &lt;with&gt; + + + + + The parameter %1 of template %2 has no default value and was not explicitly specified by the user + + + + + Error while template substitution: %1 + + + + + Error while parsing template: %1 + + TwoDModelWidget @@ -886,7 +997,7 @@ twoDModel::view::TwoDModelWidget - + Warning Attention @@ -908,12 +1019,12 @@ cm - + kg kg - + Training mode: solution will not be checked Mode entraînement : la solution ne sera pas vérifiée @@ -945,7 +1056,7 @@ Chargement du monde sans modèle de robot - + Hide details Masquer les détails diff --git a/qrtranslations/ru/plugins/robots/common/twoDModel_ru.ts b/qrtranslations/ru/plugins/robots/common/twoDModel_ru.ts index 2a80a8dd34..c1bee26909 100644 --- a/qrtranslations/ru/plugins/robots/common/twoDModel_ru.ts +++ b/qrtranslations/ru/plugins/robots/common/twoDModel_ru.ts @@ -455,6 +455,117 @@ Millimeters Миллиметры + + + The &lt;template&gt; tag was provided, but the required "name" attribute was missing. + + + + + Redefinition a template %1 that already exists + + + + + the &lt;templates&gt; tag can only contain the &lt;template&gt; tag as a child tag, actual %1 + + + + + The &lt;use&gt; tag must contain a "template" attribute + + + + + Recursive template expansion detected: %1 -> %2 + + + + + The &lt;use&gt; tag contains a template=%1 attribute that is not the name of a declared template + + + + + After substituting the parameters for the template %1, it did not become a valid xml node + + + + + + line %1 + + + + + template %1 + + + + + relative the beginning of the &lt;constraints&gt; tag + + + + + relative to the beginning of the %1 template body + + + + + Substitution chain: %1. + + + + + Currently, this method of setting &lt;content&gt; tag for the template %1 is not supported. + + + + + When defining the template %1, the syntax %2 was used to substitute an offset %3 for an undeclared parameter %4. + + + + + the &lt;params&gt; tag can only contain the &lt;param&gt; tag as a child tag for template %1, actual tag is &lt;%2&gt; + + + + + The &lt;param&gt; tag of template %1 was provided, but the required "name" attribute was missing. + + + + + The &lt;template&gt; of template %1 tag was provided, but the required child tag &lt;content&gt; was missing + + + + + The using an undeclared parameter %1 for template %2 + + + + + The &lt;use&gt; tag can only contain a child tag &lt;with&gt; + + + + + The parameter %1 of template %2 has no default value and was not explicitly specified by the user + + + + + Error while template substitution: %1 + Ошибка при раскрытии шаблона: %1 + + + + Error while parsing template: %1 + Ошибка при разборе шаблона: %1 + TwoDModelWidget @@ -1237,7 +1348,7 @@ twoDModel::view::TwoDModelWidget - + Warning Предупреждение @@ -1259,12 +1370,12 @@ см - + kg кг - + Training mode: solution will not be checked Режим тренировки: решение не будет проверяться @@ -1312,7 +1423,7 @@ Попытка загрузить слишком большое изображение может заморозить выполнение на некоторое время. Продолжить? - + Hide details Скрыть детали diff --git a/qrtranslations/vi/plugins/robots/common/twoDModel_vi.ts b/qrtranslations/vi/plugins/robots/common/twoDModel_vi.ts index 8a7ac55925..c3adc7c9ff 100644 --- a/qrtranslations/vi/plugins/robots/common/twoDModel_vi.ts +++ b/qrtranslations/vi/plugins/robots/common/twoDModel_vi.ts @@ -249,6 +249,117 @@ Millimeters Milimét + + + The &lt;template&gt; tag was provided, but the required "name" attribute was missing. + + + + + Redefinition a template %1 that already exists + + + + + the &lt;templates&gt; tag can only contain the &lt;template&gt; tag as a child tag, actual %1 + + + + + The &lt;use&gt; tag must contain a "template" attribute + + + + + Recursive template expansion detected: %1 -> %2 + + + + + The &lt;use&gt; tag contains a template=%1 attribute that is not the name of a declared template + + + + + After substituting the parameters for the template %1, it did not become a valid xml node + + + + + + line %1 + + + + + template %1 + + + + + relative the beginning of the &lt;constraints&gt; tag + + + + + relative to the beginning of the %1 template body + + + + + Substitution chain: %1. + + + + + Currently, this method of setting &lt;content&gt; tag for the template %1 is not supported. + + + + + When defining the template %1, the syntax %2 was used to substitute an offset %3 for an undeclared parameter %4. + + + + + the &lt;params&gt; tag can only contain the &lt;param&gt; tag as a child tag for template %1, actual tag is &lt;%2&gt; + + + + + The &lt;param&gt; tag of template %1 was provided, but the required "name" attribute was missing. + + + + + The &lt;template&gt; of template %1 tag was provided, but the required child tag &lt;content&gt; was missing + + + + + The using an undeclared parameter %1 for template %2 + + + + + The &lt;use&gt; tag can only contain a child tag &lt;with&gt; + + + + + The parameter %1 of template %2 has no default value and was not explicitly specified by the user + + + + + Error while template substitution: %1 + + + + + Error while parsing template: %1 + + TwoDModelWidget @@ -887,65 +998,65 @@ kg - + Warning Cảnh báo - + Do you really want to clear scene? Bạn có thực sự muốn xóa toàn bộ cảnh? - + Training mode: solution will not be checked Chế độ luyện tập: lời giải sẽ không được kiểm tra - + Checking mode: solution will be checked, errors will be reported Chế độ kiểm tra: lời giải sẽ được kiểm tra, các lỗi sẽ được báo cáo - + Saving world and robot model Đang lưu mô hình thế giới và robot - - - + + + 2D model saves (*.xml) Tệp lưu mô hình 2D (*.xml) - + Loading world and robot model Đang tải mô hình thế giới và robot - + Loading world without robot model Đang tải mô hình thế giới mà không có mô hình robot - + Hide details Ẩn chi tiết - + Show details Hiển thị chi tiết - - + + No wheel Không có bánh xe - + %1 (port %2) %1 (cổng %2) From 8e844f5d1e0307173a8dd1611c3d3a96598018ed Mon Sep 17 00:00:00 2001 From: MinyazevR Date: Mon, 19 Jan 2026 17:01:00 +0300 Subject: [PATCH 6/6] Improve code --- .../src/engine/view/parts/gridSizeWidget.cpp | 16 ++++------------ plugins/robots/common/twoDModel/twoDModel.pri | 3 +++ 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/plugins/robots/common/twoDModel/src/engine/view/parts/gridSizeWidget.cpp b/plugins/robots/common/twoDModel/src/engine/view/parts/gridSizeWidget.cpp index 31cb606a3a..4a3c021337 100644 --- a/plugins/robots/common/twoDModel/src/engine/view/parts/gridSizeWidget.cpp +++ b/plugins/robots/common/twoDModel/src/engine/view/parts/gridSizeWidget.cpp @@ -40,17 +40,8 @@ GridSizeWidget::GridSizeWidget(QWidget *parent) void GridSizeWidget::createSpinBoxes() { - auto onValueChangedLambda = [this](QObject *abstractSpinBox) { - if (auto * spinBox = qobject_cast(abstractSpinBox)) { - connect(spinBox, QOverload::of(&QDoubleSpinBox::valueChanged), - this, [this](qreal value) { - Q_EMIT gridSizeChanged(value); - }); - } - }; - - auto createSpinBoxLambda = [this, onValueChangedLambda](qreal step, int decimals, - twoDModel::model::SizeUnit::Unit unit) { + auto createSpinBoxLambda = [this](qreal step, int decimals, + twoDModel::model::SizeUnit::Unit unit) { twoDModel::model::SizeUnit sizeUnit {}; sizeUnit.setSizeUnit(unit); auto *spinBox = new QDoubleSpinBox(this); @@ -58,7 +49,8 @@ void GridSizeWidget::createSpinBoxes() spinBox->setDecimals(decimals); mSlubSpinBoxes.emplace(unit, spinBox); mStackedWidget->addWidget(spinBox); - onValueChangedLambda(spinBox); + connect(spinBox, QOverload::of(&QDoubleSpinBox::valueChanged), + this, &GridSizeWidget::gridSizeChanged); }; // Create custom Pixels SpinBox diff --git a/plugins/robots/common/twoDModel/twoDModel.pri b/plugins/robots/common/twoDModel/twoDModel.pri index b322f7a749..2b578bbf1e 100644 --- a/plugins/robots/common/twoDModel/twoDModel.pri +++ b/plugins/robots/common/twoDModel/twoDModel.pri @@ -87,6 +87,9 @@ HEADERS += \ $$PWD/src/engine/view/parts/robotItemPopup.h \ $$PWD/src/engine/view/parts/speedPopup.h \ $$PWD/src/engine/view/parts/ruler.h \ + $$PWD/src/engine/templates/details/templatesParser.h \ + $$PWD/src/engine/templates/details/template.h \ + $$PWD/src/engine/templates/templateParserApi.h \ $$PWD/src/engine/view/parts/gridSizeWidget.h \ $$PWD/src/engine/constraints/constraintsChecker.h \ $$PWD/src/engine/constraints/details/defines.h \