#
# --> if the name of the first proc already exists in interp, return
#
if {"" != [info commands scrib_lib_geo_import_mesh]} { return }
#
# --> procs in this file depend on the following scrib/lib/ files--source them
#     I guess we could do this by proc, too, not sure waht's best
#
if 0 {
    # none required yet
    set required_files ""
    scrib_lib_setup_source_files $required_files
}
#----------------------------------------------------------------------------

## import the given domain file <em>file</em> to geometry and,
## optionally, save & unload that geometry to the name <em>savefile</em>.

proc scrib_lib_geo_import_mesh {file {savefile ""}} {
    #
    # Read in mesh as geom
    #
    ic_geo_import_mesh $file 1 0
    #
    # and adjust family names to match the mesh.
    # for the above command moves "FAM" to "FAM.1"
    #
    foreach fam [ic_geo_list_families] {
	#
	# skip "ORFN*"
	#
	if ![string equal -nocase -length 4 $fam "ORFN"] {
	    #
	    # this strips the ".1" from the "FAM.1" created for "FAM"
	    #
	    ic_geo_rename_family $fam [file root $file]
	    #mess "-->DEBUG fam=$fam; file_root:[file root $file]\n"
	}
    }
    #
    # if savefile is specifed, save the meshobj and unload it
    #
    if {("" != $savefile) && [ic_geo_is_loaded]} {
	ic_save_tetin $savefile
	ic_unload_tetin
	mess "scrib_lib_geo_import_mesh: saved tin file $savefile\n"
    }
}

## get the standard file extension of a given cad system

proc scrib_lib_geo_cadsys_extension_get {cadsys} {
    
    set extension ""
    switch $cadsys {
	catia  { set extension model }
	iges   { set extension igs   }
	ideas  { set extension idi   }
	ug     { set extension prt   }
	tetin  { set extension tin   }
	domain { set extension uns   }
	default {
	    mess "cannot handle cad system $cadsys\n" red
	}
    }
    return $extension
}

# for this list see ~cvs/proj/family.C:pj_get_family_meshing_params()
# or ~cvs/med/lib/med_batch/geometry_funcs.tcl:ic_geo_set_family_params: syn array
array set _scrib_meshing_params_tags {
    dev          "Maximum deviation"
    min          "Minimum size"
    width        "Width"
    height       "Height"
    size_ratio   "Ratio"
    height_ratio "Height ratio"
    max          "Max size"
    tetra_size   "Tetra size"
}

## get the verbose string for the given internal param name.

proc scrib_lib_geo_meshing_params_verbose {param} {
    global _scrib_meshing_params_tags
    
    if {![array exists _scrib_meshing_params_tags] \
	    || ![info exists _scrib_meshing_params_tags($param)]} {
	set verbose [string totitle $param]
    } else {
	set verbose "\"$_scrib_meshing_params_tags($param)\""
    }
    return $verbose
}

## get teh list of available meshing params.

proc scrib_lib_geo_meshing_params_list {} {
    global _scrib_meshing_params_tags
    
    if ![array exists _scrib_meshing_params_tags] {
	return ""
    }
    return [array names _scrib_meshing_params_tags]
}

## set the meshing parameters on the current geometry, if each exist.

proc scrib_lib_geo_meshing_params_set {} {
    global proc_mesh_param_data
    
    if ![ic_geo_is_loaded] {
	mess "could not set meshing parameters--no geomobj\n" red
	return 0
    }
    if ![array exists proc_mesh_param_data] {
	mess "could not set meshing parameters--no proc_mesh_param_data\n" red
	return 0
    }
    #mess "DEBUG: [parray proc_mesh_param_data]\n" green
    #
    # --> NB format: proc_mesh_param_data($what,$how,$token,$param) $val
    #
    foreach key [array names proc_mesh_param_data] {
	
	set split_key [split $key ","]
	
	set what  [lindex $split_key 0]
	set how   [lindex $split_key 1]
	set token [lindex $split_key 2]
	set param [lindex $split_key 3]
	set val   $proc_mesh_param_data($key)
	
	switch -- $how {
	    naspid {  set fams [scrib_lib_geo_famname_find $token] }
	    family {  set fams [get_families_with_string_token $token] }
	    name   {  set fams ""  }
	    default {
		mess "did not expect to set meshing parameters by $how!\n" red
	    }
	}
	
	switch -- $what {
	    family {
		if {"" == $fams} {
		    mess "could not get families by method $how for $what in meshing parameters!\n" red
		}
		foreach f $fams {
		    #mess "DEBUG: setting $param $val on family $f\n"
		    ic_geo_set_family_params $f $param $val
		}
	    }
	    curve - surface {
		set entities ""
		if {"" == $fams} {
		    # then get entities with the token as part of the name
		    set entities [ic_geo_lookup $what patterns "*${token}*"]
		} else {
		    # then get entities in families with the given token in their name
		    set entities [ic_geo_lookup $what families $fams]
		}
		foreach ent $entities {
		    set ent [lindex $ent 1]
		    #mess "DEBUG: setting $param $val on $what $ent\n"		    
		    ic_set_meshing_params $what $ent $param $val
		}
	    }
	    default {
		mess "did not expect to set meshing parameters on $what!\n" red
	    }
	}
    }

    return 1
}

## find the family name of in the current geo which contains the given fileid

proc scrib_lib_geo_famname_find {fileid} {
       
    if ![ic_geo_is_loaded] {
	mess "cannot lookup fam for fileid without geometry loaded\n"
	return
    }
    #
    # get the list of families from the geomobj
    #
    set geofams [ic_geo_list_families]
    #
    # see if a standardized version of the given fileid exists...
    #
    set stdfileid [scrib_lib_assembly_famname_get $fileid]
    set matchind [lsearch -glob $geofams $stdfileid]
    if {0 <= $matchind} {
	return [lindex $geofams $matchind]
    }
    #
    # see if one starts with FAM_ then the fileid
    #
    set std_fam_name [scrib_lib_assembly_famname_get $fileid] ;# "FAM_*$fileid*"
    set matchind [lsearch -glob $geofams $std_fam_name]
    if {0 <= $matchind} {
	return [lindex $geofams $matchind]
    }
    if 0 {
    #
    # if not, try one with just the fileid
    #	
	set matchind [lsearch -glob $geofams "*$fileid*"]
	if {0 <= $matchind} {
	    return [lindex $geofams $matchind]
	}
    }
    #mess "cannot find $fileid in any of the available fams\n" red
    return ""
}

## find the family name of in the current geo which contains the given fileid

proc scrib_lib_geo_famname_find_bycoords {fileid coords} {
        #
    if ![ic_geo_is_loaded] {
	mess "cannot lookup fam for fileid without mesh loaded\n"
	return ""
    }
    #
    # get the list of families from the geomobj, then
    # get a sublist of fams which containt the fileid
    #
    set geofams [ic_geo_list_families]
    set stdfamid [scrib_lib_assembly_naspid_standardize $fileid]
    set stdfamname [scrib_lib_assembly_naspid_standardize $fileid]
    if 0 {
	# this requires Tcl8.4 --jka
	set matchfams [lsearch -all -inline -glob  $geofams "*$fileid*"]
    } else {
	set matchfams ""
	foreach gf $geofams {
	    if 0 {
		if {[string match *$fileid* $gf] \
			|| [string match *$stdfamid* $gf]} {
		    lappend matchfams $gf
		}
	    } else {
		if [string match $stdfamname $gf] {
		    lappend matchfams $gf
		}
	    }
	}
    }
    #
    # get the family with the surface nearest to coords
    #
    set mindistfam ""
    set mindist [scrib_lib_math_dbl_max]
    foreach mf $matchfams {
	set dist [scrib_lib_geo_distance_from_surfaces $mf $coords]
	if {$dist < $mindist} {
	    set mindistfam $mf
	    set mindist $dist
	}
    }
    #
    # return the family with the nearest projection
    #
    return $mindistfam
}

## get the dist of coords from the nearest surface in <em>surface_family</em>.

proc scrib_lib_geo_distance_from_surfaces {surface_families coords {surfaces ""}} {
 
   set surfs $surfaces   
   foreach fam $surface_families {
	set surfs [concat $surfs [ic_geo_get_objects surface $fam]]
   }
    if {"" == $surfs} {
	#mess "no surfaces in family $surface_family\n"
	return [scrib_lib_math_dbl_max]
    }
    set coords_proj [ic_geo_project_coords surface $surfs $coords {0 0 0}]
    if {"" == $coords_proj} {
	mess "could not project coords $coords to surface family $surface_family\n"
	return [scrib_lib_math_dbl_max]
    }
    return [scrib_lib_math_dist_get $coords $coords_proj]
}

## get nearest surface

proc scrib_lib_geo_nearest_surface {coords} {
    set data [ic_geo_nearest_object surface $coords]
    set surface [lindex $data 0]
    return $surface
}

## get nearest surface from list of surfaces...  this should be combined with above proc.

proc scrib_lib_geo_nearest_surface_list {coords surfaces} {
    set surf_dist ""
    foreach s $surfaces {
	lappend surf_dist [list $s [scrib_lib_geo_distance_from_surfaces "" $coords $s]]
    }
    return [lindex [lindex [lsort -index 1 -real $surf_dist] 0] 0]
}

## get the dist of coords from the nearest surface in <em>surface_family</em>.

proc scrib_lib_geo_distance_from_curves {curve_families coords {curves ""}} {
 
   foreach fam $curve_families {
	set curves [concat $curves [ic_geo_get_objects curve $fam]]
   }
    if {"" == $curves} {
	return [scrib_lib_math_dbl_max]
    }
    set coords_proj [ic_geo_project_coords curve $curves $coords {0 0 0}]
    if {"" == $coords_proj} {
	mess "could not project coords $coords to curves $curves\n"
	return [scrib_lib_math_dbl_max]
    }
    return [scrib_lib_math_dist_get $coords $coords_proj]
}

## for a list of points, get the closest surface for each point and return list of point/surface pairs

proc scrib_lib_geo_nearest_surface_point_pair {points max_dist} {
    set point_surf_list ""
    if {$points == ""} {set points [scrib_lib_geo_get_unattached_points ""]}
    foreach p $points {
	set loc [ic_geo_get_point_location $p] 
	set surface [scrib_lib_geo_nearest_surface $loc]
	set dist [scrib_lib_geo_distance_from_surfaces "" $loc $surface]
	if {$dist > $max_dist} continue
	lappend point_surf_list [list $p $surface]
    }
    return $point_surf_list
}

## get nearest curve from list of curves...  

proc scrib_lib_geo_nearest_curve_list {coords curves} {
    set curve_dist ""
    foreach c $curves {
	lappend curve_dist [list $c [scrib_lib_geo_distance_from_curves "" $coords $c]]
    }
    return [lindex [lindex [lsort -index 1 -real $curve_dist] 0] 0]
}

## get nearest point to a location...  

proc scrib_lib_geo_nearest_point_list {coords {points ""} } {
    if {$points == ""} {set points [ic_geo_get_objects point ""] }
    if {$points == ""} {
	mess "no points defined in scrib_lib_geo_nearest_point\n" red
	return
    }
    set dist_list ""
    if {[llength $coords] == 1} {set coords [lindex $coords 0]}
    foreach p $points {
	set loc [ic_geo_get_point_location $p]
	if {[llength $loc] == 1} {set loc [lindex $loc 0]}
	set dist [ic_vcalc distance $coords $loc]
#mess "loc is $loc ; coords is $coords; dist is $dist \n"
	lappend dist_list [list $p $dist]
    }
    return [lindex [lindex [lsort -index 1 -real $dist_list] 0] 0]
}

## unload and reload the current geometry object. this is a work-a-round.

proc scrib_lib_geo_unload_reload {} {
    
    if ![ic_geo_is_loaded] return
    
    set tfile "scrib_lib_geo_unload_reload.tin"
    ic_save_tetin $tfile
    ic_unload_tetin
    ic_load_tetin [list "$tfile"]
    file delete $tfile
}

## check to see whether or not the families/pids are out of synch for
## the current mesh and geometry object. if so, save, unload, reload.

proc scrib_lib_geo_synch_families {{tetinname ""} {domainname ""}} {
    
    if {![ic_geo_is_loaded] && ("" != $tetinname)} {
	ic_load_tetin [list "$tetinname"]
    }
    if ![ic_geo_is_loaded] {
	mess "scrib_error: cannot synch families without geo loaded!\n" red
	return ""
    }
    if {![ic_uns_is_loaded] && ("" != $domainname)} { ic_uns_load $domainname }
    if ![ic_uns_is_loaded] {
	mess "scrib_error: cannot synch families without mesh loaded!\n" red
	return ""
    }
    
    set details ""
    foreach f [ic_geo_list_families] {
	if {[ic_geo_lookup_family_pid $f] != [ic_uns_lookup_family_pid $f]} {
	    append details " family $f:\tgeo:[ic_geo_lookup_family_pid $f];\tuns:[ic_uns_lookup_family_pid $f]\n"
	}
    }
    if {"" != $details} {
	mess "scrib_warning: families in mesh and geom were out of synch--saving and reloading\n" red
	if {"" == $tetinname}  { set thisgeom unsynched.tin }
	if {"" == $domainname} { set thismesh unsynched.uns }
	#
	# save and unload mesh
	ic_save_unstruct $thismesh
	ic_unload_mesh
	#
	# save and unload geom
	ic_save_tetin $thisgeom
	ic_unload_tetin
	#
	# reload
	#
	ic_load_unstruct $thismesh
	ic_load_tetin [list "$thisgeom"]
	#
	#
	ic_rm $thismesh
	ic_rm $thisgeom
	append details "\n"
    }
    return $details
}

## untested proc
## returns pid

proc scrib_lib_geo_cad_to_tetin_load {cadsys model } {
    global proc_scrib_data
    #
    #
    #
    set pid 1
    #
    # --> get the pid for the file, wrt the given cadsystem
    #
    switch $proc_scrib_data(cadsys) {
        catia {
            set proc_scrib_data(pid) [scrib_lib_catia_file_pid_get $model]
        }
    }
    #
    # --> import the cad file to a tetin
    #
    set thisscript_tetinfile [file join $proc_scrib_data(dir) $proc_scrib_data(name).tin]
    set proc_scrib_data(cadfile) [file join $proc_scrib_data(cad_dir) $model]

    switch $proc_scrib_data(cadsys) {
        catia   {
            scrib_lib_catia_import $proc_scrib_data(cadfile) \
                    $thisscript_tetinfile $proc_scrib_data(layers)
        }
        default {
            #
            # try a more general command
            #
            set command "scrib_lib_$proc_scrib_data(cadsys)_import"
            if {$command == [info commands $command]} {
                $command $proc_scrib_data(cadfile) $thisscript_tetinfile
            } else {
                scrib_lib_utils_record_append "does not support cad system $proc_scrib_data(cadsys)"
                return
            }
        }
    }
    #
    # --> load the tetin
    #
    ic_load_tetin [list "$thisscript_tetinfile"]

    return $pid
}

## untested proc
## returns pid

proc scrib_lib_catia_to_tetin_load {catiafile tetinfile layers} {

    set pid [scrib_lib_catia_file_pid_get $model]

    set tetinfile [file join $proc_scrib_data(dir) $proc_scrib_data(name).tin]
    
    scrib_lib_catia_import $model $tetinfile $layers
    
    ic_load_tetin [list "$tetinfile"]
    
    return $pid
}

## use scrib_lib_assembly_filename_naspid_get instead

proc scrib_lib_geo_filename_naspid_get {filename keys nchar offset {defaultpid 1}} {
    # this proc has been moved.
    return [scrib_lib_assembly_filename_naspid_get $filename $keys $nchar $offset $defaultpid]
}

## Needs doc

proc scrib_lib_geo_find_part_boundary_single {{surfs ""}} {
    if {$surfs == ""} {
	set curves [ic_geo_get_objects curve ""]	
    } else {
	set curves ""
	foreach surf $surfs {
	    set curves [concat $curves [ic_geo_boundary surface $surf 0 1]]
	}
	set curves [lsort -unique $curves]
    }
    set single [scrib_lib_geo_get_single_curves $curves]
    set conn_regions [scrib_lib_geo_make_conn_regions curve $single]
    return [lindex [lindex [scrib_lib_geo_sort_by_crvs_length \
	$conn_regions -decreasing ] 0] 1]
}

## Get all connected curves or points to surfaces
## what is surface or curves
## entities would be surfaces if what is curve, and curves if what is point

proc scrib_lib_geo_get_connected_entities {what entities} {
    set ret ""
    switch $what {
	curve {set find surface}
	point {set find curve}
	default {
	    mess "invalid what value, must be point or curve\n" red
	    return
	}
    }
    foreach e $entities {
	set ret [concat $ret [ic_geo_boundary $find $e 0 1]]
    }
    return  [lsort -unique $ret]
}

## find unattached curves

proc scrib_lib_geo_get_unattached_curves { curves } {
    ic_geo_get_entities_by_attach_num curve 0 $curves
}

## find unattached points

proc scrib_lib_geo_get_unattached_points { points } {
   ic_geo_get_entities_by_attach_num point 0 $points
}

## find single curves

proc scrib_lib_geo_get_single_curves { curves } {
    ic_geo_get_entities_by_attach_num curve 1 $curves
}

## find double curves

proc scrib_lib_geo_get_double_curves { curves } {
    ic_geo_get_entities_by_attach_num curve 2 $curves
}


## sort curve_groups by their length.  Args is arguments for the sort.
## return is length curve pair

proc scrib_lib_geo_sort_by_crvs_length {curve_list_olists {args ""}} {
    set length_crvs ""
    foreach cl $curve_list_olists {
	set length 0
	foreach c $cl {set length [expr $length + [ic_geo_crv_length $c]]}
	lappend length_crvs [list $length $cl]
    }
    set cmd [concat  "lsort -index 0 -real " $args [list $length_crvs]]
    return [eval $cmd]    
}

## sort surfaces by their surface area.  Args is arguments for the sort.

proc scrib_lib_geo_sort_by_srf_area {surf_list {args ""}} {
    return [ic_geo_sort_by_srf_area $surf_list $args]
}

## sort surfaces by their curvature.  Args is arguments for the sort.

proc scrib_lib_geo_sort_by_curvature {surf_list {args ""}} {
    set ordered ""
    foreach s $surf_list {
	lappend ordered [list [ic_surface_curvature $s] $s]
    }
    set cmd [concat  "lsort -index 0 -real " $args [list $ordered]]
    #mess "cmd is $cmd\n"
    set ordered [eval $cmd]
    set surfs ""
    foreach s $ordered {
	lappend surfs [lindex $s 1]
    }
    return $surfs
}

## make connected loops from curves

proc scrib_lib_geo_make_conn_loops_ben {curves} {
    set loops ""
    set used ""
    set current [lindex $curves 0]
    set curves_left [lreplace $curves 0 0]
    set currentQ $current
    set current_list $current
    while {$curves_left != ""} {
	set pts [ic_geo_boundary curve $current 0 1]
	foreach p $pts {
	    foreach c [ic_geo_incident point $p 1] {
		if {[lsearch $used $c] > -1} {
		    set current_list ""
		    continue
		}
		if {([lsearch $current_list $c] == -1) && ([lsearch $curves $c] != -1)} {
		    lappend currentQ $c
		    lappend current_list $c
		    set pointer [lsearch $curves_left $c]
		    if $pointer {set curves_left [lreplace $curves_left $pointer $pointer]}
		    #mess "curves_left is $curves_left\n"
		}
	    }
	}
	set currentQ [lreplace $currentQ 0 0]
	if {$currentQ == ""} {
	    if {$current_list != ""} {
		lappend loops $current_list
	    	set used [concat $used $current_list]
	    }
	    if {$curves_left != ""} {
		set current [lindex $curves_left 0]
 		#lappend used $current
    		set curves_left [lreplace $curves_left 0 0]
    		set currentQ $current
    		set current_list $current 
	    } else { 
		return $loops
	    }
	} else {
	    set current  [lindex $currentQ 0]
	}
    }
    return $loops 
}

## make connected loops from curves 

proc scrib_lib_geo_make_conn_loops {curves} {
    return [ic_meshdirect_make_conn_loops $curves]
}

## This funciton will take a list of entities, and find connected regions.

proc scrib_lib_geo_make_conn_regions {type entities} {
    return [ic_geo_make_conn_regions $type $entities]
}

## This function will take a list of connected curves or surfaces,  and order them

proc scrib_lib_geo_order_conn_curves {curves {ret_first_last_pts 0} {start_pt ""}} {
    set ret ""
    set j [expr [llength $curves] + 1]
#Find starting point
    set pts ""
    foreach c $curves {
	set pts [concat $pts [ic_geo_boundary curve $c 0 1]]
    }
    if {($start_pt != "") && ([lsearch $pts $start_pt] == -1)} {
	mess "scrib_lib_geo_order_conn_curves called with start_pt $start_pt not attached to curves $curves\n" red
    }
    set start_end [scrib_lib_utils_list_remove_duplicated $pts]
    if {[llength $start_end] > 2} {mess "should only be 2 points as bounding $curves, but finding more... $start_end\n"}
    if {$start_pt == ""} {set start_pt [lindex $start_end 0]}
    set curr_pt $start_pt
    set used_pts $start_pt
    while {$j > 0} {
	set curr_cur not_set 
	foreach c [ic_geo_incident point $curr_pt 1] {
	    if {[lsearch $ret $c] != -1} continue
	    if {[lsearch $curves $c] == -1} continue
	    lappend ret $c
	    set curr_cur $c
	    break
	}
	if {$curr_cur == "not_set"} break
	foreach pt [ic_geo_boundary curve $curr_cur 0 1] {
	    if {[lsearch $used_pts $pt]  != -1} continue
	    lappend used_pts $pt
	    set curr_pt $pt
	    break
	}
	set j [expr $j - 1]
#mess "j is $j\n"
    }
    if $ret_first_last_pts {
	return [list $ret $start_pt $curr_pt $used_pts]
    } else {
	return $ret
    }
}

## This funciton will take a curve list (loop), and find all surfaces attached to it excluding any given exclusion_surfs

proc scrib_lib_geo_make_conn_buttons {loop {exclusion_surfs ""}} {
  return [ic_geo_make_conn_buttons $loop $exclusion_surfs]
}

proc scrib_lib_geo_internal_surface_boundary_exists {surfaces} {
    foreach surf $surfaces {
	if {[llength [ic_geo_boundary surface $surf 0 1]] != [llength [ic_geo_boundary surface $surf 1 1] ] } {return 1}
    }
    return 0
}

proc scrib_lib_geo_internal_surface_boundary {surf {not_single 0}} {
    return [ic_geo_get_internal_surface_boundary $surf $not_single]
}

## Needs doc

proc scrib_lib_geo_find_internal_surfaces { loop surrounding_surfs {outer_curves ""} {exclusion_surfs ""}} {
     return [ic_geo_find_internal_surfaces $loop $surrounding_surfs $outer_curves $exclusion_surfs]
}

proc scrib_lib_geo_find_internal_outer_loops {surfs {not_single 0} {all_boundary 0}} {
    return [ic_geo_find_internal_outer_loops $surfs $not_single $all_boundary]
}


proc scrib_lib_geo_remove_points_at_single_arc_ends {} {
    set curves [ic_geo_get_objects curve ""]	
    set single [scrib_lib_geo_get_single_curves $curves]
    foreach c $single {
	if ![ic_geo_crv_is_arc $c] {continue}
	set surf1 [ic_geo_incident curve $c 1]
	set pts [ic_geo_boundary curve $c 0 1] 
	foreach p $pts {
	    set crvs [ic_geo_incident point $p 1]
	    if {[llength $crvs] > 2} continue
	    foreach cc $crvs {
		if {$cc == $c} continue
		if {[ic_geo_incident curve $cc 1] != $surf1} continue
		ic_delete_geometry point names $p
	    }
	}
    }
}


proc scrib_lib_geo_remove_points_at_single_ends {} {
    set curves [ic_geo_get_objects curve ""]	
    set single [scrib_lib_geo_get_single_curves $curves]
    foreach c $single {
	set surf1 [ic_geo_incident curve $c 1]
	set pts [ic_geo_boundary curve $c 0 1] 
	foreach p $pts {
	    set crvs [ic_geo_incident point $p 1]
	    if {[llength $crvs] > 2} continue
	    foreach cc $crvs {
		if {$cc == $c} continue
		if {[ic_geo_incident curve $cc 1] != $surf1} continue
		ic_delete_geometry point names $p
	    }
	}
    }
}

proc scrib_lib_geo_find_dumb_points {angle {points ""} {dormant 1} } {
    if {$points == ""} {set points [ic_geo_get_objects point ""]}
    set dumb_points ""
    foreach p $points {
	set crvs [ic_geo_incident point $p $dormant]
	if {[llength $crvs] != 2} continue
	set ang [scrib_lib_feature_find_angle_between_curves [lindex $crvs 0] [lindex $crvs 1] $p] 
	if {($ang > $angle) && ($ang < [expr 180 - $angle])}  continue
	lappend dumb_points $p
    }
    return $dumb_points
}

#the below is a duplication of aie_average_thickness
proc scrib_lib_geo_average_thickness {fam} {
    set area 0.0
    set thickness 0.0
    foreach obj [ic_geo_get_objects surface $fam] {
	set th ""
	foreach {n v} [ic_get_meshing_params surface $obj] {
	    if {$n == "ehgt"} { set th $v }
	}
	if {$th != ""} {
	    set ar [ic_geo_srf_area $obj]
	    set area [expr $area + $ar]
	    set thickness [expr $thickness + $ar * $th]
	}
    }
    if {$area > 0} {
	return [expr $thickness / $area]
    } else {
	return 0
    }
}


proc scrib_lib_geo_curve_proximity_tol {curve_set1 curve_set2 tol} {
    set within_tol 0
    foreach c $curve_set1 {
	foreach cc $curve_set2 {
	    set pt [ic_geo_create_points_curveinter [list $c $cc] $tol INT]
	    if {$pt != ""} {
		ic_delete_geometry point names $pt
		set within_tol 1
		break
	    }
	}
	if $within_tol break
    }
    if $within_tol {
mess "curve_set1 is $curve_set1\n"
mess "curve_set2 is $curve_set2\n"
mess "tol is $tol\n"
mess "c is $c; cc is $cc\n"
    }
    return $within_tol
}

#====================================================
## This proc gets all multiple curves (blue) for parts defined in $part, or if empty all curves

proc scrib_lib_geo_get_multiple_curves {{part ""}} {
    set surfs [ic_geo_get_objects surface $part]
    set curves ""
    foreach s $surfs {set curves [concat $curves [ic_geo_boundary surface $s 0 1]]}
    set curves [lsort -unique $curves]
    set ret_curves ""
    foreach c $curves {if {[llength [ic_geo_incident curve $c 1]] == 3} {lappend ret_curves $c}}
    return $ret_curves
}

## This proc will take a family of surfaces (all surfaces have to be connected one to one), and give corner points
## Should be replaced/combined with scrib_lib_geo_get_corners_row_internal_surfaces
proc scrib_lib_geo_get_corners_row_surfaces { family } {
    set all_curves [ic_geo_get_objects curve $family]
    set curves [scrib_lib_geo_get_single_curves $all_curves]
    if {[llength [scrib_lib_geo_make_conn_regions curve $curves]] > 1} {
	mess "There are no corners since the feature is fully connected, returning side curves instead\n" 
	return [list sides [scrib_lib_geo_get_double_curves $all_curves]]
    }
    set points ""
    foreach c $curves {set points [concat $points [ic_geo_boundary curve $c 0 1]]}
    set points [lsort -unique $points]
    if {[llength $points] < 4} {
	mess "Not enough points found for $family \n"
	return ""
    }
    if {[llength $points] == 4} {
	return $points
    }
    set ret_p ""
    foreach p $points {
	set surfs ""
	foreach c [ic_geo_incident point $p 1] {
	    set surfs [concat $surfs [ic_geo_incident curve $c 1]]
	}
	set surfs [lsort -unique $surfs]
	if {[llength $surfs] == 1} {lappend ret_p $p}
    }
    if {[llength $ret_p] != 4} {
	mess "Not finding proper connections to find 4 points of $family.  \n Found $ret_p\n"
	return ""
    }
    return $ret_p
}


## This proc will take a family of surfaces (all surfaces have to be connected one to one), and give corner points
## Should be replaced by 
proc scrib_lib_geo_get_corners_row_internal_surfaces { surfaces {curves ""} {return_internal_if_all_connected 1} } {
    if {$curves == ""} {
	foreach s $surfaces {
	    set curves [concat $curves [ic_geo_boundary surface $s 0 1] ]
	}
	set all_curves $curves
	set curves [scrib_lib_utils_list_remove_duplicated $all_curves]
	set internal_curves [scrib_lib_utils_list_get_duplicate $all_curves]
    }
    if {[llength [scrib_lib_geo_make_conn_regions curve $curves]] > 1} {
	mess "All surfaces form a closed region\n" 
	if $return_internal_if_all_connected {
	    return [list sides $internal_curves]
	} else {
	    return ""
	}
    }
    set points ""
    foreach c $curves {set points [concat $points [ic_geo_boundary curve $c 0 1]]}
    set points [lsort -unique $points]
    if {[llength $points] < 4} {
	mess "Not enough points found\n"
	return ""
    }
    if {[llength $points] == 4} {
	return $points
    }
    set ret_p ""
    foreach p $points {
	set surfs ""
	foreach c [ic_geo_incident point $p 1] {
	    foreach s [ic_geo_incident curve $c 1] {
		if {[lsearch $surfaces $s] == -1} continue
		set surfs [concat $surfs $s]
	    }
	}
	set surfs [lsort -unique $surfs]
	if {[llength $surfs] == 1} {lappend ret_p $p}
    }
    if {[llength $ret_p] != 4} {
	mess "Not finding proper connections to find 4 points of $surfaces .  \n Found $ret_p\n"
	return ""
    }
    return $ret_p
}



## This proc will find 2 side surfaces of the row of surfaces found in scrib_lib_geo_get_corners_row_surfaces
proc scrib_lib_geo_get_sides_row_surfaces { family {projection_parts ""}} {
    set points [scrib_lib_geo_get_corners_row_surfaces $family]
    #if there are no corner points due to a feature that wraps onto itself, the above proc returns double sides [list of side curves]
    if {[lindex $points 0] == "sides"} {return [lindex $points 1]}
mess "corner points are $points\n" blue
    set curves [scrib_lib_geo_get_single_curves [ic_geo_get_objects curve $family]]
#mess "curves are $curves\n"
    if {[llength $curves] < 4} {
	mess "Not enough curves found for $family\n"
	return ""
    }
    set sides ""
    if {[llength $curves] == 4} {
	ic_geo_new_family POINTS
	set curve_distance ""
	#make sure projection_parts exist
	if {$projection_parts == ""} {
	    mess "No parts to project to\n" red
	    return ""
	}
	set all_parts [ic_geo_list_families]
	foreach part $projection_parts  {
		if {[lsearch $all_parts $part] != -1} continue
		mess "projection_part $part does not exist\n"
	}
mess "projection_parts are $projection_parts\n" green
	foreach c $curves {
	    set pt [ic_geo_cre_pnt_on_crv_at_par POINTS PPP 0.5 $c]
	    if {[ic_geo_check_objects_exist point $pt] == ""} {continue}
	    set loc [ic_geo_get_point_location $pt] 
	    set dist [scrib_lib_geo_distance_from_surfaces $projection_parts $loc]
	    ic_delete_geometry point names $pt  
	    lappend curve_distance [list $c $dist]
	}
	set curve_distance [lsort -index 1 -real -decreasing $curve_distance]
#mess "curve_distance is $curve_distance\n"
	lappend sides [lindex [lindex $curve_distance 0] 0]
	lappend sides [lindex [lindex $curve_distance 1] 0]
	return $sides
    }
    foreach c $curves {
	set addit 1
	foreach p [ic_geo_boundary curve $c 0 1] {
	    if {[lsearch $points $p] == -1} {set addit 0 ; break}
	}
	if $addit {lappend sides $c}
    }
    if {[llength $sides] != 2} {
	mess "Not finding proper sides for $family.  \n Found $sides\n"
	return ""
    }
    return $sides  
}

##Find side surfaces of a part
proc scrib_lib_geo_find_side_midsurfaces {{part ""} {max_dist 10} {surfaces ""} {remove_sides 0}} {
    if {$part == ""} { 
	set part_surfs $surfaces
    } else {
	set init_reg [scrib_lib_geo_make_conn_regions surface [ic_geo_get_objects surface $part]]
	if {[llength $init_reg] > 1} {
	    set ordered_pair ""
	    foreach ir $init_reg {
		lappend ordered_pair [list [llength $ir] $ir]
	   }
	    set ordered_pair [lsort -index 0 -decreasing -real $ordered_pair]
	    set part_surfs [lindex [lindex $ordered_pair 0] 1]
	} else {
	    set part_surfs [ic_geo_get_objects surface $part] 
	}
    }
    set s [lindex $part_surfs 0]
    if {$s == ""} return ""
    ic_geo_surface_normals_orient $s 0
    set sides1 [ic_geo_get_side_surfaces $max_dist names $part_surfs]
    ic_geo_surface_normals_orient $s 1
    set sides2 [ic_geo_get_side_surfaces $max_dist names $part_surfs]
#If either side1 or side2 has surfaces with internal loops, it should be chosen as the side surfaces.
    set invalid 0
    if {[scrib_lib_geo_internal_surface_boundary_exists $sides1] } {incr invalid }
    if {[scrib_lib_geo_internal_surface_boundary_exists $sides2] } {
	incr invalid 
    } else {
	if $invalid { set invalid 3}
    }
    switch $invalid {
	0 {
	    if {[llength $sides2] < [llength $sides1]} {
		set side($part) $sides2
	    } else {
		set side($part) $sides1
		ic_geo_surface_normals_orient $s 1
	    }
	}
	1 {
	    set side($part) $sides1
	    ic_geo_surface_normals_orient $s 1
	}
	2 {mess "no side surfaces could be found for $part\n" red ; return}
	3 {set side($part) $sides2 }
     }
    #find double curves for side_surfaces
    set curves ""
    foreach s $side($part) {
	set curves [concat $curves [ic_geo_boundary surface $s 0 1] ]
    }
    set all_curves $curves
    set single_curves [lsort -unique [scrib_lib_utils_list_remove_duplicated $all_curves]]
    set internal_curves [lsort -unique [scrib_lib_utils_list_get_duplicate $all_curves]]

if $remove_sides {
    #remove side surfaces that should not have been marked as side surfaces.
#mess "length1 is [llength $side($part)]\n"
    set new_sides ""
    foreach s $side($part) {
	set single 0
	set double 0
	foreach c [ic_geo_boundary surface $s 0 1] {
	    if {[lsearch $single_curves $c] != -1} {
		incr single
#mess "incrementing single. single is $single\n"
	    } elseif {[lsearch $internal_curves $c] != -1} {
		incr double
#mess "incrementing double. double is $double\n"
	    } else {
#mess "not incrementing for $c\n"
	    }
	}
	if {$double == 0} {
	    if {$single != 2} continue
	    set skip 1
	    foreach c [ic_geo_boundary surface $s 0 1] {
		if {[lindex [ic_geo_boundary curve $c 0 1] 0] == [lindex [ic_geo_boundary curve $c 0 1] 1] } {
		    set skip 0
		    break
		}
	    }
	    if $skip continue
	}
	lappend new_sides $s
    }
    set side($part) $new_sides
#mess "length2 is [llength $side($part)]\n"
}

    set regions [scrib_lib_geo_make_conn_regions surface $side($part) ]
    set all_corners ""
    foreach reg $regions {
	set corners [scrib_lib_geo_get_corners_row_internal_surfaces $reg "" 0]
	if {$corners == ""} continue
	set all_corners [concat $all_corners $corners]
#	mess "surfaces $reg are not complete side surfaces, trying to add surfaces at $corners.\n" red
	set non_reg [scrib_lib_utils_list_remove_duplicated [concat $part_surfs $reg]]
	foreach surf $non_reg {
	    set curves [ic_geo_boundary surface $surf 0 1]
	    if {[llength $curves] != 4} continue
	    set nogo 0
	    foreach c $curves {
		foreach p [ic_geo_boundary curve $c 0 1] {
		    if {[lsearch $corners $p] == -1} {set nogo 1 ; break}
		}
		if $nogo break
	    }
	    if !$nogo {
		mess "adding side $surf\n" blue
		lappend side($part) $surf
	    }
	}
    }
    set non_side [scrib_lib_utils_list_remove_duplicated [concat $part_surfs $side($part)]]
    foreach surf $non_side {
	set curves [ic_geo_boundary surface $surf 0 1]
	if {[llength $curves] != 4} continue
	set nogo 0
	foreach c $curves {
	    foreach p [ic_geo_boundary curve $c 0 1] {
		if {[lsearch $all_corners $p] == -1} {set nogo 1 ; break}
	    }
	    if $nogo break
	}
	if !$nogo {
#	    mess "adding side $surf\n" blue
	    lappend side($part) $surf
	}
    }
    return $side($part)
}


## define solid geometry type
# 1 would be easy to midsurface type
# 0 would be solid to solid mesh.
proc scrib_lib_geo_get_solid_type_old { max_dist part {make_subsets 0}} {
    set init_reg [scrib_lib_geo_make_conn_regions surface [ic_geo_get_objects surface $part]]
    if {[llength $init_reg] > 1} {
	set ordered_pair ""
	foreach ir $init_reg {
	     lappend ordered_pair [list [llength $ir] $ir]
	}
	set ordered_pair [lsort -index 0 -decreasing -real $ordered_pair]
	set part_surfs [lindex [lindex $ordered_pair 0] 1]
    } else {
	set part_surfs [ic_geo_get_objects surface $part] 
    }

    set side [scrib_lib_geo_find_side_midsurfaces "" $max_dist $part_surfs]
    if {$side == ""} {return 0}
    set non_side [scrib_lib_utils_list_remove_duplicated [concat $part_surfs $side]]
    if $make_subsets {
	foreach ss $side {ic_geo_subset_add_items SIDE  [list surface $ss]}
	foreach ss $non_side {ic_geo_subset_add_items NON_SIDE  [list surface $ss]}
    }
#mess "side is $side\n"
#mess "non_side is $non_side\n"
    set conn1 [scrib_lib_geo_make_conn_regions surface $side]
    set conn2 [scrib_lib_geo_make_conn_regions surface $non_side]
#mess "conn1 is $conn1\n"
#mess "conn2 is $conn2\n"
    set conn_sides [llength $conn1]
    set conn_non_sides [llength $conn2]
#mess "conn_sides are $conn_sides\n"
#mess "conn_non_sides are $conn_non_sides\n"
#mess "conn2 is $conn2\n"
    if {$conn_non_sides == 2} {return 1}
    return 0
}

proc scrib_lib_geo_filter_curves {angle part tol} {
    ic_save_tetin temp.tin
    ic_build_topo $tol -angle $angle -filter_points -filter_curves $part
    set angle_curves [ic_geo_get_objects curve $part]
    ic_unload_tetin
    ic_load_tetin temp.tin
#    ic_build_topo $tol $part
    return $angle_curves
}

proc scrib_lib_geo_break_into_subsets_by_angle {tol angle {part ""} {make_subsets 0}} {
    if [llength [info commands ic_geo_filter_curves]] {
	set angle_curves1 [ic_geo_filter_curves $angle $part]
    } else {
	set angle_curves1 [scrib_lib_geo_filter_curves $angle $part $tol]
    }
    set angle_curves ""
    foreach ac $angle_curves1 { 
	lappend angle_curves [lindex $ac 0]
    }

    set surfs [ic_geo_get_objects surface $part]
    set surf [lindex $surfs 0]
    set new_surfs $surf
    set used_surfs $surf
    set group [lindex $surfs 0]
    set surfs [lreplace $surfs 0 0]
    set groups ""
    while 1 {
	set new_new_surfs ""
	foreach surf $new_surfs  {
	    foreach c [ic_geo_boundary surface $surf 0 1] {
		if {[lsearch $angle_curves $c] != -1} continue
		foreach s [ic_geo_incident curve $c 1] {
		    if {[lsearch $used_surfs $s] == -1} {
			lappend group $s
			lappend used_surfs $s
			lappend new_new_surfs $s
			set place [lsearch $surfs $s]
			set surfs [lreplace $surfs $place $place]
		    }
		}
	    }	    
	}
	if [llength $new_new_surfs] {
	    set new_surfs $new_new_surfs
	} else {
	    if [llength $surfs] {
		lappend groups $group
		set surf [lindex $surfs 0]
		set new_surfs $surf
		set used_surfs $surf
		set group [lindex $surfs 0]
		set surfs [lreplace $surfs 0 0]
	    } else {
		lappend groups $group
		if $make_subsets {
		    set i 0
		    foreach group $groups {
			incr i
			foreach ss $group {ic_geo_subset_add_items REG/SIDE_$i  [list surface $ss] }
		    }
		    if [llength [info commands aie_getBatchGeomDisplay]] {aie_getBatchGeomDisplay}
		}
		return $groups
	    }
	}
    }
}

## finds out if a specified part is a solid, or thin_solid
proc scrib_lib_geo_get_solid_type {max_dist part {make_subsets 0} {simple_method 0}} {
    set tol [ic_geo_default_topo_tolerance]
    set regions [scrib_lib_geo_break_into_subsets_by_angle $tol 30 $part 1]

#This orients all surfaces inward.
    set sides [scrib_lib_geo_find_side_midsurfaces $part $max_dist]
    if ![llength $sides] {return solid} else {
	if $simple_method {
	    set dist 0
	    set part_surfs [ic_geo_get_objects surface $part] 
	    set invalid_side_regions [scrib_lib_utils_list_remove_duplicated [concat $part_surfs $sides]]
	    return [list thin_solid $dist $invalid_side_regions]
	}
    }

    set invalid_side_regions ""
    set invalid_side_num_regions 0
    set dist_count 0
    set total_dist 0
    foreach reg $regions {
	#First check for any cutout regions in any surfaces.  If these exist, it can not be a side region.
if 0 {
	set INT_BOUND 0
	foreach s $reg {
	    if [scrib_lib_geo_internal_surface_boundary_exists $s] {
		set INT_BOUND 1
		break
	    }
	}
	if $INT_BOUND {
	    incr invalid_side_num_regions
	    lappend invalid_side_regions $reg
	    continue
	}
}
	#Next check if surface area of region is greater than the perimeter / 2 * max_dist
	set surf_area [ic_geo_srf_area  $reg]
	set curves ""
	foreach s $reg {
	    set c [ic_geo_boundary surface $s 1 1]
	    set cc [ic_geo_boundary surface $s 0 1]
	    if {[llength $c] != [llength $cc] } {
		if {[llength $cc] < 5} {set c $cc}
	    }
	    set curves [concat $curves $c]
	}
	set single_curves [lsort -unique [scrib_lib_utils_list_remove_duplicated $curves]]
	set internal_curves [lsort -unique [scrib_lib_utils_list_get_duplicate $curves]]
	if {[llength $single_curves] < 2} continue
	set length 0
	foreach c $single_curves {set length [expr $length + [ic_geo_crv_length $c]]}
	set test_area [expr $length / 2 * $max_dist]
	if {$test_area < $surf_area } {
mess "test_area is $test_area; surf_area is $surf_area for part $part ; reg [llength $reg]\n" cyan
mess "reg is $reg\n" cyan
	    incr invalid_side_num_regions
	    lappend invalid_side_regions $reg
	    continue
	} else {
mess "test_area is $test_area; surf_area is $surf_area for part $part ; reg [llength $reg]\n" green
	    foreach c $internal_curves {
		set total_dist [expr $total_dist + [ic_geo_crv_length $c]]
		incr dist_count
	    }
	}
    }

    set init_reg [scrib_lib_geo_make_conn_regions surface [ic_geo_get_objects surface $part]]
    if {[llength $init_reg] > 1} {
	set ordered_pair ""
	foreach ir $init_reg {
	    lappend ordered_pair [list [llength $ir] $ir]
	}
	set ordered_pair [lsort -index 0 -decreasing -real $ordered_pair]
	set part_surfs [lindex [lindex $ordered_pair 0] 1]
    } else {
	set part_surfs [ic_geo_get_objects surface $part] 
    }
    set nonside ""
    foreach reg $invalid_side_regions {
	set nonside [concat $nonside $reg]
    }
    set side [scrib_lib_utils_list_remove_duplicated [concat $part_surfs $nonside]]

    if $make_subsets {
	foreach ss $nonside {ic_geo_subset_add_items NON_SIDE  [list surface $ss]}
	foreach ss $side {ic_geo_subset_add_items SIDE  [list surface $ss]}
    }
    if {$invalid_side_num_regions == 2} {
	if $dist_count {set dist [expr $total_dist / $dist_count]} else {set dist 0}
mess "dist is $dist\n"
	return [list thin_solid $dist $invalid_side_regions]
    } else {
#	mess "invalid_side_regions are $invalid_side_regions\n"
#	mess "invalid_side_num_regions are $invalid_side_num_regions\n"
	return solid
    }
}


















