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

proc canonical_path {name} {
    if {[file pathtype $name] != "absolute"} { set name [pwd]/$name }
    set td2 ""
    foreach p [file split $name] {
	if {$p != "."} { lappend td2 $p }
    }
    return [eval file join $td2]
}

proc mesher_hexa {{extra ""}} {
    global file_name hexa_values
    global tdv_default

    if ![lindex [check_licenses_enabled] 0] {
	user_error "No med license was obtained"
	return
    }

    if {$file_name(mesh_dir) == "" } {
	user_error "Can't run hexa : no project selected"
	return
    }

    file_save_one tetin 1

    set this_tetin $file_name(tetin)
    set thisdir [eval file join [file split [file dirname $file_name(tetin)]]]
    set wantdir [eval file join [file split $file_name(mesh_dir)]]

    if { [ file isfile $this_tetin ] && ($thisdir != $wantdir) } {
        user_error "The tetin file is not in the project directory, please save \
                the tetin file locally."
        return
    }
    if {$extra == ""} {
	# Select a blocking and tetin file automatically.
	if {($this_tetin == "") || ![file exists $this_tetin]} {
	    set this_tetin [med_file_select tetin 0 "" "to use for meshing"]
	}
	if {$this_tetin == ""} return
	if { [ file dirname $this_tetin ] != $file_name(mesh_dir) } {
		user_error "The tetin file is not in the mesh_directory"
		return
	}
	set extra "-tetin \"$this_tetin\""

	set blockf [hexa_select_blocking_file ]
	if {$blockf == ""} return
	set hexa_values(blocking_file) $blockf
	set thisdir [eval file join [file split [file dirname $blockf]]]
	set wantdir [eval file join [file split $file_name(mesh_dir)]]


	if { $blockf != "__no_blocking__" && ($thisdir != $wantdir) } {
		user_error "the blocking file $blockf is not in the mesh directory $file_name(mesh_dir)"
		return
	}
	lappend extra -block [ file tail $blockf ]

	lappend extra -domain_dir $file_name(domains_dir) \
	    -mesh_dir $file_name(mesh_dir) -use_file_suffixes
    }

    if ![geo_check_available_space] return

    set topo_mulcad_out $file_name(mesh_dir)/topo_mulcad_out.top
    set family_topo $file_name(mesh_dir)/family_topo.fto
    set subface_proj $file_name(mesh_dir)/subface_proj

    set nf1 [domain_newest_file]
    run_application_guibase icemcfd/hex_gui icemcfd/hexa HEXA_BIN \
	lib/hexa/hexa.tcl 1 $extra 1
    set nf2 [domain_newest_file]
    if {[lindex $nf2 1] > [lindex $nf1 1]} {
	if [string match domain.* [lindex $nf2 0]] {
	    set to_load $file_name(domains_dir)/Multiblock ;# $file_name(domains_dir)/domain.*
	    set is_str 1

	    # Just in case there are old versions of these files, delete them
	    cmd_rm $file_name(mesh_dir)/topo_mulcad_out
	    cmd_rm $file_name(mesh_dir)/family_topo

	} else {
	    set to_load $file_name(domains_dir)/[lindex $nf2 0]
	    set is_str 0
	}
	if ![popup "Load new mesh" "Load the new mesh\n[file tail $to_load]?" 1] { return }
	if ![file_unload_or_merge $is_str] { return }

	file_do_load_domain $to_load $topo_mulcad_out $family_topo $subface_proj

	if {$this_tetin != $file_name(tetin)} {
	    file_do_load_tetin [list $this_tetin]
	}
	tdv_home $tdv_default
    }
#    ic_boco_reload
}

proc hexa_select_blocking_file {} {
    global hexa_values file_name
    set blockf $hexa_values(blocking_file)
    if {($blockf == "") || ($blockf == "__no_blocking__")} {
	    set blockf $file_name(mesh_dir)/
    }
    if { [ file dirname $blockf ] != $file_name(mesh_dir) } {
	set blockf $file_name(mesh_dir)
    }

    set mess "Please select a blocking file to load the\
	    mesh information from.\nTo start up with a new blocking,\
		use the \"New blocking\" button."

    set file [file_select_rel $mess $blockf "Blocking file" 0 -1 file_is_blocking \
		  "" {on_side hexa_select_blocking_extra_widgets} \
		  {has_suffix "Blocking (.blk)" .blk } hexa_blocking_file_put]

    return $file
}


proc hexa_compare_blocking_file {ff1 ff2} {
    return [expr {[lindex $ff2 1] - [lindex $ff1 1]}]
}

proc hexa_select_blocking_extra_widgets {d} {
    global hexa_blocking_file_picture_frame

    form_frame $d.picture flat 0 {0 0}
    $d.picture configure -width 275 -height 175
    set hexa_blocking_file_picture_frame $d.picture
}

proc hexa_blocking_file_put {file} {
    global hexa_blocking_file_picture_frame

    set pict [ file rootname $file].ppm
    set iml $hexa_blocking_file_picture_frame.im
    if [file exists $pict] {
	if [winfo exists $iml] {
	    set im [$iml cget -image]
	    image delete $im
	} else {
	    label $iml
	    pack $iml
	}
	set im [image create photo -file $pict]
	$iml configure -image $im
    } elseif [winfo exists $iml] {
	set im [$iml cget -image]
	image delete $im
	destroy $iml
    }
}

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

proc mesher_hex_dominant {} {
    global file_name hex_dom_values

    if {$file_name(domains_dir) == ""} { 
	user_error "Can't run hex_dom : no project selected" 
	return
    }
    
    if { ![ic_uns_is_loaded] } {
	error "You need to have a surface mesh"
    }

    set form_name .hex_dom
    set title "Hex Dominant Mesher"

    set buts [ list \
        [ list Mesh [ list mesher_hex_dom_doit $form_name ] ] dismiss ]

    set d [ form_init $form_name $title mesher $buts ]
    set hex_dom_values(mesh_in) $file_name(domain)

    if { ! [ info exists hex_dom_values(mesh_out) ] ||
		$hex_dom_values(mesh_out) == "" }  {
	set hex_dom_values(mesh_out) hex_dom.uns
    }
    if { $d != "" } {
	set ln 0
	form_frame $d.fr sunken 3 "$ln 0"; set d $d.fr

# input mesh
	incr ln
	form_label $d.input "Surface mesh input file" "$ln 0"
	file_select_entry $d.meshin hex_dom_values(mesh_in) 0 1 \
            "Select a Surface mesh file." "$ln 1" "" \
            "" "" "" {has_suffix "Domain (.uns)" .uns}

# output mesh
	incr ln
        form_label $d.meshoutl "Hex dominant output mesh file" "$ln 0"
        file_select_entry $d.meshout hex_dom_values(mesh_out) 0 1 \
            "Select output mesh file." "$ln 1" "" \
            "" "" "" {has_suffix "Domain (.uns)" .uns}

# volume family
	incr ln
        form_label $d.faml "Volume element family" "$ln 0"
        form_entry $d.fam hex_dom_values(family) string "$ln 1"
        form_menubutton $d.fam_menu "    " "" "$ln 2 -fill none"
        futil_drop_down_button $d.fam_menu #ffc0c0 #ffa0a0
        bind $d.fam_menu <ButtonPress-1> mesher_hex_dom_family
        bind $d.fam_menu <ButtonRelease-1> break

	form_finish +300+300
    }


}

proc mesher_hex_dom_doit { form_name}  {
    global tdv_default
    global file_name hex_dom_values file_save

    form_kill $form_name

    ic_mesh_hexdom $hex_dom_values(family)

    update_uns_visible
    disp_new_stuff

    tdv_home $tdv_default
}

proc mesher_hex_dom_family {} {
    global hex_dom_values
    set fam [select_family]
    if {$fam != ""} {
        set hex_dom_values(family) $fam
    }
}

proc mesher_hexa_batch {} {
    global file_name hexa_values
    
    if {$file_name(mesh_dir) == ""} { 
	user_error "Can't run hexa : no project selected" 
	return
    }
    
    file_save_one tetin 1

    set this_tetin $file_name(tetin)
    
    # Select a blocking and tetin file automatically.
    if {$this_tetin == ""} {
	set this_tetin [med_file_select tetin 0 "" "to use for meshing"]
    }
    if {$this_tetin == ""} return

    set blockf [hexa_select_blocking_file ]
    if {$blockf == ""} return
    if { $blockf == "__no_blocking__" } {
	set blockf ""
    }

    set hexa_values(blocking_file) $blockf

    set replay $hexa_values(replay_file)
    if {$replay == ""} {
	set split_path [ file split $file_name(project_dir) ]
	set first [ lindex "$split_path" 0 ]
	mess "$first\n"
	if { $first == "mulcad" } {
		set replay mulcad/[lindex "$split_path" 1 ]/hexa
	} else {
		set replay $file_name(mesh_dir)/replay.hxa
	}
    }
    set replay [file_selection -message "Replay file?" -default $replay]
    if {$replay == ""} return
    set del_replay 0
    
    set hexa_values(replay_file) $replay
    
    set nf1 [domain_newest_file]
    
    if ![geo_check_available_space] return
    
    if ![ic_run_hexa $this_tetin $blockf $replay $file_name(project_dir) \
		$file_name(domains_dir) $file_name(mesh_dir) ] return
    
    if $del_replay { ic_rm $replay }
    
    set nf2 [domain_newest_file]
    if {[lindex $nf2 1] > [lindex $nf1 1]} {
	if [string match domain.* [lindex $nf2 0]] {
	    set to_load $file_name(domains_dir)/Multiblock
	} else {
	    set to_load $file_name(domains_dir)/[lindex $nf2 0]
	}
	if [ic_str_is_loaded] {
	    set mess "You already have a structured mesh.  Merge the\
		new mesh in, replace the current one, or don't load the new\
		mesh at all?"
	    switch [tk_dialog .newmesh "New mesh" $mess "" -1 \
			Merge Replace Cancel] {
			    0 { }
			    1 { file_unload domain }
			    2 { return }
			}
	}
	file_loadmesh $to_load 0
	if {$this_tetin != $file_name(tetin)} {
	    file_load tetin $this_tetin
	}
	tdv_home $tdv_default
    }
}

proc mesher_mulcad_convert {} {
#   modification : 01/00 - new version	     - Jerome Lordon
#
    global env file_name med_root domains_selected

    mess "MULCAD to Hexa converter\n" blue
    set pwd [pwd]
    set pwdl [string length $pwd]
    set topo $file_name(mesh_dir)/topo_mulcad_out
#   check pasuf file
    set pasuf $file_name(mesh_dir)/pasuf
    set pasufiles [glob -nocomplain $pasuf.*]
    if {$pasufiles != ""} {
	set i 0
	foreach d $pasufiles {
	    if {[scan $d "$file_name(mesh_dir)/pasuf.%d" num] != 1} \
		    {warningmsg "Strange file $d"; continue}
	    if {$num >> $i} {set i $num}
	}
	if {$i != 0} {set pasuf $file_name(mesh_dir)/pasuf.$i}
    }
    if ![file exists $pasuf] {
	errormsg "File \"$pasuf\" doesn't exist"
	return
    }
#   check if domain exists
    set df ""
    set nums ""
    foreach dom [glob -nocomplain $file_name(domains_dir)/*] {
	if [string match */ogrid_dir $dom] continue
	if [string match */tmpdomain* $dom] continue
	if {[string match */domain.* $dom] && \
		[scan [file extension $dom] .%d num]} {
	    set t struct ;# This is an optimization
	    lappend nums $num
	} else {
	    set t [domain_types $dom]
	}
	lappend found($t) $dom
    }
    
    if ![info exists found(unstruct)] {
       if [info exists found(struct)] {
	   mess "Converting structured domains to unstructured domain\n"
	   set dfile $file_name(domains_dir)/mulcad.unstruct
	   
	   if [ic_convert_struct_to_unstruct $file_name(domains_dir) \
		   $nums $topo "" "" $dfile ""] {
	       set df $dfile
	   }
       } else {
	  warningmsg "No valid domain exists"
	  if ![tk_dialog .quit "Run Mulcad/PADAMM" \
	       "Run MULCAD/PADAMM in batch mode?" "" -1 "Yes" "No"] {
	      mess "Select part file" blue
	      set stuff [ddn_select_part project 1]
	      if {$stuff == "" } return
	      set pn [lindex $stuff 1]
	      rm_tmp_file $file_name(domains_dir)/mulcad.unstruct
	      set cmd "$med_root/lib/med/mulcad.tcl \
		      $file_name(project_dir) $pn  mulcad.unstruct"
	      ic_run_application_exec . bin tclsh $cmd
	      if ![file exists $file_name(domains_dir)/mulcad.unstruct] {
		 errormsg "Automatic MULCAD/PADAMM failed"
	      } else {
		  set df $file_name(domains_dir)/mulcad.unstruct
	      }
	  }
      }
      if {$df == ""} return
    }
#   check topo file
    if ![file exists $topo] {
	errormsg "File \"$topo\" doesn't exist"
	return
    }
#   check tetin file
    mess "Select IPARTA file or " blue
    mess "Cancel" orange
    mess " if the tetin file already exists\n" blue
    set ipa [ddn_select_part project 1]
    set tfile $file_name(tetin)
    if {$tfile == ""} {
	set tfile $file_name(mesh_dir)/tetin_mulcad
	set unlotf 0
    } else {
	set unlotf 1
    }
    if {$ipa != ""} {
#       convert iparta to tetin
	set partf $file_name(parts_dir)/[file tail [lindex $ipa 2] ]
	if [partfile_is_binary $partf] {
	    errormsg "The part must be in ASCII format"
	    return
	}
	mess "Select file to save the tetin data\n" blue
	set tf [med_file_select tetin 1 "" "to save"]
       if {$tf == ""} {
	  errormsg "No tetin file selected"
	  return
       }
       if {[string range $tf 0 $pwdl] == "$pwd/"} {
	   set tf [string range $tf [expr $pwdl + 1] end]
       }
	if 0 {
	    set cmd "[get_program bin iparta_to_tetin] -i $partf -w $tf"
	    ic_rm $tf
	    ic_rm $tf.fboco
	    run_application_exec $cmd
	    if { ![file exists $tf] || ![file exists $tf.fboco] } {
		errormsg "Problem encountered when converting IPARTA to tetin"
		return
	    }
	}
	ic_trans_ddn_tetin $partf $tf
	
       set fr [open $tf.fboco r]
       set fw [open $tf.fboco.tmp w]
       set line [gets $fr]
       puts $fw $line
       set line "\"MAT_MULCAD\""
       puts $fw $line
       while {![eof $fr]} {
	   set line [gets $fr]
	   puts $fw $line
       }
       close $fr
       close $fw
       ic_cp $tf.fboco.tmp $tf.fboco
       rm_tmp_file $tf.fboco.tmp
    }  else {
#      select tetin file
       mess "Select existing tetin file\n" blue
       set tf [med_file_select tetin 0 "" "to use for mulcad to hexa"]
       if {$tf == ""} {
	  errormsg "No tetin file selected"
	  return
       }
       if {[string range $tf 0 $pwdl] == "$pwd/"} {
	   set tf [string range $tf [expr $pwdl + 1] end]
       }
    }
#   select domain
    if {$df == ""} {
      mess "Select unstructured domain\n" blue
      set choices [file_select_domainfiles convert 0]
      if  {$choices == ""} {
	  errormsg "No unstructured domain file selected"
	  return
      }
      set ns 0
      foreach ch $choices {
	  if $domains_selected([lindex $ch 0]) { 
	      incr ns 
	      set df $file_name(domains_dir)/$ch
	  }
      }
      if  {$ns != 1} {
	   errormsg "Warning: select one unstructured domain"
	   return
      }
    }
#   select blocking file
    mess "Select new blocking file\n" blue
    set mess "Please select a blocking file to write the mesh information\n"
    set blockf $file_name(mesh_dir)/blocking_mulcad
    set blockf [file_select $mess $blockf "Blocking file" 0 1 \
		    file_is_blocking ""]
    if  {$blockf == ""} {
	errormsg "No blocking file selected"
	return
    }
    if {[string range $blockf 0 $pwdl] == "$pwd/"} {
	 set blockf [string range $blockf [expr $pwdl + 1] end]
     }
#   run mesh2block
    set cmd "-b -m $topo -p $pasuf $df $blockf"
    rm_tmp_file $blockf
    ic_run_application_exec . icemcfd mesh2bloc $cmd
    if ![file exists $blockf] {
       errormsg "Problem encountered when converting mesh to hexa blocking"
       return
    }
#   load tetin file and run hexa
    if {$unlotf} {
       mess "Unloading tetin file\n" blue
       file_unload tetin
    }
    mess "Loading new tetin file\n" blue
#   file_load tetin $tf
    ic_load_tetin $tf
    mess "Conversion complete\n" blue
    if ![tk_dialog .quit "Run Hexa" "Run Hexa?" "" -1 "Yes" "No"] {
	mesher_hexa "-tetin $tf -block $blockf"
    }
}

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

proc mesher_tetra_full {{extra ""}} {
    global env file_name unstruct_file options

    if {$file_name(domains_dir) == ""} {
	user_error "Can't run tetra : no project selected"
	return
    }

# check if there is aleady a domain
    if [ic_uns_is_loaded] {
	set mess "You already have a an unstructed mesh.  Running the\
		tetra mesher will overwrite it. Do you wish to save it \
		first ?"
	switch [tk_dialog .newmesh "Replace mesh" $mess "" -1 \
	Save Overwrite Merge Cancel ] {
	    0 {
		mess "saving\n"
		file_savemesh 0
		file_unload domain
	    }
	    1 {
		mess "overwriting\n"
		file_unload domain
	    }
	    2 {
		mess "merging\n"
	    }
	    3 {
		mess "cancel\n"
		return
	    }
	}
    }

    set env(TETRA_NO_MODIFY_MENU) 1
    if {$file_name(tetin) == ""} {
	set tetin [med_file_select tetin 0 "" "to use for meshing"]
	if {$tetin == ""} return
    } else {
	file_save_one tetin 1
    }
    append extra " -tetin $file_name(tetin)"
    if { $options(n_processors) != "" } {
 	append extra " -nproc $options(n_processors) "
    }
    run_application_guibase icemcfd/tetra_gui icemcfd/cutter CUTTER_BIN \
	lib/tetra/tetra.tcl 1 $extra 1
# now load in the domain file ...
    set domains [ glob -nocomplain $file_name(domains_dir)/* ]
# look for domain files more recent than tetin file
    set cut_domain $file_name(tetin)
    foreach i $domains {
	if { [ file exists $i ] && \
		[ file mtime $i ]  > [ file mtime $cut_domain ] } {
		set cut_domain $i
	}
    }
    if { $cut_domain != $file_name(tetin) } {
	if [popup "Load mesh" "Load the new tetra mesh\n$cut_domain ?" 1] {
	    gui_load_domains [list $cut_domain]
	    set unstruct_file $cut_domain
	}
    }
}

proc mesher_tetra_mesh {{extra ""}} {

	mesher_tetra

}

proc mesher_global {{extra ""}} {
    global file_name global_values

    if {$file_name(mesh_dir) == ""} {
	user_error "Can't run global : no project selected"
	return
    }

    if ![info exists global_values(tetin_file)] {
	if {$file_name(tetin) == ""} {
	    set md $file_name(mesh_dir)
	    set avail [glob -nocomplain $md/*.tin $md/tetin*]
	    set dtin [lindex $avail 0]
	    if {$dtin == ""} { set dtin $md }
	    set global_values(tetin_file) $dtin
	} else {
	    file_save_one tetin 1
	    set global_values(tetin_file) $file_name(tetin)
	}
    }

    if ![info exists global_values(cart_file)] {
	if {$file_name(cart_file) == ""} {
	    set md $file_name(mesh_dir)
	    set base [file rootname [file tail $global_values(tetin_file)]]
	    set avail [glob -nocomplain $md/$base.crt $md/*.crt $md/cart_file*]
	    set dcrt [lindex $avail 0]
	    if {$dcrt == ""} { set dcrt $md }
	    set global_values(cart_file) $dcrt
	} else {
	    set global_values(cart_file) $file_name(cart_file)
	}
    }

    # initialization

    if ![info exists global_values(vold)] {
	set global_values(vold) 0
	set global_values(1D) 0
	set global_values(centermat) 0
	set global_values(assignmat) -ORFN
	set global_values(usedefaults) 0
    }

    set d [form_init .global "Global Files" mesher]
    if {$d != ""} {
	form_frame $d.fr sunken 3 {0 0}; set d $d.fr

	form_label $d.tfile "Tetin File" {5 0}
	file_select_entry $d.tetin global_values(tetin_file) 0 1 \
	    "Select a geometry file." {5 1 -cols 2} "" \
	    "" "" "" {has_suffix "Tetin (.tin)" .tin}

	form_label $d.cfile "Cart File" {6 0}
	file_select_entry $d.cartf global_values(cart_file) 0 1 \
	    "Select a Cartesian settings file." {6 1 -cols 2} \
	    "" "" "" "" {has_suffix "Cart file (.crt)" .crt}

	form_label $d.vold_l "Volume Disambiguity" {7 0}
	form_radiobutton $d.vold_f "Lowest Family" \
	    global_values(vold) 1 {7 1}
	form_radiobutton $d.vold_e "Close Volumes" \
	    global_values(vold) 0 {7 2}

	form_label $d.unkvol_l "Unknown Volumes" {8 0}
        form_radiobutton $d.assorfn "Set to ORFN" \
	    global_values(assignmat) -ORFN {8 1}
	form_radiobutton $d.fixvol "Fix" \
	    global_values(assignmat) -fixwall {8 2}
        form_radiobutton $d.assmat "Assign" \
	    global_values(assignmat) -assignmat {8 3}

	form_checkbutton $d.model_1D "1D Model" global_values(1D) \
	    {9 0 -cols 2}
	form_checkbutton $d.pushmat "Center Material Point" \
	    global_values(centermat) {10 0 -cols 2 }

	form_label $d.dispmodals "Display Modals" {11 0}
	form_radiobutton $d.last "Last Values" \
	    global_values(usedefaults) 0 {11 1}
	form_radiobutton $d.usedefs "Defaults" \
	    global_values(usedefaults) 1 {11 2}

	form_finish +300+300
    }

    if ![form_wait .global] return

    if {$extra != ""} { append extra " " }

    append extra "-tetin \"$global_values(tetin_file)\""
    if {$global_values(vold) == 1} { append extra " -no_vol_disamb 1" }
    if {$global_values(1D) == 1} { append extra " -1D 1" }
    if {$global_values(centermat) == 1} { append extra " -nopushmat 1" }
    if $global_values(usedefaults) { append extra " -usedefaults 1" }

    append extra " $global_values(assignmat) -cart \"$global_values(cart_file)\""

    set projdir $file_name(project_dir)
    set domdir $file_name(domains_dir)
    set transdir $file_name(transfer_dir)

    append extra " -projdir \"$projdir\" -domdir \"$domdir\" -transdir \"$transdir\""
    run_application_guibase icemcfd/global_gui icemcfd/global GLOBAL_BIN \
	lib/global/global.tcl 0 $extra 1
}

proc mesher_autohexa {{extra ""}} {
    global file_name

    if {$file_name(project_dir) == ""} {
	user_error "Can't run autohex : no project selected"
	return
    }

    ic_run_application_direct $file_name(project_dir) \
		bin autohex AUTOHEX_ROOT $extra
}

# ----------------------------------------------------------------------
proc mesher_tetra_expert { form_name } {
	global tetra_values form_changed
	form_done $form_name
	set form_changed 1
	if { $tetra_values(expert) } {
		set tetra_values(expert) 0
	}  else {
		set tetra_values(expert) 1
	}
}
proc mesher_tetra_some { form_name } {
	global tetra_values form_changed
	form_cancel $form_name
	set form_changed 1
	if { $tetra_values(use_some_existing) } {
		set tetra_values(use_some_existing) 0
	}  else {
		set tetra_values(use_some_existing) 1
	}
}

proc mesher_tetra {{extra ""}} {
    global tetra_values use_xwindows
    global form_changed file_name options
    global tetra_families

    if { $extra == "" } {
	set tetra_values(cutter_which) volume
    } elseif { $extra == "surface" } {
	set tetra_values(cutter_which) surface
    } else {
	error "Illegal value $extra for extra"
    }

    if {$file_name(domains_dir) == ""} {
	user_error "Can't run tetra : no project selected"
	return
    }

# always set to none
    set tetra_values(auto_orphan) none
    if {$file_name(tetin) == ""} {
# need a "No tetin file" option
	set tetra_values(tetin_file) \
	    [med_file_select tetin 0 "" "to use for meshing"]
	if {$tetra_values(tetin_file) == ""} {
# allow no tetin file.
		set tetra_values(use_some_existing) 1
	} else {
		set file_name(tetin) $tetra_values(tetin_file)
	}
    } else {
	file_save_one tetin 1
	set tetra_values(tetin_file) $file_name(tetin)


	if { $tetra_values(cutter_which) == "volume" } {
	    if [ic_geo_is_loaded] {
# check if there are any material points
	        set mats [ic_geo_get_objects material]
	        set found_live 0
	        foreach i $mats {
		    if {[ic_geo_get_family material $i] != "ORFN"} {
		        set found_live 1
		        break
		    }
	        }
	        if { $found_live == 0 } {
		    set tetra_values(auto_orphan) auto_material
	        }
	    }
	}
    }


    if { $tetra_values(cutter_which) == "volume" } {
	set title "Tetra parameters"
	set form_name .tetra
# this is an index into tetra_values
	set mesh_file tetra_mesh_file
        if { ! [ info exists tetra_values(tetra_mesh_file) ] || \
		$tetra_values(tetra_mesh_file) == "" } {
	    set tetra_values(tetra_mesh_file) \
			$file_name(domains_dir)/tetra_mesh.uns
        }
    } else {
	set title "Triangle parameters"
	set form_name .triangle
	set mesh_file triangle_mesh_file
        if { ! [ info exists tetra_values(triangle_mesh_file) ] || \
		$tetra_values(triangle_mesh_file) == "" } {
	    set tetra_values(triangle_mesh_file) \
			$file_name(domains_dir)/tri_mesh.uns
        }
    }

    set buts [ list [ list Mesh [ list mesher_tetra_doit $form_name ] ] dismiss ]
    set d [form_init $form_name $title mesher $buts]
    if { ! [ info exists tetra_values(load_after) ] } {
	set tetra_values(load_after) 1
    }
    if { ! [ info exists tetra_values(expert) ] } {
	set tetra_values(expert) 0
    }
    if { ! [ info exists tetra_values(use_some_existing) ] } {
	set tetra_values(use_some_existing) 0
    }
    if { ! [ info exists tetra_values(fix_holes) ] } {
	set tetra_values(fix_holes) 1
    }
    if { ! [ info exists tetra_values(in_process) ] } {
	set tetra_values(in_process) 0
    }

    set form_changed 0
    set tetra_families [ get_famnames ]
    if {$d != ""} {
	set ln 0
	form_frame $d.fr sunken 3 "$ln 0"; set d $d.fr

	incr ln
        form_radiobutton $d.inproc "Mesh in process" \
                tetra_values(in_process) 1 "$ln 0 -cols 2"
	incr ln
        form_radiobutton $d.outproc "Mesh out of process" \
                tetra_values(in_process) 0 "$ln 0 -cols 2"

# CAD data file
	incr ln
	form_label $d.tetinl "CAD data file" "$ln 0" \
		{ { tetra_values(in_process) 0 } }
	file_select_entry $d.tetin tetra_values(tetin_file) 0 1 \
	    "Select a geometry file." "$ln 1" \
		{ { tetra_values(in_process) 0 } } \
	    "" "" "" {has_suffix "Tetin (.tin)" .tin}

# Tetra mesh file
	incr ln
	if { $tetra_values(cutter_which) == "volume" } {
		set label "Tetra mesh file"
	} else {
		set label "Triangle mesh file"
	}
	form_label $d.tmfl $label "$ln 0" \
		{ { tetra_values(in_process) 0 } }

	set tetra_values($mesh_file) $file_name(domains_dir)/[file tail $tetra_values($mesh_file) ]

	file_select_entry $d.tmf tetra_values($mesh_file) 0 1 \
	    "Select a mesh file." "$ln 1" \
		{ { tetra_values(in_process) 0 } }  \
	    "" "" "" {has_suffix "Domain (.uns)" .uns}


	if { $tetra_values(expert) } {
# basic options
	    incr ln
	    form_button $d.expert "Show basic options" \
			"mesher_tetra_expert $form_name"  "$ln 0"

	    incr ln
	    form_checkbutton $d.fixn "Fix Non-Manifold" \
	        tetra_values(fix_nonman) "$ln 0 -cols 2"

# radio buttons for material points
	    incr ln
	    form_radiobutton $d.auton "Use Existing Material Points" \
	        tetra_values(auto_orphan) none "$ln 0 -cols 2"

	    incr ln
	    form_radiobutton $d.autom "Automatically Create Material Points" \
	        tetra_values(auto_orphan) auto_material "$ln 0 -cols 2"

	    incr ln
	    form_radiobutton $d.autoo "Automatically Create Orphan Points" \
	        tetra_values(auto_orphan) auto_orphan "$ln 0 -cols 2"

	    incr ln
	    form_checkbutton $d.fixh  \
		"Repair holes between material points" \
		tetra_values(fix_holes) "$ln 0 -cols 2"

	    if { $tetra_values(cutter_which) == "surface" } {
	        incr ln
	        form_label $d.selectfaml "Mesh these families" "$ln 0"

  	        incr ln
                form_frame $d.selectfams ridge 2 "$ln 0 -cols 2"
	        mesher_tetra_selectfams $d.selectfams tetra_families_select
	    }


	    incr ln
	    form_label $d.tsmil "Surface smoothing iterations" "$ln 0"
	    form_entry $d.tsmi tetra_values(n_tri_smoothing_steps) \
					int "$ln 1"

	    incr ln
	    form_label $d.smil "Volume smoothing iterations" "$ln 0"
	    form_entry $d.smi tetra_values(smoother_iters) int "$ln 1"

	    incr ln
	    form_label $d.smal "Volume smoothing quality limit" "$ln 0"
	    form_entry $d.sma tetra_values(smoother_aspect) float "$ln 1"

	    incr ln
	    form_checkbutton $d.st "Smooth Transition" \
                tetra_values(run_tri2tet) "$ln 0"

	    incr ln
	    form_label $d.stfl "  Transition Factor" "$ln 0"
	    form_entry $d.stf tetra_values(tri2tet_factor) float "$ln 1"


	    incr ln
	    form_checkbutton $d.cs "Run coarsener" tetra_values(run_coarsen)  \
			    "$ln 0"

	    incr ln
	    form_label $d.csal "  Aspect ratio" "$ln 0"
	    form_entry $d.csa tetra_values(coarsen_aspect) float "$ln 1"

	    if { $tetra_values(cutter_which) == "volume" } {
# save all triangles option
		incr ln
		form_checkbutton $d.alltl "Save all triangles"  \
				tetra_values(save_all_triangles) "$ln 0"
	    }

	    incr ln
	    if { $tetra_values(cutter_which) == "volume" } {
		set label "Load tetra mesh after meshing"
	    } else {
		set label "Load triangle mesh after meshing"
	    }
	    form_checkbutton $d.ld $label tetra_values(load_after) "$ln 0"

	} else {
		incr ln
		form_button $d.expert "Show expert options" \
			"mesher_tetra_expert $form_name"  "$ln 0"
	}
	if { $tetra_values(cutter_which) == "volume" } {
	  if { $tetra_values(use_some_existing) } {
	    incr ln
	    form_button $d.use_some "Do not use existing surface mesh" \
			"mesher_tetra_some $form_name" "$ln 0"

	    incr ln
	    form_label $d.use_existing "Existing surface mesh file" "$ln 0"

	    if { ! [ info exists tetra_values(existing_path) ] ||
		$tetra_values(existing_path) == "" } {
		set tetra_values(existing_path) $file_name(domains_dir)
	    }

	    file_select_entry $d.existing_path tetra_values(existing_path) 0 1 \
            "Select a mesh file." "$ln 1" "" \
            "" "" "" {has_suffix "Domain (.uns)" .uns}
#	    pathentry on $d.existing_path "" $file_name(domains_dir)


	    incr ln
            form_frame $d.selectfams ridge 2 "$ln 0 -cols 2"
            mesher_tetra_selectfams $d.selectfams tetra_families_use_existing

	  } else {
		incr ln
		form_button $d.use_some "Use existing surface mesh" \
			"mesher_tetra_some $form_name" "$ln 0"
	  }


	}

#	pathentry on $d.tetin "" $file_name(mesh_dir)
#	pathentry on $d.tmf "" $file_name(domains_dir)

	form_finish +300+300
    }


    if ![form_wait $form_name] {
        if { $form_changed } {
	    form_kill $form_name
	    mesher_tetra $extra
        }
	return
    }

}
proc mesher_tetra_doit { form_name } {

    global tetra_values tetra_families tetra_families_select file_name
    global tetra_families_use_existing options remesh disp_options
    global tdv_default uns_use_subset cmd_tempfile_dir is_win

    form_kill $form_name


    if ![geo_check_available_space] return

    set tetin $tetra_values(tetin_file)
    if { $tetin == "" } {
	set tetin __no_tetin__
    } else {
	if { ![string match */* $tetin] } {
		set tetin $file_name(mesh_dir)/$tetin
	}
    }
    if { $tetra_values(cutter_which) == "volume" } {
	set mesh_file tetra_mesh_file
    } else {
	set mesh_file triangle_mesh_file
    }
    set cut_domain $file_name(domains_dir)/[ file tail $tetra_values($mesh_file) ]
#    if ![string match */* $cut_domain] {
#	set cut_domain $file_name(domains_dir)/$cut_domain
#    }

    if { ! [ file exists [ file dirname $cut_domain ] ] } {
	ic_mkdir [ file dirname $cut_domain ]
    }
    if $is_win {
        set cmd "ic_run_tetra [win_shortname $tetin]"
        set dir [win_shortname [file dirname $cut_domain]]
        append cmd " $dir/[file tail $cut_domain] run_cutter 1"
    } else {
        set cmd "ic_run_tetra $tetin $cut_domain  run_cutter 1"
    }
    if { [ info exists tetra_values(auto_orphan) ] } {
	switch $tetra_values(auto_orphan) {
		auto_orphan { append cmd " auto_orphan 1" }
		auto_material { append cmd " auto_vol 1" }
	}
    }
    if { [ info exists tetra_values(fix_holes) ] &&
		$tetra_values(fix_holes) == 0} {
	append cmd " fix_holes 0"
    }
    if { $tetra_values(fix_nonman) == 0 } {
	append cmd " fix_non_manifold 0"
    }
    if { $tetra_values(cutter_which) == "volume"} {
        set vsmooth [expr !$tetra_values(run_tri2tet)]
	append cmd " run_smoother $vsmooth \
		   smoother_n_iter $tetra_values(smoother_iters) \
		   smoother_aspect $tetra_values(smoother_aspect)"
    } else {
	append cmd " write_volume 0 \
		n_tri_smoothing_steps $tetra_values(n_tri_smoothing_steps)"
    }
    if { $tetra_values(run_coarsen) } {
	append cmd " run_coarsener $tetra_values(run_coarsen) \
		   coarsen_aspect $tetra_values(coarsen_aspect)"
    }
    if { $tetra_values(use_some_existing) } {
# existing mesh
	set any_existing 0
        foreach f $tetra_families {

	    if { [ info exists tetra_families_use_existing($f) ] == 0 } continue
	    if { $tetra_families_use_existing($f)  == 0 } continue
	    append cmd " use_existing $f,$tetra_values(existing_path)"
	    set any_existing 1
	}
	if { ! $any_existing } {
# use all existing
		append cmd " use_existing *,$tetra_values(existing_path)"
	}
    }
    if { $tetra_values(cutter_which) == "volume" } {
	if { [ info exists tetra_values(save_all_triangles) ] &&
			$tetra_values(save_all_triangles) } {
		append cmd " save_all_triangles 1"
	}
    } else {
# save only some
	set save_all 1
	foreach f [ array names tetra_families_select ] {
		if { $tetra_families_select($f)  == 0 } {
			set save_all 0
		}
	}
	if { $save_all == 0 }  {
	    foreach f [ array names tetra_families_select ] {
		if { $tetra_families_select($f) }  {
			append cmd " save_family $f"
		}
	    }
	}
    }
# parallel
    if { [ info exists options(n_processors) ] && \
		$options(n_processors) != "" } {
	append cmd " n_processors $options(n_processors)"
    }
# run triangle smoother
    if { [ info exists tetra_values(n_tri_smoothing_steps) ] &&
		$tetra_values(n_tri_smoothing_steps) > 0 } {
	append cmd \
	" n_tri_smoothing_steps $tetra_values(n_tri_smoothing_steps)"
    }
# check for in memory
    if { [ info exists tetra_values(in_process) ] &&
		$tetra_values(in_process) } {
	append cmd " in_process 1"
    }
	

# create a logfile
    # This is needed so that remote execution will find the cmd and log files
    set cmd_tempfile_dir [file dirname $tetin]

    set logfile [cmd_tempfile tetra_cmd .log]
    if $is_win {
        set logfile [win_shortname [file dirname $logfile]]/[file tail $logfile]
    }
    append cmd " log $logfile"


    set r [ eval $cmd ]

    if !$r {
        if $is_win {
            after 500 "rm_tmp_file $logfile"
        } else {
            rm_tmp_file $logfile
        }
	return
    }

# run the Delauney mesher

    if $tetra_values(run_tri2tet) {
        if [catch {expr double($tetra_values(tri2tet_factor))} factor] {
            set factor 1.2
        }
        if ![ic_run_tri2tet $cut_domain $cut_domain tetin $tetin tetexpand $factor] {
            rm_tmp_file $logfile
            return 0
        }

# probably don't need this - Bruce
if 0 {
        if {![catch {expr int($tetra_values(smoother_iters))} ns] && $ns > 0} {
            if {[catch {expr double($tetra_values(smoother_aspect))} ar]} {
                set ar 0.5
            }
            set cmd [get_program icemcfd smooth 1]
            if {$cmd != ""} {
                append cmd " $cut_domain"
                mess "Running: $cmd\n"
                if {![catch {open "| $cmd" w+} fp]} {
                    read_until_prompt $fp improver%
                    read_until_prompt $fp improver% "smooth $ar $ns fix_surface"
                    read_until_prompt $fp improver% "save"
                    puts $fp "exit"
                    close $fp
                }
            }
        }
}
    }

    if { $tetra_values(in_process) == 0 } {
    
        if !$tetra_values(load_after) {
	    switch [ tk_dialog .tetra_load "Load mesh" \
			"Should I load the new tetra mesh?" \
			"" -1 Yes No ] {
			0 { }
			1 { rm_tmp_file $logfile; return 0 }
	    }
        }

# Load the grid.

        file_unload domain
        set uns [ gui_load_domains [list $cut_domain] 3]
        initialize_unstruct_visibility
        disp_new_stuff

# surface mesh we are done.
        if { $tetra_values(cutter_which) != "volume" } {
            rm_tmp_file $logfile
	    return
        }
    }
# now look for flood fill errors in logfile

    set lf [ open $logfile ]
    set errors ""
    while { ![eof $lf] } {
	set line [ gets $lf ]
	if [ string match "*can reach material*" $line ] {
		set line2 [ gets $lf ]
		if [ string match "*check display*" $line2 ] {
			append errors "$line\n"
		}
	}
    }
    close $lf
    rm_tmp_file $logfile

    if { $errors == "" } return
    mess "$errors" red
    switch [ tk_dialog .tetra_load "Load mesh" \
       "Your geometry has a hole, do you want to repair it?" \
       "" -1 Yes No ] {
       0 {
# yes
	}
       1 { return 0 }
    }

    set pa [tdv_active 0]
# repair leak
    unstruct_flood_fill

# turn on single  multiple
    set disp_options(uns_single_surfaces) 1
    set disp_options(uns_multiple_surfaces) 1
# create empty subset
# add triangles
# restrict to manifold
# display it
# turn on triangles
    ic_uns_subset_set_current Subset0
    ic_uns_update_family_type visible __same__ TRI_3 update 1
    ic_uns_subset_remove_manifold_elements visible
    set uns_use_subset 1
    update_uns_disp

    tdv_active $pa

# bring up repair form.
    set remesh(how) 2
    set remesh(make_consistent) 1
    unstruct_remesh
}
proc mesher_triangle { }  {
	mesher_tetra surface
}


proc mesher_tetra_selectfams { window var } {
    global tetin_file tetra_values $var file_name


    if [ info exists $var ] {
        set savefams ""
        foreach f [array names $var] {
	    if [ set ${var}($f) ] {
	        lappend savefams $f
	    }
        }
    }

    if { $file_name(tetin) != "" && ![ic_geo_is_loaded] }  {
	ic_load_tetin $file_name(tetin)
    }

    set allf [ic_geo_list_families]

    foreach f $allf {
	set found($f) 1
    }
# get rid of duplicates
    set allf ""
    foreach f [ array names found ] {
	lappend allf $f
    }


    set opts ""
    foreach f $allf {
	set col [family_color_for_name $f]
	lappend opts [list $f -text $f -selectbackground $col]
    }

    set opts [lsort -command "family_name_compare 2" $opts]

    if [ info exists $var ] {
    	catch {unset $var}
    	foreach f $savefams {
		set ${var}($f) 1
    	}
    } else {
	foreach f $allf {
		set ${var}($f) 1
	}
    }

    if { $window == "" } {
	set window .select_fams
    }
    set height [ llength $allf ]
    if { $height > 10 } {
	set height 10
    }
    check_box $window $opts $height $var

}

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

proc mesher_quad {} {
    global quad env

    set buttons { { Mesh mesher_quad_mesh } { Smooth mesher_quad_smooth } \
                  { Reset mesher_quad_reset } { Done mesher_quad_done } }

    set quad(ele_active) [ic_uns_is_loaded]
    set quad(geo_active) [ic_geo_is_loaded]
    set quad(geo_or_ele_active) [expr $quad(ele_active) || $quad(geo_active)]
    # set quad(new_nodes) [expr $quad(element) != 5 || $quad(improvement) > 2]
    # problem with updating ...
    set quad(new_nodes) 1

    set d [ form_init .quad "Surface mesher" "" $buttons ]
    set quad(element2) "error"
    if {$quad(boundary_tol) == "-1"} {
        set quad(boundary_tol) $quad(ele_tol)
    }
    element2_to_element 1
    if { $d != "" } {
        set ln 0
        form_label $d.types "Element types" "$ln 0"
        form_optionmenu $d.element_type quad(element2) \
            {{"QUAD_4"} {"QUAD_4 (one TRI_3)"} {"QUAD_4 (several TRI_3)"} \
             {"TRI_3"} {"TRI_3 (STL-like)"}} "$ln 1" "" "element2_to_element"

        incr ln
        form_label $d.blockt_h "Force structured mesh" "$ln 0" \
            {{quad(element) 1 2 4}}
        form_scale $d.block_h_scale quad(block) "" h 0 1 0.1 "$ln 1" \
            {{quad(element) 1 2 4}}

        incr ln
        form_label $d.iters "Max. # of smoothing steps" "$ln 0" \
            {or {quad(element) 1 2 3 4} {quad(improvement) 3}}
        form_entry $d.itersT quad(iters) int "$ln 1" \
            {or {quad(element) 1 2 3 4} {quad(improvement) 3}}
        incr ln
        form_label $d.conver "Rel. smoothing accuracy" "$ln 0" \
            {quad(iters) quad(new_nodes)}
        form_scale $d.conver_scale quad(conver) "" h 0 .1 .005 "$ln 1" \
            {quad(iters) quad(new_nodes)}

        #incr ln
        #form_label $d.violate "Violate surface distance" "$ln 0" \
        #    {quad(iters) quad(new_nodes)}
        #form_entry $d.violateT quad(violate) float "$ln 1" \
        #    {quad(iters) quad(new_nodes)}

        incr ln
        form_label $d.improvement "Mesh improvement level" "$ln 0" \
            {quad(iters)}
        form_scale $d.improvement_scale quad(improvement) "" h 0 3 1 "$ln 1" \
            {quad(iters)}

        incr ln
        form_label $d.etol "Ignore feature size" "$ln 0" \
            {{quad(element) 0 1 2 3 5}}
        form_entry $d.etolT quad(ele_tol) float "$ln 1" \
            {{quad(element) 0 1 2 3 5}}

        incr ln
        form_label $d.btol "Ignore boundary size" "$ln 0" \
            {{quad(element) 0 1 2 3 5} {quad(how) geo geo+mesh}}
        form_entry $d.btolT quad(boundary_tol) float "$ln 1" \
            {{quad(element) 0 1 2 3 5} {quad(how) geo geo+mesh}}

        incr ln
        form_label $d.inner "Preferred inner size" "$ln 0" \
            {{quad(element) 0 1 2 3 4}}
        form_entry $d.innerT quad(inner) float "$ln 1" \
            {{quad(element) 0 1 2 3 4}}

        incr ln
        form_checkbutton $d.surface_check "Surface projection" quad(proj) "$ln 0" \
            {quad(geo_active) quad(new_nodes)}
        form_checkbutton $d.adjust "Adjust nodes" quad(adjust_nodes) "$ln 1" \
            {{quad(how) geo}}

        incr ln
        form_label $d.dev "Max. surface deviation" "$ln 0" \
            {quad(proj) quad(new_nodes)}
        form_entry $d.dev_scale quad(dev) float "$ln 1" \
            {quad(proj) quad(new_nodes)}

        if [info exists env(QUAD_DEBUG)] {
            incr ln
            form_label $d.offset "# of offset layers" "$ln 0" \
                {{quad(complete_edges) 0}}
            form_scale $d.offset_scale quad(offset) "" h 0 5 1 "$ln 1" \
                {{quad(complete_edges) 0}}
            incr ln
            form_label $d.offset_h "Offset scaling" "$ln 0" \
                {{quad(offset)} {quad(complete_edges) 0}}
            form_scale $d.offset_h_scale quad(offset_h) "" h 0.01 1 0.01 "$ln 1" \
                {{quad(offset)} {quad(complete_edges) 0}}
        } else {
            set quad(offset) -1
            set quad(offset_h) -1.0
        }
        incr ln
        form_label $d.off_efaml "Offset element family" "$ln 0" \
            {{quad(complete_edges) 0}}
        form_frame $d.eframe flat 2 "$ln 1 -cols -"
        futil_listentry $d.eframe.new_efams quad(offset_element_family) \
            "list -inherited [get_famnames]" "$ln 0" \
            {{quad(complete_edges) 0}}
        set quad(offset_family) "-none"

        #incr ln
        #form_label $d.off_faml "Offsetting limited to" "$ln 0" \
        #    {{quad(offset)} {quad(how) geo geo+mesh} {quad(complete_edges) 0}}
        #form_frame $d.frame flat 2 "$ln 1 -cols -"
        #futil_listentry $d.frame.new_fams quad(offset_family) \
        #    "list -none -defined [get_famnames]" "$ln 0" \
        #    {{quad(offset)} {quad(how) geo geo+mesh} {quad(complete_edges) 0}}

        incr ln
        form_label $d.element "Patch definition" "$ln 0"
        form_radiobutton $d.fromgeo "Loops" quad(how) geo "$ln 1" \
            {quad(geo_active)}
        incr ln
        form_radiobutton $d.fromgeobars "Loops & bars" quad(how) geo+mesh "$ln 1" \
            {quad(geo_active) quad(ele_active)}
        incr ln
        form_radiobutton $d.frommesh "Bars/edges" quad(how) mesh "$ln 1" \
            {quad(ele_active)}

        incr ln
        form_label $d.tol "Looping tolerance" "$ln 0" \
            {quad(geo_active) {quad(how) geo geo+mesh}}
        form_entry $d.tolT quad(geo_tol) float "$ln 1" \
            {quad(geo_active) {quad(how) geo geo+mesh}}
        incr ln
        form_checkbutton $d.selection "Mesh selected loop(s)" quad(select) "$ln 0" \
            {quad(geo_active) {quad(how) geo geo+mesh}}

        form_checkbutton $d.complete "Complete edges" quad(complete_edges) "$ln 1" \
            {{quad(how) mesh}}

        incr ln
        form_checkbutton $d.multi "Multi-loop" quad(multi) "$ln 0" \
            {{quad(how) mesh} {quad(complete_edges) 0}}

        if [info exists env(QUAD_DEBUG)] {

            incr ln
            form_checkbutton $d.board_check "Iceboard" quad(board) "$ln 0"
            form_checkbutton $d.ignore_tp "Ignore TP" quad(ignore_tp) "$ln 1" \
                {quad(geo_active) {quad(how) geo geo+mesh}}

            incr ln
            form_label $d.enn "Estimated # of nodes" "$ln 0" \
                {quad(geo_active) {quad(how) geo}}
            form_entry $d.ennT quad(enn) int "$ln 1" \
                {quad(geo_active) {quad(how) geo}}

            incr ln
            form_label $d.debug "Debug level" "$ln 0"
            form_scale $d.debug_scale quad(debug) "" h -1 4 1 "$ln 1"

            incr ln
            form_button $d.test "Test mesh" ic_test_mesh "$ln 0"

        }

        form_finish bot
    }
}

proc element2_to_element {{back 0}} {
    global quad
    set convert {"QUAD_4" 4 \
                 "QUAD_4 (one TRI_3)" 1 \
                 "QUAD_4 (several TRI_3)" 2 \
                 "TRI_3" 3 \
                 "TRI_3 (STL-like)" 5 \
                 }
    foreach {n v} $convert {
        if {$back == 0 && $n == "$quad(element2)"} {set quad(element) $v}
        if {$back == 1 && $v == "$quad(element)"} {set quad(element2) $n}
    }
}

proc mesher_quad_mesh {} {
    global quad uns_type_visible fam_visible file_name

    if {$quad(element) == "4"} {
        set etol 0
    } else {
        set etol $quad(ele_tol)
    }
    if [ic_geo_is_loaded] {
        set p $quad(proj)
    } else {
        set p 0
    }
    if {$p} {
        set dev $quad(dev)
    } else {
        set dev 0
    }
    set surf 0
    if ![ic_uns_is_loaded] { ic_uns_create_empty }
    if {$quad(offset_family) != "" && $quad(offset_family) != "-none" && \
        $quad(offset_family) != "-all" && $quad(offset_family) != "-defined" && \
        $quad(offset) != 0} {
        set quad(offset_family) [string toupper $quad(offset_family)]
    }
    if {$quad(offset_element_family) != "-inherited"} {
        set quad(offset_element_family) [string toupper $quad(offset_element_family)]
    }
    if {$quad(how) == "geo" || $quad(how) == "geo+mesh"} {
        # mesh geometry loops
        if ![ic_geo_is_loaded] {
            mess "No loops found.\n" red
            return
        }
        busy 1
        set loops ""
        set curve_family ""
        if {$quad(offset_family) != "" && $quad(offset_family) != "-none" && \
            $quad(offset_family) != "-all" && $quad(offset_family) != "-defined" && \
            $quad(offset) != 0} {
            set curve_family $quad(offset_family)
        }
        if {$quad(offset_element_family) == "-inherited"} {
            set quad(offset_element_family) ""
        }
        if {$quad(offset_family) == "-defined"} {
            set offset [expr -$quad(offset)]
        } else {
            set offset $quad(offset)
        }
        if $quad(select) {
            # select loops
            set loops [geo_select loop]
            if {$loops == ""} return
        } elseif {$quad(how) == "geo"} {
            ic_delete_elements type QUAD_4
            ic_delete_elements type TRI_3
            ic_delete_elements type BAR_2
            ic_delete_elements type NODE
        }
        if {$quad(how) == "geo+mesh"} {
            set bunch 1
        } else {
            set bunch 0
        }
        if {$quad(how) == "geo"} {
            set adjust $quad(adjust_nodes)
        } else {
            set adjust 0
        }
        if {$adjust} {
            set adjust 2
        }
        if {$quad(element) == "4" || $quad(element) == "2" || $quad(element) == "1"} {
            set block $quad(block)
        } else {
            set block 0
        }
        if {[ic_geo_get_objects loop ""] == ""} {
            mess "No loops defined - will create one loop per surface.\n" blue
            set loops_to_delete ""
            foreach surf [ic_geo_get_objects surface ""] {
                set fam [ic_geo_get_family surface $surf]
                set bounds [ic_geo_boundary surface $surf]
                if {$bounds == ""} {
                    mess "Please run Geometry->Repair->Create Topology.\n" red
                    break
                }
                set curvature [ic_surface_curvature $surf]
                if {$curvature > 110} {
                    mess "Folded surface \"$surf\" encountered " red
                    mess "(curvature = $curvature).\n" red
                }
                ic_geo_create_loop $fam.$surf $fam names $bounds 0 $surf
                lappend loops_to_delete $fam.$surf
            }
        }
        if [catch {
            ic_quad_from_loops visible $quad(element) $p $quad(iters) \
                $quad(conver) $quad(improvement) $bunch $loops $quad(geo_tol) \
                $etol $curve_family $dev $quad(debug) $quad(violate) $offset \
                $quad(offset_h) $quad(offset_element_family) $block $quad(inner) \
                $quad(boundary_tol) $adjust $quad(board) $quad(ignore_tp) \
                $quad(adjust_nodes_max) $quad(enn) 0                
        } res] { mess "$res\n" red }
        busy 0
        set quad(ele_active) [ic_uns_is_loaded]
        if [info exists loops_to_delete] {ic_delete_geometry loop names $loops_to_delete}
    } elseif {$quad(how) == "mesh"} {
        # mesh bar loops
        if ![ic_uns_is_loaded] {
            mess "No elements found.\n" red
            return
        }
        set complete_edges 0
        if {$quad(complete_edges)} {
            set complete_edges 1
        } elseif {$quad(multi)} {
            set complete_edges 2
        }
        set bar_map [select_unstruct edge 0 visible ""]
        if {$bar_map == ""} return
        if {[lsearch [ic_uns_subset_list_types $bar_map] BAR_2] >= 0} {
            set node_map [ic_uns_create_selection_subset 0]
            if {$node_map == ""} return
            set the_nodes ""
            foreach e [ic_uns_subset_list_elements $bar_map] {
                if {[lindex $e 0]== "BAR_2"} {
                    lappend the_nodes [lindex $e 3]
                }
            }
            set uni_pairs [mesher_uniquify_pairs $the_nodes]
            foreach n $uni_pairs {
                ic_uns_subset_add_node_numbers $node_map $n
            }
            ic_uns_subset_delete $bar_map
            set bar_map $node_map
        }
        busy 1
        if [catch {
            ic_quad name $bar_map q 3 element $quad(element) proj $p \
            iters $quad(iters) conver $quad(conver) improvement $quad(improvement) \
            complete_edges $complete_edges ele_tol $etol dev $dev \
            offset $quad(offset) offset_h $quad(offset_h) inner $quad(inner) \
            boundary_tol $quad(boundary_tol) board $quad(board) debug $quad(debug)
        } res] { mess "$res\n" red }
        busy 0
        ic_uns_subset_delete $bar_map
    }
    foreach t {BAR_2 LINE_2 TRI_3 QUAD_4} {
        if ![info exists uns_type_visible($t)] {
            set uns_type_visible($t) 1
        }
    }
    set file_name(domain) quad_mesh.uns
}

proc mesher_uniquify_pairs {pairs} {
    set segs ""
    foreach ss $pairs {
	eval lappend segs $ss
    }
    foreach {i j} $segs {
	if {$i == $j} continue
	if {$i > $j} {
	    set k $i
	    set i $j
	    set j $k
	}
	set "found($i $j)" 1
    }
    set ret ""
    foreach ff [array names found] {
	eval lappend ret $ff
    }
    return $ret
}

proc mesher_quad_smooth {} {
    global quad

    if [ic_geo_is_loaded] {
        set p $quad(proj)
    } else {
        set p 0
    }
    if {$quad(select) == "2"} {
        set sel_map [select_unstruct element 0 visible ""]
        if {$sel_map == ""} return
        if [catch {
            ic_smooth_quad $sel_map $p $quad(iters) $quad(conver) \
                $quad(improvement) $quad(element)
            } res] { mess "$res\n" red }
            ic_uns_subset_delete $sel_map
    } else {
        if [catch {
            ic_smooth_quad visible $p $quad(iters) $quad(conver) \
                $quad(improvement) $quad(element)
        } res] { mess "$res\n" red }
    }
}

proc mesher_quad_boundary {} {
    # currently not in use
    global quad

    busy 1
    ensure_unstruct_mesh_exists
    set map visible
    $map quad_boundary $quad(element)
    update_uns_available
    busy 0
}

proc mesher_quad_reset {} {
    global quad

    set quad(element) 1
    set quad(inner) 0
    set quad(iters) 20
    set quad(conver) 0.025
    set quad(complete_edges) 0
    set quad(proj) 0
    set quad(how) geo
    set quad(select) 0
    set quad(geo_tol) 0
    set quad(ele_tol) 0
    set quad(boundary_tol) 0
    set quad(dev) 0
    set quad(improvement) 1
    set quad(violate) 0
    set quad(offset) 0
    set quad(offset_h) 1
    set quad(offset_family) "-none"
    set quad(block) 0
    set quad(adjust_nodes) 0
    set quad(debug) 0
    ic_reset_geo_selected
}

proc mesher_quad_done {} {
    global quad

    top_destroy .quad
    ic_reset_geo_selected
}

proc mesher_str_quad {} {
    global str_quad

    global file_name
    global str_quad_values str_quad_families str_quad_families_select


    set title "Parameters for stretched quads"
    set form_name .str_quad
    set mesh_file quad_mesh_file
    set str_quad_values($mesh_file) $file_name(domains_dir)/quad_mesh.uns
    set buttons { { Mesh mesher_str_quad_mesh } \
                  { Done mesher_str_quad_done } }


    set d [form_init $form_name $title "" $buttons]
    if {$d != ""} {

        set ln 0
        form_frame $d.fr sunken 3 "$ln 0"; set d $d.fr

	form_label $d.tmfl "Quad mesh file" "$ln 0"
	set fl_tail [file tail $str_quad_values($mesh_file)]
	set str_quad_values($mesh_file) $file_name(domains_dir)/$fl_tail
        file_select_entry $d.tmf str_quad_values($mesh_file) 0 1 \
            "Select a mesh file." "$ln 1" "" \
            "" "" "" {has_suffix "Domain (.uns)" .uns}

	incr ln
	form_label $d.selectfaml "Mesh these families" "$ln 0"
	incr ln
	form_frame $d.selectfams ridge 2 "$ln 0 -cols 2"
	mesher_tetra_selectfams $d.selectfams str_quad_families_select

	incr ln
	set str_quad_values(min_len) 0.1
	form_label $d.devl "Minimum length" "$ln 0"
	form_entry $d.dev str_quad_values(min_len) float "$ln 1"

	incr ln
	set str_quad_values(asp_ratio) 2
	form_label $d.aspl "Max. aspect ratio" "$ln 0"
	form_entry $d.asp str_quad_values(asp_ratio) float "$ln 1"

	incr ln
	set str_quad_values(len_ratio) 1.5
	form_label $d.lenl "Max. length ratio" "$ln 0"
	form_entry $d.len str_quad_values(len_ratio) float "$ln 1"

	form_finish bot
    }
}

proc mesher_str_quad_mesh {} {
    global str_quad str_quad_values str_quad_families_select

    set fams ""
    foreach i [ array names str_quad_families_select ] {
	if { $str_quad_families_select($i) } {
		mess "$i\n"
		append fams " $i"
	}
    }
    ic_mapped_mesh $str_quad_values(min_len) \
	   	$str_quad_values(asp_ratio) \
		$str_quad_values(len_ratio) $fams

}

proc mesher_str_quad_done {} {
    global str_quad

    top_destroy .str_quad
}

proc domain_newest_file {} {
    global file_name
    set nf ""; set nt 0
    foreach f [glob -nocomplain $file_name(domains_dir)/*.uns $file_name(domains_dir)/*.\[0-9\]*] {
	set t [file mtime $f]
	if {$t > $nt} {
	    set nt $t
	    set nf [file tail $f]
	}
    }
    return [list $nf $nt]
}

proc mesher_cart3d {} {
    global cart3d file_name

    set buttons { { Apply mesher_cart3d_apply } { Done mesher_cart3d_done } }
    set d [ form_init .cart3d "Cart3D" ""  $buttons ]
    set cart3d(tetin_file) $file_name(tetin)
    if {$d != ""} {
	set cart3d(top_widget) $d
	form_frame $d.fr flat 0 {0 0};

	set row 0
	# Load cart3D trifile
	incr row
	set act {{cart3d(load_c3dtri) 1}}
	form_radiobutton $d.fr.topt2 "Load cart3D tri file" \
		cart3d(load_c3dtri) 1 "$row 0"
	file_select_entry $d.fr.c3dtf cart3d(trifile) 0 1 \
		"Select a Cart3D tri file" "$row 1" $act \
		"" "" "" {has_suffix "Cart3D (.tri)" .tri}

	# Load Tetin file
	incr row
	set act {{cart3d(load_c3dtri) 0}}
	form_radiobutton $d.fr.topt1 "Load tetin file" \
		cart3d(load_c3dtri) 0 "$row 0"
	file_select_entry $d.fr.tf cart3d(tetin_file) 0 1 \
		"Select a tetin file" "$row 1" $act \
		"" "" "" {has_suffix "tetin (.tin)" .tin}

	# Fix normals
	incr row
	form_checkbutton $d.fr.norms "Fix Normals" \
		cart3d(fix_normals) "$row 1" $act

	# Cart3D files Prefix
	incr row;
	form_label $d.fr.c3dfl "Cart3D Files Prefix" "$row 0"
	file_select_entry $d.fr.c3dmf cart3d(file_prefix) 0 1 \
	    "Select a file prefix" "$row 1"

	# Covert to Cart3D and Intersect the components
	incr row
	form_checkbutton $d.fr.intersect "Intersect Components" \
	    cart3d(run_intersect) "$row 0"

	# Run cubes
	incr row
	form_checkbutton $d.fr.cubes "Run Cart3D Mesher" \
	    cart3d(run_cubes) "$row 0"
	set act {{cart3d(run_cubes) 1}}
	
	# Frame for cubes options
	incr row
	form_frame $d.cub sunken 2 "$row 0"

	# Finest Cell dimension
	incr row;
	set cart3d(finest_cell) "0.0 x 0.0 x 0.0"
	form_label $d.cub.sizel "Finest Cell Dimensions: " "$row 0" $act
	form_label $d.cub.finestl $cart3d(finest_cell) "$row 1" $act
	$d.cub.finestl configure -width 30 -fg blue
	set cart3d(finest_cell_label) $d.cub.finestl 

	# Nominal Radius
	incr row
	form_label $d.cub.radl "Nominal Mesh Radius ( Body Length X )" \
	    "$row 0" $act
	form_entry $d.cub.rade cart3d(nominal_radius) string "$row 1" $act

	# Starting Mesh Dimensions
	incr row
	form_label $d.cub.diml "Starting Mesh Divisions" "$row 0" $act
	form_entry $d.cub.dime cart3d(num_div) string "$row 1" $act

	# Max. Number of Cell Refinements
	incr row
	form_label $d.cub.maxrefl "Max. Number of Cell Refinements" \
	    "$row 0" $act
	form_entry $d.cub.maxrefe cart3d(max_ref) int "$row 1" $act

	# Symmetry dirX.
	incr row
	form_checkbutton $d.cub.symx "Half-Body Mesh (Symmetric) in X" \
	    cart3d(mesh_symX) "$row 0" $act; 

	# Symmetry dirY
	incr row;	
	form_checkbutton $d.cub.symy "Half-Body Mesh (Symmetric) in Y" \
	    cart3d(mesh_symY) "$row 0" $act

	# Symmetry dirZ
	incr row;
	form_checkbutton $d.cub.symz "Half-Body Mesh (Symmetric) in Z" \
	    cart3d(mesh_symZ) "$row 0" $act

	# Mesh Preview / Save
	incr row
	form_label $d.cub.mesh "Mesh Creation:" "$row 0" $act
	form_button $d.cub.compl "Compute Parameters" \
	    "mesher_cart3d_default_inputs" "$row 1" $act

	incr row
	form_radiobutton $d.cub.preview "PreView Mesh Only" \
	    cart3d(mesh_save) 0 "$row 0" $act
	incr row
	form_radiobutton $d.cub.save "Create and Save Full Mesh" \
	    cart3d(mesh_save) 1 "$row 0" $act

	# Advanced Options
	incr row;
	form_checkbutton $d.advanced "Advanced Options" \
	    cart3d(adv_options) "$row 0" $act
	set act1 {{cart3d(run_cubes) 1} && {cart3d(adv_options) 1}}

	# Frame for Adv options
	incr row;
	form_frame $d.adv sunken 2 "$row 0"
	set i 0;
	
	set cart3d(adv_frame) $d.adv
	# Outer Bounding Box
	incr row
	form_label $d.adv.$i "Outer Bounding Box :" "$row 0" $act1; incr i

	# Min diagonal
	incr row
	form_label $d.adv.$i "       Minimum Diagonal Point" \
	    "$row 0" $act1; incr i;
	form_entry $d.adv.$i cart3d(box_min) string "$row 1" $act1
	$d.adv.$i configure -width 30; incr i

	set m $d.adv.$i.m
	form_menubutton_regular $d.adv.$i "Select" $m "$row 2" $act1; incr i;
	menu $m
	$m add command -label Screen -command \
		"med_get_local_location cart3d(box_min)"
	$m add command -label "Pre  point" -command \
		"geo_select_loc point cart3d(box_min)"
	$m add command -label "Surface node" -command \
		"geo_select_loc surface_node cart3d(box_min)"	

	# Max Diagonal
	incr row
	form_label $d.adv.$i "       Maximum Diagonal Point" \
	    "$row 0" $act1; incr i;
	form_entry $d.adv.$i cart3d(box_max) string "$row 1" $act1
	$d.adv.$i configure -width 30; incr i

	set m $d.adv.$i.m
	form_menubutton_regular $d.adv.$i "Select" $m "$row 2" $act1; incr i;
	menu $m
	$m add command -label Screen -command \
		"med_get_local_location cart3d(box_max)"
	$m add command -label "Pre  point" -command \
		"geo_select_loc point cart3d(box_max)"
	$m add command -label "Surface node" -command \
		"geo_select_loc surface_node cart3d(box_max)"
	
	# Max. Hex Cell Aspect Ratio
	incr row
	form_label $d.adv.$i "Max. Hex Cell Aspect Ratio" \
	    "$row 0" $act1; incr i;
	form_entry $d.adv.$i cart3d(aspect_ratio) int "$row 1" $act1; incr i

	# Number of layers of buffer cells
	incr row
	form_label $d.adv.$i "Number of Layers of Buffer Cells" \
	    "$row 0" $act1; incr i
	form_entry $d.adv.$i cart3d(buff_lay) int "$row 1" $act1; incr i

	# Angle Threshold for Geometry Refinement
	incr row
	form_label $d.adv.$i "Angle Threshold for Refinement" \
	    "$row 0" $act1; incr i
	form_entry $d.adv.$i cart3d(max_angle) float "$row 1" $act1; incr i

	# Number of Cut planes X
	incr row
	form_label $d.adv.$i "Number of Cut Planes in X" \
	    "$row 0" $act1; incr i
	form_entry $d.adv.$i cart3d(cut_planesX) int "$row 1" $act1; incr i

	# Number of Cut planes Y
	incr row
	form_label $d.adv.$i "Number of Cut Planes in Y" "$row 0" $act1; incr i
	form_entry $d.adv.$i cart3d(cut_planesY) int "$row 1" $act1; incr i

	# Number of Cut planes Z
	incr row
	form_label $d.adv.$i "Number of Cut Planes in Z" "$row 0" $act1; incr i
	form_entry $d.adv.$i cart3d(cut_planesZ) int "$row 1" $act1; incr i
	
	# Mesh Region Internal/External		
	incr row
	form_checkbutton $d.adv.$i "Mesh Internal Region" \
	    cart3d(mesh_internal) "$row 0" $act1;

	set $cart3d(adv_options) 0
	mesher_cart3d_advanced "" "" ""

	form_finish bot
	
	mesher_cart3d_default_box
	trace variable cart3d(tetin_file) w mesher_cart3d_default_box
	trace variable cart3d(adv_options) w mesher_cart3d_advanced
    }
}

proc mesher_cart3d_default_box {{name ""} {element ""} {op ""}} {
    global cart3d

    set surfs [ic_geo_get_objects surface]
    if {$surfs == ""} return

    set csurfs ""
    foreach s $surfs { lappend csurfs "surface $s" }
    set bbox [ic_geo_bbox_of_entities $csurfs]

    set xmin [lindex [lindex $bbox 0] 0]
    set ymin [lindex [lindex $bbox 0] 1]
    set zmin [lindex [lindex $bbox 0] 2]

    set xmax [lindex [lindex $bbox 1] 0]
    set ymax [lindex [lindex $bbox 1] 1]
    set zmax [lindex [lindex $bbox 1] 2]

    set centx [expr ($xmin+$xmax)/2] 
    set centy [expr ($ymin+$ymax)/2] 
    set centz [expr ($zmin+$zmax)/2] 
    
    set max_dim [expr $xmax - $xmin]
    if {[expr $ymax-$ymin] > $max_dim } {
	set max_dim [expr $ymax - $ymin]
    } 
    if {[expr $zmax-$zmin] > $max_dim } {
	set max_dim [expr $zmax-$zmin]
    }

    set bxmin [expr $centx - $max_dim*$cart3d(nominal_radius)]
    set bymin [expr $centy - $max_dim*$cart3d(nominal_radius)]
    set bzmin [expr $centz - $max_dim*$cart3d(nominal_radius)]
    set bxmax [expr $centx + $max_dim*$cart3d(nominal_radius)]
    set bymax [expr $centy + $max_dim*$cart3d(nominal_radius)]
    set bzmax [expr $centz + $max_dim*$cart3d(nominal_radius)]

    set cart3d(box_min) [ list $bxmin $bymin $bzmin ]
    set cart3d(box_max) [ list $bxmax $bymax $bzmax ]

}

proc mesher_cart3d_advanced {name element op} {
    global cart3d
    
    if {$cart3d(adv_options) == 0} {
	grid forget $cart3d(adv_frame)
    } else {
	grid configure $cart3d(adv_frame)
    }    
}

proc mesher_cart3d_default_inputs {} {
    global cart3d
        
    append c3d_file "$cart3d(file_prefix)_c3d"

    set c3dtri_file  "$c3d_file.a.tri"
    set c3dint_file  "$c3d_file.i.tri"
    
    set inputs [ic_mesh_cart3d_auto_inputs $c3dint_file \
		    nominal_radius $cart3d(nominal_radius) \
		    num_div        $cart3d(num_div) \
		    max_ref        $cart3d(max_ref) \
		    symX           $cart3d(mesh_symX) \
		    symY           $cart3d(mesh_symY) \
		    symZ           $cart3d(mesh_symZ) ]		 

    set cart3d(finest_cell) \
	"[lindex $inputs 0] x [lindex $inputs 1] x [lindex $inputs 2]"

    $cart3d(finest_cell_label) configure -fg blue \
	-text $cart3d(finest_cell)

    set cart3d(box_min) \
	"[lindex $inputs 3] [lindex $inputs 4] [lindex $inputs 5]"

    set cart3d(box_max) \
	"[lindex $inputs 6] [lindex $inputs 7] [lindex $inputs 8]"

    return 0
}

proc mesher_cart3d_apply {} {
    global cart3d

    #Check if pts were passed by name
    if { [llength $cart3d(box_min) ] == 1 } { 
	set cart3d(box_min) [ic_geo_get_point_location $cart3d(box_min)]
    }
    #Check if pts were passed by name
    if { [llength $cart3d(box_max) ] == 1 } { 
	set cart3d(box_max) [ic_geo_get_point_location $cart3d(box_max)]
    }

    set status [ic_mesh_cart3d $cart3d(tetin_file) $cart3d(file_prefix) \
	    trifile    $cart3d(trifile) \
	load_trifile   $cart3d(load_c3dtri) \
	run_intersect  $cart3d(run_intersect) \
        run_cubes      $cart3d(run_cubes) \
	box_min        [ic_coords_into_global $cart3d(box_min)] \
	box_max        [ic_coords_into_global $cart3d(box_max)] \
	start_dim      $cart3d(num_div) \
	symX           $cart3d(mesh_symX) \
	symY           $cart3d(mesh_symY) \
	symZ           $cart3d(mesh_symZ) \
	aspect_ratio   $cart3d(aspect_ratio) \
	max_ref        $cart3d(max_ref) \
	buff_lay       $cart3d(buff_lay) \
	max_angle      $cart3d(max_angle) \
	cut_planesX    $cart3d(cut_planesX) \
	cut_planesY    $cart3d(cut_planesY) \
	cut_planesZ    $cart3d(cut_planesZ) \
	mesh_save      $cart3d(mesh_save) \
	mesh_internal  $cart3d(mesh_internal) \
	fix_normals    $cart3d(fix_normals) ]

    # Load the full mesh domain file into med optionally.
    set c3dmesh_file "$cart3d(file_prefix)_c3d.mesh"
    set domain_file  "$cart3d(file_prefix)_c3d.dom"
    if { $cart3d(run_cubes) && $cart3d(mesh_save) && !$status } {
	set mess "Do you want to load the cart3D Full Mesh?"
	switch [tk_dialog .dom "Cart3D Mesh" $mess "" -1 \
		Yes No] {
	    0 {
		set status [ic_run_cart3d2df $c3dmesh_file $domain_file]
		if { !$status && [file exists $domain_file] } {
		    ic_unload_mesh
		    ic_load_unstruct $domain_file
		}
	    }
	    1 { return }
	}
    }
}

proc mesher_cart3d_reset {} {
    global cart3d

    set cart3d(srf_fams) ""
    set cart3d(cart3d_mesh_file) ""
}

proc mesher_cart3d_done {} {
    global cart3d

    form_accept_hack .cart3d
}

proc mesher_tri2tet {} {
    global file_name tri2tet_values env

    if {$file_name(domains_dir) == ""} {
	user_error "Can't run tri2tet : no project selected"
	return
    }
    if {![ic_uns_is_loaded]} {
        user_error "You need to create or load a surface mesh first."
        return
    }
    set domain [file tail $file_name(domain)]
    if {$domain != ""} {
        set tri2tet_values(mesh_in) $file_name(domains_dir)/$domain
    } else {
        set tri2tet_values(mesh_in) ""
    }
    set tri2tet_values(mesh_out) "$file_name(domains_dir)/tri2tet_mesh.uns"

    set nelems [expr [ic_count_elements PYRA_5] + [ic_count_elements PENTA_6]]
    set mtlpts [ic_geo_list_families 1]

    if {[llength $mtlpts] < 2 || $nelems} {
        set tri2tet_values(keepall) 0
        set tri2tet_values(floodfill) 0
    } else {
        set tri2tet_values(keepall) 1
        set tri2tet_values(floodfill) 1
    }
    foreach mp $mtlpts {
        if {$mp != "ORFN" && $mp != "VORFN"} {
            set tri2tet_values(family) $mp
            break
        }
    }

    set form_name .tri2tet
    set title "Mesher parameters"

    set buts [ list \
        [ list Mesh [ list mesher_tri2tet_doit $form_name ] ] dismiss ]
    set d [form_init $form_name $title mesher $buts]
    if {$d != ""} {
	set ln 0
	form_frame $d.fr sunken 3 "$ln 0"; set d $d.fr
        set tri2tet_values(form) $d

	incr ln
	form_label $d.meshinl "Triangle Input mesh file" "$ln 0"
        form_entry $d.meshin tri2tet_values(mesh_in) readonly "$ln 1"
        set len [string length $tri2tet_values(mesh_in)]
        if {$len > 25} {set len 25}
        $d.meshin configure -width $len

	incr ln
	form_label $d.meshoutl "Tetra Output mesh file" "$ln 0"
	file_select_entry $d.meshout tri2tet_values(mesh_out) 0 1 \
	    "Select output mesh file." "$ln 1" "" \
	    "" "" "" {has_suffix "Domain (.uns)" .uns}
        if [winfo exists $d.meshout.e] {
            $d.meshout.e configure -justify left
        } else {
            $d.meshout configure -justify left
        }

	incr ln
	form_label $d.faml "Tet Mesh Family" "$ln 0"
	form_entry $d.fam tri2tet_values(family) string "$ln 1"
	form_menubutton $d.fam_menu "    " "" "$ln 2 -fill none"
	futil_drop_down_button $d.fam_menu #ffc0c0 #ffa0a0
	bind $d.fam_menu <ButtonPress-1> mesher_tri2tet_family
	bind $d.fam_menu <ButtonRelease-1> break

	incr ln
	form_label $d.expl "Tet Expansion Factor" "$ln 0"
	form_entry $d.exp tri2tet_values(tetexpand) float_blank "$ln 1"

	incr ln
	form_label $d.safl "Memory Scaling Factor" "$ln 0"
	form_entry $d.saf tri2tet_values(safety) float_blank "$ln 1"

        incr ln
	form_checkbutton $d.ka "Mesh all domains" \
            tri2tet_values(keepall) "$ln 0 -columnspan 2"

        incr ln
	form_checkbutton $d.ff "Do flood fill after meshing" \
            tri2tet_values(floodfill) "$ln 0 -columnspan 2"

        incr ln
	form_checkbutton $d.ld "Load mesh after meshing" \
            tri2tet_values(load_after) "$ln 0 -columnspan 2"

	if [info exists env(TRI2TET_DEBUG)] {

	    incr ln
	    form_label $d.estl "Estimated Elements" "$ln 0"
	    form_entry $d.est tri2tet_values(estelem) float_blank "$ln 1"

	    incr ln
	    form_label $d.outl "Output Level (-10 to 10)" "$ln 0"
	    form_entry $d.out tri2tet_values(output) int "$ln 1"

            if {$env(TRI2TET_DEBUG) == "OFF"} {
        	incr ln
		form_label $d.offl "OFF output file" "$ln 0"
		form_entry $d.off tri2tet_values(offfile) string "$ln 1"
            }
	} else {
            incr ln
	    form_checkbutton $d.out "More verbose output" \
                tri2tet_values(verbose) "$ln 0 -columnspan 2"
        }

        form_finish +300+300
    }

    if {$nelems && ![info exists env(TRI2TET_DEBUG)]} {
      form_checkbutton_setstate $tri2tet_values(form).ka 0
    } else {
      form_checkbutton_setstate $tri2tet_values(form).ka 1
    }
    form_checkbutton_setstate $tri2tet_values(form).ff [llength $mtlpts]
}

proc mesher_tri2tet_family {} {
    global tri2tet_values
    set fam [select_family]
    if {$fam != ""} {
        set tri2tet_values(family) $fam
    }
}

proc mesher_tri2tet_doit {form_name} {
    global file_name tri2tet_values env

    form_kill $form_name

    if ![geo_check_available_space] return

    set cmd ic_run_tri2tet
    if {$tri2tet_values(mesh_in) == ""} {
        set tempfile [cmd_tempfile tri2tet_temp .uns]
        ic_save_unstruct $tempfile
        append cmd " $tempfile"
    } else {
        set tempfile ""
        if [ic_uns_is_modified] {
            set result [tk_dialog .modified "Modified" \
                "The mesh has been modified - save it before running ?" \
                "" 0 Yes No Cancel]
            if {$result == 2} return
            if {$result == 0} {ic_save_unstruct $tri2tet_values(mesh_in)}
        }
        append cmd " {$tri2tet_values(mesh_in)}"
    }
    append cmd " {$tri2tet_values(mesh_out)}"

    if [info exists env(TRI2TET_DEBUG)] {
        append cmd " verbose 1"
        if {$tri2tet_values(offfile) != ""} {
            set off $file_name(domains_dir)/[file tail $tri2tet_values(offfile)]
            lappend cmd offfile $off
        }
    }
    foreach i {output estelem safety tetexpand keepall} {
        if {$tri2tet_values($i) != "" &&
            $tri2tet_values($i) != 0} {
            append cmd " $i $tri2tet_values($i)"
        }
    }
    if {$tri2tet_values(family) != ""} {
        regsub -all " " [string toupper $tri2tet_values(family)] _ fam
        append cmd " family $fam"
    }
    if {$tri2tet_values(verbose)} {append cmd " output 4"}

    set ok [eval $cmd]
    if {$tempfile != ""} {cmd_rm $tempfile}
    if {!$ok} {return 0}

    if !$tri2tet_values(load_after) {
        if {$tri2tet_values(floodfill)} {
            set msg "You have specified a flood fill operation.\
This will be done only if the new mesh is loaded."
        } else {
            set msg ""
        }
	switch [ tk_dialog .tri2tet_load "Load mesh" \
			"$msg Should I load the new mesh?" \
			"" -1 Yes No ] {
			0 { }
			1 { return 0 }
	}
    }

    file_unload domain
    gui_load_domains [list $tri2tet_values(mesh_out)] 3
    if {$tri2tet_values(floodfill)} {
        unstruct_flood_fill
        if {[ic_uns_is_modified] && ![tk_dialog .modified "Modified" \
            "Save the modified mesh ?" "" 0 Yes No Cancel]} {
            file_savemesh 0
        }
    }
#    initialize_unstruct_visibility
    disp_new_stuff
}

proc mesher_surf_tri {} {
    global file_name env

    if {[info exists env(SURF2TRI_BIN)] && $env(SURF2TRI_BIN) != ""} {
        set prog [join [split $env(SURF2TRI_BIN) \\] /]
    } else {
        set prog surf2tri
    }
    if {![file exists $prog] && [catch {get_program bin $prog} prog]} {
        mess "Error: can't find surf2tri program\n" red
        return
    }

    if {$file_name(domains_dir) == ""} {
	user_error "Can't run surf2tri : no project selected"
	return
    }
    if {$file_name(tetin) == ""} {
	set tetin [med_file_select tetin 0 "" "to use for meshing"]
	if {$tetin == ""} return
    } else {
	file_save_one tetin 1
    }

    set domain $file_name(domains_dir)/[file rootname \
        [file tail $file_name(tetin)]]_tri.uns

    set cmd [list $prog $file_name(tetin) $domain]
    mess "\n$cmd\n"
    if [catch {open |$cmd "r"} fp] {
        mess "Error: $fp\n" red
        return
    }
    while {[gets $fp line] >= 0} {
        mess "$line\n" blue
        update idletasks
    }
    if [catch {close $fp} msg] {
        mess "Error: $msg\n" red
        return
    }
    mess "Done.\n"

    if [file exists $domain] {
        file_unload domain
        gui_load_domains [list $domain]
    }
}

