protected function lngLatToPixels($lngLatPoints)
 {
     GoogleMapUtility::$TILE_SIZE = $this->tileSize;
     // points contain simple array of x,y,x,y,...
     $pointlist = array();
     $pointcount = 0;
     foreach ($lngLatPoints as $coords) {
         $lng = $coords[0];
         $lat = $coords[1];
         $relativePixelPoint = GoogleMapUtility::toZoomedPixelCoords($lat, $lng, $this->zoom);
         $pointlist[] = $absolutePixelX = $relativePixelPoint->x - $this->tileSize * $this->pixelX + $this->offsetX;
         $pointlist[] = $absolutePixelY = $relativePixelPoint->y - $this->tileSize * $this->pixelY + $this->offsetY;
         $pointcount++;
     }
     return $pointlist;
 }
 public static function toZoomedPixelCoords($lat, $lng, $zoom)
 {
     $normalised = GoogleMapUtility::toNormalisedMercatorCoords(GoogleMapUtility::toMercatorCoords($lat, $lng));
     $scale = (1 << $zoom) * GoogleMapUtility::$TILE_SIZE;
     return new GoogleMapPoint((int) ($normalised->x * $scale), (int) ($normalised->y * $scale));
 }
 /**
  * Uses {@link GoogleMapUtility} to convert a bounday box in WGS84 coordinates
  * to the tiles covered by this boundary. Stores those tiles as a unique
  * reference in the database as new {@link TileRenderQueue} objects who
  * can be rendered by the {@link TileRenderQueue_Controller}.
  * Note: This method just queues requests, doesn't render tiles itself.
  * 
  * In case you're also generating tiles "on the fly" by browser requests,
  * make sure to use the same {@link TileRenderer} instance or conventions
  * in the {@link $renderer} parameter. Otherwise you might cache tiles
  * at a different location, or with different extensions.
  * 
  * Example class MyShape
  * <example>
  * class MyShape extends DataObject {
  * static $db = array(
  * 	'MyPolygon' => 'Polygon'
  * );
  * }
  * </example>
  * <example>
  * function populateQueue() {
  * 	$query = singleton('MyShape')->extendedSQL();
  * 	$query->select = array(
  * 		'`MyShape`.`ID`',
  * 		'ASTEXT(ENVELOPE(`MyShape`.`MyPolygon`)) AS MyPolygonMBR'
  * 	);
  * 	$shapes = $query->execute();
  * 	
  * 	foreach($shapes as $shape) {
  * 		$poly = DBField::create('GeoPolygon', $shape['MyPolygonMBR']);
  * 		
  * 		// first and second-last coordinates of the ring can be assumed
  * 		// to be the min and max coordinates in this specific geopoly
  * 		$rings = $poly->getRings();
  * 		$mbrArr = $rings[0];
  * 		$lat = $mbrArr[0][1];
  * 		$lng = $mbrArr[0][0];
  * 		$maxLat = $mbrArr[2][1];
  * 		$maxLng = $mbrArr[2][0];
  * 
  * 		// add all necessary tiles for this network and bounds to the queue
  * 		TileRenderQueue::create_by_boundary($renderer, $lat, $lng, $maxLat, $maxLng);
  * 		unset($poly);
  * 	}
  * }
  * </example>
  * 
  * @param TileRenderer $renderer Used to determine the URL format and folder structure
  * @param float $lat
  * @param float $lng
  * @param float $maxLat
  * @param float $maxLng
  * @param int $minZoom
  * @param int $maxZoom 
  * @return array Numeric array of tile urls relative to the cache folder, e.g. array('42/34234-23423-17.gif','42/34234-23424-17.gif');
  */
 static function create_by_boundary($renderer, $lat, $lng, $maxLat, $maxLng, $minZoom = null, $maxZoom = null)
 {
     // Defaults from static variables
     if ($minZoom == null) {
         $minZoom = self::$min_zoom;
     }
     if ($maxZoom == null) {
         $maxZoom = self::$max_zoom;
     }
     $urls = array();
     // for each zoom level
     foreach (range($minZoom, $maxZoom) as $zoom) {
         $minPointMeters = GoogleMapUtility::latLonToMeters($lat, $lng);
         $minPointTile = GoogleMapUtility::metersToTile($minPointMeters->x, $minPointMeters->y, $zoom);
         $maxPointMeters = GoogleMapUtility::latLonToMeters($maxLat, $maxLng);
         $maxPointTile = GoogleMapUtility::metersToTile($maxPointMeters->x, $maxPointMeters->y, $zoom);
         // for each tile on y direction
         foreach (range($minPointTile->y, $maxPointTile->y) as $ty) {
             // for each tile in x direction
             foreach (range($minPointTile->x, $maxPointTile->x) as $tx) {
                 $googleTile = GoogleMapTile::create_from_tms_tile($tx, $ty, $zoom);
                 $tileUrl = $renderer->getRelativeTilePath();
                 $tileUrl .= $renderer->getFilename($googleTile->x, $googleTile->y, $googleTile->zoom);
                 $urls[] = $tileUrl;
             }
         }
     }
     if ($urls) {
         foreach ($urls as $url) {
             if (!self::has_pending_tile($url)) {
                 $item = new TileRenderQueue();
                 $item->URL = $url;
                 $item->write();
                 unset($item);
             }
         }
     }
     return $urls;
 }