示例#1
0
    def GetLocationsOrderedByProximity(self, maxSearchResults,
                                       maxDistanceMeters,
                                       LocationAllEntityAttributeDic,
                                       centerPt):
        """ Make a list of (EntityKeyName,DistanceMeters,GeoCell) sorted by DistanceMeters

            Limit the number of list entries to maxSearchResult and limit entries by
            MaxDistanceMeters. EntityKeyName and location (lattitude,longitude) are
            extracted from the supplied LocationAllEntityAttributeDic.
        """
        entityDistanceMeters = []
        for entityKeyName in LocationAllEntityAttributeDic:
            attributeDic = LocationAllEntityAttributeDic[entityKeyName]
            longitudeStr = attributeDic['longitude']
            lattitudeStr = attributeDic['lattitude']
            locationPt = float(lattitudeStr), float(longitudeStr)
            locationGpPoint = GpPoint(locationPt[0], locationPt[1])
            locationGpGridPoint = GpGridPoint()
            locationGpGridPoint.InitFromGpPoint(locationGpPoint, 16)
            locationGpCell = locationGpGridPoint.ToLongString()
            distanceInMeters = self.distanceMeters(locationPt, centerPt)
            if distanceInMeters <= maxDistanceMeters:
                tup = entityKeyName, distanceInMeters, locationGpCell
                entityDistanceMeters.append(tup)
        self.EntityDistanceMetersSorted = sorted(entityDistanceMeters,
                                                 key=self.GetDistance)

        if len(self.EntityDistanceMetersSorted) > maxSearchResults:
            self.EntityDistanceMetersSorted = self.EntityDistanceMetersSorted[
                0:maxSearchResults]
示例#2
0
    def _GetGridCellsWithinRadius(self):
        """ Create a dictionary of {GpGridCell:(nCornerPointsInBound,inBoundPointsWeight)} for top GpGridCell
            resolution.

        The weight is a measure of the closeness of contained points to the center point"""
        stepSize = MAXIMUM_RESOLUTION - self.MaxSearchResolution + 1
        self.maxResolutionSearchDic = {}
        # Iterate through GridPoints the bounding box
        for latInt in range(self.SWCornerGridPoint.LattitudeInt,self.NWCornerGridPoint.LattitudeInt + stepSize,\
                            stepSize):
            for lonInt in range (self.SWCornerGridPoint.LongitudeInt,self.SECornerGridPoint.LongitudeInt + stepSize,
                             stepSize):
                # Construct a GpGridCell at each GridPoint
                originPoint = GpGridPoint()
                originPoint.InitFromIntLatLon(latInt,lonInt,self.MaxSearchResolution)

                gridCell = GpGridCell()
                gridCell.InitFromGridPoint(originPoint)
                
                cellCornerPoints = gridCell.ListCornerPointsShort()
                nCornerPointsInBound = 0
                inBoundPointsWeight = 0.0
                for cell in cellCornerPoints:
                    if cell in self.gpGridPointsInBoundsDic:
                        nCornerPointsInBound += 1
                        inBoundPointsWeight += self.gpGridPointsInBoundsDic[cell]
                if nCornerPointsInBound > 0:
                    self.maxResolutionSearchDic[gridCell.ToShortString()] = \
                           CellSearchData(nCornerPointsInBound,inBoundPointsWeight)
 def ListChildCellsShort(self):
     """ Return a list of the 4 child cells in GpGridPointShortString format"""
     # Get the origin point of child cell that is co-located with the Origin Point
     parentResolution = self.Origin.Resolution
     if parentResolution == MAXIMUM_RESOLUTION:
         logging.debug("GpGridCell is at maximum resolution %d, so there are no child cells" %\
                          parentResolution)
         return []
     childOriginGridPoint = GpGridPoint()
     childOriginGridPoint.InitFromIntLatLon(self.Origin.LattitudeInt,self.Origin.LongitudeInt,\
                                            self.Origin.Resolution +1)
     # Create a GpGridCell at the child origin
     swChildGridCell = GpGridCell()
     swChildGridCell.InitFromGridPoint(childOriginGridPoint)
     # The 4 corner points of the SW child GridCell are the origins of the 4 child cells
     return swChildGridCell.ListCornerPointsShort()
示例#4
0
 def _GetGridPointsWithinRadius(self):
     """ Create a dictionary of GpGridPoints within distanceMeters from a center point.
     
     Scan through the GridPoints in the bounding box region. Add all in-bound points to the dictionary.
     Associate a weight with each GridPoint that is inversely proportional to its distance from the
     center point.
     """
     radiusMeters = self.SearchBoundaryMeters
     self.gpGridPointsInBoundsDic = {}
     stepSize = MAXIMUM_RESOLUTION - self.MaxSearchResolution + 1
     for latInt in range(self.SWCornerGridPoint.LattitudeInt,self.NWCornerGridPoint.LattitudeInt + stepSize, \
                         stepSize):
         for lonInt in range (self.SWCornerGridPoint.LongitudeInt,self.SECornerGridPoint.LongitudeInt + stepSize, \
                              stepSize):
             gridPoint = GpGridPoint()
             gridPoint.InitFromIntLatLon(latInt,lonInt,self.MaxSearchResolution)
             gpPoint = GpPoint(gridPoint.LattitudeFloat,gridPoint.LongitudeFloat)
             distanceMeters = GpMath.distance(self.CenterGpPoint,gpPoint)
             if distanceMeters <= radiusMeters:
                 weight = self._WeightGridPointByDistance(distanceMeters)
                 self.gpGridPointsInBoundsDic[gridPoint.ToShortString()] = weight
class GpGridCell():
    Origin = GpGridPoint()
    
    def InitFromGridPoint(self,gpGridPoint):
        self.Origin.InitFromIntLatLon(gpGridPoint.LattitudeInt,gpGridPoint.LongitudeInt,gpGridPoint.Resolution)

    def InitFromCoordinates(self, lattitude, longitude, resolution):
        self.Origin.InitFromCoordinates( lattitude, longitude, resolution)

    def InitFromShortCellString(self, cellShortString, resolution):
        self.Origin = GpGridPoint()
        self.Origin.InitFromShortString(cellShortString, resolution)
        
    def ToLongString(self):
        """ Return a long string representation of this GridCell.

        The cell is identified by the long string representation of its origin."""
        return self.Origin.ToLongString()

    def ToShortString(self):
        """ Return a short string representation of this GridCell.

        The cell is identified by the short string representation of its origin along with
        its resolution."""
        return self.Origin.ToShortString()

    def ListCornerPointsShort(self):
        """Return a list of the four corner points for this cell in the short string format.

        The points are identified by their short string representation"""
        cellList= []
        cellList.append(self.Origin.ToShortString())
        nwPoint = self.Origin.GetAdjacentPoint('N')
        cellList.append(nwPoint.ToShortString())
        nePoint = nwPoint.GetAdjacentPoint('E')
        cellList.append(nePoint.ToShortString())
        sePoint = nePoint.GetAdjacentPoint('S')
        cellList.append(sePoint.ToShortString())
        return cellList

    def ListChildCellsShort(self):
        """ Return a list of the 4 child cells in GpGridPointShortString format"""
        # Get the origin point of child cell that is co-located with the Origin Point
        parentResolution = self.Origin.Resolution
        if parentResolution == MAXIMUM_RESOLUTION:
            logging.debug("GpGridCell is at maximum resolution %d, so there are no child cells" %\
                             parentResolution)
            return []
        childOriginGridPoint = GpGridPoint()
        childOriginGridPoint.InitFromIntLatLon(self.Origin.LattitudeInt,self.Origin.LongitudeInt,\
                                               self.Origin.Resolution +1)
        # Create a GpGridCell at the child origin
        swChildGridCell = GpGridCell()
        swChildGridCell.InitFromGridPoint(childOriginGridPoint)
        # The 4 corner points of the SW child GridCell are the origins of the 4 child cells
        return swChildGridCell.ListCornerPointsShort()
示例#6
0
    def _GetBoundingBoxCells(self):
        """ Get three GpGridPoint corners of a Bounding Box for distanceMeters from a center point.

        The corner points are set to the MaxSearchResolution
        """
        centerGpPoint = self.CenterGpPoint
        degreesOffset = GpMath.distanceMetersToDegrees(centerGpPoint, self.SearchBoundaryMeters)
        # Get bounding corner points
        swCornerF = GpPoint(centerGpPoint.lat - degreesOffset.lat, \
                           centerGpPoint.lon - degreesOffset.lon)
        self.SWCornerGridPoint = GpGridPoint()
        self.SWCornerGridPoint.InitFromGpPoint(swCornerF, self.MaxSearchResolution)

        nwCornerF = GpPoint(centerGpPoint.lat + degreesOffset.lat, \
                           centerGpPoint.lon - degreesOffset.lon)
        self.NWCornerGridPoint = GpGridPoint()
        self.NWCornerGridPoint.InitFromGpPoint(nwCornerF,self.MaxSearchResolution)

        seCornerF = GpPoint(centerGpPoint.lat - degreesOffset.lat, \
                           centerGpPoint.lon + degreesOffset.lon)
        self.SECornerGridPoint = GpGridPoint()
        self.SECornerGridPoint.InitFromGpPoint(seCornerF,self.MaxSearchResolution)
 def InitFromShortCellString(self, cellShortString, resolution):
     self.Origin = GpGridPoint()
     self.Origin.InitFromShortString(cellShortString, resolution)
示例#8
0
class GpSearch:
    """ This class supports a proximity search for locations within a radius from a center point.

        The result for the search computations is a list of GpGridCells to use in a search query.
    """

    SearchBoundaryMeters = None
    MAX_SEARCH_GP_GRID_POINTS = 100000
    MaxSearchCellCount = 10
    # Dictionary of {GpGridCellShortString : CellSearchData} at MaxSearchResolution
    maxResolutionSearchDic = {}
    MaxSearchResolution =  MAXIMUM_RESOLUTION
    FinalSearchResolution = MAXIMUM_RESOLUTION

    # Dictionary of {resolution: {cellStringShort: [nChildGridCellsInBound, cumulativeWeightForCell]}}
    AllLevelCellSearchDataDic = {}
    # Dictionary of {cellStringLong: [nChildGridCellsInBound, cumulativeWeightForCell]}
    SearchCellDic = {}
    # A list of tuples (priority, GpGridCellsLongString), where priority is 0 to len(SearchCellList) - 1.
    # This list is sent to Appengine in search parameters
    SearchCellList = []

    def __init__(self):
        self.maxResolutionSearchDic = {}
        self.SearchCellDic = {}
        self.AllLevelCellSearchDataDic = {}
        self.SearchCellList = []

    
    def ComputeSearchListForMilesProximity(self,centerGpPoint, distanceMiles):
        distanceMeters = GpMath.milesToMeters(distanceMiles)
        self.ComputeSearchListForMetersProximity(centerGpPoint, distanceMeters)

    def ComputeSearchListForMetersProximity(self,centerGpPoint, distanceMeters):
        """ Compute a list of GpGridCells to use in a proximity search query.

            The final list is contained in SearchCellList[]. The cells in the search list are ordered
            by closeness of contained GpPoints to the Center Point.
        """
        self.SearchBoundaryMeters = distanceMeters
        self.CenterGpPoint = centerGpPoint
        self._GetBoundingBoxCells()
        self._LimitMaxSearchResolution()
        self._GetGridPointsWithinRadius()
        self._GetGridCellsWithinRadius()
        self._ReduceSearchCells()
        self._SplitSearchCellsToReduceSearchArea()
        self._PrioritizeCellSearchList()

    def _GetBoundingBoxCells(self):
        """ Get three GpGridPoint corners of a Bounding Box for distanceMeters from a center point.

        The corner points are set to the MaxSearchResolution
        """
        centerGpPoint = self.CenterGpPoint
        degreesOffset = GpMath.distanceMetersToDegrees(centerGpPoint, self.SearchBoundaryMeters)
        # Get bounding corner points
        swCornerF = GpPoint(centerGpPoint.lat - degreesOffset.lat, \
                           centerGpPoint.lon - degreesOffset.lon)
        self.SWCornerGridPoint = GpGridPoint()
        self.SWCornerGridPoint.InitFromGpPoint(swCornerF, self.MaxSearchResolution)

        nwCornerF = GpPoint(centerGpPoint.lat + degreesOffset.lat, \
                           centerGpPoint.lon - degreesOffset.lon)
        self.NWCornerGridPoint = GpGridPoint()
        self.NWCornerGridPoint.InitFromGpPoint(nwCornerF,self.MaxSearchResolution)

        seCornerF = GpPoint(centerGpPoint.lat - degreesOffset.lat, \
                           centerGpPoint.lon + degreesOffset.lon)
        self.SECornerGridPoint = GpGridPoint()
        self.SECornerGridPoint.InitFromGpPoint(seCornerF,self.MaxSearchResolution)


    def _LimitMaxSearchResolution(self):
        """ Limit the initial (maximum) search resolution so the number of GpGridPoints is < MAX_SEARCH_GP_GRID_POINTS.

        This limits the number of calculations to find the GpGridCell list for the search.
        """
        latCount = self.NWCornerGridPoint.LattitudeInt - self.SWCornerGridPoint.LattitudeInt
        lonCount = self.SWCornerGridPoint.LongitudeInt - self.SECornerGridPoint.LongitudeInt
        resolutionDecrease = 0
        maxResolutionDecrease = MAXIMUM_RESOLUTION - MINIMUM_RESOLUTION
        while latCount*lonCount > self.MAX_SEARCH_GP_GRID_POINTS:
            latCount  >>= 1
            lonCount  >>= 1
            resolutionDecrease += 1
            if resolutionDecrease > maxResolutionDecrease:
                break
        self.MaxSearchResolution = MAXIMUM_RESOLUTION - resolutionDecrease

    def _GetGridPointsWithinRadius(self):
        """ Create a dictionary of GpGridPoints within distanceMeters from a center point.
        
        Scan through the GridPoints in the bounding box region. Add all in-bound points to the dictionary.
        Associate a weight with each GridPoint that is inversely proportional to its distance from the
        center point.
        """
        radiusMeters = self.SearchBoundaryMeters
        self.gpGridPointsInBoundsDic = {}
        stepSize = MAXIMUM_RESOLUTION - self.MaxSearchResolution + 1
        for latInt in range(self.SWCornerGridPoint.LattitudeInt,self.NWCornerGridPoint.LattitudeInt + stepSize, \
                            stepSize):
            for lonInt in range (self.SWCornerGridPoint.LongitudeInt,self.SECornerGridPoint.LongitudeInt + stepSize, \
                                 stepSize):
                gridPoint = GpGridPoint()
                gridPoint.InitFromIntLatLon(latInt,lonInt,self.MaxSearchResolution)
                gpPoint = GpPoint(gridPoint.LattitudeFloat,gridPoint.LongitudeFloat)
                distanceMeters = GpMath.distance(self.CenterGpPoint,gpPoint)
                if distanceMeters <= radiusMeters:
                    weight = self._WeightGridPointByDistance(distanceMeters)
                    self.gpGridPointsInBoundsDic[gridPoint.ToShortString()] = weight

    def _WeightGridPointByDistance(self,distanceMeters):
        """ Create a GridPoint weight that is inversely proportional to its distance from the center point.

            This allows GridCells containing GridPoints close to the center point to be searched at a higher
            priority for a proximity query.
        """
        radiusMeters = self.SearchBoundaryMeters
        if distanceMeters > radiusMeters:
            weight = 0.0
        elif distanceMeters == 0.0:
            weight = MAXIMUM_GRID_POINT_WEIGHT
        else:
            weight = float(radiusMeters) / distanceMeters
            if weight > MAXIMUM_GRID_POINT_WEIGHT:
                weight = MAXIMUM_GRID_POINT_WEIGHT
        return weight
    

    def _GetGridCellsWithinRadius(self):
        """ Create a dictionary of {GpGridCell:(nCornerPointsInBound,inBoundPointsWeight)} for top GpGridCell
            resolution.

        The weight is a measure of the closeness of contained points to the center point"""
        stepSize = MAXIMUM_RESOLUTION - self.MaxSearchResolution + 1
        self.maxResolutionSearchDic = {}
        # Iterate through GridPoints the bounding box
        for latInt in range(self.SWCornerGridPoint.LattitudeInt,self.NWCornerGridPoint.LattitudeInt + stepSize,\
                            stepSize):
            for lonInt in range (self.SWCornerGridPoint.LongitudeInt,self.SECornerGridPoint.LongitudeInt + stepSize,
                             stepSize):
                # Construct a GpGridCell at each GridPoint
                originPoint = GpGridPoint()
                originPoint.InitFromIntLatLon(latInt,lonInt,self.MaxSearchResolution)

                gridCell = GpGridCell()
                gridCell.InitFromGridPoint(originPoint)
                
                cellCornerPoints = gridCell.ListCornerPointsShort()
                nCornerPointsInBound = 0
                inBoundPointsWeight = 0.0
                for cell in cellCornerPoints:
                    if cell in self.gpGridPointsInBoundsDic:
                        nCornerPointsInBound += 1
                        inBoundPointsWeight += self.gpGridPointsInBoundsDic[cell]
                if nCornerPointsInBound > 0:
                    self.maxResolutionSearchDic[gridCell.ToShortString()] = \
                           CellSearchData(nCornerPointsInBound,inBoundPointsWeight)

    def _ReduceSearchCells(self):
        """ Successively reduce the resolution until the number of GpGrid cells in bound is <= MaxSearchCellCount

        Add GpGridSells at each resolution to a dictionary called AllLevelCellSearchDataDic
        AllLevelCellSearchDataDic - contains {resolution: {GpGridCellShortString: [nChildCellsInBound,PerCentInBound]}
        """
        # Initialize the search data dictionary
        self.AllLevelCellSearchDataDic= {self.MaxSearchResolution : self.maxResolutionSearchDic}

        nSearchCells = len(self.maxResolutionSearchDic)
        searchLevelDic = self.maxResolutionSearchDic

        currentSearchResolution = self.MaxSearchResolution
        self.FinalSearchResolution = currentSearchResolution

        while nSearchCells > self.MaxSearchCellCount:
            if currentSearchResolution == MINIMUM_RESOLUTION:
                break
            # Build a parent search dictionary (at next lower level of resolution)
            parentSearchLevelDic = {}
            for gridCellShortStr in searchLevelDic:
                parentCell = GetParentShortGridCellString(gridCellShortStr,currentSearchResolution)
                childCellData = searchLevelDic[gridCellShortStr]

                if parentCell in parentSearchLevelDic:
                    parentCellData = parentSearchLevelDic[parentCell]
                    # Accumulate proximity weights from child cells
                    if childCellData.nChildCellsInBounds > 0:
                        parentCellData.nChildCellsInBounds += 1
                    # Accumulate proximity weights from child cells
                    parentCellData.ProximityWeight += childCellData.ProximityWeight

                else:
                    if childCellData.nChildCellsInBounds > 0:
                        parentSearchLevelDic[parentCell] = CellSearchData(1, childCellData.ProximityWeight)
                    else:
                        parentSearchLevelDic[parentCell] = CellSearchData(0, 0.0)

            nSearchCells = len(parentSearchLevelDic)
            searchLevelDic = parentSearchLevelDic
            currentSearchResolution -= 1
            self.AllLevelCellSearchDataDic[currentSearchResolution] =  parentSearchLevelDic
            self.FinalSearchResolution = currentSearchResolution

        # Create dictionary at final search resolution of {GpCellLongString: CellSearchData}
        self.FinalLevelLongStringSearchDic = {}
        finalLevelDic = self.AllLevelCellSearchDataDic[self.FinalSearchResolution]
        for cell in finalLevelDic:
            cellLong =  GpGridCellShortToLongString(cell,self.FinalSearchResolution)
            self.FinalLevelLongStringSearchDic[cellLong] = finalLevelDic[cell]


    def _SplitSearchCellsToReduceSearchArea(self):
        """ Find GpGridCells in the search list that can be split into higher resolution cells.

        If any GpGridCells in the search list have only 1 child cell that is in bounds, then replace the
        parent cell with the in-bounds child cell. Iterate up the resolution chain until a cell with more
        than one in-bounds child cell is found or the top of the tree is reached.
        """
        # Do a deep copy to save the single level results
        self.MultipleLevelSearchDic = {}
        for cell in self.FinalLevelLongStringSearchDic:
            self.MultipleLevelSearchDic[cell] = self.FinalLevelLongStringSearchDic[cell]
        hasSingleInBoundsChildCells = True
        while hasSingleInBoundsChildCells:
            hasSingleInBoundsChildCells = False
            for cell in self.MultipleLevelSearchDic:
                resolution = GetGridPointResolution(cell)
                # Check to see if top of search tree has been reached
                if resolution ==  self.MaxSearchResolution:
                    break
                searchData =  self.MultipleLevelSearchDic[cell]
                if searchData.nChildCellsInBounds == 1:
                    hasSingleInBoundsChildCells = True
                    self._SplitCell(cell)

        return

    def _SplitCell(self,GpCellLongString):
        # Delete the cell entry from the dictionary
        del self.MultipleLevelSearchDic[GpCellLongString]
        # Get the 4 child cells
        ResolutionAndGpCellShort = GpGridCellLongToShortString(GpCellLongString)
        parentCell = GpGridCell()
        parentCell.InitFromShortCellString(ResolutionAndGpCellShort[1],ResolutionAndGpCellShort[0])
        childCellList = parentCell.ListChildCellsShort()
        childResolution = ResolutionAndGpCellShort[0] + 1
        # Get the search data dictionary at the resolution of the child cells
        childLevelSearchDic = self.AllLevelCellSearchDataDic[childResolution]
        # Check for the cell entry in the All Level Search Data Dic
        for cell in childCellList:
            if cell in childLevelSearchDic:
                cellData = childLevelSearchDic[cell]
                if cellData.nChildCellsInBounds > 0:
                    # Add this cell to the Multiple Level Search Dictionary
                    longCellString = GpGridCellShortToLongString(cell, childResolution)
                    self.MultipleLevelSearchDic[longCellString] = cellData

    def _PrioritizeCellSearchList(self):
        """ Create a list of search geoCells in order of priority based on proximity weights."""

        CellAndWeight = []
        for cell in self.MultipleLevelSearchDic:
            cellSearchData = self.MultipleLevelSearchDic[cell]
            cellAndWeight = cell, cellSearchData.ProximityWeight
            CellAndWeight.append(cellAndWeight)
        sortTuple = SortTupleList(1,True)
        CellAndWeightSorted = sortTuple.doSort(CellAndWeight)
        order = 0
        for cell in CellAndWeightSorted:
            orderAndCell = order,cell[0]
            self.SearchCellList.append(orderAndCell)
            order += 1