我有一个由2D平面上4个点定义的4边凸多边形,想要能够在其中生成随机点。
如果将问题简化为一个平行四边形,那么问题会变得更简单,但更通用的答案更好。
生成随机点直到其位于多边形内并不可行,因为需要的时间真的很难预测。
我有一个由2D平面上4个点定义的4边凸多边形,想要能够在其中生成随机点。
如果将问题简化为一个平行四边形,那么问题会变得更简单,但更通用的答案更好。
生成随机点直到其位于多边形内并不可行,因为需要的时间真的很难预测。
由于提问者的问题有些含糊,因此我将回答以下问题:如何在任意四边形内从均匀分布生成一个点,实际上是如何在任意(凸)多边形内从均匀分布生成一个点的概括。答案基于从三角形中生成服从均匀分布的样本(请参见http://mathworld.wolfram.com/TrianglePointPicking.html,其中有非常好的解释)。
为了完成这个问题,我们需要:
对多边形进行三角剖分(即生成一组不重叠的三角形区域来覆盖多边形)。对于四边形,可以在任意两个不相邻的顶点之间创建一条边。对于其他多边形,请参阅http://en.wikipedia.org/wiki/Polygon_triangulation获取起点,或直接使用http://www.cgal.org/库。
对于每个三角形,赋予一个索引(即0、1、2等)。对于四边形,它们将是0、1。我们为每个三角形分配一个权重,如下所示:
然后生成一个随机索引i,使其服从有限分布的概率与它们的权重成比例。对于四边形,这是一个伯努利分布:
假设 v0、v1、v2 为三角形的顶点(通过它们的位置表示,因此v0 =(x0,y0),等等)。然后我们生成两个随机数 a0 和 a1,都从区间 [0,1] 中均匀地绘制。接着我们通过 x = a0 (v1-v0) + a1 (v2-v0) 计算出随机点 x。
注意,x 有一半的概率落在三角形外面,但如果是这种情况,它将位于由三角形和以(v1,v2)中点为圆心旋转 π 后的映像形成的平行四边形内部(图中虚线所示)。在这种情况下,我们可以生成新的点 x' = v0 + R(pi)(x - v3),其中 R(pi) 是一个π弧度(180度)的旋转。点 x' 将在三角形内部。
进一步注意,如果四边形已经是一个平行四边形,则我们不必随机选择一个三角形,我们可以确定性地选择任意一个,然后选择点 x 而无需测试它是否在其源三角形内。
x' = v0 + (v3 - x)
。我完全错了吗?再仔细看一下,我不确定自己是否正确,但我的测试用例 v0 = [0,0] 将 x' 放在三角形外面。 - Gabriel LittmanA. 如果您可以将输入限制为平行四边形,则这非常简单:
u
和v
。如果您的平行四边形由点ABCD定义,使得AB,BC,CD和DA是其边,则将您的点取为:
p = A + (u * AB) + (v * AD)
其中AB
为从点A到点B的向量,AD
为从点A到点D的向量。
B. 如果您不能用叉积计算面积,还可以使用重心坐标。对于一个四边形,重心坐标对应于4个坐标(a,b,c,d)
,使得a+b+c+d=1
。然后,四边形内的任何点P
都可以由一个四元组描述,如下所示:
P = a A + b B + c C + d D
在您的情况下,您可以生成4个随机数并将它们归一化,使它们加起来等于1。这会给您一个点。请注意,在这种情况下,点的分布将不是均匀的。
C. 您还可以像其他地方提出的那样,将四边形分解为两个三角形,并使用半平行四边形方法(即作为平行四边形,但添加条件u+v=1
)或三角形的重心坐标。然而,如果您想要均匀分布,一个三角形内有点的概率必须等于该三角形面积除以四边形面积的比例。
// public-domain code by Darel Rex Finley, 2007
int nodes, nodeX[MAX_POLY_CORNERS], pixelX, pixelY, i, j, swap ;
// Loop through the rows of the image.
for (pixelY=IMAGE_TOP; pixelY<IMAGE_BOT; pixelY++) {
// Build a list of nodes.
nodes=0; j=polyCorners-1;
for (i=0; i<polyCorners; i++) {
if (polyY[i]<(double) pixelY && polyY[j]>=(double) pixelY
|| polyY[j]<(double) pixelY && polyY[i]>=(double) pixelY) {
nodeX[nodes++]=(int) (polyX[i]+(pixelY-polyY[i])/(polyY[j]-polyY[i])
*(polyX[j]-polyX[i])); }
j=i; }
// Sort the nodes, via a simple “Bubble” sort.
i=0;
while (i<nodes-1) {
if (nodeX[i]>nodeX[i+1]) {
swap=nodeX[i]; nodeX[i]=nodeX[i+1]; nodeX[i+1]=swap; if (i) i--; }
else {
i++; }}
// Fill the pixels between node pairs.
// Code modified by SoloBold 27 Oct 2008
// The flagPixel method below will flag a pixel as a possible choice.
for (i=0; i<nodes; i+=2) {
if (nodeX[i ]>=IMAGE_RIGHT) break;
if (nodeX[i+1]> IMAGE_LEFT ) {
if (nodeX[i ]< IMAGE_LEFT ) nodeX[i ]=IMAGE_LEFT ;
if (nodeX[i+1]> IMAGE_RIGHT) nodeX[i+1]=IMAGE_RIGHT;
for (j=nodeX[i]; j<nodeX[i+1]; j++) flagPixel(j,pixelY); }}}
// TODO pick a flagged pixel randomly and fill it, then remove it from the list.
// Repeat until no flagged pixels remain.
您所说的“一般”是指所有非平行四边形的四边形,还是所有可能的四边形?
如果你有这个图形,可以画一条连接四条边的随机线,例如:
.BBBB.
A C
A C
.DDDD.
首先在单位正方形上生成一个随机点,然后在线段B和D上标记该点在X轴上的距离百分比。使用Y轴的值在线段A和C上执行相同的操作。
然后连接线段A到线段C和线段B到线段D,交点将被用作随机点。
由于舍入误差会帮助某些点,所以它并不是均匀的,但是如果您使用浮点数值,它应该是接近的。
实现也应该相当容易,因为您已经在处理多边形。您应该已经有可以执行这些简单任务的代码。
以下是快速伪代码:
void GetRandomPoint(Polygon p, ref float x, ref float y) {
float xrand = random();
float yrand = random();
float h0 = p.Vertices[0] + xrand * p.Vertices[1];
float h1 = p.Vertices[2] + yrand * p.Vertices[3];
float v0 = p.Vertices[0] + xrand * p.Vertices[2];
float v1 = p.Vertices[1] + yrand * p.Vertices[3];
GetLineIntersection(h0, h1, v0, v1, x, y);
}
以下内容适用于普通的凸四边形:
您可以从有限元方法中借鉴一些概念,特别是针对四边形(4边形)元素(请参考此处的第16.5节)。基本上,有一个双线性参数化,将u-v空间中的正方形(在这种情况下,u,v \ in [-1,1])映射到由点p_i(i = 1,2,3,4)组成的四边形。请注意,在提供的参考文献中,参数称为\eta和\xi。
基本步骤:
唯一的问题是u-v空间中均匀分布的点不会在欧几里德意义下产生在您的四边形中均匀分布的点。如果这很重要,您可以直接在四边形的边界框内以2D方式工作,并编写一个点在四边形内(可能通过将问题分成两个点在三角形内)的测试来剔除在外部的随机点。
这些点需要均匀分布吗?还是任何分布都可以?
这个多边形可以是凹的吗?还是保证是凸的?
如果上述两个问题的答案都是否定的,那么就选择任意两个顶点,并在它们之间的线段上选择一个随机点。这仅限于连接顶点的线段(即非常不均匀);您可以通过选择第三个顶点,然后在该点和第一个点之间选择一个点来做得更好——仍然不均匀,但至少可以选择多边形中的任何点。
在两个点之间选择一个随机点很容易,只需使用公式 A + p(B-A),其中A和B是两个点,p是0.0到1.0之间的随机数。