泊松盘抽样使指数超出范围。

问题描述 投票:0回答:1

这是我使用的泊松盘采样算法实现。

using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;

namespace Assets.Scripts.Algorithms
{
    public static class PoissonDiscSampling
    {
        public static List<Vector2> GeneratePoints(int seed, float radius, Vector2 sampleRegionSize, int sampleAmount)
        {
            Random.InitState(seed);
            float cellSize = radius / Mathf.Sqrt(2);
            var grid = new int[Mathf.FloorToInt(sampleRegionSize.x / cellSize), Mathf.FloorToInt(sampleRegionSize.y / cellSize)];
            var points = new List<Vector2>();
            var spawnPoints = new List<Vector2>
            {
                sampleRegionSize / 2
            };

            while (spawnPoints.Count > 0)
            {
                int spawnIndex = Random.Range(0, spawnPoints.Count);
                Vector2 spawnCenter = spawnPoints[spawnIndex];
                bool accepted = false;

                for (int i = 0; i < sampleAmount; i++)
                {
                    float angle = Random.value * Mathf.PI * 2;
                    var direction = new Vector2(Mathf.Sin(angle), Mathf.Cos(angle));
                    Vector2 candidate = spawnCenter + direction * Random.Range(radius, radius * 2);

                    if (IsValid(candidate, sampleRegionSize, cellSize, radius, points, grid))
                    {
                        points.Add(candidate);
                        spawnPoints.Add(candidate);

                        grid[(int)(candidate.x / cellSize), (int)(candidate.y / cellSize)] = points.Count;

                        accepted = true;

                        break;
                    }
                }

                if (!accepted)
                {
                    spawnPoints.RemoveAt(spawnIndex);
                }
            }

            return points;
        }

        private static bool IsValid(Vector2 candidate, Vector2 sampleRegionSize, float cellSize, float radius,
            IList<Vector2> points, int[,] grid)
        {
            if (candidate.x >= 0 && candidate.x < sampleRegionSize.x && candidate.y >= 0 && candidate.y < sampleRegionSize.y)
            {
                int cellX = (int)(candidate.x / cellSize);
                int cellY = (int)(candidate.y / cellSize);
                int searchStartX = Mathf.Max(0, cellX - 2);
                int searchStartY = Mathf.Max(0, cellY - 2);
                int searchEndX = Mathf.Min(cellX + 2, grid.GetLength(0) - 1);
                int searchEndY = Mathf.Min(cellY + 2, grid.GetLength(1) - 1);

                for (int x = searchStartX; x <= searchEndX; x++)
                {
                    for (int y = searchStartY; y <= searchEndY; y++)
                    {
                        int pointIndex = grid[x, y] - 1;

                        if (pointIndex != -1)
                        {
                            float sqrDistance = (candidate - points[pointIndex]).sqrMagnitude;

                            if (sqrDistance < radius * radius)
                            {
                                return false;
                            }
                        }
                    }
                }
            }

            return true;
        }
    }
}

但是这个算法实现有一个小问题。在行。

grid[(int)(candidate.x / cellSize), (int)(candidate.y / cellSize)] = points.Count;

迭代几次之后,它就会抛出

指数超出范围异常

不知何故(我还不知道为什么),它超越了尺寸的。grid有时它可以是负数,有时它可以基本等于大小。grid.

我被卡住了,我不知道该怎么办。好像有什么东西我根本没看出来。

谢谢!谢谢

c# algorithm unity3d poisson indexoutofrangeexception
1个回答
1
投票

让我们假设 cellSize 是1和 sampleRegionSize.X10.9. 这将导致一个大小为 10. candidate.X 必须小于 sampleRegionSize.X 有效,但 10.8 就可以了。把它投到int上,你就会得到以下结果 10. 由于数组是零索引的 10 将超出范围。

故事的寓意;不要相信浮点数学。如果您需要将浮点坐标转换为索引,请在尝试使用它之前检查索引是否有效。有 众多 物品 在...上 危险 的浮点数学。

© www.soinside.com 2019 - 2024. All rights reserved.