def boundary_cycles_from_surface(tri, angle, surface, tet_vert_coorientations = None): """ Takes a carried surface. For each cusp of tri, look at the boundary curve of the surface on the boundary torus for that cusp. Push it up slightly, record which faces of tri it goes through. """ if tet_vert_coorientations == None: tet_vert_coorientations = is_transverse_taut(tri, angle, return_type = "tet_vert_coorientations") # set up output vectors out = [] for vertex in tri.faces(0): # 0 is the dimension of the face, so this is cusps out.append([0] * tri.countFaces(2)) edge_sides = edge_side_face_collections(tri, angle, tet_vert_coorientations = tet_vert_coorientations) face_coorientations = convert_tetrahedron_coorientations_to_faces(tri, tet_vert_coorientations) for f in tri.faces(2): weight = surface[f.index()] # this should be an integer. :) for vert_num in range(3): cusp_index = f.face(0, vert_num).index() sgn = face_coorientations[f.index()] trailing_vert_num = (vert_num + sgn) % 3 trailing_edge = f.face(1, trailing_vert_num) leading_vert_num = (vert_num - sgn) % 3 leading_edge = f.face(1, leading_vert_num) # these are with respect to right hand rule on surface as viewed from above # the faces above us on the trailing edge get -weight, # the faces above us on the leading edge get +weight. left, right = edge_sides[trailing_edge.index()] pair = (f.index(), trailing_vert_num) if pair in left: side = left else: assert pair in right side = right above = side[side.index(pair) + 1:] for (f_ind, vert) in above: out[cusp_index][f_ind] -= weight left, right = edge_sides[leading_edge.index()] pair = (f.index(), leading_vert_num) if pair in left: side = left else: assert pair in right side = right above = side[side.index(pair) + 1:] for (f_ind, vert) in above: out[cusp_index][f_ind] += weight return out
def edge_equation_matrix_taut(triangulation, angle_struct): """ For each edge, find the face numbers on either side of the pis, put +1 for one side and -1 for the other. """ matrix = [] edge_sides = edge_side_face_collections(triangulation, angle_struct) for left_faces, right_faces in edge_sides: row = [0] * triangulation.countTriangles() for (face_num, vert) in left_faces: row[face_num] = row[face_num] + 1 for (face_num, vert) in right_faces: row[face_num] = row[face_num] - 1 matrix.append(row) return matrix
def pairing_of_faces_across_an_edge(tri, angle, weights, edge_index, tet_vert_coorientations=None): """ given a solution to the system of branch equations gives a pairing of faces across an edge (together with the index of the edge in that face) """ if tet_vert_coorientations == None: tet_vert_coorientations = is_transverse_taut( tri, angle, return_type="tet_vert_coorientations") edge_sides = edge_side_face_collections( tri, angle, tet_vert_coorientations=tet_vert_coorientations)[edge_index] side0 = edge_sides[0] for i in range(len(side0)): face_index = side0[i][0] weight = weights[face_index] side0[i] = [ side0[i], weight ] #first replace side_collections into weighted_side_collections sum_of_weights0 = sum(weight for [_, weight] in side0) side0_nonzero_weights = [] for x in side0: for k in range(x[1]): side0_nonzero_weights.append(x[0]) side1 = edge_sides[1] for i in range(len(side1)): face_index = side1[i][0] weight = weights[face_index] side1[i] = [side1[i], weight] sum_of_weights1 = sum(weight for [_, weight] in side1) assert sum_of_weights0 == sum_of_weights1 side1_nonzero_weights = [] for x in side1: for k in range(x[1]): side1_nonzero_weights.append(x[0]) return ([side0_nonzero_weights, side1_nonzero_weights])
def appears_twice_on_the_same_side(tri, angle, face_index, edge_index, tet_vert_coorientations=None): """ tells if a face is attached twice on the same side of an edge (if so, then lowermost and uppermost) """ if tet_vert_coorientations == None: tet_vert_coorientations = is_transverse_taut( tri, angle, return_type="tet_vert_coorientations") edge_sides = edge_side_face_collections( tri, angle, tet_vert_coorientations=tet_vert_coorientations)[edge_index] side0 = edge_sides[0] side1 = edge_sides[1] return side0[0][0] == side0[-1][0] and side0[-1][0] == face_index or side1[ 0][0] == side1[-1][0] and side1[-1][0] == face_index
def is_uppermost(tri, angle, face_index, edge_index_in_face, edge_index, tet_vert_coorientations=None): """ tells if (face_index, edge_index_in_face) is uppermost for that edge """ if tet_vert_coorientations == None: tet_vert_coorientations = is_transverse_taut( tri, angle, return_type="tet_vert_coorientations") edge_sides = edge_side_face_collections( tri, angle, tet_vert_coorientations=tet_vert_coorientations)[edge_index] side0 = edge_sides[0] side1 = edge_sides[1] return (side0[-1] == (face_index, edge_index_in_face) or side1[-1] == (face_index, edge_index_in_face))
def where_faces_are_uppermost(tri, angle, tet_vert_coorientations=None): """ returns a list whose ith elements is the index of the edge where the ith face is uppermost """ if tet_vert_coorientations == None: tet_vert_coorientations = is_transverse_taut( tri, angle, return_type="tet_vert_coorientations") n = tri.countTetrahedra() where_uppermost = [None] * 2 * n sides = edge_side_face_collections(tri, angle, tet_vert_coorientations) for edge in tri.edges(): uppermost0_index = sides[edge.index()][0][-1][0] where_uppermost[uppermost0_index] = edge.index() uppermost1_index = sides[edge.index()][1][-1][0] where_uppermost[uppermost1_index] = edge.index() for x in where_uppermost: assert x != None return where_uppermost
def make_continent_drill_flow_cycle(veering_isosig, flow_cycle, num_steps): tri, angle = isosig_to_tri_angle(veering_isosig) vt = veering_triangulation(tri, angle) #, tet_shapes = tet_shapes) ### format for loops: it is a list of tuples, ### each tuple is (tet_index, edge_index within this tet that we exit through) tet_0 = flow_cycle[0][0] face_0 = 0 ### only used for initial numbering of vertices of the continent, so who cares initial_tet_face = tet_face(vt, tet_0, face_0, verts_pos=[None, None, None, None]) con = continent(vt, initial_tet_face) side_face_collections, side_tet_collections = edge_side_face_collections( vt.tri, vt.angle, tet_vert_coorientations=vt.coorientations, return_tets=True, order_bottom_to_top=False) # print('sfc', side_face_collections) # print('stc', side_tet_collections) ### identify the next edge in the cycle init_tetrahedron = con.tetrahedra[0] init_edge = flow_edge_in_continent(init_tetrahedron, flow_cycle[0][1]) flow_tetrahedra = [init_tetrahedron] flow_edges = [init_edge] ### both in the continent upwards_flow_index = 0 downwards_flow_index = 0 for i in range(num_steps): # print(i) if i % 2 == 0: ### go up edge = flow_edges[-1] last_tet = None while True: con.update_boundary() upper_boundary_triangles = [ t for t in edge.boundary_triangles if t.is_upper ] if len(upper_boundary_triangles) == 0: break ## out of while loop last_tet = con.bury(upper_boundary_triangles[0]) assert last_tet != None upwards_flow_index = (upwards_flow_index + 1) % len(flow_cycle) assert last_tet.index == flow_cycle[upwards_flow_index][0] flow_tetrahedra.append(last_tet) flow_edges.append( flow_edge_in_continent(last_tet, flow_cycle[upwards_flow_index][1])) con.make_convex( ) ### could this take us further up dual_cycle? We don't think so else: ### go down tet = flow_tetrahedra[0] edge = tet.lower_edge() flow_edges = [edge] + flow_edges ### now build the continent to get new_lowest_tet manifold_edge = tri.edge(edge.index) downwards_flow_index = (downwards_flow_index - 1) % len(flow_cycle) ### is the flow cycle vertical through the tetrahedron? tet_below = get_tet_above_edge( vt.tri, vt.angle, manifold_edge, tet_vert_coorientations=vt.coorientations, get_tet_below_edge=True) tet_below_num = tet_below.index() top_vert_nums = get_tet_top_vert_nums(vt.coorientations, tet_below_num) top_edge_num = vert_pair_to_edge_num[tuple(top_vert_nums)] if (tet_below_num, top_edge_num) == flow_cycle[ downwards_flow_index]: ### flow cycle went straight up while True: con.update_boundary() lower_boundary_triangles = [ t for t in edge.boundary_triangles if not t.is_upper ] if len(lower_boundary_triangles) == 0: break ## out of while loop last_tet = con.bury(lower_boundary_triangles[0]) else: ### find which side of the edge our tet is in # print('edge index', edge.index) side_tet_collections_at_edge = side_tet_collections[ edge.index] ## index in the manifold side_face_collections_at_edge = side_face_collections[ edge.index] downward_path = None flow_step = flow_cycle[downwards_flow_index] for i, side_tet_collection in enumerate( side_tet_collections_at_edge): if flow_step in side_tet_collection: downward_path = side_tet_collection[: side_tet_collection .index(flow_step) + 1] downward_path_faces = side_face_collections_at_edge[ i][:side_tet_collection.index(flow_step) + 1] assert downward_path != None for j, (tet_num, edge_num) in enumerate(downward_path): con.update_boundary() lower_boundary_triangles = [ t for t in edge.boundary_triangles if not t.is_upper and t.index == downward_path_faces[j][0] ] assert len(lower_boundary_triangles) == 1 last_tet = con.bury(lower_boundary_triangles[0]) assert last_tet != None flow_tetrahedra = [last_tet] + flow_tetrahedra con.make_convex( ) ### could this take us further down dual_cycle? We don't think so con.update_boundary() return con, flow_tetrahedra, flow_edges