【问题标题】:Determining whether a array of points roughly make a circle确定一组点是否大致构成一个圆
【发布时间】:2018-05-04 21:02:58
【问题描述】:

我和我的朋友花了一两个小时在 java 中编写代码以查找由x[]x 坐标)和y[]y 坐标)表示的点数组是否大致形成圆与否。

我们进行了大量研究,但每次我们最终解决的都是包含 3 个变量的非常大的联立方程。

我们的想法是取数组的前 3 个点并找到这 3 个点的中心(圆心),然后我们可以找到由这 3 个点组成的圆的半径,如果其他点也满足距离形成中心大致等于半径然后我们有一个圆。

我们怎样才能做到这一点?

【问题讨论】:

  • 对不起英语
  • 您的想法似乎是对的。那你有什么问题?
  • 我无法在编程中实现这一点,最终得到非常奇怪的方程式。
  • 没关系,请大家进入正题
  • @quadgen 所以你说你无法在编程中实现它。为什么?什么是阻塞点?是不是通过3个点找不到圆心?

标签: java geometry


【解决方案1】:

“我们怎样才能做到这一点?”

基本上,通过做一些数学运算。

假设你有 N 个点 P1 到 Pn

  1. 选择一对点 P1 和 P2
  2. 找到点 P1 和 P2 之间的直线 L1 的中点 M1
  3. 构造另一条与穿过 M1 的 L1 成直角的直线 R1
  4. 对点 P2 和 P3 重复步骤 1 到 3,得到第二条线 R2
  5. 找到 R1 和 R2 的交点。那就是圆的候选中心C。
  6. 对于每个点 Pi,计算 C 到 Pi 的距离。

如果您的点“大致”在一个圆圈中,那么从每个点到中心的距离将“大致”相同。

步骤 1 到 6 可以通过一些简单的代数转化为解析公式。算出公式,然后把它们变成代码。

【讨论】:

  • 这真是太棒了!所以直截了当。绝对的天才!我喜欢它。我只是想知道一条穿过圆弧中点的垂直线也将穿过圆心的地方。唯一的问题是您可能会得到一些误报,因为数据可能是“几乎”圆形的,其中 R 线不会相交或相交在错误的一侧。不过,高点数和运行 O(n^2) 算法可能会增加确定性。
  • 如果您选择 3 个不靠近的点,那么它们应该在近似中心处相交。最后一步测试点在一个圆圈中的假设......大致。
【解决方案2】:

这是一个我认为可行的潜在 O(n) 解决方案。它使用简单的二维圆方程:x^2 + y^2 = r^2。我还没有真正测试过它,所以带着一粒盐吃。

此外,您还没有列出问题中的所有假设。 xy之间的关系是一对一的吗?元素的顺序呢?它们的长度相同吗? 大概是什么意思?

假设xy 是具有有序一对一映射的相同长度的整数数组,您可以循环遍历xy 并创建一个具有x^2 + y^2 值的新数组。我们称这个新数组为r2

现在是我必须定义“大致”的时候了。假设如果r2 的所有值都等于delta = 10 的可接受偏移量,那么我们就有了一个圆圈。您可以为delta 选择任意值以适合您对粗圆的定义。

在伪代码中,它看起来像这样:

delta = 10;
r2 = [];
for i = 0 to length(x) {
    r2.append(x[i] * x[i] + y[i] * y[i]);
}

random_r2_value = r2(randomInt(0, length(r2));
upper_bound = random_r2_value + delta;
lower_bound = random_r2_value - delta;

isCircle = true;

for value in r2 {
    if value >= lower_bound && value <= upper_bound {
    // yay
    continue;
    } else {
        isCircle = false;
        break;
    }
}

print(isCircle)

如果你愿意,你可以使用贪心方法来组合这两个循环。

祝你好运!

【讨论】:

    【解决方案3】:

    所以我在 Python 中玩耍(只是因为它对我来说最容易快速原型化解决方案)并想出了这个:

    from collections import namedtuple
    from math import sqrt
    from statistics import mean
    
    Point = namedtuple('Point', ['x', 'y'])
    
    def length_between_points(a: Point, b: Point):
        squared = (pow(a.x - b.x, 2) + pow(a.y - b.y, 2))
        return sqrt(squared)
    
    def normalize(raw):
        return [float(i)/max(raw) for i in raw]
    
    def is_roughly_circle(x, y, confidence=0.1):
        center = Point(x=mean(x), y=mean(y))
        points = [Point(x[i], y[i]) for i in range(len(x))]
    
        lengths_from_center = [length_between_points(p, center) for p in points]
        normalized = normalize(lengths_from_center)
        is_circle = all([length > 1 - confidence for length in normalized])
        return is_circle
    
    
    x = [1, 2, 3, 4, 5]
    y = [1, 2, 3, 4, 5]
    print(is_roughly_circle(x, y)) # False
    
    x = [0, 1, 0, -1]
    y = [1, 0, -1, 0]
    print(is_roughly_circle(x, y)) # True
    
    x = [0, 1.1, 0, -1]
    y = [1, 0, -1, 0]
    print(is_roughly_circle(x, y)) # True
    
    x = [0, 1.2, 0, -1]
    y = [1, 0, -1, 0]
    print(is_roughly_circle(x, y)) # False
    
    x = [0, 1.2, 0, -1]
    y = [1, 0, -1, 0]
    print(is_roughly_circle(x, y, confidence=0.2)) # True
    

    假设:

    1. 最好计算所有点的中心,而不仅仅是前 3 个。如果输入的第一个点位于几何中心,这不是最佳的,但可以处理这种情况。
    2. 椭圆和省略号不是“大致圆形”
    3. 可以使用置信度参数 [0,1) 设置圆的“粗糙”程度

    算法:

    1. 计算所有点的平均值(中心)
    2. 计算所有点到中心的距离
    3. 将距离标准化为 [0,1] 范围
    4. 归一化向量中的所有值是否都大于 0.9?
    5. 如果是,点集是一个置信度为 0.1 的圆。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-14
      • 2012-03-13
      • 2023-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多