Skip to content
  • 0 Votes
    3 Posts
    2k Views
    A

    @fcarney Thankyou for the prompt reply, your solution does solve my problem.

  • 0 Votes
    2 Posts
    3k Views
    VagabondV

    Okay, I have come up with a solution. I have setup a better handling for the hittest evaluation. I first check which side of the intersected boundingbox the moved item is closest to. Then I set the x, or y coordinate accordingly. I added some helper functions for this, to compute point-line distance and closest side of a rect to a point. They are all included in the snippet below.

    NOTE: the collision test will also evaluate and prohibit the item to exceed the scene bounds. It will also only solve, overlapping one other item. If the border test results in another overlap I simply set the position back to where it was prior to mouse move. Works a lot nicer than my initial implementation though.

    enum CustomGraphicsItem::BOX_SIDE { LEFT, RIGHT, UPPER, LOWER }; void CustomGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent* e) { if(mode_ == MOVE) { QPointF p = pos(); QGraphicsItem::mouseMoveEvent(e); QPointF p_new = pos(); QList<QGraphicsItem*> col_it = collidingItems(Qt::IntersectsItemBoundingRect); if(col_it.size() > 0) { qreal x_min = col_it[0]->pos().x() - boundingRect().width(); qreal x_max = col_it[0]->pos().x() + col_it[0]->boundingRect().width(); qreal y_min = col_it[0]->pos().y() - boundingRect().height(); qreal y_max = col_it[0]->pos().y() + col_it[0]->boundingRect().height(); QRectF rect(QPointF(x_min, y_min), QPointF(x_max, y_max)); switch(closestSide(p_new, rect)) { case LEFT: p_new.setX(x_min); break; case RIGHT: p_new.setX(x_max); break; case UPPER: p_new.setY(y_min); break; case LOWER: p_new.setY(y_max); break; } setPos(p_new); } // check if item in scene bounds qreal max_x = scene()->width() - boundingRect().width(); qreal max_y = scene()->height() - boundingRect().height(); if (x() < 0) setPos(0, y()); else if (x() > max_x) setPos(max_x, y()); if (y() < 0) setPos(x(), 0); else if (y() > max_y) setPos(x(), max_y); // if still colliding set pos back to start col_it = collidingItems(Qt::IntersectsItemBoundingRect); if(col_it.size() > 0) setPos(p); } } qreal CustomGraphicsItem::distance(const QPointF &p, const QLineF &l) { QPointF p1 = l.p1(); QPointF p2 = l.p2(); qreal x = p.x() - p1.x(); qreal y = p.y() - p1.y(); qreal x2 = p2.x() - p1.x(); qreal y2 = p2.y() - p1.y(); // if line is a point, return distance between point and one line node qreal norm = sqrt(x2*x2 + y2*y2); if (norm <= std::numeric_limits<int>::epsilon()) return sqrt(x*x + y*y); // distance return fabs(x*y2 - y*x2) / norm; } CustomGraphicsItem::BOX_SIDE CustomGraphicsItem::closestSide(const QPointF &p, const QRectF &rect) { qreal x_min = rect.x(); qreal x_max = rect.x() + rect.width(); qreal y_min = rect.y(); qreal y_max = rect.y() + rect.height(); qreal temp_dist = 0; // left QLineF l(QPointF(x_min, y_min), QPointF(x_min, y_max)); qreal min_dist = distance(p,l); BOX_SIDE side = LEFT; // right l.setPoints(QPointF(x_max,y_min), QPointF(x_max, y_max)); temp_dist = distance(p,l); if(temp_dist < min_dist) { min_dist = temp_dist; side = RIGHT; } // upper l.setPoints(QPointF(x_min, y_min), QPointF(x_max, y_min)); temp_dist = distance(p,l); if(temp_dist < min_dist) { min_dist = temp_dist; side = UPPER; } // lower l.setPoints(QPointF(x_min, y_max), QPointF(x_max, y_max)); temp_dist = distance(p,l); if(temp_dist < min_dist) { min_dist = temp_dist; side = LOWER; } return side; }
  • 0 Votes
    14 Posts
    6k Views
    mrjjM

    @sohyun

    oh, so it was not the image that was broken?
    super
    Nice day to you too