diff trafficintelligence/moving.py @ 1177:aa88acf06876

rewrote object concatenation method, cleaner
author Nicolas Saunier <nicolas.saunier@polymtl.ca>
date Thu, 24 Mar 2022 16:07:51 -0400
parents b55adb13f262
children 2039df59c47b
line wrap: on
line diff
--- a/trafficintelligence/moving.py	Thu Feb 17 10:55:11 2022 -0500
+++ b/trafficintelligence/moving.py	Thu Mar 24 16:07:51 2022 -0400
@@ -750,8 +750,8 @@
 
     def append(self,other):
         '''adds positions of other to the trajectory (in-place modification)'''
-        for p in other:
-            self.addPosition(p)
+        for i in range(2):
+            self.positions[i] += other.positions[i]
 
     def setPositionXY(self, i, x, y):
         if i < self.__len__():
@@ -767,7 +767,7 @@
 
     def addPosition(self, p):
         self.addPositionXY(p.x, p.y)
-
+        
     def duplicateLastPosition(self):
         self.positions[0].append(self.positions[0][-1])
         self.positions[1].append(self.positions[1][-1])
@@ -1174,6 +1174,10 @@
         else:
             return None
 
+    def append(self, other):
+        Trajectory.append(self, other)
+        self.lanes.append(other.getLanes())
+        
     def addPositionSYL(self, s, y, lane = None):
         self.addPositionXY(s,y)
         self.lanes.append(lane)
@@ -1312,59 +1316,61 @@
         inter, self.positions, self.velocities = MovingObject.aggregateTrajectories(self.features, self.getTimeInterval())
 
     @staticmethod
-    def concatenate(obj1, obj2, num = None, newFeatureNum = None, minFeatureLength = 5):
+    def concatenate(obj1, obj2, num = None, newFeatureNum = None):
         '''Concatenates two objects, whether overlapping temporally or not
 
-        Positions will be recomputed features are merged
-        Otherwise, only featureNumbers and/or features will be merged
-        minFeatureLength enforces a minimum length to avoid small features
-        (and smaller velocities that are not saved)'''
+        Positions will be recomputed if features are merged
+        Otherwise, only featureNumbers and/or features will be merged'''
         if num is None:
             newNum = obj1.getNum()
         else:
             newNum = num
         commonTimeInterval = obj1.commonTimeInterval(obj2)
-        if commonTimeInterval.empty():
-            #print('The two objects\' time intervals do not overlap: obj1 {} and obj2 {}'.format(obj1.getTimeInterval(), obj2.getTimeInterval()))
-            emptyInterval = TimeInterval(min(obj1.getLastInstant(),obj2.getLastInstant()), max(obj1.getFirstInstant(),obj2.getFirstInstant()))
-            if obj1.existsAtInstant(emptyInterval.last):
-                firstObject = obj2
-                secondObject = obj1
+        emptyInterval = TimeInterval(min(obj1.getLastInstant(),obj2.getLastInstant()), max(obj1.getFirstInstant(),obj2.getFirstInstant()))
+        if commonTimeInterval.empty() and emptyInterval.length() >= 3:
+            if newFeatureNum is None:
+                print('Not merging objects {} and {}, missing new feature number'.format(obj1.getNum(),obj2.getNum()))
+                return None, None
             else:
-                firstObject = obj1
-                secondObject = obj2
-            v = (secondObject.getPositionAtInstant(emptyInterval.last)-firstObject.getPositionAtInstant(emptyInterval.first)).divide(emptyInterval.length()-1)
-            positions = copy.deepcopy(firstObject.getPositions())
-            velocities = copy.deepcopy(firstObject.getPositions())
-            featurePositions = Trajectory()
-            featureVelocities = Trajectory()
-            p = firstObject.getPositionAtInstant(emptyInterval.first)+v
-            for t in range(emptyInterval.first+1, emptyInterval.last+1):
-            	positions.addPosition(p)
-            	velocities.addPosition(v)
-            	featurePositions.addPosition(p)
-            	featureVelocities.addPosition(v)
-            	p=p+v
-            for t in secondObject.getTimeInterval():
-                p = secondObject.getPositionAtInstant(t)
-                v = secondObject.getVelocityAtInstant(t)
-                positions.addPosition(p)
-                velocities.addPosition(v)
-                if featurePositions.length() < minFeatureLength:
+                if obj1.existsAtInstant(emptyInterval.last):
+                    firstObject = obj2
+                    secondObject = obj1
+                else:
+                    firstObject = obj1
+                    secondObject = obj2
+                v = (secondObject.getPositionAtInstant(emptyInterval.last)-firstObject.getPositionAtInstant(emptyInterval.first)).divide(emptyInterval.length()-1)
+                positions = copy.deepcopy(firstObject.getPositions())
+                velocities = copy.deepcopy(firstObject.getPositions())
+                featurePositions = Trajectory()
+                featureVelocities = Trajectory()
+                p = firstObject.getPositionAtInstant(emptyInterval.first)
+                # init new feature with position at last instant of 1st obj
+                featurePositions.addPosition(p)
+                featureVelocities.addPosition(v)
+                for t in range(emptyInterval.first+1, emptyInterval.last):
+                    p=p+v
+                    positions.addPosition(p)
+                    velocities.addPosition(v)
                     featurePositions.addPosition(p)
                     featureVelocities.addPosition(v)
-            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:
+                # last position to feature
+                p = secondObject.getPositionAtInstant(emptyInterval.last)
+                v = secondObject.getVelocityAtInstant(emptyInterval.last)
+                featurePositions.addPosition(p)
+                featureVelocities.addPosition(v)
+                # copy second trajectory
+                positions.append(secondObject.getPositions())
+                velocities.append(secondObject.getVelocities())
+                newObject = MovingObject(newNum, TimeInterval(firstObject.getFirstInstant(), secondObject.getLastInstant()), positions, velocities, nObjects = 1)
+                newFeature = MovingObject(newFeatureNum, emptyInterval, featurePositions, featureVelocities)
+                if hasattr(obj1, 'featureNumbers') and hasattr(obj2, 'featureNumbers'):
                     newObject.featureNumbers = obj1.featureNumbers+obj2.featureNumbers+[newFeatureNum]
-                else:
-                    print('Issue, new created feature has no num id')
-            if obj1.hasFeatures() and obj2.hasFeatures():
-                newObject.features = obj1.getFeatures()+obj2.getFeatures()+[MovingObject(newFeatureNum, TimeInterval(emptyInterval.first+1, emptyInterval.first+featurePositions.length()), featurePositions, featureVelocities)]
-                newObject.updatePositions()
+                if obj1.hasFeatures() and obj2.hasFeatures():
+                    newObject.features = obj1.getFeatures()+obj2.getFeatures()+[newFeature]
         else: # time intervals overlap
             newTimeInterval = TimeInterval.union(obj1.getTimeInterval(), obj2.getTimeInterval())
             newObject = MovingObject(newNum, newTimeInterval, nObjects = 1) # hypothesis is that it's the same object being reunited
+            newFeature = None
             if hasattr(obj1, 'featureNumbers') and hasattr(obj2, 'featureNumbers'):
                 newObject.featureNumbers = obj1.featureNumbers+obj2.featureNumbers
             if obj1.hasFeatures() and obj2.hasFeatures():
@@ -1376,7 +1382,7 @@
         if obj1.getUserType() != obj2.getUserType():
             print('The two moving objects have different user types: obj1 {} obj2 {}'.format(userTypeNames[obj1.getUserType()], userTypeNames[obj2.getUserType()]))
         newObject.setUserType(obj1.getUserType())
-        return newObject
+        return newObject, newFeature
 
     def getObjectInTimeInterval(self, inter):
         '''Returns a new object extracted from self,