Shoelace formula for polygonal area: Difference between revisions
m (→{{header|Wren}}: Changed to Wren S/H) |
|||
(24 intermediate revisions by 14 users not shown) | |||
Line 18: | Line 18: | ||
{{trans|Python}} |
{{trans|Python}} |
||
< |
<syntaxhighlight lang="11l">F area_by_shoelace(x, y) |
||
R abs(sum(zip(x, y[1..] [+] y[0.<1]).map((i, j) -> i * j)) |
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 |
-sum(zip(x[1..] [+] x[0.<1], y).map((i, j) -> i * j))) / 2 |
||
Line 26: | Line 26: | ||
V y = points.map(p -> p[1]) |
V y = points.map(p -> p[1]) |
||
print(area_by_shoelace(x, y))</ |
print(area_by_shoelace(x, y))</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 34: | Line 34: | ||
=={{header|360 Assembly}}== |
=={{header|360 Assembly}}== |
||
< |
<syntaxhighlight lang="360asm">* SHOELACE 25/02/2019 |
||
SHOELACE CSECT |
SHOELACE CSECT |
||
USING SHOELACE,R15 base register |
USING SHOELACE,R15 base register |
||
Line 59: | Line 59: | ||
PG DC CL12' ' buffer |
PG DC CL12' ' buffer |
||
REGEQU |
REGEQU |
||
END SHOELACE</ |
END SHOELACE</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
30 |
30 |
||
</pre> |
|||
=={{header|Action!}}== |
|||
{{libheader|Action! Tool Kit}} |
|||
{{libheader|Action! Real Math}} |
|||
<syntaxhighlight lang="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</syntaxhighlight> |
|||
{{out}} |
|||
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Shoelace_formula_for_polygonal_area.png Screenshot from Atari 8-bit computer] |
|||
<pre> |
|||
Polygon: (3,4), (5,11), (12,8), (9,5), (5,6) |
|||
Area: 30 |
|||
</pre> |
</pre> |
||
Line 68: | Line 141: | ||
{{works with|Ada|Ada|83}} |
{{works with|Ada|Ada|83}} |
||
< |
<syntaxhighlight lang="ada">with Ada.Text_IO; |
||
procedure Shoelace_Formula_For_Polygonal_Area |
procedure Shoelace_Formula_For_Polygonal_Area |
||
Line 99: | Line 172: | ||
begin |
begin |
||
Ada.Text_IO.Put_Line(Shoelace(my_polygon)'Img); |
Ada.Text_IO.Put_Line(Shoelace(my_polygon)'Img); |
||
end Shoelace_Formula_For_Polygonal_Area;</ |
end Shoelace_Formula_For_Polygonal_Area;</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> 3.00000E+01 |
<pre> 3.00000E+01 |
||
Line 155: | Line 228: | ||
=={{header|ALGOL 68}}== |
=={{header|ALGOL 68}}== |
||
< |
<syntaxhighlight lang="algol68">BEGIN |
||
# returns the area of the polygon defined by the points p using the Shoelace formula # |
# returns the area of the polygon defined by the points p using the Shoelace formula # |
||
OP AREA = ( [,]REAL p )REAL: |
OP AREA = ( [,]REAL p )REAL: |
||
Line 184: | Line 257: | ||
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 ) ) |
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 |
END |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 192: | Line 265: | ||
=={{header|APL}}== |
=={{header|APL}}== |
||
{{works with|Dyalog APL}} |
{{works with|Dyalog APL}} |
||
< |
<syntaxhighlight lang="apl">shoelace ← 2÷⍨|∘(((1⊃¨⊢)+.×1⌽2⊃¨⊢)-(1⌽1⊃¨⊢)+.×2⊃¨⊢)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> shoelace (3 4) (5 11) (12 8) (9 5) (5 6) |
<pre> shoelace (3 4) (5 11) (12 8) (9 5) (5 6) |
||
30</pre> |
30</pre> |
||
=={{header|Arturo}}== |
|||
<syntaxhighlight lang="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</syntaxhighlight> |
|||
{{out}} |
|||
<pre>30.0</pre> |
|||
=={{header|AutoHotkey}}== |
|||
<syntaxhighlight lang="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</syntaxhighlight> |
|||
{{out}} |
|||
<pre>30.000000</pre> |
|||
=={{header|BASIC256}}== |
|||
<syntaxhighlight lang="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</syntaxhighlight> |
|||
=={{header|C}}== |
=={{header|C}}== |
||
Reads the points from a file whose name is supplied via the command line, prints out usage if invoked incorrectly. |
Reads the points from a file whose name is supplied via the command line, prints out usage if invoked incorrectly. |
||
<syntaxhighlight lang="c"> |
|||
<lang C> |
|||
#include<stdlib.h> |
#include<stdlib.h> |
||
#include<stdio.h> |
#include<stdio.h> |
||
Line 247: | Line 376: | ||
return 0; |
return 0; |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
Input file, first line specifies number of points followed by the ordered vertices set with one vertex on each line. |
Input file, first line specifies number of points followed by the ordered vertices set with one vertex on each line. |
||
<pre> |
<pre> |
||
Line 265: | Line 394: | ||
=={{header|C sharp|C#}}== |
=={{header|C sharp|C#}}== |
||
{{trans|Java}} |
{{trans|Java}} |
||
< |
<syntaxhighlight lang="csharp">using System; |
||
using System.Collections.Generic; |
using System.Collections.Generic; |
||
Line 294: | Line 423: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>Given a polygon with vertices [(3, 4), (5, 11), (12, 8), (9, 5), (5, 6)], |
<pre>Given a polygon with vertices [(3, 4), (5, 11), (12, 8), (9, 5), (5, 6)], |
||
Line 301: | Line 430: | ||
=={{header|C++}}== |
=={{header|C++}}== |
||
{{trans|D}} |
{{trans|D}} |
||
< |
<syntaxhighlight lang="cpp">#include <iostream> |
||
#include <tuple> |
#include <tuple> |
||
#include <vector> |
#include <vector> |
||
Line 331: | Line 460: | ||
auto ans = shoelace(points); |
auto ans = shoelace(points); |
||
cout << ans << endl; |
cout << ans << endl; |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>30</pre> |
<pre>30</pre> |
||
=={{header|Cowgol}}== |
=={{header|Cowgol}}== |
||
< |
<syntaxhighlight lang="cowgol">include "cowgol.coh"; |
||
typedef Coord is uint16; # floating point types are not supported |
typedef Coord is uint16; # floating point types are not supported |
||
Line 374: | Line 503: | ||
var polygon: Point[] := {{3,4},{5,11},{12,8},{9,5},{5,6}}; |
var polygon: Point[] := {{3,4},{5,11},{12,8},{9,5},{5,6}}; |
||
print_i16(shoelace(&polygon[0], @sizeof polygon)); |
print_i16(shoelace(&polygon[0], @sizeof polygon)); |
||
print_nl();</ |
print_nl();</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>30</pre> |
<pre>30</pre> |
||
=={{header|D}}== |
=={{header|D}}== |
||
< |
<syntaxhighlight lang="d">import std.stdio; |
||
Point[] pnts = [{3,4}, {5,11}, {12,8}, {9,5}, {5,6}]; |
Point[] pnts = [{3,4}, {5,11}, {12,8}, {9,5}, {5,6}]; |
||
Line 407: | Line 536: | ||
auto ans = shoelace(pnts); |
auto ans = shoelace(pnts); |
||
assert(ans == 30); |
assert(ans == 30); |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>30</pre> |
<pre>30</pre> |
||
=={{header|Delphi}}== |
|||
{{works with|Delphi|6.0}} |
|||
{{libheader|SysUtils,StdCtrls}} |
|||
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. |
|||
<syntaxhighlight lang="Delphi"> |
|||
{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; |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
(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. |
|||
</pre> |
|||
=={{header|EasyLang}}== |
|||
<syntaxhighlight lang="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 |
|||
</syntaxhighlight> |
|||
=={{header|Elixir}}== |
|||
<syntaxhighlight lang="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 |
|||
</syntaxhighlight> |
|||
=={{header|F_Sharp|F#}}== |
=={{header|F_Sharp|F#}}== |
||
< |
<syntaxhighlight lang="fsharp"> |
||
// Shoelace formula for area of polygon. Nigel Galloway: April 11th., 2018 |
// 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α,gα),(nβ,gβ))->n+(nα*gβ)-(gα*nβ)) 0.0)/2.0 |
let fN(n::g) = abs(List.pairwise(n::g@[n])|>List.fold(fun n ((nα,gα),(nβ,gβ))->n+(nα*gβ)-(gα*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)])</ |
printfn "%f" (fN [(3.0,4.0); (5.0,11.0); (12.0,8.0); (9.0,5.0); (5.0,6.0)])</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 423: | Line 650: | ||
=={{header|Factor}}== |
=={{header|Factor}}== |
||
By constructing a <code>circular</code> 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 <code>2map</code> to cleanly obtain a sum. |
By constructing a <code>circular</code> 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 <code>2map</code> to cleanly obtain a sum. |
||
< |
<syntaxhighlight lang="factor">USING: circular kernel math prettyprint sequences ; |
||
IN: rosetta-code.shoelace |
IN: rosetta-code.shoelace |
||
Line 439: | Line 666: | ||
[ shoelace-sum ] 2bi@ - abs 2 / ; |
[ shoelace-sum ] 2bi@ - abs 2 / ; |
||
input shoelace-area .</ |
input shoelace-area .</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 449: | Line 676: | ||
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. |
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 <code>DOUBLE COMPLEX P(N)</code> 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]] < |
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 <code>DOUBLE COMPLEX P(N)</code> 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]] <syntaxhighlight lang="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 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 The area under that line (down to the x-axis) is the y-span midpoint (y1 + y2)/2 times the width (x2 - x1) |
||
Line 498: | Line 725: | ||
A2 = AREASL(5,POINT) |
A2 = AREASL(5,POINT) |
||
WRITE (6,*) "A=",A1,A2 |
WRITE (6,*) "A=",A1,A2 |
||
END</ |
END</syntaxhighlight> |
||
Output: WRITE (6,*) means write to output unit six (standard output) with free-format (the *). Note the different sign convention. |
Output: WRITE (6,*) means write to output unit six (standard output) with free-format (the *). Note the different sign convention. |
||
Line 512: | Line 739: | ||
===Fortran I=== |
===Fortran I=== |
||
In orginal FORTRAN 1957: |
In orginal FORTRAN 1957: |
||
< |
<syntaxhighlight lang="fortran"> |
||
C SHOELACE FORMULA FOR POLYGONAL AREA |
C SHOELACE FORMULA FOR POLYGONAL AREA |
||
DIMENSION X(33),Y(33) |
DIMENSION X(33),Y(33) |
||
Line 530: | Line 757: | ||
303 FORMAT(F10.2) |
303 FORMAT(F10.2) |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{in}} |
{{in}} |
||
<pre> |
<pre> |
||
Line 546: | Line 773: | ||
=={{header|FreeBASIC}}== |
=={{header|FreeBASIC}}== |
||
< |
<syntaxhighlight lang="freebasic">' version 18-08-2017 |
||
' compile with: fbc -s console |
' compile with: fbc -s console |
||
Line 578: | Line 805: | ||
Print : Print "hit any key to end program" |
Print : Print "hit any key to end program" |
||
Sleep |
Sleep |
||
End</ |
End</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>The area of the polygon = 30</pre> |
<pre>The area of the polygon = 30</pre> |
||
Line 584: | Line 811: | ||
=={{header|Fōrmulæ}}== |
=={{header|Fōrmulæ}}== |
||
{{FormulaeEntry|page=https://formulae.org/?script=examples/Shoelace_formula_for_polygonal_area}} |
|||
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. |
|||
'''Solution''' |
|||
Programs in Fōrmulæ are created/edited online in its [https://formulae.org website], However they run on execution servers. By default remote servers are used, but they are limited in memory and processing power, since they are intended for demonstration and casual use. A local server can be downloaded and installed, it has no limitations (it runs in your own computer). Because of that, example programs can be fully visualized and edited, but some of them will not run if they require a moderate or heavy computation/memory resources, and no local server is being used. |
|||
[[File:Fōrmulæ - Shoelace formula 01.png]] |
|||
In '''[https://formulae.org/?example=Shoelace_formula_for_polygonal_area this]''' page you can see the program(s) related to this task and their results. |
|||
'''Test case''' |
|||
[[File:Fōrmulæ - Shoelace formula 02.png]] |
|||
[[File:Fōrmulæ - Shoelace formula 03.png]] |
|||
=={{header|Go}}== |
=={{header|Go}}== |
||
< |
<syntaxhighlight lang="go">package main |
||
import "fmt" |
import "fmt" |
||
Line 609: | Line 842: | ||
func main() { |
func main() { |
||
fmt.Println(shoelace([]point{{3, 4}, {5, 11}, {12, 8}, {9, 5}, {5, 6}})) |
fmt.Println(shoelace([]point{{3, 4}, {5, 11}, {12, 8}, {9, 5}, {5, 6}})) |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 616: | Line 849: | ||
=={{header|Haskell}}== |
=={{header|Haskell}}== |
||
<syntaxhighlight lang="haskell">import Data.Bifunctor (bimap) |
|||
<lang Haskell>main :: IO () |
|||
main = print (shoelace [(3, 4), (5, 11), (12, 8), (9, 5), (5, 6)]) |
|||
----------- SHOELACE FORMULA FOR POLYGONAL AREA ---------- |
|||
-- The area of a polygon formed by the list of (x, y) coordinates. |
|||
-- The area of a polygon formed by |
|||
-- the list of (x, y) coordinates. |
|||
shoelace :: [(Double, Double)] -> Double |
shoelace :: [(Double, Double)] -> Double |
||
shoelace = |
shoelace = |
||
let calcSums (( |
let calcSums ((x, y), (a, b)) = bimap (x * b +) (a * y +) |
||
in (/ 2) |
in (/ 2) |
||
. abs |
|||
abs . uncurry (-) . foldr calcSums (0, 0) . (<*>) zip (tail . cycle)</lang> |
|||
. uncurry (-) |
|||
. foldr calcSums (0, 0) |
|||
. (<*>) zip (tail . cycle) |
|||
--------------------------- TEST ------------------------- |
|||
main :: IO () |
|||
main = |
|||
print $ |
|||
shoelace [(3, 4), (5, 11), (12, 8), (9, 5), (5, 6)]</syntaxhighlight> |
|||
{{out}} |
{{out}} |
||
<pre>30.0</pre> |
<pre>30.0</pre> |
||
Line 633: | Line 877: | ||
Implementation: |
Implementation: |
||
< |
<syntaxhighlight lang="j">shoelace=:verb define |
||
0.5*|+/((* 1&|.)/ - (* _1&|.)/)|:y |
0.5*|+/((* 1&|.)/ - (* _1&|.)/)|:y |
||
)</ |
)</syntaxhighlight> |
||
Task example: |
Task example: |
||
< |
<syntaxhighlight lang="j"> shoelace 3 4,5 11,12 8,9 5,:5 6 |
||
30</ |
30</syntaxhighlight> |
||
Exposition: |
Exposition: |
||
Line 646: | Line 890: | ||
We start with our list of coordinate pairs |
We start with our list of coordinate pairs |
||
< |
<syntaxhighlight lang="j"> 3 4,5 11,12 8,9 5,:5 6 |
||
3 4 |
3 4 |
||
5 11 |
5 11 |
||
12 8 |
12 8 |
||
9 5 |
9 5 |
||
5 6</ |
5 6</syntaxhighlight> |
||
But the first thing we do is transpose them so that x coordinates and y coordinates are the two items we are working with: |
But the first thing we do is transpose them so that x coordinates and y coordinates are the two items we are working with: |
||
< |
<syntaxhighlight lang="j"> |:3 4,5 11,12 8,9 5,:5 6 |
||
3 5 12 9 5 |
3 5 12 9 5 |
||
4 11 8 5 6</ |
4 11 8 5 6</syntaxhighlight> |
||
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: |
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: |
||
< |
<syntaxhighlight lang="j"> 3 5 12 9 5* 1|.4 11 8 5 6 |
||
33 40 60 54 20</ |
33 40 60 54 20</syntaxhighlight> |
||
Or, rephrased: |
Or, rephrased: |
||
< |
<syntaxhighlight lang="j"> (* 1&|.)/|:3 4,5 11,12 8,9 5,:5 6 |
||
33 40 60 54 20</ |
33 40 60 54 20</syntaxhighlight> |
||
We'll be subtracting what we get when we rotate in the other direction, which looks like this: |
We'll be subtracting what we get when we rotate in the other direction, which looks like this: |
||
< |
<syntaxhighlight lang="j"> ((* 1&|.)/ - (* _1&|.)/)|:3 4,5 11,12 8,9 5,:5 6 |
||
15 20 _72 _18 _5</ |
15 20 _72 _18 _5</syntaxhighlight> |
||
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. |
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. |
||
Line 679: | Line 923: | ||
{{trans|Kotlin}} |
{{trans|Kotlin}} |
||
{{works with|Java|9}} |
{{works with|Java|9}} |
||
< |
<syntaxhighlight lang="java">import java.util.List; |
||
public class ShoelaceFormula { |
public class ShoelaceFormula { |
||
Line 717: | Line 961: | ||
System.out.printf("its area is %f,%n", area); |
System.out.printf("its area is %f,%n", area); |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>Given a polygon with vertices [(3, 4), (5, 11), (12, 8), (9, 5), (5, 6)], |
<pre>Given a polygon with vertices [(3, 4), (5, 11), (12, 8), (9, 5), (5, 6)], |
||
Line 723: | Line 967: | ||
=={{header|JavaScript}}== |
=={{header|JavaScript}}== |
||
< |
<syntaxhighlight lang="javascript">(() => { |
||
"use strict"; |
|||
// ------- SHOELACE FORMULA FOR POLYGONAL AREA ------- |
|||
// shoelaceArea :: [(Float, Float)] -> Float |
// shoelaceArea :: [(Float, Float)] -> Float |
||
const shoeLaceArea = vertices => abs( |
const shoeLaceArea = vertices => abs( |
||
uncurry(subtract)( |
uncurry(subtract)( |
||
ap(zip)(compose(tail, cycle))( |
|||
vertices |
|||
) |
|||
b => a[int(b)] + x[0][int(b)] * x[1][int(!b)] |
|||
.reduce( |
|||
(a, x) => [0, 1].map(b => { |
|||
const n = Number(b); |
|||
vertices |
|||
return a[n] + ( |
|||
x[0][n] * x[1][Number(!b)] |
|||
); |
|||
}), |
|||
[0, 0] |
|||
) |
) |
||
) |
) |
||
Line 751: | Line 1,001: | ||
[5, 6] |
[5, 6] |
||
]; |
]; |
||
return unlines([ |
|||
return [ |
|||
'Polygonal area by shoelace formula:', |
|||
"Polygonal area by shoelace formula:", |
|||
`${JSON.stringify(ps)} -> ${shoeLaceArea(ps)}` |
|||
]); |
|||
] |
|||
.join("\n"); |
|||
}; |
}; |
||
Line 761: | Line 1,013: | ||
// abs :: Num -> Num |
// abs :: Num -> Num |
||
const abs = |
const abs = x => |
||
// Absolute value of a given number |
// Absolute value of a given number |
||
// without the sign. |
|||
0 > x ? -x : x; |
|||
// ap :: (a -> b -> c) -> (a -> b) -> a -> c |
// ap :: (a -> b -> c) -> (a -> b) -> (a -> c) |
||
const ap = f => |
const ap = f => |
||
// Applicative instance for functions. |
// Applicative instance for functions. |
||
Line 777: | Line 1,030: | ||
// compose (<<<) :: (b -> c) -> (a -> b) -> a -> c |
// compose (<<<) :: (b -> c) -> (a -> b) -> a -> c |
||
const compose = (...fs) => |
const compose = (...fs) => |
||
// A function defined by the right-to-left |
|||
// composition of all the functions in fs. |
|||
fs.reduce( |
fs.reduce( |
||
(f, g) => x => f(g(x)), |
(f, g) => x => f(g(x)), |
||
Line 784: | Line 1,039: | ||
// cycle :: [a] -> Generator [a] |
// cycle :: [a] -> Generator [a] |
||
function* |
const cycle = function* (xs) { |
||
// An infinite repetition of xs, |
|||
// from which an arbitrary prefix |
|||
// may be taken. |
|||
const lng = xs.length; |
const lng = xs.length; |
||
let i = 0; |
let i = 0; |
||
while (true) { |
while (true) { |
||
yield |
yield xs[i]; |
||
i = (1 + i) % lng; |
i = (1 + i) % lng; |
||
} |
} |
||
} |
}; |
||
// foldl :: (a -> b -> a) -> a -> [b] -> a |
|||
const foldl = f => |
|||
a => xs => xs.reduce((x, y) => f(x)(y), a); |
|||
// int :: Bool -> Int |
|||
const int = bln => |
|||
bln ? ( |
|||
1 |
|||
) : 0; |
|||
// length :: [a] -> Int |
// length :: [a] -> Int |
||
Line 810: | Line 1,059: | ||
// the shorter argument when one is non-finite, |
// the shorter argument when one is non-finite, |
||
// like cycle, repeat etc |
// like cycle, repeat etc |
||
"GeneratorFunction" !== xs.constructor |
|||
.constructor.name ? ( |
|||
xs.length |
xs.length |
||
) : Infinity; |
) : Infinity; |
||
// map :: (a -> b) -> [a] -> [b] |
|||
const map = f => |
|||
// The list obtained by applying f |
|||
// to each element of xs. |
|||
// (The image of xs under f). |
|||
xs => ( |
|||
Array.isArray(xs) ? ( |
|||
xs |
|||
) : xs.split('') |
|||
).map(f); |
|||
Line 836: | Line 1,074: | ||
// A new list consisting of all |
// A new list consisting of all |
||
// items of xs except the first. |
// items of xs except the first. |
||
"GeneratorFunction" !== xs.constructor |
|||
.constructor.name ? ( |
|||
Boolean(xs.length) ? ( |
|||
xs.slice(1) |
|||
) : undefined |
|||
) : (take(1)(xs), xs); |
) : (take(1)(xs), xs); |
||
Line 846: | Line 1,087: | ||
// The first n elements of a list, |
// The first n elements of a list, |
||
// string of characters, or stream. |
// string of characters, or stream. |
||
xs => |
xs => "GeneratorFunction" !== xs |
||
.constructor.constructor.name ? ( |
.constructor.constructor.name ? ( |
||
xs.slice(0, n) |
xs.slice(0, n) |
||
) : |
) : Array.from({ |
||
length: n |
length: n |
||
}, () => { |
}, () => { |
||
const x = xs.next(); |
const x = xs.next(); |
||
return x.done ? [] : [x.value]; |
return x.done ? [] : [x.value]; |
||
})); |
}).flat(); |
||
Line 861: | Line 1,103: | ||
// A function over a pair, derived |
// A function over a pair, derived |
||
// from a curried function. |
// from a curried function. |
||
(...args) => { |
|||
const |
const [x, y] = Boolean(args.length % 2) ? ( |
||
args |
args[0] |
||
) : args; |
|||
args[0] |
|||
return f(x)(y); |
|||
return f(xy[0])(xy[1]); |
|||
}; |
}; |
||
// |
// zip :: [a] -> [b] -> [(a, b)] |
||
const |
const zip = xs => ys => { |
||
const |
|||
// A single string formed by the intercalation |
|||
n = Math.min(length(xs), length(ys)), |
|||
// of a list of strings with the newline character. |
|||
vs = take(n)(ys); |
|||
return take(n)(xs) |
|||
.map((x, i) => [x, vs[i]]); |
|||
}; |
|||
// zip :: [a] -> [b] -> [(a, b)] |
|||
const zip = xs => |
|||
// Use of `take` and `length` here allows for zipping with non-finite |
|||
// lists - i.e. generators like cycle, repeat, iterate. |
|||
ys => { |
|||
const |
|||
lng = Math.min(length(xs), length(ys)), |
|||
vs = take(lng)(ys); |
|||
return take(lng)(xs).map( |
|||
(x, i) => [x, vs[i]] |
|||
); |
|||
}; |
|||
// MAIN --- |
// MAIN --- |
||
return main(); |
return main(); |
||
})();</ |
})();</syntaxhighlight> |
||
{{Out}} |
{{Out}} |
||
<pre>Polygonal area by shoelace formula: |
<pre>Polygonal area by shoelace formula: |
||
[[3,4],[5,11],[12,8],[9,5],[5,6]] -> 30</pre> |
[[3,4],[5,11],[12,8],[9,5],[5,6]] -> 30</pre> |
||
=={{header|jq}}== |
|||
{{works with|jq}} |
|||
'''Works with gojq, the Go implementation of jq''' |
|||
===={{trans|Wren}}==== |
|||
<syntaxhighlight lang="jq"># 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)."</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
The polygon with vertices at [[3,4],[5,11],[12,8],[9,5],[5,6]] has an area of 30. |
|||
</pre> |
|||
===={{trans|Julia}}==== |
|||
<syntaxhighlight lang="jq">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</syntaxhighlight> |
|||
{{out}} |
|||
As above. |
|||
=={{header|Julia}}== |
=={{header|Julia}}== |
||
Line 902: | Line 1,165: | ||
{{trans|Python}} |
{{trans|Python}} |
||
< |
<syntaxhighlight lang="julia">""" |
||
Assumes x,y points go around the polygon in one direction. |
Assumes x,y points go around the polygon in one direction. |
||
""" |
""" |
||
Line 910: | Line 1,173: | ||
x, y = [3, 5, 12, 9, 5], [4, 11, 8, 5, 6] |
x, y = [3, 5, 12, 9, 5], [4, 11, 8, 5, 6] |
||
@show x y shoelacearea(x, y)</ |
@show x y shoelacearea(x, y)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 918: | Line 1,181: | ||
=={{header|Kotlin}}== |
=={{header|Kotlin}}== |
||
< |
<syntaxhighlight lang="scala">// version 1.1.3 |
||
class Point(val x: Int, val y: Int) { |
class Point(val x: Int, val y: Int) { |
||
Line 940: | Line 1,203: | ||
println("Given a polygon with vertices at $v,") |
println("Given a polygon with vertices at $v,") |
||
println("its area is $area") |
println("its area is $area") |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 949: | Line 1,212: | ||
=={{header|Lambdatalk}}== |
=={{header|Lambdatalk}}== |
||
< |
<syntaxhighlight lang="scheme"> |
||
{def shoelace |
{def shoelace |
||
{lambda {:pol} |
{lambda {:pol} |
||
Line 977: | Line 1,240: | ||
{shoelace {pol}} |
{shoelace {pol}} |
||
-> 30 |
-> 30 |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Lua}}== |
=={{header|Lua}}== |
||
< |
<syntaxhighlight lang="lua">function shoeArea(ps) |
||
local function det2(i,j) |
local function det2(i,j) |
||
return ps[i][1]*ps[j][2]-ps[j][1]*ps[i][2] |
return ps[i][1]*ps[j][2]-ps[j][1]*ps[i][2] |
||
Line 987: | Line 1,250: | ||
for i=1,#ps-1 do sum = sum + det2(i,i+1)end |
for i=1,#ps-1 do sum = sum + det2(i,i+1)end |
||
return math.abs(0.5 * sum) |
return math.abs(0.5 * sum) |
||
end</ |
end</syntaxhighlight> |
||
Using an accumulator helper inner function |
Using an accumulator helper inner function |
||
< |
<syntaxhighlight lang="lua">function shoeArea(ps) |
||
local function ssum(acc, p1, p2, ...) |
local function ssum(acc, p1, p2, ...) |
||
if not p2 or not p1 then |
if not p2 or not p1 then |
||
Line 1,001: | Line 1,264: | ||
local p = {{3,4}, {5,11}, {12,8}, {9,5}, {5,6}} |
local p = {{3,4}, {5,11}, {12,8}, {9,5}, {5,6}} |
||
print(shoeArea(p))-- 30 </ |
print(shoeArea(p))-- 30 </syntaxhighlight> |
||
both version handle special cases of less than 3 point as 0 area result. |
both version handle special cases of less than 3 point as 0 area result. |
||
=={{header|Maple}}== |
=={{header|Maple}}== |
||
<syntaxhighlight lang="maple"> |
|||
<lang Maple> |
|||
with(ArrayTools): |
with(ArrayTools): |
||
Line 1,066: | Line 1,329: | ||
P1 := Polygon(Array([Point(3,4), Point(5,11), Point(12,8), Point(9,5), Point(5,6)])): |
P1 := Polygon(Array([Point(3,4), Point(5,11), Point(12,8), Point(9,5), Point(5,6)])): |
||
area(P1); |
area(P1); |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}}<pre> |
{{out}}<pre> |
||
Line 1,074: | Line 1,337: | ||
=={{header|Mathematica}}/{{header|Wolfram Language}}== |
=={{header|Mathematica}}/{{header|Wolfram Language}}== |
||
Geometry objects built-in in the Wolfram Language |
Geometry objects built-in in the Wolfram Language |
||
< |
<syntaxhighlight lang="mathematica">Area[Polygon[{{3, 4}, {5, 11}, {12, 8}, {9, 5}, {5, 6}}]]</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>30</pre> |
<pre>30</pre> |
||
Line 1,080: | Line 1,343: | ||
=={{header|min}}== |
=={{header|min}}== |
||
{{works with|min|0.19.3}} |
{{works with|min|0.19.3}} |
||
< |
<syntaxhighlight lang="min">((((first) map) ((last) map)) cleave) :dezip |
||
(((first) (rest)) cleave append) :rotate |
(((first) (rest)) cleave append) :rotate |
||
((0 <) (-1 *) when) :abs |
((0 <) (-1 *) when) :abs |
||
Line 1,100: | Line 1,363: | ||
) :shoelace |
) :shoelace |
||
((3 4) (5 11) (12 8) (9 5) (5 6)) shoelace print</ |
((3 4) (5 11) (12 8) (9 5) (5 6)) shoelace print</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 1,107: | Line 1,370: | ||
=={{header|MiniScript}}== |
=={{header|MiniScript}}== |
||
< |
<syntaxhighlight lang="miniscript">shoelace = function(vertices) |
||
sum = 0 |
sum = 0 |
||
points = vertices.len |
points = vertices.len |
||
Line 1,127: | Line 1,390: | ||
print "The polygon area is " + shoelace(verts) |
print "The polygon area is " + shoelace(verts) |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 1,134: | Line 1,397: | ||
=={{header|Modula-2}}== |
=={{header|Modula-2}}== |
||
< |
<syntaxhighlight lang="modula2">MODULE ShoelaceFormula; |
||
FROM RealStr IMPORT RealToStr; |
FROM RealStr IMPORT RealToStr; |
||
FROM FormatString IMPORT FormatString; |
FROM FormatString IMPORT FormatString; |
||
Line 1,189: | Line 1,452: | ||
ReadChar; |
ReadChar; |
||
END ShoelaceFormula.</ |
END ShoelaceFormula.</syntaxhighlight> |
||
=={{header|Nim}}== |
=={{header|Nim}}== |
||
< |
<syntaxhighlight lang="nim">type |
||
Point = tuple |
Point = tuple |
||
x: float |
x: float |
||
Line 1,207: | Line 1,470: | ||
var points = [(3.0, 4.0), (5.0, 11.0), (12.0, 8.0), (9.0, 5.0), (5.0, 6.0)] |
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)</ |
echo shoelace(points)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,214: | Line 1,477: | ||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
< |
<syntaxhighlight lang="perl">use strict; |
||
use warnings; |
use warnings; |
||
use feature 'say'; |
use feature 'say'; |
||
Line 1,232: | Line 1,495: | ||
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 ); |
||
say area_by_shoelace( \@poly );</ |
say area_by_shoelace( \@poly );</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>30 |
<pre>30 |
||
Line 1,240: | Line 1,503: | ||
=={{header|Phix}}== |
=={{header|Phix}}== |
||
<!--<syntaxhighlight lang="phix">(phixonline)--> |
|||
<lang Phix>enum X, Y |
|||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
|||
function shoelace(sequence s) |
|||
<span style="color: #008080;">enum</span> <span style="color: #000000;">X</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">Y</span> |
|||
atom t = 0 |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">shoelace</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> |
|||
if length(s)>2 then |
|||
<span style="color: #004080;">atom</span> <span style="color: #000000;">t</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span> |
|||
s = append(s,s[1]) |
|||
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)></span><span style="color: #000000;">2</span> <span style="color: #008080;">then</span> |
|||
for i=1 to length(s)-1 do |
|||
<span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">deep_copy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">),</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span> |
|||
t += s[i][X]*s[i+1][Y] - s[i+1][X]*s[i][Y] |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span> |
|||
end for |
|||
<span style="color: #000000;">t</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">X</span><span style="color: #0000FF;">]*</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">][</span><span style="color: #000000;">Y</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">][</span><span style="color: #000000;">X</span><span style="color: #0000FF;">]*</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">][</span><span style="color: #000000;">Y</span><span style="color: #0000FF;">]</span> |
|||
end if |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
return abs(t)/2 |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
end function |
|||
<span style="color: #008080;">return</span> <span style="color: #7060A8;">abs</span><span style="color: #0000FF;">(</span><span style="color: #000000;">t</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
constant test = {{3,4},{5,11},{12,8},{9,5},{5,6}} |
|||
?shoelace(test)</lang> |
|||
<span style="color: #008080;">constant</span> <span style="color: #000000;">test</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #000000;">11</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">12</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">9</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6</span><span style="color: #0000FF;">}}</span> |
|||
<span style="color: #0000FF;">?</span><span style="color: #000000;">shoelace</span><span style="color: #0000FF;">(</span><span style="color: #000000;">test</span><span style="color: #0000FF;">)</span> |
|||
<!--</syntaxhighlight>--> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 1,259: | Line 1,525: | ||
</pre> |
</pre> |
||
An alternative solution, which does not need the X,Y enum, and gives the same output: |
An alternative solution, which does not need the X,Y enum, and gives the same output: |
||
<!--<syntaxhighlight lang="phix">(phixonline)--> |
|||
<lang Phix>function shoelace(sequence s) |
|||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
|||
atom t = 0 |
|||
<span style="color: #008080;">function</span> <span style="color: #000000;">shoelace</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> |
|||
integer j = length(s) |
|||
<span style="color: #004080;">atom</span> <span style="color: #000000;">t</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span> |
|||
if j!=0 then |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">j</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> |
|||
sequence {x,y} = columnize(s) |
|||
<span style="color: #008080;">if</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> |
|||
for i=1 to j do |
|||
<span style="color: #004080;">sequence</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">y</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">columnize</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> |
|||
t += (y[j] + y[i]) * (x[j] - x[i]) |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">j</span> <span style="color: #008080;">do</span> |
|||
j = i |
|||
<span style="color: #000000;">t</span> <span style="color: #0000FF;">+=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">y</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span> <span style="color: #0000FF;">*</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">x</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span> |
|||
end for |
|||
<span style="color: #000000;">j</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">i</span> |
|||
end if |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
return abs(t)/2 |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span> |
|||
end function</lang> |
|||
<span style="color: #008080;">return</span> <span style="color: #7060A8;">abs</span><span style="color: #0000FF;">(</span><span style="color: #000000;">t</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span> |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span> |
|||
<span style="color: #008080;">constant</span> <span style="color: #000000;">test</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #000000;">11</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">12</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">9</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">},{</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6</span><span style="color: #0000FF;">}}</span> |
|||
<span style="color: #0000FF;">?</span><span style="color: #000000;">shoelace</span><span style="color: #0000FF;">(</span><span style="color: #000000;">test</span><span style="color: #0000FF;">)</span> |
|||
<!--</syntaxhighlight>--> |
|||
=={{header|PowerBASIC}}== |
=={{header|PowerBASIC}}== |
||
{{Trans|Visual Basic}} |
{{Trans|Visual Basic}} |
||
< |
<syntaxhighlight lang="powerbasic">#COMPILE EXE |
||
#DIM ALL |
#DIM ALL |
||
#COMPILER PBCC 6 |
#COMPILER PBCC 6 |
||
Line 1,296: | Line 1,568: | ||
CON.PRINT STR$(ShoelaceArea(x(), y())) |
CON.PRINT STR$(ShoelaceArea(x(), y())) |
||
CON.WAITKEY$ |
CON.WAITKEY$ |
||
END FUNCTION</ |
END FUNCTION</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>30</pre> |
<pre>30</pre> |
||
=={{header|Python}}== |
=={{header|Python}}== |
||
===Python: Explicit=== |
|||
<lang python>>>> def area_by_shoelace(x, y): |
|||
<syntaxhighlight lang="python">>>> def area_by_shoelace(x, y): |
|||
"Assumes x,y points go around the polygon in one direction" |
"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])) |
return abs( sum(i * j for i, j in zip(x, y[1:] + y[:1])) |
||
Line 1,311: | Line 1,584: | ||
30.0 |
30.0 |
||
>>> |
>>> |
||
</syntaxhighlight> |
|||
===Python: numpy=== |
|||
<syntaxhighlight lang="python"> |
|||
# Even simpler: |
# 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]. |
# In python we can take an advantage of that x[-1] refers to the last element in an array, same as x[N-1]. |
||
Line 1,333: | Line 1,610: | ||
# before applying the Shoelace formula. |
# before applying the Shoelace formula. |
||
</syntaxhighlight> |
|||
===Python: Defined in terms of reduce and cycle=== |
|||
</lang> |
|||
Or, defined in terms of '''reduce''' and '''cycle''': |
|||
{{Trans|Haskell}} |
{{Trans|Haskell}} |
||
{{Works with|Python|3.7}} |
{{Works with|Python|3.7}} |
||
< |
<syntaxhighlight lang="python">'''Polygonal area by shoelace formula''' |
||
from itertools import cycle, islice |
from itertools import cycle, islice |
||
Line 1,381: | Line 1,654: | ||
if __name__ == '__main__': |
if __name__ == '__main__': |
||
main()</ |
main()</syntaxhighlight> |
||
{{Out}} |
{{Out}} |
||
<pre>Polygonal area by shoelace formula: |
<pre>Polygonal area by shoelace formula: |
||
[(3, 4), (5, 11), (12, 8), (9, 5), (5, 6)] -> 30.0</pre> |
[(3, 4), (5, 11), (12, 8), (9, 5), (5, 6)] -> 30.0</pre> |
||
===Python: Alternate=== |
|||
This adopts the ''indexing'' used in the numpy example above, but does not require the numpy library. |
|||
<syntaxhighlight lang="python">>>> 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 |
|||
>>> </syntaxhighlight> |
|||
=={{header|Racket}}== |
=={{header|Racket}}== |
||
< |
<syntaxhighlight lang="racket">#lang racket/base |
||
(struct P (x y)) |
(struct P (x y)) |
||
Line 1,400: | Line 1,684: | ||
(module+ main |
(module+ main |
||
(area (P 3 4) (P 5 11) (P 12 8) (P 9 5) (P 5 6)))</ |
(area (P 3 4) (P 5 11) (P 12 8) (P 9 5) (P 5 6)))</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,410: | Line 1,694: | ||
{{works with|Rakudo|2017.07}} |
{{works with|Rakudo|2017.07}} |
||
<lang |
<syntaxhighlight lang="raku" line>sub area-by-shoelace(@p) { |
||
(^@p).map({@p[$_;0] * @p[($_+1)%@p;1] - @p[$_;1] * @p[($_+1)%@p;0]}).sum.abs / 2 |
(^@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) ] );</ |
say area-by-shoelace( [ (3,4), (5,11), (12,8), (9,5), (5,6) ] );</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>30</pre> |
<pre>30</pre> |
||
Line 1,420: | Line 1,704: | ||
===Slice and rotation=== |
===Slice and rotation=== |
||
{{works with|Rakudo|2017.07}} |
{{works with|Rakudo|2017.07}} |
||
<lang |
<syntaxhighlight lang="raku" line>sub area-by-shoelace ( @p ) { |
||
my @x := @p».[0]; |
my @x := @p».[0]; |
||
my @y := @p».[1]; |
my @y := @p».[1]; |
||
Line 1,431: | Line 1,715: | ||
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) ] ); |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre>30</pre> |
<pre>30</pre> |
||
Line 1,438: | Line 1,722: | ||
<!-- |
<!-- |
||
===endpoints as exceptions=== |
===endpoints as exceptions=== |
||
< |
<syntaxhighlight lang="rexx">/*REXX program uses a Shoelace formula to calculate the area of an N-sided polygon. */ |
||
parse arg pts; $polygon = 'polygon area of ' /*get optional args from the CL.*/ |
parse arg pts; $polygon = 'polygon area of ' /*get optional args from the CL.*/ |
||
if pts='' then pts= '(3,4),(5,11),(12,8),(9,5),(5,6)' /*Not specified? Use default. */ |
if pts='' then pts= '(3,4),(5,11),(12,8),(9,5),(5,6)' /*Not specified? Use default. */ |
||
Line 1,450: | Line 1,734: | ||
A=A + x.j * (y.jp - y.jm) /*compute a part of the area. */ |
A=A + x.j * (y.jp - y.jm) /*compute a part of the area. */ |
||
end /*j*/ |
end /*j*/ |
||
say $polygon # " points: " pts ' is ───► ' abs(A/2) /*stick a fork in it, we're done*/</ |
say $polygon # " points: " pts ' is ───► ' abs(A/2) /*stick a fork in it, we're done*/</syntaxhighlight> |
||
{{out|output|text= when using the default input:}} |
{{out|output|text= when using the default input:}} |
||
<pre> |
<pre> |
||
Line 1,458: | Line 1,742: | ||
=== wrap-around endpoints === |
=== wrap-around endpoints === |
||
< |
<syntaxhighlight lang="rexx">/*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?*/ |
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.*/ |
A= 0; @= space($, 0) /*init A; elide blanks from pts.*/ |
||
Line 1,466: | Line 1,750: | ||
do j=1 for #; jm= j-1; jp= j+1; A= A + x.j*(y.jm - y.jp) /*portion of area*/ |
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*/ |
end /*j*/ /*stick a fork in it, we're done*/ |
||
say 'polygon area of ' # " points: " $ ' is ───► ' abs(A/2)</ |
say 'polygon area of ' # " points: " $ ' is ───► ' abs(A/2)</syntaxhighlight> |
||
{{out|output|text= when using the default input:}} |
{{out|output|text= when using the default input:}} |
||
<pre> |
<pre> |
||
Line 1,474: | Line 1,758: | ||
===somewhat simplified=== |
===somewhat simplified=== |
||
reformatted and suitable for ooRexx. (x.0 etc. not needed) |
reformatted and suitable for ooRexx. (x.0 etc. not needed) |
||
<lang>/*REXX program uses a Shoelace formula to calculate the area of an N-sided polygon. */ |
<syntaxhighlight lang="text">/*REXX program uses a Shoelace formula to calculate the area of an N-sided polygon. */ |
||
parse arg pts /*obtain optional arguments from the CL*/ |
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. */ |
if pts='' then pts= '(3,4),(5,11),(12,8),(9,5),(5,6)' /*Not specified? Use default. */ |
||
Line 1,490: | Line 1,774: | ||
end |
end |
||
A=abs(A/2) /*obtain half of the ¦ A ¦ sum*/ |
A=abs(A/2) /*obtain half of the ¦ A ¦ sum*/ |
||
say 'polygon area of' n 'points:' pts 'is --->' A</ |
say 'polygon area of' n 'points:' pts 'is --->' A</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>polygon area of 5 points: (3,4),(5,11),(12,8),(9,5),(5,6) is ---> 30</pre> |
<pre>polygon area of 5 points: (3,4),(5,11),(12,8),(9,5),(5,6) is ---> 30</pre> |
||
Line 1,496: | Line 1,780: | ||
===even simpler=== |
===even simpler=== |
||
Using the published algorithm |
Using the published algorithm |
||
<lang>/*REXX program uses a Shoelace formula to calculate the area of an N-sided polygon. */ |
<syntaxhighlight lang="text">/*REXX program uses a Shoelace formula to calculate the area of an N-sided polygon. */ |
||
parse arg pts /*obtain optional arguments from the CL*/ |
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. */ |
if pts='' then pts= '(3,4),(5,11),(12,8),(9,5),(5,6)' /*Not specified? Use default. */ |
||
Line 1,510: | Line 1,794: | ||
a=a+x.n*y.1-x.1*y.n |
a=a+x.n*y.1-x.1*y.n |
||
a=abs(a)/2 |
a=abs(a)/2 |
||
say 'polygon area of' n 'points:' pts 'is --->' a</ |
say 'polygon area of' n 'points:' pts 'is --->' a</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>polygon area of 5 points: (3,4),(5,11),(12,8),(9,5),(5,6) is ---> 30</pre> |
<pre>polygon area of 5 points: (3,4),(5,11),(12,8),(9,5),(5,6) is ---> 30</pre> |
||
=={{header|Ring}}== |
=={{header|Ring}}== |
||
< |
<syntaxhighlight lang="ring"> |
||
# Project : Shoelace formula for polygonal area |
# Project : Shoelace formula for polygonal area |
||
Line 1,530: | Line 1,814: | ||
sum = sum - p[1][1] * p[i][2] |
sum = sum - p[1][1] * p[i][2] |
||
return fabs(sum) / 2 |
return fabs(sum) / 2 |
||
</syntaxhighlight> |
|||
</lang> |
|||
Output: |
Output: |
||
<pre> |
<pre> |
||
The area of the polygon = 30 |
The area of the polygon = 30 |
||
</pre> |
|||
=={{header|RPL}}== |
|||
{| class="wikitable" |
|||
! 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 |
|||
≫ <span style="color:blue">''''SHOEL''''</span> STO |
|||
| |
|||
<span style="color:blue">'''SHOEL'''</span> ''( { (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)} <span style="color:blue">'''SHOEL'''</span> |
|||
{{out}} |
|||
<pre> |
|||
1: 30 |
|||
</pre> |
</pre> |
||
=={{header|Ruby}}== |
=={{header|Ruby}}== |
||
< |
<syntaxhighlight lang="ruby"> |
||
Point = Struct.new(:x,:y) do |
Point = Struct.new(:x,:y) do |
||
Line 1,560: | Line 1,874: | ||
puts Polygon.new([3,4], [5,11], [12,8], [9,5], [5,6]).area # => 30.0 |
puts Polygon.new([3,4], [5,11], [12,8], [9,5], [5,6]).area # => 30.0 |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Scala}}== |
=={{header|Scala}}== |
||
< |
<syntaxhighlight lang="scala">case class Point( x:Int,y:Int ) { override def toString = "(" + x + "," + y + ")" } |
||
case class Polygon( pp:List[Point] ) { |
case class Polygon( pp:List[Point] ) { |
||
Line 1,590: | Line 1,904: | ||
println( "Area of " + p + " = " + p.area ) |
println( "Area of " + p + " = " + p.area ) |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre>Area of Polygon( (3,4), (5,11), (12,8), (9,5), (5,6) ) = 30.0</pre> |
<pre>Area of Polygon( (3,4), (5,11), (12,8), (9,5), (5,6) ) = 30.0</pre> |
||
Line 1,596: | Line 1,910: | ||
=={{header|Sidef}}== |
=={{header|Sidef}}== |
||
{{trans|Raku}} |
{{trans|Raku}} |
||
< |
<syntaxhighlight lang="ruby">func area_by_shoelace (*p) { |
||
var x = p.map{_[0]} |
var x = p.map{_[0]} |
||
var y = p.map{_[1]} |
var y = p.map{_[1]} |
||
Line 1,608: | Line 1,922: | ||
} |
} |
||
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])</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 1,618: | Line 1,932: | ||
{{trans|Scala}} |
{{trans|Scala}} |
||
< |
<syntaxhighlight lang="swift">import Foundation |
||
struct Point { |
struct Point { |
||
Line 1,660: | Line 1,974: | ||
]) |
]) |
||
print("\(poly) area = \(poly.area)")</ |
print("\(poly) area = \(poly.area)")</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,668: | Line 1,982: | ||
=={{header|TI-83 BASIC}}== |
=={{header|TI-83 BASIC}}== |
||
{{works with|TI-83 BASIC|TI-84Plus 2.55MP}} |
{{works with|TI-83 BASIC|TI-84Plus 2.55MP}} |
||
< |
<syntaxhighlight lang="ti83b">[[3,4][5,11][12,8][9,5][5,6]]->[A] |
||
Dim([A])->N:0->A |
Dim([A])->N:0->A |
||
For(I,1,N) |
For(I,1,N) |
||
Line 1,674: | Line 1,988: | ||
A+[A](I,1)*[A](J,2)-[A](J,1)*[A](I,2)->A |
A+[A](I,1)*[A](J,2)-[A](J,1)*[A](I,2)->A |
||
End |
End |
||
Abs(A)/2->A</ |
Abs(A)/2->A</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 1,681: | Line 1,995: | ||
=={{header|VBA}}== |
=={{header|VBA}}== |
||
{{trans|Phix}}< |
{{trans|Phix}}<syntaxhighlight lang="vb">Option Base 1 |
||
Public Enum axes |
Public Enum axes |
||
u = 1 |
u = 1 |
||
Line 1,705: | Line 2,019: | ||
Next i |
Next i |
||
Debug.Print shoelace(tcol) |
Debug.Print shoelace(tcol) |
||
End Sub</ |
End Sub</syntaxhighlight>{{out}} |
||
<pre>30</pre> |
<pre>30</pre> |
||
=={{header|VBScript}}== |
=={{header|VBScript}}== |
||
< |
<syntaxhighlight lang="vb">' Shoelace formula for polygonal area - VBScript |
||
Dim points, x(),y() |
Dim points, x(),y() |
||
points = Array(3,4, 5,11, 12,8, 9,5, 5,6) |
points = Array(3,4, 5,11, 12,8, 9,5, 5,6) |
||
Line 1,726: | Line 2,040: | ||
Next 'i |
Next 'i |
||
area = Abs(area)/2 |
area = Abs(area)/2 |
||
msgbox area,,"Shoelace formula" </ |
msgbox area,,"Shoelace formula" </syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 1,738: | Line 2,052: | ||
{{works with|VBA|6.5}} |
{{works with|VBA|6.5}} |
||
{{works with|VBA|7.1}} |
{{works with|VBA|7.1}} |
||
< |
<syntaxhighlight lang="vb">Option Explicit |
||
Public Function ShoelaceArea(x() As Double, y() As Double) As Double |
Public Function ShoelaceArea(x() As Double, y() As Double) As Double |
||
Line 1,765: | Line 2,079: | ||
Next i |
Next i |
||
Debug.Print ShoelaceArea(x(), y()) |
Debug.Print ShoelaceArea(x(), y()) |
||
End Sub</ |
End Sub</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>30</pre> |
<pre>30</pre> |
||
Line 1,771: | Line 2,085: | ||
=={{header|Visual Basic .NET}}== |
=={{header|Visual Basic .NET}}== |
||
{{trans|C#}} |
{{trans|C#}} |
||
< |
<syntaxhighlight lang="vbnet">Option Strict On |
||
Imports Point = System.Tuple(Of Double, Double) |
Imports Point = System.Tuple(Of Double, Double) |
||
Line 1,799: | Line 2,113: | ||
End Sub |
End Sub |
||
End Module</ |
End Module</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>Given a polygon with vertices [(3, 4), (5, 11), (12, 8), (9, 5), (5, 6)], |
<pre>Given a polygon with vertices [(3, 4), (5, 11), (12, 8), (9, 5), (5, 6)], |
||
Line 1,805: | Line 2,119: | ||
=={{header|Wren}}== |
=={{header|Wren}}== |
||
< |
<syntaxhighlight lang="wren">var shoelace = Fn.new { |pts| |
||
var area = 0 |
var area = 0 |
||
for (i in 0...pts.count-1) { |
for (i in 0...pts.count-1) { |
||
Line 1,814: | Line 2,128: | ||
var pts = [ [3, 4], [5, 11], [12, 8], [9, 5], [5, 6] ] |
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)).")</ |
System.print("The polygon with vertices at %(pts) has an area of %(shoelace.call(pts)).")</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,822: | Line 2,136: | ||
=={{header|XPL0}}== |
=={{header|XPL0}}== |
||
< |
<syntaxhighlight lang="xpl0">proc real Shoelace(N, X, Y); |
||
int N, X, Y; |
int N, X, Y; |
||
int S, I; |
int S, I; |
||
Line 1,832: | Line 2,146: | ||
]; |
]; |
||
RlOut(0, Shoelace(5, [3, 5, 12, 9, 5], [4, 11, 8, 5, 6]))</ |
RlOut(0, Shoelace(5, [3, 5, 12, 9, 5], [4, 11, 8, 5, 6]))</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,841: | Line 2,155: | ||
=={{header|zkl}}== |
=={{header|zkl}}== |
||
By the "book": |
By the "book": |
||
< |
<syntaxhighlight lang="zkl">fcn areaByShoelace(points){ // ( (x,y),(x,y)...) |
||
xs,ys:=Utils.Helpers.listUnzip(points); // (x,x,...), (y,y,,,) |
xs,ys:=Utils.Helpers.listUnzip(points); // (x,x,...), (y,y,,,) |
||
( xs.zipWith('*,ys[1,*]).sum(0) + xs[-1]*ys[0] - |
( xs.zipWith('*,ys[1,*]).sum(0) + xs[-1]*ys[0] - |
||
xs[1,*].zipWith('*,ys).sum(0) - xs[0]*ys[-1] ) |
xs[1,*].zipWith('*,ys).sum(0) - xs[0]*ys[-1] ) |
||
.abs().toFloat()/2; |
.abs().toFloat()/2; |
||
}</ |
}</syntaxhighlight> |
||
or an iterative solution: |
or an iterative solution: |
||
< |
<syntaxhighlight lang="zkl">fcn areaByShoelace2(points){ // ( (x,y),(x,y)...) |
||
xs,ys:=Utils.Helpers.listUnzip(points); // (x,x,...), (y,y,,,) |
xs,ys:=Utils.Helpers.listUnzip(points); // (x,x,...), (y,y,,,) |
||
N:=points.len(); |
N:=points.len(); |
||
N.reduce('wrap(s,n){ s + xs[n]*ys[(n+1)%N] - xs[(n+1)%N]*ys[n] },0) |
N.reduce('wrap(s,n){ s + xs[n]*ys[(n+1)%N] - xs[(n+1)%N]*ys[n] },0) |
||
.abs().toFloat()/2; |
.abs().toFloat()/2; |
||
}</ |
}</syntaxhighlight> |
||
< |
<syntaxhighlight lang="zkl">points:=T(T(3,4), T(5,11), T(12,8), T(9,5), T(5,6)); |
||
areaByShoelace(points).println(); |
areaByShoelace(points).println(); |
||
areaByShoelace2(points).println();</ |
areaByShoelace2(points).println();</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
Latest revision as of 15:37, 5 February 2024
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
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
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
shoelace ← 2÷⍨|∘(((1⊃¨⊢)+.×1⌽2⊃¨⊢)-(1⌽1⊃¨⊢)+.×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#
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++
#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
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α,gα),(nβ,gβ))->n+(nα*gβ)-(gα*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
Test case
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
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 gojq, the Go implementation of jq
# 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.
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
"""
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
((((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
#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
'''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
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
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
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
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
[[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
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
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
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
- Programming Tasks
- Solutions by Programming Task
- 11l
- 360 Assembly
- Action!
- Action! Tool Kit
- Action! Real Math
- Ada
- ALGOL 60
- ALGOL 68
- APL
- Arturo
- AutoHotkey
- BASIC256
- C
- C sharp
- C++
- Cowgol
- D
- Delphi
- SysUtils,StdCtrls
- EasyLang
- Elixir
- F Sharp
- Factor
- Fortran
- FreeBASIC
- Fōrmulæ
- Go
- Haskell
- J
- Java
- JavaScript
- Jq
- Julia
- Kotlin
- Lambdatalk
- Lua
- Maple
- Mathematica
- Wolfram Language
- Min
- MiniScript
- Modula-2
- Nim
- Perl
- Phix
- PowerBASIC
- Python
- Racket
- Raku
- REXX
- Ring
- RPL
- Ruby
- Scala
- Sidef
- Swift
- TI-83 BASIC
- VBA
- VBScript
- Visual Basic
- Visual Basic .NET
- Wren
- XPL0
- Zkl