我正在尝试使用Python和PIL重新创建此图像。
这是我提供的代码:
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()
这是输出:
还有如何用颜色填充那些形成的三角形?
更新:
通过在Rotating a square in PIL处修改答案,我能够做到这一点。
代码:
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()
现在,我如何正确缩放和旋转所有点以任意大小相交的正方形?
编辑,绘制三角形
绘制三角形的顶点:
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")
答案 0 :(得分:6)
这是一个可爱的数学问题。
鉴于上图,其中是起始正方形的边的长度,而是新正方形的长度,我们必须找到使得,当它旋转新方块时,所有角都碰到前一个方块的侧面。
可以定义为,其中是缩放因子。例如,如果缩放因子为0.9,则每个新正方形的边将是前一个边的边长的90%。
使用一些基本的三角函数,可以发现为:
对于通用多边形,其定义为
其中是多边形的内角值(正方形为90°,因此它会退回到上一个公式)。
从几何上讲,这是有道理的。例如,对于一个正方形,新正方形的对角线应不小于前一个正方形的对角线,即转为。
使用进行计算,我们发现
缩放比例大于1时,新的正方形将更大,但是仍然可以使用接触角的原理。
对于公式中的正负号,负号对应于顺时针旋转,正号代表逆时针旋转。
最后,可以使用正弦规则计算
考虑到这一点,您可以产生以下输出。
Obs .:该代码仅考虑正方形,也就是说,尽管可以很容易地将其归纳为等于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()
使用认为可以不同于90°的通用实现,可以对任何多边形进行此操作。这是将其应用于三角形的示例:
输出:1000次迭代,缩放系数为0.98;和比例因子。