proc hex_update_display {args} {
    global display_flag project_type surface_detail use_output_blocks
    global display_linked_to dim_to_mesh
    global geom_visible batch_mode hex_option beta_mode
    global hexa_select hexa_selection_display fam_visible

    if $batch_mode return
    if ![ic_hex_blocking_loaded] return
   
    if {$args == ""} {
	    foreach w {curve vert edge face block mesh} {
	        hex_update_display $w
	    }
	    return
    }

    # check if the mesh needs to be re-computed
    set d_to_mesh 0
    foreach what $args {
	    switch $what {
	        mesh {
		        if $display_flag(mesh) {
			        set d_to_mesh [ max $d_to_mesh  2 ]
			        set d_to_mesh [ max $d_to_mesh $dim_to_mesh ]
		        }		    
		    }
		    edge -
            edge_vol -
            edge_proj -
            edge_counts -
            edge_bunch -
            edge_mset -
            edge_shape_source -
		    edge_simple -
            edge_nodes {
		        if { $display_flag(edge) && $display_flag(edge_nodes) } {
			        set d_to_mesh [ max $d_to_mesh 1 ]
			        set d_to_mesh [ max $d_to_mesh $dim_to_mesh ]
		        }
		    }
	    }
    }
    if {$d_to_mesh > 0} {
	    hex_mesh_up_to_date 1 0 $d_to_mesh
    }

    set fam ""
    foreach what $args {
	    switch $what {
	        curve { }
	        vertex -
	        vert -
	        vert_surf -
	        vert_periodic -
	        vert_pname -
	        vert_numbers -
	        vert_how - 
	        vert_ind {
		        set fam [family_activename_string]
		        if {!$display_flag(vert) || ($fam == "")} {
		            hex_command "display_nodes erase"
		        } else {
		            set cmd "display_nodes [range_string] $fam"
		            switch $display_flag(vert_how) {
			            proj { }
			            indices { append cmd " indices" }
			            number { append cmd " numbers" }
		            }
		            if $display_flag(vert_hidden)  { append cmd " small_nodes -not_blanked" }
		            if $display_flag(vert_surf)  { append cmd " surface" }
		            if $display_flag(vert_pname) { append cmd " point_names" }
		            if $display_flag(vert_periodic) { append cmd " periodic_twins" }
		            if $display_flag(use_blanking) { append cmd " -not_blanked" }
		            if $display_flag(edge_nodes) { append cmd " projected" }
		            if !$display_flag(edge_vol) { append cmd " surface" }
		            if $use_output_blocks { append cmd " output_blocks" }
                    if [aie_wb2_is_running] {
                        global aie_ShowParametrized
                        if {$aie_ShowParametrized(vertex) && $aie_ShowParametrized(vertex,entities) != ""} {
                            append cmd " number $aie_ShowParametrized(vertex,entities) parametrized"
                        }
                    }
                    hex_command $cmd
		        }
	        }
	        edge -
	        edge_vol -
	        edge_proj -
	        edge_bunch -
	        edge_mset -
	        edge_counts -
	        edge_shape_source -
	        edge_simple -
	        edge_nodes -
	        edge_shape {
		        set fam [volume_activename_string]
		        if {(!$display_flag(edge)) || ($fam == "")} {
		            hex_command "erase_edge_mesh"
		        } else {
		            set opts [ display_edge_mesh_params ]
		            set cmd "display_edge_mesh $opts"
                    if [aie_wb2_is_running] {
                        global aie_ShowParametrized
                        if {$aie_ShowParametrized(edge) && $aie_ShowParametrized(edge,entities) != ""} {
                            append cmd " highlight_wide $aie_ShowParametrized(edge,entities)"
                        }
                    }
                    hex_command $cmd
		        }
		        hex_command "select_value erase"
	        }
	        block -
	        block_solid -
	        block_super -
	        block_ijk -
	        block_classes -
	        block_refinement -
	        block_numbers -
	        block_worst {
		        set fam [volume_activename_string]
		        if {(!$display_flag(block)) || ($fam == "")} {
		            hex_command "display_elements erase"
		        } else {
		            set opts "[range_string]"
		            if {[volume_activename_string] != ""} {
			            append opts " m [volume_activename_string] "
		            }
		            if $use_output_blocks {
			            append opts " output_blocks"
		            }
		            set lopts ""
		            if $display_flag(block_classes) {
			            append lopts " equiv"
		            }
		            if $display_flag(block_refinement) {
			            append lopts " refinement"
		            }
		            if $display_flag(use_blanking) {
			            append lopts " -not_blanked"
		            }
		            if $display_flag(block_solid) {
			            append lopts " -solid"
		            }
		            if $display_flag(block_super) {
			            append lopts " super"
		            }
		            if $display_flag(block_ijk) {
			            append lopts " orientation"
		            }
		            if $display_flag(block_noshrink) {
			            append lopts " no_shrink"
		            }
		            if {!$display_flag(block_struct) } {
                        append lopts " -hide_struct"
                    }
                    if {!$display_flag(block_unstruct) } {
                        append lopts " -hide_unstruct"
                    }
                    if {!$display_flag(block_swept) } {
                        append lopts " -hide_swept"
                    }
		            hex_command "display_elements $opts $lopts"		    
		        }
		        if $display_flag(block_worst) {
		            if {[info exists hex_option(find_worst)] && $hex_option(find_worst) != "1"} {
                        aie_hex_find_worse
                    } else {
                        if $use_output_blocks {
                            set res [eval ic_hex_worst_hex output_blocks [volume_activename_string]]
                        } else {
		                    set res [eval ic_hex_worst_hex [volume_activename_string]]
		                }
		                mess "$res"
		            }
		        } else {
		            if {[info exists hex_option(find_worst)] && $hex_option(find_worst) != "1"} {
                        aie_hex_find_worse
                    } else {
		                hex_command "worst_hex erase"
		            }
		        }
	        }
	        mesh_mesh - 
	        mesh {
		        set fams [family_activename_string]
		        if {(!$display_flag(mesh)) || $fams == ""} {
		            hex_command "display_faces erase"
		            if [aie_hex_sketching_mode] {
		                aie_hex_sketch_display_faces 0
		            }
		        } else {
		            set cmd "display_faces proj $project_type $fams [range_string]"
		            if {$display_flag(mesh_mesh) == 2} {
			            append cmd " -solid"
		            }
		            if { $display_flag(use_blanking) } {
			            append cmd " -not_blanked"
		            }
		            hex_command $cmd
                    if [aie_hex_sketching_mode] {
		                aie_hex_sketch_display_faces 1
		            }
		        }
	        }
	        face -
	        face_periodic -
	        face_norm {
		        set fams [family_activename_string]
		        if {(!$display_flag(face)) || $fams == ""} {
		            hex_command "display_super_faces erase"
		        } else {
		            set cmd "display_super_faces [range_string] [family_activename_string]"
		            if {$what == "face_periodic"} {
		                if $display_flag(face_norm) {
		                    set display_flag(face_norm) 0
		                }
		            } elseif {$what == "face_norm"} {
		                if $display_flag(face_periodic) {
		                    set display_flag(face_periodic) 0
		                }
		            }
		            if $display_flag(face_periodic) {
			            append cmd " periodic"
		            }
		            if $display_flag(face_boundary) {
			            append cmd " boundary"
		            }
		            if $use_output_blocks {
			            append cmd " output_blocks"
		            }
		            if $display_flag(use_blanking) {
			            append cmd " -not_blanked"
		            }
		            if {$display_flag(face_norm)} {
                        # Display face projections (associations)
			            append cmd " association"
		            }
		            hex_command $cmd
		        }
	        }	   
	            scan {
		        scan_update all
	        }
	    }
    }
    
    if {[info exists hexa_select] && [info exists hexa_selection_display]} {
        hex_command "$hexa_selection_display"
    }
    
    # signal change
    ic_hex_update_dladaptobj
}

# return values:
# 0 - not up to date
# 1 - up to date
# 2 - up to date, changed from prev.
proc hex_mesh_up_to_date {ask {redraw 1} {d_to_mesh -1 } {recompute 1} {ret 0}} {
    global project_type last_line hex_option dim_to_mesh
    global index_form index_dims options plot_window 
    global histo_title histo_nbars histo_minv histo_maxv histo_ylim
    global display_flag

    set last_line $recompute
    if {$d_to_mesh == -1} {
        set d_to_mesh $dim_to_mesh
    }
    set fams [volume_activename_string]
    set fams2 ""
    set blk_fams [ic_hex_non_empty_families]
    set geo_fams [ic_geo_non_empty_families]
    foreach f $fams {
        if {[lsearch $blk_fams $f] > -1 || [lsearch $geo_fams $f] > -1} {
            lappend fams2 $f
        }
    }
    set fams $fams2
    # to avoid recomputing when all parts are off
    if {$fams == ""} {
        return 1
    }
    set ptype $project_type
    if {![info exists hex_option(project_bspline)]} {
        set hex_option(project_bspline) 0
    }
    if {$ptype == 2 && $hex_option(project_bspline)} {
        set ptype 3
        set project_type 3
    }
    if {$ptype == 3 && !$hex_option(project_bspline)} {
        set ptype 2
        set project_type 2
    }
    hex_command "check_mesh $fams proj $ptype dim_to_mesh $d_to_mesh"
    if $ret { return $last_line }
    set freeze_fams ""
    if {$last_line == 0 || $ask == -1} {
        set incremental ""
        set part_disabled ""
        foreach "part proj" [string trimright [ic_hex_list_family_projection] \n] {
            if !$proj { lappend part_disabled $part }
        }
        if {$part_disabled != ""} {
            mess "Projection to part(s) $part_disabled has been disabled\n" red
        }
        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 parts" ]
            if {$stat == -1} {
                if [winfo exists .up_to_date] { destroy .up_to_date }
                return 1
            }
            if {$stat == 1} {
                return 0
            }
            if {$stat == 2} {
                set incremental "incremental"
            }
            if {$stat == 3} {	
                set freeze_fams [select_families subpart 0 0 "Select the parts to freeze"]
            }
            update
        }
        if {$last_line == 1} {
            mess "Mesh is out of date -- recomputing.\n"
        }
        # to avoid recomputing when only part VORFN is on
        if {$fams == "VORFN"} {
            mess "Will not compute Pre-mesh for part VORFN region only\n" red
            return 1
        }
        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"
        }
        mess "Number of processors = $options(n_processors)\n" 
        if {$options(n_processors) != 1} {
            append cmd " nproc $options(n_processors)"
        }
        busy 1
        if [ic_wb2_is_running] {
            aie_set_global wb2_icemcfd_running 1
        }
        mess "Recompute pre-mesh...\n"
        aie_hex_clear_worst_element
        set update_display "vert edge face block mesh"
        set res [hex_command $cmd]
        if {$res != ""} {
            set num [string first "Error:" $res]
            if {$num > -1} {
                mess "[string range $res $num end]" red
                if {[ic_hex_count_unstruct_blocks 3d] > 0} {
                    set tmp_files [glob -nocomplain "[ic_temp_dir]/temp_cmd*.[pid].*.log"]
                    foreach f $tmp_files {
                        if [file isfile $f] {
	                        set fp [open $f r]
	                        set data [read $fp]
	                        close $fp
	                        catch { file delete $f }
	                        set num [string first "ERR " $data]
	                        if {$num > -1} {
	                            mess "[string range $data $num end]" red
	                        }
	                    }
                    }
                } 
            } else {
                set num [string first "Note:" $res]
                if {$num > -1} {
                    set num2 [string first "\n" $res $num]
                    if {$num2 > -1} { mess "[string range $res $num $num2]" }
                }
            }
        }
        mess "Done recompute pre-mesh\n"
	    if [ic_wb2_is_running] {
	        aie_unset_global wb2_icemcfd_running
	    }
        busy reset
        if {[info exists plot_window] && [winfo exists $plot_window.graph]} {
            if ![hexQualityDEZ isbuilt] {
                hexQualityDEZ build
                hexQualityDEZ apply
            } else {
                if [info exists histo_title] { 
                    aie_hex_update_histogram "$histo_title" $histo_nbars $histo_minv $histo_maxv $histo_ylim
                }
            }
        }
        if $redraw {
            foreach type $update_display {
                if $display_flag($type) {
                    hex_update_display $type
                }
            }
            hex_update_display scan
        }
        return 2
    }
    return 1
}

proc max { a1 a2 } {
	if { $a1 > $a2 } {
		return $a1
	} else {
		return $a2
	}
}

proc display_edge_mesh_params { } {
    global display_flag use_output_blocks
    
    set opts "[range_string] m [volume_activename_string]"
    if $use_output_blocks {
	append opts " output_blocks"
    }
    if $display_flag(edge_vol)     { append opts " volume" }
    if $display_flag(edge_bunch)   { append opts " bunching" }
    if $display_flag(edge_counts)  { append opts " counts" }
    if $display_flag(edge_nodes)   { append opts " nodes" }
    if $display_flag(edge_proj)    { append opts " proj" }
    if $display_flag(edge_mset)    { append opts " highlight_set" }
    if $display_flag(edge_shape_source) { append opts " shape_source" }
    if $display_flag(edge_shape) { append opts " edge_shape" }
    if $display_flag(edge_simple) { append opts " -simple" }
    if $display_flag(use_blanking) { append opts " -not_blanked" }
    if $display_flag(color_by_count) { append opts " color_by_count" }
    
    #		    if $display_flag(block_numbers) {
    #			set bn [get_block_numbers]
    #			if {$bn != ""} { append opts " block_nums $bn" }
    #		    }
    if [info exists display_linked_to] {
	append opts " highlight linked $display_linked_to"
    }
    return $opts
}


################################## Scan planes ######################

proc mesh_scan_planes {w} {
    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
    global scan_plane_colwin scan_form scan_auto_repeat has_blt

    if ![ic_hex_blocking_loaded] return

    if ![info exists has_blt] {
	    set has_blt 0
    }

    hex_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
	    }
    }
    
    set scan_auto_repeat 0

    if {$w != ""} {
	    set scan_form $w.scanf
    } else {
	    set scan_form .scanf
    }
    if $ch { 
	    if [winfo exists $scan_form] { form_kill $scan_form }
    }

    if {$w != ""} {
	    set dd [form_init_sub $scan_form]
    } else {
	    set dd [form_init $scan_form "Scan planes" "" {{}}]
    }
    if {$dd != ""} {
	    set d [form_scroller $dd.scr 400 {0 0}]
	    set f $dd.f
	    form_frame $f flat 0 {0 1  -cols - -sticky w}
	    form_button $f.select "Select" "scan_select_edge" {0 0}
	    form_checkbutton $f.solid "Solid" scan_solid {1 0 -pady 4}
	    $f.solid configure -command "scan_update all"
	    #form_checkbutton $f.auto "Auto-Repeat" scan_auto_repeat {2 0 -pady 4}
	    #$f.auto configure -command "scan_auto_repeat $d $ndim"
	    form_button $f.done "Done" "scan_form_done" {3 0 -pady 4}
	
	    set up @$guibase_dir/goup.xbm
	    set dn @$guibase_dir/godown.xbm	

	    form_label $d.onl "On" {3 1}
	    form_label $d.majorl "Block Index" {3 3 -cols 3}
	    form_label $d.minorl "Grid Index" {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"
	        $d.major$i configure -width 4

	        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"
	        $d.minor$i configure -width 4
	        $d.minorup$i configure -repeatdelay 1000 -repeatinterval 10
	        $d.minordn$i configure -repeatdelay 1000 -repeatinterval 10
	        
	        #futil_colorentry $d.color$i scan_color($i) "$row 10" "" \
	        #"by material" scan_color_material($i) "scan_update $i" 1

	        set scan_plane_colwin($i) $d.color$i
	        form_button $scan_plane_colwin($i) " " "scan_update_color $i" "$row 10" ""
	        $scan_plane_colwin($i) configure -background $scan_color($i)

	    
	        bind $d.major$i <Return> "scan_update $i"
	        bind $d.minor$i <Return> "scan_update $i"
	    }
	
	    form_finish
	    if {$w != ""} {
	        pack $scan_form -side left  -expand yes -fill both
	    }
	    form_scroller_hack $dd.scr
        if {$w != ""} {
           ::AIEnv::GUIManagement::ConfigureConsoleZone 1
        }
    } 
}

proc scan_form_done {} {
    global scan_on scan_form plot_window

    if ![info exists scan_form] return
    
    if {[winfo exists $scan_form] && ([winfo parent $scan_form] == $plot_window)} {
        form_kill $scan_form
        ::AIEnv::GUIManagement::ConfigureConsoleZone 0
    } else {
        form_kill $scan_form
    }
    foreach i [array names scan_on] {
        set scan_on($i) 0
        scan_update $i
    }
    mesh_scan_done
    unset scan_form
}

proc scan_update_color {ind} {
    global scan_color scan_color_material scan_plane_colwin

    set scan_color_material($ind) [SelectColor .select_color -color $scan_color($ind)]
    if {$scan_color_material($ind) != ""} {
        if {[string length $scan_color_material($ind)] == 13} {
            scan $scan_color_material($ind) \#%2s%2s%2s%2s%2s%2s rr rr2 gg gg2 bb bb2
            set scan_color_material($ind) "\#$rr$gg$bb"
        }
        $scan_plane_colwin($ind) configure -background $scan_color_material($ind)
        set scan_color($ind) $scan_color_material($ind)    
        scan_update $ind
    }
}

proc scan_auto_repeat {d ndim} {
    global scan_auto_repeat scan_on

    if $scan_auto_repeat {
	    for {set i 0} {$i < $ndim} {incr i} {
	        if ![info exists scan_on($i)] continue
	        $d.majorup$i configure -repeatdelay 1 -repeatinterval 1
	        $d.majordn$i configure -repeatdelay 1 -repeatinterval 1
	        $d.minorup$i configure -repeatdelay 1 -repeatinterval 1
	        $d.minordn$i configure -repeatdelay 1 -repeatinterval 1
	    }
    } else {
	    for {set i 0} {$i < $ndim} {incr i} {
	        if ![info exists scan_on($i)] continue
	        $d.majorup$i configure -repeatdelay 10000 -repeatinterval 10000
	        $d.majordn$i configure -repeatdelay 10000 -repeatinterval 10000
	        $d.minorup$i configure -repeatdelay 10000 -repeatinterval 10000
	        $d.minordn$i configure -repeatdelay 10000 -repeatinterval 10000
	    }
    }
}

proc scan_reset {} {
    global scan_form plot_window

    if ![info exists scan_form] return

    set on [expr {[winfo exists $scan_form] && [winfo ismapped $scan_form]}]
    form_kill $scan_form
    if $on {
        if [winfo exists $plot_window] {
	        mesh_scan_planes $plot_window
	    } else {
	        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
    
    
    set edge [select_hexa edge 1 "Select an edge perpendicular to the desired scan plane"]
    if {$edge == ""} return
    if {[llength $edge] == 1} {set edge [lindex $edge 0]}
    set vert [lindex $edge 0]
    set dim [lindex $edge 1]
    set ind [lindex $edge 2]
    
    set major [lindex $vert $dim]
    if {$major == ""} { set major 0 } \
    elseif {$dim >= 3} {set major [lindex [split $major :] end]}
    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 dim_to_mesh

    if ![ic_hex_blocking_loaded] return
    
    if {$ind == "all"} {
	    foreach i [array names scan_on] {
	        if $scan_on($i) { scan_update $i }
	    }
	    return
    }

    if {!([info exists index_min_limit($ind)] && [info exists index_max_limit($ind)])} {
        mess "Error: Could not find the range limit for index: \#$ind\n"  red
        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 "scan_plane \{ $ind $scan_major($ind) $scan_minor($ind) \} "
    if !$scan_on($ind) { 
        append cmd " erase" 
    } else {
    	hex_mesh_up_to_date 1 1
    }
    append cmd " [range_string] proj $dim_to_mesh"
    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
    
    if ![ic_hex_blocking_loaded] return
    foreach i [array names scan_major] {
	    hex_command "scan_plane erase \{ $i 0 0 \}" 0
    }
}


##################### index control #########################################

proc setup_index_box {{w ""}} {
    global index_min_limit index_max_limit index_dims
    global index_min index_max
    global prev_index_dims guibase_dir 
    global has_blt index_form scan_form

    if ![ic_hex_blocking_loaded] return

    if ![info exists has_blt] {
        set has_blt 0
    }

    set index_form .indexf
    if {$w != "" && $w != "."} {
        set index_form $w.indexf
    }
    if [winfo exists $index_form] {
        form_kill $index_form
    }
    
    if {[info exists scan_form] && [winfo exists $scan_form]} {
        set parent [winfo parent $scan_form]
        if {$parent != "."} {
            set w ""
            set index_form .indexf
        }
    }

    set index_dims [lsort -integer [array names index_min_limit]]   
    set prev_index_dims $index_dims
    set ndims [llength $index_dims]
    if  {$w != ""} {
        set dd [form_init_sub $index_form]
    } else {
        set dd [form_init $index_form "index control" "" {{}}]
    }

    if {$dd != ""} {
        set d [form_scroller $dd.scr 400 {0 0}]
        set f $dd.f
        form_frame $f flat 3 {0 1  -cols - -sticky w}
        form_button $f.select "Select corners" "index_from_corners" {0 0 -sticky ew}
        form_button $f.reset "Reset" index_reset {1 0 -sticky ew }
        form_button $f.query "Query Edge" "hex_query edge" {2 0 -sticky ew}
        set font [$f.query cget -font]
        form_menubutton $f.load "Index Sets" $f.load.m {3 0 -sticky ew}
        $f.load configure -relief raised -font $font
        menu $f.load.m -tearoff 0
        $f.load.m add command -label "Show" -command "index_show"
        $f.load.m add command -label "Add" -command "index_add"
        $f.load.m add command -label "Clear" -command "index_clear"
        $f.load.m add command -label "Load" -command "index_load"
        $f.load.m add command -label "Save" -command "index_save"
        form_button $f.done "Done" "index_form_done" {4 0 -sticky ew}
	
        set up @$guibase_dir/goup.xbm
        set dn @$guibase_dir/godown.xbm	

        form_label $d.diml "Dim" {3 1}
        form_label $d.minorl "Min" {3 3 -cols 3}
        form_label $d.majorl "Max" {3 7 -cols 3}
        form_frame $d.dimul flat 2 {4 1 -pady 4 -anchor n}
        form_frame $d.minorul flat 2 {4 3 -cols 3 -pady 4 -anchor n}
        form_frame $d.majorul flat 2 {4 7 -cols 3 -pady 4 -anchor n}

        foreach f {dimul majorul minorul} {
            $d.$f configure -background black
        }
	
        foreach i $index_dims {
            set row [expr {$i + 5}]
            if {$i < 3} {
                set dname [lindex {I J K} $i]
            } else {
                set dname O$i
            }
            form_label $d.dim$i $dname "$row 1"
            form_entry $d.minor$i index_min($i) int "$row 3"
            form_button_bitmap $d.minorup$i $up "index_modify $i 0 1" "$row 4"
            form_button_bitmap $d.minordn$i $dn "index_modify $i 0 -1" "$row 5"
            form_entry $d.major$i index_max($i) int "$row 7"
            form_button_bitmap $d.majorup$i $up "index_modify $i 1 1" "$row 8"
            form_button_bitmap $d.majordn$i $dn  "index_modify $i 1 -1" "$row 9"
            form_colwidth $d 2 4
            form_colwidth $d 6 4
            bind $d.major$i <Return> "hex_update_display edge face block vert mesh"
            bind $d.minor$i <Return> "hex_update_display edge face block vert mesh"
        }
        form_finish
        if {$w != ""} {
            pack $index_form -side left  -expand yes -fill both
        }
        form_scroller_hack $dd.scr
        if {$w != ""} {
           ::AIEnv::GUIManagement::ConfigureConsoleZone 2
        }
    } 
}

proc index_show {} {
    global index_min index_max
    global saved_index_controls

    if ![array exists saved_index_controls] return
    if [winfo exists .index_form_load] { form_kill .index_form_load }
    set buttons {
        {"Done" "form_kill .index_form_load"}
    }
    set dd [form_init .index_form_load "Saved Index Sets" "" $buttons]
    if {$dd != ""} {
        set d [form_scroller $dd.scr 400 {0 0}]
        $d configure -bd 3 -relief sunken
        form_label $d.diml " # " {3 1}
        form_label $d.minorl "IJK Min" {3 3 -cols 3}
        form_label $d.majorl "IJK Max" {3 7 -cols 3}
	    set ii 0
	    set row 5
        foreach i [lsort -dictionary [array names saved_index_controls]] {
            form_radiobutton $d.dim$ii "[expr $ii + 1]" min_max_idx $ii "$row 1" "" "index_set_loaded $ii"
            set min ""
            set i 0
            foreach item [lindex $saved_index_controls($ii) 0] {
                append min "[lindex $item 1] "
                incr i; if {$i == 3} break
            }
            form_label $d.minor$ii $min "$row 3"
            set max ""
            set i 0
            foreach item [lindex $saved_index_controls($ii) 1] {
                append max "[lindex $item 1] "
                incr i; if {$i == 3} break
            }
            form_label $d.major$ii $max "$row 7"
            form_colwidth $d 2 4
            form_colwidth $d 6 4
            incr ii
            incr row
        }
        form_finish +400+400 1 0
        form_scroller_hack $dd.scr
        $d.dim0 invoke
    }
}

proc index_add {} {
    global index_min index_max saved_index_controls

    if [array exists saved_index_controls] {
        set idx [array size saved_index_controls]
    } else {
        set idx 0
    }
    set min ""
    foreach i [lsort -dict [array names index_min]] {
        lappend min "$i $index_min($i)"
    }
    set max ""
    foreach i [lsort -dict [array names index_max]] {
        lappend max "$i $index_max($i)"
    }
    set saved_index_controls($idx) [list $min $max]
    mess "Current Index Set ([expr $idx + 1]) added\n"
}

proc index_clear {} {
    global saved_index_controls

    if [winfo exists .index_form_load] {
        form_kill .index_form_load
    }
    if [array exists saved_index_controls] {
        unset saved_index_controls
        mess "Index Control Sets cleared\n"
    }
}

proc index_set_loaded {i} {
    global index_min index_max saved_index_controls
    
    if ![array exists saved_index_controls] return
    foreach "min max" $saved_index_controls($i) {
        foreach item $min {
            set min_idx [lindex $item 0]
            set min_val [lindex $item 1]
            set index_min($min_idx) $min_val
        }
        foreach item $max {
            set max_idx [lindex $item 0]
            set max_val [lindex $item 1]
            set index_max($max_idx) $max_val
        }
    }
    hex_update_display edge face block vert mesh
}

proc index_save {} {
    global file_name saved_index_controls

    if ![array exists saved_index_controls] return
    if [file exists $file_name(settings)] {
        set infile [file rootname [file tail $file_name(settings)]].ictrl
    } else {
        set infile index_control.ictrl
    }
    set fm [tk_getSaveFile -initialdir [pwd] -initialfile $infile -parent . -filetypes {{{Index Control Files} {.ictrl}} {{All files} *}}]
    if {$fm == ""} return
    if [aie_save_hexa_controls $fm] {
        mess "Index Control Sets saved\n"
    }
}

proc index_load {} {
    global file_name saved_index_controls
    
    if [file exists $file_name(settings)] {
        set infile [file rootname [file tail $file_name(settings)]].ictrl
    } else {
        set infile index_control.ictrl
    }
    set fm [tk_getOpenFile -initialdir [pwd] -initialfile $infile -parent . \
        -filetypes {{{Index Control Files} {.ictrl}} {{All files} *}}]   
    if {$fm == ""} return
    set fp [open $fm r]
    set loaded 0
    while {![eof $fp]} {
        catch {
            set line [string trim [gets $fp]]
            if {[lrange $line 0 2] == "array set saved_index_controls"} {
                if [array exists saved_index_controls] { unset saved_index_controls }
                array set saved_index_controls [lindex $line 3]
                incr loaded
                break
            }
        }
    }
    if $loaded {
        mess "Index Control Sets loaded\n"
    }
}

proc index_form_done {} {
    global index_form plot_window

    if ![info exists index_form] return
    if {[winfo exists $index_form] && [winfo parent $index_form] == $plot_window} {
        form_kill $index_form
        ::AIEnv::GUIManagement::ConfigureConsoleZone 0
    } else {
        if [winfo exists $index_form] {
            form_kill $index_form
        }
    }
    if [winfo exists .index_form_load] {
        form_kill .index_form_load
    }
    unset index_form
}

proc index_update_all {{update 1}} {
    foreach i {0 1 2} {
        index_modify $i 0 0 0
        index_modify $i 1 0 0
    }
    if $update { hex_update_display edge face block vert mesh }
}

proc index_modify {ind max dir {update 1}} {
    global index_min index_max index_min_limit index_max_limit
    global index_modify_running
    
    if [info exists index_modify_running] return
    set index_modify_running 1
    set minl $index_min_limit($ind)
    set maxl $index_max_limit($ind)
    if $max {
        incr index_max($ind) $dir
        set v $index_max($ind)
        if {$v < $minl} { set index_max($ind) $minl }
        if {$v > $maxl} { set index_max($ind) $maxl }
        if {$index_max($ind) < $index_min($ind)} {
	        set index_min($ind) $index_max($ind)
        }
    } else {
	    incr index_min($ind) $dir
	    set v $index_min($ind)
	    if {$v < $minl} { set index_min($ind) $minl }
	    if {$v > $maxl} { set index_min($ind) $maxl }
	    if {$index_max($ind) < $index_min($ind)} {
	        set index_max($ind) $index_min($ind)
	    }
    }
    unset index_modify_running
    if $update { hex_update_display edge face block vert mesh }
}

proc index_reset {} {
    global index_min index_max index_min_limit index_max_limit
    
    if [info exists index_min_limit] {
        foreach v [array names index_min_limit] {
            set index_min($v) $index_min_limit($v)
        }
    }
    if [info exists index_max_limit] {
        foreach v [array names index_max_limit] {
            set index_max($v) $index_max_limit($v)
        }
    }
    hex_update_display edge face block vert mesh
}

proc index_from_corners {} {
    global index_min index_max 
    
    set nodes [select_hexa vertex 2 "Select the two corner nodes" node_numbers]
    if {[llength $nodes] < 2} return
    
    set n1 [ic_hex_vertex_ijk [lindex $nodes 0]]
    set n2 [ic_hex_vertex_ijk [lindex $nodes 1]]

    foreach i {0 1 2} {
	set i1 [lindex $n1 $i]
	set i2 [lindex $n2 $i]
	if {$i1 > $i2} {
	    set index_max($i) $i1
	    set index_min($i) $i2
	} else {
	    set index_max($i) $i2
	    set index_min($i) $i1
	}
    }
    
    hex_update_display edge face block vert mesh
}

proc range_string {} {
    global index_min index_max index_min_limit index_max_limit
    
    set range ""
    foreach i [lsort -integer [array names index_min_limit]] {
	if { $index_min($i) != $index_min_limit($i) || \
			$index_max($i) != $index_max_limit($i)  } {
		lappend range "$i:$index_min($i),$index_max($i)"
	}
    }
    return $range
}

proc hex_query {what} {
    global index_form index_dims use_output_blocks display_flag
    
    if ![ic_hex_blocking_loaded] {
        mess "No blocking is loaded\n" red
        return
    }
    mess "\n"
    if {$what == "vertex"} {
        set flag vert
    } else {
        set flag $what
    }
    switch $what {
        vertex {
            set v [select_hexa $what 1 "Select $what" node_numbers]
            if {$v == ""} return
            set loc [string trimright [ic_hex_get_node_location $v] \n]
            set ijk [string trimright [ic_hex_vertex_ijk $v] \n]
            mess "Vertex number = $v, index = \{$ijk\}\n  location = \{$loc\}\n" blue
        }
        edge {
            set e [select_hexa $what 1 "Select $what" new_format]
            if {$e == ""} return
            set n1 [lindex $e 0]
            set n2 [lindex $e 1]
            set n3 [lindex $e 2]
            set hidden [ic_hex_get_hidden_nodes $n1 $n2]
            set len_hidden [llength $hidden]
            if {$len_hidden > 2} {
                mess "Edge (hidden) vertices =" blue
                mess " [lindex $hidden 0]" blue
                foreach n [lrange $hidden 1 end-1] {
                    mess " ($n)" blue
                }
                mess " [lindex $hidden end]" blue
                mess "\n"
            } else {
                mess "Edge vertices = $n1 $n2\n" blue
            }
            set edim  [ic_hex_edge_node_dim $n1 $n2] 
            set dim [lindex $edim 0]
            set index  [lindex $edim 1]
            set rev [lindex $edim 2]
            set mparams [ic_hex_mesh_params $n1 $n2]
            if {[lindex [lindex $mparams 0] 0 ] == "userdefined"} {
                set law [lindex [lindex $mparams 0] 0 ]
                set part [lindex [lindex $mparams 1] 0 ]
                set nnodes [lindex [lindex $mparams 2] 0]
                if {$dim < 3 && $dim > -1} {
                    set emsg "Edge dimension = [lindex {I J K} $dim]"
                } else {
                    set emsg "Edge dimension = O$dim"
                }
                mess "$emsg; index = $index; reversed = $rev\n" blue
                mess "Num nodes = $nnodes, mesh-law = $law, part = $part" blue
	            set n [ic_hex_get_edge_segment_number $n1 $n2]
	            if {$n > 1} {
	                mess ", num edge segments = $n\n" blue
	            } else {
	                mess "\n" 
	            }
                return
            } elseif {[lindex $mparams 0] == "linear" || [lindex $mparams 0] == "spline"} {
                set islinear 1
            } else {
                set islinear 0
            }
            if {[lindex $mparams 0] == "linked"} {
                if {[lindex $mparams 2] == "locked"} {
                    set islocked 1
                } else {
                    set islocked 0
                }
                set n1 [lindex [lindex $mparams 1] 0]
                set n2 [lindex [lindex $mparams 1] 1]
                mess "Edge is linked to edge $n1 $n2" blue
                if $islocked {
                    mess "; Edge is locked\n" blue
                } else {
                    mess "\n" blue
                }
                set mparams [ic_hex_mesh_params $n1 $n2]
                set nnodes [lindex $mparams 0]
                set len [lindex $mparams 5]
                set law [lindex $mparams 7]
                set max [lindex $mparams 8]
                set sp1 [lindex $mparams 9]; set sp2 [lindex $mparams 11]
                set sp1r [lindex $mparams 1]; set sp2r [lindex $mparams 3]
                set r1 [lindex $mparams 10]; set r2 [lindex $mparams 12]
                set r1r [lindex $mparams 2]; set r2r [lindex $mparams 4]
            } else {
                if $islinear {
                    set law [lindex $mparams 0]
                    set nnodes [lindex $mparams 1]
                    set len [lindex $mparams 7]
                } else {
                    set nnodes [lindex $mparams 0]
                    set len [lindex $mparams 5]
                    set law [lindex $mparams 7]
                    set max [lindex $mparams 8]
                    set sp1 [lindex $mparams 9]; set sp2 [lindex $mparams 11]
                    set sp1r [lindex $mparams 1]; set sp2r [lindex $mparams 3]
                    if {[lindex [lindex $mparams 1] 0] == "linked"} {
                        set sp1_linked [lrange [lindex $mparams 1] 1 2]
                    }
                    if {[lindex [lindex $mparams 3] 0] == "linked"} {
                        set sp2_linked [lrange [lindex $mparams 3] 1 2]
                    }
                    set r1 [lindex $mparams 10]; set r2 [lindex $mparams 12]
                    set r1r [lindex $mparams 2]; set r2r [lindex $mparams 4]
                }
            }
            if !$islinear {
                mess "Actual spacing 1 = $sp1, actual spacing 2 = $sp2\n" blue
                mess "Requested spacing 1 = $sp1r requested spacing 2 = $sp2r\n" blue
                mess "Actual ratio 1 = $r1, actual ratio 2 = $r2\n" blue
                mess "Requested ratio 1 = $r1r, requested ratio 2 = $r2r, " blue
                mess "Max space = $max\n" blue
                if [info exists sp1_linked] { mess "Spacing 1 is linked to edge $sp1_linked\n" blue }
                if [info exists sp2_linked] { mess "Spacing 2 is linked to edge $sp2_linked\n" blue }
            }
            if {$dim < 3 && $dim > -1} {
                set emsg "Edge dimension = [lindex {I J K} $dim]"
            } else {
                set emsg "Edge dimension = O$dim"
            }
            set f [ic_hex_get_edge_shape_factor $n1 $n2]
            if {$f != "-1" && ([string is integer $f] || [string is double $f])} {
                mess "Link factor: $f, " blue
            }
            mess "Constraints: [string trimright [ic_hex_list_edge_constraints $n1 $n2] \n]\n" blue
            mess "$emsg; index = $index; reversed = $rev\n" blue
            mess "Num nodes = $nnodes, mesh-law = $law, edge length = $len" blue
	        set n [ic_hex_get_edge_segment_number $n1 $n2]
	        if {$n > 1} {
	            mess ", num edge segments = $n\n" blue
	        } else {
	            mess "\n" 
	        }
            if {[info exists index_form] && [winfo exists $index_form.scr.c] && [info exists index_dims]} {
                catch { $index_form.scr.c yview moveto [expr $dim / ([llength $index_dims] + 0.0)] }
            }
        }
        face {
            set f [select_hexa $what 1 "Select $what"]
            if {$f == ""} return
            set f [join $f]
            if {[lindex $f end] == "u"} {
                mess "Face number = $f\n" blue
                mess "Face is type free\n" blue
                return
            }
            mess "Face vertices = $f\n" blue
            set dim [format %d [ic_hex_mesh_dimension]]
            set n1 [lindex $f 0]; set n2 [lindex $f 1]; set n3 [lindex $f 2]
            set mparams1 [list [string trimright [ic_hex_mesh_params $n1 $n2] \n]]
            set mparams2 [list [string trimright [ic_hex_mesh_params $n1 $n3] \n]]
            set nodes 1
            foreach mparams "$mparams1 $mparams2" {
                if {[lindex $mparams 0] == "linear" || [lindex $mparams 0] == "spline"} {
                    set nodes [expr ([lindex $mparams 1] - 1) * $nodes]
                } else {
                    if {[lindex $mparams 0] == "linked"} {
                        set n11 [lindex [lindex $mparams 1] 0]
                        set n22 [lindex [lindex $mparams 1] 1]
                        if {$n11 != -1 && $n22 != -1} {
                            set nodes [expr ([lindex [ic_hex_mesh_params $n11 $n22] 0] - 1) * $nodes]
                        }
                    } else {
                        if {[lindex $mparams 0] == "userdefined"} {
                            set nodes [expr ([lindex $mparams 2] - 1) * $nodes]
                        } else {
                            set nodes [expr ([lindex $mparams 0] - 1) * $nodes]
                        }
                    }
                }
            }
            mess "Face elements = $nodes\n" blue
            if {$dim != 2} {
                set proj [eval ic_hex_query_face_proj $f]
                mess "Projection type: $proj\n" blue
            }
            foreach peri [lindex [ic_hex_display_periodic_faces get_faces] 0] {
                if {[join $peri] == [lrange $f 0 end]} {
                    mess "Face is periodic\n" blue
                    break
                }
            }
        }
        block {
            set b [select_hexa $what 1 "Select $what"]
            if {$b == ""} return
            set det [ic_hex_super_determinant $b]
            set dim [format %d [ic_hex_mesh_dimension]]
            if {$dim > 2} {
                if $use_output_blocks {
                    set fam [ic_hex_get_block_family $b output_blocks]
                    set verts [string trimright [ic_hex_get_block_vertices $b output_blocks] \n]
                    set type [string trimright [ic_hex_print_block_type_info $b output_blocks] \n]
                } else {
                    set fam [ic_hex_get_block_family $b]
                    set verts [string trimright [ic_hex_get_block_vertices $b] \n]
                    set type [string trimright [ic_hex_print_block_type_info $b] \n]
                }
                if {$verts != ""} {
                    mess "Block vertices = $verts\n" blue
                }
                #mess "Block type = $type\n" blue
            } else {
                if $use_output_blocks {
                    set fam [ic_hex_get_block_family $b output_blocks]
                    set type [string trimright [ic_hex_print_block_type_info $b output_blocks] \n]
                } else {
                    set fam [ic_hex_get_block_family $b]
                    set type [string trimright [ic_hex_print_block_type_info $b] \n]
                }
               set verts ""
            }
            if {$type == "mapped" && $verts != ""} {
                catch {
                foreach "n1 n2 n3 n4 n5 n6 n7 n8" $verts {
                    set nnodes1 [hex_block_nodes_info $n1 $n2]
                    set nnodes2 [hex_block_nodes_info $n1 $n3]
                    set nnodes3 [hex_block_nodes_info $n1 $n5]
                }
                if {$nnodes1 != "" && $nnodes2 != "" && $nnodes3 != ""} {
                    set inum $nnodes1
                    set jnum $nnodes2
                    set knum $nnodes3
                    set all_elems [expr $inum * $jnum * $knum]
                }
                unset nnodes1; unset nnodes2; unset nnodes3
                }
            }
            mess "Block number = $b\n" blue
            mess "Block part = $fam" blue
            mess "Block type = $type\n" blue
            if [info exists all_elems] {
                mess "Block determinant = $det" blue
                mess "Block elements along I = $inum, J = $jnum, K = $knum\n" blue
                mess "Block elements along IJK = $all_elems\n" blue
                unset all_elems
            }
            set sblock_info [string trimright [ic_hex_print_sblock_info $b] \n]
            if {$sblock_info != ""} {
                mess "$sblock_info\n" blue
            }
            mess "\n"
        }
    }
    hex_update_display $what
}

proc hex_block_nodes_info {n1 n2} {
    global use_output_blocks

    if $use_output_blocks {
        set edges [join [string trimright [ic_hex_get_vertex_edges $n1 output_blocks] \n]]
    } else {
        set edges [join [string trimright [ic_hex_get_vertex_edges $n1] \n]]
    }
    if {[lsearch $edges $n2] >= 0} {
        set nnodes1 [ic_hex_mesh_params $n1 $n2]
        if {[lindex $nnodes1 0] == "linked"} {
            set n11 [lindex [lindex $nnodes1 1] 0]
            set n22 [lindex [lindex $nnodes1 1] 1]
            return [expr [lindex [ic_hex_mesh_params $n11 $n22] 0] - 1]
        } else {
            set rats [lindex [lindex [ic_hex_n_nodes_edge node_num $n1 $n2] 0] 2]
            if {$rats > 1} {
                return [expr (([lindex $nnodes1 0] - 1) * $rats)]
            } else {
                return [expr [lindex $nnodes1 0] - 1]
            }
        }
    }

    set n3 $n1
    set nodes "$n1"
    set ijk1 [lindex [string trimright [ic_hex_vertex_ijk $n1] \n] 0]
    set ijk2 [lindex [string trimright [ic_hex_vertex_ijk $n2] \n] 0]
    if {$ijk1 != $ijk2} { set diff 1 } else { set diff 0 }
    set idx 0

    while 1 {
        set n3 [hex_block_vertex_info2 $n3 $n2 $ijk1 $diff]
        lappend nodes $n3
        if {$n3 == $n2} break
        incr idx 
        if {$idx > 100} { set nodes "$n1"; break }
    }
    if {$nodes != "$n1"} {
        set num 0; set idx 0; set skip 0
        foreach "nn1" $nodes {
            if $skip {
                incr skip -1
                incr idx
                continue
            }
            set nn2 [lindex $nodes [expr $idx + 1]]
            if {$nn2 != ""} {
                set n_nodes [ic_hex_n_nodes_edge node_num $nn1 $nn2]
                set nums [lindex [lindex $n_nodes 0] 0]
                set segs [lindex [lindex $n_nodes 0] 1]
                set rats [lindex [lindex $n_nodes 0] 2]
                if {$segs > 1 && [expr [llength $nodes] - 1] == $segs} {
                    return [expr $nums - 1]
                } elseif {$segs > 1} {
                    set skip [expr $segs - 1]
                    set num [expr $num + $nums + 1]
                } else {
                    if {$rats > 1} {
                        set num [expr $num + (($nums -1) * $rats)]
                    } else {
                        set num [expr ($num) + $nums]
                    }
                }
                incr idx
            } else {
                break
            }
        }
        return  [expr [expr $num - ($idx - 1)] - 1]
    }
    return ""
}

proc hex_block_vertex_info2 {n1 n2 ijk1 d} {
    set loc(1) [string trimright [ic_hex_get_node_location $n1] \n]
    set loc(2) [string trimright [ic_hex_get_node_location $n2] \n]
    foreach "n3" [join [string trimright [ic_hex_get_vertex_edges $n1] \n]] {
        if {$n3 == $n1} continue
        if $d {
            if {[lindex [string trimright [ic_hex_vertex_ijk $n3] \n] 0] <= $ijk1} continue
        } else {
            if {[lindex [string trimright [ic_hex_vertex_ijk $n3] \n] 0] != $ijk1} continue
        }
        set loc(3) [string trimright [ic_hex_get_node_location $n3] \n]
        set diff [ic_geo_pnt_dist $loc(2) $loc(3)]
        if ![info exists nearest] {
            set nearest(diff) $diff
            set nearest(n) $n3
        }
        if {$diff < $nearest(diff)} {
            set nearest(diff) $diff
            set nearest(n) $n3
       }
    }
    return $nearest(n)
}

proc hex_misc_blocking_info {} {
    global use_output_blocks

    if ![ic_hex_blocking_loaded] {
        mess "No blocking is loaded\n" red
        return
    }
    mess "\n--- Blocking info ---\n"

    set dim [format %d [ic_hex_mesh_dimension]]
    mess "Blocking dimension: ${dim}D\n"

    # topo
    set topos [ic_hex_print_topo_tree]
    mess "Topologies:\n"
    foreach topo $topos {
        mess "$topo"
    }

    mess "\n"
    # index range
    mess "Index Range: [ic_hex_ijk_max]\n"

    # parts
    mess "Part dims:\n"
    foreach "part dim" [ic_hex_list_families dims] {
        mess "$part = ${dim}D\n"
    }
    mess "\n"

    # nblocks and nnodes in each I,J,K,O3,O4...
    set blknodes [ic_hex_n_nodes_edge]
    set ndims [llength $blknodes]
    mess "Number of dimensions: $ndims\n"
    mess "dim nblocks nnodes\n"
    set dims ""
    for {set i 0} {$i < $ndims} {incr i} {
	switch $i {
	    0 { set dim I }
	    1 { set dim J }
	    2 { set dim K }
	    default {set dim "O$i"}
	}
	set blocks [lindex $blknodes $i]
	set nblocks [llength $blocks]
	mess "Block Information Along: $dim $nblocks \{$blocks\}\n"
        lappend dims $dim
    }
    mess "List of Dimensions: $dims\n"
    aie_hex_show_shared_wall_info 0
    hex_number_of_blocks_info
}

proc hex_number_of_blocks_info {} {
    global use_output_blocks

    if ![ic_hex_blocking_loaded] return
    
    set blocks 0; set vorfn 0
    set mapped 0; set free 0; set swept 0

    if $use_output_blocks {
        set blks [eval ic_hex_get_block_families_and_types [volume_activename_string] output_blocks]
    } else {
        set blks [eval ic_hex_get_block_families_and_types [volume_activename_string]]
    }
    set blocks [llength $blks]
    set mapped [llength [lsearch -all $blks "*mapped*"]]
    set free [llength [lsearch -all $blks "*free*"]]
    set swept [llength [lsearch -all $blks "*swept*"]]
    set vorfn [llength [lsearch -all $blks "* ORFN *"]]
    incr vorfn [llength [lsearch -all $blks "* VORFN *"]]

    if $blocks {
        mess "\nNumber of blocks:\n"
        mess "        All blocks: $blocks\n"
        if $free {
            mess "        Free blocks: $free\n"
        }
        if $mapped {
            mess "        Mapped blocks: $mapped\n"
        }
        if $swept {
            mess "        Swept blocks: $swept\n"
        }
        if $vorfn {
            mess "        Blocks in part VORFN: $vorfn\n"
        }
    } 
}

proc hex_mesh_size {{block_info 0} {check 0}} {
    global last_line

    if ![ic_hex_blocking_loaded] {
        mess "No blocking is loaded\n" red
        return
    }
    if $block_info { hex_number_of_blocks_info }
    
    hex_command "compute_mesh_size [volume_activename_string]"
    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_nodes $nc
    set n_quads [expr {$nq + $no}]

    mess "\nMesh size:\n"
    if $n_nodes { mess "        NODES = $n_nodes\n" }
    if $n_quads { mess "        QUADS = $n_quads\n" }
    if $nh      { mess "        HEXAS = $nh\n" }
    if $check {
        if {([ic_hex_count_unstruct_blocks 2d] || [ic_hex_count_unstruct_blocks 3d]) && ([hex_mesh_up_to_date 0 0 -1 0 1] == "0")} {
            mess "Note: Pre-mesh was not recomputed before this summary, the mesh size was estimated.  Please recompute for an exact count\n" blue
         }
    }
    mess "\n"
}

proc hex_display_edge_segment {edge {seg 0} {action ""}} {
    if {$action == "reset"} {
	    hex_update_display edge
	    return
    }
    if {$edge != ""} {
	    set opts [display_edge_mesh_params]
	    set cmd "display_edge_mesh $opts "
	    append cmd " highlight_segment $seg"
	    append cmd " [lindex $edge 0] [lindex $edge 1]"
	    hex_command $cmd
    }
}

