# procedure edge_mesh_init
#
# Set up graphical editing form for canvas widget
#
# Forest Rouse ICEM CFD Engineering (c) 1998
#
# input:
#
#  length        - length of edge
#  height        - maximum height
#  type          - Type of editing curve.  If specify spline --
#		   makes polyline a spline.  Synomyms for spline are
#                  smooth and curve.
#  np		 - number of edge meshing points desired
#  ticks         - tick mark callback (for use with standard callback)
#  meshlawname     - how to translate linear/spline into eparam_law
#  act_callback  - proc to invoke on create, move, delete etc (if any)
#
# output: - none

# side effects:
#
#  Sets global array edge_meshc_params
#

proc edge_meshc_init {{length 1.0} {param 1} {type {}} {func {}} {np 4} \
			  {ticks {}} {meshlawname {}} {file_callback {}} \
			  {act_callback edge_meshc_standard_callback}
		      {incr_np_callback {}} {decr_np_callback {}}} {
    
    global edge_meshc_points edge_meshc_params
    global eparam_actual eparam_sp1 eparam_sp2
    
    # window names.  Do this first to avoid infinite loops for setting the
    # length, type and callback

    set w .edgemc
    set c $w.c
    set bd $w.bunching
    
    set edge_meshc_params(w) $w
    set edge_meshc_params(c) $c
    set edge_meshc_params(bd) $bd
    set edge_meshc_params(bdlines) ""
    set edge_meshc_params(edgepointsactive) 0
    
    # nil points
    
    set edge_meshc_points(0) {}
    set edge_meshc_points(1) {}
    set edge_meshc_points(2) {}
    
    set edge_meshc_params(width)   350
    set edge_meshc_params(height)  400
    
    set xmargin 22
    set ymargin 25
    set ylabelmargin 0
    
    set edge_meshc_params(xmargin) $xmargin
    set edge_meshc_params(ymargin) $ymargin
    
    set edge_meshc_params(point_radius) 6
    set edge_meshc_params(minsep)       1
    set edge_meshc_params(eps)          10
    set edge_meshc_params(longtick)     12
    set edge_meshc_params(shortick)     6
    set edge_meshc_params(bunchdispy)   \
	[expr $edge_meshc_params(longtick)+10]
    
    set edge_meshc_params(xorigin) $xmargin
    set edge_meshc_params(yorigin) [expr $edge_meshc_params(height)-$ymargin-$ylabelmargin]
    
    set edge_meshc_params(xmax) [expr $edge_meshc_params(width)-$xmargin]
    set edge_meshc_params(ymax) $ymargin
    
    # changeable values for xorigin and xmax
    
    set edge_meshc_params(curxorigin) $xmargin
    set edge_meshc_params(curxmax)    $edge_meshc_params(xmax)
    
    # don't let control points at end of line be overridden
    
    set edge_meshc_params(minx) [expr $xmargin + 1]
    set edge_meshc_params(maxx) [expr $edge_meshc_params(xmax)-1]
    
    # length between the edge points
    
    set edge_meshc_params(clength) 1.0
    set edge_meshc_params(fe)      0.
    set edge_meshc_params(le)      0.
    
    
    set edge_meshc_params(background)    gray
    set edge_meshc_params(fill)          black
    
    set edge_meshc_params(point_color)   red
    set edge_meshc_params(point_outline) black
    
    set edge_meshc_params(line_color)    black
    set edge_meshc_params(line_width)    1.0
    
    edge_meshc_setlength $length $param
    edge_meshc_setcurvetype $type $func
    edge_meshc_setnpoints $np
    
    set edge_meshc_params(tickmarks) $ticks
    set edge_meshc_params(current_ticklist) {}
    set edge_meshc_params(meshlawname) $meshlawname
    set edge_meshc_params(filebrowser) $file_callback
    set edge_meshc_params(callback) $act_callback
    edge_meshc_setinitpoints
    
    set edge_meshc_params(sp1) 0.
    set edge_meshc_params(sp2) 0.
    set edge_meshc_params(asp1) 0.
    set edge_meshc_params(asp2) 0.
	    
    set edge_meshc_params(reflect_sp1) 0.
    set edge_meshc_params(reflect_sp2) 0.
}

proc edge_meshc_setlength {{edge_length 1.0} {parameter 0}} {
    global edge_meshc_params
    
    if ![info exists edge_meshc_params(w)] {
	edge_meshc_init
    }
    
    set edge_meshc_params(edge_length)     $edge_length
    set edge_meshc_params(length_is_param) $parameter
    set edge_meshc_params(xnorm_length)    1.0
    set edge_meshc_params(ynorm_height)    1.0
}

# procedure edge_meshc_setcurvetype
#
# Set state of line type
#
# Forest Rouse ICEM CFD Engineering (c) 1998
#
# input:
#
#   type - Type of editing curve.  If specify spline -- makes polyline a
#	   spline.  Synomyms for spline are smooth and curve.

# output - none

# side effects:
#
#  Sets global array edge_meshc_params(smooth)
#

proc edge_meshc_setcurvetype {{type {}} {func {}}} {
    global edge_meshc_params
    
    if ![info exists edge_meshc_params(w)] {
	edge_meshc_init
    }
    switch $type {
	smooth -
	Smooth -
	spline -
	Spline -
	curve -
	Curve {
	    set edge_meshc_params(smooth) 1
	}
	
	"" {
	    #
	    # use current value but is none exists, set default to
	    # linear
	    
	    if ![info exists edge_meshc_params(smooth)] {
		set edge_meshc_params(smooth) 0
	    }
	}
	
	default {
	    set edge_meshc_params(smooth) 0
	}
    }
    
    if {$func == ""} {
	if {$edge_meshc_params(smooth)} {
	    set func "spline"
	} else {
	    set func "linear"
	}
    }
    
    set edge_meshc_params(func) $func
}

proc edge_meshc_setnpoints {{np 4}} {
    global edge_meshc_params
    
    if ![info exists edge_meshc_params(w)] {
	edge_meshc_init
    }
    
    set edge_meshc_params(npoints) $np
}

proc edge_meshc_setcallback \
    {{tick_marks {}}  {meshlawname {}} {file_callback {}} \
	 {act_callback edge_meshc_standard_callback}} {
	     
    global edge_meshc_params
    
    if ![info exists edge_meshc_params(w)] {
	edge_meshc_init
    }
    
    set edge_meshc_params(tickmarks) $tick_marks
    set edge_meshc_params(meshlawname) $meshlawname
    set edge_meshc_params(filebrowser) $file_callback
    set edge_meshc_params(callback) $act_callback
}

proc edge_meshc_setinitpoints {{initial_points {}}} {
    global edge_meshc_points edge_meshc_params
    
    # make sure the current function is erased before
    # nilling out the tag name (edge_meshc_points(1))
    
    edge_meshc_erasecurrentfunc
    
    set edge_meshc_points(0) {}
    set edge_meshc_points(1) {}
    set edge_meshc_points(2) {}
    
    # set the list of initial points based on the function
    # (edge_meshc_params(func)) and the initial point list
    # edge_meshc_initialpoints will set the end point values
    # if initial_points is empty
    
    # end points are handled seperately from the rest of the points.
    # the reason is that we need to initialize the point list at the
    # end points to properly insert the points in-between
    
    set sc_end_points ""
    set sc_restof_points ""
    
    set fe $edge_meshc_params(fe)
    set le [expr 1.0-$edge_meshc_params(le)]
    set clength $edge_meshc_params(clength)
    set end_points ""
    set restof_points ""
    
    if {$initial_points == ""} {
	switch $edge_meshc_params(func) {
	    spline -
	    s_curve {
		set end_points "$fe 0. $le 1."
		set restof_points \
		    "[expr .45*$clength+$fe] 0. [expr .55*$clength+$fe] 1."
	    }
	    
	    middle {
		set end_points "$fe 0. $le 0."
		set restof_points \
		    "[expr .3*$clength+$fe] 1. [expr .7*$clength+$fe] 1."
	    }
	    
	    ramp {
		set end_points "$fe 0. $le 1."
		set restof_points ""
	    }
	    
	    ends  {
		set end_points "$fe 1. $le 1."
		set restof_points \
		    "[expr .3*$clength+$fe] .1 [expr .7*$clength+$fe] .1"
	    }
	    
	    exp {
		set end_points "$fe 0. $le 1."
		set restof_points \
		    "[expr .45*$clength+$fe] 0. [expr .92*$clength+$fe] .2"
	    }
	    
	    bell {
		set end_points "$fe 0. $le 0."
		set restof_points \
		    "[expr .2*$clength+$fe] 0. [expr .45*$clength+$fe] 1. \
 [expr .55*$clength+$fe] 1. [expr .8*$clength+$fe] 0"
	    }
	    
	    linear -
	    constant -
	    default {
		set end_points "$fe 1. $le 1."
		set restof_points ""
	    }
	}
	set sc_end_points [edge_meshc_coordtoscreen $end_points]
	set sc_restof_points [edge_meshc_coordtoscreen $restof_points]
	set exclude 0
	set last_index -1
    } else {
	set initial_points [edge_meshc_sortinitial $initial_points]
	set sc_restof_points [edge_meshc_coordtoscreen $initial_points]
	set last_index [expr [llength $sc_restof_points]-1]
	lappend sc_end_points [lindex $sc_restof_points 0]
	lappend sc_end_points [lindex $sc_restof_points $last_index]
	set exclude 1
    }

    lappend edge_meshc_points(0) [lindex $sc_end_points 0]
    lappend edge_meshc_points(0) [lindex $sc_end_points 1]
    
    # now add the rest of the points
    
    set idx 0
    foreach p $sc_restof_points {
	if {$exclude && ($idx == 0 || $idx == $last_index)} {
	    incr idx
	    continue
	}
	incr idx
	
	set x [lindex $p 0]
	set y [lindex $p 1]
	
	set xn [edge_meshc_min [edge_meshc_max $x $edge_meshc_params(minx)] \
		    $edge_meshc_params(maxx)]
    
	set yn [edge_meshc_min [edge_meshc_max $y $edge_meshc_params(ymax)] \
		    $edge_meshc_params(yorigin)]
    
	edge_meshc_addpointsorted $xn $yn 1
    }
}

proc edge_meshc_sortinitial {initial_points} {
    set len [llength $initial_points]
    set temp ""
    for {set i 0} {$i < $len} {incr i 2} {
	set x [lindex $initial_points $i]
	set y [lindex $initial_points [expr $i+1]]
	lappend temp "$x $y"
    }
    set temp [lsort -command edge_meshc_orderpoints $temp]
    set ret ""
    foreach p $temp {
	append ret "[lindex $p 0] [lindex $p 1] "
    }
    return $ret
}

proc edge_meshc_orderpoints {point1 point2} {
    set x1 [lindex $point1 0]
    set x2 [lindex $point2 0]
    
    if {$x1 > $x2} {
	return 1
    } elseif {$x2 > $x1} {
	return -1
    }    
    return 0
}

# procedure edge_meshc_form
#
# Set up graphical editing form for canvas widget
#
# Forest Rouse ICEM CFD Engineering (c) 1998
#
# input:
#
#    initial_points - list of initial points (other than end points)
#
# output:
#
#    form status: 1 - accept, 0 cancel
#
# side effects:
#
#  Creates canvas widget with initial set of control points
#

proc edge_meshc_form {} {
    global edge_meshc_params edge_meshc_done edge_meshc_points
    global guibase_dir is_win
    
    if ![info exists edge_meshc_params(w)] {
	    edge_meshc_init
    }
    
    set w $edge_meshc_params(w)
    set c $edge_meshc_params(c)
    set bd $edge_meshc_params(bd)
    
    toplevel $w
    
    set xo $edge_meshc_params(xorigin)
    set yo $edge_meshc_params(yorigin)
    set xm $edge_meshc_params(xmax)
    set ym $edge_meshc_params(ymax)
    
    # First create parameter button frame
    
    frame $w.f1
    blt_table $w $w.f1 0,0 -columnspan 5 -fill both
    
    menubutton $w.f1.file -text "File" -relief raised -bd 2 \
	-menu $w.f1.file.menu
    
    menubutton $w.f1.funcs -text "Functions" -relief raised -bd 2 \
	-menu $w.f1.funcs.menu
    
    menubutton $w.f1.flip -text "Reverse" -relief raised -bd 2 \
	-menu $w.f1.flip.menu
    
    button $w.f1.toglinspl -text "Linear" -command edge_meshc_togglelinspl
    if $edge_meshc_params(length_is_param) {
	set lentext "Parameter"
    } else {
	set lentext "Actual"
    }
    button $w.f1.togparam -text $lentext -command edge_meshc_toggleparameter
    
    set col 0   
    foreach mb "\{$w.f1.file 1\} \{$w.f1.funcs 1\} \{$w.f1.flip 1\} \
 \{$w.f1.toglinspl 1\} \{$w.f1.togparam 1\}" {
	set widget [lindex $mb 0]
	set colspn [lindex $mb 1]
	blt_table $w.f1 $widget 0,$col -columnspan $colspn -fill both
	incr col $colspn
    }
    # make the allowed function list.  Note that both mesh_hexa (external)
    # and meshc (internal) can build and use this list
    
    set edge_meshc_params(funclist) [edge_meshc_funclist]
    
    menu $w.f1.file.menu
    $w.f1.file.menu add command -label "Save To File..." \
	-command edge_meshc_store
    $w.f1.file.menu add command -label "Load From File..." \
	-command edge_meshc_load
    
    menu $w.f1.funcs.menu
    foreach f $edge_meshc_params(funclist) {
	$w.f1.funcs.menu add command -label [lindex $f 0] \
	    -command "edge_meshc_setfunc [lindex $f 1]"
    }
    
    menu $w.f1.flip.menu
    $w.f1.flip.menu add command -label "X: About X" \
	-command "edge_meshc_reverse x 1"
    $w.f1.flip.menu add command -label "Y: About Y" \
	-command "edge_meshc_reverse y 1"
    
    $w.f1.flip.menu add command -label "First <-> Last" \
	     -command "edge_meshc_reverse edge 1"
    
    # next pack the canvas into form
    
    canvas $c -width $edge_meshc_params(width) -height \
	$edge_meshc_params(height)
    bind $c <Button-1> "edge_meshc_pointcreate %x %y"
    bind $c <Double-Button-1> "edge_meshc_pointdelete %x %y"
    
    blt_table $w $c 2,0 -columnspan 5

    label $w.labelx -text "Edge Distance"
    blt_table $w $w.labelx 3,0 -columnspan 5
    
    # bunching label
    
    set row 4
    if {$edge_meshc_params(tickmarks) != ""} {
	set yto [expr $edge_meshc_params(bunchdispy) - 3]
	canvas $bd -width $edge_meshc_params(width) \
	    -height $edge_meshc_params(bunchdispy)
	
	$bd create line $xo $yto $xm $yto -fill \
	    $edge_meshc_params(line_color)
	
	blt_table $w $bd $row,0 -columnspan 5
	incr row
	
	label $w.bunchingl -text "Bunching"
	blt_table $w $w.bunchingl $row,0 -columnspan 5
	incr row
    }
    
    checkbutton $w.activate \
	-variable edge_meshc_params(edgepointsactive)
    
    label $w.firstl -text "Set First" -fg blue
    label $w.npl -text "Num. Points" -fg blue
    label $w.lastl -text "Set Last" -fg blue
    
    blt_table $w $w.activate $row,0 -columnspan 1
    blt_table $w $w.firstl $row,1 -columnspan 1
    blt_table $w $w.npl $row,2 -columnspan 2
    blt_table $w $w.lastl $row,4 -columnspan 1
    incr row
    
    entry $w.first -width 12
    bind $w.first <Return> edge_meshc_edgepointupdate
    bind $w.first <Button-1> "edge_meshc_edgepointsactive 1"
    
    frame $w.f2
    if [info exists guibase_dir] {
	set up @$guibase_dir/goup.xbm
	set dn @$guibase_dir/godown.xbm
	
	button $w.f2.up -bitmap $up -command "edge_meshc_bmnpoints 1"
	button $w.f2.dn -bitmap $dn -command "edge_meshc_bmnpoints -1"
	
	set has_buts 1
    } else {
	set has_buts 0
    }
	    
    set col 0
    if $has_buts {
	blt_table $w.f2 $w.f2.up 0,$col -columnspan 1
	incr col
    }
    
    entry $w.f2.en -textvariable edge_meshc_params(npoints) -width 12
    
    bind $w.f2.en <Return> edge_meshc_setmodals
    blt_table $w.f2 $w.f2.en 0,$col -columnspan 1
    incr col
    
    if $has_buts {
	blt_table $w.f2 $w.f2.dn 0,$col -columnspan 1
    }
    
    entry $w.last -width 12
    bind $w.last <Return> edge_meshc_edgepointupdate
    bind $w.last <Button-1> "edge_meshc_edgepointsactive 1"
    
    blt_table $w $w.first $row,1 -columnspan 1 -padx 1m
    blt_table $w $w.f2 $row,2 -columnspan 2 -padx 1m
    blt_table $w $w.last $row,4 -columnspan 1 -padx 1m
    incr row

    label $w.first_reflect -width 12 \
	-textvariable edge_meshc_params(reflect_sp1) -fg black
    
    label $w.reflectl -text "Current Spacings" -fg blue
    
    label $w.last_reflect -width 12 \
	-textvariable edge_meshc_params(reflect_sp2) -fg black
    
    blt_table $w $w.first_reflect $row,1 -columnspan 1 -padx 1m
    blt_table $w $w.reflectl $row,2 -columnspan 2 -padx 1m
    blt_table $w $w.last_reflect $row,4 -columnspan 1 -padx 1m
    incr row
    
    set edge_meshc_done 0
    
    frame $w.empty -width 1 -height 10
    blt_table $w $w.empty $row,0 -columnspan 5
    incr row
    
    frame $w.f3
    blt_table $w $w.f3 $row,0 -columnspan 5
    incr row
    
    button $w.f3.done -text "Done" -command "set edge_meshc_done 1"
    frame $w.f3.empty -width 10
    button $w.f3.cancel -text "Cancel" -command "set edge_meshc_done 0"
    
    $w.f3.done configure -background gray
    $w.f3.cancel configure -background grey
    
    blt_table $w.f3 $w.f3.done 0,0 -columnspan 1 -fill both \
	-ipadx 2m -ipady 1m
    blt_table $w.f3 $w.f3.empty 0,1 -columnspan 1
    blt_table $w.f3 $w.f3.cancel 0,2 -columnspan 1 -fill both \
	-ipadx 2m -ipady 1m
    
    # configure all of the edgepoint entry boxes/menus
    
    edge_meshc_configureedgepoint
    
    # create initial points -- both from scratch and already stored
    # linear/spline interpolation/control points
    
    edge_meshc_setfunc $edge_meshc_params(func)
    
    set xmid [expr ($xo + $xm)/2]
    set ymid [expr ($yo + $ym)/2]
    
    set length 0
    if $edge_meshc_params(length_is_param) {
	set length $edge_meshc_params(xnorm_length)
    } else {
	set length $edge_meshc_params(edge_length)
    }
    set height $edge_meshc_params(ynorm_height)
    
    # create axes
    
    $c create line $xo $yo $xo $ym -fill $edge_meshc_params(line_color)
    $c create line $xo $yo $xm $yo -fill $edge_meshc_params(line_color)
    
    # a few tick marks
    
    set ltl $edge_meshc_params(longtick)
    set stl $edge_meshc_params(shortick)
    
    $c create line $xmid $yo $xmid [expr $yo-$stl] \
	-fill $edge_meshc_params(line_color)
    $c create line $xm $yo $xm [expr $yo-$ltl] \
	-fill $edge_meshc_params(line_color)
    
    $c create line $xo $ymid [expr $xo+$stl] $ymid \
	-fill $edge_meshc_params(line_color)
    $c create line $xo $ym [expr $xo+$ltl] $ym \
	-fill $edge_meshc_params(line_color)
    
    # a few labels
    
    $c create text $xo [expr $yo+10] -text 0.0 -anchor nw
    set edge_meshc_params(midx) \
	[$c create text $xmid [expr $yo+10] -text \
	     [format %.1f [expr $length/2.]] -anchor n]
    
    set edge_meshc_params(endx) \
	[$c create text $xm [expr $yo+10] -text [format %.1f $length] \
	     -anchor ne]
    
    $c create text 1 $ymid -text \
	[format %.1f [expr $height/2.]] -anchor w
    $c create text 1 $ym -text [format %.1f $height] -anchor w
    
    wm minsize $w 200 200
    wm title $w "Relative Point Density vs Edge Distance"
    if $is_win { wm attributes $w -topmost 1 }
    set wx [expr [winfo rootx .] + 50]
    set wy [expr [winfo rooty .] + 50]
    wm geometry $w +$wx+$wy
    
    # display initial line
    
    edge_meshc_update 1
	
    # establish the trace on edgepointsactive to turn on/off the
    # menu entries
    
    trace variable edge_meshc_params(edgepointsactive) w edge_meshc_edgepointtrace
    
    edge_meshc_checknpoints
    
    # wait until done   
    set edge_meshc_params(formup) 1

    tkwait variable edge_meshc_done
    
    # get rid of the form
    
    destroy $w
    unset edge_meshc_params(formup)
    
    # set that need initialization
    
    unset edge_meshc_params(w)
    
    # get rid of the trace for edgepointsactive
    
    trace vdelete edge_meshc_params(edgepointsactive) w edge_meshc_edgepointtrace
    
    return $edge_meshc_done
}

proc edge_meshc_funclist {} {
    
    # linear and spline names have to match eparam_law names
    
    return [list {Constant constant} \
		{Ramp ramp} \
		{"S curve" s_curve} \
		{"Parabola Middle" middle} \
		{"Parabola Ends" ends} \
		{Exponential exp} \
		{Gaussian bell} \
		{Linear linear} \
		{Spline spline}]
}
   
proc edge_meshc_funcname {{key {}}} {
    set funclist [edge_meshc_funclist]
    set allnames ""
    foreach f $funclist {
	lappend allnames [lindex $f 0]
    }
    if {$key == ""} {
	return $allnames
    } else {
	set idx [lsearch $allnames $key]
	if {$idx >= 0} {
	    return [lindex [lindex $funclist $idx] 1]
	} else {
	    return ""
	}
    }
}
   
proc edge_meshc_transfuncname {{key {}}} {
    set funclist [edge_meshc_funclist]
    set allnames ""
    foreach f $funclist {
	lappend allnames [lindex $f 1]
    }
    if {$key == ""} {
	return $allnames
    } else {
	set idx [lsearch $allnames $key]
	if {$idx >= 0} {
	    return [lindex [lindex $funclist $idx] 0]
	} else {
	    return ""
	}
    }
}
   
proc edge_meshc_funcsmooth {func} {
    switch $func {
	spline -
	s_curve -
	middle -
	ends -
	exp -	    
	bell {
	   return 1
	}
	ramp -
	linear -
	constant -
	default {
	    return 0
	}
    }
    
}

# Should use a file browser widget

proc edge_meshc_store {} {
    global edge_meshc_points edge_meshc_params
    
    set filebrowser $edge_meshc_params(filebrowser)
    set w $edge_meshc_params(w)
    
    set fd 0
    if {$filebrowser != ""} {
	set file [$filebrowser]
	if {$file != ""} {
	    if [catch {set fd [open $file w]} msg] {
		tk_dialog $w "File Error" "Cannot write $file: $msg" \
		    "" 0 "Ok"
		return
	    }
	    set writetext \
		[list $edge_meshc_params(npoints) \
		     $edge_meshc_params(smooth) \
		     [edge_meshc_screentocoord $edge_meshc_points(0)]]
	    
	    puts $fd $writetext
	    close $fd
	}
    }
}
    
proc edge_meshc_load {} {
    global edge_meshc_points edge_meshc_params
    
    set filebrowser $edge_meshc_params(filebrowser)
    set w ""
    set fd 0

    if {$filebrowser != ""} {
	set file [$filebrowser]
	if {$file != ""} {
	    if [catch {set fd [open $file r]} msg] {
		tk_dialog $w "File Error" "Cannot read $file: $msg" \
		    "" 0 "Ok"
		return
	    }
	    set readtext [read $fd]
	    close $fd
	    
	    set edge_meshc_params(npoints) [lindex $readtext 0]
	    set edge_meshc_params(smooth) [lindex $readtext 1]
	    set edge_meshc_points(0) \
		[edge_meshc_coordtoscreen [lindex $readtext 2]]
	    edge_meshc_edgeminmax
	    
	    # get rid of current points
	    
	    $edge_meshc_params(c) delete cpoints
	    edge_meshc_createcontrol
   
	    # update everyone
	    
	    edge_meshc_setmodals
	}
    }
}

proc edge_meshc_edgepointtrace {name element op} {
    global edge_meshc_params
    
    edge_meshc_configureedgepoint
    edge_meshc_edgepointupdate
}

proc edge_meshc_edgepointupdate_ext {} {
    global edge_meshc_params
    
    # don't do anything if the form is not available
    
    if [info exists edge_meshc_params(w)] {
	edge_meshc_edgepointupdate
    }
}

proc edge_meshc_edgepointupdate {} {
    edge_meshc_rescalecontrol
    edge_meshc_update 1
}

proc edge_meshc_configureedgepoint {} {
    global edge_meshc_params
    
    set state 0
    set color 0
    if $edge_meshc_params(edgepointsactive) {
	set state normal
	set color $edge_meshc_params(fill)
    } else {
	set state disabled
	set color $edge_meshc_params(background)
    }
    
    set w $edge_meshc_params(w)
    $w.f1.flip.menu entryconfigure 3 -state $state
    $w.first configure -fg $color
    $w.last configure -fg $color
    
    if $edge_meshc_params(length_is_param) {
	$w.first configure -textvariable edge_meshc_params(sp1)
	$w.last configure -textvariable edge_meshc_params(sp2)
    } else {
	$w.first configure -textvariable edge_meshc_params(asp1)
	$w.last configure -textvariable edge_meshc_params(asp2)
    }
}

# procedure edge_meshc_setmodals
#
# Update model due to changes in modal settings
#
# Forest Rouse ICEM CFD Engineering (c) 1998
#
# input: none
#
# output: - none
#
# side effects:
#
#  Sets eparam_law and eparam_np based on change in modal setting
#  invoked by right button menu.  Invokes $edge_meshc_params(meshlawname)
#

proc edge_meshc_togglelinspl {} {
    global edge_meshc_params
    
    set edge_meshc_params(smooth) [expr !$edge_meshc_params(smooth)]
    edge_meshc_setmodals
}

proc edge_meshc_toggleparameter {} {
    global edge_meshc_params
    
    set edge_meshc_params(length_is_param) \
	[expr !$edge_meshc_params(length_is_param)]
    
    edge_meshc_setparamdisplay
}

proc edge_meshc_setparamdisplay {} {
    global edge_meshc_params
    
    set length ""
    set text ""
    if $edge_meshc_params(length_is_param) {
	set length $edge_meshc_params(xnorm_length)
	set text "Parameter"
    } else {
	set length $edge_meshc_params(edge_length)
	set text "Actual"
    }
    
    set c $edge_meshc_params(c)
    set w $edge_meshc_params(w)
    $c itemconfigure $edge_meshc_params(midx) -text \
	[format %.1f [expr $length/2.]]
    
    $c itemconfigure $edge_meshc_params(endx) -text [format %.1f $length]
    
    # set the state of the parameter/actual toggle button
    
    $w.f1.togparam configure -text $text
    
    # configure the entry boxes for the parameter/actual state
    
    edge_meshc_configureedgepoint
    edge_meshc_update 1
}

proc edge_meshc_edgepointsactive {{val 1}} {
    global edge_meshc_params
    
    set edge_meshc_params(edgepointsactive) $val
    
    # trace will call update
}

proc edge_meshc_bmnpoints {val} {
    global edge_meshc_params
    
    incr edge_meshc_params(npoints) $val 
    edge_meshc_setmodals
}

proc edge_meshc_checknpoints {} {
    global edge_meshc_params
    
    if $edge_meshc_params(edgepointsactive) {
	set minn 4
    } else {
	set minn 2
    }
    
    if {$edge_meshc_params(npoints) < $minn} {
	set edge_meshc_params(npoints) $minn
    }
}

proc edge_meshc_setmodals {} {
    global eparam_law eparam_np edge_meshc_params
    
    # make sure npoints is within range
    
    edge_meshc_checknpoints
    
    set mln $edge_meshc_params(meshlawname)
    set newlaw ""
    if $edge_meshc_params(smooth) {
	set newlaw spline
    } else {
	set newlaw linear
    }
    
    # if translation routine available, translate the name
    
    if {$mln != ""} {
	set eparam_law [$mln $newlaw]
    } else {
	set eparam_law $newlaw
    }
    
    # reset the number of points
    
    set eparam_np $edge_meshc_params(npoints)
    edge_meshc_update 1
}

proc edge_meshc_setfunc {func} {
    global edge_meshc_points edge_meshc_params eparam_func
    
    if {$func == ""} {
	if {$edge_meshc_params(smooth)} {
	    set func "spline"
	} else {
	    set func "linear"
	}
    }
    
    set edge_meshc_params(func) $func
    set eparam_func [edge_meshc_transfuncname $func]
    
    # first set if the function is a spline interpolation or not
    
    set edge_meshc_params(smooth) [edge_meshc_funcsmooth $func]
    
    # now set the points.  Notice that multi-linear and spline do
    # not change the current set of control points/interpolation
    # points
    
    switch $edge_meshc_params(func) {
	spline -
	linear {
	    edge_meshc_setinitpoints \
		[edge_meshc_screentocoord $edge_meshc_points(0)]
	}
	
	s_curve -
	middle -
	ends -
	exp -	    
	bell -
	ramp -
	constant -
	default {
	    edge_meshc_setinitpoints
	}
    }
    edge_meshc_createcontrol
    
    # update the meshing parameters and the edit palette
    
    edge_meshc_setmodals
}

proc edge_meshc_reverse {axis {doupdate 1}} {
    global edge_meshc_points edge_meshc_params eparam_actual
    global eparam_sp1 eparam_sp2
    
    set points [edge_meshc_screentocoord $edge_meshc_points(0)]
    set newpoints ""
    
# tricky.  Reflecting in X reverses the end points.  To handle
# in a natural way make an indirect pointer to the order
# the points should be handled
    
    set len [llength $points]
    
# actual length of domain of control points
    
    set fe $edge_meshc_params(fe)
    set le $edge_meshc_params(le)
    set pivot [expr $fe + 1.0 - $le]
    
    set ax 0
    if {$axis == "x"} {
	set ax 0
	set order(0) [expr ($len/2)-1]
	for {set i 1} {$i < ($len/2)-1} {incr i} {
	    set order($i) $i
	}
	set order([expr ($len/2)-1]) 0
    } elseif {$axis == "y"} {
	set ax 1
	for {set i 0} {$i < $len/2} {incr i} {
	    set order($i) $i
	}
    } elseif {$axis == "edge"} {
	set ax 2
    }
		
    if {$ax < 2} {
	for {set i 0} {$i < $len/2} {incr i} {
	    set nextIndex $order($i)
	    set ii [expr 2*$nextIndex]
	    set x [lindex $points $ii]
	    set y [lindex $points [expr $ii+1]]
	    if $ax {
		set y [expr 1.0-$y]
	    } else {
		set x [expr $pivot-$x]
	    }
	    append newpoints "$x $y "
	}
    
	# reconvert back into screen coordinates
	
	edge_meshc_setinitpoints $newpoints
	if $doupdate edge_meshc_createcontrol
    }
    
    if {$ax == 0 || $ax == 2} {
	set t1 $edge_meshc_params(sp1)
	set t2 $edge_meshc_params(asp1)
	
	set edge_meshc_params(sp1) $edge_meshc_params(sp2)
	set edge_meshc_params(sp2) $t1
	
	set edge_meshc_params(asp1) $edge_meshc_params(asp2)
	set edge_meshc_params(asp2) $t2
	if $doupdate edge_meshc_rescalecontrol
    }
    if $doupdate edge_meshc_update
}

proc edge_meshc_createcontrol {} {
	    
    global edge_meshc_points
    
    set idx 0
    foreach p $edge_meshc_points(0) {
	edge_meshc_pointcreate [lindex $p 0] [lindex $p 1] 1 $idx 0
	incr idx
    }
}

proc edge_meshc_rescalecontrol {} {
	    
    global edge_meshc_points edge_meshc_params
    
    set oldorigin $edge_meshc_params(curxorigin)
    set oldlength $edge_meshc_params(clength)
    
    # now reset based on current settings of edgepointsactive
    # edge_meshc_params(sp1), edge_meshc_params(sp2)
    # (edge_meshc_params(asp1), edge_meshc_params(asp2))
    
    edge_meshc_edgeminmax
    
    # get the current values of the origin and control range
    # length.  This will be where the first and last edge points
    # are
    
    set fe $edge_meshc_params(curxorigin)
    set cl $edge_meshc_params(clength)
    set scale [expr $cl/$oldlength]
    
    set newc ""
    foreach p $edge_meshc_points(0) {
	set x [lindex $p 0]
	
	# scale to new length from first edge point to last
	
	set xn [expr $fe + round(($x-$oldorigin)*$scale)]
	lappend newc "$xn [lindex $p 1]"
    }
    set edge_meshc_points(0) $newc
    
    # get rid of current points then create the newly
    # rescaled/translated control points
	    
    $edge_meshc_params(c) delete cpoints
    set edge_meshc_points(1) ""
    edge_meshc_createcontrol
}

proc edge_meshc_edgeminmax {} {
    global edge_meshc_params eparam_sp1 eparam_sp2 eparam_actual
    
    set xo $edge_meshc_params(xorigin)
    set xrange [expr $edge_meshc_params(xmax)-$xo]
    set length $edge_meshc_params(xnorm_length)
    
    if {[scan $edge_meshc_params(sp1) %g h] != 1} {
	set edge_meshc_params(sp1) 0.
    }
    if {[scan $edge_meshc_params(sp2) %g h] != 1} {
	set edge_meshc_params(sp2) 0.
    }
    if {[scan $edge_meshc_params(asp1) %g h] != 1} {
	set edge_meshc_params(asp1) 0.
    }
    if {[scan $edge_meshc_params(asp2) %g h] != 1} {
	set edge_meshc_params(asp2) 0.
    }
    
    set edge_meshc_params(sp1) [format %.9f $edge_meshc_params(sp1)]
    set edge_meshc_params(sp2) [format %.9f $edge_meshc_params(sp2)]
    set edge_meshc_params(asp1) [format %.9f $edge_meshc_params(asp1)]
    set edge_meshc_params(asp2) [format %.9f $edge_meshc_params(asp2)]

    set fe ""
    set le ""
    set clength 0
    set edge_length $edge_meshc_params(edge_length)

    if $edge_meshc_params(edgepointsactive) {
	if $edge_meshc_params(length_is_param) {
	    set fe $edge_meshc_params(sp1)
	    set le $edge_meshc_params(sp2)
	} else {
	    set fe [expr $edge_meshc_params(asp1)/$edge_length]
	    set le [expr $edge_meshc_params(asp2)/$edge_length]
	}
	set clength [expr 1.-$le-$fe]
	
	# make sure we have a legal edge point seperations
	
	if {$clength*$xrange/$length < 2} {
	    set clength [expr 2.0/double($xrange)]
	    set le [expr $fe - $clength]
	    if $edge_meshc_params(length_is_param) {
		set edge_meshc_params(sp2) $le
	    } else {
		set edge_length $edge_meshc_params(edge_length)
		set edge_meshc_params(asp2) [expr $le*$edge_length]
	    }
	}
	
    } else {
	set fe 0.
	set le 0.
	set clength 1.0
    }
    
    set edge_meshc_params(fe) $fe
    set edge_meshc_params(le) $le
    
    # New origin for all control points
    
    set fe [expr $xo + round(($fe/$length)*$xrange)]
    set ale [expr $xo + round(((1.0-$le)/$length)*$xrange)]
     
    set edge_meshc_params(minx) [expr $fe + 1]
    set edge_meshc_params(maxx) [expr $ale - 1]
    set edge_meshc_params(curxorigin) $fe
    set edge_meshc_params(curxmax) $ale
    set edge_meshc_params(clength) $clength
    set edge_meshc_params(npoints) \
	[edge_meshc_max $edge_meshc_params(npoints) 4]
}

# procedure edge_meshc_pointcreate
#
# Controller routine to add point to line
#
# Forest Rouse ICEM CFD Engineering (c) 1998
#
# input:
#
#    x    - x coordinate
#    y    - y coordinate
#    init - 1 special initialization of beginning/ending points
#
# output: - none

# side effects:
#
#  Creates new point on canvas if it is allowed
#

proc edge_meshc_pointcreate {x y {init 0} {idx 0} {docallback 1}} {
    global edge_meshc_params edge_meshc_points
 
    set c $edge_meshc_params(c)
    set xn [edge_meshc_min [edge_meshc_max $x $edge_meshc_params(minx)] \
		$edge_meshc_params(maxx)]
    
    set yn [edge_meshc_min [edge_meshc_max $y $edge_meshc_params(ymax)] \
		$edge_meshc_params(yorigin)]
    
    if !$init {
	set idx [edge_meshc_addpointsorted $xn $yn 0]
	if {$idx < 0} return
    }
    
    set x1 [expr $xn - $edge_meshc_params(point_radius)]
    set y1 [expr $yn - $edge_meshc_params(point_radius)]
    set x2 [expr $xn + $edge_meshc_params(point_radius)]
    set y2 [expr $yn + $edge_meshc_params(point_radius)]
    
    set point [$c create oval $x1 $y1 $x2 $y2 \
		   -fill $edge_meshc_params(point_color) \
		   -outline $edge_meshc_params(point_outline)]
    
    # now add point created to list of points
    
    set edge_meshc_points(1) [linsert $edge_meshc_points(1) $idx $point]
    
    $c addtag cpoints withtag $point
    $c bind $point <Button-1> "edge_meshc_select $point"
    $c bind $point <Button1-Motion> "edge_meshc_move $point %x %y"
    $c bind $point <Button2-Motion> "edge_meshc_move $point %x %y"
    
    edge_meshc_update $docallback
}

proc edge_meshc_addpointsorted {xn yn force} {
    global edge_meshc_params edge_meshc_points
    
    set idx 0
    set np [list $xn $yn]
    set ok 0
    set minsep [expr $edge_meshc_params(point_radius)]
	
    # require a minimum seperation of points
	
    set lastx [lindex [lindex $edge_meshc_points(0) 1] 0]
    foreach f $edge_meshc_points(0) {
	set nextx  [lindex $f 0]
	if {$xn < $nextx} {
	    if {(abs($xn-$nextx) > $minsep-.5 && \
		     abs($xn-$lastx) > $minsep-.5) || $force} {
		set edge_meshc_points(0) \
		    [linsert $edge_meshc_points(0) $idx $np]
		    
		set ok 1
	    }
	    break;
	}
	set lastx $nextx
	incr idx
    }
    if !$ok { return -1 }
    return $idx
}

proc edge_meshc_select {point} {
}

# procedure edge_meshc_move
#
# Controller routine to move given point to (x, y)
#
# Forest Rouse ICEM CFD Engineering (c) 1998
#
# input:
#
#    point - tag name for point being moved
#    x     - x coordinate
#    y     - y coordinate
#
# output: - none
#
# side effects:
#
#  Moves point within domain of allowed values
#

proc edge_meshc_move {point x y} {
    
    global edge_meshc_params edge_meshc_points
    
    set idx [lsearch $edge_meshc_points(1) $point]
    if {$idx < 0} return
    
    set oldp [lindex $edge_meshc_points(0) $idx]
    set nump [expr [llength $edge_meshc_points(1)]-1]
    set minsep [expr $edge_meshc_params(minsep)]
    
    # determine limits on x value.  require that this is a function
    # that is, control points regions cannot overlap.  Arrange that by
    # requiring that the moving control point lie in range (x(idx-1), x(idx+1))
    # By using the minimum seperation of created points being at least
    # minsep, then minx and maxx at worst will be the same value

    set maxx 0
    set minx 0
    switch -- $idx \
	0 {
	    set minx $edge_meshc_params(curxorigin)
	    set maxx $minx
	} \
	$nump {
	    set minx $edge_meshc_params(curxmax)
	    set maxx $minx
	} \
	default {
	    set minx [lindex [lindex $edge_meshc_points(0) [expr $idx-1]] 0]
	    set maxx [lindex [lindex $edge_meshc_points(0) [expr $idx+1]] 0]
	    set minx [expr $minx+$minsep]
	    set maxx [expr $maxx-$minsep]
	}

    set xn [edge_meshc_min [edge_meshc_max $x $minx] $maxx]
    set yn [edge_meshc_min [edge_meshc_max $y $edge_meshc_params(ymax)] \
		$edge_meshc_params(yorigin)]
    
    set x1 [expr $xn - $edge_meshc_params(point_radius)]
    set y1 [expr $yn - $edge_meshc_params(point_radius)]
    set x2 [expr $xn + $edge_meshc_params(point_radius)]
    set y2 [expr $yn + $edge_meshc_params(point_radius)]
    
    $edge_meshc_params(c) coords $point $x1 $y1 $x2 $y2
    
    set edge_meshc_points(0) \
	[lreplace $edge_meshc_points(0) $idx $idx [list $xn $yn]]
    edge_meshc_update 1
}

# procedure edge_meshc_pointdelete
#
# Controller routine to  delete point at (x, y)
#
# Forest Rouse ICEM CFD Engineering (c) 1998
#
# input:
#
#    x     - x coordinate
#    y     - y coordinate
#
# output: - none
#
# side effects:
#
#  deletes a point if it is within bounding box given by minsep of
#  the point
#

proc edge_meshc_pointdelete {x y} {
    
    global edge_meshc_params edge_meshc_points
    
    set idx -1
    set count 0
    set minsep [expr $edge_meshc_params(point_radius)-0.5]
    set nump [expr [llength $edge_meshc_points(1)]-1]
    
    foreach p $edge_meshc_points(0) {
	if {abs($x-[lindex $p 0])<$minsep && abs($y-[lindex $p 1])<$minsep} {
	    set idx $count
	    break;
	}
	incr count
    }
    
    # don't allow first or last points to be deleted
    
    if {$idx <= 0 || $idx >= $nump} return
    
    set point [lindex $edge_meshc_points(1) $idx]
    set edge_meshc_points(0) [lreplace $edge_meshc_points(0) $idx $idx]
    set edge_meshc_points(1) [lreplace $edge_meshc_points(1) $idx $idx]
    
    $edge_meshc_params(c) delete $point
    
    edge_meshc_update
}

proc edge_meshc_erasecurrentfunc {} {
    global edge_meshc_params edge_meshc_points
    
    if {[info exists edge_meshc_points(2)] && $edge_meshc_points(2) != ""} {
	set c $edge_meshc_params(c)
	$c delete $edge_meshc_points(2)
	$c delete cpoints
    }
}

# standard method to determine where edge meshing tick marks should
# go.  Default is HEXA specific callback.

# proc edge_meshc_standard_ticks {np smooth points} {
#
# users should do a variation of the following form:
#
# return [eval edge_compute_points $np $smooth $points]
#
# where eval is just used to convert $points from a single tcl
# word to multiple ones (which old edge_compute_points wants).
# Of course what is needed by each individual procedure is required
# here.
#
# }

# standard callback of actions to carry out when points change.  Default
# just asks where the tick marks are

proc edge_meshc_standard_callback {points} {
    global edge_meshc_params edge_meshc_lock
    
    if [info exists edge_meshc_lock] return
    set edge_meshc_lock 1
    catch {
	if {$edge_meshc_params(tickmarks) != ""} {
	
	    # compute where the tickmarks should go.
	
	    set ticklist \
		[eval $edge_meshc_params(tickmarks) \
		     $edge_meshc_params(npoints) \
		     $edge_meshc_params(smooth) \
		     $edge_meshc_params(edgepointsactive) \
		     $points]
	
	    # update the tick label
	
	    set edge_meshc_params(current_ticklist) $ticklist
	    edge_meshc_updateticks $ticklist
	}
    }
    unset edge_meshc_lock
}

# procedure edge_meshc_update
#
# Controller routine to update view given state
#
# Forest Rouse ICEM CFD Engineering (c) 1998
#
# input:
#    docallback - 0 no, 1 yes (D)
#
# output: - none
#
# side effects:
#
#  Redraws view of state
#

proc edge_meshc_update {{docallback 1}} {
    global edge_meshc_points edge_meshc_params
    global eparam_actual eparam_sp1 eparam_sp2
    
    set w $edge_meshc_params(w)
    set c $edge_meshc_params(c)
    if {[llength $edge_meshc_points(0)] > 1} {
	set allpoints [edge_meshc_flatten $edge_meshc_points(0)]
    
	# invoke callback if any
    
	if {$edge_meshc_params(callback) != "" && $docallback} {
	    $edge_meshc_params(callback) \
		[edge_meshc_screentocoord $edge_meshc_points(0)]
	}
	if {$edge_meshc_points(2) == ""} {
	    
	    set edge_meshc_points(2) \
		[eval $c create line $allpoints \
		     -fill $edge_meshc_params(line_color) \
		     -width $edge_meshc_params(line_width)]
	} else {
	    eval $c coords $edge_meshc_points(2) $allpoints
	}
	$c itemconfigure $edge_meshc_points(2) \
	    -smooth $edge_meshc_params(smooth)
    }
    
    # put the points on-top
	
    $c raise cpoints
    
    # set the state of the linear/spline toggle button
    
    set text ""
    if $edge_meshc_params(smooth) {
	set text "Spline"
    } else {
	set text "Linear"
    }
    
    # update the other of actual/parameterized edge distances
    # if the edgepoint boxes are active
    
    set nfe 0
    set nle 0
    set fe 0
    set le 0
    set edge_length $edge_meshc_params(edge_length)
    
    if $edge_meshc_params(edgepointsactive) {
	if $edge_meshc_params(length_is_param) {
	    set nfe $edge_meshc_params(sp1)
	    set nle $edge_meshc_params(sp2)
	    
	    if {$nfe == ""} {
		set nfe 0.0
		set edge_meshc_params(sp1) 0.0
	    }
	    if {$nle == ""} {
		set nle 0.0
		set edge_meshc_params(sp2) 0.0
	    }
	    set edge_meshc_params(asp1) [expr $nfe*$edge_length]
	    set edge_meshc_params(asp2) [expr $nle*$edge_length]
	    
	    set edge_meshc_params(reflect_sp1) $nfe
	    set edge_meshc_params(reflect_sp2) $nle
	} else {
	    set fe $edge_meshc_params(asp1)
	    set le $edge_meshc_params(asp2)
	    
	    if {$fe == ""} {
		set fe 0.0
		set edge_meshc_params(asp1) 0.0
	    }
	    if {$le == ""} {
		set le 0.0
		set edge_meshc_params(asp2) 0.0
	    }
	    set edge_meshc_params(sp1) [expr $fe/$edge_length]
	    set edge_meshc_params(sp2) [expr $le/$edge_length]
	    
	    set edge_meshc_params(reflect_sp1) $fe
	    set edge_meshc_params(reflect_sp2) $le
	}
    } else {
	set ticklist $edge_meshc_params(current_ticklist)
	set len [llength $ticklist]
	if {$len > 3} {
	    set first_point [lindex $ticklist 0]
	    set second_point [lindex $ticklist 1]
	    set next_last_point [lindex $ticklist [expr $len - 2]]
	    set last_point [lindex $ticklist [expr $len - 1]]
	    
	    set diff1 [expr $second_point - $first_point]
	    set diff2 [expr $last_point - $next_last_point]
	    if $edge_meshc_params(length_is_param) {
		set edge_meshc_params(reflect_sp1) $diff1
		set edge_meshc_params(reflect_sp2) $diff2
	    } else {
		set edge_meshc_params(reflect_sp1) \
		    [expr $diff1*$edge_length]
		set edge_meshc_params(reflect_sp2) \
		    [expr $diff2*$edge_length]
	    }
	    
	} else {
	    set edge_meshc_params(reflect_sp1) 0.
	    set edge_meshc_params(reflect_sp2) 0.
	}
    }
    
    $w.f1.toglinspl configure -text $text
    
    update idle
}

proc edge_meshc_updateticks {ticklist} {
    global edge_meshc_params
    
    set bd $edge_meshc_params(bd)
    set yto [expr $edge_meshc_params(bunchdispy)-3]
    set ytm [expr $yto-$edge_meshc_params(longtick)]
    
    set coords ""
    set ticks [edge_meshc_tickstoscreen $ticklist]
    foreach xp $ticks {
	append coords "$xp $yto $xp $ytm $xp $yto "
    }
    
    if {$edge_meshc_params(bdlines) == ""} {
	set edge_meshc_params(bdlines) \
	    [eval $bd create line $coords \
		 -fill $edge_meshc_params(line_color) \
		 -width $edge_meshc_params(line_width)]
    } else {
	eval $bd coords $edge_meshc_params(bdlines) $coords
    }
}

# procedure edge_meshc_flatten
#
# flatten list of list of points into list suitable for canvas
#
# Forest Rouse ICEM CFD Engineering (c) 1998
#
# input:
#
#    points - list of {x y} points
#
# output:
#
#    flattened list
#
# side effects: - none

proc edge_meshc_flatten {points} {
    set ret {}
    foreach p $points {
	append ret "[lindex $p 0] [lindex $p 1] "
    }
    return $ret
}

# transform edge coordinates into screen coordinates.  points flat list
# of form $x1 $y1 $x2 $y2 ... suitable for canvas/from hexa set_mesh command
# returns list of {x y} points (internal representation)

proc edge_meshc_coordtoscreen {points} {
    global edge_meshc_params
    
    # recreate the points
	    
    set ret ""
    set yo $edge_meshc_params(yorigin)
    set xo $edge_meshc_params(xorigin)
    set xrange [expr $edge_meshc_params(xmax)-$xo]
    set yrange [expr $yo-$edge_meshc_params(ymax)]
    
    set height $edge_meshc_params(ynorm_height)
    set length $edge_meshc_params(xnorm_length)
    
    set npoints [llength $points]
    if {$npoints % 2 == 0} {
	for {set i 0} {$i < $npoints} {incr i 2} {
	    set x [lindex $points $i]
	    set y [lindex $points [expr $i+1]]
	    
	    # remember the top of the screen is screen origin (large edge y)
	    # that is why we do $yo - int ...
	    
	    set xn [expr $xo + round(($x/$length)*$xrange)]
	    set yn [expr $yo - round(($y/$height)*$yrange)]
	    
	    # make sure points are in range
	    
	    set xn [edge_meshc_min \
			[edge_meshc_max $xn $edge_meshc_params(xorigin)] \
			$edge_meshc_params(xmax)]
    
	    set yn [edge_meshc_min \
			[edge_meshc_max $yn $edge_meshc_params(ymax)] \
			$edge_meshc_params(yorigin)]
	    
	    lappend ret [list $xn $yn]
	}
    }
    return $ret
}

# transform screen coordinates into edge coordinates:  Note that points
# are in list format.  This is because we will generally be giving
# this routine a list of {x y} points.

proc edge_meshc_screentocoord {points} {
    global edge_meshc_params
    
    set ret ""
    
    set yo $edge_meshc_params(yorigin)
    set xo $edge_meshc_params(xorigin)
    set xrange [expr $edge_meshc_params(xmax)-$xo]
    set yrange [expr $yo-$edge_meshc_params(ymax)]
    
    set height $edge_meshc_params(ynorm_height)
    set length $edge_meshc_params(xnorm_length)
    
    set i 0
    set last [expr [llength $points]-1]
    foreach p $points {
	set x [lindex $p 0]
	set y [lindex $p 1]
	    
	# remember the top of the screen is screen origin (large edge y)
	# that is why we do $yo - $y
	    
	set xn [expr (double($x  - $xo)/double($xrange))*$length]
	set yn [expr (double($yo -  $y)/double($yrange))*$height]
	    
	# if this is the first and/or last point, use the
	# correct numbers (not rounded to the nearest integer)
	# for the x range
	
	if {$i == 0} {
	    set xn $edge_meshc_params(fe)
	} elseif {$i == $last} {
	    set xn [expr 1.0-$edge_meshc_params(le)]
	}
	incr i
	
	# make sure points are in range
	    
	set xn [edge_meshc_min [edge_meshc_max $xn 0.0] $length]
	set yn [edge_meshc_min [edge_meshc_max $yn 0.0] $height]
	    
	append ret "$xn $yn "
    }
    return $ret
}

proc edge_meshc_tickstoscreen {points} {
    global edge_meshc_params eparam_sp1 eparam_sp2 eparam_actual
    
    set ret ""
    set xo $edge_meshc_params(xorigin)
    set xrange [expr $edge_meshc_params(xmax)-$xo]
    set length $edge_meshc_params(xnorm_length)
    
    foreach x $points {
	    
	set xn [expr $xo + round(($x/$length)*$xrange)]
	    
	# make sure points are in range
	    
	set xn [edge_meshc_min \
		    [edge_meshc_max $xn $edge_meshc_params(xorigin)] \
		    $edge_meshc_params(xmax)]
    
	append ret "$xn "
    }
    return $ret
}

# procedure edge_meshc_min, edge_meshc_max
#
# return min and max of 2 values respectively
#
# Forest Rouse ICEM CFD Engineering (c) 1998
#
# input:
#
#    x1   - value 1
#    x2   - value 2
#
# output:
#
#    the minimum of two values or the maximum of them
#
# side effects: - none

proc edge_meshc_min {x1 x2} {
    return [expr $x1 < $x2 ? $x1 : $x2]
}

proc edge_meshc_max {x1 x2} {
    return [expr $x1 > $x2 ? $x1 : $x2]
}

