# -*- perl -*- # # $Id: Ovl.pm,v 1.3 2005/05/31 00:29:15 eserte Exp $ # Author: Slaven Rezic # # Copyright (C) 2004 Slaven Rezic. All rights reserved. # This package is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. # # Mail: eserte@users.sourceforge.net # WWW: http://bbbike.sourceforge.net # package GPS::Ovl; use strict; use vars qw($VERSION @ISA $OVL_MAGIC $OVL_MAGIC_3_0); $VERSION = sprintf("%d.%02d", q$Revision: 1.3 $ =~ /(\d+)\.(\d+)/); require GPS; push @ISA, 'GPS'; $OVL_MAGIC = "DOMGVCRD Ovlfile V2.0:"; $OVL_MAGIC_3_0 = "XXX NOT YET SUPPORTED XXX DOMGVCRD Ovlfile V3.0:"; # XXX BEGIN { if (!eval ' use Msg qw(frommain); 1; ') { warn $@ if $@; eval 'sub M ($) { $_[0] }'; eval 'sub Mfmt { sprintf(shift, @_) }'; } } sub check { my($self_or_class, $file, %args) = @_; my $self; if ($self_or_class eq __PACKAGE__ || !UNIVERSAL::isa($self_or_class, __PACKAGE__)) { # static operation $self = $self_or_class->new($file); } else { $self = $self_or_class; $self->{File} = $file; } delete $self->{FileFormat}; open(F, $file) or die "Can't open file $file: $!"; my $first_line = ; if ($first_line =~ /^\[Symbol/) { $self->{FileFormat} = "ascii"; } elsif (index($first_line, $OVL_MAGIC) == 0) { $self->{FileFormat} = "binary"; } elsif (index($first_line, $OVL_MAGIC_3_0) == 0) { $self->{FileFormat} = "binary_3_0"; } close F; defined $self->{FileFormat}; } sub convert_to_route { my($class, $file, %args) = @_; my $self = $class->new($file); require GPS::GpsmanData; require File::Temp; my($fh,$tmpfile) = File::Temp::tempfile(UNLINK => 1, SUFFIX => ".trk"); print $fh $self->convert_to_gpsman; close $fh; my @res = GPS::GpsmanData->convert_to_route($tmpfile, %args); unlink $tmpfile; @res; } sub convert_to_gpsman { my $self = shift; $self->read; my $out = <{Symbols}}) { next unless $sym->{Coords}; if ($sym->{Text}) { # NYI XXX } elsif ($sym->{Label}) { # NYI XXX } elsif ($sym->{Coords} == 1) { # NYI XXX } else { my $name = "TRACK"; # XXX better name! $out .= "!T:\t$name\n"; for my $c (@{ $sym->{Coords} }) { my($long, $lat) = @$c; $lat = ($lat < 0 ? "S" : "N") . $lat; $long = ($long < 0 ? "W" : "E") . $long; my $date = "31-Dec-1989 01:00:00"; # XXX my $elevation = 0; # XXX $out .= sprintf "\t%s\t%s\t%s\t%s\n", $date, $lat, $long, $elevation; } $out .= "\n"; } } $out; } sub new { my($class, $file) = @_; my $self = $class->SUPER::new(); $self->{File} = $file; $self; } sub read { my $self = shift; if (!UNIVERSAL::isa($self, "HASH") || !defined $self->{FileFormat}) { my $ret = $self->check($self->{File}); return if !$ret; } if (defined $self->{FileFormat}) { my $method = "read_" . $self->{FileFormat}; return $self->$method(); } #XXX del: # my $file = $self->{File}; # if (open(F, $file)) { # if (scalar =~ /^\[Symbol/) { # close F; # return $self->read_ascii; # } # close F; # } # return $self->read_binary; } sub read_ascii { my($self) = @_; my @symbols; my $sym; my @coords; my $xkoord; my $flush = sub { if ($sym) { $sym->{Coords} = [@coords] if @coords; push @symbols, $sym if $sym && keys %$sym; undef $sym; } @coords = (); }; open(F, $self->{File}) or die "Can't open file $self->{File}: $!"; while() { chomp; s/\r//; if (/\[Symbol/) { $flush->(); $sym = {}; #XXX del: # } elsif (/^\s*$/) { # $flush->(); } elsif ($sym) { if (/^XKoord\d+=(.*)$/) { $xkoord = $1; } elsif (/^YKoord\d+=(.*)$/) { push @coords, [$xkoord, $1]; undef $xkoord; } elsif (/^Text=(.*)$/) { $sym->{Text} = $1; } } } close F; $flush->(); $self->{Symbols} = \@symbols; } sub as_string_ascii { my($self, $coords, %args) = @_; my $s = ""; my $coord_i = 0; for my $coord (@$coords) { my($x,$y) = @$coord; $s .= "[Symbol ${coord_i}]\n"; $s .= "XKoord${coord_i}=$x\n"; $s .= "YKoord${coord_i}=$y\n"; $coord_i++; } $s; } { my $p; my $buf; my $_forward = sub { my($count) = @_; $p += $count; }; my $_seek_to = sub { my($to) = @_; $p = $to; }; my $_read_float = sub { my $float = unpack("d", substr($buf, $p, 8)); $p+=8; $float; }; my $_read_long = sub { my $long = unpack("l", substr($buf, $p, 4)); # XXX l = native $p+=4; $long; }; my $_read_short = sub { my $short = unpack("s", substr($buf, $p, 2)); # XXX s = native $p+=2; $short; }; my $_read_coords = sub { my $len = &$_read_short; my @coords; for (1..$len) { my($x, $y) = (&$_read_float, &$_read_float); push @coords, [$x,$y]; } @coords; }; my $_read_coord = sub { [&$_read_float, &$_read_float]; }; my $_read_string = sub { for(my $pi=$p; $pi 'red', # rot/gut befahrbar?', 6 => 'white', #weiß/Bundesstraße?', 4 => 'yellow', #gelb/verkehrsreich?', 5 => 'black', # schwarz/unbefahrbar? 2 => 'green', # Feld/Waldwege 3 => 'blue', # Kopfsteinpflaster }; sub read_binary { my($self) = @_; open(F, $self->{File}) or die "Can't open file $self->{File}: $!"; binmode F; local $/ = undef; $buf = ; close F; $p = 0; my $magic = &$_read_string; if ($magic ne $OVL_MAGIC) { die "Wrong magic: $magic\n"; } $_forward->(6); my $MapName = &$_read_string; warn "Description: $MapName\n"; $_seek_to->(0x3d); my $DimmFc = &$_read_long; my $ZoomFc = &$_read_long; my $CenterLat = &$_read_float; my $CenterLong = &$_read_float; warn "Center=$CenterLat/$CenterLong\n"; $_seek_to->(0xa9); my @symbols; #my$trace=0;my$abort=0; while($p < length $buf) { #if($trace){while(!$abort){sleep 1}$abort=0} my $sym = {}; my $typ = &$_read_short; $sym->{Typ} = $typ; if ($typ == 3) { my @x; push @x, &$_read_short for 1..6;#print "\n"; #XXXwarn "Type 3, x=@x"; $sym->{Coords} = [&$_read_coords]; my $color = $color_mapping->{$x[3]}; push @x, $color; $sym->{Balloon} = "@x"; $sym->{Color} = $color if defined $color; } elsif ($typ == 2) { #print "$typ ";printf "%04x ", &$_read_short for 1..7;print "\n"; my @x; push @x, &$_read_short for 1..2; my $subtyp = &$_read_short; if ($subtyp == 1) { # NOP } elsif ($subtyp == 0x10) { push @x, &$_read_short for 1..2; $sym->{Text} = &$_read_string; } else { warn "Unknown subtype=$subtyp p=".sprintf("%x",$p); last; } push @x, &$_read_short for 1..4; warn "Type 2, x=@x"; $sym->{Coords} = [&$_read_coords]; $sym->{Label} = &$_read_fixed_string; } elsif ($typ == 6) { my @x; push @x, &$_read_short for 1..2; my $subtyp = &$_read_short; if ($subtyp == 1) { # NOP } elsif ($subtyp == 0x10) { push @x, &$_read_short for 1..2; $sym->{Text} = &$_read_string; } else { warn "Unknown subtype=$subtyp p=".sprintf("%x",$p); last; } #print "X ";printf "%04x ", push @x, &$_read_short for 1..6;#print "\n"; warn "Type 6, x=@x"; $sym->{Coords} = [&$_read_coord]; } else { warn "Unknown type=$typ p=".sprintf("%x",$p); last; } #use Data::Dumper; print STDERR "Line " . __LINE__ . ", File: " . __FILE__ . "\n" . Data::Dumper->Dumpxs([$sym],[]); # XXX #if($sym->{Text}=~ /ZollamtXXX/){last;$trace++;$SIG{USR1}=sub{$abort=1}} push @symbols, $sym; } $self->{Symbols} = \@symbols; } sub read_binary_3_0 { my($self) = @_; open(F, $self->{File}) or die "Can't open file $self->{File}: $!"; binmode F; local $/ = undef; $buf = ; close F; $p = 0; my $magic = &$_read_string; if ($magic ne $OVL_MAGIC_3_0) { die "Wrong magic: $magic\n"; } $_seek_to->(0x44); my $MapName = &$_read_string; warn "Description: $MapName\n"; # XXX TBD... } } sub tk_export { my($self, %args) = @_; # peacify -w my $top = $main::top = $main::top; my $file = $top->getSaveFile (-defaultextension => '.ovl', -filetypes => [[M"OVL-Dateien" => '.ovl'], [M"Alle Dateien" => '*']], ); return unless defined $file; require Karte::Standard; require Karte::Polar; $Karte::Polar::obj = $Karte::Polar::obj; # peacify -w my @polar_coords = map { [ $Karte::Polar::obj->standard2map(@$_) ] } @{ $args{coords} }; my $s = $self->as_string_ascii(\@polar_coords); die "$s -> $file";#XXX open(OVL, ">$file") or main::status_message("Cannot write to $file: $!", "die"); print OVL $s; close OVL; } 1; __END__