foliage 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +22 -0
  3. data/README.md +9 -0
  4. data/app/assets/images/.keep +0 -0
  5. data/app/assets/images/map/marker/icon-2x.png +0 -0
  6. data/app/assets/images/map/marker/icon.png +0 -0
  7. data/app/assets/images/map/marker/icon.svg +67 -0
  8. data/app/assets/images/map/marker/shadow.png +0 -0
  9. data/app/assets/javascripts/core_ext.js.coffee +61 -0
  10. data/app/assets/javascripts/foliage.js.coffee +23 -0
  11. data/app/assets/javascripts/foliage/band.js.coffee +99 -0
  12. data/app/assets/javascripts/foliage/bubbles.js.coffee +77 -0
  13. data/app/assets/javascripts/foliage/categories.js.coffee +70 -0
  14. data/app/assets/javascripts/foliage/choropleth.js.coffee +51 -0
  15. data/app/assets/javascripts/foliage/color.js.coffee +39 -0
  16. data/app/assets/javascripts/foliage/gradient.js.coffee +72 -0
  17. data/app/assets/javascripts/foliage/heatmap.js.coffee +49 -0
  18. data/app/assets/javascripts/foliage/leaf.js.coffee +422 -0
  19. data/app/assets/javascripts/foliage/path.js.coffee +76 -0
  20. data/app/assets/javascripts/foliage/paths.js.coffee +131 -0
  21. data/app/assets/javascripts/foliage/point_group.js.coffee +83 -0
  22. data/app/assets/javascripts/foliage/points.js.coffee +79 -0
  23. data/app/assets/javascripts/foliage/simple.js.coffee +35 -0
  24. data/app/assets/javascripts/leaflet/geographic_util.js.coffee +23 -0
  25. data/app/assets/javascripts/leaflet/ghost_label.js.coffee +100 -0
  26. data/app/assets/javascripts/leaflet/ghost_label_cluster.js.coffee +192 -0
  27. data/app/assets/javascripts/leaflet/layers_scheduler.js.coffee +57 -0
  28. data/app/assets/javascripts/leaflet/reactive_measure.js.coffee +414 -0
  29. data/app/assets/stylesheets/all.scss +16 -0
  30. data/app/assets/stylesheets/application.css +15 -0
  31. data/app/assets/stylesheets/compass/reset.scss +3 -0
  32. data/app/assets/stylesheets/compass/reset/utilities.scss +142 -0
  33. data/app/assets/stylesheets/leaflet.scss +1093 -0
  34. data/app/assets/stylesheets/leaflet/label.scss +40 -0
  35. data/app/assets/stylesheets/leaflet/tooltip.scss +42 -0
  36. data/app/assets/stylesheets/mixins.scss +131 -0
  37. data/app/assets/stylesheets/reset.scss +89 -0
  38. data/app/assets/stylesheets/variables.scss +47 -0
  39. data/app/helpers/foliage_helper.rb +23 -0
  40. data/lib/foliage.rb +9 -0
  41. data/lib/foliage/leaf.rb +235 -0
  42. data/lib/foliage/rails.rb +2 -0
  43. data/lib/foliage/rails/engine.rb +7 -0
  44. data/lib/foliage/rails/integration.rb +8 -0
  45. data/lib/foliage/version.rb +3 -0
  46. data/vendor/assets/javascripts/.keep +0 -0
  47. data/vendor/assets/javascripts/autosize.js +211 -0
  48. data/vendor/assets/javascripts/geographiclib.js +3074 -0
  49. data/vendor/assets/javascripts/leaflet.js.erb +9175 -0
  50. data/vendor/assets/javascripts/leaflet/draw.js +3573 -0
  51. data/vendor/assets/javascripts/leaflet/easy-button.js +366 -0
  52. data/vendor/assets/javascripts/leaflet/fullscreen.js +162 -0
  53. data/vendor/assets/javascripts/leaflet/heatmap.js +142 -0
  54. data/vendor/assets/javascripts/leaflet/label.js +545 -0
  55. data/vendor/assets/javascripts/leaflet/measure.js +6966 -0
  56. data/vendor/assets/javascripts/leaflet/modal.js +364 -0
  57. data/vendor/assets/javascripts/leaflet/providers.js +479 -0
  58. data/vendor/assets/javascripts/rbush.js +621 -0
  59. data/vendor/assets/stylesheets/.keep +0 -0
  60. data/vendor/assets/stylesheets/bootstrap/mixins.scss +55 -0
  61. data/vendor/assets/stylesheets/bootstrap/variables.scss +10 -0
  62. data/vendor/assets/stylesheets/leaflet.scss +479 -0
  63. data/vendor/assets/stylesheets/leaflet/draw.scss +282 -0
  64. data/vendor/assets/stylesheets/leaflet/easy-button.scss +56 -0
  65. data/vendor/assets/stylesheets/leaflet/fullscreen.scss +2 -0
  66. data/vendor/assets/stylesheets/leaflet/measure.scss +168 -0
  67. data/vendor/assets/stylesheets/leaflet/modal.scss +85 -0
  68. metadata +171 -0
@@ -0,0 +1,2 @@
1
+ require 'foliage/rails/integration'
2
+ require 'foliage/rails/engine'
@@ -0,0 +1,7 @@
1
+ module Foliage
2
+ module Rails
3
+ class Engine < ::Rails::Engine
4
+ engine_name 'foliage'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ module Foliage
2
+ module Rails
3
+ module Integration
4
+ module ActionController
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ module Foliage
2
+ VERSION = :'0.1.0'
3
+ end
File without changes
@@ -0,0 +1,211 @@
1
+ /*!
2
+ Autosize 3.0.5
3
+ license: MIT
4
+ http://www.jacklmoore.com/autosize
5
+ */
6
+ (function (global, factory) {
7
+ if (typeof define === 'function' && define.amd) {
8
+ define(['exports', 'module'], factory);
9
+ } else if (typeof exports !== 'undefined' && typeof module !== 'undefined') {
10
+ factory(exports, module);
11
+ } else {
12
+ var mod = {
13
+ exports: {}
14
+ };
15
+ factory(mod.exports, mod);
16
+ global.autosize = mod.exports;
17
+ }
18
+ })(this, function (exports, module) {
19
+ 'use strict';
20
+
21
+ function assign(ta) {
22
+ var _ref = arguments[1] === undefined ? {} : arguments[1];
23
+
24
+ var _ref$setOverflowX = _ref.setOverflowX;
25
+ var setOverflowX = _ref$setOverflowX === undefined ? true : _ref$setOverflowX;
26
+ var _ref$setOverflowY = _ref.setOverflowY;
27
+ var setOverflowY = _ref$setOverflowY === undefined ? true : _ref$setOverflowY;
28
+
29
+ if (!ta || !ta.nodeName || ta.nodeName !== 'TEXTAREA' || ta.hasAttribute('data-autosize-on')) return;
30
+
31
+ var heightOffset = null;
32
+ var overflowY = 'hidden';
33
+
34
+ function init() {
35
+ var style = window.getComputedStyle(ta, null);
36
+
37
+ if (style.resize === 'vertical') {
38
+ ta.style.resize = 'none';
39
+ } else if (style.resize === 'both') {
40
+ ta.style.resize = 'horizontal';
41
+ }
42
+
43
+ if (style.boxSizing === 'content-box') {
44
+ heightOffset = -(parseFloat(style.paddingTop) + parseFloat(style.paddingBottom));
45
+ } else {
46
+ heightOffset = parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth);
47
+ }
48
+
49
+ update();
50
+ }
51
+
52
+ function changeOverflow(value) {
53
+ {
54
+ // Chrome/Safari-specific fix:
55
+ // When the textarea y-overflow is hidden, Chrome/Safari do not reflow the text to account for the space
56
+ // made available by removing the scrollbar. The following forces the necessary text reflow.
57
+ var width = ta.style.width;
58
+ ta.style.width = '0px';
59
+ // Force reflow:
60
+ /* jshint ignore:start */
61
+ ta.offsetWidth;
62
+ /* jshint ignore:end */
63
+ ta.style.width = width;
64
+ }
65
+
66
+ overflowY = value;
67
+
68
+ if (setOverflowY) {
69
+ ta.style.overflowY = value;
70
+ }
71
+
72
+ update();
73
+ }
74
+
75
+ function update() {
76
+ var startHeight = ta.style.height;
77
+ var htmlTop = document.documentElement.scrollTop;
78
+ var bodyTop = document.body.scrollTop;
79
+ var originalHeight = ta.style.height;
80
+
81
+ ta.style.height = 'auto';
82
+
83
+ var endHeight = ta.scrollHeight + heightOffset;
84
+
85
+ if (ta.scrollHeight === 0) {
86
+ // If the scrollHeight is 0, then the element probably has display:none or is detached from the DOM.
87
+ ta.style.height = originalHeight;
88
+ return;
89
+ }
90
+
91
+ ta.style.height = endHeight + 'px';
92
+
93
+ // prevents scroll-position jumping
94
+ document.documentElement.scrollTop = htmlTop;
95
+ document.body.scrollTop = bodyTop;
96
+
97
+ var style = window.getComputedStyle(ta, null);
98
+
99
+ if (style.height !== ta.style.height) {
100
+ if (overflowY !== 'visible') {
101
+ changeOverflow('visible');
102
+ return;
103
+ }
104
+ } else {
105
+ if (overflowY !== 'hidden') {
106
+ changeOverflow('hidden');
107
+ return;
108
+ }
109
+ }
110
+
111
+ if (startHeight !== ta.style.height) {
112
+ var evt = document.createEvent('Event');
113
+ evt.initEvent('autosize:resized', true, false);
114
+ ta.dispatchEvent(evt);
115
+ }
116
+ }
117
+
118
+ var destroy = (function (style) {
119
+ window.removeEventListener('resize', update);
120
+ ta.removeEventListener('input', update);
121
+ ta.removeEventListener('keyup', update);
122
+ ta.removeAttribute('data-autosize-on');
123
+ ta.removeEventListener('autosize:destroy', destroy);
124
+
125
+ Object.keys(style).forEach(function (key) {
126
+ ta.style[key] = style[key];
127
+ });
128
+ }).bind(ta, {
129
+ height: ta.style.height,
130
+ resize: ta.style.resize,
131
+ overflowY: ta.style.overflowY,
132
+ overflowX: ta.style.overflowX,
133
+ wordWrap: ta.style.wordWrap });
134
+
135
+ ta.addEventListener('autosize:destroy', destroy);
136
+
137
+ // IE9 does not fire onpropertychange or oninput for deletions,
138
+ // so binding to onkeyup to catch most of those events.
139
+ // There is no way that I know of to detect something like 'cut' in IE9.
140
+ if ('onpropertychange' in ta && 'oninput' in ta) {
141
+ ta.addEventListener('keyup', update);
142
+ }
143
+
144
+ window.addEventListener('resize', update);
145
+ ta.addEventListener('input', update);
146
+ ta.addEventListener('autosize:update', update);
147
+ ta.setAttribute('data-autosize-on', true);
148
+
149
+ if (setOverflowY) {
150
+ ta.style.overflowY = 'hidden';
151
+ }
152
+ if (setOverflowX) {
153
+ ta.style.overflowX = 'hidden';
154
+ ta.style.wordWrap = 'break-word';
155
+ }
156
+
157
+ init();
158
+ }
159
+
160
+ function destroy(ta) {
161
+ if (!(ta && ta.nodeName && ta.nodeName === 'TEXTAREA')) return;
162
+ var evt = document.createEvent('Event');
163
+ evt.initEvent('autosize:destroy', true, false);
164
+ ta.dispatchEvent(evt);
165
+ }
166
+
167
+ function update(ta) {
168
+ if (!(ta && ta.nodeName && ta.nodeName === 'TEXTAREA')) return;
169
+ var evt = document.createEvent('Event');
170
+ evt.initEvent('autosize:update', true, false);
171
+ ta.dispatchEvent(evt);
172
+ }
173
+
174
+ var autosize = null;
175
+
176
+ // Do nothing in Node.js environment and IE8 (or lower)
177
+ if (typeof window === 'undefined' || typeof window.getComputedStyle !== 'function') {
178
+ autosize = function (el) {
179
+ return el;
180
+ };
181
+ autosize.destroy = function (el) {
182
+ return el;
183
+ };
184
+ autosize.update = function (el) {
185
+ return el;
186
+ };
187
+ } else {
188
+ autosize = function (el, options) {
189
+ if (el) {
190
+ Array.prototype.forEach.call(el.length ? el : [el], function (x) {
191
+ return assign(x, options);
192
+ });
193
+ }
194
+ return el;
195
+ };
196
+ autosize.destroy = function (el) {
197
+ if (el) {
198
+ Array.prototype.forEach.call(el.length ? el : [el], destroy);
199
+ }
200
+ return el;
201
+ };
202
+ autosize.update = function (el) {
203
+ if (el) {
204
+ Array.prototype.forEach.call(el.length ? el : [el], update);
205
+ }
206
+ return el;
207
+ };
208
+ }
209
+
210
+ module.exports = autosize;
211
+ });
@@ -0,0 +1,3074 @@
1
+ /*
2
+ * Geodesic routines from GeographicLib translated to JavaScript. See
3
+ * http://geographiclib.sourceforge.net/html/js/
4
+ *
5
+ * The algorithms are derived in
6
+ *
7
+ * Charles F. F. Karney,
8
+ * Algorithms for geodesics, J. Geodesy 87, 43-55 (2013),
9
+ * https://dx.doi.org/10.1007/s00190-012-0578-z
10
+ * Addenda: http://geographiclib.sourceforge.net/geod-addenda.html
11
+ *
12
+ * This file is the concatenation and compression of the JavaScript files in
13
+ * doc/scripts/GeographicLib in the source tree for GeographicLib.
14
+ *
15
+ * Copyright (c) Charles Karney (2011-2015) <charles@karney.com> and licensed
16
+ * under the MIT/X11 License. For more information, see
17
+ * http://geographiclib.sourceforge.net/
18
+ *
19
+ * Version: 1.46
20
+ * File inventory:
21
+ * Math.js Geodesic.js GeodesicLine.js PolygonArea.js DMS.js
22
+ */
23
+
24
+ (function(cb) {
25
+
26
+ /**************** Math.js ****************/
27
+ /*
28
+ * Math.js
29
+ * Transcription of Math.hpp, Constants.hpp, and Accumulator.hpp into
30
+ * JavaScript.
31
+ *
32
+ * Copyright (c) Charles Karney (2011-2016) <charles@karney.com> and licensed
33
+ * under the MIT/X11 License. For more information, see
34
+ * http://geographiclib.sourceforge.net/
35
+ */
36
+
37
+ /**
38
+ * @namespace GeographicLib
39
+ * @description The parent namespace for the following modules:
40
+ * - {@link module:GeographicLib/Geodesic GeographicLib/Geodesic} The main
41
+ * engine for solving geodesic problems via the
42
+ * {@link module:GeographicLib/Geodesic.Geodesic Geodesic} class.
43
+ * - {@link module:GeographicLib/GeodesicLine GeographicLib/GeodesicLine}
44
+ * computes points along a single geodesic line via the
45
+ * {@link module:GeographicLib/GeodesicLine.GeodesicLine GeodesicLine}
46
+ * class.
47
+ * - {@link module:GeographicLib/PolygonArea GeographicLib/PolygonArea}
48
+ * computes the area of a geodesic polygon via the
49
+ * {@link module:GeographicLib/PolygonArea.PolygonArea PolygonArea}
50
+ * class.
51
+ * - {@link module:GeographicLib/DMS GeographicLib/DMS} handles the decoding
52
+ * and encoding of angles in degree, minutes, and seconds, via static
53
+ * functions in this module.
54
+ * - {@link module:GeographicLib/Constants GeographicLib/Constants} defines
55
+ * constants specifying the version numbers and the parameters for the WGS84
56
+ * ellipsoid.
57
+ *
58
+ * The following modules are used internally by the package:
59
+ * - {@link module:GeographicLib/Math GeographicLib/Math} defines various
60
+ * mathematical functions.
61
+ * - {@link module:GeographicLib/Accumulator GeographicLib/Accumulator}
62
+ * interally used by
63
+ * {@link module:GeographicLib/PolygonArea.PolygonArea PolygonArea} (via the
64
+ * {@link module:GeographicLib/Accumulator.Accumulator Accumulator} class)
65
+ * for summing the contributions to the area of a polygon.
66
+ */
67
+ "use strict";
68
+ var GeographicLib = {};
69
+ GeographicLib.Constants = {};
70
+ GeographicLib.Math = {};
71
+ GeographicLib.Accumulator = {};
72
+
73
+ (function(
74
+ /**
75
+ * @exports GeographicLib/Constants
76
+ * @description Define constants defining the version and WGS84 parameters.
77
+ */
78
+ c) {
79
+
80
+ /**
81
+ * @constant
82
+ * @summary WGS84 parameters.
83
+ * @property {number} a the equatorial radius (meters).
84
+ * @property {number} f the flattening.
85
+ */
86
+ c.WGS84 = { a: 6378137, f: 1/298.257223563 };
87
+ /**
88
+ * @constant
89
+ * @summary an array of version numbers.
90
+ * @property {number} major the major version number.
91
+ * @property {number} minor the minor version number.
92
+ * @property {number} patch the patch number.
93
+ */
94
+ c.version = { major: 1, minor: 46, patch: 0 };
95
+ /**
96
+ * @constant
97
+ * @summary version string
98
+ */
99
+ c.version_string = "1.46";
100
+ })(GeographicLib.Constants);
101
+
102
+ (function(
103
+ /**
104
+ * @exports GeographicLib/Math
105
+ * @description Some useful mathematical constants and functions (mainly for
106
+ * internal use).
107
+ */
108
+ m) {
109
+
110
+ /**
111
+ * @summary The number of digits of precision in floating-point numbers.
112
+ * @constant {number}
113
+ */
114
+ m.digits = 53;
115
+ /**
116
+ * @summary The machine epsilon.
117
+ * @constant {number}
118
+ */
119
+ m.epsilon = Math.pow(0.5, m.digits - 1);
120
+ /**
121
+ * @summary The factor to convert degrees to radians.
122
+ * @constant {number}
123
+ */
124
+ m.degree = Math.PI/180;
125
+
126
+ /**
127
+ * @summary Square a number.
128
+ * @param {number} x the number.
129
+ * @returns {number} the square.
130
+ */
131
+ m.sq = function(x) { return x * x; };
132
+
133
+ /**
134
+ * @summary The hypotenuse function.
135
+ * @param {number} x the first side.
136
+ * @param {number} y the second side.
137
+ * @returns {number} the hypotenuse.
138
+ */
139
+ m.hypot = function(x, y) {
140
+ var a, b;
141
+ x = Math.abs(x);
142
+ y = Math.abs(y);
143
+ a = Math.max(x, y); b = Math.min(x, y) / (a ? a : 1);
144
+ return a * Math.sqrt(1 + b * b);
145
+ };
146
+
147
+ /**
148
+ * @summary Cube root function.
149
+ * @param {number} x the argument.
150
+ * @returns {number} the real cube root.
151
+ */
152
+ m.cbrt = function(x) {
153
+ var y = Math.pow(Math.abs(x), 1/3);
154
+ return x < 0 ? -y : y;
155
+ };
156
+
157
+ /**
158
+ * @summary The log1p function.
159
+ * @param {number} x the argument.
160
+ * @returns {number} log(1 + x).
161
+ */
162
+ m.log1p = function(x) {
163
+ var y = 1 + x,
164
+ z = y - 1;
165
+ // Here's the explanation for this magic: y = 1 + z, exactly, and z
166
+ // approx x, thus log(y)/z (which is nearly constant near z = 0) returns
167
+ // a good approximation to the true log(1 + x)/x. The multiplication x *
168
+ // (log(y)/z) introduces little additional error.
169
+ return z === 0 ? x : x * Math.log(y) / z;
170
+ };
171
+
172
+ /**
173
+ * @summary Inverse hyperbolic tangent.
174
+ * @param {number} x the argument.
175
+ * @returns {number} tanh<sup>&minus;1</sup> x.
176
+ */
177
+ m.atanh = function(x) {
178
+ var y = Math.abs(x); // Enforce odd parity
179
+ y = m.log1p(2 * y/(1 - y))/2;
180
+ return x < 0 ? -y : y;
181
+ };
182
+
183
+ /**
184
+ * @summary Copy the sign.
185
+ * @param {number} x gives the magitude of the result.
186
+ * @param {number} y gives the sign of the result.
187
+ * @returns {number} value with the magnitude of x and with the sign of y.
188
+ */
189
+ m.copysign = function(x, y) {
190
+ return Math.abs(x) * (y < 0 || (y === 0 && 1/y < 0) ? -1 : 1);
191
+ };
192
+
193
+ /**
194
+ * @summary An error-free sum.
195
+ * @param {number} u
196
+ * @param {number} v
197
+ * @returns {object} sum with sum.s = round(u + v) and sum.t is u + v &minus;
198
+ * round(u + v)
199
+ */
200
+ m.sum = function(u, v) {
201
+ var s = u + v,
202
+ up = s - v,
203
+ vpp = s - up,
204
+ t;
205
+ up -= u;
206
+ vpp -= v;
207
+ t = -(up + vpp);
208
+ // u + v = s + t
209
+ // = round(u + v) + t
210
+ return {s: s, t: t};
211
+ };
212
+
213
+ /**
214
+ * @summary Evaluate a polynomial.
215
+ * @param {integer} N the order of the polynomial.
216
+ * @param {array} p the coefficient array (of size N + 1) (leading
217
+ * order coefficient first)
218
+ * @param {number} x the variable.
219
+ * @returns {number} the value of the polynomial.
220
+ */
221
+ m.polyval = function(N, p, s, x) {
222
+ var y = N < 0 ? 0 : p[s++];
223
+ while (--N >= 0) y = y * x + p[s++];
224
+ return y;
225
+ };
226
+
227
+ /**
228
+ * @summary Coarsen a value close to zero.
229
+ * @param {number} x
230
+ * @returns {number} the coarsened value.
231
+ */
232
+ m.AngRound = function(x) {
233
+ // The makes the smallest gap in x = 1/16 - nextafter(1/16, 0) = 1/2^57 for
234
+ // reals = 0.7 pm on the earth if x is an angle in degrees. (This is about
235
+ // 1000 times more resolution than we get with angles around 90 degrees.)
236
+ // We use this to avoid having to deal with near singular cases when x is
237
+ // non-zero but tiny (e.g., 1.0e-200). This converts -0 to +0; however
238
+ // tiny negative numbers get converted to -0.
239
+ if (x === 0) return x;
240
+ var z = 1/16,
241
+ y = Math.abs(x);
242
+ // The compiler mustn't "simplify" z - (z - y) to y
243
+ y = y < z ? z - (z - y) : y;
244
+ return x < 0 ? -y : y;
245
+ };
246
+
247
+ /**
248
+ * @summary Normalize an angle.
249
+ * @param {number} x the angle in degrees.
250
+ * @returns {number} the angle reduced to the range [&minus;180&deg;,
251
+ * 180&deg;).
252
+ */
253
+ m.AngNormalize = function(x) {
254
+ // Place angle in [-180, 180).
255
+ x = x % 360;
256
+ return x < -180 ? x + 360 : (x < 180 ? x : x - 360);
257
+ };
258
+
259
+ /**
260
+ * @summary Normalize a latitude.
261
+ * @param {number} x the angle in degrees.
262
+ * @returns {number} x if it is in the range [&minus;90&deg;, 90&deg;],
263
+ * otherwise return NaN.
264
+ */
265
+ m.LatFix = function(x) {
266
+ // Replace angle with NaN if outside [-90, 90].
267
+ return Math.abs(x) > 90 ? Number.NaN : x;
268
+ };
269
+
270
+ /**
271
+ * @summary The exact difference of two angles reduced to (&minus;180&deg;,
272
+ * 180&deg;]
273
+ * @param {number} x the first angle in degrees.
274
+ * @param {number} y the second angle in degrees.
275
+ * @return {object} diff the exact difference, y &minus; x.
276
+ *
277
+ * This computes z = y &minus; x exactly, reduced to (&minus;180&deg;,
278
+ * 180&deg;]; and then sets diff.s = d = round(z) and diff.t = e = z &minus;
279
+ * round(z). If d = &minus;180, then e &gt; 0; If d = 180, then e &le; 0.
280
+ */
281
+ m.AngDiff = function(x, y) {
282
+ // Compute y - x and reduce to [-180,180] accurately.
283
+ var r = m.sum(m.AngNormalize(x), m.AngNormalize(-y)),
284
+ d = - m.AngNormalize(r.s),
285
+ t = r.t;
286
+ return m.sum(d === 180 && t < 0 ? -180 : d, -t);
287
+ };
288
+
289
+ /**
290
+ * @summary Evaluate the sine and cosine function with the argument in
291
+ * degrees
292
+ * @param {number} x in degrees.
293
+ * @returns {object} r with r.s = sin(x) and r.c = cos(x).
294
+ */
295
+ m.sincosd = function(x) {
296
+ // In order to minimize round-off errors, this function exactly reduces
297
+ // the argument to the range [-45, 45] before converting it to radians.
298
+ var r, q, s, c, sinx, cosx;
299
+ r = x % 360;
300
+ q = Math.floor(r / 90 + 0.5);
301
+ r -= 90 * q;
302
+ // now abs(r) <= 45
303
+ r *= this.degree;
304
+ // Possibly could call the gnu extension sincos
305
+ s = Math.sin(r); c = Math.cos(r);
306
+ switch (q & 3) {
307
+ case 0: sinx = s; cosx = c; break;
308
+ case 1: sinx = c; cosx = 0 - s; break;
309
+ case 2: sinx = 0 - s; cosx = 0 - c; break;
310
+ default: sinx = 0 - c; cosx = s; break; // case 3
311
+ }
312
+ return {s: sinx, c: cosx};
313
+ };
314
+
315
+ /**
316
+ * @summary Evaluate the atan2 function with the result in degrees
317
+ * @param {number} y
318
+ * @param {number} x
319
+ * @returns atan2(y, x) in degrees, in the range [&minus;180&deg;
320
+ * 180&deg;).
321
+ */
322
+ m.atan2d = function(y, x) {
323
+ // In order to minimize round-off errors, this function rearranges the
324
+ // arguments so that result of atan2 is in the range [-pi/4, pi/4] before
325
+ // converting it to degrees and mapping the result to the correct
326
+ // quadrant.
327
+ var q = 0, t, ang;
328
+ if (Math.abs(y) > Math.abs(x)) { t = x; x = y; y = t; q = 2; }
329
+ if (x < 0) { x = -x; ++q; }
330
+ // here x >= 0 and x >= abs(y), so angle is in [-pi/4, pi/4]
331
+ ang = Math.atan2(y, x) / this.degree;
332
+ switch (q) {
333
+ // Note that atan2d(-0.0, 1.0) will return -0. However, we expect that
334
+ // atan2d will not be called with y = -0. If need be, include
335
+ //
336
+ // case 0: ang = 0 + ang; break;
337
+ //
338
+ // and handle mpfr as in AngRound.
339
+ case 1: ang = (y > 0 ? 180 : -180) - ang; break;
340
+ case 2: ang = 90 - ang; break;
341
+ case 3: ang = -90 + ang; break;
342
+ }
343
+ return ang;
344
+ };
345
+ })(GeographicLib.Math);
346
+
347
+ (function(
348
+ /**
349
+ * @exports GeographicLib/Accumulator
350
+ * @description Accurate summation via the
351
+ * {@link module:GeographicLib/Accumulator.Accumulator Accumulator} class
352
+ * (mainly for internal use).
353
+ */
354
+ a, m) {
355
+
356
+ /**
357
+ * @class
358
+ * @summary Accurate summation of many numbers.
359
+ * @classdesc This allows many numbers to be added together with twice the
360
+ * normal precision. In the documentation of the member functions, sum
361
+ * stands for the value currently held in the accumulator.
362
+ * @param {number | Accumulator} [y = 0] set sum = y.
363
+ */
364
+ a.Accumulator = function(y) {
365
+ this.Set(y);
366
+ };
367
+
368
+ /**
369
+ * @summary Set the accumulator to a number.
370
+ * @param {number | Accumulator} [y = 0] set sum = y.
371
+ */
372
+ a.Accumulator.prototype.Set = function(y) {
373
+ if (!y) y = 0;
374
+ if (y.constructor === a.Accumulator) {
375
+ this._s = y._s;
376
+ this._t = y._t;
377
+ } else {
378
+ this._s = y;
379
+ this._t = 0;
380
+ }
381
+ };
382
+
383
+ /**
384
+ * @summary Add a number to the accumulator.
385
+ * @param {number} [y = 0] set sum += y.
386
+ */
387
+ a.Accumulator.prototype.Add = function(y) {
388
+ // Here's Shewchuk's solution...
389
+ // Accumulate starting at least significant end
390
+ var u = m.sum(y, this._t),
391
+ v = m.sum(u.s, this._s);
392
+ u = u.t;
393
+ this._s = v.s;
394
+ this._t = v.t;
395
+ // Start is _s, _t decreasing and non-adjacent. Sum is now (s + t + u)
396
+ // exactly with s, t, u non-adjacent and in decreasing order (except
397
+ // for possible zeros). The following code tries to normalize the
398
+ // result. Ideally, we want _s = round(s+t+u) and _u = round(s+t+u -
399
+ // _s). The follow does an approximate job (and maintains the
400
+ // decreasing non-adjacent property). Here are two "failures" using
401
+ // 3-bit floats:
402
+ //
403
+ // Case 1: _s is not equal to round(s+t+u) -- off by 1 ulp
404
+ // [12, -1] - 8 -> [4, 0, -1] -> [4, -1] = 3 should be [3, 0] = 3
405
+ //
406
+ // Case 2: _s+_t is not as close to s+t+u as it shold be
407
+ // [64, 5] + 4 -> [64, 8, 1] -> [64, 8] = 72 (off by 1)
408
+ // should be [80, -7] = 73 (exact)
409
+ //
410
+ // "Fixing" these problems is probably not worth the expense. The
411
+ // representation inevitably leads to small errors in the accumulated
412
+ // values. The additional errors illustrated here amount to 1 ulp of
413
+ // the less significant word during each addition to the Accumulator
414
+ // and an additional possible error of 1 ulp in the reported sum.
415
+ //
416
+ // Incidentally, the "ideal" representation described above is not
417
+ // canonical, because _s = round(_s + _t) may not be true. For
418
+ // example, with 3-bit floats:
419
+ //
420
+ // [128, 16] + 1 -> [160, -16] -- 160 = round(145).
421
+ // But [160, 0] - 16 -> [128, 16] -- 128 = round(144).
422
+ //
423
+ if (this._s === 0) // This implies t == 0,
424
+ this._s = u; // so result is u
425
+ else
426
+ this._t += u; // otherwise just accumulate u to t.
427
+ };
428
+
429
+ /**
430
+ * @summary Return the result of adding a number to sum (but
431
+ * don't change sum).
432
+ * @param {number} [y = 0] the number to be added to the sum.
433
+ * @return sum + y.
434
+ */
435
+ a.Accumulator.prototype.Sum = function(y) {
436
+ var b;
437
+ if (!y)
438
+ return this._s;
439
+ else {
440
+ b = new a.Accumulator(this);
441
+ b.Add(y);
442
+ return b._s;
443
+ }
444
+ };
445
+
446
+ /**
447
+ * @summary Set sum = &minus;sum.
448
+ */
449
+ a.Accumulator.prototype.Negate = function() {
450
+ this._s *= -1;
451
+ this._t *= -1;
452
+ };
453
+ })(GeographicLib.Accumulator, GeographicLib.Math);
454
+
455
+ /**************** Geodesic.js ****************/
456
+ /*
457
+ * Geodesic.js
458
+ * Transcription of Geodesic.[ch]pp into JavaScript.
459
+ *
460
+ * See the documentation for the C++ class. The conversion is a literal
461
+ * conversion from C++.
462
+ *
463
+ * The algorithms are derived in
464
+ *
465
+ * Charles F. F. Karney,
466
+ * Algorithms for geodesics, J. Geodesy 87, 43-55 (2013);
467
+ * https://dx.doi.org/10.1007/s00190-012-0578-z
468
+ * Addenda: http://geographiclib.sourceforge.net/geod-addenda.html
469
+ *
470
+ * Copyright (c) Charles Karney (2011-2016) <charles@karney.com> and licensed
471
+ * under the MIT/X11 License. For more information, see
472
+ * http://geographiclib.sourceforge.net/
473
+ */
474
+
475
+ // Load AFTER Math.js
476
+
477
+ GeographicLib.Geodesic = {};
478
+ GeographicLib.GeodesicLine = {};
479
+ GeographicLib.PolygonArea = {};
480
+
481
+ (function(
482
+ /**
483
+ * @exports GeographicLib/Geodesic
484
+ * @description Solve geodesic problems via the
485
+ * {@link module:GeographicLib/Geodesic.Geodesic Geodesic} class.
486
+ */
487
+ g, l, p, m, c) {
488
+
489
+ var GEOGRAPHICLIB_GEODESIC_ORDER = 6,
490
+ nA1_ = GEOGRAPHICLIB_GEODESIC_ORDER,
491
+ nA2_ = GEOGRAPHICLIB_GEODESIC_ORDER,
492
+ nA3_ = GEOGRAPHICLIB_GEODESIC_ORDER,
493
+ nA3x_ = nA3_,
494
+ nC3x_, nC4x_,
495
+ maxit1_ = 20,
496
+ maxit2_ = maxit1_ + m.digits + 10,
497
+ tol0_ = m.epsilon,
498
+ tol1_ = 200 * tol0_,
499
+ tol2_ = Math.sqrt(tol0_),
500
+ tolb_ = tol0_ * tol1_,
501
+ xthresh_ = 1000 * tol2_,
502
+ CAP_NONE = 0,
503
+ CAP_ALL = 0x1F,
504
+ CAP_MASK = CAP_ALL,
505
+ OUT_ALL = 0x7F80,
506
+ astroid,
507
+ A1m1f_coeff, C1f_coeff, C1pf_coeff,
508
+ A2m1f_coeff, C2f_coeff,
509
+ A3_coeff, C3_coeff, C4_coeff;
510
+
511
+ g.tiny_ = Math.sqrt(Number.MIN_VALUE);
512
+ g.nC1_ = GEOGRAPHICLIB_GEODESIC_ORDER;
513
+ g.nC1p_ = GEOGRAPHICLIB_GEODESIC_ORDER;
514
+ g.nC2_ = GEOGRAPHICLIB_GEODESIC_ORDER;
515
+ g.nC3_ = GEOGRAPHICLIB_GEODESIC_ORDER;
516
+ g.nC4_ = GEOGRAPHICLIB_GEODESIC_ORDER;
517
+ nC3x_ = (g.nC3_ * (g.nC3_ - 1)) / 2;
518
+ nC4x_ = (g.nC4_ * (g.nC4_ + 1)) / 2;
519
+ g.CAP_C1 = 1<<0;
520
+ g.CAP_C1p = 1<<1;
521
+ g.CAP_C2 = 1<<2;
522
+ g.CAP_C3 = 1<<3;
523
+ g.CAP_C4 = 1<<4;
524
+
525
+ g.NONE = 0;
526
+ g.ARC = 1<<6;
527
+ g.LATITUDE = 1<<7 | CAP_NONE;
528
+ g.LONGITUDE = 1<<8 | g.CAP_C3;
529
+ g.AZIMUTH = 1<<9 | CAP_NONE;
530
+ g.DISTANCE = 1<<10 | g.CAP_C1;
531
+ g.STANDARD = g.LATITUDE | g.LONGITUDE | g.AZIMUTH | g.DISTANCE;
532
+ g.DISTANCE_IN = 1<<11 | g.CAP_C1 | g.CAP_C1p;
533
+ g.REDUCEDLENGTH = 1<<12 | g.CAP_C1 | g.CAP_C2;
534
+ g.GEODESICSCALE = 1<<13 | g.CAP_C1 | g.CAP_C2;
535
+ g.AREA = 1<<14 | g.CAP_C4;
536
+ g.ALL = OUT_ALL| CAP_ALL;
537
+ g.LONG_UNROLL = 1<<15;
538
+ g.OUT_MASK = OUT_ALL| g.LONG_UNROLL;
539
+
540
+ g.SinCosSeries = function(sinp, sinx, cosx, c) {
541
+ // Evaluate
542
+ // y = sinp ? sum(c[i] * sin( 2*i * x), i, 1, n) :
543
+ // sum(c[i] * cos((2*i+1) * x), i, 0, n-1)
544
+ // using Clenshaw summation. N.B. c[0] is unused for sin series
545
+ // Approx operation count = (n + 5) mult and (2 * n + 2) add
546
+ var k = c.length, // Point to one beyond last element
547
+ n = k - (sinp ? 1 : 0),
548
+ ar = 2 * (cosx - sinx) * (cosx + sinx), // 2 * cos(2 * x)
549
+ y0 = n & 1 ? c[--k] : 0, y1 = 0; // accumulators for sum
550
+ // Now n is even
551
+ n = Math.floor(n/2);
552
+ while (n--) {
553
+ // Unroll loop x 2, so accumulators return to their original role
554
+ y1 = ar * y0 - y1 + c[--k];
555
+ y0 = ar * y1 - y0 + c[--k];
556
+ }
557
+ return (sinp ? 2 * sinx * cosx * y0 : // sin(2 * x) * y0
558
+ cosx * (y0 - y1)); // cos(x) * (y0 - y1)
559
+ };
560
+
561
+ astroid = function(x, y) {
562
+ // Solve k^4+2*k^3-(x^2+y^2-1)*k^2-2*y^2*k-y^2 = 0 for positive
563
+ // root k. This solution is adapted from Geocentric::Reverse.
564
+ var k,
565
+ p = m.sq(x),
566
+ q = m.sq(y),
567
+ r = (p + q - 1) / 6,
568
+ S, r2, r3, disc, u, T3, T, ang, v, uv, w;
569
+ if ( !(q === 0 && r <= 0) ) {
570
+ // Avoid possible division by zero when r = 0 by multiplying
571
+ // equations for s and t by r^3 and r, resp.
572
+ S = p * q / 4; // S = r^3 * s
573
+ r2 = m.sq(r);
574
+ r3 = r * r2;
575
+ // The discriminant of the quadratic equation for T3. This is
576
+ // zero on the evolute curve p^(1/3)+q^(1/3) = 1
577
+ disc = S * (S + 2 * r3);
578
+ u = r;
579
+ if (disc >= 0) {
580
+ T3 = S + r3;
581
+ // Pick the sign on the sqrt to maximize abs(T3). This
582
+ // minimizes loss of precision due to cancellation. The
583
+ // result is unchanged because of the way the T is used
584
+ // in definition of u.
585
+ T3 += T3 < 0 ? -Math.sqrt(disc) : Math.sqrt(disc); // T3 = (r * t)^3
586
+ // N.B. cbrt always returns the real root. cbrt(-8) = -2.
587
+ T = m.cbrt(T3); // T = r * t
588
+ // T can be zero; but then r2 / T -> 0.
589
+ u += T + (T !== 0 ? r2 / T : 0);
590
+ } else {
591
+ // T is complex, but the way u is defined the result is real.
592
+ ang = Math.atan2(Math.sqrt(-disc), -(S + r3));
593
+ // There are three possible cube roots. We choose the
594
+ // root which avoids cancellation. Note that disc < 0
595
+ // implies that r < 0.
596
+ u += 2 * r * Math.cos(ang / 3);
597
+ }
598
+ v = Math.sqrt(m.sq(u) + q); // guaranteed positive
599
+ // Avoid loss of accuracy when u < 0.
600
+ uv = u < 0 ? q / (v - u) : u + v; // u+v, guaranteed positive
601
+ w = (uv - q) / (2 * v); // positive?
602
+ // Rearrange expression for k to avoid loss of accuracy due to
603
+ // subtraction. Division by 0 not possible because uv > 0, w >= 0.
604
+ k = uv / (Math.sqrt(uv + m.sq(w)) + w); // guaranteed positive
605
+ } else { // q == 0 && r <= 0
606
+ // y = 0 with |x| <= 1. Handle this case directly.
607
+ // for y small, positive root is k = abs(y)/sqrt(1-x^2)
608
+ k = 0;
609
+ }
610
+ return k;
611
+ };
612
+
613
+ A1m1f_coeff = [
614
+ // (1-eps)*A1-1, polynomial in eps2 of order 3
615
+ +1, 4, 64, 0, 256
616
+ ];
617
+
618
+ // The scale factor A1-1 = mean value of (d/dsigma)I1 - 1
619
+ g.A1m1f = function(eps) {
620
+ var p = Math.floor(nA1_/2),
621
+ t = m.polyval(p, A1m1f_coeff, 0, m.sq(eps)) / A1m1f_coeff[p + 1];
622
+ return (t + eps) / (1 - eps);
623
+ };
624
+
625
+ C1f_coeff = [
626
+ // C1[1]/eps^1, polynomial in eps2 of order 2
627
+ -1, 6, -16, 32,
628
+ // C1[2]/eps^2, polynomial in eps2 of order 2
629
+ -9, 64, -128, 2048,
630
+ // C1[3]/eps^3, polynomial in eps2 of order 1
631
+ +9, -16, 768,
632
+ // C1[4]/eps^4, polynomial in eps2 of order 1
633
+ +3, -5, 512,
634
+ // C1[5]/eps^5, polynomial in eps2 of order 0
635
+ -7, 1280,
636
+ // C1[6]/eps^6, polynomial in eps2 of order 0
637
+ -7, 2048
638
+ ];
639
+
640
+ // The coefficients C1[l] in the Fourier expansion of B1
641
+ g.C1f = function(eps, c) {
642
+ var eps2 = m.sq(eps),
643
+ d = eps,
644
+ o = 0,
645
+ l, p;
646
+ for (l = 1; l <= g.nC1_; ++l) { // l is index of C1p[l]
647
+ p = Math.floor((g.nC1_ - l) / 2); // order of polynomial in eps^2
648
+ c[l] = d * m.polyval(p, C1f_coeff, o, eps2) / C1f_coeff[o + p + 1];
649
+ o += p + 2;
650
+ d *= eps;
651
+ }
652
+ };
653
+
654
+ C1pf_coeff = [
655
+ // C1p[1]/eps^1, polynomial in eps2 of order 2
656
+ +205, -432, 768, 1536,
657
+ // C1p[2]/eps^2, polynomial in eps2 of order 2
658
+ +4005, -4736, 3840, 12288,
659
+ // C1p[3]/eps^3, polynomial in eps2 of order 1
660
+ -225, 116, 384,
661
+ // C1p[4]/eps^4, polynomial in eps2 of order 1
662
+ -7173, 2695, 7680,
663
+ // C1p[5]/eps^5, polynomial in eps2 of order 0
664
+ +3467, 7680,
665
+ // C1p[6]/eps^6, polynomial in eps2 of order 0
666
+ +38081, 61440
667
+ ];
668
+
669
+ // The coefficients C1p[l] in the Fourier expansion of B1p
670
+ g.C1pf = function(eps, c) {
671
+ var eps2 = m.sq(eps),
672
+ d = eps,
673
+ o = 0,
674
+ l, p;
675
+ for (l = 1; l <= g.nC1p_; ++l) { // l is index of C1p[l]
676
+ p = Math.floor((g.nC1p_ - l) / 2); // order of polynomial in eps^2
677
+ c[l] = d * m.polyval(p, C1pf_coeff, o, eps2) / C1pf_coeff[o + p + 1];
678
+ o += p + 2;
679
+ d *= eps;
680
+ }
681
+ };
682
+
683
+ A2m1f_coeff = [
684
+ // (eps+1)*A2-1, polynomial in eps2 of order 3
685
+ -11, -28, -192, 0, 256
686
+ ];
687
+
688
+ // The scale factor A2-1 = mean value of (d/dsigma)I2 - 1
689
+ g.A2m1f = function(eps) {
690
+ var p = Math.floor(nA2_/2),
691
+ t = m.polyval(p, A2m1f_coeff, 0, m.sq(eps)) / A2m1f_coeff[p + 1];
692
+ return (t - eps) / (1 + eps);
693
+ };
694
+
695
+ C2f_coeff = [
696
+ // C2[1]/eps^1, polynomial in eps2 of order 2
697
+ +1, 2, 16, 32,
698
+ // C2[2]/eps^2, polynomial in eps2 of order 2
699
+ +35, 64, 384, 2048,
700
+ // C2[3]/eps^3, polynomial in eps2 of order 1
701
+ +15, 80, 768,
702
+ // C2[4]/eps^4, polynomial in eps2 of order 1
703
+ +7, 35, 512,
704
+ // C2[5]/eps^5, polynomial in eps2 of order 0
705
+ +63, 1280,
706
+ // C2[6]/eps^6, polynomial in eps2 of order 0
707
+ +77, 2048
708
+ ];
709
+
710
+ // The coefficients C2[l] in the Fourier expansion of B2
711
+ g.C2f = function(eps, c) {
712
+ var eps2 = m.sq(eps),
713
+ d = eps,
714
+ o = 0,
715
+ l, p;
716
+ for (l = 1; l <= g.nC2_; ++l) { // l is index of C2[l]
717
+ p = Math.floor((g.nC2_ - l) / 2); // order of polynomial in eps^2
718
+ c[l] = d * m.polyval(p, C2f_coeff, o, eps2) / C2f_coeff[o + p + 1];
719
+ o += p + 2;
720
+ d *= eps;
721
+ }
722
+ };
723
+
724
+ /**
725
+ * @class
726
+ * @property {number} a the equatorial radius (meters).
727
+ * @property {number} f the flattening.
728
+ * @summary Initialize a Geodesic object for a specific ellipsoid.
729
+ * @classdesc Performs geodesic calculations on an ellipsoid of revolution.
730
+ * The routines for solving the direct and inverse problems return an
731
+ * object with some of the following fields set: lat1, lon1, azi1, lat2,
732
+ * lon2, azi2, s12, a12, m12, M12, M21, S12. See {@tutorial 2-interface},
733
+ * "The results".
734
+ * @example
735
+ * var GeographicLib = require("geographiclib"),
736
+ * geod = GeographicLib.Geodesic.WGS84;
737
+ * var inv = geod.Inverse(1,2,3,4);
738
+ * console.log("lat1 = " + inv.lat1 + ", lon1 = " + inv.lon1 +
739
+ * ", lat2 = " + inv.lat2 + ", lon2 = " + inv.lon2 +
740
+ * ",\nazi1 = " + inv.azi1 + ", azi2 = " + inv.azi2 +
741
+ * ", s12 = " + inv.s12);
742
+ * @param {number} a the equatorial radius of the ellipsoid (meters).
743
+ * @param {number} f the flattening of the ellipsoid. Setting f = 0 gives
744
+ * a sphere (on which geodesics are great circles). Negative f gives a
745
+ * prolate ellipsoid.
746
+ * @throws an error if the parameters are illegal.
747
+ */
748
+ g.Geodesic = function(a, f) {
749
+ this.a = a;
750
+ this.f = f;
751
+ this._f1 = 1 - this.f;
752
+ this._e2 = this.f * (2 - this.f);
753
+ this._ep2 = this._e2 / m.sq(this._f1); // e2 / (1 - e2)
754
+ this._n = this.f / ( 2 - this.f);
755
+ this._b = this.a * this._f1;
756
+ // authalic radius squared
757
+ this._c2 = (m.sq(this.a) + m.sq(this._b) *
758
+ (this._e2 === 0 ? 1 :
759
+ (this._e2 > 0 ? m.atanh(Math.sqrt(this._e2)) :
760
+ Math.atan(Math.sqrt(-this._e2))) /
761
+ Math.sqrt(Math.abs(this._e2))))/2;
762
+ // The sig12 threshold for "really short". Using the auxiliary sphere
763
+ // solution with dnm computed at (bet1 + bet2) / 2, the relative error in
764
+ // the azimuth consistency check is sig12^2 * abs(f) * min(1, 1-f/2) / 2.
765
+ // (Error measured for 1/100 < b/a < 100 and abs(f) >= 1/1000. For a given
766
+ // f and sig12, the max error occurs for lines near the pole. If the old
767
+ // rule for computing dnm = (dn1 + dn2)/2 is used, then the error increases
768
+ // by a factor of 2.) Setting this equal to epsilon gives sig12 = etol2.
769
+ // Here 0.1 is a safety factor (error decreased by 100) and max(0.001,
770
+ // abs(f)) stops etol2 getting too large in the nearly spherical case.
771
+ this._etol2 = 0.1 * tol2_ /
772
+ Math.sqrt( Math.max(0.001, Math.abs(this.f)) *
773
+ Math.min(1.0, 1 - this.f/2) / 2 );
774
+ if (!(isFinite(this.a) && this.a > 0))
775
+ throw new Error("Major radius is not positive");
776
+ if (!(isFinite(this._b) && this._b > 0))
777
+ throw new Error("Minor radius is not positive");
778
+ this._A3x = new Array(nA3x_);
779
+ this._C3x = new Array(nC3x_);
780
+ this._C4x = new Array(nC4x_);
781
+ this.A3coeff();
782
+ this.C3coeff();
783
+ this.C4coeff();
784
+ };
785
+
786
+ A3_coeff = [
787
+ // A3, coeff of eps^5, polynomial in n of order 0
788
+ -3, 128,
789
+ // A3, coeff of eps^4, polynomial in n of order 1
790
+ -2, -3, 64,
791
+ // A3, coeff of eps^3, polynomial in n of order 2
792
+ -1, -3, -1, 16,
793
+ // A3, coeff of eps^2, polynomial in n of order 2
794
+ +3, -1, -2, 8,
795
+ // A3, coeff of eps^1, polynomial in n of order 1
796
+ +1, -1, 2,
797
+ // A3, coeff of eps^0, polynomial in n of order 0
798
+ +1, 1
799
+ ];
800
+
801
+ // The scale factor A3 = mean value of (d/dsigma)I3
802
+ g.Geodesic.prototype.A3coeff = function() {
803
+ var o = 0, k = 0,
804
+ j, p;
805
+ for (j = nA3_ - 1; j >= 0; --j) { // coeff of eps^j
806
+ p = Math.min(nA3_ - j - 1, j); // order of polynomial in n
807
+ this._A3x[k++] = m.polyval(p, A3_coeff, o, this._n) /
808
+ A3_coeff[o + p + 1];
809
+ o += p + 2;
810
+ }
811
+ };
812
+
813
+ C3_coeff = [
814
+ // C3[1], coeff of eps^5, polynomial in n of order 0
815
+ +3, 128,
816
+ // C3[1], coeff of eps^4, polynomial in n of order 1
817
+ +2, 5, 128,
818
+ // C3[1], coeff of eps^3, polynomial in n of order 2
819
+ -1, 3, 3, 64,
820
+ // C3[1], coeff of eps^2, polynomial in n of order 2
821
+ -1, 0, 1, 8,
822
+ // C3[1], coeff of eps^1, polynomial in n of order 1
823
+ -1, 1, 4,
824
+ // C3[2], coeff of eps^5, polynomial in n of order 0
825
+ +5, 256,
826
+ // C3[2], coeff of eps^4, polynomial in n of order 1
827
+ +1, 3, 128,
828
+ // C3[2], coeff of eps^3, polynomial in n of order 2
829
+ -3, -2, 3, 64,
830
+ // C3[2], coeff of eps^2, polynomial in n of order 2
831
+ +1, -3, 2, 32,
832
+ // C3[3], coeff of eps^5, polynomial in n of order 0
833
+ +7, 512,
834
+ // C3[3], coeff of eps^4, polynomial in n of order 1
835
+ -10, 9, 384,
836
+ // C3[3], coeff of eps^3, polynomial in n of order 2
837
+ +5, -9, 5, 192,
838
+ // C3[4], coeff of eps^5, polynomial in n of order 0
839
+ +7, 512,
840
+ // C3[4], coeff of eps^4, polynomial in n of order 1
841
+ -14, 7, 512,
842
+ // C3[5], coeff of eps^5, polynomial in n of order 0
843
+ +21, 2560
844
+ ];
845
+
846
+ // The coefficients C3[l] in the Fourier expansion of B3
847
+ g.Geodesic.prototype.C3coeff = function() {
848
+ var o = 0, k = 0,
849
+ l, j, p;
850
+ for (l = 1; l < g.nC3_; ++l) { // l is index of C3[l]
851
+ for (j = g.nC3_ - 1; j >= l; --j) { // coeff of eps^j
852
+ p = Math.min(g.nC3_ - j - 1, j); // order of polynomial in n
853
+ this._C3x[k++] = m.polyval(p, C3_coeff, o, this._n) /
854
+ C3_coeff[o + p + 1];
855
+ o += p + 2;
856
+ }
857
+ }
858
+ };
859
+
860
+ C4_coeff = [
861
+ // C4[0], coeff of eps^5, polynomial in n of order 0
862
+ +97, 15015,
863
+ // C4[0], coeff of eps^4, polynomial in n of order 1
864
+ +1088, 156, 45045,
865
+ // C4[0], coeff of eps^3, polynomial in n of order 2
866
+ -224, -4784, 1573, 45045,
867
+ // C4[0], coeff of eps^2, polynomial in n of order 3
868
+ -10656, 14144, -4576, -858, 45045,
869
+ // C4[0], coeff of eps^1, polynomial in n of order 4
870
+ +64, 624, -4576, 6864, -3003, 15015,
871
+ // C4[0], coeff of eps^0, polynomial in n of order 5
872
+ +100, 208, 572, 3432, -12012, 30030, 45045,
873
+ // C4[1], coeff of eps^5, polynomial in n of order 0
874
+ +1, 9009,
875
+ // C4[1], coeff of eps^4, polynomial in n of order 1
876
+ -2944, 468, 135135,
877
+ // C4[1], coeff of eps^3, polynomial in n of order 2
878
+ +5792, 1040, -1287, 135135,
879
+ // C4[1], coeff of eps^2, polynomial in n of order 3
880
+ +5952, -11648, 9152, -2574, 135135,
881
+ // C4[1], coeff of eps^1, polynomial in n of order 4
882
+ -64, -624, 4576, -6864, 3003, 135135,
883
+ // C4[2], coeff of eps^5, polynomial in n of order 0
884
+ +8, 10725,
885
+ // C4[2], coeff of eps^4, polynomial in n of order 1
886
+ +1856, -936, 225225,
887
+ // C4[2], coeff of eps^3, polynomial in n of order 2
888
+ -8448, 4992, -1144, 225225,
889
+ // C4[2], coeff of eps^2, polynomial in n of order 3
890
+ -1440, 4160, -4576, 1716, 225225,
891
+ // C4[3], coeff of eps^5, polynomial in n of order 0
892
+ -136, 63063,
893
+ // C4[3], coeff of eps^4, polynomial in n of order 1
894
+ +1024, -208, 105105,
895
+ // C4[3], coeff of eps^3, polynomial in n of order 2
896
+ +3584, -3328, 1144, 315315,
897
+ // C4[4], coeff of eps^5, polynomial in n of order 0
898
+ -128, 135135,
899
+ // C4[4], coeff of eps^4, polynomial in n of order 1
900
+ -2560, 832, 405405,
901
+ // C4[5], coeff of eps^5, polynomial in n of order 0
902
+ +128, 99099
903
+ ];
904
+
905
+ g.Geodesic.prototype.C4coeff = function() {
906
+ var o = 0, k = 0,
907
+ l, j, p;
908
+ for (l = 0; l < g.nC4_; ++l) { // l is index of C4[l]
909
+ for (j = g.nC4_ - 1; j >= l; --j) { // coeff of eps^j
910
+ p = g.nC4_ - j - 1; // order of polynomial in n
911
+ this._C4x[k++] = m.polyval(p, C4_coeff, o, this._n) /
912
+ C4_coeff[o + p + 1];
913
+ o += p + 2;
914
+ }
915
+ }
916
+ };
917
+
918
+ g.Geodesic.prototype.A3f = function(eps) {
919
+ // Evaluate A3
920
+ return m.polyval(nA3x_ - 1, this._A3x, 0, eps);
921
+ };
922
+
923
+ g.Geodesic.prototype.C3f = function(eps, c) {
924
+ // Evaluate C3 coeffs
925
+ // Elements c[1] thru c[nC3_ - 1] are set
926
+ var mult = 1,
927
+ o = 0,
928
+ l, p;
929
+ for (l = 1; l < g.nC3_; ++l) { // l is index of C3[l]
930
+ p = g.nC3_ - l - 1; // order of polynomial in eps
931
+ mult *= eps;
932
+ c[l] = mult * m.polyval(p, this._C3x, o, eps);
933
+ o += p + 1;
934
+ }
935
+ };
936
+
937
+ g.Geodesic.prototype.C4f = function(eps, c) {
938
+ // Evaluate C4 coeffs
939
+ // Elements c[0] thru c[g.nC4_ - 1] are set
940
+ var mult = 1,
941
+ o = 0,
942
+ l, p;
943
+ for (l = 0; l < g.nC4_; ++l) { // l is index of C4[l]
944
+ p = g.nC4_ - l - 1; // order of polynomial in eps
945
+ c[l] = mult * m.polyval(p, this._C4x, o, eps);
946
+ o += p + 1;
947
+ mult *= eps;
948
+ }
949
+ };
950
+
951
+ // return s12b, m12b, m0, M12, M21
952
+ g.Geodesic.prototype.Lengths = function(eps, sig12,
953
+ ssig1, csig1, dn1, ssig2, csig2, dn2,
954
+ cbet1, cbet2, outmask,
955
+ C1a, C2a) {
956
+ // Return m12b = (reduced length)/_b; also calculate s12b =
957
+ // distance/_b, and m0 = coefficient of secular term in
958
+ // expression for reduced length.
959
+ outmask &= g.OUT_MASK;
960
+ var vals = {},
961
+ m0x = 0, J12 = 0, A1 = 0, A2 = 0,
962
+ B1, B2, l, csig12, t;
963
+ if (outmask & (g.DISTANCE | g.REDUCEDLENGTH | g.GEODESICSCALE)) {
964
+ A1 = g.A1m1f(eps);
965
+ g.C1f(eps, C1a);
966
+ if (outmask & (g.REDUCEDLENGTH | g.GEODESICSCALE)) {
967
+ A2 = g.A2m1f(eps);
968
+ g.C2f(eps, C2a);
969
+ m0x = A1 - A2;
970
+ A2 = 1 + A2;
971
+ }
972
+ A1 = 1 + A1;
973
+ }
974
+ if (outmask & g.DISTANCE) {
975
+ B1 = g.SinCosSeries(true, ssig2, csig2, C1a) -
976
+ g.SinCosSeries(true, ssig1, csig1, C1a);
977
+ // Missing a factor of _b
978
+ vals.s12b = A1 * (sig12 + B1);
979
+ if (outmask & (g.REDUCEDLENGTH | g.GEODESICSCALE)) {
980
+ B2 = g.SinCosSeries(true, ssig2, csig2, C2a) -
981
+ g.SinCosSeries(true, ssig1, csig1, C2a);
982
+ J12 = m0x * sig12 + (A1 * B1 - A2 * B2);
983
+ }
984
+ } else if (outmask & (g.REDUCEDLENGTH | g.GEODESICSCALE)) {
985
+ // Assume here that nC1_ >= nC2_
986
+ for (l = 1; l <= g.nC2_; ++l)
987
+ C2a[l] = A1 * C1a[l] - A2 * C2a[l];
988
+ J12 = m0x * sig12 + (g.SinCosSeries(true, ssig2, csig2, C2a) -
989
+ g.SinCosSeries(true, ssig1, csig1, C2a));
990
+ }
991
+ if (outmask & g.REDUCEDLENGTH) {
992
+ vals.m0 = m0x;
993
+ // Missing a factor of _b.
994
+ // Add parens around (csig1 * ssig2) and (ssig1 * csig2) to ensure
995
+ // accurate cancellation in the case of coincident points.
996
+ vals.m12b = dn2 * (csig1 * ssig2) - dn1 * (ssig1 * csig2) -
997
+ csig1 * csig2 * J12;
998
+ }
999
+ if (outmask & g.GEODESICSCALE) {
1000
+ csig12 = csig1 * csig2 + ssig1 * ssig2;
1001
+ t = this._ep2 * (cbet1 - cbet2) * (cbet1 + cbet2) / (dn1 + dn2);
1002
+ vals.M12 = csig12 + (t * ssig2 - csig2 * J12) * ssig1 / dn1;
1003
+ vals.M21 = csig12 - (t * ssig1 - csig1 * J12) * ssig2 / dn2;
1004
+ }
1005
+ return vals;
1006
+ };
1007
+
1008
+ // return sig12, salp1, calp1, salp2, calp2, dnm
1009
+ g.Geodesic.prototype.InverseStart = function(sbet1, cbet1, dn1,
1010
+ sbet2, cbet2, dn2,
1011
+ lam12, slam12, clam12,
1012
+ C1a, C2a) {
1013
+ // Return a starting point for Newton's method in salp1 and calp1
1014
+ // (function value is -1). If Newton's method doesn't need to be
1015
+ // used, return also salp2 and calp2 and function value is sig12.
1016
+ // salp2, calp2 only updated if return val >= 0.
1017
+ var vals = {},
1018
+ // bet12 = bet2 - bet1 in [0, pi); bet12a = bet2 + bet1 in (-pi, 0]
1019
+ sbet12 = sbet2 * cbet1 - cbet2 * sbet1,
1020
+ cbet12 = cbet2 * cbet1 + sbet2 * sbet1,
1021
+ sbet12a, shortline, omg12, sbetm2, somg12, comg12, t, ssig12, csig12,
1022
+ x, y, lamscale, betscale, k2, eps, cbet12a, bet12a, m12b, m0, nvals,
1023
+ k, omg12a, lam12x;
1024
+ vals.sig12 = -1; // Return value
1025
+ // Volatile declaration needed to fix inverse cases
1026
+ // 88.202499451857 0 -88.202499451857 179.981022032992859592
1027
+ // 89.262080389218 0 -89.262080389218 179.992207982775375662
1028
+ // 89.333123580033 0 -89.333123580032997687 179.99295812360148422
1029
+ // which otherwise fail with g++ 4.4.4 x86 -O3
1030
+ sbet12a = sbet2 * cbet1;
1031
+ sbet12a += cbet2 * sbet1;
1032
+
1033
+ shortline = cbet12 >= 0 && sbet12 < 0.5 && cbet2 * lam12 < 0.5;
1034
+ if (shortline) {
1035
+ sbetm2 = m.sq(sbet1 + sbet2);
1036
+ // sin((bet1+bet2)/2)^2
1037
+ // = (sbet1 + sbet2)^2 / ((sbet1 + sbet2)^2 + (cbet1 + cbet2)^2)
1038
+ sbetm2 /= sbetm2 + m.sq(cbet1 + cbet2);
1039
+ vals.dnm = Math.sqrt(1 + this._ep2 * sbetm2);
1040
+ omg12 = lam12 / (this._f1 * vals.dnm);
1041
+ somg12 = Math.sin(omg12); comg12 = Math.cos(omg12);
1042
+ } else {
1043
+ somg12 = slam12; comg12 = clam12;
1044
+ }
1045
+
1046
+ vals.salp1 = cbet2 * somg12;
1047
+ vals.calp1 = comg12 >= 0 ?
1048
+ sbet12 + cbet2 * sbet1 * m.sq(somg12) / (1 + comg12) :
1049
+ sbet12a - cbet2 * sbet1 * m.sq(somg12) / (1 - comg12);
1050
+
1051
+ ssig12 = m.hypot(vals.salp1, vals.calp1);
1052
+ csig12 = sbet1 * sbet2 + cbet1 * cbet2 * comg12;
1053
+ if (shortline && ssig12 < this._etol2) {
1054
+ // really short lines
1055
+ vals.salp2 = cbet1 * somg12;
1056
+ vals.calp2 = sbet12 - cbet1 * sbet2 *
1057
+ (comg12 >= 0 ? m.sq(somg12) / (1 + comg12) : 1 - comg12);
1058
+ // norm(vals.salp2, vals.calp2);
1059
+ t = m.hypot(vals.salp2, vals.calp2); vals.salp2 /= t; vals.calp2 /= t;
1060
+ // Set return value
1061
+ vals.sig12 = Math.atan2(ssig12, csig12);
1062
+ } else if (Math.abs(this._n) > 0.1 || // Skip astroid calc if too eccentric
1063
+ csig12 >= 0 ||
1064
+ ssig12 >= 6 * Math.abs(this._n) * Math.PI * m.sq(cbet1)) {
1065
+ // Nothing to do, zeroth order spherical approximation is OK
1066
+ } else {
1067
+ // Scale lam12 and bet2 to x, y coordinate system where antipodal
1068
+ // point is at origin and singular point is at y = 0, x = -1.
1069
+ lam12x = Math.atan2(-slam12, -clam12); // lam12 - pi
1070
+ if (this.f >= 0) { // In fact f == 0 does not get here
1071
+ // x = dlong, y = dlat
1072
+ k2 = m.sq(sbet1) * this._ep2;
1073
+ eps = k2 / (2 * (1 + Math.sqrt(1 + k2)) + k2);
1074
+ lamscale = this.f * cbet1 * this.A3f(eps) * Math.PI;
1075
+ betscale = lamscale * cbet1;
1076
+
1077
+ x = lam12x / lamscale;
1078
+ y = sbet12a / betscale;
1079
+ } else { // f < 0
1080
+ // x = dlat, y = dlong
1081
+ cbet12a = cbet2 * cbet1 - sbet2 * sbet1;
1082
+ bet12a = Math.atan2(sbet12a, cbet12a);
1083
+ // In the case of lon12 = 180, this repeats a calculation made
1084
+ // in Inverse.
1085
+ nvals = this.Lengths(this._n, Math.PI + bet12a,
1086
+ sbet1, -cbet1, dn1, sbet2, cbet2, dn2,
1087
+ cbet1, cbet2, g.REDUCEDLENGTH, C1a, C2a);
1088
+ m12b = nvals.m12b; m0 = nvals.m0;
1089
+ x = -1 + m12b / (cbet1 * cbet2 * m0 * Math.PI);
1090
+ betscale = x < -0.01 ? sbet12a / x :
1091
+ -this.f * m.sq(cbet1) * Math.PI;
1092
+ lamscale = betscale / cbet1;
1093
+ y = lam12 / lamscale;
1094
+ }
1095
+
1096
+ if (y > -tol1_ && x > -1 - xthresh_) {
1097
+ // strip near cut
1098
+ if (this.f >= 0) {
1099
+ vals.salp1 = Math.min(1, -x);
1100
+ vals.calp1 = - Math.sqrt(1 - m.sq(vals.salp1));
1101
+ } else {
1102
+ vals.calp1 = Math.max(x > -tol1_ ? 0 : -1, x);
1103
+ vals.salp1 = Math.sqrt(1 - m.sq(vals.calp1));
1104
+ }
1105
+ } else {
1106
+ // Estimate alp1, by solving the astroid problem.
1107
+ //
1108
+ // Could estimate alpha1 = theta + pi/2, directly, i.e.,
1109
+ // calp1 = y/k; salp1 = -x/(1+k); for f >= 0
1110
+ // calp1 = x/(1+k); salp1 = -y/k; for f < 0 (need to check)
1111
+ //
1112
+ // However, it's better to estimate omg12 from astroid and use
1113
+ // spherical formula to compute alp1. This reduces the mean number of
1114
+ // Newton iterations for astroid cases from 2.24 (min 0, max 6) to 2.12
1115
+ // (min 0 max 5). The changes in the number of iterations are as
1116
+ // follows:
1117
+ //
1118
+ // change percent
1119
+ // 1 5
1120
+ // 0 78
1121
+ // -1 16
1122
+ // -2 0.6
1123
+ // -3 0.04
1124
+ // -4 0.002
1125
+ //
1126
+ // The histogram of iterations is (m = number of iterations estimating
1127
+ // alp1 directly, n = number of iterations estimating via omg12, total
1128
+ // number of trials = 148605):
1129
+ //
1130
+ // iter m n
1131
+ // 0 148 186
1132
+ // 1 13046 13845
1133
+ // 2 93315 102225
1134
+ // 3 36189 32341
1135
+ // 4 5396 7
1136
+ // 5 455 1
1137
+ // 6 56 0
1138
+ //
1139
+ // Because omg12 is near pi, estimate work with omg12a = pi - omg12
1140
+ k = astroid(x, y);
1141
+ omg12a = lamscale * ( this.f >= 0 ? -x * k/(1 + k) : -y * (1 + k)/k );
1142
+ somg12 = Math.sin(omg12a); comg12 = -Math.cos(omg12a);
1143
+ // Update spherical estimate of alp1 using omg12 instead of
1144
+ // lam12
1145
+ vals.salp1 = cbet2 * somg12;
1146
+ vals.calp1 = sbet12a -
1147
+ cbet2 * sbet1 * m.sq(somg12) / (1 - comg12);
1148
+ }
1149
+ }
1150
+ // Sanity check on starting guess. Backwards check allows NaN through.
1151
+ if (!(vals.salp1 <= 0.0)) {
1152
+ // norm(vals.salp1, vals.calp1);
1153
+ t = m.hypot(vals.salp1, vals.calp1); vals.salp1 /= t; vals.calp1 /= t;
1154
+ } else {
1155
+ vals.salp1 = 1; vals.calp1 = 0;
1156
+ }
1157
+ return vals;
1158
+ };
1159
+
1160
+ // return lam12, salp2, calp2, sig12, ssig1, csig1, ssig2, csig2, eps,
1161
+ // domg12, dlam12,
1162
+ g.Geodesic.prototype.Lambda12 = function(sbet1, cbet1, dn1, sbet2, cbet2, dn2,
1163
+ salp1, calp1, slam120, clam120,
1164
+ diffp, C1a, C2a, C3a) {
1165
+ var vals = {},
1166
+ t, salp0, calp0,
1167
+ somg1, comg1, somg2, comg2, B312, eta, k2, nvals;
1168
+ if (sbet1 === 0 && calp1 === 0)
1169
+ // Break degeneracy of equatorial line. This case has already been
1170
+ // handled.
1171
+ calp1 = -g.tiny_;
1172
+
1173
+ // sin(alp1) * cos(bet1) = sin(alp0)
1174
+ salp0 = salp1 * cbet1;
1175
+ calp0 = m.hypot(calp1, salp1 * sbet1); // calp0 > 0
1176
+
1177
+ // tan(bet1) = tan(sig1) * cos(alp1)
1178
+ // tan(omg1) = sin(alp0) * tan(sig1) = tan(omg1)=tan(alp1)*sin(bet1)
1179
+ vals.ssig1 = sbet1; somg1 = salp0 * sbet1;
1180
+ vals.csig1 = comg1 = calp1 * cbet1;
1181
+ // norm(vals.ssig1, vals.csig1);
1182
+ t = m.hypot(vals.ssig1, vals.csig1); vals.ssig1 /= t; vals.csig1 /= t;
1183
+ // norm(somg1, comg1); -- don't need to normalize!
1184
+
1185
+ // Enforce symmetries in the case abs(bet2) = -bet1. Need to be careful
1186
+ // about this case, since this can yield singularities in the Newton
1187
+ // iteration.
1188
+ // sin(alp2) * cos(bet2) = sin(alp0)
1189
+ vals.salp2 = cbet2 !== cbet1 ? salp0 / cbet2 : salp1;
1190
+ // calp2 = sqrt(1 - sq(salp2))
1191
+ // = sqrt(sq(calp0) - sq(sbet2)) / cbet2
1192
+ // and subst for calp0 and rearrange to give (choose positive sqrt
1193
+ // to give alp2 in [0, pi/2]).
1194
+ vals.calp2 = cbet2 !== cbet1 || Math.abs(sbet2) !== -sbet1 ?
1195
+ Math.sqrt(m.sq(calp1 * cbet1) + (cbet1 < -sbet1 ?
1196
+ (cbet2 - cbet1) * (cbet1 + cbet2) :
1197
+ (sbet1 - sbet2) * (sbet1 + sbet2))) /
1198
+ cbet2 : Math.abs(calp1);
1199
+ // tan(bet2) = tan(sig2) * cos(alp2)
1200
+ // tan(omg2) = sin(alp0) * tan(sig2).
1201
+ vals.ssig2 = sbet2; somg2 = salp0 * sbet2;
1202
+ vals.csig2 = comg2 = vals.calp2 * cbet2;
1203
+ // norm(vals.ssig2, vals.csig2);
1204
+ t = m.hypot(vals.ssig2, vals.csig2); vals.ssig2 /= t; vals.csig2 /= t;
1205
+ // norm(somg2, comg2); -- don't need to normalize!
1206
+
1207
+ // sig12 = sig2 - sig1, limit to [0, pi]
1208
+ vals.sig12 = Math.atan2(Math.max(0, vals.csig1 * vals.ssig2 -
1209
+ vals.ssig1 * vals.csig2),
1210
+ vals.csig1 * vals.csig2 + vals.ssig1 * vals.ssig2);
1211
+
1212
+ // omg12 = omg2 - omg1, limit to [0, pi]
1213
+ vals.somg12 = Math.max(0, comg1 * somg2 - somg1 * comg2);
1214
+ vals.comg12 = comg1 * comg2 + somg1 * somg2;
1215
+ // eta = omg12 - lam120
1216
+ eta = Math.atan2(vals.somg12 * clam120 - vals.comg12 * slam120,
1217
+ vals.comg12 * clam120 + vals.somg12 * slam120);
1218
+ k2 = m.sq(calp0) * this._ep2;
1219
+ vals.eps = k2 / (2 * (1 + Math.sqrt(1 + k2)) + k2);
1220
+ this.C3f(vals.eps, C3a);
1221
+ B312 = (g.SinCosSeries(true, vals.ssig2, vals.csig2, C3a) -
1222
+ g.SinCosSeries(true, vals.ssig1, vals.csig1, C3a));
1223
+ vals.lam12 = eta - this.f * this.A3f(vals.eps) *
1224
+ salp0 * (vals.sig12 + B312);
1225
+ if (diffp) {
1226
+ if (vals.calp2 === 0)
1227
+ vals.dlam12 = - 2 * this._f1 * dn1 / sbet1;
1228
+ else {
1229
+ nvals = this.Lengths(vals.eps, vals.sig12,
1230
+ vals.ssig1, vals.csig1, dn1,
1231
+ vals.ssig2, vals.csig2, dn2,
1232
+ cbet1, cbet2, g.REDUCEDLENGTH, C1a, C2a);
1233
+ vals.dlam12 = nvals.m12b;
1234
+ vals.dlam12 *= this._f1 / (vals.calp2 * cbet2);
1235
+ }
1236
+ }
1237
+ return vals;
1238
+ };
1239
+
1240
+ /**
1241
+ * @summary Solve the inverse geodesic problem.
1242
+ * @param {number} lat1 the latitude of the first point in degrees.
1243
+ * @param {number} lon1 the longitude of the first point in degrees.
1244
+ * @param {number} lat2 the latitude of the second point in degrees.
1245
+ * @param {number} lon2 the longitude of the second point in degrees.
1246
+ * @param {bitmask} [outmask = STANDARD] which results to include.
1247
+ * @returns {object} the requested results
1248
+ * @description The lat1, lon1, lat2, lon2, and a12 fields of the result are
1249
+ * always set. For details on the outmask parameter, see {@tutorial
1250
+ * 2-interface}, "The outmask and caps parameters".
1251
+ */
1252
+ g.Geodesic.prototype.Inverse = function(lat1, lon1, lat2, lon2, outmask) {
1253
+ var r, vals;
1254
+ if (!outmask) outmask = g.STANDARD;
1255
+ if (outmask === g.LONG_UNROLL) outmask |= g.STANDARD;
1256
+ outmask &= g.OUT_MASK;
1257
+ r = this.InverseInt(lat1, lon1, lat2, lon2, outmask);
1258
+ vals = r.vals;
1259
+ if (outmask & g.AZIMUTH) {
1260
+ vals.azi1 = m.atan2d(r.salp1, r.calp1);
1261
+ vals.azi2 = m.atan2d(r.salp2, r.calp2);
1262
+ }
1263
+ return vals;
1264
+ };
1265
+
1266
+ g.Geodesic.prototype.InverseInt = function(lat1, lon1, lat2, lon2, outmask) {
1267
+ var vals = {},
1268
+ lon12, lon12s, lonsign, t, swapp, latsign,
1269
+ sbet1, cbet1, sbet2, cbet2, s12x, m12x,
1270
+ dn1, dn2, lam12, slam12, clam12,
1271
+ sig12, calp1, salp1, calp2, salp2, C1a, C2a, C3a, meridian, nvals,
1272
+ ssig1, csig1, ssig2, csig2, eps, omg12, dnm,
1273
+ numit, salp1a, calp1a, salp1b, calp1b,
1274
+ tripn, tripb, v, dv, dalp1, sdalp1, cdalp1, nsalp1,
1275
+ lengthmask, salp0, calp0, alp12, k2, A4, C4a, B41, B42,
1276
+ somg12, comg12, domg12, dbet1, dbet2, salp12, calp12;
1277
+ // Compute longitude difference (AngDiff does this carefully). Result is
1278
+ // in [-180, 180] but -180 is only for west-going geodesics. 180 is for
1279
+ // east-going and meridional geodesics.
1280
+ vals.lat1 = lat1 = m.LatFix(lat1); vals.lat2 = lat2 = m.LatFix(lat2);
1281
+ // If really close to the equator, treat as on equator.
1282
+ lat1 = m.AngRound(lat1);
1283
+ lat2 = m.AngRound(lat2);
1284
+ lon12 = m.AngDiff(lon1, lon2); lon12s = lon12.t; lon12 = lon12.s;
1285
+ if (outmask & g.LONG_UNROLL) {
1286
+ vals.lon1 = lon1; vals.lon2 = (lon1 + lon12) + lon12s;
1287
+ } else {
1288
+ vals.lon1 = m.AngNormalize(lon1); vals.lon2 = m.AngNormalize(lon2);
1289
+ }
1290
+ // Make longitude difference positive.
1291
+ lonsign = lon12 >= 0 ? 1 : -1;
1292
+ // If very close to being on the same half-meridian, then make it so.
1293
+ lon12 = lonsign * m.AngRound(lon12);
1294
+ lon12s = m.AngRound((180 - lon12) - lonsign * lon12s);
1295
+ lam12 = lon12 * m.degree;
1296
+ t = m.sincosd(lon12 > 90 ? lon12s : lon12);
1297
+ slam12 = t.s; clam12 = (lon12 > 90 ? -1 : 1) * t.c;
1298
+
1299
+ // Swap points so that point with higher (abs) latitude is point 1
1300
+ // If one latitude is a nan, then it becomes lat1.
1301
+ swapp = Math.abs(lat1) < Math.abs(lat2) ? -1 : 1;
1302
+ if (swapp < 0) {
1303
+ lonsign *= -1;
1304
+ t = lat1;
1305
+ lat1 = lat2;
1306
+ lat2 = t;
1307
+ // swap(lat1, lat2);
1308
+ }
1309
+ // Make lat1 <= 0
1310
+ latsign = lat1 < 0 ? 1 : -1;
1311
+ lat1 *= latsign;
1312
+ lat2 *= latsign;
1313
+ // Now we have
1314
+ //
1315
+ // 0 <= lon12 <= 180
1316
+ // -90 <= lat1 <= 0
1317
+ // lat1 <= lat2 <= -lat1
1318
+ //
1319
+ // longsign, swapp, latsign register the transformation to bring the
1320
+ // coordinates to this canonical form. In all cases, 1 means no change was
1321
+ // made. We make these transformations so that there are few cases to
1322
+ // check, e.g., on verifying quadrants in atan2. In addition, this
1323
+ // enforces some symmetries in the results returned.
1324
+
1325
+ t = m.sincosd(lat1); sbet1 = this._f1 * t.s; cbet1 = t.c;
1326
+ // norm(sbet1, cbet1);
1327
+ t = m.hypot(sbet1, cbet1); sbet1 /= t; cbet1 /= t;
1328
+ // Ensure cbet1 = +epsilon at poles
1329
+ cbet1 = Math.max(g.tiny_, cbet1);
1330
+
1331
+ t = m.sincosd(lat2); sbet2 = this._f1 * t.s; cbet2 = t.c;
1332
+ // norm(sbet2, cbet2);
1333
+ t = m.hypot(sbet2, cbet2); sbet2 /= t; cbet2 /= t;
1334
+ // Ensure cbet2 = +epsilon at poles
1335
+ cbet2 = Math.max(g.tiny_, cbet2);
1336
+
1337
+ // If cbet1 < -sbet1, then cbet2 - cbet1 is a sensitive measure of the
1338
+ // |bet1| - |bet2|. Alternatively (cbet1 >= -sbet1), abs(sbet2) + sbet1 is
1339
+ // a better measure. This logic is used in assigning calp2 in Lambda12.
1340
+ // Sometimes these quantities vanish and in that case we force bet2 = +/-
1341
+ // bet1 exactly. An example where is is necessary is the inverse problem
1342
+ // 48.522876735459 0 -48.52287673545898293 179.599720456223079643
1343
+ // which failed with Visual Studio 10 (Release and Debug)
1344
+
1345
+ if (cbet1 < -sbet1) {
1346
+ if (cbet2 === cbet1)
1347
+ sbet2 = sbet2 < 0 ? sbet1 : -sbet1;
1348
+ } else {
1349
+ if (Math.abs(sbet2) === -sbet1)
1350
+ cbet2 = cbet1;
1351
+ }
1352
+
1353
+ dn1 = Math.sqrt(1 + this._ep2 * m.sq(sbet1));
1354
+ dn2 = Math.sqrt(1 + this._ep2 * m.sq(sbet2));
1355
+
1356
+ // index zero elements of these arrays are unused
1357
+ C1a = new Array(g.nC1_ + 1);
1358
+ C2a = new Array(g.nC2_ + 1);
1359
+ C3a = new Array(g.nC3_);
1360
+
1361
+ meridian = lat1 === -90 || slam12 === 0;
1362
+ if (meridian) {
1363
+
1364
+ // Endpoints are on a single full meridian, so the geodesic might
1365
+ // lie on a meridian.
1366
+
1367
+ calp1 = clam12; salp1 = slam12; // Head to the target longitude
1368
+ calp2 = 1; salp2 = 0; // At the target we're heading north
1369
+
1370
+ // tan(bet) = tan(sig) * cos(alp)
1371
+ ssig1 = sbet1; csig1 = calp1 * cbet1;
1372
+ ssig2 = sbet2; csig2 = calp2 * cbet2;
1373
+
1374
+ // sig12 = sig2 - sig1
1375
+ sig12 = Math.atan2(Math.max(0, csig1 * ssig2 - ssig1 * csig2),
1376
+ csig1 * csig2 + ssig1 * ssig2);
1377
+ nvals = this.Lengths(this._n, sig12,
1378
+ ssig1, csig1, dn1, ssig2, csig2, dn2, cbet1, cbet2,
1379
+ outmask | g.DISTANCE | g.REDUCEDLENGTH,
1380
+ C1a, C2a);
1381
+ s12x = nvals.s12b;
1382
+ m12x = nvals.m12b;
1383
+ // Ignore m0
1384
+ if ((outmask & g.GEODESICSCALE) !== 0) {
1385
+ vals.M12 = nvals.M12;
1386
+ vals.M21 = nvals.M21;
1387
+ }
1388
+ // Add the check for sig12 since zero length geodesics might yield
1389
+ // m12 < 0. Test case was
1390
+ //
1391
+ // echo 20.001 0 20.001 0 | GeodSolve -i
1392
+ //
1393
+ // In fact, we will have sig12 > pi/2 for meridional geodesic
1394
+ // which is not a shortest path.
1395
+ if (sig12 < 1 || m12x >= 0) {
1396
+ // Need at least 2, to handle 90 0 90 180
1397
+ if (sig12 < 3 * g.tiny_)
1398
+ sig12 = m12x = s12x = 0;
1399
+ m12x *= this._b;
1400
+ s12x *= this._b;
1401
+ vals.a12 = sig12 / m.degree;
1402
+ } else
1403
+ // m12 < 0, i.e., prolate and too close to anti-podal
1404
+ meridian = false;
1405
+ }
1406
+
1407
+ somg12 = 2;
1408
+ if (!meridian &&
1409
+ sbet1 === 0 && // and sbet2 == 0
1410
+ (this.f <= 0 || lon12s >= this.f * 180)) {
1411
+
1412
+ // Geodesic runs along equator
1413
+ calp1 = calp2 = 0; salp1 = salp2 = 1;
1414
+ s12x = this.a * lam12;
1415
+ sig12 = omg12 = lam12 / this._f1;
1416
+ m12x = this._b * Math.sin(sig12);
1417
+ if (outmask & g.GEODESICSCALE)
1418
+ vals.M12 = vals.M21 = Math.cos(sig12);
1419
+ vals.a12 = lon12 / this._f1;
1420
+
1421
+ } else if (!meridian) {
1422
+
1423
+ // Now point1 and point2 belong within a hemisphere bounded by a
1424
+ // meridian and geodesic is neither meridional or equatorial.
1425
+
1426
+ // Figure a starting point for Newton's method
1427
+ nvals = this.InverseStart(sbet1, cbet1, dn1, sbet2, cbet2, dn2,
1428
+ lam12, slam12, clam12, C1a, C2a);
1429
+ sig12 = nvals.sig12;
1430
+ salp1 = nvals.salp1;
1431
+ calp1 = nvals.calp1;
1432
+
1433
+ if (sig12 >= 0) {
1434
+ salp2 = nvals.salp2;
1435
+ calp2 = nvals.calp2;
1436
+ // Short lines (InverseStart sets salp2, calp2, dnm)
1437
+
1438
+ dnm = nvals.dnm;
1439
+ s12x = sig12 * this._b * dnm;
1440
+ m12x = m.sq(dnm) * this._b * Math.sin(sig12 / dnm);
1441
+ if (outmask & g.GEODESICSCALE)
1442
+ vals.M12 = vals.M21 = Math.cos(sig12 / dnm);
1443
+ vals.a12 = sig12 / m.degree;
1444
+ omg12 = lam12 / (this._f1 * dnm);
1445
+ } else {
1446
+
1447
+ // Newton's method. This is a straightforward solution of f(alp1) =
1448
+ // lambda12(alp1) - lam12 = 0 with one wrinkle. f(alp) has exactly one
1449
+ // root in the interval (0, pi) and its derivative is positive at the
1450
+ // root. Thus f(alp) is positive for alp > alp1 and negative for alp <
1451
+ // alp1. During the course of the iteration, a range (alp1a, alp1b) is
1452
+ // maintained which brackets the root and with each evaluation of
1453
+ // f(alp) the range is shrunk if possible. Newton's method is
1454
+ // restarted whenever the derivative of f is negative (because the new
1455
+ // value of alp1 is then further from the solution) or if the new
1456
+ // estimate of alp1 lies outside (0,pi); in this case, the new starting
1457
+ // guess is taken to be (alp1a + alp1b) / 2.
1458
+ numit = 0;
1459
+ // Bracketing range
1460
+ salp1a = g.tiny_; calp1a = 1; salp1b = g.tiny_; calp1b = -1;
1461
+ for (tripn = false, tripb = false; numit < maxit2_; ++numit) {
1462
+ // the WGS84 test set: mean = 1.47, sd = 1.25, max = 16
1463
+ // WGS84 and random input: mean = 2.85, sd = 0.60
1464
+ nvals = this.Lambda12(sbet1, cbet1, dn1, sbet2, cbet2, dn2,
1465
+ salp1, calp1, slam12, clam12, numit < maxit1_,
1466
+ C1a, C2a, C3a);
1467
+ v = nvals.lam12;
1468
+ salp2 = nvals.salp2;
1469
+ calp2 = nvals.calp2;
1470
+ sig12 = nvals.sig12;
1471
+ ssig1 = nvals.ssig1;
1472
+ csig1 = nvals.csig1;
1473
+ ssig2 = nvals.ssig2;
1474
+ csig2 = nvals.csig2;
1475
+ eps = nvals.eps;
1476
+ somg12 = nvals.somg12;
1477
+ comg12 = nvals.comg12;
1478
+ dv = nvals.dlam12;
1479
+
1480
+ // 2 * tol0 is approximately 1 ulp for a number in [0, pi].
1481
+ // Reversed test to allow escape with NaNs
1482
+ if (tripb || !(Math.abs(v) >= (tripn ? 8 : 1) * tol0_))
1483
+ break;
1484
+ // Update bracketing values
1485
+ if (v > 0 && (numit < maxit1_ || calp1/salp1 > calp1b/salp1b)) {
1486
+ salp1b = salp1; calp1b = calp1;
1487
+ } else if (v < 0 &&
1488
+ (numit < maxit1_ || calp1/salp1 < calp1a/salp1a)) {
1489
+ salp1a = salp1; calp1a = calp1;
1490
+ }
1491
+ if (numit < maxit1_ && dv > 0) {
1492
+ dalp1 = -v/dv;
1493
+ sdalp1 = Math.sin(dalp1); cdalp1 = Math.cos(dalp1);
1494
+ nsalp1 = salp1 * cdalp1 + calp1 * sdalp1;
1495
+ if (nsalp1 > 0 && Math.abs(dalp1) < Math.PI) {
1496
+ calp1 = calp1 * cdalp1 - salp1 * sdalp1;
1497
+ salp1 = nsalp1;
1498
+ // norm(salp1, calp1);
1499
+ t = m.hypot(salp1, calp1); salp1 /= t; calp1 /= t;
1500
+ // In some regimes we don't get quadratic convergence because
1501
+ // slope -> 0. So use convergence conditions based on epsilon
1502
+ // instead of sqrt(epsilon).
1503
+ tripn = Math.abs(v) <= 16 * tol0_;
1504
+ continue;
1505
+ }
1506
+ }
1507
+ // Either dv was not postive or updated value was outside legal
1508
+ // range. Use the midpoint of the bracket as the next estimate.
1509
+ // This mechanism is not needed for the WGS84 ellipsoid, but it does
1510
+ // catch problems with more eccentric ellipsoids. Its efficacy is
1511
+ // such for the WGS84 test set with the starting guess set to alp1 =
1512
+ // 90deg:
1513
+ // the WGS84 test set: mean = 5.21, sd = 3.93, max = 24
1514
+ // WGS84 and random input: mean = 4.74, sd = 0.99
1515
+ salp1 = (salp1a + salp1b)/2;
1516
+ calp1 = (calp1a + calp1b)/2;
1517
+ // norm(salp1, calp1);
1518
+ t = m.hypot(salp1, calp1); salp1 /= t; calp1 /= t;
1519
+ tripn = false;
1520
+ tripb = (Math.abs(salp1a - salp1) + (calp1a - calp1) < tolb_ ||
1521
+ Math.abs(salp1 - salp1b) + (calp1 - calp1b) < tolb_);
1522
+ }
1523
+ lengthmask = outmask |
1524
+ (outmask & (g.REDUCEDLENGTH | g.GEODESICSCALE) ?
1525
+ g.DISTANCE : g.NONE);
1526
+ nvals = this.Lengths(eps, sig12,
1527
+ ssig1, csig1, dn1, ssig2, csig2, dn2, cbet1, cbet2,
1528
+ lengthmask, C1a, C2a);
1529
+ s12x = nvals.s12b;
1530
+ m12x = nvals.m12b;
1531
+ // Ignore m0
1532
+ if ((outmask & g.GEODESICSCALE) !== 0) {
1533
+ vals.M12 = nvals.M12;
1534
+ vals.M21 = nvals.M21;
1535
+ }
1536
+ m12x *= this._b;
1537
+ s12x *= this._b;
1538
+ vals.a12 = sig12 / m.degree;
1539
+ }
1540
+ }
1541
+
1542
+ if (outmask & g.DISTANCE)
1543
+ vals.s12 = 0 + s12x; // Convert -0 to 0
1544
+
1545
+ if (outmask & g.REDUCEDLENGTH)
1546
+ vals.m12 = 0 + m12x; // Convert -0 to 0
1547
+
1548
+ if (outmask & g.AREA) {
1549
+ // From Lambda12: sin(alp1) * cos(bet1) = sin(alp0)
1550
+ salp0 = salp1 * cbet1;
1551
+ calp0 = m.hypot(calp1, salp1 * sbet1); // calp0 > 0
1552
+ if (calp0 !== 0 && salp0 !== 0) {
1553
+ // From Lambda12: tan(bet) = tan(sig) * cos(alp)
1554
+ ssig1 = sbet1; csig1 = calp1 * cbet1;
1555
+ ssig2 = sbet2; csig2 = calp2 * cbet2;
1556
+ k2 = m.sq(calp0) * this._ep2;
1557
+ eps = k2 / (2 * (1 + Math.sqrt(1 + k2)) + k2);
1558
+ // Multiplier = a^2 * e^2 * cos(alpha0) * sin(alpha0).
1559
+ A4 = m.sq(this.a) * calp0 * salp0 * this._e2;
1560
+ // norm(ssig1, csig1);
1561
+ t = m.hypot(ssig1, csig1); ssig1 /= t; csig1 /= t;
1562
+ // norm(ssig2, csig2);
1563
+ t = m.hypot(ssig2, csig2); ssig2 /= t; csig2 /= t;
1564
+ C4a = new Array(g.nC4_);
1565
+ this.C4f(eps, C4a);
1566
+ B41 = g.SinCosSeries(false, ssig1, csig1, C4a);
1567
+ B42 = g.SinCosSeries(false, ssig2, csig2, C4a);
1568
+ vals.S12 = A4 * (B42 - B41);
1569
+ } else
1570
+ // Avoid problems with indeterminate sig1, sig2 on equator
1571
+ vals.S12 = 0;
1572
+ if (!meridian) {
1573
+ if (somg12 > 1) {
1574
+ somg12 = Math.sin(omg12); comg12 = Math.cos(omg12);
1575
+ } else {
1576
+ t = m.hypot(somg12, comg12); somg12 /= t; comg12 /= t;
1577
+ }
1578
+ }
1579
+ if (!meridian &&
1580
+ omg12 > -0.7071 && // Long difference not too big
1581
+ sbet2 - sbet1 < 1.75) { // Lat difference not too big
1582
+ // Use tan(Gamma/2) = tan(omg12/2)
1583
+ // * (tan(bet1/2)+tan(bet2/2))/(1+tan(bet1/2)*tan(bet2/2))
1584
+ // with tan(x/2) = sin(x)/(1+cos(x))
1585
+ domg12 = 1 + comg12; dbet1 = 1 + cbet1; dbet2 = 1 + cbet2;
1586
+ alp12 = 2 * Math.atan2( somg12 * (sbet1*dbet2 + sbet2*dbet1),
1587
+ domg12 * (sbet1*sbet2 + dbet1*dbet2) );
1588
+ } else {
1589
+ // alp12 = alp2 - alp1, used in atan2 so no need to normalize
1590
+ salp12 = salp2 * calp1 - calp2 * salp1;
1591
+ calp12 = calp2 * calp1 + salp2 * salp1;
1592
+ // The right thing appears to happen if alp1 = +/-180 and alp2 = 0, viz
1593
+ // salp12 = -0 and alp12 = -180. However this depends on the sign
1594
+ // being attached to 0 correctly. The following ensures the correct
1595
+ // behavior.
1596
+ if (salp12 === 0 && calp12 < 0) {
1597
+ salp12 = g.tiny_ * calp1;
1598
+ calp12 = -1;
1599
+ }
1600
+ alp12 = Math.atan2(salp12, calp12);
1601
+ }
1602
+ vals.S12 += this._c2 * alp12;
1603
+ vals.S12 *= swapp * lonsign * latsign;
1604
+ // Convert -0 to 0
1605
+ vals.S12 += 0;
1606
+ }
1607
+
1608
+ // Convert calp, salp to azimuth accounting for lonsign, swapp, latsign.
1609
+ if (swapp < 0) {
1610
+ t = salp1;
1611
+ salp1 = salp2;
1612
+ salp2 = t;
1613
+ // swap(salp1, salp2);
1614
+ t = calp1;
1615
+ calp1 = calp2;
1616
+ calp2 = t;
1617
+ // swap(calp1, calp2);
1618
+ if (outmask & g.GEODESICSCALE) {
1619
+ t = vals.M12;
1620
+ vals.M12 = vals.M21;
1621
+ vals.M21 = t;
1622
+ // swap(vals.M12, vals.M21);
1623
+ }
1624
+ }
1625
+
1626
+ salp1 *= swapp * lonsign; calp1 *= swapp * latsign;
1627
+ salp2 *= swapp * lonsign; calp2 *= swapp * latsign;
1628
+
1629
+ return {vals: vals,
1630
+ salp1: salp1, calp1: calp1,
1631
+ salp2: salp2, calp2: calp2};
1632
+ };
1633
+
1634
+ /**
1635
+ * @summary Solve the general direct geodesic problem.
1636
+ * @param {number} lat1 the latitude of the first point in degrees.
1637
+ * @param {number} lon1 the longitude of the first point in degrees.
1638
+ * @param {number} azi1 the azimuth at the first point in degrees.
1639
+ * @param {bool} arcmode is the next parameter an arc length?
1640
+ * @param {number} s12_a12 the (arcmode ? arc length : distance) from the
1641
+ * first point to the second in (arcmode ? degrees : meters).
1642
+ * @param {bitmask} [outmask = STANDARD] which results to include.
1643
+ * @returns {object} the requested results.
1644
+ * @description The lat1, lon1, azi1, and a12 fields of the result are always
1645
+ * set; s12 is included if arcmode is false. For details on the outmask
1646
+ * parameter, see {@tutorial 2-interface}, "The outmask and caps
1647
+ * parameters".
1648
+ */
1649
+ g.Geodesic.prototype.GenDirect = function (lat1, lon1, azi1,
1650
+ arcmode, s12_a12, outmask) {
1651
+ var line;
1652
+ if (!outmask) outmask = g.STANDARD;
1653
+ else if (outmask === g.LONG_UNROLL) outmask |= g.STANDARD;
1654
+ // Automatically supply DISTANCE_IN if necessary
1655
+ if (!arcmode) outmask |= g.DISTANCE_IN;
1656
+ line = new l.GeodesicLine(this, lat1, lon1, azi1, outmask);
1657
+ return line.GenPosition(arcmode, s12_a12, outmask);
1658
+ };
1659
+
1660
+ /**
1661
+ * @summary Solve the direct geodesic problem.
1662
+ * @param {number} lat1 the latitude of the first point in degrees.
1663
+ * @param {number} lon1 the longitude of the first point in degrees.
1664
+ * @param {number} azi1 the azimuth at the first point in degrees.
1665
+ * @param {number} s12 the distance from the first point to the second in
1666
+ * meters.
1667
+ * @param {bitmask} [outmask = STANDARD] which results to include.
1668
+ * @returns {object} the requested results.
1669
+ * @description The lat1, lon1, azi1, s12, and a12 fields of the result are
1670
+ * always set. For details on the outmask parameter, see {@tutorial
1671
+ * 2-interface}, "The outmask and caps parameters".
1672
+ */
1673
+ g.Geodesic.prototype.Direct = function (lat1, lon1, azi1, s12, outmask) {
1674
+ return this.GenDirect(lat1, lon1, azi1, false, s12, outmask);
1675
+ };
1676
+
1677
+ /**
1678
+ * @summary Solve the direct geodesic problem with arc length.
1679
+ * @param {number} lat1 the latitude of the first point in degrees.
1680
+ * @param {number} lon1 the longitude of the first point in degrees.
1681
+ * @param {number} azi1 the azimuth at the first point in degrees.
1682
+ * @param {number} a12 the arc length from the first point to the second in
1683
+ * degrees.
1684
+ * @param {bitmask} [outmask = STANDARD] which results to include.
1685
+ * @returns {object} the requested results.
1686
+ * @description The lat1, lon1, azi1, and a12 fields of the result are
1687
+ * always set. For details on the outmask parameter, see {@tutorial
1688
+ * 2-interface}, "The outmask and caps parameters".
1689
+ */
1690
+ g.Geodesic.prototype.ArcDirect = function (lat1, lon1, azi1, a12, outmask) {
1691
+ return this.GenDirect(lat1, lon1, azi1, true, a12, outmask);
1692
+ };
1693
+
1694
+ /**
1695
+ * @summary Create a {@link module:GeographicLib/GeodesicLine.GeodesicLine
1696
+ * GeodesicLine} object.
1697
+ * @param {number} lat1 the latitude of the first point in degrees.
1698
+ * @param {number} lon1 the longitude of the first point in degrees.
1699
+ * @param {number} azi1 the azimuth at the first point in degrees.
1700
+ * degrees.
1701
+ * @param {bitmask} [caps = STANDARD | DISTANCE_IN] which capabilities to
1702
+ * include.
1703
+ * @returns {object} the
1704
+ * {@link module:GeographicLib/GeodesicLine.GeodesicLine
1705
+ * GeodesicLine} object
1706
+ * @description For details on the caps parameter, see {@tutorial
1707
+ * 2-interface}, "The outmask and caps parameters".
1708
+ */
1709
+ g.Geodesic.prototype.Line = function (lat1, lon1, azi1, caps) {
1710
+ return new l.GeodesicLine(this, lat1, lon1, azi1, caps);
1711
+ };
1712
+
1713
+ /**
1714
+ * @summary Define a {@link module:GeographicLib/GeodesicLine.GeodesicLine
1715
+ * GeodesicLine} in terms of the direct geodesic problem specified in terms
1716
+ * of distance.
1717
+ * @param {number} lat1 the latitude of the first point in degrees.
1718
+ * @param {number} lon1 the longitude of the first point in degrees.
1719
+ * @param {number} azi1 the azimuth at the first point in degrees.
1720
+ * degrees.
1721
+ * @param {number} s12 the distance between point 1 and point 2 (meters); it
1722
+ * can be negative.
1723
+ * @param {bitmask} [caps = STANDARD | DISTANCE_IN] which capabilities to
1724
+ * include.
1725
+ * @returns {object} the
1726
+ * {@link module:GeographicLib/GeodesicLine.GeodesicLine
1727
+ * GeodesicLine} object
1728
+ * @description This function sets point 3 of the GeodesicLine to correspond
1729
+ * to point 2 of the direct geodesic problem. For details on the caps
1730
+ * parameter, see {@tutorial 2-interface}, "The outmask and caps
1731
+ * parameters".
1732
+ */
1733
+ g.Geodesic.prototype.DirectLine = function (lat1, lon1, azi1, s12, caps) {
1734
+ return this.GenDirectLine(lat1, lon1, azi1, false, s12, caps);
1735
+ };
1736
+
1737
+ /**
1738
+ * @summary Define a {@link module:GeographicLib/GeodesicLine.GeodesicLine
1739
+ * GeodesicLine} in terms of the direct geodesic problem specified in terms
1740
+ * of arc length.
1741
+ * @param {number} lat1 the latitude of the first point in degrees.
1742
+ * @param {number} lon1 the longitude of the first point in degrees.
1743
+ * @param {number} azi1 the azimuth at the first point in degrees.
1744
+ * degrees.
1745
+ * @param {number} a12 the arc length between point 1 and point 2 (degrees);
1746
+ * it can be negative.
1747
+ * @param {bitmask} [caps = STANDARD | DISTANCE_IN] which capabilities to
1748
+ * include.
1749
+ * @returns {object} the
1750
+ * {@link module:GeographicLib/GeodesicLine.GeodesicLine
1751
+ * GeodesicLine} object
1752
+ * @description This function sets point 3 of the GeodesicLine to correspond
1753
+ * to point 2 of the direct geodesic problem. For details on the caps
1754
+ * parameter, see {@tutorial 2-interface}, "The outmask and caps
1755
+ * parameters".
1756
+ */
1757
+ g.Geodesic.prototype.ArcDirectLine = function (lat1, lon1, azi1, a12, caps) {
1758
+ return this.GenDirectLine(lat1, lon1, azi1, true, a12, caps);
1759
+ };
1760
+
1761
+ /**
1762
+ * @summary Define a {@link module:GeographicLib/GeodesicLine.GeodesicLine
1763
+ * GeodesicLine} in terms of the direct geodesic problem specified in terms
1764
+ * of either distance or arc length.
1765
+ * @param {number} lat1 the latitude of the first point in degrees.
1766
+ * @param {number} lon1 the longitude of the first point in degrees.
1767
+ * @param {number} azi1 the azimuth at the first point in degrees.
1768
+ * degrees.
1769
+ * @param {bool} arcmode boolean flag determining the meaning of the
1770
+ * s12_a12.
1771
+ * @param {number} s12_a12 if arcmode is false, this is the distance between
1772
+ * point 1 and point 2 (meters); otherwise it is the arc length between
1773
+ * point 1 and point 2 (degrees); it can be negative.
1774
+ * @param {bitmask} [caps = STANDARD | DISTANCE_IN] which capabilities to
1775
+ * include.
1776
+ * @returns {object} the
1777
+ * {@link module:GeographicLib/GeodesicLine.GeodesicLine
1778
+ * GeodesicLine} object
1779
+ * @description This function sets point 3 of the GeodesicLine to correspond
1780
+ * to point 2 of the direct geodesic problem. For details on the caps
1781
+ * parameter, see {@tutorial 2-interface}, "The outmask and caps
1782
+ * parameters".
1783
+ */
1784
+ g.Geodesic.prototype.GenDirectLine = function (lat1, lon1, azi1,
1785
+ arcmode, s12_a12, caps) {
1786
+ var t;
1787
+ if (!caps) caps = g.STANDARD | g.DISTANCE_IN;
1788
+ // Automatically supply DISTANCE_IN if necessary
1789
+ if (!arcmode) caps |= g.DISTANCE_IN;
1790
+ t = new l.GeodesicLine(this, lat1, lon1, azi1, caps);
1791
+ t.GenSetDistance(arcmode, s12_a12);
1792
+ return t;
1793
+ };
1794
+
1795
+ /**
1796
+ * @summary Define a {@link module:GeographicLib/GeodesicLine.GeodesicLine
1797
+ * GeodesicLine} in terms of the inverse geodesic problem.
1798
+ * @param {number} lat1 the latitude of the first point in degrees.
1799
+ * @param {number} lon1 the longitude of the first point in degrees.
1800
+ * @param {number} lat2 the latitude of the second point in degrees.
1801
+ * @param {number} lon2 the longitude of the second point in degrees.
1802
+ * @param {bitmask} [caps = STANDARD | DISTANCE_IN] which capabilities to
1803
+ * include.
1804
+ * @returns {object} the
1805
+ * {@link module:GeographicLib/GeodesicLine.GeodesicLine
1806
+ * GeodesicLine} object
1807
+ * @description This function sets point 3 of the GeodesicLine to correspond
1808
+ * to point 2 of the inverse geodesic problem. For details on the caps
1809
+ * parameter, see {@tutorial 2-interface}, "The outmask and caps
1810
+ * parameters".
1811
+ */
1812
+ g.Geodesic.prototype.InverseLine = function (lat1, lon1, lat2, lon2, caps) {
1813
+ var r, t, azi1;
1814
+ if (!caps) caps = g.STANDARD | g.DISTANCE_IN;
1815
+ r = this.InverseInt(lat1, lon1, lat2, lon2, g.ARC);
1816
+ azi1 = m.atan2d(r.salp1, r.calp1);
1817
+ // Ensure that a12 can be converted to a distance
1818
+ if (caps & (g.OUT_MASK & g.DISTANCE_IN)) caps |= g.DISTANCE;
1819
+ t = new l.GeodesicLine(this, lat1, lon1, azi1, caps, r.salp1, r.calp1);
1820
+ t.SetArc(r.vals.a12);
1821
+ return t;
1822
+ };
1823
+
1824
+ /**
1825
+ * @summary Create a {@link module:GeographicLib/PolygonArea.PolygonArea
1826
+ * PolygonArea} object.
1827
+ * @param {bool} [polyline = false] if true the new PolygonArea object
1828
+ * describes a polyline instead of a polygon.
1829
+ * @returns {object} the
1830
+ * {@link module:GeographicLib/PolygonArea.PolygonArea
1831
+ * PolygonArea} object
1832
+ */
1833
+ g.Geodesic.prototype.Polygon = function (polyline) {
1834
+ return new p.PolygonArea(this, polyline);
1835
+ };
1836
+
1837
+ /**
1838
+ * @summary a {@link module:GeographicLib/Geodesic.Geodesic Geodesic} object
1839
+ * initialized for the WGS84 ellipsoid.
1840
+ * @constant {object}
1841
+ */
1842
+ g.WGS84 = new g.Geodesic(c.WGS84.a, c.WGS84.f);
1843
+ })(GeographicLib.Geodesic, GeographicLib.GeodesicLine,
1844
+ GeographicLib.PolygonArea, GeographicLib.Math, GeographicLib.Constants);
1845
+
1846
+ /**************** GeodesicLine.js ****************/
1847
+ /*
1848
+ * GeodesicLine.js
1849
+ * Transcription of GeodesicLine.[ch]pp into JavaScript.
1850
+ *
1851
+ * See the documentation for the C++ class. The conversion is a literal
1852
+ * conversion from C++.
1853
+ *
1854
+ * The algorithms are derived in
1855
+ *
1856
+ * Charles F. F. Karney,
1857
+ * Algorithms for geodesics, J. Geodesy 87, 43-55 (2013);
1858
+ * https://dx.doi.org/10.1007/s00190-012-0578-z
1859
+ * Addenda: http://geographiclib.sourceforge.net/geod-addenda.html
1860
+ *
1861
+ * Copyright (c) Charles Karney (2011-2016) <charles@karney.com> and licensed
1862
+ * under the MIT/X11 License. For more information, see
1863
+ * http://geographiclib.sourceforge.net/
1864
+ */
1865
+
1866
+ // Load AFTER GeographicLib/Math.js, GeographicLib/Geodesic.js
1867
+
1868
+ (function(
1869
+ g,
1870
+ /**
1871
+ * @exports GeographicLib/GeodesicLine
1872
+ * @description Solve geodesic problems on a single geodesic line via the
1873
+ * {@link module:GeographicLib/GeodesicLine.GeodesicLine GeodesicLine}
1874
+ * class.
1875
+ */
1876
+ l, m) {
1877
+
1878
+ /**
1879
+ * @class
1880
+ * @property {number} a the equatorial radius (meters).
1881
+ * @property {number} f the flattening.
1882
+ * @property {number} lat1 the initial latitude (degrees).
1883
+ * @property {number} lon1 the initial longitude (degrees).
1884
+ * @property {number} azi1 the initial azimuth (degrees).
1885
+ * @property {number} salp1 the sine of the azimuth at the first point.
1886
+ * @property {number} calp1 the cosine the azimuth at the first point.
1887
+ * @property {number} s13 the distance to point 3 (meters).
1888
+ * @property {number} a13 the arc length to point 3 (degrees).
1889
+ * @property {bitmask} caps the capabilities of the object.
1890
+ * @summary Initialize a GeodesicLine object. For details on the caps
1891
+ * parameter, see {@tutorial 2-interface}, "The outmask and caps
1892
+ * parameters".
1893
+ * @classdesc Performs geodesic calculations along a given geodesic line.
1894
+ * This object is usually instantiated by
1895
+ * {@link module:GeographicLib/Geodesic.Geodesic#Line Geodesic.Line}.
1896
+ * The methods
1897
+ * {@link module:GeographicLib/Geodesic.Geodesic#DirectLine
1898
+ * Geodesic.DirectLine} and
1899
+ * {@link module:GeographicLib/Geodesic.Geodesic#InverseLine
1900
+ * Geodesic.InverseLine} set in addition the position of a reference point
1901
+ * 3.
1902
+ * @param {object} geod a {@link module:GeographicLib/Geodesic.Geodesic
1903
+ * Geodesic} object.
1904
+ * @param {number} lat1 the latitude of the first point in degrees.
1905
+ * @param {number} lon1 the longitude of the first point in degrees.
1906
+ * @param {number} azi1 the azimuth at the first point in degrees.
1907
+ * @param {bitmask} [caps = STANDARD | DISTANCE_IN] which capabilities to
1908
+ * include; LATITUDE | AZIMUTH are always included.
1909
+ */
1910
+ l.GeodesicLine = function(geod, lat1, lon1, azi1, caps, salp1, calp1) {
1911
+ var t, cbet1, sbet1, eps, s, c;
1912
+ if (!caps) caps = g.STANDARD | g.DISTANCE_IN;
1913
+
1914
+ this.a = geod.a;
1915
+ this.f = geod.f;
1916
+ this._b = geod._b;
1917
+ this._c2 = geod._c2;
1918
+ this._f1 = geod._f1;
1919
+ this.caps = caps | g.LATITUDE | g.AZIMUTH | g.LONG_UNROLL;
1920
+
1921
+ this.lat1 = m.LatFix(lat1);
1922
+ this.lon1 = lon1;
1923
+ if (typeof salp1 === 'undefined' || typeof calp1 === 'undefined') {
1924
+ this.azi1 = m.AngNormalize(azi1);
1925
+ t = m.sincosd(m.AngRound(this.azi1)); this.salp1 = t.s; this.calp1 = t.c;
1926
+ } else {
1927
+ this.azi1 = azi1; this.salp1 = salp1; this.calp1 = calp1;
1928
+ }
1929
+ t = m.sincosd(m.AngRound(this.lat1)); sbet1 = this._f1 * t.s; cbet1 = t.c;
1930
+ // norm(sbet1, cbet1);
1931
+ t = m.hypot(sbet1, cbet1); sbet1 /= t; cbet1 /= t;
1932
+ // Ensure cbet1 = +epsilon at poles
1933
+ cbet1 = Math.max(g.tiny_, cbet1);
1934
+ this._dn1 = Math.sqrt(1 + geod._ep2 * m.sq(sbet1));
1935
+
1936
+ // Evaluate alp0 from sin(alp1) * cos(bet1) = sin(alp0),
1937
+ this._salp0 = this.salp1 * cbet1; // alp0 in [0, pi/2 - |bet1|]
1938
+ // Alt: calp0 = hypot(sbet1, calp1 * cbet1). The following
1939
+ // is slightly better (consider the case salp1 = 0).
1940
+ this._calp0 = m.hypot(this.calp1, this.salp1 * sbet1);
1941
+ // Evaluate sig with tan(bet1) = tan(sig1) * cos(alp1).
1942
+ // sig = 0 is nearest northward crossing of equator.
1943
+ // With bet1 = 0, alp1 = pi/2, we have sig1 = 0 (equatorial line).
1944
+ // With bet1 = pi/2, alp1 = -pi, sig1 = pi/2
1945
+ // With bet1 = -pi/2, alp1 = 0 , sig1 = -pi/2
1946
+ // Evaluate omg1 with tan(omg1) = sin(alp0) * tan(sig1).
1947
+ // With alp0 in (0, pi/2], quadrants for sig and omg coincide.
1948
+ // No atan2(0,0) ambiguity at poles since cbet1 = +epsilon.
1949
+ // With alp0 = 0, omg1 = 0 for alp1 = 0, omg1 = pi for alp1 = pi.
1950
+ this._ssig1 = sbet1; this._somg1 = this._salp0 * sbet1;
1951
+ this._csig1 = this._comg1 =
1952
+ sbet1 !== 0 || this.calp1 !== 0 ? cbet1 * this.calp1 : 1;
1953
+ // norm(this._ssig1, this._csig1); // sig1 in (-pi, pi]
1954
+ t = m.hypot(this._ssig1, this._csig1);
1955
+ this._ssig1 /= t; this._csig1 /= t;
1956
+ // norm(this._somg1, this._comg1); -- don't need to normalize!
1957
+
1958
+ this._k2 = m.sq(this._calp0) * geod._ep2;
1959
+ eps = this._k2 / (2 * (1 + Math.sqrt(1 + this._k2)) + this._k2);
1960
+
1961
+ if (this.caps & g.CAP_C1) {
1962
+ this._A1m1 = g.A1m1f(eps);
1963
+ this._C1a = new Array(g.nC1_ + 1);
1964
+ g.C1f(eps, this._C1a);
1965
+ this._B11 = g.SinCosSeries(true, this._ssig1, this._csig1, this._C1a);
1966
+ s = Math.sin(this._B11); c = Math.cos(this._B11);
1967
+ // tau1 = sig1 + B11
1968
+ this._stau1 = this._ssig1 * c + this._csig1 * s;
1969
+ this._ctau1 = this._csig1 * c - this._ssig1 * s;
1970
+ // Not necessary because C1pa reverts C1a
1971
+ // _B11 = -SinCosSeries(true, _stau1, _ctau1, _C1pa);
1972
+ }
1973
+
1974
+ if (this.caps & g.CAP_C1p) {
1975
+ this._C1pa = new Array(g.nC1p_ + 1);
1976
+ g.C1pf(eps, this._C1pa);
1977
+ }
1978
+
1979
+ if (this.caps & g.CAP_C2) {
1980
+ this._A2m1 = g.A2m1f(eps);
1981
+ this._C2a = new Array(g.nC2_ + 1);
1982
+ g.C2f(eps, this._C2a);
1983
+ this._B21 = g.SinCosSeries(true, this._ssig1, this._csig1, this._C2a);
1984
+ }
1985
+
1986
+ if (this.caps & g.CAP_C3) {
1987
+ this._C3a = new Array(g.nC3_);
1988
+ geod.C3f(eps, this._C3a);
1989
+ this._A3c = -this.f * this._salp0 * geod.A3f(eps);
1990
+ this._B31 = g.SinCosSeries(true, this._ssig1, this._csig1, this._C3a);
1991
+ }
1992
+
1993
+ if (this.caps & g.CAP_C4) {
1994
+ this._C4a = new Array(g.nC4_); // all the elements of _C4a are used
1995
+ geod.C4f(eps, this._C4a);
1996
+ // Multiplier = a^2 * e^2 * cos(alpha0) * sin(alpha0)
1997
+ this._A4 = m.sq(this.a) * this._calp0 * this._salp0 * geod._e2;
1998
+ this._B41 = g.SinCosSeries(false, this._ssig1, this._csig1, this._C4a);
1999
+ }
2000
+
2001
+ this.a13 = this.s13 = Number.NaN;
2002
+ };
2003
+
2004
+ /**
2005
+ * @summary Find the position on the line (general case).
2006
+ * @param {bool} arcmode is the next parameter an arc length?
2007
+ * @param {number} s12_a12 the (arcmode ? arc length : distance) from the
2008
+ * first point to the second in (arcmode ? degrees : meters).
2009
+ * @param {bitmask} [outmask = STANDARD] which results to include; this is
2010
+ * subject to the capabilities of the object.
2011
+ * @returns {object} the requested results.
2012
+ * @description The lat1, lon1, azi1, and a12 fields of the result are
2013
+ * always set; s12 is included if arcmode is false. For details on the
2014
+ * outmask parameter, see {@tutorial 2-interface}, "The outmask and caps
2015
+ * parameters".
2016
+ */
2017
+ l.GeodesicLine.prototype.GenPosition = function(arcmode, s12_a12,
2018
+ outmask) {
2019
+ var vals = {},
2020
+ sig12, ssig12, csig12, B12, AB1, ssig2, csig2, tau12, s, c, serr,
2021
+ omg12, lam12, lon12, E, sbet2, cbet2, somg2, comg2, salp2, calp2, dn2,
2022
+ B22, AB2, J12, t, B42, salp12, calp12;
2023
+ if (!outmask) outmask = g.STANDARD;
2024
+ else if (outmask === g.LONG_UNROLL) outmask |= g.STANDARD;
2025
+ outmask &= this.caps & g.OUT_MASK;
2026
+ vals.lat1 = this.lat1; vals.azi1 = this.azi1;
2027
+ vals.lon1 = outmask & g.LONG_UNROLL ?
2028
+ this.lon1 : m.AngNormalize(this.lon1);
2029
+ if (arcmode)
2030
+ vals.a12 = s12_a12;
2031
+ else
2032
+ vals.s12 = s12_a12;
2033
+ if (!( arcmode || (this.caps & g.DISTANCE_IN & g.OUT_MASK) )) {
2034
+ // Uninitialized or impossible distance calculation requested
2035
+ vals.a12 = Number.NaN;
2036
+ return vals;
2037
+ }
2038
+
2039
+ // Avoid warning about uninitialized B12.
2040
+ B12 = 0; AB1 = 0;
2041
+ if (arcmode) {
2042
+ // Interpret s12_a12 as spherical arc length
2043
+ sig12 = s12_a12 * m.degree;
2044
+ t = m.sincosd(s12_a12); ssig12 = t.s; csig12 = t.c;
2045
+ } else {
2046
+ // Interpret s12_a12 as distance
2047
+ tau12 = s12_a12 / (this._b * (1 + this._A1m1));
2048
+ s = Math.sin(tau12);
2049
+ c = Math.cos(tau12);
2050
+ // tau2 = tau1 + tau12
2051
+ B12 = - g.SinCosSeries(true,
2052
+ this._stau1 * c + this._ctau1 * s,
2053
+ this._ctau1 * c - this._stau1 * s,
2054
+ this._C1pa);
2055
+ sig12 = tau12 - (B12 - this._B11);
2056
+ ssig12 = Math.sin(sig12); csig12 = Math.cos(sig12);
2057
+ if (Math.abs(this.f) > 0.01) {
2058
+ // Reverted distance series is inaccurate for |f| > 1/100, so correct
2059
+ // sig12 with 1 Newton iteration. The following table shows the
2060
+ // approximate maximum error for a = WGS_a() and various f relative to
2061
+ // GeodesicExact.
2062
+ // erri = the error in the inverse solution (nm)
2063
+ // errd = the error in the direct solution (series only) (nm)
2064
+ // errda = the error in the direct solution (series + 1 Newton) (nm)
2065
+ //
2066
+ // f erri errd errda
2067
+ // -1/5 12e6 1.2e9 69e6
2068
+ // -1/10 123e3 12e6 765e3
2069
+ // -1/20 1110 108e3 7155
2070
+ // -1/50 18.63 200.9 27.12
2071
+ // -1/100 18.63 23.78 23.37
2072
+ // -1/150 18.63 21.05 20.26
2073
+ // 1/150 22.35 24.73 25.83
2074
+ // 1/100 22.35 25.03 25.31
2075
+ // 1/50 29.80 231.9 30.44
2076
+ // 1/20 5376 146e3 10e3
2077
+ // 1/10 829e3 22e6 1.5e6
2078
+ // 1/5 157e6 3.8e9 280e6
2079
+ ssig2 = this._ssig1 * csig12 + this._csig1 * ssig12;
2080
+ csig2 = this._csig1 * csig12 - this._ssig1 * ssig12;
2081
+ B12 = g.SinCosSeries(true, ssig2, csig2, this._C1a);
2082
+ serr = (1 + this._A1m1) * (sig12 + (B12 - this._B11)) -
2083
+ s12_a12 / this._b;
2084
+ sig12 = sig12 - serr / Math.sqrt(1 + this._k2 * m.sq(ssig2));
2085
+ ssig12 = Math.sin(sig12); csig12 = Math.cos(sig12);
2086
+ // Update B12 below
2087
+ }
2088
+ }
2089
+
2090
+ // sig2 = sig1 + sig12
2091
+ ssig2 = this._ssig1 * csig12 + this._csig1 * ssig12;
2092
+ csig2 = this._csig1 * csig12 - this._ssig1 * ssig12;
2093
+ dn2 = Math.sqrt(1 + this._k2 * m.sq(ssig2));
2094
+ if (outmask & (g.DISTANCE | g.REDUCEDLENGTH | g.GEODESICSCALE)) {
2095
+ if (arcmode || Math.abs(this.f) > 0.01)
2096
+ B12 = g.SinCosSeries(true, ssig2, csig2, this._C1a);
2097
+ AB1 = (1 + this._A1m1) * (B12 - this._B11);
2098
+ }
2099
+ // sin(bet2) = cos(alp0) * sin(sig2)
2100
+ sbet2 = this._calp0 * ssig2;
2101
+ // Alt: cbet2 = hypot(csig2, salp0 * ssig2);
2102
+ cbet2 = m.hypot(this._salp0, this._calp0 * csig2);
2103
+ if (cbet2 === 0)
2104
+ // I.e., salp0 = 0, csig2 = 0. Break the degeneracy in this case
2105
+ cbet2 = csig2 = g.tiny_;
2106
+ // tan(alp0) = cos(sig2)*tan(alp2)
2107
+ salp2 = this._salp0; calp2 = this._calp0 * csig2; // No need to normalize
2108
+
2109
+ if (arcmode && (outmask & g.DISTANCE))
2110
+ vals.s12 = this._b * ((1 + this._A1m1) * sig12 + AB1);
2111
+
2112
+ if (outmask & g.LONGITUDE) {
2113
+ // tan(omg2) = sin(alp0) * tan(sig2)
2114
+ somg2 = this._salp0 * ssig2; comg2 = csig2; // No need to normalize
2115
+ E = m.copysign(1, this._salp0);
2116
+ // omg12 = omg2 - omg1
2117
+ omg12 = outmask & g.LONG_UNROLL ?
2118
+ E * (sig12 -
2119
+ (Math.atan2(ssig2, csig2) -
2120
+ Math.atan2(this._ssig1, this._csig1)) +
2121
+ (Math.atan2(E * somg2, comg2) -
2122
+ Math.atan2(E * this._somg1, this._comg1))) :
2123
+ Math.atan2(somg2 * this._comg1 - comg2 * this._somg1,
2124
+ comg2 * this._comg1 + somg2 * this._somg1);
2125
+ lam12 = omg12 + this._A3c *
2126
+ ( sig12 + (g.SinCosSeries(true, ssig2, csig2, this._C3a) -
2127
+ this._B31));
2128
+ lon12 = lam12 / m.degree;
2129
+ vals.lon2 = outmask & g.LONG_UNROLL ? this.lon1 + lon12 :
2130
+ m.AngNormalize(m.AngNormalize(this.lon1) + m.AngNormalize(lon12));
2131
+ }
2132
+
2133
+ if (outmask & g.LATITUDE)
2134
+ vals.lat2 = m.atan2d(sbet2, this._f1 * cbet2);
2135
+
2136
+ if (outmask & g.AZIMUTH)
2137
+ vals.azi2 = m.atan2d(salp2, calp2);
2138
+
2139
+ if (outmask & (g.REDUCEDLENGTH | g.GEODESICSCALE)) {
2140
+ B22 = g.SinCosSeries(true, ssig2, csig2, this._C2a);
2141
+ AB2 = (1 + this._A2m1) * (B22 - this._B21);
2142
+ J12 = (this._A1m1 - this._A2m1) * sig12 + (AB1 - AB2);
2143
+ if (outmask & g.REDUCEDLENGTH)
2144
+ // Add parens around (_csig1 * ssig2) and (_ssig1 * csig2) to ensure
2145
+ // accurate cancellation in the case of coincident points.
2146
+ vals.m12 = this._b * (( dn2 * (this._csig1 * ssig2) -
2147
+ this._dn1 * (this._ssig1 * csig2)) -
2148
+ this._csig1 * csig2 * J12);
2149
+ if (outmask & g.GEODESICSCALE) {
2150
+ t = this._k2 * (ssig2 - this._ssig1) * (ssig2 + this._ssig1) /
2151
+ (this._dn1 + dn2);
2152
+ vals.M12 = csig12 + (t * ssig2 - csig2 * J12) * this._ssig1 / this._dn1;
2153
+ vals.M21 = csig12 - (t * this._ssig1 - this._csig1 * J12) * ssig2 / dn2;
2154
+ }
2155
+ }
2156
+
2157
+ if (outmask & g.AREA) {
2158
+ B42 = g.SinCosSeries(false, ssig2, csig2, this._C4a);
2159
+ if (this._calp0 === 0 || this._salp0 === 0) {
2160
+ // alp12 = alp2 - alp1, used in atan2 so no need to normalize
2161
+ salp12 = salp2 * this.calp1 - calp2 * this.salp1;
2162
+ calp12 = calp2 * this.calp1 + salp2 * this.salp1;
2163
+ } else {
2164
+ // tan(alp) = tan(alp0) * sec(sig)
2165
+ // tan(alp2-alp1) = (tan(alp2) -tan(alp1)) / (tan(alp2)*tan(alp1)+1)
2166
+ // = calp0 * salp0 * (csig1-csig2) / (salp0^2 + calp0^2 * csig1*csig2)
2167
+ // If csig12 > 0, write
2168
+ // csig1 - csig2 = ssig12 * (csig1 * ssig12 / (1 + csig12) + ssig1)
2169
+ // else
2170
+ // csig1 - csig2 = csig1 * (1 - csig12) + ssig12 * ssig1
2171
+ // No need to normalize
2172
+ salp12 = this._calp0 * this._salp0 *
2173
+ (csig12 <= 0 ? this._csig1 * (1 - csig12) + ssig12 * this._ssig1 :
2174
+ ssig12 * (this._csig1 * ssig12 / (1 + csig12) + this._ssig1));
2175
+ calp12 = m.sq(this._salp0) + m.sq(this._calp0) * this._csig1 * csig2;
2176
+ }
2177
+ vals.S12 = this._c2 * Math.atan2(salp12, calp12) +
2178
+ this._A4 * (B42 - this._B41);
2179
+ }
2180
+
2181
+ if (!arcmode)
2182
+ vals.a12 = sig12 / m.degree;
2183
+ return vals;
2184
+ };
2185
+
2186
+ /**
2187
+ * @summary Find the position on the line given s12.
2188
+ * @param {number} s12 the distance from the first point to the second in
2189
+ * meters.
2190
+ * @param {bitmask} [outmask = STANDARD] which results to include; this is
2191
+ * subject to the capabilities of the object.
2192
+ * @returns {object} the requested results.
2193
+ * @description The lat1, lon1, azi1, s12, and a12 fields of the result are
2194
+ * always set; s12 is included if arcmode is false. For details on the
2195
+ * outmask parameter, see {@tutorial 2-interface}, "The outmask and caps
2196
+ * parameters".
2197
+ */
2198
+ l.GeodesicLine.prototype.Position = function(s12, outmask) {
2199
+ return this.GenPosition(false, s12, outmask);
2200
+ };
2201
+
2202
+ /**
2203
+ * @summary Find the position on the line given a12.
2204
+ * @param {number} a12 the arc length from the first point to the second in
2205
+ * degrees.
2206
+ * @param {bitmask} [outmask = STANDARD] which results to include; this is
2207
+ * subject to the capabilities of the object.
2208
+ * @returns {object} the requested results.
2209
+ * @description The lat1, lon1, azi1, and a12 fields of the result are
2210
+ * always set. For details on the outmask parameter, see {@tutorial
2211
+ * 2-interface}, "The outmask and caps parameters".
2212
+ */
2213
+ l.GeodesicLine.prototype.ArcPosition = function(a12, outmask) {
2214
+ return this.GenPosition(true, a12, outmask);
2215
+ };
2216
+
2217
+ /**
2218
+ * @summary Specify position of point 3 in terms of either distance or arc
2219
+ * length.
2220
+ * @param {bool} arcmode boolean flag determining the meaning of the second
2221
+ * parameter; if arcmode is false, then the GeodesicLine object must have
2222
+ * been constructed with caps |= DISTANCE_IN.
2223
+ * @param {number} s13_a13 if arcmode is false, this is the distance from
2224
+ * point 1 to point 3 (meters); otherwise it is the arc length from
2225
+ * point 1 to point 3 (degrees); it can be negative.
2226
+ **********************************************************************/
2227
+ l.GeodesicLine.prototype.GenSetDistance = function(arcmode, s13_a13) {
2228
+ if (arcmode)
2229
+ this.SetArc(s13_a13);
2230
+ else
2231
+ this.SetDistance(s13_a13);
2232
+ };
2233
+
2234
+ /**
2235
+ * @summary Specify position of point 3 in terms distance.
2236
+ * @param {number} s13 the distance from point 1 to point 3 (meters); it
2237
+ * can be negative.
2238
+ **********************************************************************/
2239
+ l.GeodesicLine.prototype.SetDistance = function(s13) {
2240
+ var r;
2241
+ this.s13 = s13;
2242
+ r = this.GenPosition(false, this.s13, g.ARC);
2243
+ this.a13 = 0 + r.a12; // the 0+ converts undefined into NaN
2244
+ };
2245
+
2246
+ /**
2247
+ * @summary Specify position of point 3 in terms of arc length.
2248
+ * @param {number} a13 the arc length from point 1 to point 3 (degrees);
2249
+ * it can be negative.
2250
+ **********************************************************************/
2251
+ l.GeodesicLine.prototype.SetArc = function(a13) {
2252
+ var r;
2253
+ this.a13 = a13;
2254
+ r = this.GenPosition(true, this.a13, g.DISTANCE);
2255
+ this.s13 = 0 + r.s12; // the 0+ converts undefined into NaN
2256
+ };
2257
+
2258
+ })(GeographicLib.Geodesic, GeographicLib.GeodesicLine, GeographicLib.Math);
2259
+
2260
+ /**************** PolygonArea.js ****************/
2261
+ /*
2262
+ * PolygonArea.js
2263
+ * Transcription of PolygonArea.[ch]pp into JavaScript.
2264
+ *
2265
+ * See the documentation for the C++ class. The conversion is a literal
2266
+ * conversion from C++.
2267
+ *
2268
+ * The algorithms are derived in
2269
+ *
2270
+ * Charles F. F. Karney,
2271
+ * Algorithms for geodesics, J. Geodesy 87, 43-55 (2013);
2272
+ * https://dx.doi.org/10.1007/s00190-012-0578-z
2273
+ * Addenda: http://geographiclib.sourceforge.net/geod-addenda.html
2274
+ *
2275
+ * Copyright (c) Charles Karney (2011-2016) <charles@karney.com> and licensed
2276
+ * under the MIT/X11 License. For more information, see
2277
+ * http://geographiclib.sourceforge.net/
2278
+ */
2279
+
2280
+ // Load AFTER GeographicLib/Math.js and GeographicLib/Geodesic.js
2281
+
2282
+ (function(
2283
+ /**
2284
+ * @exports GeographicLib/PolygonArea
2285
+ * @description Compute the area of geodesic polygons via the
2286
+ * {@link module:GeographicLib/PolygonArea.PolygonArea PolygonArea}
2287
+ * class.
2288
+ */
2289
+ p, g, m, a) {
2290
+
2291
+ var transit, transitdirect;
2292
+ transit = function(lon1, lon2) {
2293
+ // Return 1 or -1 if crossing prime meridian in east or west direction.
2294
+ // Otherwise return zero.
2295
+ var lon12, cross;
2296
+ // Compute lon12 the same way as Geodesic::Inverse.
2297
+ lon1 = m.AngNormalize(lon1);
2298
+ lon2 = m.AngNormalize(lon2);
2299
+ lon12 = m.AngDiff(lon1, lon2).s;
2300
+ cross = lon1 < 0 && lon2 >= 0 && lon12 > 0 ? 1 :
2301
+ (lon2 < 0 && lon1 >= 0 && lon12 < 0 ? -1 : 0);
2302
+ return cross;
2303
+ };
2304
+
2305
+ // an alternate version of transit to deal with longitudes in the direct
2306
+ // problem.
2307
+ transitdirect = function(lon1, lon2) {
2308
+ // We want to compute exactly
2309
+ // int(floor(lon2 / 360)) - int(floor(lon1 / 360))
2310
+ // Since we only need the parity of the result we can use std::remquo but
2311
+ // this is buggy with g++ 4.8.3 and requires C++11. So instead we do
2312
+ lon1 = lon1 % 720.0; lon2 = lon2 % 720.0;
2313
+ return ( ((lon2 >= 0 && lon2 < 360) || lon2 < -360 ? 0 : 1) -
2314
+ ((lon1 >= 0 && lon1 < 360) || lon1 < -360 ? 0 : 1) );
2315
+ };
2316
+
2317
+ /**
2318
+ * @class
2319
+ * @property {number} a the equatorial radius (meters).
2320
+ * @property {number} f the flattening.
2321
+ * @property {bool} polyline whether the PolygonArea object describes a
2322
+ * polyline or a polygon.
2323
+ * @property {number} num the number of vertices so far.
2324
+ * @property {number} lat the current latitude (degrees).
2325
+ * @property {number} lon the current longitude (degrees).
2326
+ * @summary Initialize a PolygonArea object.
2327
+ * @classdesc Computes the area and perimeter of a geodesic polygon.
2328
+ * This object is usually instantiated by
2329
+ * {@link module:GeographicLib/Geodesic.Geodesic#Polygon Geodesic.Polygon}.
2330
+ * @param {object} geod a {@link module:GeographicLib/Geodesic.Geodesic
2331
+ * Geodesic} object.
2332
+ * @param {bool} [polyline = false] if true the new PolygonArea object
2333
+ * describes a polyline instead of a polygon.
2334
+ */
2335
+ p.PolygonArea = function(geod, polyline) {
2336
+ this._geod = geod;
2337
+ this.a = this._geod.a;
2338
+ this.f = this._geod.f;
2339
+ this._area0 = 4 * Math.PI * geod._c2;
2340
+ this.polyline = !polyline ? false : polyline;
2341
+ this._mask = g.LATITUDE | g.LONGITUDE | g.DISTANCE |
2342
+ (this.polyline ? g.NONE : g.AREA | g.LONG_UNROLL);
2343
+ if (!this.polyline)
2344
+ this._areasum = new a.Accumulator(0);
2345
+ this._perimetersum = new a.Accumulator(0);
2346
+ this.Clear();
2347
+ };
2348
+
2349
+ /**
2350
+ * @summary Clear the PolygonArea object, setting the number of vertices to
2351
+ * 0.
2352
+ */
2353
+ p.PolygonArea.prototype.Clear = function() {
2354
+ this.num = 0;
2355
+ this._crossings = 0;
2356
+ if (!this.polyline)
2357
+ this._areasum.Set(0);
2358
+ this._perimetersum.Set(0);
2359
+ this._lat0 = this._lon0 = this.lat = this.lon = Number.NaN;
2360
+ };
2361
+
2362
+ /**
2363
+ * @summary Add the next vertex to the polygon.
2364
+ * @param {number} lat the latitude of the point (degrees).
2365
+ * @param {number} lon the longitude of the point (degrees).
2366
+ * @description This adds an edge from the current vertex to the new vertex.
2367
+ */
2368
+ p.PolygonArea.prototype.AddPoint = function(lat, lon) {
2369
+ var t;
2370
+ if (this.num === 0) {
2371
+ this._lat0 = this.lat = lat;
2372
+ this._lon0 = this.lon = lon;
2373
+ } else {
2374
+ t = this._geod.Inverse(this.lat, this.lon, lat, lon, this._mask);
2375
+ this._perimetersum.Add(t.s12);
2376
+ if (!this.polyline) {
2377
+ this._areasum.Add(t.S12);
2378
+ this._crossings += transit(this.lon, lon);
2379
+ }
2380
+ this.lat = lat;
2381
+ this.lon = lon;
2382
+ }
2383
+ ++this.num;
2384
+ };
2385
+
2386
+ /**
2387
+ * @summary Add the next edge to the polygon.
2388
+ * @param {number} azi the azimuth at the current the point (degrees).
2389
+ * @param {number} s the length of the edge (meters).
2390
+ * @description This specifies the new vertex in terms of the edge from the
2391
+ * current vertex.
2392
+ */
2393
+ p.PolygonArea.prototype.AddEdge = function(azi, s) {
2394
+ var t;
2395
+ if (this.num) {
2396
+ t = this._geod.Direct(this.lat, this.lon, azi, s, this._mask);
2397
+ this._perimetersum.Add(s);
2398
+ if (!this.polyline) {
2399
+ this._areasum.Add(t.S12);
2400
+ this._crossings += transitdirect(this.lon, t.lon2);
2401
+ }
2402
+ this.lat = t.lat2;
2403
+ this.lon = t.lon2;
2404
+ }
2405
+ ++this.num;
2406
+ };
2407
+
2408
+ /**
2409
+ * @summary Compute the perimeter and area of the polygon.
2410
+ * @param {bool} reverse if true then clockwise (instead of
2411
+ * counter-clockwise) traversal counts as a positive area.
2412
+ * @param {bool} sign if true then return a signed result for the area if the
2413
+ * polygon is traversed in the "wrong" direction instead of returning the
2414
+ * area for the rest of the earth.
2415
+ * @returns {object} r where r.number is the number of vertices, r.perimeter
2416
+ * is the perimeter (meters), and r.area (only returned if polyline is
2417
+ * false) is the area (meters<sup>2</sup>).
2418
+ * @description If the object is a polygon (and not a polygon), the perimeter
2419
+ * includes the length of a final edge connecting the current point to the
2420
+ * initial point. If the object is a polyline, then area is nan. More
2421
+ * points can be added to the polygon after this call.
2422
+ */
2423
+ p.PolygonArea.prototype.Compute = function(reverse, sign) {
2424
+ var vals = {number: this.num}, t, tempsum, crossings;
2425
+ if (this.num < 2) {
2426
+ vals.perimeter = 0;
2427
+ if (!this.polyline)
2428
+ vals.area = 0;
2429
+ return vals;
2430
+ }
2431
+ if (this.polyline) {
2432
+ vals.perimeter = this._perimetersum.Sum();
2433
+ return vals;
2434
+ }
2435
+ t = this._geod.Inverse(this.lat, this.lon, this._lat0, this._lon0,
2436
+ this._mask);
2437
+ vals.perimeter = this._perimetersum.Sum(t.s12);
2438
+ tempsum = new a.Accumulator(this._areasum);
2439
+ tempsum.Add(t.S12);
2440
+ crossings = this._crossings + transit(this.lon, this._lon0);
2441
+ if (crossings & 1)
2442
+ tempsum.Add( (tempsum.Sum() < 0 ? 1 : -1) * this._area0/2 );
2443
+ // area is with the clockwise sense. If !reverse convert to
2444
+ // counter-clockwise convention.
2445
+ if (!reverse)
2446
+ tempsum.Negate();
2447
+ // If sign put area in (-area0/2, area0/2], else put area in [0, area0)
2448
+ if (sign) {
2449
+ if (tempsum.Sum() > this._area0/2)
2450
+ tempsum.Add( -this._area0 );
2451
+ else if (tempsum.Sum() <= -this._area0/2)
2452
+ tempsum.Add( +this._area0 );
2453
+ } else {
2454
+ if (tempsum.Sum() >= this._area0)
2455
+ tempsum.Add( -this._area0 );
2456
+ else if (tempsum < 0)
2457
+ tempsum.Add( -this._area0 );
2458
+ }
2459
+ vals.area = tempsum.Sum();
2460
+ return vals;
2461
+ };
2462
+
2463
+ /**
2464
+ * @summary Compute the perimeter and area of the polygon with a tentative
2465
+ * new vertex.
2466
+ * @param {number} lat the latitude of the point (degrees).
2467
+ * @param {number} lon the longitude of the point (degrees).
2468
+ * @param {bool} reverse if true then clockwise (instead of
2469
+ * counter-clockwise) traversal counts as a positive area.
2470
+ * @param {bool} sign if true then return a signed result for the area if the
2471
+ * polygon is traversed in the "wrong" direction instead of returning the
2472
+ * @returns {object} r where r.number is the number of vertices, r.perimeter
2473
+ * is the perimeter (meters), and r.area (only returned if polyline is
2474
+ * false) is the area (meters<sup>2</sup>).
2475
+ * @description A new vertex is *not* added to the polygon.
2476
+ */
2477
+ p.PolygonArea.prototype.TestPoint = function(lat, lon, reverse, sign) {
2478
+ var vals = {number: this.num + 1}, t, tempsum, crossings, i;
2479
+ if (this.num === 0) {
2480
+ vals.perimeter = 0;
2481
+ if (!this.polyline)
2482
+ vals.area = 0;
2483
+ return vals;
2484
+ }
2485
+ vals.perimeter = this._perimetersum.Sum();
2486
+ tempsum = this.polyline ? 0 : this._areasum.Sum();
2487
+ crossings = this._crossings;
2488
+ for (i = 0; i < (this.polyline ? 1 : 2); ++i) {
2489
+ t = this._geod.Inverse(
2490
+ i === 0 ? this.lat : lat, i === 0 ? this.lon : lon,
2491
+ i !== 0 ? this._lat0 : lat, i !== 0 ? this._lon0 : lon,
2492
+ this._mask);
2493
+ vals.perimeter += t.s12;
2494
+ if (!this.polyline) {
2495
+ tempsum += t.S12;
2496
+ crossings += transit(i === 0 ? this.lon : lon,
2497
+ i !== 0 ? this._lon0 : lon);
2498
+ }
2499
+ }
2500
+
2501
+ if (this.polyline)
2502
+ return vals;
2503
+
2504
+ if (crossings & 1)
2505
+ tempsum += (tempsum < 0 ? 1 : -1) * this._area0/2;
2506
+ // area is with the clockwise sense. If !reverse convert to
2507
+ // counter-clockwise convention.
2508
+ if (!reverse)
2509
+ tempsum *= -1;
2510
+ // If sign put area in (-area0/2, area0/2], else put area in [0, area0)
2511
+ if (sign) {
2512
+ if (tempsum > this._area0/2)
2513
+ tempsum -= this._area0;
2514
+ else if (tempsum <= -this._area0/2)
2515
+ tempsum += this._area0;
2516
+ } else {
2517
+ if (tempsum >= this._area0)
2518
+ tempsum -= this._area0;
2519
+ else if (tempsum < 0)
2520
+ tempsum += this._area0;
2521
+ }
2522
+ vals.area = tempsum;
2523
+ return vals;
2524
+ };
2525
+
2526
+ /**
2527
+ * @summary Compute the perimeter and area of the polygon with a tentative
2528
+ * new edge.
2529
+ * @param {number} azi the azimuth of the edge (degrees).
2530
+ * @param {number} s the length of the edge (meters).
2531
+ * @param {bool} reverse if true then clockwise (instead of
2532
+ * counter-clockwise) traversal counts as a positive area.
2533
+ * @param {bool} sign if true then return a signed result for the area if the
2534
+ * polygon is traversed in the "wrong" direction instead of returning the
2535
+ * @returns {object} r where r.number is the number of vertices, r.perimeter
2536
+ * is the perimeter (meters), and r.area (only returned if polyline is
2537
+ * false) is the area (meters<sup>2</sup>).
2538
+ * @description A new vertex is *not* added to the polygon.
2539
+ */
2540
+ p.PolygonArea.prototype.TestEdge = function(azi, s, reverse, sign) {
2541
+ var vals = {number: this.num ? this.num + 1 : 0}, t, tempsum, crossings;
2542
+ if (this.num === 0)
2543
+ return vals;
2544
+ vals.perimeter = this._perimetersum.Sum() + s;
2545
+ if (this.polyline)
2546
+ return vals;
2547
+
2548
+ tempsum = this._areasum.Sum();
2549
+ crossings = this._crossings;
2550
+ t = this._geod.Direct(this.lat, this.lon, azi, s, this._mask);
2551
+ tempsum += t.S12;
2552
+ crossings += transitdirect(this.lon, t.lon2);
2553
+ t = this._geod.Inverse(t.lat2, t.lon2, this._lat0, this._lon0, this._mask);
2554
+ vals.perimeter += t.s12;
2555
+ tempsum += t.S12;
2556
+ crossings += transit(t.lon2, this._lon0);
2557
+
2558
+ if (crossings & 1)
2559
+ tempsum += (tempsum < 0 ? 1 : -1) * this._area0/2;
2560
+ // area is with the clockwise sense. If !reverse convert to
2561
+ // counter-clockwise convention.
2562
+ if (!reverse)
2563
+ tempsum *= -1;
2564
+ // If sign put area in (-area0/2, area0/2], else put area in [0, area0)
2565
+ if (sign) {
2566
+ if (tempsum > this._area0/2)
2567
+ tempsum -= this._area0;
2568
+ else if (tempsum <= -this._area0/2)
2569
+ tempsum += this._area0;
2570
+ } else {
2571
+ if (tempsum >= this._area0)
2572
+ tempsum -= this._area0;
2573
+ else if (tempsum < 0)
2574
+ tempsum += this._area0;
2575
+ }
2576
+ vals.area = tempsum;
2577
+ return vals;
2578
+ };
2579
+
2580
+ })(GeographicLib.PolygonArea, GeographicLib.Geodesic,
2581
+ GeographicLib.Math, GeographicLib.Accumulator);
2582
+
2583
+ /**************** DMS.js ****************/
2584
+ /*
2585
+ * DMS.js
2586
+ * Transcription of DMS.[ch]pp into JavaScript.
2587
+ *
2588
+ * See the documentation for the C++ class. The conversion is a literal
2589
+ * conversion from C++.
2590
+ *
2591
+ * Copyright (c) Charles Karney (2011-2015) <charles@karney.com> and licensed
2592
+ * under the MIT/X11 License. For more information, see
2593
+ * http://geographiclib.sourceforge.net/
2594
+ */
2595
+
2596
+ GeographicLib.DMS = {};
2597
+
2598
+ (function(
2599
+ /**
2600
+ * @exports GeographicLib/DMS
2601
+ * @description Decode/Encode angles expressed as degrees, minutes, and
2602
+ * seconds. This module defines several constants:
2603
+ * - hemisphere indicator (returned by
2604
+ * {@link module:GeographicLib/DMS.Decode Decode}) and a formatting
2605
+ * indicator (used by
2606
+ * {@link module:GeographicLib/DMS.Encode Encode})
2607
+ * - NONE = 0, no designator and format as plain angle;
2608
+ * - LATITUDE = 1, a N/S designator and format as latitude;
2609
+ * - LONGITUDE = 2, an E/W designator and format as longitude;
2610
+ * - AZIMUTH = 3, format as azimuth;
2611
+ * - the specification of the trailing component in
2612
+ * {@link module:GeographicLib/DMS.Encode Encode}
2613
+ * - DEGREE;
2614
+ * - MINUTE;
2615
+ * - SECOND.
2616
+ */
2617
+ d) {
2618
+
2619
+ var lookup, zerofill, internalDecode, numMatch,
2620
+ hemispheres_ = "SNWE",
2621
+ signs_ = "-+",
2622
+ digits_ = "0123456789",
2623
+ dmsindicators_ = "D'\":",
2624
+ // dmsindicatorsu_ = "\u00b0\u2032\u2033"; // Unicode variants
2625
+ dmsindicatorsu_ = "\u00b0'\"", // Use degree symbol
2626
+ components_ = ["degrees", "minutes", "seconds"];
2627
+ lookup = function(s, c) {
2628
+ return s.indexOf(c.toUpperCase());
2629
+ };
2630
+ zerofill = function(s, n) {
2631
+ return String("0000").substr(0, Math.max(0, Math.min(4, n-s.length))) +
2632
+ s;
2633
+ };
2634
+ d.NONE = 0;
2635
+ d.LATITUDE = 1;
2636
+ d.LONGITUDE = 2;
2637
+ d.AZIMUTH = 3;
2638
+ d.DEGREE = 0;
2639
+ d.MINUTE = 1;
2640
+ d.SECOND = 2;
2641
+
2642
+ /**
2643
+ * @summary Decode a DMS string.
2644
+ * @description The interpretation of the string is given in the
2645
+ * documentation of the corresponding function, Decode(string&, flag&)
2646
+ * in the {@link
2647
+ * http://geographiclib.sourceforge.net/html/classGeographicLib_1_1DMS.html
2648
+ * C++ DMS class}
2649
+ * @param {string} dms the string.
2650
+ * @returns {object} r where r.val is the decoded value (degrees) and r.ind
2651
+ * is a hemisphere designator, one of NONE, LATITUDE, LONGITUDE.
2652
+ * @throws an error if the string is illegal.
2653
+ */
2654
+ d.Decode = function(dms) {
2655
+ var dmsa = dms, end,
2656
+ v = 0, i = 0, mi, pi, vals,
2657
+ ind1 = d.NONE, ind2, p, pa, pb;
2658
+ dmsa = dmsa.replace(/\u00b0/g, 'd')
2659
+ .replace(/\u00ba/g, 'd')
2660
+ .replace(/\u2070/g, 'd')
2661
+ .replace(/\u02da/g, 'd')
2662
+ .replace(/\u2032/g, '\'')
2663
+ .replace(/\u00b4/g, '\'')
2664
+ .replace(/\u2019/g, '\'')
2665
+ .replace(/\u2033/g, '"')
2666
+ .replace(/\u201d/g, '"')
2667
+ .replace(/\u2212/g, '-')
2668
+ .replace(/''/g, '"')
2669
+ .trim();
2670
+ end = dmsa.length;
2671
+ // p is pointer to the next piece that needs decoding
2672
+ for (p = 0; p < end; p = pb, ++i) {
2673
+ pa = p;
2674
+ // Skip over initial hemisphere letter (for i == 0)
2675
+ if (i === 0 && lookup(hemispheres_, dmsa.charAt(pa)) >= 0)
2676
+ ++pa;
2677
+ // Skip over initial sign (checking for it if i == 0)
2678
+ if (i > 0 || (pa < end && lookup(signs_, dmsa.charAt(pa)) >= 0))
2679
+ ++pa;
2680
+ // Find next sign
2681
+ mi = dmsa.substr(pa, end - pa).indexOf('-');
2682
+ pi = dmsa.substr(pa, end - pa).indexOf('+');
2683
+ if (mi < 0) mi = end; else mi += pa;
2684
+ if (pi < 0) pi = end; else pi += pa;
2685
+ pb = Math.min(mi, pi);
2686
+ vals = internalDecode(dmsa.substr(p, pb - p));
2687
+ v += vals.val; ind2 = vals.ind;
2688
+ if (ind1 == d.NONE)
2689
+ ind1 = ind2;
2690
+ else if (!(ind2 == d.NONE || ind1 == ind2))
2691
+ throw new Error("Incompatible hemisphere specifies in " +
2692
+ dmsa.substr(0, pb));
2693
+ }
2694
+ if (i === 0)
2695
+ throw new Error("Empty or incomplete DMS string " + dmsa);
2696
+ return {val: v, ind: ind1};
2697
+ };
2698
+
2699
+ internalDecode = function(dmsa) {
2700
+ var vals = {}, errormsg = "",
2701
+ sign, beg, end, ind1, k,
2702
+ ipieces, fpieces, npiece,
2703
+ icurrent, fcurrent, ncurrent, p,
2704
+ pointseen,
2705
+ digcount, intcount,
2706
+ x;
2707
+ do { // Executed once (provides the ability to break)
2708
+ sign = 1;
2709
+ beg = 0; end = dmsa.length;
2710
+ ind1 = d.NONE;
2711
+ k = -1;
2712
+ if (end > beg && (k = lookup(hemispheres_, dmsa.charAt(beg))) >= 0) {
2713
+ ind1 = (k & 2) ? d.LONGITUDE : d.LATITUDE;
2714
+ sign = (k & 1) ? 1 : -1;
2715
+ ++beg;
2716
+ }
2717
+ if (end > beg &&
2718
+ (k = lookup(hemispheres_, dmsa.charAt(end-1))) >= 0) {
2719
+ if (k >= 0) {
2720
+ if (ind1 !== d.NONE) {
2721
+ if (dmsa.charAt(beg - 1).toUpperCase() ===
2722
+ dmsa.charAt(end - 1).toUpperCase())
2723
+ errormsg = "Repeated hemisphere indicators " +
2724
+ dmsa.charAt(beg - 1) + " in " +
2725
+ dmsa.substr(beg - 1, end - beg + 1);
2726
+ else
2727
+ errormsg = "Contradictory hemisphere indicators " +
2728
+ dmsa.charAt(beg - 1) + " and " + dmsa.charAt(end - 1) + " in " +
2729
+ dmsa.substr(beg - 1, end - beg + 1);
2730
+ break;
2731
+ }
2732
+ ind1 = (k & 2) ? d.LONGITUDE : d.LATITUDE;
2733
+ sign = (k & 1) ? 1 : -1;
2734
+ --end;
2735
+ }
2736
+ }
2737
+ if (end > beg && (k = lookup(signs_, dmsa.charAt(beg))) >= 0) {
2738
+ if (k >= 0) {
2739
+ sign *= k ? 1 : -1;
2740
+ ++beg;
2741
+ }
2742
+ }
2743
+ if (end === beg) {
2744
+ errormsg = "Empty or incomplete DMS string " + dmsa;
2745
+ break;
2746
+ }
2747
+ ipieces = [0, 0, 0];
2748
+ fpieces = [0, 0, 0];
2749
+ npiece = 0;
2750
+ icurrent = 0;
2751
+ fcurrent = 0;
2752
+ ncurrent = 0;
2753
+ p = beg;
2754
+ pointseen = false;
2755
+ digcount = 0;
2756
+ intcount = 0;
2757
+ while (p < end) {
2758
+ x = dmsa.charAt(p++);
2759
+ if ((k = lookup(digits_, x)) >= 0) {
2760
+ ++ncurrent;
2761
+ if (digcount > 0) {
2762
+ ++digcount; // Count of decimal digits
2763
+ } else {
2764
+ icurrent = 10 * icurrent + k;
2765
+ ++intcount;
2766
+ }
2767
+ } else if (x === '.') {
2768
+ if (pointseen) {
2769
+ errormsg = "Multiple decimal points in " +
2770
+ dmsa.substr(beg, end - beg);
2771
+ break;
2772
+ }
2773
+ pointseen = true;
2774
+ digcount = 1;
2775
+ } else if ((k = lookup(dmsindicators_, x)) >= 0) {
2776
+ if (k >= 3) {
2777
+ if (p === end) {
2778
+ errormsg = "Illegal for colon to appear at the end of " +
2779
+ dmsa.substr(beg, end - beg);
2780
+ break;
2781
+ }
2782
+ k = npiece;
2783
+ }
2784
+ if (k === npiece - 1) {
2785
+ errormsg = "Repeated " + components_[k] +
2786
+ " component in " + dmsa.substr(beg, end - beg);
2787
+ break;
2788
+ } else if (k < npiece) {
2789
+ errormsg = components_[k] + " component follows " +
2790
+ components_[npiece - 1] + " component in " +
2791
+ dmsa.substr(beg, end - beg);
2792
+ break;
2793
+ }
2794
+ if (ncurrent === 0) {
2795
+ errormsg = "Missing numbers in " + components_[k] +
2796
+ " component of " + dmsa.substr(beg, end - beg);
2797
+ break;
2798
+ }
2799
+ if (digcount > 0) {
2800
+ fcurrent = parseFloat(dmsa.substr(p - intcount - digcount - 1,
2801
+ intcount + digcount));
2802
+ icurrent = 0;
2803
+ }
2804
+ ipieces[k] = icurrent;
2805
+ fpieces[k] = icurrent + fcurrent;
2806
+ if (p < end) {
2807
+ npiece = k + 1;
2808
+ icurrent = fcurrent = 0;
2809
+ ncurrent = digcount = intcount = 0;
2810
+ }
2811
+ } else if (lookup(signs_, x) >= 0) {
2812
+ errormsg = "Internal sign in DMS string " +
2813
+ dmsa.substr(beg, end - beg);
2814
+ break;
2815
+ } else {
2816
+ errormsg = "Illegal character " + x + " in DMS string " +
2817
+ dmsa.substr(beg, end - beg);
2818
+ break;
2819
+ }
2820
+ }
2821
+ if (errormsg.length)
2822
+ break;
2823
+ if (lookup(dmsindicators_, dmsa.charAt(p - 1)) < 0) {
2824
+ if (npiece >= 3) {
2825
+ errormsg = "Extra text following seconds in DMS string " +
2826
+ dmsa.substr(beg, end - beg);
2827
+ break;
2828
+ }
2829
+ if (ncurrent === 0) {
2830
+ errormsg = "Missing numbers in trailing component of " +
2831
+ dmsa.substr(beg, end - beg);
2832
+ break;
2833
+ }
2834
+ if (digcount > 0) {
2835
+ fcurrent = parseFloat(dmsa.substr(p - intcount - digcount,
2836
+ intcount + digcount));
2837
+ icurrent = 0;
2838
+ }
2839
+ ipieces[npiece] = icurrent;
2840
+ fpieces[npiece] = icurrent + fcurrent;
2841
+ }
2842
+ if (pointseen && digcount === 0) {
2843
+ errormsg = "Decimal point in non-terminal component of " +
2844
+ dmsa.substr(beg, end - beg);
2845
+ break;
2846
+ }
2847
+ // Note that we accept 59.999999... even though it rounds to 60.
2848
+ if (ipieces[1] >= 60 || fpieces[1] > 60) {
2849
+ errormsg = "Minutes " + fpieces[1] + " not in range [0,60)";
2850
+ break;
2851
+ }
2852
+ if (ipieces[2] >= 60 || fpieces[2] > 60) {
2853
+ errormsg = "Seconds " + fpieces[2] + " not in range [0,60)";
2854
+ break;
2855
+ }
2856
+ vals.ind = ind1;
2857
+ // Assume check on range of result is made by calling routine (which
2858
+ // might be able to offer a better diagnostic).
2859
+ vals.val = sign *
2860
+ ( fpieces[2] ? (60*(60*fpieces[0] + fpieces[1]) + fpieces[2]) / 3600 :
2861
+ ( fpieces[1] ? (60*fpieces[0] + fpieces[1]) / 60 : fpieces[0] ) );
2862
+ return vals;
2863
+ } while (false);
2864
+ vals.val = numMatch(dmsa);
2865
+ if (vals.val === 0)
2866
+ throw new Error(errormsg);
2867
+ else
2868
+ vals.ind = d.NONE;
2869
+ return vals;
2870
+ };
2871
+
2872
+ numMatch = function(s) {
2873
+ var t, sign, p0, p1;
2874
+ if (s.length < 3)
2875
+ return 0;
2876
+ t = s.toUpperCase().replace(/0+$/,"");
2877
+ sign = t.charAt(0) === '-' ? -1 : 1;
2878
+ p0 = t.charAt(0) === '-' || t.charAt(0) === '+' ? 1 : 0;
2879
+ p1 = t.length - 1;
2880
+ if (p1 + 1 < p0 + 3)
2881
+ return 0;
2882
+ // Strip off sign and trailing 0s
2883
+ t = t.substr(p0, p1 + 1 - p0); // Length at least 3
2884
+ if (t === "NAN" || t === "1.#QNAN" || t === "1.#SNAN" || t === "1.#IND" ||
2885
+ t === "1.#R")
2886
+ return Number.NaN;
2887
+ else if (t === "INF" || t === "1.#INF")
2888
+ return sign * Number.POSITIVE_INFINITY;
2889
+ return 0;
2890
+ };
2891
+
2892
+ /**
2893
+ * @summary Decode two DMS strings interpreting them as a latitude/longitude
2894
+ * pair.
2895
+ * @param {string} stra the first string.
2896
+ * @param {string} strb the first string.
2897
+ * @param {bool} [longfirst = false] if true assume then longitude is given
2898
+ * first (in the absense of any hemisphere indicators).
2899
+ * @returns {object} r where r.lat is the decoded latitude and r.lon is the
2900
+ * decoded longitude (both in degrees).
2901
+ * @throws an error if the strings are illegal.
2902
+ */
2903
+ d.DecodeLatLon = function(stra, strb, longfirst) {
2904
+ var vals = {},
2905
+ valsa = d.Decode(stra),
2906
+ valsb = d.Decode(strb),
2907
+ a = valsa.val, ia = valsa.ind,
2908
+ b = valsb.val, ib = valsb.ind,
2909
+ lat, lon;
2910
+ if (!longfirst) longfirst = false;
2911
+ if (ia === d.NONE && ib === d.NONE) {
2912
+ // Default to lat, long unless longfirst
2913
+ ia = longfirst ? d.LONGITUDE : d.LATITUDE;
2914
+ ib = longfirst ? d.LATITUDE : d.LONGITUDE;
2915
+ } else if (ia === d.NONE)
2916
+ ia = d.LATITUDE + d.LONGITUDE - ib;
2917
+ else if (ib === d.NONE)
2918
+ ib = d.LATITUDE + d.LONGITUDE - ia;
2919
+ if (ia === ib)
2920
+ throw new Error("Both " + stra + " and " + strb + " interpreted as " +
2921
+ (ia === d.LATITUDE ? "latitudes" : "longitudes"));
2922
+ lat = ia === d.LATITUDE ? a : b;
2923
+ lon = ia === d.LATITUDE ? b : a;
2924
+ if (Math.abs(lat) > 90)
2925
+ throw new Error("Latitude " + lat + " not in [-90,90]");
2926
+ vals.lat = lat;
2927
+ vals.lon = lon;
2928
+ return vals;
2929
+ };
2930
+
2931
+ /**
2932
+ * @summary Decode a DMS string interpreting it as an arc length.
2933
+ * @param {string} angstr the string (this must not include a hemisphere
2934
+ * indicator).
2935
+ * @returns {number} the arc length (degrees).
2936
+ * @throws an error if the string is illegal.
2937
+ */
2938
+ d.DecodeAngle = function(angstr) {
2939
+ var vals = d.Decode(angstr),
2940
+ ang = vals.val, ind = vals.ind;
2941
+ if (ind !== d.NONE)
2942
+ throw new Error("Arc angle " + angstr + " includes a hemisphere N/E/W/S");
2943
+ return ang;
2944
+ };
2945
+
2946
+ /**
2947
+ * @summary Decode a DMS string interpreting it as an azimuth.
2948
+ * @param {string} azistr the string (this may include an E/W hemisphere
2949
+ * indicator).
2950
+ * @returns {number} the azimuth (degrees).
2951
+ * @throws an error if the string is illegal.
2952
+ */
2953
+ d.DecodeAzimuth = function(azistr) {
2954
+ var vals = d.Decode(azistr),
2955
+ azi = vals.val, ind = vals.ind;
2956
+ if (ind === d.LATITUDE)
2957
+ throw new Error("Azimuth " + azistr + " has a latitude hemisphere N/S");
2958
+ return azi;
2959
+ };
2960
+
2961
+ /**
2962
+ * @summary Convert angle (in degrees) into a DMS string (using &deg;, ',
2963
+ * and &quot;).
2964
+ * @param {number} angle input angle (degrees).
2965
+ * @param {number} trailing one of DEGREE, MINUTE, or SECOND to indicate
2966
+ * the trailing component of the string (this component is given as a
2967
+ * decimal number if necessary).
2968
+ * @param {number} prec the number of digits after the decimal point for
2969
+ * the trailing component.
2970
+ * @param {number} [ind = NONE] a formatting indicator, one of NONE,
2971
+ * LATITUDE, LONGITUDE, AZIMUTH.
2972
+ * @returns {string} the resulting string formatted as follows:
2973
+ * * NONE, signed result no leading zeros on degrees except in the units
2974
+ * place, e.g., -8&deg;03'.
2975
+ * * LATITUDE, trailing N or S hemisphere designator, no sign, pad
2976
+ * degrees to 2 digits, e.g., 08&deg;03'S.
2977
+ * * LONGITUDE, trailing E or W hemisphere designator, no sign, pad
2978
+ * degrees to 3 digits, e.g., 008&deg;03'W.
2979
+ * * AZIMUTH, convert to the range [0, 360&deg;), no sign, pad degrees to
2980
+ * 3 digits, e.g., 351&deg;57'.
2981
+ */
2982
+ d.Encode = function(angle, trailing, prec, ind) {
2983
+ // Assume check on range of input angle has been made by calling
2984
+ // routine (which might be able to offer a better diagnostic).
2985
+ var scale = 1, i, sign,
2986
+ idegree, fdegree, f, pieces, ip, fp, s;
2987
+ if (!ind) ind = d.NONE;
2988
+ if (!isFinite(angle))
2989
+ return angle < 0 ? String("-inf") :
2990
+ (angle > 0 ? String("inf") : String("nan"));
2991
+
2992
+ // 15 - 2 * trailing = ceiling(log10(2^53/90/60^trailing)).
2993
+ // This suffices to give full real precision for numbers in [-90,90]
2994
+ prec = Math.min(15 - 2 * trailing, prec);
2995
+ for (i = 0; i < trailing; ++i)
2996
+ scale *= 60;
2997
+ for (i = 0; i < prec; ++i)
2998
+ scale *= 10;
2999
+ if (ind === d.AZIMUTH)
3000
+ angle -= Math.floor(angle/360) * 360;
3001
+ sign = angle < 0 ? -1 : 1;
3002
+ angle *= sign;
3003
+
3004
+ // Break off integer part to preserve precision in manipulation of
3005
+ // fractional part.
3006
+ idegree = Math.floor(angle);
3007
+ fdegree = (angle - idegree) * scale + 0.5;
3008
+ f = Math.floor(fdegree);
3009
+ // Implement the "round ties to even" rule
3010
+ fdegree = (f == fdegree && (f & 1)) ? f - 1 : f;
3011
+ fdegree /= scale;
3012
+
3013
+ fdegree = Math.floor((angle - idegree) * scale + 0.5) / scale;
3014
+ if (fdegree >= 1) {
3015
+ idegree += 1;
3016
+ fdegree -= 1;
3017
+ }
3018
+ pieces = [fdegree, 0, 0];
3019
+ for (i = 1; i <= trailing; ++i) {
3020
+ ip = Math.floor(pieces[i - 1]);
3021
+ fp = pieces[i - 1] - ip;
3022
+ pieces[i] = fp * 60;
3023
+ pieces[i - 1] = ip;
3024
+ }
3025
+ pieces[0] += idegree;
3026
+ s = "";
3027
+ if (ind === d.NONE && sign < 0)
3028
+ s += '-';
3029
+ switch (trailing) {
3030
+ case d.DEGREE:
3031
+ s += zerofill(pieces[0].toFixed(prec),
3032
+ ind === d.NONE ? 0 :
3033
+ 1 + Math.min(ind, 2) + prec + (prec ? 1 : 0)) +
3034
+ dmsindicatorsu_.charAt(0);
3035
+ break;
3036
+ default:
3037
+ s += zerofill(pieces[0].toFixed(0),
3038
+ ind === d.NONE ? 0 : 1 + Math.min(ind, 2)) +
3039
+ dmsindicatorsu_.charAt(0);
3040
+ switch (trailing) {
3041
+ case d.MINUTE:
3042
+ s += zerofill(pieces[1].toFixed(prec), 2 + prec + (prec ? 1 : 0)) +
3043
+ dmsindicatorsu_.charAt(1);
3044
+ break;
3045
+ case d.SECOND:
3046
+ s += zerofill(pieces[1].toFixed(0), 2) + dmsindicatorsu_.charAt(1);
3047
+ s += zerofill(pieces[2].toFixed(prec), 2 + prec + (prec ? 1 : 0)) +
3048
+ dmsindicatorsu_.charAt(2);
3049
+ break;
3050
+ default:
3051
+ break;
3052
+ }
3053
+ }
3054
+ if (ind !== d.NONE && ind !== d.AZIMUTH)
3055
+ s += hemispheres_.charAt((ind === d.LATITUDE ? 0 : 2) +
3056
+ (sign < 0 ? 0 : 1));
3057
+ return s;
3058
+ };
3059
+ })(GeographicLib.DMS);
3060
+
3061
+ cb(GeographicLib);
3062
+
3063
+ })(function(geo) {
3064
+ if (typeof module === 'object' && module.exports) {
3065
+ /******** support loading with node's require ********/
3066
+ module.exports = geo;
3067
+ } else if (typeof define === 'function' && define.amd) {
3068
+ /******** support loading with AMD ********/
3069
+ define('geographiclib', [], function() { return geo; });
3070
+ } else {
3071
+ /******** otherwise just pollute our global namespace ********/
3072
+ window.GeographicLib = geo;
3073
+ }
3074
+ });