我正在尝试编写一个执行以下计算的python脚本:
输入: (1)清单L:一些二维点的清单 (2)列表V:三角形的顶点 (3)正整数n:从该三角形创建的Koch雪花的顺序
输出: 列表O,L的子集,包含位于区域Kn上或区域内的L点,该区域是由n阶雪花定义的区域。
我的尝试: 首先,我认为我首先要实现一个标准算法来绘制给定顺序(和边长)的雪花。这是我写的代码:
import turtle
from test import test
world= turtle.Screen()
t= turtle.Turtle()
def koch(t, order, size):
if order == 0:
t.forward(size)
else:
for angle in [60, -120, 60, 0]:
koch(t, order-1, size/3)
t.left(angle)
def koch_fractal(t, order, size, main_polygon_sides= 3):
for i in range(main_polygon_sides):
koch(t, order, size)
t.right(360/main_polygon_sides)
koch_fractal(t, 2, 100)
world.mainloop()
但由于它没有说明雪花的区域,我无法继续前进。接下来,我认为雪花的区域可能会有一些见解,所以我写了这个函数:
from math import sqrt
koch_cache={}
def koch_fractal_area(n, side):
original_area = (sqrt(3)/4) * side**2 #Area of the original triangle
koch_cache[0] = original_area
for i in range(n+1):
if i not in koch_cache:
koch_cache[i] = koch_cache[i-1] + (3*4**(i-1))*(sqrt(3)/4) * (side/(3**i))**2
return koch_cache[n]
它实现了一个显式公式来计算面积。同样,它似乎与我试图做的事情无关。
我该如何处理这个问题? 提前谢谢!
答案 0 :(得分:2)
可以以相同的方式检查点位置,以递归方式创建Koch雪花。步骤是:
这种方法更快,因为它不会创建整个多边形并对其进行检查。
这是使用numpy for points的实现:
import numpy
def on_negative_side(p, v1, v2):
d = v2 - v1
return numpy.dot(numpy.array([-d[1], d[0]]), p - v1) < 0
def in_side(p, v1, v2, n):
if n <= 0:
return False
d = v2 - v1
l = numpy.linalg.norm(d)
s = numpy.dot(d / l, p - v1)
if s < 0 or s > l: # No need for a check if point is outside edge 'boundaries'
return False
# Yves's check
nd = numpy.array([-d[1], d[0]])
m_v = nd * numpy.sqrt(3) / 6
if numpy.dot(nd / l, v1 - p) > numpy.linalg.norm(m_v):
return False
# Create next points
p1 = v1 + d/3
p2 = v1 + d/2 - m_v
p3 = v1 + 2*d/3
# Check with two inner edges
if on_negative_side(p, p1, p2):
return in_side(p, v1, p1, n-1) or in_side(p, p1, p2, n-1)
if on_negative_side(p, p2, p3):
return in_side(p, p2, p3, n-1) or in_side(p, p3, v2, n-1)
return True
def _in_koch(p, V, n):
V_next = numpy.concatenate((V[1:], V[:1]))
return all(not on_negative_side(p, v1, v2) or in_side(p, v1, v2, n)
for v1, v2 in zip(V, V_next))
def in_koch(L, V, n):
# Triangle points (V) are positive oriented
return [p for p in L if _in_koch(p, V, n)]
L = numpy.array([(16, -16), (90, 90), (40, -40), (40, -95), (50, 10), (40, 15)])
V = numpy.array([(0, 0), (50, -50*numpy.sqrt(3)), (100, 0)])
for n in xrange(3):
print n, in_koch(L, V, n)
print in_koch(L, V, 100)
答案 1 :(得分:2)
为了提高效率,将点与一侧进行比较时,请使用以下规则:
如果您在蓝色区域,则该点在外面,
如果您在橙色区域,则该点位于内部,
否则你需要递归测试,但确保选择点所在的绿色三角形,这样你只能在一个子侧进行递归。
< / LI>这可能看起来像一个小的差异,但它可以节省大量资金。实际上,在第n
代,薄片具有3 x 4^n
侧(即第10代3145728
);如果你递归到一个子方面,你将只进行12
测试!
@cdlane的版本是最糟糕的,因为它每次都会进行详尽的测试。 @ante的版本介于两者之间,因为它有时会提前停止,但仍然可以执行指数级的测试。
一种简单的实现方法是假设要检查的一面始终为(0,0)-(1,0)
。然后测试测试点所属的三角形是一件简单的事情,因为顶点的坐标是固定的并且是已知的。这可以通过与直线的四次比较来完成。
当您需要递归到子侧时,您将通过将子侧移动到原点,缩放3并旋转60°(如果需要)来变换该子侧;将相同的变换应用于测试点。
答案 2 :(得分:0)
找到一个a routine for performing the "point in polygon" inclusion test的Python模块;使用turtle的begin_poly()
,end_poly()
和get_poly()
来捕获代码生成的顶点,然后应用绕组数测试:
from turtle import Turtle, Screen
from point_in_polygon import wn_PnPoly
points = [(16, -16), (90, 90), (40, -40), (40, -95)]
screen = Screen()
yertle = Turtle()
yertle.speed("fastest")
def koch(turtle, order, size):
if order == 0:
turtle.forward(size)
else:
for angle in [60, -120, 60, 0]:
koch(turtle, order - 1, size / 3)
turtle.left(angle)
def koch_fractal(turtle, order, size, main_polygon_sides=3):
for _ in range(main_polygon_sides):
koch(turtle, order, size)
turtle.right(360 / main_polygon_sides)
yertle.begin_poly()
koch_fractal(yertle, 2, 100)
yertle.end_poly()
polygon = yertle.get_poly()
yertle.penup()
inside_points = []
for n, point in enumerate(points):
yertle.goto(point)
yertle.write(str(n), align="center")
winding_number = wn_PnPoly(point, polygon)
if winding_number:
print(n, "is inside snowflake")
inside_points.append(point)
else:
print(n, "is outside snowflake")
print(inside_points)
yertle.hideturtle()
screen.exitonclick()
% python3 test.py
0 is inside snowflake
1 is outside snowflake
2 is inside snowflake
3 is outside snowflake
[(16, -16), (40, -40)]