changeset 1041:fc7c0f38e8a6

added nObjects to MovingObject, with loading/saving
author Nicolas Saunier <nicolas.saunier@polymtl.ca>
date Wed, 04 Jul 2018 16:06:23 -0400
parents 20799ac9524e
children b1ba6d44fcb9
files trafficintelligence/moving.py trafficintelligence/storage.py trafficintelligence/tests/moving.txt
diffstat 3 files changed, 41 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/trafficintelligence/moving.py	Wed Jul 04 15:37:04 2018 -0400
+++ b/trafficintelligence/moving.py	Wed Jul 04 16:06:23 2018 -0400
@@ -1141,12 +1141,13 @@
     and a usertype (e.g. road user) coded as a number (see userTypeNames)
     '''
 
-    def __init__(self, num = None, timeInterval = None, positions = None, velocities = None, geometry = None, userType = userType2Num['unknown']):
+    def __init__(self, num = None, timeInterval = None, positions = None, velocities = None, geometry = None, userType = userType2Num['unknown'], nObjects = None):
         super(MovingObject, self).__init__(num, timeInterval)
         self.positions = positions
         self.velocities = velocities
         self.geometry = geometry
         self.userType = userType
+        self.setNObjects(nObjects) # a feature has None for nObjects
         self.features = None
         # compute bounding polygon from trajectory
 
@@ -1213,7 +1214,7 @@
             for t in secondObject.getTimeInterval():
             	positions.addPosition(secondObject.getPositionAtInstant(t))
             	velocities.addPosition(secondObject.getVelocityAtInstant(t))
-            newObject = MovingObject(newNum, TimeInterval(firstObject.getFirstInstant(), secondObject.getLastInstant()), positions, velocities)
+            newObject = MovingObject(newNum, TimeInterval(firstObject.getFirstInstant(), secondObject.getLastInstant()), positions, velocities, nObjects = 1)
             if hasattr(obj1, 'featureNumbers') and hasattr(obj2, 'featureNumbers'):
                 if newFeatureNum is not None:
                     newObject.featureNumbers = obj1.featureNumbers+obj2.featureNumbers+[newFeatureNum]
@@ -1223,7 +1224,7 @@
                 newObject.features = obj1.getFeatures()+obj2.getFeatures()+[MovingObject(newFeatureNum, TimeInterval(emptyInterval.first+1, emptyInterval.last-1), featurePositions, featureVelocities)]
         else: # time intervals overlap
             newTimeInterval = TimeInterval.union(obj1.getTimeInterval(), obj2.getTimeInterval())
-            newObject = MovingObject(newNum, newTimeInterval)
+            newObject = MovingObject(newNum, newTimeInterval, nObjects = 1) # hypothesis is that it's the same object being reunited
             if hasattr(obj1, 'featureNumbers') and hasattr(obj2, 'featureNumbers'):
                 newObject.featureNumbers = obj1.featureNumbers+obj2.featureNumbers
             if obj1.hasFeatures() and obj2.hasFeatures():
@@ -1243,7 +1244,7 @@
         intersection = TimeInterval.intersection(inter, self.getTimeInterval())
         if not intersection.empty():
             trajectoryInterval = TimeInterval(intersection.first-self.getFirstInstant(), intersection.last-self.getFirstInstant())
-            obj = MovingObject(self.num, intersection, self.positions.getTrajectoryInInterval(trajectoryInterval), self.geometry, self.userType)
+            obj = MovingObject(self.num, intersection, self.positions.getTrajectoryInInterval(trajectoryInterval), self.geometry, self.userType, self.nObjects)
             if self.velocities is not None:
                 obj.velocities = self.velocities.getTrajectoryInInterval(trajectoryInterval)
             return obj
@@ -1330,6 +1331,15 @@
     def setUserType(self, userType):
         self.userType = userType
 
+    def getNObjects(self):
+        return self.nObjects
+
+    def setNObjects(self, nObjects):
+        if nObjects is None or nObjects >= 1:
+            self.nObjects = nObjects
+        else:
+            print('Number of objects represented by object {} must be greater or equal to 1 ({})'.format(self.getNum(), nObjects))
+        
     def setFeatures(self, features, featuresOrdered = False):
         '''Sets the features in the features field based on featureNumbers
         if not all features are loaded from 0, one needs to renumber in a dict'''
--- a/trafficintelligence/storage.py	Wed Jul 04 15:37:04 2018 -0400
+++ b/trafficintelligence/storage.py	Wed Jul 04 16:06:23 2018 -0400
@@ -229,16 +229,23 @@
 
     return objects
 
-def loadUserTypesFromTable(cursor, objectNumbers):
+def loadObjectAttributesFromTable(cursor, objectNumbers, loadNObjects = False):
     objectCriteria = getObjectCriteria(objectNumbers)
-    queryStatement = 'SELECT object_id, road_user_type FROM objects'
+    queryStatement = 'SELECT object_id, road_user_type'
+    if loadNObjects:
+        queryStatement += ', n_objects'
+    queryStatement += ' FROM objects'
     if objectNumbers is not None:
         queryStatement += ' WHERE object_id '+objectCriteria
     cursor.execute(queryStatement)
-    userTypes = {}
-    for row in cursor:
-        userTypes[row[0]] = row[1]
-    return userTypes
+    attributes = {}
+    if loadNObjects:
+        for row in cursor:
+            attributes[row[0]] = row[1:]
+    else:
+        for row in cursor:
+            attributes[row[0]] = row[1]
+    return attributes
 
 def loadTrajectoriesFromSqlite(filename, trajectoryType, objectNumbers = None, withFeatures = False, timeStep = None, maxNObjectFeatures = 1):
     '''Loads the trajectories (in the general sense, 
@@ -290,9 +297,11 @@
                     obj.featureNumbers = featureNumbers[obj.getNum()]
 
                 # load userType
-                userTypes = loadUserTypesFromTable(cursor, objectNumbers)
+                attributes = loadObjectAttributesFromTable(cursor, objectNumbers, True)
                 for obj in objects:
-                    obj.userType = userTypes[obj.getNum()]
+                    userType, nObjects = attributes[obj.getNum()]
+                    obj.setUserType(userType)
+                    obj.setNObjects(nObjects)
 
                 if withFeatures:
                     nFeatures = 0
@@ -452,7 +461,7 @@
         if objectType == 'bb':
             topCorners = loadTrajectoriesFromTable(connection, 'bounding_boxes', 'bbtop', objectNumbers, timeStep)
             bottomCorners = loadTrajectoriesFromTable(connection, 'bounding_boxes', 'bbbottom', objectNumbers, timeStep)
-            userTypes = loadUserTypesFromTable(connection.cursor(), objectNumbers) # string format is same as object
+            userTypes = loadObjectAttributesFromTable(connection.cursor(), objectNumbers) # string format is same as object
 
             for t, b in zip(topCorners, bottomCorners):
                 num = t.getNum()
@@ -1033,7 +1042,7 @@
         for row_index, row in instants.iterrows():
             objNum = int(row['NO'])
             tmp = data[data['NO'] == objNum]
-            objects[objNum] = moving.MovingObject(num = objNum, timeInterval = moving.TimeInterval(row['first'], row['last']))
+            objects[objNum] = moving.MovingObject(num = objNum, timeInterval = moving.TimeInterval(row['first'], row['last']), nObjects = 1)
             # positions should be rounded to nDecimals decimals only
             objects[objNum].curvilinearPositions = moving.CurvilinearTrajectory(S = npround(tmp['POS'].tolist(), nDecimals), Y = npround(tmp['POSLAT'].tolist(), nDecimals), lanes = tmp['LANE'].tolist())
             if objectNumbers is not None and objectNumbers > 0 and len(objects) >= objectNumbers:
@@ -1052,7 +1061,7 @@
                 if objNum not in objects:
                     if warmUpLastInstant is None or instant >= warmUpLastInstant:
                         if objectNumbers is None or len(objects) < objectNumbers:
-                            objects[objNum] = moving.MovingObject(num = objNum, timeInterval = moving.TimeInterval(instant, instant))
+                            objects[objNum] = moving.MovingObject(num = objNum, timeInterval = moving.TimeInterval(instant, instant), nObjects = 1)
                             objects[objNum].curvilinearPositions = moving.CurvilinearTrajectory()
                 if (warmUpLastInstant is None or instant >= warmUpLastInstant) and objNum in objects:
                     objects[objNum].timeInterval.last = instant
@@ -1076,7 +1085,7 @@
                         if objNum not in objects:
                             if warmUpLastInstant is None or instant >= warmUpLastInstant:
                                 if objectNumbers is None or len(objects) < objectNumbers:
-                                    objects[objNum] = moving.MovingObject(num = objNum, timeInterval = moving.TimeInterval(instant, instant))
+                                    objects[objNum] = moving.MovingObject(num = objNum, timeInterval = moving.TimeInterval(instant, instant), nObjects = 1)
                                     objects[objNum].curvilinearPositions = moving.CurvilinearTrajectory()
                         if (warmUpLastInstant is None or instant >= warmUpLastInstant) and objNum in objects:
                             objects[objNum].timeInterval.last = instant
@@ -1181,7 +1190,7 @@
         obj = moving.MovingObject(num = int(numbers[0]), 
                                   timeInterval = moving.TimeInterval(firstFrameNum, lastFrameNum), 
                                   positions = moving.Trajectory([[float(numbers[6])],[float(numbers[7])]]), 
-                                  userType = int(numbers[10]))
+                                  userType = int(numbers[10]), nObjects = 1)
         obj.userType = int(numbers[10])
         obj.laneNums = [int(numbers[13])]
         obj.precedingVehicles = [int(numbers[14])] # lead vehicle (before)
--- a/trafficintelligence/tests/moving.txt	Wed Jul 04 15:37:04 2018 -0400
+++ b/trafficintelligence/tests/moving.txt	Wed Jul 04 16:06:23 2018 -0400
@@ -180,6 +180,11 @@
 True
 
 >>> o1 = MovingObject.generate(1, Point(-5.,0.), Point(1.,0.), TimeInterval(0,10))
+>>> o1.getNObjects() is None
+True
+>>> o1.setNObjects(1.1)
+>>> o1.setNObjects(0.5)
+Number of objects represented by object 1 must be greater or equal to 1 (0.5)
 >>> o2 = MovingObject.generate(2, Point(0.,-5.), Point(0.,1.), TimeInterval(0,10))
 >>> MovingObject.computePET(o1, o2, 0.1)
 (0.0, 5, 5)