原來這是一個比我最初估計的更具挑戰性的問題,它是一個純粹的實施工作任務。困難在於定義一個好的吸引力模型。
模擬上吸引普通自由落體(彷彿在通過多點羣衆創造一個真正的重力場)是有問題的,因爲你必須指定此過程的持續時間。如果持續時間足夠短,位移將很小,並且吸引子周圍的聚類不會被注意到。如果持續時間足夠長,那麼所有點將落在吸引子上或與它們太靠近。
計算每個點的一個炮打響的新位置(而不進行基於時間的仿真)是簡單的,但問題是,是否每一個點的最終位置必須由所有吸引或只有最接近的影響其中一個。後一種方法(吸引到最接近一個)證明會產生更具視覺吸引力的結果。我以前的方法無法取得好成績(但請注意,我只嘗試過相對簡單的吸引功能)。
的Python 3.4的代碼使用matplotlib
可視化如下:
#!/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()
我的意思是,有趣的目標,但你有實現這個想法有什麼問題? –