Salut tout le monde

Je viens de me mettre à l'import de bâti, en suivant les instructions de :
http://wiki.openstreetmap.org/wiki/WikiProject_France/Cadastre/Import_semi-automatique_des_b%C3%A2timents

Après plusieurs heures de dur labeur, ça marchotte sur mon Mac. La plupart des 
problèmes étaient liés à l'installation de GDAL et de l'interface Perl 
correspondante, ce qui marche maintenant à 100%.
Ce qui a été très frustrant, c'est que les liens pour télécharger les fichiers 
OSM tout prêts étaient indiqués tout à la fin de la page. Tout mon travail pour 
faire marcher les scripts était donc limite inutile.... J'ai mis les liens en 
haut de la page pour éviter la même chose aux suivants.

Pour ce qui est des scripts eux-même, voilà ce que j'ai trouvé :

- globalement, il faudrait fusionner les 2 scripts (bash et Perl) en un seul en 
Perl    
D'une part la compatibilité est problématique (sur mon Mac, j'ai du changer des 
[ ] en [[ ]], ainsi que des appels à sed ), mais en plus ça rendrait le code 
plus lisible et donc maintenable
Je joins d'ailleurs ma version des scripts.

- pour le "surface0" qui est codé en dur, chez moi c'est "surface1" dans les 
SVG que je retrouve. J'ai du changé le code en conséquence.

- pour la bbox, chez moi elle a un contour blanc mais pas de fill noir, et elle 
n'est donc pas reconnue par le script. Les fichiers OSM générés sont donc 
vides. Le code que j'utilise :

        if ( $#bbox_pts != 3 && $elt eq "path" ) {
            my $s = $atts{'d'};
                my @points = lire_points (\$s,@m);
                warn "bbox has $#points" if $#points != 3;
        @bbox_pts = minmax(@points);
        return;
        }

- après ces modifications, j'arrive à avoir des fichiers OSM qui contiennent 
quelque chose, par contre beaucoup de ways (buildings...) ne sont pas fermés. 
Je regarderai ça quand je pourrais, mais peut-être que quelqu'un a une idée ?

a+

Olivier
#!/usr/bin/perl
# WTFPLv2 [http://sam.zoy.org/wtfpl/]
use strict;
use XML::Parser;
use Geo::OSR;
use Getopt::Std;
use Data::Dumper;

our ($opt_p,$opt_b,$opt_r,$opt_w,$opt_l,$opt_t);
getopts("l:p:b:r:w:t:");
unless ($opt_p || $opt_b || $opt_r || $opt_w || $opt_l || $opt_t) {
# Options par defaut, on affiche les limites administratives, le bati,
# les waterway et les riverbank sur la sortie standard
    $opt_b = $opt_r = $opt_w = $opt_t = "-";
}

# Associe chaque nom de fichiers avec son filehandler.
my %files;

sub handle_opts {
    my ($str) = @_;
    if (defined($str) && !defined($files{$str})) {
	my $filehandle;
	open($filehandle,">$str") or die "Impossible d'ouvrir : $!";
	$files{$str} = \$filehandle;
    }
    return $files{$str};
}

# Imprime une chaîne de caractères sur tous les fichiers ouverts
sub print_files {
    my ($str) = @_;
    if (%files) {
	for my $file (keys %files) {
	    print {${$files{$file}}} $str;
	}
    }
    else {
	print STDOUT $str;
    }
}

handle_opts($opt_l);
handle_opts($opt_p);
handle_opts($opt_b);
handle_opts($opt_r);
handle_opts($opt_w);
handle_opts($opt_t);

if (($#ARGV % 5) != 0) {
    print "Usage: svg-parser.pl (-lpbrwt) [IGNF] [[fichier.svg] [bbox] ..]\n";
    exit;
}

my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
my $tag_source = "cadastre-dgi-fr source : Direction Générale des Impôts - Cadastre. Mise à jour : " . ($year + 1900);
my $tag_version = "v0.3";

# Identifie à quoi correspond chaque couleur de remplissage du svg
my %couleurs_remplissage = ("ffffff" => "bbox",
			    # rgb(100%,89.802551%,59.999084%) ffe599
			    "ffe599" => "building_nowall",
			    # rgb(100%,79.998779%,19.999695%) ffcc33
			    "ffcc33" => "building",
			    # fill:rgb(59.606934%,76.470947%,85.488892%) 98c3da
			    "98c3da" => "water",
			    # fill:rgb(10.195923%,47.842407%,67.449951%) 1a7aac
			    "1a7aac" => "riverbank"
    );

# Identifie à quoi correspond chaque objet qui ne peut être identifié
# uniquement grâce à sa couleur de remplissage
# Pour les ways fermés
my %style_closed = (
    "fill:none;stroke-width:0.77;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" => "parcelle",
    "fill:none;stroke-width:18;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(100%,100%,100%);stroke-opacity:1;stroke-miterlimit:10;" => "limite"
    );

# Pour les ways ouverts
my %style_opened = (
    "fill:none;stroke-width:0.77;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:17.72,11.82;stroke-miterlimit:10;" => "trottoir",
    "fill:none;stroke-width:0.77;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:5.9,5.9;stroke-miterlimit:10;" => "trottoir",
    "fill:none;stroke-width:3.55;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" => "train",
    "fill:none;stroke-width:0.77;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:5.9,11.82;stroke-miterlimit:10;" => "footpath"
    );

my %tags = ("building" =>        " <tag k=\"building\" v=\"yes\"/>\n",
	    "building_nowall" => " <tag k=\"building\" v=\"yes\"/>\n"
	                       . " <tag k=\"wall\" v=\"no\"/>\n",
	    # La couleur ne permet pas de différencier une piscine, d'une mare, d'une fontaine, d'un lac
	    "water" =>           " <tag k=\"natural\" v=\"water\"/>\n",
	    "riverbank" =>       " <tag k=\"waterway\" v=\"riverbank\"/>\n",
	    "parcelle" =>        " <tag k=\"natural\" v=\"land\"/>\n",
	    "limite" =>          " <tag k=\"boundary\" v=\"administrative\"/>\n",
	    "trottoir" =>        " <tag k=\"man_made\" v=\"sidewalk\"/>\n",
	    "train" =>           " <tag k=\"railway\" v=\"rail\"/>\n",
	    "footpath" =>        " <tag k=\"highway\" v=\"footpath\"/>\n"
    );

our @bbox_lbr93;
our @bbox_pts;
# Hash qui à chaque point associe une ref
my %points;
my @ways;
my @relations;
my $refnodes = 0;
my $refways = 0;
my $refrel = 0;

my $source = Geo::OSR::SpatialReference->create ();
my $target = Geo::OSR::SpatialReference->create ();

$source->ImportFromProj4("+init=IGNF:" . shift . " +wktext");
$target->ImportFromEPSG ('4326');

my $transf = new Geo::OSR::CoordinateTransformation ($source, $target);

my $parser = new XML::Parser ( Handlers => {
    Start => \&hdl_start,
    End   => \&hdl_end,
    Default => \&hdl_def
			       });
my $surface = 0;
my $profondeur_groupe = 0;

sub hdl_start {
    my  ($p, $elt, %atts) = @_;
    print "hdl_start" . Dumper($p, $elt, \%atts) . "\n";
    $profondeur_groupe++ if ($surface == 1 && $elt eq 'g');
    $surface = 1  if ($surface == 0 && $elt eq 'g' && $atts{'id'} eq 'surface1');
    if ($surface && $elt eq 'path' )
    {
	my @m  = get_matrix ($atts{'transform'});

	if ( $#bbox_pts != 3 && $elt eq "path" ) {
	    my $s = $atts{'d'};
		my @points = lire_points (\$s,@m);
		warn "bbox has $#points" if $#points != 3;
    	@bbox_pts = minmax(@points);
    	return;
	}

	if ($atts{'style'} =~ m/fill:rgb\(/)
	{
	    print "style=" . $atts{'style'} . "\n";
	    my ($rouge,$vert,$bleu) = ($atts{'style'} =~ m/fill:rgb\((\d*\.?\d*)%,(\d*\.?\d*)%,(\d*\.?\d*)%\)/);
	    my $couleur_hexa = (hexa ($rouge)).(hexa ($vert)).(hexa ($bleu));

	    my $type = $couleurs_remplissage{$couleur_hexa};
	    print "couleur_hexa=" . $couleur_hexa. "\n";
	    print "type=" . $type. "\n";
        
        # print "$couleurs_remplissage{$couleur_hexa} . "\n";
	    my $s = $atts{'d'};
	    if (defined($type)) {
		my @points = lire_points (\$s,@m);

	    print "points=" . Dumper(\...@points) . "\n";
        print "#bbox_pts=" . $#bbox_pts . "\n";
        print "#points=" . $#points . "\n";
        print "est_dans_bbox=" . est_dans_bbox(@points) ."\n";
		if ($#bbox_pts != 3) {
		    if ($type eq "bbox")
		    {
			@bbox_pts = minmax(@points);
		    }
		}
		else
		{
		    if (($#points >= 0) && est_dans_bbox(@points))
		    {
			my $ref = new_rel("multipolygon");
			rel_add_way($ref,new_way($type,\...@points)) if ($#points >= 0);
			while ($s =~ m/M (-?\d*\.?\d*) (-?\d*\.?\d*) L/)
			{
			    my @points = lire_points (\$s,@m);
# Le signe de la référence au way indique le sens d'orientation du polygone
			    rel_add_way($ref,(-1+2*(aire_polygone(@points)>0)) * new_way($type,\...@points)) if ($#points >= 0);
			}
		    }
		}
	    }
	}
	elsif ($#bbox_pts == 3)
	{
	    $atts{'style'} =~ s/^ *//;
	    $atts{'style'} =~ s/ *$//;
	    my $type;
	    if ($atts{'d'} =~ m/Z/) {
		$type = $style_closed{$atts{'style'}};
	    }
	    else {
		$type = $style_opened{$atts{'style'}};
	    }
	    if (defined($type)) {
		my $s = $atts{'d'};
		my @points = lire_points (\$s,@m);
		if (est_dans_bbox(@points)) {
		    my $ref = new_rel("multipolygon");
		    rel_add_way($ref,new_way($type,\...@points)) if ($#points >= 0);
		    while ($s =~ m/M (-?\d*\.?\d*) (-?\d*\.?\d*) L/)
		    {
			my @points = lire_points (\$s,@m);
			rel_add_way($ref,new_way($type,\...@points)) if ($#points >= 0);
		    }
		}
	    }
	}
    }
}

sub hdl_end {
    my  ($p, $elt, %atts) = @_;
    if ($surface == 1 && $elt eq 'g') {
	if ($profondeur_groupe == 0) {
	    $surface = 0;
	    @bbox_pts = ();
	}
	else {
	    $profondeur_groupe--;
	}
    }
}

sub hdl_def {}

sub lire_points {
    my ($s,@m) = @_;
    my @points;
    return unless $$s =~ s/^M //;
    $points[0] = transform_point ($s,@m);
    my $i = 1;
    while ($$s =~ s/^L //)
    {
	$points[$i] = transform_point ($s,@m);
	$i += 1;
    }
    $$s =~ s/^Z //;
    return @points
}

# Transforme les coordonnées d'un point pris à la tête d'une chaîne
# pour obtenir des coordonnées en Lambert93
sub transform_point {
    my ($s,@m) = @_;
    my $p;

    ($p->[0],$p->[1]) = $$s =~ m/(-?\d*\.?\d*) (-?\d*\.?\d*) ?/;
    $$s =~ s/(-?\d*\.?\d*) (-?\d*\.?\d*) ?//;

    # Transformations dues à la matrice associées au path
    ($p->[0],$p->[1]) = (
	($m[0]*$p->[0] +  $m[2]*$p->[1] + $m[4]),
	($m[1]*$p->[0] +  $m[3]*$p->[1] + $m[5]));

    if ($#bbox_pts == 3)
    {
	# On "convertit" les coordonnées à partir du référentiel du
	# pdf (en pts) vers du LAMBERT93
	($p->[0],$p->[1]) = (
	    (($p->[0]
	      - $bbox_pts[0]) * ($bbox_lbr93[2]-$bbox_lbr93[0])/($bbox_pts[2]-$bbox_pts[0])
	     + $bbox_lbr93[0]),
	    (($p->[1]
	      - $bbox_pts[1]) * ($bbox_lbr93[1]-$bbox_lbr93[3])/($bbox_pts[3]-$bbox_pts[1])
	     + $bbox_lbr93[3])
	    );
    }
    # Si la bbox n'a pas encore été définie, on retourne les
    # coordonnées brutes, dans le référentiel du pdf
    return $p;
}

sub get_matrix {
    my ($s) = @_;
    return split (/,/, $s) if $s =~ s/matrix\((.*)\)/$1/;
    return (1,0,0,1,0,0)
}

sub minmax {
    my @nodes = @_;
    my ($xmin,$ymin,$xmax,$ymax);
    my $node;
    foreach $node (@nodes) {
	$xmin = $node->[0] if (!defined($xmin) || $node->[0] < $xmin);
	$ymin = $node->[1] if (!defined($ymin) || $node->[1] < $ymin);
	$xmax = $node->[0] if (!defined($xmax) || $node->[0] > $xmax);
	$ymax = $node->[1] if (!defined($ymax) || $node->[1] > $ymax);
    }
    return ($xmin,$ymin,$xmax,$ymax)
}

# Teste si le premier node d'un way se trouve dans la bbox, si il est
# sur un bord, teste le point suivant, si tous les points sont sur des
# bords retourne vrai
sub est_dans_bbox {
    my @nodes = @_;
    for my $node (@nodes) {
	if ($node->[0] >= $bbox_lbr93[0] &&
	    $node->[1] >= $bbox_lbr93[1] &&
	    $node->[0] <= $bbox_lbr93[2] &&
	    $node->[1] <= $bbox_lbr93[3])
	{
	    if (!($node->[0] == $bbox_lbr93[0] ||
		  $node->[1] == $bbox_lbr93[1] ||
		  $node->[0] == $bbox_lbr93[2] ||
		  $node->[1] == $bbox_lbr93[3]))
	    {
		return 1;
	    }
	}
	else
	{
	    return 0;
	}
    }
    return 1;
}

# Retourne l'aire d'un polygone * 2 (peut servir à déterminer le sens)
sub aire_polygone
{
    my (@points) = @_;
    my $somme;

    for my $i (0..$#points) {
	$somme += $points[$i-1][0]*$points[$i][1] - $points[$i][0]*$points[$i-1][1];
    }
    return $somme;
}

# Transforme un pourcentage en sa valeur héxadécimale (de 00 à ff)
sub hexa {
    my ($pourcent) = @_;
    # on arrondi au plus proche car sinon sprintf prend la valeur tronquée
    return sprintf("%02x", int ($pourcent * 255 / 100 + 0.5));
}

sub new_point {
    my ($lat,$lon,$type) = @_;
    my $str = sprintf("%.2f,%.2f",$lon,$lat);
    if (defined($points{$str}))
    {
	push @{$points{$str}{"type"}}, $type;
	return $points{$str}{"ref"};
    }
    else
    {
	$points{$str}{"coord"} = [$lon,$lat];
	$points{$str}{"ref"} = $refnodes;
	$points{$str}{"type"} = [$type];
	return $refnodes++;
    }
}

sub new_way {
    my ($type,$points) = @_;
    my %way;
    $way{"type"} = $type;
    $way{"ref"} = $refways;
    foreach my $node (@$points) {
	my ($lon,$lat) = ($node->[0],$node->[1]);
	push @{$way{"nodes"}}, new_point($lat,$lon,$type);
    }
    $ways[$refways] = \%way;
    return $refways++;
}

sub new_rel {
    my ($type) = @_;
    my %rel;
    $rel{"type"} = $type;
    $rel{"ref"} = $refrel;
    $relations[$refrel] = \%rel;
    return $refrel++;
}

sub rel_add_way {
    my ($ref,@ways) = @_;
    push @{$relations[$ref]{"ways"}},@ways;
}

my @points_imprimes = ();
my @ways_imprimes = ();
sub print_point
{
    my ($lon,$lat,$ref,$file) = @_;
    if (defined($file) && !defined($points_imprimes[$ref]{$file}))
    {
	($lon,$lat) = @{$transf->TransformPoint ($lon,$lat)};
	print {${$files{$file}}} "<node id=\"" , -1-$ref , "\" lat=\"$lat\" lon=\"$lon\"/>\n";
	$points_imprimes[$ref]{$file} = 1;
    }
}

sub print_way
{
    my ($ref_way,$file,$type,$tag) = @_;
    if (defined($file) && !defined($ways_imprimes[$ref_way]{$file})) {
	print {${$files{$file}}} "<way id=\"" , -1-$ref_way , "\">\n";
	foreach my $ref_node (@{$ways[$ref_way]{"nodes"}})
	{
	    print {${$files{$file}}} " <nd ref=\"" , -1-$ref_node , "\"/>\n";
	}
	print {${$files{$file}}} $tags{$type} if $tag;
	print {${$files{$file}}} " <tag k=\"source\" v=\"$tag_source\"/>\n";
	print {${$files{$file}}} " <tag k=\"note:import-bati\" v=\"$tag_version\"/>\n";
	print {${$files{$file}}} "</way>\n";
    }
}

# Traite chaque fichier associé à sa bbox dans l'ordre des arguments
my @bbox_lbr93_glob;
while (@ARGV) {
    my $fichier = shift;
    $bbox_lbr93[0] = shift;
    $bbox_lbr93[1] = shift;
    $bbox_lbr93[2] = shift;
    $bbox_lbr93[3] = shift;

    print "bbox_lbr93=" . Dumper(\...@bbox_lbr93) . "\n";
# Calcule la bbox globale
    $bbox_lbr93_glob[0] = $bbox_lbr93[0]
	if (!defined($bbox_lbr93_glob[0]) || $bbox_lbr93[0] < $bbox_lbr93_glob[0]);
    $bbox_lbr93_glob[1] = $bbox_lbr93[1]
	if (!defined($bbox_lbr93_glob[1]) || $bbox_lbr93[1] < $bbox_lbr93_glob[1]);
    $bbox_lbr93_glob[2] = $bbox_lbr93[2]
	if (!defined($bbox_lbr93_glob[2]) || $bbox_lbr93[2] > $bbox_lbr93_glob[2]);
    $bbox_lbr93_glob[3] = $bbox_lbr93[3]
	if (!defined($bbox_lbr93_glob[3]) || $bbox_lbr93[3] > $bbox_lbr93_glob[3]);

    $parser->parsefile($fichier);
}

my @points_imprimes = ();
my @ways_imprimes = ();
# On imprime l'en-tête sur tous les fichiers de sortie
my @bbox_wgs84_glob;
@bbox_wgs84_glob[0,1] = @{$transf->TransformPoint (@bbox_lbr93_glob[0,1])};
@bbox_wgs84_glob[2,3] = @{$transf->TransformPoint (@bbox_lbr93_glob[2,3])};
print_files "<?xml version='1.0' encoding='UTF-8'?>\n";
print_files "<osm version='0.6' generator='plop'>\n";
print_files "<bounds minlat=\"$bbox_wgs84_glob[1]\" minlon=\"$bbox_wgs84_glob[0]\" maxlat=\"$bbox_wgs84_glob[3]\" maxlon=\"$bbox_wgs84_glob[2]\"/>\n";

for my $coord_point (sort keys %points) {
    my ($lon,$lat) = @{$points{$coord_point}{"coord"}};
    my $ref = $points{$coord_point}{"ref"};
    for my $type (@{$points{$coord_point}{"type"}}) {
	print_point($lon,$lat,$ref,$opt_b) if (($type eq "building_nowall" || $type eq "building"));
	print_point($lon,$lat,$ref,$opt_w) if (($type eq "water"));
	print_point($lon,$lat,$ref,$opt_r) if (($type eq "riverbank"));
	print_point($lon,$lat,$ref,$opt_p) if (($type eq "parcelle" || $type eq "trottoir" || $type eq "footpath"));
	print_point($lon,$lat,$ref,$opt_t) if (($type eq "train"));
	print_point($lon,$lat,$ref,$opt_l) if (($type eq "limite"));
    }
}

for my $rel (@relations) {
    if ($#{$rel->{"ways"}} >= 0) {
	my $tag = 1;
	my $file;
	my $first_way = $ways[$rel->{"ways"}[0]];
	my $type = $first_way->{"type"};

	$file = $opt_b if (($type eq "building_nowall" || $type eq "building"));
	$file = $opt_w if (($type eq "water"));
	$file = $opt_r if (($type eq "riverbank"));
	$file = $opt_p if (($type eq "parcelle" || $type eq "trottoir" || $type eq "footpath"));
	$file = $opt_t if (($type eq "train"));
	$file = $opt_l if (($type eq "limite"));

	next unless (defined($file));

	for my $ref_way (@{$rel->{"ways"}}) {
	    my $type = $ways[$ref_way]{"type"};
	    # N'écrit pas le tag pour un inner
	    print_way(abs($ref_way),$file,$type,($ref_way>=0));
	}
	if ($#{$rel->{"ways"}} >= 1) {
	    print {${$files{$file}}} "<relation id=\"" , -1-$rel->{"ref"} , "\">\n";
	    print {${$files{$file}}} " <tag k=\"type\" v=\"" , $rel->{"type"} , "\"/>\n";
	    print {${$files{$file}}} " <member type=\"way\" ref=\"" , -1-$rel->{"ways"}[0] , "\" role=\"outer\"/>\n";
	    my $ways = $rel->{"ways"};
	    foreach my $way (@{$ways}[1..$#{$ways}])
	    {
		# L'orientation du polygone indique si on ajoute ou si on enlève
		my ($role,$ref);
		if ($way > 0) {
		    $role = "outer";
		    $ref = $way;
		}
		else {
		    $role = "inner";
		    $ref = -$way;
		}
		print {${$files{$file}}} " <member type=\"way\" ref=\"" , -1-$ref , "\" role=\"$role\"/>\n";
	    }
	    print {${$files{$file}}} "</relation>\n";
	}
    }
}

# On ferme les balises ouvertes
print_files "</osm>";

Attachment: import-bati.sh
Description: Binary data

> 

_______________________________________________
Talk-fr mailing list
[email protected]
http://lists.openstreetmap.org/listinfo/talk-fr

Répondre à