Prolog - 实施区域公式

时间:2014-04-11 18:18:02

标签: prolog

我想计算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。 谁能认出我的错误?

2 个答案:

答案 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