def hsv_to_rgb(h, s, v): # h: hue: 0 to 360 # s: saturation: 0 to 1 # v: value: 0 to 1 def f(n): k = (n + (h / 60)) % 6 return v - (v * s * max(0, min(k, 4 - k, 1))) r, g, b = int(f(5) * 255), int(f(3) * 255), int(f(1) * 255) r, g, b = base_repr(r, base=16).zfill(2), base_repr( g, base=16).zfill(2), base_repr(b, base=16).zfill(2) return "#" + r + g + b
def get_ifs(self): transformations = [] prob_numerators = [] prob_denominators = [] for row in self.transformation_entries: try: a, b, c, d, e, f, p_num, p_den = list( map(lambda entry: float(entry.get()), row)) except ValueError: error_message( "There was an error in parsing the IFS code input.") return transformations.append(AffineTransformation(a, b, c, d, e, f)) prob_numerators.append(int(p_num)) prob_denominators.append(int(p_den)) return IteratedFunctionSystem( transformations), prob_numerators, prob_denominators
def go_button_pressed(): user_input = transformations_frame.get_ifs() if user_input is None: return ifs, prob_numerators, prob_denominators = transformations_frame.get_ifs() gen_op = generator_var.get() if gen_op == "Pseudo-random number generator": if use_bias_var.get() == 0: probs = [1.0 / ifs.size] * ifs.size else: probs = [r / s for r, s in zip(prob_numerators, prob_denominators)] gen = example_generators.get_random_generator(ifs.size, probs) elif use_bias_var.get() == 0: gen = dict(example_generators.all_generators)[gen_op](ifs.size) elif lcm(prob_denominators) > len(digits): error_message( "The least common multiple of the probability denominators must not be larger than " + str(len(digits)) + ".") return else: norm_gen = dict(example_generators.all_generators)[gen_op]( lcm(prob_denominators)) gen = example_generators.get_biased(norm_gen, prob_numerators, prob_denominators) try: num_iters = int(num_iters_entry.get()) except ValueError: error_message("Could not parse " + num_iters_entry.get() + " as a number of iterations.") return img, gen_str = ifs.get_image(IMAGE_WIDTH, IMAGE_HEIGHT, num_iters, gen, colors=show_colors_var.get() == 1, first_transformations=100) first_transformations_label.config(state=tk.NORMAL) first_transformations_label.delete(0, tk.END) first_transformations_label.insert(0, gen_str) first_transformations_label.config(state=tk.DISABLED) fractal_label.config(image=img) fractal_label.image = img
def num_selected(self): try: num = int(self.num_selector_entry.get()) except ValueError as err: error_message("The number of transformations selected, " + self.num_selector_entry.get() + ", is invalid.") return if num > len(digits): error_message("The number of transformations selected, " + self.num_selector_entry.get() + ", must not be greater than " + str(len(digits)) + ".") return if num < 1: error_message("The number of transformations selected, " + self.num_selector_entry.get() + ", must not be less than 1.") return affine_val_labels = ["a", "b", "c", "d", "e", "f"] for w in self.affine_vals_frame.winfo_children(): w.destroy() num_label = tk.Entry(self.affine_vals_frame, width=8, justify=tk.CENTER) num_label.grid(row=0, column=0) num_label.config(state=tk.DISABLED, disabledforeground="black") for col in range(len(affine_val_labels)): col_label = tk.Entry(self.affine_vals_frame, width=8, justify=tk.CENTER) col_label.grid(row=0, column=col + 1) col_label.insert(0, affine_val_labels[col]) col_label.config(state=tk.DISABLED, disabledforeground="black") p_col_label = tk.Entry(self.affine_vals_frame, width=19, justify=tk.CENTER) p_col_label.grid(row=0, column=len(affine_val_labels) + 1, columnspan=3, padx=(10, 0)) p_col_label.insert(0, "p=r/s") p_col_label.config(state=tk.DISABLED, disabledforeground="black") self.transformation_entries = [] for row in range(num): row_entries = [] row_label = tk.Entry(self.affine_vals_frame, width=8, justify=tk.CENTER) row_label.grid(row=row + 1, column=0) row_label.insert(0, base_repr(row, base=num)) row_label.config(state=tk.DISABLED, disabledforeground="black") for col in range(len(affine_val_labels)): col_entry = tk.Entry(self.affine_vals_frame, width=8, justify=tk.CENTER) col_entry.grid(row=row + 1, column=col + 1) row_entries.append(col_entry) p_numerator_entry = tk.Entry(self.affine_vals_frame, width=8, justify=tk.RIGHT) p_numerator_entry.grid(row=row + 1, column=len(affine_val_labels) + 1, padx=(10, 0)) row_entries.append(p_numerator_entry) p_slash_label = tk.Label(self.affine_vals_frame, text="/") p_slash_label.grid(row=row + 1, column=len(affine_val_labels) + 2) p_denominator_entry = tk.Entry(self.affine_vals_frame, width=8, justify=tk.LEFT) p_denominator_entry.grid(row=row + 1, column=len(affine_val_labels) + 3) row_entries.append(p_denominator_entry) self.transformation_entries.append(row_entries)
def get_image(self, image_width, image_height, num_iters, generator, starting_point=Coordinate(0, 0), bg_color="#000000", fg_color="#00FF00", colors=True, first_transformations=100): img = PhotoImage(width=image_width, height=image_height) # Set background color img.put(bg_color, to=(0, 0, image_width, image_height)) # Calculation of points all_points = [starting_point] all_transformations = [0] gen_str = "" current_point = starting_point for i in range(num_iters): gen_val = next(generator) index = int(gen_val, base=self.size) t = self.transformations[index] current_point = t.transform(current_point) all_points.append(current_point) all_transformations.append(index) gen_str += gen_val # Stretch to fit image min_x = min(all_points, key=lambda pt: pt.x).x max_x = max(all_points, key=lambda pt: pt.x).x min_y = min(all_points, key=lambda pt: pt.y).y max_y = max(all_points, key=lambda pt: pt.y).y fractal_width = max_x - min_x fractal_height = max_y - min_y fractal_size = max(fractal_width, fractal_height) drawn_points = [] draw_colors = [] for pt, index in zip(all_points, all_transformations): new_x = ((pt.x - min_x) / fractal_size) * image_width new_y = ((pt.y - min_y) / fractal_size) * image_height new_y = image_height - new_y drawn_points.append(Coordinate(new_x, new_y)) draw_colors.append(hsv_to_rgb(index * 360 / self.size, 1, 1)) # Draw points if colors: for pt, dot_color in zip(drawn_points, draw_colors): img.put(dot_color, (round(pt.x), round(pt.y))) else: for pt in drawn_points: img.put(fg_color, (round(pt.x), round(pt.y))) return img, gen_str[:first_transformations]