comparison trafficintelligence/moving.py @ 1106:799ef82caa1a v0.2.4

added code to compute bounding rectangle around each user
author Nicolas Saunier <nicolas.saunier@polymtl.ca>
date Fri, 15 Mar 2019 15:58:37 -0400
parents 1e833fd8490d
children 6e8ab471ebd4
comparison
equal deleted inserted replaced
1105:e62c2f5e25e6 1106:799ef82caa1a
227 return Point(self.x-other.x, self.y-other.y) 227 return Point(self.x-other.x, self.y-other.y)
228 228
229 def __neg__(self): 229 def __neg__(self):
230 return Point(-self.x, -self.y) 230 return Point(-self.x, -self.y)
231 231
232 def __mul__(self, alpha):
233 'Warning, returns a new Point'
234 return Point(self.x*alpha, self.y*alpha)
235
236 def divide(self, alpha):
237 'Warning, returns a new Point'
238 return Point(self.x/alpha, self.y/alpha)
239
232 def __getitem__(self, i): 240 def __getitem__(self, i):
233 if i == 0: 241 if i == 0:
234 return self.x 242 return self.x
235 elif i == 1: 243 elif i == 1:
236 return self.y 244 return self.y
242 if clockwise: 250 if clockwise:
243 return Point(self.y, -self.x) 251 return Point(self.y, -self.x)
244 else: 252 else:
245 return Point(-self.y, self.x) 253 return Point(-self.y, self.x)
246 254
255 def normalize(self):
256 return self.divide(self.norm2())
257
247 def projectLocal(self, v, clockwise = True): 258 def projectLocal(self, v, clockwise = True):
248 'Projects point projected on v, v.orthogonal()' 259 'Projects point projected on v, v.orthogonal()'
249 e1 = v/v.norm2() 260 e1 = v.normalize()
250 e2 = e1.orthogonal(clockwise) 261 e2 = e1.orthogonal(clockwise)
251 return Point(Point.dot(self, e1), Point.dot(self, e2)) 262 return Point(Point.dot(self, e1), Point.dot(self, e2))
252 263
253 def rotate(self, theta): 264 def rotate(self, theta):
254 return Point(self.x*cos(theta)-self.y*sin(theta), self.x*sin(theta)+self.y*cos(theta)) 265 return Point(self.x*cos(theta)-self.y*sin(theta), self.x*sin(theta)+self.y*cos(theta))
255 266
256 def __mul__(self, alpha):
257 'Warning, returns a new Point'
258 return Point(self.x*alpha, self.y*alpha)
259
260 def divide(self, alpha):
261 'Warning, returns a new Point'
262 return Point(self.x/alpha, self.y/alpha)
263
264 def plot(self, options = 'o', **kwargs): 267 def plot(self, options = 'o', **kwargs):
265 plot([self.x], [self.y], options, **kwargs) 268 plot([self.x], [self.y], options, **kwargs)
266 269
267 @staticmethod 270 @staticmethod
268 def plotSegment(p1, p2, options = 'o', **kwargs): 271 def plotSegment(p1, p2, options = 'o', **kwargs):
351 @staticmethod 354 @staticmethod
352 def distanceNorm2(p1, p2): 355 def distanceNorm2(p1, p2):
353 return (p1-p2).norm2() 356 return (p1-p2).norm2()
354 357
355 @staticmethod 358 @staticmethod
356 def plotAll(points, **kwargs): 359 def plotAll(points, options = '', **kwargs):
357 from matplotlib.pyplot import scatter 360 plot([p.x for p in points],[p.y for p in points], options, **kwargs)
358 scatter([p.x for p in points],[p.y for p in points], **kwargs)
359 361
360 def similarOrientation(self, refDirection, cosineThreshold): 362 def similarOrientation(self, refDirection, cosineThreshold):
361 'Indicates whether the cosine of the vector and refDirection is smaller than cosineThreshold' 363 'Indicates whether the cosine of the vector and refDirection is smaller than cosineThreshold'
362 return Point.cosine(self, refDirection) >= cosineThreshold 364 return Point.cosine(self, refDirection) >= cosineThreshold
363 365
396 398
397 @staticmethod 399 @staticmethod
398 def agg(points, aggFunc = mean): 400 def agg(points, aggFunc = mean):
399 return Point(aggFunc([p.x for p in points]), aggFunc([p.y for p in points])) 401 return Point(aggFunc([p.x for p in points]), aggFunc([p.y for p in points]))
400 402
403 @staticmethod
404 def boundingRectangle(points, v):
405 '''Returns the bounding rectangle of the points, aligned on the vector v
406 A list of points is returned: front left, front right, rear right, rear left'''
407 e1 = v.normalize()
408 e2 = e1.orthogonal()
409 xCoords = []
410 yCoords = []
411 for p in points:
412 xCoords.append(Point.dot(e1, p))
413 yCoords.append(Point.dot(e2, p))
414 xmin = min(xCoords)
415 xmax = max(xCoords)
416 ymin = min(yCoords)
417 ymax = max(yCoords)
418 frontLeft = Point(xmax, ymin)
419 frontRight = Point(xmax, ymax)
420 rearLeft = Point(xmin, ymin)
421 rearRight = Point(xmin, ymax)
422 return [Point(Point.dot(e1, p), Point.dot(e2, p)) for p in [frontLeft, frontRight, rearRight, rearLeft]]
423
401 if shapelyAvailable: 424 if shapelyAvailable:
402 def pointsInPolygon(points, polygon): 425 def pointsInPolygon(points, polygon):
403 '''Optimized tests of a series of points within (Shapely) polygon (not prepared)''' 426 '''Optimized tests of a series of points within (Shapely) polygon (not prepared)'''
404 if type(polygon) == PreparedGeometry: 427 if type(polygon) == PreparedGeometry:
405 prepared_polygon = polygon 428 prepared_polygon = polygon
507 i += 1 530 i += 1
508 if i < len(alignment): 531 if i < len(alignment):
509 d = s - alignment.getCumulativeDistance(i-1) # distance on subsegment 532 d = s - alignment.getCumulativeDistance(i-1) # distance on subsegment
510 #Get difference vector and then snap 533 #Get difference vector and then snap
511 dv = alignment[i] - alignment[i-1] 534 dv = alignment[i] - alignment[i-1]
512 magnitude = dv.norm2() 535 #magnitude = dv.norm2()
513 normalizedV = dv.divide(magnitude) 536 normalizedV = dv.normalize()
514 #snapped = alignment[i-1] + normalizedV*d # snapped point coordinate along alignment 537 #snapped = alignment[i-1] + normalizedV*d # snapped point coordinate along alignment
515 # add offset finally 538 # add offset finally
516 orthoNormalizedV = normalizedV.orthogonal() 539 orthoNormalizedV = normalizedV.orthogonal()
517 return alignment[i-1] + normalizedV*d + orthoNormalizedV*y 540 return alignment[i-1] + normalizedV*d + orthoNormalizedV*y
518 else: 541 else:
1759 xj = array(fj.getXCoordinates()[inter.first-fj.getFirstInstant():int(fj.length())-(fj.getLastInstant()-inter.last)]) 1782 xj = array(fj.getXCoordinates()[inter.first-fj.getFirstInstant():int(fj.length())-(fj.getLastInstant()-inter.last)])
1760 yj = array(fj.getYCoordinates()[inter.first-fj.getFirstInstant():int(fj.length())-(fj.getLastInstant()-inter.last)]) 1783 yj = array(fj.getYCoordinates()[inter.first-fj.getFirstInstant():int(fj.length())-(fj.getLastInstant()-inter.last)])
1761 relativePositions[(i,j)] = Point(median(xj-xi), median(yj-yi)) 1784 relativePositions[(i,j)] = Point(median(xj-xi), median(yj-yi))
1762 relativePositions[(j,i)] = -relativePositions[(i,j)] 1785 relativePositions[(j,i)] = -relativePositions[(i,j)]
1763 1786
1787 def computeBoundingPolygon(self, instant):
1788 '''Returns a bounding box for the feature positions at instant
1789 bounding box format is a list of points (4 in this case for a rectangle)
1790
1791 TODO add method argument if using different methods/shapes'''
1792 if self.hasFeatures():
1793 positions = [f.getPositionAtInstant(instant) for f in self.getFeatures() if f.existsAtInstant(instant)]
1794 return Point.boundingRectangle(positions, self.getVelocityAtInstant(instant))
1795 else:
1796 print('Object {} has no features'.format(self.getNum()))
1797 return None
1798
1764 ### 1799 ###
1765 # User Type Classification 1800 # User Type Classification
1766 ### 1801 ###
1767 def classifyUserTypeSpeedMotorized(self, threshold, aggregationFunc = median, nInstantsIgnoredAtEnds = 0): 1802 def classifyUserTypeSpeedMotorized(self, threshold, aggregationFunc = median, nInstantsIgnoredAtEnds = 0):
1768 '''Classifies slow and fast road users 1803 '''Classifies slow and fast road users