Popularity
5.0
Growing
Activity
0.5
-
12
2
0

# jord alternatives and similar packages

Based on the "Geography" category.
Alternatively, view jord alternatives based on common mentions on social networks and blogs.

• ### mapalgebra

Efficient, polymorphic Map Algebra in Haskell.
• ### vectortiles

A native Haskell codec for Mapbox Vector Tiles.
• ### Scout APM: A developer's best friend. Try free for 14-days

Scout APM uses tracing logic that ties bottlenecks to source code so you know the exact line of code causing performance issues and can get back to building a great product faster.
Promo
• ### geodetics

Haskell library of data types and calculations for positions on planet Earth

• ### hcoord

Easily convert between latitude/longitude, Universal Transverse Mercator (UTM) and Ordnance Survey (OSGB) references with Haskell.
• ### geodetic-types

Geodetic types
• ### HSlippyMap

OpenStreetMap Slippy Map Algo

Do you think we are missing an alternative of jord or a related project?

## Jord - Geographical Position Calculations

Jord [Swedish] is Earth [English]

## What is this?

Jord is a Haskell library that implements various geographical position calculations using the algorithms described in Gade, K. (2010) - A Non-singular Horizontal Position Representation, Shudde, Rex H. (1986) - Some tactical algorithms for spherical geometry and Vincenty, T. (1975) - Direct and Inverse Solutions of Geodesics on the Ellipsoid:

• conversion between ECEF (earth-centred, earth-fixed), latitude/longitude and n-vector positions for spherical and ellipsoidal earth model,
• conversion between latitude/longitude and n-vector positions,
• local frames (body; local level, wander azimuth; north, east, down): delta between positions, target position from reference position and delta,
• great circles: surface distance, initial & final bearing, interpolated position, great circle intersections, cross track distance, ...,
• geodesic: surface distance, initial & final bearing and destination,
• kinematics: position from p0, bearing and speed, closest point of approach between tracks, intercept (time, speed, minimum speed),
• transformation between coordinate systems (both fixed and time-dependent).
• polygon triangulation

## How do I build it?

If you have Stack, then:

``````\$ stack build --test
``````

If you have Cabal, then:

``````\$ cabal v2-build
\$ cabal v2-test
``````

## How do I use it?

See documentation on Hackage

Import the core functional modules as qualified:

``````import qualified Data.Geo.Jord.Angle as Angle
import qualified Data.Geo.Jord.Duration as Duration
import qualified Data.Geo.Jord.Geocentric as Geocentric
import qualified Data.Geo.Jord.Geodetic as Geodetic
import qualified Data.Geo.Jord.Geodesic as Geodesic
import qualified Data.Geo.Jord.GreatCircle as GreatCircle
import qualified Data.Geo.Jord.Kinematics as Kinematics
import qualified Data.Geo.Jord.Length as Length
import qualified Data.Geo.Jord.Local as Local
import qualified Data.Geo.Jord.Polygon as Polygon
import qualified Data.Geo.Jord.Positions as Positions
import qualified Data.Geo.Jord.Speed as Speed
import qualified Data.Geo.Jord.Tx as Tx
``````

Note: modules can be selectively imported as non-qualified, but i.m.o. the code reads better when modules are imported qualified.

Import models and transformation parameters:

``````import Data.Geo.Jord.Model (Epoch(..))
import Data.Geo.Jord.Models
import qualified Data.Geo.Jord.Txs as Txs
``````

## Solutions to the 10 examples from NavLab

### Example 1: A and B to delta

Given two positions, A and B as latitudes, longitudes and depths relative to Earth, E.

Find the exact vector between the two positions, given in meters north, east, and down, and find the direction (azimuth) to B, relative to north. Assume WGS-84 ellipsoid. The given depths are from the ellipsoid surface. Use position A to define north, east, and down directions. (Due to the curvature of Earth and different directions to the North Pole, the north, east, and down directions will change (relative to Earth) for different places. A must be outside the poles for the north and east directions to be defined.)

``````example1 :: IO()
example1 = do
let pA = Geodetic.latLongHeightPos 1 2 (Length.metres 3) WGS84
let pB = Geodetic.latLongHeightPos 4 5 (Length.metres 6) WGS84

let ned = Local.nedBetween pA pB
-- Ned {north = 331.730863099km, east = 332.998501491km, down = 17.39830421km}

let slantRange = Local.slantRange ned
-- 470.357383823km

let bearing = Local.bearing ned
-- 45°6'33.346"

let elevation = Local.elevation ned
-- -2°7'11.381"

putStrLn ("NavLab, Example1: A and B to delta\n\
\  delta      = " ++ (show ned) ++ "\n\
\  slantRange = " ++ (show slantRange) ++ "\n\
\  bearing    = " ++ (show bearing) ++ "\n\
\  elevation  = " ++ (show elevation) ++ "\n")
``````

### Example 2: B and delta to C

A radar or sonar attached to a vehicle B (Body coordinate frame) measures the distance and direction to an object C. We assume that the distance and two angles (typically bearing and elevation relative to B) are already combined to the vector p_BC_B (i.e. the vector from B to C, decomposed in B). The position of B is given as n_EB_E and z_EB, and the orientation (attitude) of B is given as R_NB (this rotation matrix can be found from roll/pitch/yaw by using zyx2R).

Find the exact position of object C as n-vector and depth ( n_EC_E and z_EC ), assuming Earth ellipsoid with semi-major axis a and flattening f. For WGS-72, use a = 6 378 135 m and f = 1/298.26.

``````example2 :: IO()
example2 = do
let frameB =
Local.frameB
(Angle.decimalDegrees 40)
(Angle.decimalDegrees 20)
(Angle.decimalDegrees 30)
let pB = Geodetic.nvectorHeightPos 1 2 3 (Length.metres 400) WGS72
let delta = Local.deltaMetres 3000 2000 100

let pC = Local.destination pB frameB delta
-- 53°18'46.839"N,63°29'6.179"E 406.006017m (WGS72)

putStrLn ("NavLab, Example 2: B and delta to C\n\
\  pC = " ++ (show pC) ++ "\n")
``````

### Example 3: ECEF-vector to geodetic latitude

Position B is given as an “ECEF-vector” p_EB_E (i.e. a vector from E, the center of the Earth, to B, decomposed in E). Find the geodetic latitude, longitude and height (latEB, lonEB and hEB), assuming WGS-84 ellipsoid.

``````example3 :: IO()
example3 = do
let ecef = Geocentric.metresPos 5733900.0 (-6371000.0) 7008100.000000001 WGS84

let geod = Positions.toGeodetic ecef
-- 39°22'43.495"N,48°0'46.035"W 4702.059834295km (WGS84)

putStrLn ("NavLab, 3: ECEF-vector to geodetic latitude\n\
\  geodetic pos = " ++ (show geod) ++ "\n")
``````

### Example 4: Geodetic latitude to ECEF-vector

Geodetic latitude, longitude and height are given for position B as latEB, lonEB and hEB, find the ECEF-vector for this position, p_EB_E.

``````example4 :: IO()
example4 = do
let geod = Geodetic.latLongHeightPos 1 2 (Length.metres 3) WGS84

let ecef = Positions.toGeocentric geod
-- Position {gx = 6373.290277218km, gy = 222.560200675km, gz = 110.568827182km, model = WGS84}

putStrLn ("NavLab, 4: Geodetic latitude to ECEF-vector\n\
\  geocentric pos = " ++ (show ecef) ++ "\n")
``````

### Example 5: Surface distance

Find the surface distance sAB (i.e. great circle distance) between two positions A and B. The heights of A and B are ignored, i.e. if they don’t have zero height, we seek the distance between the points that are at the surface of the Earth, directly above/below A and B. The Euclidean distance (chord length) dAB should also be found. Use Earth radius 6371e3 m. Compare the results with exact calculations for the WGS-84 ellipsoid.

``````example5 :: IO()
example5 = do
let pA = Geodetic.s84Pos 88 0
let pB = Geodetic.s84Pos 89 (-170)

let distance = GreatCircle.distance pA pB
-- 332.456901835km

putStrLn ("NavLab, 5: Surface distance\n\
\  distance = " ++ (show distance) ++ "\n")
``````

### Example 6: Interpolated position

Given the position of B at time t0 and t1, n_EB_E(t0) and n_EB_E(t1).

Find an interpolated position at time ti, n_EB_E(ti). All positions are given as n-vectors.

``````example6 :: IO()
example6 = do
let pA = Geodetic.s84Pos 89 0
let pB = Geodetic.s84Pos 89 180
let f = 0.6

let interpolated = GreatCircle.interpolated pA pB f
-- 89°47'59.929"N,180°0'0.000"E (S84)

putStrLn ("NavLab, 6: Interpolated position\n\
\  interpolated = " ++ (show interpolated) ++ "\n")
``````

### Example 7: Mean position

Three positions A, B, and C are given as n-vectors n_EA_E, n_EB_E, and n_EC_E. Find the mean position, M, given as n_EM_E. Note that the calculation is independent of the depths of the positions.

``````example7 :: IO()
example7 = do
let ps =
[ Geodetic.s84Pos 90 0
, Geodetic.s84Pos 60 10
, Geodetic.s84Pos 50 (-20)
]

let mean = GreatCircle.mean ps
-- Just 67°14'10.150"N,6°55'3.040"W (S84)

putStrLn ("NavLab, Example 7: Mean position\n\
\  mean = " ++ (show mean) ++ "\n")
``````

### Example 8: A and azimuth/distance to B

We have an initial position A, direction of travel given as an azimuth (bearing) relative to north (clockwise), and finally the distance to travel along a great circle given as sAB. Use Earth radius 6371e3 m to find the destination point B.

In geodesy this is known as “The first geodetic problem” or “The direct geodetic problem” for a sphere, and we see that this is similar to Example 2, but now the delta is given as an azimuth and a great circle distance. (“The second/inverse geodetic problem” for a sphere is already solved in Examples 1 and 5.)

``````example8 :: IO()
example8 = do
let p = Geodetic.s84Pos 80 (-90)
let bearing = Angle.decimalDegrees 200
let distance = Length.metres 1000

let dest = GreatCircle.destination p bearing distance
-- 79°59'29.575"N,90°1'3.714"W (S84)

putStrLn ("NavLab, Example 8: A and azimuth/distance to B\n\
\  destination = " ++ (show dest) ++ "\n")
``````

### Example 9: Intersection of two paths

Define a path from two given positions (at the surface of a spherical Earth), as the great circle that goes through the two points.

Path A is given by A1 and A2, while path B is given by B1 and B2.

Find the position C where the two great circles intersect.

``````example9 :: IO()
example9 = do
let a1 = Geodetic.s84Pos 51.885 0.235
let a2 = Geodetic.s84Pos 48.269 13.093
let b1 = Geodetic.s84Pos 49.008 2.549
let b2 = Geodetic.s84Pos 56.283 11.304

let ga = GreatCircle.through a1 a2
let gb = GreatCircle.through b1 b2
let intersections = GreatCircle.intersections <\$> ga <*> gb
-- Just (Just (50°54'6.260"N,4°29'39.052"E (S84),50°54'6.260"S,175°30'20.947"W (S84)))

let ma = GreatCircle.minorArc a1 a2
let mb = GreatCircle.minorArc b1 b2
let intersection = GreatCircle.intersection <\$> ma <*> mb
-- Just (Just 50°54'6.260"N,4°29'39.052"E (S84))

putStrLn ("NavLab, Example 9: Intersection of two paths\n\
\  great circle intersections = " ++ (show intersections) ++ "\n\
\  minor arc intersection     = " ++ (show intersection) ++ "\n")
``````

### Example 10: Cross track distance

*Path A is given by the two positions A1 and A2 (similar to the previous example).

Find the cross track distance sxt between the path A (i.e. the great circle through A1 and A2) and the position B (i.e. the shortest distance at the surface, between the great circle and B).

``````example10 :: IO()
example10 = do
let p = Geodetic.s84Pos 1 0.1
let gc = GreatCircle.through (Geodetic.s84Pos 0 0) (Geodetic.s84Pos 10 0)

let sxt = fmap (\g -> GreatCircle.crossTrackDistance p g) gc
-- Just 11.117814411km

putStrLn ("NavLab, Example 10: Cross track distance\n\
\  cross track distance = " ++ (show sxt) ++ "\n")
``````

## Solutions to the geodesic problems (Vincenty)

### Example 11: Inverse problem

Given the coordinates of the two points (Φ1, L1) and (Φ2, L2), the inverse problem finds the azimuths α1, α2 and the ellipsoidal distance s.

``````example11 :: IO()
example11 = do
let pA = Geodetic.wgs84Pos 88 0
let pB = Geodetic.wgs84Pos 89 (-170)

let inv = Geodesic.inverse pA pB
let initialBearing = fmap Geodesic.initialBearing inv
-- Just (Just 356°40'8.701")

let finalBearing = fmap Geodesic.finalBearing inv
-- Just (Just 186°40'19.615")

let distance = fmap Geodesic.length inv
-- Just 333.947509469km

putStrLn ("Geodesic, Example 11: Inverse problem\n\
\    initial bearing = " ++ (show initialBearing) ++ "\n\
\    final bearing   = " ++ (show finalBearing) ++ "\n\
\    distance        = " ++ (show distance) ++ "\n")
``````

### Example 12: Direct problem

Given an initial point (Φ1, L1) and initial azimuth, α1, and a distance, s, along the geodesic the problem is to find the end point (Φ2, L2) and azimuth, α2.

``````example12 :: IO()
example12 = do
let p = Geodetic.wgs84Pos 80 (-90)
let bearing = Angle.decimalDegrees 200
let distance = Length.metres 1000

let dct = Geodesic.direct p bearing distance
let destination = fmap Geodesic.endPosition dct
-- Just 79°59'29.701"N,90°1'3.436"W (WGS84)

let finalBearing = fmap Geodesic.finalBearing dct
-- Just (Just 199°58'57.528")

putStrLn ("Geodesic, Example 12: Direct problem\n\
\    destination   = " ++ (show destination) ++ "\n\
\    final bearing = " ++ (show finalBearing) ++ "\n")
``````

## Solutions to kinematics problems

### Example 13: Closest point of approach

The Closest Point of Approach (CPA) refers to the positions at which two dynamically moving objects reach their closest possible distance.

``````example13 :: IO()
example13 = do
let ownship = Kinematics.Track
(Geodetic.s84Pos 20 (-60))
(Angle.decimalDegrees 10)
(Speed.knots 15)
let intruder = Kinematics.Track
(Geodetic.s84Pos 34 (-50))
(Angle.decimalDegrees 220)
(Speed.knots 300)

let cpa = Kinematics.cpa ownship intruder
let timeToCpa = fmap Kinematics.timeToCpa cpa
-- Just 3H9M56.155S

let distanceAtCpa = fmap Kinematics.distanceAtCpa cpa
-- Just 124.231730834km

let cpaOwnshipPosition = fmap Kinematics.cpaOwnshipPosition cpa
-- Just 20°46'43.641"N,59°51'11.225"W (S84)

let cpaIntruderPosition = fmap Kinematics.cpaIntruderPosition cpa
-- Just 21°24'8.523"N,60°50'48.159"W (S84)

putStrLn ("Kinematics, Example 13: Closest point of approach\n\
\    time to CPA      = " ++ (show timeToCpa) ++ "\n\
\    distance at CPA  = " ++ (show distanceAtCpa) ++ "\n\
\    CPA ownship pos  = " ++ (show cpaOwnshipPosition) ++ "\n\
\    CPA intruder pos = " ++ (show cpaIntruderPosition) ++ "\n")
``````

### Example 14: Speed required to intercept target

Inputs are the initial latitude and longitude of an interceptor and a target, and the target course and speed. Also input is the time of the desired intercept. Outputs are the speed required of the interceptor, the course of the interceptor, the distance travelled to intercept, and the latitude and longitude of the intercept.

``````example14 :: IO()
example14 = do
let track = Kinematics.Track
(Geodetic.s84Pos 34 (-50))
(Angle.decimalDegrees 220)
(Speed.knots 600)
let interceptor = Geodetic.s84Pos 20 (-60)
let interceptTime = Duration.seconds 2700

let intercept = Kinematics.interceptByTime track interceptor interceptTime
let distanceToIntercept = fmap Kinematics.distanceToIntercept intercept
-- Just 1015.302358852km

let interceptPosition = fmap Kinematics.interceptPosition intercept
-- Just 28°8'12.046"N,55°27'21.411"W (S84)

let interceptorBearing = fmap Kinematics.interceptorBearing intercept
-- Just 26°7'11.649"

let interceptorSpeed = fmap Kinematics.interceptorSpeed intercept
-- Just 1353.736478km/h

putStrLn ("Kinematics, Example 14: Speed required to intercept target\n\
\    distance to intercept = " ++ (show distanceToIntercept) ++ "\n\
\    intercept position    = " ++ (show interceptPosition) ++ "\n\
\    interceptor bearing   = " ++ (show interceptorBearing) ++ "\n\
\    interceptor speed     = " ++ (show interceptorSpeed) ++ "\n")
``````

### Example 15: Time required to intercept target

Inputs are the initial latitude and longitude of an interceptor and a target, and the target course and speed. For a given interceptor speed, it may or may not be possible to make an intercept.

The first algorithm is to compute the minimum interceptor speed required to achieve intercept and the time required to make such and intercept.

The second algorithm queries the user to input an interceptor speed. If the speed is at least that required for intercept then the time required to intercept is computed.

``````example15 :: IO()
example15 = do
let track = Kinematics.Track
(Geodetic.s84Pos 34 (-50))
(Angle.decimalDegrees 220)
(Speed.knots 600)
let interceptor = Geodetic.s84Pos 20 (-60)

let minIntercept = Kinematics.intercept track interceptor
let minTimeToIntercept = fmap Kinematics.timeToIntercept minIntercept
-- Just 1H39M53.831S

let minDistanceToIntercept = fmap Kinematics.distanceToIntercept minIntercept
-- Just 162.294627463km

let minInterceptPosition = fmap Kinematics.interceptPosition minIntercept
-- Just 20°43'42.305"N,61°20'56.848"W (S84)

let minInterceptorBearing = fmap Kinematics.interceptorBearing minIntercept
-- Just 300°10'18.053"

let minInterceptorSpeed = fmap Kinematics.interceptorSpeed minIntercept
-- Just 97.476999km/h

putStrLn ("Kinematics, Example 15: Time required to intercept target (min)\n\
\    time to intercept     = " ++ (show minTimeToIntercept) ++ "\n\
\    distance to intercept = " ++ (show minDistanceToIntercept) ++ "\n\
\    intercept position    = " ++ (show minInterceptPosition) ++ "\n\
\    interceptor bearing   = " ++ (show minInterceptorBearing) ++ "\n\
\    interceptor speed     = " ++ (show minInterceptorSpeed) ++ "\n")

let interceptSpeed = Speed.knots 700

let intercept = Kinematics.interceptBySpeed track interceptor interceptSpeed
let timeToIntercept = fmap Kinematics.timeToIntercept intercept
-- Just 0H46M4.692S

let distanceToIntercept = fmap Kinematics.distanceToIntercept intercept
-- Just 995.596069189km

let interceptPosition = fmap Kinematics.interceptPosition intercept
-- Just 27°59'36.764"N,55°34'43.852"W(S84)

let interceptorBearing = fmap Kinematics.interceptorBearing intercept
-- Just 25°56'7.484"

putStrLn ("Kinematics, Example 15: Time required to intercept target\n\
\    time to intercept     = " ++ (show timeToIntercept) ++ "\n\
\    distance to intercept = " ++ (show distanceToIntercept) ++ "\n\
\    intercept position    = " ++ (show interceptPosition) ++ "\n\
\    interceptor bearing   = " ++ (show interceptorBearing) ++ "\n")
``````

## Solutions to coordinates transformation problems

### Example 16: Transformation between fixed models

Convert the coordinates of a geocentric position between the WGS84 model and the NAD83 model.

``````example16 :: IO()
example16 = do
let pWGS84 = Geocentric.metresPos 4193790.895437 454436.195118 4768166.813801 WGS84

-- using explicit parameters:
-- Position {gx = 4193.792080781km, gy = 454.433921298km, gz = 4768.16615479km, model = NAD83}

-- using the transformation graph:
-- Just (Position {gx = 4193.792080781km, gy = 454.433921298km, gz = 4768.16615479km, model = NAD83})

putStrLn ("Coordinates transformation, Example 16: WGS84 -> NAD83\n\
\    WGS84 = " ++ (show pWGS84) ++ "\n\
``````

### Example 17: Transformation between time dependent models

Convert the coordinates of a geocentric position between the ITRF2014, ITRF2000 and NAD83 (CORS96) models

``````example17 :: IO()
example17 = do
let pITRF2014 = Geocentric.metresPos 4193790.895437 454436.195118 4768166.813801 ITRF2014

-- using explicit parameters:
let tx = Tx.params Txs.from_ITRF2014_to_ITRF2000
let pITRF2000 = Positions.transformAt' pITRF2014 (Epoch 2014.0) ITRF2000 tx
-- Position {gx = 4193.790907273km, gy = 454.436197881km, gz = 4768.166792308km, model = ITRF2000}

-- using the transformation graph (goes via ITRF2000):
-- Just (Position {gx = 4193.791801305km, gy = 454.433876376km, gz = 4768.166397281km, model = NAD83_CORS96})

putStrLn ("Coordinates transformation, Example 17: ITRF2014 -> ITRF2000 -> NAD83 (CORS96)\n\
\    ITRF2014       = " ++ (show pITRF2014) ++ "\n\
\    ITRF2000       = " ++ (show pITRF2000) ++ "\n\
``````

## Solutions to polygon triangulation

### Example 18: Triangulation of a simple polygon

``````example18 :: IO()
example18 = do
let p = Polygon.simple
[ Geodetic.s84Pos 45 45
, Geodetic.s84Pos (-45) 45
, Geodetic.s84Pos (-45) (-45)
, Geodetic.s84Pos 45 (-45)
]

let ts = fmap Polygon.triangulate p
-- Right [ Triangle 45°0'0.000"N,45°0'0.000"W (S84) 45°0'0.000"N,45°0'0.000"E (S84) 45°0'0.000"S,45°0'0.000"E (S84)
--       , Triangle 45°0'0.000"S,45°0'0.000"E (S84) 45°0'0.000"S,45°0'0.000"W (S84) 45°0'0.000"N,45°0'0.000"W (S84)
--       ]

putStrLn ("Polygon triangulation, Example 18: Simple polygon\n\
\    triangles = " ++ (show ts) ++ "\n")
``````

### Example 19: Triangulation of a circle

``````example19 :: IO()
example19 = do
let p = Polygon.circle (Geodetic.s84Pos 0 0) (Length.kilometres 10) 10

let ts = fmap Polygon.triangulate p
-- Right [ Triangle 0°4'21.923"N,0°3'10.298"W (S84) 0°5'23.755"N,0°0'0.000"E (S84) 0°4'21.923"N,0°3'10.298"E (S84)
--       , Triangle 0°4'21.923"N,0°3'10.298"W (S84) 0°4'21.923"N,0°3'10.298"E (S84) 0°1'40.045"N,0°5'7.909"E (S84)
--       , Triangle 0°4'21.923"N,0°3'10.298"W (S84) 0°1'40.045"N,0°5'7.909"E (S84) 0°1'40.045"S,0°5'7.909"E (S84)
--       , Triangle 0°4'21.923"N,0°3'10.298"W (S84) 0°1'40.045"S,0°5'7.909"E (S84) 0°4'21.923"S,0°3'10.298"E (S84)
--       , Triangle 0°4'21.923"N,0°3'10.298"W (S84) 0°4'21.923"S,0°3'10.298"E (S84) 0°5'23.755"S,0°0'0.000"E (S84)
--       , Triangle 0°4'21.923"N,0°3'10.298"W (S84) 0°5'23.755"S,0°0'0.000"E (S84) 0°4'21.923"S,0°3'10.298"W (S84)
--       , Triangle 0°4'21.923"N,0°3'10.298"W (S84) 0°4'21.923"S,0°3'10.298"W (S84) 0°1'40.045"S,0°5'7.909"W (S84)
--       , Triangle 0°1'40.045"S,0°5'7.909"W (S84) 0°1'40.045"N,0°5'7.909"W (S84) 0°4'21.923"N,0°3'10.298"W (S84)
--       ]

putStrLn ("Polygon triangulation, Example 19: Circle\n\
\    triangles = " ++ (show ts) ++ "\n")
``````

### Example 20: Triangulation of an arc

``````example20 :: IO()
example20 = do
let p = Polygon.arc (Geodetic.s84Pos 0 0) (Length.kilometres 10) (Angle.decimalDegrees 10) (Angle.decimalDegrees  20) 5

let ts = fmap Polygon.triangulate p
-- Right [ Triangle 0°5'4.230"N,0°1'50.730"E (S84) 0°5'18.836"N,0°0'56.219"E (S84) 0°5'16.081"N,0°1'10.073"E (S84)
--       , Triangle 0°5'4.230"N,0°1'50.730"E (S84) 0°5'16.081"N,0°1'10.073"E (S84) 0°5'12.723"N,0°1'23.794"E (S84)
--       , Triangle 0°5'12.723"N,0°1'23.794"E (S84) 0°5'8.770"N,0°1'37.355"E (S84) 0°5'4.230"N,0°1'50.730"E (S84)
--       ]

putStrLn ("Polygon triangulation, Example 20: Arc\n\
\    triangles = " ++ (show ts) ++ "\n")
``````
``````main :: IO()
main = do
example1
example2
example3
example4
example5
example6
example7
example8
example9
example10
example11
example12
example13
example14
example15
example16
example17
example18
example19
example20
``````

*Note that all licence references and agreements mentioned in the jord README section above are relevant to that project's source code only.