propose and discuss a megawidget for easy map display
Richard Suchenwirth 2000-05-04 -- Recently the wish for geographic data was seen again on comp.lang.tcl, and I have also had that for quite some time. Wouldn't it be nice to be able to say
set M [gmap .m -title France -height 500 -width 500] $M add France Paris Lyon Marseille Bordeaux Toulouse $M postscript -file france.ps
.. and you can imagine what these few commands would do. Basically, it would be a value-added canvas for display, and a well-stocked database of geodata that, asked for "France", would give the coordinates of France's boundary line, which would be transformed to canvas coordinates and rendered as a polygon.
The Tcl way is to do things simply, evidently, and effectively. How could geodata be implemented in Tcl? We might have three kinds of objects: points, lines, and areas.
Points would be characterized by latitude, longitude, elevation (meters over standard sea level, optional and defaulting to 0). Internally floating points, there would be converters
gmap scan "51 09 N/07 56 E" ==> {51.15 -7.933 0} gmap format {51.15 -7.93 100} ==> "51°09'N 07°56'E"
assuming North and West to be positive. Points would further have a name (e.g. "Paris") and other freely choosable attributes as array elements, for instance
gmap set Paris ==> loc {48.4 -2.4 0} name Paris type city capital 1 pop 2.2m
where the "capital" attribute might lead to underlining the city name in the map, and the "pop" attribute might control the size of the oval drawn at "loc".
Lines would have a list of points, by location or by name, so
$M add [gmap set L1 {loc {Paris London} carrier "Air France"}]
would draw a straight line between these cities, possibly labeled with the carrier.
Areas would have a list of lines, explicit or by name. As boundaries are shared by two areas, it would be clever to define them only once, and let the neighboring areas both refer to that, using a naming convention that facilitates [array names] searches, e.g. "+DE+FR" would be the borderline between Germany and France. Rendering an area would consist in concatenating the lines into one and, after transforming the coordinates, draw a polygon.
Labels for points, lines, and areas would be displayed next to their objects. Before we have a clever layout mechanism, they'd be movable so you can manually arrange them on the canvas for best looks. To make these operations persistent, a "$M dump" operation would include such edited positions in the resulting huge list, which could be saved to file and redisplayed with a "$M set" operation. One Tk extension such gmaps could really use would be rotated canvas text.
Lots of work - now it's only for the doing ;-) I will start it right away sometime in my spare time, and put the pieces here on the Wiki, but can't guarantee a completion date. Maybe others would like to join and contribute code or geodata, here on the Wiki?
Took me over a year, but now see my first shot at Mapping Colorado.
For starters, here's initial scan-format routines to be called from gmap:
proc gmap:scan s { set ele 0 regexp {([0-9][0-9]) *([0-5][0-9]) *([NS]) */ *([01]?[0-9][0-9]) *([0-5][0-9]) *([EW])} $s -> latd latm latl lond lonm lonl scan $latd %d latd scan $latm %d latm scan $lond %d lond scan $lonm %d lonm set lat [expr $latd+$latm/60.] if {$latl=="S"} {set lat -$lat} set lon [expr $lond+$lonm/60.] if {$lonl=="E"} {set lon -$lon} list $lat $lon $ele } proc gmap:format g { set latf [lindex $g 0] set lonf [lindex $g 1] set latl N; set lonl W if {$latf<0} {set latl S; set latf [expr -$latf]} if {$lonf<0} {set lonl E; set lonf [expr -$lonf]} set latd [expr int($latf)] set latm [expr int(round(($latf-$latd)*60))] set lond [expr int($lonf)] set lonm [expr int(round(($lonf-$lond)*60))] format "%02d %02d %s/%02d %02d %s" \ $latd $latm $latl $lond $lonm $lonl }
I think it should be also possible to display point and spatial information into such a widget. And dealing with different coordinate systems is also quite a mess but must be reflected IMO. BTW I found on FreeGIS a link to a library reading ARC-View Files to which a TCL-binding could be nice. JH