我有一个带有多个点的多边形,并且必须添加一个新点。现有的点存储在一个数组中:
var points = [
{x: 0, y:0},
{x: 100, y: 0},
{x: 100, y: 100},
{x: 0, y: 100}
];
如何确定应将newPoint
添加到数组的哪个位置?
尝试:我遍历所有现有点并计算newPoint
与它们的距离,并将现有点排序为包含这些点索引的数组,按顺序排列与newPoint
的距离越来越远。
按照我当前尝试的方法,下一步将检查2个最近点是否相邻。如果是,请在newPoint
数组中添加points
。如果它们不相邻,那么我有点卡在这里:)你如何检查2点是否相邻?
任何帮助都非常感谢!
jsfiddle: http://jsfiddle.net/y3kmm/
订单之所以重要的原因是因为形状通常以顺时针方式绘制。这是一个jsfiddle,其中蓝色多边形在正确的位置添加了一个点,并且在points
数组的末尾添加了一个点的红色多边形。
jsfiddle: http://jsfiddle.net/TyQXV/
答案 0 :(得分:4)
正如我之前所说,你并不需要使用sort来增加程序的复杂性:只需存储两个初始点,将它们视为最接近的点,然后在迭代另一点时替换它们。
但是,您的问题有多种可能的解决方案;你必须为它定义更多的约束。
例如,考虑形成正方形的四个点:
·-------·
| |
| |
| |
·-------·
现在,在多边形内的随机位置添加一个点:
·-------·
| |
| · |
| |
·-------·
有两个以上可能的顺序仍会保持多边形凸起:
·-------·
\ |
· |
/ |
·-------·
· ____·
|\ / |
| · |
| |
·-------·
答案 1 :(得分:3)
好的,让我们仔细看看多边形。
我们会叫他泰德。当Ted(或一般多边形)看到一个点时,他试图在自己内部吸收它。并且为了同化,他决定给予他的许多方中的一个荣耀,以及抓住要点。现在,特德忙于处理更重要的事情,所以方需要自己决定哪一个会做好事。我会再说一遍;的侧强>
我们走了,泰德附近有一点,幸福地意识不到它很快就会消耗殆尽。那么,特德的双方如何决定哪一个会抓住这一点呢?嗯,这需要公平的游戏。感觉到垂直距离从它到最短点的那一侧将是这样做的一方。的最短即可。的垂直即可。的距离强>
同化完成!
要记住的另一件事是像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);
};
现在,让我们来看看有效性。如果在将点添加到多边形之后,新的边穿过任何其他边,那么小家伙就会结束。我们需要确保我们的算法能够解决这个问题。
我想到了两个版本;一个便宜,一个贵。
方法1 :
如果多边形中几乎没有凹陷,则此方法可以完美地工作。此方法仅检查新边与旧边相邻的边不相交。
假设我们有一个方S
。它的两个相邻边是Sprev
和Snext
。这两个新方面是S1p
和S2p
。 S1p
和Sprev
共有点S.p1
。 S2p
和Snext
共同点S.p2
。
根据这种方法,当且仅当在:
之间没有交叉时,加法才有效Sprev
和S2p
Snext
和S1p
所以,这种方法适用于拒绝。如果我们找不到任何交叉点,那么边S
可以有效地添加该点。
<强> Method 1 Demo 强>
方法2 :
方法1失败,因为多边形的凹度增加。因此,我们需要进一步检查以确保有效的点加法。
此方法实际上是方法1的扩展。在发现对Sprev
和S2p
以及Snext
和S1p
不相交之后,我们检查是否新边与多边形的所有其他边相交(当然除了Sprev
和Snext
之外)。
如果在检查完所有方面后没有拒绝添加,我们完全确定此添加有效。
问题是,虽然拒绝速度足够快,但接受验证需要很长时间,这使得这种方法非常昂贵。
此外,复杂性取决于多边形的边数。随着多边形复杂度的增加,检查有效性将花费越来越多的时间。
<强> Method 2 Demo 强>
我必须注意,我用于检查线段交叉的算法取自How do you detect where two line segments intersect?。这真是太棒了。
这就是我的全部。我必须说,这是一种方法。可能还有另一种更好的方式还没有打动我。我希望你不要特别介意泰德。而且,感谢您提出一个好问题,我很喜欢。
答案 2 :(得分: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);
最近的点不一定是下一个应该绘制的点。
答案 3 :(得分:0)
The reason why the order matters is because Shapes are usually drawn in a clockwise manner.
你刚回答了你的问题。添加新点的位置取决于您想要的形状,因此与距离无关。您只需在要绘制的位置添加点即可。
说,您是否已经知道形状应该是什么,或者您必须根据用户点击鼠标的位置来猜测形状?如果您必须猜测,则可能必须设置默认行为。否则,请为您的用户提供其他参数。