我正在尝试实现Jarvis'算法来查找一组点的凸包,但由于某种原因它不起作用。这是我的实施:
procedure TPointList.ConvexHull(aHull : TPointList); //Return the convex hull of a set of 2D points
var
vPointOnHull : TPoint2D;
vEndpoint : TPoint2D;
I : integer;
begin
aHull.Clear;
if Count < 3 then exit;
vPointOnHull := Self.LeftMostPoint;
repeat
aHull.Add(vPointOnHull);
vEndpoint := Self.Point[0];
for I := 1 to Self.Count-1 do
if Orientation(vPointOnHull,vEndpoint,Self.Point[I]) = LeftHandSide then
vEndpoint := Self.Point[I];
vPointOnHull := vEndpoint;
until vEndpoint = aHull.Point[0];
end;
该方法会开始反复向aHull添加相同的点。在一个测试用例中,我发送了点(200; 200)(300; 100)(200; 50)和(100; 100),算法首先将(100; 100)添加到aHull,这是正确的,但是它开始一遍又一遍地添加(200; 200)。
显然我在实施中做错了,但对于我的生活,我看不出是什么。
更新:
Jonathan Dursi让我走上正轨。这一行
if Orientation(vPointOnHull,vEndpoint,Self.Point[I]) = LeftHandSide then
应该替换为
if (vPointOnHull = vEndpoint) or (Orientation(vPointOnHull,vEndpoint,Self.Point[I]) = LeftHandSide) then
像魅力一样: - )
答案 0 :(得分:12)
(200; 200)是第0点可能不是一个小说。
看起来你并没有将当前点(vPointOnHull)排除在终点(vEndPoint)之外,而且你的Orientation实现并没有拒绝这种情况;假设如果交叉积为正,则返回LHS,如果vPointOnHull == vEndPoint,则交叉乘积为零,因此从不LHS。因此,一旦选择了Point 0,就没有任何东西可以取代Point 0,等等。
你可以修改方向以在这种情况下返回“退化”或某些东西,并且也拒绝该点,或者你可以将当前点排除在永远的终点之外。请注意,您不希望做出明显的事情,在游进过程中从点集中过滤掉当前的CH点,因为您需要找到终点是关闭循环的第一个点。
更新:在FastGEO的东西上看一下,可能更新Orientation不是要走的路(尽管在这个算法中需要考虑共线点的情况;如果有的话在船体上是共线点,你真的想要最接近的点,所以你想在if语句后面有一个else if Orientation = Collinear then.. update vEndpoint if new point is closer
子句。
最简单的可能只是添加几行来跟踪当前的指标,以便您可以轻松地测试相等性:有点像
iPointOnHull := Self.IndexOfLeftMostPoint;
vPointOnHull := Self.LeftMostPoint
...
vEndpoint := Self.Point[0];
iEndPoint := 0;
if (iPointOnHull = 0) then
begin
vEndPoint := Self.Point[1];
iEndPoint := 1;
end
...
vPointOnHull := vEndPoint;
iPointOnHull := iEndPoint;
答案 1 :(得分:0)
循环使用以下代码行添加:
aHull.Add(vPointOnHull);
vPointOnHull
仅在以下行中指定:
vPointOnHull := Self.LeftMostPoint;
vPointOnHull := vEndpoint;
您已经解释过LeftMostPoint
已正确添加,因此重复必须来自vEndPoint
,这些是在以下行中指定的:
vEndpoint := Self.Point[0];
vEndpoint := Self.Point[I];
所以我猜最后的作业(在下面的if语句中)永远不会到达。
if Orientation(vPointOnHull,vEndpoint,Self.Point[I]) = LeftHandSide then
vEndpoint := Self.Point[I];
- 的Jeroen