con*_*dor 3 python python-imaging-library
I'm trying to recreate this image using Python and PIL.
This is the code I come upped with:
from PIL import Image, ImageDraw
def draw_lines(draw, points):
new_points = []
for idx, point in enumerate(points):
x, y = point
if idx != len(points) - 1:
if idx == 0:
x = x + 25
elif idx == 1:
y = y + 25
elif idx == 2:
x = x - 25
elif idx == 3:
y = y - 25
else:
x = x + 25
new_points.append((x, y))
draw.line(new_points, fill="black", width=1)
return new_points
def main():
im = Image.new('RGB', (501, 501), color=(255, 255, 255))
draw = ImageDraw.Draw(im)
points = [
(0, 0),
(500, 0),
(500, 500),
(0, 500),
(0, 0),
]
draw.line(points, fill="black", width=1)
for i in range(80):
points = draw_lines(draw, points)
im.save("out.png")
if __name__ == '__main__':
main()
Run Code Online (Sandbox Code Playgroud)
and this is the output:
and also how can I fill those formed triangles with color?
Update:
By modifying the answer here Rotating a square in PIL, I was able to do this.

Code:
import math
from PIL import Image, ImageDraw
def distance(ax, ay, bx, by):
return math.sqrt((by - ay) ** 2 + (bx - ax) ** 2)
def rotated_about(ax, ay, bx, by, angle):
radius = distance(ax, ay, bx, by)
angle += math.atan2(ay - by, ax - bx)
return (
round(bx + radius * math.cos(angle)),
round(by + radius * math.sin(angle))
)
image = Image.new('RGB', (510, 510), color=(255, 255, 255))
draw = ImageDraw.Draw(image)
def draw_sqr(pos, sqlen, rota):
square_center = pos
square_length = sqlen
square_vertices = (
(square_center[0] + square_length / 2, square_center[1] + square_length / 2),
(square_center[0] + square_length / 2, square_center[1] - square_length / 2),
(square_center[0] - square_length / 2, square_center[1] - square_length / 2),
(square_center[0] - square_length / 2, square_center[1] + square_length / 2)
)
square_vertices = [rotated_about(x, y, square_center[0], square_center[1], math.radians(rota)) for x, y in
square_vertices]
draw.polygon(square_vertices, outline="black")
def draw_rot_sqr(pos):
scale = 500
rot = 0
n = 1.1575
for i in range(10):
draw_sqr(pos, scale, rot)
rot = rot * n + 10
scale = scale / n - 10
draw_rot_sqr((255, 255))
image.show()
Run Code Online (Sandbox Code Playgroud)
Now, how can I properly scale and rotate the squares where all points intersect with the sides at any size?
Edit, drawing triangles
Vertices for drawing triangles:
def draw_sqr(pos, p_len, rota):
x, y = pos
altitude = p_len * math.sqrt(3) / 2
apothem = altitude / 3
x_top = x
y_top = y - apothem * 2
x_base_1 = x + p_len / 2
x_base_2 = x - p_len / 2
y_base = y + apothem
vertices = (
(x_top, y_top),
(x_base_1, y_base),
(x_base_2, y_base)
)
vertices = [rotated_about(x, y, pos[0], pos[1], rota) for x, y in
vertices]
draw.polygon(vertices, outline="black")
Run Code Online (Sandbox Code Playgroud)
这是一个可爱的数学问题。
鉴于上图,其中
是起始正方形的边的长度,并且
是新方块的长度,我们必须找到
这样一来,当旋转新正方形时,所有角都会接触前一个正方形的边。
可以定义为
,其中
是比例因子。例如,如果缩放因子为0.9,则每个新正方形的边将是前一个边的长度的90%。
有了一些基本的三角学,
可以发现是:

对于通用多边形,其定义为

在其中
是多边形的内角值(正方形为90°,因此它会退回到上一个方程式)。
从几何上讲,这是有道理的。例如,对于一个正方形,新正方形的对角线
应该不小于上一个的边,即
。
解决
,我们发现

缩放比例超过1时,新的正方形将更大,但是仍然可以使用接触角的原理。
至于公式中的正负号,负号对应于顺时针旋转,正号代表逆时针旋转。
最后,
可以用正弦法则计算
考虑到这一点,您可以产生以下输出。
观察:该代码仅考虑正方形,即它认为
等于90°,尽管它可以很容易地泛化(请参阅
和
方程式)。
import math
from PIL import Image, ImageDraw
def calc_a(L, f):
return L/2.0*(1-(1-2*(1-f**2))**.5)
def calc_theta(L, f, direction='cw'):
a = calc_a(L, f)
if direction == 'cw':
d = 1
elif direction == 'ccw':
d = -1
return d*math.asin(a/(f*L))
def distance(ax, ay, bx, by):
return math.sqrt((by - ay) ** 2 + (bx - ax) ** 2)
def rotated_about(ax, ay, bx, by, angle):
radius = distance(ax, ay, bx, by)
angle += math.atan2(ay - by, ax - bx)
return (
round(bx + radius * math.cos(angle)),
round(by + radius * math.sin(angle))
)
image = Image.new('RGB', (510, 510), color=(255, 255, 255))
draw = ImageDraw.Draw(image)
def draw_sqr(pos, sqlen, rota):
square_center = pos
square_length = sqlen
square_vertices = (
(square_center[0] + square_length / 2, square_center[1] + square_length / 2),
(square_center[0] + square_length / 2, square_center[1] - square_length / 2),
(square_center[0] - square_length / 2, square_center[1] - square_length / 2),
(square_center[0] - square_length / 2, square_center[1] + square_length / 2)
)
square_vertices = [rotated_about(x, y, square_center[0], square_center[1], rota) for x, y in
square_vertices]
draw.polygon(square_vertices, outline="black")
def draw_rot_sqr(pos):
side = 500 # starting square side length
f = 0.9 # should be bigger than 1/sqrt(2), for math reasons
base_theta = calc_theta(side, f, direction='cw')
theta = 0 # first square has no rotation
for i in range(10):
draw_sqr(pos, side, theta)
# theta is relative to previous square, so we should accumulate it
theta += base_theta
side *= f
draw_rot_sqr((255, 255))
image.show()
Run Code Online (Sandbox Code Playgroud)
使用考虑到这一点的通用实现
可以与90°不同,可以使用任何多边形来实现。这是将其应用于三角形的示例:
输出:1000次迭代,缩放系数为0.98;和
比例因子。
| 归档时间: |
|
| 查看次数: |
86 次 |
| 最近记录: |