#
# Stuff for handling meshing directives.
# Author: Jason Aftosmis, 2001
#
# -------------------------------------------------

#
# use of flexlist relies on flextags lement for getting values...i don't like it either...--jka, xxx
#
array set meshdirect_boltspider_tags {
    alltags     "result_fam quad_layers rows_bars active"
    flextags    "result_fam quad_layers active"
    reqargs     "result_fam"
    icontype    "circle"
    iconparams  "8 0"
    iconlocfunc "ic_meshdirect_sub_boltspider_icon_locs"
    
    result_fam  "md_spider_fam"
    quad_layers "n_quad_layers"
    rows_bars   "md_spider_n_bar_rows"
    active      "md_spider_active"
}
array set meshdirect_seamweld_tags {
    alltags     "target_fam result_fam method radius rbe3s maxproj splitting \
                 glinka_layers glinka_height glinka_ratio active"
    flextags    "target_fam result_fam maxproj splitting active"
    reqargs     "target_fam result_fam"
    icontype    "ecks"
    iconparams  "8"
    iconlocfunc "ic_meshdirect_sub_seamweld_icon_locs"
    
    target_fam    "md_seamweld_target_fam"
    radius        "md_seamweld_radius"
    method        "md_seamweld_method"
    rbe3s         "md_seamweld_rbe3_fam"
    result_fam    "md_seamweld_fam"
    maxproj       "md_seamweld_maxprojection"
    splitting     "md_seamweld_element_splitting"
    glinka_layers "md_seamweld_glinka_layers"
    glinka_height "md_seamweld_glinka_height"
    glinka_ratio  "md_seamweld_glinka_height_ratio"
    glinka_ratio  "md_seamweld_glinka_height_ratio"
    glinka_side   "md_seamweld_glinka_side"
    active        "md_seamweld_active"
    glinka_subtype  "md_seamweld_glinka_subtype"
}
array set meshdirect_spotweld_tags {
    alltags     "target_fam result_fam method rbe3s radius maxproj splitting active"
    flextags    "target_fam result_fam method rbe3s radius maxproj splitting active"
    reqargs     "target_fam result_fam"
    icontype    "ecks"
    iconparams  "8"
    iconlocfunc "ic_meshdirect_sub_spotweld_icon_locs"
    
    target_fam  "md_spotweld_target_fam"
    result_fam  "md_spotweld_fam"
    method      "md_spotweld_method"
    rbe3s       "md_spotweld_rbe3_fam"
    radius      "md_spotweld_radius"
    maxproj     "md_spotweld_maxprojection"
    splitting   "md_spotweld_element_splitting"
    active      "md_spotweld_active"
    
    source_pt   "md_spotweld_source_ppt"
}
array set meshdirect_connector_tags {
    alltags     "source_type target_fam target_type result_fam maxproj active"
    flextags    "source_type target_fam target_type result_fam maxproj active"
    reqargs     "source_type target_fam target_type result_fam"
    icontype    "barbell"
    iconparams  "8 0 0 1"
    
    source_type "md_connector_source_type"
    target_fam  "md_connector_target_fam"
    target_type "md_connector_target_type"
    result_fam  "md_connector_fam"
    maxproj     "md_connector_maxprojection"
    active      "md_connector_active"
}


#
# for mapping text back to the tag for meshdirect_spotweld_tags(method)
#
array set meshdirect_spotweldtypes {
    standard      "Point to point"
    meshless_bar  "Mesh indpendenent line"
    meshless_hex  "Mesh indpendenent hexa"
    meshless_area "Area weld"
}
array set meshdirect_seamweldtypes {
    standard      "Point to point"
    curtain_quad  "Curtain Tris/Quads"
    glinka        "Glinka"
}
#
# for mapping text back to the tag for meshdirect_spotweld_tags(splitting)
#
array set meshdirect_weldsplitting {
    terminate       "Terminate"
    propagate       "Propagate"
    remesh_tri_quad "Remesh area (Tri/Quad)"
}
array set meshdirect_glinkasides {
    both_surface_norms    "Both directions"
    positive_surface_norm "Positive direction"
    negative_surface_norm "Negative direction"
}
array set meshdirect_glinkasubtypes {
    tweld 0
    lapweld 1
}
#remesh_all_quad "Remesh area (All Quad)"

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


## return a list of the valid types of meshing directives that can be set in MED.

proc ic_meshdirect_sub_available_directives_get {} {   
    return "spotweld boltspider seamweld connector"
}

## needs doc.

proc ic_meshdirect_sub_param_for_tag {directive tag} {
    
    if {0 > [lsearch [ic_meshdirect_sub_available_directives_get] $directive]} {
	return ""
    }
    
    global meshdirect_${directive}_tags
    
    array set cur_tags [array get meshdirect_${directive}_tags]
    
    if ![info exists cur_tags($tag)] {
	#mess "unhandled type in ic_meshdirect_sub_param_for_tag: $directive for $tag\n"
	return ""
    }
    
    return $cur_tags($tag)
}

## Underlying proc for settings meshing directives on a family by params

proc ic_meshdirect_sub_params_set {fams args} {
    
    if {"" == $fams} {
	mess "cannot set meshing directive parameters with null family-list\n" red
	return -1
    }
    
    if {"" == $args} { return 0 }
    
    foreach fam $fams {
	
	if {"" == [ic_geo_get_objects all $fam]} {   
	    #mess "Warning: setting meshing directives on $fam, which has no geometric entities in it\n" red
	    #continue
	}
	
	foreach {n v} $args {
	    
	    if {("" == $n) || ("" == $v)} { continue }
	    
	    ic_geo_set_family_params $fam $n $v
	    #mess "DEBUG: set parms (n: $n; v: $v) on family $fam\n"
	}
    }
}

proc ic_meshdirect_sub_extra_args_set {fams arg_pairs} {
    
    foreach f $fams {
	eval ic_meshdirect_sub_params_set $f $arg_pairs
    }
}

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

proc ic_meshdirect_shadow_name_suffix {} { return "_SHADOW" }

## Get the name of the shadow curve for the curve <em>crv</em> when projected
## to the given surface <em>srf</em>.

proc ic_meshdirect_spot_weld_shadow_point_name {srf pnt} {
    return "${srf}_${pnt}[ic_meshdirect_shadow_name_suffix]"
}

## Get the family name of the curve into which a shadow curve would go when projected
## to the given surface <em>srf</em>.

proc ic_meshdirect_spot_weld_shadow_point_family {srf} {
    if [catch {ic_geo_get_family surface $srf} res] {
	return "__none__"
    }
    return $res
}

## Get the name of the shadow curve for the curve <em>crv</em> when projected
## to the given surface <em>srf</em>.

proc ic_meshdirect_seam_weld_shadow_curve_name {srf crv} {
    return "${srf}_${crv}[ic_meshdirect_shadow_name_suffix]"
}

## Get the family name of the curve into which a shadow curve would go when projected
## to the given surface <em>srf</em>.

proc ic_meshdirect_seam_weld_shadow_curve_family {srf} {
    if [catch {ic_geo_get_family surface $srf} res] {
	return "__none__"
    }
    return $res
}


##
proc ic_meshdirect_sub_boltspider_icon_locs { family } {
    #
    # o this is a littl bit wrong in that it will 
    #   display an icon foreach curve, rather than foreach
    #   group of curves which make up a bolt-hole.
    #
    # o note that there can be 'm' curves making up 'n'
    #   boltspiders in a single family. --jka
    #
    # --> get the center of each curve in the family
    #
    set locs ""
    set crvs [ic_geo_get_objects curve $family]
    set ncrvs [llength $crvs]
    if !$ncrvs {return "geometry_or_mesh"}
    foreach crv $crvs {
		set p0($crv) [lindex [ic_geo_get_crv_pos 0 $crv] 0]
		set p1($crv) [lindex [ic_geo_get_crv_pos 1 $crv] 0]
		set len($crv) [ic_geo_crv_length $crv]
		set d [ic_vcalc distance $p0($crv) $p1($crv)]
		if {[expr $d /$len($crv)] > 0.5} {
			set center($crv) [ic_vcalc sum_smult $p0($crv) $p1($crv) 0.5]
		} else {
			set p [lindex [ic_geo_get_crv_pos 0.5 $crv] 0]
			set center($crv) [ic_vcalc sum_smult $p0($crv) $p 0.5]
		}
		set nconnect($crv) 1
    }
    # may be circular curve?
    foreach crv $crvs {	
		if !$len($crv) continue
		set d [ic_vcalc distance $p0($crv) $p1($crv)]
		if {[expr $d /$len($crv)] > 0.001} continue 
		lappend locs $center($crv)
		unset p0($crv)
		unset p1($crv)
    }
    # try connect:
    # do until no new connections
    set connected_curves ""    
    while 1 {
	set connected 0
	set crvs [array names p0]
	foreach crv $crvs {
		if {[lsearch $connected_curves $crv] < 0} { lappend connected_curves $crv }
		foreach try $crvs {
			if {$crv == $try} continue
			set diff [expr abs($len($crv) - $len($try))]
			set d [ic_vcalc distance $p0($crv) $p0($try)]
			if {[expr $d /$len($crv)] < 0.001} {
			    set connected 1
			    set p0($crv) $p1($try)
                            if {$diff > 0.001} { set diff_crvs_len 1 }
                            if {[lsearch $connected_curves $try] < 0} { lappend connected_curves $try }
			    break
			}
			set d [ic_vcalc distance $p0($crv) $p1($try)]
			if {[expr $d /$len($crv)] < 0.001} {
			    set connected 1
                            if {$diff > 0.001} { set diff_crvs_len 1 }
                            if {[lsearch $connected_curves $try] < 0} { lappend connected_curves $try }
                            set p0($crv) $p0($try)
                            break		
			}
			set d [ic_vcalc distance $p1($crv) $p0($try)]
			if {[expr $d /$len($crv)] < 0.001} {
			    set connected 1
                            if {$diff > 0.001} { set diff_crvs_len 1 }
                            if {[lsearch $connected_curves $try] < 0} { lappend connected_curves $try }
			    set p1($crv) $p1($try)
			    break
			}
			set d [ic_vcalc distance $p1($crv) $p1($try)]
			if {[expr $d /$len($crv)] < 0.001} {
			    set connected 1
                            if {$diff > 0.001} { set diff_crvs_len 1 }
                            if {[lsearch $connected_curves $try] < 0} { lappend connected_curves $try }
			    set p1($crv) $p0($try)
			    break
			}
		}
		if !$connected	continue
		unset p0($try) 
		unset p1($try)
		set center($crv) [ic_vcalc sum $center($crv) $center($try)]
		incr nconnect($crv) $nconnect($try)
		# if connected , break crv-try loops and start over search for connections.
		break
	}
	# break "while" loop if no new connections
	if !$connected break
    }

    if {$connected_curves != "" && [info exists diff_crvs_len] && [llength [array names p0]] == 1} {
        # Different curves len - temporary create 1 connected curve to get correct location
        set nconnected_curves ""
        foreach crv $connected_curves {
            lappend nconnected_curves [ic_geo_duplicate curve $crv]
        }
        set ncrv [ic_geo_cre_crv_concat CURVES TEMP. 0.1 "$nconnected_curves"]
        set np0 [lindex [ic_geo_get_crv_pos 0.0 $ncrv] 0]
        set np1 [lindex [ic_geo_get_crv_pos 0.5 $ncrv] 0]
	lappend locs [ic_vcalc sum_smult $np0 $np1 0.5]
	lappend locs [ic_vcalc sum_smult $np0 $np1 0.5]
	ic_delete_geometry curve names "$ncrv"
	ic_delete_geometry curve names "$nconnected_curves"
    } else {
        # Now all possible curves connected:
        foreach crv [array names p0] {
		set coeff [expr double(1.0/$nconnect($crv))]
		lappend locs [ic_vcalc smult $center($crv) $coeff]
        }
        foreach crv [array names p1] {
		set coeff [expr double(1.0/$nconnect($crv))]
		lappend locs [ic_vcalc smult $center($crv) $coeff]
        }
    }
    if {"" == $locs} {
	return "geometry_or_mesh"
    }
    return $locs
}

##

proc ic_meshdirect_sub_seamweld_icon_locs {family} {
    #
    set locs ""
    foreach crv [ic_geo_get_objects curve $family] {
	foreach p [list 0 0.25 .5 0.75 1] {
	    if ![catch {ic_geo_get_crv_pos $p $crv} res] {
		lappend locs [lindex $res 0]
	    }
	}
    }
    return $locs
}

##

proc ic_meshdirect_sub_spotweld_icon_locs {family} {
    # get the location of each point in the family
    set locs ""
    foreach pnt  [ic_geo_get_objects point $family] {
	lappend locs [ic_geo_get_point_location $pnt]
    }
    return $locs
}


#------------------------------------------------------------------------
#
#
proc ic_meshdirect_sub_set_list {type list} {
    foreach entry $list { unstruct_meshdirect_set $type $entry }    
}

#
proc old_ic_meshdirect_set_old {type entry} {
    
    global meshdirect_connector_tags meshdirect_boltspider_tags
    global meshdirect_spotweld_tags meshdirect_seamweld_tags
    
    if ![info exists meshdirect_${type}_tags] {
	mess "unhandled type in unstruct_meshdirect_set: $type\n"
	return ""
    }
    array set cur_tags [array get meshdirect_${type}_tags]
    
    # each entry will consist of the family then each tag
    # then a junk element ("flexlist_delete" or "1")
    set nelsinarray [array names $cur_tags]
    set properl [expr [llength $nelsinarray] + 2]
    
    if { [llength [lindex $entry 0]] > 1 } {
	return [unstruct_meshdirect_set_list $type $entry]
    } elseif {$properl != [llength $entry]}  {
	mess "unstruct_meshdirect_set: unrecognized format for $type\n$entry"
	return ""
    }
    
    # Set the parameters
    set nth 0
    set fam [lindex $entry $nth]
    # Make sure the family exists in the tetin file, so can set params on it
    if ![ic_geo_check_family $fam] { ic_geo_new_family $fam }
    incr nth
    foreach t [array names $cur_tags] {
	set val [lindex $entry $nth]
	ic_geo_set_family_params $fam $cur_tags($t) $val
	incr nth
    }
    
    # make sure the family is visible
    add_new_family $fam 1
}

proc unstruct_meshdirect_get {type {fams ""}} {
    global meshdirect_connector_tags meshdirect_boltspider_tags
    global meshdirect_spotweld_tags meshdirect_seamweld_tags
    
    if { $fams == "" } { set fams [ic_uns_list_families] }

    if ![info exists meshdirect_${type}_tags] {
	mess "unhandled type in unstruct_meshdirect_get: $type\n"
	return ""
    }
    array set cur_tags [array get meshdirect_${type}_tags]
    
    set list ""
    foreach f $fams {
	set entry $f
	set ngot 0
	set ntags 0
	if { ($f == "ORFN") || ($f == "VORFN") } continue
	foreach t [array names $cur_tags] {
	    incr ntags
	    set ent [ic_geo_get_family_param $f $cur_tags($t)]
	    if {"" == $ent} continue
	    incr ngot
	    append entry " $ent"
	    #lappend list $entry
	}
	if {$ntags == $ngot} { lappend list $entry }
    }
    return $list
}
#
# this resets all of the mesh_direct params in the tetin file
#
proc unstruct_meshdirect_reset {{types ""} {fams ""}} {
    global meshdirect_spotweld_tags meshdirect_boltspider_tags
    global meshdirect_seamweld_tags meshdirect_connector_tags
    
    if { $types == "" } { set types [ic_meshdirect_sub_available_directives_get] }
    if { $fams == "" } { set fams [ic_uns_list_families] } 
    
    set del_string ""
    
    foreach ty $types {
	if ![info exists meshdirect_${ty}_tags] {
	    mess "unhandled type in unstruct_meshdirect_reset: $ty\n"
	    return
	}
	array set typetags [array get meshdirect_${ty}_tags]
	
	foreach t [array names $typetags] { lappend taglist $typetags($t) }
	ic_geo_reset_family_params $fams $taglist
    }
}
#
# returns the list of params from the tetin file
#
proc unstruct_meshdirect_list {{types ""} {fams ""}} {
    global meshdirect_vals
    
    if { $types == ""} { 
	set types [ic_meshdirect_sub_available_directives_get]
    }
    
    set list ""
    foreach t $types {
	if { [ info exists meshdirect_vals(${t}_active) ] == 0 } {
	    set meshdirect_vals(${t}_active) 1
	}
	if $meshdirect_vals(${t}_active) {
	    if { $fams != "" } {
		foreach f $fams {
		    if { ($f == "ORFN") || ($f == "VORFN") } continue
		    set val [unstruct_meshdirect_get $t $f]
		    if { $val == "" } continue
		    lappend list $val
		}
	    } else {
		if {![llength $list]} {
		    lappend list [unstruct_meshdirect_get $t "" ]
		} else {
		    set list [unstruct_meshdirect_get $t ""]
		}
	    }
	}
    }
    return $list
}


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


if 0 {

#--------------- W E L D I N G   C O D E -----------------------------

## read the given "filename" for spotwelding parameters
##      --mode can be one of: { biwasm, vif }
##      --projection_max controls projection dist in scrib_lib_welding_prepoint_create

proc ic_meshdirect_welding_spot_import {filename mode projection_max {report_file ""}} {
    global welding_proj_max welding_nwspots welding_nwspots_by_fam
    global welding_report_filename
    #
    # --> this is setting the global variable, since i'm too lazy to pass it around
    #
    set welding_report_filename $report_file
    set welding_proj_max $projection_max
    #
    # --> keep track of the number of spotwelds *per family*
    #
    set welding_nwspots(total_lines) 0
    set welding_nwspots(total_welds) 0
    set welding_nwspots(ntoolong) 0
    set welding_nwspots(nbadpartrefs) 0
    set welding_nwspots(npts) 0
    set welding_nwspots(nlineerrors) 0
    set welding_nwspots(filename) $filename
    #
    # --> open the file and read each line in file...
    #    
    set fstat [catch {open $filename r} fp]
    if $fstat {
	mess "WELD_READ_ERROR: cannot open file $filame...returning.\n" red
	return -1
    }
    #
    # --> make sure the parsing command exists
    #
    set cmd "scrib_lib_welding_line_parse_${mode}"
    if {"" == [info commands $cmd]} {
	mess "WELD_READ_INFO: could not get command $cmd for parsing $mode data file $filename\n" red
	return -1
    }
    
    mess "\n\nBeginning to import $mode spotweld data from $filename\n"
    mess "\tmaximum weld projection is $projection_max\n\n"
    #
    # --> get all the lines from the file
    #
    while { ![eof $fp] } {
	#
	# --> get a line from the file
	#
	set line [string trim [gets $fp]]
	#
	# --> and parse it based on the mode (biwasm, vif, ...)
	#
	set no_report 0
	set read_error 0
	set exec_status ""
	set data [scrib_lib_welding_line_parse $mode $fp $line]
	switch -- $data {
	    0 {
		# this is fine--it could have been a comment, blank line or something
		set no_report 1
	    }
	    -1 {
		# something went horribly wrong
		set read_error 1
		set exec_status -1
	    }
	    default {
		# best case scenario; obviously this list order and integrity is CRUCIAL
		set ppname     [lindex $data 0]
		set coords     [lindex $data 1]
		set compfams   [lindex $data 2]
		set result_fam [lindex $data 3]
		set exec_status [scrib_lib_welding_execute_one_weld $ppname $coords $compfams $result_fam]
	    }
	}
	if {"" != $exec_status} {	    	
	    foreach res $exec_status {
		incr read_error [expr {"-1" == [lindex $res 0]}]
	    }
	    if $read_error {
		# something went (horribly) wrong
		mess "WELD_READ_ERROR: unsuccessful importing the weld: $line\n***\n" red
		incr welding_nwspots(nlineerrors) $read_error
	    }
	    if !$no_report {
		scrib_lib_welding_report_line_status $mode $line $exec_status
		incr welding_nwspots(total_lines)
	    }
	}
    }
    
    scrib_lib_welding_report_summary
    
    return 0
}

}

## This operation will detect and set up bolt holes 
## Syntax is ic_meshdirect_bolt_holes d1 d2 number of nodes ratio width loops part smart_sizing
## parameter d1 is the min bolt hole diameter
## parameter d2 is the max bolt hole diameter
## parameter number_of_nodes is the number of nodes that should be put on the hole, where 0 means to remove the hole
## parameter ratio will set this as the height ratio on the bolt hole curves
## parameter width will set the number of layers for the bolt hole curves
## parameter loops are defined loops that represent a bolt hole.  These loops should already be confirmed to be valid bolt holes.
## parameter curves are a list of curves to evaluate.  If it is set to "" all curves in the model will be checked
## parameter part is the part to put the bolt hole curves into
## parameter smart_sizing is 1 or 0. 1 or on will adjust max size to give spacing scaled back by width and ratios defined.

proc ic_meshdirect_bolt_holes {d1 d2 {number_of_nodes ""} {ratio 1} {width 2} {loops ""} {curves ""} {part HOLE} {smart_sizing 1} } {
    if {$loops == ""} {
	if {$curves == ""} {
	    set all_curves [ic_geo_get_objects curve ""]
	} else {
	    set all_curves $curves
	}
	set loops [ic_meshdirect_make_conn_loops \
	    [ic_geo_get_entities_by_attach_num curve 1 $all_curves]]

	set loops [ic_meshdirect_remove_unclosed_loops $loops]
    }
#mess "loops are $loops, nloops is [llength $loops]\n"

    set skip 0
    set number_of_holes 0
    set number_of_holes_removed 0
    foreach con_region $loops {
	if {[llength $con_region] == 1} {set con_region [lindex $con_region 0]}
	foreach c $con_region {
	    if {[ic_geo_check_objects_exist curve $c] == ""} {
		set skip 1
		mess "for some reason a curve seems to be missing...\n" red
		break
	    }
	}
	if $skip continue
	#Find the length of the curves in the connected region
	#Note, ratio must be set to define curves to be offset
	set length 0
	set mesh_size [lindex [ic_get_meshing_params curve [lindex $con_region 0]] 1]
	set height [expr $mesh_size * $ratio]
	foreach curve $con_region {
	    set length [expr $length + [ic_geo_crv_length $curve]]
	}
  	set diam [expr $length / 3.14]		
	if { ($diam < $d2) && ($diam > $d1)} {
	    incr number_of_holes
	    if {$number_of_nodes == 0} {
		ic_geo_remove_feature $con_region
		ic_mess "curve(s) $con_region have been removed.\n"
		incr number_of_holes_removed
	    } elseif {$number_of_nodes == ""} {
		foreach curve $con_region {
		    if {$smart_sizing && ($width > 0)} {
			set Msize [lindex [ic_get_meshing_params curve $curve] 1]
			if {$Msize <= 0} {
			    mess "curve parameters are not defined, not setting smart sizing\n"
			    ic_set_meshing_params curve $curve erat $ratio ehgt $height nlay $width
			} else { 
			    set element_size $Msize
			    set growth_size [expr $element_size * $ratio]
			    set Lradial $growth_size
			    set w [expr $width - 1]
			    while {$w > 0} {
				set w [expr $w - 1]
				set growth_size [expr $growth_size * $ratio] 
				set Lradial [expr $Lradial + $growth_size]
			    }
#			    mess "Lradial is $Lradial\n"
			    set angle [expr 360 / (2 * [expr $length / $element_size])]
			    set ss [expr sin(2*3.1416*$angle/360) * $Lradial]
			    set ss_ratio [expr ($ss * 2 + $element_size) / $element_size]
			    ic_set_meshing_params curve $curve emax [expr $Msize / $ss_ratio] \
				erat $ratio ehgt $height nlay $width
			}
		    } else {
			ic_set_meshing_params curve $curve erat $ratio ehgt $height nlay $width
		    }
		}
		if {$part != ""} {
		    if ![ic_geo_check_family $part] { ic_geo_new_family $part }
		    ic_geo_set_family curve $part names $con_region
		} else {
		    foreach cc $con_region {ic_geo_subset_add_items HOLE [list curve $cc]}
		    if [llength [info commands aie_getBatchGeomDisplay]] {aie_getBatchGeomDisplay}
		}
		continue  
	    } else {
		foreach curve $con_region {
		    set percent [expr  [ic_geo_crv_length $curve] / $length ]
    		    set size [expr [ic_geo_crv_length $curve] / ($number_of_nodes * $percent ) ]
		    set csize [lindex [ic_get_meshing_params curve $curve] 1] 
		    if {$size < $csize} {
			ic_set_meshing_params curve $curve emax $size erat $ratio ehgt [expr $ratio * $size] nlay $width
		    } else {
			ic_set_meshing_params curve $curve erat $ratio ehgt $height nlay $width
		    }
		}
	    }
	    if {$part != ""} {
		if ![ic_geo_check_family $part] { ic_geo_new_family $part }
		ic_geo_set_family curve $part names $con_region
	    } else {
		foreach cc $con_region {ic_geo_subset_add_items HOLE [list curve $cc]}
		if [llength [info commands aie_getBatchGeomDisplay]] {aie_getBatchGeomDisplay}
	    }
	}
    }
    if $number_of_holes_removed {mess "$number_of_holes_removed holes were removed from the model\n"}
    return $number_of_holes
}

## This function takes a set of loops or groups of curves and only returns the valid closed loops.
## A valid closed loop is one that the curves form 1 loop with no free ends.

proc ic_meshdirect_remove_unclosed_loops { loops } {
    set ret_loops ""
    set i 1
    foreach loop $loops {
	#mess "loop is $loop; \n"
	if {[llength $loop] == 1} {set loop [lindex $loop 0] }
 
	set points ""
	foreach curve $loop {
	    set points [concat $points [ic_geo_boundary curve $curve 0 1]]
	}
	set non_duplicate_points [ic_list_remove_duplicated $points]
	if {$non_duplicate_points == "" } {
	    lappend ret_loops $loop
	}
    }
    return $ret_loops
}

##This function takes a list of curves and returns the connected regions.

proc ic_meshdirect_make_conn_loops {curves} {
 set ret ""
 set j [llength $curves]
 while {$j > 0} {
  set crv    [lindex $curves 0]
  set curves [lreplace $curves 0 0]
  set pnts   [ic_geo_boundary curve $crv 0 1]
  set crvs_0 $crv
  set crvs_1 ""
  foreach i "0 1" {
     set pt   [lindex $pnts $i]
     while 1 {
        set chck 0
        set cr_p [ic_geo_incident point $pt 1]
        set plc  [lsearch  $cr_p $crv]
        set cr_p [lreplace $cr_p $plc $plc]
        foreach c $cr_p {
          if {[lsearch $curves $c] == -1} continue
          if {[lsearch $crvs_0 $c] == -1 && [lsearch $crvs_1 $c] == -1} {
             lappend crvs_$i $c
             set plc [lsearch $curves $c]
             set curves [lreplace $curves $plc $plc]
             set chck 1
             }
          if $chck break
          }
        if !$chck break
        set crv $c
        set pts [ic_geo_boundary curve $crv 0 1]
        set plc [lsearch $pts $pt]
        set pt  [lindex [lreplace $pts $plc $plc] 0]
        }
     }
   set j [llength $curves]
   if {$crvs_1 != ""} {
      for {set m 0} {$m < [llength $crvs_1]} {incr m} {
         set crvs_0 [concat [lindex $crvs_1 $m] $crvs_0]
         }
      }
   lappend ret [list $crvs_0]
 }
 if {[llength $ret] == 1} {set ret [lindex $ret 0]}
 return $ret
}


## This command will take a set of surfs and check them to find buttons or raised group of surfaces
## For example, a regular button looks like:
## x--------------------x
## |                          |
## |            / \          |
## |            \ /          |
## |                          |
## x--------------------x 
## Or seam button
## x--------------------x
## |             |            |
## |      1    / \      2   |
## |            \ /           |
## |             |            |
## x--------------------x 

proc ic_meshdirect_find_button_features {{surfs ""}	{exclusion_surfs ""} {butt_type ""}} {

    switch $butt_type {
	seam {
	}
	default {
	    mess "scanning geometry for $butt_type buttons ...\n"
	}
    }
    if {$surfs == ""} {set surfs [ic_geo_get_objects surface ""]}
    set surfs [ic_geo_sort_by_srf_area $surfs  -decreasing ]
    set button_surfs ""
    set button_surf_list ""
    #surf could be a list of surfaces with a seam
    # x--------------------x
    # |             |            |
    # |      1    / \      2   |
    # |            \ /           |
    # |             |            |
    # x--------------------x 
    interrupt init
    set interrupt_pending 0
    set ntotal [llength $surfs]
    set ntt 0
    foreach surf $surfs {
#mess "surf is $surf\n" blue
	interrupt check $ntt $ntotal
	incr ntt
	if {$interrupt_pending == 1} {
 	    interrupt finish
	    return 0
 	}
	if {[lsearch $button_surfs $surf] != -1} {continue}
	if {[llength $surf] < 2} {
	    set inner_c [ic_geo_get_internal_surface_boundary $surf 1]
	    set outer_c [ic_geo_boundary surface $surf 1 1] 
#	    set outer_c [ic_geo_get_entities_by_attach_num curve 2 $outer_c]
	} else {
	    set inner_outer [ic_geo_find_internal_outer_loops $surf 1]
	    if {[llength $inner_outer] != 2} {
		mess "was not able to find internal and outer curves for $surf\n"
		continue
	    }
	    set outer_c [lindex $inner_outer 0]
	    set inner_c [lindex $inner_outer 1]
	}
#mess "inner_curves are $inner_c, outer_curves are $outer_c\n" blue
	if {$outer_c == ""} continue
	if {$inner_c == ""} continue

	set loops [ic_meshdirect_make_conn_loops $inner_c]
	#mess "internal loops for surface $surf are $loops\n" blue
	#mess "button_surfs are $button_surfs\n"
	set loops [lsort -unique $loops]

	foreach loop $loops {
	    if {[llength $loop] == 1} {set loop [lindex $loop 0]}
#mess "executing ic_geo_find_internal_surfaces loop $loop\n \
#    surf $surf\n outer_c $outer_c\n exclusion_surfs $exclusion_surfs\n" 
	    set new_surfs [ic_geo_find_internal_surfaces $loop $surf $outer_c  $exclusion_surfs]
	    if {$new_surfs == "" } {continue}
	    set button_surfs [concat $button_surfs $new_surfs]
	    lappend button_surf_list $new_surfs	
	}
    }
    interrupt finish
    return $button_surf_list
}

##Needs doc

proc ic_meshdirect_find_seam_buttons { {surfs ""} {exclusion_surfs ""}}  {

    if {$surfs == ""} {set surfs [ic_geo_get_objects surface ""]}
    if {$exclusion_surfs == ""} {
	foreach s [ic_geo_get_objects surface ""] {
	    if {[lsearch $surfs $s] == -1} {lappend exclusion_surfs $s}
	}
    }
    #mess "surfs is $surfs\n"
    set surfs [ic_geo_sort_by_srf_area $surfs  -decreasing ]
    #mess "surfs is $surfs\n"

    set seam_surfs ""
    set used_surfs ""
    set button_surfs ""
    mess "scanning geometry for seam buttons ...\n"
    interrupt init
    set interrupt_pending 0
    set ntotal [llength $surfs]
    set ntt 0
    foreach surf $surfs {
	interrupt check $ntt $ntotal
	incr ntt
	if {$interrupt_pending == 1} {
 	    interrupt finish
	    return 0
 	}
	if {[lsearch $used_surfs $surf] != -1} continue
	if {[lsearch $button_surfs $surf] != -1} continue
#	mess "surf is $surf\n"
	set curves [ic_geo_boundary surface $surf 1 1]
	if {$curves < 6} continue
	set curves [ic_geo_get_entities_by_attach_num curve 2  $curves]
#	mess "curves are $curves\n"
	#if {[ic_surface_curvature $surf] > 60} {continue}
	#2 curves must have the same neighbors.
	set crv_srf_list ""
	set attached_surfs ""
	foreach c $curves {
	    set att_surfs [ic_geo_incident curve $c 1]
	    foreach as $att_surfs {
		if {$as == $surf} continue
		lappend attached_surfs $as
		lappend crv_srf_list [list $c $as]
	    }
	}
	foreach as $attached_surfs {
	    set count($as) 0
	}
	foreach cs $crv_srf_list {
	    set crv [lindex $cs 0]
	    set srf [lindex $cs 1]
	    incr count($srf)
	}
	set double_neighbors ""
	foreach as $attached_surfs {
	    if {$count($as) < 2} continue
	    lappend double_neighbors $as
	}
	set double_neighbors [lsort -unique $double_neighbors]
	set double_neighbors [ic_geo_sort_by_srf_area $double_neighbors  -decreasing ]
#	mess "double_neighbors are $double_neighbors\n"
if 0 {
	set first 1
	set last_srf ""
	set this_surf_seam_surfs ""
	foreach curve $curves {
	    set nsrfs [ic_geo_incident curve $curve 1]
	    set new_srf ""
	    foreach l $nsrfs {
		if {$l == $surf} continue
		if {[lsearch $used_surfs $l] != -1} continue
		lappend new_srf $l
	    }
	    if {$new_srf == ""} {set new_srf single}
	    if $first {
		    set last_srf $new_srf
		    set first_srf $new_srf
		    set first 0
		    set neighbors $new_srf
	    }
	    if {$last_srf == $new_srf} {continue}
	    if {$new_srf == $first_srf} {continue}
	    if {[lsearch $neighbors $new_srf] != -1} {
		set s [list $surf $new_srf]
		if {[lsearch $s single] != -1} {
		    continue
		} 
		#mess "s is $s\n" blue
		lappend this_surf_seam_surfs $new_srf
	    }
	    lappend neighbors $new_srf
	    set last_srf $new_srf
	}
	set this_surf_seam_surfs [ic_geo_sort_by_srf_area $this_surf_seam_surfs  -decreasing ]
	mess "this_surf_seam_surfs is $this_surf_seam_surfs\n"
}
	foreach tsss $double_neighbors {
		if {[lsearch $used_surfs $tsss] != -1} {continue}
		set s [list $tsss $surf]
#		mess "running ic_meshdirect_find_button_features [list $s] $exclusion_surfs seam\n"
		set new_button_surfs [ic_meshdirect_find_button_features [list $s] \
		    $exclusion_surfs seam]
#mess "new_button_surfs are $new_button_surfs\n"
		if {$new_button_surfs == ""} continue
		set button_surfs [concat $button_surfs $new_button_surfs]
#		set used_surfs [concat [concat $used_surfs $new_button_surfs ]]   
		foreach bb $new_button_surfs {
		  foreach b $bb {
		    lappend used_surfs $b
		  }
		}
#		mess "used_surfs is $used_surfs\n"		 
#		mess "button_surfs are $button_surfs\n"
	}
	lappend used_surfs $surf
#	mess "used_surfs is $used_surfs\n"		 
    }
    interrupt finish
    set button_surfs [lsort -unique $button_surfs]
#mess "seam_surfs are $seam_surfs"

#mess  "button_surfs are $button_surfs\n" blue

    return $button_surfs
}

## Needs doc

proc ic_meshdirect_fillet_find_surf {
    {a_min 10} {a_max 170} {l_min 1} {fllt_type 0} {surfs ""} {param 0} {msh_lmt ""}} {
global mv_set interrupt_pending
  set fllt_nm ""
  set fllt_info ""
  if ![info exist mv_set(old_way)] {set mv_set(old_way) 0}
  if {$fllt_type != 1 && $fllt_type != 2 && $fllt_type != 3} {set fllt_type 0}
  busy 1
  if {$msh_lmt == ""} {
     set msh_lmt [list "{0 5} 2" "{5 10} 3" "{10 25} 4" "{25 50} 5"]}
  set ret [ic_meshdirect_fillet_find $a_min $a_max $l_min $surfs]
#mess "mv_set(srf_nm) is $mv_set(srf_nm)\n" debug
#mess "mv_set(srf_info) is $mv_set(srf_info)\n"
#mess "mv_set(arc_nm) is $mv_set(arc_nm)\n" debug
#mess "mv_set(arc_info) is $mv_set(arc_info)\n"
  if {$ret == 0} {
     busy reset
     return
     }
  set srf_nm   $mv_set(srf_nm)
  set srf_info $mv_set(srf_info)
  set arc_nm   $mv_set(arc_nm)
  set arc_info $mv_set(arc_info)
  if {$arc_nm == ""} {
     busy 0 
     return
     }
  
  #scrib_lib_exec_interrupt init
  interrupt init
  set interrupt_pending 0
  set ntotal [llength $srf_nm]
  for {set i 0} {$i < $ntotal} {incr i} {
    #scrib_lib_exec_interrupt check $i [expr $ntotal+3]
    interrupt check $i [expr $ntotal+3]
    if {$interrupt_pending == 1} {
       #scrib_lib_exec_interrupt finish
       interrupt finish
       busy reset
       return
       }
    set fllt 0
    set arc_0 0 
    set arc_1 0
    set arc_2 0
    set arc_3 0
    set n_cr [lindex [lindex $srf_info $i] 0]
    set bnd  [lindex [lindex $srf_info $i] 1]
#mess "n_cr is $n_cr\n"
    if {$n_cr == 3} {
       set c0 [lsearch $arc_nm [lindex $bnd 0]]
       set c1 [lsearch $arc_nm [lindex $bnd 1]]
       set c2 [lsearch $arc_nm [lindex $bnd 2]]
       if {$c0 != -1 && $c1 != -1 && $c2 != -1} {
          set fllt   1 
          set arc_0  1 
          set arc_1  1
          set arc_2  1
          }
       }
    if {$n_cr == 4} {
       set c0 [lsearch $arc_nm [lindex $bnd 0]]
       set c1 [lsearch $arc_nm [lindex $bnd 1]]
       set c2 [lsearch $arc_nm [lindex $bnd 2]]
       set c3 [lsearch $arc_nm [lindex $bnd 3]]
       if {$c0 != -1 && $c2 != -1} {
          set fllt  1 
          set arc_0 1 
          set arc_2 1
          }
       if {$c1 != -1 && $c3 != -1} {
          set fllt  1 
          set arc_1 1
          set arc_3 1
          }
       }
    if {$n_cr > 4 && $n_cr < 12} {
       foreach j "0 1 2 3" {
         set sd_$j -1        
         set nm [lindex $bnd $j]
         if {[llength $nm] == 1} {
            set sd_$j [lsearch $arc_nm $nm]
            } else {
              set fam   [ic_geo_get_family curve [lindex $nm 0] ]
              set nw_nm [ic_geo_new_name curve $fam]
              catch {ic_geo_cre_crv_concat $fam $nw_nm 1 $nm} err
              if {$nw_nm == $err} {
#	         if {$mv_set(old_way) == 0} {
	            set rst [ic_meshdirect_fillet_find_arc $nw_nm $a_min $a_max $l_min]
#	            } else {
#	              set rst [scrib_lib_fillet_find_arc_old $nw_nm $a_min $a_max $l_min]
#	              }
	         if {$rst != 0} {set sd_$j 1}
	         ic_delete_geometry curve names $nw_nm
                 }
              }
         }
       if {$sd_0 != -1 && $sd_2 != -1} {
          set fllt  1 
	  set arc_0 1 
	  set arc_2 1
	  }
       if {$sd_1 != -1 && $sd_3 != -1} {
          set fllt  1 
          set arc_1 1
          set arc_3 1
          }
       }
    if $fllt {
       lappend fllt_nm [lindex $srf_nm $i]
       lappend fllt_info [list $n_cr [list $arc_0 $arc_1 $arc_2 $arc_3]]
       }
    }
#mess "fllt_nm is $fllt_nm\n"
  set mv_set(fllt_nm)   $fllt_nm
  set mv_set(fllt_info) $fllt_info
  #scrib_lib_exec_interrupt check [incr i] [expr $ntotal+3]
  interrupt check [incr i] [expr $ntotal+3]
  ic_meshdirect_fillet_continues $fllt_type
  #scrib_lib_exec_interrupt check [incr i] [expr $ntotal+3]
  interrupt check [incr i] [expr $ntotal+3]
  
  if {$fllt_type == 0 } {
     set crv_pair $mv_set(crv_mdl_p)
     set crv_list $mv_set(crv_mdl_lst)
     set rtrn_srf $mv_set(grp_srf_mdl)
     }
  if {$fllt_type == 1 } {
       set crv_pair $mv_set(crv_sng_p)
       set crv_list $mv_set(crv_sng_lst)
       set rtrn_srf $mv_set(grp_srf_sng)
     }
  if {$fllt_type == 2 } {
       set crv_pair $mv_set(crv_cls_p)
       set crv_list $mv_set(crv_cls_lst)
       set rtrn_srf $mv_set(grp_srf_cls)
     }
  if {$fllt_type == 3 } {
     set crv_pair [concat $mv_set(crv_sng_p)   $mv_set(crv_cls_p)]
     set crv_list [concat $mv_set(crv_sng_lst) $mv_set(crv_cls_lst)]
     set rtrn_srf [list $mv_set(grp_srf_sng) $mv_set(grp_srf_cls)]
     }   
  if {$param == 1} {  
     ic_meshdirect_set_param_crvs $crv_list $msh_lmt
     #scrib_lib_exec_interrupt check [incr i] [expr $ntotal+3]
     interrupt check [incr i] [expr $ntotal+3]
     ic_meshdirect_set_param_crvs_prll $crv_pair
     }
  #scrib_lib_exec_interrupt finish
  interrupt finish
  busy reset
  return $rtrn_srf
}

## Needs doc

proc ic_meshdirect_fillet_find {a_min a_max l_min {surfs ""}} {
global mv_set interrupt_pending
  set mv_set(srf_nm)   ""
  set mv_set(srf_info) ""
  set mv_set(arc_nm)   ""
  set mv_set(arc_info) ""
  set mv_set(fllt_nm)  ""
  set crvs             ""
  set arc_nm           ""
  set arc_info         ""
  if {$surfs == ""} {set surfs [ic_geo_get_objects surface "" ] }
  mess "Scaning geometry for fillets ...\n" blue
  #scrib_lib_exec_interrupt init
  interrupt init
  set interrupt_pending 0
  set ntotal [llength $surfs]
  set ntt 0
  foreach srf $surfs {
    #scrib_lib_exec_interrupt check $ntt $ntotal
    interrupt check $ntt $ntotal
    incr ntt
    if {$interrupt_pending == 1} {
       #scrib_lib_exec_interrupt finish
       interrupt finish
       return 0
    }
    set srf_angl [ic_surface_curvature $srf]
    if {$srf_angl > -5 && $srf_angl < 5} continue
    catch {ic_geo_boundary surface $srf 1 1} bnd
    if {$bnd == ""} continue
    set len [llength $bnd]
    if  {$len > 4} {
        set oppst [ic_meshdirect_find_opposite_side $srf $bnd]
        if {$oppst == ""} {
           set sds "Error"
           } else {set sds [list $len $oppst]}
        } else {
          set sds [list $len $bnd]
          }
    foreach cr $bnd {
      if {[lsearch $crvs $cr] == -1} {
         lappend crvs $cr
#         if {$mv_set(old_way) == 0} {
		set arc [ic_meshdirect_fillet_find_arc $cr $a_min $a_max $l_min]
#	    } else {
#		set arc [scrib_lib_fillet_find_arc_old $cr $a_min $a_max $l_min]
#            }

         if {$arc != 0} {
            lappend arc_nm   $cr
            lappend arc_info $arc
            }
         }
      }
    lappend srf_nm   $srf
    lappend srf_info $sds
    }
  #scrib_lib_exec_interrupt finish
  interrupt finish
  if {$arc_nm == "" || $arc_info == ""} {return 0}
  set mv_set(srf_nm)   $srf_nm
  set mv_set(srf_info) $srf_info
  set mv_set(arc_nm)   $arc_nm
  set mv_set(arc_info) $arc_info
}

## Needs doc

proc ic_meshdirect_fillet_find_arc {cr a_min a_max l_min {tol -1}} {
global mv_set
 # Mod --VG 06/23/06
 # tol[erance] parameter is relative to curve length 
  set ret_val 0
  set lng [ic_geo_crv_length $cr]
  set rel_tol [expr $tol * $lng]
   if [ic_geo_crv_is_arc $cr $rel_tol] {return $ret_val}
  if {$lng < $l_min} {return $ret_val}
  set fam   [ic_geo_get_family curve $cr]
  foreach i "0 1 2" {
     set p_$i [ic_geo_cre_pnt_on_crv_at_par $fam "" [expr $i*0.5] $cr]
     set l_$i [ic_geo_get_point_location [subst $[subst p_$i]]]
     }
  ic_virtual define point cnt1 "$p_0 $p_1 $p_2 radius 0 angle 0 offset 0"
  set cnt [lindex [ic_virtual check point cnt1] 0]
  if ![scrib_lib_math_is_point $cnt] {
      ic_delete_geometry point names "$p_0 $p_1 $p_2" 0
      return $ret_val
      }

  set v1   [scrib_lib_math_vector_sub $l_0 $cnt]
  set v2   [scrib_lib_math_vector_sub $l_2 $cnt]
  set ang  [expr [scrib_lib_math_angle_between_vectors $v1 $v2]/0.017453292]
  set rds  [scrib_lib_math_vector_length [scrib_lib_math_vector_sub $cnt $l_0]]
  if {$ang > $a_min && $ang < $a_max} {
     set ret_val [list $rds $ang $lng]
     lappend ret_val $cnt
     }
 
  ic_delete_geometry point names "$p_0 $p_1 $p_2" 0
  return $ret_val
}

## Needs doc

proc ic_meshdirect_fillet_find_by_arc {{surfs ""} {l_min 1} {l_max  20} {min_curvature 15} \
	 {max_srf_area 5000} {max_perim 2000} {fllt_type 2} {tol -1}}  {
 # Mod --VG 06/23/06
 # tol[erance] parameter is relative to curve length 
 #
    ic_mess "Scaning geometry for fillets ...\n" 
    if {$surfs == ""} {set surfs [ic_geo_get_objects surface "" ] }
    set crvs ""
    foreach s $surfs {
	set crvs [concat $crvs [ic_geo_boundary surface $s 1 1]]
    }
    set crvs [lsort -unique $crvs]
    set arcs ""
    set pfillet ""
    foreach c $crvs {
		set lng [ic_geo_crv_length $c]
		set rel_tol [expr $tol * $lng]
		if ![ic_geo_crv_is_arc $c $rel_tol] continue
		if {$lng < $l_min || $lng > $l_max} continue
	lappend arcs $c
	foreach s [ic_geo_incident curve $c 1] {
	    if {[ic_surface_curvature $s] < $min_curvature} continue
	    if {[ic_geo_srf_area $s] > $max_srf_area} continue
	    lappend pfillet $s
	}
    }
    set pfillet [lsort -unique $pfillet]
    set p2fillet ""
    #remove fillet surfaces with inner holes
    foreach p $pfillet {
	if {[ic_geo_boundary surface $p 0 1] != [ic_geo_boundary surface $p 1 1]} continue
	lappend p2fillet $p
    }
    if {$fllt_type == 1} {return $p2fillet}

    set fillet_regions ""
    set regions [ic_geo_make_conn_regions surface $p2fillet]
    while {[llength $regions] > 0} {
#mess "regions are $regions\n"
    	set region [lindex $regions 0]
	set regions [lreplace $regions 0 0]
	set out_in [ic_geo_find_internal_outer_loops $region]
	set inner [lindex $out_in 1]
	if {$inner == ""} {continue}
	set inner_pts ""
	foreach c $inner {set inner_pts [concat $inner_pts [ic_geo_boundary curve $c 0 1]]}
	set inner_pts [lsort -unique $inner_pts]
	set loop ""
	foreach s $region {
	    foreach c [ic_geo_boundary surface $s 0 1] {
		foreach p [ic_geo_boundary curve $c 0 1] {
		    if {[lsearch $inner_pts $p] != -1} {lappend loop $s}
		}
	    }
	}
          set loop [lsort -unique $loop]
	set new_regions [ic_geo_make_conn_regions surface $loop]
	if {[llength $new_regions] > 1} {
	    set regions [concat $regions $new_regions]
	    continue
	} 
	if  {[llength $loop] < [llength $region]} {
	    set out_in [ic_geo_find_internal_outer_loops $loop]
	    set inner [lindex $out_in 1]
	    if {$inner == ""} {
		mess "loop $loop is getting dissolved\n"
		continue
	    }	    		
	}
	# need to check for max perimeter of loop, and 
	# if there are more than 2 sharp angles
	set outer [lindex $out_in 0]
	#mess "outer is $outer\n" green
	set outer_pts ""
	foreach c $outer {set outer_pts [concat $outer_pts [ic_geo_boundary curve $c 0 1]]}
	set outer_pts [lsort -unique $outer_pts]
	set length 0
	foreach o $outer {set length [expr $length + [ic_geo_crv_length $o]]}
	if {$length > $max_perim} {continue}
	set sharp_corners 0
	set bad_surfs_list ""
	set bad_corners ""
	foreach p $outer_pts {
	    set crvs [ic_geo_incident point $p 1]
	    set cc ""
	    foreach c $crvs {
		if {[lsearch $outer $c] == -1} continue
		lappend cc $c
	    }
	    if {[llength $cc] != 2} {
		mess "bad assumption is being made... skipping\n" red
		set sharp_corners 4
		break
	    }
	    set angle [ic_meshdirect_find_angle_between_curves \
		[lindex $cc 0]  [lindex $cc 1] $p] 
	    if {($angle < 30) || ($angle > 150) } {continue}
	    #mess "angle is $angle\n"
	    incr sharp_corners
	    lappend bad_corners $p
	}
	if {$sharp_corners > 2} {
	    #The following removes hanging surfaces.  Should probably make this a special proc...
	    set nogo 1
	    if {$sharp_corners == 4} {
		set all ""
		foreach p $bad_corners {
		    set current ""
		    foreach c [ic_geo_incident point $p 1] {
			foreach s [ic_geo_incident curve $c 1] {
			    if {[lsearch $p2fillet $s] == -1} continue
			    if {[lsearch $current $s] != -1} continue
			    lappend current $s
			    lappend all $s
			}
		    }
		}
		 foreach a [lsort -unique $all] {
		     set iii 0
		     foreach aa $all {
			if {$a == $aa} {incr iii} 
		    }
		    if {$iii == 4} {
			set loop2 [lappend loop $a]
			set loop2 [ic_list_remove_duplicated $loop2]
			set out_in [ic_geo_find_internal_outer_loops $loop2]
			set inner2 [lindex $out_in 1]
			if {$inner2 == ""} {break}
			set inner $inner2
			set loop $loop2
			set outer [lindex $out_in 0]
			mess "surface $a seems to be a hanging fillet surface... Removing\n"
			set nogo 0
			break
		    } 
		}		    
		if $nogo {
		    mess "bad_corners are $bad_corners\n" blue
		    continue		
		}
	     } else {
#mess "bad_corners are $bad_corners\n" blue
		continue
	    }
	}
	if {$fllt_type == 2} {
	    set exclusion_surfs ""
	    foreach sss [ic_geo_get_objects surface ""] {
		if {[lsearch $surfs $sss] == -1} { lappend exclusion_surfs $sss }
	    }
	    set new_surfs ""
	    foreach in [ic_meshdirect_make_conn_loops $inner] {
		set new_surfs [concat $new_surfs [ic_geo_find_internal_surfaces $in \
		    $loop $outer $exclusion_surfs]]
	    }
	    lappend fillet_regions [concat $loop $new_surfs]
	} else {
	    lappend fillet_regions $loop
	}
    }
    return $fillet_regions
}


## Needs doc

proc ic_meshdirect_fillet_continues {fllt_type} {
global mv_set

  set arc_nm    $mv_set(arc_nm)
  set srf_nm    $mv_set(srf_nm)
  set fllt_nm   $mv_set(fllt_nm)
  set arc_info  $mv_set(arc_info)
  set srf_info  $mv_set(srf_info)
  set fllt_info $mv_set(fllt_info)
  set mv_set(crv_list) ""
  set srf_set   ""
  set tri_lst   ""
  set tri_par   ""
  set tri_nm    ""
  set sng_nm    ""
  set crv_sng_p ""
  set crv_cls_p ""
  set crv_mdl_p ""
  for {set i 0} {$i < [llength $fllt_nm]} {incr i} {
    set srf   [lindex $fllt_nm   $i]
    set inf   [lindex $fllt_info $i]
    if {[lsearch $srf_set $srf] != -1} continue  
    set grp_srf_nm $srf
    set n_crv [lindex $inf 0]
    if {$n_crv < 4} continue
    set crv_f [lindex $inf 1]
    foreach s "0 1" {
      set ss  [expr $s+2]
      set plc [lsearch $srf_nm $srf]
      set bnd [lindex [lindex $srf_info $plc] 1]
      set c_i [lindex $bnd $s]
      set c_j [lindex $bnd $ss]
      
      if {[lindex $crv_f $s] == 1 && [lindex $crv_f $ss] == 1} {
         if  {[llength $c_i] != 1 || [llength $c_j] != 1} continue
         lappend crv_${i}_$s $c_i $c_j
         set ind 1
         foreach sd "0 1" {
           set sngl_$sd 0
           if {$ind == -2} {continue} else {set ind 1}
           set fllt_cls 0
           set crv_p [list "$c_i $c_j"]
           set cr [lindex "$c_i $c_j" $sd] 
           set srj [ic_geo_incident curve $cr 1]
           set plc [lsearch $srj $srf]
           set srj_old $srj
           set srj [lreplace $srj $plc $plc]
           if {[llength $srj] == 0} {lappend sng_nm $srj_old; set sngl_$sd 1} 
           if {[llength $srj] != 1} continue
           if {$srj != ""} {lappend grp_srf_nm $srj}
           while {$ind > 0} {
             if {[lsearch $fllt_nm $srj] == -1} {set ind 0; continue}
             set plc  [lsearch $srf_nm $srj]
             if {[lindex [lindex $srf_info $plc] 0] == 3} {
                if {[lsearch $tri_nm $srj] == -1} {lappend tri_nm $srj}
                lappend tri_lst $grp_srf_nm
                lappend tri_crv [subst $[subst crv_${i}_$s]]
                set ind 0
                continue
                }
             
             set bnd  [lindex [lindex $srf_info $plc] 1]
             set pl_i [lsearch $bnd $cr]
             if {$pl_i == -1} {set ind 0; continue}
             if {$pl_i < 2} {
                set pl_j [expr $pl_i+2]
                } else {
                  set pl_j [expr $pl_i-2]
                  }
             set crj [lindex  $bnd $pl_j]
             if {$crj == $c_j} {set ind -2; set fllt_cls 1; continue}
             set plj [lsearch $arc_nm $crj]
             if {$plj == -1} {set ind 0; continue}
             set pair [lreplace $bnd $pl_i $pl_i]
             set nw_j [lsearch  $pair $crj]
             set pair [lreplace $pair $nw_j $nw_j]
             lappend crv_p    $pair 
             lappend crv_${i}_$s $crj
             set sri [ic_geo_incident curve $crj 1]
             set plc [lsearch $sri $srj]
             set srj_old $srj
             set srj [lreplace $sri $plc $plc]
             if {$srj != ""} {lappend grp_srf_nm $srj}
             set cr  $crj
             if {[llength $srj] == 0} {lappend sng_nm $srj_old; set sngl_$sd 1}
             if {[llength $srj] != 1} {set ind 0; continue}
             incr ind
             if {$ind > 1000} {set ind 0}
             }
           }
           if {$fllt_cls == 1} {
              set crv_nm     crv_cls_p
              set crv_nm_lst crv_cls_lst
              lappend grp_srf_cls $grp_srf_nm 
              if {$fllt_type == 2 || $fllt_type == 3} {
                 set srf_set [concat $srf_set $grp_srf_nm]
                 }
              } else {
                if {$sngl_0 == 1 && $sngl_1 == 1} {
                   set crv_nm     crv_sng_p
                   set crv_nm_lst crv_sng_lst
                   lappend grp_srf_sng $grp_srf_nm
                   if {$fllt_type == 1 || $fllt_type == 3} {
                      set srf_set [concat $srf_set $grp_srf_nm]
                      }
                   } else {
                     set crv_nm     crv_mdl_p 
                     set crv_nm_lst crv_mdl_lst
                     lappend grp_srf_mdl $grp_srf_nm
                     if {$fllt_type == 0} {
                        set srf_set [concat $srf_set $grp_srf_nm]
                        }
                     }
                }
           set $crv_nm [concat [subst $[subst $crv_nm]] $crv_p]
           if [info exist crv_${i}_0] {
	      if {[subst $[subst crv_${i}_0]] == ""} break
	         lappend $crv_nm_lst [subst $[subst crv_${i}_0]]
	         }
	   if [info exist crv_${i}_1] {
	      if {[subst $[subst crv_${i}_1]] == ""} break
	      lappend $crv_nm_lst [subst $[subst crv_${i}_1]] 
              }
           }
        }
    }
    foreach nm "cls sng mdl" {
       if [info exist crv_${nm}_p] {
          set mv_set(crv_${nm}_p) [subst $[subst crv_${nm}_p]]
          } else {set mv_set(crv_${nm}_p) ""}
       if [info exist crv_${nm}_lst] {
          set mv_set(crv_${nm}_lst) [subst $[subst crv_${nm}_lst]]
          } else {set mv_set(crv_${nm}_lst) ""}
       if [info exist grp_srf_$nm] {
          set mv_set(grp_srf_$nm) [subst $[subst grp_srf_$nm]]
          } else {set mv_set(grp_srf_$nm) ""}
       }
  set mv_set(a) $tri_lst
  if {$tri_nm != ""} {
     set tri_grp [ic_meshdirect_fillet_continues_tri $tri_lst $tri_nm $sng_nm $tri_crv $fllt_type]
     }
}

## Needs doc

proc ic_meshdirect_fillet_continues_tri {tri_lst tri_nm sng_nm tri_crv fllt_type} {
global mv_set
   set tri_tmp ""
   set cls_tri_srf ""
   set sng_tri_srf ""
   for {set i 0} {$i < [expr [llength $tri_lst]-1]} {incr i} {
      set lst_i [lindex $tri_lst $i]
      for {set j [expr $i+1]} {$j < [llength $tri_lst]} {incr j} {
         set lst_j [lindex $tri_lst $j]
         set chck 0
         foreach m $lst_i {
           if {[lsearch $lst_j $m] == -1} break
           set chck 1
           }
           if {$chck == 1} break
         }
      if {$chck == 0} {
         lappend tri_tmp $lst_i
         lappend tri_tcr [lindex $tri_crv $i]
         }
      }
   set tri_sng_lst ""
   set tri_mid_lst ""
   for {set i 0} {$i < [llength $tri_tmp]} {incr i} {
      set mid_srf ""
      set tri_srf ""
      set sng_chck 0
      foreach m [lindex $tri_tmp $i] {
         if {[lsearch $tri_nm $m] == -1} {
            lappend mid_srf $m} else {lappend tri_srf $m}
         if {[lsearch $sng_nm $m] != -1} {set sng_chck 1}
         }
      if {$sng_chck == 1 && [llength $tri_srf] == 1} {
         lappend sng_tri_srf $tri_srf
         lappend sng_mid_srf $mid_srf
         lappend tri_sng_crv [lindex $tri_tcr $i]
         } 
      if {[llength $tri_srf] == 2}   {
         lappend cls_tri_srf $tri_srf
         lappend cls_mid_srf $mid_srf
         lappend tri_cls_crv [lindex $tri_tcr $i]
         }
      }

    set tri_done ""
    if {$fllt_type != 1} {
      for {set i 0} {$i < [expr [llength $cls_tri_srf]-1]} {incr i} {
        set tmp $cls_tri_srf
        set srf [lindex [lindex $cls_tri_srf $i] 0]
        set srj [lindex [lindex $cls_tri_srf $i] 1]
        if {[lsearch $tri_done $srf] != -1} continue
        set tris [list $srf $srj]
        set tmp [lreplace $tmp $i $i 0]
        set srf_grp [concat $srf [lindex $cls_mid_srf $i]]
        set crv_grp [lindex $tri_cls_crv $i]
        while 1 {
            set srch -1
            for {set j 0} {$j < [llength $tmp]} {incr j} {
              set lst [lindex $tmp $j]
              set srch [lsearch $lst $srf]
              if {$srch != -1} {
                 if {$srch == 0} {set srf [lindex $lst 1]} else {set srf [lindex $lst 0]}
                 set tmp [lreplace $tmp $j $j 0]
                 set srf_grp [concat $srf_grp [lindex $cls_mid_srf $j] $srf]
                 set crv_grp [concat $crv_grp [lindex $tri_cls_crv $j]]
                 lappend tris $srf
                 break
                 }
              }
            if {$srf == $srj} {
               set tri_done [concat $tri_done $tris]
               foreach s $srf_grp {
                  if {[lsearch $tri_nm $s] != -1} continue
                  set plc  [lsearch $mv_set(srf_nm) $s]
                  set crvs [lindex [lindex $mv_set(srf_info) $plc] 1]
                  set pair ""
                  foreach c $crvs {
                     if {[lsearch $crv_grp $c] == -1} {lappend pair $c}
                     }
                  lappend mv_set(crv_cls_p) $pair
                  }
               
	       lappend mv_set(crv_cls_lst) $crv_grp
               lappend mv_set(grp_srf_cls) $srf_grp
               break}
            if {$srch == -1} break
            }
        }
     }
#set tri_done ""

   if {$fllt_type != 2} {
       for {set i 0} {$i < [expr [llength $sng_tri_srf]-1]} {incr i} {
         set tmp $cls_tri_srf
         set tsg $sng_tri_srf
         set srf [lindex $sng_tri_srf $i]
         if {[lsearch $tri_done $srf] != -1} continue
         set tsg [lreplace $tsg $i $i 0]
         set tris $srf
         set srf_grp $srf
         set crv_grp ""
         for {set k 0} {$k < [llength $sng_tri_srf]} {incr k} {
            if {[lindex $sng_tri_srf $k] == $srf} {
               set srf_grp [concat $srf_grp [lindex $sng_mid_srf $k]]
               set crv_grp [concat $crv_grp [lindex $tri_sng_crv $k]]
               }
            }
         while 1 {
             set srch -1
             for {set j 0} {$j < [llength $tmp]} {incr j} {
               set lst [lindex $tmp $j]
               set srch [lsearch $lst $srf]
               if {$srch != -1 || [lsearch $sng_tri_srf $srf] == -1} {
                  if {$srch == 0} {set srf [lindex $lst 1]} else {set srf [lindex $lst 0]}
                  set tmp [lreplace $tmp $j $j 0]
                  set srf_grp [concat $srf_grp [lindex $cls_mid_srf $j] $srf]
                  set crv_grp [concat $crv_grp [lindex $tri_cls_crv $j]]
                  lappend tris $srf
                  break
                  }
               }
             if {[lsearch $tsg $srf] != -1} {
                for {set k 0} {$k < [llength $sng_tri_srf]} {incr k} {
		  if {[lindex $sng_tri_srf $k] == $srf} {
		     set srf_grp [concat $srf_grp [lindex $sng_mid_srf $k]]
                     set crv_grp [concat $crv_grp [lindex $tri_sng_crv $k]]
		     }
                  }
                set tri_done [concat $tri_done $tris]
                foreach s $srf_grp {
                   if {[lsearch $tri_nm $s] != -1} continue
                   set plc  [lsearch $mv_set(srf_nm) $s]
                   set crvs [lindex [lindex $mv_set(srf_info) $plc] 1]
                   set pair ""
                   foreach c $crvs {
                      if {[lsearch $crv_grp $c] == -1} {lappend pair $c}
                      }
                   lappend mv_set(crv_sng_p) $pair
                   }
                
 	        lappend mv_set(crv_sng_lst) $crv_grp
                lappend mv_set(grp_srf_sng) $srf_grp
                break}
             if {$srch == -1} break
             }
         }
     }
 
}

## Needs doc

proc ic_meshdirect_set_param_crvs_prll {crv_p} {
global mv_set
  
  foreach grp $crv_p {
    if {[llength [lindex $grp 0]] != 1} continue
    if {[llength [lindex $grp 1]] != 1} continue
    foreach i "0 1" {
       set lng [ic_geo_crv_length [lindex $grp $i]]
       if {$lng == 0} {set lng [ic_geo_feature_size curve [lindex $grp $i]]}
       set lng_$i $lng
       set param  [ic_get_meshing_params curve [lindex $grp $i]]
       set plc    [expr [lsearch  $param "emax"]+1]
       set par    [lindex  $param $plc]
       if {$par == 0 || $par == ""} {
          set n_cl 1
          } else { 
            set len [subst $[subst lng_$i]]
            set n_cl   [expr $len/double($par)]
            }
       set n_$i  [expr round($n_cl)]
       } 
    set n   [lindex [lsort -real [list $n_0  $n_1]] end]
    set m_0 [lsearch $mv_set(crv_msh) [lindex $grp 0]]
    set m_1 [lsearch $mv_set(crv_msh) [lindex $grp 1]]
    if  {$m_0 != -1 && $m_1 == -1} {set n $n_0}
    if  {$m_0 == -1 && $m_1 != -1} {set n $n_1}
    if  {$m_0 != -1 && $m_1 != -1} continue
    if !$n {set n 1}
    set par_0 [expr $lng_0/double($n)]
    set par_1 [expr $lng_1/double($n)]
    ic_set_meshing_params curve [lindex $grp 0] emax $par_0
    ic_set_meshing_params curve [lindex $grp 1] emax $par_1
    }
}

#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-
proc ic_meshdirect_set_param_crvs {crv_list msh_lmt} {
global mv_set

  set crv_msh ""
  foreach grp $crv_list {
    if {[llength $grp] == 1} continue
    set avr 0
    set num 1
    foreach crv $grp {
      if {[llength $crv] > 1} { 
         set len 0 
         foreach c $crv {
           set  plc  [lsearch $mv_set(arc_nm) $c]
           set  len  [expr [lindex [lindex $mv_set(arc_info) $plc] 2]+$len]
           }
         lappend tot_l $crv $len
         } else {
           set  plc  [lsearch $mv_set(arc_nm) $crv]
           set  len  [lindex [lindex $mv_set(arc_info) $plc] 2]
           }
      if ![scrib_lib_math_is_int_real $len] continue
      set  avr  [expr ($avr+$len)/double($num)]
      incr num
      }
    if ![scrib_lib_math_is_int_real $avr] continue
    foreach i $msh_lmt {
      set min [lindex [lindex $i 0] 0] 
      set max [lindex [lindex $i 0] 1] 
      if {$avr > $min && $avr <= $max} {
         set n_e [lindex $i 1]
         foreach crv $grp {
           if {[llength $crv] > 1} {
              set plc [lsearch $tot_l $crv]
              if {$plc == -1} continue
              set t_l [lindex $tot_l [expr $plc+1]]
              foreach c $crv {
	        set  plc  [lsearch $mv_set(arc_nm) $c]
	        set  len  [lindex [lindex $mv_set(arc_info) $plc] 2]
	        if   ![scrib_lib_math_is_int_real $len] continue
	        set  dif  [expr $n_e*$len/double($t_l)]
	        set  par  [expr $len/$dif]
	        ic_set_meshing_params curve $c emax $par
	        lappend crv_msh $c
                }
              } else {
                set  plc  [lsearch $mv_set(arc_nm) $crv]
	        set  len  [lindex [lindex $mv_set(arc_info) $plc] 2]
	        set  par  [expr $len/double($n_e)]
                ic_set_meshing_params curve $crv emax $par
                lappend crv_msh $crv
                }
           }
         break
         }
      }
    }
  set mv_set(crv_msh) $crv_msh
}

##Needs doc

proc ic_meshdirect_find_opposite_side {srf {bnd ""} {ret 0}} {
    
    if {"" == $srf} { return "" }

    if {$bnd == ""} { set bnd [ic_geo_boundary surface $srf 1 1] }
    
    if {[llength $bnd] < 4} { return }
    
    for {set i 0} {$i < [llength $bnd]} {incr i} {
	set j [expr $i+1]
	if {$j == [llength $bnd]} { set j 0 }
	set p_l1 [ic_geo_boundary curve [lindex $bnd $i] 0 1]
	set p_l2 [ic_geo_boundary curve [lindex $bnd $j] 0 1]
	foreach p $p_l1 {
	    if {[lsearch $p_l2 $p] != -1} {
		set uv [ic_geo_find_nearest_srf_pnt $srf $p]
		if {$uv == "" || [llength $uv] != 2} return
		lappend p_nm $p
		lappend l_uv $uv
            }
	}
    }
    
    if ![info exists p_nm] { busy reset ; return }
    if {[llength $p_nm] != [llength $bnd]} { return }
    if {[llength $p_nm] < 4} { return }
    for {set i 0} {$i < [expr [llength $bnd]-1]} {incr i} {
	for {set j [expr $i+1]} {$j < [llength $bnd]} {incr j} {
	    set d_x [expr [lindex [lindex $l_uv $i] 0]-[lindex [lindex $l_uv $j] 0]]
	    set d_y [expr [lindex [lindex $l_uv $i] 1]-[lindex [lindex $l_uv $j] 1]]
	    lappend dis_l [list "$i $j" [expr sqrt(pow($d_x,2)+pow($d_y,2))]]
	}
    }
    set max_d [lsort -real -decreasing -index 1 $dis_l]
    set pl_1  [lindex [lindex [lindex $max_d 0] 0] 0]
    set pl_3  [lindex [lindex [lindex $max_d 0] 0] 1]
    set i 1
    while {$i < [llength $bnd]} {
	set pl_2 [lindex [lindex [lindex $max_d $i] 0] 0]
	set pl_4 [lindex [lindex [lindex $max_d $i] 0] 1]
	if  {$pl_1 == $pl_2 || $pl_1 == $pl_3 || $pl_1 == $pl_4 || \
		 $pl_2 == $pl_3 || $pl_2 == $pl_4 || $pl_3 == $pl_4} {
	    incr i 
	    if {$i == [llength $bnd]} return
	} else break
    }
    set l_srt [lsort -real [list $pl_1 $pl_2 $pl_3 $pl_4]]
    foreach i "1 2 3 4" {
	set indx_$i [lindex $l_srt [expr $i-1]]
    }
    
    set sd_1  [lrange $bnd [expr $indx_1+1] $indx_2]   
    set sd_2  [lrange $bnd [expr $indx_2+1] $indx_3]   
    set sd_3  [lrange $bnd [expr $indx_3+1] $indx_4] 
    set sd_4a [lrange $bnd [expr $indx_4+1] end]
    set sd_4b [lrange $bnd 0 $indx_1]
    set sd_4  [concat $sd_4a $sd_4b]   
    
    set p_1 [lindex $p_nm $indx_1]
    set p_2 [lindex $p_nm $indx_2]
    set p_3 [lindex $p_nm $indx_3]
    set p_4 [lindex $p_nm $indx_4]
    if $ret {
	return [list $p_1  $sd_1 $p_2 $sd_2 $p_3 $sd_3 $p_4 $sd_4]
    } else {
        return [list $sd_1 $sd_2 $sd_3 $sd_4]
    }
}


## Needs doc

proc ic_meshdirect_find_angle_between_curves {crv1 crv2 {pnt ""}} {
    
    if {$pnt == ""} {
	if 0 {
	    foreach pt [ic_geo_boundary curve $crv1 0 1] {
		if {[lsearch [ic_geo_boundary curve $crv2 0 1] $pt] != -1} {set pnt $pt}
	    }
	} else {
	    # should be faster --jka
	    set pts1 [lsort [ic_geo_boundary curve $crv1 0 1]]
	    set pts2 [lsort [ic_geo_boundary curve $crv2 0 1]]
	    foreach p $pts2 {
		if {0 <= [lsearch $pts1 $p]} {
		    set pnt $p
		    break
		}
	    }
	}
    }
    
    if {$pnt == ""} { return "" }
    
    set t_par1 [ic_geo_find_nearest_crv_pnt $crv1 $pnt]
    set t_par2 [ic_geo_find_nearest_crv_pnt $crv2 $pnt]
    set tangent1 [ic_geo_get_crv_tan $t_par1 $crv1]
    set tangent2 [ic_geo_get_crv_tan $t_par2 $crv2]
    #mess "t_par1 is $t_par1, t_par2 is $t_par2\n" blue
    #mess "tangent1 is $tangent1 tangent2 is $tangent2\n" green
    set angle [scrib_lib_math_angle_between_vectors $tangent1 $tangent2]
    
    return [expr $angle / 3.14 * 180]
}





