From 6f06aba6d7e52378d6192c631917f69a1b5d0f2e Mon Sep 17 00:00:00 2001 From: Christian Klinger Date: Mon, 23 May 2016 10:19:36 +0200 Subject: Improved positioning into the grid. (Pixel-precise calculations). --- src/server/mainwindow/mainwindow.cpp | 119 +++++++++++++++-------------------- 1 file changed, 51 insertions(+), 68 deletions(-) (limited to 'src/server/mainwindow/mainwindow.cpp') diff --git a/src/server/mainwindow/mainwindow.cpp b/src/server/mainwindow/mainwindow.cpp index 76f5e00..88ed17d 100644 --- a/src/server/mainwindow/mainwindow.cpp +++ b/src/server/mainwindow/mainwindow.cpp @@ -174,53 +174,64 @@ float distance(QPoint a, QPoint b) { int sum = dx*dx + dy*dy; return sqrt((float) sum); } + +float distance(QPointF a, QPointF b) { + int dx = a.x() - b.x(); + int dy = a.y() - b.y(); + int sum = dx*dx + dy*dy; + return sqrt(sum); +} + + + /***************************************************************************//** - * Place the frame into a free position that is closest (Euclidean distance) to - * the preferred point. + * \brief: find the closest available frame. + * + * Closest: smallest Euclidean distance from center to center * - * If current position out of range, place frame into the closest free cell. * 'Algorithm': ideally, go in circles around the preferred point until you find * a free spot. Lazy way: store all free positions in an array and find later * there the closest (<- that's what I do) * - * @param frame + * @param preferred in Pixels! + * @param toIgnore, ignore this connectionframe when considering free slots + * @return the free slot */ -void MainWindow::placeFrameInFreeSlot(ConnectionFrame* frame, QPoint preferred) -{ +QPoint MainWindow::closestFreeSlot(QPoint preferredPixels, ConnectionFrame* toIgnore) { const QSize& clientSize = Global::getCurrentRoom()->clientSize; - /* Get occupied cell of each frame and store status in an array */ bool grid[_tilesX][_tilesY]; - memset(grid, 0, sizeof(bool) * _tilesX * _tilesY); // set everything to false + memset(grid, 0, sizeof(bool) * _tilesX * _tilesY); /* set everything to false */ /* fill grid */ - for (QList::iterator it(_clientFrames.begin()); it != _clientFrames.end(); ++it) - { - const QPoint& position = (*it)->getGridPosition(); - - for (int x = position.x(); x < position.x() + clientSize.width(); x++) { - for (int y = position.y(); y < position.y() + clientSize.height(); y++) { + for (auto it = _clientFrames.begin(); it != _clientFrames.end(); ++it) { + + if (*it == toIgnore) { continue; } + + const QPoint& p = (*it)->getGridPosition(); + + for (int x = p.x(); x < p.x() + clientSize.width(); x++) { + for (int y = p.y(); y < p.y() + clientSize.height(); y++) { grid[x][y] = true; } } } - /* Now place in next free cell, start looking at current position of frame */ - vector freePositions; + QList freePositions; + /* check all positions to see if they are available */ for (int x = 0; x <= _tilesX - clientSize.width(); x++) { for ( int y = 0; y <= _tilesY - clientSize.height(); y++) { /* check if (x,y) is free */ bool isFree = true; for (int dx = 0; dx < clientSize.width(); dx++) { - for (int dy = 0; dy < clientSize.width(); dy++) { + for (int dy = 0; dy < clientSize.height(); dy++) { if (grid[x + dx][y + dy]) { isFree = false; + goto endLoop; // double-break } } } - if (isFree) { - QPoint freePos(x,y); - freePositions.push_back(freePos); - } +endLoop: + if (isFree) { freePositions << QPoint(x,y); } } } /* among all the free positions, find the closest */ @@ -228,12 +239,22 @@ void MainWindow::placeFrameInFreeSlot(ConnectionFrame* frame, QPoint preferred) QPoint bestPosition = QPoint(-1, -1); for (QPoint freePos : freePositions) { - float dist = distance(freePos, preferred); + QPoint freePosCenter( freePos.x() * getTileWidthPx() + getTileWidthPx() * clientSize.width() / 2, + freePos.y() * getTileHeightPx() + getTileHeightPx() * clientSize.height() / 2); + float dist = distance(freePosCenter, preferredPixels); if (dist < min_distance) { min_distance = dist; bestPosition = freePos; } } + return bestPosition; +} + +/* place frame in the cloest available spot */ +void MainWindow::placeFrameInFreeSlot(ConnectionFrame* frame, QPoint preferredPixels) { + + QPoint bestPosition = closestFreeSlot(preferredPixels, frame); + frame->setGridPosition(bestPosition); QPoint freePosPx(bestPosition.x() * getTileWidthPx(), bestPosition.y() * getTileHeightPx()); frame->setCurrentPosition(freePosPx); @@ -652,56 +673,17 @@ void MainWindow::reset() /***************************************************************************//** -* Place Frame to from user specified position. -* Behaviour: If placed exactly on another frame: replace that frame and place it -* on the closest free slot. Otherwise: place connectionFrame on the closest free -* slot. +* Place frame to from user specified position. Should be called when a +* connectionFrame is dropped during the "drag-n-drop". */ void MainWindow::onPlaceFrame(bool activateTrash, ConnectionFrame* connectionFrame) { - if (_tilesX <= 0 || _tilesY <= 0) - return; - const QPoint &p = connectionFrame->frameGeometry().center(); - const QSize &s = ui->frmRoom->geometry().size(); - /* round to grid */ - int x = p.x() / getTileWidthPx(); - int y = p.y() / getTileHeightPx(); - if (x < 0) { - x = 0; - } else if (x > s.width() - getTileWidthPx()) { - qDebug() << "oopsie"; - x = (_tilesX - 1); - } - if (y < 0) { - y = 0; - } else if (y > s.height() - getTileHeightPx()) { - qDebug() << "oopsie2"; - y = (_tilesY - 1); - } - /* --- */ - - QPoint newPos(x,y); - connectionFrame->setGridPosition(newPos); - placeFrameInFreeSlot(connectionFrame, newPos); - - /* if there is already a frame at that position, push it away */ - bool replacedFrame = false; - for (auto it = _clientFrames.begin(); it != _clientFrames.end(); ++it) { - if (*it == connectionFrame) { continue; } - - if ((*it)->getGridPosition() == newPos) { - connectionFrame->setGridPosition(newPos); - placeFrameInFreeSlot(*it, newPos); /* place frame in free slot, close to newPos */ - replacedFrame = true; - break; - } - } - if (!replacedFrame) { - placeFrameInFreeSlot(connectionFrame, newPos); - } - /* update positions */ + // if (_tilesX <= 0 || _tilesY <= 0) return; + const QPoint &preferredPixels = connectionFrame->frameGeometry().center(); + placeFrameInFreeSlot(connectionFrame, preferredPixels); - savePosition(connectionFrame); /* save in local config to remember position */ + /* save in local config to remember position */ + savePosition(connectionFrame); resizeEvent(NULL); } @@ -724,6 +706,7 @@ void MainWindow::onFrameClicked(ConnectionFrame* frame) frame->setSelection(true); qDebug() << "ID of frame: " << frame->computerId(); qDebug() << "ID of selectedFrame: " << getSelectedFrame()->computerId(); + qDebug() << "position of selectedFrame: " << getSelectedFrame()->getGridPosition(); unlockContextButtons(); } -- cgit v1.2.3-55-g7522