简体   繁体   English

如何在 C++ 中有效地生成多边形内部的随机 X 和 Y 值?

[英]How can I efficiently generate a random X and Y value INSIDE of a polygon in C++?

So I'm creating a virtual mapping software that essentially breaks coordinates into Areas.所以我正在创建一个虚拟地图软件,它基本上将坐标分解为区域。 An Area is comprised of a defined list of boundary coordinates (coordinates that make the outer rim of the area, which connect to one another).区域由定义的边界坐标列表(构成区域外缘的坐标,它们相互连接)组成。

With this software, I need to randomly select points in EACH area that reside INSIDE of the areas boundary coordinates.使用此软件,我需要在每个区域中随机选择位于区域边界坐标内的点。 Each area is different from the other and can have many more or even less sides, but with a minimum of 3 sides and no maximum sides.每个区域都与另一个不同,可以有更多或更少的边,但最少有 3 个边,没有最大边。

I currently have a solution in which I simply generate random numbers until the numbers are within the area.我目前有一个解决方案,我只是生成随机数,直到数字在该区域内。 However, due to the quantity of Areas (have vastly different Boundary coordinates ranging in small to HUGE values) & the quantity of points (could be 1-100+) this tactic proves to be highly inefficient (takes a long time to finish running).然而,由于区域的数量(具有从小到大的巨大差异的边界坐标)和点的数量(可能是 1-100+),这种策略被证明是非常低效的(需要很长时间才能完成运行) . I would like to hear peoples ideas or even experiences/work on how to optimize this so it isn't so sluggish.我想听听人们的想法,甚至是如何优化它的经验/工作,这样它就不会那么迟钝了。

I've created a small demo application to explain the situation better...我创建了一个小的演示应用程序来更好地解释这种情况......

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

The sample output would output a coordinate set inside the Area... In this specific example my first run it output:示例输出将输出区域内的坐标集......在这个特定示例中,我第一次运行它输出:

Random Coordinate: (-1, 1)

I've read that dividing the Area into triangles,then picking a random triangle, and generating a random coordinate within that triangle is the best solution... But I've no idea how to generate triangles out of an Areas coordinate set, and if I could do that... Why wouldn't I just use that technique to choose a random coordinate...?我读过将区域划分为三角形,然后选择一个随机三角形,并在该三角形内生成随机坐标是最好的解决方案......但我不知道如何从区域坐标集中生成三角形,并且如果我可以这样做...为什么我不使用该技术来选择一个随机坐标...?

--------Edit-------- - - - - 编辑 - - - -

Thanks to Matt Timmermans I was able to solve this issue by further researching the subject and applying most of what Matt explained below.感谢 Matt Timmermans,我能够通过进一步研究这个主题并应用 Matt 在下面解释的大部分内容来解决这个问题。

If anyone else is having difficulty with the subject, here's what I came up with (mostly what Matt mentioned, with some changes)如果其他人对这个主题有困难,这就是我想出的(主要是马特提到的,有一些变化)

1) Triangulate the polygon into multiple triangles, in my case I needed a simple and lightweight C++ solution with 0 graphical interfaces. 1) 将多边形三角化为多个三角形,在我的情况下,我需要一个具有 0 个图形界面的简单轻量级 C++ 解决方案。 I managed to find a working class online called Triangulate here http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml .我设法在http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml找到了一个名为 Triangulate 的在线工人阶级。

2) Randomly choose a triangle using weighted probability. 2)使用加权概率随机选择一个三角形。 If a triangle occupies 80% of the original polygon, it should be chosen roughly 80% of the time.如果一个三角形占据了原始多边形的 80%,那么大约 80% 的时间应该选择它。

At this point in the process I was able to do some research and find some variations, the simplest of which is the one I chose (as seen below).在这个过程中的这一点上,我能够做一些研究并找到一些变化,其中最简单的是我选择的一个(如下所示)。

3) Once you have chosen a triangle, generate a uniformly random point within this triangle. 3)一旦你选择了一个三角形,在这个三角形内生成一个均匀随机的点。 This can be accomplished through the use of this formula:这可以通过使用以下公式来完成:

P = (1 - sqrt(r1)) * A + (sqrt(r1) * (1 - r2)) * B + (sqrt(r1) * r2) * C

Where r1 and r2 are random numbers between 0 and 1 as described in this article section 4.2... http://www.cs.princeton.edu/~funk/tog02.pdf其中 r1 和 r2 是 0 和 1 之间的随机数,如本文第 4.2 节所述... http://www.cs.princeton.edu/~funk/tog02.pdf

You are done, that's all it takes!你完成了,这就是全部!

Alternatively, you can continue with what Matt suggested, both methods seem to work perfectly in any case.. Which is...或者,您可以继续使用 Matt 建议的方法,这两种方法似乎在任何情况下都可以完美运行……这是……

3) Copy the triangle and create a parallelogram with it and the original triangle. 3)复制三角形并用它和原始三角形创建一个平行四边形。 Using the following formulas:使用以下公式:

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) Generate a random number from within the parallelogram by generating a random x and y value between the min and max x and y values of the parallelogram until you are within the parallelogram. 4) 通过在平行四边形的最小和最大 x 和 y 值之间生成随机 x 和 y 值,直到您在平行四边形内,从平行四边形内生成随机数。 5) If the random coordinate is INSIDE the COPIED triangle, map it to the corresponding point in the original triangle, if not you're done. 5)如果随机坐标在复制的三角形内,则将其映射到原始三角形中的相应点,否则就完成了。

  1. Divide the polygon into triangles将多边形分成三角形
  2. Randomly choose a triangle, giving each triangle a probability proportional to its area随机选择一个三角形,给每个三角形一个与其面积成正比的概率
  3. Copy the triangle to make a parallelogram复制三角形以制作平行四边形
  4. Pick a random point in the parallelogram by randomly choosing coordinates in the base and height directions通过随机选择底和高度方向的坐标,在平行四边形中随机选择一个点
  5. If the random point is in the copy of the triangle, not in the original triangle, then map it to the corresponding point in the original triangle.如果随机点在三角形的副本中,而不在原始三角形中,则将其映射到原始三角形中的对应点。
  6. Done -- you're left with a random point in the chosen triangle, which is a random point chosen uniformly from the polygon.完成 - 您在所选三角形中留下了一个随机点,这是从多边形中均匀选择的一个随机点。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在 C++ 中有效地生成排序均匀分布的随机数? - How can I generate sorted uniformly distributed random numbers efficiently in C++? 如何在c ++中生成随机顶点以形成凸多边形? - How to generate random vertices to form a convex polygon in c++? 在C ++中,如何根据双值概率生成随机数? - In C++, How Can I Generate A Random Number Based Off Of A Double Value Probability? 如何将 Boost Polygon 划分为区域以在 C++ 中获得随机点? - How can i divide a Boost Polygon into regions to get random points in c++? C++ - 如何通过将 x/y/z 增加给定值 x 来生成 n 个 3D 坐标的每个可能组合 - C++ - How to generate every possible combination of n 3D coordinates by incrementing x/y/z by a given value x 我应该如何在 C++ 的类方法中正确使用 __attribute__ ((format (printf, x, y))) ? - How should I properly use __attribute__ ((format (printf, x, y))) inside a class method in C++? 如何在 C++ 中有效地构造随机骰子 - How to efficiently construct random dice in C++ 如何在C ++中有效地计算2 ^ y = 2 ^ q0 + ... + 2 ^ qn中的&#39;y&#39;? - how to compute 'y' in 2^y = 2^q0 + … + 2^qn efficiently in C++? 如何从C ++中的双变量正态和学生T分布中生成随机样本? - How can I generate random samples from bivariate normal and student T distibutions in C++? 在C ++中,如何生成介于两个范围之间的随机数? - In C++, how can I generate a random number that falls between two ranges?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM