Shoelace formula for polygonal area

From Rosetta Code
Task
Shoelace formula for polygonal area
You are encouraged to solve this task according to the task description, using any language you may know.

Given the n + 1 vertices x[0], y[0] .. x[N], y[N] of a simple polygon described in a clockwise direction, then the polygon's area can be calculated by:

abs( (sum(x[0]*y[1] + ... x[n-1]*y[n]) + x[N]*y[0]) -
     (sum(x[1]*y[0] + ... x[n]*y[n-1]) + x[0]*y[N])
   ) / 2

(Where abs returns the absolute value)

Task

Write a function/method/routine to use the the Shoelace formula to calculate the area of the polygon described by the ordered points:

     (3,4), (5,11), (12,8), (9,5), and (5,6) 


Show the answer here, on this page.

11l

Translation of: Python
F area_by_shoelace(x, y)
   R abs(sum(zip(x, y[1..] [+] y[0.<1]).map((i, j) -> i * j))
        -sum(zip(x[1..] [+] x[0.<1], y).map((i, j) -> i * j))) / 2

V points = [(3, 4), (5, 11), (12, 8), (9, 5), (5, 6)]
V x = points.map(p -> p[0])
V y = points.map(p -> p[1])

print(area_by_shoelace(x, y))
Output:
30

360 Assembly

*        SHOELACE                  25/02/2019
SHOELACE CSECT
         USING  SHOELACE,R15       base register
         MVC    SUPS(8),POINTS     x(nt+1)=x(1); y(nt+1)=y(1)
         LA     R9,0               area=0
         LA     R7,POINTS          @x(1)
         LA     R6,NT              do i=1 to nt
LOOP     L      R3,0(R7)             x(i)
         M      R2,12(R7)            *y(i+1)
         L      R5,8(R7)             x(i+1)
         M      R4,4(R7)             *y(i)
         SR     R3,R5                x(i)*y(i+1)-x(i+1)*y(i)
         AR     R9,R3                area=area+x(i)*y(i+1)-x(i+1)*y(i)
         LA     R7,8(R7)             @x(i++)
         BCT    R6,LOOP            enddo
         LPR    R9,R9              area=abs(area)
         SRA    R9,1               area=area/2
         XDECO  R9,PG              edit area
         XPRNT  PG,L'PG            print area
         BR     R14                return to caller
NT       EQU    (SUPS-POINTS)/8    nt  number of points
POINTS   DC     F'3',F'4',F'5',F'11',F'12',F'8',F'9',F'5',F'5',F'6'
SUPS     DS     2F                 x(nt+1),y(nt+1)
PG       DC     CL12' '            buffer
         REGEQU
         END    SHOELACE
Output:
          30

Action!

INCLUDE "H6:REALMATH.ACT"

PROC Area(INT ARRAY xs,ys BYTE count REAL POINTER res)
  BYTE i,next
  REAL x1,y1,x2,y2,tmp1,tmp2

  IntToReal(0,res)
  IntToReal(xs(0),x1) IntToReal(ys(0),y1)
  FOR i=0 TO count-1
  DO
    next=i+1
    IF next=count THEN
      next=0
    FI
    IntToReal(xs(next),x2) IntToReal(ys(next),y2)

    RealMult(x1,y2,tmp1)
    RealAdd(res,tmp1,tmp2)
    RealMult(x2,y1,tmp1)
    RealSub(tmp2,tmp1,res)

    RealAssign(x2,x1) RealAssign(y2,y1)
  OD
  
  RealAbs(res,tmp1)
  IntToReal(2,tmp2)
  RealDiv(tmp1,tmp2,res)
RETURN

PROC PrintPolygon(INT ARRAY xs,ys BYTE count)
  BYTE i

  FOR i=0 TO count-1
  DO
    PrintF("(%I,%I)",xs(i),ys(i))
    IF i<count-1 THEN
      Print(", ")
    ELSE
      PutE()
    FI
  OD
RETURN

PROC Test(INT ARRAY xs,ys BYTE count)
  REAL res

  Area(xs,ys,count,res)
  Print("Polygon: ")
  PrintPolygon(xs,ys,count)

  Print("Area: ")
  PrintRE(res) PutE()
RETURN

PROC Main()
  INT ARRAY
    xs(5)=[3 5 12 9 5],
    ys(5)=[4 11 8 5 6]

  Put(125) PutE() ;clear screen

  Test(xs,ys,5)
RETURN
Output:

Screenshot from Atari 8-bit computer

Polygon: (3,4), (5,11), (12,8), (9,5), (5,6)
Area: 30

Ada

Works with: Ada version 83
with Ada.Text_IO;

procedure Shoelace_Formula_For_Polygonal_Area
is
   type Point is record
      x, y : Float;
   end record;
   
   type Polygon is array (Positive range <>) of Point;
   
   function Shoelace(input : in Polygon) return Float
   is
      sum_1 : Float := 0.0;
      sum_2 : Float := 0.0;
      tmp : constant Polygon := input & input(input'First);
   begin
      for I in tmp'First .. tmp'Last - 1 loop
         sum_1 := sum_1 + tmp(I).x * tmp(I+1).y;
         sum_2 := sum_2 + tmp(I+1).x * tmp(I).y;
      end loop;
      return abs(sum_1 - sum_2) / 2.0;
   end Shoelace;
   
   my_polygon : constant Polygon :=
     ((3.0, 4.0),
      (5.0, 11.0),
      (12.0, 8.0),
      (9.0, 5.0),
      (5.0, 6.0));
begin
   Ada.Text_IO.Put_Line(Shoelace(my_polygon)'Img);
end Shoelace_Formula_For_Polygonal_Area;
Output:
 3.00000E+01

ALGOL 60

Optimized version:

begin
    comment Shoelace formula for polygonal area - Algol 60;
    real array x[1:33],y[1:33];
    integer i,n;
    real a;
    ininteger(0,n);
    for i:=1 step 1 until n do
    begin
        inreal(0,x[i]);
        inreal(0,y[i])
    end;   
    x[i]:=x[1];
    y[i]:=y[1];
    a:=0;
    for i:=1 step 1 until n do
        a:=a+x[i]*y[i+1]-x[i+1]*y[i];   
    a:=abs(a/2.);
    outreal(1,a)
end
Output:
     30.00

Non-optimized version:

begin
    comment Shoelace formula for polygonal area - Algol 60;
    real array x[1:32],y[1:32]; 
    integer i,j,n;
    real a;
    ininteger(0,n);
    for i:=1 step 1 until n do
    begin
        inreal(0,x[i]); inreal(0,y[i])
    end;   
    a:=0;
    for i:=1 step 1 until n do
    begin
        j:=if i=n then 1 else i+1;
        a:=a+x[i]*y[j]-x[j]*y[i]
    end;   
    a:=abs(a/2.);
    outreal(1,a)
end
Output:
     30.00

ALGOL 68

BEGIN
    # returns the area of the polygon defined by the points p using the Shoelace formula #
    OP  AREA = ( [,]REAL p )REAL:
        BEGIN
            [,]REAL points = p[ AT 1, AT 1 ]; # normalise array bounds to start at 1 #
            IF 2 UPB points /= 2 THEN
                # the points do not have 2 coordinates #
                -1
            ELSE
                REAL   result := 0;
                INT    n       = 1 UPB points;
                IF n > 1 THEN
                    # there at least two points #
                    []REAL x   = points[ :, 1 ];
                    []REAL y   = points[ :, 2 ];
                    FOR i TO 1 UPB points - 1 DO
                        result +:= x[ i     ] * y[ i + 1 ];
                        result -:= x[ i + 1 ] * y[ i     ]
                    OD;
                    result     +:= x[ n ] * y[ 1 ];
                    result     -:= x[ 1 ] * y[ n ]
                FI;
                ( ABS result ) / 2
            FI
        END # AREA # ;

    # test case as per the task #
    print( ( fixed( AREA [,]REAL( ( 3.0, 4.0 ), ( 5.0, 11.0 ), ( 12.0, 8.0 ), ( 9.0, 5.0 ), ( 5.0, 6.0 ) ), -6, 2 ), newline ) )
END
Output:
 30.00

APL

Works with: Dyalog APL
shoelace  2÷|(((1¨)+.×12¨)-(11¨)+.×2¨)
Output:
      shoelace (3 4) (5 11) (12 8) (9 5) (5 6)
30

Arturo

define :point [x,y][]

shoelace: function [pts][
    [leftSum, rightSum]: 0

    loop 0..dec size pts 'i [
        j: (i + 1) % size pts
        'leftSum + pts\[i]\x * pts\[j]\y
        'rightSum + pts\[j]\x * pts\[i]\y
    ]
    return 0.5 * abs leftSum - rightSum
]

points: @[
    to :point [3.0, 4.0]
    to :point [5.0, 11.0]
    to :point [12.0, 8.0]
    to :point [9.0, 5.0]
    to :point [5.0, 6.0]
]

print shoelace points
Output:
30.0

AutoHotkey

V := [[3, 4], [5, 11], [12, 8], [9, 5], [5, 6]]

n := V.Count()
for i, O in V
    Sum += V[i, 1] * V[i+1, 2]  -  V[i+1, 1] * V[i, 2]
MsgBox % result := Abs(Sum += V[n, 1] * V[1, 2]  -  V[1, 1] * V[n, 2]) / 2
Output:
30.000000

BASIC256

arraybase 1
dim array = {{3,4}, {5,11}, {12,8}, {9,5}, {5,6}}

print "The area of the polygon = "; Shoelace(array)
end

function Shoelace(p)
    sum = 0
    for i = 1 to p[?][] -1
        sum += p[i][1] * p[i +1][2]
        sum -= p[i +1][1] * p[i][2]
    next i
    sum += p[i][1] * p[1][2]
    sum -= p[1][1] * p[i][2]
    return abs(sum) \ 2
end function

C

Reads the points from a file whose name is supplied via the command line, prints out usage if invoked incorrectly.

#include<stdlib.h>
#include<stdio.h>
#include<math.h>

typedef struct{
	double x,y;
}point;

double shoelace(char* inputFile){
	int i,numPoints;
	double leftSum = 0,rightSum = 0;
	
	point* pointSet;
	FILE* fp = fopen(inputFile,"r");
	
	fscanf(fp,"%d",&numPoints);
	
	pointSet = (point*)malloc((numPoints + 1)*sizeof(point));
	
	for(i=0;i<numPoints;i++){
		fscanf(fp,"%lf %lf",&pointSet[i].x,&pointSet[i].y);
	}
	
	fclose(fp);
	
	pointSet[numPoints] = pointSet[0];
	
	for(i=0;i<numPoints;i++){
		leftSum += pointSet[i].x*pointSet[i+1].y;
		rightSum += pointSet[i+1].x*pointSet[i].y;
	}
	
	free(pointSet);
	
	return 0.5*fabs(leftSum - rightSum);
}

int main(int argC,char* argV[])
{
	if(argC==1)
		printf("\nUsage : %s <full path of polygon vertices file>",argV[0]);
	
	else
		printf("The polygon area is %lf square units.",shoelace(argV[1]));
	
	return 0;
}

Input file, first line specifies number of points followed by the ordered vertices set with one vertex on each line.

5
3 4
5 11
12 8
9 5
5 6

Invocation and output :

C:\rosettaCode>shoelace.exe polyData.txt
The polygon area is 30.000000 square units.

C#

Translation of: Java
using System;
using System.Collections.Generic;

namespace ShoelaceFormula {
    using Point = Tuple<double, double>;

    class Program {
        static double ShoelaceArea(List<Point> v) {
            int n = v.Count;
            double a = 0.0;
            for (int i = 0; i < n - 1; i++) {
                a += v[i].Item1 * v[i + 1].Item2 - v[i + 1].Item1 * v[i].Item2;
            }
            return Math.Abs(a + v[n - 1].Item1 * v[0].Item2 - v[0].Item1 * v[n - 1].Item2) / 2.0;
        }

        static void Main(string[] args) {
            List<Point> v = new List<Point>() {
                new Point(3,4),
                new Point(5,11),
                new Point(12,8),
                new Point(9,5),
                new Point(5,6),
            };
            double area = ShoelaceArea(v);
            Console.WriteLine("Given a polygon with vertices [{0}],", string.Join(", ", v));
            Console.WriteLine("its area is {0}.", area);
        }
    }
}
Output:
Given a polygon with vertices [(3, 4), (5, 11), (12, 8), (9, 5), (5, 6)],
its area is 30.

C++

Translation of: D
#include <iostream>
#include <tuple>
#include <vector>

using namespace std;

double shoelace(vector<pair<double, double>> points) {
	double leftSum = 0.0;
	double rightSum = 0.0;

	for (int i = 0; i < points.size(); ++i) {
		int j = (i + 1) % points.size();
		leftSum  += points[i].first * points[j].second;
		rightSum += points[j].first * points[i].second;
	}

	return 0.5 * abs(leftSum - rightSum);
}

void main() {
	vector<pair<double, double>> points = {
		make_pair( 3,  4),
		make_pair( 5, 11),
		make_pair(12,  8),
		make_pair( 9,  5),
		make_pair( 5,  6),
	};

	auto ans = shoelace(points);
	cout << ans << endl;
}
Output:
30

Cowgol

include "cowgol.coh";

typedef Coord is uint16; # floating point types are not supported

record Point is
    x: Coord;
    y: Coord;
end record;

sub shoelace(p: [Point], length: intptr): (area: Coord) is
    var left: Coord := 0;
    var right: Coord := 0;
    
    var y0 := p.y;
    var x0 := p.x;
    
    while length > 1 loop
        var xp := p.x;
        var yp := p.y;
        p := @next p;
        left := left + xp * p.y;
        right := right + yp * p.x;
        length := length - 1;
    end loop;
    
    left := left + y0 * p.x;
    right := right + x0 * p.y;
    if left < right then
        area := right - left;
    else
        area := left - right;
    end if;
    
    area := area / 2;
end sub;

var polygon: Point[] := {{3,4},{5,11},{12,8},{9,5},{5,6}};
print_i16(shoelace(&polygon[0], @sizeof polygon));
print_nl();
Output:
30

D

import std.stdio;

Point[] pnts = [{3,4}, {5,11}, {12,8}, {9,5}, {5,6}];

void main() {
    auto ans = shoelace(pnts);
    writeln(ans);
}

struct Point {
    real x, y;
}

real shoelace(Point[] pnts) {
    real leftSum = 0, rightSum = 0;

    for (int i=0; i<pnts.length; ++i) {
        int j = (i+1) % pnts.length;
        leftSum  += pnts[i].x * pnts[j].y;
        rightSum += pnts[j].x * pnts[i].y;
    }

    import std.math : abs;
    return 0.5 * abs(leftSum - rightSum);
}

unittest {
    auto ans = shoelace(pnts);
    assert(ans == 30);
}
Output:
30

Delphi

Works with: Delphi version 6.0

In keeping with the principles of modularity and reusability, the problem has been broken down into subroutines that can process any polygon. In other words, the subroutines don't just solve the area of one polygon; they can find the area of any polygon.

{Create a 2D vector type}

type T2DVector = record
 X, Y: double;
 end;

{Test polygon}

var Polygon: array [0..4] of T2DVector =
 ((X:3; Y:4), (X:5; Y:11), (X:12; Y:8), (X:9; Y:5), (X:5; Y:6));


function GetPolygonArea(Polygon: array of T2DVector): double;
{Return the area of the polygon }
{K = [(x1y2 + x2y3 + x3y4 + ... + xny1) - (x2y1 + x3y2 + x4y3 + ... + x1yn)]/2}
var I,Inx: integer;
var P1,P2: T2DVector;
var Sum1,Sum2: double;
begin
Result:=0;
Sum1:=0; Sum2:=0;
for I:=0 to Length(Polygon)-1 do
	begin
	{Vector back to the beginning}
	if I=(Length(Polygon)-1) then Inx:=0
	else Inx:=I+1;
	P1:=Polygon[I];
	P2:=Polygon[Inx];
	Sum1:=Sum1 + P1.X * P2.Y;
	Sum2:=Sum2 + P2.X * P1.Y;
	end;
Result:=abs((Sum1 - Sum2)/2);
end;

procedure ShowPolygon(Poly: array of T2DVector; Memo: TMemo);
var I: integer;
var S: string;
begin
S:='';
for I:=0 to High(Poly) do
 S:=S+Format('(%2.1F, %2.1F) ',[Poly[I].X, Poly[I].Y]);
Memo.Lines.Add(S);
end;


procedure ShowPolygonArea(Memo: TMemo);
var Area: double;
begin
ShowPolygon(Polygon,Memo);
Area:=GetPolygonArea(Polygon);
Memo.Lines.Add('Area: '+FloatToStrF(Area,ffFixed,18,2));
end;
Output:
(3.0, 4.0) (5.0, 11.0) (12.0, 8.0) (9.0, 5.0) (5.0, 6.0) 
Area: 30.00
Elapsed Time: 3.356 ms.


EasyLang

proc shoelace . p[][] res .
   sum = 0
   for i = 1 to len p[][] - 1
      sum += p[i][1] * p[i + 1][2]
      sum -= p[i + 1][1] * p[i][2]
   .
   sum += p[i][1] * p[1][2]
   sum -= p[1][1] * p[i][2]
   res = abs sum / 2
.
data[][] = [ [ 3 4 ] [ 5 11 ] [ 12 8 ] [ 9 5 ] [ 5 6 ] ]
shoelace data[][] res
print res

Elixir

def shoelace(points) do
  points
  |> Enum.reduce({0, List.last(points)}, fn {x1, y1}, {sum, {x0, y0}} ->
    {sum + (y0 * x1 - x0 * y1), {x1, y1}}
  end)
  |> elem(0)
  |> div(2)
end

F#

// Shoelace formula for area of polygon. Nigel Galloway: April 11th., 2018
let fN(n::g) = abs(List.pairwise(n::g@[n])|>List.fold(fun n ((,),(,))->n+(*)-(*)) 0.0)/2.0
printfn "%f" (fN [(3.0,4.0); (5.0,11.0); (12.0,8.0); (9.0,5.0); (5.0,6.0)])
Output:
30.000000

Factor

By constructing a circular from a sequence, we can index elements beyond the length of the sequence, wrapping around to the beginning. We can also change the beginning of the sequence to an arbitrary index. This allows us to use 2map to cleanly obtain a sum.

USING: circular kernel math prettyprint sequences ;
IN: rosetta-code.shoelace

CONSTANT: input { { 3 4 } { 5 11 } { 12 8 } { 9 5 } { 5 6 } }

: align-pairs ( pairs-seq -- seq1 seq2 )
    <circular> dup clone [ 1 ] dip
    [ change-circular-start ] keep ;

: shoelace-sum ( seq1 seq2 -- n )
    [ [ first ] [ second ] bi* * ] 2map sum ;

: shoelace-area ( pairs-seq -- area )
    [ align-pairs ] [ align-pairs swap ] bi
    [ shoelace-sum ] 2bi@ - abs 2 / ;

input shoelace-area .
Output:
30

Fortran

Fortran 90

Except for the use of "END FUNCTION name instead of just END, and the convenient function SUM with array span expressions (so SUM(P) rather than a DO-loop to sum the elements of array P), both standardised with F90, this would be acceptable to F66, which introduced complex number arithmetic. Otherwise, separate X and Y arrays would be needed, but complex numbers seemed convenient seeing as (x,y) pairs are involved. But because the MODULE facility of F90 has not been used, routines invoking functions must declare the type of the function names, especially if the default types are unsuitable, as here. In function AREA, the x and y parts are dealt with together, but in AREASL they might be better as separate arrays, thus avoiding the DIMAG and DBLE functions to extract the x and y parts. Incidentally, the x and y parts can be interchanged and the calculation still works. Comparing the two resulting areas might give some indication of their accuracy.

If the MODULE protocol were used, the size of an array parameter is passed as a secret additional parameter accessible via the special function UBOUND, but otherwise it must be passed as an explicit parameter. A quirk of the compiler requires that N be declared before it appears in DOUBLE COMPLEX P(N) so as it is my practice to declare parameters in the order specified, here N comes before P. However, it is not clear whether specifying P(N) does much good (as in array index checking) as an alternative is to specify P(*) meaning merely that the array has one dimension, or even P(12345) to the same effect, with no attention to the actual numerical value. See for example Array_length#Fortran
      DOUBLE PRECISION FUNCTION AREA(N,P)	!Calculates the area enclosed by the polygon P.
C   Uses the mid-point rule for integration. Consider the line joining (x1,y1) to (x2,y2)
C The area under that line (down to the x-axis) is the y-span midpoint (y1 + y2)/2 times the width (x2 - x1)
C This is the trapezoidal rule for a single interval, and follows from simple geometry.
C Now consider a sequence of such points heading in the +x direction: each successive interval's area is positive.
C Follow with a sequence of points heading in the -x direction, back to the first point: their areas are all negative.
C The resulting sum is the area below the +x sequence and above the -x sequence: the area of the polygon.
C   The point sequence can wobble as it wishes and can meet the other side, but it must not cross itself
c as would be done in a figure 8 drawn with a crossover instead of a meeting.
C   A clockwise traversal (as for an island) gives a positive area; use anti-clockwise for a lake.
       INTEGER N		!The number of points.
       DOUBLE COMPLEX P(N)	!The points.
       DOUBLE COMPLEX PP,PC	!Point Previous and Point Current.
       DOUBLE COMPLEX W		!Polygon centre. Map coordinates usually have large offsets.
       DOUBLE PRECISION A	!The area accumulator.
       INTEGER I		!A stepper.
        IF (N.LT.3) STOP "Area: at least three points are needed!"	!Good grief.
        W = (P(1) + P(N/3) + P(2*N/3))/3	!An initial working average.
        W = SUM(P(1:N) - W)/N + W	!A good working average is the average itself.
        A = 0			!The area enclosed by the point sequence.
        PC = P(N) - W		!The last point is implicitly joined to the first.
        DO I = 1,N		!Step through the positions.
          PP = PC			!Previous position.
          PC = P(I) - W			!Current position.
          A = (DIMAG(PC) + DIMAG(PP))*(DBLE(PC) - DBLE(PP)) + A	!Area integral component.
        END DO			!On to the next position.
        AREA = A/2		!Divide by two once.
      END FUNCTION AREA		!The units are those of the points.

      DOUBLE PRECISION FUNCTION AREASL(N,P)	!Area enclosed by polygon P, by the "shoelace" method.
       INTEGER N		!The number of points.
       DOUBLE COMPLEX P(N)	!The points.
       DOUBLE PRECISION A	!A scratchpad.
        A = SUM(DBLE(P(1:N - 1)*DIMAG(P(2:N)))) + DBLE(P(N))*DIMAG(P(1))
     1    - SUM(DBLE(P(2:N)*DIMAG(P(1:N - 1)))) - DBLE(P(1))*DIMAG(P(N))
        AREASL = A/2		!The midpoint formula requires a halving.
      END FUNCTION AREASL	!Negative for clockwise, positive for anti-clockwise.

      INTEGER ENUFF
      DOUBLE PRECISION AREA,AREASL	!The default types are not correct.
      DOUBLE PRECISION A1,A2		!Scratchpads, in case of a debugging WRITE within the functions.
      PARAMETER (ENUFF = 5)		!The specification.
      DOUBLE COMPLEX POINT(ENUFF)	!Could use X and Y arrays instead.
      DATA POINT/(3D0,4D0),(5D0,11D0),(12D0,8D0),(9D0,5D0),(5D0,6D0)/	!"D" for double precision.

      WRITE (6,*) POINT
      A1 = AREA(5,POINT)
      A2 = AREASL(5,POINT)
      WRITE (6,*) "A=",A1,A2
      END

Output: WRITE (6,*) means write to output unit six (standard output) with free-format (the *). Note the different sign convention.

 (3.00000000000000,4.00000000000000) (5.00000000000000,11.0000000000000)
 (12.0000000000000,8.00000000000000) (9.00000000000000,5.00000000000000)
 (5.00000000000000,6.00000000000000)
 A=   30.0000000000000       -30.0000000000000

The "shoelace" method came as a surprise to me, as I've always used what I had thought the "obvious" method. Note that function AREA makes one pass through the point data not two, and because map coordinate values often have large offsets a working average is used to reduce the loss of precision. This requires faith that SUM(P(1:N) - W) will be evaluated as written, not as SUM(P(1:N)) - N*W with even greater optimisation opportunity awaiting in cancelling further components of the expression. For example, the New Zealand metric grid has (2510000,6023150) as (Easting,Northing) or (x,y) at its central point of 41°S 173°E rather than (0,0) so seven digits of precision are used up. If anyone wants a copy of a set of point sequences for NZ (30,000 positions, 570KB) with lots of islands and lakes, even a pond in an island in a lake in the North Island...

Fortran I

In orginal FORTRAN 1957:

C SHOELACE FORMULA FOR POLYGONAL AREA
      DIMENSION X(33),Y(33)
      READ 101,N
      DO 1 I=1,N
   1    READ 102,X(I),Y(I)   
      X(I)=X(1)
      Y(I)=Y(1)
      A=0
      DO 2 I=1,N
   2    A=A+X(I)*Y(I+1)-X(I+1)*Y(I)
      A=ABSF(A/2.)
      PRINT 303,A
      STOP
 101  FORMAT(I2)
 102  FORMAT(2F6.2)
 303  FORMAT(F10.2)
Input:
 5
  3.00  4.00 
  5.00 11.00
 12.00  8.00
  9.00  5.00
  5.00  6.00
Output:
     30.00

FreeBASIC

' version 18-08-2017
' compile with: fbc -s console

Type _point_
    As Double x, y
End Type

Function shoelace_formula(p() As _point_ ) As Double

    Dim As UInteger i
    Dim As Double sum

    For i = 1 To UBound(p) -1
        sum += p(i   ).x * p(i +1).y
        sum -= p(i +1).x * p(i   ).y
    Next
    sum += p(i).x * p(1).y
    sum -= p(1).x * p(i).y

    Return Abs(sum) / 2
End Function

' ------=< MAIN >=------

Dim As _point_ p_array(1 To ...) = {(3,4), (5,11), (12,8), (9,5), (5,6)}

Print "The area of the polygon ="; shoelace_formula(p_array())

' empty keyboard buffer
While Inkey <> "" : Wend
Print : Print "hit any key to end program"
Sleep
End
Output:
The area of the polygon = 30

Fōrmulæ

Fōrmulæ programs are not textual, visualization/edition of programs is done showing/manipulating structures but not text. Moreover, there can be multiple visual representations of the same program. Even though it is possible to have textual representation —i.e. XML, JSON— they are intended for storage and transfer purposes more than visualization and edition.

Programs in Fōrmulæ are created/edited online in its website.

In this page you can see and run the program(s) related to this task and their results. You can also change either the programs or the parameters they are called with, for experimentation, but remember that these programs were created with the main purpose of showing a clear solution of the task, and they generally lack any kind of validation.

Solution

File:Fōrmulæ - Shoelace formula 01.png

Test case

File:Fōrmulæ - Shoelace formula 02.png

File:Fōrmulæ - Shoelace formula 03.png

Go

package main

import "fmt"

type point struct{ x, y float64 }

func shoelace(pts []point) float64 {
    sum := 0.
    p0 := pts[len(pts)-1]
    for _, p1 := range pts {
        sum += p0.y*p1.x - p0.x*p1.y
        p0 = p1
    }
    return sum / 2
}

func main() {
    fmt.Println(shoelace([]point{{3, 4}, {5, 11}, {12, 8}, {9, 5}, {5, 6}}))
}
Output:
30

Haskell

import Data.Bifunctor (bimap)

----------- SHOELACE FORMULA FOR POLYGONAL AREA ----------

-- The area of a polygon formed by
-- the list of (x, y) coordinates.

shoelace :: [(Double, Double)] -> Double
shoelace =
  let calcSums ((x, y), (a, b)) = bimap (x * b +) (a * y +)
   in (/ 2)
        . abs
        . uncurry (-)
        . foldr calcSums (0, 0)
        . (<*>) zip (tail . cycle)

--------------------------- TEST -------------------------
main :: IO ()
main =
  print $
    shoelace [(3, 4), (5, 11), (12, 8), (9, 5), (5, 6)]
Output:
30.0

J

Implementation:

shoelace=:verb define
  0.5*|+/((* 1&|.)/ - (* _1&|.)/)|:y
)

Task example:

   shoelace 3 4,5 11,12 8,9 5,:5 6
30

Exposition:

We start with our list of coordinate pairs

   3 4,5 11,12 8,9 5,:5 6
 3  4
 5 11
12  8
 9  5
 5  6

But the first thing we do is transpose them so that x coordinates and y coordinates are the two items we are working with:

   |:3 4,5 11,12 8,9 5,:5 6
3  5 12 9 5
4 11  8 5 6

We want to rotate the y list by one (in each direction) and multiply the x list items by the corresponding y list items. Something like this, for example:

   3 5 12 9 5* 1|.4 11 8 5 6
33 40 60 54 20

Or, rephrased:

   (* 1&|.)/|:3 4,5 11,12 8,9 5,:5 6
33 40 60 54 20

We'll be subtracting what we get when we rotate in the other direction, which looks like this:

   ((* 1&|.)/ - (* _1&|.)/)|:3 4,5 11,12 8,9 5,:5 6
15 20 _72 _18 _5

Finally, we add up that list, take the absolute value (there are contexts where signed area is interesting - for example, some graphics application - but that was not a part of this task) and divide that by 2.

Java

Translation of: Kotlin
Works with: Java version 9
import java.util.List;

public class ShoelaceFormula {
    private static class Point {
        int x, y;

        Point(int x, int y) {
            this.x = x;
            this.y = y;
        }

        @Override
        public String toString() {
            return String.format("(%d, %d)", x, y);
        }
    }

    private static double shoelaceArea(List<Point> v) {
        int n = v.size();
        double a = 0.0;
        for (int i = 0; i < n - 1; i++) {
            a += v.get(i).x * v.get(i + 1).y - v.get(i + 1).x * v.get(i).y;
        }
        return Math.abs(a + v.get(n - 1).x * v.get(0).y - v.get(0).x * v.get(n - 1).y) / 2.0;
    }

    public static void main(String[] args) {
        List<Point> v = List.of(
            new Point(3, 4),
            new Point(5, 11),
            new Point(12, 8),
            new Point(9, 5),
            new Point(5, 6)
        );
        double area = shoelaceArea(v);
        System.out.printf("Given a polygon with vertices %s,%n", v);
        System.out.printf("its area is %f,%n", area);
    }
}
Output:
Given a polygon with vertices [(3, 4), (5, 11), (12, 8), (9, 5), (5, 6)],
its area is 30.000000,

JavaScript

(() => {
    "use strict";

    // ------- SHOELACE FORMULA FOR POLYGONAL AREA -------

    // shoelaceArea :: [(Float, Float)] -> Float
    const shoeLaceArea = vertices => abs(
        uncurry(subtract)(
            ap(zip)(compose(tail, cycle))(
                vertices
            )
            .reduce(
                (a, x) => [0, 1].map(b => {
                    const n = Number(b);

                    return a[n] + (
                        x[0][n] * x[1][Number(!b)]
                    );
                }),
                [0, 0]
            )
        )
    ) / 2;


    // ----------------------- TEST -----------------------
    const main = () => {
        const ps = [
            [3, 4],
            [5, 11],
            [12, 8],
            [9, 5],
            [5, 6]
        ];

        return [
                "Polygonal area by shoelace formula:",
                `${JSON.stringify(ps)} -> ${shoeLaceArea(ps)}`
            ]
            .join("\n");
    };


    // ---------------- GENERIC FUNCTIONS -----------------

    // abs :: Num -> Num
    const abs = x =>
        // Absolute value of a given number
        // without the sign.
        0 > x ? -x : x;


    // ap :: (a -> b -> c) -> (a -> b) -> (a -> c)
    const ap = f =>
        // Applicative instance for functions.
        // f(x) applied to g(x).
        g => x => f(x)(
            g(x)
        );


    // compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
    const compose = (...fs) =>
        // A function defined by the right-to-left
        // composition of all the functions in fs.
        fs.reduce(
            (f, g) => x => f(g(x)),
            x => x
        );


    // cycle :: [a] -> Generator [a]
    const cycle = function* (xs) {
        // An infinite repetition of xs,
        // from which an arbitrary prefix
        // may be taken.
        const lng = xs.length;
        let i = 0;

        while (true) {
            yield xs[i];
            i = (1 + i) % lng;
        }
    };


    // length :: [a] -> Int
    const length = xs =>
        // Returns Infinity over objects without finite
        // length. This enables zip and zipWith to choose
        // the shorter argument when one is non-finite,
        // like cycle, repeat etc
        "GeneratorFunction" !== xs.constructor
        .constructor.name ? (
            xs.length
        ) : Infinity;


    // subtract :: Num -> Num -> Num
    const subtract = x =>
        y => y - x;


    // tail :: [a] -> [a]
    const tail = xs =>
        // A new list consisting of all
        // items of xs except the first.
        "GeneratorFunction" !== xs.constructor
        .constructor.name ? (
            Boolean(xs.length) ? (
                xs.slice(1)
            ) : undefined
        ) : (take(1)(xs), xs);


    // take :: Int -> [a] -> [a]
    // take :: Int -> String -> String
    const take = n =>
        // The first n elements of a list,
        // string of characters, or stream.
        xs => "GeneratorFunction" !== xs
        .constructor.constructor.name ? (
            xs.slice(0, n)
        ) : Array.from({
            length: n
        }, () => {
            const x = xs.next();

            return x.done ? [] : [x.value];
        }).flat();


    // uncurry :: (a -> b -> c) -> ((a, b) -> c)
    const uncurry = f =>
        // A function over a pair, derived
        // from a curried function.
        (...args) => {
            const [x, y] = Boolean(args.length % 2) ? (
                args[0]
            ) : args;

            return f(x)(y);
        };


    // zip :: [a] -> [b] -> [(a, b)]
    const zip = xs => ys => {
        const
            n = Math.min(length(xs), length(ys)),
            vs = take(n)(ys);

        return take(n)(xs)
            .map((x, i) => [x, vs[i]]);
    };


    // MAIN ---
    return main();
})();
Output:
Polygonal area by shoelace formula:
[[3,4],[5,11],[12,8],[9,5],[5,6]] -> 30

jq

Works with: jq

Works with gojq, the Go implementation of jq

Translation of: Wren

# jq's length applied to a number is its absolute value.
def shoelace:
  . as $a
  | reduce range(0; length-1) as $i (0;
      . + $a[$i][0]*$a[$i+1][1] - $a[$i+1][0]*$a[$i][1] )
  | (. + $a[-1][0]*$a[0][1] - $a[0][0]*$a[-1][1])|length / 2;

[ [3, 4], [5, 11], [12, 8], [9, 5], [5, 6] ]
| "The polygon with vertices at \(.) has an area of \(shoelace)."
Output:
The polygon with vertices at [[3,4],[5,11],[12,8],[9,5],[5,6]] has an area of 30.

Translation of: Julia

def zip_shoelace:
   def sumprod: reduce .[] as [$x,$y] (0; . + ($x * $y));
   . as {$x, $y}
   | [$x, ($y[1:] + [$y[0]])] | transpose | sumprod as $a
   | [($x[1:] + [$x[0]]), $y] | transpose | sumprod as $b
   | ($a - $b) | length / 2;

{x: [3, 5, 12, 9, 5], y: [4, 11, 8, 5, 6] }
| zip_shoelace
Output:

As above.

Julia

Works with: Julia version 0.6
Translation of: Python
"""
Assumes x,y points go around the polygon in one direction.
"""
shoelacearea(x, y) =
    abs(sum(i * j for (i, j) in zip(x, append!(y[2:end], y[1]))) -
        sum(i * j for (i, j) in zip(append!(x[2:end], x[1]), y))) / 2

x, y = [3, 5, 12, 9, 5], [4, 11, 8, 5, 6]
@show x y shoelacearea(x, y)
Output:
x = [3, 5, 12, 9, 5]
y = [4, 11, 8, 5, 6]
shoelacearea(x, y) = 30.0

Kotlin

// version 1.1.3

class Point(val x: Int, val y: Int) {
    override fun toString() = "($x, $y)"
}
 
fun shoelaceArea(v: List<Point>): Double {
    val n = v.size
    var a = 0.0
    for (i in 0 until n - 1) { 
        a += v[i].x * v[i + 1].y - v[i + 1].x * v[i].y
    }
    return Math.abs(a + v[n - 1].x * v[0].y - v[0].x * v[n -1].y) / 2.0  
}

fun main(args: Array<String>) {
    val v = listOf(
        Point(3, 4), Point(5, 11), Point(12, 8), Point(9, 5), Point(5, 6)
    )
    val area = shoelaceArea(v) 
    println("Given a polygon with vertices at $v,")
    println("its area is $area")
}
Output:
Given a polygon with vertices at [(3, 4), (5, 11), (12, 8), (9, 5), (5, 6)],
its area is 30.0

Lambdatalk

{def shoelace
 {lambda {:pol}
  {abs
   {/ 
    {- 
     {+ {S.map {{lambda {:pol :i} {* {car {A.get :i :pol}}
                                     {cdr {A.get {+ :i 1} :pol}}}} :pol}
               {S.serie 0 {- {A.length :pol} 2}}}
                                  {* {car {A.get {- {A.length :pol} 1} :pol}}
                                     {cdr {A.get 0 :pol}}}}
     {+ {S.map {{lambda {:pol :i} {* {car {A.get {+ :i 1} :pol}}
                                     {cdr {A.get :i :pol}}}} :pol}
               {S.serie 0 {- {A.length :pol} 2}}} 
                                  {* {car {A.get 0 :pol}}
                                     {cdr {A.get {- {A.length :pol} 1} :pol}}}}} 2}}}}
-> shoelace

{def pol
  {A.new {cons 3 4}
         {cons 5 11}
         {cons 12 8}
         {cons 9 5}
         {cons 5 6}}}
-> pol = [(3 4),(5 11),(12 8),(9 5),(5 6)]

{shoelace {pol}}
-> 30

Lua

function shoeArea(ps)
  local function det2(i,j)
    return ps[i][1]*ps[j][2]-ps[j][1]*ps[i][2]
  end
  local sum = #ps>2 and det2(#ps,1) or 0
  for i=1,#ps-1 do sum = sum + det2(i,i+1)end
  return math.abs(0.5 * sum)
end

Using an accumulator helper inner function

function shoeArea(ps)
  local function ssum(acc, p1, p2, ...)
    if not p2 or not p1 then
      return math.abs(0.5 * acc)
    else
      return ssum(acc + p1[1]*p2[2]-p1[2]*p2[1], p2, ...)
    end
  end
  return ssum(0, ps[#ps], table.unpack(ps))
end

local p = {{3,4}, {5,11}, {12,8}, {9,5}, {5,6}}
print(shoeArea(p))-- 30

both version handle special cases of less than 3 point as 0 area result.

Maple

with(ArrayTools):

module Point()
 option object;
 local x := 0;
 local y := 0;

 export getX::static := proc(self::Point, $)
  return self:-x;
 end proc;

 export getY::static := proc(self::Point, $)
  return self:-y
 end proc;

 export ModuleApply::static := proc()
  Object(Point, _passed);
 end proc;

 export ModuleCopy::static := proc(new::Point, proto::Point, X, Y, $)
  new:-x := X;
  new:-y := Y;
 end proc;

 export ModulePrint::static := proc(self::Point)
  return cat("(", self:-x, ",", self:-y, ")");
 end proc;
end module:

module Polygon()
 option object;
 local vertices := Array([Point(0,0)]);

 export getVertices::static := proc(self::Polygon)
  return self:-vertices;
 end proc;

 export area::static := proc(self::Polygon)
  local i, N := ArrayNumElems(self:-vertices);
  local total := getX(self:-vertices[N]) * getY(self:-vertices[1]) - getX(self:-vertices[1]) * getY(self:-vertices[N]);
  total += map(`+`, seq(getX(self:-vertices[i]) * getY(self:-vertices[i+1]), i = 1..(N-1))) - map(`+`, seq(getX(self:-vertices[i+1]) * getY(self:-vertices[i]), i = 1..(N-1)));
  return abs(total / 2);
 end proc;

 export ModuleApply::static := proc()
  Object(Polygon, _passed);
 end proc;

 export ModuleCopy::Static := proc(new::Polygon, proto::Polygon, Ps, $)
  new:-vertices := Ps;
 end proc;

 export ModulePrint::static := proc(self::Polygon)
  return self:-vertices;
 end proc;
end module:

P1 := Polygon(Array([Point(3,4), Point(5,11), Point(12,8), Point(9,5), Point(5,6)])):
area(P1);
Output:

                                     30

Mathematica/Wolfram Language

Geometry objects built-in in the Wolfram Language

Area[Polygon[{{3, 4}, {5, 11}, {12, 8}, {9, 5}, {5, 6}}]]
Output:
30

min

Works with: min version 0.19.3
((((first) map) ((last) map)) cleave) :dezip
(((first) (rest)) cleave append) :rotate
((0 <) (-1 *) when) :abs

(
  =b =a a size :n 0 :i () =list
  (i n <) (
    a i get b i get ' prepend list append #list
    i succ @i
  ) while list
) :rezip

(rezip (-> *) map sum) :cross-sum

(
  ((dezip rotate) (dezip swap rotate)) cleave
  ((id) (cross-sum) (id) (cross-sum)) spread
  - abs 2 /
) :shoelace

((3 4) (5 11) (12 8) (9 5) (5 6)) shoelace print
Output:
30.0

MiniScript

shoelace = function(vertices)
    sum = 0
    points = vertices.len
    
    for i in range(0,points-2)
        sum = sum + vertices[i][0]*vertices[i+1][1]
    end for
    sum = sum + vertices[points-1][0]*vertices[0][1]
    
    for i in range(points-1,1)
        sum = sum - vertices[i][0]*vertices[i-1][1]
    end for
    sum = sum - vertices[0][0]*vertices[points-1][1]
    
    return abs(sum)/2
end function

verts = [[3,4],[5,11],[12,8],[9,5],[5,6]]

print "The polygon area is "  + shoelace(verts)
Output:
The polygon area is 30

Modula-2

MODULE ShoelaceFormula;
FROM RealStr IMPORT RealToStr;
FROM FormatString IMPORT FormatString;
FROM Terminal IMPORT WriteString,WriteLn,ReadChar;

TYPE
    Point = RECORD
        x,y : INTEGER;
    END;

PROCEDURE PointToString(self : Point; VAR buf : ARRAY OF CHAR);
BEGIN
    FormatString("(%i, %i)", buf, self.x, self.y);
END PointToString;

PROCEDURE ShoelaceArea(v : ARRAY OF Point) : REAL;
VAR
    a : REAL;
    i,n : INTEGER;
BEGIN
    n := HIGH(v);
    a := 0.0;
    FOR i:=0 TO n-1 DO
        a := a + FLOAT(v[i].x * v[i+1].y - v[i+1].x * v[i].y);
    END;
    RETURN ABS(a + FLOAT(v[n].x * v[0].y - v[0].x * v[n].y)) / 2.0;
END ShoelaceArea;

VAR
    v : ARRAY[0..4] OF Point;
    buf : ARRAY[0..63] OF CHAR;
    area : REAL;
    i : INTEGER;
BEGIN
    v[0] := Point{3,4};
    v[1] := Point{5,11};
    v[2] := Point{12,8};
    v[3] := Point{9,5};
    v[4] := Point{5,6};
    area := ShoelaceArea(v);

    WriteString("Given a polygon with verticies ");
    FOR i:=0 TO HIGH(v) DO
        PointToString(v[i], buf);
        WriteString(buf);
        WriteString(" ");
    END;
    WriteLn;

    RealToStr(area, buf);
    WriteString("its area is ");
    WriteString(buf);
    WriteLn;

    ReadChar;
END ShoelaceFormula.

Nim

type
  Point = tuple
    x: float
    y: float

func shoelace(points: openArray[Point]): float =
  var leftSum, rightSum = 0.0
  for i in 0..<len(points):
    var j = (i + 1) mod len(points)
    leftSum  += points[i].x * points[j].y
    rightSum += points[j].x * points[i].y
  0.5 * abs(leftSum - rightSum)

var points = [(3.0, 4.0), (5.0, 11.0), (12.0, 8.0), (9.0, 5.0), (5.0, 6.0)]

echo shoelace(points)
Output:
30.0

Perl

use strict;
use warnings;
use feature 'say';

sub area_by_shoelace {
    my $area;
    our @p;
    $#_ > 0 ? @p = @_ : (local *p = shift);
    $area += $p[$_][0] * $p[($_+1)%@p][1] for 0 .. @p-1;
    $area -= $p[$_][1] * $p[($_+1)%@p][0] for 0 .. @p-1;
    return abs $area/2;
}

my @poly = ( [3,4], [5,11], [12,8], [9,5], [5,6] );

say area_by_shoelace(   [3,4], [5,11], [12,8], [9,5], [5,6]   );
say area_by_shoelace( [ [3,4], [5,11], [12,8], [9,5], [5,6] ] );
say area_by_shoelace(  @poly );
say area_by_shoelace( \@poly );
Output:
30
30
30
30

Phix

with javascript_semantics
enum X, Y
function shoelace(sequence s)
    atom t = 0
    if length(s)>2 then
        s = append(deep_copy(s),s[1])
        for i=1 to length(s)-1 do
            t += s[i][X]*s[i+1][Y] - s[i+1][X]*s[i][Y]
        end for
    end if
    return abs(t)/2
end function
 
constant test = {{3,4},{5,11},{12,8},{9,5},{5,6}}
?shoelace(test)
Output:
30

An alternative solution, which does not need the X,Y enum, and gives the same output:

with javascript_semantics
function shoelace(sequence s)
    atom t = 0
    integer j = length(s)
    if j!=0 then
        sequence {x,y} = columnize(s)
        for i=1 to j do
            t += (y[j] + y[i]) * (x[j] - x[i])
            j = i
        end for
    end if
    return abs(t)/2
end function
 
constant test = {{3,4},{5,11},{12,8},{9,5},{5,6}}
?shoelace(test)

PowerBASIC

Translation of: Visual Basic
#COMPILE EXE
#DIM ALL
#COMPILER PBCC 6

FUNCTION ShoelaceArea(x() AS DOUBLE, y() AS DOUBLE) AS DOUBLE
LOCAL i, j AS LONG
LOCAL Area AS DOUBLE

  j = UBOUND(x())
  FOR i = LBOUND(x()) TO UBOUND(x())
    Area += (y(j) + y(i)) * (x(j) - x(i))
    j = i
  NEXT i
  FUNCTION = ABS(Area) / 2
END FUNCTION

FUNCTION PBMAIN () AS LONG
  REDIM x(0 TO 4) AS DOUBLE, y(0 TO 4) AS DOUBLE
  ARRAY ASSIGN x() = 3, 5, 12, 9, 5
  ARRAY ASSIGN y() = 4, 11, 8, 5, 6
  CON.PRINT STR$(ShoelaceArea(x(), y()))
  CON.WAITKEY$
END FUNCTION
Output:
30

Python

Python: Explicit

>>> def area_by_shoelace(x, y):
    "Assumes x,y points go around the polygon in one direction"
    return abs( sum(i * j for i, j in zip(x,             y[1:] + y[:1]))
               -sum(i * j for i, j in zip(x[1:] + x[:1], y            ))) / 2

>>> points = [(3,4), (5,11), (12,8), (9,5), (5,6)]
>>> x, y = zip(*points)
>>> area_by_shoelace(x, y)
30.0
>>>

Python: numpy

# Even simpler:
# In python we can take an advantage of that x[-1] refers to the last element in an array, same as x[N-1].
# Introducing the index i=[0,1,2,...,N-1]; i-1=[-1,0,...,N-2]; N is the number of vertices of a polygon.
# Thus x[i] is a sequence of the x-coordinate of the polygon vertices, x[i-1] is the sequence shifted by 1 index.
# Note that the shift must be negative. The positive shift x[i+1] results in an error: x[N] index out of bound.

import numpy as np
# x,y are arrays containing coordinates of the polygon vertices
x=np.array([3,5,12,9,5]) 
y=np.array([4,11,8,5,6]) 
i=np.arange(len(x))
#Area=np.sum(x[i-1]*y[i]-x[i]*y[i-1])*0.5 # signed area, positive if the vertex sequence is counterclockwise
Area=np.abs(np.sum(x[i-1]*y[i]-x[i]*y[i-1])*0.5) # one line of code for the shoelace formula

# Remember that applying the Shoelace formula
# will result in a loss of precision if x,y have big offsets.
# Remove the offsets first, e.g. 
# x=x-np.mean(x);y=y-np.mean(y)
# or
# x=x-x[0];y=y-y[0]
# before applying the Shoelace formula.

Python: Defined in terms of reduce and cycle

Translation of: Haskell
Works with: Python version 3.7
'''Polygonal area by shoelace formula'''

from itertools import cycle, islice
from functools import reduce
from operator import sub

# --------- SHOELACE FORMULA FOR POLYGONAL AREA ----------

# shoelaceArea :: [(Float, Float)] -> Float
def shoelaceArea(xys):
    '''Area of polygon with vertices
       at (x, y) points in xys.
    '''
    def go(a, tpl):
        l, r = a
        (x, y), (dx, dy) = tpl
        return l + x * dy, r + y * dx

    return abs(sub(*reduce(
        go,
        zip(
            xys,
            islice(cycle(xys), 1, None)
        ),
        (0, 0)
    ))) / 2


# ------------------------- TEST -------------------------
# main :: IO()
def main():
    '''Sample calculation'''

    ps = [(3, 4), (5, 11), (12, 8), (9, 5), (5, 6)]
    print(__doc__ + ':')
    print(repr(ps) + '  ->  ' + str(shoelaceArea(ps)))


if __name__ == '__main__':
    main()
Output:
Polygonal area by shoelace formula:
[(3, 4), (5, 11), (12, 8), (9, 5), (5, 6)]  ->  30.0

Python: Alternate

This adopts the indexing used in the numpy example above, but does not require the numpy library.

>>> def area_by_shoelace2(x, y):
	return abs(sum(x[i-1]*y[i]-x[i]*y[i-1] for i in range(len(x)))) / 2.

>>> points = [(3,4), (5,11), (12,8), (9,5), (5,6)]
>>> x, y = zip(*points)
>>> area_by_shoelace2(x, y)
30.0
>>>

Racket

#lang racket/base

(struct P (x y))

(define (area . Ps)
  (define (A P-a P-b)
    (+ (for/sum ((p_i Ps)
                 (p_i+1 (in-sequences (cdr Ps)
                                      (in-value (car Ps)))))
         (* (P-a p_i) (P-b p_i+1)))))
  (/ (abs (- (A P-x P-y) (A P-y P-x))) 2))

(module+ main
  (area (P 3 4) (P 5 11) (P 12 8) (P 9 5) (P 5 6)))
Output:
30

Raku

(formerly Perl 6)

Index and mod offset

Works with: Rakudo version 2017.07
sub area-by-shoelace(@p) {
    (^@p).map({@p[$_;0] * @p[($_+1)%@p;1] - @p[$_;1] * @p[($_+1)%@p;0]}).sum.abs / 2
}

say area-by-shoelace( [ (3,4), (5,11), (12,8), (9,5), (5,6) ] );
Output:
30

Slice and rotation

Works with: Rakudo version 2017.07
sub area-by-shoelace ( @p ) {
    my @x := @p».[0];
    my @y := @p».[1];

    my $s := ( @x Z* @y.rotate( 1) ).sum
           - ( @x Z* @y.rotate(-1) ).sum;

    return $s.abs / 2;
}

say area-by-shoelace( [ (3,4), (5,11), (12,8), (9,5), (5,6) ] );
Output:
30

REXX

wrap-around endpoints

/*REXX program uses  a  Shoelace  formula to calculate the area of an  N─sided  polygon.*/
parse arg $;  if $=''  then $= "(3,4),(5,11),(12,8),(9,5),(5,6)"      /*Use the default?*/
A= 0;                  @= space($, 0)                   /*init A; elide blanks from pts.*/
         do #=1  until @=='';      parse var  @    '('   x.#   ","   y.#   ')'   ","   @
         end   /*#*/                                    /* [↨]  get X and Y coördinates.*/
z= #+1;                 y.0= y.#;  y.z= y.1             /*define low & high Y end points*/
         do j=1  for #;  jm= j-1;  jp= j+1;   A= A + x.j*(y.jm - y.jp) /*portion of area*/
         end   /*j*/                                    /*stick a fork in it, we're done*/
say 'polygon area of '      #      " points: "       $       '  is ───► '        abs(A/2)
output   when using the default input:
polygon area of  5  points:  (3,4),(5,11),(12,8),(9,5),(5,6)   is ───►  30

somewhat simplified

reformatted and suitable for ooRexx. (x.0 etc. not needed)

/*REXX program uses a  Shoelace  formula to calculate the area of an  N-sided  polygon. */
parse arg pts                                    /*obtain optional arguments from the CL*/
if pts='' then pts= '(3,4),(5,11),(12,8),(9,5),(5,6)'   /*Not specified?   Use default. */
pts=space(pts,0); z=pts                                 /*elide extra blanks;  save pts.*/
do n=1 until z=''                                       /*perform destructive parse on z*/
  parse var z '(' x.n ',' y.n ')' ',' z                 /*obtain X and Y coördinates    */
  end
z=n+1; y.z=y.1                                          /* take care of end points      */
       y.0=y.n
A=0                                                     /*initialize the  area  to zero.*/
do j=1 for n;
  jp=j+1;
  jm=j-1;
  A=A+x.j*(y.jp-y.jm)                                   /*compute a part of the area.   */
  end
A=abs(A/2)                                              /*obtain half of the  ¦ A ¦  sum*/
say 'polygon area of' n 'points:' pts 'is --->' A
Output:
polygon area of 5 points: (3,4),(5,11),(12,8),(9,5),(5,6) is ---> 30

even simpler

Using the published algorithm

/*REXX program uses a  Shoelace  formula to calculate the area of an  N-sided  polygon. */
parse arg pts                                    /*obtain optional arguments from the CL*/
if pts='' then pts= '(3,4),(5,11),(12,8),(9,5),(5,6)'   /*Not specified?   Use default. */
pts=space(pts,0); z=pts                                 /*elide extra blanks;  save pts.*/
do n=1 until z=''                                       /*perform destructive parse on z*/
  parse var z '(' x.n ',' y.n ')' ',' z                 /*obtain X and Y coördinates    */
  end
a=0
Do i=1 To n-1
  j=i+1
  a=a+x.i*y.j-x.j*y.i
  End
a=a+x.n*y.1-x.1*y.n
a=abs(a)/2
say 'polygon area of' n 'points:' pts 'is --->' a
Output:
polygon area of 5 points: (3,4),(5,11),(12,8),(9,5),(5,6) is ---> 30

Ring

# Project : Shoelace formula for polygonal area

p = [[3,4], [5,11], [12,8], [9,5], [5,6]] 
see "The area of the polygon = " + shoelace(p)

func shoelace(p)
        sum = 0 
        for i = 1 to len(p) -1
             sum = sum + p[i][1] * p[i +1][2]
             sum = sum - p[i +1][1] * p[i][2]
        next
        sum = sum + p[i][1] * p[1][2]
        sum = sum - p[1][1] * p[i][2] 
        return fabs(sum) / 2

Output:

The area of the polygon = 30

RPL

RPL code Comment
≪ 
   DUP 1 GET +  
   0 2 3 PICK SIZE FOR j
      OVER j GET LAST 1 - GET
      OVER RE OVER IM * SWAP RE ROT IM * - +
   NEXT
   ABS 2 / SWAP DROP
≫ 'SHOEL' STO
SHOEL ( { (vertices) } → area ) 
append 1st vertice at the end
sum = 0 ; loop 
  get 2 vertices
  sum += determinant 
  end loop
finalize calculation, clean stack
return area
{(3,4) (5,11) (12,8) (9,5) (5,6)} SHOEL
Output:
1: 30

Ruby

Point = Struct.new(:x,:y) do

  def shoelace(other)
    x * other.y - y * other.x
  end

end

class Polygon

  def initialize(*coords)
    @points = coords.map{|c| Point.new(*c) } 
  end

  def area
    points = @points + [@points.first]
    points.each_cons(2).sum{|p1,p2| p1.shoelace(p2) }.abs.fdiv(2)
  end

end

puts Polygon.new([3,4], [5,11], [12,8], [9,5], [5,6]).area  # => 30.0

Scala

case class Point( x:Int,y:Int ) { override def toString = "(" + x + "," + y + ")" }

case class Polygon( pp:List[Point] ) {
  require( pp.size > 2, "A Polygon must consist of more than two points" )

  override def toString = "Polygon(" + pp.mkString(" ", ", ", " ") + ")"
  
  def area = {
  
    // Calculate using the Shoelace Formula
    val xx = pp.map( p => p.x )
    val yy = pp.map( p => p.y )
    val overlace = xx zip yy.drop(1)++yy.take(1)
    val underlace = yy zip xx.drop(1)++xx.take(1)
    
    (overlace.map( t => t._1 * t._2 ).sum - underlace.map( t => t._1 * t._2 ).sum).abs / 2.0
  }
}

// A little test...
{
val p = Polygon( List( Point(3,4), Point(5,11), Point(12,8), Point(9,5), Point(5,6) ) )

assert( p.area == 30.0 )

println( "Area of " + p + " = " + p.area )
}
Output:
Area of Polygon( (3,4), (5,11), (12,8), (9,5), (5,6) ) = 30.0

Sidef

Translation of: Raku
func area_by_shoelace (*p) {
    var x = p.map{_[0]}
    var y = p.map{_[1]}

    var s = (
        (x ~Z* y.rotate(+1)).sum -
        (x ~Z* y.rotate(-1)).sum
    )

    s.abs / 2
}

say area_by_shoelace([3,4], [5,11], [12,8], [9,5], [5,6])
Output:
30

Swift

Translation of: Scala
import Foundation

struct Point {
  var x: Double
  var y: Double
}

extension Point: CustomStringConvertible {
  var description: String {
    return "Point(x: \(x), y: \(y))"
  }
}

struct Polygon {
  var points: [Point]

  var area: Double {
    let xx = points.map({ $0.x })
    let yy = points.map({ $0.y })
    let overlace = zip(xx, yy.dropFirst() + yy.prefix(1)).map({ $0.0 * $0.1 }).reduce(0, +)
    let underlace = zip(yy, xx.dropFirst() + xx.prefix(1)).map({ $0.0 * $0.1 }).reduce(0, +)

    return abs(overlace - underlace) / 2
  }

  init(points: [Point]) {
    self.points = points
  }

  init(points: [(Double, Double)]) {
    self.init(points: points.map({ Point(x: $0.0, y: $0.1) }))
  }
}

let poly = Polygon(points: [
  (3,4),
  (5,11),
  (12,8),
  (9,5),
  (5,6)
])

print("\(poly) area = \(poly.area)")
Output:
Polygon(points: [Point(x: 3.0, y: 4.0), Point(x: 5.0, y: 11.0), Point(x: 12.0, y: 8.0), Point(x: 9.0, y: 5.0), Point(x: 5.0, y: 6.0)]) area = 30.0

TI-83 BASIC

Works with: TI-83 BASIC version TI-84Plus 2.55MP
[[3,4][5,11][12,8][9,5][5,6]]->[A]
Dim([A])->N:0->A
For(I,1,N)
    I+1->J:If J>N:Then:1->J:End
    A+[A](I,1)*[A](J,2)-[A](J,1)*[A](I,2)->A
End
Abs(A)/2->A
Output:
          30

VBA

Translation of: Phix
Option Base 1
Public Enum axes
    u = 1
    v
End Enum
Private Function shoelace(s As Collection) As Double
    Dim t As Double
    If s.Count > 2 Then
        s.Add s(1)
        For i = 1 To s.Count - 1
            t = t + s(i)(u) * s(i + 1)(v) - s(i + 1)(u) * s(i)(v)
        Next i
    End If
    shoelace = Abs(t) / 2
End Function
 
Public Sub polygonal_area()
    Dim task() As Variant
    task = [{3,4;5,11;12,8;9,5;5,6}]
    Dim tcol As New Collection
    For i = 1 To UBound(task)
        tcol.Add Array(task(i, u), task(i, v))
    Next i
    Debug.Print shoelace(tcol)
End Sub
Output:
30

VBScript

' Shoelace formula for polygonal area - VBScript
    Dim points, x(),y()
    points = Array(3,4, 5,11, 12,8, 9,5, 5,6)
    n=(UBound(points)+1)\2
    Redim x(n+1),y(n+1)
    j=0
    For i = 1 To n
        x(i)=points(j)
        y(i)=points(j+1)
        j=j+2
    Next 'i
    x(i)=points(0)
    y(i)=points(1)
    For i = 1 To n
        area = area + x(i)*y(i+1) - x(i+1)*y(i)
    Next 'i
    area = Abs(area)/2
    msgbox area,,"Shoelace formula"
Output:
30

Visual Basic

Works with: Visual Basic version 5
Works with: Visual Basic version 6
Works with: VBA version Access 97
Works with: VBA version 6.5
Works with: VBA version 7.1
Option Explicit

Public Function ShoelaceArea(x() As Double, y() As Double) As Double
Dim i As Long, j As Long
Dim Area As Double
 
  j = UBound(x())
  For i = LBound(x()) To UBound(x())
    Area = Area + (y(j) + y(i)) * (x(j) - x(i))
    j = i
  Next i
  ShoelaceArea = Abs(Area) / 2
End Function

Sub Main()
Dim v As Variant
Dim n As Long, i As Long, j As Long
  v = Array(3, 4, 5, 11, 12, 8, 9, 5, 5, 6)
  n = (UBound(v) - LBound(v) + 1) \ 2 - 1
  ReDim x(0 To n) As Double, y(0 To n) As Double
  j = 0
  For i = 0 To n
    x(i) = v(j)
    y(i) = v(j + 1)
    j = j + 2
  Next i
  Debug.Print ShoelaceArea(x(), y())
End Sub
Output:
30

Visual Basic .NET

Translation of: C#
Option Strict On

Imports Point = System.Tuple(Of Double, Double)

Module Module1

    Function ShoelaceArea(v As List(Of Point)) As Double
        Dim n = v.Count
        Dim a = 0.0
        For i = 0 To n - 2
            a += v(i).Item1 * v(i + 1).Item2 - v(i + 1).Item1 * v(i).Item2
        Next
        Return Math.Abs(a + v(n - 1).Item1 * v(0).Item2 - v(0).Item1 * v(n - 1).Item2) / 2.0
    End Function

    Sub Main()
        Dim v As New List(Of Point) From {
            New Point(3, 4),
            New Point(5, 11),
            New Point(12, 8),
            New Point(9, 5),
            New Point(5, 6)
        }
        Dim area = ShoelaceArea(v)
        Console.WriteLine("Given a polygon with vertices [{0}],", String.Join(", ", v))
        Console.WriteLine("its area is {0}.", area)
    End Sub

End Module
Output:
Given a polygon with vertices [(3, 4), (5, 11), (12, 8), (9, 5), (5, 6)],
its area is 30.

Wren

var shoelace = Fn.new { |pts|
    var area = 0
    for (i in 0...pts.count-1) {
        area = area + pts[i][0]*pts[i+1][1] - pts[i+1][0]*pts[i][1]
    }
    return (area + pts[-1][0]*pts[0][1] - pts[0][0]*pts[-1][1]).abs / 2
}

var pts = [ [3, 4], [5, 11], [12, 8], [9, 5], [5, 6] ]
System.print("The polygon with vertices at %(pts) has an area of %(shoelace.call(pts)).")
Output:
The polygon with vertices at [[3, 4], [5, 11], [12, 8], [9, 5], [5, 6]] has an area of 30.

XPL0

proc real Shoelace(N, X, Y);
int     N, X, Y;
int     S, I;
[S:= 0;
for I:= 0 to N-2 do
        S:= S + X(I)*Y(I+1) - X(I+1)*Y(I);
S:= S + X(I)*Y(0) - X(0)*Y(I);
return float(abs(S)) / 2.0;
];

RlOut(0, Shoelace(5, [3, 5, 12, 9, 5], [4, 11, 8, 5, 6]))
Output:
   30.00000

zkl

By the "book":

fcn areaByShoelace(points){	// ( (x,y),(x,y)...)
   xs,ys:=Utils.Helpers.listUnzip(points); // (x,x,...), (y,y,,,)
   ( xs.zipWith('*,ys[1,*]).sum(0) + xs[-1]*ys[0] - 
     xs[1,*].zipWith('*,ys).sum(0) - xs[0]*ys[-1] )
   .abs().toFloat()/2;
}

or an iterative solution:

fcn areaByShoelace2(points){	// ( (x,y),(x,y)...)
   xs,ys:=Utils.Helpers.listUnzip(points); // (x,x,...), (y,y,,,)
   N:=points.len();
   N.reduce('wrap(s,n){ s + xs[n]*ys[(n+1)%N] - xs[(n+1)%N]*ys[n] },0)
   .abs().toFloat()/2;
}
points:=T(T(3,4), T(5,11), T(12,8), T(9,5), T(5,6));
areaByShoelace(points).println();
areaByShoelace2(points).println();
Output:
30
30