$threadinfo) {
$thread = $threadinfo["thread"];
if( ! $thread->isAlive() ) {
echo "Thread $index is done\n";
unset( $threads[$index] );
$threads = array_values($threads);
}
}
// Check if there is room to start a new thread
if (count($threads) < $maxThreads && !empty($files)) {
echo "**\n**Starting thread with file ".$files[0]." and maxid $maxid**\n**\n";
// Start the render thread
$thread = new Thread("render");
$thread->start($render_dir, $files[0], $maxid, $initial_nodes, 0);
$threads[] = array("thread" => $thread, "dir" => $thread_dir);
$maxid+=100; // Assume maximum of 100 splitted tiles per initial tile
// Remove this tile from the todo list
unset($files[0]);
$files = array_values($files);
}
// let the CPU do its work
sleep( 1 );
die();
}
} else {
// Use non-threaded recursive method for rendering
$maxid = getMaxSourceId($type);
$files = getSourceIds("",$type);
foreach($files as $file) {
echo spaces(0)."Render top level file $file\n";
$maxid = render($render_dir, $file, $maxid, $initial_nodes, 0, false);
}
}
// Delete any file that has 0 bytes length (has to be done before the updateKml function)
echo spaces(0)."Cleanup after rendering\n";
$files = getSourceIds("","img");
foreach($files as $file) {
if (filesize("$file.img") == 0) {
echo spaces(0)."Deleting file $file.img because it has 0 bytes length\n";
unlink("$file.img");
}
}
// Update the initial KML split result file that lists all the tiles with the actual tiles produced by the recursive process
echo spaces(0)."Update the KML file\n";
updateKml("initial.kml", "world.kml");
// Create a list of countries and their associated tiles
echo spaces(0)."Match the countries with their associated tiles\n";
// Matchit is a custom made script to match country bboxes to tile bboxes.
$matchit = new Matchit($date, "/home/lambertus/garmin/utils/matchit/countries", $render_dir, "world.kml");
$matchit->Run();
// Move the results to the final directory
// Create the web directory where the tiles are stored
echo spaces(0)."Create the web dir: $web_dir/$date\n";
if (!is_dir("$web_dir")) {
mkdir("$web_dir");
}
if (!is_dir("$web_dir/$date")) {
mkdir("$web_dir/$date");
}
// Move all files to the new directory
echo spaces(0)."Move the images to the webdir\n";
exec("mv *.img $web_dir/$date");
exec("mv world.kml $web_dir/$date");
exec("cp countries.js $web_dir/$date");
exec("cp countries.xml $web_dir/$date");
echo "Distribute the version to the other server(s)\n";
exec("$script_dir/distribute.sh $date");
echo spaces(0)."Finalize by writing a new version\n";
file_put_contents("$web_dir/version", $date);
echo spaces(0)."Done!\n";
}
// Recursive functions that splits and renders until success (or no solution)
function render($thread_dir, $sourceid, $maxid, $nodes, $level, $noSubsplit) {
global $script_dir;
global $family_id;
global $product_id;
global $name;
global $style_dir;
global $style;
global $bounds;
global $description;
global $max_size;
global $type;
global $mkgmapOptions;
$mkgmap = "/home/lambertus/garmin/utils/mkgmap/mkgmap.jar";
chdir($thread_dir);
//echo "Styles: $style_dir, style: $style\n";
//$mapid = $maxid+1;
$file = "$sourceid.$type";
$name = "$sourceid.img";
$command = "ulimit -t 900 && java -Xmx1792M -ea -jar $mkgmap";
$command.= " --family-id=$family_id";
$command.= " --product-id=$product_id";
$command.= " --draw-priority=20";
$command.= " --description='$description'";
$command.= " --series-name='$description'";
$command.= " --style-file='$style_dir'";
$command.= " --style='$style'";
$command.= " --bounds='$bounds'";
foreach ($mkgmapOptions as $option) {
$command.=$option;
}
$command.= " --input-file=$file";
echo "$command\n";
$output = passthru($command, $retval);
$exists =file_exists($name);
$size = filesize($name);
if ($noSubsplit == true) {
if ($size == 0) {
echo spaces($level)." Failed render attempt $name, but cannot be split further\n";
if (file_exists($name)) {
unlink($name);
}
} else {
echo spaces($level)." Just don't subsplit $name further\n";
}
} else {
if ($retval == 1 || !$exists || $size == 0 || $size>$max_size) {
echo spaces($level)."Processing file $file failed (result=$retval, exists=$exists, size=$size)\n";
echo spaces($level)." Removing $name\n";
if (file_exists($name)) {
unlink($name);
}
$level++;
$maxid = subsplit($thread_dir, $sourceid, $maxid, $nodes, $level);
}
}
return $maxid;
}
// Split an OSM file
function subsplit($thread_dir, $tileid, $maxid, $nodes, $level) {
global $cities;
global $type;
$mapid = $maxid+1;
$newtileid = $tileid;
if ($nodes >= 10000) {
echo spaces($level)."Acquire the split lock\n";
$fp = fopen("splitter.lock", "w+");
flock($fp, LOCK_EX);
echo spaces($level)."Splitting $tileid with nodes=$nodes, starting at $mapid. Max id was $maxid, level = $level\n";
$output = "xml";
if (strcmp($type, "o5m") == 0) {
$output = "o5m";
}
$command = "java -Xmx2048M -jar ~/garmin/utils/splitter/splitter.jar --output=$output --keep-complete=true --mapid=".$mapid." --max-nodes=".$nodes." --write-kml=".$tileid.".kml --no-trim=true --geonames-file=$cities $tileid.$type";
//echo spaces($level).$command."\n";
//passthru($command);
$result = array();
exec($command, $result);
$newtileid = $maxid;
// Determine the maximum id produced by the split
$newmaxid = getMaxSourceId($type);
// Release the split lock
flock($fp, LOCK_UN);
fclose($fp);
// Find "nodes but can't be split further" in Splitter's output
$bCannotSplit = false;
foreach ($result as $line) {
if (strpos($line, "nodes but can't be split further") > 0){
echo spaces($level)." Found the text 'nodes but cant be split further' -> giving up subsplitting\n";
$bCannotSplit = true;
break;
}
}
// Check the result
if (($newmaxid - $maxid) < 2 && $bCannotSplit == false) { // require at least two sub files
echo spaces($level)."The split did not result in at least two subtiles, try again with less nodes per tile\n";
$level++;
if ($nodes > 100000) {
$nodes = $nodes - 100000;
} else {
$nodes = $nodes - 10000;
}
$newmaxid = subsplit($thread_dir, $tileid, $maxid, $nodes, $level);
} else {
// Render the new source files
$maxid++;
$tiles = $newmaxid - $maxid;
for ($i = 0; $i <= $tiles; $i++) {
echo spaces($level)."Start render with $maxid, $newmaxid, $level, $nodes\n";
$newmaxid = render($thread_dir, $maxid, $newmaxid, $nodes, $level, $bCannotSplit);
$maxid++;
}
echo spaces($level)."Done with subsplit at level $level\n";
}
} else {
echo spaces($level)."Giving up....\n";
$newmaxid = $maxid;
// Remove the last Splitter result XML file
unlink("$tileid.kml");
}
return $newmaxid;
}
function getMaxSourceId($type) {
$maxid = 0;
$ids = getSourceIds("",$type);
foreach ($ids as $id) {
if ($id > $maxid)
$maxid = $id;
}
return $maxid;
}
function getSourceIds($path = "", $extention = "osm.gz") {
$ids = array();
sleep(1);
if (strlen($path) > 0 && substr($path, -1) != "/") $path.="/";
echo "getSourceIds(): searching for $path*.$extention\n";
foreach (glob("$path*.$extention") as $filename) {
$parts = explode(".", $filename);
$paths = explode("/", $parts[0]);
$ids[] = $paths[count($paths)-1];
}
return $ids;
}
function spaces($level) {
$ret="";
for ($i = 0; $i < $level; $i++) {
$ret .= " ";
}
$ret .= date('H:i:s')." ";
return $ret;
}
function simplexml_append(SimpleXMLElement $parent, SimpleXMLElement $new_child){
$node1 = dom_import_simplexml($parent);
$dom_sxe = dom_import_simplexml($new_child);
$node2 = $node1->ownerDocument->importNode($dom_sxe, true);
$node1->appendChild($node2);
}
function simplexml_replace(SimpleXMLElement $parent, SimpleXMLElement $new_child){
$node1 = dom_import_simplexml($parent);
$dom_sxe = dom_import_simplexml($new_child);
$node2 = $node1->ownerDocument->importNode($dom_sxe, true);
$node1->parentNode->replaceChild($node2,$node1);
}
// The input KML is assumed to use tile id 1 to [n] while we want to work with mapid to mapid+[n]
// so the map id is added to the input id and written to the output
function upgradeKml($input, $output, $mapid) {
// Load the original KML file
if (file_exists($input)) {
$xml = simplexml_load_file($input);
} else {
exit("Failed to open $input.");
}
foreach ($xml->Document->Placemark as $tile) {
$id = (int)$tile->name+$mapid;
$tile->name = $id;
}
// Write out the new version of the KML file
$fh = fopen($output, "w+");
if ($fh) {
fwrite($fh, $xml->asXML());
fclose($fh);
}
}
function updateKml($input, $output) {
$kmlRed = "
";
$kmlBlue = "
";
// Load the original KML file
if (file_exists($input)) {
$xml = simplexml_load_file($input);
} else {
exit("Failed to open $input.");
}
// loop through all KML files to update the original KML file
foreach (glob("*.kml") as $replacement) {
//if (strpos($replacement, $name) === false) {
$id = explode(".", $replacement);
// Load each new KML file
$newxml = simplexml_load_file($replacement);
// Loop through the original KML file until the replacement ID is found
foreach ($xml->Document->Placemark as $oldPlacemark) {
//echo "split result id = ".$id[0].", world.kml compare: ".$oldPlacemark->name."\n";
if (strpos($oldPlacemark->name, $id[0]) !== false) {
// This KML file contains subtiles -> delete the tile they replace
echo "removing initial split result ".$oldPlacemark->name."\n";
// Remove the placemark from the original KML file
//unset($oldPlacemark); // This should also work to replace the two lines below
$oNode = dom_import_simplexml($oldPlacemark);
$oNode->parentNode->removeChild($oNode);
// Add the replacement placemarks
foreach ($newxml->Document->Placemark as $newPlacemark) {
echo "adding ".$newPlacemark->name." for ".$id[0]."\n";
simplexml_append($xml->Document, $newPlacemark);
}
break;
}
}
//}
}
// Determine which tiles actually exist (update KML rendering)
$red = simplexml_load_string($kmlRed);
$blue = simplexml_load_string($kmlBlue);
simplexml_replace($xml->Document->Style, $red);
simplexml_append($xml->Document, $blue);
foreach ($xml->Document->Placemark as $tile) {
$name = $tile->name.".img";
if (file_exists($name) == true) {
$tile->styleUrl = "#Blue";
} else {
$tile->styleUrl = "#Red";
}
// Add filesize
$size = filesize($name);
$tile->addChild("size", $size);
}
// Write out the new version of the KML file
$fh = fopen($output, "w+");
if ($fh) {
fwrite($fh, $xml->asXML());
fclose($fh);
}
}
// ensure $dir ends with a slash
function delTree($dir) {
$files = glob( $dir . '*', GLOB_MARK );
foreach( $files as $file ){
if( substr( $file, -1 ) == '/' )
delTree( $file );
else
unlink( $file );
}
rmdir( $dir );
}
?>