【问题标题】:Generating uniform random numbers on a sphere/circle filled with a cube/square在填充有立方体/正方形的球体/圆上生成均匀的随机数
【发布时间】:2017-09-01 08:31:22
【问题描述】:

我正在尝试在填充有立方体的球体上生成随机点。 因为我不知道该怎么做,所以我从 2d 开始。 (用样方填充的圆圈。)

我正在尝试做的事情:在外圈内但在绿色方块之外生成随机点。

基本上在蓝色区域。

广场位于(-1|-1),(1|-1),(1|1),(-1|1)
圆的半径为r = sqrt(2),以(0|0) 为中心。

我已经有脚本:

  • 在圆上生成一个随机点(均匀地):

    float a = 2 * MathUtils.PI * MathUtils.random(1f); // angle between 0 and 2pi
    float r = radius * Math.sqrt(MathUtils.random(0, 1f)
    float x = r * MathUtils.cos(a);
    float y = r * MathUtils.sin(a);
    
  • 计算给定角度的半径以形成正方形:

    float r = (1/Math.sqrt(2)) / MathUtils.cos(((a+45)%90-45)/180*MathUtils.PI);
    

    (1/Math.sqrt(2)) 是正方形边长的一半

在有人问之前: 我知道我可以重新生成绿色方块内的点,直到我得到一个在外面的点,但我不想这样做。

感谢您的帮助。谢谢你:)

【问题讨论】:

  • 2D 还是 3D?您说的是球体和立方体,但指的是 2D 图像。
  • 我想要 3d 的,但我想不通,所以我先用 2d 尝试了它

标签: java math random geometry


【解决方案1】:

仅在立方体外的球体区域(帽和楔形)生成点是相当困难的,因此拒绝方法看起来是合理的。

但您可以减少无用点的数量,在 2D 情况下生成点 in the ring only 在 3D 情况下生成球壳。

所以伪代码可能看起来像

 //2d
 SquaredR  = RandomUniformInRange(0.5, 1)
 R = Sqrt(SquaredR)

 //3d
 CubedR  = RandomUniformInRange(Pow(3, -3/2), 1)
 R = Pow(CubedR, 1/3)

 //generate point on the circle or on the sphere with radius R

 if Abs(x) > Sqrt(2)/2 or Sqrt(3)/3  and so on - reject

拥有 R,您可以使用 here 中的任何方法在球体上生成点

【讨论】:

    【解决方案2】:

    这是这个想法的粗略草图。您选择一个象限进行采样,例如右侧的一个。

    首先,从 -pi/4 到 pi/4 采样角度

    float a = -MathUtils.PI/4.0f + MathUtils.PI/2.0 * MathUtils.random(0.f,1.f);
    float c = MathUtils.cos(a);
    float s = MathUtils.sin(a);
    

    其次,求最小半径。从 (0,0) 以角度 a 射出的光线将与象限线在 x=1 处相交至少

    float rmin = 1.0f / c;
    float rmax = Math.sqrt(2.0f);
    

    rminrmax = sqrt(2) 的样本,考虑到对于平面,您对半径的平方进行采样,然后使用 sqrt(),对于 3d 空间,您对半径的立方进行采样,然后使用 cbrt()。

    float r2 = rmin*rmin + (rmax*rmax-rmin*rmin)*MathUtils.random(0.f,1.f);
    float r  = Math.sqrt(r);
    
    float x = r * c;
    float y = r * s;
    

    现在,我们构造的 (x,y) 是这样一种方式,它保证在圆下方的右象限和 x=1 线的右侧。

    要覆盖所有四个象限,只需对要将点移动到哪个象限进行采样

    float q = MathUtils.random(0.f,1.f);
    if (q < 0.25f) // top quadrant
        return (y, x);
    if (q < 0.5f)  // left quadrant
        return (-x, y);
    if (q < 0.75f)  // bottom quadrant
        return (y, -x);
    return (x,y); // right quadrant
    

    请多多包涵 - 我的 Java 已经很生疏了,我没有办法测试代码。

    在 3D 情况下,您必须处理两个角度、立方半径、八个八分圆而不是四个象限,但一般逻辑是相同的

    更新

    我错了,我建议的采样会导致点分布不均匀。

    来自 PDF:

    PDF(phi, r) = S_(-\pi/4)^\phi d\phi S_1/cos(\phi)^\sqrt(2) r dr
    

    我们可以得到我们必须使 \phi 采样不均匀。不幸的是,从 U(0,1) 到采样 \phi 需要求解非线性方程

    \pi/2 (0.5*(\phi/\pi/4 + 1) - U(0,1)) = 0.5*(tan(phi) + 1) - U(0,1)
    

    所以算法是:

    • 样本 U(0,1)
    • 通过求解上述方程找到合适的 \phi
    • 找到较低的R边界
    • 样本R

    绘制这个非线性函数的快速代码(抱歉,用 Python 编写)

    import numpy as np
    import matplotlib.pyplot as plt
    
    def f(phi, ksi):
        c   = 0.5 * np.pi
        c_2 = 0.5 * c
    
        left = c * (0.5 * (phi/c_2     + 1.0) - ksi)
        rght =     (0.5 * (np.tan(phi) + 1.0) - ksi)
    
        return left - rght
    
    nof_points = 41
    phi   = np.linspace(-0.25*np.pi, 0.25*np.pi, nof_points)
    y0_00 = f(phi, 0.00)
    y0_25 = f(phi, 0.25)
    y0_50 = f(phi, 0.50)
    y0_75 = f(phi, 0.75)
    y0_99 = f(phi, 1.00)
    
    plt.plot(phi, y0_00, 'ro', phi, y0_25, 'b+', phi, y0_50, 'gx', phi, y0_75, 'm.', phi, y0_99, 'y^')
    plt.show()
    

    并为 U(0,1) 的五个值绘制函数(代码中的 ksi)

    可以重新安排采样,使r 采样是非线性的,但它表现出相同的问题 - 需要求解具有多项式和三角函数部分的非线性方程

    更新二

    为了记录,如果你想先采样r,那么它必须从非线性方程的解中采样: r2 sec-1(r) - sqrt(r2 - 1) = U(0,1)*(\pi/2 - 1)

    在区间 [1...sqrt(2)]

    求解后发现采样r\phi可以在r允许的区间内均匀采样:[-cos-1(1/r) ... + cos-1(1/r)]

    【讨论】:

    • 我不确定,但这不会在我的正方形角落附近产生更多点吗?由于每个角度的可能半径大小不同,所以不应该“缩放”角度吗? (在 0°:从 1 到 sqrt(2),但在 45°:只有 sqrt(2) 的半径可能)
    • @SchokokuchenBäcker你是对的我错了,看看更新
    猜你喜欢
    • 2019-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-29
    相关资源
    最近更新 更多