User:Mga geo/osmapi.pl
Jump to navigation
Jump to search
#!/usr/bin/perl
#
# osmapi.pl
# auteur: Marc GAUTHIER
#
#
use strict;
use warnings;
use Carp;
use Data::Dumper;
use Utils;
select (STDERR);$|=1;
select (STDOUT);$|=1;
our $self->{DEBUG} = 0;
our $CommunesDir = '../35/communes/';
if ( ! -d $CommunesDir ) {
mkdir $CommunesDir;
}
my ( $sp );
$sp = 'xapi';
$sp = 'osm2kml';
warn "$0 sp:$sp";
my $sub = UNIVERSAL::can('main',"$sp");
if ( defined $sub ) {
&$sub(@ARGV);
} else {
warn "main sp:$sp inconnu";
}
exit;
# conversion de fichiers osm en fichier kml
# lit un fichier csv contenant les id des relations à prendre en compte
# le fichier correspondant à chaque id est lu
# pour chaque chemin/way, le segment est calculé
# ce segment est simplifié (diminution du nombre de points)
# le kml est généré
#
#
sub osm2kml {
my ( $oa, $id, $tag, %id,$nb_id, $i_id, $f_csv, $f_osm );
csv_hash("../35/communes.csv","id",\%id);
$nb_id = scalar(keys %id);
warn "osm2kml() nb_id:$nb_id";
$i_id = 0;
for $id ( keys %id ) {
$oa = new OsmApi;
$i_id++;
if ( $id{$id}->{'ref:INSEE'} ne '35288' ) {
# next;
}
warn "osm2kml() id:$id $i_id/$nb_id ref:INSEE:".$id{$id}->{'ref:INSEE'}." ".$id{$id}->{name};
if ( $id{$id}->{'ref:INSEE'} !~ /^\d{5}$/ ) {
confess;
}
$f_osm = "../35/communes/${id}.osm";
$oa->{osm} = '';
if ( ! -f $f_osm ) {
$oa->getRelation($id);
$oa->ecritOSM($f_osm);
}
if ( -f $f_osm ) {
$oa->litOSM($f_osm);
$oa->analyseOSM();
}
$oa->ajouteLigneWay();
$oa->osm2commune($CommunesDir.$id{$id}->{'ref:INSEE'}.".kml");
# $oa->clean();
# warn "osm2kml() nb_relations:".scalar(keys%{$oa->{relation}} );
if ( $i_id > 1000 ) {
last;
}
}
return;
$oa->ajouteLigneWay();
# $oa->{DEBUG} = 10;
$oa->osm2commune("../35/communes.kml");
}
# extraction avec xapi sur une zone
sub xapi {
my ( $oa, $id, $tag, %id,$nb_id, $i_id, $f_csv, $f_osm );
$oa = new OsmApi;
$oa->setBbox('-2.26,47.55,-1.02,48.75');
# $oa->setBbox('-1.7155,48.0256,-1.4645,48.2102');
$tag = 'relation';
$tag = 'node';
$oa->getXapi($tag);
$oa->ecritOSM("../35/bbbox_${tag}.osm");
return;
}
# http://www.openstreetmap.org/browse/relation/973226
sub grab {
my ( $oa, $id, $tag, %id,$nb_id, $i_id, $f_csv, $f_osm );
$oa = new OsmApi;
# $oa->setBbox('-2.26,47.55,-1.02,48.75');
# $oa->setBbox('-1.7155,48.0256,-1.4645,48.2102');
# liste des communes à partir de leur limites administratives
$oa->litOSM("../35/35_rel.osm");
$oa->analyseOSM();
$oa->{DEBUG} = 0;
my $csv = $oa->extraitCommunes();
putLignes("../35/communes.csv",$csv);
return;
# extraction avec xapi sur une zone
$tag = 'relation';
$tag = 'node';
$oa->getXapi($tag);
$oa->ecritOSM("../35/bbbox_${tag}.osm");
return;
# production du fichier kml pour une commune
$id = '78150'; # Cesson
$oa->litOSM("../35/${id}.osm");
$oa->analyseOSM();
# warn Dumper \$oa->{'way'};
# $oa->{DEBUG} = 1;
$oa->osm2commune("../35/${id}.kml");
return;
$oa->litOSM("../35/${id}.osm");
$id = '973226'; # Antrain
$oa->getRelation($id);
$oa->ecritOSM("../35/${id}.osm");
return;
}
#
# la partie requete http pour obtenir les informations
#
package OsmApi;
use strict;
use Carp;
use Data::Dumper;
use MIME::Base64;
use HTTP::Request::Common;
use LWP::UserAgent;
use URI;
use Encode;
use HTML::Entities;
use Poly;
sub new {
my( $class, %attr ) = @_;
my $self = {
DEBUG => 0,
};
bless($self, $class);
$self->{ua} = new LWP::UserAgent(agent => 'mgaClientV6', timeout => 120);
if( defined $attr{username} and defined $attr{password} ) {
# my $encoded = MIME::Base64::encode_base64("$attr{username}:$attr{password}","");
# $self->{ua}->default_header( "Authorization", "Basic $encoded" );
$self->{ua}->credentials('www.openstreetmap.org:80','Web Password',$attr{username},$attr{password});
}
# filtrage par boite ?
if( defined $attr{'bbox'} ) {
$self->setBbox($attr{'bbox'});
}
if ( defined $ENV{HTTP_PROXY} ) {
$self->{ua}->proxy(['http'], $ENV{HTTP_PROXY});
}
$self->{osm} = <<'EOF';
<?xml version='1.0' encoding="UTF-8"?>
<osm version="0.6" generator="perl OsmApi">
EOF
return $self;
}
sub clean {
$self->{osm} = '';
$self->{kml} = '';
$self->{'content'} = '';
undef $self->{ways};
undef $self->{way};
undef $self->{nodes};
undef $self->{node};
for my $id ( keys %{$self->{relation}} ) {
delete$self->{relation}{$id};
}
warn "clean() nb_relations:".scalar(keys%{$self->{relation}} );
}
#
# mise en place de la boite englobante
sub setBbox {
my $self = shift;
my $bbox = shift;
my ($minlon, $minlat, $maxlon, $maxlat) = split(",", $bbox);
if ( not defined($maxlon) ) {
confess "setBbox($bbox) mauvais format";
}
if ( $maxlon < $minlon ) {
confess "setBbox($bbox) $maxlon < $minlon";
}
if ( $maxlat < $minlat ) {
confess "setBbox($bbox) ($maxlat < $minlat";
}
$self->{'bbox'} = $bbox;
($self->{minlat}, $self->{minlon}, $self->{maxlat}, $self->{maxlon} ) = ($minlat, $minlon, $maxlat, $maxlon);
}
#
# mise en place de la boite englobante
sub LatLoninBbox {
my ($self, $lat, $lon) = @_;
if ( not defined $self->{maxlon} ) {
return 1;
}
return 0 if (($lat < $self->{minlat}) || ($lat > $self->{maxlat}));
return 0 if (($lon < $self->{minlon}) || ($lon > $self->{maxlon}));
return 1
}
#
# écrit le fichier osm
sub ecritOSM {
my $self = shift;
my $f_osm = shift;
# ajout des tags xml et osm si besoin
if ( $self->{osm} !~ m{^<\?xml} ) {
$self->{osm} = <<'EOF' . $self->{osm};
<?xml version='1.0' encoding="UTF-8"?>
<osm version="0.6" generator="perl OsmApi">
EOF
}
if ( $self->{osm} !~ m{</osm>} ) {
$self->{osm} .= <<'EOF';
</osm>
EOF
}
# open(OSM, ">:encoding(UTF-8)", $f_osm) or confess "ecritOSM() open(OSM, >:encoding(UTF-8), $f_osm) erreur:$!";
open(OSM, ">", $f_osm) or confess "ecritOSM() open(OSM, $f_osm) erreur:$!";
print OSM $self->{osm};
close(OSM);
warn "ecritOSM() $f_osm";
$self->{osm} = '';
}
# lit le fichier osm
sub litOSM {
my $self = shift;
my $f_osm = shift;
warn "litOSM($f_osm)";
open(OSM, $f_osm) or confess "litOSM() open(OSM, $f_osm) erreur:$!";
$self->{osm} = join('',<OSM>);
$self->{'content'} = $self->{'osm'};
close(OSM);
}
#
# un get en http
# met à jour $self->{content}
sub get {
my $self = shift;
my $url = shift;
warn "get($url)";
my $req = new HTTP::Request 'GET' => $url;
my $res = $self->{ua}->request($req);
$self->{content} = '';
if ($res->is_success) {
$self->{content} = $res->content;
} else {
warn "get($url) Error: " . $res->status_line;
}
$self->{content} =~ s{.*generator="OpenStreetMap server">.}{}s;
$self->{content} =~ s{</osm>.*}{}s;
$self->{osm} .= $self->{content};
# confess $self->{content};
}
#
# extraction des communes:
# relations avec admin_level=8
sub extraitCommunes {
my $self = shift;
my $relation = $self->{relation};
my $csv = '';
$csv .= sprintf("%s;%s;%s\n","id","name","ref:INSEE");
for my $relation_id ( keys %{$self->{relation}} ) {
# type=boundary,
if ( not defined $self->{relation}->{$relation_id}{tag}{'admin_level'} ) {
next;
}
if ( $self->{relation}->{$relation_id}{tag}{'admin_level'} != 8 ) {
next;
}
if ( not defined $self->{relation}->{$relation_id}{tag}{'ref:INSEE'} ) {
warn "relation_id:$relation_id manque ref:INSEE";
next;
}
if ( $self->{relation}->{$relation_id}{tag}{'ref:INSEE'} !~ m{^35} ) {
next;
}
$csv .= sprintf("%s;%s;%s\n",$relation_id,$self->{relation}->{$relation_id}{tag}{'name'},$self->{relation}->{$relation_id}{tag}{'ref:INSEE'});
warn"extraitCommunes() relation_id:$relation_id name:". $self->{relation}->{$relation_id}{tag}{'name'}
. " ref:INSEE:". $self->{relation}->{$relation_id}{tag}{'ref:INSEE'} if $self->{'DEBUG'};
}
return $csv;
}
# http://wiki.openstreetmap.org/wiki/API_v0.6
#
# recuperation des communes:
# relations avec admin_level=8
sub getXapi {
my $self = shift;
my $tag = shift;
# on augmente le time-out à 4 minutes
$self->{ua}->timeout(240);
if ( $tag eq 'relation' ) {
$self->get("http://xapi.openstreetmap.org/api/0.6/relation[admin_level=8][bbox=$self->{bbox}]");
}
if ( $tag eq 'node' ) {
$self->get("http://xapi.openstreetmap.org/api/0.6/node[place=town|city|village|hamlet][bbox=$self->{bbox}]");
}
}
# http://wiki.openstreetmap.org/wiki/API_v0.6
#
# récuperation d'une relation
sub getRelation {
my $self = shift;
my $id = shift;
my $element = 'relation';
@{$self->{ways}} = ();
$self->get("http://www.openstreetmap.org/api/0.6/$element/$id/full");
$self->analyseOSM();
my $nb_ways = scalar( @{$self->{ways}}) ;
warn "getRelation() nb_ways: $nb_ways";
return;
# warn Dumper $self->{relation};
# parcours des membres (way) à la recherche des noeuds
#
@{$self->{nodes}} = ();
for my $way_id ( @{$self->{ways}} ) {
$self->get("http://www.openstreetmap.org/api/0.6/way/$way_id");
$self->analyseOSM();
}
my $nb_nodes = scalar( @{$self->{nodes}}) ;
warn "getRelation() nb_nodes: $nb_nodes";
# return;
# un noeud peut appartenir à deux ways
my $i_nodes = 0;
for my $node ( @{$self->{nodes}} ) {
$i_nodes++;
warn "getRelation() $i_nodes/$nb_nodes";
$self->get("http://www.openstreetmap.org/api/0.6/node/$node");
# return;
}
}
#
# analyse d'une réponse OSM au format xml
# les différentes informations sont remontées dans des hashes: relation, way, node
# l'id sert d'index
sub analyseOSM {
my $self = shift;
warn "analyseOSM() debut nb_relations:".scalar(keys %{$self->{relation}});
my ( %element, $element, $id, @attr, $attr, $tags, $line, $regexp );
$regexp = 'node|way|relation';
if ( @_ ) {
$regexp = 'relation';
$regexp = shift;
}
$element = '';
for $line ( split("\n",$self->{content}) ) {
# un nouvel objet
if ( $line =~ m{^\s*<($regexp).*\sid=["']([^"']+)["']} ) {
$element = $1;
$id = $2;
$element{$element}++;
warn "analyseOSM() object:$element id:$id" if $self->{DEBUG};
# on l'a déjà eu! on recommence
if ( defined $self->{$element}->{$id} ) {
delete $self->{$element}->{$id};
}
$attr = {};
$tags = {};
# les attributs
@attr = $line =~ m{(\w+)=['"](.*?)['"]}g;
while ( @attr ) {
my $key = shift @attr;
my $value = shift @attr;
$self->{$element}->{$id}->{$key} = $value;
}
# la mémorisation de la lonlat pour les nodes
if ( $element eq 'node' ) {
if ( $self->LatLoninBbox($self->{$element}->{$id}->{lat},$self->{$element}->{$id}->{lon}) ) {
$self->{$element}->{$id}->{lonlat} = $self->{$element}->{$id}->{lon} . ',' . $self->{$element}->{$id}->{lat};
} else {
delete $self->{$element}->{$id};
warn "analyseOSM() hors zone:$element $id ";
}
}
next;
}
# la fin d'un object
if ( $element ne '' && ( $line =~ m{^\s*</(node|way|relation)} or $line =~ m{^\s*<(node|way|relation).*/>} ) ) {
$element = '';
next;
}
# node ref
if ( $element eq 'way' && $line =~ /^\s*<nd.*\sref=["']([^"']+)["']/ ) {
push @{$self->{nodes}}, $1;
push @{$self->{$element}->{$id}->{ref}}, $1;
next;
}
# les membres des relations
if ( $element eq 'relation' && $line =~ /^\s*<member/ ) {
# les attributs
@attr = $line =~ m{(\w+)=['"](.*?)['"]}g;
$attr = {};
while ( @attr ) {
my $key = shift @attr;
my $value = shift @attr;
$attr->{$key} = $value;
}
# on mémorise les ways pour recherche ultérieure
if ( defined $attr->{'type'} && $attr->{'type'} eq 'way' ) {
push @{$self->{ways}}, $attr->{'ref'};
}
# push @{$self->{$element}->{$id}->{ref}}, $attr;
warn "analyseOSM() $element:$id $line ref:".$attr->{'ref'} if $self->{'DEBUG'};
push @{$self->{$element}->{$id}->{ref}}, $attr->{'ref'};
next;
}
# les tags des relations
# <tag k='admin_level' v='8'/>
if ( $element eq 'relation' && $line =~ /^\s*<tag k=["']([^']+)["'] v=["']([^']+)["']/) {
warn "analyseOSM() $element:$id tag $1=>$2" if ( $self->{'DEBUG'} );
$tags->{$1} = $2;
$self->{$element}->{$id}->{tag}->{$1} = $2;
next;
}
}
warn "analyseOSM() fin nb_relations:".scalar(keys %{$self->{relation}})." nb_nodes:".$element{'node'};
}
sub osm2commune {
my $self = shift;
my $f_kml = shift;
warn "osm2commune() nb_relations:".scalar(keys%{$self->{relation}} );
$self->kml_debut();
for my $relation_id ( keys %{$self->{relation}} ) {
$self->kml_commune($relation_id);
}
$self->kml_fin($f_kml);
}
# ---------------------------------------------------------------------------------------------
#
# l'entête du fichier kml
sub kml_debut {
my $self = shift;
$self->{kml} = <<'EOF';
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.2">
<Document>
<name>OSM admin-level=8</name>
<author>
<name>Marc Gauthier</name>
</author>
<Style id="orange">
<LineStyle>
<color>ff00aaff</color>
<width>2</width>
</LineStyle>
<PolyStyle>
<color>660020e0</color>
</PolyStyle>
</Style>
<Folder>
<name>Contours</name>
<open>0</open>
EOF
}
#
# la fin du fichier kml
sub kml_fin {
my $self = shift;
my $f_kml = shift;
$self->{kml} .= <<'EOF';
</Folder>
</Document>
</kml>
EOF
# open(KML,">:encoding(UTF-8)", "$f_kml") or die "open(KML,>$f_kml) erreur:$!";
open(KML,">", "$f_kml") or die "open(KML,>$f_kml) erreur:$!";
print KML $self->{kml};
close(KML);
warn "kml_fin() f_kml: $f_kml";
}
#
# le kml pour une commune
# le contour de la commune est constitué de plusieurs lignes
# deux méthodes, on les met dans une MultiGeometry
# - LineString
# - Polygon
# Cas difficile: les role="exclave"
# plusieurs polygones
# 909651;Tresbœuf;35343 une enclave
# 905534;Saint-Malo;35288 les îles
# 145072;Saint-Briac-sur-Mer;35256
# 108303;Cancale;35049
# Iffendic: - 2 trous au sud de Boisgervilly, à l'ouest d'Iffendic
# http://wiki.openstreetmap.org/wiki/Relation:boundary
# http://code.google.com/p/pyosm/source/browse/tools/osm2mp-preprocess.py?spec=svnf33b378075455c4963d1d712dd5fd0528b6cec3d&r=f33b378075455c4963d1d712dd5fd0528b6cec3d
# http://wiki.openstreetmap.org/wiki/Key:place
# http://wiki.openstreetmap.org/wiki/FR:Key:place
sub kml_commune {
my $self = shift;
my $relation_id = shift;
if ( not defined $self->{relation}->{$relation_id}{tag}{'name'} ) {
confess Dumper $self->{relation}->{$relation_id};
}
if ( $self->{relation}->{$relation_id}{tag}{'admin_level'} ne 8 ) {
return;
}
warn "kml_commune() $relation_id:".$self->{relation}->{$relation_id}{tag}{'name'};
my ( $kml_multi, $kml_line );
$self->{kml} .= <<EOF;
<Placemark>
<desc>$self->{relation}->{$relation_id}{tag}{'name'}</desc>
<name>$self->{relation}->{$relation_id}{tag}{'ref:INSEE'}</name>
<styleUrl>#orange</styleUrl>
EOF
$kml_multi = <<EOF;
<MultiGeometry>
EOF
my ( %segment, @segment, $deb, $fin, %coord, $coord, $way_id, @ajout );
warn "kml_commune() relation_id:$relation_id nb_ref:".scalar(@{$self->{relation}->{$relation_id}{'ref'}}) if $self->{DEBUG};
for $way_id ( @{$self->{relation}->{$relation_id}{'ref'}} ) {
warn "kml_commune() relation_id:$relation_id way_id:$way_id" if $self->{DEBUG};
if ( not defined $self->{way}->{$way_id} ) {
warn "kml_commune() relation_id:$relation_id way_id:$way_id absent" if $self->{DEBUG};
# confess Dumper $self->{way};
next;
}
if ( not defined $self->{way}->{$way_id}{'coord'} ) {
next;
}
warn "kml_commune() relation_id:$relation_id way_id:$way_id nb_nodes:".scalar(@{$self->{way}->{$way_id}{'coord'}}) if $self->{DEBUG};
$kml_multi .= <<EOF;
<LineString><coordinates>
EOF
$kml_multi .= join("\n",@{$self->{way}->{$way_id}{'coord'}});
$kml_multi .= <<EOF;
</coordinates></LineString>
EOF
$deb = $self->{way}->{$way_id}{'coord'}[0];
$fin = $self->{way}->{$way_id}{'coord'}[-1];
warn "kml_commune() relation_id:$relation_id way_id:$way_id deb:$deb fin:$fin nb_coord:".scalar(@{$self->{way}->{$way_id}{'coord'}}) if $self->{DEBUG};
$coord{$way_id}{'deb'} = $deb;
$coord{$way_id}{'fin'} = $fin;
}
$kml_multi .= <<EOF;
</MultiGeometry>
</Placemark>
EOF
# assemblage des lignes en polygone
# on commence avec la première ligne récupérée, !!! hors exclave !!!
# on peut avoir plusieurs polygones!!! les exclaves
# @lignes contient les way_id des différentes lignes
# @segment contient le polygone en cours de construction
# $self->{DEBUG} = 1;
my ( @lignes );
@segment = ( 0,0 );
my @polygone = ();
# warn Dumper \%coord if $self->{DEBUG};
warn "kml_commune() relation_id:$relation_id nb_lignes:",scalar(@lignes) if $self->{DEBUG};
my $i_polygone = -1;
for ( my $i=0; $i <1000;$i++ ) {
# warn Dumper \@segment;
warn "kml_commune() relation_id:$relation_id i:$i polygone de nb_segment:".scalar(@segment) if $self->{DEBUG};
$i_polygone++;
$polygone[$i_polygone] = [@segment];
@lignes = keys %coord;
if ( @lignes ) {
$way_id = shift @lignes;
delete $coord{$way_id};
@segment = @{$self->{way}->{$way_id}{'coord'}};
} else {
warn "kml_commune() relation_id:$relation_id i:$i plus de lignes" if $self->{DEBUG};
last;
}
# ajout de lignes tant que c'est possible
# il faut rechercher la way_id qui commence ou fini avec ces coordonnées
for ( my $j=0; $j < 1000; $j++) {
if ( $segment[0] eq $segment[-1] ) {
last;
}
$fin = $segment[-1];
warn "kml_commune() relation_id:$relation_id i:$i nb_segments:".scalar(@segment)." reste nb_lignes:".scalar(@lignes) if $self->{DEBUG};
@ajout = ();
for $way_id ( keys %coord ) {
# le segment est dans le bon ordre
if ( $coord{$way_id}{'deb'} eq $fin ) {
warn "kml_commune() relation_id:$relation_id i:$i fin:$fin ajout bon ordre de way_id:$way_id" if $self->{DEBUG};
delete $coord{$way_id};;
@ajout = @{$self->{way}->{$way_id}{'coord'}};
last;
}
# le segment est dans le mauvais ordre
if ( $coord{$way_id}{'fin'} eq $fin ) {
warn "kml_commune() relation_id:$relation_id i:$i fin:$fin ajout ordre inverse way_id:$way_id" if $self->{DEBUG};
delete $coord{$way_id};;
@ajout = reverse(@{$self->{way}->{$way_id}{'coord'}});
last;
}
}
if ( @ajout ) {
if ( $ajout[0] ne $segment[-1] ) {
warn "kml_commune() relation_id:$relation_id i:$i BUG";
confess Dumper \@ajout;
}
shift @ajout;
warn "kml_commune() relation_id:$relation_id i:$i ajout nb_segments:",scalar(@ajout) if $self->{DEBUG};
push @segment, @ajout;
} else {
last;
}
}
}
shift @polygone;
# confess Dumper \@polygone;
$self->{kml} .= <<EOF;
<MultiGeometry>
EOF
warn "kml_commune() nb_polygone:",scalar(@polygone) if $self->{DEBUG};
for my $segment ( @polygone ) {
@segment = @{$segment};
# début égal à la fin ?
$coord = join("\n",@segment);
$kml_line = <<EOF;
<LineString>
<coordinates>
$coord
</coordinates>
</LineString>
EOF
$kml_line = <<EOF;
<Polygon>
<outerBoundaryIs>
<LinearRing>
<coordinates>
$coord
</coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
EOF
# confess Dumper \@segment;
$self->{kml} .= $kml_line;
}
$self->{kml} .= <<EOF;
</MultiGeometry>
</Placemark>
EOF
$self->{nb_placemark}++;
}
#
# transformation des noeuds d'une way en une ligne
sub ajouteLigneWay {
my $self = shift;
warn "ajouteLigneWay debut nb_ways:".scalar(keys %{$self->{way}});
my ( $way_id, $node_id );
for $way_id ( keys %{$self->{way}} ) {
warn "ajouteLigneWay way_id:$way_id" if $self->{DEBUG};
@{$self->{way}->{$way_id}{'coord'}} = ();
for $node_id ( @{$self->{way}->{$way_id}->{ref}} ) {
if ( not defined $self->{node}->{$node_id} ) {
warn "ajouteLigneWay way_id:$way_id node_id:$node_id absent" if $self->{DEBUG};
next;
}
push @{$self->{way}->{$way_id}{'coord'}},$self->{node}->{$node_id}->{lonlat};
}
$self->Douglas_Peucker($way_id);
}
}
#
# diminution du nombre de points
sub Douglas_Peucker {
my $self = shift;
my $way_id = shift;
my ( @Ipoints, @Opoints, $lon, $lat, $coord, @reste);
@Ipoints = ();
for $coord ( @{$self->{way}{$way_id}->{coord}} ) {
($lon, $lat, @reste) = split ',', $coord;
push( @Ipoints, [$lat,$lon] ) ;
}
@Opoints = Poly::Douglas_Peucker( \@Ipoints, 100 ) ;
# warn "Douglas_Peucker() ".scalar(@Ipoints)."=>".scalar(@Opoints);
@{$self->{way}{$way_id}->{coord}} = ();
for $coord ( @Opoints ) {
# confess Dumper \$coord;
push @{$self->{way}{$way_id}->{coord}},$coord->[1].",".$coord->[0];
}
}