def generate_path_tree(self): """ Specialized path generation for Waterbomb tesselation pattern """ unit_factor = self.calc_unit_factor() length = self.options.length * unit_factor vertex_radius = self.options.vertex_radius * unit_factor cols = self.options.columns lines = self.options.lines phase_shift = self.options.phase_shift pattern_first_line = self.options.pattern_first_line pattern_last_line = self.options.pattern_last_line # create vertices vertex_line_types = [[ Path(((i / 2.) * length, 0), style='p', radius=vertex_radius) for i in range(2 * cols + 1) ], [ Path((i * length, 0), style='p', radius=vertex_radius) for i in range(cols + 1) ], [ Path(((i + 0.5) * length, 0), style='p', radius=vertex_radius) for i in range(cols) ]] vertices = [] for i in range(2 * lines + 1): if i % 2 == 0 or (pattern_first_line == 'magic_ball' and i == 1) or (pattern_last_line == 'magic_ball' and i == 2 * lines - 1): type = 0 elif (i / 2 + phase_shift) % 2 == 0: type = 1 else: type = 2 vertices = vertices + Path.list_add(vertex_line_types[type], (0, 0.5 * i * length)) # create a list for the horizontal creases and another for the vertical creases # alternate strokes to minimize laser cutter path corr_fist_line = length / 2 if pattern_first_line == 'magic_ball' else 0 corr_last_line = length / 2 if pattern_last_line == 'magic_ball' else 0 grid = [ Path.generate_hgrid([0, length * cols], [0, length * lines], lines, 'm'), Path.generate_vgrid( [0, length * cols], [corr_fist_line, length * lines - corr_last_line], 2 * cols, 'm') ] vgrid_a = Path.generate_vgrid([0, length * cols], [0, length / 2], 2 * cols, 'v') vgrid_b = Path.list_add(vgrid_a, (0, (lines - 0.5) * length)) if pattern_first_line == 'magic_ball' and pattern_last_line == 'magic_ball': grid[1] = [[vgrid_a[i], grid[1][i], vgrid_b[i]] if i % 2 == 0 else [vgrid_b[i], grid[1][i], vgrid_a[i]] for i in range(len(grid[1]))] elif pattern_first_line == 'magic_ball': grid[1] = [[vgrid_a[i], grid[1][i]] if i % 2 == 0 else [grid[1][i], vgrid_a[i]] for i in range(len(grid[1]))] elif pattern_last_line == 'magic_ball': grid[1] = [[grid[1][i], vgrid_b[i]] if i % 2 == 0 else [vgrid_b[i], grid[1][i]] for i in range(len(grid[1]))] # create generic valley Path lines, one pointing up and other pointing down valley_types = [ Path([(i * length / 2, (1 - i % 2) * length / 2) for i in range(2 * cols + 1)], 'v'), Path([(i * length / 2, (i % 2) * length / 2) for i in range(2 * cols + 1)], 'v') ] # define which lines must be of which type, according to parity and options senses = np.array( [bool((i % 2 + i) / 2 % 2) for i in range(2 * lines)]) senses = 1 * senses # converts bool array to 0's and 1's if phase_shift: senses = np.invert(senses) if pattern_first_line == "magic_ball": senses[0] = ~senses[0] if pattern_last_line == "magic_ball": senses[-1] = ~senses[-1] valleys = [ valley_types[senses[i]] + (0, i * length / 2) for i in range(2 * lines) ] # convert first and last lines to mountains if magic_ball if pattern_first_line == "magic_ball": valleys[0].style = 'm' if pattern_last_line == "magic_ball": valleys[-1].style = 'm' # invert every two lines to minimize laser cutter movements for i in range(1, 2 * lines, 2): valleys[i].invert() self.edge_points = [ (0 * length * cols, 0 * length * lines), # top left (1 * length * cols, 0 * length * lines), # top right (1 * length * cols, 1 * length * lines), # bottom right (0 * length * cols, 1 * length * lines) ] # bottom left self.path_tree = [grid, valleys, vertices]
def generate_path_tree(self): """ Specialized path generation for Waterbomb tesselation pattern """ unit_factor = self.calc_unit_factor() vertex_radius = self.options.vertex_radius * unit_factor lines = self.options.lines sides = self.options.sides radius = self.options.radius * unit_factor angle_ratio = self.options.angle_ratio mirror_cells = self.options.mirror_cells theta = (pi / 2.) * (1 - 2. / sides) l = 2. * radius * cos(theta * (1. - angle_ratio)) a = 2. * radius * sin(pi / sides) # b = sqrt(a*a + l*l - 2*a*l*cos(angle_ratio*theta)) # phi = abs(acos((l*l + b*b - a*a)/(2*l*b))) # gamma = pi/2 - angle_ratio*theta - phi # dy = b*cos(gamma) # dx = b*sin(gamma) dy = l * sin(theta * angle_ratio) dx = l * cos(theta * angle_ratio) - a add_attachment = self.options.add_attachment attachment_percentage = self.options.attachment_percentage / 100. attachment_height = a * (attachment_percentage - 1) * tan( angle_ratio * theta) vertices = [] for i in range(sides + 1): for j in range(lines + 1): if mirror_cells: vertices.append( Path((dx * ((lines - j) % 2) + a * i, dy * j), style='p', radius=vertex_radius)) else: vertices.append( Path((dx * (lines - j) + a * i, dy * j), style='p', radius=vertex_radius)) # create a horizontal grid, then offset each line according to angle grid_h = Path.generate_hgrid([0, a * sides], [0, dy * lines], lines, 'm') if not mirror_cells: # shift every mountain line of the grid to the right by increasing amounts grid_h = Path.list_add(grid_h, [(i * dx, 0) for i in range(lines - 1, 0, -1)]) else: # shift every OTHER mountain line of the grid a bit to the right grid_h = Path.list_add(grid_h, [((i % 2) * dx, 0) for i in range(lines - 1, 0, -1)]) if add_attachment: for i in range(lines % 2, lines - 1, 2): # hacky solution, changes length of every other mountain line grid_h[i].points[1 - i % 2] = (grid_h[i].points[1 - i % 2][0] + a * attachment_percentage, grid_h[i].points[1 - i % 2][1]) # create MV zigzag for Kresling pattern zigzag = Kresling.generate_kresling_zigzag(sides, radius, angle_ratio, add_attachment) zigzags = [] # duplicate zigzag pattern for desired number of cells if not mirror_cells: for i in range(lines): zigzags.append( Path.list_add(zigzag, (i * dx, (lines - i) * dy))) else: zigzag_mirror = Path.list_reflect(zigzag, (0, lines * dy / 2), (dx, lines * dy / 2)) for i in range(lines): if i % 2 == 1: zigzags.append( Path.list_add(zigzag_mirror, (0, -(lines - i + (lines - 1) % 2) * dy))) else: zigzags.append(Path.list_add(zigzag, (0, (lines - i) * dy))) # create edge strokes if not mirror_cells: self.edge_points = [ (a * sides, dy * lines), # bottom right (0, dy * lines), # bottom left (dx * lines, 0), # top left (dx * lines + a * sides, 0) ] # top right if add_attachment: for i in range(lines): x = dx * (lines - i) + a * (sides + attachment_percentage) self.edge_points.append((x, dy * i)) self.edge_points.append((x, dy * i - attachment_height)) if i != lines - 1: self.edge_points.append( (x - dx - a * attachment_percentage, dy * (i + 1))) pass else: self.edge_points = [(a * sides + (lines % 2) * dx, 0)] for i in range(lines + 1): self.edge_points.append([((lines + i) % 2) * dx, dy * i]) self.edge_points.append( [a * sides + ((lines + i) % 2) * dx, lines * dy]) if add_attachment: for i in range(lines + 1): if not i % 2 == 0: self.edge_points.append([ a * sides + (i % 2) * (dx + a * attachment_percentage), dy * (lines - i) - (i % 2) * attachment_height ]) self.edge_points.append([ a * sides + (i % 2) * (dx + a * attachment_percentage), dy * (lines - i) ]) if (i != lines): self.edge_points.append([ a * sides + (i % 2) * (dx + a * attachment_percentage), dy * (lines - i) + (i % 2) * attachment_height ]) else: self.edge_points.append([ a * sides + (i % 2) * (dx + a * attachment_percentage), dy * (lines - i) ]) else: for i in range(lines + 1): self.edge_points.append( [a * sides + (i % 2) * dx, dy * (lines - i)]) self.path_tree = [grid_h, zigzags, vertices]