from compas_slicer.print_organization import BasePrintOrganizer
from compas_slicer.pre_processing.preprocessing_utils import topological_sorting as topo_sort
from compas_slicer.print_organization.curved_print_organization import BaseBoundary
import compas_slicer
from compas.geometry import closest_point_on_polyline, distance_point_point, Polyline, Vector, normalize_vector, Point
import logging
from compas_slicer.geometry import Path, PrintPoint
import compas_slicer.utilities as utils
from compas_slicer.parameters import get_param
logger = logging.getLogger('logger')
__all__ = ['InterpolationPrintOrganizer']
[docs]class InterpolationPrintOrganizer(BasePrintOrganizer):
"""
Organizing the printing process for the realization of non-planar contours.
Attributes
----------
slicer: :class:`compas_slicer.slicers.PlanarSlicer`
An instance of the compas_slicer.slicers.PlanarSlicer.
parameters: dict
DATA_PATH: str
"""
[docs] def __init__(self, slicer, parameters, DATA_PATH):
assert isinstance(slicer, compas_slicer.slicers.InterpolationSlicer), 'Please provide an InterpolationSlicer'
BasePrintOrganizer.__init__(self, slicer)
self.DATA_PATH = DATA_PATH
self.OUTPUT_PATH = utils.get_output_directory(DATA_PATH)
self.parameters = parameters
self.vertical_layers = slicer.vertical_layers
self.horizontal_layers = slicer.horizontal_layers
assert len(self.vertical_layers) + len(self.horizontal_layers) == len(slicer.layers)
if len(self.horizontal_layers) > 0:
assert len(self.horizontal_layers) == 1, "Only one brim horizontal layer is currently supported."
assert self.horizontal_layers[0].is_brim, "Only one brim horizontal layer is currently supported."
logger.info('Slicer has one horizontal brim layer.')
# topological sorting of vertical layers depending on their connectivity
self.topo_sort_graph = None
if len(self.vertical_layers) > 1:
self.topological_sorting()
self.selected_order = None
# creation of one base boundary per vertical_layer
self.base_boundaries = self.create_base_boundaries()
def __repr__(self):
return "<InterpolationPrintOrganizer with %i vertical_layers>" % len(self.vertical_layers)
[docs] 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)
[docs] def create_base_boundaries(self):
""" Creates one BaseBoundary per vertical_layer."""
bs = []
root_vs = utils.get_mesh_vertex_coords_with_attribute(self.slicer.mesh, 'boundary', 1)
root_boundary = BaseBoundary(self.slicer.mesh, [Point(*v) for v in root_vs])
if len(self.vertical_layers) > 1:
for i, vertical_layer in enumerate(self.vertical_layers):
parents_of_current_node = self.topo_sort_graph.get_parents_of_node(i)
if len(parents_of_current_node) == 0:
boundary = root_boundary
else:
boundary_pts = []
for parent_index in parents_of_current_node:
parent = self.vertical_layers[parent_index]
boundary_pts.extend(parent.paths[-1].points)
boundary = BaseBoundary(self.slicer.mesh, boundary_pts)
bs.append(boundary)
else:
bs.append(root_boundary)
# save intermediary outputs
b_data = {i: b.to_data() for i, b in enumerate(bs)}
utils.save_to_json(b_data, self.OUTPUT_PATH, 'boundaries.json')
return bs
[docs] 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
[docs] 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
if __name__ == "__main__":
pass