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

proc set_phase_tri_edit {in} {
    global tetra_leo_bin cut_domain env config_dir tetin_file mesh_dirty
    global te_family te_shading te_aspect families process_ident
    global current_phase last_line cut_domain_in_import single_buffer
    global show_icons show_nodes show_nnums show_enums has_tetin tetin_merge_pid
    
    if $in {
	set home 0
	if {![info exists process_ident] || ($process_ident != "leo")} {
	    if {![info exists cut_domain] && \
		    [file exists $config_dir(domains)/cut_domain.1]} {
		set cut_domain cut_domain.1
	    }
	    
	    if ![select_cut_domain 1] return
	    
	    if $cut_domain_in_import {
		set ddir $config_dir(import)
		set imp 1
	    } else {
		set ddir $config_dir(domains)
		set imp 0
	    }
	    if ![info exists tetin_file] {
		set tetin_file tetin1
	    }
	    
	    set has_tetin 0
	    if {$imp && ($tetin_file != "") && \
		    [file exists $config_dir(mesh)/$tetin_file] && \
		    ![tk_dialog .load_tetin "Load tetin" \
			  "Load the file $tetin_file?" "" -1 "Yes" "No"]} {
		set has_tetin 1
	    } elseif {!$imp && ($tetin_file != "") && \
		    [file exists $config_dir(mesh)/$tetin_file]} {
		set has_tetin 1
	    }
	    
	    set env(LEO_TETRA) 1
	    if $single_buffer {
		set args "-single_buffer"
	    } else {
		set args ""
	    }
	    start_process leo .v.view $tetra_leo_bin leo% 0 $args
	    if {$imp && ![info exists tetin_merge_pid]} {
		command "set all_pids_value 0" 0
	    }
	    reload_leo_domain $ddir/$cut_domain 1 1
	    
	    print_family_stats
	    
	    if $has_tetin {
		busy 1
		command "cad_load_tetin $config_dir(mesh)/$tetin_file 0"
		set prev $current_phase
		set current_phase dummy
		update_display surf
		set current_phase $prev
		disable_stuff 1
		busy 0
	    }
	    catch {unset mesh_dirty}
	    set home 1
	}
	set is_quad [expr {$current_phase == "quad_edit"}]
	command "lte_init $show_icons $show_nodes $show_nnums $show_enums $is_quad"
	
	if ![info exists te_family] {
	    set te_family [lindex $families 0]
	    set te_aspect 0.2
	    set te_shading 0
	}
	modify_list_families
	te_sel_all
	if $home { command view_home }
	
    } else {
	command lte_end
	
	if {$current_phase == "mesher"} {
	    if [info exists mesh_dirty] modify_save_mesh
	    finish_process
	    
	    disable_stuff 0
	
	    # May as well do this here ...
	    set tmps [glob -nocomplain $config_dir(domains)/__temp_*]
	    if {$tmps != ""} { eval exec /bin/rm -f $tmps }
	}
    }
}

proc te_selection {} {
    global botform_geo current_phase te_selection_filename
    
    if {$current_phase == "tri_edit"} {
	set d [form_init .tri_select "Triangle selection" tri_edit_select done]
    } else {
	set d [form_init .quad_select "Quad selection" tri_edit_select done]
    }
    
    if {$d != ""} {
	form_frame $d.fr sunken 2 {0 0}; set d $d.fr
	form_label $d.esell "Select elements:" {1 0 -cols 3}
	form_label $d.extl "Extend selection:" {11 0 -cols 3}
	
	form_button $d.sclear "Clear" te_sel_clear {2 2 -cols 3}
	form_button $d.sall "Select all" te_sel_all {3 2 -cols 3}
	form_button $d.sinv "Select unselected" te_sel_inv {4 2 -cols 3}
	form_button $d.sadds "Screen unblank" te_sel_screen_add {5 2 -cols 3}
	form_button $d.sremoves "Screen blank" te_sel_screen_remove \
		{6 2 -cols 3}
	form_button $d.srestrs "Screen restrict" te_sel_screen_restrict \
		{7 2 -cols 3}
	form_button $d.enuml "Single element" te_sel_number {8 2 -cols 3}
	form_label $d.enumnl "Number:" {9 2}
	form_entry $d.enumn te_number int {9 3 -cols 2}
	set te_number 0
	bind $d.enumn <Return> te_sel_number
	
	
	form_button $d.diagv "Diag val" te_sel_screen_aspect \
	    {18 2}
	set te_sel_screen_diag "Aspect ratio"
	set opts [list list "Aspect ratio" "Skew" "Min angle" "Max angle" "Edge ratio" "Deviation"]
	futil_menuentry $d.diagt te_sel_screen_diag $opts {18 3}
	$d.diagt configure -width 4
	form_label $d.saspl "Worse than" {19 2}
	form_entry $d.saspv te_aspect float {19 3}
	bind $d.saspv <Return> te_sel_screen_aspect
	
	if 0 {
	    if {$current_phase == "tri_edit"} {
		form_button $d.sasp "Aspect ratio" te_sel_screen_aspect \
		    {18 2 -cols 2}
		form_label $d.saspl "Less than" {19 2}
		form_entry $d.saspv te_aspect float {19 3}
		bind $d.saspv <Return> te_sel_screen_aspect
	    } else {
		form_button $d.sasp "Determinant" te_sel_screen_determinant \
		    {18 2 -cols 2}
		form_label $d.saspl "Less than" {19 2}
		form_entry $d.saspv te_determinant float {19 3}
		bind $d.saspv <Return> te_sel_screen_determinant
	    }
	}
	form_button $d.xaddl "Add layer" te_ext_layer_add {31 2 -cols 3}
	form_button $d.xremovel "Remove layer" te_ext_layer_remove {32 2 -cols 3}
	form_button $d.xfilll "Fill to curves" te_fill_to_curve {33 2 -cols 3}
	form_button $d.xatt "All attached (edge)" "te_all_attached 1" {34 2 -cols 3}
	form_button $d.xatn "All attached (vert)" "te_all_attached 0" {35 2 -cols 3}
	form_button $d.batt "Blank attached (edge)" "te_blank_attached 1" {36 2 -cols 3}
	form_button $d.batn "Blank attached (vert)" "te_blank_attached 0" {37 2 -cols 3}
	form_button $d.attt "Attached to tetras" te_sel_att_tetra {38 2 -cols 3}
	form_button $d.blanki "Blank invisible" te_blank_invisible {39 2 -cols 3}
	
	form_frame $d.file flat 0 {43 0 -cols -}
	form_button $d.file.s "Save to file" "te_loadsave 1" {0 0}
	form_button $d.file.l "Load from file" "te_loadsave 0" {0 1}
	form_label $d.file.f "Filename:" {1 0}
	form_entry $d.file.e te_selection_filename string {1 1}
	
	form_colwidth $d 0 2 M
	form_rowheight $d 0 5 
	form_rowheight $d 20 5 
	form_rowheight $d 40 5 
	
	set te_selection_filename selection_list
	
	form_finish $botform_geo
    }
}

proc te_loadsave {save} {
    global te_selection_filename
    
    command "lte_loadsave $save \"$te_selection_filename\""
}

proc te_movenodes {} {
    global botform_geo te_move_type current_phase te_share_volume
    
    set d [form_init .tri_move "Move nodes" tri_edit_move done]
    if {$d != ""} {
	set te_move_type surf
	form_radiobutton $d.pl "Plane of screen" te_move_type plane {0 0}
	form_radiobutton $d.li "In direction"    te_move_type line {1 0}
	form_radiobutton $d.ve "Onto line"       te_move_type vector {2 0}
	form_radiobutton $d.sf "On model"        te_move_type surf {3 0}
	form_radiobutton $d.osf "Onto surface"   te_move_type onto_surf {4 0}
	form_radiobutton $d.ocf "Onto curve"     te_move_type onto_curve {5 0}
	foreach i {pl li ve sf osf ocf} {
	    $d.$i configure -command te_move_node
	}
	
	if {$current_phase == "tri_edit"} {
	    form_radiobutton $d.splm "Split manifold" \
		    te_move_type splitm {6 0}
	    $d.splm configure -command te_move_node
	    form_radiobutton $d.spln "Split non-manifold" \
		    te_move_type splitn {7 0}
	    $d.spln configure -command te_move_node
	}
	#form_checkbutton $d.dupn "Share node with volume" te_share_volume {8 0}
	set te_share_volume 0
	
	form_finish $botform_geo
    }
}

proc te_swap_edges {} {
    global last_line mesh_dirty
    
    banner "Left button = select elements, middle = accept, right =\
	    back up / cancel."
    while 1 {
	command "select_stuff elem 3 mesh_pickable" 0
	
	set elems [lrange [lindex $last_line 0] 1 2]
	if {[llength $elems] < 2} break
	
	command "lte_swap_edges $elems" 0
	if !$last_line {
	    mess "Can't swap edges.\n" red
	} else {
	    set mesh_dirty 1
	}
    }
    banner ""
}

proc te_update_shading {} {
    global te_shading current_phase
    
    if {($current_phase == "mesher") || ($current_phase == "modify")} {
	mess "Please switch to the triangles menu to use this function\n"
	return
    }
    
    if $te_shading {
	command "lte_set_shading flat"
    } else {
	command "lte_set_shading wire"
    }
}

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

proc te_sel_clear {} {
    command lte_sel_clear
}

proc te_sel_all {} {
    command "lte_sel_all \"[mesh_family_string]\""
}

proc te_sel_inv {} {
    command lte_sel_invert
}

proc te_sel_number {} {
    global te_number
    command "lte_sel_number $te_number"
}

proc te_sel_screen_add {} {
    global last_line
    
    banner "Select the elements to add with the left button;\
	    middle = accept, right = back up / cancel."
    command "lte_show_all_elements 1 \"[mesh_family_string]\"" 0
    command "select_stuff elem 0 mesh_pickable 0" 0
    command "lte_sel_add" 0
    command "lte_show_all_elements 0 \"[mesh_family_string]\"" 0
    banner ""
}

proc te_sel_screen_remove {} {
    global last_line
    
    banner "Select the elements to remove with the left button;\
	    middle = accept, right = back up / cancel."
    command "select_stuff elem 0 mesh_pickable 0" 0
    command "lte_sel_remove" 0
    banner ""
}

proc te_sel_screen_restrict {} {
    global last_line
    
    banner "Select the elements to restrict to with the left button;\
	    middle = accept, right = back up / cancel."
    command "select_stuff elem 0 mesh_pickable 0" 0
    banner ""
    if !$last_line return
    command "lte_sel_restrict" 0
}

proc te_sel_screen_aspect {} {
    global te_aspect te_sel_screen_diag
    
    switch $te_sel_screen_diag {
	"Aspect ratio" { set diag relaspect }
	"Skew"         { set diag skew }
	"Min angle"    { set diag minangle }
	"Max angle"    { set diag maxangle }
	"Edge ratio"   { set diag maxratio }
	"Deviation"    {
	    command "lte_set_project [modify_list_families]"
	    set diag surf_dev
	}
    }
    
    command "lte_sel_aspect $te_aspect \"[mesh_family_string]\" $diag"
}

proc te_sel_screen_determinant {} {
    global te_determinant
    
    command "lte_sel_determinant $te_determinant \"[mesh_family_string]\""
}

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

proc te_ext_layer_add {} {
    command "lte_ext_layer_add"
}

proc te_ext_layer_remove {} {
    command "lte_ext_layer_remove"
}

proc te_fill_to_curve {} {
    command "lte_fill_to_curve"
}

proc te_all_attached {edge} {
    command "lte_all_attached $edge"
}

proc te_blank_attached {edge} {
    banner "Select the elements to remove with the left button;\
	    middle = accept, right = back up / cancel."
    command "select_stuff elem 0 mesh_pickable 0" 0
    banner ""
    command "lte_blank_attached $edge"
}

proc te_sel_att_tetra {} {
    command "lte_sel_att_tetra"
}

proc te_blank_invisible {} {
    raise .v
    update
    command "lte_blank_invisible"
}

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

proc te_del_screen {} {
    global last_line mesh_dirty
    
    banner "Left button = select elements, middle = accept, right =\
	    back up / cancel."
    command "select_stuff elem 0 mesh_pickable 0" 0
    banner ""
    
    command "delete_elements_selected" 0
    set mesh_dirty 1
}

proc te_del_disp {} {
    global mesh_dirty last_line
    
    command lte_list_displayed
    set elems $last_line
    if {$elems == ""} return
    command "delete_elements \{$elems\}"
    set mesh_dirty 1
}

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

proc te_create_screen {} {
    global mesh_dirty te_family family_number_of_name last_line
    global mesh_family_active families current_phase
    global te_last_family cut_domain_in_import has_tetin
    
    if ![info exists te_last_family] { set te_last_family "" }
    
    set fams ""
    foreach f $families {
	lappend fams $f
    }
    set fams [linsert [lsort $fams] 0 "Screen select"]
    
    set mess "Choose a family for the new elements."
    set ff [choose_one $mess $fams $te_last_family +300+300]
    if {$ff == ""} return
    
    if {$ff == "Screen select"} {    
	banner "Select an element with the correct family;\
		middle = done, right = cancel."
	command "select_stuff elem 2 mesh_pickable" 0
	banner ""
	set fam_elem [lrange [lindex $last_line 0] 0 1]
	if {$fam_elem == ""} return
	command "get_family $fam_elem"
	set fam $last_line
    } else {
	foreach f $families {
	    if {$ff == $f} { set fam $f }
	}
	if ![info exists fam] {
	    error "The family must be one that already exists."
	}
    }
    set te_last_family $fam
    
    if {$current_phase == "tri_edit"} {
	set num 3
	set type TRI
    } else {
	set num 4
	set type QUAD
    }
    
    set allow_cad 0
    if {$cut_domain_in_import && $has_tetin} {
	if ![tk_dialog .allow_cad "Allow tetin" \
		 "Allow selection of nodes on surface meshes defined in\
			the tetin file?" "" -1 "Yes" "No"] {
			    set allow_cad 1
			}
    }
    
    command "lte_set_project [modify_list_families]" 0
    command "start_create_elements $allow_cad" 0
    while 1 {
	set nodes [pick_some_nodes $num " (n or p to create)"]
	if {[llength $nodes] < $num} {
	    command "end_create_elements" 0
	    return
	}
	command "create_elements \{$nodes\} $fam $type"
	command "lte_sel_add \{$last_line\}"
	set mesh_dirty 1
    }}

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

proc te_split {} {
    global botform_geo current_phase split_tol split_dlim split_project
    global cad_bspline_tolerance split_neighbors is_win
    
    set d [form_init .split "Split elements" tri_edit_split done]
    if {$d != ""} {
	set split_tol 0.0
	if [info exists cad_bspline_tolerance] {
	    set split_tol $cad_bspline_tolerance
	}
	set split_dlim 2
	set split_project 1
	set split_neighbors 1
	
	form_button $d.path   "Use screen path" te_split_screen \
	    {0 0 -cols 3}
	form_button $d.quads  "Split displayed quads" te_split_quads  \
	    {1 0 -cols 3}
	form_button $d.side   "Split into 2 triangles" te_split_side \
	    {2 0 -cols 3}
	form_button $d.center "Split into 3 triangles" te_split_center \
	    {3 0 -cols 3}
	form_button $d.star   "Split into 4 triangles" te_split_single \
	    {4 0 -cols 3}
	if !$is_win {
	    form_button $d.bytol  "By tolerance" te_split_tol {5 0 -cols 3}
	    form_colwidth $d 0 4 M
	    form_label $d.toll "Tol value" {6 1}
	    form_label $d.dliml "Depth limit" {7 1}
	    form_entry $d.tol split_tol float {6 2}
	    form_entry $d.dlim split_dlim int {7 2}
	    form_button $d.dtol "Query tolerance" te_query_tol {8 1 -cols 2}
	    form_checkbutton $d.pro "Project nodes" split_project {9 1 -cols 2}
	    form_checkbutton $d.neigh "Neighbors into 4" split_neighbors {10 1 -cols 2}
	
	    bind $d.tol <Return> te_split_tol
	    bind $d.dlim <Return> te_split_tol
	}
	form_finish $botform_geo
    }
}

proc te_split_screen {} {
    global mesh_dirty last_line
    
    banner "Draw the split line with the left button (multiple clicks);\
	    middle = done, right = back up / cancel."
    command "lte_set_project [modify_list_families]" 0
    command lte_split_screen
    banner ""
    
    if $last_line { set mesh_dirty 1 }
}

proc te_split_quads {} {
    global mesh_dirty last_line
    
    command lte_split_quads
    if $last_line { set mesh_dirty 1 }
}

proc te_split_side {} {
    global mesh_dirty last_line
    
    banner "Select pairs of adjacent triangles with the left button."
    command "lte_set_project [modify_list_families]" 0
    while 1 {
	command lte_split_side
    	if {![scan $last_line %d num] || !$num} break
	set mesh_dirty 1
    }
    banner ""
}

proc te_split_center {} {
    global mesh_dirty last_line
    
    banner "Select a triangle with the left button."
    command "lte_set_project [modify_list_families]" 0
    while 1 {
	command lte_split_center
	if {![scan $last_line %d num] || !$num} break
	set mesh_dirty 1
    }
    banner ""
}

proc te_split_single {} {
    global mesh_dirty last_line
    
    banner "Select a triangle with the left button."
    command "lte_set_project [modify_list_families]" 0
    while 1 {
	command lte_split_single
	if {![scan $last_line %d num] || !$num} break
	set mesh_dirty 1
    }
    banner ""
}

proc te_query_tol {} {
    global last_line split_tol
    
    command "lte_set_project [modify_list_families]" 0
    
    banner "Pick the element with the left button; right = cancel."
    command "select_stuff elem 2 mesh_pickable" 0
    banner ""
    set el [lindex [lindex $last_line 0] 1]
    if {$el != ""} {
	command "lte_query_tol $el"
	set split_tol $last_line
    }
}

proc te_split_tol {} {
    global last_line split_tol split_dlim split_project split_neighbors
    
    if $split_project { command "lte_set_project [modify_list_families]" 0 }
    
    # Note: tol could be 0 or -1 ...
    #if !$split_tol { error "Tolerance is 0 -- can't split" }
    
    command "lte_split_tol $split_tol $split_dlim $split_project \
		$split_neighbors"
}

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

proc te_reorient {} {
    global mesh_dirty last_line must_clear_vectors
    
    if [info exists must_clear_vectors] {
	command "lte_set_vectors 0" 0
	unset must_clear_vectors
	return
    }
    
    command "lte_set_vectors 1" 0
    banner "Select an element for reference with the left button;\
		middle = done, right = back up / cancel."
    command "select_stuff elem 2 mesh_pickable" 0
    banner ""
    
    if ![llength $last_line] {
	command "lte_set_vectors 0" 0
	return
    }
    set ref [lindex [lindex $last_line 0] 1]
    
    set rev [tk_dialog .keep "Keep orientation" \
		 "Keep the existing orientation (as displayed for the selected\
		triangle) or reverse it?" "" -1 Keep Reverse]
    
    command "lte_reorient $ref $rev"
    mess "$last_line elements were reoriented.\n"
    if $last_line { set mesh_dirty 1 }
    command "lte_set_vectors 1" 0
    set must_clear_vectors 1
    mess "Click on the Reorient button again to clear the vectors on the screen\n"
}

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

proc te_join {} {
    global mesh_dirty last_line te_join
    
    command "lte_get_smallest_edge 0" 0
    set te_join(ntol) [expr {[lindex $last_line 0] / 3.0}]
    set te_join(etol) [lindex $last_line 0]
    set te_join(smv1) [lindex $last_line 1]
    set te_join(smv2) [lindex $last_line 2]
    set te_join(smn1) [lindex $last_line 3]
    set te_join(smn2) [lindex $last_line 4]
    set te_join(sme) [lindex $last_line 5]
    
    set d [form_init .join "Join edges" "" {{{Join edges} te_do_join} done}]
    if {$d != ""} {
	set te_join(type) one
	set te_join(maxi) 5
	set te_join(init_mt) 0
	set te_join(do_restrict) 0
	
	form_radiobutton $d.onestep "One step" te_join(type) one {0 0 -cols -}
	set act {{te_join(type) one}}
	form_label $d.oneetl "Edge tol" {1 1} $act
	form_label $d.onentl "Node tol" {2 1} $act
	form_entry $d.oneet te_join(etol) float {1 2} $act
	form_entry $d.onent te_join(ntol) float {2 2} $act
	
	form_radiobutton $d.m "Multiple steps" te_join(type) mult {10 0 -cols -}
	set act {{te_join(type) mult}}
	form_label $d.multil "Max iterations" {11 1} $act
	form_entry $d.multi te_join(maxi) float {11 2} $act
	form_label $d.multijl "Initial merge tol" {12 1} $act
	form_entry $d.multij te_join(init_mt) float {12 2} $act
	form_checkbutton $d.multsr "Screen restrict between steps" \
	    te_join(do_restrict) {13 1 -cols 2} $act
	
	form_label $d.sml "Smallest edge in model:" {20 0 -cols -}
	form_label $d.emel "Element num:" {21 1}
	form_label $d.emv1l "Vertex num:" {22 1}
	form_label $d.emv2l "Vertex num:" {23 1}
	form_label $d.emn1l "Node num:" {24 1}
	form_label $d.emn2l "Node num:" {25 1}
	form_entry $d.eme te_join(sme) string {21 2}
	form_entry $d.emv1 te_join(smv1) string {22 2}
	form_entry $d.emv2 te_join(smv2) string {23 2}
	form_entry $d.emn1 te_join(smn1) string {24 2}
	form_entry $d.emn2 te_join(smn2) string {25 2}
	
	form_colwidth $d 0 4 M
	form_finish bot
    }
}

proc te_do_join {} {
    global te_join last_line mesh_dirty
    
    switch $te_join(type) {
	one {
	    command "lte_join_edges 0 $te_join(etol) $te_join(ntol)"
	    mess "[lindex $last_line 0] edge triangles were deleted.\n"
	    mess "[lindex $last_line 1] new edge triangles were created.\n"
	}
	mult {
	    mess "Doing initial node merge ...\n"
	    command "lte_merge_nodes_dist 0 $te_join(init_mt)" 0
	    mess "    Nodes eliminated = [lindex $last_line 0]\n"
	    mess "    Elements eliminated = [lindex $last_line 1]\n"
	    
	    for {set iter 0} {$iter < $te_join(maxi)} {incr iter} {
		mess "Selecting single element edges ...\n"
		command "lte_diag 0 0 single_select_clear" 0
		mess "    $last_line elements\n"
		if {$last_line == 0} {
		    mess "No single edge elements -- done\n"
		    break
		}
		
		if $te_join(do_restrict) {
		    mess "Optional screen restrict -- click the right\
			button to keep all visible ...\n"
		    te_sel_screen_restrict
		}
		
		command "lte_get_smallest_edge 0" 0
		set te_join(ntol) [expr {[lindex $last_line 0] / 3.0}]
		set te_join(etol) [lindex $last_line 0]
		
		mess "Joining edges ...\n"
		command "lte_join_edges 0 $te_join(etol) $te_join(ntol)"
		mess "    [lindex $last_line 0] edge triangles were deleted.\n"
		mess "    [lindex $last_line 1] new edge triangles were created.\n"
		
		if {![string compare $last_line "0 0"]} {
		    mess "No edges joined -- done\n"
		    break
		}
	    }
	}
    }
    # Be conservative here
    set mesh_dirty 1
}

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

proc te_move_node {} {
    global mesh_dirty last_line te_move_type te_share_volume
    global te_move_surf te_move_curve te_move_surf_fam te_move_curve_fam
    
    set how $te_move_type
    if {$how == "line"} {
	banner "Select two nodes to define a direction with the left button;\
		middle = done, right = back up / cancel."
	command lte_get_direction
	if {$last_line == ""} {
	    banner ""
	    mess "No direction given\n" red
	    return
	}
	set how "line $last_line"
	
    } elseif {$how == "vector"} {
	banner "Select two nodes to define a line with the left button;\
		middle = done, right = back up / cancel."
	command lte_get_line
	if {$last_line == ""} {
	    banner ""
	    mess "No line given\n" red
	    return
	}
	set how "vector $last_line"
	
    } elseif {$how == "splitm"} {
	banner "Select the two side nodes to split with the left button;\
		middle = done, right = back up / cancel."
	command "select_stuff node 3 mesh_pickable"
	banner ""
	set spe [lrange $last_line 0 1]
	if {$spe == ""} return
	
	set how "splitm $spe"
    
    } elseif {$how == "splitn"} {
	banner "Select the elements that go with the new node with the\
		left button; middle = done, right = back up / cancel."
	command "select_stuff elem 0 mesh_pickable"
	banner ""
	set spe [lrange [lindex $last_line 0] 1 end]
	if {$spe == ""} return
	
	set how "splitn $spe"
    }
    
    switch [lindex $how 0] {
	plane - line { set cons "" }
	default {
	    set cons [modify_list_families]
	    if {$cons == ""} {
		mess "Warning: no CAD families are active -- no projection\
			will be done\n" red
	    }
	    command "lte_set_project $cons" 0
	}
    }
    
    banner "Select and move nodes with the left button; middle = done,\
	    right = back up / cancel."
    command "lte_move_node \{$how\} $te_share_volume"
    banner ""
    set mesh_dirty 1
}

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

proc te_change_family {} {
    global mesh_family_active families mesh_dirty
    
    set fams ""
    foreach f $families {
	lappend fams $f
    }
    set fams [lsort $fams]
    
    set mess "Choose a family name.  Note that ALL the currently\
	selected triangles will be changed to this new family."
    set ff [choose_one $mess $fams "" +300+300]
    if {$ff == ""} return
    
    foreach f $families {
	if {$ff == $f } { set new_fam $f }
    }
    if ![info exists new_fam] {
	set new_fam [add_one_family $ff]
    }
    
    command "lte_change_family $new_fam"
    set mesh_dirty 1
}

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

proc te_merge_nodes {} {
    global te_merge_distance
    
    set d [form_init .merge "Merge nodes" tri_edit done]
    if {$d != ""} {
	set te_merge_distance 0
	form_button $d.ss "Screen select" te_merge_nodes_screen {0 0 -cols 2}
	form_button $d.sma "Collapse edges" "te_merge_nodes_dist 1" \
	    {1 0 -cols 2}
	form_button $d.sme "All visible nodes" "te_merge_nodes_dist 0" \
	    {2 0 -cols 2}
	form_label $d.distl "Tol:" {3 0}
	form_entry $d.dist te_merge_distance float {3 1}
	form_finish bot
    }
}

proc te_merge_nodes_screen {} {
    global mesh_dirty last_line
    
    banner "Select one node to merge the others into with the left button;\
		middle = done, right = cancel."
    command "select_stuff node 1 mesh_pickable"
    set node [lindex $last_line 0]
    banner ""
    if {$node == ""} return
    
    banner "Select nodes to be merged into this one with the left button;\
		middle = done, right = back up / cancel."
    command "lte_merge_nodes $node"
    banner ""
    
    set mesh_dirty 1
}
  
proc te_merge_nodes_dist {adj} {
    global mesh_dirty last_line te_merge_distance
    
    command "lte_merge_nodes_dist $adj $te_merge_distance"
    set nn [lindex $last_line 0]
    set ne [lindex $last_line 1]
    mess "Nodes eliminated = $nn\n"
    mess "Elements eliminated = $ne\n"
    
    if {$nn || $ne} { set mesh_dirty 1 }
}

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

proc te_delete_nodes {} {
    global mesh_dirty last_line
    
    banner "Select the nodes to delete with the left button;\
		middle = done, right = back up / cancel."
    command "select_stuff node 0 mesh_pickable 0"
    banner ""
    if !$last_line return
    
    command "lte_delete_nodes"
    
    set mesh_dirty 1
}

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

proc te_smooth_disp {} {
    global mesh_dirty last_line te_value te_iters botform_geo form_done_flag
    global te_smtype has_tetin
    
    if !$has_tetin {
	mess "This operation not possible if there is no tetin file.\n" red
	return
    }
    if ![info exists te_smtype] { set te_smtype aspect }
    set d [form_init .te_smooth "Smooth triangle mesh" tri_edit_smooth \
	       {done cancel}]
    if {$d != ""} {
	set te_value 0.3
	set te_iters 3
	form_frame $d.fr sunken 2 {0 0}; set d $d.fr
	form_label $d.typel "Criterion:" {0 0}
	form_label $d.aspl "Value:" {10 0}
	form_label $d.itersl "Iterations:" {11 0}
	form_radiobutton $d.tasp "Aspect ratio" te_smtype aspect {0 1}
	form_radiobutton $d.tskew "Skew" te_smtype skew {1 1}
	form_radiobutton $d.tmina "Min angle" te_smtype mina {2 1}
	form_radiobutton $d.tmaxa "Max angle" te_smtype maxa {3 1}
	form_entry $d.asp te_value float {10 1}
	form_entry $d.iters te_iters float {11 1}
	form_finish $botform_geo
    }
    tkwait variable form_done_flag(.te_smooth)
    if !$form_done_flag(.te_smooth) return
    
    busy 1
    command "lte_smooth_elements $te_smtype $te_iters $te_value"
    busy 0
    mess "[lindex $last_line 0] triangles deleted,\
	[lindex $last_line 1] bars deleted\n"
    mess "[lindex $last_line 2] nodes moved, average distance =\
	    [lindex $last_line 3]\n"
    mess "You may have to clear the selection and redisplay it if the surface\
		does not look right.\n"
    set mesh_dirty 1
}

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

proc te_diagnostics {} {
    global botform_geo te_diagtype te_face_angle
    global te_delaunay_angle te_delaunay_tolerance
    global te_overlap_angle te_diagall te_onlyedge
    
    if ![info exists te_diagtype] { set te_diagtype aspect }
    
    set d [form_init .te_diag "Diagnostics" tri_edit_diag done]
    if {$d != ""} {
	set te_face_angle 45
	set te_delaunay_angle 30
	set te_delaunay_tolerance 0
	set te_overlap_angle 15
	set te_diagall 0
	set te_onlyedge 0
	
	form_frame $d.fr sunken 2 {0 0}; set d $d.fr
	form_button $d.histo "Histogram" te_histogram {0 0}
	
	form_radiobutton $d.tasp "Aspect ratio" te_diagtype aspect {0 1}
	form_radiobutton $d.tskew "Skew" te_diagtype skew {1 1}
	form_radiobutton $d.tmina "Min angle" te_diagtype mina {2 1}
	form_radiobutton $d.tmaxa "Max angle" te_diagtype maxa {3 1}
	form_radiobutton $d.tdev "Deviation" te_diagtype dev {4 1}
	
	form_button $d.dups "Duplicate triangles" "te_diag dups" \
		{10 0 -cols 2}
	#form_button $d.mids "Midside nodes" "te_diag mids" {11 0 -cols 2}
	#form_button $d.nman "Non-manifold edges" "te_diag nman" {12 0 -cols 2}
	form_button $d.sing "Single edges" "te_diag single" \
		{13 0 -cols 2}
	form_button $d.mult "Multiple edges" "te_diag multiple" \
		{14 0 -cols 2}
	form_button $d.over "Overlapping triangles" "te_diag overlap" \
		{15 0 -cols 2}
	form_label $d.overvl Angle {16 0 -fill x}
	$d.overvl configure -anchor e
	form_entry $d.overv te_overlap_angle float {16 1}
	form_button $d.dela "Delaunay violations" "te_diag delaunay" \
		{17 0 -cols 2}
	form_label $d.delavl Angle {18 0 -fill x}
	$d.delavl configure -anchor e
	form_entry $d.delav te_delaunay_angle float {18 1}
	form_label $d.delatl Tol {19 0 -fill x}
	$d.delatl configure -anchor e
	form_entry $d.delat te_delaunay_tolerance float {19 1}
	
	form_button $d.vman "Non-manifold vertices" "te_diag vman" \
		{22 0 -cols 2}
	form_button $d.tang "Feature lines" "te_diag feature" \
		{23 0 -cols 2}
	form_label $d.tangvl Angle {24 0 -fill x}
	$d.tangvl configure -anchor e
	form_entry $d.tangv te_face_angle float {24 1}
	
	form_radiobutton $d.sele "Selected elements" te_diagall 0 {30 0 -cols 2}
	form_radiobutton $d.alle "All elements" te_diagall 1 {31 0 -cols 2}
	
	form_checkbutton $d.onlye "Show only edges" te_onlyedge {32 0 -cols 2}
	
	form_button $d.del "Delete shown elements" "te_diag delete" \
		{40 0 -cols 2}
	form_button $d.sel "Select shown elements" "te_diag select" \
		{41 0 -cols 2}
	form_button $d.clear "Clear diagnostics" "te_diag clear" \
		{42 0 -cols 2}
	
	form_rowheight $d 29 4
	form_rowheight $d 39 4
	
	form_finish $botform_geo
    }
    form_wait .te_diag
    
    te_diag clear
}

proc te_diag {what} {
    global last_line te_face_angle te_delaunay_angle te_overlap_angle
    global mesh_dirty te_diagall te_onlyedge te_delaunay_tolerance
    
    if {$what == "delete"} {
	set msg "Really delete all elements in the current selection that are\
		also displayed in red or pink?"
	if ![tk_dialog .del "Delete elements" $msg "" -1 No Yes] return
	set mesh_dirty 1
    } elseif {$what == "nman"} {
	mess "Pink: elements with free edges (no adjacent triangles).\n"
	mess "Red: elements with multiply-connected edges (more than 1\
		adjacent triangles.\n"
    }
    
    if {$what == "feature"}  { set what "feature $te_face_angle" }
    if {$what == "delaunay"} { set what "delaunay $te_delaunay_angle $te_delaunay_tolerance" }
    if {$what == "overlap"}  { set what "overlap $te_overlap_angle" }
    command "lte_diag $te_diagall $te_onlyedge \"$what\""
    mess "$last_line elements\n"
}

proc te_histogram {{label ""} {nbars 25} {min 0} {max 1} {ylim 16} {args ""}} {
    global all_lines te_shading te_diagtype histo_xformat te_diagall
    global has_tetin last_line te_prev_shading
    
    if {$label == ""} {
	switch $te_diagtype {
	    aspect { set label "Aspect ratio";      set min 0; set max 1 }
	    skew   { set label "Skew";              set min 0; set max 1 }
	    mina   { set label "Min angle";         set min 0; set max 60 }
	    maxa   { set label "Max angle";         set min 60; set max 180 }
	    dev    {
		if !$has_tetin {
		    mess "This operation not possible when there is no tetin\
			file loaded.\n" red
		    return
		}
		set label "Surface deviation"; set min 0; set max *
		command "lte_set_project [modify_list_families]"
	    }
	}
    }
    
    command "lte_histogram $te_diagtype $min $max $nbars $te_diagall" 0
    
    # returns for each line: low high count
    
    set xvals ""
    set yvals ""

    foreach line $all_lines {
	if {[llength $line] == 3} {
	    set low [lindex $line 0]
	    set hi [lindex $line 1]
	    set n [lindex $line 2]
	    lappend xvals $low
	    lappend yvals $n
	}
    }
    if ![info exists hi] {
	mess "Error: histogram wasn't computed\n" red
	return
    }
    
    command "set lte_histo_stats" 0

    mess "Min value  = [lindex $last_line 0]\n"
    mess "Max value  = [lindex $last_line 1]\n"
    mess "Mean value = [lindex $last_line 2]\n"
    mess "Num values = [lindex $last_line 4]\n"
    mess "Bad values = [lindex $last_line 5]\n"
    
    if ![lindex $last_line 4] {
	mess "Skipping histogram -- no values\n"
	return
    }
    
    lappend xvals [expr {$hi + ($hi - $low)}]
    
    set histo_xformat %g
    make_histogram .histogram $label $xvals $yvals \
	    $ylim "" te_histogram te_histogram_select
    
    set te_prev_shading $te_shading
    set te_shading 1
    te_update_shading
}

proc te_histogram_select {w intervals arguments solid } {
    global te_shading te_prev_shading
    
    if {$intervals == ""} {
	command "lte_clear_histogram"
	set te_shading $te_prev_shading
	te_update_shading
    } else {
	mess "SELECT $intervals $solid"
    }
}

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

proc te_project_nodes {} {
    global mesh_dirty last_line
    
    command "lte_set_project [modify_list_families]" 0
    command "lte_project_nodes"
    mess "[lindex $last_line 0] nodes projected,\
	max dist = [lindex $last_line 1]\n"
    
    set mesh_dirty 1
}

proc te_add_bars {} {
    global mesh_dirty
    
    command "start_create_bars" 0
    while 1 {
	set nodes [pick_some_nodes 2]
	if {[llength $nodes] < 2} {
	    command "end_create_bars" 0
	    return
	}
	command "create_bar \{$nodes\}"
	set mesh_dirty 1
    }
}

proc te_del_bars {} {
    global mesh_dirty last_line

    set elems [pick_some_bars 0]
    if {$elems == ""} return
    command "delete_bars \{$elems\}"
    set mesh_dirty 1
}

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

proc undo_action {} {
    global current_phase mesh_dirty last_line
    
    if {($current_phase != "tri_edit") && ($current_phase != "quad_edit")} {
	mess "Undo/redo is only available in surface edit mode.\n" red
	return
    }
    command tetra_undo
    if $last_line { set mesh_dirty 1 }
}

proc redo_action {} {
    global current_phase mesh_dirty last_line
    
    if {($current_phase != "tri_edit") && ($current_phase != "quad_edit")} {
	mess "Undo/redo is only available in surface edit mode.\n" red
	return
    }
    command tetra_redo
    if $last_line { set mesh_dirty 1 }
}
