8

我有一个带有几个点的多边形,必须添加一个新点。现有点存储在一个数组中:

var points = [
    {x: 0, y:0},
    {x: 100, y: 0},
    {x: 100, y: 100},
    {x: 0, y: 100}
];

您如何确定newPoint应将其添加到数组的哪个位置?

尝试:我遍历所有现有点并计算newPoint与它们的距离,并将现有点排序到包含这些点的索引的数组中,以增加距离newPoint

按照我目前尝试的方法,下一步将检查两个最近的点是否相邻。如果是,则将它们newPoint之间的值添加到points数组中。如果它们不相邻,那么我有点卡在这里:) 你如何检查这两个点是否相邻?

非常感谢任何帮助!

jsfiddle:http: //jsfiddle.net/y3kmm/


顺序之所以重要,是因为形状通常以顺时针方式绘制。points这是一个 jsfiddle,其中蓝色多边形在正确的位置添加了一个点,而红色多边形在数组末尾添加了一个点。

jsfiddle:http: //jsfiddle.net/TyQXV/

4

4 回答 4

4

正如我之前所说,您实际上不必使用排序来增加程序的复杂性:只需存储两个初始点,认为它们是最接近的,然后在迭代另一个点时替换它们。

但是,您的问题有不止一种可能的解决方案;您必须为其定义更多约束。

例如,考虑四个点形成一个正方形:

·-------·
|       |
|       |
|       |
·-------·

现在,将一个点添加到多边形内的随机位置:

·-------·
|       |
| ·     |
|       |
·-------·

仍然有两个以上可能的顺序可以保持多边形凸:

·-------·
 \      |
  ·     |
 /      |
·-------·

·   ____·
|\ /    |
| ·     |
|       |
·-------·
于 2012-12-24T20:58:34.130 回答
3

好吧,让我们仔细看看多边形。

泰德

我们叫他泰德。当泰德(或一般的多边形)看到一个点时,他会尝试在自己内部吸收它。为了同化,他决定让他的众多方面之一有幸伸出援手并抓住这一点。现在,泰德正忙于更重要的事情,所以双方需要自己决定哪一方会做好事。我再说一遍;双方

在此处输入图像描述

我们走了,泰德附近有一个点,幸福地没有意识到它很快就会被恶毒地消耗掉。那么,泰德的一方如何决定哪一方将抢夺这一点呢?好吧,它需要是公平的游戏。感觉到从它到该点的垂直距离最短的一侧将是执行此操作的一侧。最短的。垂直距离

在此处输入图像描述

同化完成!

要记住的另一件事是,像 Ted 这样的多边形重视生存而不是同化。与该点垂直距离最短的一侧只有在它不穿过其他一侧时才开始同化。因此,仅考虑有效同化的方面。否则,坏事就会发生

在此处输入图像描述

我不必要的言辞中有两点很重要;

  • 我们添加点的一侧应该与该点有最短的垂直距离
  • 除了与点的垂直距离最短外,将点添加到这一侧应该是有效的。这很重要,毕竟,我们不想进行大规模多边形谋杀。

所以,这里有一些伪代码;

For each side S in polygon P
Do
    d := perpendicularDistanceFromSide(S, point);
    If d is less than shortestPerpendicularDistance
    Do
        If additionIsValid(S, point, P)
        Do
            shortestPerpendicularDistance := d;
            index = S.index;
        End If
    End If
End For

从侧面找到垂直距离很容易;

var perpendicularDistance = function(side, point) {
    //Find direction vector of side
    var dir = {x: side.p2.x - side.p1.x, y: side.p2.y - side.p1.y};
    var m = Math.sqrt(dir.x*dir.x + dir.y*dir.y);
    if(m !== 0) {
        d.x = d.x/m;
        d.y = d.y/m;
    }

    //Find position vector of point, from side
    var pVec = {x: point.x - side.p1.x, y: point.y - side.p1.y};

    //Absolut of cross product of dir and pVec. 
    //It's essentially |pVec|*Sin(q), q is the angle between
    //dir and pVec.
    return Math.abs(dir.x*pVec.y - dir.y*pVec.x);
};

现在,让我们看看有效性。如果在将点添加到多边形之后,新的边穿过任何其他边,那么小家伙就结束了。我们需要确保我们的算法考虑到这一点。

我为此想了两个版本;一便宜一贵。

方法一

如果多边形中几乎没有凹面,则此方法非常有效。此方法仅检查新边不与旧边相邻的边相交。

说我们有一方S。它的两个相邻边是SprevSnext。两个新的边是S1pS2pS1p并且SprevS.p1共同点。S2p并且SnextS.p2共同点。

根据这种方法,当且仅当以下之间不存在交集时,加法才有效:

  • SprevS2p
  • SnextS1p

因此,此方法适用于拒绝。如果我们找不到任何交点,边S可以有效地添加点。

方法 1 演示

方法二

随着多边形的凹度增加,方法 1 失败。因此,我们需要做进一步的检查以确保有效的加点。

This method is really an extension of Method 1. After finding that the pairs Sprev and S2p, and Snext and S1p are not intersecting, we check if the new sides are intersecting with all the other sides of the polygon (apart from Sprev and Snext, of course).

If the addition is not rejected after all the sides are checked, we are completely sure that this addition is valid.

The problem is, that while rejection is quick enough, reaching acceptance takes a long time, making this method quite expensive.

Furthermore, the complexity depends on the number of sides of the polygon. As the polygon complexity increases, checking validity will take more and more time.

Method 2 Demo

我必须注意,我用于检查线段相交的算法取自如何检测两条线段相交的位置?. 这太棒了。

这就是我所拥有的。这是一种方法,我必须说。可能还有另一种更好的方法还没有让我印象深刻。我希望你不要太介意泰德。另外,感谢您提出一个好问题,我很喜欢。

于 2012-12-25T17:08:20.917 回答
2

我相信您的计算不会解决您遇到的问题。例如,取以下两个多边形:

var poly3 = new Kinetic.Polygon({
    x: 200,
    y: 100,
    points: [0,25,25,0,150,100,75,125],
    fill: 'green',
    stroke: 'black',
    strokeWidth: 0,
    name: 'poly',
    draggable: false
});
group.add(poly3);

var poly4 = new Kinetic.Polygon({
    x: 300,
    y: 100,
    points: [0,25,25,0,75,125,150,100],
    fill: 'yellow',
    stroke: 'black',
    strokeWidth: 0,
    name: 'poly',
    draggable: false
});
group.add(poly4);

最近的点不一定是接下来应该绘制的点。

于 2012-12-24T21:01:27.443 回答
0

The reason why the order matters is because Shapes are usually drawn in a clockwise manner.

你刚刚回答了你的问题。添加新点的位置取决于您想要的形状,因此与距离无关。您只需在要绘制的位置添加点。

比如说,您是否已经知道形状应该是什么,或者您是否必须根据用户单击鼠标的位置来猜测形状?如果您必须猜测,您可能必须设置默认行为。否则,给你的用户一个额外的参数。

于 2012-12-25T00:44:24.483 回答