计算两条直线是否对称

Calculate if two lines are symmetrical

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

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

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

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

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 个部分验证了这一点,那么我可以认为这些段是对称的。这种方法的巨大问题是线条可以有不同的大小。您知道计算绘图区域对称性的任何方法吗?由于我把图片保存为位图,所以我也试过找直接在图片文件上计算的方法,但是没找到

我已经 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;
}

距离点–段

对于点到线段的距离,您可以在 Whosebug 上找到很多问题,这些问题都有很好的答案,例如here.

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

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

比如1条线100分,分成10份,每份10分。 第二个90分,将得到10分9分

计算每个部分的中点。 fig1

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

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

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

祝你好运