Hello.
I took the code from the one other forum. This code makes resizeble rectangles. I corrected a little for displaying pictures.
if anyone knows, tell me how to calculate the position of the MovableCircle so that the initial aspect ratio is preserved.

I've implemented part of the algorithm for eBottomRight and eTopLeft, but it still works very bad and doesn't work for BottomLeft and TopRight points. I want that it will be look like Krita or PureRef resize behaviour.

Thanks for any help, regards max

calc part:
Qt Code:
  1. void MovableCircle::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
  2. {
  3. auto pos = mapToScene(event->pos() + _shiftMouseCoords);
  4.  
  5. qreal xl = (pos.x() == 0) ? .1 : pos.x();
  6. qreal yl = (pos.y() == 0) ? .1 : pos.y();
  7.  
  8. qreal arl = qAbs(xl / yl);
  9.  
  10. if (circlePos_ == eBottomRight) {
  11. if (arl > aspectRatio_) {
  12. pos.setX(yl * aspectRatio_);
  13. } else {
  14. pos.setY(xl / aspectRatio_);
  15.  
  16. }
  17. }
  18.  
  19. if (circlePos_ == eTopLeft) {
  20. LOG_WARNING(logger, "Circle Pos: ", circlePos_, ", ", pos.x(), " ", pos.y());
  21. LOG_WARNING(logger, "Init Aspect Ratio: ", aspectRatio_, ", Current AspectRatio:", arl);
  22. if (arl > aspectRatio_) {
  23. LOG_DEBUG(logger, "> Before: ", pos.x(), ", ", pos.y());
  24. pos.setY(xl / aspectRatio_);
  25. LOG_DEBUG(logger, "> After: ", pos.x(), ", ", pos.y());
  26. } else {
  27. LOG_DEBUG(logger, "< Before: ", pos.x(), ", ", pos.y());
  28. pos.setX(yl * aspectRatio_);
  29. LOG_DEBUG(logger, "< After: ", pos.x(), ", ", pos.y());
  30. }
  31. }
  32.  
  33. setPos(pos);
  34. emit circleMoved();
  35. }
To copy to clipboard, switch view to plain text mode 


MovableCircle class:
Qt Code:
  1. class MovableCircle : public QGraphicsObject
  2. {
  3. Q_OBJECT
  4. public:
  5. enum ECirclePos {
  6. eTopLeft = 0,
  7. eTopRight,
  8. eBottomRight,
  9. eBottomLeft,
  10. };
  11.  
  12. explicit MovableCircle(ECirclePos cp, double ar, QGraphicsItem *parent = 0);
  13.  
  14. private:
  15. QRectF boundingRect() const;
  16. QPainterPath shape() const;
  17. void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
  18. void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
  19. void mousePressEvent(QGraphicsSceneMouseEvent *event);
  20. void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
  21. QPointF _shiftMouseCoords;
  22.  
  23. private:
  24. double aspectRatio_;
  25. ECirclePos circlePos_;
  26. signals:
  27. void circleMoved();
  28. };
  29.  
  30.  
  31. MovableCircle::MovableCircle(ECirclePos cp, double ar, QGraphicsItem *parent) :
  32. QGraphicsObject(parent), aspectRatio_(ar), circlePos_(cp)
  33. {
  34. setFlag(ItemClipsToShape, true);
  35. setCursor(QCursor(Qt::PointingHandCursor));
  36. }
  37.  
  38. QRectF MovableCircle::boundingRect() const
  39. {
  40. qreal adjust = 0.5;
  41. return QRectF(-5 - adjust, -5 - adjust,
  42. 10 + adjust, 10 + adjust);
  43. }
  44.  
  45. QPainterPath MovableCircle::shape() const
  46. {
  47. qreal adjust = 0.5;
  48. path.addEllipse(-5 - adjust, -5 - adjust,
  49. 10 + adjust, 10 + adjust);
  50. return path;
  51. }
  52.  
  53. void MovableCircle::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
  54. {
  55. Q_UNUSED(option);
  56. Q_UNUSED(widget);
  57.  
  58. painter->setBrush(QBrush(QColor(0, 160, 230)));
  59. painter->setPen(QPen(QColor(0, 160, 230)));
  60. painter->drawEllipse(-5, -5, 10, 10);
  61. }
  62.  
  63. void MovableCircle::mousePressEvent(QGraphicsSceneMouseEvent *event)
  64. {
  65. _shiftMouseCoords = this->pos() - mapToScene(event->pos());
  66. this->setCursor(QCursor(Qt::ClosedHandCursor));
  67. }
  68.  
  69. void MovableCircle::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
  70. {
  71. auto pos = mapToScene(event->pos() + _shiftMouseCoords);
  72.  
  73. qreal xl = (pos.x() == 0) ? .1 : pos.x();
  74. qreal yl = (pos.y() == 0) ? .1 : pos.y();
  75.  
  76. qreal arl = qAbs(xl / yl);
  77.  
  78. if (circlePos_ == eBottomRight) {
  79. if (arl > aspectRatio_) {
  80. pos.setX(yl * aspectRatio_);
  81. } else {
  82. pos.setY(xl / aspectRatio_);
  83.  
  84. }
  85. }
  86.  
  87. if (circlePos_ == eTopLeft) {
  88. if (arl > aspectRatio_) {
  89. pos.setY(xl / aspectRatio_);
  90. } else {
  91. pos.setX(yl * aspectRatio_);
  92. }
  93. }
  94.  
  95. setPos(pos);
  96. emit circleMoved();
  97. }
  98.  
  99. void MovableCircle::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
  100. {
  101. Q_UNUSED(event);
  102. this->setCursor(QCursor(Qt::PointingHandCursor));
  103. }
To copy to clipboard, switch view to plain text mode 


MoveItem class:
Qt Code:
  1. class MoveItem : public QObject, public QGraphicsItem//public QGraphicsObject
  2. {
  3. Q_OBJECT
  4. Q_INTERFACES(QGraphicsItem)
  5. public:
  6. explicit MoveItem(uint64_t& zc, QGraphicsItem *parent = 0);
  7. ~MoveItem();
  8.  
  9. signals:
  10. protected:
  11. QRectF boundingRect() const override;
  12. void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
  13. void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
  14. void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
  15. void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
  16. void wheelEvent(QGraphicsSceneWheelEvent *event) override;
  17. void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
  18. void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override;
  19. void hoverMoveEvent(QGraphicsSceneHoverEvent *event) override;
  20. private:
  21. QPointF shiftMouseCoords_;
  22. QImage qimage_;
  23. QPixmap pixmap_;
  24. uint64_t& zCounter_;
  25. MovableCircle *_topLeftCircle, *_topRightCircle, *_bottomLeftCircle, *_bottomRightCircle;
  26. QSizeF _size;
  27. QRectF rect_;
  28. public slots:
  29. };
  30.  
  31.  
  32. MoveItem::MoveItem(uint64_t& zc, QGraphicsItem *parent) :
  33. QGraphicsItem(parent), zCounter_(zc)
  34. {
  35. setZValue(zCounter_);
  36. qimage_ = QImage("kot.png");
  37. pixmap_ = QPixmap::fromImage(qimage_);
  38. _size = pixmap_.size();
  39. rect_ = qimage_.rect();
  40.  
  41. setAcceptHoverEvents(true);
  42. setFlag(QGraphicsItem::ItemIsMovable, true);
  43.  
  44. double ar = _size.width() / _size.height();
  45. // Top Left
  46. _topLeftCircle = new MovableCircle(MovableCircle::eTopLeft, ar, this);
  47. _topLeftCircle->setPos(0, 0);
  48. // Top Right
  49. _topRightCircle = new MovableCircle(MovableCircle::eTopRight, ar, this);
  50. _topRightCircle->setPos(_size.width(), 0);
  51. // Bottom Right
  52. _bottomRightCircle = new MovableCircle(MovableCircle::eBottomRight, ar, this);
  53. _bottomRightCircle->setPos(_size.width(), _size.height());
  54. // Bottom Left
  55. _bottomLeftCircle = new MovableCircle(MovableCircle::eBottomLeft, ar, this);
  56. _bottomLeftCircle->setPos(0, _size.height());
  57.  
  58. // Signals
  59. // If a delimiter point has been moved, so force the item to redraw
  60.  
  61. connect(_topLeftCircle, &MovableCircle::circleMoved, this, [this](){
  62. _bottomLeftCircle->setPos( _topLeftCircle->pos().x(), _bottomLeftCircle->pos().y());
  63. _topRightCircle->setPos(_topRightCircle->pos().x(), _topLeftCircle->pos().y());
  64. update(); // force to Repaint
  65. });
  66.  
  67. connect(_topRightCircle, &MovableCircle::circleMoved, this, [this](){
  68. _topLeftCircle->setPos(_topLeftCircle->pos().x(), _topRightCircle->pos().y());
  69. _bottomRightCircle->setPos(_topRightCircle->pos().x(), _bottomRightCircle->pos().y());
  70. update(); // force to Repaint
  71. });
  72.  
  73. connect(_bottomLeftCircle, &MovableCircle::circleMoved, this, [this](){
  74. _topLeftCircle->setPos(_bottomLeftCircle->pos().x(), _topLeftCircle->pos().y());
  75. _bottomRightCircle->setPos(_bottomRightCircle->pos().x(), _bottomLeftCircle->pos().y());
  76. update(); // force to Repaint
  77. });
  78.  
  79. connect(_bottomRightCircle, &MovableCircle::circleMoved, this, [this](){
  80. _bottomLeftCircle->setPos(_bottomLeftCircle->pos().x(), _bottomRightCircle->pos().y());
  81. _topRightCircle->setPos(_bottomRightCircle->pos().x(), _topRightCircle->pos().y());
  82. update(); // force to Repaint
  83. });
  84. }
  85.  
  86. MoveItem::~MoveItem()
  87. {
  88.  
  89. }
  90.  
  91.  
  92. QRectF MoveItem::boundingRect() const
  93. {
  94. qreal distX = sqrt(pow(_topLeftCircle->x() - _topRightCircle->x(),2) +
  95. pow(_topLeftCircle->y() - _topRightCircle->y(),2)); // eucledian distance
  96.  
  97. qreal distY = sqrt(pow(_topLeftCircle->x() - _bottomLeftCircle->x(),2) +
  98. pow(_topLeftCircle->y() - _bottomLeftCircle->y(),2)); // eucledian distance
  99.  
  100.  
  101. return QRectF(qMin(_topLeftCircle->pos().x(), _topRightCircle->pos().x()) ,
  102. qMin(_topLeftCircle->pos().y(), _bottomLeftCircle->pos().y()),
  103. distX, distY);
  104. }
  105.  
  106. void MoveItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
  107. {
  108. painter->drawImage(boundingRect(), qimage_);
  109. painter->setPen(QPen(QColor(0, 160, 230),2));
  110. painter->drawRect(boundingRect());
  111. Q_UNUSED(widget);
  112. }
  113.  
  114. void MoveItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
  115. {
  116. this->setPos(mapToScene(event->pos()+ shiftMouseCoords_));
  117. }
  118.  
  119. void MoveItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
  120. {
  121. setZValue(++zCounter_);
  122.  
  123. shiftMouseCoords_ = (this->pos() - mapToScene(event->pos()))/scale();
  124.  
  125. if (event->button() == Qt::LeftButton) {
  126. if (event->modifiers() == Qt::ShiftModifier) {
  127. } else {
  128. QGraphicsItem::mousePressEvent(event);
  129. }
  130. }
  131. }
  132.  
  133. void MoveItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
  134. {
  135. if (event->button() == Qt::LeftButton) {
  136. if (event->modifiers() == Qt::ShiftModifier) {
  137. } else {
  138. QGraphicsItem::mousePressEvent(event);
  139. }
  140. }
  141. }
To copy to clipboard, switch view to plain text mode