为程序游戏内容生成六边形内的随机点

发布于 2024-09-10 05:15:03 字数 113 浏览 5 评论 0原文

我正在使用程序技术为我正在编写的游戏生成图形。

为了生成一些树林,我想将树木随机散布在以 <0,0> 为中心的正六边形区域内。

以统一的方式生成这些点的最佳方法是什么?

I'm using procedural techniques to generate graphics for a game I am writing.

To generate some woods I would like to scatter trees randomly within a regular hexagonal area centred at <0,0>.

What is the best way to generate these points in a uniform way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

双手揣兜 2024-09-17 05:15:03

如果您能为六边形找到一个好的矩形边界框,则生成均匀随机点的最简单方法是通过拒绝采样(http://en.wikipedia.org/wiki/Rejection_sampling

即找到一个完全包含你的六边形的矩形,然后在矩形内生成均匀的随机点(这很简单,只需独立生成随机点即可)正确范围内每个坐标的值)。检查随机点是否落在六边形内。如果是,请保留。如果不是,则再画一个点。

只要你能找到一个好的边界框(矩形的面积不应超过它所包围的六边形面积的常数因子),这将非常快。

If you can find a good rectangular bounding box for your hexagon, the easiest way to generate uniformly random points is by rejection sampling (http://en.wikipedia.org/wiki/Rejection_sampling)

That is, find a rectangle that entirely contains your hexagon, and then generate uniformly random points within the rectangle (this is easy, just independently generate random values for each coordinate in the right range). Check if the random point falls within the hexagon. If yes, keep it. If no, draw another point.

So long as you can find a good bounding box (the area of the rectangle should not be more than a constant factor larger than the area of the hexagon it encloses), this will be extremely fast.

你是暖光i 2024-09-17 05:15:03

一种可能简单的方法如下:

    F ____ B
     /\  /\
  A /__\/__\ E
    \  /\  /
     \/__\/
     D     C

考虑平行四边形 ADCO(中心为 O)和 AOBF。

其中的任何一点都可以写成两个向量 AO 和 AF 的线性组合。

这两个平行四边形中的点 P 满足

P = x* AO + y * AF 或 xAO + yAD。

其中 0 <= x < 1 和 0 <= y <= 1 (我们折扣与 BECO 共享的边)。

类似地,平行四边形 BECO 中的任何点 Q 都可以写成向量 BO 和 BE 的线性组合,使得

Q = xBO + yBE,其中 0 <=x <=1 且 0 <=1。 =y <= 1。

因此,为了选择随机点,

我们

以 2/3 的概率选择 A,以 1/3 的概率选择 B。

如果选择 A,则在 [0,1) 中选择 x(注意,半开区间 [0,1)),在 [-1,1] 中选择 y,并选择点 P = xAO+yAF如果y> 0 否则选择 P = x*AO + |y|*AD。

如果选择 B,则在 [0,1] 中选择 x,在 [0,1] 中选择 y,然后选择点 Q = xBO + yBE。

因此,需要三次随机数调用才能选择一个点,这可能足够好,具体取决于您的情况。

A possibly simple way is the following:

    F ____ B
     /\  /\
  A /__\/__\ E
    \  /\  /
     \/__\/
     D     C

Consider the parallelograms ADCO (center is O) and AOBF.

Any point in this can be written as a linear combination of two vectors AO and AF.

An point P in those two parallelograms satisfies

P = x* AO + y * AF or xAO + yAD.

where 0 <= x < 1 and 0 <= y <= 1 (we discount the edges shared with BECO).

Similarly any point Q in the parallelogram BECO can be written as the linear combination of vectors BO and BE such that

Q = xBO + yBE where 0 <=x <=1 and 0 <=y <= 1.

Thus to select a random point

we select

A with probability 2/3 and B with probability 1/3.

If you selected A, select x in [0,1) (note, half-open interval [0,1)) and y in [-1,1] and choose point P = xAO+yAF if y > 0 else choose P = x*AO + |y|*AD.

If you selected B, select x in [0,1] and y in [0,1] and choose point Q = xBO + yBE.

So it will take three random number calls to select one point, which might be good enough, depending on your situation.

指尖上得阳光 2024-09-17 05:15:03

如果是正六边形,想到的最简单的方法就是将其分成三个菱形。这样,(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()

这是一张图片。

替代文本 http://www.freeimagehosting.net/uploads/0f80ad5d9a.png

If it's a regular hexagon, the simplest method that comes to mind is to divide it into three rhombuses. That way (a) they have the same area, and (b) you can pick a random point in any one rhombus with two random variables from 0 to 1. Here is a Python code that works.

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()

A couple of people in the discussion raised the question of uniformly sampling a discrete version of the hexagon. The most natural discretization is with a triangular lattice, and there is a version of the above solution that still works. You can trim the rhombuses a little bit so that they each contain the same number of points. They only miss the origin, which has to be allowed separately as a special case. Here is a code for that:

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()

And here is a picture.

alt text http://www.freeimagehosting.net/uploads/0f80ad5d9a.png

清风不识月 2024-09-17 05:15:03

传统方法(适用于任何多边形形状的区域)是对原始六边形进行梯形分解。完成后,您可以通过以下两步过程选择随机点:

1) 从分解中选择一个随机梯形。每个梯形的选择概率与其面积成正比。

2) 在步骤 1 中选择的梯形中均匀地选择一个随机点。

如果您愿意,可以使用三角剖分代替梯形分解。

The traditional approach (applicable to regions of any polygonal shape) is to perform trapezoidal decomposition of your original hexagon. Once that is done, you can select your random points through the following two-step process:

1) Select a random trapezoid from the decomposition. Each trapezoid is selected with probability proportional to its area.

2) Select a random point uniformly in the trapezoid chosen on step 1.

You can use triangulation instead of trapezoidal decomposition, if you prefer to do so.

夜巴黎 2024-09-17 05:15:03

将其切成六个三角形(因此这适用于任何正多边形),随机选择一个三角形,然后 随机选择所选三角形中的一个点

在三角形中选择随机点是一个有据可查的问题。

当然,这非常快,您只需为每个点生成 3 个随机数 --- 无需拒绝等。

更新:

由于您必须生成两个随机数,这就是你的做法

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;
}

Chop it up into six triangles (hence this applies to any regular polygon), randomly choose one triangle, and randomly choose a point in the selected triangle.

Choosing random points in a triangle is a well-documented problem.

And of course, this is quite fast and you'll only have to generate 3 random numbers per point --- no rejection, etc.

Update:

Since you will have to generate two random numbers, 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;
}
沫尐诺 2024-09-17 05:15:03

您可以查看我 2009 年的论文,其中我导出了一种“精确”方法来在不同的晶格形状(“六边形”、“菱形”和“三角形”)内生成“随机点”。据我所知,这是“最优化的方法”,因为对于每个 2D 位置,您只需要两个随机样本。之前导出的其他作品需要每个 2D 位置 3 个样本!

希望这能回答这个问题!

http://arxiv.org/abs/1306.0162

You may check my 2009 paper, where I derived an "exact" approach to generate "random points" inside different lattice shapes: "hexagonal", "rhombus", and "triangular". As far as I know it is the "most optimized approach" because for every 2D position you only need two random samples. Other works derived earlier require 3 samples for each 2D position!

Hope this answers the question!

http://arxiv.org/abs/1306.0162

_蜘蛛 2024-09-17 05:15:03

1)从点到数字进行二分(只需枚举它们),得到随机数->明白了。

另一个解决方案。

2)如果N - 六边形边长,则从[1..N]中获取3个随机数,从某个角开始,用这些数字向3个方向移动3次。

1) make biection from points to numbers (just enumerate them), get random number -> get point.

Another solution.

2) if N - length of hexagon's side, get 3 random numbers from [1..N], start from some corner and move 3 times with this numbers for 3 directions.

绿萝 2024-09-17 05:15:03

上面的拒绝采样解决方案直观且简单,但使用矩形和(大概)欧几里德 X/Y 坐标。您可以通过使用半径为 r 的圆来稍微提高效率(尽管仍然不是最佳),并使用从中心开始的极坐标生成随机点,其中距离为 rand()*r,theta(以弧度为单位)为兰特()* 2 * PI。

The rejection sampling solution above is intuitive and simple, but uses a rectangle, and (presumably) euclidean, X/Y coordinates. You could make this slightly more efficient (though still suboptimal) by using a circle with radius r, and generate random points using polar coordinates from the center instead, where distance would be rand()*r, and theta (in radians) would be rand()*2*PI.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文