Fixed map items collision detection over map limits
authorSami Rämö <sami.ramo@ixonos.com>
Mon, 14 Jun 2010 13:47:15 +0000 (16:47 +0300)
committerSami Rämö <sami.ramo@ixonos.com>
Mon, 14 Jun 2010 13:47:15 +0000 (16:47 +0300)
src/map/baselocationitem.cpp
src/map/baselocationitem.h
src/map/frienditemshandler.cpp
src/map/frienditemshandler.h

index 2643cd5..95f5acd 100644 (file)
@@ -36,6 +36,8 @@ BaseLocationItem::BaseLocationItem(QObject *parent)
 
 QRect BaseLocationItem::sceneTransformedBoundingRect(int zoomLevel) const
 {
+    qDebug() << __PRETTY_FUNCTION__;
+
     QRect rect = sceneBoundingRect().toRect();
 
     // returned rect size is size of original image and not scaled to size of currently presented
@@ -46,16 +48,5 @@ QRect BaseLocationItem::sceneTransformedBoundingRect(int zoomLevel) const
     int heightDelta = (rect.height() * multiplier - rect.height()) / 2;
     int widthDelta = (rect.width() * multiplier - rect.width()) / 2;
 
-    rect.adjust(-widthDelta, -heightDelta, widthDelta, heightDelta);
-
-    // make sure that left edge of the returned rect is always inside the world coordinates
-    // so collisions are detected even if the items are spanned around
-
-    while (rect.left() < MAP_MIN_PIXEL_X)
-        rect.translate(MAP_PIXELS_X, 0);
-
-    while (rect.left() > MAP_PIXELS_X - 1)
-        rect.translate(-MAP_PIXELS_X, 0);
-
-    return rect;
+    return rect.adjusted(-widthDelta, -heightDelta, widthDelta, heightDelta);
 }
index 821ae7b..ed85f74 100644 (file)
@@ -55,10 +55,6 @@ public:
     * sceneBoundingRect does always return the lowest map tile level scene bounding rect which
     * is scaled to current zoom level.
     *
-    * Left side of the returned rect is always inside the world coordinates, so collision
-    * detection based on this rect does work also when items are spanned outside the
-    * world coordinates.
-    *
     * @param zoomLevel Zoom level for which the sceneBoundingRect should be transformed
     * @return sceneBoundingRect transformed to given zoom level
     */
index 7775f7c..9562570 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "friendgroupitem.h"
 #include "friendlocationitem.h"
+#include "mapcommon.h"
 #include "mapengine.h"
 #include "mapscene.h"
 #include "user/user.h"
@@ -87,14 +88,13 @@ void FriendItemsHandler::checkFriendForCollidingFriends(FriendLocationItem *item
     qDebug() << __PRETTY_FUNCTION__;
 
     FriendGroupItem *group = 0;
-    QRect itemSceneRect = item->sceneTransformedBoundingRect(m_zoomLevel);
 
     // loop through all friend items
     QLinkedList<FriendLocationItem *>::iterator iter = m_friendItems.begin();
     while (iter != m_friendItems.end()) {
         // but don't check myself and friends which are already part of a group
         if (item != *iter && !(*iter)->isPartOfGroup()) {
-            if (itemSceneRect.intersects((*iter)->sceneTransformedBoundingRect(m_zoomLevel))) {
+            if (collides(item, *iter)) {
                 if (!group) {
                     group = new FriendGroupItem(item);
                     m_mapScene->addItem(group);
@@ -114,14 +114,12 @@ void FriendItemsHandler::checkGroupForCollidingFriends(FriendGroupItem *group)
 {
     qDebug() << __PRETTY_FUNCTION__;
 
-    QRect groupSceneRect = group->sceneTransformedBoundingRect(m_zoomLevel);
-
     // loop through all friend items
     QLinkedList<FriendLocationItem *>::iterator iter = m_friendItems.begin();
     while (iter != m_friendItems.end()) {
         // but don't check friends which are already part of a group
         if (!(*iter)->isPartOfGroup()) {
-            if (groupSceneRect.intersects((*iter)->sceneTransformedBoundingRect(m_zoomLevel))) {
+            if (collides(group, *iter)) {
                 group->joinFriend(*iter);
             }
         }
@@ -133,14 +131,12 @@ void FriendItemsHandler::checkGroupForCollidingGroups(FriendGroupItem *group)
 {
     qDebug() << __PRETTY_FUNCTION__;
 
-    QRect groupSceneRect = group->sceneTransformedBoundingRect(m_zoomLevel);
-
     // loop through all groups
     QLinkedList<FriendGroupItem *>::iterator iter = m_friendGroupItems.begin();
     while (iter != m_friendGroupItems.end()) {
         // but don't check myself
         if (group != *iter) {
-            if (groupSceneRect.intersects((*iter)->sceneTransformedBoundingRect(m_zoomLevel))) {
+            if (collides(group, *iter)) {
                 (*iter)->mergeWithGroup(group);
                 m_mapScene->removeItem(*iter);
                 delete *iter;
@@ -156,16 +152,26 @@ void FriendItemsHandler::checkGroupForCollidingGroups(FriendGroupItem *group)
     }
 }
 
-void FriendItemsHandler::mergeCollidingGroups()
+bool FriendItemsHandler::collides(BaseLocationItem *item1, BaseLocationItem *item2)
 {
-    qDebug() << __PRETTY_FUNCTION__;
+    QRect rect = item1->sceneTransformedBoundingRect(m_zoomLevel);
 
-    // loop through all groups
-    QLinkedList<FriendGroupItem *>::iterator iter = m_friendGroupItems.begin();
-    while (iter != m_friendGroupItems.end()) {
-        checkGroupForCollidingGroups(*iter);
-        iter++;
+    if (rect.intersects(item2->sceneTransformedBoundingRect(m_zoomLevel)))
+        return true;
+
+    if (rect.left() < MAP_MIN_PIXEL_X) {
+        QRect translated = rect.translated(MAP_PIXELS_X, 0);
+        if (translated.intersects(item2->sceneTransformedBoundingRect(m_zoomLevel)))
+            return true;
     }
+
+    if (rect.right() > MAP_MAX_PIXEL_X) {
+        QRect translated = rect.translated(-MAP_PIXELS_X, 0);
+        if (translated.intersects(item2->sceneTransformedBoundingRect(m_zoomLevel)))
+            return true;
+    }
+
+    return false;
 }
 
 void FriendItemsHandler::deleteFriendItem(FriendLocationItem *item)
@@ -247,6 +253,18 @@ void FriendItemsHandler::friendListUpdated(QList<User *> &friendsList)
     refactorFriendItems(m_zoomLevel);
 }
 
+void FriendItemsHandler::mergeCollidingGroups()
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    // loop through all groups
+    QLinkedList<FriendGroupItem *>::iterator iter = m_friendGroupItems.begin();
+    while (iter != m_friendGroupItems.end()) {
+        checkGroupForCollidingGroups(*iter);
+        iter++;
+    }
+}
+
 void FriendItemsHandler::refactorFriendItems(int zoomLevel)
 {
     qDebug() << __PRETTY_FUNCTION__;
index 6a04c33..3a96a0e 100644 (file)
@@ -26,6 +26,7 @@
 #include <QLinkedList>
 #include <QObject>
 
+class BaseLocationItem;
 class FriendGroupItem;
 class FriendLocationItem;
 class MapScene;
@@ -120,6 +121,19 @@ private:
     void cleanOldFriendData(const QList<User *> &friendsList);
 
     /**
+    * @brief Check if items collide
+    *
+    * Does check if items sceneTransformedBoundingRect() does intersect. If item1's rect is
+    * over the limits of the map, then rect is translated to opposite side of the map and
+    * intersections are tested there too.
+    *
+    * @param item1 First item
+    * @param item2 Secont item
+    * @return True if collision was found, otherwise false
+    */
+    bool collides(BaseLocationItem *item1, BaseLocationItem *item2);
+
+    /**
       * @brief Delete FriendLocationItem
       *
       * Drops item from all groups, removes it from scene and deletes the item.