#
# This file is part of:
#
#  gpsman --- GPS Manager: a manager for GPS receiver data
#
# Copyright (c) 1998-2013 Miguel Filgueiras migfilg@t-online.de
#
#    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.
#
#  File: elevation.tcl
#  Last change:  6 October 2013
#
# This file contains mostly code contributed by Alessandro Palmas
#   (alpalmas _AT_ tin.it)
#
# Includes contributions by
#   - Miguel Filgueiras marked "MF change"/"MF contribution"
#   - Martin Buck (m _AT_ rtin-buck.de) marked "MB contribution"
#   - Benoit Steiner (benetsteph _AT_ free.fr) marked "BS contribution"
#

proc GMRTHgraph {w} {
    # compute data in RT edit/show window and call Hgraph
    # MF changes:
    #   - if there are undefined WPs discard them and give a warning
    #   - return the result from the call to Hgraph
    global WPAlt MESS DSCALE

    set frb $w.fr.fr3.fr31
    set dbTot 0
    set alTot 0
    set lll ""
    set tmp [expr [$frb.frbx.bxn size]-1]
    for { set i 0 } { $i < $tmp } { incr i } {
	#get the elevation
	set tmpname [$frb.frbx.box get $i];# get the wp name of ith WP
	set tmpwpindex [IndexNamed WP $tmpname];# get its index (-1 if undef)
	# MF change: an undefined waypoint should be discarded
	if { $tmpwpindex == -1 } {
	    DisplayInfo [format $MESS(undefinedWP) $tmpname]
	    continue
	}
	set alTot $WPAlt($tmpwpindex)
	# MF change: leg distances must be computed as the information in
	#   the listbox $frb.frbx.bxd is rounded when displayed and is not
	#    accurate enough
	set next [$frb.frbx.box get [expr $i+1]]
	if { [set tmp2 [lindex [CompWPDistBear $tmpname $next] 0]] == "---" } {
	    set tmp2 0
	} else { set tmp2 [expr $tmp2*$DSCALE] }
	# MF change: added start segment flag
	lappend lll [list $dbTot $alTot 0]
	# since each leg gives the distance to the next wp, we must save the
	# current dbtot to be associated to next wp
	set dbTot [expr $dbTot + $tmp2]
    }
    # and now the last one!
    set tmpname [$frb.frbx.box get $tmp];# get the wp name of ith WP
    set tmpwpindex [IndexNamed WP $tmpname];# get its index (-1 if undef)
    # MF change: an undefined waypoint should be discarded
    if { $tmpwpindex >= 0 } {
	set alTot $WPAlt($tmpwpindex)
	# MF change: added start segment flag
	lappend lll [list $dbTot $alTot 0]
    } else { DisplayInfo [format $MESS(undefinedWP) $tmpname] }
    # MF change: added type argument and return the result from Hgraph
    return [Hgraph $lll elevation]
}

proc RTHG3D {w} {
    # MF contribution: this code moved out from proc GMRoute
    #  $w is the RT window
    # prepare data needed for the call to proc HG3D
    # MF change: return the result from the call to HG3D
    global WPPosn WPAlt WPDatum Datum MESS

    # MF contribution: get list of WP names
    set box $w.fr.fr3.fr31.frbx.box
    set wps [$box get 0 end]

    set tmp ""
    set tmp2 ""
    foreach wp $wps {
	set i [IndexNamed WP $wp];# get its index (-1 if undef)
	if { $i >= 0 } {
	    lappend  tmp [list [lindex $WPPosn($i) 0] \
			       [lindex $WPPosn($i) 1] $WPDatum($i)]
	    lappend  tmp2 $WPAlt($i)
	} else {
	    # MF contribution: warn if there are undefined WPs
	    DisplayInfo [format $MESS(undefinedWP) $wp]
	}
    }
    # MF change: using $Datum instead of $WPDatum(0) and
    #  return the result from HG3D
    return [HG3D $tmp $tmp2 $Datum]
}

proc Hnormalize {x xmin scale} {
	return [expr ($x-$xmin)*$scale]
}

## MB contribution
proc Hrescale {c newwidth newheight} {
    set currentsize [$c coords currentsize]
    set currentwidth [lindex $currentsize 0]
    set currentheight [lindex $currentsize 1]
    # Avoid division by 0 next time
    if {$currentwidth && $currentheight} {
	$c scale all 0 0 [expr double($newwidth) / $currentwidth] \
		[expr double($newheight) / $currentheight]
    }
    return
}
##---

proc Hgraph {k what args} {
    # MF contribution
    #  - when plotting altitudes, $k is now a list of triples with
    #   distance or time, altitude, and a start segment flag; this
    #   flag is used to interrupt the plot
    #  - added new arguments:
    #    $what in {elevation, climbrate, speed}
    #    $args either void or "time" for a time axis in which case $k
    #      is a either list of pairs with seconds and speed, or
    #      a list of triples with seconds, altitude, and start segment flag
    #      if $what=="climbrate", $args=="time"
    #  - avoiding problems if window is resized by replacing use of
    #   HGpxwp array by tags in graph lines
    #  - allowing for more than one plot window at the same time
    #  - some simplifications for efficiency
    #  - using tags and lists with distance/time and altitude for
    #   retrieving and displaying this information later on
    #  - button to extend the ticks in the horizontal axis to the top of
    #   the window and restore them
    #  - changing the text font
    #  - return list with window created
    #----
    global MESS TXT BITMAP
    # MF contribution
    global NoImgLib ImgOutFormats DPOSX DPOSY MapWidth MAPH2 PlotWNo \
	HGinfo PlotFont

    if { $args == "time" } {
	set totdist 0
    } else { set totdist 1 }
    #----

    # in list k {x y segstart} triples from a track/route
    # check to have enough points for a graph
    if { [llength $k] < 3 } {
	GMMessage $MESS(missingdata)
	# MF change: return list with window created if any
	return {}
    }

    # MX and MY are the width and heigth of the canvas
    # MF contrib: using map width and half map height
    set MX $MapWidth
    set MY $MAPH2
    if { $what == "climbrate" } {
	# MF contrib
	# a time axis is always used in this case
	set xmin 0
	foreach "k valids secs0 xmax ymin ymax" [ClimbRateData $k] {}
	if { $valids == "" } {
	    GMMessage $MESS(missingdata)
	    # MF change: return list with window created if any
	    return {}
	}
    } else {
	# initializations
	set xmin 99999
	set ymin 99999
	set xmax -99999
	set ymax -99999
	# MF contribution: default value for initial time-stamp
	set secs0 ""
	#-----
	# get max amd min of x and y
	set valids 0
	if { $totdist } {
	    foreach a $k {
		set x [lindex $a 0]
		if { ! [regexp \
		      {^ *-?[0-9]+(\.[0-9]+)?([eE]-?[1-9][0-9]*)? *$} $x] } {
                   continue
		}
		set y [lindex $a 1]
		if { ! [regexp \
		      {^ *-?[0-9]+(\.[0-9]+)?([eE]-?[1-9][0-9]*)? *$} $y] } {
                    continue
		}
		if {$x < $xmin} {set xmin $x}
		if {$y < $ymin} {set ymin $y}
		if {$x > $xmax} {set xmax $x}
		if {$y > $ymax} {set ymax $y}
		incr valids
	    }
	} else {
	    # MF contrib
	    # time axis: x-values replaced by differences from first value
	    set kk ""
	    foreach a $k {
		foreach "x y newsegm" $a { break }
		if { [regexp \
		      {^ *-?[0-9]+(\.[0-9]+)?([eE]-?[1-9][0-9]*)? *$} $y] && \
		     [regexp {^ *[0-9]+ *$} $x] } {
		    if { $secs0 == "" } {
			set secs0 $x
			set xmin [set x 0]
		    } else { set x [expr $x-$secs0] }
		    set xmax $x
		    if {$y < $ymin} {set ymin $y}
		    if {$y > $ymax} {set ymax $y}
		    incr valids
		}
		lappend kk [list $x $y $newsegm]
	    }
	    set k $kk
	}
    }
    if { $valids < 3 || $xmax == $xmin } {
	GMMessage $MESS(missingdata)
	# MF change: return list with window created if any
	return {}
    }
    # the last couple must be wrong to stop (force last print)
    # MF change: added segment starter flag
    lappend k {99999 * 0}
    # now find the right quota lines to plot
    set yexcursion [expr $ymax-$ymin]
    if {$yexcursion > 10000.0} {
	set deltay [expr int($yexcursion/4.0)]
    } else {
	foreach mx "5000 2000 1000 500 250 100 50 25 10  5   2 0" \
	    deltay "1000  500  250 100  50  25 10  5 2.5 1 0.5 0.1" {
		if {$yexcursion > $mx } { break }
	    }     	
    }
    # put the max at nearest delta, but save true max
    set trueymax $ymax
    set ymax [expr ( (int($ymax) / $deltay) + 1) * $deltay]

    # calculate the scale constants to fit the canvas
    set scalx  [expr 1.0*$MX/($xmax-$xmin)]
    set scaly  [expr 1.0*$MY/($ymax-$ymin)]

    # MF contribution: name of window with number
    #  changed name in the rest of this procedure
    set w .graph[incr PlotWNo]
    #-----

    #go graphic
    if { [winfo exists $w] } {
	# MF change: using proc HgraphClose
	HgraphClose $w
    }
    # MF change: using general proc as for other GPSMan toplevels
    GMToplevel $w $what +$DPOSX+$DPOSY . \
        [list WM_DELETE_WINDOW "HgraphClose $w"] {}
    #----
    # a frame with border to avoid wm corniche to cover inner canvas
    frame $w.gf -borderwidth 3
    # includes MB contributions (expand and fill options)
    pack $w.gf -expand yes -fill both

    # CURRENT: use font metrics
    array set ftarr [font metrics $PlotFont]
    # one line of text: olot
    #set olot [expr ($ftarr(-ascent)+$ftarr(-descent)+$ftarr(-linespace))]
    set olot $ftarr(-linespace)
    set c [canvas $w.gf.c -height [expr $MY+50+$olot+$olot] \
	       -width [expr $MX+2] -highlightthickness 0]
    pack $c -expand yes -fill both
    # MB contribution
    # This is a hack that allows us to easily remember the current canvas size
    $c create line [$c cget -width] [$c cget -height] 0 0 \
	-tags currentsize -state hidden
    bind $c <Configure> "Hrescale $c %w %h"
    #----

    set bf [frame $w.bf]
    pack $bf -side bottom

    # MF change: using proc HgraphClose
    set b [button $w.bf.b -text $TXT(ok) -command "HgraphClose $w"]
    # MF change: use of Img lib
    if { $NoImgLib } {
	set p [button $w.bf.p -text "$TXT(saveto) PS" \
		   -command "SaveCanvas $w.gf.c {} PS file" ]
    } else {
	set m $w.bf.p.m ; set c $w.gf.c
	set p [menubutton $w.bf.p -text "$TXT(saveto)..." -menu $m]
	menu $m
	$m add command -label PS -command "SaveCanvas $c {} PS file"
	foreach f $ImgOutFormats {
	    $m add command -label $f -command "SaveCanvas $c {} $f file"
	}
    }
    # MF contrib: save canvas, extend/restore ticks in horizontal axis
    #  and change font
    button $w.bf.pp -text $TXT(print) \
	-command "SaveCanvas $w.gf.c {} PS printer"
    button $w.bf.btick -text $TXT(vertgridlines) \
	-command "HgraphVertGrid $w"
    button $w.bf.font -text $TXT(optPLOTFONT) \
	-command "CanvasChangeFont $c PlotFont PlotFont;
		    $w.bf.font configure -state normal"
    pack $p $w.bf.pp $w.bf.btick $w.bf.font $b -side left
    #----

    # MF contrib
    # prepare to record information related to tags
    array unset HGinfo $c,*
    set infolist "" ; set infotag 0
    #----
    # normalize list k
    # and put in z a list of point to plot
    set bad "false"
    set z ""
    set count 0
    set first 1
    foreach a $k {
	incr count
	# MF change: getting x, y and start segment flag
	foreach "x tmp newsegm" $a { break }
	# extraction of x, with check
	# MF change: merging the tests on x and y in the same if
	# extraction of y, with check
	# only the first bad elevation wp is used (start bad zone),
	#  the others are ignored
	if { ! [regexp \
		    {^ *-?[0-9]+(\.[0-9]+)?([eE]-?[1-9][0-9]*)? *$} $x] || \
	       ! [regexp \
		      {^ *-?[0-9]+(\.[0-9]+)?([eE]-?[1-9][0-9]*)? *$} $tmp] } {
	    if { $bad == "false" } {
		set bad "true"
		if { [llength $z] < 4 } { continue };#not enough data to plot
		# MF contrib: add tag and information list
		eval $c create line $z -tags {[list primo=$first itg=$infotag]}
		set HGinfo($c,$infotag) $infolist
		incr infotag ; set infolist [lrange $infolist end-1 end]
		set z [lrange $z end-1 end]
		set first [expr $count-1]
	    }
	} else {
	    # MF contrib: record information
	    lappend infolist $x $tmp
	    #-----
	    set x [expr int([Hnormalize $x $xmin $scalx])]
	    set y [Hnormalize $tmp $ymin $scaly]
	    set y [expr int($MY-$y)]
	    if { $bad == "true"} {
		set bad "false"
		lappend z $x $y
		if { [llength $z] < 4 } { continue }
		# MF: add tag and information list
		eval $c create line $z -fill red -stipple $BITMAP(brokenline) \
		   -tags {[list profile primo=$first last=$count itg=$infotag]}
		set HGinfo($c,$infotag) $infolist
		incr infotag ; set infolist [lrange $infolist end-1 end]
		set z ""
		set first $count
	    } elseif { $newsegm == 1 } {
		# MF contrib: deal with segment starter
		if { [llength $z] > 2 } {
		    # plot line linking previous points
		    eval $c create line $z \
			-tags {[list primo=$first itg=$infotag]}
		    set HGinfo($c,$infotag) [lreplace $infolist end-1 end]
		    incr infotag ; set infolist [lrange $infolist end-3 end]
		}
		# plot broken line between last and current points
		set x0 [lindex $z end-1] ; set y0 [lindex $z end]
		$c create line $x0 $y0 $x $y -fill DeepPink \
		    -stipple $BITMAP(brokenline) \
                    -tags [list profile primo=[expr $count-1] itg=$infotag]
		set HGinfo($c,$infotag) $infolist
		incr infotag ; set infolist [lrange $infolist end-1 end]
		set z ""
		set first $count		
	    }
	    lappend z $x $y
	}
    };#foreach

    if { $what != "climbrate" } {
	# measures in climb rate do not correspond to points
	bind $c <Button-1> "HGtest1 $c %x %y"
	bind $c <Shift-Button-1> "HGtest2 $c %x %y"
	# MF change: BS contribution is only for altitudes
	if { $what == "elevation" } {
	    # BS contribution:
	    bind $c <Control-Button-1> \
		"HGtest3 $c %x %y $totdist [list $secs0]"
	    #=====
	}
	#-----
    }
    ###

    # plot quota lines
    for {set y  -1000} { $y < $ymax } { set y [expr $y+$deltay] } {
	if { $y>$ymin } {
	    set tmp [Hnormalize $y $ymin $scaly]
	    set tmp [expr $MY-$tmp]
	    set tmp [expr int($tmp)]
	    # MF contribution: lowering these items and using $PlotFont
	    set it [$c create text 50 $tmp -fill "red" -text "$y" \
			-font $PlotFont -tags txt]
	    $c lower $it
	    set it [$c create line 0 $tmp $MX $tmp -fill "tan" -width 2]
	    $c lower $it
	}
    }
    # for plot data is beautified
    set trueymax [expr round($trueymax * 10)/10.0]
    set ymin [expr round($ymin * 10)/10.0]

    if { $totdist } {
	set xexcursion [expr round(($xmax-$xmin)*10)/10.0]
	if {$xexcursion > 10000.0} {
	    set deltax [expr int($xexcursion/4.0)]
	} else {
	    foreach mx "5000 2000 1000 500 250 100 50 10 5 2   0" \
		deltax "2000 1000  250 100  50  25 10  5 1 0.5 0.1" {
		    if {$xexcursion > $mx } { break }
		}     	
	}

	for {set x 0} {$x < $xmax} { set x [expr $x+$deltax] } {
	    if {($x<$xmax)&&($x>$xmin)} {
		set tmp [Hnormalize ($x $xmin $scalx)]
		set tmp [expr int($tmp)]
		# MF contribution: lowering these items and new tag
		set it [$c create line $tmp $MY $tmp [expr $MY - 10] \
			    -fill "tan" -tags vgline]
		$c lower $it
		# MF contribution: show value
		set it [$c create text $tmp [expr $MY+5] -anchor n \
			    -text $x -fill red -font $PlotFont \
			    -tags txt]
		$c lower $it
		#======
	    }
	}
    } else {
	# MF contrib
	# time axis
	set secs0t [expr $secs0%86400]
	set time0 [FormatTime $secs0t]
	if { [string length $time0] == 5 } {
	    set hour0 0 ; scan $time0 %0d:%0d min0
	    set time0 "00:$time0"
	} else {
	    scan $time0 %0d:%0d: hour0 min0 
	}
	if { [set hrs [expr $xmax/3600]] > 4 } {
	    # mark only full hours
	    set xhr0 [set x [expr ($hour0+1)*3600-$secs0t]]
	    set deltax 3600
	    set min0 0 ; set min_mx 0 ; set min_d 0
	} else {
	    if { $hrs > 1 } {
		# mark hours and quarters
		set min_mx 15 ; set min_d 15
	    } elseif { ($xmax-$hrs*3600)/60 > 5 } {
		# mark hours and each 5 minutes
		set min_mx 55 ; set min_d 5
	    } else {
		# mark hours and each minute
		set min_mx 59 ; set min_d 1
	    }
	    if { $min0 >= $min_mx } {
		set min0 $min_mx
		set x [expr ($hour0+1)*3600-$secs0t]
	    } else {
		set min0 [expr $min0-$min0%$min_d]
		set x [expr 60*($hour0*60+$min0+$min_d)-$secs0t]
	    }
	    set xhr0 $x ; set deltax [expr $min_d*60]
	}
	while 1 {
	    if { $min0 == $min_mx } {
		set min0 0
		if { $hour0 == 23 } {
		    set hour0 0
		} else { incr hour0 }
	    } else { incr min0 $min_d }
	    set tmp [expr [Hnormalize $x 0 $scalx]]
	    # MF contrib: using $PlotFont
	    set it [$c create text $tmp $MY -anchor n \
			-text [format "%02d:%02d" $hour0 $min0] -fill red \
		        -font $PlotFont -tags txt]
	    $c lower $it
	    set it [$c create line $tmp $MY $tmp [expr $MY-10] \
			-fill "tan" -tags vgline]
	    $c lower $it
	    if { [incr x $deltax] > $xmax } { break }
	}
    }
    # MF contrib: make an invisible tick in the horizontal axis for
    #  keeping track of its normal upper vertical coordinate
    $c create line 0 [expr $MY-10] 0 $MY -tags hvgline -state hidden
    #---
    # MF change: time values are self-documented, placing extreme values
    #   replaced "h. max"/"h. min" by "max"/"min"; lowering the items
    #   and using $PlotFont
    set xextrs 50
    # CURRENT
    array set ftarr [font metrics $PlotFont]
    #set olot [expr ($ftarr(-ascent)+$ftarr(-descent)+$ftarr(-linespace))]
    set olot $ftarr(-linespace)
    #
    if { $totdist } {
 	set it [$c create text [expr $MX - 5] [expr $MY + 30 + $olot] \
		    -fill "black" -anchor e -text "delta $deltax" \
		    -font $PlotFont -tags txt]
	$c lower $it
	set it [$c create text [expr $MX - 5] [expr $MY + 30 + 2*$olot] \
		    -fill "black" -anchor e -text "tot. $xexcursion" \
		    -font $PlotFont -tags txt]
	$c lower $it
    } else {
	set xhr0 [Hnormalize $xhr0 0 $scalx]
	set deltax [Hnormalize $deltax 0 $scalx]
	if { abs($xextrs-$xhr0) < 50 } {
	    # try to avoid overlapping of time value and extreme values
	    set xextrs [expr $xhr0+$deltax/2]
	}
    }
    $c create text $xextrs [expr $MY + 30 + $olot] -fill "black" \
	-justify "left" -anchor w -text "max: $trueymax" -font $PlotFont \
	-tags txt
    $c create text $xextrs [expr $MY + 30 + 2*$olot] -fill "black" \
        -justify "left" -anchor w -text "min: $ymin" -font $PlotFont -tags txt
    #----

    #to be polite, let's return explicitly
    # MF change: still being polite, return list with window created if any
    return [list $w]
}

proc HGtest2 {c x y}  {

    $c delete "oldlt"
    return
}

proc HGtest1 {c x y} {

    # MF contribution:
    #  - avoid problems if window was resized by replacing use of
    #   HGpxwp array by tags in graph lines
    #  - maximum x and y must depend on current window size
    #  - using $PlotFont
    global PlotFont

    foreach "mx my" [$c coords currentsize] { break }
    set my [expr $my*0.85]

    #search nearest $x associated with wp

    # - draw vertical line at $x
    set vline [$c create line  $x $my $x 0 -fill tan]
    # - delete any similar line that is overlapped by it
    # - find overlap with a graph line, assuming that there is at most one
    set ptno -1
    foreach it [$c find overlapping $x $my $x 0] {
	set ts [$c gettags $it]
	if { [lsearch -exact $ts oldlt] != -1 } {
	    $c delete $it
	} elseif { [set i [lsearch -glob $ts primo=*]] != -1 } {
	    # if this fails, $ptno will be -1
	    scan [lindex $ts $i] primo=%d ptno
	    set gline $it
	}
    }
    if { $ptno == -1 } {
	# - no graph line is intersected: clean and return
	$c delete $vline
	return
    }
    $c addtag oldlt withtag $vline
    # - get coordinates of graph line and follow them until close to $x
    set cmp "<" ; set lastx -1e20
    foreach "xg yg" [$c coords $gline] {
	if { $xg < $x } {
	    if { $xg != $lastx } {
		set pts $ptno ; set lastx $xg
	    } else { lappend pts $ptno }
	} elseif { $xg == $x } {
	    if { $cmp == "<" } {
		set cmp ""
		set pts $ptno
	    } else { lappend pts $ptno }
	} else {
	    # $xg > $x
	    switch $cmp {
		< {
		    if { $x-$lastx < $xg-$x } { break }
		    set cmp ">"
		    set pts $ptno ; set lastx $xg
		}
		> {
		    if { $xg != $lastx } { break }
		    lappend pts $ptno
		}
		"" {
		    break
		}
	    }
	}
	incr ptno
    }
    # - prepare label to show point number(s)
    if { [lindex $pts 1] != "" } {
	set pts "${cmp}[lindex $pts 0]-[lindex $pts end]"
    } else { set pts "${cmp}$pts" }
    #----
    if {$x > [expr $mx/2]} {
	set an "e"
	set ju "right"
    } else {
	set an "w"
	set ju "left"
    }
    $c create oval  [expr $x-1] [expr $y-1] [expr $x+1] [expr $y+1] \
	-outline tan -fill tan -tags oldlt
    $c create text  $x $y -text $pts -anchor $an -justify $ju -fill tan \
	-tags {oldlt txt} -font $PlotFont
    return
}

# BS contribution: based on proc HGtest1, display info on plot points
proc HGtest3 {c x y dist_or_time secs0} {
    # MF change
    global HGinfo DTUNIT SUBDTUNIT PlotFont
    #======

    foreach "mx my" [$c coords currentsize] { break }

    #search nearest $x associated with wp
    # - delete any similar line that is overlapped by it
    # - find overlap with a graph line, assuming that there is at most one
    # MF change: make sure it has the tag itg=*
    
    set ptno -1
    foreach it [$c find overlapping $x $my $x 0] {
	set ts [$c gettags $it]
	if { [lsearch -exact $ts oldlt] != -1 } {
	    $c delete $it
	} elseif { [set i [lsearch -glob $ts itg=*]] != -1 } {
	    # solid line
	    regsub itg= [lindex $ts $i] "" infotag
	    set i [lsearch -glob $ts primo=*]
	    scan [lindex $ts $i] primo=%d ptno
	    if { [set i [lsearch -glob $ts last=*]] != -1 } {
		regsub last= [lindex $ts $i] "" ptnext
	    } else { set ptnext -1 }
	    set gline $it
	}
    }
    if { $ptno == -1 } {
	# - no graph line is intersected: clean and return
	return
    }

    # BS changes start here

    set before_x 0 ; set after_x 0 ; set lastx 0 ; set lasty 0
    set before_y 0 ; set after_y 0 ; set lastcox 0 ; set lastcoy 0

    # search the point on the graph closest to the selected area
    set pts -1
    foreach "xg yg" [$c coords $gline] "cox coy" $HGinfo($c,$infotag) {
	if { $xg > $x } {
	    set after_x $xg ; set after_y $yg 
	    set before_x $lastx; set before_y $lasty
	    if { $x-$before_x <= $after_x-$x } 	{
		set alt $lastcoy ; set xval $lastcox
		set pts [expr $ptno-1]
		set x $before_x ; set y $before_y 	
	    } else {
		if { $ptnext == -1 } {
		    set pts $ptno
		} else { set pts $ptnext }
		set alt $coy ; set xval $cox
		set x $after_x; set y $after_y
	    }
	    break
	}
 	set lastx $xg ; set lasty $yg ; set lastcox $cox ; set lastcoy $coy
 	incr ptno
    }
    if { $pts == -1 } {
	# cursor was to the right of last line
	set pts [expr $ptno-1]
	set alt $coy ; set xval $cox
    }
    
    # BS: Display coordinates of the point

    # Displays (altitude and distance) or (altitude alone) depending on the
    #  selected graphic

    # MF change:
    #  - showing user units
    #  - using append to avoid long lines
    #  - altitude and distance/time are retrieved above

    # Avoided an error when clicked on the last chart point
    # (at the right of the chart)
    if {$xval != ""} {
	#Avoids writing too right of the graph	   		
	if {$x > $mx-60} {
	    set x_text [expr $mx-60]
	}  else { set x_text [expr $x+20] } 

	# The position of the legend depends on the curve 
	if { $after_y >= $before_y } {
	    set y_text [expr $y-5]
	} else {
	    set y_text [expr $y+30]
	}
   
	# Avoids writing too high or too low on the graph
	if {$y_text > $my-40} {
	    set y_text [expr $my-40]
	}
	if {$y_text < 20} {
	    set y_text 20
	} 	

	append comment $pts "\nalt=" [format %5.0f $alt] $SUBDTUNIT
	if { $dist_or_time == 1 } {
	    append comment "\nd:" [format %5.3f $xval] $DTUNIT
	} elseif { $secs0 != "" } {
	    append comment "\n" [FormatTime [expr round($xval+$secs0)%86400]]
	}

	# The position of the legend depends on the curve

	# MF ccontrib: clear old information near the legend
	set its [$c find overlapping [expr $x_text-30] [expr $y_text-30] \
		     [expr $x_text+110] [expr $y_text+60]]
	#---

	# Display the selected point
	$c create oval  [expr $x-3] [expr $y-3] [expr $x+3] [expr $y+3] \
	    -outline tan -fill tan -tags oldlt
	# MF contrib: using $PlotFont
	$c create text  $x_text $y_text -text $comment -anchor "w" \
	    -justify "left" -fill "red" -tags {oldlt txt} -font $PlotFont

	# BS: end
	# MF ccontrib: clear old information near the legend
	foreach it $its {
	    set ts [$c gettags $it]
	    if { [lsearch $ts oldlt] != -1 } { $c delete $it }
	}
    }
    return
}

# MF contribution
proc HgraphClose {w} {
    # close elevation graph window and delete information on it
    global HGinfo

    array unset HGinfo $w.*,*
    destroy $w
    return
}

# MF contribution
proc HgraphVertGrid {w} {
    # expand to window top or restore the ticks in horizontal axis

    if { ! [winfo exists [set c $w.gf.c]] || \
	     [set its [$c find withtag vgline]] == "" } { return }
    if { [lindex [$c coords [lindex $its 0]] 3] == 0 } {
	# resizing the canvas will change this value
	set ny [lindex [$c coords hvgline] 1]
    } else { set ny 0 }
    foreach it $its {
	set ncs [lreplace [$c coords $it] 3 3 $ny]
	eval $c coords $it $ncs
    }
    return
}

# MF contribution
proc ClimbRateData {salts} {
    # produce climb rate data from list of triples with seconds, altitude
    #  and start segment flag
    # a filter kindly provided by Paul Scorer (P.Scorer _AT_ leedsmet.ac.uk)
    #  is applied to the altitude values if there is enough data
    #  (at least 10 altitude values, so that 2 filtered values can be
    #  computed)
    # return empty list if not enough data
    # return list with: list of pairs with seconds from first valid rate
    #  and climb rate, length of this list, seconds for the first valid
    #  rate, maximum value of seconds from first valid rate, minimum and
    #  maximum values of climb rate

    # compute unfiltered climb rates
    set secs0 "" ; set where 1
    set rates "" ; set secs ""
    foreach p $salts {
	foreach "s a newsegm" $p { break }
	# start segment flag not used
	if { [regexp \
		  {^ *-?[0-9]+(\.[0-9]+)?([eE]-?[1-9][0-9]*)? *$} $a] && \
		 [regexp {^ *[0-9]+ *$} $s] } {
	    if { $where == 1 } {
		set sa $s
		set aa $a
		set where 2
	    } else {
		if { $where == 2 } {
		    set dt [expr $s-$sa]
		    set secs0 [expr 0.5*($s+$sa)]
		    set secs [set sa 0]
		    set where 3
		} else {
		    set s [expr $s-$secs0]
		    set dt [expr $s-$sa]
		    lappend secs [expr round(0.5*($s+$sa))]
		    set sa $s
		}
		lappend rates [expr ($a-$aa)/$dt]
		set aa $a
	    }
	}
    }
    if { $secs0 == "" } {
	# no time data
	return ""
    }	
    set secs0 [expr round($secs0)]
    # is there enough data to filter?
    set scrs ""
    if { [lindex $rates 4] == "" } {
	set rmin 1e40 ; set rmax -1e40
	foreach r $rates s $secs {
	    lappend scrs [list $s $r]
	    if { $r > $rmax } { set rmax $r }
	    if { $r < $rmin } { set rmin $r }
	}
	return [list $scrs [llength $scrs] $secs0 $sa $rmin $rmax]
    }
    # compute filter coefficients
    set coeffs ""
    foreach i "1 3 5 7 9 11 13 15" {
	lappend coeffs [expr 0.125*(1-cos(0.3926990816987241548*$i))]
    }
    lappend rates 0 0 0 0
    set rates [linsert $rates 0 0 0 0 0]
    set vals [lrange $rates 0 6]
    set n 0 ; set rmin 1e40 ; set rmax -1e40
    foreach val [lreplace $rates 0 6] t [lrange $secs 3 end-4] {
	lappend vals $val
	set sum 0
	foreach c $coeffs v $vals {
	    set sum [expr $sum+$c*$v]
	}
	lappend scrs [list $t $sum]
	if { $sum > $rmax } { set rmax $sum }
	if { $sum < $rmin } { set rmin $sum }
	set vals [lreplace $vals 0 0]
	incr n
    }
    return [list $scrs $n $secs0 $sa $rmin $rmax]
}

#----

############
#### 3D ####
############

#Local Globals : an array
array set HG3Dglob {
        c1 ""
        alt ""
        raw ""
        shear_hd ""
        shear_vd ""
        altok ""
        nptdiv ""
        npt ""
        zmin ""
        alt2 ""
        c1 ""
        xaxe {{-100 0} {100 0}}
        yaxe {{0 -100} {0 100}}
        HEIGHT 400
        WIDTH 400
	ELEV 100.0
        HEIGHT_ 410
        WIDTH_ 410
        X0 {[expr $HG3Dglob(WIDTH)/2]}
        Y0 {[expr $HG3Dglob(HEIGHT)/2]}
        Xcross {[expr $HG3Dglob(WIDTH)/2]}
        Ycross {[expr $HG3Dglob(HEIGHT)/2]}
        marks ""
        div 10
        scale_lock 0
        text_on 1
        ztilt 1.0
	xyscale 1.0
	zscale 1.0
        anim_stop 100
        anim_en 0
        pow 0
        abort 0
	compsem 0
	displ,pow -1
	displ,ztilt -1
	displ,zscale -1
	displ,xyscale -1
}


proc HG3D {pts alt datum} {
	global ProjTMPoint
	global ASKPROJPARAMS
	global HG3Dglob
	set nptdiv $HG3Dglob(nptdiv)
	set npt  $HG3Dglob(npt)
	set zmin   $HG3Dglob(zmin)
	set raw  $HG3Dglob(raw)
	set c1  $HG3Dglob(c1)
	set  HEIGHT  $HG3Dglob(HEIGHT)
	set  HEIGHT_  $HG3Dglob(HEIGHT_)
	set  WIDTH_  $HG3Dglob(WIDTH_)
	set  WIDTH  $HG3Dglob(WIDTH)
	set  div  $HG3Dglob(div)

        catch {unset P3DData}

	#Initialize Projection
	set oldask $ASKPROJPARAMS
	set ASKPROJPARAMS 0
	# MF contribution: changed to call of general init proc
	ProjInit TM P3DData $datum $pts
	set ASKPROJPARAMS $oldask

	#extract x,y,z
	# find min z (plateau)
	# ---> TBD what if z invalid?
	set raw ""
	set zmin 9000.0
	set zmax 0.0
	set npt 0
	foreach i $pts j $alt {
		lappend raw [ProjTMPoint P3DData \
			           [lindex $i 0] [lindex $i 1] [lindex $i 2] ]
		# IF no altitude, use the last one ...
		# OK, this is a dirty  trick.
		if { ! [CheckSignedFloat Ignore $j] } { set j $zmin;continue}
		#
		if { $j < $zmin } { set zmin $j }
		if { $j > $zmax } { set zmax $j }
		incr npt
		}
	set nptdiv [expr $npt/$div]
	set HG3Dglob(zmin) $zmin
	set HG3Dglob(nptdiv) $nptdiv
	set HG3Dglob(npt) $npt
	# we have $npt points and we will mark every $nptdiv of them

	# HERE we must divide $alt to fit ELEV
	set HG3Dglob(zscale) [expr $HG3Dglob(ELEV) / ($zmax - $zmin) ]
	# Note we do not touch values! we will use them after for:
	# get the elevation data to plot
	set HG3Dglob(altok) ""		;#if we want to check elevation after...
	set lastgoodz $zmin
	foreach j $alt {
		# trace goodness in altok
		if { ! [CheckSignedFloat Ignore $j] } {
			set j $lastgoodz
			lappend HG3Dglob(altok) 0
		} else {
			lappend HG3Dglob(altok) 1
			set lastgoodz $j
		}
	  }


	# now we relocate all data to fit in a square
	# large HEIGHT 400 and wide WIDTH
	# centered in X0,Y0
	#
	# first of all we must find max and min
	set Mxtmp 0
	set Mytmp 0
	set mxtmp 0
	set mytmp 0
	set Mtmp 0
	set mtmp 0
	foreach i $raw {
		set x [lindex $i 0]
		set y [lindex $i 1]
		if { $x > $Mtmp} { set Mtmp $x }
		if { $y > $Mtmp} { set Mtmp $y }
		if { $x < $mtmp} { set mtmp $x }
		if { $y < $mtmp} { set mtmp $y }
	}
	#
	# then we scale data to fit
	# and we translate to X0,Y0
	#
	set HEIGHT [expr $HG3Dglob(HEIGHT) *1.0]
	set WIDTH  [expr $HG3Dglob(WIDTH) *1.0]
	set tmp [expr ($HEIGHT > $WIDTH) ? $HEIGHT : $WIDTH]
	set scale_factor [expr ($tmp/($Mtmp - $mtmp)/2)]
	set raw1 ""
	foreach i $raw {
		set x [lindex $i 0]
		set y [lindex $i 1]
		set x1 [expr ($x * $scale_factor)]
		set y1 [expr ($y * $scale_factor)]
		lappend raw1 [list $x1 $y1]
	}
	set HG3Dglob(raw) $raw1

	# FIRST PLOT
        # MF change: HG3D_canvas returns list with window and canvas path
        foreach {w c1} [HG3D_canvas $alt] { break }
	#EXPORT
	set HG3Dglob(c1) $c1
	set HG3Dglob(alt2) $alt
	# MF change: return list with window created
    return [list $w]
}

proc rotate {before w} {
	# before: list of x,y to rotate
	# w: rotation in degrees
	set rotated ""
	set w [expr $w*3.14/180.0] ;# radians (roughly)
	set cosw [expr cos($w)]
	set sinw [expr sin($w)]
	foreach i $before {
		set x [lindex $i 0]
		set y [lindex $i 1]
		lappend rotated [list [expr $x * $cosw + $y * $sinw] \
		                      [expr -$x * $sinw + $y * $cosw] ]
	}

	return $rotated
}

### the following procs have been changed and then replaced by HG3D_do_calc
#  proc HG3D_calc_ {} {
#      global HG3Dglob
#
#      if { $HG3Dglob(pow) != $HG3Dglob(displpow) } {
#  	HG3D_calc $HG3Dglob(ztilt) $HG3Dglob(pow)
#      }
#      return
#  }
#
#  proc HG3D_calc_z {ztilt} {
#      global HG3Dglob
#
#      HG3D_calc $ztilt $HG3Dglob(pow)
#      return
#  }
#
#  proc HG3D_calc_p {pow} {
#      global HG3Dglob
#
#      if { $pow != $HG3Dglob(displpow) } {
#  	HG3D_calc $HG3Dglob(ztilt) $pow
#      }
#      return
#  }

proc HG3D_do_calc {param args} {
    # compute after change in parameter
    #  $param in {pow ztilt zscale xyscale}
    #  $args can contain the parameter value (when used in widget call-back)
    global HG3Dglob

    if { $HG3Dglob(displ,$param) != $HG3Dglob($param) } {
	HG3D_calc
    }
    return
}

proc HG3Dabort {} {
	global HG3Dglob

    set HG3Dglob(abort) 1
    return
}

# MF contribution
proc HG3Dabortb {} {
    # enable "abort" button
    global HG3Dglob

    $HG3Dglob(abbutton) configure -state normal
    return
}

proc HG3Dabortw {args} {
    # restore state and interface after abort
    global HG3Dglob

    after cancel HG3D_calc_wait
    set HG3Dglob(abort) 0
    set HG3Dglob(compsem) 0
    # restore parameters
    foreach param "pow ztilt zscale xyscale" {
	set HG3Dglob($param) $HG3Dglob(displ,$param)
    }
    $HG3Dglob(abbutton) configure -state disabled
    ResetCursor .
    update idletasks
    return
}

proc HG3D_calc_wait {} {
    # wait for computation to finish and launch a new one after it
    global HG3Dglob

    if { $HG3Dglob(abort) } {
	set HG3Dglob(compsem) 0
	return
    }
    if { $HG3Dglob(compsem) == 0 } {
	HG3D_calc
	return
    }
    after 200 HG3D_calc_wait
    return
}
#--

# no parameters needed: using global variables
proc HG3D_calc {} {
	global HG3Dglob

        # MF contrib
        #  check if there is a computation going on
        if { $HG3Dglob(compsem) > 1 } { return }
	if { $HG3Dglob(compsem) == 1 } {
	    if { $HG3Dglob(abort) } { return }
	    incr HG3Dglob(compsem)
	    after 200 HG3D_calc_wait
	    return
	}
	set HG3Dglob(compsem) 1
	# save locally the current parameters that may be changed by the user
	#  during the computation
	foreach param "pow ztilt zscale xyscale" {
	    set $param $HG3Dglob($param)
	}
	SetCursor . watch
	HG3Dabortb
	#---

	set nptdiv $HG3Dglob(nptdiv)
	set npt  $HG3Dglob(npt)
	set zmin   $HG3Dglob(zmin)
	set raw  $HG3Dglob(raw)
	set c1  $HG3Dglob(c1)
	set HEIGHT  $HG3Dglob(HEIGHT)
	set HEIGHT_  $HG3Dglob(HEIGHT_)
	set WIDTH_  $HG3Dglob(WIDTH_)
	set WIDTH  $HG3Dglob(WIDTH)
	set alt2 $HG3Dglob(alt2)
	set X0 $HG3Dglob(X0)
	set Y0 $HG3Dglob(Y0)
	set div $HG3Dglob(div)
	set xaxe $HG3Dglob(xaxe)
	set yaxe $HG3Dglob(yaxe)
	set scale_lock $HG3Dglob(scale_lock)

	# ROTATE
	# find max and min to choose the dimension of the nsew cross
	####
	set tmp 0 ; set n 0
	foreach i $raw {
		set x [expr abs([lindex $i 0])]
		set y [expr abs([lindex $i 1])]
		if { $x > $tmp} { set tmp $x }
		if { $y > $tmp} { set tmp $y }
		#test if abort
		if { [incr n]%10 == 0 } {
		    if { $HG3Dglob(abort) } {
			HG3Dabortw
			return 1
		    }
		    update
		}
	    }
	#set tmp [expr $tmp/4.0]
	set tmp 100.0
	set xaxe ""
	set yaxe ""
	lappend xaxe [list [expr -$tmp] 0 ] [list $tmp 0 ]
	lappend yaxe [list 0 [expr -$tmp] ] [list 0 $tmp ]
	#puts "$xaxe $yaxe"
	# ROTATE
	set rawrot [rotate $raw $pow]
	set xaxe1 [rotate $xaxe $pow]
	set yaxe1 [rotate $yaxe $pow]
	# SHEARING
	set zt [expr $ztilt * $zscale]
	set shear_h ""			;# no elevation
	set shear_v ""			;# with elevation
	set lastgoodz $zmin
	set n 0
	foreach i $rawrot j $alt2 k $HG3Dglob(altok) {
		set x [lindex $i 0]
		set y [lindex $i 1]
		set xp [expr ($x + $y/2) * $xyscale]
		set yp [expr $y/2 *  $xyscale]
		lappend shear_h [list $xp $yp]
		if { $k } {
			set lastgoodz $j
		} else {
			set j $lastgoodz
		}
		set z [expr $j - $zmin]
		set yp2 [expr ($y/2+$z*$zt) * $xyscale]
		lappend shear_v [list $xp $yp2]
		#test if abort
		if { [incr n]%10 == 0 } {
		    if { $HG3Dglob(abort) } {
			HG3Dabortw
			return 1
		    }
		    update
		}
	    }

	#shear the axes
	set xaxe2 ""
	set yaxe2 ""
	    set n 0
	foreach i $xaxe1 j $yaxe1 {
		set x [lindex $i 0]
		set y [lindex $i 1]
		set xp [expr $x + $y/2]
		set yp [expr $y/2]
		lappend xaxe2 [list $xp $yp]
		set x [lindex $j 0]
		set y [lindex $j 1]
		set xp [expr $x + $y/2]
		set yp [expr $y/2]
		lappend yaxe2 [list $xp $yp]
		#test if abort
	    if { [incr n]%10 == 0 } {
		if { $HG3Dglob(abort) } {
		    HG3Dabortw
		    return 1
		}
		update
	    }
	}


	# translate
	set tmp ""
	foreach i $shear_h {
		set x [expr [lindex $i 0] + $HG3Dglob(X0)]
		set y [expr [lindex $i 1] + $HG3Dglob(Y0)]
		lappend tmp [list $x $y]
		}
		set shear_h $tmp
	set tmp ""
	foreach i $shear_v {
		set x [expr [lindex $i 0] + $HG3Dglob(X0)]
		set y [expr [lindex $i 1] + $HG3Dglob(Y0)]
		lappend tmp [list $x $y]
		}
		set shear_v $tmp

	set tmp ""
	#axes
	set xaxe3 ""
	set yaxe3 ""
		set n 0
	foreach i $xaxe2 j $yaxe2 {
		set x [expr [lindex $i 0] + $HG3Dglob(X0)]
		set y [expr [lindex $i 1] + $HG3Dglob(Y0)]
		lappend xaxe3 [list $x $y]
		set x [expr [lindex $j 0] + $HG3Dglob(X0)]
		set y [expr [lindex $j 1] + $HG3Dglob(Y0)]
		lappend yaxe3 [list $x $y]
		#test if abort
	    if { [incr n]%10 == 0 } {
		if { $HG3Dglob(abort) } {
		    HG3Dabortw
		    return 1
		}
		update
	    }
	}
	
	set shear_hd ""
	set shear_vd ""
	set marks ""		;# { {x y count} ...}
	set  count 1		;# GPSMan uses 1 as first wp
	set  k $nptdiv	;# dirty trick
	set n 0
	foreach i $shear_h j $shear_v z $alt2 {
		set tmp ""
		set x [lindex $i 0]
		set y [lindex $i 1]
		set y [expr $HEIGHT - $y]	;#invert y
		lappend shear_hd $x $y
		# a little more... some marks here and then
		lappend tmp $x $y	;# to use or not, I save it
		set x [lindex $j 0]
		set y [lindex $j 1]
		set y [expr $HEIGHT - $y]	;#invert y
		lappend shear_vd $x $y
		lappend tmp $x $y $count $z;# to use or not, I save it
		if { $k == $nptdiv } {
			# a little more... we save a mark
			lappend marks $tmp
			set k 0
			}
		incr k
		incr count
		#test if abort
			if { [incr n]%10 == 0 } {
			    if { $HG3Dglob(abort) } {
				HG3Dabortw
				return 1
			    }
			    update
			}
		    }
	#And now, last mark always on! (some times twice... oh well!)
	lappend marks $tmp
	set HG3Dglob(marks) $marks
	#puts "debug 3 $marks"

	#axes
	set xaxe4 ""
	set yaxe4 ""
		    set n 0
	foreach i $xaxe3 j $yaxe3 {
		set x [lindex $i 0]
		set y [lindex $i 1]
		set y [expr $HEIGHT - $y]	;#invert y
		lappend xaxe4 [list $x $y]
		set x [lindex $j 0]
		set y [lindex $j 1]
		set y [expr $HEIGHT - $y]	;#invert y
		lappend yaxe4 [list $x $y]
		#test if abort
	    if { [incr n]%10 == 0 } {
		if { $HG3Dglob(abort) } {
		    HG3Dabortw
			return 1
		}
		update
	    }
	}
	
	# PLEASE NOTE: shear_v was { {x y} {x y} ... }
	# shear_vd is { x y x y ... }
	# the same for shear_h and hd
	
	if { [incr n]%10 == 0 } {
	    if { $HG3Dglob(abort) } {
		HG3Dabortw
		return 1
	    }
	    update
	}
	#PLOT
	HG3D_plot $c1 $shear_hd  $shear_vd $alt2 $marks $nptdiv $xaxe4 $yaxe4

	# save display state
	foreach param "pow ztilt zscale xyscale" {
	    set HG3Dglob(displ,$param) [set $param]
	}
	# we were fast, no need for abort window
	set HG3Dglob(abort) 0
	set HG3Dglob(compsem) 0
	foreach b "abbutton shbutton" {
	    $HG3Dglob($b) configure -state disabled
	}
	ResetCursor .
	update idletasks
	return
}

proc HG3D_animtog {w s2} {
	global HG3Dglob TXT
	set HG3Dglob(anim_en) [expr ! $HG3Dglob(anim_en)]
	if { $HG3Dglob(anim_en) == 0 } {
		$s2 configure -state disabled \
			-label "$TXT(azimuth) ($TXT(noanabbr))"
		} else {
		$s2 configure -state normal \
			-label "$TXT(azimuth) ($TXT(animabbrev))"
		}
	return
}

proc HG3Dchpow {i} {
	global HG3Dglob
	set HG3Dglob(pow) [expr $HG3Dglob(pow) + $i]
    $HG3Dglob(shbutton) configure -state normal
	return
}

proc HG3D_canvas {alt} {
	global HG3Dglob TXT
        # MF contribution
        global NoImgLib ImgOutFormats COLOUR DPOSX DPOSY
        #---

	set c1  $HG3Dglob(c1)
	set npt  $HG3Dglob(npt)
	set HEIGHT_    $HG3Dglob(HEIGHT_)
	set WIDTH_     $HG3Dglob(WIDTH_)
	set scale_lock $HG3Dglob(scale_lock)
	set ztilt $HG3Dglob(ztilt)
	set anim_stop $HG3Dglob(anim_stop)
	#
	destroy .elev3D
	# MF change: using general proc as for other GPSMan toplevels
        set w [GMToplevel .elev3D elevation +$DPOSX+$DPOSY . \
	       {WM_DELETE_WINDOW {destroy .elev3D}} {}]
	#-----
	set f0 [frame $w.f0]
	set c1 [canvas $f0.c1 -width $WIDTH_  -height $HEIGHT_]

	set f0a [frame $w.f0a]
	set f0b [frame $w.f0b]
	set s2 [scale $f0a.s2 -orient horizontal -from 0 -to 360 \
		-variable HG3Dglob(pow) \
		-label "$TXT(azimuth) ($TXT(animabbrev))" -length 120 \
         	-command {HG3D_do_calc pow}]
	set HG3Dglob(s2) $s2
	if {($npt >=  $HG3Dglob(anim_stop)) ||  $HG3Dglob(anim_en)== 0 } {
		$s2 configure -state disabled \
			-label "$TXT(azimuth) ($TXT(noanabbr))"
		set HG3Dglob(anim_en) 0
	} else {
	        $s2 configure -state normal \
			-label "$TXT(azimuth) ($TXT(animabbrev))"
		set HG3Dglob(anim_en) 1
	}
	set s2p [button $f0b.srp -text "+15" -command "HG3Dchpow 15"]
	set s2m [button $f0b.srm -text "-15" -command "HG3Dchpow -15"]
	set s2k [button $f0b.srk -text $TXT(show) \
		-command { HG3D_do_calc pow } -state disabled]
	set HG3Dglob(shbutton) $s2k
        # MF contribution: using variable so that status is correctly displayed
        set HG3Dglob(anim_en_b) $HG3Dglob(anim_en)
	set s2r [checkbutton $f0a.sr2 -text $TXT(animate) \
		-variable HG3Dglob(anim_en_b) \
		-command "HG3D_animtog $w $s2" -selectcolor $COLOUR(check)]
	#--
	# MF contribution
	button $f0b.abort -text $TXT(abort) -command HG3Dabort -state disabled
	set HG3Dglob(abbutton) $f0b.abort
	#--

	pack $f0
	pack $c1
	pack $f0a -side left
	pack $s2 $s2r
	pack $f0b -side left
	# MF contribution: pack abort button
	pack $s2m $s2k $s2p $HG3Dglob(abbutton) -side left
	#Radiobuttons
	set f1 [frame $w.f1]
	set f2 [frame $w.f2]
	set f3 [frame $w.f3]
	set f4 [frame $w.f4]
	set f5 [frame $w.f5]
	pack $f1 $f2 $f3
	pack $f4 $f5
	## four radiobuttons for North, South, etc.
		# BUT you can use the azimuth slide, too
	pack [radiobutton $f1.n -text "N" -variable HG3Dglob(pow) \
		-value 180 -command {HG3D_do_calc pow} \
		-selectcolor $COLOUR(check)]
	pack [radiobutton $f2.w -text "W" -variable HG3Dglob(pow) \
		-value 270 -command {HG3D_do_calc pow} \
		-selectcolor $COLOUR(check)] -side left
	pack [radiobutton $f2.e -text "E" -variable HG3Dglob(pow) \
		-value 90  -command {HG3D_do_calc pow} \
		-selectcolor $COLOUR(check)] -side right
	pack [radiobutton $f3.s -text "S" -variable HG3Dglob(pow) \
		-value 0   -command {HG3D_do_calc pow} \
		-selectcolor $COLOUR(check)]
	# show view from South
	$f3.s select
	#menubuttons
	frame $w.f6
	set mn $w.f6.view.m
	menubutton $w.f6.view -text $TXT(view) -relief raised \
	             -direction below -menu $mn
	menu $mn -tearoff 0
	$mn add cascade -label $TXT(zelev) -menu $mn.z
	menu $mn.z -tearoff 0
	foreach i "0.1 0.25 0.5 0.75 1.0 2.0 5.0" {
		$mn.z add radiobutton -label $i -variable HG3Dglob(ztilt) \
			-value $i -command {HG3D_do_calc ztilt} \
			-selectcolor $COLOUR(check)
	}
	$mn add cascade -label $TXT(xyelev) -menu $mn.xy
	menu $mn.xy -tearoff 0
	foreach i "0.5 0.75 1.0 1.5 2.0" {
		$mn.xy add radiobutton -label $i -variable HG3Dglob(xyscale) \
			-value $i -command {HG3D_do_calc xyscale} \
			-selectcolor $COLOUR(check)
	}
	#
	$mn add checkbutton -label $TXT(notext) -variable HG3Dglob(text_on) \
		-command HG3D_text -selectcolor $COLOUR(check)

	button $w.f6.ok -text $TXT(ok) -command "destroy $w; "

	pack $w.f6  $w.f6.view -side left -fill x

	if { $NoImgLib } {
	    set p [button $w.f6.p -text "$TXT(saveto) PS" \
		    -command "SaveCanvas $c1 {} PS file"]
	} else {
	    set m $w.f6.p.m
	    set p [menubutton $w.f6.p -text "$TXT(saveto)..." -menu $m]
	    menu $m
	    $m add command -label PS -command "SaveCanvas $c1 {} PS file"
	    foreach f $ImgOutFormats {
		$m add command -label $f -command "SaveCanvas $c1 {} $f file"
	    }
	}
	button $w.f6.pp -text $TXT(print) \
		-command "SaveCanvas $c1 {} PS printer"
	pack $p $w.f6.pp $w.f6.ok -side left -fill x
	#----

	#BIND
	$c1 bind point <1> "HG3Dsel1 $c1 %x %y"
	$c1 bind point <2> "HG3Dsel2 $c1 %x %y"
	$c1 bind plot <2> "HG3Dsel2 $c1 %x %y"
	#
	#bind $c1 <B1-Motion> "HG3Dmove $c1 %x %y"
	#bind $c1 <B2-Motion> "HG3Dnewcenter $c1 %x %y"
	$c1 bind selected <B1-Motion> "HG3Dmove $c1 %x %y"
	$c1 bind selected <B2-Motion> "HG3Dnewcenter $c1 %x %y"
	#
	# MF change: return list with window created and canvas path
    return [list $w $c1]
}


proc HG3Dsel2 {c1 x y}  {
	# Select both the plot (tag:plot) and the cross (tag:point)
	global HG3Dglob
        $c1 dtag selected
        set tmp [$c1 gettags current]
        if {[string match "*point*" $tmp] || [string match "*plot*" $tmp]} {
        	$c1 addtag selected withtag point
        	$c1 addtag selected withtag plot
        	}
}

proc HG3Dnewcenter {c1 x y}  {
	# move both the plot (tag:plot) and the cross (tag:point)
	global HG3Dglob
        #$c1 move selected [expr $x-$HG3Dglob(X0)] [expr $y-$HG3Dglob(HEIGHT)+$HG3Dglob(Y0)]
        set tmpdeltax [expr $x-$HG3Dglob(X0)]
        set tmpdeltay [expr $y-$HG3Dglob(HEIGHT)+$HG3Dglob(Y0)]
        $c1 move selected  $tmpdeltax $tmpdeltay
	set HG3Dglob(X0) $x
	set HG3Dglob(Y0) [expr $HG3Dglob(HEIGHT) - $y]
        set HG3Dglob(Xcross) [expr $HG3Dglob(Xcross) + $tmpdeltax] 
        set HG3Dglob(Ycross) [expr $HG3Dglob(Ycross) + $tmpdeltay] 
}

proc HG3Dsel1 {c1 x y} {
	# The cardinal cross only (point tag)
        global HG3Dglob
        $c1 dtag selected
        set tmp [$c1 gettags current]
        if {[string match "*point*" $tmp]} {$c1 addtag selected withtag point}
        return
}

proc HG3Dmove {c1 x y}  {
	# Move only he cardinal cross only (point tag)
        global HG3Dglob
        $c1 move selected [expr $x-$HG3Dglob(Xcross)] [expr $y-$HG3Dglob(Ycross)]
        set HG3Dglob(Xcross) $x
        set HG3Dglob(Ycross) $y
        return
        }

proc HG3D_plot { c1 shear_hd shear_vd alt marks nptdiv xaxe yaxe } {
	global HG3Dglob
	#
	$c1 delete all
	$c1 create line $shear_hd -tags "plot"
	# solution 1: fast
	#$c1 create line $shear_vd -fill blue
	#solution 2 
	set l [llength $HG3Dglob(altok)]
	for { set i 0; set j 0} {$j < [expr $l - 1]} {incr i 2; incr j} {
		set a ""
		set x [lindex $shear_vd $i ]
		set y [lindex $shear_vd [expr $i+1]]
		lappend a $x $y
		set x [lindex $shear_vd [expr $i+2]]
		set y [lindex $shear_vd [expr $i+3]]
		lappend a $x $y
		set g [lindex $HG3Dglob(altok) $j ]
		set h [lindex $HG3Dglob(altok) [expr $j+1] ]
		set g [expr $g * $h]
		if { $g } {
			$c1 create line $a -fill blue -tags "plot"
		} else {
			$c1 create line $a -fill cyan -tags "plot"
		}
		
	}
	#end of solution 2
	####
	# the cross
	set x1 [lindex [lindex $xaxe 0] 0]
	set y1 [lindex [lindex $xaxe 0] 1]
	set x2 [lindex [lindex $xaxe 1] 0]
	set y2 [lindex [lindex $xaxe 1] 1]
	$c1 create line $x1 $y1 $x2 $y2 -fill green -tags "point"
	$c1 create text $x2 $y2 -text "E" -tags "c point"
	$c1 create text $x1 $y1 -text "W" -tags "c point"
	set x1 [lindex [lindex $yaxe 0] 0]
	set y1 [lindex [lindex $yaxe 0] 1]
	set x2 [lindex [lindex $yaxe 1] 0]
	set y2 [lindex [lindex $yaxe 1] 1]
	$c1 create line $x1 $y1 $x2 $y2 -fill red -arrow last -tags "point"
	$c1 create text $x2 $y2 -text "N" -tags "c point"
	$c1 create text $x1 $y1 -text "S" -tags "c point"
	HG3D_text
	return
}

proc HG3D_text {} {
	global HG3Dglob
	set c1  $HG3Dglob(c1)
	set marks $HG3Dglob(marks)
	foreach i $marks {
		set x1 [lindex $i 0]
		set y1 [lindex $i 1]
		set k [lindex $i 4]
		set x2 [lindex $i 2]
		set y2 [lindex $i 3]
		set hz [lindex $i 5]
		if { ! [CheckSignedFloat Ignore $hz] } {
			set hz "?"
		} else {
			set hz [expr round($hz)]
		}
		$c1 create line $x1 $y1 $x2 $y2 -fill red -tags "plot"
		if {$HG3Dglob(text_on)} {
		    $c1 create text $x1 $y1 -text "$k" -tags "plot b"
		    $c1 create text $x2 $y2 -text "$hz" -tags "plot b"
		} else {
		    $c1 delete "b"
		}
	}
	return
}
