| Copyright | (c) 2018 Cedric Liegeois |
|---|---|
| License | BSD3 |
| Maintainer | Cedric Liegeois <ofmooseandmen@yahoo.fr> |
| Stability | experimental |
| Portability | portable |
| Safe Haskell | Safe |
| Language | Haskell2010 |
Data.Geo.Jord.Geodetics
Description
Geodetic calculations assuming a spherical earth model.
All functions are implemented using the vector-based approached described in Gade, K. (2010). A Non-singular Horizontal Position Representation
Synopsis
- data GreatCircle
- class IsGreatCircle a where
- greatCircle :: a -> GreatCircle
- greatCircleE :: a -> Either String GreatCircle
- greatCircleF :: MonadFail m => a -> m GreatCircle
- gcPos :: GreatCircle -> NVector
- gcBearing :: GreatCircle -> Angle
- data GreatArc
- class IsGreatArc a where
- gaStart :: GreatArc -> NVector
- gaEnd :: GreatArc -> NVector
- alongTrackDistance :: NTransform a => a -> GreatArc -> Length -> Length
- alongTrackDistance84 :: NTransform a => a -> GreatArc -> Length
- angularDistance :: NTransform a => a -> a -> Maybe a -> Angle
- antipode :: NTransform a => a -> a
- crossTrackDistance :: NTransform a => a -> GreatCircle -> Length -> Length
- crossTrackDistance84 :: NTransform a => a -> GreatCircle -> Length
- destination :: NTransform a => a -> Angle -> Length -> Length -> a
- destination84 :: NTransform a => a -> Angle -> Length -> a
- finalBearing :: (Eq a, NTransform a) => a -> a -> Maybe Angle
- initialBearing :: (Eq a, NTransform a) => a -> a -> Maybe Angle
- interpolate :: NTransform a => a -> a -> Double -> a
- intersection :: NTransform a => GreatArc -> GreatArc -> Maybe a
- intersections :: NTransform a => GreatCircle -> GreatCircle -> Maybe (a, a)
- isBetween :: NTransform a => a -> GreatArc -> Bool
- isInsideSurface :: (Eq a, NTransform a) => a -> [a] -> Bool
- mean :: NTransform a => [a] -> Maybe a
- surfaceDistance :: NTransform a => a -> a -> Length -> Length
- surfaceDistance84 :: NTransform a => a -> a -> Length
The GreatCircle type
data GreatCircle Source #
A circle on the surface of the Earth which lies in a plane passing through the Earth's centre. Every two distinct and non-antipodal points on the surface of the Earth define a Great Circle.
It is internally represented as its normal vector - i.e. the normal vector to the plane containing the great circle.
see IsGreatCircle.
Instances
| Eq GreatCircle Source # | |
Defined in Data.Geo.Jord.Geodetics | |
| Show GreatCircle Source # | |
Defined in Data.Geo.Jord.Geodetics Methods showsPrec :: Int -> GreatCircle -> ShowS # show :: GreatCircle -> String # showList :: [GreatCircle] -> ShowS # | |
class IsGreatCircle a where Source #
Class for data from which a GreatCircle can be computed.
Minimal complete definition
Methods
Arguments
| :: a | |
| -> GreatCircle |
|
Arguments
| :: a | |
| -> Either String GreatCircle |
|
Arguments
| :: MonadFail m | |
| => a | |
| -> m GreatCircle |
|
Instances
gcPos :: GreatCircle -> NVector Source #
position (n-vector) on the great circle
The GreatArc type
A closed segment of GreatCircle. It represent the shortest path on the surface of the Earth
between the two positions.
see IsGreatArc.
Instances
| Eq GreatArc Source # | |
| Show GreatArc Source # | |
| IsGreatCircle GreatArc Source # |
|
Defined in Data.Geo.Jord.Geodetics Methods greatCircle :: GreatArc -> GreatCircle Source # greatCircleE :: GreatArc -> Either String GreatCircle Source # greatCircleF :: MonadFail m => GreatArc -> m GreatCircle Source # | |
class IsGreatArc a where Source #
Class for data from which a GreatArc can be computed.
Minimal complete definition
Methods
Arguments
| :: a | |
| -> GreatArc |
|
Instances
| NTransform a => IsGreatArc (a, a) Source # |
let p1 = decimalLatLongHeight 45.0 (-143.5) (metres 1500)
let p2 = decimalLatLongHeight 46.0 14.5 (metres 3000)
greatArc (p1, p2) -- heights are ignored, great arc are always at earth surface.
|
| NTransform a => IsGreatArc (Track a, Duration) Source # |
|
| NTransform a => IsGreatArc (Track a, Duration, Length) Source # |
|
Calculations
alongTrackDistance :: NTransform a => a -> GreatArc -> Length -> Length Source #
alongTrackDistance p ga r how far position p is along a path described
by great arc ga: if a perpendicular is drawn from p to the great arc, the
along-track distance is the signed distance from the start point to where the
perpendicular crosses the path.
let p = decimalLatLong 53.2611 (-0.7972)
let ga = greatArc (decimalLatLong 53.3206 (-1.7297)) (decimalLatLong 53.1887 0.1334)
alongTrackDistance p ga r84 -- 62.3315757 kilometres
alongTrackDistance84 :: NTransform a => a -> GreatArc -> Length Source #
alongTrackDistance using the mean radius of the WGS84 reference ellipsoid.
angularDistance :: NTransform a => a -> a -> Maybe a -> Angle Source #
angularDistance p1 p2 n computes the angle between the horizontal positions p1 and p2.
If n is Nothing, the angle is always in [0..180], otherwise it is in [-180, +180],
signed + if p1 is clockwise looking along n, - in opposite direction.
antipode :: NTransform a => a -> a Source #
antipode p computes the antipodal horizontal position of p:
the horizontal position on the surface of the Earth which is diametrically opposite to p.
crossTrackDistance :: NTransform a => a -> GreatCircle -> Length -> Length Source #
crossTrackDistance p gc r computes the signed distance from horizontal position p to great circle gc.
Returns a negative Length if position if left of great circle,
positive Length if position if right of great circle; the orientation of the
great circle is therefore important:
let gc1 = greatCircle (decimalLatLong 51 0) (decimalLatLong 52 1)
let gc2 = greatCircle (decimalLatLong 52 1) (decimalLatLong 51 0)
crossTrackDistance p gc1 r84 = (- crossTrackDistance p gc2 r84)
let p = decimalLatLong 53.2611 (-0.7972)
let gc = greatCircleBearing (decimalLatLong 53.3206 (-1.7297)) (decimalDegrees 96.0)
crossTrackDistance p gc r84 -- -305.663 metres
crossTrackDistance84 :: NTransform a => a -> GreatCircle -> Length Source #
crossTrackDistance using the mean radius of the WGS84 reference ellipsoid.
destination :: NTransform a => a -> Angle -> Length -> Length -> a Source #
destination p b d r computes the destination position from position p having
travelled the distance d on the initial bearing (compass angle) b (bearing will normally vary
before destination is reached) and using the earth radius r.
let p0 = ecefToNVector (ecefMetres 3812864.094 (-115142.863) 5121515.161) s84
let p1 = ecefMetres 3826406.4710518294 8900.536398998282 5112694.233184049
let p = destination p0 (decimalDegrees 96.0217) (metres 124800) r84
nvectorToEcef p s84 = p1
destination84 :: NTransform a => a -> Angle -> Length -> a Source #
destination using the mean radius of the WGS84 reference ellipsoid.
finalBearing :: (Eq a, NTransform a) => a -> a -> Maybe Angle Source #
finalBearing p1 p2 computes the final bearing arriving at p2 from p1 in compass angle.
Compass angles are clockwise angles from true north: 0 = north, 90 = east, 180 = south, 270 = west.
The final bearing will differ from the initialBearing by varying degrees according to distance and latitude.
Returns Nothing if both horizontal positions are equals.
initialBearing :: (Eq a, NTransform a) => a -> a -> Maybe Angle Source #
initialBearing p1 p2 computes the initial bearing from p1 to p2 in compass angle.
Compass angles are clockwise angles from true north: 0 = north, 90 = east, 180 = south, 270 = west.
Returns Nothing if both horizontal positions are equals.
interpolate :: NTransform a => a -> a -> Double -> a Source #
interpolate p0 p1 f# computes the horizontal position at fraction f between the p0 and p1@.
Special conditions:
interpolate p0 p1 0.0 = p0
interpolate p0 p1 1.0 = p1
let p1 = latLongHeight (readLatLong "53°28'46''N 2°14'43''W") (metres 10000)
let p2 = latLongHeight (readLatLong "55°36'21''N 13°02'09''E") (metres 20000)
interpolate p1 p2 0.5 = decimalLatLongHeight 54.7835574 5.1949856 (metres 15000)
intersection :: NTransform a => GreatArc -> GreatArc -> Maybe a Source #
Computes the intersection between the two given GreatArcs.
see also intersections
let spd = kilometresPerHour 1000
let t1 = Track (decimalLatLong 51.885 0.235) (decimalDegrees 108.63) spd
let t2 = Track (decimalLatLong 49.008 2.549) (decimalDegrees 32.72) spd
let oneHour = hours 1
let ga1 = greatArc (t1, oneHour)
let ga2 = greatArc (t2, oneHour)
intersection ga1 ga2 = Just (decimalLatLong 50.9017225 4.494278333333333)
intersections :: NTransform a => GreatCircle -> GreatCircle -> Maybe (a, a) Source #
Computes the intersections between the two given GreatCircles.
Two GreatCircles intersect exactly twice unless there are equal (regardless of orientation),
in which case Nothing is returned.
let gc1 = greatCircleBearing (decimalLatLong 51.885 0.235) (decimalDegrees 108.63)
let gc2 = greatCircleBearing (decimalLatLong 49.008 2.549) (decimalDegrees 32.72)
let (i1, i2) = fromJust (intersections gc1 gc2)
i1 = decimalLatLong 50.9017226 4.4942782
i2 = antipode i1
isBetween :: NTransform a => a -> GreatArc -> Bool Source #
isBetween p ga determines whether position p is between start and end points
of great arc ga.
If p is not on the great arc, returns whether p is within the area bound
by perpendiculars to the great arc at each point (in the same hemisphere).
isInsideSurface :: (Eq a, NTransform a) => a -> [a] -> Bool Source #
isInsideSurface p ps determines whether the p is inside the polygon defined by the list of positions ps.
The polygon is closed if needed (i.e. if head ps /= last ps).
Uses the angle summation test: on a sphere, due to spherical excess, enclosed point angles will sum to less than 360°, and exterior point angles will be small but non-zero.
Always returns False if ps does not at least defines a triangle.
let malmo = decimalLatLong 55.6050 13.0038
let ystad = decimalLatLong 55.4295 13.82
let lund = decimalLatLong 55.7047 13.1910
let helsingborg = decimalLatLong 56.0465 12.6945
let kristianstad = decimalLatLong 56.0294 14.1567
let polygon = [malmo, ystad, kristianstad, helsingborg, lund]
let hoor = decimalLatLong 55.9295 13.5297
let hassleholm = decimalLatLong 56.1589 13.7668
isInsideSurface hoor polygon = True
isInsideSurface hassleholm polygon = False
mean :: NTransform a => [a] -> Maybe a Source #
mean ps computes the mean geographic horitzontal position of ps, if it is defined.
The geographic mean is not defined for antipodals position (since they cancel each other).
Special conditions:
mean [] = Nothing
mean [p] = Just p
mean [p1, p2, p3] = Just circumcentre
mean [p1, .., antipode p1] = Nothing
surfaceDistance :: NTransform a => a -> a -> Length -> Length Source #
surfaceDistance p1 p2 computes the surface distance (length of geodesic) between the positions p1 and p2.
surfaceDistance84 :: NTransform a => a -> a -> Length Source #
surfaceDistance using the mean radius of the WGS84 reference ellipsoid.