
# Stuff to run the mesher.  This does not include any of the code that
# handles the mesh after it has been loaded, or the mesher form.
#
# Copyright (c) 1993, 1994 Pacific Marketing and Consulting
# Author:  Wayne A. Christopher, wayne@pmac.com
#          Pacific Marketing and Consulting, Berkeley, California
#
# Subgrid spacing works like this.
# grid_subgrid_info(name,xxx) xxx is: parent imin jmin kmin imax kmax kmax
# 					      iref jref kref

proc grid_set_type_global {} {
    global grid_type

    set grid_type global
    return 0
}

proc edit_grid_global {d} {
    global global_only_uniform unit_default
    
    #grid_edit_unit_form $d.units {2 0 -cols -}
    
    if ![info exists global_only_uniform] {
	form_radiobutton $d.unif "Uniform spacing" grid_gtype unif \
	    {9 0 -cols 2}
    }
    
    set act {{grid_gtype unif}}
    form_label $d.xcl "    X count" {10 0} $act
    form_label $d.ycl "    Y count" {11 0} $act
    form_label $d.zcl "    Z count" {12 0} $act	
    form_entry $d.x grid_gcount_i int {10 1} $act
    form_entry $d.y grid_gcount_j int {11 1} $act
    form_entry $d.z grid_gcount_k int {12 1} $act
	
    form_checkbutton $d.sg "Subgrids" grid_subgrids {13 0} \
	    {{grid_gtype unif}}
    form_button $d.esg " Edit " grid_edit_global_subgrids {13 1} \
	    {grid_subgrids {grid_gtype unif}}
    
    if ![info exists global_only_uniform] {
	if 0 {
	    form_radiobutton $d.ratios "Equi-ratio" grid_gtype ratio \
		{21 0}
	    set act {{grid_gtype ratio}}
	    form_label $d.xrlab "    X" {22 0} $act
	    form_label $d.yrlab "    Y" {23 0} $act
	    form_label $d.zrlab "    Z" {24 0} $act
	    form_label $d.ratioil "  Initial" {21 1} $act
	    form_label $d.ratiorl "  Ratio" {21 2} $act
	    form_label $d.ratiopl "  Side" {21 3 -cols 2} $act
	    foreach {i r} {i 22 j 23 k 24} {
		form_entry $d.ratioi$i grid_gratio(${i}_init) float "$r 1" $act
		form_entry $d.ratior$i grid_gratio(${i}_rat) float "$r 2" $act
		form_radiobutton $d.ratiol$i Lo grid_gratio(${i}_dir) 0 "$r 3" $act
		form_radiobutton $d.ratioh$i Hi grid_gratio(${i}_dir) 1 "$r 4" $act
	    }
	}
	
	# ----------------------------------------------------------------

	form_radiobutton $d.key "Using objects" grid_gtype key \
	    {30 0 -cols 2}
	
	set act {{grid_gtype key}}
	form_label $d.mxcl "    X max" {31 0} $act
	form_label $d.mycl "    Y max" {32 0} $act
	form_label $d.mzcl "    Z max" {33 0} $act	
	form_entry $d.mx grid_gmax_i int {31 1} $act
	form_entry $d.my grid_gmax_j int {32 1} $act
	form_entry $d.mz grid_gmax_k int {33 1} $act
	form_label $d.nxcl "    X min" {31 2} $act
	form_label $d.nycl "    Y min" {32 2} $act
	form_label $d.nzcl "    Z min" {33 2} $act	
	form_entry $d.nx grid_gmin_i int {31 3} $act
	form_entry $d.ny grid_gmin_j int {32 3} $act
	form_entry $d.nz grid_gmin_k int {33 3} $act
	
	form_checkbutton $d.hg "Enable H-grid" grid_hgrid {39 0} $act
	form_checkbutton $d.min "Minimal mesh" grid_minglobal {39 1 -cols 3} $act
	#form_checkbutton $d.po "Per-object" grid_perobject {40 0} $act
	#form_button $d.epo " Edit " grid_edit_perobject_params {40 1} {grid_perobject {grid_gtype key}}
	form_checkbutton $d.rr "Ratio regions" grid_ratios {41 0} $act
	form_button $d.rro " Edit " grid_edit_global_ratios {41 1} \
	    {grid_ratios {grid_gtype key}}
    }
}

proc grid_runonce_global {gfile mfile efile pfile mapfile do_part suff inc_others} {
    global global_path grid_current_prefix grid_subgrids grid_subgrid_info
    global no_exit_job no_run_mesher tetin_do_offset_scale
    
    set grid_current_prefix ""
    
    if ![file executable $global_path] {
	mess "Error: the global binary could not be found!\n" red
	mess "Path = $global_path\n"
	return 0
    }
    
    set no_exit_job mesher
    
    set tetin_do_offset_scale [tetin_compute_offset_scale]
    
    # First make sure that the tetra sizes will be the same as the lengths.
    foreach obj [grid_get_object_list 0 "" 0 0] {
	foreach sh [db_shapes $obj] {
	    set min ""
	    foreach i [$sh get -grid_length] {
		if {($min == "") || ($i < $min)} {
		    set min $i
		}
	    }
	    $sh configure -grid_height "$min $min $min $min $min $min" \
		-grid_ratio "2 2 2 2 2 2"
	}
    }
    
    mess "Writing [directory]/tetin_auto ...\n"
    write_tetin_file [directory]/tetin_auto 0
    
    grid_write_mapping $mapfile ""

    if [info exists no_run_mesher] {
	mess "Not running mesher\n" red
	return 0
    }
    
    set mapfile [directory]/subgrid_map
    cmd_rm $mapfile
    
    mess "Running mesher...\n"
    
    set suffixes main
    if ![grid_run_global_region main $mfile.main] {
	unset no_exit_job
	return 0
    }
    if $grid_subgrids {
	foreach s [list_subgrids] {
	    lappend suffixes $s
	    
	    if ![grid_run_global_region $s $mfile.$s] {
		unset no_exit_job
		return 0
	    }
	}
    }
    
    global_merge_files $mfile $suffixes $mapfile
    
    tetin_free_cutouts_for_solid
    
    unset no_exit_job
    
    return 1
}

proc grid_run_global_region {rname mfile} {
    global global_path whoami grid_mapping job_scratch
    global grid_objects_highlighted domain
    global model_attachment
    global grid_usegraphics grid_editinput type_name
    global grid_current_prefix grid_line_list grid_run_smoother
    global grid_dont_remove_temp tetin_volume_fams tetin_surface_fams
    global grid_cad_objects_found warn_need_full_mesher_license grid_hgrid
    global famboco_family_number
    
    set cart cart_file.$rname
    
    mess "Writing [directory]/$cart for $rname region ...\n"
    if ![write_cart_file [directory]/$cart $rname \
	     [directory]/subgrid_map $mfile] {
		 mess "Meshing cancelled.\n" red
		 return 0
	     }
    mess "Done.\n"
    
    cmd_rm $mfile
    if [file exists $mfile] {
	user_error "Can't remove the file $mfile before running mesher --\
               please check the permissions on the directory [directory mesh]"
	return
    }
    set tetin_file [directory]/tetin_auto
    if {$rname != "main"} { append tetin_file .$rname }
    
    set mf [file tail $mfile]
    
    set vols "$tetin_volume_fams $tetin_surface_fams"
    
    foreach n {1 2} {
	set fp [open [directory]/global_in$n w]
	if $grid_hgrid {
	    set nums ""
	    foreach v $tetin_volume_fams {
		lappend nums $famboco_family_number($v)
	    }
	    puts $fp "write_hgrid ./$mf $nums"
	} else {
	    puts $fp "flood_fill_staircase -assignmat -shrinkwrap -autofix -fixvolid"
	    if {$n == 1} { set zz 0 } else { set zz "" }
	    #puts $fp "write_unstruct ./$mf $zz $vols"
	    puts $fp "write_unstruct ./$mf"
	}
	puts $fp "exit"
	close $fp
    }
    
    # -pushmat -no_vol_disamb
    set cmd1 [list $global_path -sheetmetal -vface]
    if {$grid_cad_objects_found || [info exists no_basic_licenses]} {
	if ![info exists warn_need_full_mesher_license] {
	    mess "Note that since you have CAD objects you must have a \"global\" license and not a \"global_a\" license.\n"
	    set warn_need_full_mesher_license 1
	}
    } else {
	#lappend cmd1 -basic
    }
    lappend cmd1 -i $cart
    
    # set retval [run_background $cmd [directory tetin] 1]
    set ignore_messages [list "*material point*on boundary*" \
			     "*defining_triangle called on non-boundary*" \
			     "*node not written in write_unstruct*" \
			     "*face between vols*"]
    
    for {set iters 0} {$iters < 20} {incr iters} {
	cmd_rm [directory]/$mf
	set cmdx $cmd1
	lappend cmdx < global_in1
	run_background $cmdx [directory] 1 "" $ignore_messages
	if ![file exists [directory]/$mf] {
	    return 0
	}
	
	# This works in one step now
	break
	
	set nps [grid_check_for_junk $mfile]
	if {$nps == ""} {
	    mess "No unassigned elements found.\n"
	    break
	}
	#cmd_cp $tetin_file $tetin_file.iter$iters
	#cmd_cp $mfile $mfile.iter$iters
	if ![add_matpoints_to_tetin $tetin_file $nps] {
	    break
	}
    }
    if {$iters == 20} {
	mess "Error: too many iterations of adding material points\n"
	return 0
    }
    
    # NOTE: the following comment is not currently true ...
    # For global we always write out 0 elements and filter them out later
    # so it doesn't matter.
    
    if 0 {
	cmd_rm [directory]/$mf
	set cmdx $cmd1
	lappend cmdx < global_in2
	run_background $cmdx [directory] 1 "" $ignore_messages
	if ![file exists [directory]/$mf] {
	    return 0
	}
    }
    
    return 1
}

proc global_merge_files {mfile suffixes mapfile} {
    #puts "global_merge_files $mfile \"$suffixes\" $mapfile"
    if {[llength $suffixes] == 1} {
	cmd_cp $mfile.[lindex $suffixes 0] $mfile
    } else {
	set fp [open $mapfile r]
	set main [lrange [gets $fp] 1 end]
	while {![eof $fp]} {
	    set line [gets $fp]
	    if {[lindex $line 0] != "sub"} continue
	    lappend depends([lindex $line 2]) [lrange $line 1 end]
	}
	close $fp
	set order [concat [list [lindex $main 0] -1 1 1 1] [lrange $main 1 3] \
		       [list 1 1 1]]
	set f_order([lindex $main 0]) 0
	
	set nd 1
	set queue [lindex $main 0]
	while {$queue != ""} {
	    set branch [lindex $queue 0]
	    set queue [lrange $queue 1 end]
	    if [info exists depends($branch)] {
		foreach dep $depends($branch) {
		    set dd [concat [list [lindex $dep 0] \
					$f_order([lindex $dep 1])] \
				[lrange $dep 2 end]]
		    set order [concat $order $dd]
		    lappend queue [lindex $dep 0]
		    set f_order([lindex $dd 0]) $nd
		    incr nd
		}
	    }
	}
	set cwd [pwd]
	cd [file dirname $mfile]
	#puts "merge_subgrids [file tail $mfile] $order"
	eval merge_subgrids [file tail $mfile] $order
	cd $cwd
    }
}

proc merge_domain_files {args} { puts $args }

proc objrange_cmp {r1 r2} {
    set start1 [lindex $r1 11]
    set start2 [lindex $r2 11]
    if {$start1 < $start2} {
	return 1
    } elseif {$start1 > $start2} {
	return -1
    } else {
	return 0
    }
}

proc write_cart_file {file rname mapfile mfile} {
    global grid_gtype grid_gmax_i grid_gmax_j grid_gmax_k
    global grid_gmin_i grid_gmin_j grid_gmin_k
    global model_container 
    global grid_perobject min_global_space domain
    global grid_subgrid_info grid_gratio grid_ratios grid_ratio_info
    global tetin_do_offset_scale tetin_scale_used
    
    set minpt ""; set maxpt ""
    
    set fp [open $file w]
    puts $fp "set_grid_type cartesian"
    
    set warn_maxt 10000000
    
    set totalnodes 1
    
    foreach dir {0 1 2} {
	set ijk [lindex {i j k} $dir]
	set stats [global_stations $rname $dir 1 1]
	set ns [llength $stats]
	
	set min_global_space($ijk) 0
	set prevpt ""
	set firstpt ""
	
	puts $fp "define_grid $ijk $ns"
	foreach pt $stats {
	    puts $fp $pt
	    
	    if {$firstpt == ""} { set firstpt $pt }
	    if {$prevpt != ""} {
		set diff [format %g [expr $pt - $prevpt]]
		if {$diff && (!$min_global_space($ijk) || \
				  ($min_global_space($ijk) > $diff))} {
		    set min_global_space($ijk) $diff
		    #puts "$pt - $prevpt"
		}
	    }
	    set prevpt $pt
	}
	lappend minpt $firstpt
	lappend maxpt $prevpt
	set min_global_space($ijk) [expr $min_global_space($ijk) \
					/ $tetin_scale_used]
	set numnodes($ijk) [llength $stats]
	set totalnodes [expr ($totalnodes + 0.0) * $numnodes($ijk)]
    }
    
    if {$grid_gtype == "unif"} {
	global_spacing $rname count start end incr p_min p_max p_ref \
		$tetin_do_offset_scale
	set mfp [open $mapfile a]
	if {$rname == "main"} {
	    puts $mfp "main [file tail $mfile] \
			$count(0) $count(1) $count(2)"
	} else {
	    set par $grid_subgrid_info($rname,parent)
	    puts $mfp "sub [file tail $mfile] grid_output.$par \
				$p_min(0) $p_min(1) $p_min(2) \
				$p_max(0) $p_max(1) $p_max(2) \
				$p_ref(0) $p_ref(1) $p_ref(2)"
	}
	close $mfp
	#puts "write to $mapfile"
    }
    
    
    puts $fp "boundary_family 0 0 0 0 0 0"
    if {$rname == "main"} {
	puts $fp "include tetin_auto"
    } else {
	puts $fp "include tetin_auto.$rname"
    }
    puts $fp "return"
    close $fp
    
    if {$totalnodes > $warn_maxt} {
 	set mess "Warning: there will be $totalnodes total nodes in\
 		section $rname of the mesh.  Continue?"
 	if [tk_dialog .too_many_n "Too many nodes" $mess \
 		"" -1 Okay Cancel] { return 0 }
    } else {
	mess "Section $rname: expect $numnodes(i) x $numnodes(j) x $numnodes(k) = [expr int($totalnodes)] nodes\n"
    }
    
    if {$rname != "main"} {
	# We need to write a separate tetin file for each subregion because
	# we can't have multiple material points at infinity - they 
	# confuse global.
	mess "Writing [directory]/tetin_auto.$rname ...\n"
	write_tetin_file [directory]/tetin_auto.$rname 0 [concat $minpt $maxpt]
    }
    return 1
}

proc global_stations {rname dir ask trans} {
    global tdv_default
    global grid_gtype grid_gmax_i grid_gmax_j grid_gmax_k
    global grid_gmin_i grid_gmin_j grid_gmin_k
    global model_container 
    global grid_perobject min_global_space domain
    global grid_subgrid_info grid_gratio grid_ratios grid_ratio_info
    global tetin_do_offset_scale grid_hgrid grid_minglobal grid_global_maxrat
    global app_name meshing_units
    
    if {($app_name == "icepak") || ($app_name == "airpak") } {
	set grid_global_maxrat 4.0
    }
    
    if $trans {
	set offs $tetin_do_offset_scale
    } else {
	set offs "1 0 0 0   0 1 0 0   0 0 1 0   0 0 0 1"
    }
    
    set minpt ""; set maxpt ""
    
    set ttol [grid_get_ttol]
    
    set warn_max1 10000
    
    set maxr $grid_global_maxrat
	
    set stats ""
    switch $grid_gtype {
	unif {
	    global_spacing $rname count start end incr p_min p_max p_ref \
		$offs
	    
	    set diri [lindex {i j k} $dir]
	    
	    for {set n 0} {$n < $count($diri) - 1} {incr n} {
		lappend stats [expr $start($diri) + $incr($diri) * $n]
	    }
	    lappend stats [expr $end($diri)]
	}
	key {
	    if {$rname != "main"} { error "nonunif subgrids don't work yet" }
	    
	    global_spacing $rname count start end incr p_min p_max p_ref ""
	    
	    # We should use the cart_file object more extensively but for
	    # now just use it to compute ranges, etc.
	    set cartf [cart_file -trans_matrix $offs]
	    
	    set shapes ""
	    foreach ss [[$model_container getval body_shape] list] {
		if [$ss get -active] { lappend shapes $ss }
	    }
	    set un $meshing_units
	    set ijk [lindex {i j k} $dir]
	    set xyz [lindex {X Y Z} $dir]
	    set maxh [unit_convert [set grid_gmax_$ijk] $un 0]
	    set minh [unit_convert [set grid_gmin_$ijk] $un 0]
	    
	    if {$maxh == 0} {
		# Just make it be the full size of the cabinet
		set bb [$tdv_default bbox interesting]
		if {$bb != ""} {
		    set maxh [expr {[lindex [lindex $bb 1] $dir] - \
					[lindex [lindex $bb 0] $dir]}]
		    set umaxh [unit_convert $maxh $un 1]
		    mess "Maximum size in the $xyz direction set to $umaxh $un\n"
		}
	    }
	    
	    set ranges ""
	    
	    if $grid_ratios {
		foreach r [list_ratios] {
		    foreach v {dir count type startr endr} {
			set r_$v $grid_ratio_info($r,$v)
		    }
		    if {$dir != $r_dir} continue
		    foreach v {start end starth endh} {
			set r_$v [unit_convert $grid_ratio_info($r,$v) \
				      $un 0]
		    }
		    
		    lappend ranges [list $r_start $r_end $r_type $r_count \
					$r_starth $r_startr \
					$r_endh $r_endr 0 $maxh 1]
		}
	    }
	    set round_i [expr {$ranges == ""}]
	    
	    set objranges ""
	    foreach sh $shapes {
		if {[$sh get -object] == $domain} continue
		
		if $grid_minglobal {
		    set ucount 0
		} else {
		    switch [$sh get -shtype] {
			cyl - circ { set ucount -4 }
			incline - polygon { set ucount -5 }
			default { set ucount 0 }
		    }
		}
		
		if $round_i {
		    set sbb [$sh get_bbox]
		    set smin [lindex [lindex $sbb 0] $dir]
		    set smax [lindex [lindex $sbb 1] $dir]
		    set mm [lindex [$sh get -grid_length] $dir]
		    if {($mm == "") || $grid_hgrid} { set mm 0 }
		    lappend objranges [list $smin $smax uniform $ucount \
					   0 0 0 0 3 $mm 1]
		    #puts "$smin $smax uniform $ucount 0 0 0 0 3 $mm 1"
		} else {
		    set po $grid_perobject
		    if $grid_hgrid { set po 0 }
		    set keypts [get_key_points $sh $dir $maxh $minh $po]
		    lappend objranges [concat [list 0 0 explicit \
						   [llength $keypts] \
						   0 0 0 0 2 0 1] $keypts]
		}
	    }
	    set ranges [concat $ranges [lsort -command objrange_cmp \
					    $objranges]]
	    
	    lappend ranges [list $start($dir) $end($dir) uniform 0 \
				0 0 0 0 3 $maxh 1]
	    
	    #puts "ranges $ranges"
	    $cartf set_ranges $dir $ranges
	    
	    set maxs [$cartf count_stations $dir]
	    if {$ask && ($maxs > $warn_max1)} {
		set mess "Warning: in the $xyz direction there might\
 			be up to $maxs stations.  Continue?"
		if [tk_dialog .too_many_st "Too many stations" $mess \
			"" -1 Okay Cancel] { return 0 }
	    }
	    
	    # If we only have minsize intervals then we can even
	    # out the ranges and round up or down as necessary.
	    if $round_i {
		$cartf compute_rounded_intervals $dir $minh $maxr
	    } else {
		$cartf compute $dir ""
	    }
	    
	    if {$minh > 0} {
		# If we did round_intervals this probably won't come up...
		set nf [$cartf filter_small_steps $dir $minh \
			    [expr $maxh * 1.1]]
		if {[lindex $nf 0] || [lindex $nf 1]} {
		    mess "In the $xyz direction, filtered out\
				[lindex $nf 0] stations and moved\
				[lindex $nf 1] stations to eliminate small\
				gaps (leaving [lindex $nf 2])\n"
		}
	    }
	    
	    set stats [$cartf list_stations $dir]
	    $cartf delete
	}
    }
    return $stats
}

proc global_loc_to_index {sub loc dir} {
    set stations [global_stations $sub $dir 0 0]
    set prev [lindex $stations 0]
    set i 1
    foreach stat [lrange $stations 1 end] {
	# puts "loc $loc stat $stat prev $prev"
	if {($loc >= $prev) && ($loc <= $stat)} { return $i }
	incr i
	set prev $stat
    }
    return -1
}

proc global_spacing {rname count_var start_var end_var incr_var
		     {pmin_var ""} {pmax_var ""} {pref_var ""} {tmat ""}} {
    global grid_gcount_i grid_gcount_j grid_gcount_k domain
    global grid_subgrids grid_subgrid_info meshing_units
    
    set un $meshing_units

    if {$rname == "main"} {
	set sh [$domain getval body_shape]
	set bb [$sh get_bbox]
	set bmin [lindex $bb 0]
	set bmax [lindex $bb 1]
	if {$tmat != ""} {
	    set bmin [tetin_matrix_trans_point $bmin]
	    set bmax [tetin_matrix_trans_point $bmax]
	}
	#puts "rname $rname bmin $bmin bmax $bmax tmat $tmat"
	foreach i {0 1 2} {
	    set ijk [lindex {i j k} $i]
	    set count($ijk) [set grid_gcount_$ijk]
	    set start($ijk) [lindex $bmin $i]
	    set end($ijk)   [lindex $bmax $i]
	}
	
    } else {
	#puts "tmat is $tmat"
	global_spacing $grid_subgrid_info($rname,parent) \
	    p_count p_start p_end p_incr "" "" "" $tmat
	
	set xminpt ""; set xmaxpt ""
	foreach i {0 1 2} {
	    set ijk [lindex {i j k} $i]
	    lappend xminpt [unit_convert $grid_subgrid_info($rname,${ijk}min) \
				$un 0]
	    lappend xmaxpt [unit_convert $grid_subgrid_info($rname,${ijk}max) \
				$un 0]
	}
	#puts "$xminpt $xmaxpt"
	set xminpt [tetin_matrix_trans_point $xminpt]
	set xmaxpt [tetin_matrix_trans_point $xmaxpt]
	#puts "$xminpt $xmaxpt"
	#parray p_start
	#parray p_end
	#parray p_incr
	
	foreach i {0 1 2} {
	    set xmin [lindex $xminpt $i]
	    set xmax [lindex $xmaxpt $i]
	    set ijk [lindex {i j k} $i]
	    set xref $grid_subgrid_info($rname,${ijk}ref)
	    set pmin [expr int(($xmin - $p_start($i)) / ($p_incr($i) + 0.0))]
	    set pmax [expr int(($xmax - $p_start($i) + $p_incr($i) / 100.0) / \
				   ($p_incr($i) + 0.0))]
	    
	    if {$pmin < 0} { set pmin 0 }
	    if {$pmax < 0} { set pmax 0 }
	    if {$pmin >= $p_count($i)} { set pmin [expr $p_count($i) - 1] }
	    if {$pmax >= $p_count($i)} { set pmax [expr $p_count($i) - 1] }
	    if {$pmin >= $pmax} { error "pmin and pmax are bad: $pmin $pmax" }
	    
	    set count($ijk) [expr ($pmax - $pmin) * $xref + 1]
	    set start($ijk) [expr $p_start($i) + $p_incr($i) * $pmin]
	    set end($ijk)   [expr $p_start($i) + $p_incr($i) * $pmax]
	    
	    incr pmin; incr pmax
	    if {$pmin_var != ""} { uplevel 1 set ${pmin_var}($i) $pmin }
	    if {$pmax_var != ""} { uplevel 1 set ${pmax_var}($i) $pmax }
	    if {$pref_var != ""} { uplevel 1 set ${pref_var}($i) $xref }
	}
    }
    
    foreach i {0 1 2} {
	set ijk [lindex {i j k} $i]
	if {$count($ijk) < 2} {
	    user_error "Grid count must be more than 1"
	    return
	}
	set incr($ijk)  [expr {($end($ijk) - $start($ijk)) / \
				   ($count($ijk) - 1.0)}]
	
	uplevel 1 set ${count_var}($ijk) $count($ijk)
	uplevel 1 set ${start_var}($ijk) $start($ijk)
	uplevel 1 set ${end_var}($ijk) $end($ijk)
	uplevel 1 set ${incr_var}($ijk) $incr($ijk)
	
	uplevel 1 set ${count_var}($i) $count($ijk)
	uplevel 1 set ${start_var}($i) $start($ijk)
	uplevel 1 set ${end_var}($i) $end($ijk)
	uplevel 1 set ${incr_var}($i) $incr($ijk)
    }
}

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

proc grid_edit_global_perobject {} {
    global edit_params_active edit_params_used
    global object_type_list object_type_title form_done_flag botform_geo
    global grid_perobject_buttons
    
    set buts [list done cancel \
		  [list "Enable all" "grid_set_all_enabled 1"] \
		  [list "Disable all" "grid_set_all_enabled 0"]]
    
    catch {unset edit_params_active}
    catch {unset edit_params_used}
    catch {unset grid_perobject_buttons}
    
    form_kill .grid_global_perobject
    set d [form_init .grid_global_perobject "Per-object global sizes" \
	       "mesh sub" $buts]
    if {$d == ""} return
    
    set fr [form_scroller $d.scr 400 {0 0}]
    
    set row 1
    foreach type $object_type_list {
	switch $type { property - part continue }
	
	set objects ""
	foreach obj [db_list_objects $type] {
	    if [$obj si_value active] { lappend objects $obj }
	}
	if {$objects == ""} continue
	
	form_label $fr.l$row "$object_type_title($type):" \
	    "$row 0 -cols -"
	incr row
	
	foreach obj $objects {
	    if {$type == "domain"} {
		set obname ""
	    } else {
		set obname [$obj getval name]
	    }
	    set sects [$obj getval section_list]
	    switch [llength $sects] {
		0 continue
		1 {
		    set sh [$obj getval ${sects}_shape]
		    if {[$sh get -shtype] == "none"} continue
		    set edit_params_active($sh) [$sh get -grid_enabled]
		    set edit_params_used($sh) [grid_any_params_used $sh]
		    form_checkbutton $fr.a$row $obname \
			edit_params_active($sh) "$row 3"
		    set grid_perobject_buttons($sh) $fr.a$row
		    form_button $fr.b$row Edit \
			"grid_global_perobject_one $obj $sh" \
			"$row 4" edit_params_active($sh)
		    form_label $fr.u$row "" "$row 5" edit_params_active($sh)
		    $fr.u$row configure -textvariable edit_params_used($sh)
		    incr row
		}
		default {
		    form_label $fr.l$row $obname "$row 1 -cols 2"
		    incr row
		    foreach ss $sects {
			set sh [$obj getval ${ss}_shape]
			if {[$sh get -shtype] == "none"} continue
			set edit_params_active($sh) [$sh get -grid_enabled]
			set edit_params_used($sh) [grid_any_params_used $sh]
			form_checkbutton $fr.a$row $ss \
			    edit_params_active($sh) "$row 3"
			set grid_perobject_buttons($sh) $fr.a$row
			form_button $fr.b$row Edit \
			    "grid_global_perobject_one $obj $sh" \
			    "$row 4" edit_params_active($sh)
			form_label $fr.u$row "" "$row 5" \
			    edit_params_active($sh)
			$fr.u$row configure -textvariable edit_params_used($sh)
			incr row
		    }
		}
	    }
	}
    }
    form_colwidth $fr 0 2 M
    form_colwidth $fr 1 2 M
    
    form_finish bot
    $d.scr configure -height [expr {[winfo reqheight $d.scr] + 1}]
    
    if ![form_wait .grid_global_perobject] return
    
    foreach sh [array names edit_params_active] {
	$sh configure -grid_enabled $edit_params_active($sh)
    }
}

proc grid_global_perobject_type {sh} {
    global domain edit_params_for use_grid_grading
    
    set obj [$sh get -object]
    
    set tt [lindex [split [$sh get -type] _] 1]
    set tp $tt
    switch $tt {
	quad    { append tt _[$sh getval plane] }
	incline {
	    append tt _[$sh getval axis]
	    if {[$sh si_value thickness] != 0} {
		append tt _thick
	    }
	}
	polygon {
	    set n [$sh getval nverts]
	    append tt _$n
	    if ![info exists edit_params_for(polygon_$n)] {
		set ll ""; set hh ""; set rr ""
		for {set i 0} {$i < $n} {incr i}  {
		    set i2 [expr {$i + 2}]
		    lappend ll [list "Side [expr $i + 1] count" length $i]
		    lappend hh [list "Side [expr $i + 1] height" height $i2]
		    lappend rr [list "Side [expr $i + 1] ratio" ratio $i2]
		}
		set edit_params_for(polygon_$n) \
		    [concat $ll [list [list "Height count" length $n]] {{}} \
			 [list [list "Bottom height" height 0] \
			      [list "Top height" height 1]] $hh {{}} \
			 [list [list "Bottom ratio" ratio 0] \
			      [list "Top ratio" ratio 1]] $rr]
		
		if $use_grid_grading {
		    lappend edit_params_for(polygon_$n) {} \
			[list "Grading height" height [expr $n + 2]] \
			[list "Grading ratio"  ratio  [expr $n + 2]]
		}
	    }
	}
    }
    if {$obj == $domain} { append tt _domain }
    if {[$obj getval obtype] == "wall"} {
	append tt _oneside
    }
    return $tt
}

proc grid_global_perobject_one {obj sh} {
    global edit_params_used edit_params_for form_done_flag botform_geo
    global edit_param_val edit_param_actual edit_param_on domain
    global grid_copyto_mode use_grid_grading grid_copyto_mode meshing_units
    
    set tw .grid_global_params
    
    set u $meshing_units
    
    set buts [list \
		  [list Done {
		      global form_done_flag grid_copyto_mode
		      if [info exists grid_copyto_mode] {
			  grid_global_perobject_copyto
		      }
		      form_done .grid_global_params
		      set form_done_flag(.grid_global_params) 1
		  } ] \
		  [list Cancel {
		      global form_done_flag grid_copyto_mode
		      if [info exists grid_copyto_mode] {
			  grid_global_perobject_copyto
		      }
		      form_cancel .grid_global_params
		  } ] \
		  [list "Copy to" "grid_global_perobject_copyto"]]
    
    set d [form_init $tw "" "grid sub sub" $buts]
    if {$d == ""} return
    
    top_title $tw [$obj getval name]
    
    if {$d != ""} {
	form_label $d.top1 Requested {0 1}
	form_checkbutton $d.lx "X size" edit_param_on(x) {1 0}
	form_checkbutton $d.ly "Y size" edit_param_on(y) {2 0}
	form_checkbutton $d.lz "Z size" edit_param_on(z) {3 0}
	form_entry $d.ex edit_param_val(x) float {1 1} edit_param_on(x)
	form_entry $d.ey edit_param_val(y) float {2 1} edit_param_on(y)
	form_entry $d.ez edit_param_val(z) float {3 1} edit_param_on(z)
    }
    set rvals [$sh get -grid_length]
    set edit_param_val(x) [unit_convert [lindex $rvals 0] $u 1]
    set edit_param_val(y) [unit_convert [lindex $rvals 1] $u 1]
    set edit_param_val(z) [unit_convert [lindex $rvals 2] $u 1]
    foreach i {x y z} {
	set edit_param_on($i) [expr {($edit_param_val($i) != "") && \
					 ($edit_param_val($i) != 0)}]
    }
    if {$d != ""} { form_finish $botform_geo }
    
    tkwait variable form_done_flag($tw)
    if !$form_done_flag($tw) return
    
    grid_global_perobject_toshape $sh
}

proc grid_global_perobject_toshape {sh} {
    global edit_param_val edit_param_on edit_params_active meshing_units
    
    set u $meshing_units
    
    set len ""
    foreach i {x y z} {
	if $edit_param_on($i) {
	    if {$edit_param_val($i) == ""} {
		lappend len 0
	    } else {
		lappend len [unit_convert $edit_param_val($i) $u 0]
	    }
	} else {
	    lappend len 0
	}
    }
    set edit_params_active($sh) 1
    $sh configure -grid_length $len
}

proc grid_global_perobject_toshape_region {p1 p2} {
    global grid_perobject_buttons
    
    set others [select_shapes_by_screen_region $p1 $p2 0]
    
    foreach osh $others {
	if [info exists grid_perobject_buttons($osh)] {
	    mess "Copied to \"[[$osh get -object] getval name]\"\n"
	    grid_global_perobject_toshape $osh
	}
    }
}

proc grid_global_perobject_copyto {} {
    global tdv_default
    global grid_copyto_mode grid_perobject_buttons
    
    if [info exists grid_copyto_mode] {
	mess "Finished \"Copy to\".\n"
	unset grid_copyto_mode
	foreach sh [array names grid_perobject_buttons] {
	    grid_global_perobject_chbut $sh $grid_perobject_buttons($sh) 0
	}
	tdv_multiple_rubbox $tdv_default ""
	return
    }
    set grid_copyto_mode 1
    
    mess "Click on the object names in the \"Per-object mesh parameters\"\
	window that you want to copy to, or select by region from the screen. \
	Click on the \"Copy to\" button again to finish.\n"
    foreach sh [array names grid_perobject_buttons] {
	grid_global_perobject_chbut $sh $grid_perobject_buttons($sh) 1
    }
    tdv_multiple_rubbox $tdv_default "grid_global_perobject_toshape_region"
}

proc grid_global_perobject_chbut {sh but on} {
    if $on {
	$but configure -relief ridge -foreground \#88ff88
	bind $but <1> "grid_global_perobject_copy_toshape $sh; break"
    } else {
	$but configure -relief flat -foreground black
	bind $but <1> ""
    }
}

proc grid_global_perobject_copy_toshape {sh} {
    mess "Copied to \"[[$sh get -object] getval name]\"\n"
    grid_global_perobject_toshape $sh
}

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

proc list_ratios {} {
    global grid_ratio_info
    
    set ret ""
    foreach rn [lsort [array names grid_ratio_info]] {
	set r [split $rn ,]
	if {[lindex $r 1] == "dir"} { lappend ret [lindex $r 0] }
    }
    return [lsort -integer $ret]
}

proc grid_edit_global_ratios {} {
    global grid_ratio_info ratio_edit_info
    
    form_kill .ratios
    
    set d [form_init .ratios "Define ratios" "" done]
    if {$d == ""} return
    
    form_label $d.dirl "Dir"        {0 0 -cols 2}
    form_label $d.startl "Start"    {0 3 -cols 2}
    form_label $d.endl "End"        {0 6 -cols 2}
    form_label $d.typel "Type"      {0 9 -cols 2}
    form_label $d.starthl "Start H" {0 12 -cols 2}
    form_label $d.startrl "Start R" {0 15 -cols 2}
    form_label $d.endhl "End H"     {0 21 -cols 2}
    form_label $d.endrl "End R"     {0 24 -cols 2}
    form_label $d.countl "Count"    {0 27 -cols 2}
    form_label $d.dell "Delete"     {0 30 -cols 2}
    
    foreach i {0 3 6 9 12 15 21 24 27 30} {
	form_underline $d.ul$i "1 $i -cols 2"
    }
    
    form_button $d.new New ratio_newline {1000 0 -fill none}
    
    set ratio_edit_info(frame) $d
    set ratio_edit_info(count) 0

    foreach s [list_ratios] { ratio_addline $s }
    
    form_finish bot
    
}

proc ratio_newline {} {
    global ratio_edit_info grid_ratio_info
    
    set name $ratio_edit_info(count)
    foreach {p v} {
	dir 0 start 0 end 1 count 10
	type geo_start startr 2 starth 1 endr 2 endh 1
    } {
	set grid_ratio_info($name,$p) $v
    }
    ratio_addline $name
}

proc ratio_addline {name} {
    global ratio_edit_info grid_ratio_info
    
    set num $ratio_edit_info(count)
    incr ratio_edit_info(count)
    set nr [expr $num + 10]
    set d $ratio_edit_info(frame)
    
    form_frame $d.dir$num flat 0 "$nr 0"
    form_radiobutton $d.dir$num.x X grid_ratio_info($name,dir) 0 {0 0}
    form_radiobutton $d.dir$num.y Y grid_ratio_info($name,dir) 1 {0 1}
    form_radiobutton $d.dir$num.z Z grid_ratio_info($name,dir) 2 {0 2}

    form_entry $d.start$num grid_ratio_info($name,start) float "$nr 3"
    form_entry $d.end$num grid_ratio_info($name,end) float "$nr 6"
    
    form_frame $d.type$num flat 0 "$nr 9"
    form_radiobutton $d.type$num.s Start grid_ratio_info($name,type) \
	geo_start {0 0}
    form_radiobutton $d.type$num.e End grid_ratio_info($name,type) \
	geo_end {0 1}
    form_radiobutton $d.type$num.u Unif grid_ratio_info($name,type) \
	uniform {0 2}
    
    form_entry $d.starth$num grid_ratio_info($name,starth) float "$nr 12" \
	[list [list grid_ratio_info($name,type) geo_start]]
    form_entry $d.startr$num grid_ratio_info($name,startr) float "$nr 15" \
	[list [list grid_ratio_info($name,type) geo_start]]
    
    form_entry $d.endh$num grid_ratio_info($name,endh) float "$nr 21" \
	[list [list grid_ratio_info($name,type) geo_end]]
    form_entry $d.endr$num grid_ratio_info($name,endr) float "$nr 24" \
	[list [list grid_ratio_info($name,type) geo_end]]
    
    form_entry $d.count$num grid_ratio_info($name,count) float_blank "$nr 27" \
        [list [list grid_ratio_info($name,type) uniform]]
    
    form_button $d.del$num Delete "ratio_delete $d $num $name" "$nr 30"
}

proc ratio_delete {d num name} {
    global grid_ratio_info
    
    foreach w {dir start end type starth startr endh endr count del} {
	destroy $d.$w$num
	catch {unset grid_ratio_info($name,$w)}
    }
}

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

proc list_subgrids {} {
    global grid_subgrid_info
    
    set ret ""
    foreach rn [array names grid_subgrid_info] {
	set r [split $rn ,]
	if {[lindex $r 1] == "parent"} { lappend ret [lindex $r 0] }
    }
    return [lsort $ret]
}

proc grid_edit_global_subgrids {} {
    global subgrid_edit_info
    
    form_kill .subgrids
    
    set d [form_init .subgrids "Define subgrids" "" done]
    if {$d == ""} return
    
    form_label $d.namel "Name" {0 0 -cols 2}
    form_label $d.parentl "Parent" {0 3 -cols 2}
    form_label $d.xminl "Xmin" {0 6 -cols 2}
    form_label $d.yminl "Ymin" {0 9 -cols 2}
    form_label $d.zminl "Zmin" {0 12 -cols 2}
    form_label $d.xmaxl "Xmax" {0 15 -cols 2}
    form_label $d.ymaxl "Ymax" {0 18 -cols 2}
    form_label $d.zmaxl "Zmax" {0 21 -cols 2}
    form_label $d.xrefl "Xref" {0 24 -cols 2}
    form_label $d.yrefl "Yref" {0 27 -cols 2}
    form_label $d.zrefl "Zref" {0 30 -cols 2}
    form_label $d.dell "Delete" {0 33 -cols 2}
    foreach i {0 3 6 9 12 15 18 21 24 27 30 33} {
	form_underline $d.ul$i "1 $i -cols 2"
    }
    
    form_button $d.new New subgrid_newline {1000 0 -fill none}
    
    set subgrid_edit_info(frame) $d
    set subgrid_edit_info(count) 0

    foreach s [list_subgrids] { subgrid_addline $s }
    
    form_finish bot
    
}

proc subgrid_newline {} {
    global subgrid_edit_info grid_subgrid_info
    
    set num $subgrid_edit_info(count)
    set name reg$num
    set grid_subgrid_info($name,parent) main
    foreach p {imin jmin kmin imax jmax kmax} {
	set grid_subgrid_info($name,$p) 0
    }
    foreach p {iref jref kref} {
	set grid_subgrid_info($name,$p) 3
    }
    subgrid_addline $name
}

    
proc subgrid_addline {name} {
    global subgrid_edit_info grid_subgrid_info
    
    set num $subgrid_edit_info(count)
    incr subgrid_edit_info(count)
    set nr [expr $num + 10]
    set d $subgrid_edit_info(frame)
    
    form_label $d.name$num $name "$nr 0"
    
    form_entry $d.parent$num grid_subgrid_info($name,parent) string "$nr 3"
    
    form_entry $d.xmin$num grid_subgrid_info($name,imin) float "$nr 6"
    form_entry $d.ymin$num grid_subgrid_info($name,jmin) float "$nr 9"
    form_entry $d.zmin$num grid_subgrid_info($name,kmin) float "$nr 12"
    form_entry $d.xmax$num grid_subgrid_info($name,imax) float "$nr 15"
    form_entry $d.ymax$num grid_subgrid_info($name,jmax) float "$nr 18"
    form_entry $d.zmax$num grid_subgrid_info($name,kmax) float "$nr 21"
    form_entry $d.xref$num grid_subgrid_info($name,iref) int "$nr 24"
    form_entry $d.yref$num grid_subgrid_info($name,jref) int "$nr 27"
    form_entry $d.zref$num grid_subgrid_info($name,kref) int "$nr 30"
    form_button $d.del$num Delete "subgrid_delete $d $num $name" "$nr 33"
}

proc subgrid_delete {d num name} {
    global grid_subgrid_info
    
    foreach w {name parent imin jmin kmin imax jmax kmax iref jref kref del} {
	destroy $d.$w$num
	catch {unset grid_subgrid_info($name,$w)}
    }
}

