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')
Beispiel #2
0
    def get_layer_ppts(self, layer, base_boundary):
        """ Creates the PrintPoints of a single layer."""
        max_layer_height = get_param(self.parameters,
                                     key='max_layer_height',
                                     defaults_type='layers')
        min_layer_height = get_param(self.parameters,
                                     key='min_layer_height',
                                     defaults_type='layers')
        avg_layer_height = get_param(self.parameters, 'avg_layer_height',
                                     'layers')

        all_pts = [pt for path in layer.paths for pt in path.points]
        closest_fks, projected_pts = utils.pull_pts_to_mesh_faces(
            self.slicer.mesh, all_pts)
        normals = [
            Vector(*self.slicer.mesh.face_normal(fkey)) for fkey in closest_fks
        ]

        count = 0
        crv_to_check = Path(
            base_boundary.points,
            True)  # creation of fake path for the lower boundary

        layer_ppts = {}
        for i, path in enumerate(layer.paths):
            layer_ppts['path_%d' % i] = []

            for p in path.points:
                cp = closest_point_on_polyline(p,
                                               Polyline(crv_to_check.points))
                d = distance_point_point(cp, p)

                ppt = PrintPoint(pt=p,
                                 layer_height=avg_layer_height,
                                 mesh_normal=normals[count])

                ppt.closest_support_pt = Point(*cp)
                ppt.distance_to_support = d
                ppt.layer_height = max(min(d, max_layer_height),
                                       min_layer_height)
                ppt.up_vector = Vector(
                    *normalize_vector(Vector.from_start_end(cp, p)))
                ppt.frame = ppt.get_frame()

                layer_ppts['path_%d' % i].append(ppt)
                count += 1

            crv_to_check = path

        return layer_ppts
    def generate_paths(self):
        """ Generates isocontours. """
        start_domain, end_domain = min(self.scalar_field), max(
            self.scalar_field)
        step = (end_domain - start_domain) / (self.no_of_isocurves + 1)

        max_dist = get_param(self.parameters,
                             key='vertical_layers_max_centroid_dist',
                             defaults_type='layers')
        vertical_layers_manager = VerticalLayersManager(max_dist)

        # create paths + layers
        with progressbar.ProgressBar(max_value=self.no_of_isocurves) as bar:
            for i in range(0, self.no_of_isocurves + 1):
                for vkey, data in self.mesh.vertices(data=True):
                    if i == 0:
                        data['scalar_field'] = self.scalar_field[
                            vkey] - 0.05 * step  # things can be tricky in the edge
                    else:
                        data['scalar_field'] = self.scalar_field[
                            vkey] - i * step

                contours = ScalarFieldContours(self.mesh)
                contours.compute()
                contours.add_to_vertical_layers_manager(
                    vertical_layers_manager)

                bar.update(i)  # advance progress bar

        self.layers = vertical_layers_manager.layers
Beispiel #4
0
    def generate_paths(self):
        """ Generates isocontours. """
        paths_type = 'flat'  # 'spiral' # 'zigzag'
        v_left, v_right = 0.0, 1.0 - 1e-5

        max_dist = get_param(self.parameters,
                             key='vertical_layers_max_centroid_dist',
                             defaults_type='layers')
        vertical_layers_manager = VerticalLayersManager(max_dist)

        # create paths + layers
        with progressbar.ProgressBar(max_value=self.no_of_isocurves) as bar:
            for i in range(0, self.no_of_isocurves + 1):
                if i == 0:
                    i += 0.05  # contours are a bit tricky in the edges
                if paths_type == 'spiral':
                    u1, u2 = i, i + 1.0
                else:  # 'flat'
                    u1 = u2 = i

                p1 = (u1, v_left)
                p2 = (u2, v_right)

                contours = UVContours(self.mesh, p1, p2)
                contours.compute()
                contours.add_to_vertical_layers_manager(
                    vertical_layers_manager)

                bar.update(i)  # advance progress bar

        self.layers = vertical_layers_manager.layers
Beispiel #5
0
 def topological_sorting(self):
     """ When the print consists of various paths, this function initializes a class that creates
     a directed graph with all these parts, with the connectivity of each part reflecting which
     other parts it lies on, and which other parts lie on it."""
     max_layer_height = get_param(self.parameters,
                                  key='max_layer_height',
                                  defaults_type='layers')
     self.topo_sort_graph = topo_sort.SegmentsDirectedGraph(
         self.slicer.mesh,
         self.vertical_layers,
         max_layer_height,
         DATA_PATH=self.DATA_PATH)
    def create_compound_targets(self):
        """ Creates the target_LOW and the target_HIGH and computes the geodesic distances. """

        # --- low target
        geodesics_method = get_param(self.parameters,
                                     key='target_LOW_geodesics_method',
                                     defaults_type='interpolation_slicing')
        method, params = 'min', [
        ]  # no other union methods currently supported for lower target
        self.target_LOW = CompoundTarget(self.mesh,
                                         'boundary',
                                         1,
                                         self.DATA_PATH,
                                         union_method=method,
                                         union_params=params,
                                         geodesics_method=geodesics_method)

        # --- high target
        geodesics_method = get_param(self.parameters,
                                     key='target_HIGH_geodesics_method',
                                     defaults_type='interpolation_slicing')
        method, params = get_union_method(self.parameters)
        self.target_HIGH = CompoundTarget(self.mesh,
                                          'boundary',
                                          2,
                                          self.DATA_PATH,
                                          union_method=method,
                                          union_params=params,
                                          geodesics_method=geodesics_method)

        # --- uneven boundaries of high target
        self.target_HIGH.offset = get_param(
            self.parameters,
            key='uneven_upper_targets_offset',
            defaults_type='interpolation_slicing')
        self.target_HIGH.compute_uneven_boundaries_weight_max(self.target_LOW)

        #  --- save intermediary get_distance outputs
        self.target_LOW.save_distances("distances_LOW.json")
        self.target_HIGH.save_distances("distances_HIGH.json")
def get_union_method(params_dict):
    """
    Read input params_dict and return union method id and its parameters.
    target_type: LOW/HIGH
    """
    smooth_union_data = get_param(params_dict,
                                  key='target_HIGH_smooth_union',
                                  defaults_type='interpolation_slicing')
    chamfer_union_data = get_param(params_dict,
                                   key='target_HIGH_chamfer_union',
                                   defaults_type='interpolation_slicing')
    stairs_union_data = get_param(params_dict,
                                  key='target_HIGH_stairs_union',
                                  defaults_type='interpolation_slicing')
    if smooth_union_data[0]:
        method = 'smooth'
        params = smooth_union_data[1]
        assert not chamfer_union_data[0] and not stairs_union_data[
            0], 'You can only select one union method.'
        assert len(params) == 1, 'Wrong number of union params'
        return method, params
    elif chamfer_union_data[0]:
        method = 'chamfer'
        params = chamfer_union_data[1]
        assert not smooth_union_data[0] and not stairs_union_data[
            0], 'You can only select one union method.'
        assert len(params) == 1, 'Wrong number of union params'
        return method, params
    elif stairs_union_data[0]:
        method = 'stairs'
        params = stairs_union_data[1]
        assert not smooth_union_data[0] and not chamfer_union_data[
            0], 'You can only select one union method.'
        assert len(params) == 2, 'Wrong number of union params'
        return method, params
    else:
        method = 'min'
        params = []
        return method, params
Beispiel #8
0
    def create_printpoints(self):
        """
        Create the print points of the fabrication process
        Based on the directed graph, select one topological order.
        From each path collection in that order copy PrintPoints dictionary in the correct order.
        """
        current_layer_index = 0

        # (1) --- First add the printpoints of the horizontal brim layer (first layer of print)
        self.printpoints_dict['layer_0'] = {}
        if len(self.horizontal_layers) > 0:  # first add horizontal brim layers
            paths = self.horizontal_layers[0].paths
            for j, path in enumerate(paths):
                self.printpoints_dict['layer_0']['path_%d' % j] = \
                    [PrintPoint(pt=point, layer_height=get_param(self.parameters, 'avg_layer_height', 'layers'),
                                mesh_normal=utils.get_normal_of_path_on_xy_plane(k, point, path, self.slicer.mesh))
                     for k, point in enumerate(path.points)]
            current_layer_index += 1

        # (2) --- Select order of vertical layers
        if len(self.vertical_layers
               ) > 1:  # the you need to select one topological order
            all_orders = self.topo_sort_graph.get_all_topological_orders()
            self.selected_order = all_orders[
                0]  # TODO: add more elaborate selection strategy
        else:
            self.selected_order = [
                0
            ]  # there is only one segment, only this option

        # (3) --- Then create the printpoints of all the vertical layers in the selected order
        for index, i in enumerate(self.selected_order):
            layer = self.vertical_layers[i]
            self.printpoints_dict['layer_%d' % current_layer_index] = {}
            self.printpoints_dict['layer_%d' %
                                  current_layer_index] = self.get_layer_ppts(
                                      layer, self.base_boundaries[i])
            current_layer_index += 1
Beispiel #9
0
    def create_printpoints(self):
        """ Create the print points of the fabrication process """
        count = 0
        logger.info('Creating print points ...')
        with progressbar.ProgressBar(max_value=self.slicer.number_of_points) as bar:

            for i, layer in enumerate(self.slicer.layers):
                self.printpoints_dict['layer_%d' % i] = {}

                for j, path in enumerate(layer.paths):
                    self.printpoints_dict['layer_%d' % i]['path_%d' % j] = []

                    for k, point in enumerate(path.points):
                        normal = utils.get_normal_of_path_on_xy_plane(k, point, path, self.slicer.mesh)

                        h = get_param(self.parameters, 'avg_layer_height', defaults_type='layers')
                        printpoint = PrintPoint(pt=point, layer_height=h, mesh_normal=normal)

                        self.printpoints_dict['layer_%d' % i]['path_%d' % j].append(printpoint)
                        bar.update(count)
                        count += 1

        # transfer gradient information to printpoints
        transfer_mesh_attributes_to_printpoints(self.slicer.mesh, self.printpoints_dict)

        # add non-planar print data to printpoints
        for i, layer in enumerate(self.slicer.layers):
            layer_key = 'layer_%d' % i
            for j, path in enumerate(layer.paths):
                path_key = 'path_%d' % j
                for pp in self.printpoints_dict[layer_key][path_key]:
                    grad_norm = pp.attributes['gradient_norm']
                    grad = pp.attributes['gradient']
                    pp.distance_to_support = grad_norm
                    pp.layer_height = grad_norm
                    pp.up_vector = Vector(*normalize_vector(grad))
                    pp.frame = pp.get_frame()