
# This code creates the user interface for the mesh editor.
#
# Copyright (c) 1997 Pacific Marketing and Consulting, Inc,
#       and ICEM Systems, GmbH.  All rights reserved.
# Author:  Wayne A. Christopher, wayne@icemcfd.com
# $Revision$ on $Date$

# This file contains special comments of the form ## html ... which are
# used to automatically generate documentation

## <h3>Structured mesh editing and modification functions</h3>

## Does a mesh exist?

proc ic_str_is_loaded {} {
    global str_cur
    return [expr {$str_cur != ""}]
}
set dont_record_command(ic_str_is_loaded) 1

## Has the mesh been modified?

proc ic_str_is_modified {} {
    global str_cur
    return [expr {($str_cur != "") && [$str_cur get -modified]}]
}
set dont_record_command(ic_str_is_modified) 1

## Set the structured mesh modified flag.

proc ic_str_set_modified {mod} {
    global str_cur
    if {$str_cur != ""} { $str_cur configure -modified $mod }
}
set dont_record_command(ic_str_set_modified) 1

## Something has changed with the families - color, etc
## Update all the colors on all the surfaces

proc ic_str_families_changed {} {
    global str_cur

    if {$str_cur != ""} {
        foreach s [$str_cur list_surfs all] {
            set fam [$s get -family]
            $s configure -color_fam [family_color_for_name $fam]
        }
    }
}

## What are the ijk limits of a domain

proc ic_str_ijk_limits {num} {
    global str_cur
    return [$str_cur get_domain_ijk $num]
}
set dont_record_command(ic_str_ijk_limits) 1

## What is the dimension of this domain

proc ic_str_domain_dimension {num} {
    global str_cur
    return [$str_cur domain_dimension $num]
}
set dont_record_command(ic_str_domain_dimension) 1

## Returns the dimension of the domain file without
## loading the domain.

proc ic_str_domainfile_dimension {domain} {
    return [str_domainfile_dimension $domain]
}
set dont_record_command(ic_str_domainfile_dimension) 1

## Return the topo info for this object

proc ic_str_get_topo_info {what num full} {
    global str_cur
    return [$str_cur get_topo_info $what $num $full]
}
set dont_record_command(ic_str_get_topo_info) 1

## Get the family for an object

proc ic_str_get_family {what num} {
    global str_cur
    set s [$str_cur get_surf $what $num]
    return [$s get -family]
}
set dont_record_command(ic_str_get_family) 1

## Get the name of an object

proc ic_str_get_name {what num} {
    global str_cur
    set s [$str_cur get_surf $what $num]
    return [$s get -name]
}
set dont_record_command(ic_str_get_name) 1

## Get the IJK ranges of an object

proc ic_str_get_ijk {what num} {
    global str_cur
    set s [$str_cur get_surf $what $num]
    return [$s list_ijk]
}
set dont_record_command(ic_str_get_ijk) 1

## List the objects in some families

proc ic_str_list_in_families {what fams} {
    global str_cur
    set ret ""
    foreach f $fams { set ffound($f) 1 }
    set n [$str_cur num_topo_objects $what]
    for {set i 1} {$i <= $n} {incr i} {
	if [info exists ffound([ic_str_get_family $what $i])] {
	    lappend ret $i
	}
    }
    return $ret
}
set dont_record_command(ic_str_list_in_families) 1

## How many objects are in a given family

proc ic_str_count_in_families {fams} {
    global str_cur
    if ![ic_str_is_loaded] { return 0 }
    set ret 0
    foreach f $fams {
        incr ret [$str_cur count_in_family $f]
    }
    return $ret
}
set dont_record_command(ic_str_count_in_families) 1

## List the adjacent objects for this object - currently only adjacent domains
## to this domain are supported

proc ic_str_adjacent_surfs {what num} {
    global str_cur
    return [$str_cur list_adjacent_surfs $what $num]
}
set dont_record_command(ic_str_adjacent_surfs) 1

## List the boundary subfaces for this domain.

proc ic_str_boundaries_of_entity {what num} {
    global str_cur
    return [$str_cur list_boundaries_of_entity $what $num]
}
set dont_record_command(ic_str_boundaries_of_entity) 1

## Load the structured mesh in the given <em>dir</em>. The argument
## <em>auto_topo</em> will force a topology to be created automatically
## if it does not exist.

proc ic_str_load {domain_prefix topofile famtopofile subfaceprojfile {suffices ""} \
	{auto_topo 0}} {
    global str_cur 
    
    mess "Loading multiblock mesh...$domain_prefix $topofile $famtopofile\n"
    set str_cur [domain_load_struct $domain_prefix $topofile $famtopofile \
		    $subfaceprojfile $suffices $auto_topo]
    if {$str_cur == ""} { return 0 }
    initialize_struct_visibility
    mess "Done loading.\n"
    return 1
}

proc ic_load_struct {domain_prefix topofile famtopofile {subfaceprojfile ""}} {
    return [ic_str_load $domain_prefix $topofile $famtopofile $subfaceprojfile]
}

## Import a number (<em>nfiles</em>) of structured mesh files
## (<em>files</em>) into a mesh object using the specified <em>backend</em>.
## The optional argument <em>create (default: 1)</em> allows one to
## overwrite the current mesh object, while <em>prec (default: 1 [single])</em>
## allows one to specify the real-number precision. One can also specify
## the time step <em>tstep (default: 0)</em> and any additional arguments
## (<em>args</em>) necessary for the import.

proc ic_str_readexternal {backend nfiles files {create 1} {prec 1} \
                              {tstep 0} args} {
    global str_cur str_option
    
    busy 1
    if {$str_cur == "" || $create} {
        set str_cur [str_mesh -update_undo_cmd undo_redo_update]
        $str_cur initialize_mesh
        undo_redo_update 0 0
        set merging 0
    } else {
        set merging 1
    }
    
    set cmd [list $str_cur load_external_mesh $prec $tstep $backend \
                $nfiles]
    
    append cmd " $files $args 2d_to_3d 0"
    puts $cmd
    if [catch $cmd res] {
        mess $res\n red
        set str_cur ""
        busy 0
        return ""
    }

    mess "load complete ... compute topology ...\n"
    if [catch {ic_str_settopo $merging} msg] {
	mess $res\n red
	set str_cur ""
	busy 0
	return ""
    }
    initialize_struct_visibility
}

## Set the topology

proc ic_str_settopo {merging {ask 1}} {
    global str_cur str_option
    global batch_mode

    if $batch_mode {
        set ask 0
    }		
    
    if {![info exists str_cur] || $str_cur == ""} {
        return ""
    }
    
    if $merging {
        set mess "You can merge the common subfaces, edges, and vertices now,\
                or keep them separate.  You can merge them later\
                using the Copy/move form."
	    if $ask {
        	set stat [tk_dialog .comptopo "Recompute topology" $mess "" -1 "Merge" "Keep separate"]
	    } else {
	        set stat 0
	    }
        if {$stat == 0} {
            ic_str_recompute_topo
        }
    }
    
    if ![$str_cur num_topo_objects domain] {
        mess "No domains were found\n" red
        $str_cur delete
        set str_cur ""
        busy 0
        return ""
    }
    
    if {[$str_cur num_topo_objects domain] == 1} {
        mess "Creating basic subfaces for one domain\n"
        #$str_cur set_basic_topo
        ic_str_set_basic_topo
    } else {
        if {$ask == 0 || (![tk_dialog .comptopo "Recompute topology" \
             "There is no topology for this mesh. Recompute it? This \
             may take a while." "" -1 "Recompute" "Cancel"])} {
             mess "Please wait: computing topology\n"
             #$str_cur assign_subface_families
             #$str_cur recompute_topo "" ""
             ic_str_recompute_topo 1 "" ""
        } else {
             #$str_cur set_basic_topo
             ic_str_set_basic_topo
	    } 
    }
    
    if {[$str_cur num_topo_objects domain] > 100} {
        set str_option(domain,names) 0
    } else {
        set str_option(domain,names) 1
    }
    $str_cur check
    str_topo_surfs $str_cur
    
    busy 0
    return $str_cur
}

proc ic_str_set_basic_topo {} {
    global str_cur
    
    if {$str_cur == ""} return
    $str_cur set_basic_topo 
}

## Print a summary of the domains, etc, to the message window

proc ic_str_summary {} {
    global str_cur
    struct_summary $str_cur
}

## Save a structured mesh

proc ic_str_save {domain_dir topofile famtopofile subfaceprojfile {dompref domain.}} {
    global str_cur
    
    $str_cur save_domain $domain_dir $dompref $topofile $famtopofile $subfaceprojfile
}

## Save a structured mesh with default filenames in the given project directory.

proc ic_save_domain_proj {proj_dir} {
    global str_cur undo_redo
    
    $str_cur save_domain_proj $proj_dir
    ic_undo_clear
}

## How many objects of a given type.

proc ic_str_num_entities {type} {
    global str_cur
    return [$str_cur num_topo_objects $type]
}
set dont_record_command(ic_str_num_entities) 1

## List the numbers of the objects of a given type.

proc ic_str_list_entities {type} {
    global str_cur
    
    set ret ""
    set nob [$str_cur num_topo_objects $type]
    for {set i 1} {$i <= $nob} {incr i} { lappend ret $i }
    return $ret
}
set dont_record_command(ic_str_list_entities) 1

## List the numbers of the objects of a given type only if visible or blanked

proc ic_str_list_entities_visible {type vis} {
    global str_cur
    
    set ret ""
    foreach im [$str_cur list_surfs $type] {
	if {[$im get -visible] == $vis} {
	    lappend ret [$im get -number]
	}
    }
    return $ret
}
set dont_record_command(ic_str_list_entities_visible) 1

## List the families in this mesh

proc ic_str_list_families {} {
    global str_cur
    if {$str_cur == ""} { return "" }
    return [lsort [$str_cur list_families]]
}
set dont_record_command(ic_str_list_families) 1

## Clear all the diagnostics from a struct mesh

proc ic_str_clear_diagnostics {} {
    global str_cur struct_diag_cellset
    
    if [info exists struct_diag_cellset] {
	$struct_diag_cellset delete
	unset struct_diag_cellset
    }
    $str_cur clear_diagnostics
}

## Compute diagnostics

proc ic_str_metric {type domains} {
    global str_cur
    return [$str_cur compute_diagnostic $type $domains]
}

## Create a diagnostic cell set

proc ic_str_create_diagnostic_subset {{vis 1}} {
    global str_cur struct_diag_cellset batch_mode
    global tdv_default
    
    set hm [str_surf -mesh $str_cur -color [$tdv_default highlight_color] \
		-visible 1]
    if {$vis && !$batch_mode} {$tdv_default add_image $hm }
    set struct_diag_cellset $hm
}

## Configure the diagnostic cell set 

proc ic_str_configure_diagnostic_subset {args} {
    global struct_diag_cellset
    
    eval $struct_diag_cellset configure $args
}

## Configure the diagnostic cell set 

proc ic_str_set_with_diagnostic {intervals domains} {
    global struct_diag_cellset
    
    $struct_diag_cellset clear_ijk
    set tot 0
    foreach int $intervals {
	set n [$struct_diag_cellset add_with_diagnostic [lindex $int 0] \
		   [lindex $int 1] 1 1 $domains]
	incr tot $n
    }
    return $tot
}

## Use the diagnostic data for a histogram

proc ic_str_histogram {min max nbars domains} {
    global str_cur
    return [$str_cur diagnostic_histogram $min $max $nbars $domains]
}

## Make a new domain

proc ic_str_copy_domain {num} {
    global str_cur
    set nd [$str_cur copy_domain $num]
    str_topo_make_one_surf "" domain $nd
    return $nd
}

## Move a domain.  The <b>num</b> argument gives the domain
## to operate on.
## <ul>
## <li> <b>cent</b> : a list of X Y Z giving the center for rotation, scaling,
## and mirroring, which could be "centroid"
## <li> <b>translate</b> : the X Y Z values for translating the entity
## <li> <b>rotate</b> : the number of degrees to rotate the object about the
## axis given by <b>rotate_axis</b>
## <li> <b>rotate_axis</b> : the vector giving the axis to rotate about
## <li> <b>scale</b> : a scale value, or 3 values giving the factor to scale
## in X Y and Z
## <li> <b>mirror</b> : the axis about which to mirror
## <li> <b>flip_ijk</b> : a triple of 1's and 0's that says whether to flip
## the IJK axis
## <li> <b>permute_ijk</b> : a permutation of 0 1 2
## </ul>

proc ic_str_move_domain {num args} {
    global str_cur
    
    set cent "0 0 0"
    set translate ""
    set rotate ""
    set rotate_axis "0 0 1"
    set scale ""
    set mirror ""
    set permute_ijk ""
    set flip_ijk ""
    
    foreach {n v} $args { set $n $v }
    
    if {$cent == "centroid"} {
        set cent [$str_cur domain_centroid $num]
    }
    
    if {$translate != ""} {
        $str_cur translate_domain $num $translate
    }
    if {$rotate != ""} {
        # should rotate in the same direction like geometry and mesh
        $str_cur rotate_domain $num $rotate_axis [expr $rotate * -1.0] $cent
    }
    if {$scale != ""} {
	if {[llength $scale] == 1} { set scale "$scale $scale $scale" }
        $str_cur scale_domain $num $scale $cent
    }
    if {$mirror != ""} {
        $str_cur mirror_domain $num $mirror $cent
    }
    if {$permute_ijk != ""} {
	    if {$flip_ijk == ""} { set flip_ijk "0 0 0" }
        $str_cur permute_ijk_domain $num $flip_ijk $permute_ijk
    } elseif {$flip_ijk != ""} {
	    if {$permute_ijk == ""} { set permute_ijk "0 1 2" }
        $str_cur permute_ijk_domain $num $flip_ijk $permute_ijk
    }
    foreach surf [$str_cur get_surf domain $num] {
        if {"" != $surf} {
            $surf signal_change 1
        } else {
            mess "Couldn't get surf of domain $num\n" red
        }
    }
}

## Create a selection cell set, or a node selection surface

proc ic_str_create_selection_subset {{vis 1} {nodes 0}} {
    global str_cur struct_select_surfs batch_mode
    global tdv_default
    
    set hm [str_surf -mesh $str_cur -color [$tdv_default highlight_color] \
		-visible 1]
    if $nodes {
	$hm configure -draw_nodes 1 -width 3 -draw_xyz 1
    }
    if {$vis && !$batch_mode} {$tdv_default add_image $hm }
    set struct_select_surfs $hm
}

## Clear the selection cell set

proc ic_str_clear_selection_subset {} {
    global str_cur struct_select_surfs
    
    if [info exists struct_select_surfs] {
        foreach surf $struct_select_surfs {
	    if {[$surf get -surftype] == ""} {
	        $surf delete
	    }
        }
        set struct_select_surfs ""
    }
}

## How many nodes are there?

proc ic_str_selection_numnodes {} {
    global struct_select_surfs
    return [$struct_select_surfs num_nodes]
}
set dont_record_command(ic_str_selection_numnodes) 1

## What's the bb of the selection

proc ic_str_selection_get_bbox {} {
    global struct_select_surfs
    return [$struct_select_surfs get_bbox]
}
set dont_record_command(ic_str_selection_get_bbox) 1

## Check the orientation of a domain

proc ic_str_domain_orient {num} {
    global str_cur
    
    return [$str_cur domain_orient $num]
}
set dont_record_command(ic_str_domain_orient) 1

## Align all domains with one domain

proc ic_str_align_all_ijks {num stop_num} {
    global str_cur
    $str_cur align_all_ijks $num $stop_num
}

## Update all the graphical images

proc ic_str_update_surfs {} {
    global str_cur batch_mode
    str_topo_surfs $str_cur
    if !$batch_mode {
        disp_change_overall_visible domain
    }    
}

## Return the centroid of a domain

proc ic_str_domain_centroid {num} {
    global str_cur
    return [$str_cur domain_centroid $num]
}
set dont_record_command(ic_str_domain_centroid) 1

## Merge two subfaces

proc ic_str_merge_subfaces {num1 num2} {
    global str_cur
    set ok [$str_cur merge_subfaces $num1 $num2]
    if $ok {
	set s2 [$str_cur get_surf subface $num2]
	str_topo_delete_surf $str_cur $s2
    }
    return $ok
}

## Split one subfaces

proc ic_str_split_subface {num} {
    global str_cur
    
    set new [$str_cur split_subface $num]
    if {$new == ""} {
	mess "Couldn't split that subface $num\n" red
	return ""
    }
    str_topo_make_one_surf $str_cur subface $new
    return $new
}

## Change the family for an entity

proc ic_str_change_family {type nums fam} {
    global str_cur batch_mode

    set new [$str_cur create_family $fam 0]
    foreach num $nums {
        $str_cur set_family $type $num $fam
    }
    if $new {
        add_new_family $fam 1
        if !$batch_mode { update_fam_window }
    }
    if $batch_mode return
    set on [get_fam_visible $fam]
    foreach n $nums {
        set s [$str_cur get_surf $type $n]
        if {$s == ""} continue
        $s configure -visible $on -color_fam [family_color_for_name $fam] -family $fam
    }
}

proc ic_str_families_color_changed {part color} {
    global str_cur batch_mode

    if {$str_cur == ""} return
    if $batch_mode return
    foreach type {domain subface edge vertex} {
        foreach n [ic_str_list_entities $type] {
            if {[lindex [lindex [ic_str_get_topo_info $type $n 0] 0] 2] == "$part"} {
                ic_str_configure_one_attribute $type $n color_fam $color
            }
        }
    }
}
set dont_record_command(ic_str_families_color_changed) 1

## Create the surfaces of a particular type

proc ic_str_topo_make_surfs {stype force} {
    global str_cur
    
    str_topo_make_surfs $str_cur $stype $force
}

## Recompute the topology

proc ic_str_recompute_topo {{do_assign 1} {symfams ""} {callback struct_comptopo_callback}} {
    global str_cur batch_mode
    
    if $do_assign {
        $str_cur assign_subface_families
    }
    $str_cur recompute_topo $callback $symfams
    mess "Updating topological entity lists...\n"
    str_topo_surfs $str_cur
    if !$batch_mode { initialize_struct_visibility }
}

## This step has to happen before copying domains

proc ic_str_assign_subface_families {} {
    global str_cur
    $str_cur assign_subface_families
}

## Dump the topo information to a file

proc ic_str_dump_topo_info {file} {
    global str_cur
    $str_cur dump $file
}

## Change the properties of some surfaces

proc ic_str_configure {what nums shade type_color nodes ijk names numbers \
		       outlines node_size famcols simplify ijk_shrink width \
		       extended changes draw_twin} {
    global str_cur disp_temp_highlight batch_mode
    
    if {$str_cur == ""} return
    if $batch_mode return 
    if {$what == "all"} {
	set what {domain subface edge vertex region}
    }
    
    foreach w $what {
	$str_cur configure_surfs $w \
	    $shade $type_color $nodes $ijk $names $numbers $outlines \
	    $node_size $famcols $simplify $ijk_shrink $width $extended \
	    $changes $draw_twin
    }
    foreach s [array names disp_temp_highlight] {
	$s configure -color [lindex $disp_temp_highlight($s) 1] \
	    -use_color_fam 0 -width 2 -visible 1
    }
}
set dont_record_command(ic_str_configure) 1

proc ic_str_configure_one_attribute {what num param value} {
    global str_cur disp_temp_highlight batch_mode
    
    if {$str_cur == ""} return
    if $batch_mode return 
    set im [$str_cur get_surf $what $num]
    if {$im == ""} return
    $im configure -$param $value
}
set dont_record_command(ic_str_configure_one_attribute) 1

## Temporily highlight one surface.

proc ic_str_highlight {what nums on {color ""}} {
    global disp_temp_highlight str_cur tdv_default batch_mode

    if $batch_mode return
    if {$color == ""} { set color [$tdv_default highlight_color] }

    if {$nums == "all"} {
	set nums [$str_cur list_surfnums $what]
    }
    foreach num $nums {
	set im [$str_cur get_surf $what $num]
	if {$im == ""} continue
	if $on {
	    set disp_temp_highlight($im) \
		[list [$im get -visible] [$im get -color_type] \
		     [$im get -name_color] [$im get -width] \
		     [$im get -use_color_fam]]
	    $im configure -visible 1 -color_type $color -name_color red \
		-width 2 -use_color_fam 0
	} else {
	    if [info exists disp_temp_highlight($im)] {
		set d $disp_temp_highlight($im)
		$im configure -visible [lindex $d 0] \
		    -color_type [lindex $d 1] \
		    -name_color [lindex $d 2] -width [lindex $d 3] \
		    -use_color_fam [lindex $d 4]
		unset disp_temp_highlight($im)
	    }
	}
	
	$im signal_change 0
    }
}
set dont_record_command(ic_str_highlight) 1

proc ic_str_unset_temp_highlight_array {} {
    global disp_temp_highlight
    if [info exists disp_temp_highlight] {
        unset disp_temp_highlight
    }
}
set dont_record_command(ic_str_unset_temp_highlight_array) 1

## Turn on or off one surface

proc ic_str_set_nums_visible {type nvals} {
    global str_cur batch_mode
      
    if $batch_mode return
    foreach {count on} $nvals {
	set im [$str_cur get_surf $type $count]
	if {$im != ""} { $im configure -visible $on }
    }
}
set dont_record_command(ic_str_set_nums_visible) 1

## Turn on or off multiple families
## If fvals is blank then turn on or off all types as specified, likewise
## for tvals.  Note that fvals == "" means turn on everything even if it's
## not in any family

proc ic_str_set_type_family_visible {tvals fvals} {
    global str_cur batch_mode
       
    if {$str_cur == ""} return
    if $batch_mode return 
    if {$tvals == ""} {
	set tvals {domain 1 subface 1 edge 1 vertex 1 region 1}
    }
    array set fam_on $fvals
    
    foreach {type on} $tvals {
	foreach surf [$str_cur list_surfs $type] {
	    set fam [$surf get -family]
	    if [info exists fam_on($fam)] {
		$surf configure -visible [expr $on && $fam_on($fam)]
	    } elseif {$fvals == ""} {
		$surf configure -visible $on
	    }
	}
    }
}
set dont_record_command(ic_str_set_type_family_visible) 1

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

## Create a new scan plane

proc ic_str_scanp_create {name color} {
    global str_cur scanp_regions batch_mode
    global tdv_default
    
    set ns [str_surf -mesh $str_cur -visible 1 -shade wire \
		-name $name -surftype "" -take_domain_bbox 1 \
		-color_type $color]
    if !$batch_mode { $tdv_default add_image $ns }
    set scanp_regions($name) $ns
}

## Set a scan plane

proc ic_str_scanp_set {name dom ijk ind ext color} {
    global str_cur scanp_regions
    
    set ns $scanp_regions($name)

    $ns scanp_set $dom $ijk $ind $ext
    if {$color != ""} { $ns configure -color $color }
}

## Move a scan plane

proc ic_str_scanp_move {name dir ext} {
    global str_cur scanp_regions
    
    set ns $scanp_regions($name)
    
    return [$ns scanp_move $dir $ext]
}

## Get or set the config params on a scan plane.  If <b>name</b> is "" then
## this applies to all scan planes.

proc ic_str_scanp_configure {name args} {
    global str_cur scanp_regions
    
    if {$name == ""} {
	foreach name [array names scanp_regions] {
	    eval $scanp_regions($name) configure $args
	}
	return ""
    } else {
	return [eval $scanp_regions($name) configure $args]
    }
}

## Delete a scan plane.  If name is "" then delete them all

proc ic_str_scanp_delete {name} {
    global str_cur scanp_regions
    
    if {$name == ""} {
	foreach n [array names scanp_regions] {
	    ic_str_scanp_delete $n
	}
    } else {
	if [info exists scanp_regions($name)] {
	    $scanp_regions($name) delete
	    unset scanp_regions($name)
	}
    }
}

## List the currently active scan planes

proc ic_str_scanp_list {} {
    global scanp_regions
    return [array names scanp_regions]
}
set dont_record_command(ic_str_scanp_list) 1

## Check whether a scan plane exists

proc ic_str_scanp_exists {name} {
    global scanp_regions
    return [info exists scanp_regions($name)]
}
set dont_record_command(ic_str_scanp_exists) 1

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

## Pick structured items based on a polygon
## how can be item or node

proc ic_str_pick_polygon {type poly how mode} {
    global tdv_default
    set stuff ""
    foreach xx [$tdv_default pick_polygon str_$type $poly $mode] {
	set num [[lindex $xx 0] get -number]
	if {$how == "item"} {
	    lappend stuff $num
	} else {
	    lappend stuff [list $num [lindex $xx 1]]
	}
    }
    return $stuff
}
set dont_record_command(ic_str_pick_polygon) 1

## Pick structured items based on a screen position
## how can be item or node

proc ic_str_pick_single {type x y how} {
    global tdv_default

    set xx [$tdv_default pick $x $y str_$type $how 0]
    if {$xx != ""} {
	return [[lindex $xx 0] get -number]
    } else {
	return ""
    }
}
set dont_record_command(ic_str_pick_single) 1

## Pick structured nodes based on a polygon, and add them to the selected
## node surface

proc ic_str_add_pick_polygon {what poly vect partial} {
    global struct_select_surfs
    
    set from_surfs ""
    foreach ss [info commands str_surf__*] {
	if {[$ss get -visible] && ($ss != $struct_select_surfs)} {
	    lappend from_surfs $ss
	}
    }
    if {$from_surfs == ""} {
	error "No surfaces are visible to select from\n"
    }
    
    $struct_select_surfs add_pick_polygon_$what $poly $vect \
	$from_surfs $partial 0
}
set dont_record_command(ic_str_add_pick_polygon) 1

## Pick structured nodes based on a single location, and add them to the
## selected node surface

proc ic_str_add_pick_single {what pt vec} {
    global struct_select_surfs
    
    set from_surfs ""
    foreach ss [info commands str_surf__*] {
	if [$ss get -visible] {
	    lappend from_surfs $ss
	}
    }
    if {$from_surfs == ""} {
	error "No surfaces are visible to select from\n"
    }
    
    return [$struct_select_surfs add_pick_single_$what $pt $vec $from_surfs 0]
}
set dont_record_command(ic_str_add_pick_single) 1

## Add all nodes from the currently visible scan planes to the selection

proc ic_str_pick_scan_plane_nodes {} {
    global scanp_regions struct_select_surfs
    
    foreach n [array names scanp_regions] {
	if [$scanp_regions($n) get -visible] {
	    $struct_select_surfs add_nodes_from_surf $scanp_regions($n) 0
	}
    }
}
set dont_record_command(ic_str_pick_scan_plane_nodes) 1

## Uniquify the selection

proc ic_str_uniqify_selection {} {
    global struct_select_surfs
    $struct_select_surfs uniqify
}

## Push node positions on the selected surface

proc ic_str_push_node_positions {} {
    global struct_select_surfs
    $struct_select_surfs push_node_positions
}

## Clear node positions on the selected surface

proc ic_str_clear_node_positions {} {
    global struct_select_surfs
    $struct_select_surfs clear_node_positions
}

## Pop node positions on the selected surface

proc ic_str_pop_node_positions {} {
    global struct_select_surfs
    $struct_select_surfs pop_node_positions
}

## Drag nodes

proc ic_str_drag_nodes {startpt pt vec do_proj allow_invert} {
    global struct_select_surfs projlib
    if $do_proj { set p $projlib } else { set p "" }
    $struct_select_surfs drag_nodes $startpt $pt $vec $p $allow_invert
}

## Remove the last selection

proc ic_str_pick_remove_last {} {
    global struct_select_surfs
    $struct_select_surfs add_remove_last
}
set dont_record_command(ic_str_pick_remove_last) 1

## Check for blockinterface

proc ic_str_check_blockif_surf {type number} {
    global str_cur    
    return [$str_cur check_blockif_surf $number $type]
}
set dont_record_command(ic_str_check_blockif_surf) 1

## Return all blockinterfaces subfaces

proc ic_str_list_blockif_subfaces {} {
    global str_cur    
    return [$str_cur list_blockif_incl_periodic_subfaces]
}
set dont_record_command(ic_str_list_blockif_subfaces) 1

## Return all blockinterfaces of type <type>

proc ic_str_list_blockif_surfs {type} {
    global str_cur    
    return [$str_cur list_blockif_surfs $type]
}
set dont_record_command(ic_str_list_blockif_surfs) 1

## Return all boundary subfaces

proc ic_str_list_boundary_subfaces {} {
    global str_cur    
    return [$str_cur list_boundary_excl_periodic_subfaces]
}
set dont_record_command(ic_str_list_boundary_subfaces) 1

proc ic_str_save_previous_nodes {} {
    global str_cur   
    $str_cur save_previous_nodes
}
set dont_record_command(ic_str_save_previous_nodes) 1

## Done smoothing (glsm)

proc ic_str_glb_sm_init {} {
    global str_cur
    $str_cur glb_sm_init
}
set dont_record_command(ic_str_glb_sm_init) 1

## Post smoothing - create a cellset (glsm)

proc ic_str_post_diagnostic {type list show} {
    global str_cur struct_diag_cellset batch_mode
    global tdv_default
    ic_str_metric $type $list
    set struct_diag_cellset [str_surf -mesh $str_cur \
				 -color [$tdv_default highlight_color] \
				 -visible $show]
    if !$batch_mode { $tdv_default add_image $struct_diag_cellset }
    $struct_diag_cellset configure -shade flat_wire
    $struct_diag_cellset clear_ijk
}
set dont_record_command(ic_str_post_diagnostic) 1

## Post smoothing - add a cellset (glsm)

proc ic_str_post_add_diagnostic {iv list} {
    global struct_diag_cellset
    set iv1 [lindex $iv 1]
    set iv2 [lindex $iv 2]
    return [$struct_diag_cellset add_with_diagnostic $iv1 $iv2 1 1 $list]
}
set dont_record_command(ic_str_post_add_diagnostic) 1

## Create a non-relaxation/relaxation zone (glsm)

proc ic_str_create_zone {color shade} {
    global str_cur batch_mode
    global tdv_default
    set im [str_surf -mesh $str_cur -visible 1 -color $color \
    		     -shade $shade]
    if !$batch_mode { $tdv_default add_image $im }
    return $im
}
set dont_record_command(ic_str_create_zone) 1

## Delete the ijk zone (glsm) 

proc ic_str_delete_zone {im} {
    $im delete
}
set dont_record_command(ic_str_delete_zone) 1

## Configure the ijk zone (glsm) 

proc ic_str_configure_zone {im param value} {
    $im configure -${param} $value
}
set dont_record_command(ic_str_configure_zone) 1

## Clear the ijk zone (glsm)

proc ic_str_clear_ijk_zone {im} {
    $im clear_ijk
}
set dont_record_command(ic_str_clear_ijk_zone) 1

## Add a ijk zone (glsm)

proc ic_str_add_ijk_zone {im dom min max} {
    $im add_ijk $dom $min $max
}
set dont_record_command(ic_str_add_ijk_zone) 1

## Move a ijk zone (glsm)

proc ic_str_scanp_move_zone {type number what ext} {
    global str_cur
    set im [ic_str_get_surf_zone $type $number]
    $im scanp_move $what $ext
}
set dont_record_command(ic_str_scanp_move_zone) 1

## Get image of zone (glsm)

proc ic_str_get_surf_zone {type number} {
    global str_cur
    return [$str_cur get_surf $type $number]
}
set dont_record_command(ic_str_get_surf_zone) 1

## Struct smoothing / predefined mesh (glsm)

proc ic_str_smooth_glsm {change project smooth_domain face_methods volume_methods \
    niter nsteps maxlevel sfit conditional check_det damping vertex_fix \
    edge_freeze wedge_check multigrid2d reduced_edge fix_fam \
    inner_vol_sm ns_rel angle_freeze_edge n_iter \
    interp_faces interp_volumes prog_select threshold_det threshold_angle \
    subface_extensions ijk_extensions edge_attrib relax_subfaces \
    relaxation_zones viol_geom_zones viol_geom_subfaces base_subfaces_no \
    meshing_law subface_extend direction_vector base_regions \
    type_improve type_postsm proj_limit group_bad_elem \
    smooth_dir mesh_type smooth_ngh_method surfresolv min_mxr \
    edge_no_global_smooth incr_3d_plane_smooth relax_weights_2d \
    relax_weights_3d relax_weights_inner_2d relax_weights_inner_3d \
    n_iter_glb n_steps_glb global_vertices_opp plane_numbers \
    grid_exp_face grid_exp_vol min_res abs_dist_bnd n_points_abs_dist_bnd \
    abs_dist_subf n_abs_dist_subf vertex_attrib relaxation_factor \
    use_orthog_position use_fract_position grid_exp_rate_subf_perp \
    grid_exp_rate_subf_1 first_cell_height last_cell_height use_pthreads \
    {num_procs 0} {hostfile ""} {timeout 0} {verbose 0}} {

    global str_cur projlib

    catch {
    $str_cur smooth $projlib struct_smooth_callback $change $project \
    smooth_domain $smooth_domain \
    face_methods $face_methods \
    volume_methods $volume_methods \
    niter $niter \
    nsteps $nsteps \
    maxlevel $maxlevel \
    sfit $sfit \
    conditional $conditional \
    check_det $check_det \
    damping $damping \
    vertex_fix $vertex_fix \
    edge_freeze $edge_freeze \
    wedge_check $wedge_check \
    fix_fam $fix_fam \
    multigrid2d $multigrid2d \
    reduced_edge $reduced_edge \
    inner_vol_sm $inner_vol_sm \
    ns_rel $ns_rel \
    angle_freeze_edge $angle_freeze_edge \
    n_iter $n_iter \
    interp_faces $interp_faces \
    interp_volumes $interp_volumes \
    prog_select $prog_select \
    threshold_det $threshold_det \
    threshold_angle $threshold_angle \
    subface_extensions $subface_extensions \
    ijk_extensions $ijk_extensions \
    edge_attrib $edge_attrib \
    relax_subfaces $relax_subfaces \
    relaxation_zones $relaxation_zones \
    viol_geom_zones $viol_geom_zones \
    viol_geom_subfaces $viol_geom_subfaces \
    base_subfaces_no $base_subfaces_no \
    meshing_law $meshing_law \
    subface_extend $subface_extend \
    direction_vector $direction_vector \
    base_regions $base_regions \
    type_improve $type_improve \
    type_postsm $type_postsm \
    proj_limit $proj_limit \
    group_bad_elem $group_bad_elem \
    smooth_dir $smooth_dir \
    mesh_type $mesh_type \
    smooth_ngh_method $smooth_ngh_method \
    surfresolv $surfresolv \
    min_mxr $min_mxr \
    edge_no_global_smooth $edge_no_global_smooth \
    incr_3d_plane_smooth $incr_3d_plane_smooth \
    relax_weights_2d $relax_weights_2d \
    relax_weights_3d $relax_weights_3d \
    relax_weights_inner_2d $relax_weights_inner_2d \
    relax_weights_inner_3d $relax_weights_inner_3d \
    n_iter_glb $n_iter_glb \
    n_steps_glb $n_steps_glb \
    global_vertices_opp $global_vertices_opp \
    plane_nos $plane_numbers \
    grid_exp_face $grid_exp_face \
    grid_exp_vol $grid_exp_vol \
    min_res $min_res \
    abs_dist_bnd $abs_dist_bnd \
    n_points_abs_dist_bnd $n_points_abs_dist_bnd \
    abs_dist_subf $abs_dist_subf \
    n_abs_dist_subf $n_abs_dist_subf \
    vertex_attrib $vertex_attrib \
    relaxation_factor $relaxation_factor \
    use_orthog_position $use_orthog_position \
    use_fract_position $use_fract_position \
    grid_exp_rate_subf_perp $grid_exp_rate_subf_perp \
    grid_exp_rate_subf_1 $grid_exp_rate_subf_1 \
    first_cell_height $first_cell_height \
    last_cell_height $last_cell_height \
    use_pthreads $use_pthreads \
    num_procs $num_procs \
    hostfile $hostfile \
    timeout $timeout \
    verbose $verbose
    }
}

## After struct smoothing/predefined mesh (glsm) clear all

proc ic_str_smooth_glsm_clear {} {
    if { [info procs etm_done_smoot*] != ""} {
        etm_done_smooth
    }
    get_etm_undo_option 1
}

## Get number of nodes

proc ic_str_get_num_nodes {what num} {
    global str_cur
    set s [$str_cur get_surf $what $num]
    return [$s num_nodes]
}
set dont_record_command(ic_str_get_num_nodes) 1

## Get bounding box

proc ic_str_get_bbox {what num} {
    global str_cur
    set s [$str_cur get_surf $what $num]
    return [$s get_bbox]
}
set dont_record_command(ic_str_get_bbox) 1

## Move nodes

proc ic_str_move_nodes_exact {what num set_pos dox doy doz xv yv zv} {
    global str_cur struct_select_surfs
    if {$num == "selected"} {
	set s $struct_select_surfs
    } else {
	set s [$str_cur get_surf $what $num]
    }
    return [$s move_nodes_exact $set_pos "$dox $doy $doz" "$xv $yv $zv"]
}
set dont_record_command(ic_str_move_nodes_exact) 1

## return all edges from a list of vertices

proc ic_str_list_vertex_edges {numbers} {
    global str_cur    
    return [$str_cur list_vertex_edges $numbers]
}
set dont_record_command(ic_str_list_vertex_edges) 1

## return all vertices from a list of edges

proc ic_str_list_edge_vertices {numbers} {
    global str_cur    
    return [$str_cur list_edge_vertices $numbers]
}
set dont_record_command(ic_str_list_edge_vertices) 1

proc ic_str_nspacking {dir nspack_domain base_subfaces_no \
    inside_layers outside_layers subface_extend first_layer_height \
    compute_n_outlayers} {
    global str_cur 
    
    $str_cur nspack struct_smooth_callback 1 $dir \
  		  nspack_domain $nspack_domain \
      		  sfit 1 \
      		  base_subfaces_no $base_subfaces_no \
      		  base_regions "" \
      		  inside_layers $inside_layers \
      		  outside_layers $outside_layers \
      		  subface_extend $subface_extend \
      		  first_layer_height $first_layer_height \
      		  compute_n_outlayers $compute_n_outlayers
}
set dont_record_command(ic_str_nspacking) 1

proc ic_str_calc_load_balancing {np {ctype 0} {crit 2} {all_info 1} \
				{gnum 6000} {gpow 0.9} {wg 0.875} {ws 0.125} \
				{shw 1.0} {snum 256}} {
    global str_cur

    $str_cur calc_load_balancing $np $ctype $crit $all_info $gnum $gpow \
				 $wg $ws $shw $snum
}
set dont_record_command(ic_calc_load_balancing) 1
