Mercurial > hg > nsaunier > traffic-intelligence
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 |
