gpt4 book ai didi

python - 将一个或多个吸引子添加到一组随机二维点

转载 作者:行者123 更新时间:2023-11-28 18:28:26 24 4
gpt4 key购买 nike

给定一组像这样生成的伪随机二维点:

points = random.sample([[x, y] for x in xrange(width) for y in yrange(height)], 100)

我希望能够添加一个或多个非随机吸引点,其他点将围绕这些吸引点绘制。我不打算对此进行动画处理,因此它不需要非常高效,但我希望能够指定如何将随机点绘制到每个吸引点(例如,基于距离的平方和一个给定的引力常数),然后将我的点提供给一个函数,该函数返回原始列表的修改版本:

points = random.sample([[x, y] for x in xrange(width) for y in xrange(height)], 100)

attractors = [(25, 102), (456, 300), (102, 562)]

def attract(random_points_list, attractor_points_list):
(...)
return modified_points_list

new_points_list = attract(points, attractors)

然后,这个新的点列表将用于为 Voronoi 图(不是这个问题的一部分)播种。

最佳答案

事实证明,这是一个比我最初估计的纯实现工作任务更具挑战性的问题。困难在于定义一个好的吸引力模型。

  1. 模拟吸引子上的普通自由落体(就像在由多个质点产生的真实重力场中一样)是有问题的,因为您必须指定此过程的持续时间。如果持续时间足够短,位移就会很小,吸引子周围的聚集也不会引人注意。如果持续时间足够长,那么所有点都将落在吸引子上或离吸引子太近。

  2. 在一次拍摄中计算每个点的新位置(不进行基于时间的模拟)更简单,但问题是每个点的最终位置是否必须受到所有的影响吸引子或只有最接近的一个。后一种方法(只吸引最近的一个)被证明可以产生更具视觉吸引力的结果。我无法通过前一种方法取得良好的效果(但请注意,我只尝试了相对简单的吸引力功能)。

使用 matplotlib 可视化的 Python 3.4 代码如下:

#!/usr/bin/env python3

import random
import numpy as np
import matplotlib.pyplot as plt

def dist(p1, p2):
return np.linalg.norm(np.asfarray(p1) - np.asfarray(p2))


def closest_neighbor_index(p, attractors):
min_d = float('inf')
closest = None
for i,a in enumerate(attractors):
d = dist(p, a)
if d < min_d:
closest, min_d = i, d
return closest


def group_by_closest_neighbor(points, attractors):
g = []
for a in attractors:
g.append([])
for p in points:
g[closest_neighbor_index(p, attractors)].append(p)
return g


def attracted_point(p, a, f):
a = np.asfarray(a)
p = np.asfarray(p)
r = p - a
d = np.linalg.norm(r)
new_d = f(d)
assert(new_d <= d)
return a + r * new_d/d


def attracted_point_list(points, attractor, f):
result=[]
for p in points:
result.append(attracted_point(p, attractor, f))
return result


# Each point is attracted only to its closest attractor (as if the other
# attractors don't exist).
def attract_to_closest(points, attractors, f):
redistributed_points = []
grouped_points = group_by_closest_neighbor(points, attractors)
for a,g in zip(attractors, grouped_points):
redistributed_points.extend(attracted_point_list(g,a,f))
return redistributed_points


def attraction_translation(p, a, f):
return attracted_point(p, a, f) - p


# Each point is attracted by multiple attracters.
# The resulting point is the average of the would-be positions
# computed for each attractor as if the other attractors didn't exist.
def multiattract(points, attractors, f):
redistributed_points = []
n = float(len(attractors))
for p in points:
p = np.asfarray(p)
t = np.zeros_like(p)
for a in attractors:
t += attraction_translation(p,a,f)
redistributed_points.append(p+t/n)
return redistributed_points


def attract(points, attractors, f):
""" Draw points toward attractors

points and attractors must be lists of points (2-tuples of the form (x, y)).

f maps distance of the point from an attractor to the new distance value,
i.e. for a single point P and attractor A, f(distance(P, A)) defines the
distance of P from A in its new (attracted) location.

0 <= f(x) <= x must hold for all non-negative values of x.
"""

# multiattract() doesn't work well with simple attraction functions
# return multiattract(points, attractors, f);
return attract_to_closest(points, attractors, f);

if __name__ == '__main__':
width=400
height=300
points = random.sample([[x, y] for x in range(width) for y in range(height)], 100)
attractors = [(25, 102), (256, 256), (302, 62)]

new_points = attract(points, attractors, lambda d: d*d/(d+100))
#plt.scatter(*zip(*points), marker='+', s=32)
plt.scatter(*zip(*new_points))
plt.scatter(*zip(*attractors), color='red', marker='x', s=64, linewidths=2)

plt.show()

关于python - 将一个或多个吸引子添加到一组随机二维点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39433259/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com