Fixed map items collision detection over map limits
[situare] / src / map / frienditemshandler.cpp
index 9bb018f..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"
 
 FriendItemsHandler::FriendItemsHandler(MapScene *mapScene, QObject *parent)
     : QObject(parent),
-      m_mapScene(mapScene)
+      m_mapScene(mapScene),
+      m_zoomLevel(0)
 {
+    qDebug() << __PRETTY_FUNCTION__;
 }
 
-FriendItemsHandler::~FriendItemsHandler()
+void FriendItemsHandler::addFriendItem(User *friendData)
 {
-    qDeleteAll(m_friendItems.begin(),m_friendItems.end());
-    m_friendItems.clear();
+    qDebug() << __PRETTY_FUNCTION__;
+
+    FriendLocationItem *item = new FriendLocationItem(friendData->userId());
+
+    item->setProfileImage(friendData->profileImage(), friendData->profileImageUrl());
+    item->setPos(MapEngine::convertLatLonToSceneCoordinate(friendData->coordinates()));
+    m_friendItems.append(item);
+    m_mapScene->addItem(item);
+
+    connect(item, SIGNAL(locationItemClicked(QList<QString>)),
+            this, SIGNAL(locationItemClicked(QList<QString>)));
 }
 
 void FriendItemsHandler::checkAllFriendsForCollidingFriends()
 {
-    qWarning() << __PRETTY_FUNCTION__;
+    qDebug() << __PRETTY_FUNCTION__;
 
-    QLinkedList<FriendLocationItem *>::iterator i = m_friendItems.begin();
-    while (i != m_friendItems.end()) {
-        checkFriendForCollidingFriends(*i);
-        i++;
+    QLinkedList<FriendLocationItem *>::iterator iter = m_friendItems.begin();
+    while (iter != m_friendItems.end()) {
+        // check only friends which are not part of group already
+        if (!(*iter)->isPartOfGroup()) {
+            checkFriendForCollidingFriends(*iter);
+        }
+        iter++;
     }
-
-//    foreach(FriendGroupItem *item, m_friendGroupItems) {
-//        m_friendGroupItems.removeAll(item);
-//        m_mapScene->removeItem(item);
-//    }
-
-//    int lastItem = m_friendItems.size() - 1;
-//    for (int checking = 0; checking <= lastItem; checking++) {
-//        QRect beginItemRect = m_friendItems.at(checking)->sceneTransformedBoundingRect(m_zoomLevel);
-
-//        // don't check items which are already part of a group (and thus unvisible)
-//        if (m_friendItems.at(checking)->isPartOfGroup())
-//            continue;
-
-//        // check all other items
-//        for (int another = 0; another <= lastItem; another++)
-//        {
-//            // don't check against itself
-//            if (checking == another)
-//                continue;
-
-//            // don't check against items which are already part of a group (and thus unvisible)
-//            if (m_friendItems.at(another)->isPartOfGroup())
-//                continue;
-
-//            // does items collide
-//            QRect iterItemRect = m_friendItems.at(another)->sceneTransformedBoundingRect(m_zoomLevel);
-//            if (beginItemRect.intersects(iterItemRect)) {
-//                qWarning() << __PRETTY_FUNCTION__ << "collision found" << checking << another;
-//                FriendGroupItem *group = new FriendGroupItem();
-//                m_friendGroupItems.append(group);
-//                group->setPos(m_friendItems.at(checking)->pos());
-//                group->joinFriend(m_friendItems.at(checking));
-//                group->joinFriend(m_friendItems.at(another));
-//                m_mapScene->addItem(group);
-//                break;
-//            }
-//        }
-//    }
 }
 
 void FriendItemsHandler::checkAllGroupsForCollidingFriends()
 {
-    // check against colliding friends
-        // join friends to group
-    /// @todo IMPLEMENT
+    qDebug() << __PRETTY_FUNCTION__;
+
+    // loop through all groups
+    QLinkedList<FriendGroupItem *>::iterator iter = m_friendGroupItems.begin();
+    while (iter != m_friendGroupItems.end()) {
+        checkGroupForCollidingFriends(*iter);
+        iter++;
+    }
 }
 
 void FriendItemsHandler::checkFriendForCollidingFriends(FriendLocationItem *item)
@@ -107,83 +88,114 @@ 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 i = m_friendItems.begin();
-    while (i != m_friendItems.end()) {
+    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 != *i && !(*i)->isPartOfGroup()) {
-            if (itemSceneRect.intersects((*i)->sceneTransformedBoundingRect(m_zoomLevel))) {
+        if (item != *iter && !(*iter)->isPartOfGroup()) {
+            if (collides(item, *iter)) {
                 if (!group) {
                     group = new FriendGroupItem(item);
                     m_mapScene->addItem(group);
                     m_friendGroupItems.append(group);
+
+                    connect(group, SIGNAL(locationItemClicked(QList<QString>)),
+                            this, SIGNAL(locationItemClicked(QList<QString>)));
                 }
-                group->joinFriend(*i);
+                group->joinFriend(*iter);
             }
         }
-        i++;
+        iter++;
     }
 }
 
-void FriendItemsHandler::checkGroupForCollidingGroups(FriendGroupItem *group)
+void FriendItemsHandler::checkGroupForCollidingFriends(FriendGroupItem *group)
 {
     qDebug() << __PRETTY_FUNCTION__;
 
-    QRect groupSceneRect = group->sceneTransformedBoundingRect(m_zoomLevel);
-
     // loop through all friend items
-    QLinkedList<FriendGroupItem *>::iterator i = m_friendGroupItems.begin();
-    while (i != m_friendGroupItems.end()) {
-        // but don't check myself
-        if (group != *i) {
-            if (groupSceneRect.intersects((*i)->sceneTransformedBoundingRect(m_zoomLevel))) {
-                /// @todo MERGE GROUP i TO group
-                /// get other group friends, remove from scene and list, delete
+    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 (collides(group, *iter)) {
+                group->joinFriend(*iter);
             }
         }
-        i++;
+        iter++;
     }
 }
 
-void FriendItemsHandler::mergeCollidingGroups()
+void FriendItemsHandler::checkGroupForCollidingGroups(FriendGroupItem *group)
 {
+    qDebug() << __PRETTY_FUNCTION__;
+
     // 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 (collides(group, *iter)) {
+                (*iter)->mergeWithGroup(group);
+                m_mapScene->removeItem(*iter);
+                delete *iter;
+                iter = m_friendGroupItems.erase(iter);
+            }
+            else {
+                iter++;
+            }
+        }
+        else {
+            iter++;
+        }
+    }
+}
 
-        // merge groups
+bool FriendItemsHandler::collides(BaseLocationItem *item1, BaseLocationItem *item2)
+{
+    QRect rect = item1->sceneTransformedBoundingRect(m_zoomLevel);
+
+    if (rect.intersects(item2->sceneTransformedBoundingRect(m_zoomLevel)))
+        return true;
 
-    /// @todo IMPLEMENT
+    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::cleanOldFriendData(const QList<User *> &friendsList)
+void FriendItemsHandler::deleteFriendItem(FriendLocationItem *item)
 {
-    // loop through all m_friendItem items
-    QLinkedList<FriendLocationItem *>::iterator i = m_friendItems.begin();
-    while (i != m_friendItems.end()) {
-        bool friendFound = false;
-
-        // check against each item in the friendsList
-        QList<User *>::const_iterator j;
-        for (j = friendsList.begin(); j != friendsList.end(); j++) {
-            if ((**i).userId() == (**j).userId()) {
-                friendFound = true;
-                break;
-            }
-        }
+    qDebug() << __PRETTY_FUNCTION__;
 
-        if (!friendFound) {
-            m_mapScene->removeItem(*i);
-            i = m_friendItems.erase(i);
-        }
-        else {
-            i++;
-        }
+    dropFriendFromAllGroups(item);
+    m_mapScene->removeItem(item);
+    delete item;
+}
+
+void FriendItemsHandler::dropFriendFromAllGroups(FriendLocationItem *item)
+{
+    qDebug() << __PRETTY_FUNCTION__;
+
+    foreach (FriendGroupItem *group, m_friendGroupItems) {
+        group->dropFriend(item);
     }
 }
 
 void FriendItemsHandler::dropOutOfGroupFriends()
 {
+    qDebug() << __PRETTY_FUNCTION__;
+
     // loop through all group items and drop friends which doesn't collide anymore
     // delete group if possible
     foreach (FriendGroupItem *group, m_friendGroupItems) {
@@ -195,27 +207,68 @@ void FriendItemsHandler::dropOutOfGroupFriends()
     }
 }
 
-void FriendItemsHandler::receiveFriendLocations(QList<User *> &friendsList)
+void FriendItemsHandler::friendListUpdated(QList<User *> &friendsList)
 {
-    qWarning() << __PRETTY_FUNCTION__;
+    qDebug() << __PRETTY_FUNCTION__;
 
-    static int receiveFriendsLocationsCounter = 0;
+    // loop through friend items and find matching friend data. If matching data
+    // is not found then remove item
+    QLinkedList<FriendLocationItem *>::iterator iter = m_friendItems.begin();
+    while (iter != m_friendItems.end()) {
+        bool found = false;
+        foreach (User * friendData, friendsList) {
+            if (friendData->userId() == (*iter)->userId()) {
+                found = true;
+                break;
+            }
+        }
+        if (!found) {
+            // data for friend item was not found so item must be deleted
+            deleteFriendItem(*iter);
+            iter = m_friendItems.erase(iter);
+        }
+        else {
+            iter++;
+        }
+    }
 
-    if (receiveFriendsLocationsCounter == 0) {
-        receiveFriendsLocationsCounter++;
-        updateFriendItemList(friendsList);
+    // loop through new friend data, find matching friend items and update them, or add new items
+    // if old items are not found
+    foreach (User * friendData, friendsList) {
+        bool found = false;
+        foreach (FriendLocationItem *friendItem, m_friendItems) {
+            if (friendData->userId() == friendItem->userId()) {
+                // friend item was found so update the data
+                updateFriendItem(friendItem, friendData);
+                found = true;
+                break;
+            }
+        }
+        if (!found) {
+            // friend item was not found so new item must be added
+            addFriendItem(friendData);
+        }
     }
 
-    else {
-        /// @todo VILLE: New friends are never added to list & scene
-        receiveFriendsLocationsCounter++;
-        updateFriendLocationsAndImages(friendsList);
-        cleanOldFriendData(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__;
+
     m_zoomLevel = zoomLevel;
 
     mergeCollidingGroups();
@@ -224,45 +277,16 @@ void FriendItemsHandler::refactorFriendItems(int zoomLevel)
     checkAllFriendsForCollidingFriends();
 }
 
-void FriendItemsHandler::updateFriendItemList(const QList<User *> &friendsList)
+void FriendItemsHandler::updateFriendItem(FriendLocationItem *friendItem, User *friendData)
 {
     qDebug() << __PRETTY_FUNCTION__;
 
-    qDeleteAll(m_friendItems.begin(),m_friendItems.end());
-    m_friendItems.clear();
+    // update position
+    QPoint newPosition = MapEngine::convertLatLonToSceneCoordinate(friendData->coordinates());
+    if (friendItem->pos().toPoint() != newPosition)
+        friendItem->setPos(newPosition);
 
-
-    for (int i=0; i<friendsList.count(); i++) {
-        FriendLocationItem *friendLocation
-                = new FriendLocationItem(friendsList.at(i)->profileImage(),
-                                         friendsList.at(i)->coordinates(),0);
-
-        friendLocation->setUserId(friendsList.at(i)->userId());
-        m_friendItems.append(friendLocation);
-        m_mapScene->addItem(friendLocation);
-
-        //refactorFriendItems(m_zoomLevel);
-    }
-}
-
-void FriendItemsHandler::updateFriendLocationsAndImages(const QList<User *> &friendsList)
-{
-    for (int i=0; i<friendsList.count(); i++) {
-
-        QLinkedList<FriendLocationItem *>::iterator j;
-        for (j = m_friendItems.begin(); j!= m_friendItems.end(); j++) {
-
-            if ((*j)->userId() == friendsList.at(i)->userId()) {
-
-                if ((*j)->position()
-                    != MapEngine::convertLatLonToSceneCoordinate(friendsList.at(i)->coordinates()))
-                    (*j)->setPosition(friendsList.at(i)->coordinates());
-
-                if ((*j)->profileImageUrl()
-                    != friendsList.at(i)->profileImageUrl()) {
-                    (*j)->setPixmap(friendsList.at(i)->profileImage());
-                }
-            }
-        }
-    }
+    // update image
+    if (friendItem->profileImageUrl() != friendData->profileImageUrl())
+        friendItem->setProfileImage(friendData->profileImage(), friendData->profileImageUrl());
 }