1
$\begingroup$

Here's the relevant piece of code:

QPointF GraphicsItem::handleCollisions(const QPointF& new_pos) const {
    auto collisions = collidingItems();
    auto rect = mapToParent(boundingRect().translated(new_pos - pos())).boundingRect();
    for(int k=0; k < collisions.count(); k++)
    {
        auto item = collisions[k];
        if (item->parentItem() == parentItem()) {
            auto rect1 = item->mapToParent(item->boundingRect()).boundingRect();
            rect1 = rect1.intersected(rect);
            auto v = rect1.center() - rect.center();
            if (v.x() >= 0) {
                if (v.y() >= 0) {
                    if (rect1.width() <= rect1.height())
                        item->setPos(item->pos() + QPointF(rect1.width(), 0) * 1.5);
                    else
                        item->setPos(item->pos() + QPointF(0, rect1.height()));
                }
                else {
                    if (rect1.width() <= rect1.height())
                        item->setPos(item->pos() + QPointF(rect1.width(), 0));
                    else
                        item->setPos(item->pos() + QPointF(0, -rect1.height()));
                }
            }
            else {
                if (v.y() >= 0) {
                    if (rect1.width() <= rect1.height())
                        item->setPos(item->pos() + QPointF(-rect1.width(), 0));
                    else
                        item->setPos(item->pos() + QPointF(0, rect1.height()));
                }
                else {
                    if (rect1.width() <= rect1.height())
                        item->setPos(item->pos() + QPointF(-rect1.width(), 0));
                    else
                        item->setPos(item->pos() + QPointF(0, -rect1.height()));
                }
            }
        }
    }
    return new_pos;     // return this position unchanged
}

Here's a video showing the result, which is very low quality IMHO.

YouTube Video

I'd like the result to be smooth: Ie. the pushed box moves at precisely the same velocity as the pushing box.

Thanks for your mathematical ingenuity. It will not go unpayed. I am making this app for you: a visual diagram chaser with the ability to create new logic rules visually. It has never been done.

What you saw in the video was a a C++ application I'm writing as a port of an earlier python prototype I showed you:

Previous post


Question for you: Is 10 dollars to much to ask per license on a kickstarter campaign? That would amount to 10,000 USD if I sold 1000 copies, and I'm sure I can snag at least that many of you, because this app will be the shits.

If you're interested in how I plan to implement the categorical logic, please ask. It is a way that hasn't been tried before AFAIK.

$\endgroup$
  • $\begingroup$ I think I can solve this with a collision list. First we move like we did in the code above, but successive moves within the same mouse move sequence (demarked by press/release of mouse) always move the items in the collision list by the same delta as the item being moved or maybe a component there of, until the mouse is released. The collision list gets populated with colliding items and updated each call to handleCollisions(). I think that might work. $\endgroup$ – Shine On You Crazy Diamond Sep 16 '18 at 5:42
0
$\begingroup$

I've got a partial solution. The code simplifies (in Qt5) down to this simple snippet:

QPointF GraphicsItem::handleCollisions(const QPointF& new_pos) const {
    auto collisions = collidingItems();
    auto delta = new_pos - this->pos();
    auto parent = parentItem();

    for (int k=0; k < collisions.count(); k++) {
        auto item = collisions[k];
        if (item->parentItem() == parent) {
            // Without this check, the boxes stick together, kind of neat
            if (collidesWithPath(item->mapToItem(this, item->shape().translated(delta * 1.1))));
                item->setPos(item->pos() + delta);
        }
    }

    return new_pos;     // Return pos unchanged
}

Only problem is the boxes stick together now. They move perfectly in synchrony but they're stuck. So I put that check there, but it's not working. I'll post a solution to this when I find the bug.


The inner if condition should be:

    if (item->collidesWithPath(mapToItem(item, shape.translated(delta)))) {
        item->setPos(item->pos() + delta);
    }
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.