What is the area of this polygon?

19

1

Calculate the area of a polygon.

Inspired by this shoelace algorithm video.

Task

Your job is to create a program or function that calculates the area of a polygon. Program or function is defined according the the default definition in meta.

Input

You will receive the X and Y coordinates of each vertex of the polygon. You can take the input as a list of tuples ([[x1, y1], [x2, y2], etc]), a matrix, or a flat list ([x1, y1, x2, y2, etc]). Two lists containing x and y coordinates respectively are allowed as well. The vertices are numbered counterclockwise and the first vertex is the same as the last vertex provided, thus closing the polygon.

If you want you can take the input without the last vertex (so receive each coordinate just once).

You can assume that the edges of the polygons don't intersect. You can also assume that all vertices have integer coordinates.

Output

The area of the polygon. All standard output methods are allowed. If your language does not allow for float division and the solution would not be an integer, you are allowed to return a fraction. The fraction does not necessarily have to be simplified, so returning 2/4 would be allowed.

Winning criterium

Shortest code wins!

Test cases

[[4,4],[0,1],[-2,5],[-6,0],[-1,-4],[5,-2],[4,4]]
55

enter image description here

[[1,1],[0,1],[1,0],[1,1]]
0.5
1/2

enter image description here

JAD

Posted 2017-06-14T13:25:04.107

Reputation: 2 898

Is input like [x1, x2, x3], [y1, y2, y3] allowed? – programmer5000 – 2017-06-14T13:34:07.713

@programmer5000 and Martin Ender , yes, I'll edit it in :) – JAD – 2017-06-14T13:35:36.927

I agree, voted to reopen. – programmer5000 – 2017-06-14T13:53:01.787

1@flawr I made that a dupe of this. It is not really a dupe of its dupe target, which to apply the same method as here recursively would require finding the vertices that are crossing points and would require ordering the resulting subsets into counter-clockwise fashion - that seems much more complex. – Jonathan Allan – 2017-06-14T14:08:13.313

Answers

13

Jelly,  8  6 bytes

-1 byte thanks to Emigna (redundant , ÆḊ has a left-depth of 2)
-1 byte thanks to Emigna, again (halve, H, is floating point no need to ÷2)

ṡ2ÆḊSH

A monadic link taking a list of pairs of coordinates in counter-clockwise fashion as per the examples (with the one repeat) and returning the area.

Try it online!

How?

Applies the shoelace algorithm, just as described in the video (which I happened to also watch just the other day!)

ṡ2ÆḊSH - Link: list of [x,y] coordinate pairs anticlockwise & wrapped, p
ṡ2     - all overlapping slices of length 2
  ÆḊ   - determinant (vectorises)
    S  - sum
     H - halve

Jonathan Allan

Posted 2017-06-14T13:25:04.107

Reputation: 67 804

The second test-case returns -0.5 for me :o – JAD – 2017-06-14T13:32:47.863

Oh, I'll have to check it out... – Jonathan Allan – 2017-06-14T13:33:31.950

That's because as [x,y] coordinates they are given clockwise rather than counter-clockwise. An input of [[1,1],[0,1],[1,0],[1,1]] will return a 0.5. – Jonathan Allan – 2017-06-14T13:38:11.007

1Woops, I'll edit that :D – JAD – 2017-06-14T13:39:01.280

I don't think you need right? – Emigna – 2017-06-14T13:47:53.327

@Emigna Ah yes, good catch! – Jonathan Allan – 2017-06-14T13:49:34.383

1Also, H instead of ÷2 – Emigna – 2017-06-14T13:50:26.317

29

Mathematica, 13 bytes

Area@*Polygon

Martin Ender

Posted 2017-06-14T13:25:04.107

Reputation: 184 808

Could it get more trivial? – Mr. Xcoder – 2017-06-14T19:27:26.303

5

@Mr.Xcoder Sure.

– Martin Ender – 2017-06-14T19:27:41.107

o_O - I am literally mindblown... – Mr. Xcoder – 2017-06-14T19:28:37.730

3That's Mathematica for you. Every conceivable thing is built in to the language. – Brian Minton – 2017-06-15T14:37:36.047

19

Octave, 9 bytes

@polyarea

Inputs are a vector with the x values and a vector with the y values. This works in MATLAB too.

Try it online!

Luis Mendo

Posted 2017-06-14T13:25:04.107

Reputation: 87 464

16

JavaScript (ES6), 69 67 47 bytes

Thanks to @Rick for noticing that we don't need the absolute value if the vertices are guaranteed to be sorted in counterclockwise order and for suggesting to take a flat list as input, saving 20 bytes!

Takes input as a flat list of vertices, including the last vertex.

f=([x,y,...a])=>1/a[0]?x*a[1]/2-y*a[0]/2+f(a):0

Try it online!

How?

This is based on the formula used in many other answers. For \$n\$ 0-indexed vertices:

$$area=\left|\frac{(x_0y_1-y_0x_1)+(x_1y_2-y_1x_2)+\ldots+(x_{n-1}y_0-y_{n-1}x_0)}{2}\right|$$

Arnauld

Posted 2017-06-14T13:25:04.107

Reputation: 111 334

Very impressive! Could you explain how it works? – Rugnir – 2017-06-15T14:40:10.050

The vertices in the second test case were mistakenly ordered incorrectly. The abs shouldn't be necessary. – Rick – 2017-06-15T17:42:36.237

You can also save 7 bytes switching to a flat list: a=>(g=([x,y,...a])=>1-a?0:x*a[1]-y*a[0]+g(a))(a)/2 – Rick – 2017-06-15T18:42:29.730

@Rick is right - abs isn't necessary. Without it the formula calculates the signed area, which is positive because the vertices are given in the counterclockwise order. – Angs – 2018-04-25T21:43:39.393

@Rick Thanks! Updated ... about 10 months later :/ – Arnauld – 2018-04-25T23:12:48.047

7

R, 54 52 bytes

pryr::f({for(i in 2:nrow(x))F=F+det(x[i-1:0,]);F/2})

Which evaluates to the function:

function (x) 
{
    for (i in 2:nrow(x)) F = F + det(x[i - 1:0, ])
    F/2
}

Makes use of the predefined F = FALSE = 0. Implements the shoelace algorithm in the linked video :)

-2 bytes thanks to Giuseppe

JAD

Posted 2017-06-14T13:25:04.107

Reputation: 2 898

-1 byte for i+-1:0 as the row index – Giuseppe – 2017-06-14T16:29:34.607

@Giuseppe Nice. I'll remove the + as well ;) – JAD – 2017-06-14T17:38:15.957

6

Mathics, 31 bytes

Total[Det/@Partition[#,2,1]/2]&

Try it online!


Mathematica, 25 bytes

Tr@BlockMap[Det,#,2,1]/2&

alephalpha

Posted 2017-06-14T13:25:04.107

Reputation: 23 988

6

Python 3, 72 71 bytes

from numpy import*
g=lambda x,y:(dot(x[:-1],y[1:])-dot(x[1:],y[:-1]))/2

Takes two lists, as it was allowed in the comments

x = [x0,x1,x2, ...]
y = [y0,y1,y2, ...] 

Try it online!

This is basically just the implementation of the shoelace-formula. May I get plus points for a golf that you actually would implement like that? :D

-1, there is no need for a space behind x,y:.


P. Siehr

Posted 2017-06-14T13:25:04.107

Reputation: 227

Taking two lists is also mentioned in the body of the question now :) – JAD – 2017-06-14T14:34:09.057

@JarkoDubbeldam Uh, I just saw, that it has to output the area. This solution currently just returns the area. Is that allowed as well, or shall it be printed? – P. Siehr – 2017-06-14T14:37:02.037

A function returning a value counts as output :) – JAD – 2017-06-14T14:37:40.730

I think that with python you don't even have to name the function, so just starting with lambda x,y: is fine. – JAD – 2017-06-14T14:38:23.893

@JarkoDubbeldam Are there anywhere rules for each language? – P. Siehr – 2017-06-14T14:40:25.217

I don't think there are rules for each language separately, but rather rules that apply to certain types of programs. I'll try and see if I can find specifics. – JAD – 2017-06-14T14:46:26.660

@JarkoDubbeldam That would be great, as I am new to this. – P. Siehr – 2017-06-14T14:48:05.697

@P.Siehr https://codegolf.meta.stackexchange.com/a/11925/20260

– xnor – 2017-06-14T20:30:03.307

4

JS (ES6), 98 95 94 93 88 86 82 81 77 73 bytes

(X,Y)=>{for(i in X){a+=(X[i]+X[i-1])*(Y[i]-Y[i-1]);if(!+i)a=0}return a/2}

Takes input like [x1, x2, x3], [y1, y2, y3], and skips the repeated coord pair.

-3 bytes thanks to @JarkoDubbeldam

-4 bytes thanks to @JarkoDubbeldam

-1 byte thanks to @ZacharyT

-4 bytes thanks to @ZacharyT

-4 bytes thanks to @Rick

user70700

Posted 2017-06-14T13:25:04.107

Reputation:

3

J, 12 bytes

Assuming the input is a list of 2 element lists (ie, a table)

-:+/-/ .*2[\
  • 2[\ -- breaks it down into the shoelace Xs, ie, overlapping squares of 4 elms
  • -/ .* -- the determinant of each
  • +/ -- sum it
  • -: -- divide by 2

If we get the input as a single list, we need to first transform into a table, giving us 20 bytes:

-:+/-/ .*2[\ _2&(,\)

Jonah

Posted 2017-06-14T13:25:04.107

Reputation: 8 729

1"Assuming the input is a list of 2 element lists (ie, a table)" This is allowed :) – JAD – 2017-06-15T07:20:27.293

3

MS-SQL, 66 bytes

SELECT geometry::STPolyFromText('POLYGON('+p+')',0).STArea()FROM g

MS SQL 2008 and higher support Open Geospatial Consortium (OGC)-standard spatial data/functions, which I'm taking advantage of here.

Input data is stored in field p of pre-existing table g, per our input standards.

Input is a text field with ordered pairs in the following format: (4 4,0 1,-2 5,-6 0,-1 -4,5 -2,4 4)

Now just for fun, if you allowed my input table to hold Open Geospatial Consortium-standard geometry objects (instead of just text data), then it becomes almost trivial:

--Create and populate input table, not counted in byte total
CREATE TABLE g (p geometry)
INSERT g VALUES (geometry::STPolyFromText('POLYGON((5 5, 10 5, 10 10, 5 5))', 0))

--23 bytes!
SELECT p.STArea()FROM g

BradC

Posted 2017-06-14T13:25:04.107

Reputation: 6 099

1

Haskell, 45 bytes

(a:b:c)?(d:e:f)=(a*e-d*b)/2+(b:c)?(e:f)
_?_=0

Try it online!

Angs

Posted 2017-06-14T13:25:04.107

Reputation: 4 825

0

Perl 5 -pa, 62 bytes

map$\+=$F[$i]*($a[($i+1)%@a]-$a[$i++-1]),@a=eval<>}{$\=abs$\/2

Try it online!

Takes input as a list of X coordinates on the first line followed by a list of Y coordinates on the second.

Xcali

Posted 2017-06-14T13:25:04.107

Reputation: 7 671