def planarize_mesh(mesh, fixed=None, kmax=100, d=1.0, callback=None, callback_args=None): """Planarise the faces of a mesh. Planarisation is implemented as a two-step iterative procedure. At every iteration, faces are first individually projected to their best-fit plane, and then the vertices are projected to the centroid of the disconnected corners of the faces. Parameters: mesh fixed kmax d callback callback_args Returns: None """ # planarize every face individually # by projecting all vertices onto the best-fit plane # reconnect the corners of the faces # by mapping the vertices to the centroids of the face corners if callback: if not callable(callback): raise Exception('The callback is not callable.') fixed = fixed or [] fixed = set(fixed) for k in range(kmax): key_xyz = {key: [] for key in mesh.vertices()} for fkey in mesh.faces(): points = mesh.face_coordinates(fkey) plane = bestfit_plane_from_points(points) projections = project_points_plane(points, plane) for index, key in enumerate(mesh.face_vertices(fkey)): key_xyz[key].append(projections[index]) for key, attr in mesh.vertices(data=True): if key in fixed: continue x, y, z = centroid_points(key_xyz[key]) attr['x'] = x attr['y'] = y attr['z'] = z if callback: callback(mesh, k, callback_args)
def planarize_faces(vertices, faces, fixed=None, kmax=100, callback=None, callback_args=None): """Planarise a set of connected faces. Planarisation is implemented as a two-step iterative procedure. At every iteration, faces are first individually projected to their best-fit plane, and then the vertices are projected to the centroid of the disconnected corners of the faces. Parameters ---------- vertices : list The vertex coordinates. faces : list The vertex indices per face. fixed : list, optional [None] A list of fixed vertices. kmax : int, optional [100] The number of iterations. callback : callable, optional [None] A user-defined callback that is called after every iteration. callback_args : list, optional [None] A list of arguments to be passed to the callback function. """ if callback: if not callable(callback): raise Exception('The callback is not callable.') fixed = fixed or [] fixed = set(fixed) for k in range(kmax): positions = [[] for _ in range(len(vertices))] for face in iter(faces): points = [vertices[index] for index in face] plane = bestfit_plane(points) projections = project_points_plane(points, plane) for i, index in enumerate(face): positions[index].append(projections[i]) for index, vertex in enumerate(vertices): if index in fixed: continue x, y, z = centroid_points(positions[index]) vertex[0] = x vertex[1] = y vertex[2] = z if callback: callback(k, callback_args)
def mesh_planarize_faces(mesh, fixed=None, kmax=100, callback=None, callback_args=None): """Planarise a set of connected faces. Planarisation is implemented as a two-step iterative procedure. At every iteration, faces are first individually projected to their best-fit plane, and then the vertices are projected to the centroid of the disconnected corners of the faces. Parameters ---------- mesh : :class:`compas.datastructures.Mesh` A mesh object. fixed : list[int], optional A list of fixed vertices. kmax : int, optional The number of iterations. d : float, optional A damping factor. callback : callable, optional A user-defined callback that is called after every iteration. callback_args : list[Any], optional A list of arguments to be passed to the callback function. Returns ------- None """ if callback: if not callable(callback): raise Exception('The callback is not callable.') fixed = fixed or [] fixed = set(fixed) for k in range(kmax): positions = {key: [] for key in mesh.vertices()} for fkey in mesh.faces(): vertices = mesh.face_vertices(fkey) points = [mesh.vertex_coordinates(key) for key in vertices] plane = bestfit_plane(points) projections = project_points_plane(points, plane) for index, key in enumerate(vertices): positions[key].append(projections[index]) for key, attr in mesh.vertices(True): if key in fixed: continue x, y, z = centroid_points(positions[key]) attr['x'] = x attr['y'] = y attr['z'] = z if callback: callback(k, callback_args)
def test_project_points_plane(): assert allclose( project_points_plane([[0, 2.5, 2]], ([3, 4, 5], [6, 7, 8.8])), [[2.0278256587047525, 4.865796601822211, 4.974144299433638]])
def RunCommand(is_interactive): #load Derivation and model derivation = Derivation.from_json( rhino_UI_utilities.get_json_file_location()) model = derivation.get_next_step() #select beams selection_reference = [] selection_reference.append( rs.GetObject(message="select start Beam", filter=32, preselect=True)) selection_reference.extend( rs.GetObjects(message="select Beams to connect", filter=32, preselect=True)) #load helpers helper = UI_helpers() #name search selected_beams = helper.extract_BeambyName(model, selection_reference) #check for parallel planes, uses the function above start_beam = selected_beams[0] beams_to_connect = selected_beams[1:] parallel_check = check_for_parallel_vectors(start_beam, beams_to_connect) if parallel_check != True: raise IndexError('beams are not parallel') else: print("beams are parallel") #check for coplanarity, uses the function above coplanar_planes = {} face_ids_coplanar_planes = {} for i in range(1, 5): start_beam_plane = start_beam.face_plane(i).copy() start_beam_origin = start_beam_plane.point a = get_coplanar_planes(start_beam_plane, start_beam_origin, beams_to_connect) if a != False: coplanar_planes['' + str(i)] = a[0] face_ids_coplanar_planes['' + str(i)] = a[1] else: pass print("face_dictionary here", face_ids_coplanar_planes) if len(coplanar_planes.keys()) == 2: print("'success", coplanar_planes) else: raise IndexError('beams are not coplanar') #user inputs face_id = rs.GetInteger(("possible face connections " + "face_id " + coplanar_planes.keys()[0] + " or face_id " + coplanar_planes.keys()[1]), None, None, None) start_point = (helper.Get_SelectPointOnMeshEdge("Select mesh edge", "Pick point on edge")) ext_start = rs.GetReal("extension length start", 200, None, None) ext_end = rs.GetReal("extension length end", 200, None, None) #list of coplanar planes extracted from coplanar_planes dict using face_id as key coplanar_planes_along_selected_face = [] coplanar_planes_along_selected_face.append( start_beam.face_plane(face_id).copy()) for key, value in coplanar_planes.items(): if key == "" + str(face_id): coplanar_planes_along_selected_face.extend(value) #list of face_ids of coplanar planes coplanar_face_ids = [] coplanar_face_ids.append(face_id) for key, value in face_ids_coplanar_planes.items(): if key == "" + str(face_id): coplanar_face_ids.extend(value) #intersection points by passing a line from the origin of start beam to the adjacent planes of the coplanar planes of all beams points_to_compare = [] for i in range(len(selected_beams)): beam = selected_beams[i] start_beam_selected_face_frame = selected_beams[0].face_frame(face_id) line_pt_a = start_beam_selected_face_frame.point normal = start_beam_selected_face_frame.normal line_pt_b = add_vectors(line_pt_a, scale_vector(normal, 0.3)) line_to_intersect = Line(line_pt_a, line_pt_b) face_index = coplanar_face_ids[i] adjacent_planes = beam.neighbour_face_plane(face_index) for p in adjacent_planes: intersection_point = intersection_line_plane(line_to_intersect, p) points_to_compare.append(intersection_point) viz_pts = [] #project distance from points_to_compare to the plane of the start Beam distances = [] start_beam_face_frame = start_beam.face_frame(face_id).copy() start_beam_Plane_perpendicular_to_face_id_Plane = Plane( start_beam_face_frame.point, start_beam_face_frame.normal) viz_pts.append(start_beam_Plane_perpendicular_to_face_id_Plane.point) for point in points_to_compare: viz_pts.append(point) vector = subtract_vectors( point, start_beam_Plane_perpendicular_to_face_id_Plane.point) distances.append( dot_vectors( vector, start_beam_Plane_perpendicular_to_face_id_Plane.normal)) #search to find max point maximum_distance = max(distances) minimum_distance = min(distances) beam_length = (maximum_distance - minimum_distance) + ext_start + ext_end ext_len = maximum_distance + ext_start #project selected point to perpendicular planes of the beams to connect if coplanar_planes.keys()[0] == "1" or coplanar_planes.keys()[0] == "3": start_beam_perpendicular_plane = start_beam.face_plane(5).copy() elif coplanar_planes.keys()[0] == "2" or coplanar_planes.keys()[0] == "4": start_beam_perpendicular_plane = start_beam.face_plane(6).copy() tol = 1.0e-5 # tol = 5.0 perpendicular_plane = [] for beam in beams_to_connect: for i in range(5, 7): beam_plane = beam.face_plane(i).copy() print("beam_plane", beam_plane) angle_check = start_beam_perpendicular_plane.normal.angle( beam_plane.normal) print("angle", angle_check) if (abs(angle_check) - 0) < tol or (abs(angle_check) - 180) < tol: perpendicular_plane.append(beam_plane) print(perpendicular_plane) print(len(perpendicular_plane)) #project points projected_point_list = [] new_start_point = project_points_plane([start_point], start_beam_perpendicular_plane) projected_point_list.extend(new_start_point) for plane in perpendicular_plane: new_point = project_points_plane(new_start_point, plane) projected_point_list.extend(new_point) #list of distance to move joints on match beam model.rule_Connect_90lap(selected_beams, projected_point_list, coplanar_face_ids, beam_length, ext_len, create_id()) print(len(projected_point_list)) print(projected_point_list) #Save Derivation (Model is also saved) derivation.to_json(rhino_UI_utilities.get_json_file_location(), pretty=True) # Visualization viz_point = [] for pt in projected_point_list: a = (pt[0], pt[1], pt[2]) viz_point.append({'pos': a, 'color': (0, 255, 0)}) artist = MeshArtist(None, layer='BEAM::Beams_out') artist.clear_layer() artist.draw_points(viz_point) for beam in model.beams: artist = MeshArtist( beam.mesh, layer='BEAM::Beams_out' ) #.mesh is not ideal fix in beam and assemble class artist.draw_faces(join_faces=True)
pts_a = rs.DivideCurve(crv_a, div_r) # ------------------------------ # compas geometry function # create planes along the rail curve planes = [] for i in range(div_r): vec = subtract_vectors(pts_a[i + 1], pts_a[i]) planes.append([pts_a[i], vec]) # subsequentely project profile curve to all planes pts_uv = [] pts = pts_p for i in range(div_r - 1): pts = project_points_plane(pts, planes[i]) pts_uv.append(pts) # create mesh object trans_mesh = Mesh() # add vertices for u in xrange(len(pts_uv)): for v in xrange(len(pts_uv[u])): x, y, z = pts_uv[u][v] trans_mesh.add_vertex((u, v), x=x, y=y, z=z) # add faces for u in xrange(len(pts_uv) - 1): for v in xrange(len(pts_uv[u]) - 1): trans_mesh.add_face([(u, v), (u + 1, v), (u + 1, v + 1), (u, v + 1)])