Skip to content

Instantly share code, notes, and snippets.

@beotiger
Created April 3, 2024 20:38
Show Gist options
  • Select an option

  • Save beotiger/cd6ea171692844d4822146c959306db4 to your computer and use it in GitHub Desktop.

Select an option

Save beotiger/cd6ea171692844d4822146c959306db4 to your computer and use it in GitHub Desktop.
crazy lines in Python
#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