view tools/makegmaps.php @ 209:1288e2f8d769 gmap2

Rename variables.
author Matti Hamalainen <ccr@tnsp.org>
date Wed, 12 Mar 2014 16:15:09 +0200
parents 260644076c07
children 265debcae71c
line wrap: on
line source

#!/usr/bin/php
<?php

// Paths and files
$binConvert = "convert";
$binMercurial = "hg";

$pathMapUtils = "maputils/";
$pathImageCache = "cache/";
$pathMarkerData = "../";
$pathTileData = "../tiles/";

$pathRawMaps = $pathMapUtils."maps/";

$rawSuffix = ".new";
$rawAltSuffix = ".map";

$fontFile = "./lucon.ttf";
$tileDim = 256;



/* Internal data and settings
 */
$locPath = $pathMapUtils."maps/";
$continentJS = $pathMarkerData."continents.js";
$tradelaneOut = $pathMarkerData."tradelane.json";
$tradelaneOverlay = $pathMarkerData."troverlay.json";
$mkloc = $pathMapUtils."mkloc";

$modes = array(
  "xml"     => array("batclient.xml"     , 0, 0),
  "json"    => array("markers.json"       , 0, 0),
);

$mapPalette = array();
$mapPalette["!"]  = array(204,255,255);
$mapPalette["%"]  = array(  0,170,170);
$mapPalette["-"]  = array( 51, 51, 51);
$mapPalette["|"]  = array( 51, 51, 51);
$mapPalette["/"]  = array( 51, 51, 51);
$mapPalette["+"]  = array( 51, 51, 51);
$mapPalette["\\"] = array( 51, 51, 51);
$mapPalette["="]  = array( 72, 67, 57);
$mapPalette["@"]  = array(255,107,  0);
$mapPalette["F"]  = array(  0,136,  0);
$mapPalette["L"]  = array(255, 80,  0);
$mapPalette["S"]  = array( 68,204,204);
$mapPalette["^"]  = array(113,130,146);
$mapPalette["c"]  = array( 95, 86, 85);
$mapPalette["f"]  = array(  0,182,  0);
$mapPalette["i"]  = array(255,255,255);
$mapPalette["l"]  = array(100,100,255);
$mapPalette["s"]  = array(157,168, 10);
$mapPalette["v"]  = array( 34,221, 34);
$mapPalette["x"]  = array(138,131, 96);
$mapPalette["z"]  = array(177,164,133);
$mapPalette["#"]  = array( 79, 54, 69);
$mapPalette["."]  = array( 85,146,  0);
$mapPalette[","]  = array(140, 87, 56);
$mapPalette["?"]  = array(255,255,  0);
$mapPalette["C"]  = array(153,153,  0);
$mapPalette["H"]  = array(102, 63,  0);
$mapPalette["R"]  = array( 51,102,255);
$mapPalette["V"]  = array(255, 51,  0);
$mapPalette["b"]  = array(207,196,165);
$mapPalette["d"]  = array(238,187, 34);
$mapPalette["h"]  = array(153,102,  0);
$mapPalette["j"]  = array( 19,150, 54);
$mapPalette["r"]  = array(102,153,255);
$mapPalette["t"]  = array( 97,195,162);
$mapPalette["w"]  = array(119,170,255);
$mapPalette["y"]  = array(167,204, 20);
$mapPalette["~"]  = array( 51, 51,170);
$mapPalette["1"]  = array(255,102, 16);
$mapPalette[3]    = array(0,0, 0);


function makeDir($path)
{
  if (file_exists($path))
    return TRUE;
  else
    return mkdir($path, 0755, TRUE);
}


/*
 * Build maputils and fetch latest map data
 */
if (!file_exists($pathMapUtils))
{
  // If maputils does not exist, clone the repository
  $tmp = $binMercurial." clone http://pupunen.net/hg/maputils/ ".escapeshellarg($pathMapUtils);
  echo "* $tmp\n";
  passthru($tmp) == 0 or die("Error executing: ".$tmp."\n");

  // Clone th-libs
  $tmp = $binMercurial." clone http://tnsp.org/hg/th-libs/ ".escapeshellarg($pathMapUtils."th-libs/");
  echo "* $tmp\n";
  passthru($tmp) == 0 or die("Error executing: ".$tmp."\n");
}
else
{
  $tmp = "cd ".escapeshellarg($pathMapUtils)." && ".$binMercurial." pull && ".$binMercurial." update";
  echo "* $tmp\n";
  passthru($tmp) == 0 or die("Error executing: ".$tmp."\n");

  $tmp = "cd ".escapeshellarg($pathMapUtils."th-libs/")." && ".$binMercurial." pull && ".$binMercurial." update";
  echo "* $tmp\n";
  passthru($tmp) == 0 or die("Error executing: ".$tmp."\n");
}

$tmp = "cd ".escapeshellarg($pathMapUtils)." && make";
echo "* $tmp\n";
passthru($tmp) == 0 or die("Error executing: ".$tmp."\n");


if (!file_exists($mkloc))
  die($mkloc." not found. Maputils package not built, or some other error occured.\n");

$tmp = "cd ".escapeshellarg($pathMapUtils)." && make";
passthru($tmp) == 0 or die("Error executing: ".$tmp."\n");

$tmp = "cd ".escapeshellarg($pathRawMaps)." && make fetch 2> /dev/null";
passthru($tmp) == 0 or die("Error executing: ".$tmp."\n");


/*
 * Include continent and tradelane configuration 
 */
$config = $pathMapUtils."www/world.inc.php";
if (!file_exists($config))
  die("Required continent/tradelane configuration file '$config' not found.\n");

require $config;


/*
 * Generate continents JavasScript data file
 */
echo "* Generating $continentJS ...\n";
$str = "var pmapContinents =\n[\n";
foreach ($continentList as $name => $data)
if ($data[4] && $data[7])
{
  $str .= sprintf("  [%-15s, %5d, %5d, %5d, %5d],\n",
  "\"".$data[0]."\"",
  $data[1],
  $data[2],
  $data[1] + $data[5] - 1,
  $data[2] + $data[6] - 1);
}
$str .= "];\n";

if (file_put_contents($continentJS, $str) === FALSE)
  die("Error writing continent data to ".$continentJS."\n");



/*
 * Generate marker files from LOC data
 */
echo "Converting location data from LOC files to GMaps markers...\n";

foreach ($modes as $mode => $mdata)
{
  $tmp = escapeshellcmd($mkloc)." -v -o ".escapeshellarg($pathMarkerData.$mdata[0])." -G ".$mode." ";

  foreach ($continentList as $name => $data)
  {
    if ($data[4] && $data[7])
    {
      // has a map
      $tmp .=
      "-l ".escapeshellarg($locPath.$name.".loc")." ".
      "-c ".escapeshellarg($data[0])." ".
      "-x ".escapeshellarg($worldMap["ox"] + $data[1] + $mdata[1])." ".
      "-y ".escapeshellarg($worldMap["oy"] + $data[2] + $mdata[2])." ";
    }
  }

  passthru($tmp) == 0 or die("Error executing: ".$tmp."\n");
}


/* Calculate worldmap coordinates from continent coordinates
 */
function getWorldCoords($cont, $xp, $yp, &$xc, &$yc)
{
  global $worldMap, $continentList;

  if (!isset($continentList[$cont]))
    return FALSE;

  $xc = $worldMap["ox"] + $continentList[$cont][1] + $xp - 1;
  $yc = $worldMap["oy"] + $continentList[$cont][2] + $yp - 1;
  return TRUE;
}


/* Get worldmap coordinates for a given tradelane waypoint
 */
function getWaypointCoords($waypoint, &$xc, &$yc)
{
  global $tradelanePoints;
  
  if (!isset($tradelanePoints[$waypoint]))
    return FALSE;

  return getWorldCoords($tradelanePoints[$waypoint][0],
    $tradelanePoints[$waypoint][1], $tradelanePoints[$waypoint][2], $xc, $yc);
}


function outputJSON($qfilename, $qdata)
{
  if (file_put_contents($qfilename, json_encode($qdata), LOCK_EX) === FALSE)
    die("Could not write to file '".$qfilename."'.\n");
}


/* Export tradelane waypoint data
 */
if (!isset($tradelanePoints))
  die("PHP array \$tradelanePoints not set, '$config' is old or incompatible.\n");

echo "\nCreating tradelane waypoint data '".$tradelaneOut."' ...\n";

$qdata = array();

foreach ($tradelanePoints as $name => $data)
{
  $html = "<b>TRADELANE WPT</b><br>".htmlentities($name);

  if (!getWorldCoords($data[0], $data[1], $data[2], $xc, $yc))
    die("Invalid tradelane waypoint '".$name."', continent '".$data[0]."' not defined.\n");

  $qdata[] = array(
    "x" => $xc,
    "y" => $yc,
    "name" => $name,
    "html" => $html,
    "continent" => "",
    "type" => "tradelane",
    "flags" => 0,
  );
}

outputJSON($tradelaneOut, $qdata);


/* Export tradelane polyline data
 */
echo "\nCreating tradelane polyline data '".$tradelaneOverlay."' ...\n";
if (!isset($tradelaneDefs))
  die("PHP array \$tradelaneDefs not set, '$config' is old or incompatible.\n");

$qdata = array();
foreach ($tradelaneDefs as $index => $points)
{
  $qline = array();

  foreach ($points as $point)
  {
    if (!getWaypointCoords($point, $xc, $yc))
      die("Invalid tradelane definition #$index: waypoint '".$point."' not defined.\n");

    $qline[] = array(
      "x" => $xc,
      "y" => $yc
    );
  }
  
  $qdata[] = $qline;
}


outputJSON($tradelaneOverlay, $qdata);

/*
 * Generate PNG maps
 */
function makeMap($inFilename, $outFilename, $zlevel, $data)
{
  global $mapPalette, $fontFile;

  // Try to open input file
  $file = @fopen($inFilename, "r");
  if ($file === FALSE)
  {
    echo "Could not open input '".$inFilename."'\n";
    return FALSE;
  }

  // Derp
  $zoom = pow(2, $zlevel - 1);
  $width = $data[5];
  $height = $data[6];

  // Create image and assign colors
  $im = @imagecreate($width*$zoom, $height*$zoom);
  if ($im === FALSE)
  {
    echo "Could not allocate image data for '".$inFilename."'\n";
    return FALSE;
  }

  $black = imagecolorallocate($im, 0, 0, 0);
  foreach ($mapPalette as $id => $val)
    $colors[$id] = imagecolorallocate($im, $val[0], $val[1], $val[2]);

  imagefilledrectangle($im, 0, 0, $width*$zoom, $height*$zoom, $black);

  // Font sizes
  $fontsize[ 8] = 7;
  $fontsize[16] = 13;
  $fontsize[32] = 26;

  // Read input raw
  $y = 0;
  while ($y < $height && ($data = fgets($file, 4096)) !== FALSE) 
  {
    for ($x = 0; $x < $width; $x++)
    {
      if ($zoom == 1)
      {
        imagesetpixel($im, $x, $y, $colors[$data[$x]]);
      }
      else 
      if ($zoom < 6)
      {
        imagefilledrectangle($im, $x*$zoom, $y*$zoom, ($x+1)*$zoom-1, ($y+1)*$zoom-1, $colors[$data[$x]]);
      }
      else
      {
        imagettftext($im,
          $fontsize[$zoom], 0,
          $x*$zoom + $fontsize[$zoom]/4,
          $y*$zoom + $fontsize[$zoom],
          $colors[$data[$x]],
          $fontFile,
          $data[$x]);
      }
    }
    $y++;
    echo ".";
  }

  if (imagepng($im, $outFilename) === FALSE)
  {
    echo "Error creating '".$outFilename."'\n";
    imagedestroy($im);
    return FALSE;
  }

  imagedestroy($im);
  return TRUE;
}

if (!makeDir($pathImageCache)) {
  die("Failed to create cache directory '".$pathImageCache."'!\n");
}

echo "Generating basic map data...\n";
foreach ($continentList as $name => $data)
if ($data[4] && $data[7])
{
  $inFilename = $pathRawMaps.$name.$rawSuffix;
  if (!file_exists($inFilename))
  {
    $inFilename = $pathRawMaps.$name.$rawAltSuffix;
    if (!file_exists($inFilename))
      die("Required file '".$pathRawMaps.$name."(".$rawSuffix."|".$rawAltSuffix.")' does not exist.\n");
  }
  $inMtime = filemtime($inFilename);
  
  for ($zoom = 1; $zoom <= 5; $zoom++)
  {
    $outFilename = $pathImageCache.$name."_".($zoom + 4).".png";
    $outMtime = file_exists($outFilename) ? filemtime($outFilename) : -1;
    echo "- ".$name." (".$data[0]."): ";
    if ($inMtime > $outMtime)
    {
      $res = makeMap($inFilename, $outFilename, $zoom, $data);
      echo ($res ? "OK" : "FAIL")."\n";
    }
    else
      echo "SKIPPED\n";
  }
}


/*
 * Generate small versions
 */
echo "\nGenerating scaled small map data...\n";
$mapScales = array("50", "25", "12.5", "6.25", "3.125");
foreach ($continentList as $name => $data)
if ($data[4] && $data[7])
{
  $n = count($mapScales);
  $inFilename = $pathImageCache.$name."_".$n.".png";
  if (!file_exists($inFilename))
  {
    die("Required file '".$inFilename."' does not exist.\n");
  }
  $inMtime = filemtime($inFilename);

  foreach ($mapScales as $scale)
  {
    $n--;
    $outFilename = $pathImageCache.$name."_".$n.".png";
    $outMtime = file_exists($outFilename) ? filemtime($outFilename) : -1;

    echo "* ".$inFilename." -> ".$outFilename.": ";
    if ($inMtime > $outMtime)
    {
      $tmp = escapeshellcmd($binConvert)." ".escapeshellarg($inFilename)." -scale ".escapeshellarg($scale."%")." -type Palette ".escapeshellarg($outFilename);
      passthru($tmp) == 0 or die("Error executing: ".$tmp."\n");
      echo "OK\n";
    }
    else
      echo "SKIPPED\n";
  }
}


/*
 * Build tiles
 */
function createTile($scale, $zoom, $x, $y, $mapData, $mapMtime)
{
  global $continentList, $worldMap, $pathImageCache, $pathTileData, $tileDim;

  $outFilename = $pathTileData.$zoom."/".$y."/".$x.".png";
  if (file_exists($outFilename) && filemtime($outFilename) >= $mapMtime)
  {
    echo "!";
    return;
  }

  $drawn = 0;
  $im = false;

  foreach ($continentList as $continent => $data)
  {
    $cx = $data[1] + $worldMap["ox"];
    $cy = $data[2] + $worldMap["oy"];
    $cw = $data[5];
    $ch = $data[6];
    
    $tx = -($cx*$scale - $x*$tileDim);
    $ty = -($cy*$scale - $y*$tileDim);

    if (($cx + $cw)*$scale > $x*$tileDim && 
        ($cy + $ch)*$scale > $y*$tileDim &&
        ($cx * $scale)     < ($x+1)*$tileDim && 
        ($cy * $scale)     < ($y+1)*$tileDim)
    {
      if ($drawn == 0)
      {
        if ($zoom < 9)
        {
          $im = @imagecreate($tileDim, $tileDim);
          $sea = imagecolorallocate($im, 51, 51, 170);
          imagefilledrectangle($im, 0, 0, $tileDim, $tileDim, $sea);
        }
        else
        {
          $inFilename = $pathTileData.$zoom."/sea.png";
          $im = @imagecreatefrompng($inFilename);
          if ($im === false)
            die("\nCould not open '".$inFilename."'.\n");
        }
      }

      $dx = $tileDim;
      $dy = $tileDim;
      $xx = 0;
      $yy = 0;

      if ($tx < 0)
      {
        $xx -= $tx;
        $dx += $tx+1;
        $tx  = 0;
      }

      if ($ty < 0)
      {
        $yy -= $ty;
        $dy += $ty+1;
        $ty  = 0;
      }

      if ($dx > $cw*$scale-$tx)
        $dx = $cw*$scale - $tx;

      if ($dy > $ch*$scale-$ty)
        $dy = $ch*$scale - $ty;

      if ($im !== false)
      {
        imagecopy($im, $mapData[$continent], $xx, $yy, $tx, $ty, $dx, $dy);
        $drawn++;
      }
    }
  }

  if ($drawn > 0)
  {
    makeDir($pathTileData.$zoom."/".$y, 0755);
    imagepng($im, $outFilename);
    imagedestroy($im);
  }
/* 
   else {
    if (file_exists($outFilename))
      unlink($outFilename);

    symlink($pathTileData."sea.png", $outFilename);
    echo "+";
  }
*/
}


echo "\nBuilding tiles data for all zoom levels ...\n";

$mapData = array();

for ($zoom = 1; $zoom <= 10; $zoom++)
{
  $zoom2 = $zoom - 1;
  $scale = pow(2, $zoom2 - 5);

  makeDir($pathTileData.$zoom);

  echo "\nzoom level $zoom: ";

  $mx = ceil(($worldMap["w"] * $scale) / $tileDim);
  $my = ceil(($worldMap["h"] * $scale) / $tileDim);
  $mw = ceil( $worldMap["w"] * $scale);
  $mh = ceil( $worldMap["h"] * $scale);

  $mapMtime = -1;
  foreach ($continentList as $continent => $data)
  if ($data[4] && $data[7])
  {
    $mapFile = $pathImageCache.$continent."_".$zoom2.".png";
    $mapData[$continent] = @imagecreatefrompng($mapFile);
    $tmp = filemtime($mapFile);
    if ($tmp > $mapMtime)
      $mapMtime = $tmp;
  }

  for ($y = 0; $y < $mx; $y++)
  {
    for ($x = 0; $x < $my; $x++)
      createTile($scale, $zoom, $x, $y, $mapData, $mapMtime);
    echo ".";
  }
  echo "\n";

  // Free image data for each continent
  foreach($continentList as $continent => $data)
  {
    if ($data[4] && $data[7])
      imagedestroy($mapData[$continent]);
  }
}

?>