Mercurial Hosting > 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) |