def findPointsOnLinks(self, pointX, pointY, radius, primaryRadius, secondaryRadius, prevPoints, limitClosestPoints = sys.maxint): """ findPointsOnLinks searches through the graph and finds all PointOnLinks that are within the radius. Then, eligible links are proposed primaryRadius distance around the GTFS point, or secondaryRadius distance from the previous VISTA points. Returns an empty list if none are found. This corresponds with algorithm "FindPointsOnLinks" in Figure 1 of Perrine, et al. 2015. @type pointX: float @type pointY: float @type radius: float @type primaryRadius: float @type secondaryRadius: float @type prevPoints: list<PointOnLink> @type limitClosestPoints: int @rtype list<PointOnLink> """ # TODO: This brute-force implementation can be more efficient with quad trees, etc. rather than # scanning through all elements. radiusSq = radius ** 2 primaryRadiusSq = primaryRadius ** 2 secondaryRadiusSq = secondaryRadius ** 2 retSet = set() # Find perpendicular and non-perpendicular PointOnLinks that are within radius. for link in self.linkMap.values(): "@type link: graph.GraphLink" (distSq, linkDist, perpendicular) = linear.pointDistSq(pointX, pointY, link.origNode.coordX, link.origNode.coordY, link.destNode.coordX, link.destNode.coordY, link.distance) if distSq <= radiusSq: pointOnLink = PointOnLink(link, linkDist, not perpendicular, math.sqrt(distSq)) # We are within the initial search radius. Are we then within the primary radius? if distSq <= primaryRadiusSq: # Yes, easy. Add to the list: retSet.add(pointOnLink) else: # Check to see if the point is close to a previous point: for prevPoint in prevPoints: "@type prevPoint: PointOnLink" distSq = linear.getNormSq(pointOnLink.pointX, pointOnLink.pointY, prevPoint.pointX, prevPoint.pointY) if (distSq < secondaryRadiusSq): # We have a winner: retSet.add(pointOnLink) break ret = list(retSet) # TODO: If there is a nonperpendicular link and distance = 0, and there also exists in the set a link # that leads to the first link's parent node, then get rid of that first link. # Keep limited number of closest values ret.sort(key = operator.attrgetter('refDist')) return ret[0:limitClosestPoints]