[docs]classInterpolationPrintOrganizer(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):assertisinstance(slicer,compas_slicer.slicers.InterpolationSlicer),'Please provide an InterpolationSlicer'BasePrintOrganizer.__init__(self,slicer)self.DATA_PATH=DATA_PATHself.OUTPUT_PATH=utils.get_output_directory(DATA_PATH)self.parameters=parametersself.vertical_layers=slicer.vertical_layersself.horizontal_layers=slicer.horizontal_layersassertlen(self.vertical_layers)+len(self.horizontal_layers)==len(slicer.layers)iflen(self.horizontal_layers)>0:assertlen(self.horizontal_layers)==1,"Only one brim horizontal layer is currently supported."assertself.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 connectivityself.topo_sort_graph=Noneiflen(self.vertical_layers)>1:try:self.topological_sorting()exceptAssertionError:logger.exception("topology sorting failed\n")logger.critical("integrity of the output data ")# TODO: perhaps its better to be even more explicit and add a# FAILED-timestamp.txt file?self.selected_order=None# creation of one base boundary per vertical_layerself.base_boundaries=self.create_base_boundaries()
def__repr__(self):return"<InterpolationPrintOrganizer with %i vertical_layers>"%len(self.vertical_layers)
[docs]deftopological_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."""avg_layer_height=get_param(self.parameters,key='avg_layer_height',defaults_type='layers')self.topo_sort_graph=topo_sort.SegmentsDirectedGraph(self.slicer.mesh,self.vertical_layers,4*avg_layer_height,DATA_PATH=self.DATA_PATH)
[docs]defcreate_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)forvinroot_vs])iflen(self.vertical_layers)>1:fori,vertical_layerinenumerate(self.vertical_layers):parents_of_current_node=self.topo_sort_graph.get_parents_of_node(i)iflen(parents_of_current_node)==0:boundary=root_boundaryelse:boundary_pts=[]forparent_indexinparents_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 outputsb_data={i:b.to_data()fori,binenumerate(bs)}utils.save_to_json(b_data,self.OUTPUT_PATH,'boundaries.json')returnbs
[docs]defcreate_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']={}iflen(self.horizontal_layers)>0:# first add horizontal brim layerspaths=self.horizontal_layers[0].pathsforj,pathinenumerate(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))fork,pointinenumerate(path.points)]current_layer_index+=1# (2) --- Select order of vertical layersiflen(self.vertical_layers)>1:# then you need to select one topological orderifnotself.topo_sort_graph:logger.error("no topology graph found, cannnot set the order of vertical layers")self.selected_order=[0]else:all_orders=self.topo_sort_graph.get_all_topological_orders()self.selected_order=all_orders[0]# TODO: add more elaborate selection strategyelse: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 orderforindex,iinenumerate(self.selected_order):layer=self.vertical_layers[i]self.printpoints_dict['layer_%d'%current_layer_index]=self.get_layer_ppts(layer,self.base_boundaries[i])current_layer_index+=1
[docs]defget_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=[ptforpathinlayer.pathsforptinpath.points]closest_fks,projected_pts=utils.pull_pts_to_mesh_faces(self.slicer.mesh,all_pts)normals=[Vector(*self.slicer.mesh.face_normal(fkey))forfkeyinclosest_fks]count=0crv_to_check=Path(base_boundary.points,True)# creation of fake path for the lower boundarylayer_ppts={}fori,pathinenumerate(layer.paths):layer_ppts['path_%d'%i]=[]fork,pinenumerate(path.points):cp=closest_point_on_polyline(p,Polyline(crv_to_check.points))d=distance_point_point(cp,p)normal=normals[count]ppt=PrintPoint(pt=p,layer_height=avg_layer_height,mesh_normal=normal)ppt.closest_support_pt=Point(*cp)ppt.distance_to_support=dppt.layer_height=max(min(d,max_layer_height),min_layer_height)ppt.up_vector=self.get_printpoint_up_vector(path,k,normal)ifdot_vectors(subtract_vectors(p,ppt.closest_support_pt),ppt.up_vector)<0:ppt.up_vector=Vector(*scale_vector(ppt.up_vector,-1))ppt.frame=ppt.get_frame()layer_ppts['path_%d'%i].append(ppt)count+=1crv_to_check=pathreturnlayer_ppts