确定一个点是否属于n阶Koch雪花指定的区域

2024-05-23 20:46:38 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图编写一个执行以下计算的python脚本:

输入: (1) 列表L:一些二维点的列表 (2) 列表V:三角形的顶点 (3) 正整数n:从该三角形创建Koch雪花的顺序

输出: 列表O,L的一个子集,包含来自L的点,位于区域Kn上或内部,Kn是由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()

但既然它没有说明雪花的区域,我就不能再往前走了。接下来,我认为雪花的区域可能包含一些见解,因此我编写了以下函数:

^{pr2}$

它实现了一个显式公式来计算面积。再说一次,这似乎和我想做的无关。在

我如何解决这个问题? 提前谢谢!在


Tags: testimport区域列表size顺序mainorder
3条回答

enter image description here

为提高效率,将点与边进行比较时,请使用以下规则:

  • 如果您在蓝色区域,则该点在外部,

  • 如果您在橙色区域,则该点在内部,

  • 否则,您将需要递归测试,但是请确保选择点所在的绿色三角形,以便只在一个子边上递归。

这看起来可能只是一个小小的差别,但却可以节省大量开支。实际上,在第n-代时,薄片有3 x 4^n面(即第十代的3145728);如果你递归到一个子边,你将只做12测试!在

@cdlane的版本是最差的,因为它每次都会执行一个详尽的测试。@ante的版本介于两者之间,因为它有时会提前停止,但仍然可以执行指数级的测试。在


一种简单的实现方法是假设要检查的那一面总是(0,0)-(1,0)。然后测试测试点属于哪个三角形是一件简单的事情,因为顶点的坐标是固定的和已知的。这可以通过四个与直线的比较来完成。在

当您需要递归到子边时,您将通过将其移动到原点、缩放3并旋转60°(如有必要)来变换该子边;将相同的变换应用于测试点。在

可以用递归创建Koch雪花的相同方式检查点位置。步骤包括:

  • 检查是给定三角形内的点
  • 否则,than点在一些三角形边的负边上。对于点在负边上的每一条边,递归地检查该边的“中间三角形”中的点,若不递归检查下两个可能的雪花边部分。在

这种方法更快,因为它不创建整个多边形并对其进行检查。在

以下是使用numpy实现的要点:

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)

找到一个具有a routine for performing the "point in polygon" inclusion test的Python模块;使用turtle的begin_poly()end_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()

enter image description here

^{pr2}$

相关问题 更多 >