
# This code creates the user interface for the hexa mesher.
#
# Copyright (c) 1993 - 1995 Pacific Marketing and Consulting, Inc,
#       and ICEM Systems, GmbH.  All rights reserved.
# Author:  Wayne A. Christopher, wayne@icemcfd.com

proc mesh_recompute {} {
	mesh_up_to_date -1 1
}

proc get_freeze_fams { fams } {
	set freeze_fams [ select_material "Please select the \
		families to freeze during the re-meshing" ]
	set mesh_fams ""
	foreach i $fams {
		if { [ lsearch $freeze_fams $i ] == -1 } {
			append mesh_fams " $i"
		}
	}
	set both "{ $mesh_fams } { $freeze_fams }"
	return $both
}
proc mesh_up_to_date {ask {redraw 1} {d_to_mesh -1 } } {
    global project_type last_line mesh_option dim_to_mesh
    if { [ winfo exists .up_to_date ] } {
	wm deiconify .up_to_date
	raise .up_to_date
	return
    }
    if { $d_to_mesh == -1 } {
	set d_to_mesh $dim_to_mesh
    }
    
    set fams [volume_activename_string]
    set ptype $project_type
    if { ! [ info exists mesh_option(project_bspline) ] } {
	set mesh_option(project_bspline) 0
    }
    if { $ptype == 2  && $mesh_option(project_bspline) } {
	    set ptype 3
    }
    hex_command "check_mesh $fams proj $ptype dim_to_mesh $d_to_mesh"
    set freeze_fams ""
    if { $last_line == 0 || $ask == -1 } {
	set incremental ""
	if { $ask } {
	    if { $last_line == 1 } {
		set mess "Mesh is currently up to date -- recompute anyway?"
	    } else {
		set mess "Mesh is currently out of date -- recompute?"
	    }
	    set stat [tk_dialog .up_to_date "Mesh" $mess "" -1 \
			"Yes" "No" "Re-mesh out of date parts" \
			"Re-mesh specific families" ]
	    if { $stat == 1 } {
		return 0
	    }
	    if { $stat == 2 } {
		set incremental "incremental"
	    }
	    if { $stat == 3 } {
		set both [ get_freeze_fams $fams ]
		set fams [ lindex $both 0 ]
		set freeze_fams [ lindex $both 1 ]
	    }
	}
	if { $last_line == 1 } {
		mess "Mesh is out of date -- recomputing.\n"
	}
	set dim_to_mesh $d_to_mesh
	set cmd "create_mesh $fams proj $ptype $incremental dim_to_mesh $dim_to_mesh"
	if { $freeze_fams != "" } {
		append cmd " -freeze $freeze_fams"
	}
	hex_command $cmd

	if $redraw {
	    hex_update_display face edge scan mesh
	}
    }
    return 1
}

if (0) {
proc mesh_scan_planes {} {
    global scan_major scan_minor scan_on scan_solid tool_dir last_line
    global subindex_min_limit subindex_max_limit guibase_dir
    global index_min_limit index_max_limit scan_color scan_color_material
    
    mesh_up_to_date 1 1
    
    hex_command "n_nodes_edge"
    set ch 0
    set ndim [llength $last_line]
    for {set d 0} {$d < $ndim} {incr d} {
	set dims [string trim [lindex $last_line $d]]
	if ![info exists index_max_limit($d)] { set index_max_limit($d) 0 }
	for {set i 0} {$i <= $index_max_limit($d)} {incr i} {
	    set subindex_min_limit($d,$i) 0
	    set x [lindex $dims $i]
	    set subindex_max_limit($d,$i) [expr {($x == "") ? 0 : $x}]
	}
	if {($dims == "") && [info exists scan_on($d)]} {
	    unset scan_on($d)
	    set ch 1
	} elseif ![info exists scan_on($d)] {
	    set scan_on($d) 0
	    set ch 1
	}
    }
    foreach i [array names scan_on] {
	if {$i >= $ndim} {
	    unset scan_on($i)
	    set ch 1
	}
    }
    if $ch { form_kill .scanp }
    
    set buts {{Done {form_done .scanp; mesh_scan_done}}}
    
    set dd [form_init .scanp "Scan plane control" mesh $buts]
    if {$dd != ""} {
	set d [form_scroller $dd.scr 400 {0 0}]
	
	set up @$guibase_dir/goup.xbm
	set dn @$guibase_dir/godown.xbm
	
	form_checkbutton $d.solid "Solid" scan_solid {1 1 -cols 2}
	$d.solid configure -command "scan_update all"
	
	form_button $d.select "Screen select" "scan_select_edge" \
		{1 3 -cols - -fill y}
	form_label $d.onl "On" {3 1}
	form_label $d.majorl "Major" {3 3 -cols 3}
	form_label $d.minorl "Minor" {3 7 -cols 3}
	form_label $d.colorl "Color" {3 10}
	form_frame $d.onul flat 2 {4 1 -pady 4 -anchor n}
	form_frame $d.majorul flat 2 {4 3 -cols 3 -pady 4 -anchor n}
	form_frame $d.minorul flat 2 {4 7 -cols 3 -pady 4 -anchor n}
	form_frame $d.colorul flat 2 {4 10 -cols 3 -pady 4 -anchor n}
	foreach i {onul majorul minorul colorul} {
	    $d.$i configure -background black
	}
	
	for {set i 0} {$i < $ndim} {incr i} {
	    if ![info exists scan_on($i)] continue
	    
	    if ![info exists scan_major($i)] { set scan_major($i) 0 }
	    if ![info exists scan_minor($i)] { set scan_minor($i) 1 }
	    if ![info exists scan_color($i)] { set scan_color($i) white }
	    if ![info exists scan_color_material($i)] {
		set scan_color_material($i) 1
	    }

	    set row [expr {$i + 5}]
	    form_checkbutton $d.on$i "# $i" scan_on($i) "$row 1"
	    $d.on$i configure -command "scan_update $i"
	    
	    form_entry $d.major$i scan_major($i) int "$row 3"
	    form_button_bitmap $d.majorup$i $up "scan_major $i 1" "$row 4"
	    form_button_bitmap $d.majordn$i $dn "scan_major $i -1" "$row 5"
	    
	    form_entry $d.minor$i scan_minor($i) int "$row 7"
	    form_button_bitmap $d.minorup$i $up "scan_minor $i 1" "$row 8"
	    form_button_bitmap $d.minordn$i $dn "scan_minor $i -1" "$row 9"
	    
	    form_colwidth $d 2 4
	    form_colwidth $d 6 4
	    
	    futil_colorentry $d.color$i scan_color($i) "$row 10" "" \
		"by material" scan_color_material($i) "scan_update $i" 1
	    
	    bind $d.major$i <Return> "scan_update $i"
	    bind $d.minor$i <Return> "scan_update $i"
	}
	
	form_finish bot
	form_scroller_hack $dd.scr
    }
    form_wait .scanp
    foreach i [array names scan_on] {
	set scan_on($i) 0
	scan_update $i
    }
}

proc scan_reset {} {
    set on [expr {[winfo exists .scanp] && [winfo ismapped .scanp]}]
    form_kill .scanp
    if $on {
	mesh_scan_planes
	scan_update all
    }
}

proc scan_select_edge {} {
    global index_max_limit index_min_limit scan_major scan_minor
    global subindex_min_limit subindex_max_limit scan_on
    global last_line
    
    set edge [select_edge "Select an edge perpendicular to the desired\
	    scan plane" 1 new_format]
    if {$edge == ""} return
    set cmd "edge_node_dim [ lindex $edge 0 ] [ lindex $edge 1 ]"
    hex_command $cmd
	
    set dim [lindex $last_line 0]
    set major [lindex $last_line 1]

    if {$major == ""} { set major 0 }
    if {$major > $index_max_limit($dim)} { set major $index_max_limit($dim) }
    if {$major < $index_min_limit($dim)} { set major $index_min_limit($dim) }
    set scan_major($dim) $major
    set scan_minor($dim) [expr {($subindex_min_limit($dim,$major) + \
	    $subindex_max_limit($dim,$major)) / 2}]
    
    set scan_on($dim) 1
    scan_update $dim
}

# returns 1 if anything changed
proc scan_major {ind dir {callup 1}} {
    global index_min_limit index_max_limit scan_major
    
    set minl $index_min_limit($ind)
    set maxl $index_max_limit($ind)
    incr scan_major($ind) $dir
    set v $scan_major($ind)
    set ch 1
    if {$v < $minl} { set scan_major($ind) $minl; set ch 0 }
    if {$v >= $maxl} { set scan_major($ind) [ expr { $maxl - 1 } ] ; set ch 0 }
    
    if {$ch && $callup} { if ![scan_minor $ind 0] { scan_update $ind } }
    return $ch
}

# this proceedured is called when minor index is incremented

proc scan_minor {ind dir} {
    global subindex_min_limit subindex_max_limit scan_major scan_minor
    
    set minl $subindex_min_limit($ind,$scan_major($ind))
    set maxl $subindex_max_limit($ind,$scan_major($ind))
    incr scan_minor($ind) $dir
    set v $scan_minor($ind)
    set ch 1
    if {$v < $minl} {
	set scan_minor($ind) $minl
	if {$dir != 0} {
	    set ch [scan_major $ind $dir 0]
	    if $ch {
		set s $scan_major($ind)
		set scan_minor($ind) [expr {$subindex_max_limit($ind,$s) - 2}]
	    }
	}
    }
    if {$v >= $maxl} {
	set scan_minor($ind) [expr {$maxl - 1}]
	if {$dir != 0} {
	    set ch [scan_major $ind $dir 0]
	    if $ch {
		set s $scan_major($ind)
		set scan_minor($ind) [expr {$subindex_min_limit($ind,$s) + 1}]
	    }
	}
    }

    
    if $ch { scan_update $ind }
    return $ch
}

proc scan_update {ind} {
    global scan_major scan_minor scan_on scan_solid project_type scan_color
    global scan_color_material subindex_min_limit subindex_max_limit
    global index_min_limit index_max_limit
    
    if {$ind == "all"} {
	foreach i [array names scan_on] {
	    if $scan_on($i) { scan_update $i }
	}
	return
    }

    set minl $index_min_limit($ind)
    set maxl $index_max_limit($ind)
    if { [ scan $scan_major($ind) "%d" scan_major($ind) ] == 0 } {
# check for illegible numbers
	set scan_major($ind) $minl
    }
    
    if { $scan_major($ind) < $minl } {
	mess "Major index must be greater than or equal to $minl\n" red
	set scan_major($ind) $minl
    } elseif { $scan_major($ind) >= $maxl } {
	mess "Major index must be less than $maxl\n" red
	set scan_major($ind) [ expr { $maxl - 1 } ]
    }

    set minl $subindex_min_limit($ind,$scan_major($ind))
    set maxl $subindex_max_limit($ind,$scan_major($ind))
# check for illegible numbers
    if { [ scan $scan_minor($ind) "%d" scan_minor($ind) ] == 0 } {
	set scan_minor($ind) $minl
    }
    if { $scan_minor($ind) < $minl } {
	mess "Minor index must be in range $minl $maxl\n" red
	set scan_minor($ind) $minl
    } elseif { $scan_minor($ind) > $maxl } {
	mess "Minor index must be in range $minl $maxl\n" red
	set scan_minor($ind) $maxl
    }

    
    set cmd "sp \{ $ind $scan_major($ind) $scan_minor($ind) \} "
    
    if !$scan_on($ind) { 
	append cmd " erase" 
    } else {
    	mesh_up_to_date 1 1
    }
    
    append cmd " [range_string] proj $project_type"
    if $scan_solid { append cmd " -solid" }
    set fam [family_activename_string]
    if {$fam != ""} { append cmd " m $fam" }
    if {($scan_color_material($ind) != "1") && \
	    ([scan $scan_color($ind) \#%2s%2s%2s rr gg bb] == 3)} {
	append cmd " color 0x$bb$gg$rr"
    }
    hex_command $cmd
}

proc mesh_scan_done {} {
    global scan_major
    
    foreach i [array names scan_major] {
	hex_command "sp erase \{ $i 0 0 \}" 0
    }
}
}

# -------------------------

proc check_const_r {} {
	global button_instructions last_line

	set mess "Please select the icon for the face to check \
			 $button_instructions"
	set cmd "select_super_face node_numbers \
			[range_string] [family_activename_string]"
	hex_command "$cmd"
	set faces $last_line
	if { $faces != "" } {
		hex_command "check_face_radii [ lindex $faces 0 ]"
	}

}
proc mesh_diag {which title ask} {
    global diag_which
    set diag_which $which
    switch $which {
	determinant {
	    mesh_do_diag $ask $title 20 0 1
	}
	angle {
	    mesh_do_diag $ask $title 20 0 90
	}
	volume {
	    mesh_do_diag $ask $title 20 0 0
	}
	determinant_27 {
	    mesh_do_diag $ask $title 20 0 1
	}
	warpage {
	    mesh_do_diag $ask $title 20 0 90
	}
	eriksson {
	    mesh_do_diag $ask $title 20 0 1
	}
	aspect_ratio {
	    mesh_do_diag $ask $title 20 1 20
	}
	min_side {
	    mesh_do_diag $ask $title 20 0 0
	}
	workbench {
	    mesh_do_diag $ask $title 20 0 1 
	}
	default {
	    mess "no such diagnostic $which" red
	}
    }
    replay_record_hex_command "\#!mesh_diag $which \{$title\} 0"
}

proc mesh_do_diag {ask title {nbars 20} {min 0} {max 1} {ylim 16} {args ""}} {
    global all_lines project_type diag_which diag_maxval dim_to_mesh
    global histo_min histo_max
    
    if ![info exists diag_maxval] { set diag_maxval 0 }

    set dim_to_mesh 3
    
    mesh_up_to_date 1
    
    if { $diag_which == "volume" } {
	    if $ask {
		set maxv [question_box .max_volume "Max volume" \
			      "Maximum value to plot (0 = no limit) ?" \
			      $diag_maxval]
		if {$maxv == ""} return
		set diag_maxval $maxv
	    } else {
		set diag_maxval $max
	    }
	    
	    set maxstr ""
	    if $diag_maxval { set maxstr " maxval $diag_maxval" }
	    hex_command "rh $nbars [volume_activename_string] proj\
  		$project_type minval $min volume$maxstr" 0
    } else {
	    hex_command "rh $nbars [volume_activename_string] proj\
  		$project_type minval $min $diag_which maxval $max" 0
    }
    
    set no_range [expr {$min == $max}]
    
    set xvals ""
    set yvals ""
    set ymax 0
    set hi 0
    set low 0
    foreach line $all_lines {
	if {[llength $line] == 4} {
	    set n [lindex $line 0]
	    set low [lindex $line 1]
	    set hi [lindex $line 2]
	    set per [lindex $line 3]
	    if {$no_range || (($low >= $min) && ($hi <= $max))} {
		lappend xvals $low
		lappend yvals $n
		if {$n > $ymax} {
		    set ymax $n
		}
	    }
	}
    }
    if ![info exists hi] return
    
    lappend xvals $hi
    
    set histo_min [ lindex $xvals 0 ]
    set histo_max [ lindex $xvals end ]
# save the formating from the input
    if { $min == $histo_min } {
	set histo_min $min
    }
    if { $max == $histo_max } {
	set histo_max $max
    }
    make_histogram .histogram $title $xvals $yvals \
	    $ylim "" "mesh_do_diag 0" mesh_histo_select \
		"$histo_min $histo_max" "" 2
}

proc mesh_histo_select {w intervals arguments solid } {
    global project_type diag_which histo_min
    

    set max [lindex [lindex $intervals 0] 0]
    set min [lindex [lindex $intervals 0] 1]
    foreach i $intervals {
	set low [lindex $i 0]
	set hi [lindex $i 1]
	if {$low < $min} {
	    set min $low
	}
	if {$hi > $max} {
	    set max $hi
	}
    }
    set rmin [ lindex $arguments 0 ]
    set rmax [ lindex $arguments 1 ]
    if {$min == $rmin } {
	set min -1.0e10
    }
    if { $max == $rmax } {
	set max 1.0e10
    }
    if {$min < $max} {
	set dtype $diag_which
	set sol ""; if $solid { set sol "-solid" }
# now display all contiguous
	set new_intervals ""
	set last_low [ lindex [ lindex $intervals 0 ] 0 ]
	set last_hi $last_low
	foreach i $intervals { 
		set low [lindex $i 0]
        	set hi [lindex $i 1]
		if { $low == $last_hi } {
# extend an interval
			set last_hi $hi
		} else {
# output new interval
			lappend new_intervals " $last_low $last_hi "
			set last_low $low
			set last_hi $hi
		}
	}
	if { $last_hi != "" } {
		lappend new_intervals " $last_low $last_hi "
	}
	set intervals $new_intervals
	set min [lindex [lindex $intervals 0] 0]
	if { $min ==  $histo_min } {
		set min -100.0
	}
    	set max [lindex [lindex $intervals 0] 1]
	set cmd "rr $min $max [volume_activename_string] proj\
  			$project_type $dtype $sol"
	set intervals [ lrange $intervals 1 end ]
	foreach i $intervals {
		append cmd " -interval [ lindex $i 0 ] [ lindex $i 1 ]"
	}
	hex_command "$cmd"
    } else {
	hex_command "rr erase"
    }
}

# -------------------------

#proc mesh_toggle_projtype {} {
#}

proc mesh_check_size {} {
    global last_line
    
    hex_command "compute_mesh_size [volume_activename_string]" 0
    set nc 0
    set ne 0
    set nf 0
    set nv 0
    set nq 0
    set no 0
    set nh 0

    foreach i {0 1 2 3 4 5 6} {
	set [lindex {nc ne nf nv nq no nh} $i] [lindex $last_line $i]
    }
    set n_nodes [expr {$nc + $ne + $nf + $nv}]
    set n_quads [expr {$nq + $no}]
    
    mess "Mesh size:\n"
    mess "\tnodes = $n_nodes\n"
    mess "\tquads = $n_quads\n"
    mess "\thexas = $nh\n"
}

proc mesh_params {} {
    global form_done_flag param_family_var param_family_list
    global families family_name family_dims botform_geo
    
    set buts {
	{Apply  {mesh_params_apply .params.main.fr.surfs}}
	{Query  {mesh_params_query .params.main.fr.surfs}}
	{Done   {form_done .params; mesh_params_done 1}}
	{Cancel {form_done .params; mesh_params_done 0}}
    }
    
    set d [form_init .params "Mesh parameters" mesh $buts]
    if {$d != ""} {
	form_frame $d.fr sunken 3 {0 0}; set d $d.fr

	form_frame $d.p flat 0 {1 1 -cols - -fill none}
	form_label $d.p.ll "Max length" {1 1}
	form_label $d.p.hl "Init height" {2 1}
	form_label $d.p.rl "Height ratio" {3 1}
	
	form_entry $d.p.l mesh_length float_var {1 2}
	form_entry $d.p.h mesh_height float_var {2 2}
	form_entry $d.p.r mesh_ratio float_var {3 2}
	
	form_listbox $d.surfs "Surfaces" "" "mesh_param_remove_surf $d.surfs" \
		"" 10x6 {2 1 -rows 2 -fill both}
	form_button $d.addsurf "Add surfaces" "mesh_param_add_surfs $d.surfs" \
		{4 1}

	form_label $d.faml "Families" {2 2}
	form_frame $d.fams ridge 2 {3 2 -rows 2}
	
	form_checkbutton $d.fix "Fix edge node counts" mesh_params_fix_counts \
	    {5 1 -cols - -fill none}
    }
    set surflist .params.main.fr.surfs
    
    set fams ""
    foreach f $families {
	if {$family_dims($f) < 3} {
	    lappend fams [list $f -text $family_name($f) \
		    -command "update_param_display $surflist"]
	}
    }
    if {![info exists param_family_list] || ($param_family_list != $fams)} {
	foreach w [winfo children .params.main.fr.fams] { destroy $w }
	set param_family_list $fams
	check_box .params.main.fr.fams $fams 6 param_family_var 1 \
		"update_param_display $surflist"
	
	# This is kind of wierd.
	if {$d != ""} {
	    form_finish $botform_geo
	} else {
	    wm withdraw .params
	    update
	    wm geometry .params $botform_geo
	    sun_geometry .params $botform_geo
	    wm deiconify .params
	}
    }
    update_param_display $surflist
}

proc update_param_display {surflist} {
    global family_name
    
    set stuff [mesh_params_active $surflist]

    set fams ""
    foreach f [lindex $stuff 0] {
	lappend fams "$family_name($f)"
    }
    
    if {$fams != ""} {
	hex_command "display_surfaces simple params $fams" 0
    }
    if {[lindex $stuff 1] != ""} {
	hex_command "display_surfaces simple params name [lindex $stuff 1]" 0
    }
}

proc mesh_params_active {surflist} {
    global param_family_var
    
    set fams ""
    foreach f [array names param_family_var] {
	if $param_family_var($f) { lappend fams $f }
    }
    set surfs [form_listbox_get $surflist]
    return [list $fams $surfs]
}

proc mesh_params_apply {surflist} {
    global mesh_length mesh_height mesh_ratio family_name
    
    set stuff [mesh_params_active $surflist]

    set fams ""
    foreach f [lindex $stuff 0] {
	lappend fams "$family_name($f)"
    }
    
    set cmd set_surface_params
    if {$mesh_length != ""} { append cmd " maxlen $mesh_length" }
    if {$mesh_height != ""} { append cmd " height $mesh_height" }
    if {$mesh_ratio != ""}  { append cmd " ratio $mesh_ratio" }

    if { $fams != "" } {
    	hex_command "$cmd families $fams"
    }
    if { [lindex $stuff 1] != "" } {
    	hex_command "$cmd [lindex $stuff 1]"
    }
    #file_dirty
    
    update_param_display $surflist
    hex_update_display edge face block
}

proc mesh_params_query {surflist} {
    global mesh_length mesh_height mesh_ratio last_line
    
    set s1 [form_listbox_get $surflist 0]
    if {$s1 == ""} {
	mess "You must select a surface before querying mesh parameters.\n" red
	return
    }
    hex_command "get_surface_params $s1"
    set mesh_length [lindex $last_line 0]
    set mesh_height [lindex $last_line 1]
    set mesh_ratio  [lindex $last_line 2]
}

proc mesh_param_add_surfs {surflist} {
    global button_instructions

    set surfs [select_surface "Please select surfaces \
		$button_instructions" ]
    foreach s $surfs {
	form_listbox_add $surflist $s
    }
}

proc mesh_param_remove_surf {surflist surf} {
    global display_flag
    
    form_listbox_delete $surflist $surf
}

proc mesh_params_done {doit} {
    global mesh_params_fix_counts button_instructions
    
    if $doit {
	set cmd "set_mesh_params [volume_activename_string]"
	if $mesh_params_fix_counts { append cmd " fix_counts" }
	hex_command $cmd
    }
    hex_command "del erase 0" 0
    hex_update_display surf
}

# ----------------------------------------------

# This is really bogus -- just cut and pasted from the previous form .....

proc mesh_cparams {} {
    global form_done_flag cparam_family_var cparam_family_list
    global families family_name family_dims botform_geo
    
    set buts {
	{Apply  {mesh_cparams_apply .cparams.main.fr.curves}}
	{Query  {mesh_cparams_query .cparams.main.fr.curves}}
	{Done   {form_done .cparams; mesh_cparams_done 1}}
	{Cancel {form_done .cparams; mesh_cparams_done 0}}
    }
    
    set d [form_init .cparams "Mesh parameters" mesh $buts]
    if {$d != ""} {
	form_frame $d.fr sunken 3 {0 0}; set d $d.fr

	form_frame $d.p flat 0 {1 1 -cols - -fill none}
	form_label $d.p.ll "Max length" {1 1}
	form_label $d.p.hl "Init height" {2 1}
	form_label $d.p.rl "Height ratio" {3 1}
	
	form_entry $d.p.l mesh_length float_var {1 2}
	form_entry $d.p.h mesh_height float_var {2 2}
	form_entry $d.p.r mesh_ratio float_var {3 2}
	
	form_listbox $d.curves "Curves" "" \
	    "mesh_cparam_remove_curve $d.curves" "" 10x6 \
	    {2 1 -rows 2 -fill both}
	form_button $d.addcurve "Add curves" \
	    "mesh_cparam_add_curves $d.curves" {4 1}

	form_label $d.faml "Families" {2 2}
	form_frame $d.fams ridge 2 {3 2 -rows 2}
	
	form_checkbutton $d.fix "Fix edge node counts" mesh_params_fix_counts \
	    {5 1 -cols - -fill none}
    }
    set curvelist .cparams.main.fr.curves
    
    set fams ""
    foreach f $families {
	if {$family_dims($f) < 3} {
	    lappend fams [list $f -text $family_name($f) \
		    -command "update_cparam_display $curvelist"]
	}
    }
    if {![info exists cparam_family_list] || ($cparam_family_list != $fams)} {
	foreach w [winfo children .cparams.main.fr.fams] { destroy $w }
	set cparam_family_list $fams
	check_box .cparams.main.fr.fams $fams 6 cparam_family_var 1 \
		"update_cparam_display $curvelist"
	
	# This is kind of wierd.
	if {$d != ""} {
	    form_finish $botform_geo
	} else {
	    wm withdraw .cparams
	    update
	    wm geometry .cparams $botform_geo
	    sun_geometry .cparams $botform_geo
	    wm deiconify .cparams
	}
    }
    update_cparam_display $curvelist
}

proc update_cparam_display {curvelist} {
    global family_name
    
    set stuff [mesh_cparams_active $curvelist]

    set fams ""
    foreach f [lindex $stuff 0] {
	lappend fams "$family_name($f)"
    }
    
    if {$fams != ""} {
	hex_command "display_curve params $fams" 0
    }
    if {[lindex $stuff 1] != ""} {
	hex_command "display_curve params [lindex $stuff 1]" 0
    }
}

proc mesh_cparams_active {curvelist} {
    global cparam_family_var
    
    set fams ""
    foreach f [array names cparam_family_var] {
	if $cparam_family_var($f) { lappend fams $f }
    }
    set curves [form_listbox_get $curvelist]
    return [list $fams $curves]
}

proc mesh_cparams_apply {curvelist} {
    global mesh_length mesh_height mesh_ratio family_name
    
    set stuff [mesh_cparams_active $curvelist]

    set fams ""
    foreach f [lindex $stuff 0] {
	lappend fams "$family_name($f)"
    }
    
    set cmd set_curve_params
    if {$mesh_length != ""} { append cmd " maxlen $mesh_length" }
    if {$mesh_height != ""} { append cmd " height $mesh_height" }
    if {$mesh_ratio != ""}  { append cmd " ratio $mesh_ratio" }

    if { $fams != "" } {
	hex_command "$cmd families $fams"
    }
    if { [lindex $stuff 1] != "" } {
    	hex_command "$cmd [lindex $stuff 1]"
    }
    #file_dirty
    
    update_cparam_display $curvelist
    hex_update_display edge face block
}

proc mesh_cparams_query {curvelist} {
    global mesh_length mesh_height mesh_ratio last_line
    
    set s1 [form_listbox_get $curvelist 0]
    if {$s1 == ""} {
	mess "You must select a curve before querying mesh parameters.\n" red
	return
    }
    hex_command "get_curve_params $s1"
    set mesh_length [lindex $last_line 0]
    set mesh_height [lindex $last_line 1]
    set mesh_ratio  [lindex $last_line 2]
}

proc mesh_cparam_add_curves {curvelist} {
    global button_instructions

    set curves [select_curve "Please select curves with the \
		$button_instructions" ]
    foreach s $curves {
	form_listbox_add $curvelist $s
    }
}

proc mesh_cparam_remove_curve {curvelist curve} {
    global display_flag
    
    form_listbox_delete $curvelist $curve
}

proc mesh_cparams_done {doit} {
    global mesh_params_fix_counts
    
    if $doit {
	set cmd "set_mesh_params [volume_activename_string]"
	if $mesh_params_fix_counts { append cmd " fix_counts" }
	hex_command $cmd
    }
    hex_command "del erase 0" 0
    hex_update_display curve
}

# ----------------------------------------------

proc edge_mesh_nupcallback {} {
    global eparam_np eparam_nlocked mesh_option
    if { $eparam_nlocked } return
    set delta  [expr int(pow(2, $mesh_option(grid_level)))]
    incr eparam_np $delta
    mesh_eparam_apply 0 0
}

proc edge_mesh_ndncallback {} {
    global eparam_np eparam_nlocked mesh_option
    if { $eparam_nlocked } return
    set delta  [expr - int(pow(2, $mesh_option(grid_level)))]
    if {$eparam_np > (1 - $delta)} {
	incr eparam_np $delta
	mesh_eparam_apply 0 0
    }
}

proc update_h1h2 {} {
	global eparam_rel
	global eparam_length eparam_sp1 eparam_sp2
	
	if { $eparam_rel } {
		set eparam_sp1 [ expr $eparam_sp1/$eparam_length ]
		set eparam_sp2 [ expr $eparam_sp2/$eparam_length ]
	} else {
		set eparam_sp1 [ expr $eparam_sp1*$eparam_length ]
		set eparam_sp2 [ expr $eparam_sp2*$eparam_length ]
	}
}
proc point_family_names {{key ""}} {
    return [ic_geo_list_parts]
	if { $key == "" } {
		global families family_name family_dims
		set names ""
		foreach i $families {
			if { [ info exists family_name($i) ] && \
			     [ info exists family_dims($i) ] && \
				$family_dims($i) == 0 } {
				lappend names $family_name($i)
			}
		}
		return $names
	} else {
		mess "what should I do here ? \n"
	}
}
proc mesh_eparams {{edge ""} {skip 0}} {
    global eparam_family 
    global eparam_highlight_dep eparam_highlight_master
    global eparam_sp1 eparam_sp2 eparam_spmax eparam_rat1 eparam_rat2
    global guibase_dir eparam_density edge_meshc_params edge_meshc_done
    global eparam_edge eparam_np eparam_length botform_geo tool_dir
    global eparam_locked eparam_parallel eparam_parallelv eparam_law
    global eparam_linked eparam_linkedijk eparam_scale eparam_func
    global eparam_actual mesh_eparam_editcv mesh_eparam_editspc
    global subtitle_font input_background form_entry_datatype
    global sp1_linked sp2_linked 
    global eparam_nlocked mesh_option last_line eparam_rel

    if {![info exists mesh_option(grid_level)]} {
        hex_command multi_grid_level
        set mesh_option(grid_level) $last_line
    }
    
    set buts {
	{Apply {mesh_eparam_apply 0 1}}
	{Reset {mesh_eparam_reset}}
	{Done {
	    form_done .eparam
	    
	    # is the linear/beizer form up?
	    
	    if [info exists edge_meshc_params(formup)] {
		set edge_meshc_done 0
		update idle
	    }
    
	    catch {uplevel \#0 unset display_linked_to}
	    hex_update_display edge face block
	} }
    }
    
    set d [form_init .eparam "Edge meshing parameters" mesh $buts]
    if {$d != ""} {
	set eparam_parallel 0
	set eparam_parallelv 0
	set eparam_scale 1
	set mesh_eparam_editcv 0
	set mesh_eparam_editspc 1
	set edge_meshc_params(edgepointsactive) 0
	set eparam_density ""
	
	form_frame $d.fr sunken 3 {0 0}; set d $d.fr
	
	set up @$guibase_dir/goup.xbm
	set dn @$guibase_dir/godown.xbm
	
	# ---------------
	
	set ln 0
	form_label $d.top1 Parameter "$ln 1"
	form_label $d.top2 Requested "$ln 2 -cols 3"
	form_label $d.top3 Actual "$ln 5"
	
	incr ln
	form_label $d.edgel "Edge id" "$ln 1"
	form_entry $d.edge eparam_edge string "$ln 2 -cols 3"


# edge length
	incr ln
	form_label $d.lenl "Edge length" "$ln 1"
	form_entry $d.len eparam_length float_var "$ln 2 -cols 3" 
#	    mesh_eparam_editspc

# number of points
	incr ln
	form_label $d.npl "Num points" "$ln 1"
# number field
	form_entry $d.np eparam_np int "$ln 2" 
# up arrow
	form_button_bitmap $d.npup $up \
	    "edge_mesh_nupcallback" "$ln 3" 
# down arrow
	form_button_bitmap $d.npdn $dn \
	    "edge_mesh_ndncallback" "$ln 4" 
# 
	form_checkbutton $d.nlocked "locked" eparam_nlocked \
		"$ln 5 -cols -"
# mesh_eparam_editspc

# meshing law
	incr ln
	form_label $d.lawl "Meshing law" "$ln 1"
	form_entry $d.law eparam_law string "$ln 2 -cols 2"
# Make a menu of laws.  Need to do this by hand to have
# a cascaded menu of editable functions.
	
	futil_choicelist $d.law string "mesh_law_names" "$ln 4" \
	    "" "mesh_eparam_apply 0 0"
	
	$d.np configure -width 5
	$d.law configure -width 7
	$d.edge configure -width 8
	
# family for user defined
	form_label $d.familyl "Family" "$ln 5" { {  eparam_law UserDefined } }
	

	form_entry $d.family eparam_family string "$ln 6" \
				{ {  eparam_law UserDefined } }
	futil_choicelist $d.family string "point_family_names" "$ln 7" \
	    "" "mesh_eparam_apply 0 0"
	    
# spacing 1

	incr ln
	form_label $d.sp1l "Spacing 1" "$ln 1"
	form_entry $d.sp1 eparam_sp1 float_var "$ln 2 -cols 3" mesh_eparam_editspc
# actual spacing 1
	form_entry $d.sp1a eparam_actual(sp1) float_var "$ln 5" mesh_eparam_editspc

# link for spacing 1	
	form_checkbutton $d.sp1_link_c "linked" sp1_linked "$ln 6"
	form_button $d.sp1_link_s "Sel"  \
		{ mesh_eparam_sellink eparam_sp1 } \
	    		"$ln 7" sp1_linked
	form_button $d.sp1_link_r "Rev"  \
		{ mesh_eparam_revlink eparam_sp1 } \
	    		"$ln 8" sp1_linked
	
# ratio 1
	incr ln
	form_label $d.rat1l "Ratio 1" "$ln 1" { { eparam_law !Hyperbolic } \
		    { eparam_law !FullCosinus } { eparam_law !"HalfCosinus 1" }\
		    { eparam_law !"HalfCosinus 2" } }
	form_entry $d.rat1 eparam_rat1 float_var "$ln 2 -cols 3" \
		    { mesh_eparam_editspc { eparam_law !Hyperbolic } \
		    { eparam_law !FullCosinus } { eparam_law !"HalfCosinus 1" }\
		    { eparam_law !"HalfCosinus 2" } }
	form_entry $d.rat1a eparam_actual(rat1) float_var "$ln 5" \
			mesh_eparam_editspc
# spacing 2
	incr ln
	form_label $d.sp2l "Spacing 2" "$ln 1"
	form_entry $d.sp2 eparam_sp2 float_var "$ln 2 -cols 3" mesh_eparam_editspc
	form_entry $d.sp2a eparam_actual(sp2) float_var "$ln 5" mesh_eparam_editspc

# link for spacing 2
	form_checkbutton $d.sp2_link_c "linked" sp2_linked "$ln 6"
	form_button $d.sp2_link_s "Sel"  \
		{ mesh_eparam_sellink eparam_sp2 } \
	    		"$ln 7" sp2_linked
	form_button $d.sp2_link_r "Rev"  \
		{ mesh_eparam_revlink eparam_sp2 } \
	    		"$ln 8" sp2_linked
	
# ratio 2
	incr ln
	form_label $d.rat2l "Ratio 2" "$ln 1" { { eparam_law !Hyperbolic } \
		    { eparam_law !FullCosinus } { eparam_law !"HalfCosinus 1" }\
		    { eparam_law !"HalfCosinus 2" } }
	form_entry $d.rat2 eparam_rat2 float_var "$ln 2 -cols 3" \
		    { mesh_eparam_editspc { eparam_law !Hyperbolic } \
		    { eparam_law !FullCosinus } { eparam_law !"HalfCosinus 1" }\
		    { eparam_law !"HalfCosinus 2" } }
	form_entry $d.rat2a eparam_actual(rat2) float_var "$ln 5" \
		mesh_eparam_editspc
# max space
	incr ln
	form_label $d.maxsl "Max space" "$ln 1"
	form_entry $d.maxs eparam_spmax float_var "$ln 2 -cols 3" \
	    mesh_eparam_editspc
	form_entry $d.maxsa eparam_actual(spmax) float_var "$ln 5" \
	    mesh_eparam_editspc

# graphs

	incr ln
	form_label $d.editl "Graphs" "$ln 1"
	form_entry $d.func eparam_func string "$ln 2 -cols 2"
	
	futil_choicelist $d.func string "edge_meshc_funcname" "$ln 4" \
	    "" "mesh_eparam_setlaw edit"

	form_button $d.editc "Edit" "mesh_eparam_editc {} 0" \
	    "$ln 5" mesh_eparam_editcv
		
	
# Edge meshing locked	
	incr ln
	form_checkbutton $d.locked "Parameters locked" eparam_locked \
		"$ln 1 -cols -"

# Spacing relative
	incr ln
	form_checkbutton $d.sp_rel "Spacing relative" eparam_rel \
		"$ln 1 -cols -"
	$d.sp_rel configure -command "update_h1h2"

# Copy to parallel
	incr ln
	form_checkbutton $d.parallel "Copy to parallel edges" eparam_parallel \
		"$ln 1 -cols 4"
	form_radiobutton $d.para All eparam_parallelv 0 "$ln 5" \
	    eparam_parallel

	incr ln
	form_radiobutton $d.parv Visible eparam_parallelv 1 "$ln 5" \
	    eparam_parallel

	incr ln
	form_radiobutton $d.parscale "Copy relative" \
			eparam_scale 1 "$ln 1 -cols 2"

	incr ln
	form_radiobutton $d.parns "Copy absolute" \
			eparam_scale 0 "$ln 1 -cols 2"

#	    eparam_parallel

# linked bunching
	
	incr ln
	form_frame $d.link flat 0 "$ln 1 -cols -"
	form_checkbutton $d.link.c "Linked bunching" eparam_linked {0 0}
	form_entry $d.link.v eparam_linkedijk float_var {0 1} eparam_linked
	form_button $d.link.s "Select" \
		{ mesh_eparam_sellink  eparam_linkedijk } {0 2} eparam_linked
	form_button $d.link.r "Reverse" \
		{ mesh_eparam_revlink  eparam_linkedijk } {0 3} eparam_linked
	
# highlight dependent
	incr ln
	form_checkbutton $d.highdep "Highlight dependent edges" \
	    eparam_highlight_dep "$ln 1 -cols -"
	$d.highdep configure -command mesh_eparam_redraw

# highlight adjacent
	incr ln
	form_checkbutton $d.highattached "Highlight attached faces" \
	    eparam_highlight_attached "$ln 1 -cols 1"
	$d.highdep configure -command mesh_eparam_redraw

	incr ln
	form_checkbutton $d.highmaster "Highlight master edge" \
	    eparam_highlight_master "$ln 1 -cols -"
	$d.highmaster configure -command "mesh_eparam_redraw"

# ?? call mesh_eparam_redraw
	incr ln
	
	form_frame $d.buts flat 0 "$ln 1 -cols -"
	
	form_button $d.buts.selnew "Select new edge" mesh_eparam_selnew \
		{0 0}
	form_button $d.buts.scrpos "Screen position" mesh_eparam_scrpos \
		{0 1}
	form_button $d.buts.copyto "Copy to edge" "mesh_eparam_copyto 0" \
		{1 0}
	form_button $d.buts.copyrev "Copy to reversed" "mesh_eparam_copyto 1" \
		{1 1}
	form_button $d.buts.copyfr "Copy from edge" "mesh_eparam_copyfr 0" \
		{2 0}
	form_button $d.buts.crrev "Copy from reversed" "mesh_eparam_copyfr 1" \
		{2 1}
	form_button $d.buts.rev "Reverse parameters" "mesh_eparam_apply 1 1" \
		{3 0}
	
	    if {$edge != "" && $skip} {
	        form_finish $botform_geo 0
	    } else {
	        form_finish $botform_geo
	    }
    }
    
    mesh_eparam_selnew $edge
    
    if {$edge != ""} {
        form_done .eparam
    }
}

proc mesh_eparam_setlaw {lawname} {
    global eparam_law edge_meshc_params mesh_eparam_editspc eparam_func
    
    if {[string tolower [string range $lawname 0 3]] == "edit"} {
	
	# first, based on the function name, set if the law is spline
	# or multi-linear
		    
	set funcname [edge_meshc_funcname $eparam_func]
	if [edge_meshc_funcsmooth $funcname] {
	    set eparam_law Spline
	} else {
	    set eparam_law Linear
	}
	
	# disable parameter entry boxes
	
	set mesh_eparam_editspc 0
	
	if ![mesh_eparam_editc $funcname 1] {
	    
	    # form is already up -- just
	    # reset the points for all but spline and multi-linear
	    # functions.  (all others imply reseting of points)
	
	    edge_meshc_setfunc $funcname
	}
	
    } else {
	if {[lsearch [mesh_law_names] $lawname] == -1} {
	    mess "Illegal law name $lawname"
	} else {
	    set eparam_law $lawname
	    mesh_eparam_apply 0 0
	}
    }
}

proc mesh_eparam_sellink { var_name } {
    global eparam_linkedijk eparam_locked 
    global button_instructions

    
    set edge [select_hexa edge 1 "Please select the edge to link to \
		$button_instructions" "new_format selected_bunching"]
    if {$edge == ""} return

    
    global $var_name
    set $var_name "linked [lrange $edge 0 1]"

    set eparam_locked 1
}

proc mesh_eparam_revlink { var_name } {
    global $var_name

    set var [set $var_name]
    if {![string compare [lindex $var 0] "linked"]} {
	set e1 [lindex $var 1]
	set e2 [lindex $var 2]
	set $var_name "linked $e2 $e1"
    } else { 
	if {[llength $var] == 2} {
	    set e1 [lindex $var 0]
	    set e2 [lindex $var 1]
	    set $var_name "$e2 $e1"
	}
    }
}

proc mesh_law_names {{key ""}} {
    set "names(BiGeometric)"       default
    set "names(Uniform)"       uniform
    set "names(Hyperbolic)"    hyperbolic
    set "names(Poisson)"       poisson
    set "names(Curvature)"     curvature
    set "names(Geometric 1)"   geo1
    set "names(Geometric 2)"   geo2
    set "names(Exponential 1)" exp1
    set "names(Exponential 2)" exp2
    set "names(Biexponential)" biexponential
    set "names(Linear)"	       linear
    set "names(Spline)"	       spline
    set "names(FullCosinus)"   fcosinus
    set "names(HalfCosinus 1)" hcosinus1
    set "names(HalfCosinus 2)" hcosinus2
    set "names(UserDefined)"   userdefined
    set "names(OthoOffset)"    ortho
    foreach n [array names names] { set names($names($n)) $n }
    
    if {$key == ""} {
	return [list BiGeometric Uniform Hyperbolic Poisson Curvature \
		    "Geometric 1" "Geometric 2" \
		    "Exponential 1" "Exponential 2" Biexponential \
		    Linear Spline FullCosinus "HalfCosinus 1" "HalfCosinus 2" \
		    UserDefined ]
    } else {
	return $names($key)
    }
}

proc mesh_eparam_selnew {{in_edge ""}} {
    global eparam_edge eparam_edgelist eparam_highlight_dep
    global edge_meshc_points edge_meshc_params
    global button_instructions edge_meshc_done
    global eparam_highlight_master sp1_linked sp2_linked eparam_parallel
    global eparam_highlight_attached
    
    focus .v
    set opts "new_format selected_bunching"
    if { $eparam_highlight_attached } {
	    append opts " -faces"
    }

    if {$in_edge != ""} {
	    set edge $in_edge
    } else {
	    set edge [select_hexa edge 1 "Please select an edge $button_instructions" $opts ]
    }
    if {$edge == ""} return
    
    # reset the density of points for linear/spline edge meshing defaults
    
    if [info exists edge_meshc_params(formup)] {
	    set edge_meshc_done 0
	    update idle
    } 
    
    set eparam_density ""
    set edge_meshc_params(edgepointsactive) 0
    set edge_meshc_points(0) {}
    set edge_meshc_points(1) {}
    set edge_meshc_points(2) {}
    set eparam_parallel 0
    
    set eparam_edge $edge
    set eparam_edgelist [list $edge]
    mesh_eparam_update
    if { $eparam_highlight_dep || $eparam_highlight_master } {
    	mesh_eparam_redraw
    }
}

proc swap {a b} {
    upvar 1 $a l1
    upvar 1 $b l2
    set temp $l1
    set l1 $l2
    set l2 $temp
}

proc mesh_eparam_update {{edge ""} { rev 0 } } {
    global eparam_sp1 eparam_sp2 eparam_spmax eparam_rat1 eparam_rat2
    global eparam_save eparam_density eparam_length eparam_func
    global eparam_edge eparam_np last_line eparam_locked
    global eparam_law eparam_highlight_dep display_linked_to
    global eparam_linked eparam_linkedijk
    global eparam_actual display_flag edge_meshc_done
    global edge_meshc_params edge_meshc_points mesh_eparam_editcv
    global mesh_eparam_editspc sp1_linked sp2_linked
    global eparam_nlocked eparam_rel
    
    if {$edge == ""} { set edge $eparam_edge }
    
    hex_command "mesh_params \{ [lindex $edge 0] \} [lindex $edge 1]" 0
    #file_dirty
    
    set mesh_eparam_editcv 0
    set mesh_eparam_editspc 1
    set eparam_density ""
    set eparam_nlocked 0
    set eparam_rel 0

    set cur_law [lindex $last_line 0]
    if {![string compare $cur_law "linear"] ||
	![string compare $cur_law "spline"]} {
	set islinear 1
    } else {
	set islinear 0
    }
    
# is the linear/beizer form up and we are requesting non-linear law?
	    
    if {!$islinear && [info exists edge_meshc_params(formup)]} {
	set edge_meshc_done 0
	update idle
    }
    
    if { [ lindex $last_line 0 ] == "userdefined" } {
	global eparam_family
	set eparam_law [mesh_law_names [lindex $last_line 0]]
	set eparam_family [ lindex $last_line 1 ]
	set eparam_np [ lindex $last_line 2 ]
    } elseif ![string compare [lindex $last_line 0] "linked"] {
	foreach i {0 1 2 3 4 5 6 7 8} {
	    set v [lindex {np sp1 rat1 sp2 rat2 length law spmax} $i]
	    set eparam_$v ""
	}
	set eparam_linked 1
	set eparam_linkedijk [lindex $last_line 1]
	set eparam_locked [expr {[lindex $last_line 2] == "locked"}]
	if { [ llength $last_line ] == 4 } {
		set eparam_np [ lindex $last_line 3 ]
	}
	
# set the number of nodes from the linked edge
#	hex_command "mesh_params [lindex $eparam_linkedijk 0] \
#				[lindex $eparam_linkedijk 1]" 0
#	set eparam_np [ lindex $last_line 0 ] 
    } else {
	if $islinear {
	    
# extract the law name and the # of points
	    
	    set eparam_law [mesh_law_names [lindex $last_line 0]]
	    set eparam_func $eparam_law
	    set eparam_np [lindex $last_line 1]
	    set np [lindex $last_line 2]
	    
	    set mesh_eparam_editcv 1
	    set mesh_eparam_editspc 0
	    
# can get into update 2 ways: 1) after an apply
# as a selection (ie requires initialization)
# do this first because both setcurvetype and
# setnpoints will initialize things in case 
# the form is not initialized

	    set isinit [info exists edge_meshc_params(formup)]
	    
	    edge_meshc_setcurvetype $eparam_law
	    edge_meshc_setnpoints $eparam_np
	    edge_meshc_setlength $eparam_length
	    
# if form is already up, don't want to do this
	    
	    if !$isinit {
		
		set density ""
		set firstx 0.0
		set lastx 0.0
		
		for {set i 0} {$i < $np} {incr i} {
		    set x [lindex $last_line [expr 2*$i+3]]
		    set y [lindex $last_line [expr 2*$i+4]]
		    append density "$x $y "
		    
		    if {$i == 0} {
			set firstx $x
		    } elseif {$i == $np-1} {
			set lastx [expr 1.0 - $x]
		    }
		}
		
		# is the length on the line?
		
		set ll [llength $last_line]
		if {$ll == 2*$np + 4} {
		    set eparam_length [lindex $last_line [expr 2*$np + 3]]
		} else {
		    set eparam_length 1.0
		}
		edge_meshc_setlength $eparam_length
	    
		edge_meshc_setcallback eparam_density_callback \
		    mesh_law_names edge_meshc_filebrowser
	    
		# if we have no density, use default density
		# ((0, 1) to (1, 1))
	    
		if {$density == ""} {
		    
		    mesh_eparam_initedgepoints
		    edge_meshc_setinitpoints
		    
		    set eparam_density \
			[edge_meshc_screentocoord $edge_meshc_points(0)]
		} else {
		
# use given density set on the points
		
		    edge_meshc_setinitpoints $density
		    set eparam_density $density
		    
		    if {$firstx == 0.0} {
			set edge_meshc_params(edgepointsactive) 0
			set lastx 0.0
		    } else {
			set edge_meshc_params(edgepointsactive) 1
			
			# set the current actual spacings
			
			set eparam_actual(sp1) $edge_meshc_params(asp1)
			set eparam_actual(sp2) $edge_meshc_params(asp2)
		    }
		    set edge_meshc_params(fe) $firstx
		    set edge_meshc_params(sp1) $firstx
		    set edge_meshc_params(asp1) \
			[expr $firstx*$eparam_length]
			
		    set edge_meshc_params(le) $lastx
		    set edge_meshc_params(sp2) $lastx
		    set edge_meshc_params(asp2) \
			[expr $lastx*$eparam_length]
		    		    
		    set edge_meshc_params(clength) [expr 1.0-$firstx-$lastx]
		    edge_meshc_edgeminmax
		}
	    } else {
		catch {edge_meshc_update 1}
		set eparam_density \
		    [edge_meshc_screentocoord $edge_meshc_points(0)]
	    }
	    set eparam_linked 0
	    set eparam_linkedijk ""
	    
	} else {
	    
# get standard spacing + bunching law
	    if { [ llength $last_line ] < 9 } {
		mess "expecting 9 params from mesh_params\n" red
		return
	    }
	    
	    foreach i {0 1 2 3 4 5 6 7 8} {
		set v [lindex {np sp1 rat1 sp2 rat2 length \
				   locked law spmax} $i]
		set eparam_$v [lindex $last_line $i]
		
		if {$v == "law"} {
		    set eparam_law [mesh_law_names $eparam_law]
		}
		
	    }
# get actual spacing parameters
	    foreach i {0 1 2 3 4 5} {
		    set v [lindex {sp1 rat1 sp2 rat2 spmax} $i]
		    set eparam_actual($v) [lindex $last_line [expr $i+9]]
	    }
# check for number of nodes locked
	    if { [ llength $last_line ] >= 15 && \
			[ lindex $last_line 14 ] == "n_locked" }  {
		set eparam_nlocked 1
	    } 
	    if $rev {
#		puts "eparam_sp1 $eparam_sp1 eparam_sp2 $eparam_sp2"
		swap eparam_sp1 eparam_sp2
#		puts "eparam_sp1 $eparam_sp1 eparam_sp2 $eparam_sp2"
		swap eparam_rat1 eparam_rat2
#		puts "eparam_law $eparam_law"
		set eparam_law [ law_swap $eparam_law ] 
#		puts "eparam_law $eparam_law"
	    }

	    set eparam_linked 0
	    set eparam_linkedijk ""
	    set sp1_linked 0
	    if { [ lindex $eparam_sp1 0 ] == "linked" } {
		set sp1_linked 1
	    }
	    set sp2_linked 0
#	    puts "$eparam_sp2"
	    if { [ lindex $eparam_sp2 0 ] == "linked" } {
		set sp2_linked 1
	    }
	}
    }
    
    foreach i {np sp1 rat1 sp2 rat2 length locked law spmax \
		   density linked linkedijk} {
	set eparam_save($i) [set eparam_$i]
    }
    if $eparam_highlight_dep {
	set display_linked_to \
	    "[lindex $eparam_edge 0] [lindex $eparam_edge 1]"
    } else {
	catch {unset display_linked_to}
    }
    
# all of the redraw should happen in mesh_eparams_redraw
#    if {$display_flag(edge_mset) || $eparam_highlight_dep} {
#	hex_update_display edge
#    }
}

proc mesh_eparam_scrpos {} {
    global display_flag eparam_edge
    global button_instructions
    
    banner "Modify the edge meshing $button_instructions"
    set cmd "dynamic_edge_mesh \{ [lindex $eparam_edge 0] \} \
	    [lindex $eparam_edge 1] [range_string] m \
	    [volume_activename_string]"
    if $display_flag(edge_vol) { append cmd " volume" }
    hex_command $cmd 1 1
    #file_dirty
    banner ""
    mesh_eparam_update
}

proc mesh_eparam_copyto {rev} {
    global last_line eparam_edge eparam_edgelist eparam_scale
    global button_instructions
    
    set options "new_format "
    
    set edges [select_hexa edge 0 "Please select edges to copy to \
		$button_instructions" $options]
    if {$edges == ""} return
    
    mesh_eparam_apply $rev 1 $edges $eparam_scale
    mesh_eparam_redraw
}

proc mesh_eparam_copyfr {rev} {
    global last_line eparam_edge eparam_edgelist eparam_scale
    global button_instructions
    
    set options "new_format "
    
    set edge [select_hexa edge 1 "Please select the edge to copy from \
	    $button_instructions" $options]
    if {$edge == ""} return
    
    mesh_eparam_update $edge $rev
    mesh_eparam_apply 0 1 "" $eparam_scale
}
proc law_swap { lname } {
	switch $lname {
	    geo1 {
		return geo2
	    }
	    "Geometric 1" {
		return "Geometric 2"
	    }
	    geo2 {
		return geo1
	    }
	    "Geometric 2" {
	    	return "Geometric 1"
	    }
	    "Exponential 1" {
	    	return "Exponential 2"
	    }
	    "Exponential 2" {
	    	return "Exponential 1"
	    }
	    exp1 {
		return exp2
	    }
	    exp2 {
		return exp1
	    }
	    "HalfCosinus 1" {
	    	return "HalfCosinus 2"
	    }
	    "HalfCosinus 2" {
	    	return "HalfCosinus 1"
	    }
	    hcosinus1 {
		return hcosinus2
	    }
	    hcosinus2 {
		return hcosinus1
	    }
	    default {
		return $lname
	    }
	}
}

proc mesh_eparam_apply {rev {commitform 0} {edges ""} {scale 0} } {
    global eparam_edgelist eparam_sp1 eparam_sp2 eparam_spmax
    global eparam_rat1 eparam_rat2 eparam_law eparam_density eparam_length
    global eparam_np eparam_locked eparam_parallel eparam_parallelv
    global display_flag eparam_linked eparam_linkedijk eparam_scale
    global edge_meshc_params edge_meshc_points mesh_eparam_editcv
    global mesh_eparam_editspc eparam_curedgelist eparam_func
    global eparam_nlocked eparam_rel eparam_family
    
#    puts "scale $scale"
    set mesh_eparam_editcv 0
    set mesh_eparam_editspc 1
    if {!$eparam_linked && ($eparam_np == "")} {
# It was linked but is no longer linked, so we have to do some tricks.
	if { $eparam_law == "" } {
		set eparam_law "BiGeometric"
	}
	foreach edge $eparam_edgelist {
	    hex_command "set_mesh \{ [lindex $edge 0] \} \
			[lindex $edge 1] [mesh_law_names $eparam_law]" 0
	}
	mesh_eparam_update
    }
    
    if {$edges == ""} { set edges $eparam_edgelist }
    
    set eparam_curedgelist $edges
    set lmax ""
    set stuff ""
    set cmd ""
    foreach edge $edges {
	if { $eparam_law == "UserDefined" } {
		if { $eparam_family == "" } {
			return
		}
		set cmd "set_mesh [lindex $edge 0] [lindex $edge 1] \
			userdefined $eparam_family n $eparam_np"
	} elseif $eparam_linked {
	    if {$eparam_linkedijk == ""} {
		tk_dialog .err "Error" \
		"Can't set linked bunching -- no edge is specifed." \
		"" 0 Ok
	    }
	    set cmd "set_mesh [lindex $edge 0] [lindex $edge 1]"
	    if { [ lindex  $eparam_linkedijk 0 ] != "linked" } {
		append cmd " linked $eparam_linkedijk"
	    } else {
		append cmd " $eparam_linkedijk"
	    }
	} else {
# non-linked edges
	    
	    if {$eparam_spmax == ""} {
		set lmax ""
	    } else {
		set lmax "lmax $eparam_spmax"
	    }
	    if {$eparam_law == "Spline" || $eparam_law == "Linear"} {
# spline stuff.
		set mesh_eparam_editcv 1
		set mesh_eparam_editspc 0
		set eparam_func $eparam_law
		
		# If this is an intialization -- set defaults
		
		set graphformup [info exists edge_meshc_params(formup)]
		if $graphformup {
		    
		    # implicit apply of current parameters on form
		    # if we apply with the form up IFF commitform
		    # parameter is 1
		    
		    if $commitform {
			set eparam_density \
			    [edge_meshc_screentocoord $edge_meshc_points(0)]
		    }
		}
		
		if {$eparam_density == ""} {
		    
		    edge_meshc_setcallback eparam_density_callback \
			mesh_law_names edge_meshc_filebrowser
	    
		    edge_meshc_setcurvetype $eparam_law
		    edge_meshc_setnpoints $eparam_np
		    edge_meshc_setlength $eparam_length
		    
		    # set the initial edge spacings and control points
		    
		    mesh_eparam_initedgepoints		    
		    edge_meshc_setinitpoints
		    
		    # set the initial point list
		    
		    set eparam_density \
			[edge_meshc_screentocoord $edge_meshc_points(0)]
		    
		} else {
		    set len [llength $eparam_density]
		    set firstx [lindex $eparam_density 0]
		    if {$firstx == 0.0} {
			set edge_meshc_params(edgepointsactive) 0
		    } else {
			set edge_meshc_params(edgepointsactive) 1
		    }
		}
		
# Check if reversed.
		
		if $rev {
		    edge_meshc_reverse x $graphformup
		    set eparam_density \
			[edge_meshc_screentocoord $edge_meshc_points(0)]
		}
		
		set key ""
		if $edge_meshc_params(edgepointsactive) {
		    set key "end_spacing"
		}
		set np [expr [llength $eparam_density]/2]
		set stuff "[mesh_law_names $eparam_law] $np $eparam_density \
 			$key"
	    } else {
		
# just in case we have empty values for sp1, sp2 etc
		
		if {$eparam_sp1 == ""} {
		    if { $eparam_length != "" } {
		        set eparam_sp1 [expr $eparam_length*.1]
		        set eparam_sp2 [expr $eparam_length*.1]
		    }
		    set eparam_rat1 2
		    set eparam_rat2 2
		    set eparam_rel 0
		}
		set h1 $eparam_sp1
		set r1 $eparam_rat1
		set h2 $eparam_sp2
		set r2 $eparam_rat2
		if { $eparam_law == "" } {
			set lname default
		} else {
			set lname [mesh_law_names $eparam_law]
		}
		if $rev {
			swap h1 h2
			swap r1 r2
			set lname [ law_swap $lname ]
		}
		if { $eparam_rel } {
                        set h1 "h1rel $h1"
                        set h2 "h2rel $h2"
                } elseif { $scale } {
                        set h1 "h1rel [expr ($h1 + .0)/$eparam_length]"
                        set h2 "h2rel [expr ($h2 + .0)/$eparam_length]"
                } else {
			if { $h1 != "" } {
                        	set h1 "h1 $h1"
			} else {
				set h1 ""
			}
			if { $h2 != "" } {
                        	set h2 "h2 $h2"
			} else {
				set h2 ""
			}
                }
		set stuff "$h1 r1 $r1 $h2 r2 $r2 $lmax $lname"
	    }
	    set cmd "set_mesh \{ [lindex $edge 0] \} [lindex $edge 1] \
		n $eparam_np $stuff"
	    if  { $eparam_nlocked } {
		append cmd " nlocked"
	    }
	}
	if $eparam_parallel {
	    lappend cmd copy_to_parallel
	    if $eparam_parallelv {
		append cmd " [range_string] m [family_activename_string]"
	    }
	    if { $eparam_scale == 0 } {
		append cmd " no_scale"
	    }
	}
	if $eparam_locked {
	    append cmd " locked"
	} else {
	    append cmd " unlocked"
	}
	
	hex_command $cmd
	#file_dirty
    }
    mesh_eparam_redraw
    mesh_eparam_update
}

proc mesh_eparam_redraw {} {
    global display_flag eparam_edgelist eparam_parallel eparam_highlight_dep
    global eparam_highlight_master eparam_linkedijk
    
    
    set opts [display_edge_mesh_params ]
    set cmd "dem $opts selected_bunching "
    foreach edge $eparam_edgelist {
	if { $eparam_highlight_master && $eparam_linkedijk != "" } {
		append cmd " color:yellow $eparam_linkedijk"
	}
	
# highlight this edge and  ...
	append cmd " highlight"

# perhaps the parallel edges
	if $eparam_parallel { 
		append cmd " parallel"
	} elseif { $eparam_highlight_dep } {
# or the dependend edges
		append cmd " linked"
	}
	append cmd " \{ [lindex $edge 0] \} [lindex $edge 1]"

    }
    hex_command $cmd 0
}

proc mesh_eparam_reset {{var eparam_save}} {
    global eparam_save
    
   foreach i [array names $var] {
	global eparam_$i
	set eparam_$i [set ${var}($i)]
    }
}

proc mesh_eparam_editc {func {doinitedgepoints 0}} {
    global ai_environment
    global eparam_length eparam_law eparam_density edge_meshc_points
    global eparam_np edge_meshc_params eparam_actual
    
    if {[info exists edge_meshc_params(formup)] && [winfo exists $edge_meshc_params(w)]} {
	    return 0
    }
    
    if {$func != "" && $eparam_law != "Spline" && $eparam_law != "Linear"} {
	    return 0
    }
    
    # make sure initialization data exists
    
    edge_meshc_setcallback eparam_density_callback mesh_law_names \
	edge_meshc_filebrowser
	    
    edge_meshc_setcurvetype $eparam_law $func
    edge_meshc_setnpoints $eparam_np
    edge_meshc_setlength $eparam_length
    
    # set up first/last edge point spacings
    
    if $doinitedgepoints { mesh_eparam_initedgepoints }
    
    # compute initial set of points
    
    if [edge_meshc_form] {
	set eparam_density [edge_meshc_screentocoord $edge_meshc_points(0)]
	
	if $edge_meshc_params(edgepointsactive) {
			
	    # set the current actual spacings
			
	    set eparam_actual(sp1) $edge_meshc_params(asp1)
	    set eparam_actual(sp2) $edge_meshc_params(asp2)
	}
	mesh_eparam_apply 0 0
    }
    mesh_eparam_redraw
    mesh_eparam_update

    if {([info exists ai_environment] && $ai_environment)} {
        mParamsDEZ hexMeshParamsUpdate 0
    }

    return 1
}
    
proc eparam_density_callback {args} {
# proc eparam_density_callback {np smooth edgepact points} 
    
    global last_line edge_meshc_points
    
    set np [lindex $args 0]
    set smooth [lindex $args 1]
    set edgepact [lindex $args 2]
    set points [lrange $args 3 end]
    set disttype ""
    if $smooth {
	set disttype smooth
    } else {
	set disttype linear
    }
    
    set eparam_density [edge_meshc_screentocoord $edge_meshc_points(0)]
    set cmd "compute_spline_distribution $disttype $edgepact \
 [expr [llength $points]/2] $np $points"
    
    hex_command $cmd 0
    return $last_line
}

proc mesh_eparam_restoresave {} {
    global eparam_last_save
    
    # really need to restore last state.  Temporary hack that
    # will restore our original configuration
    
    mesh_eparam_reset
    mesh_eparam_apply 0 0
}

proc mesh_eparam_initedgepoints {} {
    global eparam_actual eparam_sp1 eparam_sp2 eparam_length
    global edge_meshc_params
    
    if {$eparam_sp1 != ""} {
	set sp1 $eparam_actual(sp1)
	set sp2 $eparam_actual(sp2)
    } else {
	set sp1 [expr $eparam_length*.1]
	set sp2 [expr $eparam_length*.1]
    }
	
    if {$sp1 != 0. || $sp2 != 0.} {
	set edge_meshc_params(edgepointsactive) 1
	set fe [expr $sp1/$eparam_length]
	set le [expr $sp2/$eparam_length]
	
	set edge_meshc_params(fe) $fe
	set edge_meshc_params(sp1) $fe
	set edge_meshc_params(asp1) $sp1
	
	set edge_meshc_params(le) $le
	set edge_meshc_params(sp2) $le
	set edge_meshc_params(asp2) $sp2
	
	set edge_meshc_params(clength) [expr 1.0-$fe-$le]
	edge_meshc_edgeminmax
    } else {
	set edge_meshc_params(edgepointsactive) 0
    }
}

proc edge_meshc_filebrowser {} {
    return [futil_get_file]
}

# ----------------------------------------------

proc mesh_assign_sizes_doit {} {
	global reassign_fix
	set com "set_mesh_params [volume_activename_string]"
	if { $reassign_fix == "counts" } {
		append com " fix_counts"
	} elseif { $reassign_fix == "laws" } {
		append com " fix_laws"
	}
	hex_command $com
	#file_dirty
	get_indices 1
}
proc mesh_assign_sizes {} {
    global reassign_fix
    set mess "Warning: this operation will delete all edge meshing.\
\nThe edge counts can be kept the same or allowed to change."
    set buts { { Accept mesh_assign_sizes_doit } cancel }
    set d [ form_init .recalsize "Recalculate Mesh Size" "xxx" $buts ]
    if { [ info exists reassign_fix ] == 0 } {
	set reassign_fix none
    } 
    if { $reassign_fix != "counts" && \
		$reassign_fix != "laws" && \
		$reassign_fix != "none" } {
	set reassign_fix none
    }
    if { $d != "" } {
	form_frame $d.fr sunken 2 { 0 0 }; set d $d.fr
	form_radiobutton $d.fix_counts \
			"Fix Counts" reassign_fix counts "0 1 -cols -"
	form_radiobutton $d.fix_laws \
			"Fix Laws" reassign_fix laws "1 1 -cols -"
	form_radiobutton $d.neither \
			"Fix nothing"  reassign_fix none "2 1 -cols -"
	form_finish +300+300
    }

#    switch [tk_dialog .reassign "Reassign sizes" $mess "" -1 \
#		"Fix counts" "Change counts" "Cancel"] {
#		    0 {
#			hex_command "set_mesh_params [volume_activename_string] \
#				 fix_counts"
#			file_dirty
#		    	get_indices 1
#		    }
#		    1 {
#			hex_command "set_mesh_params [volume_activename_string]"
#			file_dirty
#		    	get_indices 1
#		    }
#		}
}

# ----------------------------------------------

proc mesh_refinement {} {
    global form_done_flag mesh_factor mesh_refdim mesh_alldims botform_geo
    
    block_unmark
    hex_command "del marked -solid m [volume_activename_string]" 0
    
    set buts {
	{Apply mesh_ref_apply}
	{Done {block_unmark; form_done .mrefine}}
    }
    set d [form_init .mrefine "Mesh refinement" mesh $buts]
    if {$d != ""} {
	set mesh_factor 1
	set mesh_refdim 0
	set mesh_alldims 0
	
	form_frame $d.fr sunken 3 {0 0}; set d $d.fr
	
	form_label $d.factl "Factor:" {0 0}
	form_entry $d.fact mesh_factor int {0 1 -cols 2}
	form_button $d.factq Query mesh_ref_query {1 1 -cols 2}
	
	form_label $d.whichl "Dimensions:" {3 0}
	form_radiobutton $d.alld All mesh_alldims 1 {3 1}
	form_radiobutton $d.oned One mesh_alldims 0 {3 2}
	form_entry $d.refdim mesh_refdim int {4 1} {{mesh_alldims 0}}
	form_button $d.refdimq Select mesh_ref_seldim {4 2} {{mesh_alldims 0}}
	
	form_label $d.regl "Region:" {10 0}
	form_label $d.labm "Materials:" {12 0}
	form_label $d.labc "2 corners:" {13 0}
	form_label $d.labb "Block:" {14 0}
	form_label $d.labn "Block Numbers:" {15 0}
	form_button $d.addm "Add" "block_mark_fams 1 0" {12 1}
	form_button $d.rm "Remove" "block_mark_fams 0 0" {12 2}
	form_button $d.addb "Add" {while {[block_mark 1 0]} {}} {13 1}
	form_button $d.remb "Remove" {while {[block_mark 0 0]} {}} {13 2}
	form_button $d.as "Add" {block_mark_super 1 1 "to Refine" ""} {14 1}
	form_button $d.rs "Remove" \
	    {block_mark_super 0 1 "to Refine" ""} {14 2}
	form_button $d.addbn "Add" \
	    {block_mark_numbers 1 "to Refine" ""} {15 1}
	form_button $d.rembn "Remove" \
	    {block_mark_numbers 0 "to Refine" ""} {15 2}
	form_button $d.clb "Clear blocks" "block_unmark" {16 1 -cols 2}
	
	form_finish $botform_geo
    }
}

proc mesh_ref_apply {} {
    global mesh_alldims mesh_factor mesh_refdim
    
    if $mesh_alldims {
	hex_command "set_refinement -1 $mesh_factor"
    } else {
	hex_command "set_refinement $mesh_refdim $mesh_factor"
    }
    #file_dirty
}

proc mesh_ref_query {} {
    global last_line mesh_factor mesh_alldims mesh_refdim
    
    if { $mesh_alldims } {
    	hex_command "query_refinement"
    } else {
	hex_command "query_refinement $mesh_refdim"
    }
    if ![scan $last_line %d mesh_factor] {
	mess "Warning: couldn't get refinement factor for marked blocks\n" red
	set mesh_factor 1
    }
}

proc mesh_ref_seldim {} {
    global mesh_refdim
    global button_instructions
    
    set stuff [select_hexa edge 1 "Select the edge along which to refine \
		$button_instructions"]
    if {$stuff != ""} {
	set mesh_refdim [lindex $stuff 1]
    }
}

# -------------------------

proc mesh_renumber_domains {} {
    global last_line display_flag use_output_blocks
    global renumber_pos renumber_at renumber_tag
    
    catch {form_kill .renum}
    catch {unset renumber_at}
    catch {unset renumber_pos}
    
    set cmd pack_superblocks
    if $use_output_blocks { append cmd " output_blocks" }
    append cmd " [volume_activename_string]"
    hex_command $cmd
    
    set ndom $last_line
    if !$ndom {
	mess "Error: can't renumber blocks -- no superblocks found\n" red
	return
    }
    #set ndom 300
    
# save off old values
    set db $display_flag(block)
    set ds $display_flag(block_super)
# turn on super block display
    set display_flag(block) 1
    set display_flag(block_super) 1
    hex_update_display block
    
    set d [form_init .renum "Domain renumbering" mesh "accept cancel"]
    
    set can [form_canvas $d.c 400x200 sunken 2 {0 0 -fill y} 0 1]
    
    set its ""
    for {set i 1} {$i <= $ndom} {incr i} {
	set r [expr {($i - 1) / 10}]
	set c [expr {($i - 1) % 10}]
	set renumber_pos($i) "$r $c"
	
	set it2 [$can create rectangle 0 0 0 0 -fill [.renum cget -background]\
		     -width 1 -outline black]
	set it [$can create text 0 0 -fill black -text $i]
	
	#frame $can.fr$i -width 28 -height 18 -relief raised -borderwidth 2
	#label $can.fr$i.l -text $i
	#pack $can.fr$i.l -fill both -anchor c
	#pack propagate $can.fr$i 0
	#set it [$can create window 0 0 -window $can.fr$i -anchor c]
	set renumber_tag($i) "$it $it2"
	renumber_putrc $i
	
	foreach x "$it $it2" {
	    $can bind $x <ButtonPress-1> "$can raise $it2; $can raise $it"
	    $can bind $x <Button1-Motion> \
		"renumber_move $i \[renum_p %W x %x\] \[renum_p %W y %y\]"
	    $can bind $x <ButtonRelease-1> \
		"renumber_putrc $i \[renum_p %W x %x\] \[renum_p %W y %y\]"
	}
	
	lappend its $it $it2
    }
    set bb [eval $can bbox $its]
    set v0 [lindex $bb 0]
    set v1 [lindex $bb 1]
    set v2 [lindex $bb 2]
    set v3 [lindex $bb 3]
    $can configure -scrollregion "$v0 $v1 $v2 [expr $v3 + 40]"
    
    form_finish bot
    
    if [form_wait .renum] {
	set cmd "change_superblocks"
	if $use_output_blocks { append cmd " output_blocks" }
	
	# Now grab all the data.
	foreach rc [lsort -command renumber_cmp [array names renumber_at]] {
	    lappend cmd $renumber_at($rc)
	}
	hex_command $cmd
    }

# restore old values
    set display_flag(block) $db
    set display_flag(block_super) $ds 

    hex_update_display edge face block
}

proc renum_p {w x v} {
    return [expr int([$w canvas$x $v])]
}

proc renumber_cmp {v1 v2} {
    if {[lindex $v1 0] == [lindex $v2 0]} {
	return [expr {[lindex $v1 1] - [lindex $v2 1]}]
    } else {
	return [expr {[lindex $v1 0] - [lindex $v2 0]}]
    }
}

proc renumber_putrc {i {xpos ""} {ypos ""}} {
    global renumber_pos renumber_at renumber_tag
    
    
    set can .renum.main.c.c
    set r [lindex $renumber_pos($i) 0]
    set c [lindex $renumber_pos($i) 1]
    if {$xpos != ""} { set c [expr $xpos / 40] }
    if {$ypos != ""} { set r [expr $ypos / 20] }
    set xpos [expr {$c * 40}]
    set ypos [expr {$r * 20}]
    renumber_setpos $i $xpos $ypos
    
    catch {unset renumber_at($renumber_pos($i))}
    
    # Now move the others out of the way.
    renumber_moveup $r $c
    
    set "renumber_at($r $c)" $i
    set renumber_pos($i) "$r $c"
}

proc renumber_setpos {i x y} {
    global renumber_tag
    
    set can .renum.main.c.c
    $can coords [lindex $renumber_tag($i) 0] \
	[expr $x + 20] [expr $y + 10]
    $can coords [lindex $renumber_tag($i) 1] \
	[expr $x + 1] [expr $y + 1] [expr $x + 39] [expr $y + 19]
}

proc renumber_moveup {r c} {
    global renumber_at
    
    
    if [info exists "renumber_at($r $c)"] {
	set nr $r; set nc [expr $c + 1]
	if {$nc == 10} { set nc 0; incr nr }
	renumber_moveup $nr $nc
	renumber_putrc [set "renumber_at($r $c)"] \
	    [expr $nc * 40] [expr $nr * 20]
    }
}

proc renumber_move {i xpos ypos} {
    renumber_setpos $i [expr $xpos - 20] [expr $ypos - 10]
}

#proc renumber_change_check {var sub w} {
#   global $var
#   set cur [set ${var}($sub)]
#   if {$cur != [string trim $sub]} {
#	
#    }
#}

# -------------------------

proc mesh_periodic {} {
    set d [form_init .nodes_periodic "Periodic nodes" done]
    if {$d != ""} {
	form_button $d.per "Make nodes periodic" \
	    "mesh_make_periodic periodic" {0 0}
	form_button $d.nper "Make nodes not periodic" \
	    "mesh_make_periodic not_periodic" {1 0}
	form_finish bot
    }
}


proc mesh_make_periodic {what} {
    global button_instructions

    while 1 {
	set nn [select_node "Please select two vertices  $button_instructions" 2]
	if {[llength $nn] != 2} return
	
	hex_command "make_nodes_$what \{ [lindex $nn 0] \} \{ [lindex $nn 1] \}"
    }
}

# -------------------------

proc mesh_smooth {} {
    global smoothing
    global config_dir
    
    set d [form_init .smooth "Smoothing" mesh]
    if {$d != ""} {
	set smoothing(iters) 5
	set smoothing(how) determinant
	set smoothing(blocks) 0
	set smoothing(limit_bad_determ) 30.0
	set smoothing(limit_bad_angle) 80.0
	set smoothing(sfit) 1
	set smoothing(ign_prescribed_points) 0
	set smoothing(fix_boundaries) 0
	
	form_label $d.iterl "Iterations" {0 0}
	form_entry $d.iter smoothing(iters) int {0 1}
	form_label $d.bad_determl "Threshold Determinant" {1 0}
	form_entry $d.bad_determ smoothing(limit_bad_determ) float_var {1 1}
	form_label $d.bad_anglel "Threshold Angle" {2 0}
	form_entry $d.bad_angle smoothing(limit_bad_angle) float_var {2 1}
	form_label $d.sfitl "Surface fitting" {3 0}
	form_radiobutton $d.sfiton "On" smoothing(sfit) 1 {3 1}
	form_radiobutton $d.sfitoff "Off" smoothing(sfit) 0 {3 2}
	form_label $d.ignl "Ignore Prescr.Pnts" {4 0}
	form_radiobutton $d.ignon "On" smoothing(ign_prescribed_points) 1 {4 1}
	form_radiobutton $d.ignoff "Off" smoothing(ign_prescribed_points) 0 {4 2}
	form_label $d.fbndl "Fix boundaries" {5 0}
	form_radiobutton $d.fbndon "On" smoothing(fix_boundaries) 1 {5 1}
	form_radiobutton $d.fbndoff "Off" smoothing(fix_boundaries) 0 {5 2}
	form_label $d.mth "Method" {6 0}
	form_radiobutton $d.sdet "Determinant" smoothing(how) \
	    determinant {6 1}
	form_radiobutton $d.sang "Angle" smoothing(how) \
	    angle {7 1}
	form_radiobutton $d.swar "Warp" smoothing(how) \
	    warp {8 1}
	form_radiobutton $d.slap "Laplace" smoothing(how) \
	    laplace {9 1}
	form_label $d.sml "Smooth" {10 0}
	form_radiobutton $d.msh "Mesh" smoothing(blocks) 0 {10 1}
	form_radiobutton $d.blk "Blocks" smoothing(blocks) 1 {11 1}
	
	form_finish bot
    }
    if ![form_wait .smooth] return
    
    set cmd "smooth $smoothing(iters)"
    if $smoothing(blocks) { append cmd " blocks" }
    append cmd " [volume_activename_string] sm_param $config_dir/mesh"
    set type_selected 0
    switch $smoothing(how) {
	determinant {
	 set type_selected 0
	}
	angle {
	 set type_selected 1
	}
	warp {
	 set type_selected 2
	}
	laplace {
	 set type_selected 3
	}
    }
    append cmd " type_selected $type_selected"
    if {$smoothing(how) == "laplace"} {
      append cmd " no_step $smoothing(iters)"
    }
    append cmd " sfit $smoothing(sfit)"
    if {$smoothing(how) == "determinant"} {
      append cmd " limit_bad_determ $smoothing(limit_bad_determ)"
    }
    if {$smoothing(how) == "angle" || $smoothing(how) == "warp"} {
      append cmd " limit_bad_angle $smoothing(limit_bad_angle)"
    }
    append cmd " ign_prescribed_points $smoothing(ign_prescribed_points)"
    append cmd " fix_boundaries $smoothing(fix_boundaries)"
    hex_command "$cmd"
    hex_update_display edge face block mesh   
}

# -------------------------

proc mesh_match_edges {} {
    global button_instructions

    while 1 {
    	set e1 [select_edge "Pick the source edge $button_instructions" 1 \
			new_format ]
    	if {$e1 == ""} return
    	set e2 [select_edge "Pick the destination edge $button_instructions" 1 \
			new_format ]
    	if {$e2 == ""} return
    	hex_command "match_edges [lindex $e1 0] [lindex $e1 1] \
		[lindex $e2 0] [lindex $e2 1]"
    }
}

# -------------------------

proc mesh_scale {} {
    set m "Enter factor by which to scale the edge mesh.\n(Please note that\
	this will increase the\ntotal mesh size by this value cubed.)"
    set sc [question_box .meshsize "Scale mesh size" $m 1]
    if {$sc == ""} return
    hex_command "scale_mesh_size $sc"
}

proc mesh_make_even {} {
	hex_command "make_mesh_even"
}
proc mesh_init_output {} {
    hex_command init_output_blocks
    global use_output_blocks
    if { $use_output_blocks == 1 } {
    	hex_update_display block edge
    }
}

# -------------------------

proc mesh_options {} {
    global mesh_option last_line dim_to_mesh
    
    hex_command projection_limit;     set mesh_option(proj_limit) $last_line
    hex_command multi_grid_level;     set mesh_option(grid_level) $last_line
    hex_command default_bunching_law; set mesh_option(bunch_law) \
	[mesh_law_names $last_line]
    hex_command floating_grid;	 set mesh_option(floating_grid) $last_line
    hex_command transfinite_degree; set mesh_option(transfinite_degree) $last_line
    hex_command reference_blocking; set mesh_option(reference_blocking) $last_line
    if { ! [ info exists mesh_option(project_bspline) ] } {
	set mesh_option(project_bspline) 0
    }
    hex_command unstruct_face_type; set mesh_option(unstruct_face_type) $last_line
	
    
    set d [form_init .mesh_opts "Meshing options" mesh]
    if {$d != ""} {
	set ln 0
	form_label $d.mgl "Multigrid level" "$ln 0"
	form_entry $d.mg mesh_option(grid_level) int "$ln 1"
	incr ln

	form_label $d.pll "Projection limit" "$ln 0"
	form_entry $d.pl mesh_option(proj_limit) float_var "$ln 1"
	incr ln

	form_label $d.bll "Default meshing law" "$ln 0"
	form_entry $d.bl mesh_option(bunch_law) string "$ln 1"
	futil_choicelist $d.bl string "mesh_law_names" "$ln 2"
	incr ln

	form_label $d.fll  "Floating grid" "$ln 0"
	form_checkbutton $d.fl "" mesh_option(floating_grid) \
			"$ln 1 -cols - "
	incr ln

	form_label $d.pbspl "Project to Bsplines" "$ln 0"
	form_checkbutton $d.pbsp "" mesh_option(project_bspline) \
			"$ln 1 -cols - "

	foreach i { { "vertices" 0 v } { "edges" 1 e } { "faces" 2 f } \
			{ blocks 3 b } } {
		incr ln
		set text [ lindex $i 0 ]
		set dim [ lindex $i 1 ]
		set nm [ lindex $i 2 ] 
		radiobutton $d.$nm -variable dim_to_mesh -value $dim \
			-command "mesh_up_to_date 1; change_projection" \
			-text "Mesh $text"
		blt_table $d $d.$nm $ln,0 \
			-columnspan 3 -anchor w -pady 0
	}

	incr ln
	form_label $d.tfdl "Transfinite degree" "$ln 0"
	form_radiobutton $d.linear Linear mesh_option(transfinite_degree) \
			 1 "$ln 1"
	form_radiobutton $d.quadratic Quadratic \
			mesh_option(transfinite_degree) 2 "$ln 2"

	incr ln
	form_label $d.refbl "Reference topology" "$ln 0"
	form_entry $d.refb mesh_option(reference_blocking) string "$ln 1"

	incr ln
	form_label $d.uftl "Unstruct face type:" "$ln 0"
	form_radiobutton $d.one_tri "One tri" \
		mesh_option(unstruct_face_type) "one_tri" "$ln 1"
	incr ln
	form_radiobutton $d.several_tris "Several tris" \
		mesh_option(unstruct_face_type) "several_tris" "$ln 1"
	incr ln
	form_radiobutton $d.all_tris "All tris" \
		mesh_option(unstruct_face_type) "all_tris" "$ln 1"
	incr ln
	form_radiobutton $d.all_quads "All quads" \
		mesh_option(unstruct_face_type) "all_quads" "$ln 1"
	incr ln
	form_radiobutton $d.stl "Stl" \
		mesh_option(unstruct_face_type) "stl" "$ln 1"

	form_finish bot
    }
    
    if ![form_wait .mesh_opts] return
    
    hex_command "default_bunching_law [mesh_law_names $mesh_option(bunch_law)]"
    hex_command "projection_limit $mesh_option(proj_limit)"
    hex_command "multi_grid_level $mesh_option(grid_level)"
    hex_command "transfinite_degree $mesh_option(transfinite_degree)"
    if { $mesh_option(floating_grid) } {
	hex_command "floating_grid on"
    } else {
	hex_command "floating_grid off"
    }
    hex_command "reference_blocking $mesh_option(reference_blocking)"
    hex_command "unstruct_face_type $mesh_option(unstruct_face_type)"
}
