def approximation_distance(sv0, sv1, sv2): # center-of-gravity distance sv_cog = SuperVertex.compute_surface_center_of_gravity( sv0, sv1, sv2) cog_surface = sv_cog.XYZ_vec3() cog_3d = (sv0.XYZ_vec3() + sv1.XYZ_vec3() + sv2.XYZ_vec3()) / 3 cog_distance = np.linalg.norm(cog_surface - cog_3d) distance = cog_distance if APPROX_DIST_MULTI_SAMPLING: # halfway-point distances hw0_surface = SuperVertex.compute_halfway(sv0, sv1).XYZ_vec3() hw1_surface = SuperVertex.compute_halfway(sv1, sv2).XYZ_vec3() hw2_surface = SuperVertex.compute_halfway(sv2, sv0).XYZ_vec3() hw0_3d = sv0.XYZ_vec3() + ( (sv1.XYZ_vec3() - sv0.XYZ_vec3()) / 2) hw1_3d = sv1.XYZ_vec3() + ( (sv2.XYZ_vec3() - sv1.XYZ_vec3()) / 2) hw2_3d = sv2.XYZ_vec3() + ( (sv0.XYZ_vec3() - sv2.XYZ_vec3()) / 2) hw0_distance = np.linalg.norm(hw0_surface - hw0_3d) hw1_distance = np.linalg.norm(hw1_surface - hw1_3d) hw2_distance = np.linalg.norm(hw2_surface - hw2_3d) distance = (distance + hw0_distance + hw1_distance + hw2_distance) / 4 if APPROX_DIST_AREA_WRIGHTED: area = calculate_area(sv0.XYZ_vec3(), sv1.XYZ_vec3(), sv2.XYZ_vec3()) distance /= area**0.5 return distance**2
def insert_halfway_as_debug(omesh, h): sv0 = sv_from_vh(omesh, omesh.from_vertex_handle(h)) sv1 = sv_from_vh(omesh, omesh.to_vertex_handle(h)) p0 = sv0.XYZ_vec3() p1 = sv1.XYZ_vec3() phw = p0 + ((p1 - p0) / 2) svhw = SuperVertex(*phw) svhw.set_same_face_as(sv0) DEBUG_VERTICES.append(svhw) return
def split_edge(omesh, vertices, eh, meta_block): def remove_encroaching_vertices(omesh, vertices, vh, h): def remove_one_encroaching_vertex(omesh, vertices, phw, h): for vh in omesh.vertices(): if omesh.is_boundary(vh): continue pcurr = np.array((omesh.point(vh))) if np.linalg.norm(phw - pcurr) < h: remove_inner_vertex(omesh, vertices, vh) return True return False phw = np.array((omesh.point(vh))) n_deleted = 0 while remove_one_encroaching_vertex(omesh, vertices, phw, h): n_deleted += 1 return n_deleted hh = omesh.halfedge_handle(eh, 0) vh0 = omesh.from_vertex_handle(hh) vh1 = omesh.to_vertex_handle(hh) sv0 = sv_from_vh(omesh, vh0) sv1 = sv_from_vh(omesh, vh1) if omesh.is_boundary(eh): sv_new = SuperVertex.compute_halfway_on_shared_edge(sv0, sv1) else: sv_new = SuperVertex.compute_halfway(sv0, sv1) vertices.append(sv_new) # split segment vh_new = omesh.add_vertex(sv_new.XYZ_vec3()) set_supervertex_property(omesh, vh_new, sv_new) omesh.split_edge(eh, vh_new) omesh.garbage_collection() meta_block[MeshkD.NV_SPLT] += 1 # remove encroaching vertices if omesh.is_boundary(eh): h = np.linalg.norm(sv_new.XYZ_vec3() - sv0.XYZ_vec3()) n_deleted = remove_encroaching_vertices(omesh, vertices, vh_new, h) meta_block[MeshkD.NV_DELT] += n_deleted return vh_from_sv(omesh, sv_new)
def sample_supervertex(surface, curve2d, parameter): p2d = curve2d.Value(parameter) p3d = surface.Value(p2d.X(), p2d.Y()) sv = SuperVertex(x=p3d.X(), y=p3d.Y(), z=p3d.Z(), u=p2d.X(), v=p2d.Y()) return sv
def scc_from_c_2d(c_2d, other_sv): scc = SuperVertex(u=c_2d[0], v=c_2d[1]) scc.face = other_sv.face scc.face_id = other_sv.face_id scc.project_to_XYZ() return scc
def split_segment(scdt, segment_index): def count_segments(segment_loops): nos = 0 for segment_loop in segment_loops: nos += len(segment_loop) return nos vertices, segment_loops, _ = scdt l_index, s_index = segment_index print('split_segment()') print(segment_index, '->', segment_loops[l_index][s_index]) segment_loop = segment_loops[l_index] vi0, vi1 = segment_loop[s_index] # compute and insert halfway vertex sv0 = vertices[vi0] sv1 = vertices[vi1] sv_halfway = SuperVertex.compute_halfway_on_shared_edge(sv0, sv1) # segment vertices are never deleted -> insert before inner vertices to avoid index shift hw_index = count_segments(segment_loops) # == num of boundary vertices vertices.insert(hw_index, sv_halfway) # delete old and insert new segments print('del', segment_loop[s_index]) del segment_loop[s_index] new_s0 = (vi0, hw_index) new_s1 = (hw_index, vi1) print('insert', new_s1) print('insert', new_s0) segment_loop.insert(s_index, new_s1) segment_loop.insert(s_index, new_s0) # delete encroaching vertices new_segments_length = np.linalg.norm(sv0.XYZ_vec3() - sv_halfway.XYZ_vec3()) inner_vertices_offset = hw_index + 1 sv_index = inner_vertices_offset while sv_index < len(vertices): sv = vertices[sv_index] dist_to_hw = np.linalg.norm(sv.XYZ_vec3() - sv_halfway.XYZ_vec3()) if dist_to_hw < new_segments_length: del vertices[sv_index] else: sv_index += 1 return
def chew93_Surface(face_mesh, meta_block): vertices, wire_meshes, triangles, _ = face_mesh # step 1: compute initial CDT and iteratively transform into SCDT print('generating initial mesh...', end='') sys.stdout.flush() triangulate_cdt(face_mesh) omesh = parse_into_openmesh(face_mesh) flip_until_scdt(omesh) # step 2+3: find largest triangle that fails shape ans size criteria print('\b\b\b - done\nrefining mesh...', end='') delta = find_largest_failing_triangle(omesh) global iter_counter iter_counter = 0 while delta.is_valid() and iter_counter != MAX_ITERATIONS: print('\rrefining mesh... iteration', iter_counter, '', end='') if iter_counter == DEBUG_ITERATION: #TODO remove after debuging sv0, sv1, sv2 = collect_triangle_supervertices(omesh, delta) (x, y, z), (u, v) = calculate_cog(sv0, sv1, sv2) sv_cog = SuperVertex(x, y, z, u, v, same_as=sv0) DEBUG_VERTICES.append(sv_cog) else: DEBUG_VERTICES.clear() handle, scc = calculate_refinement(omesh, delta, meta_block) if isinstance(handle, om.FaceHandle): vh_new = insert_inner_vertex(omesh, vertices, handle, scc, meta_block) else: assert isinstance(handle, om.EdgeHandle) vh_new = split_edge(omesh, vertices, handle, meta_block) meta_block[MeshkD.NV_REFI] += 1 # after vertex insertion and possible deletion, restore SCDT criteria restore_scdt(omesh, vh_new) # update for next iteration delta = find_largest_failing_triangle(omesh) iter_counter += 1 parse_back(omesh, face_mesh) vertices += DEBUG_VERTICES return
def sample_interior(face_mesh): vertices, _, _, face = face_mesh additional_vertices = [] surface = BRepAdaptor_Surface(face) FU = surface.FirstUParameter() LU = surface.LastUParameter() FV = surface.FirstVParameter() LV = surface.LastVParameter() U_LENGTH = LU - FU V_LENGTH = LV - FV if INTERIOR_SAMPLING_METHOD == INTERIOR_GRID: for u_index in range(1, GRID_U_SAMPLES + 1): for v_index in range(1, GRID_V_SAMPLES + 1): u_offset = U_OFFSET_FACTOR / (GRID_U_SAMPLES + 1) v_offset = V_OFFSET_FACTOR / (GRID_V_SAMPLES + 1) u = FU + ((u_index / (GRID_U_SAMPLES + 1)) + u_offset) * U_LENGTH v = FV + ((v_index / (GRID_V_SAMPLES + 1)) + v_offset) * V_LENGTH sv_add = SuperVertex(u=u, v=v, same_as=vertices[0]) sv_add.project_to_XYZ() additional_vertices.append(sv_add) elif INTERIOR_SAMPLING_METHOD == INTERIOR_RANDOM: for i in range(RANDOM_SAMPLES): rand0 = random.randint( 1, RANDOM_RESOLUTION - 1) / RANDOM_RESOLUTION rand1 = random.randint( 1, RANDOM_RESOLUTION - 1) / RANDOM_RESOLUTION u = FU + rand0 * U_LENGTH v = FV + rand1 * V_LENGTH sv_add = SuperVertex(u=u, v=v, same_as=vertices[0]) sv_add.project_to_XYZ() additional_vertices.append(sv_add) else: raise Exception( 'sample_interior() error - INTERIOR_SAMPLING_METHOD unknown') return additional_vertices
def insert_inner_vertex(scdt, c): vertices, _, _ = scdt assert len(vertices) > 0 svc = SuperVertex(x=c[0], y=c[1], z=c[2]) svc.face_id = vertices[0].face_id svc.face = vertices[0].face svc.project_to_UV() vertices.append(svc) return
def insert_halfway_vertex_of_edge(scdt, edge_vertex_indices): vertices, _, _ = scdt assert len(vertices) > 0 ev0, ev1 = edge_vertex_indices sv0 = vertices[ev0] sv1 = vertices[ev1] p0 = sv0.UV_vec2() p1 = sv1.UV_vec2() p01 = p1 - p0 hw = p0 + (p01 / 2) svhw = SuperVertex(u=hw[0], v=hw[1]) svhw.face = sv0.face svhw.face_id = sv0.face_id svhw.project_to_XYZ() vertices.append(svhw) return
def travel(omesh, delta, hh, c_3d, c_2d_candidates, normal, meta_block): def traveled_too_far(omesh, hh, p_orig, ray_dir): vh_opposite = omesh.to_vertex_handle(hh) p_opposite = sv_from_vh(omesh, vh_opposite).XYZ_vec3() p_opposite -= p_orig # move system to origin p_projected = np.abs(np.dot(p_opposite, ray_dir)) if p_projected > 1.0: print('traveled too far:', p_projected) return p_projected > 1.0 def halfedge_crossed_by_ray_shadow(omesh, hh, ray_ori, ray_dir, normal): # print('halfedge_crossed_by_ray_shadow: ', end='') assert np.allclose(np.linalg.norm(ray_dir), 1.0) assert np.allclose(np.linalg.norm(normal), 1.0) p_from = sv_from_vh(omesh, omesh.from_vertex_handle(hh)).XYZ_vec3() p_to = sv_from_vh(omesh, omesh.to_vertex_handle(hh)).XYZ_vec3() v_from = shortest_vector_between_two_lines(p_from, normal, ray_ori, ray_dir) v_to = shortest_vector_between_two_lines(p_to, normal, ray_ori, ray_dir) dp = np.dot(v_from, v_to) # print(dp < 0) return dp < 0 meta_block[MeshkD.NT_INVK] += 1 svh0 = sv_from_vh(omesh, omesh.from_vertex_handle(hh)) svh1 = sv_from_vh(omesh, omesh.to_vertex_handle(hh)) sv_orig = SuperVertex.compute_halfway(svh0, svh1) p_orig = sv_orig.XYZ_vec3() ray_dir = normalize(c_3d - p_orig) # halt if we encounter a boundary edge (split case) # travel_iteration = 0 #TODO remove after debuging while not omesh.is_boundary(omesh.edge_handle(hh)): # if travel_iteration > 262: #TODO remove after debuging # print('travel() error - travel limit reached!') # break # else: # travel_iteration += 1 # if iter_counter == DEBUG_ITERATION: # insert_halfway_as_debug(omesh, hh) meta_block[MeshkD.NT_LOOP] += 1 # get inside neighboring triangle hh = omesh.opposite_halfedge_handle(hh) fh = omesh.face_handle(hh) # halt if surface circumcenter is found to be insides fh (insert case) inside_index = find_point_inside(omesh, fh, c_2d_candidates) if inside_index >= 0: return fh, scc_from_c_2d(c_2d_candidates[inside_index], sv_orig) hh = omesh.next_halfedge_handle( hh) # go to first of the opposite halfedges if traveled_too_far(omesh, hh, p_orig, ray_dir): pass # which of the remaining edges is crossed to travel further in that direction if not halfedge_crossed_by_ray_shadow(omesh, hh, p_orig, ray_dir, normal): # shadow apparently crossed the other edge hh = omesh.next_halfedge_handle(hh) assert halfedge_crossed_by_ray_shadow(omesh, hh, p_orig, ray_dir, normal) meta_block[MeshkD.NT_SHAD] += 1 return omesh.edge_handle(hh), None