[英]Distributing points over a surface within boundries
我对将预定义数量的点分布在4个侧面(如正方形)上的方式(算法)感兴趣。
主要问题是每个点必须彼此之间具有最小和最大距离(两个预定义值之间的随机性)。 基本上,任何两个点的距离都不应比我们说的2更近,而不能比3更远。
我的代码将以红宝石实现(点是位置,表面是地图),但是任何想法或摘要都绝对受欢迎,因为我的所有想法都包含相当多的蛮力。
试试这篇论文 。 它有一个不错的,直观的算法,可以满足您的需求。
在我们的建模中,我们采用了另一种模型:我们认为每个中心都通过排斥字符串与其所有邻居相关。
在模拟开始时,中心以及弦的强度是随机分布的。 我们随机选择移动一个中心。 然后我们计算由给定中心的所有邻居引起的合力,并计算在合力意义上成比例和定向的位移。
经过一定数量的迭代(取决于中心的数量和初始随机性的程度)后,系统变得稳定。
如果从图中不清楚,则此方法会生成均匀分布的点。 您可以改为使用在边界内为零(例如,介于2和3之间)的力,否则为非零(如果点太近则排斥,如果点太远则有吸引力)。
这是我的Python实现(对不起,我不知道ruby)。 只需导入它,然后调用uniform()即可获取点列表。
import numpy as np
from numpy.linalg import norm
import pylab as pl
# find the nearest neighbors (brute force)
def neighbors(x, X, n=10):
dX = X - x
d = dX[:,0]**2 + dX[:,1]**2
idx = np.argsort(d)
return X[idx[1:11]]
# repulsion force, normalized to 1 when d == rmin
def repulsion(neib, x, d, rmin):
if d == 0:
return np.array([1,-1])
return 2*(x - neib)*rmin/(d*(d + rmin))
def attraction(neib, x, d, rmax):
return rmax*(neib - x)/(d**2)
def uniform(n=25, rmin=0.1, rmax=0.15):
# Generate randomly distributed points
X = np.random.random_sample( (n, 2) )
# Constants
# step is how much each point is allowed to move
# set to a lower value when you have more points
step = 1./50.
# maxk is the maximum number of iterations
# if step is too low, then maxk will need to increase
maxk = 100
k = 0
# Force applied to the points
F = np.zeros(X.shape)
# Repeat for maxk iterations or until all forces are zero
maxf = 1.
while maxf > 0 and k < maxk:
maxf = 0
for i in xrange(n):
# Force calculation for the i-th point
x = X[i]
f = np.zeros(x.shape)
# Interact with at most 10 neighbors
Neib = neighbors(x, X, 10)
# dmin is the distance to the nearest neighbor
dmin = norm(Neib[0] - x)
for neib in Neib:
d = norm(neib - x)
if d < rmin:
# feel repulsion from points that are too near
f += repulsion(neib, x, d, rmin)
elif dmin > rmax:
# feel attraction if there are no neighbors closer than rmax
f += attraction(neib, x, d, rmax)
# save all forces and the maximum force to normalize later
F[i] = f
if norm(f) <> 0:
maxf = max(maxf, norm(f))
# update all positions using the forces
if maxf > 0:
X += (F/maxf)*step
k += 1
if k == maxk:
print "warning: iteration limit reached"
return X
我认为您的蛮力想法之一就是随机地反复生成点,并检查约束是否满足。
另一种方法是采用一种满足约束条件的配置,并反复干扰其中的一小部分,这是随机选择的,例如移动单个点,以移动到随机选择的附近配置。 如果您经常进行此操作,则应转到几乎与起点无关的随机配置。 可以在http://en.wikipedia.org/wiki/Metropolis%E2%80%93Hastings_algorithm或http://en.wikipedia.org/wiki/Gibbs_sampling下进行辩护。
我可能会尝试随机执行,然后删除掉与其他点接近的点。 您可以比较距离的平方,以节省一些数学时间。
或创建带有边框的单元格并在每个单元格中放置一个点。 随机性较小,这取决于这是否是“仅用于外观的事物”。 但这可能很快。
我做出了让步,最终使用了Poisson Disk Sampling方法。
结果非常接近我的需求,尤其是尝试次数较少(这也大大降低了成本)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.