def test_to_obj(): mesh = Mesh.from_obj(compas.get('faces.obj')) mesh.to_obj('data/temp.obj') mesh = Mesh.from_obj(compas.get('temp.obj')) assert mesh.number_of_faces() == 25 assert mesh.number_of_vertices() == 36 assert mesh.number_of_edges() == 60
def read_mesh_from_filename(self, filename, meshcls): if not os.path.isfile(filename): raise FileNotFoundError("No such file: '%s'" % filename) extension = filename[(filename.rfind(".") + 1):] if extension == "dae": # no dae support yet #mesh = Mesh.from_dae(filename) obj_filename = filename.replace(".dae", ".obj") if os.path.isfile(obj_filename): mesh = Mesh.from_obj(obj_filename) # former DAE files have yaxis and zaxis swapped # TODO: already fix in conversion to obj frame = Frame([0,0,0], [1,0,0], [0,0,1]) T = Transformation.from_frame(frame) mesh_transform(mesh, T) else: raise FileNotFoundError("Please convert '%s' into an OBJ file, \ since DAE is currently not supported \ yet." % filename) elif extension == "obj": mesh = Mesh.from_obj(filename) elif extension == "stl": mesh = Mesh.from_stl(filename) else: raise ValueError("%s file types not yet supported" % extension.upper()) return meshcls(mesh)
def test_to_obj(): _, fname = tempfile.mkstemp(suffix='.obj', prefix='temp_mesh_test') mesh = Mesh.from_obj(compas.get('faces.obj')) mesh.to_obj(fname) mesh = Mesh.from_obj(fname) assert mesh.number_of_faces() == 25 assert mesh.number_of_vertices() == 36 assert mesh.number_of_edges() == 60
def test_normal(): mesh = Mesh.from_obj(compas.get('faces.obj')) assert mesh.normal() == [0.0, 0.0, 1.0] mesh = Mesh.from_stl(compas.get('cube_binary.stl')) assert mesh.normal() == [0.0, 0.0, 0.0] mesh = Mesh.from_obj(compas.get('quadmesh.obj')) assert mesh.normal() == [-2.380849234996509e-06, 4.1056122145028854e-05, 0.8077953732329284]
def test_centroid(): mesh = Mesh.from_obj(compas.get('faces.obj')) assert mesh.centroid() == [5.0, 5.0, 0.0] mesh = Mesh.from_stl(compas.get('cube_binary.stl')) assert mesh.centroid() == [0.0, 0.0, 0.5] mesh = Mesh.from_obj(compas.get('quadmesh.obj')) assert mesh.centroid() == [2.508081952064351, 2.554046390557884, 1.2687133268242006]
def test_area(): mesh = Mesh.from_obj(compas.get('faces.obj')) assert mesh.area() == 100 mesh = Mesh.from_stl(compas.get('cube_binary.stl')) assert mesh.area() == 6 mesh = Mesh.from_obj(compas.get('quadmesh.obj')) assert mesh.area() == 22.802429316496635
def test_vertices_on_boundary(): mesh = Mesh.from_obj(compas.get('quadmesh.obj')) assert mesh.vertices_on_boundary() == [ 0, 1, 2, 3, 4, 5, 6, 7, 14, 15, 17, 33, 35, 37, 38, 39, 40, 41, 42, 43, 44, 45, 53, 62, 71, 73, 74, 75, 76, 84, 85, 86, 87, 88, 89, 98 ] mesh = Mesh.from_obj(compas.get('boxes.obj')) assert mesh.vertices_on_boundary() == []
def main(): compas_mesh = Mesh.from_obj(os.path.join(DATA, MODEL)) delta = get_param({}, key='delta', defaults_type='gcode') # boolean for delta printers print_volume_x = get_param({}, key='print_volume_x', defaults_type='gcode') # in mm print_volume_y = get_param({}, key='print_volume_y', defaults_type='gcode') # in mm if delta: move_mesh_to_point(compas_mesh, Point(0, 0, 0)) else: move_mesh_to_point(compas_mesh, Point(print_volume_x / 2, print_volume_y / 2, 0)) # ----- slicing slicer = PlanarSlicer(compas_mesh, slicer_type="cgal", layer_height=4.5) slicer.slice_model() generate_brim(slicer, layer_width=3.0, number_of_brim_offsets=4) simplify_paths_rdp_igl(slicer, threshold=0.6) seams_smooth(slicer, smooth_distance=10) slicer.printout_info() save_to_json(slicer.to_data(), OUTPUT_DIR, 'slicer_data.json') # ----- print organization print_organizer = PlanarPrintOrganizer(slicer) print_organizer.create_printpoints() # Set fabrication-related parameters set_extruder_toggle(print_organizer, slicer) print_organizer.printout_info() # create and output gcode gcode_parameters = {} # leave all to default gcode_text = print_organizer.output_gcode(gcode_parameters) utils.save_to_text_file(gcode_text, OUTPUT_DIR, 'my_gcode.gcode')
def test_vertices_on_boundaries(): mesh = Mesh.from_obj(compas.get('quadmesh.obj')) print(mesh.vertices_on_boundaries()) assert mesh.vertices_on_boundaries() == [[ 6, 5, 4, 3, 2, 1, 0, 15, 14, 85, 84, 86, 76, 75, 74, 73, 88, 87, 33, 71, 17, 53, 89, 35, 62, 98, 44, 45, 37, 38, 39, 40, 41, 42, 43, 7 ]]
def weld_mesh(mesh, OUTPUT_PATH, precision='2f'): """ Welds mesh and check that the result is valid. """ for f_key in mesh.faces(): if len(mesh.face_vertices(f_key)) < 3: mesh.delete_face(f_key) welded_mesh = compas.datastructures.mesh_weld(mesh, precision=precision) welded_mesh.to_obj(os.path.join( OUTPUT_PATH, 'temp.obj')) # make sure there's no empty f_keys welded_mesh = Mesh.from_obj(os.path.join( OUTPUT_PATH, 'temp.obj')) # TODO: find a better way to do this try: welded_mesh.unify_cycles() logger.info("Unified cycles of welded_mesh") except AssertionError: logger.error("Attention! Could NOT unify cycles of welded_mesh") if not welded_mesh.is_valid(): # and iteration < 3: logger.error("Attention! Welded mesh is INVALID") if not welded_mesh.is_manifold(): logger.error("Attention! Welded mesh is NON-MANIFOLD") return welded_mesh
def get_mesh_info(object_dir='faces.obj'): """ This function generates a mesh for an input object input: object_dir => the input object direction output: mesh_info_dict => all the detalies about the generated mesh inclding mesh instance, the vertices, vectecies on the boundary, and non-boundary vertices """ # create the mesh from .obj file mesh = Mesh.from_obj(cp.get(object_dir)) # get all vertices of the mesh all_vertices = list(mesh.vertices()) # get vertices on the boundary of the mesh on_boundry_vertices = list(mesh.vertices_on_boundary()) # get vertices which are not on the boundary of the mesh non_on_boundry_vertices = list( set(all_vertices) - set(on_boundry_vertices)) mesh_info_dict = { 'mesh': mesh, 'all_vertices': all_vertices, 'on_boundry_vertices': on_boundry_vertices, 'non_on_boundry_vertices': non_on_boundry_vertices } return mesh_info_dict
def from_obj(self): filename, _ = get_obj_file() if filename: self.mesh = Mesh.from_obj(filename) # self.center_mesh() self.view.make_buffers() self.view.updateGL()
def main(): compas_mesh = Mesh.from_obj(os.path.join(DATA, MODEL)) move_mesh_to_point(compas_mesh, Point(0, 0, 0)) # Slicing slicer = PlanarSlicer(compas_mesh, slicer_type="cgal", layer_height=5.0) slicer.slice_model() # Sorting into vertical layers and reordering sort_into_vertical_layers(slicer, max_paths_per_layer=10) reorder_vertical_layers(slicer, align_with="x_axis") # Post-processing generate_brim(slicer, layer_width=3.0, number_of_brim_offsets=5) simplify_paths_rdp_igl(slicer, threshold=0.7) seams_smooth(slicer, smooth_distance=10) slicer.printout_info() save_to_json(slicer.to_data(), OUTPUT_DIR, 'slicer_data.json') # PlanarPrintOrganization print_organizer = PlanarPrintOrganizer(slicer) print_organizer.create_printpoints() set_extruder_toggle(print_organizer, slicer) add_safety_printpoints(print_organizer, z_hop=10.0) set_linear_velocity_constant(print_organizer, v=25.0) set_blend_radius(print_organizer, d_fillet=10.0) print_organizer.printout_info() printpoints_data = print_organizer.output_printpoints_dict() utils.save_to_json(printpoints_data, OUTPUT_DIR, 'out_printpoints.json')
def visualize_mesh_traversal() -> None: ''' Datastructures task ''' mesh = Mesh.from_obj(get('faces.obj')) x_values = {} for vkey in mesh.vertices_on_boundary(): x_values[vkey] = mesh.vertex_coordinates(vkey)[0] max_x = max(x_values.values()) print("Vertices on the right edge of the mesh:") print([key for key in x_values if x_values[key] == max_x]) start_key = int(input("\nSelect start vertex: ")) path_verts = traverse_mesh(mesh, start_key) print('\nPath calculated, starting MeshPlotter.') plotter = MeshPlotter(mesh, figsize=(16, 10)) plotter.draw_vertices(text={key: key for key in path_verts}, radius=0.2, facecolor={key: '#ff0000' for key in path_verts}) plotter.draw_edges() plotter.draw_faces() plotter.show()
def test_face_coordinates(): mesh = Mesh.from_obj(compas.get('quadmesh.obj')) assert mesh.face_coordinates(0, 'xyz') == [ [3.661179780960083, 2.32784628868103, 1.580246925354004], [3.775796413421631, 1.727785348892212, 1.382716059684753], [4.22069787979126, 1.696692585945129, 1.086419701576233], [4.109739303588867, 2.34430718421936, 1.283950567245483]] assert mesh.face_coordinates(0, 'zy') == [ [1.580246925354004, 2.32784628868103], [1.382716059684753, 1.727785348892212], [1.086419701576233, 1.696692585945129], [1.283950567245483, 2.34430718421936]]
def test_vertex_faces(): mesh = Mesh.from_obj(compas.get('faces.obj')) corners = list(mesh.vertices_where({'vertex_degree': 2})) boundary = list(mesh.vertices_where({'vertex_degree': 3})) internal = list(mesh.vertices_where({'vertex_degree': 4})) assert len(mesh.vertex_faces(corners[0])) == 1 assert len(mesh.vertex_faces(boundary[0])) == 2 assert len(mesh.vertex_faces(internal[0])) == 4
def test_vertex_normal(): mesh = Mesh.from_obj(compas.get('quadmesh.obj')) assert mesh.vertex_normal(0) == [ -0.7875436283909406, 0.07148692938164082, 0.6120985642103861 ] assert mesh.vertex_normal(5) == [ -0.482011312317331, -0.32250183520381565, 0.814651864963369 ]
def create_mesh(self, filepath): """ creates a "compas" mesh from a Rhino mesh object (saved as .obj file) filepath: file path in string format saves: compas mesh object """ mesh = Mesh.from_obj(filepath) self.dic_attr['mesh'] = mesh
def parse_collision_mesh_from_path(dir_path, filename, scale=1e-3): file_path = os.path.join(dir_path, filename) obj_name = filename.split('.')[0] if filename.endswith('.obj'): mesh = Mesh.from_obj(file_path) elif filename.endswith('.stl'): mesh = Mesh.from_stl(file_path) else: return None cm = CollisionMesh(mesh, obj_name) cm.scale(scale) return cm
def load_model(self, xdraw_function=None): """Load the geometry (meshes) of the robot. Args: xdraw_function (function, ): The function to draw the meshes in the respective CAD environment. Defaults to None. """ path = self.get_model_path() # the links loaded as meshes m0 = Mesh.from_obj(os.path.join(path, 'base_and_shoulder.obj')) m1 = Mesh.from_obj(os.path.join(path, 'upperarm.obj')) m2 = Mesh.from_obj(os.path.join(path, 'forearm.obj')) m3 = Mesh.from_obj(os.path.join(path, 'wrist1.obj')) m4 = Mesh.from_obj(os.path.join(path, 'wrist2.obj')) m5 = Mesh.from_obj(os.path.join(path, 'wrist3.obj')) # draw the geometry in the respective CAD environment if xdraw_function: m0 = xdraw_function(m0) m1 = xdraw_function(m1) m2 = xdraw_function(m2) m3 = xdraw_function(m3) m4 = xdraw_function(m4) m5 = xdraw_function(m5) self.model = [m0, m1, m2, m3, m4, m5]
def main(): start_time = time.time() ### --- Load stl compas_mesh = Mesh.from_obj(os.path.join(DATA, MODEL)) ### --- Move to origin move_mesh_to_point(compas_mesh, Point(0, 0, 0)) ### --- Slicer # options: 'default' : Both for open and closed paths. But slow # 'cgal' : Very fast. Only for closed paths. Requires additional installation (compas_cgal). slicer = PlanarSlicer(compas_mesh, slicer_type="cgal", layer_height=1.5) slicer.slice_model() ### --- Generate brim generate_brim(slicer, layer_width=3.0, number_of_brim_paths=3) ### --- Simplify the paths by removing points with a certain threshold # change the threshold value to remove more or less points simplify_paths_rdp(slicer, threshold=0.7) ### --- Smooth the seams between layers # change the smooth_distance value to achieve smoother, or more abrupt seams seams_smooth(slicer, smooth_distance=10) ### --- Prints out the info of the slicer slicer.printout_info() viewer = ObjectViewer() viewer.view.use_shaders = False slicer.visualize_on_viewer(viewer) utils.save_to_json(slicer.to_data(), OUTPUT_DIR, 'slicer_data.json') ### --- Fabrication - related information print_organizer = PrintOrganizer(slicer) print_organizer.create_printpoints(compas_mesh) print_organizer.set_extruder_toggle() print_organizer.add_safety_printpoints(z_hop=20) print_organizer.set_linear_velocity("constant", v=25) ### --- Save printpoints dictionary to json file printpoints_data = print_organizer.output_printpoints_dict() utils.save_to_json(printpoints_data, OUTPUT_DIR, 'out_printpoints.json') print_organizer.visualize_on_viewer(viewer, visualize_polyline=True, visualize_printpoints=False) viewer.update() viewer.show() end_time = time.time() print("Total elapsed time", round(end_time - start_time, 2), "seconds")
def create_setup(filename): """ Setting up the stage for testing. """ FILE = os.path.abspath(os.path.join(DATA, filename)) compas_mesh = Mesh.from_obj(FILE) slicer = PlanarSlicer(compas_mesh, slicer_type="default", layer_height=20) slicer.slice_model() generate_brim(slicer, layer_width=3.0, number_of_brim_offsets=3) simplify_paths_rdp(slicer, threshold=1.3) # seams_smooth(slicer, smooth_distance=10) slicer.printout_info() print_organizer = PlanarPrintOrganizer(slicer) print_organizer.create_printpoints() return slicer, print_organizer
def load_model(self, xdraw_function=None): """Load the geometry (meshes) of the tool. Args: xdraw_function (function, optional): The function to draw the meshes in the respective CAD environment. Defaults to None. """ datapath = get_data("robots/ur/tools/measurement_tool.obj") self.model = [Mesh.from_obj(datapath)] # draw the geometry in the respective CAD environment if xdraw_function: for i, m in enumerate(self.model): self.model[i] = xdraw_function(m)
def _mesh_import(url, filename): """Internal function to load meshes using the correct loader. Name and file might be the same but not always, e.g. temp files.""" file_extension = _get_file_format(url) if file_extension not in SUPPORTED_FORMATS: raise NotImplementedError( 'Mesh type not supported: {}'.format(file_extension)) print(filename) if file_extension == "dae": # no dae support yet #mesh = Mesh.from_dae(filename) obj_filename = filename.replace(".dae", ".obj") if os.path.isfile(obj_filename): mesh = Mesh.from_obj(obj_filename) # former DAE files have yaxis and zaxis swapped # TODO: already fix in conversion to obj frame = Frame([0,0,0], [1,0,0], [0,0,1]) T = Transformation.from_frame(frame) mesh_transform(mesh, T) return mesh else: raise FileNotFoundError("Please convert '%s' into an OBJ file, \ since DAE is currently not supported \ yet." % filename) if file_extension == 'obj': return Mesh.from_obj(filename) elif file_extension == 'stl': return Mesh.from_stl(filename) elif file_extension == 'ply': return Mesh.from_ply(filename) raise Exception
def main(): start_time = time.time() ### --- Load stl compas_mesh = Mesh.from_obj(os.path.join(DATA, MODEL)) ### --- Move to origin move_mesh_to_point(compas_mesh, Point(0, 0, 0)) ### --- Slicer # try out different slicers by changing the slicer_type # options: 'default', 'meshcut', 'cgal' slicer = PlanarSlicer(compas_mesh, slicer_type="default", layer_height=1.5) slicer.slice_model() ### --- Generate brim generate_brim(slicer, layer_width=3.0, number_of_brim_paths=3) ### --- Simplify the printpaths by removing points with a certain threshold # change the threshold value to remove more or less points simplify_paths_rdp(slicer, threshold=0.9) ### --- Prints out the info of the slicer slicer.printout_info() viewer = ObjectViewer() viewer.view.use_shaders = False slicer.visualize_on_viewer(viewer) utils.save_to_json(slicer.to_data(), OUTPUT_DIR, 'slicer_data.json') ### --- Fabrication - related information print_organizer = PrintOrganizer(slicer) print_organizer.create_printpoints(compas_mesh) print_organizer.set_extruder_toggle() print_organizer.add_safety_printpoints(z_hop=20) print_organizer.set_linear_velocity("constant", v=25) ### --- Save printpoints dictionary to json file printpoints_data = print_organizer.output_printpoints_dict() utils.save_to_json(printpoints_data, OUTPUT_DIR, 'out_printpoints.json') # # print_organizer.visualize_on_viewer(viewer, visualize_polyline=True, visualize_printpoints=False) viewer.update() viewer.show() end_time = time.time() print("Total elapsed time", round(end_time - start_time, 2), "seconds")
def load_multiple_meshes(starts_with, ends_with, path, folder_name): """ Load all the meshes that have the specified name, and print them in different colors. """ filenames = get_files_with_name(starts_with, ends_with, os.path.join(path, folder_name, 'output')) meshes = [ Mesh.from_obj(os.path.join(path, folder_name, 'output', filename)) for filename in filenames ] loaded_meshes = [] for i, m in enumerate(meshes): artist = MeshArtist(m) color = get_color(i, total=len(meshes)) mesh = artist.draw(color) loaded_meshes.append(mesh) return loaded_meshes
def _mesh_import(name, file): """Internal function to load meshes using the correct loader. Name and file might be the same but not always, e.g. temp files.""" file_extension = _get_file_format(name) if file_extension not in SUPPORTED_FORMATS: raise NotImplementedError( 'Mesh type not supported: {}'.format(file_extension)) if file_extension == 'obj': return Mesh.from_obj(file) elif file_extension == 'stl': return Mesh.from_stl(file) elif file_extension == 'ply': return Mesh.from_ply(file) raise Exception
def fixed_waam_setup(): HERE = os.path.dirname(__file__) package_path = os.path.abspath( os.path.join(HERE, "..", "..", "data", "robots", "abb_fixed_waam")) urdf_filename = os.path.join(package_path, "urdf", "abb_fixed_waam.urdf") srdf_filename = os.path.join(package_path, "srdf", "abb_fixed_waam.srdf") model = RobotModel.from_urdf_file(urdf_filename) semantics = RobotSemantics.from_srdf_file(srdf_filename, model) tool_frame_robotA = Frame.from_euler_angles( [0.591366, -0.000922, 1.570177], static=True, axes='xyz', point=[-0.002241, -0.000202, 0.505922]) tool_mesh_robotA = Mesh.from_obj( os.path.join(package_path, "meshes", "collision", "waam_tool.obj")) robotA_tool = Tool(tool_mesh_robotA, tool_frame_robotA, collision=tool_mesh_robotA) return urdf_filename, semantics, robotA_tool
return f, g # ============================================================================== # Main # ============================================================================== if __name__ == "__main__": import compas from compas.datastructures import Mesh from compas.plotters import MeshPlotter from compas.topology import mesh_quads_to_triangles mesh = Mesh.from_obj(compas.get('faces.obj')) mesh_quads_to_triangles(mesh) split = mesh.split_edge_tri(15, 20) facecolor = { key: '#cccccc' if key != split else '#ff0000' for key in mesh.vertices() } plotter = MeshPlotter(mesh, figsize=(10, 7)) plotter.draw_vertices(text={key: key for key in mesh.vertices()}, radius=0.2,
return pymesh.slice_mesh(m, [0, 0, 1], 50) # def mesh_contours_igl(mesh, levels=None, density=100): # pass # ============================================================================== # Main # ============================================================================== if __name__ == "__main__": import compas from compas.datastructures import Mesh from compas.datastructures import mesh_contours_numpy mesh = Mesh.from_obj(compas.get('saddle.obj')) # res = mesh_contours_pymesh(mesh) # print(res) levels, contours = mesh_contours_numpy(mesh) for i in range(len(contours)): level = levels[i] contour = contours[i] print(level) for path in contour: for polygon in path: print([point.tolist() for point in polygon])