【问题标题】:Calculate if two lines are symmetrical计算两条线是否对称
【发布时间】:2020-02-14 12:46:32
【问题描述】:

我正在开发一个应用程序来检查绘制是否对称。所有用户行都存储在一个由点列表组成的 ArrayList 中,也是结构化的:

private ArrayList<ArrayList<Pair<Float,Float>>> segments = new ArrayList<>();

这是我构建绘图区域的方式:

黑色形状是背景的一部分,当我必须检查对称性时,我不需要考虑它。我只需要它的中心(我将其存储为单个坐标),因为我需要考虑通过它检查对称性。由于绘画是由儿童绘制的,因此我还需要考虑一些灵活性,因为线条永远不会完全对称。我实现了一个方法,将每个部分分成 10 个部分,然后检查每个部分的坐标是否有相似的增加/减少:

private boolean checkShape (int z, ArrayList<Pair<Float,Float>> points) {
    ArrayList<Pair<Float,Float>> copia = segments.get(z);
    int nGroupsFirstShape = (segments.get(z).size()*10)/100;
    int nValuesFirstShape[] = new int[10];
    for (int j=0, j2=0; j<10; j++, j2+=nGroupsFirstShape) {
        int sumValues=0;
        sumValues+=copia.get(j2).first-copia.get(j2+nGroupsFirstShape-1).first;
        sumValues+=copia.get(j2).second-copia.get(j2+nGroupsFirstShape-1).second;
        nValuesFirstShape[j] = sumValues;
    }
    ArrayList<Pair<Float,Float>> copia2 = points;
    int nGroupSecondShape = (copia2.size()*10)/100;
    int nValuesSecondShape[] = new int[10];
    for (int j=0, j2=0; j<10; j++, j2+=nGroupSecondShape) {
        int sumValues=0;
        sumValues+=copia2.get(j2).first-copia2.get(j2+nGroupSecondShape-1).first;
        sumValues+=copia2.get(j2).second-copia2.get(j2+nGroupSecondShape-1).second;
        nValuesSecondShape[j] = sumValues;
    }
    int differences[] = new int[10];
    int numberOf = 0;
    for (int index=0; index<10; index++) {
        differences[index] = nValuesFirstShape[index] - nValuesSecondShape[index];
        if (differences[index]<0) differences[index] = -differences[index];
        if (differences[index]<nGroupsFirstShape*2.5) numberOf++;
    }
    if (numberOf>=6) return true; else return false;
}

如果至少对 6 个部分进行了验证,那么我可以认为这些段是对称的。这种方法的巨大问题是线条可以有不同的大小。你知道计算绘图区域对称性的任何方法吗?由于我将图片保存为位图,所以我也尝试了直接在图片文件上计算的方法,但是没有找到

【问题讨论】:

  • 您在寻找什么样的对称性?你提到了一个中心。那么它是关于已知中心的点反射吗?
  • 您的示例有几条曲线,但您的数据结构仅存储两个点,这意味着您只有直线。
  • @NicoSchertler 是的,我正在寻找关于黑色形状中心的点反射
  • @Code-Apprentice 将曲线逐点存储到ArrayList中
  • @Babbara 所以ArrayList基本上代表了很多小线段来组成曲线?

标签: java android math geometry symmetric


【解决方案1】:

我多年没有编写 Java 代码,现在也没有那么多时间。因此,此答案不包含运行的 Java 代码,而仅包含想法和一些伪代码。无论如何,我希望这对您有所帮助。

一个给了两个curvescurve1curve2,以及一个反射中心c。 您想计算一条曲线是否是给定阈值 maxDist 内另一条曲线的点反射。

计算它的函数可能如下所示:

function checkSymmetry(Curve curve1, Curve curve2, Vector c, float maxDist) {
    // reflect one curve
    Curve curve2refl = reflect(curve2, c);
    // compute curve distance
    float d = dist(curve1, curve2refl);
    // check if distance is below threshold
    return d < maxDist;

(为了更好的可读性,我确实引入了一些类,而不是您的 ArrayLists of ArrayLists of Pairs of ...。我建议您在代码中也这样做。)

点反射

点反射的公式可以在Wikipedia上找到:点p与反射中心c的反射是:2*c - p

要反映一条曲线,您必须反映它的所有顶点。

距离曲线-曲线

当两条红色曲线(几乎)对称时,在它们中的一条反射之后,它们应该(几乎)相同,即距离(几乎)为零。但是两条曲线的距离是多少?

在数学集合论中存在Hausdorff distance。对于非数学家来说,这有点复杂。但它给出了定义曲线距离的想法:一条曲线的顶点到另一条曲线的最大距离:

function dist(Curve curve1, Curve curve2) {
    d = 0;
    for (Vector p : curve1.vertices) {
        d = max(d, dist(curve2, p));
    }
    for (Vector p : curve2.vertices) {
        d = max(d, dist(curve1, p));
    }
    return d;
}

距离点-曲线

所以我们确实减少了计算点到曲线距离的问题。这是该点到任何曲线段的最小距离:

function dist(Curve curve, Vector p) {
    d = dist(p, curve.vertices.get(0));
    for (int i = 1, n = curve.vertices.size(); i < n; ++i) {
        Vector p1 = curve.vertices.get(i-1);
        Vector p2 = curve.vertices.get(i);
        d = min(d, dist(new Segment(p1, p2), p));
    }
    return d;
}

距离点-段

对于一个点到一个段的距离,您会在 stackoverflow 上找到很多答案很好的问题,例如here.

【讨论】:

    【解决方案2】:

    我认为这是一个很好的数学算法:

    第 1 步: 将每一行分成N个部分。 (图中的正方形) 线上的点数可能会有所不同,但现在部分的数量将相同。

    例如,1 条线是 100 个点,将它分成 10 个部分,每个部分将落入 10 个点。 90分的第二个,9分的10分。

    计算每个部分的中点。 fig1

    第 2 步: 在两条线的每个中点之间,我们找到中间。 (图中黑点) fig2

    第 3 步: 我们建立一条与这些点偏差最小的线。 (图中红线) fig3

    第 4 步: 中点偏离线的估计。通过平均和最大偏差,就可以衡量线条的相似程度。

    祝你好运

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-19
      • 2019-07-09
      • 2014-01-07
      • 1970-01-01
      • 2011-01-29
      相关资源
      最近更新 更多