예제 #1
0
 /**
  * @param InputInterface $input
  * @param OutputInterface $output
  *
  * @throws \InvalidArgumentException
  * @return int|null|void
  */
 protected function execute(InputInterface $input, OutputInterface $output)
 {
     $this->helper = $this->getHelper('resource');
     $mapmode = strtolower($input->getOption('mapmode'));
     if (!in_array($mapmode, array('world', 'server'))) {
         throw new \InvalidArgumentException("--mapmode must be 'world' or 'server'");
     }
     $mapname = $input->getOption('mapname');
     $this->mapdir = $input->getOption('mapdir');
     $lang = $input->getOption('lang');
     if ($this->mapdir[0] != '/') {
         $this->mapdir = $this->helper->get('app.path') . '/' . $this->mapdir;
     }
     $withMap = $input->hasParameterOption('--with-map');
     $withCity = $input->hasParameterOption('--with-city');
     $withRegionColor = $input->hasParameterOption('--with-region-color');
     $output->writeln("=======================");
     $output->writeln("mode = <info>{$mapmode}</info>");
     $output->writeln("mapdir = <info>{$this->mapdir}</info>");
     if (!$withMap && !$withCity && empty($lang)) {
         throw new \InvalidArgumentException("Use --with-map, --with-city, --lang options\n");
     }
     $config = $this->helper->get('map-config');
     $this->proj = new MapProjection();
     $this->proj->setServerZones($this->helper->get('server.json.array'));
     $maps = $config['maps'];
     if ($mapmode == 'world') {
         $this->proj->setWorldZones($this->helper->get('world.json.array'));
     } else {
         // include individual zone map
         $maps = array_merge($maps, $config['zones']);
         unset($maps['world']);
         $this->proj->setWorldZones(array('grid' => array(array(0, 47520), array(108000, 0))));
     }
     $this->mapmode = $mapmode;
     $this->mapname = $mapname;
     $this->tileStorage = $this->helper->get('tilestorage');
     // map tiles
     $minMapZoom = 1;
     $maxMapZoom = 11;
     // city map on world image
     $minCityZoom = 10;
     $maxCityZoom = 11;
     // text tiles
     $minTextZoom = 5;
     $maxTextZoom = 12;
     // generate tiles for world map zone placement
     if ($withMap) {
         $this->doMaps($maps, $minMapZoom, $maxMapZoom, $output);
     }
     if ($withCity) {
         $this->doMaps($config['cities'], $minCityZoom, $maxCityZoom, $output);
     }
     if (!empty($lang)) {
         $languages = explode(',', $lang);
         foreach ($languages as $l) {
             $this->doTextTiles($l, $minTextZoom, $maxTextZoom, $output);
         }
     }
 }
예제 #2
0
 /**
  * @return float
  */
 public function getTileSize()
 {
     $size = TileStorageInterface::TILE_SIZE;
     if ($this->zoom > $this->maxZoom) {
         $size = $this->proj->scale($this->zoom) / $this->proj->scale($this->maxZoom) * $size;
     }
     return $size;
 }
예제 #3
0
 /**
  * Draw same type to labels (area, region, etc) into tiles
  *
  * @param int $zoom
  * @param Label[] $labels
  * @param array $style
  * @param bool $withIcon
  *
  * @throws \RuntimeException
  */
 protected function processLabels($zoom, $labels, $style, $withIcon)
 {
     $scale = $this->proj->scale($zoom);
     $count = count($labels);
     foreach ($labels as $id => $label) {
         $mem = memory_get_usage();
         if (!isset($label->text[$this->lang])) {
             throw new \RuntimeException("Missing translation ({$this->lang}), abort");
         }
         // center point in grid
         $point = new Point($label->point->x * $scale, $label->point->y * $scale);
         $text = $label->text[$this->lang];
         // center tile
         $txHome = floor($point->x / TileStorageInterface::TILE_SIZE);
         $tyHome = floor($point->y / TileStorageInterface::TILE_SIZE);
         $this->info("[{$mem}] + ({$zoom}) ({$count}) [{$txHome}, {$tyHome}], {$text}, \r");
         --$count;
         // label position relative to tile
         $cx = $point->x - $txHome * TileStorageInterface::TILE_SIZE;
         $cy = $point->y - $tyHome * TileStorageInterface::TILE_SIZE;
         $this->debug("+ ({$id}:{$text}) {$point} ({$txHome}, {$tyHome}) -> cx/cy [{$cx}, {$cy}]\n");
         $bbox = $this->getTextDimensions($style, $text);
         $tileBounds = $this->getTileBounds($point, $bbox);
         // 1x1 tile will give 0/0 as width/height
         $xTiles = $tileBounds->getWidth() + 1;
         $yTiles = $tileBounds->getHeight() + 1;
         $tx1 = $tileBounds->left;
         $ty1 = $tileBounds->top;
         // work image
         $canvas = $this->createTile($xTiles * TileStorageInterface::TILE_SIZE, $yTiles * TileStorageInterface::TILE_SIZE);
         // load tiles that needs to be modified
         $this->loadCanvas($canvas, $zoom, $tx1, $ty1, $xTiles, $yTiles);
         // label position relative to canvas
         $p = new Point($cx + ($txHome - $tx1) * TileStorageInterface::TILE_SIZE, $cy + ($tyHome - $ty1) * TileStorageInterface::TILE_SIZE);
         if ($withIcon) {
             $this->drawIcon($canvas, $p);
         }
         if ($style['fontSize'] > 0) {
             $this->drawText($canvas, $p, $style, $text, $label->color);
         }
         // now save those tiles back
         $this->saveCanvas($canvas, $zoom, $tx1, $ty1, $xTiles, $yTiles);
         imagedestroy($canvas);
     }
 }
예제 #4
0
 /**
  * @return resource
  * @throws \RuntimeException
  */
 protected function _background()
 {
     $canvas = imagecreatetruecolor($this->width, $this->height);
     if ($canvas === false) {
         throw new \RuntimeException("Unable to create output image at size [{$this->width}x{$this->height}]");
     }
     if ($this->center === null) {
         if ($this->bounds === null) {
             // no features on map, so take center point in world zone
             $world = $this->proj->getZoneBounds('world');
             $this->bounds = clone $world;
         }
         $cx = ($this->bounds->left + $this->bounds->right) / 2;
         $cy = ($this->bounds->top + $this->bounds->bottom) / 2;
         $this->center = new Point($cx, $cy);
     } else {
         // this comes in handy with automatic zoom
         $this->extend($this->center);
     }
     if ($this->zoom === null) {
         $this->zoom = $this->getBoundsZoom();
     }
     //calculate viewport
     $scale = $this->getZoomScale();
     // calculate viewport
     $halfWidth = $this->width / 2;
     $halfHeight = $this->height / 2;
     // absolute coords for viewport
     $vpLeft = $this->center->x * $scale - $halfWidth;
     $vpTop = $this->center->y * $scale - $halfHeight;
     $vpRight = $vpLeft + $this->width;
     $vpBottom = $vpTop + $this->height;
     $this->viewport = new Bounds($vpLeft, $vpBottom, $vpRight, $vpTop);
     $this->draw($canvas);
     return $canvas;
 }
예제 #5
0
 /**
  * @param int $zoom
  * @param float $expected
  *
  * @dataProvider zoomScaleProvider
  */
 public function testScale($zoom, $expected)
 {
     $mod = $this->proj->scale($zoom);
     $this->assertEquals($expected, $mod);
 }
예제 #6
0
<?php

use Bmsite\Maps\MapProjection;
use Bmsite\Maps\ResourceLoader;
use Bmsite\Maps\StaticMap;
require_once __DIR__ . '/../vendor/autoload.php';
$tiledir = '/srv/websites/maps/htdocs/webroot/api/tiles';
$params = array('maptype' => 'atys', 'size' => '512x300', 'maxzoom' => 10, 'markers' => array('icon:lm_marker|color:0xff5050|label:Glue|8749.71,-3163.33', 'icon:lm_marker|color:0xff5050|label:Zun|8812.64,-3243.71', 'icon:lm_marker|color:0xff5050|label:Koorin|8732.69,-3387.78', 'icon:lm_marker|color:0xff5050|label:Splinter|8909.87,-3028.54', 'icon:lm_marker|color:0xff5050|label:Oath|8991.02,-3053.90'));
$loader = new ResourceLoader();
$proj = new MapProjection();
$proj->setServerZones($loader->loadJson('server.json'));
$proj->setWorldZones($loader->loadJson('world.json'));
$map = new StaticMap($tiledir, $proj);
$map->configure($params);
$etag = $map->etag();
echo "etag:[{$etag}]\n";
$img = $map->render();
file_put_contents(__DIR__ . '/../static-map-result.png', $img);
$size = strlen($img);
echo "size:[{$size}]\n";
예제 #7
0
 /**
  * @param resource $mapImage
  * @param int $zoom
  * @param int $mapImageWidth
  * @param int $mapImageHeight
  * @param Bounds $zoneBounds
  */
 protected function mapCutter($mapImage, $zoom, $mapImageWidth, $mapImageHeight, $zoneBounds)
 {
     // map image coords at base zoom
     $zoneLeft = $zoneBounds->left;
     $zoneBottom = $zoneBounds->bottom;
     $zoneRight = $zoneBounds->right;
     $zoneTop = $zoneBounds->top;
     $this->info("");
     $zoomScale = $this->projWorld->scale($zoom);
     // coords at current zoom level
     $left = $zoneLeft * $zoomScale;
     $bottom = $zoneBottom * $zoomScale;
     $right = $zoneRight * $zoomScale;
     $top = $zoneTop * $zoomScale;
     $width = $right - $left;
     $height = $bottom - $top;
     $scaleWidth = $mapImageWidth / $width;
     $scaleHeight = $mapImageHeight / $height;
     $this->debug("({$zoom}) map size ({$width}, {$height}), scaled (%.3f, %.3f)\n", $scaleWidth, $scaleHeight);
     // tiles this image lands
     $leftTile = floor($left / TileStorageInterface::TILE_SIZE);
     $topTile = floor($top / TileStorageInterface::TILE_SIZE);
     // right/bottom are +1 in value
     // (map on 0,0 tile has 1,1 as right/bottom) as we need top-left coords for that tile
     $rightTile = ceil($right / TileStorageInterface::TILE_SIZE);
     $bottomTile = ceil($bottom / TileStorageInterface::TILE_SIZE);
     $xTiles = $rightTile - $leftTile;
     $yTiles = $bottomTile - $topTile;
     $this->debug("    num tiles ({$xTiles}, {$yTiles}), map at ({$left}, {$top}):({$right}, {$bottom}) on tiles({$leftTile}, {$topTile}, %d, %d)\n", $rightTile - 1, $bottomTile - 1);
     $x1 = 0;
     $cw = 0;
     for ($xTile = 0; $xTile < $xTiles; $xTile++) {
         $y1 = 0;
         $ch = 0;
         for ($yTile = 0; $yTile < $yTiles; $yTile++) {
             $mem = memory_get_usage();
             $this->info("[{$mem}] - zoom % 2d (% 5dx% 5d @ %8d grid, mul=%.5f), tile % 3dx% 3d\r", $zoom, $width, $height, pow(2, $zoom) * TileStorageInterface::TILE_SIZE, $zoomScale, $xTile, $yTile);
             // tile coords within grid
             $tx1 = ($leftTile + $xTile) * TileStorageInterface::TILE_SIZE;
             $ty1 = ($topTile + $yTile) * TileStorageInterface::TILE_SIZE;
             $tx2 = ($leftTile + $xTile) * TileStorageInterface::TILE_SIZE + TileStorageInterface::TILE_SIZE;
             $ty2 = ($topTile + $yTile) * TileStorageInterface::TILE_SIZE + TileStorageInterface::TILE_SIZE;
             // image padding in tile
             $pad_l = 0;
             $pad_t = 0;
             $pad_r = 0;
             $pad_b = 0;
             if ($tx1 < $left) {
                 $pad_l = floor($left - $tx1);
             }
             if ($ty1 < $top) {
                 $pad_t = floor($top - $ty1);
             }
             if ($tx2 > $right) {
                 $pad_r = ceil($tx2 - $right);
             }
             if ($ty2 > $bottom) {
                 $pad_b = ceil($ty2 - $bottom);
             }
             $this->debug(">> (xTile:{$xTile}, yTile:{$yTile}): (tx1:{$tx1},ty1:{$ty1}):(tx2:{$tx2},ty2:{$ty2}), padding ({$pad_l}, {$pad_t}):({$pad_r}, {$pad_b})\n");
             $dstWidth = TileStorageInterface::TILE_SIZE - $pad_r - $pad_l;
             $dstHeight = TileStorageInterface::TILE_SIZE - $pad_b - $pad_t;
             $cw = $dstWidth * $scaleWidth;
             $ch = $dstHeight * $scaleHeight;
             $this->debug(">> copy from (%d, %d):(%d,%d) to tile (%d, %d):(%d,%d)\n", $x1, $y1, $cw, $ch, $pad_l, $pad_t, $dstWidth, $dstHeight);
             $out = $this->loadTileImage($zoom, $leftTile + $xTile, $topTile + $yTile);
             imagecopyresampled($out, $mapImage, $pad_l, $pad_t, $x1, $y1, $dstWidth, $dstHeight, $cw, $ch);
             if ($this->debug) {
                 $c = imagecolorallocatealpha($out, 255, 0, 0, 50);
                 imagerectangle($out, $pad_l, $pad_t, $pad_l + $dstWidth, $pad_t + $dstHeight, $c);
             }
             $this->saveTileImage($zoom, $leftTile + $xTile, $topTile + $yTile, $out);
             $y1 += $ch;
         }
         $x1 += $cw;
     }
 }