Mercurial > hg > nsaunier > traffic-intelligence
comparison python/moving.py @ 290:df58d361f19e
refactoring of Interval and TimeInterval using class methods (intersection, union)
| author | Nicolas Saunier <nicolas.saunier@polymtl.ca> |
|---|---|
| date | Tue, 29 Jan 2013 18:23:47 -0500 |
| parents | e0d41c7f53d4 |
| children | d280b881e860 |
comparison
equal
deleted
inserted
replaced
| 289:e56c34c1ebac | 290:df58d361f19e |
|---|---|
| 8 | 8 |
| 9 #from shapely.geometry import Polygon | 9 #from shapely.geometry import Polygon |
| 10 | 10 |
| 11 __metaclass__ = type | 11 __metaclass__ = type |
| 12 | 12 |
| 13 class Interval: | 13 class Interval(object): |
| 14 '''Generic interval: a subset of real numbers (not iterable)''' | 14 '''Generic interval: a subset of real numbers (not iterable)''' |
| 15 def __init__(self, first=0, last=-1, revert = False): | 15 def __init__(self, first=0, last=-1, revert = False): |
| 16 if revert and last<first: | 16 if revert and last<first: |
| 17 self.first=last | 17 self.first=last |
| 18 self.last=first | 18 self.last=first |
| 44 | 44 |
| 45 def inside(self, interval2): | 45 def inside(self, interval2): |
| 46 '''Indicates if the temporal interval of self is comprised in interval2''' | 46 '''Indicates if the temporal interval of self is comprised in interval2''' |
| 47 return (self.first >= interval2.first) and (self.last <= interval2.last) | 47 return (self.first >= interval2.first) and (self.last <= interval2.last) |
| 48 | 48 |
| 49 def union(self, interval2): | 49 @classmethod |
| 50 def union(cls, interval1, interval2): | |
| 50 '''Smallest interval comprising self and interval2''' | 51 '''Smallest interval comprising self and interval2''' |
| 51 return Interval(min(self.first, interval2.first), max(self.last, interval2.last)) | 52 return cls(min(interval1.first, interval2.first), max(interval2.last, interval2.last)) |
| 52 | 53 |
| 53 def intersection(self, interval2): | 54 @classmethod |
| 55 def intersection(cls, interval1, interval2): | |
| 54 '''Largest interval comprised in both self and interval2''' | 56 '''Largest interval comprised in both self and interval2''' |
| 55 return Interval(max(self.first, interval2.first), min(self.last, interval2.last)) | 57 return cls(max(interval1.first, interval2.first), min(interval1.last, interval2.last)) |
| 56 | 58 |
| 57 def distance(self, interval2): | 59 def distance(self, interval2): |
| 58 if not self.intersection(interval2).empty(): | 60 if not Interval.intersection(self, interval2).empty(): |
| 59 return 0 | 61 return 0 |
| 60 elif self.first > interval2.last: | 62 elif self.first > interval2.last: |
| 61 return self.first - interval2.last | 63 return self.first - interval2.last |
| 62 elif self.last < interval2.first: | 64 elif self.last < interval2.first: |
| 63 return interval2.first - self.last | 65 return interval2.first - self.last |
| 67 | 69 |
| 68 def unionIntervals(intervals): | 70 def unionIntervals(intervals): |
| 69 'returns the smallest interval containing all intervals' | 71 'returns the smallest interval containing all intervals' |
| 70 inter = intervals[0] | 72 inter = intervals[0] |
| 71 for i in intervals[1:]: | 73 for i in intervals[1:]: |
| 72 inter = inter.union(i) | 74 inter = Interval.union(inter, i) |
| 73 return inter | 75 return inter |
| 74 | 76 |
| 75 | 77 |
| 76 class TimeInterval(Interval): | 78 class TimeInterval(Interval): |
| 77 '''Temporal interval: set of instants at fixed time step, between first and last, included | 79 '''Temporal interval: set of instants at fixed time step, between first and last, included |
| 78 | 80 |
| 79 For example: based on frame numbers (hence the modified length method) | 81 For example: based on frame numbers (hence the modified length method) |
| 80 It may be modified directly by setting first and last''' | 82 It may be modified directly by setting first and last''' |
| 81 | 83 |
| 82 def __init__(self, first=0, last=-1): | 84 def __init__(self, first=0, last=-1): |
| 83 Interval.__init__(self, first, last, False) | 85 super(TimeInterval, self).__init__(first, last, False) |
| 86 | |
| 87 @staticmethod | |
| 88 def fromInterval(inter): | |
| 89 return TimeInterval(inter.first, inter.last) | |
| 84 | 90 |
| 85 def __getitem__(self, i): | 91 def __getitem__(self, i): |
| 86 if not self.empty(): | 92 if not self.empty(): |
| 87 return self.first+i | 93 return self.first+i |
| 88 | 94 |
| 105 # '''Class for a polygon bounding a set of points | 111 # '''Class for a polygon bounding a set of points |
| 106 # with methods to create intersection, unions... | 112 # with methods to create intersection, unions... |
| 107 # ''' | 113 # ''' |
| 108 # We will use the polygon class of Shapely | 114 # We will use the polygon class of Shapely |
| 109 | 115 |
| 110 class STObject: | 116 class STObject(object): |
| 111 '''Class for spatio-temporal object, i.e. with temporal and spatial existence | 117 '''Class for spatio-temporal object, i.e. with temporal and spatial existence |
| 112 (time interval and bounding polygon for positions (e.g. rectangle)). | 118 (time interval and bounding polygon for positions (e.g. rectangle)). |
| 113 | 119 |
| 114 It may not mean that the object is defined | 120 It may not mean that the object is defined |
| 115 for all time instants within the time interval''' | 121 for all time instants within the time interval''' |
| 136 | 142 |
| 137 def existsAtInstant(self, t): | 143 def existsAtInstant(self, t): |
| 138 return self.timeInterval.contains(t) | 144 return self.timeInterval.contains(t) |
| 139 | 145 |
| 140 def commonTimeInterval(self, obj2): | 146 def commonTimeInterval(self, obj2): |
| 141 return self.getTimeInterval().intersection(obj2.getTimeInterval()) | 147 return TimeInterval.intersection(self.getTimeInterval(), obj2.getTimeInterval()) |
| 142 | 148 |
| 143 class Point: | 149 class Point(object): |
| 144 def __init__(self, x, y): | 150 def __init__(self, x, y): |
| 145 self.x = x | 151 self.x = x |
| 146 self.y = y | 152 self.y = y |
| 147 | 153 |
| 148 def __str__(self): | 154 def __str__(self): |
| 233 @staticmethod | 239 @staticmethod |
| 234 def plotAll(points, color='r'): | 240 def plotAll(points, color='r'): |
| 235 from matplotlib.pyplot import scatter | 241 from matplotlib.pyplot import scatter |
| 236 scatter([p.x for p in points],[p.y for p in points], c=color) | 242 scatter([p.x for p in points],[p.y for p in points], c=color) |
| 237 | 243 |
| 238 class NormAngle: | 244 class NormAngle(object): |
| 239 '''Alternate encoding of a point, by its norm and orientation''' | 245 '''Alternate encoding of a point, by its norm and orientation''' |
| 240 | 246 |
| 241 def __init__(self, norm, angle): | 247 def __init__(self, norm, angle): |
| 242 self.norm = norm | 248 self.norm = norm |
| 243 self.angle = angle | 249 self.angle = angle |
| 272 predictedSpeedTheta.norm = min(predictedSpeedTheta.norm, maxSpeed) | 278 predictedSpeedTheta.norm = min(predictedSpeedTheta.norm, maxSpeed) |
| 273 predictedPosition = position+predictedSpeedTheta.getPoint() | 279 predictedPosition = position+predictedSpeedTheta.getPoint() |
| 274 return predictedPosition, predictedSpeedTheta | 280 return predictedPosition, predictedSpeedTheta |
| 275 | 281 |
| 276 | 282 |
| 277 class FlowVector: | 283 class FlowVector(object): |
| 278 '''Class to represent 4-D flow vectors, | 284 '''Class to represent 4-D flow vectors, |
| 279 ie a position and a velocity''' | 285 ie a position and a velocity''' |
| 280 def __init__(self, position, velocity): | 286 def __init__(self, position, velocity): |
| 281 'position and velocity should be Point instances' | 287 'position and velocity should be Point instances' |
| 282 self.position = position | 288 self.position = position |
| 300 def segmentIntersection(p1, p2, p3, p4): | 306 def segmentIntersection(p1, p2, p3, p4): |
| 301 '''Returns the intersecting point of the segments [p1, p2] and [p3, p4], None otherwise''' | 307 '''Returns the intersecting point of the segments [p1, p2] and [p3, p4], None otherwise''' |
| 302 from numpy import matrix | 308 from numpy import matrix |
| 303 from numpy.linalg import linalg, det | 309 from numpy.linalg import linalg, det |
| 304 | 310 |
| 305 if (Interval(p1.x,p2.x, True).intersection(Interval(p3.x,p4.x, True)).empty() | 311 if (Interval.intersection(Interval(p1.x,p2.x,True), Interval(p3.x,p4.x,True)).empty()) or (Interval.intersection(Interval(p1.y,p2.y,True), Interval(p3.y,p4.y,True)).empty()): |
| 306 or Interval(p1.y,p2.y, True).intersection(Interval(p3.y,p4.y, True)).empty()): | |
| 307 return None | 312 return None |
| 308 else: | 313 else: |
| 309 dp1 = p2-p1#[s1[0][1]-s1[0][0], s1[1][1]-s1[1][0]] | 314 dp1 = p2-p1#[s1[0][1]-s1[0][0], s1[1][1]-s1[1][0]] |
| 310 dp2 = p4-p3#[s2[0][1]-s2[0][0], s2[1][1]-s2[1][0]] | 315 dp2 = p4-p3#[s2[0][1]-s2[0][0], s2[1][1]-s2[1][0]] |
| 311 | 316 |
| 326 else: | 331 else: |
| 327 return None | 332 return None |
| 328 | 333 |
| 329 # TODO: implement a better algorithm for intersections of sets of segments http://en.wikipedia.org/wiki/Line_segment_intersection | 334 # TODO: implement a better algorithm for intersections of sets of segments http://en.wikipedia.org/wiki/Line_segment_intersection |
| 330 | 335 |
| 331 class Trajectory: | 336 class Trajectory(object): |
| 332 '''Class for trajectories: temporal sequence of positions | 337 '''Class for trajectories: temporal sequence of positions |
| 333 | 338 |
| 334 The class is iterable''' | 339 The class is iterable''' |
| 335 | 340 |
| 336 def __init__(self, positions=None): | 341 def __init__(self, positions=None): |
| 529 '''Class for moving objects: a spatio-temporal object | 534 '''Class for moving objects: a spatio-temporal object |
| 530 with a trajectory and a geometry (constant volume over time) and a usertype (e.g. road user) | 535 with a trajectory and a geometry (constant volume over time) and a usertype (e.g. road user) |
| 531 ''' | 536 ''' |
| 532 | 537 |
| 533 def __init__(self, num = None, timeInterval = None, positions = None, geometry = None, userType = None): | 538 def __init__(self, num = None, timeInterval = None, positions = None, geometry = None, userType = None): |
| 534 STObject.__init__(self, num, timeInterval) | 539 super(MovingObject, self).__init__(num, timeInterval) |
| 535 self.positions = positions | 540 self.positions = positions |
| 536 self.geometry = geometry | 541 self.geometry = geometry |
| 537 self.userType = userType | 542 self.userType = userType |
| 538 # compute bounding polygon from trajectory | 543 # compute bounding polygon from trajectory |
| 539 | 544 |
| 540 def getObjectInTimeInterval(self, inter): | 545 def getObjectInTimeInterval(self, inter): |
| 541 '''Returns a new object extracted from self, | 546 '''Returns a new object extracted from self, |
| 542 restricted to time interval inter''' | 547 restricted to time interval inter''' |
| 543 intersection = inter.intersection(self.getTimeInterval()) | 548 intersection = TimeInterval.intersection(inter, self.getTimeInterval()) |
| 544 if not intersection.empty(): | 549 if not intersection.empty(): |
| 545 trajectoryInterval = TimeInterval(intersection.first-self.getFirstInstant(), intersection.last-self.getFirstInstant()) | 550 trajectoryInterval = TimeInterval(intersection.first-self.getFirstInstant(), intersection.last-self.getFirstInstant()) |
| 546 obj = MovingObject(self.num, intersection, self.positions.getTrajectoryInInterval(trajectoryInterval), self.geometry, self.userType) | 551 obj = MovingObject(self.num, intersection, self.positions.getTrajectoryInInterval(trajectoryInterval), self.geometry, self.userType) |
| 547 if self.velocities: | 552 if self.velocities: |
| 548 obj.velocities = self.velocities.getTrajectoryInInterval(trajectoryInterval) | 553 obj.velocities = self.velocities.getTrajectoryInInterval(trajectoryInterval) |
