def _slicer_task_4b(layer, ewidth, iwidth, conf, top_masks, bot_masks, perims): # Solid Mask outmask = [] for mask in top_masks: outmask = geom.union(outmask, geom.close_paths(mask)) for mask in bot_masks: outmask = geom.union(outmask, geom.close_paths(mask)) solid_mask = geom.clip(outmask, perims[-1]) bounds = geom.paths_bounds(outmask) # Solid Infill solid_infill = [] base_ang = 45 if layer % 2 == 0 else -45 solid_mask = geom.offset(solid_mask, conf['infill_overlap'] - ewidth) lines = geom.make_infill_lines(bounds, base_ang, 1.0, ewidth) for line in lines: lines = [line] lines = geom.clip(lines, solid_mask, subj_closed=False) solid_infill.extend(lines) # Sparse Infill sparse_infill = [] infill_type = conf['infill_type'] density = conf['infill_density'] / 100.0 if density > 0.0: if density >= 0.99: infill_type = "Lines" mask = geom.offset(perims[-1], conf['infill_overlap'] - iwidth) mask = geom.diff(mask, solid_mask) if infill_type == "Lines": base_ang = 90 * (layer % 2) + 45 lines = geom.make_infill_lines(bounds, base_ang, density, iwidth) elif infill_type == "Triangles": base_ang = 60 * (layer % 3) lines = geom.make_infill_triangles(bounds, base_ang, density, iwidth) elif infill_type == "Grid": base_ang = 90 * (layer % 2) + 45 lines = geom.make_infill_grid(bounds, base_ang, density, iwidth) elif infill_type == "Hexagons": base_ang = 120 * (layer % 3) lines = geom.make_infill_hexagons(bounds, base_ang, density, iwidth) else: lines = [] for line in lines: lines = [line] lines = geom.clip(lines, mask, subj_closed=False) sparse_infill.extend(lines) return solid_infill, sparse_infill
def _slicer_task_4a(ewidth, conf, layer_paths, supp_outline): # Raft raft_outline = [] raft_infill = [] if conf['adhesion_type'] == "Raft": rings = math.ceil(conf['brim_width'] / ewidth) outset = min(conf['skirt_outset'] + ewidth * conf['skirt_loops'], conf['raft_outset']) paths = geom.union(layer_paths, supp_outline) raft_outline = geom.offset(paths, outset) bounds = geom.paths_bounds(raft_outline) mask = geom.offset(raft_outline, conf['infill_overlap'] - ewidth) lines = geom.make_infill_lines(bounds, 0, 0.75, ewidth) raft_infill.append(geom.clip(lines, mask, subj_closed=False)) for layer in range(conf['raft_layers'] - 1): base_ang = 90 * ((layer + 1) % 2) lines = geom.make_infill_lines(bounds, base_ang, 1.0, ewidth) raft_infill.append( geom.clip(lines, raft_outline, subj_closed=False)) # Brim brim = [] adhesion = conf['adhesion_type'] brim_w = conf['brim_width'] if adhesion == "Brim": rings = math.ceil(brim_w / ewidth) for i in range(rings): brim.append(geom.offset(layer_paths, (i + 0.5) * ewidth)) # Skirt skirt = [] priming = [] skirt_w = conf['skirt_outset'] minloops = conf['skirt_loops'] minlen = conf['skirt_min_len'] skirt = geom.offset(layer_paths, brim_w + skirt_w + ewidth / 2.0) plen = sum( sum([ math.hypot(p2[0] - p1[0], p2[1] - p1[1]) for p1, p2 in zip(path, path[1:] + path[0:1]) ]) for path in skirt) loops = minloops if adhesion != "Raft": loops = max(loops, math.ceil(minlen / plen)) for i in range(loops - 1): priming.append(geom.offset(skirt, (i + 1) * ewidth)) return (geom.close_paths(raft_outline), raft_infill, geom.close_paths(brim), geom.close_paths(skirt), geom.close_paths(priming))
def _slicer_task_3b(layer, conf, ewidth, overhangs): # Support outline = [] infill = [] density = conf['support_density'] / 100.0 if density > 0.0: outline = geom.offset(overhangs, -ewidth / 2.0) outline = geom.close_paths(outline) mask = geom.offset(outline, conf['infill_overlap'] - ewidth) bounds = geom.paths_bounds(mask) lines = geom.make_infill_lines(bounds, 0, density, ewidth) infill = geom.clip(lines, mask, subj_closed=False) return outline, infill
def _slicer_task_1(z, ewidth, suppwidth, layer_h, conf, model): # Layer Slicing paths = model.slice_at_z(z - layer_h / 2, layer_h) paths = geom.orient_paths(paths) paths = geom.union(paths, []) # Overhang Masks supp_ang = conf['overhang_angle'] tris = model.get_overhang_footprint_triangles(ang=supp_ang, z=z) overhangs = geom.diff(geom.union(tris, []), paths) # Perimeters perims = [] for i in range(conf['shell_count']): shell = geom.offset(paths, -(i + 0.5) * ewidth) shell = geom.close_paths(shell) perims.append(shell) return paths, overhangs, perims
def slice_to_file(self, filename, showgui=False, threads=-1): print("Slicing start") layer_h = self.conf['layer_height'] dflt_nozl = self.conf['default_nozzle'] infl_nozl = self.conf['infill_nozzle'] supp_nozl = self.conf['support_nozzle'] ptcache = self.model.points if infl_nozl == -1: infl_nozl = dflt_nozl if supp_nozl == -1: supp_nozl = dflt_nozl dflt_nozl_d = self.conf['nozzle_{0}_diam'.format(dflt_nozl)] infl_nozl_d = self.conf['nozzle_{0}_diam'.format(infl_nozl)] supp_nozl_d = self.conf['nozzle_{0}_diam'.format(supp_nozl)] self.layer_height = layer_h self.extrusion_ratio = 1.25 self.extrusion_width = dflt_nozl_d * self.extrusion_ratio self.infill_width = infl_nozl_d * self.extrusion_ratio self.support_width = supp_nozl_d * self.extrusion_ratio height = self.model.points.maxz - self.model.points.minz layer_cnt = math.floor(height / layer_h) self.model.assign_layers(layer_h) self.layer_zs = [ self.model.points.minz + layer_h * (layer + 1) for layer in range(layer_cnt) ] if threads <= 0: threads = multiprocessing.cpu_count() * 2 # print('<tkcad formatversion="1.1" units="inches" showfractions="YES" material="Aluminum">', file=sys.stderr) executor = ThreadPoolExecutor if threads == 1 else ProcessPoolExecutor with executor(max_workers=threads) as ex: print("Stage 1: Perimeters") (self.layer_paths, self.overhang_masks, self.perimeter_paths) = zip(*list( ex.map(Slicer._slicer_task_1, self.layer_zs, [self.extrusion_width] * layer_cnt, [self.support_width] * layer_cnt, [layer_h] * layer_cnt, [self.conf] * layer_cnt, [self.model] * layer_cnt, chunksize=20))) print("Stage 2: Generate Masks") overhang_future = ex.submit(Slicer._slicer_task_2a, self.conf, self.overhang_masks, self.layer_paths) top_masks, bot_masks = zip(*list( ex.map(Slicer._slicer_task_2b, range(layer_cnt), [( [] if i < 1 else self.perimeter_paths[i - 1][-1]) for i in range(layer_cnt)], [p[-1] for p in self.perimeter_paths], [([] if i >= layer_cnt - 1 else self.perimeter_paths[i + 1][-1]) for i in range(layer_cnt)], chunksize=20))) overhang_drops = overhang_future.result() print("Stage 3: Support & Raft") (self.support_outline, self.support_infill) = zip(*list( ex.map(Slicer._slicer_task_3b, range(layer_cnt), [self.conf] * layer_cnt, [self.support_width] * layer_cnt, overhang_drops, chunksize=20))) del overhang_drops print("Stage 4: Path Generation") self.future_raft = ex.submit(self._slicer_task_4a, self.support_width, self.conf, self.layer_paths[0], self.support_outline[0]) top_cnt = self.conf['top_layers'] bot_cnt = self.conf['bottom_layers'] (self.solid_infill, self.sparse_infill) = zip(*list( ex.map(self._slicer_task_4b, range(layer_cnt), [self.extrusion_width] * layer_cnt, [self.infill_width] * layer_cnt, [self.conf] * layer_cnt, [top_masks[i:i + top_cnt] for i in range(layer_cnt)], [ bot_masks[max(0, i - bot_cnt + 1):i + 1] for i in range(layer_cnt) ], self.perimeter_paths, chunksize=20))) (self.raft_outline, self.raft_infill, self.brim_paths, self.skirt_paths, self.priming_paths) = self.future_raft.result() del top_masks del bot_masks raft_layers = len(self.raft_infill) for i in range(raft_layers): self.layer_zs.append(self.layer_zs[-1] + self.conf['layer_height']) print("Gcode") with open(filename, "w") as f: f.write("( raft_outline )\n") outline = geom.close_paths(self.raft_outline) for line in self._paths_gcode(outline, self.support_width, supp_nozl, self.layer_zs[0]): f.write(line) f.write("( raft_infill )\n") for layer, layer_paths in enumerate(self.raft_infill): for line in self._paths_gcode(layer_paths, self.support_width, supp_nozl, self.layer_zs[layer]): f.write(line) layer = raft_layers if self.priming_paths: f.write("( priming )\n") paths = geom.close_paths(self.priming_paths) for line in self._paths_gcode(paths, self.support_width, supp_nozl, self.layer_zs[layer]): f.write(line) if self.skirt_paths: f.write("( skirt )\n") for line in self._paths_gcode(self.skirt_paths, self.support_width, supp_nozl, self.layer_zs[layer]): f.write(line) if self.brim_paths: f.write("( brim )\n") paths = self.brim_paths for line in self._paths_gcode(paths + paths[0], self.support_width, supp_nozl, self.layer_zs[layer]): f.write(line) for slicenum in range(len(self.perimeter_paths)): layer = raft_layers + slicenum outline = geom.close_paths(self.support_outline[slicenum]) f.write("( support outline )\n") for line in self._paths_gcode(outline, self.support_width, supp_nozl, self.layer_zs[layer]): f.write(line) f.write("( support infill )\n") for line in self._paths_gcode(self.support_infill[slicenum], self.support_width, supp_nozl, self.layer_zs[layer]): f.write(line) f.write("( perimeters )\n") for paths in reversed(self.perimeter_paths[slicenum]): paths = geom.close_paths(paths) for line in self._paths_gcode(paths, self.extrusion_width, dflt_nozl, self.layer_zs[layer]): f.write(line) f.write("( solid fill )\n") for line in self._paths_gcode(self.solid_infill[slicenum], self.extrusion_width, dflt_nozl, self.layer_zs[layer]): f.write(line) f.write("( sparse infill )\n") for line in self._paths_gcode(self.sparse_infill[slicenum], self.infill_width, infl_nozl, self.layer_zs[layer]): f.write(line) # print('</tkcad>', file=sys.stderr) if showgui: self._display_paths()