# 
# PERL osmgraph module by gary68
#
# !!! store as osmgraph.pm in folder OSM in lib directory !!!
#
# This module contains a lot of useful graphic functions for working with osm files and data. This enables you (in conjunction with osm.pm)
# to easily draw custom maps. Although not as sophisticated as Mapnik, Osmarender and KOSMOS.
# Have a look at the last (commented) function below. It is useful for your main program!
#
#
#
#
# Copyright (C) 2009, Gerhard Schwanz
#
# This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the 
# Free Software Foundation; either version 3 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses/>

#
# USAGE
#
#
# drawArea ($color, @nodes) - real world
# drawAreaPix ($color, @nodes) - pixels
# drawChartColumns ($lon, $lat, $offX, $offY, $sizeY, $columnWidthPix, $yMax, $color, @values)
# drawCircleRadius ($lon, $lat, $radius, $size, $color)
# drawCircleRadiusText ($lon, $lat, $radius, $size, $color, $text)
# drawHead ($text, $color, $size) / size (1..5) 
# drawFoot ($text, $color, $size) / size (1..5) 
# drawLegend ($size, @entries) / size (1..5) ("t1", "col1", "t2", "col2")
# drawNodeDot ($lon, $lat, $color, $size) / size (1..5) - real world
# drawNodeDotPix ($lon, $lat, $color, $size) / size (1..5) - pixels
# drawNodeCircle ($lon, $lat, $color, $size) / size (1..5) - real world
# drawNodeCirclePix ($lon, $lat, $color, $size) / size (1..5) - pixels
# drawRuler ($color)
# drawTextPix ($x, $y, $text, $color, $size) / size (1..5) bottom left = (0,0)
# drawTextPix2 ($x, $y, $text, $color, $size) / size (1..5) top left = (0,0) 
# drawTextPos ($lon, $lat, $offX, $offY, $text, $color, $size) / size (1..5)
# drawWay ($color, $size, @nodes) / size = thickness / real world
# drawWayPix ($color, $size, @nodes) / size = thickness / pixels
# enableSVG ()
# initGraph ($sizeX, $left, $bottom, $right, $top) / real world coordinates, sizeX in pixels, Y automatic
# labelWay ($col, $size, $font, $text, $tSpan, @nodes) / size can be 0..5 (or bigger...) / $tSpan = offset to line/way
# writeGraph ($fileName)
# writeSVG ($fileName)
#
#
# INTERNAL
# 
# convert ($x, $y)						-> ($x1, $y1) pixels in graph
#
# INFO
#
# graph top left coordinates: (0,0)
# font size (1..5). 1 = smallest, 5 = giant
# size for lines = pixel width / thickness
# pass color as string, i.e. "black". list see farther down.
#
#

package OSM::osmgraph ; #  

use strict ;
use warnings ;

use Math::Trig;
use File::stat;
use Time::localtime;
use List::Util qw[min max] ;
use GD ;
use Encode ;


use vars qw($VERSION @ISA @EXPORT @EXPORT_OK);

$VERSION = '3.0' ; # PUBLISHED

require Exporter ;

@ISA = qw ( Exporter AutoLoader ) ;

@EXPORT = qw ( drawArea drawAreaPix drawCircleRadius drawCircleRadiusText drawChartColumns drawHead drawFoot drawLegend drawNodeDot drawNodeDotPix drawNodeCircle drawNodeCirclePix drawRuler drawTextPix drawTextPix2 drawTextPos drawWay drawWayPix enableSVG initGraph labelWay writeGraph writeSVG) ;

#
# constants
#

my %colorHash ;

@{$colorHash{"black"}} = (0, 0, 0) ;
@{$colorHash{"darkgray"}} = (79,79,79) ;
@{$colorHash{"gray"}} = (145, 145, 145) ;
@{$colorHash{"lightgray"}} = (207, 207, 207) ;
@{$colorHash{"white"}} = (255, 255, 255) ;

@{$colorHash{"red"}} = (255, 0, 0) ;
@{$colorHash{"orange"}} = (255, 165, 0) ;
@{$colorHash{"darkorange"}} = (255, 140, 0) ;
@{$colorHash{"tomato"}} = (255, 140, 0) ;
@{$colorHash{"yellow"}} = (255, 255, 0) ;

@{$colorHash{"blue"}} = (0, 0, 255) ;
@{$colorHash{"lightblue"}} = (135, 206, 235) ;
@{$colorHash{"pink"}} = (255, 105, 180) ;
@{$colorHash{"green"}} = (0, 255, 0) ;
@{$colorHash{"darkgreen"}} = (105, 139, 105) ;
@{$colorHash{"lightgreen"}} = (0, 255, 127) ;
@{$colorHash{"brown"}} = (139, 69, 19) ;
@{$colorHash{"lightbrown"}} = (244, 164, 96) ;

my %fonts ;
$fonts{1} = gdTinyFont ;
$fonts{2} = gdSmallFont ;
$fonts{3} = gdMediumBoldFont ;
$fonts{4} = gdLargeFont ;
$fonts{5} = gdGiantFont ;

#
# variables
#
my $image ;
my %color ;

my ($top, $bottom, $left, $right) ; # min and max real world coordinates
my ($sizeX, $sizeY) ; # pic size in pixels

my $svgEnabled = 0 ;

my @svgOutputWaysNodes = () ;
my @svgOutputAreas = () ;
my @svgOutputText = () ;
my @svgOutputPixel = () ;
my @svgOutputDef = () ;
my @svgOutputPathText = () ;
my $pathNumber = 0 ;
my $svgBaseFontSize = 10 ;


sub initGraph {
#
# function initializes the picture, the colors and the background (white)
#
	my ($x, $l, $b, $r, $t) = @_ ;	
	
	$sizeX = $x ;
	$sizeY = $x * ($t - $b) / ($r - $l) / cos ($t/360*3.14*2) ;
	$top = $t ;
	$left = $l ;
	$right = $r ;
	$bottom = $b ;

	$image = new GD::Image($sizeX, $sizeY);
	$image->trueColor() ;

	my $c ;
	foreach $c (keys %colorHash) {
		$color{$c} = $image->colorAllocate(@{$colorHash{$c}}) ;
	}

	$image->filledRectangle(0,0,$sizeX-1,$sizeY-1,$color{"white"}) ;
	
}

sub writeGraph {
#
# writes the created graph to a file
#
	my $fileName = shift ;
	my $picFile ;

	open ($picFile, ">", $fileName) || die ("error opening graph file") ;
	binmode $picFile ;
	print $picFile $image->png ; 
	close $picFile ;
}

sub convert {
#
# converts real world coordinates to system graph pixel coordinates
#
	my ($x, $y) = @_ ;

	my ($x1) = int( ($x - $left) / ($right - $left) * $sizeX ) ;
	my ($y1) = $sizeY - int( ($y - $bottom) / ($top - $bottom) * $sizeY ) ;

	return ($x1, $y1) ;
}

sub drawHead {
#
# draws text on top left corner of the picture
#
	my ($text, $col, $size) = @_ ;
	$image->string($fonts{$size}, 20, 20, encode("iso-8859-1", decode("utf8", $text)), $color{$col} ) ;

	if ($svgEnabled) {
		push @svgOutputText, svgElementText (20, 20, $text, $size, $col, "") ;
	}
}

sub drawFoot {
#
# draws text on bottom left corner of the picture, below legend
#
	my ($text, $col, $size) = @_ ;
	$image->string($fonts{$size}, 20, ($sizeY-20), encode("iso-8859-1", decode("utf8", $text)), $color{$col} ) ;

	if ($svgEnabled) {
		push @svgOutputText, svgElementText (20, ($sizeY-20), $text, $size, $col, "") ;
	}
}


sub drawTextPos {
#
# draws text at given real world coordinates. however an offset can be given for not to interfere with node dot i.e.
#
	my ($lon, $lat, $offX, $offY, $text, $col, $size) = @_ ;
	my ($x1, $y1) = convert ($lon, $lat) ;
	$x1 = $x1 + $offX ;
	$y1 = $y1 - $offY ;

	$image->string($fonts{$size}, $x1, $y1, encode("iso-8859-1", decode("utf8", $text)), $color{$col}) ;
	if ($svgEnabled) {
		push @svgOutputText, svgElementText ($x1, $y1, $text, $size, $col, "") ;
	}
}


sub drawTextPix {
#
# draws text at pixel position
#
	my ($x1, $y1, $text, $col, $size) = @_ ;

	$image->string($fonts{$size}, $x1, $sizeY-$y1, encode("iso-8859-1", decode("utf8", $text)), $color{$col}) ;
	if ($svgEnabled) {
		push @svgOutputText, svgElementText ($x1, $sizeY-$y1, $text, $size, $col, "") ;
	}
}

sub drawTextPix2 {
#
# draws text at pixel position
#
	my ($x1, $y1, $text, $col, $size) = @_ ;

	$image->string($fonts{$size}, $x1, $y1, encode("iso-8859-1", decode("utf8", $text)), $color{$col}) ;
	if ($svgEnabled) {
		push @svgOutputPixel, svgElementText ($x1, $y1+9, $text, $size, $col, "") ;
	}
}

sub drawNodeDot {
#
# draws node as a dot at given real world coordinates
#
	my ($lon, $lat, $col, $size) = @_ ;
	my ($x1, $y1) = convert ($lon, $lat) ;
	$image->filledEllipse($x1, $y1, $size, $size, $color{$col}) ;		

	if ($svgEnabled) {
		push @svgOutputWaysNodes, svgElementCircleFilled ($x1, $y1, $size, $col) ;
	}
}

sub drawNodeDotPix {
#
# draws node as a dot at given pixels
#
	my ($x1, $y1, $col, $size) = @_ ;
	$image->filledEllipse($x1, $y1, $size, $size, $color{$col}) ;		

	if ($svgEnabled) {
		push @svgOutputPixel, svgElementCircleFilled ($x1, $y1, $size, $col) ;
	}
}

sub drawNodeCircle {
#
# draws node as a circle at given real world coordinates
#
	my ($lon, $lat, $col, $size) = @_ ;
	my ($x1, $y1) = convert ($lon, $lat) ;
	
	$image->setThickness(2) ;
	$image->ellipse($x1, $y1, $size, $size, $color{$col}) ;		
	$image->setThickness(1) ;

	if ($svgEnabled) {
		push @svgOutputWaysNodes, svgElementCircle ($x1, $y1, $size, 2, $col) ;
	}
}

sub drawNodeCirclePix {
#
# draws node as a circle at given real world coordinates
#
	my ($x1, $y1, $col, $size) = @_ ;
	
	$image->setThickness(2) ;
	$image->ellipse($x1, $y1, $size, $size, $color{$col}) ;		
	$image->setThickness(1) ;

	if ($svgEnabled) {
		push @svgOutputWaysNodes, svgElementCircle ($x1, $y1, $size, 2, $col) ;
	}
}

sub drawCircleRadius {
#
# draws circle at real world coordinates with radius in meters
#
	my ($lon, $lat, $radius, $size, $col) = @_ ;
	my $radX ; my $radY ;
	my ($x1, $y1) = convert ($lon, $lat) ;

	$radX = ($radius/1000) / (($right - $left) * 111.1) / cos ($top/360*3.14*2) * $sizeX ;
	$radY = $radX ;
	$image->setThickness($size) ;
	$image->ellipse($x1, $y1, 2*$radX, 2*$radY, $color{$col}) ;		
	$image->setThickness(1) ;
	if ($svgEnabled) {
		push @svgOutputWaysNodes, svgElementCircle ($x1, $y1, $radX, $size, $col) ;
	}
}

sub drawCircleRadiusText {
#
# draws circle at real world coordinates with radius in meters
#
	my ($lon, $lat, $radius, $size, $col, $text) = @_ ;
	my $radX ; my $radY ;
	my ($x1, $y1) = convert ($lon, $lat) ;

	$radX = ($radius/1000) / (($right - $left) * 111.1) / cos ($top/360*3.14*2) * $sizeX ;
	$radY = $radX ;
	$image->setThickness($size) ;
	$image->ellipse($x1, $y1, 2*$radX, 2*$radY, $color{$col}) ;		
	$image->setThickness(1) ;
	if ($size > 4 ) { $size = 4 ; }
	$image->string($fonts{$size+1}, $x1, $y1+$radY+1, $text, $color{$col}) ;
	if ($svgEnabled) {
		push @svgOutputWaysNodes, svgElementCircle ($x1, $y1, $radX, $size, $col) ;
		push @svgOutputText, svgElementText ($x1, $y1+$radY+10, $text, $size, $col, "") ;
	}
	
}


sub drawWay {
#
# draws way as a line at given real world coordinates. nodes have to be passed as array ($lon, $lat, $lon, $lat...)
# $size = thickness
#
	my ($col, $size, @nodes) = @_ ;
	my $i ;
	my @points = () ;

	$image->setThickness($size) ;
	for ($i=0; $i<$#nodes-2; $i+=2) {
		my ($x1, $y1) = convert ($nodes[$i], $nodes[$i+1]) ;
		my ($x2, $y2) = convert ($nodes[$i+2], $nodes[$i+3]) ;
		$image->line($x1,$y1,$x2,$y2,$color{$col}) ;
	}
	if ($svgEnabled) {
		for ($i=0; $i<$#nodes; $i+=2) {
			my ($x, $y) = convert ($nodes[$i], $nodes[$i+1]) ;
			push @points, $x ; push @points, $y ; 
		}
		push @svgOutputWaysNodes, svgElementPolyline ($col, $size, @points) ;
	}
	$image->setThickness(1) ;
}

sub drawWayPix {
#
# draws way as a line at given pixels. nodes have to be passed as array ($x, $y, $x, $y...)
# $size = thickness
#
	my ($col, $size, @nodes) = @_ ;
	my $i ;
	my @points = () ;

	$image->setThickness($size) ;
	for ($i=0; $i<$#nodes-2; $i+=2) {
		my ($x1, $y1) = ($nodes[$i], $nodes[$i+1]) ;
		my ($x2, $y2) = ($nodes[$i+2], $nodes[$i+3]) ;
		$image->line($x1,$y1,$x2,$y2,$color{$col}) ;
	}
	if ($svgEnabled) {
		for ($i=0; $i<$#nodes; $i+=2) {
			my ($x, $y) = ($nodes[$i], $nodes[$i+1]) ;
			push @points, $x ; push @points, $y ; 
		}
		push @svgOutputPixel, svgElementPolyline ($col, $size, @points) ;
	}
	$image->setThickness(1) ;
}


sub labelWay {
#
# labels a way (ONLY SVG!)
#
	my ($col, $size, $font, $text, $tSpan, @nodes) = @_ ;
	my $i ;
	my @points = () ;

	#print "labelWay: $col, $size, $font, $text\n" ;

	if ($svgEnabled) {
		for ($i=0; $i<$#nodes; $i+=2) {
			my ($x, $y) = convert ($nodes[$i], $nodes[$i+1]) ;
			push @points, $x ; push @points, $y ; 
		}
		my $pathName = "Path" . $pathNumber ; $pathNumber++ ;
		push @svgOutputDef, svgElementPath ($pathName, @points) ;
		push @svgOutputPathText, svgElementPathText ($col, $size, $font, $text, $pathName, $tSpan) ;
	}
	$image->setThickness(1) ;
}


sub drawArea {
#
# draws an area like waterway=riverbank or landuse=forest. 
# pass color as string and nodes as list (x1, y1, x2, y2...) - real world coordinates
#
	my ($col, @nodes) = @_ ;
	my $i ;
	my $poly ; my @points = () ;
	$poly = new GD::Polygon ;
	
	for ($i=0; $i<$#nodes; $i+=2) {
		my ($x1, $y1) = convert ($nodes[$i], $nodes[$i+1]) ;
		$poly->addPt ($x1, $y1) ;
		push @points, $x1 ; push @points, $y1 ; 
	}
	$image->filledPolygon ($poly, $color{$col}) ;
	if ($svgEnabled) {
		push @svgOutputAreas, svgElementPolygonFilled ($col, @points) ;
	}
}

sub drawAreaPix {
#
# draws an area like waterway=riverbank or landuse=forest. 
# pass color as string and nodes as list (x1, y1, x2, y2...) - pixels
#
	my ($col, @nodes) = @_ ;
	my $i ;
	my $poly ; my @points = () ;
	$poly = new GD::Polygon ;
	
	for ($i=0; $i<$#nodes; $i+=2) {
		my ($x1, $y1) = ($nodes[$i], $nodes[$i+1]) ;
		$poly->addPt ($x1, $y1) ;
		push @points, $x1 ; push @points, $y1 ; 
	}
	$image->filledPolygon ($poly, $color{$col}) ;
	if ($svgEnabled) {
		push @svgOutputPixel, svgElementPolygonFilled ($col, @points) ;
	}
}



sub drawRuler {
#
# draws ruler in top right corner, size is automatic
#
	my $col = shift ;

	my $B ;
	my $B2 ;
	my $L ;
	my $Lpix ;
	my $x ;
	my $text ;
	my $rx = $sizeX - 20 ;
	my $ry = 20 ;
	
	$B = $right - $left ; 				# in degrees
	$B2 = $B * cos ($top/360*3.14*2) * 111.1 ;	# in km
	$text = "100m" ; $x = 0.1 ;			# default length ruler
	if ($B2 > 5) {$text = "500m" ; $x = 0.5 ; }	# enlarge ruler
	if ($B2 > 10) {$text = "1km" ; $x = 1 ; }
	if ($B2 > 50) {$text = "5km" ; $x = 5 ; }
	if ($B2 > 100) {$text = "10km" ; $x = 10 ; }
	$L = $x / (cos ($top/360*3.14*2) * 111.1 ) ;	# length ruler in km
	$Lpix = $L / $B * $sizeX ;			# length ruler in pixels

	$image->setThickness(1) ;
	$image->line($rx-$Lpix,$ry,$rx,$ry,$color{$col}) ;
	$image->line($rx-$Lpix,$ry,$rx-$Lpix,$ry+10,$color{$col}) ;
	$image->line($rx,$ry,$rx,$ry+10,$color{$col}) ;
	$image->line($rx-$Lpix/2,$ry,$rx-$Lpix/2,$ry+5,$color{$col}) ;
	$image->string(gdSmallFont, $rx-$Lpix, $ry+15, $text, $color{$col}) ;

	if ($svgEnabled) {
		push @svgOutputText, svgElementLine ($rx-$Lpix,$ry,$rx,$ry, $col, 1) ;
		push @svgOutputText, svgElementLine ($rx-$Lpix,$ry,$rx-$Lpix,$ry+10, $col, 1) ;
		push @svgOutputText, svgElementLine ($rx,$ry,$rx,$ry+10, $col, 1) ;
		push @svgOutputText, svgElementLine ($rx-$Lpix/2,$ry,$rx-$Lpix/2,$ry+5, $col, 1) ;
		push @svgOutputText, svgElementText ($rx-$Lpix, $ry+15, $text, 2, $col, "") ;
	}
}



sub drawLegend {
#
# draws legend (list of strings with different colors) in lower left corner, above foot. pass ("text", "color", ...)
#
	my ($size, @entries) = @_ ;
	my $i ;
	my $offset = 40 ;
	
	for ($i=0; $i<$#entries; $i+=2) {
		$image->string($fonts{$size}, 20, ($sizeY-$offset), $entries[$i], $color{$entries[$i+1]}) ;
		$offset += 20 ;
		if ($svgEnabled) {
			push @svgOutputText, svgElementText (20, ($sizeY-$offset), $entries[$i], $size, $entries[$i+1], "") ;
		}
	}
}




sub drawChartColumns {
#
# draws a column chart at given real world coordinates. however, an offset can be given to bring distance between node/position and chart.
# pass max column size (Y), column width in pixels and YMAX. values below 0 and above YMAX will be truncated. 
# chart will be framed black and gray.
#
	my ($lon, $lat, $offX, $offY, $colSizeY, $columnWidthPix, $yMax, $col, @values) = @_ ;
	my ($x, $y) = convert ($lon, $lat) ;
	$x = $x + $offX ;
	$y = $y - $offY ;
	my $num = scalar (@values) ;

	$image->line($x,$y,$x+$num*$columnWidthPix,$y,$color{$col}) ; #lower
	$image->line($x,$y,$x,$y-$colSizeY,$color{$col}) ; #left
	$image->line($x,$y-$colSizeY,$x+$num*$columnWidthPix,$y-$colSizeY,$color{"gray"}) ; #top
	$image->line($x+$num*$columnWidthPix,$y,$x+$num*$columnWidthPix,$y-$colSizeY,$color{"gray"}) ; #right
	
	my $i ;
	for ($i=0; $i<=$#values; $i++) {
		if ($values[$i] > $yMax) { $values[$i] = $yMax ; }
		if ($values[$i] < 0) { $values[$i] = 0 ; }
		my $yCol = ($values[$i] / $yMax) * $colSizeY ;
		$image->filledRectangle($x+$i*$columnWidthPix, $y, $x+($i+1)*$columnWidthPix, $y-$yCol, $color{$col}) ;
	}	

	# TODO SVG output

}

#####
# SVG
#####


sub enableSVG {
#
# only when called will svg elements be collected for later export to file
#
	$svgEnabled = 1 ;
}

sub writeSVG {
#
# writes svg elemets collected so far to file
#
	my ($fileName) = shift ;
	my $file ;
	open ($file, ">", $fileName) || die "can't open svg output file";
	print $file "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\n" ;
	print $file "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\" >\n" ;
	print $file "<svg version=\"1.1\" baseProfile=\"full\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:ev=\"http://www.w3.org/2001/xml-events\" width=\"$sizeX\" height=\"$sizeY\" >\n" ;
	print $file "<rect width=\"$sizeX\" height=\"$sizeY\" y=\"0\" x=\"0\" fill=\"#ffffff\" />\n" ;

	print $file "<defs>\n" ;
	foreach (@svgOutputDef) { print $file $_, "\n" ; }
	print $file "</defs>\n" ;

	print $file "<g id=\"Areas\">\n" ;
	foreach (@svgOutputAreas) { print $file $_, "\n" ; }
	print $file "</g>\n" ;

	print $file "<g id=\"WaysAndNodes\">\n" ;
	foreach (@svgOutputWaysNodes) { print $file $_, "\n" ; }
	print $file "</g>\n" ;

	print $file "<g id=\"Text\">\n" ;
	foreach (@svgOutputText) { print $file $_, "\n" ; }
	print $file "</g>\n" ;

	print $file "<g id=\"Labels\">\n" ;
	foreach (@svgOutputPathText) { print $file $_, "\n" ; }
	print $file "</g>\n" ;

	print $file "<g id=\"Pixels\">\n" ;
	foreach (@svgOutputPixel) { print $file $_, "\n" ; }
	print $file "</g>\n" ;

	print $file "</svg>\n" ;
	close ($file) ;
}

sub svgElementText {
#
# creates string with svg element incl utf-8 encoding
# TODO support different fonts
#
	my ($x, $y, $text, $size, $col, $font) = @_ ; 
	my $fontSize = 12 + ($size - 1) * 4 ;
	my $svg = "<text x=\"" . $x . "\" y=\"" . $y . "\" font-size=\"" . $fontSize . "\" fill=\"#" . colorToHex(@{$colorHash{$col}}) . "\">" . $text . "</text>" ;
	return $svg ;
}

sub svgElementCircleFilled {
#
# draws circle not filled
#
	my ($x, $y, $size, $col) = @_ ;
	my $svg = "<circle cx=\"" . $x . "\" cy=\"" . $y . "\" r=\"" . $size . "\" fill=\"#" . colorToHex(@{$colorHash{$col}})  . "\" />" ;
	return $svg ;
}

sub svgElementCircle {
#
# draws filled circle / dot
#
	my ($x, $y, $radius, $size, $col) = @_ ;
	my $svg = "<circle cx=\"" . $x . "\" cy=\"" . $y . "\" r=\"" . $radius . "\" fill=\"none\" stroke=\"#" . colorToHex(@{$colorHash{$col}})  . "\" stroke-width=\"2\" />" ;
	return $svg ;
}

sub svgElementLine {
#
# draws line between two points
#
	my ($x1, $y1, $x2, $y2, $col, $size) = @_ ;
	my $svg = "<polyline points=\"" . $x1 . "," . $y1 . " " . $x2 . "," . $y2 . "\" stroke=\"#" . colorToHex(@{$colorHash{$col}}) . "\" stroke-width=\"" . $size . "\"/>" ;
	return $svg ;
}

sub svgElementPolyline {
#
# draws way to svg
#
	my ($col, $size, @points) = @_ ;
	my $svg = "<polyline points=\"" ;
	my $i ;
	for ($i=0; $i<scalar(@points)-1; $i+=2) {
		$svg = $svg . $points[$i] . "," . $points[$i+1] . " " ;
	}
	$svg = $svg . "\" stroke=\"#" . colorToHex(@{$colorHash{$col}}) . "\" stroke-width=\"" . $size . "\" fill=\"none\" />" ;
	return $svg ;
}

sub svgElementPath {
#
# creates path element for later use with textPath
#
	my ($pathName, @points) = @_ ;
	my $svg = "<path id=\"" . $pathName . "\" d=\"M " ;
	my $i ;
	my $first = 1 ;
	for ($i=0; $i<scalar(@points); $i+=2) {
		if ($first) {
			$svg = $svg . $points[$i] . "," . $points[$i+1] . " " ;
			$first = 0 ;
		}
		else {
			$svg = $svg . "L " . $points[$i] . "," . $points[$i+1] . " " ;
		}
	}
	$svg = $svg . "\" />\n" ;
}

sub svgElementPathText {
#
# draws text to path element
#
	my ($col, $size, $font, $text, $pathName, $tSpan) = @_ ;
	my $fontSize = 12 + ($size - 1) * 4 ;
	my $svg = "<text font-family=\"" . $font . "\" " ;
	$svg = $svg . "font-size=\"" . $fontSize . "\" " ;
	$svg = $svg . "fill=\"#" . colorToHex(@{$colorHash{$col}}) . "\" >\n" ;
	$svg = $svg . "<textPath xlink:href=\"#" . $pathName . "\" text-anchor=\"middle\" startOffset=\"50%\" >\n" ;
	$svg = $svg . "<tspan dy=\"" . $tSpan . "\" >" . $text . " </tspan>\n" ;
	$svg = $svg . "</textPath>\n</text>\n" ;
	return $svg ;
}

sub svgElementPolygonFilled {
#
# draws areas in svg, filled with color
#
	my ($col, @points) = @_ ;
	my $i ;
	my $svg = "<polygon fill=\"#" . colorToHex(@{$colorHash{$col}}) . "\" points=\"" ;
	for ($i=0; $i<scalar(@points); $i+=2) {
		$svg = $svg . $points[$i] . "," . $points[$i+1] . " " ;
	}
	$svg = $svg . "\" />" ;
	return $svg ;
}

sub colorToHex {
#
# converts array of integers (rgb) to hex string without hash # (internaly used)
#
	my @arr = @_ ;
	my $string = "" ; 
	$string = sprintf "%02x", $arr[0] ;
	$string = $string . sprintf "%02x", $arr[1] ;
	$string = $string . sprintf "%02x", $arr[2] ;
	return $string ;
}

1 ;

#
# copy this useful function to your main program and uncomment, if needed
#
# sub nodes2Coordinates {
#
# transform list of nodeIds to list of lons/lats
#
#	my @nodes = @_ ;
#	my $i ;
#	my @result = () ;
#
#	#print "in @nodes\n" ;
#
#	for ($i=0; $i<=$#nodes; $i++) {
#		push @result, $lon{$nodes[$i]} ;
#		push @result, $lat{$nodes[$i]} ;
#	}
#	return @result ;
#}

