Openseamap/DE:KAP-Dateien aus OSeaMap erstellen

From OpenStreetMap Wiki
Jump to navigation Jump to search

Vorwort

BSB-Seekarten (KAP-Dateien) werden in Programmen, wie z.B. OpenCPN verwendet.

Um aus den OpenSeapMap- bzw. OpenStreetMap-Daten eine Seekarte zu erstellen, wird ein Bild mit eingezeichneten Seezeichen als PNG benötigt.

Eine weiter Möglichkeit ist es, eine KAP-Datei direkt aus OSM-Daten mit dem Programm Smrender zu erzeugen.

Beschaffung/Erstellung der Vorlagendatei

eigenen Mapnik-Renderer aufsetzen

  • Mapnik aufsetzen
  • Renderregeln einpflegen
  • berechnen lassen
  • ...


Benutzung von vorgefertigten Kacheln

Eine weitere Möglichkeit besteht darin, die fertig gerenderten Kacheln des OpenSeaMap-Tileservers dafür zu verwenden.

Der OpenSeaMap-Server verwendet die Mapnik-Kacheln der OpenStreetMap-Tileserver und überlagert diese mit transparenten, eigenen Kacheln, auf denen die Seezeichen vorhanden sind. Diese Möglichkeit kann man sich auch zu Nutze machen, um eine Seekarte im PNG-Format herzustellen. Man lädt alle benötigten Kacheln vom Tile-Server der OpenStreetMap herunter und überlagert diese mit den Kacheln der OpenSeaMap (wenn überhaupt vorhanden). Als letztes müssen diese Kacheln noch zu einem einzigen Bild (PNG) zusammengefasst werden.

Perl-Skript

Das folgende Perl-Skript erledigt diese Aufgabe, indem zuerst die Kacheln ermittelt werden, welche den benötigten Bereich darstellen. Diese werden durch 'wget' in ein Verzeichnis geladen und durch ImageMagick mit den Kacheln den Seezeichen überlagert. Als nächstes werden die Kacheln wieder mit Hilfe von ImageMagick zu einem einzigen Bild zusammengefasst.


Voraussetzungen:

  • Perl-Interpreter
  • wget
  • ImageMagick
  • Internet-Verbindung
  • möglichst leeres Verzeichnis zur Speicherung der Kacheln

Sourcecode

#!/usr/bin/perl
use Math::Trig;


$level=15;
$latStart = 54.70;
$lonStart = 9.82;
$latEnde = 54.57;
$lonEnde = 10.08;

($xstart, $ystart) = getTileNumber($latStart,$lonStart,$level);
($xende,  $yende)  = getTileNumber($latEnde, $lonEnde, $level);
$xanz = $xende-$xstart;
$yanz = $yende-$ystart;

$urlOSM="http://tile.openstreetmap.org";
$urlOSeaMap="http://tiles.openseamap.org/seamark";


# Status anzeigen
print ("Anzahl x: $xanz\n");
print ("Anzahl y: $yanz\n");

($dummy, $lonStart, $latStart, $$dummy) = Project($xstart,$ystart,$level);
($latEnde, $dummy, $dummy, $lonEnde) = Project($xende,$yende,$level);
print (" -> $latStart, $lonStart, $latEnde, $lonEnde \n"); 

# Aufräumen
`rm *.png *.log`;

# liegt es im Rahmen?
if ($xanz*$yanz > 25*25) {
   die "Zu viele Teile";
}
# Hauptschleife
for ($x=$xstart; $x<$xstart+$xanz; $x++){
   for ($y=$ystart; $y<$ystart+$yanz; $y++){
       print ("Level, X, Y = $level, $x, $y\n");
       `wget "$urlOSM/$level/$x/$y.png" -o "$level-$y-$x.log" -O "$level-$y-$x.png" `;
       `wget "$urlOSeaMap/$level/$x/$y.png" -o log -O "SeaMap-$level-$y-$x.png" `;
       if ( -e "SeaMap-$level-$y-$x.png"){ 
          unless ( -z "SeaMap-$level-$y-$x.png"){
             `convert -type PaletteMatte -matte -transparent "#F8F8F8" "SeaMap-$level-$y-$x.png" "SeaMap-$level-$y-$x.png"`; 
             `composite "SeaMap-$level-$y-$x.png" "$level-$y-$x.png" "$level-$y-$x.png"` 
          }
          `rm "SeaMap-$level-$y-$x.png"`;
       }
   }
}
`montage +frame +shadow +label -tile "$xanz x $yanz" -geometry 256x256+0+0 *.png joined.png`;



sub getTileNumber {
   my ($lat,$lon,$zoom) = @_;
   my $xtile = int( ($lon+180)/360 *2**$zoom ) ;
   my $ytile = int( (1 - log(tan(deg2rad($lat)) + sec(deg2rad($lat)))/pi)/2 *2**$zoom ) ;
   return ($xtile, $ytile);
}

sub Project {
  my ($X,$Y, $Zoom) = @_;
  my $Unit = 1 / (2 ** $Zoom);
  my $relY1 = $Y * $Unit;
  my $relY2 = $relY1 + $Unit;
 
  # note: $LimitY = ProjectF(degrees(atan(sinh(pi)))) = log(sinh(pi)+cosh(pi)) = pi
  # note: degrees(atan(sinh(pi))) = 85.051128..
  # my $LimitY = ProjectF(85.0511);
 
  # so stay simple and more accurate
  my $LimitY = pi;
  my $RangeY = 2 * $LimitY;
  $relY1 = $LimitY - $RangeY * $relY1;
  $relY2 = $LimitY - $RangeY * $relY2;
  my $Lat1 = ProjectMercToLat($relY1);
  my $Lat2 = ProjectMercToLat($relY2);
  $Unit = 360 / (2 ** $Zoom);
  my $Long1 = -180 + $X * $Unit;
  return ($Lat2, $Long1, $Lat1, $Long1 + $Unit); # S,W,N,E
}
sub ProjectMercToLat($){
  my $MercY = shift;
  return rad2deg(atan(sinh($MercY)));
}
sub ProjectF{
  my $Lat = shift;
  $Lat = deg2rad($Lat);
  my $Y = log(tan($Lat) + sec($Lat));
  return $Y;
}

Python-Tool

GMapCatcher (Windows/Linux) ist ein recht komfortables Werkzeug, um Tiles herunterzuladen.

Die Vorteile:

  • Tiles können entlang eines GPX-Tracks heruntergeladen werden (geeignet fuer Wasserstrassen)
  • die Tiles können in der OSM-Verzeichnisstruktur abgelegt werden (Settings > Custom Maps Directory > OSM statt Files)


Stitchedtiles.png

Im Falle einer Wasserstraße:

  • erstellt man sich einen GPX-Track (z.B. mit JOSM oder dem Wasserstraßenrouter von http://maps.grade.de )
  • benutzt das beiliegende Download-Tool
    • z.B. Win download --gpx=ruhr.gpx --width=1 --min-zoom=1 --max-zoom=1
    • z.B. Linux mapdownloader --gpx=ruhr.gpx --width=1 --min-zoom=1 --max-zoom=1
  • GMapCatcher-zoom=1 entspricht OSM-zoom=16
  • Vorausgesetzt, man hat mit einem jungfäulichem Verzeichniss angefangen, sind nun die Tiles für eine Karte beisammen. Im Falle der schiffbaren Ruhr sind das bei zoomlevel=16 ca. 370 Tiles. Würde man den Bereich über eine Bounding-Box herunterladen, wären das ca. 1700 Tiles!
  • mit dem bash-Script http://www.openstreetmap.org/user/mkarau/diary/20256 kann man anschliessend die Tiles zu einem großen .png zusammensetzen. Die fehlenden Tiles werden automatisch durch ein z.B. weißes Bild ersetzt. Die linke obere und rechte untere Ecke wird in Tilenames angegeben und kann für diie Kalibrierung genutzt werden.

Alternativ kann man auch im GMapCatcher entlang der gewünschten Route surfen und anschliessend die gespeicherten Tiles zusammenfügen.

weiteres Vorgehen

Mit dem, aus dem obigen Vorgehen, resultierenden Bild, kann nach dieser Anleitung die KAP-Datei erstellt werden. Alternativ mit imgkap.

Referenzen