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:
{
auto pos = mapToScene(event->pos() + _shiftMouseCoords);
qreal xl = (pos.x() == 0) ? .1 : pos.x();
qreal yl = (pos.y() == 0) ? .1 : pos.y();
qreal arl = qAbs(xl / yl);
if (circlePos_ == eBottomRight) {
if (arl > aspectRatio_) {
pos.setX(yl * aspectRatio_);
} else {
pos.setY(xl / aspectRatio_);
}
}
if (circlePos_ == eTopLeft) {
LOG_WARNING(logger, "Circle Pos: ", circlePos_, ", ", pos.x(), " ", pos.y());
LOG_WARNING(logger, "Init Aspect Ratio: ", aspectRatio_, ", Current AspectRatio:", arl);
if (arl > aspectRatio_) {
LOG_DEBUG(logger, "> Before: ", pos.x(), ", ", pos.y());
pos.setY(xl / aspectRatio_);
LOG_DEBUG(logger, "> After: ", pos.x(), ", ", pos.y());
} else {
LOG_DEBUG(logger, "< Before: ", pos.x(), ", ", pos.y());
pos.setX(yl * aspectRatio_);
LOG_DEBUG(logger, "< After: ", pos.x(), ", ", pos.y());
}
}
setPos(pos);
emit circleMoved();
}
void MovableCircle::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
auto pos = mapToScene(event->pos() + _shiftMouseCoords);
qreal xl = (pos.x() == 0) ? .1 : pos.x();
qreal yl = (pos.y() == 0) ? .1 : pos.y();
qreal arl = qAbs(xl / yl);
if (circlePos_ == eBottomRight) {
if (arl > aspectRatio_) {
pos.setX(yl * aspectRatio_);
} else {
pos.setY(xl / aspectRatio_);
}
}
if (circlePos_ == eTopLeft) {
LOG_WARNING(logger, "Circle Pos: ", circlePos_, ", ", pos.x(), " ", pos.y());
LOG_WARNING(logger, "Init Aspect Ratio: ", aspectRatio_, ", Current AspectRatio:", arl);
if (arl > aspectRatio_) {
LOG_DEBUG(logger, "> Before: ", pos.x(), ", ", pos.y());
pos.setY(xl / aspectRatio_);
LOG_DEBUG(logger, "> After: ", pos.x(), ", ", pos.y());
} else {
LOG_DEBUG(logger, "< Before: ", pos.x(), ", ", pos.y());
pos.setX(yl * aspectRatio_);
LOG_DEBUG(logger, "< After: ", pos.x(), ", ", pos.y());
}
}
setPos(pos);
emit circleMoved();
}
To copy to clipboard, switch view to plain text mode
MovableCircle class:
class MovableCircle : public QGraphicsObject
{
Q_OBJECT
public:
enum ECirclePos {
eTopLeft = 0,
eTopRight,
eBottomRight,
eBottomLeft,
};
explicit MovableCircle
(ECirclePos cp,
double ar,
QGraphicsItem *parent
= 0);
private:
private:
double aspectRatio_;
ECirclePos circlePos_;
signals:
void circleMoved();
};
MovableCircle
::MovableCircle(ECirclePos cp,
double ar,
QGraphicsItem *parent
) : QGraphicsObject(parent), aspectRatio_(ar), circlePos_(cp)
{
setFlag(ItemClipsToShape, true);
setCursor
(QCursor(Qt
::PointingHandCursor));
}
QRectF MovableCircle
::boundingRect() const {
qreal adjust = 0.5;
return QRectF(-5 - adjust,
-5 - adjust,
10 + adjust, 10 + adjust);
}
{
qreal adjust = 0.5;
path.addEllipse(-5 - adjust, -5 - adjust,
10 + adjust, 10 + adjust);
return path;
}
{
Q_UNUSED(option);
Q_UNUSED(widget);
painter->drawEllipse(-5, -5, 10, 10);
}
{
_shiftMouseCoords = this->pos() - mapToScene(event->pos());
this
->setCursor
(QCursor(Qt
::ClosedHandCursor));
}
{
auto pos = mapToScene(event->pos() + _shiftMouseCoords);
qreal xl = (pos.x() == 0) ? .1 : pos.x();
qreal yl = (pos.y() == 0) ? .1 : pos.y();
qreal arl = qAbs(xl / yl);
if (circlePos_ == eBottomRight) {
if (arl > aspectRatio_) {
pos.setX(yl * aspectRatio_);
} else {
pos.setY(xl / aspectRatio_);
}
}
if (circlePos_ == eTopLeft) {
if (arl > aspectRatio_) {
pos.setY(xl / aspectRatio_);
} else {
pos.setX(yl * aspectRatio_);
}
}
setPos(pos);
emit circleMoved();
}
{
Q_UNUSED(event);
this
->setCursor
(QCursor(Qt
::PointingHandCursor));
}
class MovableCircle : public QGraphicsObject
{
Q_OBJECT
public:
enum ECirclePos {
eTopLeft = 0,
eTopRight,
eBottomRight,
eBottomLeft,
};
explicit MovableCircle(ECirclePos cp, double ar, QGraphicsItem *parent = 0);
private:
QRectF boundingRect() const;
QPainterPath shape() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
QPointF _shiftMouseCoords;
private:
double aspectRatio_;
ECirclePos circlePos_;
signals:
void circleMoved();
};
MovableCircle::MovableCircle(ECirclePos cp, double ar, QGraphicsItem *parent) :
QGraphicsObject(parent), aspectRatio_(ar), circlePos_(cp)
{
setFlag(ItemClipsToShape, true);
setCursor(QCursor(Qt::PointingHandCursor));
}
QRectF MovableCircle::boundingRect() const
{
qreal adjust = 0.5;
return QRectF(-5 - adjust, -5 - adjust,
10 + adjust, 10 + adjust);
}
QPainterPath MovableCircle::shape() const
{
QPainterPath path;
qreal adjust = 0.5;
path.addEllipse(-5 - adjust, -5 - adjust,
10 + adjust, 10 + adjust);
return path;
}
void MovableCircle::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
painter->setBrush(QBrush(QColor(0, 160, 230)));
painter->setPen(QPen(QColor(0, 160, 230)));
painter->drawEllipse(-5, -5, 10, 10);
}
void MovableCircle::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
_shiftMouseCoords = this->pos() - mapToScene(event->pos());
this->setCursor(QCursor(Qt::ClosedHandCursor));
}
void MovableCircle::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
auto pos = mapToScene(event->pos() + _shiftMouseCoords);
qreal xl = (pos.x() == 0) ? .1 : pos.x();
qreal yl = (pos.y() == 0) ? .1 : pos.y();
qreal arl = qAbs(xl / yl);
if (circlePos_ == eBottomRight) {
if (arl > aspectRatio_) {
pos.setX(yl * aspectRatio_);
} else {
pos.setY(xl / aspectRatio_);
}
}
if (circlePos_ == eTopLeft) {
if (arl > aspectRatio_) {
pos.setY(xl / aspectRatio_);
} else {
pos.setX(yl * aspectRatio_);
}
}
setPos(pos);
emit circleMoved();
}
void MovableCircle::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(event);
this->setCursor(QCursor(Qt::PointingHandCursor));
}
To copy to clipboard, switch view to plain text mode
MoveItem class:
{
Q_OBJECT
public:
~MoveItem();
signals:
protected:
QRectF boundingRect
() const override;
private:
uint64_t& zCounter_;
MovableCircle *_topLeftCircle, *_topRightCircle, *_bottomLeftCircle, *_bottomRightCircle;
public slots:
};
{
setZValue(zCounter_);
pixmap_
= QPixmap::fromImage(qimage_
);
_size = pixmap_.size();
rect_ = qimage_.rect();
setAcceptHoverEvents(true);
double ar = _size.width() / _size.height();
// Top Left
_topLeftCircle = new MovableCircle(MovableCircle::eTopLeft, ar, this);
_topLeftCircle->setPos(0, 0);
// Top Right
_topRightCircle = new MovableCircle(MovableCircle::eTopRight, ar, this);
_topRightCircle->setPos(_size.width(), 0);
// Bottom Right
_bottomRightCircle = new MovableCircle(MovableCircle::eBottomRight, ar, this);
_bottomRightCircle->setPos(_size.width(), _size.height());
// Bottom Left
_bottomLeftCircle = new MovableCircle(MovableCircle::eBottomLeft, ar, this);
_bottomLeftCircle->setPos(0, _size.height());
// Signals
// If a delimiter point has been moved, so force the item to redraw
connect(_topLeftCircle, &MovableCircle::circleMoved, this, [this](){
_bottomLeftCircle->setPos( _topLeftCircle->pos().x(), _bottomLeftCircle->pos().y());
_topRightCircle->setPos(_topRightCircle->pos().x(), _topLeftCircle->pos().y());
update(); // force to Repaint
});
connect(_topRightCircle, &MovableCircle::circleMoved, this, [this](){
_topLeftCircle->setPos(_topLeftCircle->pos().x(), _topRightCircle->pos().y());
_bottomRightCircle->setPos(_topRightCircle->pos().x(), _bottomRightCircle->pos().y());
update(); // force to Repaint
});
connect(_bottomLeftCircle, &MovableCircle::circleMoved, this, [this](){
_topLeftCircle->setPos(_bottomLeftCircle->pos().x(), _topLeftCircle->pos().y());
_bottomRightCircle->setPos(_bottomRightCircle->pos().x(), _bottomLeftCircle->pos().y());
update(); // force to Repaint
});
connect(_bottomRightCircle, &MovableCircle::circleMoved, this, [this](){
_bottomLeftCircle->setPos(_bottomLeftCircle->pos().x(), _bottomRightCircle->pos().y());
_topRightCircle->setPos(_bottomRightCircle->pos().x(), _topRightCircle->pos().y());
update(); // force to Repaint
});
}
MoveItem::~MoveItem()
{
}
QRectF MoveItem
::boundingRect() const {
qreal distX = sqrt(pow(_topLeftCircle->x() - _topRightCircle->x(),2) +
pow(_topLeftCircle->y() - _topRightCircle->y(),2)); // eucledian distance
qreal distY = sqrt(pow(_topLeftCircle->x() - _bottomLeftCircle->x(),2) +
pow(_topLeftCircle->y() - _bottomLeftCircle->y(),2)); // eucledian distance
return QRectF(qMin
(_topLeftCircle
->pos
().
x(), _topRightCircle
->pos
().
x()) ,
qMin(_topLeftCircle->pos().y(), _bottomLeftCircle->pos().y()),
distX, distY);
}
{
painter->drawImage(boundingRect(), qimage_);
painter->drawRect(boundingRect());
Q_UNUSED(widget);
}
{
this->setPos(mapToScene(event->pos()+ shiftMouseCoords_));
}
{
setZValue(++zCounter_);
shiftMouseCoords_ = (this->pos() - mapToScene(event->pos()))/scale();
if (event->button() == Qt::LeftButton) {
if (event->modifiers() == Qt::ShiftModifier) {
} else {
}
}
}
{
if (event->button() == Qt::LeftButton) {
if (event->modifiers() == Qt::ShiftModifier) {
} else {
}
}
}
class MoveItem : public QObject, public QGraphicsItem//public QGraphicsObject
{
Q_OBJECT
Q_INTERFACES(QGraphicsItem)
public:
explicit MoveItem(uint64_t& zc, QGraphicsItem *parent = 0);
~MoveItem();
signals:
protected:
QRectF boundingRect() const override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
void wheelEvent(QGraphicsSceneWheelEvent *event) override;
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override;
void hoverMoveEvent(QGraphicsSceneHoverEvent *event) override;
private:
QPointF shiftMouseCoords_;
QImage qimage_;
QPixmap pixmap_;
uint64_t& zCounter_;
MovableCircle *_topLeftCircle, *_topRightCircle, *_bottomLeftCircle, *_bottomRightCircle;
QSizeF _size;
QRectF rect_;
public slots:
};
MoveItem::MoveItem(uint64_t& zc, QGraphicsItem *parent) :
QGraphicsItem(parent), zCounter_(zc)
{
setZValue(zCounter_);
qimage_ = QImage("kot.png");
pixmap_ = QPixmap::fromImage(qimage_);
_size = pixmap_.size();
rect_ = qimage_.rect();
setAcceptHoverEvents(true);
setFlag(QGraphicsItem::ItemIsMovable, true);
double ar = _size.width() / _size.height();
// Top Left
_topLeftCircle = new MovableCircle(MovableCircle::eTopLeft, ar, this);
_topLeftCircle->setPos(0, 0);
// Top Right
_topRightCircle = new MovableCircle(MovableCircle::eTopRight, ar, this);
_topRightCircle->setPos(_size.width(), 0);
// Bottom Right
_bottomRightCircle = new MovableCircle(MovableCircle::eBottomRight, ar, this);
_bottomRightCircle->setPos(_size.width(), _size.height());
// Bottom Left
_bottomLeftCircle = new MovableCircle(MovableCircle::eBottomLeft, ar, this);
_bottomLeftCircle->setPos(0, _size.height());
// Signals
// If a delimiter point has been moved, so force the item to redraw
connect(_topLeftCircle, &MovableCircle::circleMoved, this, [this](){
_bottomLeftCircle->setPos( _topLeftCircle->pos().x(), _bottomLeftCircle->pos().y());
_topRightCircle->setPos(_topRightCircle->pos().x(), _topLeftCircle->pos().y());
update(); // force to Repaint
});
connect(_topRightCircle, &MovableCircle::circleMoved, this, [this](){
_topLeftCircle->setPos(_topLeftCircle->pos().x(), _topRightCircle->pos().y());
_bottomRightCircle->setPos(_topRightCircle->pos().x(), _bottomRightCircle->pos().y());
update(); // force to Repaint
});
connect(_bottomLeftCircle, &MovableCircle::circleMoved, this, [this](){
_topLeftCircle->setPos(_bottomLeftCircle->pos().x(), _topLeftCircle->pos().y());
_bottomRightCircle->setPos(_bottomRightCircle->pos().x(), _bottomLeftCircle->pos().y());
update(); // force to Repaint
});
connect(_bottomRightCircle, &MovableCircle::circleMoved, this, [this](){
_bottomLeftCircle->setPos(_bottomLeftCircle->pos().x(), _bottomRightCircle->pos().y());
_topRightCircle->setPos(_bottomRightCircle->pos().x(), _topRightCircle->pos().y());
update(); // force to Repaint
});
}
MoveItem::~MoveItem()
{
}
QRectF MoveItem::boundingRect() const
{
qreal distX = sqrt(pow(_topLeftCircle->x() - _topRightCircle->x(),2) +
pow(_topLeftCircle->y() - _topRightCircle->y(),2)); // eucledian distance
qreal distY = sqrt(pow(_topLeftCircle->x() - _bottomLeftCircle->x(),2) +
pow(_topLeftCircle->y() - _bottomLeftCircle->y(),2)); // eucledian distance
return QRectF(qMin(_topLeftCircle->pos().x(), _topRightCircle->pos().x()) ,
qMin(_topLeftCircle->pos().y(), _bottomLeftCircle->pos().y()),
distX, distY);
}
void MoveItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->drawImage(boundingRect(), qimage_);
painter->setPen(QPen(QColor(0, 160, 230),2));
painter->drawRect(boundingRect());
Q_UNUSED(widget);
}
void MoveItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
this->setPos(mapToScene(event->pos()+ shiftMouseCoords_));
}
void MoveItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
setZValue(++zCounter_);
shiftMouseCoords_ = (this->pos() - mapToScene(event->pos()))/scale();
if (event->button() == Qt::LeftButton) {
if (event->modifiers() == Qt::ShiftModifier) {
} else {
QGraphicsItem::mousePressEvent(event);
}
}
}
void MoveItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
if (event->modifiers() == Qt::ShiftModifier) {
} else {
QGraphicsItem::mousePressEvent(event);
}
}
}
To copy to clipboard, switch view to plain text mode
Bookmarks