Ahoj,
obrázky parcel od Petra Vejsady mi nějak nedaly spát, tak jsem včera v
noci ubastlil skript na konverzi parcel do OSM.
Skriptík nemá jiné ambice než vyzkoušet si natažení parcel do JOSM a
vůbec se seznámit s VFR formátem RUIANu, takže nečekejte zázraky. Mj.
nefungují multipolygony, beru jen polygony typu gml:LinearRing apod.
Tagování jsem narychlo opsal z
http://wiki.openstreetmap.org/wiki/Cs:RUIAN, knihovny na zpracování
GML apod. jsem zatím nehledal.
Vyžaduje perl, proj, Geo::Proj4
(http://search.cpan.org/dist/Geo-Proj4/), a grid jezek_czech08.llb
přejmenovaný na "czech" (vyšťouráno tady v archívu,
http://freegis.fsv.cvut.cz/gwiki/S-JTSK_/_Grid).
Pár obrázků:
http://www.maatts.cz/obrazek/3/lomnice-ruian-parcely-png/
http://www.maatts.cz/obrazek/3/blansko-ruian-parcely-png/
http://www.maatts.cz/obrazek/3/brno-ruian-parcely-png/
Vyzkoušeno na uvedených třech obcích = na čtvrté klidně může
zhavarovat. ;-)
BACHA - ve velkých městech skript žere mraky paměti, optimalizacema
jsem se netrápil. :-)) Třeba Brno (kód obce 582786) má ve výsledku
1.122.529 uzlů a 251.328 parcel, a skriptík na to potřebuje aspoň 12GB
RAM a/nebo hodně swapu na SSD.
Martin
#!/usr/bin/perl -w
use strict;
use Geo::Proj4;
use XML::Simple;
use Data::Dumper;
#
# !!! NEPOUZIVAT PRO OSTRE MAPOVANI DO OSM, POKUSNA ALFA VERZE !!!
#
#
# Pouziti:
#
# (1) Stahnout Kompletni datovou sadu vybrane oblasti z http://vdp.cuzk.cz/vdp/ruian/vymennyformat/vyhledej, napr. podle kodu
# 581976 = Lomnice u Tisnova
# 581283 = Blansko
# 582786 = Brno (velke!)
#
# (2) gunzip 20140630_OB_581976_UKSH.xml.gz
#
# (3) par2osm.pl 20140630_OB_581976_UKSH.xml > lomnice.osm
#
#
#
my $input_file = $ARGV[0];
die "No input file specified" unless (defined $input_file);
die "Input file not found" unless (-f $input_file);
my $epsg_srs_name = 'urn:ogc:def:crs:EPSG::5514';
my $proj_from = Geo::Proj4->new('+proj=krovak +ellps=bessel +nadgrids=czech');
my $proj_to = Geo::Proj4->new('+proj=longlat +datum=WGS84');
die "Undefined source projection" unless (defined $proj_to);
die "Undefined destination projection" unless (defined $proj_from);
my $nodemap = {};
my $idgen = -1;
my $druh_pozemku_map = {
# 1 => [] ???
2 => [ 'landuse', 'farmland' ],
3 => [ 'landuse', 'hop_garden' ],
4 => [ 'landuse', 'vineyard' ],
5 => [ 'leisure', 'garden' ],
6 => [ 'landuse', 'orchard' ],
7 => [ 'landuse', 'meadow' ],
8 => [ 'landuse', 'meadow' ],
10 => [ 'landuse', 'forest', 'wood', 'yes' ],
};
my $zpusoby_vyuziti_map = {
1 => [ 'landuse', 'greenhouse_horticulture' ],
2 => [ 'landuse', 'plant_nursery' ],
3 => [ 'landuse', 'plantation', 'wood', 'yes' ],
4 => [ 'natural', 'wood', 'wood', 'yes' ],
5 => [ 'landuse', 'forest', 'wood', 'yes' ],
6 => [ 'natural', 'water', 'water', 'pond' ],
7 => [ 'waterway', 'river' ],
8 => [ 'waterway', 'canal' ],
9 => [ 'natural', 'water', 'water', 'lake' ],
10 => [ 'natural', 'water', 'water', 'reservoir' ],
11 => [ 'natural', 'wetland' ],
#12 => [ ] ???
13 => [ 'landuse', 'brownfield' ],
14 => [ 'landuse', 'railway' ],
15 => [ 'landuse', 'highway' ],
16 => [ 'landuse', 'highway' ],
17 => [ 'landuse', 'highway' ],
18 => [ 'landuse', 'transport' ],
19 => [ 'landuse', 'grass' ],
20 => [ 'landuse', 'recreation_ground' ],
21 => [ 'landuse', 'cemetery' ],
#22 => [] ???
23 => [ 'highway', 'service', 'area', 'yes' ],
24 => [ 'landuse', 'quarry' ],
25 => [ 'landuse', 'landfill' ],
#26 => [] ???
27 => [ 'natural', 'scrub' ], # ???? ... casty vyskyt
28 => [ 'natural', 'water' ],
29 => [ 'landuse', 'industrial' ],
};
sub warning
{
my ($text) = @_;
print STDERR "$text\n";
return undef;
}
sub nodemap_get
{
my ($lon, $lat) = @_;
my $key = "$lon/$lat";
my $node = $nodemap->{$key};
return $node if (defined $node);
my $krpos = [$lon, $lat];
my $osmpos = $proj_from->transform ($proj_to, $krpos);
$node = {
id => --$idgen,
krpos => $krpos,
osmpos => $osmpos,
};
$nodemap->{$key} = $node;
return $node;
}
sub parse_gml_pos
{
my ($pos) = @_;
return undef unless ($pos =~ /^\s*(\S+)\s+(\S+)\s*$/);
my $lon = $1;
my $lat = $2;
return nodemap_get ($lon, $lat);
}
sub parse_gml_poslist
{
my ($poslist) = @_;
$poslist =~ s/^\s*//;
$poslist =~ s/\s*$//;
my @list = split (/\s+/, $poslist);
die "Odd number of poslist entries: $poslist"
unless ((int(@list) % 2) == 0);
my $waynodes = [];
for (my $i = 0; $i < int(@list); $i += 2)
{
my $lon = @list[$i];
my $lat = @list[$i + 1];
push (@$waynodes, nodemap_get ($lon, $lat));
}
my $way = {
id => --$idgen,
nodes => $waynodes
};
return $way;
}
sub parse_pai_defpoint
{
my ($xdefpoint) = @_;
my $gml_point = $xdefpoint->{'gml:Point'};
return undef unless (defined $gml_point);
my $gml_pos = $gml_point->{'gml:pos'};
return undef unless (defined $gml_pos);
my $srs_name = $gml_point->{'srsName'};
return undef unless (defined $srs_name);
die "Unsupported EPSG: $srs_name" unless ($srs_name eq $epsg_srs_name);
return parse_gml_pos ($gml_pos);
}
sub parse_gml_polygon
{
my ($xpolygon, $ruian_id) = @_;
my $srs_name = $xpolygon->{'srsName'};
return undef unless (defined $srs_name);
die "Unsupported EPSG: $srs_name" unless ($srs_name eq $epsg_srs_name);
my $xexterior = $xpolygon->{'gml:exterior'};
die "$ruian_id: Polygon has no exterior"
unless (defined $xexterior);
my $xlring = $xexterior->{'gml:LinearRing'};
return warning ("$ruian_id: Polygon has no exterior linear ring")
unless (defined $xlring);
my $xposlist = $xlring->{'gml:posList'};
die "$ruian_id: Polygon has no exterior posList"
unless (defined $xposlist);
my $exterior_way = parse_gml_poslist ($xposlist);
#### TODO: parse interior ways too !!!!
my $polygon = {
id => --$idgen,
outer => [ $exterior_way ],
inner => []
};
return $polygon;
}
sub parse_parcel
{
my ($xparcel) = @_;
die "Undefined xparcel" unless (defined $xparcel);
#print Dumper $xparcel;
my $ruian_id = $xparcel->{'pai:Id'};
die "Parcel has no ID!" unless (defined $ruian_id);
my $druh_pozemku_kod = $xparcel->{'pai:DruhPozemkuKod'};
my $zpusoby_vyuziti_kod = $xparcel->{'pai:ZpusobyVyuzitiPozemku'};
my $polygon = undef;
my $defpoint = undef;
my $xgeometry = $xparcel->{'pai:Geometrie'};
if (defined $xgeometry)
{
my $xdefpoint = $xgeometry->{'pai:DefinicniBod'};
die "$ruian_id: parcel has no pai:DefinicniBod"
unless (defined $xdefpoint);
$defpoint = parse_pai_defpoint ($xdefpoint);
die "$ruian_id: cannot parse pai:DefinicniBod"
unless (defined $defpoint);
my $xorigborder = $xgeometry->{'pai:OriginalniHranice'};
if (defined $xorigborder)
{
my $xpolygon = $xorigborder->{'gml:Polygon'};
die "$ruian_id: parcel border has no gml:Polygon"
unless (defined $xpolygon);
$polygon = parse_gml_polygon ($xpolygon, $ruian_id);
}
}
my $parcel = {
id => --$idgen,
ruian_id => $ruian_id,
def_point => $defpoint,
polygon => $polygon,
druh_pozemku_kod => $druh_pozemku_kod,
zpusoby_vyuziti_kod => $zpusoby_vyuziti_kod,
};
return $parcel;
}
sub render_osm_node
{
my ($fd, $node) = @_;
return if (defined $node->{rendered});
my $node_id = $node->{id};
my $osmpos = $node->{osmpos};
print $fd " <node id=\"$node_id\" lon=\"$osmpos->[0]\" lat=\"$osmpos->[1]\">\n";
print $fd " <tag k=\"created_by\" v=\"par2osm\"/>\n";
print $fd " </node>\n";
$node->{rendered} = 1;
}
sub render_osm_way
{
my ($fd, $way, $way_tags) = @_;
my $way_id = $way->{id};
my $waynodes = $way->{nodes};
foreach my $node (@$waynodes)
{
render_osm_node ($fd, $node);
}
print $fd "<way id=\"$way_id\">\n";
print $fd " <tag k=\"created_by\" v=\"par2osm\"/>\n";
print $fd " <tag k=\"source\" v=\"cuzk:ruian\"/>\n";
print $fd " $way_tags\n";
foreach my $node (@$waynodes)
{
my $node_id = $node->{id};
print $fd " <nd ref=\"$node_id\"/>\n";
}
print $fd "</way>\n";
}
sub tarray2tags
{
my ($tarr) = @_;
my $tags = '';
for (my $i = 0; $i < int(@$tarr); $i += 2)
{
my $key = $tarr->[$i];
my $val = $tarr->[$i+1];
$tags .= "<tag k=\"$key\" v=\"$val\"/>\n";
}
return $tags;
}
sub parcel_landuse_tags
{
my ($parcel) = @_;
my $zvp = $parcel->{zpusoby_vyuziti_kod};
if (defined $zvp)
{
my $tarr = $zpusoby_vyuziti_map->{$zvp};
return tarray2tags ($tarr) if (defined $tarr);
}
my $dp = $parcel->{druh_pozemku_kod};
if (defined $dp)
{
my $tarr = $druh_pozemku_map->{$dp};
return tarray2tags ($tarr) if (defined $tarr);
}
$zvp = '?' unless (defined $zvp);
$dp = '?' unless (defined $dp);
warning ("$parcel->{ruian_id}: unknown landuse: druh_pozemku=$dp, zpusoby_vyuziti=$zvp");
#### co se zbytkem??
return
"<tag k=\"landuse\" v=\"unknown\"/>\n" .
"<tag k=\"ruian:aux:druh-pozemku\" v=\"$dp\"/>\n".
"<tag k=\"ruian:aux:zpusob-vyuziti\" v=\"$zvp\"/>\n";
}
sub render_osm_parcel
{
my ($fd, $parcel) = @_;
my $ruian_id = $parcel->{ruian_id};
my $polygon = $parcel->{polygon};
# ignore parcels without geometry...
return warning ("$ruian_id: missing geometry")
unless (defined $polygon);
my $parcel_tags = "<tag k=\"ref:ruian:parcel\" v=\"$ruian_id\"/>\n";
$parcel_tags .= parcel_landuse_tags ($parcel);
my $outers = $polygon->{outer};
my $inners = $polygon->{inner};
die "Multipolygons not supported yet!!!"
unless (int(@$outers) == 1 && int(@$inners) == 0);
my $way = $outers->[0];
render_osm_way ($fd, $way, $parcel_tags);
}
sub render_osm_xml
{
my ($fd, $parcels) = @_;
print $fd "<?xml version='1.0' encoding='UTF-8'?>\n";
print $fd "<osm version='0.6' generator='pyshp'>\n";
my $count = 0;
foreach my $parcel (@$parcels)
{
render_osm_parcel ($fd, $parcel);
++$count;
#last if ($count >= 10);
}
print $fd "<!-- parcels rendered: $count -->\n";
print $fd "</osm>\n";
}
sub main
{
my $xml = new XML::Simple;
# read XML file
my $xdata = $xml->XMLin($input_file);
my $xparcels = $xdata->{'vf:Data'}->{'vf:Parcely'}->{'vf:Parcela'};
#print Dumper $parcels;
my $parcels = [];
foreach my $xparcel (@$xparcels)
{
my $parcel = parse_parcel ($xparcel);
push (@$parcels, $parcel);
}
#### specify output file on command line?
my $fd;
open ($fd, ">&STDOUT") || die "Cannot dup stdout";
render_osm_xml ($fd, $parcels);
close ($fd);
}
main ();
1;
__END__
------- TODO ------------
* Dodelat zpracovani 'interior' polygonu a vytvaret multipolygony
* Blansko/Brno - Nezpracuji se polygony tvaru:
<gml:Polygon gml:id="HPA.19737019010" srsName="urn:ogc:def:crs:EPSG::5514" srsDimension="2">
<gml:exterior>
<gml:Ring>
<gml:curveMember>
<gml:LineString gml:id="HPA.19737019010.1">
<gml:posList>-593365.17 -1141552.76 -593367.31 -1141550.90 -593367.64 -1141547.07 -593362.82 -1141530.46 -593361.26 -1
</gml:LineString>
</gml:curveMember>
<gml:curveMember>
<gml:Curve gml:id="HPA.19737019010.2">
<gml:segments>
<gml:ArcString>
<gml:posList>-593307.73 -1141550.07 -593303.32 -1141556.05 -593301.76 -1141561.38</gml:posList>
</gml:ArcString>
</gml:segments>
</gml:Curve>
</gml:curveMember>
<gml:curveMember>
<gml:LineString gml:id="HPA.19737019010.3">
<gml:posList>-593301.76 -1141561.38 -593302.10 -1141572.54 -593304.49 -1141586.26 -593319.02 -1141583.37 -593319.60 -1
</gml:LineString>
</gml:curveMember>
</gml:Ring>
</gml:exterior>
</gml:Polygon>
_______________________________________________
Talk-cz mailing list
Talk-cz@openstreetmap.org
https://lists.openstreetmap.org/listinfo/talk-cz