在 `M x N` 二維網格中生成 10 個隨機坐標,**使其空間分布「聚集」而非均勻分散** (即點之間距離較小,形成簇)。
| 算法 | 原理 | 聚集程度控制 | 代碼複雜度 | 適用場景 |
|---|---|---|---|---|
| 高斯混合模型 (GMM) 采樣 | 預設 K 個簇中心,每點從最近簇的高斯分布采樣 | 協方差矩陣 `σ²` 控制擴散半徑 | 低 | 自然現象模擬、遊戲資源點 |
| 泊松盤采樣 (Poisson Disk) 反向 | 標準算法生成「最小距離」均勻分布,**取反邏輯**:強制最小距離極小 | 半徑 `r` → 極小值 | 中 | 需嚴格控制最小間距 |
| 聚類優先采樣 | 先隨機選 1-3 個種子點,後續點在現有點半徑 `R` 內均勻生成 | 種子數、半徑 `R` | **極低** | 快速原型、程序化地圖 |
| Perlin/Simplex Noise 閾值 | 生成噪聲圖,高值區域作為候選區,在候選區均勻采樣 | 噪聲頻率、閾值 | 中 | 地形生成、有機形狀簇 |
#include
#include
#include
struct Point { int x, y; };
std::vector generateClustered(int width, int height, int count, int clusterRadius) {
std::vector points;
std::mt19937 rng(std::random_device{}());
std::uniform_int_distribution distX(0, width - 1);
std::uniform_int_distribution distY(0, height - 1);
std::uniform_int_distribution distR(-clusterRadius, clusterRadius);
// 1. 先產生 1-3 個種子點
int seeds = std::uniform_int_distribution(1, 3)(rng);
for (int i = 0; i < seeds; ++i) {
points.push_back({ distX(rng), distY(rng) });
}
// 2. 其餘點在現有點鄰域內生成
while ((int)points.size() < count) {
const Point& base = points[std::uniform_int_distribution(0, points.size() - 1)(rng)];
int nx = base.x + distR(rng);
int ny = base.y + distR(rng);
// 邊界裁剪
nx = std::clamp(nx, 0, width - 1);
ny = std::clamp(ny, 0, height - 1);
points.push_back({ nx, ny });
}
return points;
}
// 使用示例
auto pts = generateClustered(100, 100, 10, 5); // 100x100 網格, 10點, 聚類半徑5
for (auto& p : pts) std::cout << p.x << "," << p.y << "\n";
#include // 需 Eigen 庫
struct Cluster { Eigen::Vector2d mean; Eigen::Matrix2d cov; };
std::vector generateGMM(int width, int height, int count, const std::vector& clusters) {
std::vector points;
std::mt19937 rng(std::random_device{}());
std::uniform_real_distribution<> distCluster(0.0, 1.0);
std::normal_distribution<> norm(0.0, 1.0);
// 累積權重選簇
std::vector weights;
for (auto& c : clusters) weights.push_back(1.0); // 均等權重
std::discrete_distribution<> clusterDist(weights.begin(), weights.end());
for (int i = 0; i < count; ++i) {
const auto& cl = clusters[clusterDist(rng)];
// Box-Muller 采樣二維高斯
double u1 = norm(rng), u2 = norm(rng);
Eigen::Vector2d z(u1, u2);
Eigen::Vector2d sample = cl.mean + cl.cov.llt().matrixL() * z; // Cholesky 分解
int x = std::clamp(int(std::round(sample.x())), 0, width - 1);
int y = std::clamp(int(std::round(sample.y())), 0, height - 1);
points.push_back({ x, y });
}
return points;
}
// 定義兩個簇:左上、右下
std::vector clusters = {
{ {20, 20}, (Eigen::Matrix2d() << 25, 0, 0, 25).finished() }, // 圓形簇 σ=5
{ {80, 80}, (Eigen::Matrix2d() << 16, 8, 8, 16).finished() } // 橢圓簇
};
auto pts = generateGMM(100, 100, 10, clusters);
int grid[100][100] = {0};
for (auto& p : pts) grid[p.y][p.x] = 1; // 注意行列順序
// 現在 grid 中 1 表示有點,可直接用於渲染/邏輯判斷
**「聚類優先采樣」5 行核心代碼即可產生位置聚集的隨機點**,參數 `clusterRadius` 直觀控制緊湊度。需更自然形狀用 **GMM**,需嚴格最小間距用 **泊松盤反向**。二維數組僅作為最終標記容器,生成邏輯與數組結構解耦。