# Library functions for the scripting library (scrib)
#
# File: scrib/lib/bolts.tcl
#
# $Revision$ on $Date$
# 
# Copyright (c) 1993-2003 ICEM CFD Engineering
#
#--------------------------------------------------------------------
#
# --> if the name of the first proc already exists in interp, return
#
if {"" != [info commands scrib_lib_bolts_make_ogrid]} { 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 {
    if {"" != [info commands scrib_lib_setup_source_files]} {
	set required_files "tetra utils"
	scrib_lib_setup_source_files $required_files
    }
}

## needs doc.

proc scrib_lib_bolts_make_ogrid {family} {
    global elem_list enodes etype num_connected diagonals
    global base_elements both_quads nodes
    
    # each bolt hole has to be in a unique family
    # see comment below about UnsMap::AddAttachedCmd
    
    # create the subset for the bars
    set barsubset [ic_uns_subset_create]
    ic_uns_subset_add_families_and_types $barsubset $family {BAR_2 LINE_2}
    set bars [ic_uns_subset_list_elements $barsubset]
    #mess "DEBUG: bars: $barsubset: $bars\n" red
    
    # UnsMap::AddAttachedCmd can't handle bars
    if 0 {
	#set maps [ic_uns_subset_into_connected_regions $barsubset]
	#mess "maps: $maps\n" green
	# put the bar elements on the bolt holes into distinct subset   
	#foreach hole [ic_uns_subset_into_connected_regions $barsubset]
	#mess "DEBUG: [ic_uns_subset_into_connected_regions $barsubset]\n" red
    }
    
    set nodes ""
    foreach bar $bars {set nodes [concat $nodes [lindex $bar 2	] ]}
    set nodes [ic_list_uniquify $nodes]
    #mess "DEBUG: nodes in $family are $nodes\n"
    
    #==============
    
    # Now that nodes are identified, make a subset of each node,
    # and the elements it is attached to. the idea here is that
    # each node should only be attached to two quads.
    
    #The following puts the nodes and what is attached into subsets
    set n 1
    foreach node $nodes {
	scrib_lib_bolts_find_connected_mesh $node
	#=================
	#If more than 2 are connected, some editing needs to be done.  	
	if { $num_connected($node) == 3 } {
	    ic_mess "node $node has more than 2 elements attached, elem_list($node) is $elem_list($node)\n"
	    if {"" == $diagonals($node)} continue
	    if {[llength $diagonals($node)] > 1} {
		mess "there is some problem here\n"
		continue
	    }
	    if {($etype($diagonals($node)) == "TRI_3") && ($both_quads($node) == 1)} {
		    # Case1: Base elements are quads diagonal is a tri
		    # Solution: Merge nodes of tri not on boundary to remove	
		    # Need to check for node dimensions -not done yet, if both are surface,
		    # we can merge the two nodes of tris not on bolt,
		    # and move to center but maybe have to check to see if
		    # it inverts any elements, if dimension of one node is higher,
		    # merge to that node, also check for inverting as above.
		    set nodessubset [ic_uns_subset_create]
	   	    if {[llength $diagonals($node)] != 1} {continue} else {set el $diagonals($node)}
		    foreach n $enodes($el) { 
			mess "trying to add node $n to $nodessubset\n" green
			if {[lsearch -exact $nodes $n] != -1} {continue}
			ic_uns_subset_add_node_numbers $nodessubset $n
		    }
		    set test [ic_uns_subset_list_elements $nodessubset]
		    #mess "DEBUG: nodessubset $nodessubset is $test\n" green
		    ic_uns_merge_nodes $nodessubset "" {0 0 0} {0 0 0} 0
		    set test [ic_uns_subset_list_elements $nodessubset]
		    #mess "DEBUG: nodessubset $nodessubset is $test\n" green
		    set stuff [ic_uns_print_info $nodessubset node]
		    #mess "DEBUG: stuff $stuff\n" red
	    }
	    if {($etype($diagonals($node)) == "TRI_3") && ($both_quads($node) == 0)} {
		    #Case 2:  1 base element is tri, one is quad, and diag is tri
		    # Solution: combine two tris to a quad
		    #the two tris should be combined to one quad
		    set tri ""
		    foreach el $base_elements($node) {
			if { $etype($el) == "TRI_3"} {
				if {$tri != ""} {ic_mess "There are two tris as base elements\n"}
				set tri $el
			}
		    }
		    #we have the two elements, but to create a quad, we need proper order.
		    set common_nodes ""
		    foreach d $enodes($diagonals($node)) {
			if {[lsearch -exact $enodes($tri) $d] > -1} {
				lappend common_nodes $d
			}  else {
				set first_node $d
			}
		    }
		    ic_mess "common_nodes are $common_nodes, unique node is $first_node\n"
		    set last_node ""
		    foreach n $enodes($tri) {
			if {[lsearch -exact $enodes($diagonals($node)) $n] == -1} {set last_node $n}
		    }
		    set node_ordered  [list $first_node [lindex $common_nodes 0] \
			[lindex $common_nodes 1] $last_node]
		   ic_mess "element will be created from nodes $node_ordered\n"

		    set elset [ic_uns_subset_create]
		    ic_uns_subset_add_number $elset "$diagonals($node)" 1 MIXED		 
		    ic_uns_subset_add_number $elset "$tri" 1 MIXED	
		    ic_delete_elements subset $elset

   		    set nodeset [ic_uns_subset_create]
		    foreach i $node_ordered {
		    	ic_uns_subset_add_node_numbers $nodeset $i
		    }
		    ic_uns_create_element QUAD_4 MESH $nodeset 1
	    }
	    if {($etype($diagonals($node)) == "QUAD_4") && ($both_quads($node) == 1)} {
		    # Case 3: both base element are quad, and diag is quad
		    # Solution: break diagonal quad to tri, ensure edge split not on node, 
		    # merge two nodes to remove diagonal tri

		    # Need to check for node dimensions -not done yet
		    # if both are surface,
		    # we can merge the two corner nodes, and move to center
		    # but maybe have to check to see if it inverts any elements, 
		    # if so maybe also merge third node (the one not on the bolt).
		    # if dimension of one node is higher, merge to that node,
		    # also check for inverting as above
		    set elset [ic_uns_subset_create]
		    ic_uns_subset_add_number $elset $diagonals($node) 1 MIXED
		    ic_uns_change_type $elset quad tri 0
		    ic_uns_subset_delete $elset
		    #Now check to see if the new split is attached to node $node
		    #ic_uns_subset_delete $tmpsubset	
		    #need to reorder first
		    set junk [ic_uns_subset_create]
		    ic_uns_subset_add_near_nodes $junk 1
		    ic_uns_reorder $junk dir {1 0 0}
		    ic_uns_subset_delete $junk
		    #done reordering
		    scrib_lib_bolts_find_connected_mesh $node
		    #if the number of nodes connected to $node > 3, edge needs to be swapped
		    if {$num_connected($node) > 3} {
			#need to find diagonals, so that we can figure what should be swapped.
			if {[llength $diagonals($node)] != 2} {
				mess "DEGUG: there is some problem here\n"
				continue
			}
			set diag1 [lindex $diagonals($node) 0]
			set diag2 [lindex $diagonals($node) 1]
		    	set common_nodes ""
		    	foreach d $enodes($diag2) {
				if {[lsearch -exact $enodes($diag1) $d] > -1} {
					lappend common_nodes $d
		 		}
			}
			ic_mess "common_nodes are $common_nodes"
			if {[llength $common_nodes] != 2} {
				ic_mess "there is a problem\n"
				continue
			}
			set nset [ic_uns_subset_create]
			foreach i $common_nodes {
		    		ic_uns_subset_add_node_numbers $nset $i
		    	}
			ic_uns_swap_edges $nset 1
		    	scrib_lib_bolts_find_connected_mesh $node
		    }	
		    #number of elements as diagonal should now be 2    
		    set nodessubset [ic_uns_subset_create]
		    if {[llength $diagonals($node)] != 1} {continue} else {set el $diagonals($node)}
		    foreach n $enodes($el) { 
			mess "trying to add node $n to $nodessubset\n" green
			if {[lsearch -exact $nodes $n] != -1} {continue}
			ic_uns_subset_add_node_numbers $nodessubset $n
		    }
		    set test [ic_uns_subset_list_elements $nodessubset]
		    #mess "DEBUG: nodessubset $nodessubset is $test\n" green
		    ic_uns_merge_nodes $nodessubset "" {0 0 0} {0 0 0} 0
		    set test [ic_uns_subset_list_elements $nodessubset]
		    #mess "DEBUG: nodessubset $nodessubset is $test\n" green
		    set stuff [ic_uns_print_info $nodessubset node]
		    #mess "DEBUG: stuff $stuff\n" red
	    }	
	    if {($etype($diagonals($node)) == "QUAD_4") && ($both_quads($node) == 0)} {
		    # Case 4: at least one base element is a tri, and diag is quad
		    # Solution: break diagonal quad to tri, ensure edge split not on node, 
		    # combine new diag tri with base_tri.
	
		    # split quad to tri, it's edge should be attached to base_node $node, 
		    # if not, swap edge created. check each $base_element, and it's $etype()
		    # to see if it is a quad. If there is only one tri, find which tri
		    # from the quad split should be combined to form 
		    # one quad on boundary -which shares same edge. 
		    # Then, the remaining tri should be merged as in Case 1
		    # If there are two tris, each of the split quad's tris should
		    # have another tri to combine to quad.
		    set elset [ic_uns_subset_create]
		    ic_uns_subset_add_number $elset $diagonals($node) 1 MIXED
		    ic_uns_change_type $elset quad tri 0
		    ic_uns_subset_delete $elset
		    #Now check to see if the new split is attached to node $node
		    #ic_uns_subset_delete $tmpsubset	
		    #need to reorder first
		    set junk [ic_uns_subset_create]
		    ic_uns_subset_add_near_nodes $junk 1
		    ic_uns_reorder $junk dir {1 0 0}
		    ic_uns_subset_delete $junk
		    #done reordering
		    scrib_lib_bolts_find_connected_mesh $node
		    #if the number of nodes connected to $node > 3, edge needs to be swapped
		    if {$num_connected($node) > 3} {
			#need to find diagonals, so that we can figure what should be swapped.
			if {[llength $diagonals($node)] != 2} {
				mess "DEGUG: there is some problem here\n"
				continue
			}
			ic_mess "diagonals($node) are $diagonals($node)\n"
			set diag1 [lindex $diagonals($node) 0]
			set diag2 [lindex $diagonals($node) 1]
		    	set common_nodes ""
		    	foreach d $enodes($diag2) {
				if {[lsearch -exact $enodes($diag1) $d] > -1} {
					lappend common_nodes $d
		 		}
			}
			ic_mess "common_nodes are $common_nodes"
			if {[llength $common_nodes] != 2} {
				ic_mess "there is a problem\n"
				continue
			}
			set nset [ic_uns_subset_create]
			foreach i $common_nodes {
		    		ic_uns_subset_add_node_numbers $nset $i
		    	}
			ic_uns_swap_edges $nset 1
		    	scrib_lib_bolts_find_connected_mesh $node
		    }	
		    set tri ""
		    foreach el $base_elements($node) {
			if { $etype($el) == "TRI_3"} {
				if {$tri != ""} {ic_mess "There are two tris as base elements\n"}
				set tri $el
			}
		    }
		    #we have the two elements, but to create a quad, we need proper order.
		    set common_nodes ""
		    foreach d $enodes($diagonals($node)) {
			if {[lsearch -exact $enodes($tri) $d] > -1} {
				lappend common_nodes $d
			}  else {
				set first_node $d
			}
		    }
		    ic_mess "common_nodes are $common_nodes, unique node is $first_node\n"
		    set last_node ""
		    foreach n $enodes($tri) {
			if {[lsearch -exact $enodes($diagonals($node)) $n] == -1} {set last_node $n}
		    }
		    set node_ordered  [list $first_node [lindex $common_nodes 0] \
			[lindex $common_nodes 1] $last_node]
		   ic_mess "element will be created from nodes $node_ordered\n"

		    set elset [ic_uns_subset_create]
		    ic_uns_subset_add_number $elset "$diagonals($node)" 1 MIXED		 
		    ic_uns_subset_add_number $elset "$tri" 1 MIXED	
		    ic_delete_elements subset $elset

   		    set nodeset [ic_uns_subset_create]
		    foreach i $node_ordered {
			ic_mess "i is $i, node_ordered is $node_ordered\n"
		    	ic_uns_subset_add_node_numbers $nodeset $i
		    }
		    ic_uns_create_element QUAD_4 MESH $nodeset 1
			
	    }
	}
	#===================
	if { $num_connected($node) == 4 } {
	    ic_mess "node $node has 4 elements attached.\n"
	    set n 1
	    foreach d $diagonals($node) {
		    set diags($n) $d
		    incr n
	    }
	    if [info exists diags(3)] {
	    	ic_mess "There is a problem with diagonals here\n" red
		continue
	    }
	    set n 1
	    foreach b $base_elements($node) {
		    set bases($n) $b
		    incr n
	    }
	    if [info exists bases(3)] {
	    	ic_mess "something is wrong with base nodes\n" 
		continue
	    }
	    #find base/diag pairs.  diag1 should be connected to base1, and diag2 to base2
	    #if not rename, so that they are.
	    set common_nodes ""
	    foreach n $enodes($bases(1)) {
		if {[lsearch -exact $enodes($diags(1)) $n] > -1} {
			lappend common_nodes $n
		 }		
	    }
	    if {[llength common_nodes] == 2} {
		ic_mess "$bases(1) is attached to $diags(1), $bases(2) is attached to $diags(2) \n" green
	    } elseif {[llength common_nodes] == 1}  {
		set bbbb $bases(1)
		set bases(1) $bases(2)
		set bases(2) $bbbb
		ic_mess "$bases(1) is attached to $diags(1), $bases(2) is attached to $diags(2) \n" blue
	    } else {
		ic_mess "There is a problem with attachments\n" red
		continue
	    }
	    #base/diag pairs should now be identified.
	    foreach p {1 2} {
		set base $bases($p)
		set diag $diags($p)
		ic_mess "diag is $diag, base is $base\n" blue
	    	if {($etype($base) == "QUAD_4") && ($etype($diag) == "QUAD_4")} {
		    # Case 5: both base and diag are quads
		    # Solution: merge opposite corner nodes, not on base 
		    # assumption ic_uns_subset_list_elements returns ordered set of nodes from quad
		    set pointer [lsearch -exact $enodes($diag) $node]
		    if {$pointer == 0} {
			set m_nodes [list [lindex $enodes($diag) 1] [lindex $enodes($diag) 2] ]
			set top_tri_node [lindex $enodes($diag) 3] 
		    } elseif {$pointer == 1} {
			set m_nodes [list [lindex $enodes($diag) 0] [lindex $enodes($diag) 3] ]
			set top_tri_node [lindex $enodes($diag) 1] 
		    } elseif {$pointer == 2} {
			set m_nodes [list [lindex $enodes($diag) 0] [lindex $enodes($diag) 3] ]
			set top_tri_node [lindex $enodes($diag) 1] 
		    } elseif {$pointer == 3} {
			set m_nodes [list [lindex $enodes($diag) 1] [lindex $enodes($diag) 2] ]
			set top_tri_node [lindex $enodes($diag) 2] 
		    } else {
			mess "pointer $pointer is messed up.\n"
		    }
		    set nodessubset [ic_uns_subset_create]
		    foreach n $m_nodes { 
			mess "trying to add node $n to $nodessubset\n" green
			ic_uns_subset_add_node_numbers $nodessubset $n
		    }
		    set test [ic_uns_subset_list_elements $nodessubset]
		    #mess "DEBUG: nodessubset $nodessubset is $test\n" green
		    ic_uns_merge_nodes $nodessubset "" {0 0 0} {0 0 0} 0
		    set test [ic_uns_subset_list_elements $nodessubset]
		    #mess "DEBUG: nodessubset $nodessubset is $test\n" green
		    set stuff [ic_uns_print_info $nodessubset node]
		    #mess "DEBUG: stuff $stuff\n" red		    
		}
	    	if {($etype($base) == "TRI_3") && ($etype($diag) == "QUAD_4")} {
		    # Case 6: base is tri and diag is quad
		    # Solution: delete tri and quad, and create a quad on base, and tri to fill hole.
		    # assumption ic_uns_subset_list_elements returns ordered set of nodes from quad
		    set pointer [lsearch -exact $enodes($diag) $node]
		    if {$pointer == 0} {
			set m_nodes [list [lindex $enodes($diag) 1] [lindex $enodes($diag) 2] ]
			set top_tri_node [lindex $enodes($diag) 3] 
		    } elseif {$pointer == 1} {
			set m_nodes [list [lindex $enodes($diag) 0] [lindex $enodes($diag) 3] ]
			set top_tri_node [lindex $enodes($diag) 1] 
		    } elseif {$pointer == 2} {
			set m_nodes [list [lindex $enodes($diag) 0] [lindex $enodes($diag) 3] ]
			set top_tri_node [lindex $enodes($diag) 1] 
		    } elseif {$pointer == 3} {
			set m_nodes [list [lindex $enodes($diag) 1] [lindex $enodes($diag) 2] ]
			set top_tri_node [lindex $enodes($diag) 2] 
		    } else {
			mess "pointer $pointer is messed up.\n"
		    }
		    set first_node ""
		    foreach n $enodes($base) {
			if {[lsearch -exact $enodes($diag) $n] == -1} {
				lappend first_node $n		
			}	
		    }
		    if {[llength $first_node] != 1} {
			mess "Problem computing first node $first_node" red
			continue
		    }
		    foreach n $m_nodes {
			if {[lsearch -exact $enodes($base) $n] > -1} {
				set common_corner $n		
			} else {
				set away_corner $n
			}
		    }
		    set quad_nodes [concat $first_node $node $common_corner $away_corner]
		    ic_mess "quad will be created from nodes $quad_nodes\n"
		    set tri_nodes [concat $common_corner $away_corner $top_tri_node]
		    mess "tri will be created from nodes $tri_nodes\n"
		    #first delete existing elements:
		    set elset [ic_uns_subset_create]
		    ic_uns_subset_add_number $elset "$base" 1 MIXED		 
		    ic_uns_subset_add_number $elset "$diag" 1 MIXED	
		    ic_delete_elements subset $elset
		    set nodessubset [ic_uns_subset_create]
		    foreach n $quad_nodes { 
			mess "trying to add node $n to $nodessubset\n" green
			ic_uns_subset_add_node_numbers $nodessubset $n
		    }
		    set test [ic_uns_subset_list_elements $nodessubset]
		    #mess "DEBUG: nodessubset $nodessubset is $test\n" green
		    ic_uns_create_element QUAD_4 MESH $nodessubset 1
		    set test [ic_uns_subset_list_elements $nodessubset]
		    #mess "DEBUG: nodessubset $nodessubset is $test\n" green
		    set stuff [ic_uns_print_info $nodessubset node]
		    #mess "DEBUG: stuff $stuff\n" red		   
		    #now create the tri 
		    set nodessubset [ic_uns_subset_create]
		    foreach n $tri_nodes { 
			mess "trying to add node $n to $nodessubset\n" green
			ic_uns_subset_add_node_numbers $nodessubset $n
		    }
		    set test [ic_uns_subset_list_elements $nodessubset]
		    #mess "DEBUG: nodessubset $nodessubset is $test\n" green
		    ic_uns_create_element TRI_3 MESH $nodessubset 1
		    set test [ic_uns_subset_list_elements $nodessubset]
		    #mess "DEBUG: nodessubset $nodessubset is $test\n" green
		    set stuff [ic_uns_print_info $nodessubset node]
		    #mess "DEBUG: stuff $stuff\n" red		    
		}
	    	if {($etype($base) == "QUAD_4") && ($etype($diag) == "TRI_3")} {
		    # Case 7: diag is tri and base is quad
		    # Solution: merge nodes of tri not on base. 
		    mess "case 7 not implemented yet\n" yellow
		}
	    	if {($etype($base) == "TRI_3") && ($etype($diag) == "TRI_3")} {
		    # Case 8: diag is tri and base is tri
		    # Solution: combine tris as in Case 2
		    mess "case 8 not implemented yet\n" yellow
		}
	    }
	}
	#===================
	#if more than four are attached, I guess it would probably be primarily tris, but I was 
	#going to ignore this untill I saw a case that required it.
	if { $num_connected($node) > 4 } {
	    ic_mess "node $node has more than 4 elements attached, this is not supported yet.\n"
	}
	incr n
    }
    set barsubset [ic_uns_subset_create]
    ic_uns_subset_add_families_and_types $barsubset $family {BAR_2 LINE_2}
    ic_uns_subset_add_layer $barsubset 3 all surf
    ic_uns_quad_remesh $barsubset complete_edges 0 merge_ends 0 all_dim 0 element 2 \
	    proj 1 max_steps 100 ele_tol 0 how 5 debug 0 dev 0 iters 20 make_consistent 0 \
	    surf 0 conver 0.025 geo_active 1 merge_tol 0.10
}

## needs doc.

proc scrib_lib_bolts_find_connected_mesh {node} {
    global elem_list etype enodes num_connected diagonals
    global base_elements both_quads nodes
    
    set tmpsubset [ic_uns_subset_create]
    ic_uns_subset_add_near_nodes $tmpsubset $node
    set list [ic_uns_subset_list_elements $tmpsubset]
    #mess "DEBUG: list is $list\n"
    
    #================
    
    #find number attached (2 quads would be ideal, however, we will assume 2 tris will also work)
    set elem_list($node) ""
    foreach el $list {
	if {([lindex $el 0] == "QUAD_4") || ([lindex $el 0] == "TRI_3")} {
	    set num [lindex $el 1]
	    lappend elem_list($node) $num 
	    set etype($num) [lindex $el 0]
	    set enodes($num) [lindex $el 2]
	    #ic_mess "elem_list($node) is $elem_list($node) \n"
	}
    }
    set num_connected($node) [llength $elem_list($node)]
    if 0 {
	set nodessubset [ic_uns_subset_create]
	foreach el $elem_list($node) { 
	    foreach n $enodes($el) {
		mess "trying to add node $n to $nodessubset\n" green
		ic_uns_subset_add_node_numbers $nodessubset $n
	    }
	}
	set test [ic_uns_subset_list_elements $nodessubset]
	#mess "DEBUG: nodessubset $nodessubset is $test\n" green
    }
    set diagonals($node) ""
    set base_elements($node) ""
    foreach el $elem_list($node) {
	set num_nodes_on_hole($el) 0
	foreach n $enodes($el) { 
	    if  {[lsearch $nodes $n] != -1} { incr num_nodes_on_hole($el) }
	}
	if {$num_nodes_on_hole($el) < 2} {lappend diagonals($node) $el} else {
	    lappend base_elements($node) $el
	}
	set both_quads($node) 1
	foreach base $base_elements($node) {
	    if {$etype($base) == "TRI_3"} { set both_quads($node) 0 }
	}
	mess "diagonals($node): $diagonals($node);\n both_quads($node): $both_quads($node)\n" blue
    }
}
if 0 {
    #
    # "main"
    #
    foreach fam [ic_uns_list_families] {
	if {[string range $fam 0 3] == "HOLE"} {
	    scrib_lib_bolts_make_ogrid $fam 
	}
    }
}

