我正在使用程序技术为我正在编写的游戏生成图形。
为了产生一些树林,我想在以< 0,0>为中心的正六边形区域内随机散布树木。
以统一的方式生成这些点的最佳方法是什么?
答案 0 :(得分:13)
如果你能为六边形找到一个好的矩形边界框,那么生成均匀随机点的最简单方法就是拒绝采样(http://en.wikipedia.org/wiki/Rejection_sampling)
也就是说,找到一个完全包含六边形的矩形,然后在矩形内生成均匀的随机点(这很容易,只需为右边的每个坐标独立生成随机值)。检查随机点是否落在六边形内。如果是,请保留它。如果不是,请提出另一点。
只要你能找到一个好的边界框(矩形的面积不应该大于它所包围的六边形面积的常数因子),这将非常快。
答案 1 :(得分:8)
一种可能简单的方法如下:
F ____ B
/\ /\
A /__\/__\ E
\ /\ /
\/__\/
D C
考虑平行四边形ADCO(中心是O)和AOBF。
此处的任何一点都可以写成两个矢量AO和AF的线性组合。
这两个平行四边形中的点P满足
P = x * AO + y * AF或x AO + y AD。
其中0 <= x&lt; 1和0&lt; = y&lt; = 1(我们对与BECO共享的边缘进行折扣)。
类似地,平行四边形BECO中的任何点Q都可以写为矢量BO和BE的线性组合,以便
Q = x BO + y BE其中0 <= x <= 1且0 <= y <= 1。
因此选择一个随机点
我们选择
A概率为2/3,B概率为1/3。
如果选择了A,则选择[0,1]中的x(注意,半开区间[0,1))和[-1,1]中的y并选择点P = x AO + y AF如果y&gt; 0否则选择P = x * AO + | y | * AD。
如果选择了B,请选择[0,1]中的x和[0,1]中的y,然后选择点Q = x BO + y BE。
因此,根据您的情况,选择一个点需要三个随机数调用,这可能已经足够了。
答案 2 :(得分:6)
如果它是正六边形,最简单的方法就是把它分成三个菱形。这样(a)它们具有相同的区域,并且(b)你可以在任何一个菱形中选择一个随机点,其中包含0到1的两个随机变量。这是一个有效的Python代码。
from math import sqrt
from random import randrange, random
from matplotlib import pyplot
vectors = [(-1.,0),(.5,sqrt(3.)/2.),(.5,-sqrt(3.)/2.)]
def randinunithex():
x = randrange(3);
(v1,v2) = (vectors[x], vectors[(x+1)%3])
(x,y) = (random(),random())
return (x*v1[0]+y*v2[0],x*v1[1]+y*v2[1])
for n in xrange(500):
v = randinunithex()
pyplot.plot([v[0]],[v[1]],'ro')
pyplot.show()
讨论中的几个人提出了均匀采样离散版六边形的问题。最自然的离散化是三角形格子,并且上述解决方案的一个版本仍然有效。您可以稍微修剪菱形,使它们各自包含相同数量的点。他们只是错过了原点,必须作为一个特例单独允许。这是一个代码:
from math import sqrt
from random import randrange, random
from matplotlib import pyplot
size = 10
vectors = [(-1.,0),(.5,sqrt(3.)/2.),(.5,-sqrt(3.)/2.)]
def randinunithex():
if not randrange(3*size*size+1): return (0,0)
t = randrange(3);
(v1,v2) = (vectors[t], vectors[(t+1)%3])
(x,y) = (randrange(0,size),randrange(1,size))
return (x*v1[0]+y*v2[0],x*v1[1]+y*v2[1])
# Plot 500 random points in the hexagon
for n in xrange(500):
v = randinunithex()
pyplot.plot([v[0]],[v[1]],'ro')
# Show the trimmed rhombuses
for t in xrange(3):
(v1,v2) = (vectors[t], vectors[(t+1)%3])
corners = [(0,1),(0,size-1),(size-1,size-1),(size-1,1),(0,1)]
corners = [(x*v1[0]+y*v2[0],x*v1[1]+y*v2[1]) for (x,y) in corners]
pyplot.plot([x for (x,y) in corners],[y for (x,y) in corners],'b')
pyplot.show()
这是一张照片。
alt text http://www.freeimagehosting.net/uploads/0f80ad5d9a.png
答案 3 :(得分:2)
传统方法(适用于任何多边形形状的区域)是对原始六边形进行梯形分解。完成后,您可以通过以下两步过程选择随机点:
1)从分解中选择一个随机梯形。每个梯形的选择概率与其面积成正比。
2)在步骤1中选择的梯形中均匀选择一个随机点。
如果您愿意,可以使用三角测量而不是梯形分解。
答案 4 :(得分:1)
将其切成六个三角形(因此这适用于任何正多边形),随机选择一个三角形和randomly choose a point in the selected triangle。
选择三角形中的随机点为well-documented problem。
当然,这是非常快的,你只需每点产生3个随机数 - 没有拒绝等等。
由于您必须生成两个随机数,this is how you do it:
R = random(); //Generate a random number called R between 0-1
S = random(); //Generate a random number called S between 0-1
if(R + S >=1)
{
R = 1 – R;
S = 1 – S;
}
答案 5 :(得分:1)
您可以查看我的2009年论文,在那里我推导出一种“精确”的方法,在不同的格子形状内生成“随机点”:“六角形”,“菱形”和“三角形”。据我所知,它是“最优化的方法”,因为对于每个2D位置,您只需要两个随机样本。之前派生的其他作品需要每个2D位置3个样本!
希望这能回答这个问题!
答案 6 :(得分:0)
1)从点到数字进行切换(只是枚举它们),得到随机数 - &gt;得到点。
另一种解决方案。
2)如果N - 六边形的长度,从[1..N]得到3个随机数,从某个角开始,用3个方向移动3次。
答案 7 :(得分:0)
上面的拒绝采样解决方案直观而简单,但使用矩形和(推测)欧几里德,X / Y坐标。你可以通过使用半径为r的圆来提高效率(尽管仍然不是最理想的),并使用来自中心的极坐标生成随机点,其中距离为rand()* r,而theta(以弧度表示)将是兰特()* 2 * PI。