如何在c++中有效地生成多边形内部的随机X和Y值
How can I efficiently generate a random X and Y value INSIDE of a polygon in C++?
所以我正在创建一个虚拟地图软件,它基本上将坐标分解为区域。一个区域由一组定义好的边界坐标(构成区域外缘的坐标,它们彼此相连)组成。
使用此软件,我需要在每个区域中随机选择位于区域边界坐标内的点。每个区域都是不同的,可以有更多或更少的边,但至少有3个边,没有最大边。
我目前有一个解决方案,我简单地生成随机数,直到数字在区域内。然而,由于区域的数量(有非常不同的边界坐标,范围从小到巨大的值)&点数(可以是1-100+)这个策略被证明是非常低效的(需要很长时间才能完成跑步)。我想听听大家的想法,甚至经验/工作如何优化这一点,使它不是那么迟钝。
我已经创建了一个小的演示应用程序来更好地解释这种情况…
#include "stdafx.h"
#include <vector>
#include <random>
const int GenerateRandomNumberBetween(
const int start,
const int end)
{
const int stable_end = ((end < start) ? start : end);
std::random_device rd;
std::mt19937 generator(rd());
std::uniform_int_distribution<int> distribution(start, stable_end);
return distribution(generator); // generates number in the range the distribution value
}
class Area
{
public:
Area()
{
// Define a primitive area for this example, but please note that this is a very basic area, and most areas are acctually much larger and have many more sides...
// This sample area creates a triangle.
//(-2, 2);
boundaries_x_coordinates.push_back(-2);
boundaries_y_coordinates.push_back(2);
//(2, 2);
boundaries_x_coordinates.push_back(2);
boundaries_y_coordinates.push_back(2);
//(-2, 2);
boundaries_x_coordinates.push_back(-2);
boundaries_y_coordinates.push_back(-2);
}
const bool InArea(
const int x,
const int y)
{
// This function works just fine, and can be ignored... I just included it to show that we check if the new coordinates are indeed within the given Area.
int minX = 0;
int maxX = 0;
int minY = 0;
int maxY = 0;
for (int i = 0; i < boundaries_x_coordinates.size(); i++)
{
if (boundaries_x_coordinates[0] < minX)
{
minX = boundaries_x_coordinates[0];
}
if (boundaries_x_coordinates[0] > maxX)
{
maxX = boundaries_x_coordinates[0];
}
if (boundaries_y_coordinates[1] < minY)
{
minY = boundaries_y_coordinates[1];
}
if (boundaries_y_coordinates[1] > maxY)
{
maxY = boundaries_y_coordinates[1];
}
}
if (boundaries_x_coordinates.size() < 3)
{
return false;
}
else if (x < minX || x > maxX || y < minY || y > maxY)
{
return false;
}
else
{
size_t i, j, c = 0;
for (i = 0, j = boundaries_x_coordinates.size() - 1; i < boundaries_x_coordinates.size(); j = i++)
{
if (((boundaries_y_coordinates[i] > y) != (boundaries_y_coordinates[j] > y)) &&
(x < (boundaries_x_coordinates[j] - boundaries_x_coordinates[i]) * (y - boundaries_y_coordinates[i]) /
(boundaries_y_coordinates[j] - boundaries_y_coordinates[i]) + boundaries_x_coordinates[i]))
{
c = !c;
}
}
return (c == 0) ? false : true;
}
}
std::vector<int> GenerateRandomPointInsideArea()
{
int minX = 0, maxX = 0, minY = 0, maxY = 0;
for (int i = 0; i < boundaries_x_coordinates.size(); i++)
{
if (boundaries_x_coordinates[i] < minX)
{
minX = boundaries_x_coordinates[i];
}
if (boundaries_x_coordinates[i] > maxX)
{
maxX = boundaries_x_coordinates[i];
}
if (boundaries_y_coordinates[i] < minY)
{
minY = boundaries_y_coordinates[i];
}
if (boundaries_y_coordinates[i] > maxY)
{
maxY = boundaries_y_coordinates[i];
}
}
// The problem is here, this do while statement takes a tremendous of time to execute in realistic Areas simply because it takes a
// long time to generate all the random coordinates inside the area (sometimes could be as little as 1 coordinate set, sometimes could be 100).
int random_x = 0;
int random_y = 0;
do
{
random_x = GenerateRandomNumberBetween(minX, maxX);
random_y = GenerateRandomNumberBetween(minY, maxY);
} while (!InArea(random_x, random_y));
std::vector<int> random_coordinates;
random_coordinates.push_back(random_x);
random_coordinates.push_back(random_y);
return random_coordinates;
}
private:
std::vector<int> boundaries_x_coordinates;
std::vector<int> boundaries_y_coordinates;
};
int main()
{
Area* sample_area = new Area();
std::vector<int> random_coordinates = sample_area->GenerateRandomPointInsideArea();
printf("Random Coordinate: (%i, %i)n", random_coordinates[0], random_coordinates[1]);
// Pause to see results.
system("pause");
return 0;
}
示例输出将输出区域内的坐标集…在这个特定的示例中,我第一次运行它输出:
Random Coordinate: (-1, 1)
我读到将区域划分为三角形,然后随机选择一个三角形,并在该三角形内生成随机坐标是最佳解决方案……但我不知道如何从一个区域坐标集中生成三角形,如果我能做到这一点……为什么我不使用这种技术来选择一个随机坐标呢?
——编辑 --------
感谢Matt Timmermans,我能够通过进一步研究这个主题并应用Matt下面解释的大部分内容来解决这个问题。
如果其他人对这个主题有困难,以下是我想到的(主要是Matt提到的,做了一些修改)
1)将多边形三角化成多个三角形,在我的情况下,我需要一个简单而轻量级的c++解决方案,没有图形界面。我在网上找到了一个叫做Triangulate的工人阶级网站http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml。2)使用加权概率随机选择一个三角形。如果一个三角形占据了原多边形的80%,那么它应该在大约80%的时间内被选中。
在这个过程中,我能够做一些研究并找到一些变化,其中最简单的是我选择的(如下所示)。
3)一旦你选择了一个三角形,在这个三角形内生成一个均匀随机的点。这可以通过使用下面的公式来实现:
P = (1 - sqrt(r1)) * A + (sqrt(r1) * (1 - r2)) * B + (sqrt(r1) * r2) * C
其中r1和r2为0 ~ 1之间的随机数,如本文4.2节所述…http://www.cs.princeton.edu/恐惧/tog02.pdf
你完成了,这是所有需要的!
或者,你可以继续Matt的建议,这两种方法似乎在任何情况下都很有效。这是…
3)复制三角形,用它和原始三角形创建一个平行四边形。使用以下公式:
M=(A+C)/2
P4=M-(B-M)
Where...
M is a midpoint in the original triangle where the copied triangle will connect.
A,B,C are the 3 vertices in the original triangle
P4 is the new point the forms the parallelogram with the other 3 points of the original triangle.
4)通过在平行四边形的最小和最大x和y值之间生成一个随机x和y值,从平行四边形内生成一个随机数,直到你在平行四边形内。5)如果随机坐标在复制的三角形内部,则将其映射到原始三角形的相应点,否则就完成了
- 将多边形划分为三角形
- 随机选择一个三角形,给每个三角形一个与其面积成比例的概率
- 复制三角形形成平行四边形
- 在平行四边形中随机选取一个点,在基础和高度方向上随机选择坐标
- 如果随机点在三角形的副本中,而不是在原始三角形中,则将其映射到原始三角形中的相应点。
- 完成——你在选中的三角形中留下一个随机的点,这是一个随机的点,从多边形中均匀选择。
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- 为什么 Serial.println(<char[]>);返回随机字符?
- 字符串-C++后显示的随机字符
- 将函数类成员映射到类本身内部
- 循环中的随机函数
- 在c++构造函数中使用随机字符串生成器
- Boost Spirit,获取迭代器内部语义动作
- 我不明白为什么我声明一个空的内部结构并将其传递给构造函数
- 内联函数中具有内部链接的全局变量
- 在函数内部的声明中初始化数组,并在外部使用它
- 如何在不知道向量大小的情况下输入向量内部的向量?
- 卷曲bracers内部结构的声明
- 使用std::mt19937从字符串中返回一个随机单词
- 从函数角度看ID到文件路径的内部与外部映射
- 为什么std::condition_variable notify_all的工作速度比notify_one快(对于随机请
- spdlog标头仅与外部fmt一起使用.spdlog错误:'内部':不是'fmt'
- 我在理解 AVX 随机内部函数如何为 8 位时遇到一些问题
- 具有内部随机函数的结构的CUDA移植
- 如何在c++中有效地生成多边形内部的随机X和Y值
- 如何清理(用随机字节覆盖)std::string内部缓冲区