$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 ); } ?>