Created
April 3, 2024 20:38
-
-
Save beotiger/cd6ea171692844d4822146c959306db4 to your computer and use it in GitHub Desktop.
crazy lines in Python
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #Import the required libraries | |
| from tkinter import * | |
| import math | |
| WIDTH, HEIGHT = 500, 500 | |
| class GradientColor: | |
| @staticmethod | |
| def hex_to_RGB(hex): | |
| """ "#FFFFFF" -> [255,255,255] """ | |
| # Pass 16 to the integer function for change of base | |
| return [int(hex[i:i+2], 16) for i in range(1, 6, 2)] | |
| @staticmethod | |
| def RGB_to_hex(RGB): | |
| """ [255,255,255] -> "#FFFFFF" """ | |
| # Components need to be integers for hex to make sense | |
| RGB = [int(x) for x in RGB] | |
| return "#"+"".join(["0{0:x}".format(v) if v < 16 else | |
| "{0:x}".format(v) for v in RGB]) | |
| @staticmethod | |
| def color_dict(gradient): | |
| """ Takes in a list of RGB sub-lists and returns dictionary of | |
| colors in RGB and hex form for use in a graphing function | |
| defined later on """ | |
| return {"hex":[GradientColor.RGB_to_hex(RGB) for RGB in gradient], | |
| "r":[RGB[0] for RGB in gradient], | |
| "g":[RGB[1] for RGB in gradient], | |
| "b":[RGB[2] for RGB in gradient]} | |
| @staticmethod | |
| def linear_gradient(start_hex, finish_hex="#FFFFFF", n=10): | |
| """ returns a gradient list of (n) colors between | |
| two hex colors. start_hex and finish_hex | |
| should be the full six-digit color string, | |
| inlcuding the number sign ("#FFFFFF") """ | |
| # Starting and ending colors in RGB form | |
| s = GradientColor.hex_to_RGB(start_hex) | |
| f = GradientColor.hex_to_RGB(finish_hex) | |
| # Initilize a list of the output colors with the starting color | |
| RGB_list = [s] | |
| # Calcuate a color at each evenly spaced value of t from 1 to n | |
| for t in range(1, n): | |
| # Interpolate RGB vector for color at the current value of t | |
| curr_vector = [ | |
| int(s[j] + (float(t)/(n-1))*(f[j]-s[j])) | |
| for j in range(3) | |
| ] | |
| # Add it to our list of output colors | |
| RGB_list.append(curr_vector) | |
| return GradientColor.color_dict(RGB_list) | |
| # Some utility functions can be removed if not in need | |
| def constrain(n, low, high): | |
| """Helper function for map""" | |
| return max(min(n, high), low) | |
| def map_5js(n, start1, stop1, start2, stop2, withinBounds=False): | |
| """map function from P5.js""" | |
| newval = (n - start1) / (stop1 - start1) * (stop2 - start2) + start2 | |
| if not withinBounds: return newval | |
| if start2 < stop2: return constrain(newval, start2, stop2) | |
| else: return constrain(newval, stop2, start2) | |
| def get_line(x1, y1, x2, y2): | |
| points = [] | |
| issteep = abs(y2-y1) > abs(x2-x1) | |
| if issteep: | |
| x1, y1 = y1, x1 | |
| x2, y2 = y2, x2 | |
| rev = False | |
| if x1 > x2: | |
| x1, x2 = x2, x1 | |
| y1, y2 = y2, y1 | |
| rev = True | |
| deltax = x2 - x1 | |
| deltay = abs(y2-y1) | |
| error = int(deltax / 2) | |
| y = y1 | |
| ystep = None | |
| if y1 < y2: | |
| ystep = 1 | |
| else: | |
| ystep = -1 | |
| for x in range(x1, x2 + 1): | |
| if issteep: | |
| points.append((y, x)) | |
| else: | |
| points.append((x, y)) | |
| error -= deltay | |
| if error < 0: | |
| y += ystep | |
| error += deltax | |
| # Reverse the list if the coordinates were reversed | |
| if rev: | |
| points.reverse() | |
| return points | |
| def drawLine(canvas, color, x1, y1, x2, y2, **kwargs): | |
| """Draw a line on the canvas with specified color""" | |
| return canvas.create_line(x1, y1, x2, y2, capstyle=ROUND, fill=color, **kwargs) | |
| def setPixel(canvas, color, x, y, width=1): | |
| """Set one pixel as 1x1 rectangle""" | |
| return canvas.create_rectangle(x, y, x + 1, y + 1, outline=color, fill=color, width=width) | |
| def draw_narrowing_line(canvas, color, x1, y1, x2, y2, width): | |
| """Draw line that narrows to its end""" | |
| points = get_line(x1, y1, x2, y2) | |
| w = width | |
| # print(f'len(points)={len(points)}, width={width}') | |
| # i = len(points) -- для утолчающейся линии | |
| i = 0 | |
| for point in points: | |
| w = map_5js(i, 0, len(points), width, 0, True) | |
| print(f'w={w}') | |
| i += 1 | |
| setPixel(canvas, color, point[0], point[1], width=w) | |
| print(f'len(points)={len(points)}, width={width}') | |
| def testGradients(evt=None): | |
| canvas.delete(ALL) | |
| num = 256 | |
| startColor = '#500050' | |
| endColor = '#FFC8FF' | |
| colors = GradientColor.linear_gradient(startColor, endColor, num)['hex'] | |
| for i in range(num): | |
| x1, y1 = 0, i | |
| x2, y2 = num - 1, i | |
| color = colors[i] | |
| drawLine(canvas, color, x1, y1, x2, y2) | |
| win = Tk() | |
| win.geometry(f'{WIDTH}x{HEIGHT}') | |
| canvas = Canvas(win, width=WIDTH, height=WIDTH) | |
| canvas.pack() | |
| canvas.bind('<1>', testGradients) | |
| x1, y1 = 25, 25 | |
| x2, y2 = 200, 200 | |
| color1 = '#F00' | |
| color2 = '#F0F' | |
| width = 10 | |
| # drawLine(canvas, color1, x1, y1, x2, y2, width=20) | |
| draw_narrowing_line(canvas, color2, x1, y1, x2, y2, width=width) | |
| win.mainloop() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment