我想计算Prolog中多边形的面积。
多边形的面积由公式给出:
| {(x1*y2-y1*x2) + (x2*y3-y2*x3) + .... + (xn*y1 - yn*x1)}/2 |
其中(x1,y1),(x2,y2)....(xn,yn)
是多边形的点。
这是我尝试在Prolog中实现公式:
area(Points,Area):-areaAcc(Points,0,Area).
areaAcc([(X1,Y1),(X2,Y2)|List], Acc, Area):-
areaAcc2([(X1,Y1),(X2,Y2)|List], Acc, Area, (X1,Y1)).
areaAcc2([(X1,Y1),(X2,Y2)|List],Acc,Area,(FirstX,FirstY)):-
NewAcc is (X1*Y2-Y1*X2) + Acc,
areaAcc2([(X2,Y2)|List], NewAcc, Area, (FirstX,FirstY)).
areaAcc2([(Xm,Ym),(Xn,Yn)|[]],Acc,Area,(FirstX,FirstY)):-
Area is abs((Acc + (Xn*FirstY - Yn*FirstX))/2).
但是当我跑步时:
area([(4,10),(9,7),(11,2),(2,2),(4,10)],Area).
我得到Area = 51.5
而不是正确答案:Area = 45.5
。
谁能认出我的错误?
答案 0 :(得分:2)
如果简化基本情况(最后一个子句),和传递一个未闭合的多边形,结果是正确的
areaAcc2([(Xn,Yn)],Acc,Area,(FirstX,FirstY)):-
Area is abs((Acc + (Xn*FirstY - Yn*FirstX))/2).
产量
?- area([(4,10),(9,7),(11,2),(2,2)], A).
A = 45.5
否则,使用库支持实现它会更容易:
area_poly(Points, A) :-
aggregate_all(sum(E),
(append(_, [(X1,Y1),(X2,Y2)|_], Points), E is (X1*Y2-Y1*X2)), A2),
A is abs(A2/2).
请注意,它会错过公式的最后一个总和,但它会产生正确的值,因为我们传递一个已经闭合的多边形......
?- area_poly([(4,10),(9,7),(11,2),(2,2),(4,10)], A).
A = 45.5.
编辑在SWI-Prolog和YAP(我认为是共享源代码)中可以使用aggregate_all / 3,而在{SICStus Prolog上 - 来自Internet search。我认为所有这些都来自Quintus Prolog。关于实现,我草拟了lag,但当然重用库代码更好......
答案 1 :(得分:1)
自从我为这类问题出汗以来已经有一段时间了。但是从
工作这是我对解决方案的看法(假设点数正确排序):
area_polygon( [] , _ ) :- ! , fail . % not a polygon.
area_polygon( [P1] , _ ) :- ! , fail . % 1 single point is not a polygon.
area_polygon( [P1,P2] , _ ) :- ! , fail . % 2 points is a line segment and not a polygon.
area_polygon( [P1,P2,P3|Ps] , A ) :- % now we're getting somehere: 3 points is a triangle.
append( [P1,P2,P3|Ps] , [P1] , X ) , % append the first point to the list so it ends where it started.
area_polygon( X , 0.0 , A ) % call the worker predicate, seeding its accumulator with 0.0
.
area_polygon( [] , T , A ) :- A is abs( T ) / 2.0 .
area_polygon( [(X1,Y1),(X2,Y2)|Ps] , T , A ) :-
T1 is T + (X1+X2) * (Y2-Y1) ,
area_polygon( [(X2,Y2)|Ps] , T1 , A )
.
根据您表示多边形的方式,您可能不需要调用append/3
。