I really love Turf.js. Last year, I started diving into iOS development. I wanted to use methods from Turf.js in iOS applications, so I was excited to see my colleague start the turf-swift project.

After expressing interest in bringing new methods over to turf-swift, I began weekly pair programming sessions to learn how to port over Turf’s polygon area method. Here’s how we did it.

If you have a geometry background, its not too hard to calculate the area of a polygon on a flat plane. But because maps are hard, calculating the area of a polygon that lies on a sphere is way harder. So how is it done? Well luckily, very smart people at NASA already did this for us.

When Turf.js was created, this algorithm and many others were translated from pure math into JavaScript. Our part of this project would be to translate the JavaScript implementation of this algorithm to Swift code.

One of the challenging features of working with polygons is that they can have holes in them. For example, if you have a polygon in the shape of a donut, you’ll need to subtract the area of the donut hole from the area of the donut to calculate the correct area of the donut shape. This would also have to be taken into consideration while building out the Swift version of this method.

Polygon features are composed of one outer ring with one or more inner rings. For our Swift implementation, we began defining a new `Polygon`

struct that could be created with an outer ring and an array of one or more inner rings.

```
public struct Polygon {
var outerRing: Ring
var innerRings: [Ring]
}
```

Another struct called `Ring`

can be created using an array of `CLLocationCoordinate`

s. Rings must have three or more coordinates. Within the `Ring`

struct, we port over the JavaScript code necessary from Turf.js turf-area package to calculate the ring area.

Once we can create a new `Ring`

struct, we can calculate the area of that ring like so:

```
let ringCoordinates = [
CLLocationCoordinate2DMake(40.17, -83.58),
CLLocationCoordinate2DMake(30.67, -69.34),
CLLocationCoordinate2DMake(24.52, -88.94),
CLLocationCoordinate2DMake(40.17, -83.58)
]
let ring = Ring(coordinates: ringCoordinates)
print(ring.area)
```

In this case `ring.area`

came out to 1419766110812.166 square meters. To make sure this was correct, I ran the same function with the above coordinates with Turf.js, which resulted in the same value.

Now, to account for the donuts. Back in the `Polygon`

struct, we needed to calculate the entire area given the outer ring and any inner rings, if they existed. The Swift implementation of this JavaScript code looks like this:

```
public struct Polygon {
var outerRing: Ring
var innerRings: [Ring]
public var area: Double {
return abs(outerRing.area) - innerRings
.map { abs($0.area) }
.reduce(0, +)
}
}
```

*I think this looks a lot nicer than JavaScript!*

In the Polygon’s area property, there are a couple of things happening:

- We map over each inner ring and retrieve the area of each one using the
`area`

property that was defined in earlier`Ring`

struct. - Once we have the area of each ring, we sum up all of the areas of the inner rings by performing a reduce operation on resulting array of inner ring areas.
- Now that we have the sum of the inner ring areas, we finally subtract this from the area of the outer ring. This gives us the final area of the entire polygon.

Below is the full turf-swift implementation of the polygon ring area calculation for the polygon illustrated above:

```
let outerRing = [
[
CLLocationCoordinate2DMake(37.00255267215955, -109.05029296875),
CLLocationCoordinate2DMake(37.020098201368114, -102.0849609375),
CLLocationCoordinate2DMake(41.0130657870063, -102.041015625),
CLLocationCoordinate2DMake(40.97989806962013, -109.072265625),
CLLocationCoordinate2DMake(37.00255267215955, -109.05029296875)
]
let innerRing = [
CLLocationCoordinate2DMake(40.6306300839918, -108.56689453125),
CLLocationCoordinate2DMake(37.43997405227057, -108.61083984375),
CLLocationCoordinate2DMake(37.405073750176925, -102.50244140624999),
CLLocationCoordinate2DMake(40.66397287638688, -102.4365234375),
CLLocationCoordinate2DMake(40.6306300839918, -108.56689453125)
]
let polygon = Polygon(outerRing: outerRing, innerRings: [innerRing])
print(polygon.area)
```

The result? 78588446934.433655 square meters. The same calculation with Turf.js also results in the same value. We added some tests to confirm this and a new turf-swift method was born.

Written on January 15th, 2018 by Nadia Barbosa