# author/changes - jari.spaete@ansys.com
# Stuff to deal with mesh, geometry, and blocking subsets

proc aie_subset_names {} {
    foreach name [ic_uns_subset_list] { set ret($name) 1 }
    foreach name [ic_geo_subset_list] { set ret($name) 1 }
    return [lsort [array names ret]]
}

proc aie_info_geom_subset {name} {
    set surfaces 0
    set curves 0
    set points 0
    set bodies 0
    foreach item [ic_geo_subset_get_items $name] {
        if {$item == "surface"} {incr surfaces}
        if {$item == "curve"} {incr curves}
        if {$item == "point"} {incr points}
        if {$item == "body"} {incr bodies}
    }
    mess "\n\n---------------------\n"
    mess "Info for $name\n"
    if $surfaces {mess "Subset contains $surfaces surfaces\n"}
    if $curves {mess "Subset contains $curves curves\n"}
    if $points {mess "Subset contains $points points\n"}
    if $bodies {mess "Subset contains $bodies bodies\n"}
    mess "Subset contains part(s) [ic_geo_subset_list_families $name]\n"
    mess "Bounding box around subset is [ic_geo_subset_bbox $name]\n"
    mess "---------------------\n"
}

proc aie_add_to_geom_subset {name} {
    set Names [geo_select entity 0 "" 0 0 "" 0 "" 0 1]
    set Names2 ""
    foreach ll $Names {
        set t [lindex $ll 0]
        foreach n [lrange $ll 1 end] { lappend Names2 $t $n }
    }
    ic_geo_subset_add_items $name $Names2
    aie_reset_geo_selected
}

proc aie_remove_from_geom_subset {name} {
    set Names [geo_select entity]
    set Names2 ""
    foreach ll $Names {
	set t [lindex $ll 0]
	foreach n [lrange $ll 1 end] { lappend Names2 $t $n }
    }
    ic_geo_subset_remove_items $name $Names2
    aie_reset_geo_selected
#    modifyGeomSubsetDEZ unload
}

proc aie_copy_geom_subset {name} {
    set newname [ic_geo_subset_unused_name Subset]
    set newname [question_box .newname "New name" "Name for copy of subset $name" $newname]
    if {$newname == ""} return
   
    ic_geo_subset_copy $name $newname
    ::AIEnv::GUIManagement::Tree::AddGroup geom_subset $newname
    ::AIEnv::GUIManagement::Tree::ToggleGroupVisibility geom_subset $newname same
}

proc aie_rename_geom_subset {name} {
    set newname [question_box .newname "New name" "New name for subset $name" $name]
    if {($newname == "") || ($newname == $name)} return
    
    if [ic_geo_subset_exists $newname] {
        user_error "Subset $newname already exists"
        return
    }
    ic_geo_subset_copy $name $newname
    ic_geo_subset_delete $name
    ::AIEnv::GUIManagement::Tree::RenameGroup geom_subset $name $newname
    ::AIEnv::GUIManagement::Tree::ToggleGroupVisibility geom_subset $newname same
    
    modifyGeomSubsetDEZ unload
}

proc aie_delete_geom_subset {names {could_be_assem 1}} {
    if $could_be_assem {
	set new_names ""
	foreach name $names {
	    set l [string length $name]
	    foreach s [ic_geo_subset_list] {
            set ss $name/ 
            if {[string range $s 0 $l] == $ss} {lappend new_names $s}
	    }
	    lappend new_names $name
	}
	set names $new_names
    }
    foreach name $names {
        ic_geo_subset_delete $name
        ::AIEnv::GUIManagement::Tree::DeleteGroup geom_subset $name 0
    }
    modifyGeomSubsetDEZ unload
}

proc aie_edit_geom_subset {name} {
    global current_subset_to_load

    if {$name == "*"} {
        createGeomSubsetDEZ show
    } else {
        if ![ic_geo_subset_exists $name] {
            mess "There is no subset named \"$name\" - please open up the branch and modify the lowest-level entries\n" red
            return
        }
        set current_subset_to_load(name) $name
        modifyGeomSubsetDEZ show
        unset current_subset_to_load(name)
        modifyGeomSubsetDEZ set name $name
    }
}

proc aie_geom_subset_set_visible {name on} {
    if {$name == "*"} {
	foreach name [ic_geo_subset_list] {
	    ic_geo_subset_visible $name $on
	    ::AIEnv::GUIManagement::Tree::NodeVisibleStatus geom_subset $name [expr {$on ? 1 : -1}]
	}
	    ::AIEnv::GUIManagement::Tree::NodeVisibleStatus geom_subset * [expr {$on ? 1 : -1}]
    } else {
	    ic_geo_subset_visible $name $on
	    ::AIEnv::GUIManagement::Tree::NodeVisibleStatus geom_subset $name [expr {$on ? 1 : -1}]
    }
}


proc aie_clear_geom_subset {names} {
    foreach name $names {
        foreach name2 [concat [ic_geo_subset_list $name] [ic_geo_subset_list $name/*]] {
            ic_geo_subset_clear $name2
        }
    }
}

proc onCreateGeomSubsetDEZLoad {} {
    global current_subset_to_load
    if [info exists current_subset_to_load(name)] {
        set name $current_subset_to_load(name)
    } else {
        set name [ic_geo_subset_unused_name Subset]
    }
    set GeomSubsetList [lsort -ascii [ic_geo_subset_list]]
    set entityList ""
    set select_geom_0d 0
    foreach sd {1 2 3} {
        set select_geom_${sd}d 1
    }
    geo_select_either_set_prefix ::AIEnv::DEZ::createGeomSubsetDEZ::select_
    set AllowActiveReload 1
    set currentGeomSubsetCreateMethod 0
    set number 1
    set layerAddinVal 0
    set layerRemoveinVal 0
    set surfaceList ""
    set angle 180
    set curvature 360
    if {[info exists mesh_max_size_attr] && ($mesh_max_size_attr == "")} {
		set mesh_max_size_attr "< 1"
	}
    if {[info exists curve_len_attr] && ($curve_len_attr == "")} {
		set curve_len_attr "> 100"
	}
    if {[info exists surf_area_attr] && ($surf_area_attr == "")} {
		set surf_area_attr "> 100"
	}		
}

proc onModifyGeomSubsetDEZLoad {} {
    global current_subset_to_load

    if [info exists current_subset_to_load(name)] {
        set name $current_subset_to_load(name)
    } else {
        set name [ic_geo_subset_unused_name Subset]
    }
    set entityList ""
    set select_geom_0d 0
    foreach sd {1 2 3} {
        set select_geom_${sd}d 1
    }
    
    geo_select_either_set_prefix ::AIEnv::DEZ::modifyGeomSubsetDEZ::select_
    set AllowActiveReload 1
    set currentGeomSubsetCreateMethod 0
    set number 1
    set layerAddinVal 0
    set layerRemoveinVal 0
    set modifyGeomSubsetSelectVal 0
    set removeGeomOptionsVal 0
    ::AIEnv::GUIManagement::ExclusiveGroup::DropDownHandler layerGeomAddin ""
    if {[trace vinfo layerGeomAddinVal] != ""} {
        trace vdelete layerGeomAddinVal w aie_subset_add_to_one_side
    }
    trace variable layerGeomAddinVal w aie_subset_add_to_one_side
    if {[trace vinfo modifyGeomSubsetSelectVal] != ""} {
        trace vdelete modifyGeomSubsetSelectVal w aie_subset_add_to_one_side
    }
    trace variable modifyGeomSubsetSelectVal w aie_subset_add_to_one_side
}

proc aie_subset_add_to_one_side {na el {op ""}} {
    global show_tmp_subset
    
    set sel [modifyGeomSubsetDEZ get modifyGeomSubsetSelectVal]
    set add [modifyGeomSubsetDEZ get layerGeomAddinVal]
    if {(($sel != 2) || ($add != 3)) || ($op == "done")} {
        foreach item [array names show_tmp_subset] {
            set type [lindex [split $item ,] 0]
            set ent [lindex [split $item ,] 1]
            if {[ic_geo_check_objects_exist $type $ent] == ""} continue
            ic_show_geo_selected $type $ent 0
            unset show_tmp_subset($type,$ent)
        } 
        return
    }
    foreach item [array names show_tmp_subset] { unset show_tmp_subset($item) }
    
    busy 1
    set name [modifyGeomSubsetDEZ get name]
    foreach {n v} [ic_geo_subset_get_items $name] {
        if {$n == "surface"} {
            foreach crv [ic_geo_boundary surface $v] {
                if {($crv != "$v") && ![info exists show_tmp_subset(curve,$crv)]} {
                    set show_tmp_subset(curve,$crv) 1
                    ic_show_geo_selected curve $crv 1 "" 1
                }
                foreach sf [ic_geo_incident curve $crv] {
                    if {($sf != "$v") && ![info exists show_tmp_subset(surface,$sf)]} {
                        set show_tmp_subset(surface,$sf) 1
                        ic_show_geo_selected surface $sf 1 "" 1
                    }
                }
            }
        } elseif {$n == "curve"} {
            foreach sf [ic_geo_incident curve $v] {
                if {($sf != "$v") && ![info exists show_tmp_subset(surface,$sf)]} {
                    set show_tmp_subset(surface,$sf) 1
                    ic_show_geo_selected surface $sf 1 "" 1
                }
            }
        }
    } 
    foreach {n v} [ic_geo_subset_get_items $name] {
        ic_show_geo_selected $n $v 0
    }
    if ![info exists show_tmp_subset] {
        mess "No entity found for \"At one Side\" option.\n"
    }
    busy 0
} 

proc aie_subset_curvature_spec {num {dez ""}} {}

proc aie_subset_angle_spec {num {dez ""}} {}

proc onCreateGeomSubsetDEZApply {} {
    global current_subset_to_load

    if {$name == ""} { set name [ic_geo_subset_unused_name Subset] }
    regsub -all " " $name _ name
    regsub -all ! $name _ name
    regsub -all \\^ $name _ name
    set dims ""
    foreach d {0 1 2 3} {
	if [set select_geom_${d}d] {
	    lappend dims $d
	}
    }
    if {$dims == ""} {
	mess "No types are selected\n" red
	return
    }
    if [info exists createGeomSubsetSelectVal] {
	switch $createGeomSubsetSelectVal {
	    0 {
		ic_geo_subset_add_items $name $entityList
	    }
	    1 {
		if {$surfaceList == ""} {mess "No surfaces selected\n" red ; return}
		ic_undo_group_begin
#		tdv_active 0
		set regions [ic_geo_sort_by_srf_area [ic_geo_make_conn_regions surface $surfaceList $angle $curvature] -decreasing]
		set p 1001
		ic_geo_subset_add_items $name ""
		foreach r $regions {
		    set pp [string range $p 1 end]
		    set nname $name/REG$pp
		    incr p
		    set sublist ""
		    foreach rr $r {lappend sublist surface $rr}
		    ic_geo_subset_add_items $nname $sublist
		}
		aie_getBatchGeomDisplay
#		tdv_active 1
		ic_undo_group_end
		set surfaceList ""
		if [info exists current_subset_to_load(name)] {
		    createGeomSubsetDEZ set name $current_subset_to_load(name)
		} else {
		    createGeomSubsetDEZ set name [ic_geo_subset_unused_name Subset]
                    mess "name is $name\n"
		}
	    }
	    2 {
			set list [GeomSubRestrEval]
			if {$list == ""} return
			ic_geo_subset_add_items $name $list
			ic_mess "Done: subset $name\n"
			ic_highlight
	    }
	    3 {
		error NYI
		set p1 [list $minx $miny $minz]
		set p2 [list $maxx $maxy $maxz]
		ic_uns_subset_add_region $uns $p1 $p2 $BoxFlag $dims
	    }
	}
    }
    if {$createGeomSubsetSelectVal != 1} {
	::AIEnv::GUIManagement::Tree::AddGroup geom_subset $name 1
	::AIEnv::GUIManagement::Tree::ToggleGroupVisibility geom_subset $name same
    }
    if {$name == "" || [ic_geo_subset_exists $name]} {
        createGeomSubsetDEZ set name [ic_geo_subset_unused_name Subset]
    }
     set GeomSubsetList [lsort -ascii [ic_geo_subset_list]]
}

proc onModifyGeomSubsetDEZApply {} {
    if [info exists modifyGeomSubsetSelectVal] {
	switch $modifyGeomSubsetSelectVal {
	    0 { # Add to GeomSubset by Selection
		ic_geo_subset_add_items $name $entityList
	    }
	    1 { # Remove from GeomSubset by Selection
		switch $removeGeomOptionsVal {
                    0 {
		        ic_geo_subset_remove_items $name $entityList
                    }
                    1 { # Remove Layer
                        for {set i 0} {$i < $number} {incr i} {
                            ic_geo_subset_remove_layer $name
                        }
                    }
                }
	    }
	    2 { # Add Layer(s) to GeomSubset
		switch $layerGeomAddinVal {
		    0 { # Add Layer
			for {set i 0} {$i < $number} {incr i} {
			    set nn [ic_geo_subset_add_layer $name 0 0 all]
			}
		    }
		    1 { # All Attached
			set nn [ic_geo_subset_add_layer $name 1 0 all]
		    }
		    2 { # To Angle
			set nn [ic_geo_subset_add_layer $name 1 $angle all]
		    }
		    3 { # Add at one side (curves/surfaces supported)
			if {$entitySideList != ""} {
			    ic_geo_subset_add_items $name $entitySideList
			    set nn 1
			} else {
			    set nn 0
			}
		    }
		}
		mess "$nn more entities\n"
	    }
	    3 { # Remove Layer(s) from GeomSubset
		# this is not implemented
		switch $layerRemoveinVal {
		    0 { # Remove Layer
		    }
		    1 { # All Attached
		    }
		    2 { # To Angle
		    }
		}
	    }
	}
    }
    set number $number ;# reenable the GUI
}

proc onmodifyGeomSubsetPickFinish {} {
    global auto_pick_mode
    if {$auto_pick_mode && $entityList != ""} {
        modifyGeomSubsetDEZ apply
        modifyGeomSubsetPick pick
    }
}

proc onmodifyGeomSubsetSidePickFinish {} {
    global auto_pick_mode
    if {$auto_pick_mode && $entitySideList != ""} {
        modifyGeomSubsetDEZ apply
        set entitySideList ""
        aie_subset_add_to_one_side "" "" ""
        modifyGeomSubsetSidePick pick
    }
}

proc onremoveGeomSubsetPickFinish {} {
    global auto_pick_mode
    if {$auto_pick_mode && $entityList != ""} {
        modifyGeomSubsetDEZ apply
        removeGeomSubsetPick pick
    }
}

proc oncreateGeomSubSelLoad {} {
    global auto_pick_mode
    if $auto_pick_mode { 
	createGeomSubsetPick pick
    }
}

proc oncreateGeomSubsetPickFinish {} {
    global auto_pick_mode
    if {$auto_pick_mode && $entityList != ""} {
	createGeomSubsetDEZ apply
	createGeomSubsetPick pick
    }
}

proc onmodifyGeomSubSelLoad {} {
    global auto_pick_mode
    if {$auto_pick_mode && $entityList != ""} { 
	modifyGeomSubsetPick pick
    } 
}

proc onCreateGeomSubsetDEZUnload {} {
    geo_select_either_set_prefix ""
}

proc onModifyGeomSubsetDEZUnload {} {
    geo_select_either_set_prefix ""
    aie_subset_add_to_one_side "" "" "done"
    if {[trace vinfo layerGeomAddinVal] != ""} {
        trace vdelete layerGeomAddinVal w aie_subset_add_to_one_side
    }
    if {[trace vinfo modifyGeomSubsetSelectVal] != ""} {
        trace vdelete modifyGeomSubsetSelectVal w aie_subset_add_to_one_side
    }
}

proc GeomSubRestrProc {} {
	::AIEnv::DEZ::createGeomSubsetDEZ::GeomSubRestrEval
}
namespace eval ::AIEnv::DEZ::createGeomSubsetDEZ {
proc GeomSubRestrEval {} {
foreach v {entityList GeomSubRestrGGMeshVal mesh_max_size_attr
	GeomSubRestrGGLengthVal curve_len_attr GeomSubRestrGGAreaVal surf_area_attr
} {
	variable $v
}
	ic_reset_geo_selected
	if {$entityList == ""} {
		set srfs [ic_geo_get_objects surface]
		set crvs [ic_geo_get_objects curve]
	} else {
		set srfs ""
		set crvs ""
		foreach {type ent} $entityList {
			if {$type == "curve"} {lappend crvs $ent}
			if {$type == "surface"} {lappend srfs $ent}
		}
	}
	set restrList ""
	set restrSrf ""
	set restrCrv ""
	set minArea 1e8
	set maxArea 0
	set minLength 1e8
	set maxLength 0
	set maxMesh -1
	set minMesh 1e8
	foreach ent $srfs {
		if {!$GeomSubRestrGGMeshVal && !$GeomSubRestrGGAreaVal} break
		if $GeomSubRestrGGMeshVal {
			set params [ic_set_meshing_params surface $ent]
			set MeshOk 1
			foreach {pn pv} $params {
				if {$pn == "emax"} {			
					set MeshOk [aie_compare_value $pv $mesh_max_size_attr]
					if {$pv > $maxMesh} {set maxMesh $pv}
					if {$pv < $minMesh} {set minMesh $pv}					
					break
				}
			}
			if !$MeshOk continue
		}
		if $GeomSubRestrGGAreaVal {
			set pv [ic_geo_srf_area $ent]
			set AreaOk [aie_compare_value $pv $surf_area_attr]
			if {$pv < $minArea} {set minArea $pv}
			if {$pv > $maxArea} {set maxArea $pv}			
			if !$AreaOk continue
		}
		lappend restrSrf $ent
		lappend restrList surface $ent
	}
	foreach ent $crvs {
		if {!$GeomSubRestrGGMeshVal && !$GeomSubRestrGGLengthVal} break
		if $GeomSubRestrGGMeshVal {
			set params [ic_set_meshing_params curve $ent]
			set MeshOk 1
			foreach {pn pv} $params {
				if {$pn == "emax"} {			
					set MeshOk [aie_compare_value $pv $mesh_max_size_attr]
					if {$pv > $maxMesh} {set maxMesh $pv}
					if {$pv < $minMesh} {set minMesh $pv}		
					break
				}
			}
			if !$MeshOk continue
		}
		if $GeomSubRestrGGLengthVal {
			set pv [ic_geo_crv_length $ent]
			set LengthOk [aie_compare_value $pv $curve_len_attr]
			if {$pv < $minLength} {set minLength $pv}
			if {$pv > $maxLength} {set maxLength $pv}	
			if !$LengthOk continue
		}
		lappend restrCrv $ent
		lappend restrList curve $ent	
	}
	ic_highlight type curve names $restrCrv
	if [llength $restrSrf] {
		ic_highlight type surface add $restrSrf
	}
	set ns [llength $restrSrf]
	set nc [llength $restrCrv]
	set ne [expr $ns+$nc]
	if {$maxArea > 0} {
		ic_mess "Surface area: constraints $surf_area_attr, selected $ns,  min = $minArea, max = $maxArea\n" 
	}
	if {$maxLength > 0} {
		ic_mess "Curve length: constraints $curve_len_attr, selected $nc, min = $minLength, max = $maxLength\n" 
	}
	if {$maxMesh >= 0} {
		ic_mess "Mesh max size: constraints $mesh_max_size_attr, selected $ne, min = $minMesh, max = $maxMesh\n" 
	}
	ic_mess \n				
	return $restrList
}
}			

proc aie_init_geom_subsets {} {
    ::AIEnv::GUIManagement::Tree::doInsertIfNeeded geom_subsetNode   
    foreach name [ic_geo_subset_list] {
        ::AIEnv::GUIManagement::Tree::AddGroup geom_subset $name 0
        ::AIEnv::GUIManagement::Tree::ToggleGroupVisibility geom_subset $name same
    }
}

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

# this is supposed to create a mesh subset from the mesh attached to a geometry object.

proc aie_create_mesh_subset {name what} {

    ic_uns_get_attached_elements [lindex $what 0] [lindex $what 1] $name
    ::AIEnv::GUIManagement::Tree::AddGroup mesh_subset $name 0
    ::AIEnv::GUIManagement::Tree::ToggleGroupVisibility mesh_subset $name same
}

proc aie_new_mesh_subset {name} {

    ic_uns_subset_create $name
    ::AIEnv::GUIManagement::Tree::AddGroup mesh_subset $name 0
    ::AIEnv::GUIManagement::Tree::ToggleGroupVisibility mesh_subset $name same
    return $name
}

proc aie_copy_mesh_subset {name} {

    if ![ic_uns_subset_exists $name] {
        mess "There is no subset named \"$name\" - please open up the branch and modify the lowest-level entries\n" red
        return
    }
    set newname [ic_uns_subset_unused_name Subset]
    set newname [question_box .newname "New name" "Name for copy of subset $name" $newname]
    if {$newname == ""} return
    
    set newname [ic_uns_subset_create $newname 1 $name]
    ::AIEnv::GUIManagement::Tree::AddGroup mesh_subset $newname
    ::AIEnv::GUIManagement::Tree::ToggleGroupVisibility mesh_subset $newname same
}

proc aie_rename_mesh_subset {name} {

    if ![ic_uns_subset_exists $name] {
        mess "There is no subset named \"$name\" - please open up the branch and modify the lowest-level entries\n" red
        return
    }
    set newname [question_box .newname "New name" "New name for subset $name" $name]
    if {($newname == "") || ($newname == $name)} return
    
    if [ic_uns_subset_exists $newname] {
        user_error "Subset $newname already exists"
        return
    }
    set newname [ic_uns_subset_create $newname 1 $name]
    ic_uns_subset_delete $name
    
    ::AIEnv::GUIManagement::Tree::RenameGroup mesh_subset $name $newname
    if {[regexp \/ $name]} {
        set idx [string first / $name]
        if {$idx != -1 && $idx != 0} {
            set nname1 [string range $name 0 [expr $idx - 1]]
            set nname2 mesh_subset-[string range $name 0 [expr $idx - 1]]
            if {[::AIEnv::GUIManagement::Tree::GetChildren $nname2] == ""} {
                ::AIEnv::GUIManagement::Tree::DeleteGroup mesh_subset $nname1 0
            }
        }
    }
    modifyMeshSubsetDEZ unload
}

proc aie_delete_mesh_subset {names} {

    foreach name $names {
	if [ic_uns_subset_exists $name] {
	    ic_uns_subset_delete $name
	    ::AIEnv::GUIManagement::Tree::DeleteGroup mesh_subset $name 0
	} else {
	    set nname mesh_subset-$name
	    regsub -all {[ \t\n]} $nname _ nname
	    set children [::AIEnv::GUIManagement::Tree::GetChildren $nname]
	    if {$children != ""} {
	        mess "There is no subset named \"$name\" - please open up the branch and modify the lowest-level entries\n" red
	        return
	    } else {
	        ::AIEnv::GUIManagement::Tree::DeleteGroup mesh_subset $name 0
	    }
	}
    }
    modifyMeshSubsetDEZ unload
}

proc aie_edit_mesh_subset {name} {

    global current_subset_to_load
    if {$name == "*"} {
	    createMeshSubsetDEZ show
    } else {
	    if ![ic_uns_subset_exists $name] {
	        mess "There is no subset named \"$name\" - please open up the branch and modify the lowest-level entries\n" red
	        return
	    }
        select_toolbar_delete 
	    set current_subset_to_load(name) $name
	    modifyMeshSubsetDEZ show
	    unset current_subset_to_load(name)
	    modifyMeshSubsetDEZ set name $name
    }
}

proc aie_mesh_subset_set_visible {name on} {

    if {$name == "*"} {
        foreach name [ic_uns_subset_list 1] {
            ic_uns_subset_visible $name $on
        }
    } else {
        ic_uns_subset_visible $name $on
    }
}

proc aie_clear_mesh_subset {names} {

    foreach name $names {
	    foreach name2 [concat [ic_uns_map_list 0 $name] [ic_uns_map_list 0 $name/*]] {
	        ic_uns_subset_clear $name2
	    }
    }
}

proc aie_remove_from_mesh_subset {name} {

    if ![ic_uns_subset_exists $name] {
        mess "There is no subset named \"$name\" - please open up the branch and modify the lowest-level entries\n" red
        return
    }
    set entityList [select_unstruct element]
    if {$entityList != ""} {
        ic_uns_subset_subtract_from $name $entityList
        ic_uns_subset_delete $entityList
        if ![ic_uns_subset_count_elements $name] { ic_uns_subset_visible $name 1 }
    }
}

proc aie_add_to_mesh_subset {name} {

    if ![ic_uns_subset_exists $name] {
        mess "There is no subset named \"$name\" - please open up the branch and modify the lowest-level entries\n" red
        return
    }
    set entityList [select_unstruct element]
    if {$entityList != ""} {
        ic_uns_subset_add_from $name $entityList
        ic_uns_subset_delete $entityList
    }
}

proc aie_break_by_part_mesh_subset {name} {

    catch { array unset sinfo }
    foreach e [ic_uns_subset_list_elements $name] {
        if {[lindex $e 0] == "VERTEX"} continue
        lappend sinfo([lindex $e 4],[lindex $e 0]) [lindex $e 2]
    }
    set delete 1
    foreach e [array names sinfo] {
        if ![ic_uns_subset_exists [lindex [split $e ,] 0]] {
            set s [aie_new_mesh_subset [lindex [split $e ,] 0]]
            mess "Creating mesh subset $s\n"
        } else {
            set s [lindex [split $e ,] 0]
            #mess "Adding to mesh subset $s\n"
        }
        ic_uns_subset_add_number $s $sinfo($e) 2 [lindex [split $e ,] 1]
    }
    if $delete {
        aie_delete_mesh_subset [list $name]
    }
}

proc aie_break_by_connectivity_mesh_subset {name} {
    foreach s [ic_uns_subset_into_connected_regions2 $name all] {
        ::AIEnv::GUIManagement::Tree::AddGroup mesh_subset $s 0
        ::AIEnv::GUIManagement::Tree::ToggleGroupVisibility mesh_subset $s same
    }
}

proc aie_info_mesh_subset {name} {

    if ![ic_uns_subset_exists $name] {
        mess "There is no subset named \"$name\" - please open up the branch and modify the lowest-level entries\n" red
        return
    }
    mess "\n\n---------------------\n"
    mess "Info for $name\n"
    set nums [ic_uns_subset_count_elements $name]
    mess "Subset contains $nums elements\n"
#    mess "subset contains [ic_uns_subset_count_nodes $name] nodes\n"
    if $nums {
        mess "Subset contains type(s) [ic_uns_subset_list_types $name]\n"
        mess "Subset contains part(s) [ic_uns_subset_list_families $name]\n"
        set bbox [ic_uns_subset_bbox $name]
        set lcs [ic_csystem_get_current]
        if {$lcs != "global"} {
            set min [ic_coords_into_local [lindex $bbox 0]]
            set min "[format %g [lindex $min 0]] [format %g [lindex $min 1]] [format %g [lindex $min 2]]"
            set max [ic_coords_into_local [lindex $bbox 1]]
            set max "[format %g [lindex $max 0]] [format %g [lindex $max 1]] [format %g [lindex $max 2]]"
            mess "Bounding box around subset is $bbox (in $lcs: \{$min\} \{$max\})\n"
        } else {
            mess "Bounding box around subset is $bbox\n"
        }
    }
    mess "---------------------\n"
}

proc aie_promote_to_elset_mesh_subset {name} {

    if ![ic_uns_subset_exists $name] {
        mess "There is no subset named \"$name\" - please open up the branch and modify the lowest-level entries\n" red
        return
    }
    if {[string range $name 0 11] == "ELEMENT_SETS"} {
        mess "This subset is already marked as an element set. \n" red
        return
    }
    if {$name == ""} return
    set place [string last / $name]
    set nname [string range $name [expr $place + 1] end]

    set newname ELEMENT_SETS/$nname
    
    if [ic_uns_subset_exists $newname] {
        user_error "Subset $newname already exists"
        return
    }
    set newname [ic_uns_subset_create $newname 1 $name]
    ic_uns_subset_delete $name
    
    ::AIEnv::GUIManagement::Tree::RenameGroup mesh_subset $name $newname
    modifyMeshSubsetDEZ unload
    aie_subset_mesh_shading
}

proc aie_promote_to_nset_mesh_subset {name} {

    if ![ic_uns_subset_exists $name] {
        mess "There is no subset named \"$name\" - please open up the branch and modify the lowest-level entries\n" red
        return
    }
    if {[string range $name 0 8] == "NODE_SETS"} {
        mess "This subset is already marked as a node set. \n" red
        return
    }
    if {$name == ""} return
    set place [string last / $name]
    set nname [string range $name [expr $place + 1] end]

    set newname NODE_SETS/$nname
    
    if [ic_uns_subset_exists $newname] {
        user_error "Subset $newname already exists"
        return
    }
    set newname [ic_uns_subset_create $newname 1 $name]
    ic_uns_subset_delete $name
    
    ::AIEnv::GUIManagement::Tree::RenameGroup mesh_subset $name $newname
    modifyMeshSubsetDEZ unload
    aie_subset_mesh_shading
}

proc aie_mesh_subset_dezbut_clear {} {
    ic_uns_subset_clear $name
    mess "Removed all elements from subset\n"
}

proc aie_mesh_subset_dezbut_reset {} {
    ic_uns_update_family_type $name [ic_uns_subset_list_families Selected] \
	[ic_uns_subset_list_types Selected] update 1
}

proc aie_mesh_subset_dezbut_active {} {
    ic_uns_update_family_type $name [ic_uns_subset_list_families Selected] \
	[ic_uns_subset_list_types Selected] restrict_to 1
}

proc aie_mesh_subset_worst_element {metric {parts ""} {types ""}} {
    if ![ic_uns_is_loaded] {
        mess "No mesh is currently loaded\n" red
        return
    }
    set metric_map [ic_uns_create_diagnostic_subset 0]
    if {$parts == ""} {set parts [ic_uns_list_families]}
    if {$types == ""} {set types [list TRI_3 QUAD_4 TETRA_4 HEXA_8 PENTA_6 PYRA_5]}
    ic_uns_subset_add_families_and_types $metric_map $parts $types
    set worst_qual [lindex [ic_uns_metric $metric_map $metric] 3]
    mess "worst quality is $worst_qual\n" red
    set worst_el_sub [ic_uns_create_diagnostic_subset 0]
    ic_uns_set_with_diagnostic $worst_el_sub $metric_map [list [list [expr $worst_qual - 0.000001] [expr $worst_qual + 0.000001]]]
    mess " [ic_uns_subset_count_elements $worst_el_sub] element with this metric\n" red
    ic_uns_subset_delete $metric_map
    #Delete the subset for the worst element and add stuff from map.
    ic_uns_subset_delete WORST_ELEMENT_SUBSET
    set subset [ic_uns_subset_create WORST_ELEMENT_SUBSET]
    ic_uns_subset_add_from $subset $worst_el_sub
    ic_uns_subset_delete $worst_el_sub
    if {"" != [info commands aie_subset_put_in_tree]} { aie_subset_put_in_tree mesh $subset }
}

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

proc onCreateMeshSubsetDEZLoad {} {
    global current_subset_to_load
    if [info exists current_subset_to_load(name)] {
        set name $current_subset_to_load(name)
    } else {
        set name [ic_uns_subset_unused_name Subset]
    }
    set entityList ""
    set select_mesh_0d 0
    foreach sd {1 2 3} {
        set select_mesh_${sd}d 1
    }
    geo_select_either_set_prefix ::AIEnv::DEZ::createMeshSubsetDEZ::select_
    set AllowActiveReload 1
    set currentMeshSubsetCreateMethod 0
    set number 1

    set layerAddinVal 0
    set layerRemoveinVal 0
    set elem_numbers 1
}

proc onModifyMeshSubsetDEZLoad {} {
    global current_subset_to_load tdv_default

    if [info exists current_subset_to_load(name)] {
        set name $current_subset_to_load(name)
    } else {
        set name [ic_uns_subset_unused_name Subset]
    }
    set entityList ""
    set select_mesh_0d 0
    foreach sd {1 2 3} {
        set select_mesh_${sd}d 1
    }
    
    geo_select_either_set_prefix ::AIEnv::DEZ::modifyMeshSubsetDEZ::select_
    set AllowActiveReload 1
    set currentMeshSubsetCreateMethod 0
    set number 1
    set elem_num 1
    set other_name ""
    set layerAddinVal 0
    set layerRemoveinVal 0

    set bb [$tdv_default bbox interesting]
    if {$bb != ""} {
        foreach c $bb m {min max} {
	        foreach v $c x {x y z} {
		        set $m$x [format %g $v]
	        }
	    }
    }
    set other_choices [ldelete [ic_uns_subset_list] $name]
}

proc onCreateMeshSubsetDEZApply {} {
    global options beta_mode disp_options

    if {$name == "" || [ic_uns_subset_exists $name]} {
        set name [ic_uns_subset_unused_name Subset]
    }
    set dims ""
    foreach d {0 1 2 3} {
	    if [set select_mesh_${d}d] {
	        lappend dims $d
	    }
    }
    if [info exists options(external_num)] {
        set ext $options(external_num)
    } else {
        set ext 1
    }

    if ![info exists createMeshSubsetSelectVal] return
    set uns [ic_uns_subset_create $name]
	switch $createMeshSubsetSelectVal {
	    0 {
		    if {$entityList != ""} {
		        ic_uns_subset_add_from $name $entityList
		        ic_uns_subset_delete $entityList
		        mess "New subset $name created\n" blue
		        set entityList ""
		    }
	    }
	    1 {
	        regsub -all \{ $location "" location; regsub -all \} $location "" location
		    if {[llength $location] == 3} {
		        if {$dims == ""} {
			        mess "No types are selected\n" red
			        ic_uns_subset_delete $name
			        return
		        }
		        set lcs [ic_csystem_get_current]
                if {$lcs != "global"} {
                    mess "Using active local coordinate system $lcs to create subset $name\n"
                }
		        ic_uns_subset_add_near_pos $uns $location $dims
                set types ""
                set list_types [ic_uns_subset_list_types $uns]
                foreach type $list_types {
                    if {[regexp NODE+ $type]} { append types "0 " }
                    if {([regexp LINE_+ $type]) || ([regexp BAR_+ $type])} { append types "1 " }
                    if {([regexp TRI_+ $type]) || ([regexp QUAD_+ $type])} { append types "2 " }
                    if {([regexp TETRA_+ $type]) || ([regexp HEXA_+ $type]) || ([regexp PYRA_+ $type]) || ([regexp PENTA_+ $type])} { append types "3 " }
                }
                if {$types == "" && $list_types == "" && ($dims == "0" || $dims == "1" || $dims == "2")} {
                    ic_uns_subset_add_near_pos $uns $location "$dims" $dims
                } elseif {$types == "" && $list_types == "" && ($dims == "0 2" || $dims == "1 2")} {
                    ic_uns_subset_add_near_pos $uns $location "$dims" 2
                } elseif {[lsearch $dims 2] >= 0 && [lsearch $types 2] < 0} {
                    set uns2 [ic_uns_subset_create]
                    ic_uns_subset_add_near_pos $uns2 $location "1 2" 2
                    set types [ic_uns_subset_list_types $uns2]
                    if {([regexp TRI_+ $types]) || ([regexp QUAD_+ $types])} { 
                        catch { set verts1 ""; array unset verts2; array unset verts3 }
                        foreach inf [ic_uns_subset_info $uns] { lappend verts1 [lindex $inf 4] }
                        foreach inf [ic_uns_subset_info $uns2] { append verts2([lindex $inf 1]) [lindex $inf 4]; set verts3([lindex $inf 1]) [lindex $inf 3] }
                        foreach v [array names verts2] {
                           set i1 [lindex $verts2($v) 0]
                           set i2 [lindex $verts2($v) 1]
                           set i3 [lindex $verts2($v) 2]
                           foreach vv $verts1 {
                               if {[lsearch $vv $i1] < 0} continue
                               if {[lsearch $vv $i2] < 0} continue
                               if {[lsearch $vv $i3] < 0} continue
                               if [info exists verts3($v)] {
                                    if [regexp QUAD_+ $verts3($v)] {
                                        set i4 [lindex $verts2($v) 3]
                                        if {[lsearch $vv $i4] < 0} continue
                                    }
                                    ic_uns_subset_add_number $uns $v 2 $verts3($v)
                                }
                                break
                            }
                        }
                    }
                    ic_uns_subset_delete $uns2
                }
		    } else {
		        mess "Need to specify X Y Z values\n" red
		        ic_uns_subset_delete $name
		        return
		    }
	    }
	    2 {
		    switch $createSubNumTVal {
		        0 {
			        if {$elem_numbers == ""} {
			            mess "Error: missing element number\n" red
			            ic_uns_subset_delete $name
			            return
			        }
			        if {[regexp -all -- {:} $elem_numbers] && $beta_mode} {
			            set add_elem [aie_use_scheme_input $elem_numbers]
			        } else {
			            set add_elem $elem_numbers
			        }
			        set n [ic_uns_subset_add_number $name $add_elem [expr 1 + $options(external_num)] MIXED]
			        switch -- $n {
			            -1 { mess "That element is already selected\n" }
			            0 { mess "Error: no element with that number\n" red }
			            1 { mess "1 more element\n"; set elem_numbers  "" }
			            default { mess "$n more elements with those numbers\n"; set elem_numbers  "" }
			        }
		        }
		        1 {
			        set created_nodes 0
			        foreach node $node_numbers {
			            if [catch { ic_uns_subset_add_near_nodes $name $node $ext}] {
				            mess "Warning: no nodes numbered $node were found\n" red
			            } else {
			                incr created_nodes
			            }
			        }
			        if !$created_nodes {
			            ic_uns_subset_delete $name
			            return
			        }
		        }
		    }
	    }
	    3 {
		    if {$dims == ""} {
		        mess "No types are selected\n" red
		        return
		    }
		    foreach {n v} "minx {Min x} miny {Min y} minz {Min z} maxx {Min x} maxy {Min y} maxz {Min z}" {
		        if {[set $n] == "" || (![string is integer -strict [set $n]] && ![string is double [set $n]])} {
		            mess "Invalid $v value\n" red
		            ic_uns_subset_delete $uns
		            return
		        }
		    }
		    set p1 [list $minx $miny $minz]
		    set p2 [list $maxx $maxy $maxz]
		    set lcs [ic_csystem_get_current]
            if {$lcs != "global"} {
                mess "Using active local coordinate system $lcs to create subset $uns\n"
            }
            ic_uns_subset_add_region $uns $p1 $p2 $BoxFlag $dims
	    }
	}
    mess "Subset $uns contains [ic_uns_subset_count_elements $uns] elements\n"
    ::AIEnv::GUIManagement::Tree::AddGroup mesh_subset $name 1
    ::AIEnv::GUIManagement::Tree::ToggleGroupVisibility mesh_subset $name same
    if {$name == "" || [ic_uns_subset_exists $name]} {
        set name [ic_uns_subset_unused_name Subset]
        createMeshSubsetDEZ set name $name
    }
}

proc onModifyMeshSubsetDEZApply {} {
    global options

    set dims ""
    foreach d {0 1 2 3} {
	    if [set select_mesh_${d}d] {
	        lappend dims $d
	    }
    }
    if [info exists options(external_num)] {
	    set ext $options(external_num)
    } else {
	    set ext 1
    }
    if [info exists modifyMeshSubsetSelectVal] {
        switch $modifyMeshSubsetSelectVal {
	        0 { # Add to MeshSubset by Selection
		        if {$entityList == ""} return
		        ic_uns_subset_add_from $name $entityList
		        ic_uns_subset_delete $entityList
	        }
	        1 { # Add To Subset near Position or external node number
		        if {[llength $location] == 3} {
		            if {$dims == ""} {
			            mess "No types are selected\n" red
			            return
		            }
		            ic_uns_subset_add_near_pos $name $location $dims
		        } else {
		            mess "Need to specify X Y Z values\n" red
		            return
		        }
	        }
	        2 { # Add By ElementNumber
		        switch $addSubNumTVal {
		            0 {
			            set n [ic_uns_subset_add_number $name $elem_numbers [expr 1 +  $options(external_num)] MIXED]
			            switch -- $n {
			                -1 { mess "That element is already selected\n" }
			                0 { mess "Error: no element with that number\n" red }
			                1 { mess "1 more element\n" }
			                default { mess "$n more elements with those numbers\n" }
			            }
		            }
		            1 {
			            foreach node $node_numbers {
			                if [catch {ic_uns_subset_add_near_nodes $name $node $ext}] {
				                mess "Warning: no nodes numbered $node were found\n" red
			                }
			            }
		            }
		        }
	        }
	        3 { # Add Contents of Subset
                if {$other_name == ""} return
		        ic_uns_subset_add_from $name $other_name
	        }
	        4 { # Add To Subset in Region
		        if {$dims == ""} {
		            mess "No types are selected\n" red
		            return
		        }
		        foreach {n v} "minx {Min x} miny {Min y} minz {Min z} maxx {Min x} maxy {Min y} maxz {Min z}" {
		            if {[set $n] == "" || (![string is integer -strict [set $n]] && ![string is double [set $n]])} {
		                mess "Invalid $v value\n" red
		                return
		            }
		        }
		        set p1 [list $minx $miny $minz]
		        set p2 [list $maxx $maxy $maxz]
		        set lcs [ic_csystem_get_current]
                if {$lcs != "global"} {
                    mess "Using active local coordinate system $lcs to modify subset $name\n"
                }
		        ic_uns_subset_add_region $name $p1 $p2 $BoxFlag $dims
	        }
	        5 { # Restrict to MeshSubset by Selection
		        if {$entityList == ""} return
		        ic_uns_subset_copy $name $entityList
		        ic_uns_subset_delete $entityList
	        }
	        6 { # Remove from MeshSubset by Selection
                if {$entityList == ""} return
		        ic_uns_subset_subtract_from $name $entityList
		        ic_uns_subset_delete $entityList
	        }
	        7 { # Add Layer(s) to MeshSubset
		        if $AllFlag { set map active } else { set map all }
		        if $VolFlag { set in_what all } else { set in_what surf }
		        switch $layerMeshAddinVal {
		            0 { # Add Layer
			            set n [ic_uns_subset_add_layer $name $number $map $in_what]
			            mess "$n more elements\n"
		            }
		            1 { # All Attached
			            ic_uns_subset_add_attached $name $in_what all 0
		            }
		            2 { # Same Part
			            ic_uns_subset_add_attached $name $in_what part 0
		            }
		            3 { # To Curve
			            ic_uns_subset_add_attached $name $in_what curve 0
		            }
		            4 { # To Angle
			            ic_uns_subset_add_attached $name $in_what angle $angle
		            }
		        }
		        mess "[ic_uns_subset_count_elements $name] elements\n"
	        }
	        8 { # Remove Layer(s) from MeshSubset
		        switch $layerRemoveinVal {
		            0 { # Remove Layer
			            ic_uns_subset_set_current $name
			            set n [ic_uns_subset_remove_layer $name $number all]
			            mess "$n fewer elements\n"
		            }
		            1 - 2 - 3 - 4 { # All Attached (various)
			            set how [lindex {"" all part curve angle} $layerRemoveinVal]
			            set tmp [select_unstruct element 0 visible ""]
			            if {$tmp == ""} return
			            ic_uns_subset_add_attached $tmp $name $how $angle
			            ic_uns_subset_subtract_from $name $tmp
			            ic_uns_subset_delete $tmp
			            mess "[ic_uns_subset_count_elements $name] elements\n"
		            }
		        }
	        }
	        9 { # make scan plane
		        if [lmember HEXA_8 [ic_uns_subset_list_types $name]] {
		            ic_uns_scan_plane $name set $iflag $jflag $kflag 0 0 0
		        } else {
		            user_error "You must use a subset that contains at least one HEXA_8 element"
		        }
	        }
	    }
    }
    mess "Subset $name contains [ic_uns_subset_count_elements $name] elements\n"
    set number $number ;# reenable the GUI
    set entityList ""
}

proc aie_subset_mesh_shading {{shade ""}} {
    global aie_meshStyle mesh_subset_shading histo_color_by_quality histo_solid 
    global histo_crit env
    
    if ![info exists mesh_subset_shading] {
        set mesh_subset_shading Inherited
    }
    if {$mesh_subset_shading == "Inherited" || $shade == "Inherited"} {
        set mesh_subset_shading Inherited
        aie_changeMeshDisplay
        return
    } else {
        if {$shade != ""} {
            set mesh_subset_shading $shade
        }
    }
    foreach sub [ic_uns_subset_list_visible Selected] {
        if {$sub == ""} continue
        if {[lindex [split $sub /] 0] == "DIAGNOSTIC"} {
            if {[info exist histo_color_by_quality] && $histo_color_by_quality} {
                ic_uns_subset_configure $sub -color_by_quality 1 
                if [info exist histo_solid] {
                    if $histo_solid {
                        ic_uns_subset_configure $sub -shade flat_wire
                    } else {
                        ic_uns_subset_configure $sub -shade flat
                    }
                }
            }
            continue
        }
        if {[expr [::AIEnv::GUIManagement::Tree::NodeVisibleStatus mesh_subset $sub 1] == 1]} {
            if {$mesh_subset_shading == "Solid/wire"} {
                ic_uns_subset_configure $sub -shade flat_wire
            } elseif {$mesh_subset_shading == "Solid"} {
                ic_uns_subset_configure $sub -shade flat
            } elseif {$mesh_subset_shading == "Wire"} {
                ic_uns_subset_configure $sub -shade wire
            }
            if {$mesh_subset_shading == "color_by_quality"} {
                #ic_uns_subset_configure $sub -color_by_quality 1
            } else {
                #ic_uns_subset_configure $sub -color_by_quality 0
            }
        }
    }
}

proc onmodifyMeshSubsetPickFinish {} {
    global auto_pick_mode
    if {$auto_pick_mode && $entityList != ""} {
        modifyMeshSubsetDEZ apply
        modifyMeshSubsetPick pick
    }
}

proc onremoveMeshSubsetPickFinish {} {
    global auto_pick_mode
    if {$auto_pick_mode && $entityList != ""} {
        modifyMeshSubsetDEZ apply
        removeMeshSubsetPick pick
    }
}

proc onmodifyMeshSubsetResPickFinish {} {
    global auto_pick_mode
    if {$auto_pick_mode && $entityList != ""} {
        modifyMeshSubsetDEZ apply
        modifyMeshSubsetResPick pick
    }
}

proc onmodifyMeshSubSelLoad {} {
    global auto_pick_mode
    if $auto_pick_mode { modifyMeshSubsetPick pick }
}

proc onremoveMeshSubSelLoad {} {
    global auto_pick_mode
    if $auto_pick_mode { removeMeshSubsetPick pick }
}

proc onmodifyMeshSubRestrLoad {} {
    global auto_pick_mode
    if $auto_pick_mode { modifyMeshSubsetResPick pick }
}

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

proc aie_mesh_subset_scan_plane_incr {i j k} {
    ic_uns_scan_plane $::AIEnv::DEZ::modifyMeshSubsetDEZ::name advance $i $j $k
    ::AIEnv::GUIManagement::DEZ::ExecuteUserProc modifyMeshSubsetDEZ Apply DefaultApply
}

proc oncreateMeshSubSelLoad {} {
    global auto_pick_mode
    if $auto_pick_mode { 
        createMeshSubsetPick pick
    }
}

proc oncreateMeshSubsetPickFinish {} {
    global auto_pick_mode
    if {$auto_pick_mode && $entityList != ""} {
        createMeshSubsetDEZ apply
        createMeshSubsetPick pick
    }
}

proc onmodifyMeshSubSelLoad {} {
    global auto_pick_mode
    if {$auto_pick_mode && $entityList != ""} { 
        modifyMeshSubsetPick pick
    } 
}

proc onmodifyMeshSubsetPickFinish {} {
    global auto_pick_mode
    if {$auto_pick_mode && $entityList != ""} { 
        modifyMeshSubsetDEZ apply	
        modifyMeshSubsetPick pick
    }
}

proc onCreateMeshSubsetDEZUnload {} {
    geo_select_either_set_prefix ""
}

proc onModifyMeshSubsetDEZUnload {} {
    geo_select_either_set_prefix ""
}

proc aie_init_mesh_subsets {} {
    ::AIEnv::GUIManagement::Tree::doInsertIfNeeded mesh_subsetNode   
    foreach name [ic_uns_subset_list 1] {
        if {![ic_uns_subset_count_elements $name] && ![ic_uns_subset_count_nodes $name]} continue
        ::AIEnv::GUIManagement::Tree::AddGroup mesh_subset $name 0
        ::AIEnv::GUIManagement::Tree::ToggleGroupVisibility mesh_subset $name same
    }
}

proc aie_use_scheme_input {numbers} {
    set add_elem ""
    foreach item $numbers {
        set nfound [regexp -all -- {:} $item]
        switch $nfound {
            0 {
                # no scheme used
                append add_elem "$item "
            }
            1 {
                # from:to scheme used
                set from [lindex [split $item :] 0]
                set to [lindex [split $item :] 1]
                for {set i $from} {$i <= $to} {incr i} {
                    append add_elem "$i "
                }
            }
            2 {
                set from [lindex [split $item :] 0]
                set to [lindex [split $item :] 1]
                set add [lindex [split $item :] 2]
                if {$from < $to && $add > 0} {
                    # from:to:add scheme used
                    for {set i $from} {$i <= $to} {incr i $add} {
                        append add_elem "$i "
                    }
                } elseif {$from > $to && $add < 0} {
                    # to:from:subtract scheme used
                    for {set i $from} {$i >= $to} {incr i $add} {
                        append add_elem "$i "
                    }
                }
            }
            default {
                append add_elem "[split $item :] "
            }
        }
    }
    return $add_elem
}

proc aie_mesh_subset_get_element_type {num {extern 0}} {
    set sub [ic_uns_create_selection_subset 0]
    ic_uns_subset_add_number $sub $num [expr 1 + $extern] MIXED
    set type [lindex [ic_uns_subset_list_elements $sub] 0]
    ic_uns_subset_delete $sub
    return [lindex $type 0]
}

proc aie_mesh_subset_remove_dim {sub dim} {
    set remove [ic_uns_create_selection_subset 0]
    ic_uns_subset_visible $remove 0
    ic_uns_subset_copy $remove all $dim
    ic_uns_uniqify $remove
    ic_uns_subset_subtract_from $sub $remove
    ic_uns_subset_delete $remove
}

proc aie_mesh_subset_remove_parts {sub parts types} {
    set remove [ic_uns_create_selection_subset 0]
    ic_uns_subset_visible $remove 0
    ic_uns_subset_make_families $remove $parts
    ic_uns_uniqify $remove
    set remove_from [ic_uns_subset_create]
    ic_uns_subset_visible $remove_from 0
    ic_uns_subset_add_families_and_types $remove_from $parts $types
    ic_uns_subset_add_from $remove $remove_from
    ic_uns_subset_delete $remove_from
    ic_uns_subset_subtract_from $sub $remove
    ic_uns_subset_delete $remove
}

proc aie_mesh_subset_update_elements {sub elems types parts dim {extern 0}} {

    if ![ic_uns_subset_exists $sub] {
        mess "No such subset $sub\n"
        return 
    }
    busy 1
    set n [ic_uns_subset_add_number $sub $elems [expr 1 + $extern] MIXED]
    if {[lsearch $dim 0] >= 0} {
        if {[lsearch $types NODE] < 0} {
            aie_mesh_subset_remove_dim $sub 0
        }
    }
    if {[lsearch $dim 1] >= 0} {
        set found 0
        foreach t "BAR_2 BAR_3 LINE_2 LINE_3" {
            if {[lsearch $types $t] >= 0} { 
                set found 1
            }
        }
        if !$found {
            aie_mesh_subset_remove_dim $sub 1
        }
    }
    if {[lsearch $dim 2] >= 0} {
        set found 0
        foreach t "TRI_3 TRI_6 QUAD_4 QUAD_8 QUAD_9" {
            if {[lsearch $types $t] >= 0} {
                set found 1
            }
        }
        if !$found {
            aie_mesh_subset_remove_dim $sub 2
        }
    }
    if {[lsearch $dim 3] >= 0} {
        set found 0
        foreach t "TETRA_4 TETRA_10 HEXA_8 HEXA_20 PENTA_6 PENTA_15 \
               HEXA_27 PENTA_18 PYRA_5 PYRA_14 PYRA_13" {
            if {[lsearch $types $t] >= 0} {
                set found 1
            }
        }
        if !$found {
            aie_mesh_subset_remove_dim $sub 3
        }  
    }            
    foreach p [ic_uns_subset_list_families $sub] {
        if {[lsearch $parts $p] < 0} {
            aie_mesh_subset_remove_parts $sub $p [ic_uns_list_types]
        }
    }
#    mess "Updated subset $sub\n"
    busy 0
}

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

proc aie_subset_put_in_tree {type name} {
    ::AIEnv::GUIManagement::Tree::AddGroup ${type}_subset $name 1
    ::AIEnv::GUIManagement::Tree::ToggleGroupVisibility ${type}_subset $name same
}

proc aie_edit_block_subset {name} {
    global current_subset_to_load
    
    if ![ic_hex_blocking_loaded] {
        mess "No Blocking is loaded!\n" red
        return
    }
    if {$name == "*"} {
        createBlockSubsetDEZ show
    } else {
        set current_subset_to_load(name) $name
        modifyBlockSubsetDEZ show
        unset current_subset_to_load(name)
    }
}

proc oncreateBlockSubsetDEZLoad {} {
    global current_subset_to_load
    
    if [info exists current_subset_to_load(name)] {
        set name $current_subset_to_load(name)
    } else {
        set name [ic_hex_subset_unused_name]
    }
    set BlockSubsetList [lsort -ascii [ic_hex_list_subsets]]
    set TypeSubsetList {{DISPLAY} {NAMED_SELECTION}}
    set stype DISPLAY
}

proc oncreateBlockSubsetDEZAfterLoad {} {
    
    if {[trace vinfo stype] != ""} {
        trace vdelete stype w aie_hex_subset_trace_stype
    }
    trace variable stype w aie_hex_subset_trace_stype
    after 100 { aie_hex_subset_trace_stype "" "" "" }
}

proc aie_hex_subset_trace_stype {name element op} {

    createBlockSubsetDEZ set blockList ""
    createBlockSubsetDEZ set faceList ""
    createBlockSubsetDEZ set edgeList ""
    createBlockSubsetDEZ set vertexList ""

    if {[createBlockSubsetDEZ get stype] == "DISPLAY"} {
        ::AIEnv::GUIManagement::ToggleGrey createBlockSubsetPick 0
        ::AIEnv::GUIManagement::ToggleGrey createFaceSubsetPick 1
        ::AIEnv::GUIManagement::ToggleGrey createEdgeSubsetPick 1
        ::AIEnv::GUIManagement::ToggleGrey createVertexSubsetPick 1
    } else {
        ::AIEnv::GUIManagement::ToggleGrey createBlockSubsetPick 1
        ::AIEnv::GUIManagement::ToggleGrey createFaceSubsetPick 0
        ::AIEnv::GUIManagement::ToggleGrey createEdgeSubsetPick 0
        ::AIEnv::GUIManagement::ToggleGrey createVertexSubsetPick 0
    }
}

proc oncreateBlockSubsetDEZApply {} {
    global fam_visible 

    if {$stype == "DISPLAY"} {
        if {$blockList == ""} {
            msg ERROR "No block selected for subset"
            return
        }
    }
    if {$name == ""} { 
        set name [ic_hex_subset_unused_name] 
    }
    set fname [string toupper [string trimright $name]]
    if {$fname == "VORFN"}  {
        msg ERROR "Name: VORFN already in use for Part; use some other name" 
        return
    }
    if [ic_geo_check_family $fname] {
        msg ERROR "Name: $name already in use for Part/Subset; use some other name" 
        return
    }
    if [ic_hex_subset_exist $fname] {
        msg ERROR "Subset/Part with name $fname already exists; use some other name"
        return
    }
    ic_geo_new_family $fname
    set name $fname
    
    if {$stype == "DISPLAY"} {
        set subset_type display
    } else {
        set subset_type named_selection
    }
    
    if {$subset_type == "display"} {
        set hex_subnum [ic_hex_create_subset display $fname]
    } else {
        set hex_subnum [ic_hex_create_named_selection_subset $fname]
    }
    if {$hex_subnum < 0} {
        mess "Subset $fname creation failed\n" red
        return
    }
    if {$stype == "DISPLAY"} {
        if {$blockList != ""} {
            eval ic_hex_subset_add_items $fname block [llength $blockList] $blockList
        }
    }
    if {$stype == "NAMED_SELECTION"} {
        if {$faceList != ""} {
            set items ""
            foreach e $faceList {
		        if {[lindex [join $e] end] == "u"} { # for unstruct faces
		            set uitems ""
			        foreach n [join $e] {
			            if [regexp {[0-9]} $n] {
				            lappend uitems $n
			            }
			        }
				    lappend uitems -1 -1
			        set uitems [list $uitems]
			        eval ic_hex_subset_add_named_selection_items $fname face [llength $uitems] [join $uitems]
		       } else { 
			        lappend items $e
		       }
		    }
		    if {$items != ""} {
                eval ic_hex_subset_add_named_selection_items $fname face [llength $items] [join $items]
            }
        }
        if {$edgeList != ""} {
            eval ic_hex_subset_add_named_selection_items $fname edge [llength $edgeList] [join $edgeList]
        }
        if {$vertexList != ""} {
            set vertices ""
            foreach v $vertexList {
                lappend vertices $v 0 -1
			}
            eval ic_hex_subset_add_named_selection_items $fname vertex [llength $vertexList] [join $vertices]
        }
    }
    if ![ic_hex_subset_exist $fname] {
        mess "Subset $fname creation failed\n" red
        return
    }
    set fam_visible($fname) 1
    ::AIEnv::GUIManagement::Tree::AddGroup block_subset $fname 1
    ::AIEnv::GUIManagement::Tree::ToggleBlockingVisibility block_subset $fname same
}

proc oncreateBlockSubsetDEZUnLoad {} {
    if {[trace vinfo stype] != ""} {
        trace vdelete stype w aie_hex_subset_trace_stype
    }
}

proc aie_rename_block_subset {name} {
    global fam_visible

    set newname [question_box .newname "New name" "New name for subset $name" $name]
    if {$newname == ""} return
    
    set newname [string toupper $newname]
    if [ic_hex_subset_exist $newname] {
        msg ERROR "Subset/Part with name $newname already exists"
        return
    }
    if {$newname == "VORFN"}  {
        msg ERROR "Name: VORFN already in use for Part; use some other name" 
        return
    }
    if [ic_geo_check_family $newname] {
        msg ERROR "Name: $newname already in use for Part/Subset; use some other name" 
        return
    }
    
    ic_geo_rename_family $name $newname
    if [ic_hex_subset_named_selection $name] {
        ic_hex_rename_named_selection_subset $name $newname
    } else {
        ic_hex_rename_subset $name $newname
    }

    if [info exists fam_visible($name)] {
        set fam_visible($newname) $fam_visible($name)
    } else {
        set fam_visible($newname) 1
    }
    
    if [ic_hex_subset_named_selection $newname] {
        set delete 1
        if [ic_uns_is_loaded] {
            foreach fam [ic_uns_non_empty_families $name] {
                if [ic_uns_count_in_families $fam] { set delete 0; break }
            }
            foreach fam [ic_uns_non_empty_families $name/] {
                if [ic_uns_count_in_families $fam] { set delete 0; break }
            }
        }
        if $delete {
            catch { unset fam_visible($name) }
        }
    } else {
        catch { unset fam_visible($name) }
    }
    ::AIEnv::GUIManagement::Tree::RenameGroup block_subset $name $newname
}

proc aie_delete_block_subset {name} {
    global fam_visible

    ic_geo_delete_family $name
    if [ic_hex_subset_named_selection $name] {
        ic_hex_delete_named_selection_subset $name
        set delete 1
        if [ic_uns_is_loaded] {
            foreach fam [ic_uns_non_empty_families $name/] {
                if [ic_uns_count_in_families $fam] { set delete 0; break }
            }
        }
        if $delete {
            catch { unset fam_visible($name) }
        }
    } else {
        ic_hex_delete_subset $name
        catch { unset fam_visible($name) }
    }

    ::AIEnv::GUIManagement::Tree::DeleteGroup block_subset $name 0
    aie_hex_display_named_selection_subset
    hex_update_display
}

proc onModifyBlockSubsetDEZLoad {} {
    global current_subset_to_load
    if [info exists current_subset_to_load(name)] {
        set name $current_subset_to_load(name)
    } else {
        set name [ic_hex_subset_unused_name Subset]
    }
    set blockList ""
    set AllowActiveReload 1
}

proc onModifyBlockSubsetDEZAfterLoad {} {

    modifyBlockSubsetDEZ set blockList ""
    modifyBlockSubsetDEZ set faceList ""
    modifyBlockSubsetDEZ set edgeList ""
    modifyBlockSubsetDEZ set vertexList ""
    
    if ![ic_hex_subset_named_selection $name] { 
        ::AIEnv::GUIManagement::ToggleGrey modifyBlockSubsetPick 0
        ::AIEnv::GUIManagement::ToggleGrey modifyFaceSubsetPick 1
        ::AIEnv::GUIManagement::ToggleGrey modifyEdgeSubsetPick 1
        ::AIEnv::GUIManagement::ToggleGrey modifyVertexSubsetPick 1
        ::AIEnv::GUIManagement::ToggleGrey removeBlockSubsetPick 0
        ::AIEnv::GUIManagement::ToggleGrey removeFaceSubsetPick 1
        ::AIEnv::GUIManagement::ToggleGrey removeEdgeSubsetPick 1
        ::AIEnv::GUIManagement::ToggleGrey removeVertexSubsetPick 1
    } else {
        ::AIEnv::GUIManagement::ToggleGrey modifyBlockSubsetPick 1
        ::AIEnv::GUIManagement::ToggleGrey modifyFaceSubsetPick 0
        ::AIEnv::GUIManagement::ToggleGrey modifyEdgeSubsetPick 0
        ::AIEnv::GUIManagement::ToggleGrey modifyVertexSubsetPick 0
        ::AIEnv::GUIManagement::ToggleGrey removeBlockSubsetPick 1
        ::AIEnv::GUIManagement::ToggleGrey removeFaceSubsetPick 0
        ::AIEnv::GUIManagement::ToggleGrey removeEdgeSubsetPick 0
        ::AIEnv::GUIManagement::ToggleGrey removeVertexSubsetPick 0
    }  
}

proc onModifyBlockSubsetDEZApply {} {
    
    if ![ic_hex_subset_named_selection $name] {
        if {$blockList == ""} {
            msg ERROR "No block selected to add/remove from subset"
            return
        }
    }
    switch $modifyBlockSubsetSelectVal {
        0 {
            if {$blockList != "" && ![ic_hex_subset_named_selection $name]} {
	            eval ic_hex_subset_add_items $name block [llength $blockList] $blockList
	        }
	        if [ic_hex_subset_named_selection $name] {
	            if {$faceList != ""} {
                    set items ""
                    foreach e $faceList {
		                if {[lindex [join $e] end] == "u"} {
		                    set uitems ""
			                foreach n [join $e] {
			                    if [regexp {[0-9]} $n] {
				                    lappend uitems $n
			                    }
			                }
				            lappend uitems -1 -1
			                set uitems [list $uitems]
			                eval ic_hex_subset_add_named_selection_items $name face [llength $uitems] [join $uitems]
		                } else { 
			                lappend items $e
		                }
		            }
                    if {$items != ""} {
                        eval ic_hex_subset_add_named_selection_items $name face [llength $items] [join $items]
                    }
                }
                if {$edgeList != ""} {
                    eval ic_hex_subset_add_named_selection_items $name edge [llength $edgeList] [join $edgeList]
                }
                if {$vertexList != ""} {
                    set vertices ""
                    foreach v $vertexList {
                        lappend vertices $v 0 -1
			        }
                    eval ic_hex_subset_add_named_selection_items $name vertex [llength $vertexList] [join $vertices]
                }
	        }
	    }
	    1 {
	        if {$blockList != "" && ![ic_hex_subset_named_selection $name]} {
	            eval ic_hex_subset_remove_items $name block [llength $blockList] $blockList
	        }
	        if [ic_hex_subset_named_selection $name] {
	            if {$faceList != ""} {
                    set items ""
                    foreach e $faceList {
		                if {[lindex [join $e] end] == "u"} {
		                    set uitems ""
			                foreach n [join $e] {
			                    if [regexp {[0-9]} $n] {
				                    lappend uitems $n
			                    }
			                }
				            lappend uitems -1 -1
			                set uitems [list $uitems]
			                eval ic_hex_subset_remove_named_selection_items $name face [llength $uitems] [join $uitems]
		                } else { 
			                lappend items $e
		                }
		            }
                    if {$items != ""} {
                        eval ic_hex_subset_remove_named_selection_items $name face [llength $items] [join $items]
                    }
                }
                if {$edgeList != ""} {
                    eval ic_hex_subset_remove_named_selection_items $name edge [llength $edgeList] [join $edgeList]
                }
                if {$vertexList != ""} {
                    set vertices ""
                    foreach v $vertexList {
                        lappend vertices $v 0 -1
			        }
                    eval ic_hex_subset_remove_named_selection_items $name vertex [llength $vertexList] [join $vertices]
                }
	        }
	    }
    }
    hex_update_display
    if [ic_hex_subset_named_selection $name] {
        aie_hex_display_named_selection_subset
    }
}

proc aie_info_block_subset {name} {

    if ![ic_hex_subset_exist $name] {
        mess "There is no subset named \"$name\" - please open up the branch and modify the lowest-level entries\n" red
        return
    }
    mess "\n\n------------------------------------------\n"
    mess "Info for subset $name\n"
    if [ic_hex_subset_named_selection $name] {
        mess "Subset type: NAMED_SELECTION\n"
        mess "Subset contains:\n"
        set items [string trimright [ic_hex_list_subset_entities $name vertex] \n]
        if {$items != ""} {
            mess "[llength $items] vertices: $items\n"
        }
        set items [string trimright [ic_hex_list_subset_entities $name edge] \n]
        if {$items != ""} {
            mess "[llength $items] edge(s): $items\n"
        }
        set items [string trimright [ic_hex_list_subset_entities $name face] \n]
        if {$items != ""} {
            mess "[llength $items] face(s): $items\n"
        }
    } else {
        mess "Subset type: DISPLAY\n"
        set blocks [ic_hex_list_subset_entities $name block]
        mess "Subset contains [llength $blocks] block(s) [string trimright $blocks \n]\n"
    }
    mess "------------------------------------------\n"
}

proc aie_hex_display_named_selection_subset {} {
    global hex_display_named_selection
 
    if ![ic_hex_blocking_loaded] return
       
    set ta [tdv_active 0] 
    foreach subset [array names hex_display_named_selection] {
        if [ic_hex_subset_exist number $hex_display_named_selection($subset)] {
            ic_hex_delete_subset number $hex_display_named_selection($subset)
            unset hex_display_named_selection($subset)
        }
    }

    set named [::AIEnv::GUIManagement::Tree::GetBlockingSubsetVisibility 1]
    if {$named == ""} {
        tdv_active $ta
        return
    }

    set sub [format %d [ic_hex_create_subset selection]]
    foreach subset $named {
        if ![ic_hex_subset_named_selection $subset] continue
        foreach type {vertex edge face} {
            set items [string trimright [ic_hex_list_subset_entities $subset $type] \n]
	        if {$items == ""} continue
            if {$type == "edge"} {
                set eitems ""
                foreach e $items {
                    lappend eitems [list [lindex $e 0] [lindex $e 1] [lindex $e 2]]
                }
                eval ic_hex_subset_add_items number $sub edge [llength $eitems] [join $eitems]
            } elseif {$type == "face"} {
                set mitems ""       
                foreach e $items {
		            if {[lindex [join $e] end] == "u"} {
		                set uitems ""
			            foreach n [join $e] {
			                if [regexp {[0-9]} $n] {
				                lappend uitems $n
			                }
			            }
				        lappend uitems -1 -1
			            set uitems [list $uitems]
			            eval ic_hex_subset_add_items number $sub face [llength $uitems] [join $uitems]
		            } else { 
			            lappend mitems $e
		            }
		        }
		        if {$mitems != ""} {
                    eval ic_hex_subset_add_items number $sub face [llength $mitems] [join $mitems]
                }
            }  elseif {$type == "vertex"} {
                set vitems ""
                foreach v $items {
			        if {$v != ""} {
			            if {[llength $v] == 1} {
				            lappend v 0 -1
			            }				
			            lappend vitems $v
			        }
		        }
		        eval ic_hex_subset_add_items number $sub vertex [llength $vitems] [join $vitems]
           } else {
                foreach f $items {
                    eval ic_hex_subset_add_items number $sub $type [llength $items] [join $items]
                }
            }
            set disp_opts ""
            switch $type {
                vertex { set disp_opts " numbers" }
	            edge { #set disp_opts "[range_string] m [volume_activename_string] -not_blanked" }
	            face { set disp_opts "" }
	        }
	        # selection subset for display all entity types
            eval ic_hex_display_subset number $sub $type $disp_opts
        }        
        set hex_display_named_selection($subset) $sub
    }
    tdv_active $ta
}

proc aie_init_hex_subsets {} {
    global fam_visible
    
    ::AIEnv::GUIManagement::Tree::doInsertIfNeeded block_subsetNode
    foreach name [ic_hex_subset_list_named_selections] {
        set fam_visible($name) 1
        if ![ic_geo_check_family $name] {
            ic_geo_new_family $name
        }
        ::AIEnv::GUIManagement::Tree::AddGroup block_subset $name 0
        ::AIEnv::GUIManagement::Tree::ToggleGroupVisibility block_subset $name same
    }
}

###############################################################################

proc aie_geom_subsets_into_parts {} {
# This function is a replacement of automatic parts creation from Named Selection (WB)
# There is no check for multiple definitions of the same entity
# May be added if necessary
# Undo restore parts, but not Subsets!!!

    set existing_subsets [ic_geo_subset_list]
    if {$existing_subsets == ""} {
        mess "No subset(s) defined to create part(s) from\n" red
        return
    }
    ic_save_model_for_undo
    ic_undo_suspend
    set nothing_selected 1
	foreach subset $existing_subsets {
	    set status [::AIEnv::GUIManagement::Tree::NodeVisibleStatus geom_subset $subset]
        if {$status == 1} {
            set nothing_selected 0
            set fam [aie_new_part $subset]
            foreach {type name} [ic_geo_subset_get_items $subset] {
                ic_geo_set_family $type $fam names $name
            }
            aie_delete_geom_subset $subset
        }
	}
	if $nothing_selected {
	    mess "No subset(s) selected to create part(s) from\n" red
	}
	aie_delete_empty_parts
    aie_update_icons geom
    ic_undo_resume
}









