簡體   English   中英

如何在 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 在下面解釋的大部分內容來解決這個問題。

如果其他人對這個主題有困難,這就是我想出的(主要是馬特提到的,有一些變化)

1) 將多邊形三角化為多個三角形,在我的情況下,我需要一個具有 0 個圖形界面的簡單輕量級 C++ 解決方案。 我設法在http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml找到了一個名為 Triangulate 的在線工人階級。

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/~funk/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)如果隨機坐標在復制的三角形內,則將其映射到原始三角形中的相應點,否則就完成了。

  1. 將多邊形分成三角形
  2. 隨機選擇一個三角形,給每個三角形一個與其面積成正比的概率
  3. 復制三角形以制作平行四邊形
  4. 通過隨機選擇底和高度方向的坐標,在平行四邊形中隨機選擇一個點
  5. 如果隨機點在三角形的副本中,而不在原始三角形中,則將其映射到原始三角形中的對應點。
  6. 完成 - 您在所選三角形中留下了一個隨機點,這是從多邊形中均勻選擇的一個隨機點。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM