正多边形内点黄金分割冒险游戏

1. 题目:

正多边形 内点的冒险游戏

内容描述:

  1. 选定五边形(P1, P2, ..., P5)内的一个任意点 P0 。
  2. 从 P0 出发,到任意顶点距离的 0.618 的点P0’(黄金分割点),给该P0’点着色。
  3. 从P0’点出发,重复第2步, 求得新的黄金分割点并着色。
  4. 以上重复 N 次,比如,30000次

问题: 最后所有黄金分割点形成的图案。

2. 思考

  • 步骤一: 正多边形生成问题

    • 以原点为中心,长度为a,每次旋转 angle = 2* PI /n 弧度 .
    • 计算顶点的坐标 : Points ( a * cos(angle), angle
    • 计算正多边形的顶点坐标集合。 Points(a * cos(angle), a * sin(angle) )
    • 上述步骤定义成一个函数,返回一个列表,列表的每一项为坐标(x,y)
  • 步骤二:黄金分割点的计算 :P0点到 PN点 距离的 0.618

    • P0' = P0 + (PN-P0) * 0.618
  • 步骤三:显示多边形和黄金分割点

  • 用 plot 或 scatter 画线 和 点

3. 代码

  • 步骤一:定义正多边形函数
# Step 1.1 : 定义 正 n 边形的函数,calculate_pentagon_vertices, 返回顶点坐标列表
#          方法,以原点为中心,旋转 angle = 2 * math.pi / n 弧度,然后利用cos,sin 计算顶点坐标
# 
import math

def calculate_pentagon_vertices(a, n):   #  a 为原点到顶点的距离 ,n 为正n 边形顶点个数
   # 正 n边形的中心角度  
   angle = 2 * math.pi / n 
   # 列表 vertices存放顶点坐标,用于返回
   vertices = []
   # 计算正n边形的顶点  
   for i in range(n):
       # 计算每个顶点的x和y坐标  
       x = a * math.cos(i * angle)  
       y = a * math.sin(i * angle)  
       vertices.append((x, y)) 
   return vertices
# step 1. 2: 调用函数,得到一个顶点列表 vertices
vertices = calculate_pentagon_vertices(2,5)
  • 步骤二:计算黄金分割点,并显示
# step 2: 计算黄金分割点,并显示
import matplotlib.pyplot as plt
import random

Golden = 0.618
Number = 40000          # 黄金分割次数

# vertices 将第1项追加尾部,为了绘图时候首尾相连。注意:执行后vertices长度增加了一个
vertices.append(vertices[0])            
                                       
X = [Point[0] for Point in vertices]    # Point 为顶点
Y = [Point[1] for Point in vertices]

# 使用plot()绘制正多边形 
plt.plot(X, Y, marker='o', linestyle='-')  # marker='o' 指定点为圆圈,linestyle='-' 指定线为实线  

# 单独绘制起始点  ,我们这里设置为原点
plt.plot(0, 0, 'ro')  # 'r' 表示红色,'o' 表示圆圈  
P0_x, P0_y = 0, 0

plot_x = []        # 方法三:存放所有黄金分割点的 坐标,P0_x
plot_y = []        # 方法三:存放所有黄金分割点的 坐标,P0_y

for i in range(Number):
   # 随机指定一个顶点 PN
   PN = random.randint(1,len(vertices)-1)
   # 求 P0 --- PN 之间的新的点,仍然记为 P0
   P0_x = P0_x + (X[PN]- P0_x)* Golden
   P0_y = P0_y + (Y[PN]- P0_y)* Golden
   # plt.plot(P0_x, P0_y, 'go')               # 方法一: plot 绘图 'r' 表示红色,'o' 表示圆圈
   # plt.scatter(P0_x, P0_y, color = 'green') # 方法二: scatter 绘图 ,一次一个点
   plot_x.append(P0_x)                        # 方法三: 保存所有黄金点 X坐标,循环结束时候,scatter 绘图 
   plot_y.append(P0_y)                        # 方法三: 保存所有黄金点 Y坐标,循环结束时候,scatter 绘图 

plt.plot(plot_x[0], plot_y[0], 'bo')   # 删除第一个黄金分割点之前,先绘制该点 (换个颜色)
del plot_x[0]             # 删除第一个黄金分割点,why? 可以对比一下绘图结果。
del plot_y[0]             # 删除第一个黄金分割点,why? 可以对比一下绘图结果。

plt.scatter(plot_x, plot_y, color = 'green')   # 方法三: 保存所有黄金点 Y坐标,循环结束时候,scatter 绘图

# 设置标题和坐标轴标签  
# plt.title('line and point')  
plt.axis('equal')  # 保持纵横比相等  
# plt.xlabel('x轴')  
# plt.ylabel('y轴')  
 
# 显示网格  
plt.grid(True)  
 
# 显示图表  
plt.show()

4. 结果

如图:
image

5. 改进

  • 将代码 step2 封装为一个函数
# 定义一个函数
def draw_golden(vertices,  Number = 40000, Golden = 0.618):
    # step 3: 计算黄金分割点,并显示
    import matplotlib.pyplot as plt
    import random

    # vertices 将第1项追加尾部,为了绘图时候首尾相连。注意:执行后vertices长度增加了一个
    vertices.append(vertices[0])            
                                       
    X = [Point[0] for Point in vertices]    # Point 为顶点
    Y = [Point[1] for Point in vertices]

    # 使用plot()绘制正多边形 
    plt.plot(X, Y, marker='o', linestyle='-')  # marker='o' 指定点为圆圈,linestyle='-' 指定线为实线  

    # 单独绘制起始点  ,我们这里设置为原点
    plt.plot(0, 0, 'ro')  # 'r' 表示红色,'o' 表示圆圈  
    P0_x, P0_y = 0, 0

    plot_x = []        # 方法三:存放所有黄金分割点的 坐标,P0_x
    plot_y = []        # 方法三:存放所有黄金分割点的 坐标,P0_y

    for i in range(Number):
       # 随机指定一个顶点 PN
       PN = random.randint(1,len(vertices)-1)
       # 求 P0 --- PN 之间的新的点,仍然记为 P0
       P0_x = P0_x + (X[PN]- P0_x)* Golden
       P0_y = P0_y + (Y[PN]- P0_y)* Golden
       # plt.plot(P0_x, P0_y, 'go')               # 方法一: plot 绘图 'r' 表示红色,'o' 表示圆圈
       # plt.scatter(P0_x, P0_y, color = 'green') # 方法二: scatter 绘图 ,一次一个点
       plot_x.append(P0_x)                        # 方法三: 保存所有黄金点 X坐标,循环结束时候,scatter 绘图 
       plot_y.append(P0_y)                        # 方法三: 保存所有黄金点 Y坐标,循环结束时候,scatter 绘图 

    plt.plot(plot_x[0], plot_y[0], marker='o',  color = 'b')   # 删除第一个黄金分割点之前,先绘制该点 (换个颜色)
    del plot_x[0]             # 删除第一个黄金分割点,why? 可以对比一下绘图结果。
    del plot_y[0]             # 删除第一个黄金分割点,why? 可以对比一下绘图结果。

    plt.scatter(plot_x, plot_y, color = 'green')   # 方法三: 保存所有黄金点 Y坐标,循环结束时候,scatter 绘图

    # 设置标题和坐标轴标签  
    plt.axis('equal')  # 保持纵横比相等  
    # 显示网格  
    plt.grid(True)  
    # 显示图表  
    plt.show()
	
  • 测试一: 改变 边数
  1. 正三边形(等边三角形),结果:
vertices = calculate_pentagon_vertices(2,3)
draw_golden(vertices, 1000)

image

  1. 四边形
vertices = calculate_pentagon_vertices(2,4)
draw_golden(vertices, 1000)

image

  1. 正五边形
vertices = calculate_pentagon_vertices(2,5)
draw_golden(vertices, 10000)

image

  1. 正六边形
vertices = calculate_pentagon_vertices(2,6)
draw_golden(vertices, 10000)

image

  • 测试2: 改变黄金分割参数
vertices = calculate_pentagon_vertices(2,6)
draw_golden(vertices, 10000, 0.7)

image

posted on 2024-07-05 08:51  小林觉  阅读(16)  评论(2编辑  收藏  举报

导航