
# This code creates the user interface for the mesh editor.
#
# Copyright 1997 Pacific Marketing and Consulting, Inc
#           and ICEM Systems GmbH.  All rights reserved.
# Author: Andreas Kolms

proc unstruct_uncouple {{three 0}} {
    if [ic_geo_is_loaded] {
        set proj 1
    } else {
        set proj 0
    }
    if ![ic_uns_is_loaded] {
        mess "Mesh is not loaded.\n" red
        return
    }
    if ![ic_uns_num_couplings] {
        mess "This mesh has no couplings.\n" red
        return
    }
    #
    # 3-1-1 refinement is not supported because it is not such easy to
    # implement for non-trivial cases.  3-3-1 works for 2.5D cases,
    # 3-3-3 is fine in general.
    #
    # three =  1 = do pure 3-3-3 refinement
    #         -1 = allow unstable patterns
    #
    set db 0
    busy 1
    ic_uns_uncouple all $proj $three $db
    busy 0
    update_uns_available
}

proc unstruct_bandwidth {} {
    global bandwidth
    
    set d [form_init .bandwidth "Bandwidth options"]
    if {$d != ""} {
        form_label $d.itersl "Iterations" {0 0}
        form_label $d.typel "Type" {1 0}
        form_entry $d.iters bandwidth(iters) int {0 1}
        form_radiobutton $d.prof Profile bandwidth(type) profile {1 1}
        form_radiobutton $d.band Bandwidth bandwidth(type) bandwidth {2 1}
        form_finish bot
        mess "Warning: the bandwidth operation cannot be undone\n" red
    }
    if ![form_wait .bandwidth] return
    ic_uns_bandwidth all $bandwidth(iters) $bandwidth(type)
}

proc unstruct_refine {} {
    global refine select_unstruct_optiong uns_type_visible

    set refine(geo_active) [ic_geo_is_loaded]
    set d [form_init .refine "Refinement options"]
    if { $refine(deviation) == 0 } {
        # set appropriate initial surface deviation value
        set min_tri_val [expr [ic_uns_min_tri_size visible] * 0.25]
        set min_quad_val [expr [ic_uns_min_quad_size visible] * 0.25]
        set refine(deviation) [expr { ($min_tri_val <= $min_quad_val) \
                                ? $min_tri_val : $min_quad_val}] 
    }
    if {$d != ""} {
        form_radiobutton $d.deviation "Max. surface deviation" \
            refine(use_tol) 1 {0 0} \
            {{refine(geo_active)} {refine(do_project)}}
        form_entry $d.deviationT refine(deviation) float {0 1} \
            {{refine(use_tol)} {refine(geo_active)} {refine(do_project)}} 4 
        form_radiobutton $d.edgelength "Max. edge length" \
            refine(use_tol) 0 {1 0}
        form_entry $d.edgelengthT refine(edgelength) float {1 1} 4
        form_label $d.steps "Max. # of steps" {2 0}
        form_entry $d.stepsT refine(steps) int {2 1}
        form_radiobutton $d.use_all "Refine all visible" refine(use_all) 1 \
            {3 0 -cols 2}
        form_radiobutton $d.selected "Refine selected" refine(use_all) 0 \
            {4 0 -cols 2}
        form_checkbutton $d.proj "Project nodes" refine(do_project) \
            {5 0 -cols 2} {{refine(geo_active)}}
        form_finish bot
    }
    if ![form_wait .refine] return
    if { $refine(do_project) && $refine(geo_active) } {
        set pl 1
    } else {
        set pl 0
    }
    if {$refine(use_tol) && $refine(geo_active) } {
        set dev $refine(deviation)
    } else {
        set dev -1
    }
    if {!$refine(use_tol)} {
        set edge $refine(edgelength)
    } else {
        set edge -1
    }
    if $refine(use_all) {
        ic_uns_refine_surface visible $dev $refine(steps) $pl 0 $edge
        if ![info exists uns_type_visible(TRI_3)] {
            set uns_type_visible(TRI_3) 1
        }
        update_uns_available
    } else {
        while 1 {
            set sel_map [select_unstruct element 0 visible ""]
            if {$sel_map == ""} return
            set types [ic_uns_subset_list_types $sel_map]
            if {([lsearch $types TRI_3] == -1) &&
                ([lsearch $types TETRA_4] == -1) &&
                ([lsearch $types QUAD_4] == -1)} {
                ic_uns_subset_delete $sel_map
                mess "Element type(s) $types not supported.\n" red
                return
            }
            ic_uns_refine_surface $sel_map $dev $refine(steps) $pl 0 $edge
            ic_uns_subset_delete $sel_map
            if ![info exists uns_type_visible(TRI_3)] {
                set uns_type_visible(TRI_3) 1
            }
            update_uns_available
        }
    }
}

proc unstruct_insert_tetra {mid} {
    if ![ic_uns_is_loaded] {
        mess "Triangle mesh is not loaded.\n" red
        return
    }
    ic_uns_insert_tetra visible $mid
    update_uns_available
}

proc unstruct_tri2quad {} {
    global tri2quad uns_type_visible

    set tri2quad(geo_active) [ic_geo_is_loaded]
    set tri2quad(scheme) 1
    set d [form_init .tri2quad "Tri -> Quad options"]
    set tri2quad(proj2) "error"
    proj2_to_proj 1
    if {$d != ""} {
        set ln 0
        form_label $d.skewl "Combine triangles" "$ln 0"
        incr ln
        form_label $d.skewl2 "  up to a skewness of" "$ln 0"
        form_entry $d.skew tri2quad(skew) int "$ln 1"
        incr ln
        form_label $d.warpl "  and up to a warpage of" "$ln 0"
        form_entry $d.warp tri2quad(warp) int "$ln 1"
        incr ln
        form_checkbutton $d.quadrization "Quadrization" tri2quad(quadrization) "$ln 0"
        incr ln
        form_checkbutton $d.improvement "Improvement" tri2quad(improvement) "$ln 0"
        incr ln
        #form_checkbutton $d.proj "Surface projection" tri2quad(proj) "$ln 0" \
        #    {{tri2quad(geo_active)}}
        form_label $d.proj "Surface projection" "$ln 0"
        form_optionmenu $d.proj_type tri2quad(proj2) \
            {{"Off"} {"Geometry"} {"Mesh"}} "$ln 1" "" "proj2_to_proj"
        #incr ln
        #form_label $d.iters "Max. # of smoothing steps" "$ln 0" \
        #    {{tri2quad(scheme) 0}}
        #form_entry $d.itersT tri2quad(iters) int "$ln 1" \
        #    {{tri2quad(scheme) 0}}
        #incr ln
        #form_label $d.conver "Smoothing accuracy" "$ln 0" \
        #    {{tri2quad(scheme) 0}}
        #form_entry $d.converT tri2quad(conver) float "$ln 1" \
        #    {{tri2quad(scheme) 0}}
        form_finish bot
    }
    if ![form_wait .tri2quad] return
    set p 0
    if {$tri2quad(geo_active) || $tri2quad(proj) == 2} {
        set p $tri2quad(proj)
    }
    if {$tri2quad(improvement)} {
        #  automatic remeshing
        set max_steps -1
    } else {
        #  no remeshing
        set max_steps 0
    }
    if {$tri2quad(scheme) == 0} {
        ic_change_tri_quad skew $tri2quad(skew) warp $tri2quad(warp) \
            iters $tri2quad(iters) conver $tri2quad(conver) improvement \
            $tri2quad(improvement) quadrization $tri2quad(quadrization) \
            debug $tri2quad(debug) proj $p
    } else {
        set map visible
        while 1 {
            if {!$tri2quad(quadrization)} {
                set sel_map [select_unstruct element 0 $map ""]
                if {$sel_map == ""} return
            } else {
                #
                #   quadrization always on entire mesh
                #
                set sel_map visible
            }
            ic_change_tri_quad_2 $sel_map $p $tri2quad(debug) 0 $max_steps \
                $tri2quad(skew) $tri2quad(warp) $tri2quad(quadrization)
            if {$sel_map == "visible"} return
            ic_uns_subset_delete $sel_map
        }
    }
}

proc proj2_to_proj {{back 0}} {
    global tri2quad
    set convert {"Off" 0 \
                 "Geometry" 1 \
                 "Mesh" 2 \
                 }
    foreach {n v} $convert {
        if {$back == 0 && $n == "$tri2quad(proj2)"} {set tri2quad(proj) $v}
        if {$back == 1 && $v == "$tri2quad(proj)"} {set tri2quad(proj2) $n}
    }
}

proc unstruct_remesh {} {
    global remesh env

    set remesh(geo_active) [ic_geo_is_loaded]
    set buts [list {Apply apply_unstruct_remesh} reset cancel help]
    set d [form_init .remesh "Surface mesh repair options" "" $buts]
    set remesh(element_new) "error"
    element_new_to_old 1
    set mult_try 1
    if {$d != ""} {
        set ln 0
        form_label $d.types "Element types" "$ln 0"
        form_optionmenu $d.element_type remesh(element_new) \
            {{"QUAD_4"} {"QUAD_4 (one TRI_3)"} {"QUAD_4 (several TRI_3)"} \
             {"TRI_3"} {"TRI_3 (STL-like)"}} "$ln 1" "" "element_new_to_old"

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

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

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

        incr ln
        form_checkbutton $d.complete "Complete edges" remesh(complete_edges) "$ln 0" \
            {{remesh(how) 2}}

        #incr ln
        form_checkbutton $d.surf "Interpolation surface" remesh(surf) "$ln 1" \
            {{remesh(proj) 0} {remesh(how) 2} {remesh(element) 1 2 3 4}}

        incr ln
        form_checkbutton $d.proj "Surface projection" remesh(proj) "$ln 0" \
            {{remesh(geo_active)} {remesh(how) 0 1 2 5 7 8} {remesh(element) 1 2 3 4}}

        #incr ln
        form_checkbutton $d.consist "Keep volume consistent" remesh(make_consistent) \
            "$ln 1" \
            {{remesh(how) 0 1 2 4} {remesh(element) 3 5}}

        incr ln
        form_label $d.dev "Max. rel. surface deviation" "$ln 0" \
            {{remesh(proj)} {remesh(geo_active)} {remesh(how) 0 1 2} \
            {remesh(element) 1 2 3 4}}
        form_scale $d.dev_scale remesh(dev) "" h 0 0.3 0.02 "$ln 1" \
            {{remesh(proj)} {remesh(geo_active)} {remesh(how) 0 1 2} \
            {remesh(element) 1 2 3 4}}

        incr ln
        form_label $d.merg "Rel. merge tolerance" "$ln 0" \
            {{remesh(how) 3}}
        form_scale $d.merg_scale remesh(merge_tol) "" h 0 .4 .05 "$ln 1" \
            {{remesh(how) 3}}
        incr ln
        form_checkbutton $d.ends "Merge end nodes" remesh(merge_ends) "$ln 0" \
            {{remesh(how) 3}}

        #incr ln
        form_checkbutton $d.prescribed "Ignore dimension" remesh(all_dim) "$ln 1" \
            {{remesh(how) 7 8 0}}

        incr ln
        form_label $d.angle "Ignore curve angle" "$ln 0" \
            {{remesh(how) 7} {remesh(all_dim)}}
        form_scale $d.angle_value remesh(angle) "" h 0 60 5 "$ln 1" \
            {{remesh(how) 7} {remesh(all_dim)}}

        incr ln
        form_label $d.qual "Up to quality" "$ln 0" \
            {{remesh(inner) 0} {remesh(how) 7}}
        form_scale $d.qual_scale remesh(quality) "" h 0.1 1 .1 "$ln 1" \
            {{remesh(inner) 0} {remesh(how) 7}}

        incr ln
        form_label $d.steps "Max. # of steps" "$ln 0" \
            {{remesh(how) 7}}
        form_entry $d.stepsT remesh(max_steps) int "$ln 1" \
            {{remesh(how) 7}}

        incr ln
        form_label $d.offset "# of offset layers" "$ln 0" \
            {{remesh(how) 0}}
        form_scale $d.offset_scale remesh(offset) "" h 0 5 1 "$ln 1" \
            {{remesh(how) 0}}
        incr ln
        form_label $d.offset_h "Offset scaling" "$ln 0" \
            {{remesh(offset)} {remesh(how) 0}}
        form_scale $d.offset_h_scale remesh(offset_h) "" h 0.1 1.5 0.1 "$ln 1" \
            {{remesh(offset)} {remesh(how) 0}}

        incr ln
        form_label $d.new_fam_1 "Family for new elements" "$ln 0" \
            {{remesh(how) 0}}
        set famnames "-inherited [ get_famnames ]"
        form_frame $d.new_fam_2 flat 0 "$ln 1 -cols -"
        futil_listentry $d.new_fam_2.1 remesh(material) "list $famnames" "$ln 0" \
            {{remesh(how) 0}}

        incr ln
        form_label $d.qfunc "Quality metric" "$ln 0" \
            {{remesh(how) 7}}
        form_optionmenu $d.qfunc2 remesh(diagnostic) \
            {{"Angle error"} {"Custom quality"} {"Quality"} {"Aspect ratio"}} "$ln 1" \
            {{remesh(how) 7}}

        if [info exists env(QUAD_DEBUG)] {
            incr ln
            form_label $d.debug "Debug level" "$ln 0"
            form_scale $d.debug_scale remesh(debug) "" h -1 4 1 "$ln 1"
        }

        incr ln
        form_frame $d.frame ridge 2 "$ln 0 -cols -"
        incr ln
        form_radiobutton $d.frame.how7 "Re-mesh bad elements" remesh(how) 7 "$ln 0"
        form_radiobutton $d.frame.how0 "Re-mesh elements" remesh(how) 0 "$ln 1"
        incr ln
        form_radiobutton $d.frame.how8 "Enforce node" remesh(how) 8 "$ln 0"
        form_radiobutton $d.frame.how1 "Fill gaps/holes within elements" \
            remesh(how) 1 "$ln 1"
        incr ln
        form_radiobutton $d.frame.how5 "Smooth elements" remesh(how) 5 "$ln 0"
        incr ln
        if {$remesh(how) == 6} {set remesh(how) 2}
        if {$remesh(how) == 4} {set remesh(how) 3}
        form_radiobutton $d.frame.how2 "Mesh within edges" remesh(how) 2 "$ln 0"
        form_radiobutton $d.frame.how3 "Stitch edges" remesh(how) 3 "$ln 1"

        form_finish bot
    }
    if ![form_wait .remesh] {
        erase_flood_fill_lines
        return
    }
}

proc element_new_to_old {{back 0}} {
    global remesh
    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 == "$remesh(element_new)"} {set remesh(element) $v}
        if {$back == 1 && $v == "$remesh(element)"} {set remesh(element_new) $n}
    }
}

proc apply_unstruct_remesh {} {
    global remesh selmap 

    set map visible
    while 1 {
        if {$remesh(how) == 0 || $remesh(how) == 1 ||
            $remesh(how) == 5 || $remesh(how) == 7} {
            set sel_map [select_unstruct element 0 $map ""]
        } elseif {$remesh(how) == 8} {
            set sel_map [select_unstruct node 1 $map ""]
        } else {
            set sel_map [select_unstruct edge 0 $map ""]
	    if 0 {
            if {$remesh(how) == 2} {
                if {$sel_map == ""} return
                set node_map [ic_uns_create_selection_subset 0]
                if {$node_map == ""} return
                set the_nodes ""
                set types [ic_uns_subset_list_types $sel_map]
                if {[lsearch $types BAR_2] >= 0} {
                  set use BAR_2; set idx1 0; set idx2 3
                } else {
                  set use VERTEX; set idx1 5; set idx2 4
                }
                foreach e [ic_uns_subset_list_elements $sel_map] {
                    set t [lindex $e $idx1]
                    if {$t == "$use"} {
                        set n [lindex $e $idx2]
                        lappend the_nodes $n
                    }
                }
                set uni_pairs [uncouple_uniquify_pairs $the_nodes]
                foreach n $uni_pairs {   
                   ic_uns_subset_add_node_numbers $node_map $n
                }
                ic_uns_subset_delete $sel_map
                set sel_map $node_map
            }
	    }
        }
        if {$sel_map == ""} return
        if {$remesh(how) == 0 || $remesh(how) == 1 ||
            $remesh(how) == 5 || $remesh(how) == 7} {
            set types [ic_uns_subset_list_types $sel_map]
            if {([lsearch $types TRI_3] == -1) &&
                ([lsearch $types TETRA_4] == -1) &&
                ([lsearch $types QUAD_4] == -1) &&
                ([lsearch $types BAR_2] == -1) &&
                ([lsearch $types NODE] == -1)} {
                ic_uns_subset_delete $sel_map
                mess "Element type(s) $types not supported.\n" red
                return
            }
        } elseif {$remesh(how) == 8} {
            set vertex "-1"
            set elems [ic_uns_subset_list_elements $sel_map]
            if {[llength $elems] > 1} {
                ic_uns_subset_delete $sel_map
                mess "Number of nodes > 1. Only 1 node is allowed\
                      for \"Enforce node\".\n" red
                return
            }
            foreach item $elems {
                if {[lindex $item 0] == "VERTEX"} {
                    set vertex [lindex $item 1]
                }
            }
        }
        set args ""
        foreach h [array names remesh] {
            if {$h != "quality" || $remesh(inner) == 0} {
                append args "$h {$remesh($h)} "
            }
        }
        if {$remesh(how) == 8} {
            append args "vertex $vertex "
        }
        if {$remesh(all_dim) == 0} {
            append args "keep_fixed_nodes 1 "
        }
        eval ic_uns_quad_remesh $sel_map $args
        ic_uns_subset_delete $sel_map

        if { $remesh(make_consistent) && [ ic_count_elements TETRA_4 ] > 0 } {
            unstruct_flood_fill
        }
        update_uns_available
    }
}

proc uncouple_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
}
