diff --git a/.vscode/settings.json b/.vscode/settings.json index b7e254a5..391bbf6c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,5 +2,4 @@ "python.linting.pylintEnabled": false, "python.linting.flake8Enabled": true, "python.linting.enabled": true, - "python.pythonPath": "C:\\Users\\joburger\\Anaconda3\\envs\\compas_slicer\\python.exe" } \ No newline at end of file diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 31297d8b..763d69d4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,14 +11,16 @@ Unreleased **Added** * Output nested printpoints +* Added reverse_open_paths argument to seams_align to control if the direction of open paths should be reversed or not. Defaults to False. +* Added reverse_open_paths argument to sort_paths_minimum_travel_time to control if the direction of open paths should be reversed or not. Defaults to False. **Changed** -* Updates in the visualization of PrintPoints -* Added seams_align(next_path) to the standard planar slicing routine -* Added unify_path_orientation back into the standard planar slicing routine - +* Updates in the visualization of PrintPoints. +* Added seams_align(next_path) to the standard planar slicing routine. +* Added unify_path_orientation back into the standard planar slicing routine. **Fixed** +* Changed unify_path_orientation to only work for closed paths. **Deprecated** diff --git a/src/compas_slicer/geometry/print_point.py b/src/compas_slicer/geometry/print_point.py index 17d68170..5f04eab1 100644 --- a/src/compas_slicer/geometry/print_point.py +++ b/src/compas_slicer/geometry/print_point.py @@ -42,6 +42,10 @@ def __init__(self, pt, layer_height, mesh_normal): self.pt = pt self.layer_height = layer_height + # --- layer, path index attributes + self.layer_index = None + self.path_index = None + self.mesh_normal = mesh_normal # compas.geometry.Vector self.up_vector = Vector(0, 0, 1) # default value that can be updated self.frame = self.get_frame() # compas.geometry.Frame @@ -90,6 +94,9 @@ def to_data(self): 'point': [self.pt[0], self.pt[1], self.pt[2]], 'layer_height': self.layer_height, + 'layer_index': self.layer_index, + 'path_index': self.path_index, + 'mesh_normal': self.mesh_normal.to_data(), 'up_vector': self.up_vector.to_data(), 'frame': self.frame.to_data(), diff --git a/src/compas_slicer/post_processing/seams_align.py b/src/compas_slicer/post_processing/seams_align.py index d5063d0a..21a115e4 100644 --- a/src/compas_slicer/post_processing/seams_align.py +++ b/src/compas_slicer/post_processing/seams_align.py @@ -8,7 +8,7 @@ __all__ = ['seams_align'] -def seams_align(slicer, align_with="next_path"): +def seams_align(slicer, align_with="next_path", reverse_open_paths=False): """Aligns the seams (start- and endpoint) of a print. Parameters @@ -22,6 +22,8 @@ def seams_align(slicer, align_with="next_path"): x_axis = orients the seam to the x_axis y_axis = orients the seam to the y_axis Point(x,y,z) = orients the seam according to the given point + reverse_open_paths: bool (defaults to False) + Boolean toggle whether to reverse the direction of open paths or not. Returns ------- @@ -39,24 +41,23 @@ def seams_align(slicer, align_with="next_path"): # determines the correct point to align the current path with if len(layer.paths) == 1 and i == 0: # if ONE PATH and FIRST LAYER - # >>> align with second layer - pt_to_align_with = slicer.layers[i + 1].paths[0].points[0] + # >>> align with first point of first layer (no change) + pt_to_align_with = slicer.layers[0].paths[0].points[0] if len(layer.paths) == 1 and i != 0: - last_path_index = len(slicer.layers[i - 1].paths) - 1 # if ONE PATH and NOT FIRST LAYER - # >>> align with previous layer - pt_to_align_with = slicer.layers[i - 1].paths[last_path_index].points[-1] + # >>> align with last point of previous layer + pt_to_align_with = slicer.layers[i - 1].paths[0].points[-1] if len(layer.paths) != 1 and i == 0 and j == 0: # if MULTIPLE PATHS and FIRST LAYER and FIRST PATH - # >>> align with second path of first layer + # >>> align with last point of next path of first layer pt_to_align_with = slicer.layers[i].paths[i + 1].points[-1] if len(layer.paths) != 1 and j != 0: # if MULTIPLE PATHS and NOT FIRST PATH - # >>> align with previous path + # >>> align with last point of previous path pt_to_align_with = slicer.layers[i].paths[j - 1].points[-1] if len(layer.paths) != 1 and i != 0 and j == 0: - # if MULTIPLE PATHS and NOT FIRST LAYER and FIRST PATH - # >>> align with first path of previous layer + # if MULTIPLE PATHS and NOT FIRST LAYER and NOT FIRST PATH + # >>> align with last point of previous path of previous layer last_path_index = len(slicer.layers[i - 1].paths) - 1 pt_to_align_with = slicer.layers[i - 1].paths[last_path_index].points[-1] @@ -74,7 +75,7 @@ def seams_align(slicer, align_with="next_path"): # CLOSED PATHS if path.is_closed: # get the points of the current layer and path - path_to_change = layer.paths[j].points + path_to_change = path.points # check if start- and end-points are the same point if path_to_change[0] == path_to_change[-1]: @@ -94,11 +95,11 @@ def seams_align(slicer, align_with="next_path"): if first_last_point_the_same: shift_list = shift_list + [shift_list[0]] - layer.paths[j].points = shift_list + path.points = shift_list else: # OPEN PATHS - path_to_change = layer.paths[j].points + path_to_change = path.points # get the distance between the align point and the start/end point start = path_to_change[0] @@ -107,8 +108,9 @@ def seams_align(slicer, align_with="next_path"): d_end = distance_point_point(end, pt_to_align_with) # if closer to end point > reverse list - if d_start > d_end: - layer.paths[j].points.reverse() + if reverse_open_paths: + if d_start > d_end: + path.points.reverse() if __name__ == "__main__": diff --git a/src/compas_slicer/post_processing/simplify_paths_rdp.py b/src/compas_slicer/post_processing/simplify_paths_rdp.py index 8d3937af..212d8d63 100644 --- a/src/compas_slicer/post_processing/simplify_paths_rdp.py +++ b/src/compas_slicer/post_processing/simplify_paths_rdp.py @@ -3,13 +3,8 @@ import logging import progressbar from compas.geometry import Point -import compas_slicer.utilities as utils from compas.plugins import PluginNotInstalledError -packages = utils.TerminalCommand('conda list').get_split_output_strings() -if 'igl' in packages: - import igl - logger = logging.getLogger('logger') __all__ = ['simplify_paths_rdp', @@ -55,7 +50,7 @@ def simplify_paths_rdp_igl(slicer, threshold): Low threshold removes few points, high threshold removes many points. """ try: - utils.check_package_is_installed('igl') + import igl logger.info("Paths simplification rdp - igl") remaining_pts_num = 0 diff --git a/src/compas_slicer/post_processing/sort_paths_minimum_travel_time.py b/src/compas_slicer/post_processing/sort_paths_minimum_travel_time.py index 50f15a5b..9dc7a865 100644 --- a/src/compas_slicer/post_processing/sort_paths_minimum_travel_time.py +++ b/src/compas_slicer/post_processing/sort_paths_minimum_travel_time.py @@ -8,13 +8,15 @@ __all__ = ['sort_paths_minimum_travel_time'] -def sort_paths_minimum_travel_time(slicer): +def sort_paths_minimum_travel_time(slicer, reverse_open_paths=False): """Sorts the paths within a horizontal layer to reduce total travel time. Parameters ---------- slicer: :class:`compas_slicer.slicers.BaseSlicer` An instance of one of the compas_slicer.slicers classes. + reverse_open_paths: bool (defaults to False) + Boolean toggle whether to reverse the direction of open paths or not. """ logger.info("Sorting contours to minimize travel time") @@ -23,7 +25,7 @@ def sort_paths_minimum_travel_time(slicer): for i, layer in enumerate(slicer.layers): sorted_paths = [] while len(layer.paths) > 0: - index = closest_path(ref_point, layer.paths) # find the closest path to the reference point + index = closest_path(ref_point, layer.paths, reverse_open_paths) # find the closest path to the reference point sorted_paths.append(layer.paths[index]) # add the closest path to the sorted list ref_point = layer.paths[index].points[-1] layer.paths.pop(index) @@ -31,7 +33,7 @@ def sort_paths_minimum_travel_time(slicer): slicer.layers[i].paths = sorted_paths -def adjust_seam_to_closest_pos(ref_point, path): +def adjust_seam_to_closest_pos(ref_point, path, reverse_open_paths): """Aligns the seam (start- and endpoint) of a contour so that it is closest to a given point. for open paths, check if the end point closest to the reference point is the start point @@ -57,11 +59,12 @@ def adjust_seam_to_closest_pos(ref_point, path): path.points = adjusted_seam else: # if path is open # if end point is closer than start point >> flip - if distance_point_point(ref_point, path.points[0]) > distance_point_point(ref_point, path.points[-1]): - path.points.reverse() + if reverse_open_paths: + if distance_point_point(ref_point, path.points[0]) > distance_point_point(ref_point, path.points[-1]): + path.points.reverse() -def closest_path(ref_point, somepaths): +def closest_path(ref_point, somepaths, reverse_open_paths): """Finds the closest path to a reference point in a list of paths. Parameters @@ -74,7 +77,7 @@ def closest_path(ref_point, somepaths): for i, path in enumerate(somepaths): # for each path, adjust the seam to be in the closest vertex to ref_point - adjust_seam_to_closest_pos(ref_point, path) + adjust_seam_to_closest_pos(ref_point, path, reverse_open_paths) # calculate the minimum distance to the nearest seam of each path min_dist_temp = distance_point_point(ref_point, path.points[0]) if min_dist_temp < min_dist: diff --git a/src/compas_slicer/post_processing/unify_paths_orientation.py b/src/compas_slicer/post_processing/unify_paths_orientation.py index d0bbb84b..fa830651 100644 --- a/src/compas_slicer/post_processing/unify_paths_orientation.py +++ b/src/compas_slicer/post_processing/unify_paths_orientation.py @@ -19,14 +19,15 @@ def unify_paths_orientation(slicer): for i, layer in enumerate(slicer.layers): for j, path in enumerate(layer.paths): - reference_points = None # find reference points for each path, if possible - if j > 0: - reference_points = layer.paths[0].points - elif i > 0 and j == 0: - reference_points = slicer.layers[i - 1].paths[0].points - - if reference_points: # then reorient current pts based on reference - path.points = match_paths_orientations(path.points, reference_points, path.is_closed) + if path.is_closed: + reference_points = None # find reference points for each path, if possible + if j > 0: + reference_points = layer.paths[0].points + elif i > 0 and j == 0: + reference_points = slicer.layers[i - 1].paths[0].points + + if reference_points: # then reorient current pts based on reference + path.points = match_paths_orientations(path.points, reference_points, path.is_closed) def match_paths_orientations(pts, reference_points, is_closed): diff --git a/src/compas_slicer/print_organization/planar_print_organizer.py b/src/compas_slicer/print_organization/planar_print_organizer.py index cb37689b..4bbd32d7 100644 --- a/src/compas_slicer/print_organization/planar_print_organizer.py +++ b/src/compas_slicer/print_organization/planar_print_organizer.py @@ -60,6 +60,9 @@ def create_printpoints(self, generate_mesh_normals=True): n = normals[count] if generate_mesh_normals else Vector(0, 0, 1) printpoint = PrintPoint(pt=point, layer_height=self.slicer.layer_height, mesh_normal=n) + printpoint.layer_index = i + printpoint.path_index = j + self.printpoints_dict['layer_%d' % i]['path_%d' % j].append(printpoint) bar.update(count) count += 1 diff --git a/src/compas_slicer/slicers/planar_slicing/planar_slicing_cgal.py b/src/compas_slicer/slicers/planar_slicing/planar_slicing_cgal.py index baee5d57..d15fbeaf 100644 --- a/src/compas_slicer/slicers/planar_slicing/planar_slicing_cgal.py +++ b/src/compas_slicer/slicers/planar_slicing/planar_slicing_cgal.py @@ -4,7 +4,6 @@ from compas_slicer.geometry import Path import progressbar import logging -import compas_slicer.utilities as utils from compas.plugins import PluginNotInstalledError logger = logging.getLogger('logger') @@ -21,11 +20,10 @@ def create_planar_paths_cgal(mesh, planes): A compas mesh. planes: list, :class: 'compas.geometry.Plane' """ - packages = utils.TerminalCommand('conda list').get_split_output_strings() - if 'compas-cgal' in packages or 'compas_cgal' in packages: + try: from compas_cgal.slicer import slice_mesh - else: + except Exception: raise PluginNotInstalledError("--------ATTENTION! ----------- \ Compas_cgal library is missing! \ You can't use this planar slicing method without it. \