C# 如何根据任意区域选择正方形中的随机浮动?

C# 如何根据任意区域选择正方形中的随机浮动?,c#,random,weighted,cartesian-coordinates,C#,Random,Weighted,Cartesian Coordinates,我有一个正方形,在x和y方向上从-1到1 在这个正方形中选择一个随机点非常简单: Random r = new Random(); float x = (float)Math.Round(r.NextDouble() * 2 - 1, 4); float y = (float)Math.Round(r.NextDouble() * 2 - 1, 4); 这给了我,在我的平方里,任何一点,概率相等 这也将是相当容易的只是删除一部分的广场从可能性 Random r = new Random();

我有一个正方形,在x和y方向上从-1到1

在这个正方形中选择一个随机点非常简单:

Random r = new Random();
float x = (float)Math.Round(r.NextDouble() * 2 - 1, 4);
float y = (float)Math.Round(r.NextDouble() * 2 - 1, 4);
这给了我,在我的平方里,任何一点,概率相等

这也将是相当容易的只是删除一部分的广场从可能性

Random r = new Random();
float x = (float)Math.Round(r.NextDouble() * 1.5 - 1, 4);
float y = (float)Math.Round(r.NextDouble() * 2 - 1, 4);

但我真正努力做的是,将随机数加权到某个区域。具体来说,我希望此处突出显示的部分更有可能出现,其他所有部分(红色部分除外,红色部分仍然禁止进入)的概率应更低,具体取决于与高亮度线的距离。最远的一个点应该有0次机会,其余的一个现有的机会,当更接近该线时会更高,点正好在我的线上(因为我将它们四舍五入到一个特定的小数点,所以有点在该线上)具有最好的几率

对不起,这些难看的照片。这是我在绘画中所能做的最好的表达我思想的方式

“最有可能”的区域是一个空菱形(只有顶点(-1,0)、(0,-0.5)、(1,0)、(0,0.5)的区域),当然红色区域会覆盖权重,因为它是禁区。红色区域是x>0.5的任何区域

有人知道怎么做吗?我在用C语言工作,但老实说,任何非深奥语言的算法都能做到。我完全不知道该怎么做

一位评论者指出,在算法中添加禁区是一个额外的困难,没有实际用途

您可以假设,在运行加权算法后,我将自己处理“超限”部分。由于它仅占面积的25%,大多数情况下,如果我这样做,它甚至不会对性能产生影响:

while (x > 0.5)
{
    runAlgorithmAgain();
}

所以你可以放心地忽略这一部分作为答案。

好的,这里是我对这件事的看法。我想提出一个算法,在一些拒绝的情况下,可能会解决你的问题。注意,由于接受-拒绝的需要,它可能比你预期的要慢

我们在一个象限中采样(比如,左下象限),然后使用反射将点放入任何其他象限,然后拒绝红色区域点

基本上,象限内的采样是两步过程。首先,我们对边界线上的第一个位置进行采样。一旦我们在该线上获得位置,我们就从钟形分布(例如高斯或拉普拉斯分布)中进行采样,并将点沿与边界线方向正交的方向移动

代码可以编译,但完全未经测试,所以请用数字检查一切

using System;

namespace diamond
{
    class Program
    {
        public const double SQRT_5 = 2.2360679774997896964091736687313;

        public static double gaussian((double mu, double sigma) N, Random rng) {
            var phi = 2.0 * Math.PI * rng.NextDouble();
            var r   = Math.Sqrt( -2.0 * Math.Log(1.0 - rng.NextDouble()) );
            return N.mu + N.sigma * r * Math.Sin(phi);
        }

        public static double laplace((double mu, double sigma) L, Random rng) {
            var v = - L.sigma * Math.Log(1.0 - rng.NextDouble());
            return L.mu + ((rng.NextDouble() < 0.5) ? v : -v );
        }

        public static double sample_length(double lmax, Random rng) {
            return lmax * rng.NextDouble();
        }

        public static (double, double) move_point((double x, double y) pos, (double wx, double wy) dir, double l) {
            return (pos.x + dir.wx * l, pos.y + dir.wy * l);
        }

        public static (double, double) sample_in_quadrant((double x0, double y0) pos, (double wx, double wy) dir, double lmax, double sigma, Random rng) {
            while (true) {
                var l = sample_length(lmax, rng);
                (double x, double y) = move_point(pos, dir, l);

                var dort = (dir.wy, -dir.wx); // orthogonal to the line direction

                var s = gaussian((0.0, sigma), rng); // could be laplace instead of gaussian

                (x, y) = move_point((x, y), dort, s);
                if (x >= -1.0 && x <= 0.0 && y >= 0.0 && y <= 1.0) // acceptance/rejection
                    return (x, y);
            }
        }

        public static (double, double) sample_in_plane((double x, double y) pos, (double wx, double wy) dir, double lmax, double sigma, Random rng) {
            (double x, double y) = sample_in_quadrant(pos, dir, lmax, sigma, rng);

            if (rng.NextDouble() < 0.25)
                return (x, y);

            if (rng.NextDouble() < 0.5) // reflection over X
                return (x, -y);

            if (rng.NextDouble() < 0.75) // reflection over Y
                return (-x, y);

            return (-x, -y); // reflection over X&Y
        }

        static void Main(string[] args) {
            var rng = new Random(32345);

            var L = 0.5 * SQRT_5 + 0.5 / SQRT_5; // sampling length, BIGGER THAN JUST A SEGMENT IN THE QUADRANT
            (double x0, double y0) pos = (-1.0, 0.0); // initial position
            (double wx, double wy) dir = (2.0 / SQRT_5, 1.0 / SQRT_5); // directional cosines, wx*wx + wy*wy = 1
            double sigma = 0.2; // that's a value to play with

            // last rejection stage
            (double x, double y) pt;
            while(true) {
                pt = sample_in_plane(pos, dir, L, sigma, rng);

                if (pt.x < 0.5) // reject points in the red area, accept otherwise
                    break;
            }
            Console.WriteLine(String.Format("{0} {1}", pt.x, pt.y));
        }
    }
}
使用系统;
名称空间菱形
{
班级计划
{
公共建筑双平方英尺=2.2360679774997896964091736687313;
公共静态双高斯((双μ,双西格玛)N,随机rng){
var phi=2.0*Math.PI*rng.NextDouble();
var r=Math.Sqrt(-2.0*Math.Log(1.0-rng.NextDouble());
返回N.mu+N.sigma*r*Math.Sin(phi);
}
公共静态双拉普拉斯((双μ,双西格玛)L,随机rng){
var v=-L.sigma*Math.Log(1.0-rng.NextDouble());
返回L.mu+((rng.NextDouble()<0.5)?v:-v);
}
公共静态双样本长度(双lmax,随机rng){
返回lmax*rng.NextDouble();
}
公共静态(双,双)移动点((双x,双y)位置,(双wx,双wy)方向,双l){
返回(位置x+dir.wx*l,位置y+dir.wy*l);
}
公共静态(双,双)样本在象限中((双x0,双y0)位置,(双wx,双wy)方向,双lmax,双西格玛,随机rng){
while(true){
var l=样本长度(lmax,rng);
(双x,双y)=移动点(位置,方向,l);
var dort=(dir.wy,-dir.wx);//与直线方向正交
var s=高斯((0.0,sigma),rng);//可以是拉普拉斯而不是高斯
(x,y)=移动点((x,y),dort,s);

如果(x>=-1.0&&x=0.0&&y,我认为你需要澄清你说“更有可能”是什么意思.你心目中的概率分布是什么?它是平的,例如,70%在图内,30%在图外?因为它是连续的,而不是离散的,所以这个数字不会那么简单。我在寻找一个通用的解决方案,以便以后可以更改概率,但我想说,可能有50%的概率在0.4个单位内(abs(x)+abs(y)我想你需要两个算法,一个选择随机点考虑更可能的事情,另一个算法做截取。考虑到截取极限区域是平方的1/4,考虑到权重的形状,选择截取极限区域的可能性更大,这一部分现在基本上可以忽略,我可以暂时忽略(is_off_limits()){chooseageain()}这在大多数情况下几乎不会影响性能。因此,是的,您可以忽略这一点,因为主要算法HMI以前问过一个我认为与此相关的问题。您得到了点。您得到了4行。您所要做的就是找到最近的点(在每行上)到随机选择的点,然后计算该点距离主区域的百分比。使用该百分比删除/保留随机选择的点。显然,如果点距离较远,则更可能被删除,如果点距离较近,则更可能保留。