
proc geo_convex_hull {} {
    global data_available convex_hull tdv_default
    
    set orig_surfs [geo_select entity]
    if {$orig_surfs == ""} { return "" }
    
    set convex_hull(tol) [lindex [ic_geo_get_triangulation_tolerance] 0]
    
    set d [form_init .convex_hull "Convex hull params"]
    if {$d != ""} {
	form_radiobutton $d.alls "Create a single hull around all surfaces" \
	    convex_hull(how) single {0 0 -cols -}
	form_radiobutton $d.ints "Interactively define splitting planes" \
	    convex_hull(how) interact {1 0 -cols -}
	form_radiobutton $d.arrs "Split by regular grid of planes" \
	    convex_hull(how) grid {2 0 -cols -}
	set act {{convex_hull(how) grid}}
	form_colwidth $d 0 2 M
	form_frame $d.dt flat 0 {5 1 -cols -}
	form_label $d.dt.l "Division alignment: " {0 0} $act
	form_radiobutton $d.dt.m Model convex_hull(divs_type) model {0 1} $act
	form_radiobutton $d.dt.s Screen convex_hull(divs_type) screen {0 2} $act
	form_label $d.xgl "X divisions" {6 1} $act
	form_label $d.ygl "Y divisions" {7 1} $act
	form_label $d.zgl "Z divisions" {8 1} $act
	form_entry $d.xg convex_hull(xdivs) int {6 2} $act
	form_entry $d.yg convex_hull(ydivs) int {7 2} $act
	form_entry $d.zg convex_hull(zdivs) int {8 2} $act

	form_checkbutton $d.coars "Coarsen surfaces first" \
	    convex_hull(coarsen) {10 0 -cols -}
	form_label $d.toll "Tolerance" {11 1} convex_hull(coarsen)
	form_entry $d.tol convex_hull(tol) float {11 2} convex_hull(coarsen)
	
	form_checkbutton $d.remint "Remove interior faces" \
	    convex_hull(rem_int) {20 0 -cols -}
#	form_checkbutton $d.delafter "Delete original surfaces" convex_hull(del_after) {21 0 -cols -}
	
	form_radiobutton $d.usefam "Use family" \
	    convex_hull(ask_fams) 0 {25 0 -cols 2}
	form_entry $d.famname convex_hull(use_fam) string {25 2} \
	    {{convex_hull(ask_fams) 0}}
	form_radiobutton $d.askfam "Ask for family for each component" \
	    convex_hull(ask_fams) 1 {26 0 -cols -}
	form_checkbutton $d.sfams "Make separate hulls for each input family" \
	    convex_hull(sep_fams) {30 0 -cols -}
	
	form_finish bot
    }
    if ![form_wait .convex_hull] return
    
    geo_convex_hull_doit $orig_surfs
}

proc geo_convex_hull_doit {orig_surfs} {
    global data_available convex_hull tdv_default
    global tdv_default

    busy 1
    
    # First copy all the surfaces.
    set all_surfs ""
    foreach e $orig_surfs {
	set t [lindex $e 0]; set n [lindex $e 1]
	set n2 [ic_geo_duplicate $t $n "" 1]
	lappend all_surfs [list $t $n2]
	#set orig_visible($e) [$e get -visible]
	#$e configure -visible 0
    }
#    foreach a $all_surfs {
#	$a signal_change 1
#    }
#    $projlib signal_change 1
    
    switch $convex_hull(how) {
	single {
	    set surfs_regions [list $all_surfs]
	    set planes ""
	}
	interact {
		busy reset
	    banner "Draw lines with the left button, middle = done, right = back up/cancel, 'x' = cancel, 'F9' = dynamics."
	    set planes [tdv_multiple_planes $tdv_default]
	    banner ""
		busy 1
	    if {$planes == ""} {
		mess "No planes selected - using all surfaces.\n"
		set surfs_regions [list $all_surfs]
	    } else {
		set surfs_regions [geo_split_by_regions $all_surfs $planes]
	    }
	}
	grid {
	    set planes [geo_split_make_grid $all_surfs $convex_hull(divs_type)\
			    $convex_hull(xdivs) $convex_hull(ydivs) \
			    $convex_hull(zdivs)]
	    set surfs_regions [geo_split_by_regions $all_surfs $planes]
	}
    }
    
    if $convex_hull(coarsen) {
	foreach ss1 $surfs_regions {
	    foreach ss2 $ss1 {
		set t [lindex $ss2 0]; set n [lindex $ss2 1]
		if {($t != "surface") && ($t != "curve")} continue
		
		set nt [lindex [ic_geo_num_segments $t $n] 0]
		if {$convex_hull(coarsen) && ($nt > 32)} {
		    ic_geo_coarsen tol $convex_hull(tol) ${t}s $n noisy 0
		}
	    }
	}
    }
    busy 0
    
    if $convex_hull(sep_fams) {
	set new_regions ""
	foreach surfs $surfs_regions {
	    catch {unset in_fam}
	    foreach s $surfs {
		set f [ic_geo_get_family [lindex $s 0] [lindex $s 1]]
		lappend in_fam($f) $s
	    }
	    foreach f [array names in_fam] {
		lappend new_regions $in_fam($f)
	    }
	}
	set surfs_regions $new_regions
    }
    
    set tol [expr [tdv_get_diameter $tdv_default] * \
		 $convex_hull(tol)]
    
    set nfam 0
    foreach surfs $surfs_regions {
	if $convex_hull(ask_fams) {
	    set fam [select_families 0 0 1 "Select the part for this\
		set of surfaces.  Cancel\nor ORFN means to skip it." \
			 fam_visible bot]
	} else {
	    set fam $convex_hull(use_fam)
	}
	incr nfam [ic_geo_new_family $fam]
	set nname [ic_geo_new_name surface $fam/]
	set ok 0
	if {($fam != "") && ($fam != "ORFN")} {
	    set ok [ic_geo_convex_hull $surfs $nname $fam]
	}
	# Now get rid of the old surfaces.
	catch {unset objs}
	foreach ss $surfs {
	    lappend objs([lindex $ss 0]) [lindex $ss 1]
	}
	foreach type [array names objs] {
	    ic_delete_geometry $type names $objs($type)
	}
	if {$ok && $convex_hull(rem_int)} {
	    set ndel 0
	    foreach p $planes {
		incr ndel [ic_geo_remove_triangles_on_plane $nname $p $tol]
	    }
	    
	    if $ndel { mess "Deleted $ndel internal triangles\n" }
	}
    }
    if $nfam { update_fam_window }
    set data_available(geom_facet) 1
}

proc geo_split_by_regions {surfs planes} {
    #puts "classify_by_regions $planes $surfs"
    set buckets [ic_geo_classify_by_regions $planes $surfs 1]
    #puts $buckets
    foreach b $buckets s $surfs {
	lappend got($b) $s
    }
    
    set surfs ""
    foreach b [array names got] {
	if {$b != 1} { set surfs [concat $surfs $got($b)] }
    }
	#VG: sometimes got(1) not defined...
	if [info exists got(1)] {
    set surfs1 [ic_geo_split_surfaces $got(1) $planes]
    set surfs [concat $surfs $surfs1]
    }
    unset got
    
    # Do it again with the split ones but don't ask for a shared
    # bucket this time.
    #puts "classify_by_regions $planes $surfs"
    set buckets [ic_geo_classify_by_regions $planes $surfs 0]
    #puts $buckets
    foreach b $buckets s $surfs {
	lappend got($b) $s
    }
    set surfs ""
    foreach buck [array names got] {
	lappend surfs $got($buck)
    }
    return $surfs
}

proc geo_split_make_grid {surfs dtype xd yd zd} {
    global tdv_default

    set bb [ic_geo_bbox_of_entities $surfs]
    
    switch $dtype {
	screen {
	    set p1 [lindex [$tdv_default screen2world 0 0] 0]
	    set p2 [lindex [$tdv_default screen2world 1000 0] 0]
	    set p3 [lindex [$tdv_default screen2world 0 1000] 0]
	    set zvec [lindex [$tdv_default screen2world 0 0] 1]
	}
	model {
	    set p1 "0 0 0"
	    set p2 "1 0 0"
	    set p3 "0 1 0"
	    set zvec "0 0 1"
	}
    }
    set xvec ""; set yvec ""
    foreach i {0 1 2} {
	lappend xvec [expr [lindex $p2 $i] - [lindex $p1 $i]]
	lappend yvec [expr [lindex $p3 $i] - [lindex $p1 $i]]
    }
    
    set planes ""
    foreach d {x y z} {
	set pls [make_plane_divisions [set ${d}vec] [set ${d}d] \
		     [lindex $bb 0] [lindex $bb 1]]
	set planes [concat $planes $pls]
    }
    return $planes
}
