# plotcontour.tcl --
#     Contour plotting test program for the Plotchart package
#
#  Author: Mark Stucky
#
#  The basic idea behind the method used for contouring within this sample
#  is primarily based on :
#
#    (1) "Contour Plots of Large Data Sets" by Chris Johnston
#        Computer Language, May 1986
#
#  a somewhat similar method was also described in
#
#    (2) "A Contouring Subroutine" by Paul D. Bourke
#        BYTE, June 1987
#        http://astronomy.swin.edu.au/~pbourke/projection/conrec/
#
#  In (1) it is assumed that you have a N x M grid of data that you need
#  to process.  In order to generate a contour, each cell of the grid
#  is handled without regard to it's neighbors.  This is unlike many other
#  contouring algorithms that follow the current contour line into
#  neighboring cells in an attempt to produce "smoother" contours.
#
#  In general the method described is:
#
#     1) for each four cornered cell of the grid,
#        calculate the center of the cell (average of the four corners)
#
#           data(i  ,j)   : Point (1)
#           data(i+1,j)   : Point (2)
#           data(i+1,j+1) : Point (3)
#           data(i  ,j+1) : Point (4)
#           center        : Point (5)
#
#               (4)-------------(3)
#                | \           / |
#                |  \         /  |
#                |   \       /   |
#                |    \     /    |
#                |     \   /     |
#                |      (5)      |
#                |     /   \     |
#                |    /     \    |
#                |   /       \   |
#           ^    |  /         \  |
#           |    | /           \ |
#           J   (1)-------------(2)
#
#                I ->
#
#        This divides the cell into four triangles.
#
#     2) Each of the five points in the cell can be assigned a sign (+ or -)
#        depending upon whether the point is above (+) the current contour
#        or below (-).
#
#        A contour will cross an edge whenever the points on the boundary of
#        the edge are of an opposite sign.
#
#        A few examples :
#
#           (-)     (-)        (-)  |  (+)       (-)     (-)        (+)  |  (-)
#                                    \                _                   \
#                                     \              /  \                  \
#               (-)  -             (-) |          _ /(+) |           -  (+)  -
#                  /                  /                 /              \
#                 /                 /                  /                \
#           (-)  |  (+)        (-)  |  (+)       (+)  |  (-)        (-)  |  (+)
#
#
#        (Hopefully the "rough" character diagrams above give you the
#        general idea)
#
#        It turns out that there are 32 possibles combinations of + and -
#        and therefore 32 basic paths through the cell.  And if you swap
#        the (+) and (-) in the diagram above, the "same" basic path is
#        generated:
#
#           (+)     (+)        (+)  |  (-)       (+)     (+)        (-)  |  (+)
#                                    \                _                   \
#                                     \              /  \                  \
#               (+)  -             (+) |          _ /(-) |           -  (-)  -
#                  /                  /                 /              \
#                 /                 /                  /                \
#           (+)  |  (-)        (+)  |  (-)       (-)  |  (+)        (+)  |  (-)
#
#
#        So, it turns out that there are 16 basic paths through the cell.
#
###############################################################################
#
#  The original article/code worked on all four triangles together and
#  generated one of the 16 paths.
#
#  For this version of the code, I split the cell into the four triangles
#  and handle each triangle individually.
#
#  Doing it this way is slower than the above method for calculating the
#  contour lines.  But since it "simplifies" the code when doing "color filled"
#  contours, I opted for the longer calculation times.
#
#
# AM:
# Introduce the following methods in createXYPlot:
# - grid            Draw the grid (x,y needed)
# - contourlines    Draw isolines (x,y,z needed)
# - contourfill     Draw shades (x,y,z needed)
# - contourbox      Draw uniformly coloured cells (x,y,z needed)
#
# This needs still to be done:
# - colourmap       Set colours to be used (possibly interpolated)
#
# Note:
# To get the RGB values of a named colour:
# winfo rgb . color (divide by 256)
#
# The problem:
# What interface do we use?
#
# Changes:
# - Capitalised several proc names (to indicate they are private to
#   the Plotchart package)
# - Changed the data structure from an array to a list of lists.
#   This means:
#   - No confusion about the start of indices
#   - Lists can be passed as ordinary arguments
#   - In principle they are faster, but that does not really
#     matter here
# To do:
# - Absorb all global arrays into the Plotchart system of private data
# - Get rid of the bug in the shades algorithm ;)
#

# DrawGrid --
#     Draw the grid as contained in the lists of coordinates
# Arguments:
#     w           Canvas to draw in
#     x           X-coordinates of grid points (list of lists)
#     y           Y-coordinates of grid points (list of lists)
# Result:
#     None
# Side effect:
#     Grid drawn as lines between the vertices
# Note:
#     STILL TO DO
#     A cell is only drawn if there are four well-defined
#     corners. If the x or y coordinate is missing, the cell is
#     skipped.
#
proc ::Plotchart::DrawGrid {w x y} {

    set maxrow [llength $x]
    set maxcol [llength [lindex $x 0]]

    for {set i 0} {$i < $maxrow} {incr i} {
        set xylist {}
        for {set j 0} {$j < $maxcol} {incr j} {
            lappend xylist [lindex $x $i $j] [lindex $y $i $j]
        }
        C_line $w $xylist black
    }

    for {set j 0} {$j < $maxcol} {incr j} {
        set xylist {}
        for {set i 0} {$i < $maxrow} {incr i} {
            lappend xylist [lindex $x $i $j] [lindex $y $i $j]
        }
        C_line $w $xylist black
    }
}

# DrawIsolines --
#     Draw isolines in the given grid
# Arguments:
#     canv        Canvas to draw in
#     x           X-coordinates of grid points (list of lists)
#     y           Y-coordinates of grid points (list of lists)
#     f           Values of the parameter on the grid cell corners
#     cont        List of contour classes (or empty to indicate
#                 automatic scaling
# Result:
#     None
# Side effect:
#     Isolines drawn
# Note:
#     A cell is only drawn if there are four well-defined
#     corners. If the x or y coordinate is missing or the value is
#     missing, the cell is skipped.
#
proc ::Plotchart::DrawIsolines {canv x y f {cont {}} } {
    variable contour_options

    set contour_options(simple_box_contour) 0
    set contour_options(filled_contour) 0

#   DrawContour $canv $x $y $f 0.0 100.0 20.0
    DrawContour $canv $x $y $f $cont
}

# DrawShades --
#     Draw filled contours in the given grid
# Arguments:
#     canv        Canvas to draw in
#     x           X-coordinates of grid points (list of lists)
#     y           Y-coordinates of grid points (list of lists)
#     f           Values of the parameter on the grid cell corners
#     cont        List of contour classes (or empty to indicate
#                 automatic scaling
# Result:
#     None
# Side effect:
#     Shades (filled contours) drawn
# Note:
#     A cell is only drawn if there are four well-defined
#     corners. If the x or y coordinate is missing or the value is
#     missing, the cell is skipped.
#
proc ::Plotchart::DrawShades {canv x y f {cont {}} } {
    variable contour_options

    set contour_options(simple_box_contour) 0
    set contour_options(filled_contour) 1

#   DrawContour $canv $x $y $f 0.0 100.0 20.0
    DrawContour $canv $x $y $f $cont
}

# DrawBox --
#     Draw filled cells in the given grid (colour chosen according
#     to the _average_ of the four corner values)
# Arguments:
#     canv        Canvas to draw in
#     x           X-coordinates of grid points (list of lists)
#     y           Y-coordinates of grid points (list of lists)
#     f           Values of the parameter on the grid cell corners
#     cont        List of contour classes (or empty to indicate
#                 automatic scaling
# Result:
#     None
# Side effect:
#     Filled cells (quadrangles) drawn
# Note:
#     A cell is only drawn if there are four well-defined
#     corners. If the x or y coordinate is missing or the value is
#     missing, the cell is skipped.
#
proc ::Plotchart::DrawBox {canv x y f {cont {}} } {
    variable contour_options

    set contour_options(simple_box_contour) 1
    set contour_options(filled_contour) 0

#   DrawContour $canv $x $y $f 0.0 100.0 20.0
    DrawContour $canv $x $y $f $cont
}

# Draw3DFunctionContour --
#    Plot a function of x and y with a color filled contour
# Arguments:
#    w           Name of the canvas
#    function    Name of a procedure implementing the function
#    cont        contour levels
# Result:
#    None
# Side effect:
#    The plot of the function - given the grid
#
proc ::Plotchart::Draw3DFunctionContour { w function {cont {}} } {
    variable scaling
    variable contour_options

    set contour_options(simple_box_contour) 0
    set contour_options(filled_contour) 1
    set noTrans 0

    ::Plotchart::setColormapColors  [llength $cont] 0.0

    set nxcells $scaling($w,nxcells)
    set nycells $scaling($w,nycells)
    set xmin    $scaling($w,xmin)
    set xmax    $scaling($w,xmax)
    set ymin    $scaling($w,ymin)
    set ymax    $scaling($w,ymax)
    set dx      [expr {($xmax-$xmin)/double($nxcells)}]
    set dy      [expr {($ymax-$ymin)/double($nycells)}]

    foreach {fill border} $scaling($w,colours) {break}

    #
    # Draw the quadrangles making up the plot in the right order:
    # first y from minimum to maximum
    # then x from maximum to minimum
    #
    for { set j 0 } { $j < $nycells } { incr j } {
        set y1 [expr {$ymin + $dy*$j}]
        set y2 [expr {$y1   + $dy}]
        for { set i $nxcells } { $i > 0 } { incr i -1 } {
            set x2 [expr {$xmin + $dx*$i}]
            set x1 [expr {$x2   - $dx}]

            set z11 [$function $x1 $y1]
            set z12 [$function $x1 $y2]
            set z21 [$function $x2 $y1]
            set z22 [$function $x2 $y2]

            foreach {px11 py11} [coords3DToPixel $w $x1 $y1 $z11] {break}
            foreach {px12 py12} [coords3DToPixel $w $x1 $y2 $z12] {break}
            foreach {px21 py21} [coords3DToPixel $w $x2 $y1 $z21] {break}
            foreach {px22 py22} [coords3DToPixel $w $x2 $y2 $z22] {break}

            set xb [list $px11 $px21 $px22 $px12]
            set yb [list $py11 $py21 $py22 $py12]
            set fb [list $z11  $z21  $z22  $z12 ]

            Box_contour $w $xb $yb $fb $cont $noTrans

            $w create line $px11 $py11 $px21 $py21 $px22 $py22 \
                           $px12 $py12 $px11 $py11 \
                           -fill $border
      }
   }
}


# DrawContour --
#     Routine that loops over the grid and delegates the actual drawing
# Arguments:
#     canv        Canvas to draw in
#     x           X-coordinates of grid points (list of lists)
#     y           Y-coordinates of grid points (list of lists)
#     f           Values of the parameter on the grid cell corners
#     cont        List of contour classes (or empty to indicate
#                 automatic scaling)
# Result:
#     None
# Side effect:
#     Isolines, shades or boxes drawn
# Note:
#     A cell is only drawn if there are four well-defined
#     corners. If the x or y coordinate is missing or the value is
#     missing, the cell is skipped.
#
proc ::Plotchart::DrawContour {canv x y f cont} {
    variable contour_options
    variable colorMap

    #
    # Construct the class-colour list
    #
    set cont [MakeContourClasses $f $cont [expr {1-$contour_options(filled_contour)}]]

    set fmin  [lindex $cont 0 0]
    set fmax  [lindex $cont end 0]
    set ncont [llength $cont]

    # Now that we know how many entries (ncont), create
    # the colormap colors
    #
    # I moved this into MakeContourClasses...
    #    ::Plotchart::setColormapColors  $ncont

    set maxrow [llength $x]
    set maxcol [llength [lindex $x 0]]

    for {set i 0} {$i < $maxrow-1} {incr i} {
        set i1 [expr {$i + 1}]
        for {set j 0} {$j < $maxcol-1} {incr j} {
            set j1 [expr {$j + 1}]

            set x1 [lindex $x $i1 $j]
            set x2 [lindex $x $i $j]
            set x3 [lindex $x $i $j1]
            set x4 [lindex $x $i1 $j1]

            set y1 [lindex $y $i1 $j]
            set y2 [lindex $y $i $j]
            set y3 [lindex $y $i $j1]
            set y4 [lindex $y $i1 $j1]

            set f1 [lindex $f $i1 $j]
            set f2 [lindex $f $i $j]
            set f3 [lindex $f $i $j1]
            set f4 [lindex $f $i1 $j1]

            set xb [list $x1 $x2 $x3 $x4]
            set yb [list $y1 $y2 $y3 $y4]
            set fb [list $f1 $f2 $f3 $f4]

            if { [lsearch $fb {}] >= 0 ||
                 [lsearch $xb {}] >= 0 ||
                 [lsearch $yb {}] >= 0    } {
                continue
            }

            Box_contour $canv $xb $yb $fb $cont
        }
    }
}

# Box_contour --
#     Draw a filled box
# Arguments:
#     canv        Canvas to draw in
#     xb          X-coordinates of the four corners
#     yb          Y-coordinates of the four corners
#     fb          Values of the parameter on the four corners
#     cont        List of contour classes and colours
# Result:
#     None
# Side effect:
#     Box drawn for a single cell
#
proc ::Plotchart::Box_contour {canv xb yb fb cont {doTrans 1}} {
    variable colorMap
    variable contour_options

    foreach {x1 x2 x3 x4} $xb {}
    foreach {y1 y2 y3 y4} $yb {}
    foreach {f1 f2 f3 f4} $fb {}

    set xc [expr {($x1 + $x2 + $x3 + $x4) * 0.25}]
    set yc [expr {($y1 + $y2 + $y3 + $y4) * 0.25}]
    set fc [expr {($f1 + $f2 + $f3 + $f4) * 0.25}]

    if {$contour_options(simple_box_contour)} {

        set fmin  [lindex $cont 0]
        set fmax  [lindex $cont end]
        set ncont [llength $cont]

        set ic 0
        for {set i 0} {$i < $ncont} {incr i} {
            set ff [lindex $cont $i 0]
            if {$ff <= $fc} {
                set ic $i
            }
        }

        set xylist [list $x1 $y1 $x2 $y2 $x3 $y3 $x4 $y4]

        # canvasPlot::polygon $win $xylist -fill $cont($ic,color)
        ###        C_polygon $canv $xylist $cont($ic,color)
        C_polygon $canv $xylist [lindex $cont $ic 1]

    } else {

#debug#        puts "Tri_contour 1)"
        Tri_contour $canv $x1 $y1 $f1 $x2 $y2 $f2 $xc $yc $fc $cont $doTrans

#debug#        puts "Tri_contour 2)"
        Tri_contour $canv $x2 $y2 $f2 $x3 $y3 $f3 $xc $yc $fc $cont $doTrans

#debug#        puts "Tri_contour 3)"
        Tri_contour $canv $x3 $y3 $f3 $x4 $y4 $f4 $xc $yc $fc $cont $doTrans

#debug#        puts "Tri_contour 4)"
        Tri_contour $canv $x4 $y4 $f4 $x1 $y1 $f1 $xc $yc $fc $cont $doTrans

    }

}

# Tri_contour --
#     Draw isolines or shades in a triangle
# Arguments:
#     canv        Canvas to draw in
#     x1,x2,x3    X-coordinate  of the three corners
#     y1,y2,y3    Y-coordinates of the three corners
#     f1,f2,f3    Values of the parameter on the three corners
#     cont        List of contour classes and colours
# Result:
#     None
# Side effect:
#     Isolines/shades drawn for a single triangle
#
proc ::Plotchart::Tri_contour { canv x1 y1 f1 x2 y2 f2 x3 y3 f3 cont {doTrans 1} } {
    variable contour_options
    variable colorMap

    set ncont [llength $cont]


    # Find the min/max function values for this triangle
    #
    set tfmin  [min $f1 $f2 $f3]
    set tfmax  [max $f1 $f2 $f3]

    # Based on the above min/max, figure out which
    # contour levels/colors that bracket this interval
    #
    set imin 0
    set imax 0   ;#mbs#
    for {set i 0} {$i < $ncont} {incr i} {
        set ff [lindex $cont $i]           ; ### set ff $cont($i,fval)
        if {$ff <= $tfmin} {
            set imin $i
            set imax $i
        }
        if { $ff <= $tfmax} {
            set imax $i
        }
    }

    set vertlist {}

    # Loop over all contour levels of interest for this triangle
    #
    for {set ic $imin} {$ic <= $imax} {incr ic} {

        # Get the value for this contour level
        #
        set ff [lindex $cont $ic 0]         ;###  set ff $cont($ic,fval)

        set xylist   {}
        set pxylist  {}

        # Classify the triangle based on whether the functional values, f1,f2,f3
        # are above (+), below (-), or equal (=) to the current contour level ff
        #
        set s1 [::Plotchart::setFLevel $f1 $ff]
        set s2 [::Plotchart::setFLevel $f2 $ff]
        set s3 [::Plotchart::setFLevel $f3 $ff]

        set class "$s1$s2$s3"

        # Describe class here...

        # ( - - - )   : Case A,
        # ( - - = )   : Case B, color a point, do nothing
        # ( - - + )   : Case C, contour between {23}-{31}
        # ( - = - )   : Case D, color a point, do nothing
        # ( - = = )   : Case E, contour line between 2-3
        # ( - = + )   : Case F, contour between 2-{31}
        # ( - + - )   : Case G, contour between {12}-{23}
        # ( - + = )   : Case H, contour between {12}-3
        # ( - + + )   : Case I, contour between {12}-{31}
        # ( = - - )   : Case J, color a point, do nothing
        # ( = - = )   : Case K, contour line between 1-3
        # ( = - + )   : Case L, contour between 1-{23}
        # ( = = - )   : Case M, contour line between 1-2
        # ( = = = )   : Case N, fill full triangle, return
        # ( = = + )   : Case M,
        # ( = + - )   : Case L,
        # ( = + = )   : Case K,
        # ( = + + )   : Case J,
        # ( + - - )   : Case I,
        # ( + - = )   : Case H,
        # ( + - + )   : Case G,
        # ( + = - )   : Case F,
        # ( + = = )   : Case E,
        # ( + = + )   : Case D,
        # ( + + - )   : Case C,
        # ( + + = )   : Case B,
        # ( + + + )   : Case A,


        switch -- $class {

            "---" {
                ############### Case A ###############

#debug#                puts "class A = $class , $ic , $ff"
                if {$contour_options(filled_contour)} {
                    set pxylist [list $x1 $y1 $x2 $y2 $x3 $y3]
                    C_polygon $canv $pxylist [lindex $colorMap $ic] $doTrans
                }
                return
            }

            "+++" {
#debug#                puts "class A = $class , $ic , $ff"
                if {$contour_options(filled_contour)} {
                    if {$ic == $imax} {
                        set pxylist [list $x1 $y1 $x2 $y2 $x3 $y3]
                        set ictmp [expr {$ic + 1}]
                        C_polygon $canv $pxylist [lindex $colorMap $ictmp] $doTrans
                        return
                    }
                }
            }

            "===" {
                ############### Case N ###############

#debug#                puts "class N = $class , $ic , $ff"
                if {$contour_options(filled_contour)} {
                    set pxylist [list $x1 $y1 $x2 $y2 $x3 $y3]
                    C_polygon $canv $pxylist [lindex $colorMap $ic] $doTrans
                }
                return
            }

            "--=" {
                ############### Case B ###############

#debug#                puts "class B = $class , $ic , $ff"
                if {$contour_options(filled_contour)} {
                    set pxylist [list $x1 $y1 $x2 $y2 $x3 $y3]
                    C_polygon $canv $pxylist [lindex $colorMap $ic] $doTrans
                }
                return
            }

            "++=" {
#debug#                puts "class B= $class , $ic , $ff , do nothing unless ic == imax"
                if {$ic == $imax} {
                    if {$contour_options(filled_contour)} {
                        set pxylist [list $x1 $y1 $x2 $y2 $x3 $y3]
                        set ictmp [expr {$ic + 1}]
                        C_polygon $canv $pxylist [lindex $colorMap $ictmp] $doTrans
                        return
                    }
                }
            }

            "-=-" {
                ############### Case D ###############

#debug#                puts "class D = $class , $ic , $ff"
                if {$contour_options(filled_contour)} {
                    set pxylist [list $x1 $y1 $x2 $y2 $x3 $y3]
                    C_polygon $canv $pxylist [lindex $colorMap $ic] $doTrans
                }
                return
            }

            "+=+" {
#debug#                puts "class D = $class , $ic , $ff , do nothing unless ic == imax"
                if {$ic == $imax} {
                    if {$contour_options(filled_contour)} {
                        set pxylist [list $x1 $y1 $x2 $y2 $x3 $y3]
                        set ictmp [expr {$ic + 1}]
                        C_polygon $canv $pxylist [lindex $colorMap $ictmp] $doTrans
                        return
                    }
                }
            }

            "=--" {
                ############### Case J ###############

#debug#                puts "class J = $class , $ic , $ff"
                if {$contour_options(filled_contour)} {
                    set pxylist [list $x1 $y1 $x2 $y2 $x3 $y3]
                    C_polygon $canv $pxylist [lindex $colorMap $ic] $doTrans
                }
                return
            }

            "=++" {
#debug#                puts "class J = $class , $ic , $ff , do nothing unless ic == imax"
                if {$ic == $imax} {
                    if {$contour_options(filled_contour)} {
                        set pxylist [list $x1 $y1 $x2 $y2 $x3 $y3]
                        set ictmp [expr {$ic + 1}]
                        C_polygon $canv $pxylist [lindex $colorMap $ictmp] $doTrans
                        return
                    }
                }
            }

            "=-=" {
                ############### Case K ###############

#debug#                puts "class K = $class , $ic , $ff"
                set xylist [list $x1 $y1 $x3 $y3]
                if {$contour_options(filled_contour)} {
                    set pxylist [list $x1 $y1 $x2 $y2 $x3 $y3]
                    C_polygon $canv $pxylist [lindex $colorMap $ic] $doTrans
                }
                C_line $canv $xylist [lindex $colorMap $ic] $doTrans
                return

            }

            "=+=" {
#debug#                puts "class K = $class , $ic , $ff"
                set xylist [list $x1 $y1 $x3 $y3]
                if {$ic == $imax} {
                    if {$contour_options(filled_contour)} {
                        set pxylist [list $x1 $y1 $x2 $y2 $x3 $y3]
                        set ictmp [expr {$ic + 1}]
                        C_polygon $canv $pxylist [lindex $colorMap $ictmp] $doTrans
                        return
                    }
                    C_line $canv $xylist [lindex $colorMap $ic] $doTrans

                } else {
                    C_line $canv $xylist [lindex $colorMap $ic] $doTrans
                }
            }

            "-==" {
                ############### Case E ###############

#debug#                puts "class E = $class , $ic , $ff"
                set xylist [list $x2 $y2 $x3 $y3]
                if {$contour_options(filled_contour)} {
                    set pxylist [list $x1 $y1 $x2 $y2 $x3 $y3]
                    C_polygon $canv $pxylist [lindex $colorMap $ic] $doTrans
                }
                C_line $canv $xylist [lindex $colorMap $ic] $doTrans
                return
            }

            "+==" {
#debug#                puts "class E = $class , $ic , $ff"
                set xylist [list $x2 $y2 $x3 $y3]
                if {$ic == $imax} {
                    if {$contour_options(filled_contour)} {
                        set pxylist [list $x1 $y1 $x2 $y2 $x3 $y3]
                        set ictmp [expr {$ic + 1}]
                        C_polygon $canv $pxylist [lindex $colorMap $ictmp] $doTrans
                        return
                    }
                    C_line $canv $xylist [lindex $colorMap $ic] $doTrans

                } else {
                    C_line $canv $xylist [lindex $colorMap $ic] $doTrans
                }
            }

            "==-" {
                ############### Case M ###############

#debug#                puts "class M = $class , $ic , $ff"
                set xylist [list $x1 $y1 $x2 $y2]
                if {$contour_options(filled_contour)} {
                    set pxylist [list $x1 $y1 $x2 $y2 $x3 $y3]
                    C_polygon $canv $pxylist [lindex $colorMap $ic] $doTrans
                }
                C_line $canv $xylist [lindex $colorMap $ic] $doTrans
                return
            }

            "==+" {
#debug#                puts "class M = $class , $ic , $ff"
                set xylist [list $x1 $y1 $x2 $y2]
                if {$ic == $imax} {
                    if {$contour_options(filled_contour)} {
                        set pxylist [list $x1 $y1 $x2 $y2 $x3 $y3]
                        set ictmp [expr {$ic + 1}]
                        C_polygon $canv $pxylist [lindex $colorMap $ictmp] $doTrans
                        return
                    }
                    C_line $canv $xylist [lindex $colorMap $ic] $doTrans

                } else {
                    C_line $canv $xylist [lindex $colorMap $ic] $doTrans
                }

            }

            "-=+" {
                ############### Case F ###############

#debug#                puts "class F = $class , $ic , $ff"
                set xylist [list $x2 $y2]
                set xyf2  [fintpl $x3 $y3 $f3 $x1 $y1 $f1 $ff]
                foreach {xx yy} $xyf2 {}
                lappend xylist $xx $yy

                if {$contour_options(filled_contour)} {
                        set pxylist $xylist
                        lappend pxylist $x1 $y1
                        C_polygon $canv $pxylist [lindex $colorMap $ic] $doTrans
                }
                C_line $canv $xylist [lindex $colorMap $ic] $doTrans

                set x1 $xx; set y1 $yy; set f1 $ff

                if {$ic == $imax} {
                    if {$contour_options(filled_contour)} {
                        set pxylist [list $x1 $y1 $x2 $y2 $x3 $y3]
                        set ictmp [expr {$ic + 1}]
                        C_polygon $canv $pxylist [lindex $colorMap $ictmp] $doTrans
                        return
                    }
                }

            }

            "+=-" {
#debug#                puts "class F = $class , $ic , $ff"
                set xylist [list $x2 $y2]
                set xyf2  [fintpl $x3 $y3 $f3 $x1 $y1 $f1 $ff]
                foreach {xx yy} $xyf2 {}
                lappend xylist $xx $yy

                if {$contour_options(filled_contour)} {
                        set pxylist $xylist
                        lappend pxylist $x3 $y3
                        C_polygon $canv $pxylist [lindex $colorMap $ic] $doTrans
                }
                C_line $canv $xylist [lindex $colorMap $ic] $doTrans

                set x3 $xx; set y3 $yy; set f3 $ff

                if {$ic == $imax} {
                    if {$contour_options(filled_contour)} {
                        set pxylist [list $x1 $y1 $x2 $y2 $x3 $y3]
                        set ictmp [expr {$ic + 1}]
                        C_polygon $canv $pxylist [lindex $colorMap $ictmp] $doTrans
                        return
                    }
                }

            }

            "-+=" {
                ############### Case H ###############

#debug#                puts "class H = $class , $ic , $ff"
                set xylist [fintpl $x1 $y1 $f1 $x2 $y2 $f2 $ff]
                foreach {xx yy} $xylist {}
                lappend xylist $x3 $y3

                if {$contour_options(filled_contour)} {
                        set pxylist $xylist
                        lappend pxylist $x1 $y1
                        C_polygon $canv $pxylist [lindex $colorMap $ic] $doTrans
                }
                C_line $canv $xylist [lindex $colorMap $ic] $doTrans

                set x1 $xx; set y1 $yy; set f1 $ff

                if {$ic == $imax} {
                    if {$contour_options(filled_contour)} {
                        set pxylist [list $x1 $y1 $x2 $y2 $x3 $y3]
                        set ictmp [expr {$ic + 1}]
                        C_polygon $canv $pxylist [lindex $colorMap $ictmp] $doTrans
                        return
                    }
                }

            }

            "+-=" {
#debug#                puts "class H = $class , $ic , $ff"
                set xylist [fintpl $x1 $y1 $f1 $x2 $y2 $f2 $ff]
                foreach {xx yy} $xylist {}
                lappend xylist $x3 $y3
                C_line $canv $xylist [lindex $colorMap $ic] $doTrans

                if {$contour_options(filled_contour)} {
                        set pxylist $xylist
                        lappend pxylist $x2 $y2
                        C_polygon $canv $pxylist [lindex $colorMap $ic] $doTrans
                }
                C_line $canv $xylist [lindex $colorMap $ic] $doTrans

                set x2 $xx; set y2 $yy; set f2 $ff

                if {$ic == $imax} {
                    if {$contour_options(filled_contour)} {
                        set pxylist [list $x1 $y1 $x2 $y2 $x3 $y3]
                        set ictmp [expr {$ic + 1}]
                        C_polygon $canv $pxylist [lindex $colorMap $ictmp] $doTrans
                        return
                    }
                }

            }

            "=-+" {
                ############### Case L ###############

#debug#                puts "class L = $class , $ic , $ff"
                set xylist [fintpl $x2 $y2 $f2 $x3 $y3 $f3 $ff]
                foreach {xx yy} $xylist {}
                lappend xylist $x1 $y1
                C_line $canv $xylist [lindex $colorMap $ic] $doTrans

                if {$contour_options(filled_contour)} {
                        set pxylist $xylist
                        lappend pxylist $x2 $y2
                        C_polygon $canv $pxylist [lindex $colorMap $ic] $doTrans
                }
                C_line $canv $xylist [lindex $colorMap $ic] $doTrans

                set x2 $xx; set y2 $yy; set f2 $ff

                if {$ic == $imax} {
                    if {$contour_options(filled_contour)} {
                        set pxylist [list $x1 $y1 $x2 $y2 $x3 $y3]
                        set ictmp [expr {$ic + 1}]
                        C_polygon $canv $pxylist [lindex $colorMap $ictmp] $doTrans
                        return
                    }
                }

            }

            "=+-" {
#debug#                puts "class L = $class , $ic , $ff"
                set xylist [fintpl $x2 $y2 $f2 $x3 $y3 $f3 $ff]
                foreach {xx yy} $xylist {}
                lappend xylist $x1 $y1
                C_line $canv $xylist [lindex $colorMap $ic] $doTrans

                if {$contour_options(filled_contour)} {
                        set pxylist $xylist
                        lappend pxylist $x3 $y3
                        C_polygon $canv $pxylist [lindex $colorMap $ic] $doTrans
                }
                C_line $canv $xylist [lindex $colorMap $ic] $doTrans

                set x3 $xx; set y3 $yy; set f3 $ff

                if {$ic == $imax} {
                    if {$contour_options(filled_contour)} {
                        set pxylist [list $x1 $y1 $x2 $y2 $x3 $y3]
                        set ictmp [expr {$ic + 1}]
                        C_polygon $canv $pxylist [lindex $colorMap $ictmp] $doTrans
                        return
                    }
                }

            }

            "--+" {
                ############### Case C ###############

#debug#                puts "class C = $class , $ic , $ff"
                set xyf1  [fintpl $x2 $y2 $f2 $x3 $y3 $f3 $ff]
                set xyf2  [fintpl $x3 $y3 $f3 $x1 $y1 $f1 $ff]
                set xylist $xyf1
                foreach {xx1 yy1} $xyf1 {}
                foreach {xx2 yy2} $xyf2 {}
                lappend xylist $xx2 $yy2
                if {$contour_options(filled_contour)} {
                    set pxylist $xylist
                    lappend pxylist $x1 $y1 $x2 $y2
                    C_polygon $canv $pxylist [lindex $colorMap $ic] $doTrans
                    if {$ic == $imax} {
                        set pxylist $xylist
                        lappend pxylist $x3 $y3
                        C_polygon $canv $pxylist [lindex $colorMap $ic] $doTrans
                    }
                }
                C_line $canv $xylist [lindex $colorMap $ic] $doTrans
                set oldlist {}
                set x1 $xx1; set y1 $yy1; set f1 $ff
                set x2 $xx2; set y2 $yy2; set f2 $ff
                if {$ic == $imax} {
                    if {$contour_options(filled_contour)} {
                        set pxylist [list $x1 $y1 $x2 $y2 $x3 $y3]
                        set ictmp [expr {$ic + 1}]
                        C_polygon $canv $pxylist [lindex $colorMap $ictmp] $doTrans
                        return
                    }
                }
            }

            "++-" {
#debug#                puts "class C = $class , $ic , $ff"
                set xyf1  [fintpl $x2 $y2 $f2 $x3 $y3 $f3 $ff]
                set xyf2  [fintpl $x3 $y3 $f3 $x1 $y1 $f1 $ff]
                set xylist $xyf1
                foreach {xx1 yy1} $xyf1 {}
                foreach {xx2 yy2} $xyf2 {}
                lappend xylist $xx2 $yy2
                if {$contour_options(filled_contour)} {
                    set pxylist $xylist
                    lappend pxylist $x3 $y3
                    C_polygon $canv $pxylist [lindex $colorMap $ic] $doTrans
                }

                if {$ic == $imax} {
                    if {$contour_options(filled_contour)} {
                        set pxylist $xylist
                        lappend pxylist $x1 $y1 $x2 $y2
                        set ictmp [expr {$ic + 1}]
                        C_polygon $canv $pxylist [lindex $colorMap $ictmp] $doTrans
                    }

                } else {

#debug#                    puts "call Tri_contour : 1) $class"
#debug#                    puts "   : $xx1 $yy1 $ff $xx2 $yy2 $ff $x1 $y1 $f1"
                    Tri_contour $canv $xx1 $yy1 $ff $xx2 $yy2 $ff $x1 $y1 $f1 $cont $doTrans

#debug#                    puts "call Tri_contour : 2) $class"
#debug#                    puts "   : $xx1 $yy1 $ff $x1 $y1 $f1 $x2 $y2 $f2"
                    Tri_contour $canv $xx1 $yy1 $ff $x1 $y1 $f1 $x2 $y2 $f2 $cont $doTrans

                }
                C_line $canv $xylist [lindex $colorMap $ic] $doTrans
                return

            }

            "-+-" {
                ############### Case G ###############

#debug#                puts "class G = $class , $ic , $ff"
                set xyf1  [fintpl $x1 $y1 $f1 $x2 $y2 $f2 $ff]
                set xyf2  [fintpl $x2 $y2 $f2 $x3 $y3 $f3 $ff]
                set xylist $xyf1
                foreach {xx1 yy1} $xyf1 {}
                foreach {xx2 yy2} $xyf2 {}
                lappend xylist $xx2 $yy2
                if {$contour_options(filled_contour)} {
                    set pxylist $xylist
                    lappend pxylist $x3 $y3 $x1 $y1
                    C_polygon $canv $pxylist [lindex $colorMap $ic] $doTrans
                    if {$ic == $imax} {
                        set pxylist $xylist
                        lappend pxylist $x2 $y2
                        C_polygon $canv $pxylist [lindex $colorMap $ic] $doTrans
                    }
                }
                C_line $canv $xylist [lindex $colorMap $ic] $doTrans
                set oldlist {}
                set x1 $xx1; set y1 $yy1; set f1 $ff
                set x3 $xx2; set y3 $yy2; set f3 $ff

                if {$ic == $imax} {
                    if {$contour_options(filled_contour)} {
                        set pxylist [list $x1 $y1 $x2 $y2 $x3 $y3]
                        set ictmp [expr {$ic + 1}]
                        C_polygon $canv $pxylist [lindex $colorMap $ictmp] $doTrans
                        return
                    }
                }

            }

            "+-+" {
#debug#                puts "class G = $class , $ic , $ff"
                set xyf1  [fintpl $x1 $y1 $f1 $x2 $y2 $f2 $ff]
                set xyf2  [fintpl $x2 $y2 $f2 $x3 $y3 $f3 $ff]
                foreach {xx1 yy1} $xyf1 {}
                foreach {xx2 yy2} $xyf2 {}
                set xylist $xyf1
                lappend xylist $xx2 $yy2
                if {$contour_options(filled_contour)} {
                    set pxylist $xylist
                    lappend pxylist $x2 $y2
                    C_polygon $canv $pxylist [lindex $colorMap $ic] $doTrans
                }

                if {$ic == $imax} {
                    if {$contour_options(filled_contour)} {
                        set pxylist $xylist
                        lappend pxylist $x3 $y3 $x1 $y1
                        set ictmp [expr {$ic + 1}]
                        C_polygon $canv $pxylist [lindex $colorMap $ictmp] $doTrans
                    }

                } else {

#debug#                    puts "call Tri_contour : 1) $class"
#debug#                    puts "   : $xx1 $yy1 $ff $xx2 $yy2 $ff $x3 $y3 $f3"
                    Tri_contour $canv $xx1 $yy1 $ff $xx2 $yy2 $ff $x3 $y3 $f3 $cont $doTrans

#debug#                    puts "call Tri_contour : 2) $class"
#debug#                    puts "   : $xx1 $yy1 $ff $x3 $y3 $f3 $x1 $y1 $f1"
                    Tri_contour $canv $xx1 $yy1 $ff $x3 $y3 $f3 $x1 $y1 $f1 $cont $doTrans
                }
                C_line $canv $xylist [lindex $colorMap $ic] $doTrans
                return

            }

            "+--" {
                ############### Case I ###############

#debug#                puts "class I = $class , $ic , $ff"
                set xyf1  [fintpl $x1 $y1 $f1 $x2 $y2 $f2 $ff]
                set xyf2  [fintpl $x3 $y3 $f3 $x1 $y1 $f1 $ff]
                set xylist $xyf1
                foreach {xx1 yy1} $xyf1 {}
                foreach {xx2 yy2} $xyf2 {}
                lappend xylist $xx2 $yy2
                if {$contour_options(filled_contour)} {
                    set pxylist $xylist
                    lappend pxylist $x3 $y3 $x2 $y2
                    C_polygon $canv $pxylist [lindex $colorMap $ic] $doTrans
                    if {$ic == $imax} {
                        set pxylist $xylist
                        lappend pxylist $x1 $y1
                        C_polygon $canv $pxylist [lindex $colorMap $ic] $doTrans
                    }
                }
                C_line $canv $xylist [lindex $colorMap $ic] $doTrans
                set oldlist {}
                set x2 $xx1; set y2 $yy1; set f2 $ff
                set x3 $xx2; set y3 $yy2; set f3 $ff

                if {$ic == $imax} {
                    if {$contour_options(filled_contour)} {
                        set pxylist [list $x1 $y1 $x2 $y2 $x3 $y3]
                        set ictmp [expr {$ic + 1}]
                        C_polygon $canv $pxylist [lindex $colorMap $ictmp] $doTrans
                        return
                    }
                }

            }

            "-++" {
#debug#                puts "class I = $class , $ic , $ff"
                set xyf1  [fintpl $x1 $y1 $f1 $x2 $y2 $f2 $ff]
                set xyf2  [fintpl $x3 $y3 $f3 $x1 $y1 $f1 $ff]
                foreach {xx1 yy1} $xyf1 {}
                foreach {xx2 yy2} $xyf2 {}
                set xylist $xyf1
                lappend xylist $xx2 $yy2
                if {$contour_options(filled_contour)} {
                    set pxylist $xylist
                    lappend pxylist $x1 $y1
                    C_polygon $canv $pxylist [lindex $colorMap $ic] $doTrans
                }

                if {$ic == $imax} {
                    if {$contour_options(filled_contour)} {
                        set pxylist $xylist
                        lappend pxylist $x3 $y3 $x2 $y2
                        set ictmp [expr {$ic + 1}]
                        C_polygon $canv $pxylist [lindex $colorMap $ictmp] $doTrans
                    }

                } else {

#debug#                    puts "call Tri_contour : 1) $class"
#debug#                    puts "   : $xx1 $yy1 $ff $xx2 $yy2 $ff $x3 $y3 $f3"
                    Tri_contour $canv $xx1 $yy1 $ff $xx2 $yy2 $ff $x3 $y3 $f3 $cont $doTrans

#debug#                    puts "call Tri_contour : 2) $class"
#debug#                    puts "   : $xx1 $yy1 $ff $x3 $y3 $f3 $x2 $y2 $f2"
                    Tri_contour $canv $xx1 $yy1 $ff $x3 $y3 $f3 $x2 $y2 $f2 $cont $doTrans
                }
                C_line $canv $xylist [lindex $colorMap $ic] $doTrans
                return

            }

        }

    }
}

# setFLevel --
#     Auxiliary function: used to classify one functional value to another
# Arguments:
#     f1          Second break point and value
#     f2          Value to find
# Result:
#     +    f1 > f2
#     =    f1 = f2
#     -    f1 < f2
#
proc ::Plotchart::setFLevel {f1 f2} {
    if {$f1 > $f2} {
        return "+"
    } else {
        if {$f1 < $f2} {
            return "-"
        } else {
            return "="
        }
    }
}

# fintpl --
#     Auxiliary function: inverse interpolation
# Arguments:
#     x1,y1,f1    First break point and value
#     x2,y2,f2    Second break point and value
#     ff          Value to find
# Result:
#     x,y coordinates of point with that value
#
proc ::Plotchart::fintpl {x1 y1 f1 x2 y2 f2 ff} {

    if {[expr {$f2 - $f1}] != 0.0} {
        set xx  [expr {$x1 + (($ff - $f1)*($x2 - $x1)/($f2 - $f1))}]
        set yy  [expr {$y1 + (($ff - $f1)*($y2 - $y1)/($f2 - $f1))}]
    } else {

        # If the logic was handled correctly above, this point
        # should never be reached.
        #
        # puts "FINTPL : f1 == f2 : x1,y1 : $x1 , $y1 : x2,y2 : $x2 , $y2"
        set xx $x1
        set yy $y1
    }

    set xmin [min $x1 $x2]
    set xmax [max $x1 $x2]
    set ymin [min $y1 $y2]
    set ymax [max $y1 $y2]

    if {$xx < $xmin} { set xx $xmin }
    if {$xx > $xmax} { set xx $xmax }
    if {$yy < $ymin} { set yy $ymin }
    if {$yy > $ymax} { set yy $ymax }

    return [list $xx $yy]
}

# min --
#     Auxiliary function: find the minimum of the arguments
# Arguments:
#     val         First value
#     args        All others
# Result:
#     Minimum over the arguments
#
proc ::Plotchart::min { val args } {
    set min $val
    foreach val $args {
        if { $val < $min } {
            set min $val
        }
    }
    return $min
}

# max --
#     Auxiliary function: find the maximum of the arguments
# Arguments:
#     val         First value
#     args        All others
# Result:
#     Maximum over the arguments
#
proc ::Plotchart::max { val args } {
    set max $val
    foreach val $args {
        if { $val > $max } {
            set max $val
        }
    }
    return $max
}

# C_line --
#     Draw a line
# Arguments:
#     canv        Canvas to draw in
#     xylist      List of raw coordinates
#     color       Chosen colour
#     args        Any additional arguments (for line style and such)
# Result:
#     None
#
proc ::Plotchart::C_line {canv xylist color {doTrans 1} } {

    if {$doTrans} {
        set wxylist {}
        foreach {xx yy} $xylist {
            foreach {pxcrd pycrd} [::Plotchart::coordsToPixel $canv $xx $yy] {break}
            lappend wxylist $pxcrd $pycrd
        }
        eval "$canv create line $wxylist -fill $color"

    } else {
        $canv create line $xylist -fill $color
    }
}

# C_polygon --
#     Draw a polygon
# Arguments:
#     canv        Canvas to draw in
#     xylist      List of raw coordinates
#     color       Chosen colour
#     args        Any additional arguments (for line style and such)
# Result:
#     None
#
proc ::Plotchart::C_polygon {canv xylist color {doTrans 1}} {

    if {$doTrans} {
        set wxylist {}
        foreach {xx yy} $xylist {
            foreach {pxcrd pycrd} [::Plotchart::coordsToPixel $canv $xx $yy] {break}
            lappend wxylist $pxcrd $pycrd
        }
        eval "$canv create polygon $wxylist -fill $color"

    } else {
        $canv create polygon $xylist -fill $color
    }
}

# MakeContourClasses --
#     Return contour classes and colours
# Arguments:
#     values      List of values
#     classes     Given list of classes or class/colours
#     offset      Correction for calculating colours
# Result:
#     List of pairs of class limits and colours
# Note:
#     This should become more sophisticated!
#
proc ::Plotchart::MakeContourClasses {values classes offset} {
    variable contour_options
    variable colorMap

    if { [llength $classes] == 0 } {
        set min {}
        set max {}
        foreach row $values {
            foreach v $row {
                if { $v == {} } {continue}

                if { $min == {} || $min > $v } {
                    set min $v
                }

                if { $max == {} || $max < $v } {
                    set max $v
                }
            }
        }

        foreach {xmin xmax xstep} [determineScale $min $max] {break}

        #
        # The contour classes must encompass all values
        # There might be a problem with border cases
        #
        set classes {}
        set x $xmin

        while { $x < $xmax+0.5*$xstep } {
            #mbs# lappend classes [list $x]
            set  x [expr {$x+$xstep}]
            lappend classes [list $x]
        }

        # Now that we know how many entries (ncont), create
        # the colormap colors
        #
        ::Plotchart::setColormapColors  [expr {[llength $classes] + 1}] $offset

    } elseif { [llength [lindex $classes 0]] == 1 } {
        #mbs#  Changed the above line from " == 2 " to " == 1 "
        ::Plotchart::setColormapColors  [llength $classes] $offset
        return $classes
    }

    #
    # Add the colours
    #
#####    set cont {}
#####    set c 0
#####
#####    foreach x $classes {
#####        set col [lindex $contour_options(colourmap) $c]
#####        if { $col == {} } {
#####            set c 0
#####            set col [lindex $contour_options(colourmap) $c]
#####        }
#####        lappend cont [list $x $col]
#####        incr c
#####    }
#####
#####    return $cont

#debug#    puts "classes (cont) : $classes"

    return $classes
}


# setColormapColors --
#     Auxiliary function: Based on the current colormap type
#     create a colormap with requested number of entries
# Arguments:
#     ncont       Number of colors in the colormap
#     offset      Offset for interval
# Result:
#     List of colours
#
proc ::Plotchart::setColormapColors  {ncont offset} {
    variable colorMapType
    variable colorMap

#debug#    puts "SetColormapColors : ncont = $ncont"

    # Note : The default colormap is "jet"

    switch -- $colorMapType {

        custom {
            return
        }

        hsv {
            set hueStart     0.0
            set hueEnd     240.0
            set colorMap   {}

            for {set i 0} {$i <= $ncont} {incr i} {
                if { $ncont > 1 } {
                    set dh [expr {($hueStart - $hueEnd) / ($ncont - $offset)}]
                } else {
                    set dh 0.0
                }
                set hue  [expr {$hueStart - ($i * $dh)}]
                if {$hue < 0.0} {
                    set hue  [expr {360.0 + $hue}]
                }
                set rgbList [Hsv2rgb $hue 1.0 1.0]
                set r    [expr {int([lindex $rgbList 0] * 65535)}]
                set g    [expr {int([lindex $rgbList 1] * 65535)}]
                set b    [expr {int([lindex $rgbList 2] * 65535)}]

                set color  [format "#%.4x%.4x%.4x" $r $g $b]
                lappend colorMap $color
            }
        }

        hot {
            set colorMap {}
            set nc1          [expr {int($ncont * 0.33)}]
            set nc2          [expr {int($ncont * 0.67)}]

            for {set i 0} {$i <= $ncont} {incr i} {

                if {$i <= $nc1} {
                    set fval  [expr { double($i) / (double($nc1)) } ]
                    set r     [expr {int($fval * 65535)}]
                    set g     0
                    set b     0
                } else {
                    if {$i <= $nc2} {
                        set fval  [expr { double($i-$nc1) / (double($nc2-$nc1)) } ]
                        set r     65535
                        set g     [expr {int($fval * 65535)}]
                        set b     0
                    } else {
                        set fval  [expr { double($i-$nc2) / (double($ncont-$nc2)) } ]
                        set r     65535
                        set g     65535
                        set b     [expr {int($fval * 65535)}]
                    }
                }
                set color  [format "#%.4x%.4x%.4x" $r $g $b]
                lappend colorMap $color
            }
        }

        cool {
            set colorMap {}

            for {set i 0} {$i <= $ncont} {incr i} {

                set fval  [expr { double($i) / (double($ncont)-$offset) } ]
                set val   [expr { 1.0 - $fval }]

                set r    [expr {int($fval * 65535)}]
                set g    [expr {int($val * 65535)}]
                set b    65535

                set color  [format "#%.4x%.4x%.4x" $r $g $b]
                lappend colorMap $color
            }
        }

        grey -
        gray {
            set colorMap {}

            for {set i 0} {$i <= $ncont} {incr i} {

                set fval  [expr { double($i) / (double($ncont)-$offset) } ]
                set val  [expr {0.4 + (0.5 * $fval) }]

                set r    [expr {int($val * 65535)}]
                set g    [expr {int($val * 65535)}]
                set b    [expr {int($val * 65535)}]

                set color  [format "#%.4x%.4x%.4x" $r $g $b]
                lappend colorMap $color
            }
        }

        jet -
        default {
            set hueStart   240.0
            set hueEnd       0.0
            set colorMap   {}

            for {set i 0} {$i <= $ncont} {incr i} {
                if { $ncont > 1 } {
                    set dh [expr {($hueStart - $hueEnd) / ($ncont - $offset)}]
                } else {
                    set dh 0.0
                }
                set hue  [expr {$hueStart - ($i * $dh)}]
                if {$hue < 0.0} {
                    set hue  [expr {360.0 + $hue}]
                }
                set rgbList [Hsv2rgb $hue 1.0 1.0]
                set r    [expr {int([lindex $rgbList 0] * 65535)}]
                set g    [expr {int([lindex $rgbList 1] * 65535)}]
                set b    [expr {int([lindex $rgbList 2] * 65535)}]

                set color  [format "#%.4x%.4x%.4x" $r $g $b]
                lappend colorMap $color
            }
        }

    }
}

# colorMap --
#     Define the current colormap type
# Arguments:
#     cmap        Type of colormap
# Result:
#     Updated the internal variable "colorMapType"
# Note:
#     Possibly handle "custom" colormaps differently
#     At present, if the user passes in a list (length > 1)
#     rather than a string, then it is assumes that (s)he
#     passed in a list of colors.
#
proc ::Plotchart::colorMap {cmap} {
    variable colorMapType
    variable colorMap

    switch -- $cmap {

        "grey" -
        "gray" { set colorMapType $cmap }

        "jet"  { set colorMapType $cmap }

        "hot"  { set colorMapType $cmap }

        "cool" { set colorMapType $cmap }

        "hsv"  { set colorMapType $cmap }

        default {
            if {[string is alpha $cmap] == 1} {
                puts "Colormap : Unknown colorMapType, $cmap.  Using JET"
                set colorMapType jet

            } else {
                if {[llength $cmap] > 1} {
                    set colorMapType "custom"
                    set colorMap     $cmap
                }
            }
        }
    }
}



########################################################################
#  The following two routines were borrowed from :
#
#        http://mini.net/cgi-bin/wikit/666.html
########################################################################

# Rgb2hsv --
#
#       Convert a color value from the RGB model to HSV model.
#
# Arguments:
#       r g b  the red, green, and blue components of the color
#               value.  The procedure expects, but does not
#               ascertain, them to be in the range 0 to 1.
#
# Results:
#       The result is a list of three real number values.  The
#       first value is the Hue component, which is in the range
#       0.0 to 360.0, or -1 if the Saturation component is 0.
#       The following to values are Saturation and Value,
#       respectively.  They are in the range 0.0 to 1.0.
#
# Credits:
#       This routine is based on the Pascal source code for an
#       RGB/HSV converter in the book "Computer Graphics", by
#       Baker, Hearn, 1986, ISBN 0-13-165598-1, page 304.
#
proc ::Plotchart::Rgb2hsv {r g b} {
    set h [set s [set v 0.0]]
    set sorted [lsort -real [list $r $g $b]]
    set v [expr {double([lindex $sorted end])}]
    set m [lindex $sorted 0]

    set dist [expr {double($v-$m)}]
    if {$v} {
        set s [expr {$dist/$v}]
    }
    if {$s} {
        set r' [expr {($v-$r)/$dist}] ;# distance of color from red
        set g' [expr {($v-$g)/$dist}] ;# distance of color from green
        set b' [expr {($v-$b)/$dist}] ;# distance of color from blue
        if {$v==$r} {
            if {$m==$g} {
                set h [expr {5+${b'}}]
            } else {
                set h [expr {1-${g'}}]
            }
        } elseif {$v==$g} {
            if {$m==$b} {
                set h [expr {1+${r'}}]
            } else {
                set h [expr {3-${b'}}]
            }
        } else {
            if {$m==$r} {
                set h [expr {3+${g'}}]
            } else {
                set h [expr {5-${r'}}]
            }
        }
        set h [expr {$h*60}]          ;# convert to degrees
    } else {
        # hue is undefined if s == 0
        set h -1
    }
    return [list $h $s $v]
}

# Hsv2rgb --
#
#       Convert a color value from the HSV model to RGB model.
#
# Arguments:
#       h s v  the hue, saturation, and value components of
#               the color value.  The procedure expects, but
#               does not ascertain, h to be in the range 0.0 to
#               360.0 and s, v to be in the range 0.0 to 1.0.
#
# Results:
#       The result is a list of three real number values,
#       corresponding to the red, green, and blue components
#       of a color value.  They are in the range 0.0 to 1.0.
#
# Credits:
#       This routine is based on the Pascal source code for an
#       HSV/RGB converter in the book "Computer Graphics", by
#       Baker, Hearn, 1986, ISBN 0-13-165598-1, page 304.
#
proc ::Plotchart::Hsv2rgb {h s v} {
    set v [expr {double($v)}]
    set r [set g [set b 0.0]]
    if {$h == 360} { set h 0 }
    # if you feed the output of rgb2hsv back into this
    # converter, h could have the value -1 for
    # grayscale colors.  Set it to any value in the
    # valid range.
    if {$h == -1} { set h 0 }
    set h [expr {$h/60}]
    set i [expr {int(floor($h))}]
    set f [expr {$h - $i}]
    set p1 [expr {$v*(1-$s)}]
    set p2 [expr {$v*(1-($s*$f))}]
    set p3 [expr {$v*(1-($s*(1-$f)))}]
    switch -- $i {
        0 { set r $v  ; set g $p3 ; set b $p1 }
        1 { set r $p2 ; set g $v  ; set b $p1 }
        2 { set r $p1 ; set g $v  ; set b $p3 }
        3 { set r $p1 ; set g $p2 ; set b $v  }
        4 { set r $p3 ; set g $p1 ; set b $v  }
        5 { set r $v  ; set g $p1 ; set b $p2 }
    }
    return [list $r $g $b]
}

# DrawIsolinesFunctionValues --
#     Draw isolines in the given grid with given function values.
# Arguments:
#     canv : Canvas to draw in
#     xvec : List of points in the x axis
#     yvec : List of points in the y axis
#     fmat : Matrix of function values at the points defined by x and y.
#       The matrix is given as a list of rows, where each row
#       stores the function values with a fixed y and a varying x.
#     cont        List of contour classes (or empty to indicate
#                 automatic scaling
# Result:
#     None
# Side effect:
#     Isolines drawn
# Note:
#     A cell is only drawn if there are four well-defined
#     corners. If the x or y coordinate is missing or the value is
#     missing, the cell is skipped.
# Author : Michael Baudin
#
proc ::Plotchart::DrawIsolinesFunctionValues {canv xvec yvec fmat {cont {}}} {
  variable scaling
  set nx [llength $xvec]
  set ny [llength $xvec]
  if {$nx!=$ny} then {
    error "The number of values in xvec (nx=$nx) is different from the number of values in yvec (ny=$ny)"
  }
  #
  # Check the given values of xvec and yvec against the scaling of the plot,
  # which was given at the creation of the plot.
  #
  set index 0
  foreach xval $xvec {
    if {$xval > $scaling($canv,xmax) || $xval < $scaling($canv,xmin)} then {
      error "The given x value $xval at index $index of xvec is not in the x-axis range \[$scaling($canv,xmin),$scaling($canv,xmax)\]"
    }
    incr index
  }
  set index 0
  foreach yval $yvec {
    if {$yval > $scaling($canv,ymax) || $yval < $scaling($canv,ymin)} then {
      error "The given y value $yval at index $index of yvec is not in the y-axis range \[$scaling($canv,ymin),$scaling($canv,ymax)\]"
    }
    incr index
  }
  #
  # Form the xmat and ymat matrices based on the given x and y.
  #
  set xmat {}
  for {set iy 0} {$iy < $ny} {incr iy} {
    set xi {}
    for {set ix 0} {$ix < $nx} {incr ix} {
      lappend xi [lindex $xvec $ix]
    }
    lappend xmat $xi
  }
  set ymat {}
  for {set iy 0} {$iy < $ny} {incr iy} {
    set yi {}
    set yiy [lindex $yvec $iy]
    for {set ix 0} {$ix < $nx} {incr ix} {
      lappend yi $yiy
    }
    lappend ymat $yi
  }
  DrawIsolines $canv $xmat $ymat $fmat $cont
}

# DrawLegendIsolines --
#
#     Draw isolines in the legend for this plot
#
# Arguments:
#     w           Canvas/plot to draw in
#     values      List of values as used for the plot itself
#     contours    Contour classes
#
# Result:
#     None
#
# Side effect:
#     Entries in the legend added
#
# Note:
#     No support for an empty list of contour classes yet
#
proc ::Plotchart::DrawLegendIsolines {w values contours} {
    variable data_series
    variable colorMap

    set contours [MakeContourClasses $values $contours 1]

    set count 0
    foreach class $contours colour $colorMap {
        incr count
        set data_series($w,isoline_$class,-colour) $colour
        set data_series($w,isoline_$class,-type)   "line"

        DrawLegend $w "isoline_$class" "$class"

        if { $count == [llength $contours] } {
            break
        }
    }
}

# DrawLegendShades --
#
#     Draw shades in the legend for this plot
#
# Arguments:
#     w           Canvas/plot to draw in
#     values      List of values as used for the plot itself
#     contours    Contour classes
#
# Result:
#     None
#
# Side effect:
#     Entries in the legend added
#
# Note:
#     No support for an empty list of contour classes yet
#
proc ::Plotchart::DrawLegendShades {w values contours} {
    variable data_series
    variable colorMap

    set contours [MakeContourClasses $values $contours 0]

    set count 0
    set dir   "<"
    foreach class $contours colour $colorMap {
        incr count

        if { $count == [llength $colorMap] } {
            set dir ">"
            set class [lindex $contours end]
        }

        set data_series($w,shade_${dir}_$class,-colour) $colour
        set data_series($w,shade_${dir}_$class,-type)   "rectangle"

        DrawLegend $w "shade_${dir}_$class" "$dir $class"
    }
}

#
# Define default colour maps
#
namespace eval ::Plotchart {
     set contour_options(colourmap,rainbow) \
        {darkblue blue cyan green yellow orange red magenta}
     set contour_options(colourmap,white-blue) \
        {white paleblue cyan blue darkblue}

     set contour_options(colourmap,detailed) {
#00000000ffff
#000035e4ffff
#00006bc9ffff
#0000a1aeffff
#0000d793ffff
#0000fffff285
#0000ffffbca0
#0000ffff86bc
#0000ffff50d7
#0000ffff1af2
#1af2ffff0000
#50d7ffff0000
#86bcffff0000
#bca0ffff0000
#f285ffff0000
#ffffd7930000
#ffffa1ae0000
#ffff6bc90000
#ffff35e40000
#ffff00000000
#ffff00000000
}
    set contour_options(colourmap) $contour_options(colourmap,detailed)
}

#
# Define the default colour map
#
::Plotchart::colorMap jet

# End of plotcontour.tcl
