leaflet-geodesic-rails 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a10437447f4ecbedb10278f52a2c96e175c67311
4
+ data.tar.gz: 8eb2076cfead12eece7edba2bce9637167a6ffeb
5
+ SHA512:
6
+ metadata.gz: 3633df28e6b19f1df6e3d6f31c52b96519723099b2ce662bb8381a75c891d003eaa4670cc45bb7f9a3900dc3c8a15d7c5b5cd38d5667d3733da00fe996597014
7
+ data.tar.gz: 4279f33c5ff7dcb5fec1595ce27ad73013a32da8bd9f11fff43d971b34ff224b93a797c41bd9457367b5daf917f0c6337a06abd1438b655b48949410984551a0
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Volker Wiegand
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,30 @@
1
+ # Leaflet.Geodesic for Rails
2
+
3
+ Engine wrapper for the Leaflet Geodesic library by @henrythasler.
4
+
5
+ https://github.com/henrythasler/Leaflet.Geodesic.git
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'leaflet-geodesic-rails'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install leaflet-geodesic-rails
20
+
21
+ ## Usage
22
+
23
+ Provides the following assets:
24
+
25
+ leaflet.geodesic.js
26
+
27
+ ## License
28
+ MIT License, full text of license see [here][License]
29
+
30
+ [License]: https://github.com/henrythasler/Leaflet.Geodesic/blob/master/LICENSE "LICENSE"
@@ -0,0 +1,9 @@
1
+ require "leaflet/geodesic/rails/version"
2
+
3
+ module Leaflet
4
+ module Geodesic
5
+ module Rails
6
+ # Your code goes here...
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ module Leaflet
2
+ module Geodesic
3
+ module Rails
4
+ VERSION = "0.7.0"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,409 @@
1
+ // This file is part of Leaflet.Geodesic.
2
+ // Copyright (C) 2014 Henry Thasler
3
+ // based on code by Chris Veness Copyright (C) 2014 https://github.com/chrisveness/geodesy
4
+ //
5
+ // Leaflet.Geodesic is free software: you can redistribute it and/or modify
6
+ // it under the terms of the GNU General Public License as published by
7
+ // the Free Software Foundation, either version 3 of the License, or
8
+ // (at your option) any later version.
9
+ //
10
+ // Leaflet.Geodesic is distributed in the hope that it will be useful,
11
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ // GNU General Public License for more details.
14
+ //
15
+ // You should have received a copy of the GNU General Public License
16
+ // along with Leaflet.Geodesic. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+
19
+
20
+ /** Extend Number object with method to convert numeric degrees to radians */
21
+ if (typeof Number.prototype.toRadians == 'undefined') {
22
+ Number.prototype.toRadians = function() { return this * Math.PI / 180; }
23
+ }
24
+
25
+ /** Extend Number object with method to convert radians to numeric (signed) degrees */
26
+ if (typeof Number.prototype.toDegrees == 'undefined') {
27
+ Number.prototype.toDegrees = function() { return this * 180 / Math.PI; }
28
+ }
29
+
30
+ var INTERSECT_LNG = 179.999; // Lng used for intersection and wrap around on map edges
31
+
32
+ L.Geodesic = L.MultiPolyline.extend({
33
+ options: {
34
+ color:'blue',
35
+ steps: 10,
36
+ dash: 1
37
+ },
38
+
39
+ initialize: function (latlngs, options) {
40
+ this.options = this._merge_options(this.options, options);
41
+ this.datum = {};
42
+ this.datum.ellipsoid = { a: 6378137, b: 6356752.3142, f: 1/298.257223563 }; // WGS-84
43
+ L.MultiPolyline.prototype.initialize.call(this, latlngs, this.options);
44
+ },
45
+
46
+ setLatLngs: function (latlngs) {
47
+ this._latlngs = (this.options.dash<1)?this._generate_GeodesicDashed(latlngs):this._generate_Geodesic(latlngs);
48
+ L.MultiPolyline.prototype.setLatLngs.call(this, this._latlngs);
49
+ },
50
+
51
+ /**
52
+ * Calculates some statistic values of current geodesic multipolyline
53
+ * @returns (Object} Object with several properties (e.g. overall distance)
54
+ */
55
+ getStats: function () {
56
+ var obj={ distance: 0,
57
+ points: 0,
58
+ polygons: this._latlngs.length
59
+ }, poly, points;
60
+
61
+ for(poly=0; poly<this._latlngs.length;poly++) {
62
+ obj.points+=this._latlngs[poly].length;
63
+ for(points=0;points<(this._latlngs[poly].length-1);points++) {
64
+ obj.distance += this._vincenty_inverse(this._latlngs[poly][points], this._latlngs[poly][points+1]).distance;
65
+ }
66
+ }
67
+ return obj;
68
+ },
69
+
70
+ /**
71
+ * Creates a great circle. Replaces all current lines.
72
+ * @param {Object} center - geographic position
73
+ * @param {number} radius - radius of the circle in meters
74
+ */
75
+ createCircle: function (center, radius) {
76
+ var _geo = [], _geocnt=0;
77
+ var prev = {lat:0, lng:0, brg:0};//new L.LatLng(0, 0);
78
+ var s;
79
+
80
+ _geo[_geocnt] = [];
81
+ for(s=0; s<=this.options.steps; ) {
82
+ var direct = this._vincenty_direct(center, 360/this.options.steps*s, radius);
83
+ var gp = new L.LatLng(direct.lat, direct.lng);
84
+ if(Math.abs(gp.lng-prev.lng) > 180) {
85
+ var inverse = this._vincenty_inverse(prev, gp);
86
+ var sec = this._intersection(prev, inverse.initialBearing, {lat: -89, lng:((gp.lng-prev.lng)>0)?-INTERSECT_LNG:INTERSECT_LNG}, 0);
87
+ if(sec) {
88
+ _geo[_geocnt].push(new L.LatLng(sec.lat, sec.lng));
89
+ _geocnt++;
90
+ _geo[_geocnt] = [];
91
+ prev = new L.LatLng(sec.lat, -sec.lng);
92
+ _geo[_geocnt].push(prev);
93
+ }
94
+ else {
95
+ _geocnt++;
96
+ _geo[_geocnt] = [];
97
+ _geo[_geocnt].push(gp);
98
+ prev = gp;
99
+ s++;
100
+ }
101
+ }
102
+ else {
103
+ _geo[_geocnt].push(gp);
104
+ prev = gp;
105
+ s++;
106
+ }
107
+ }
108
+
109
+ this._latlngs = _geo;
110
+ L.MultiPolyline.prototype.setLatLngs.call(this, this._latlngs);
111
+ },
112
+
113
+ /**
114
+ * Creates a geodesic MultiPolyline from given coordinates
115
+ * @param {Object} latlngs - One or more polylines as an array. See Leaflet doc about MultiPolyline
116
+ * @returns (Object} An array of arrays of geographical points.
117
+ */
118
+ _generate_Geodesic: function (latlngs) {
119
+ var _geo = [], _geocnt=0, s, poly, points;
120
+ // _geo = latlngs; // bypass
121
+
122
+ for(poly=0; poly<latlngs.length;poly++) {
123
+ _geo[_geocnt] = [];
124
+ for(points=0;points<(latlngs[poly].length-1);points++) {
125
+ var inverse = this._vincenty_inverse(latlngs[poly][points], latlngs[poly][points+1]);
126
+ var prev = latlngs[poly][points];
127
+ _geo[_geocnt].push(prev);
128
+ for(s=1; s<=this.options.steps; ) {
129
+ var direct = this._vincenty_direct(latlngs[poly][points], inverse.initialBearing, inverse.distance/this.options.steps*s);
130
+ var gp = new L.LatLng(direct.lat, direct.lng);
131
+ if(Math.abs(gp.lng-prev.lng) > 180) {
132
+ var sec = this._intersection(latlngs[poly][points], inverse.initialBearing, {lat: -89, lng:((gp.lng-prev.lng)>0)?-INTERSECT_LNG:INTERSECT_LNG}, 0);
133
+ if(sec) {
134
+ _geo[_geocnt].push(new L.LatLng(sec.lat, sec.lng));
135
+ _geocnt++;
136
+ _geo[_geocnt] = [];
137
+ prev = new L.LatLng(sec.lat, -sec.lng);
138
+ _geo[_geocnt].push(prev);
139
+ }
140
+ else {
141
+ _geocnt++;
142
+ _geo[_geocnt] = [];
143
+ _geo[_geocnt].push(gp);
144
+ prev = gp;
145
+ s++;
146
+ }
147
+ }
148
+ else {
149
+ _geo[_geocnt].push(gp);
150
+ prev = gp;
151
+ s++;
152
+ }
153
+ }
154
+ }
155
+ _geocnt++;
156
+ }
157
+ return _geo;
158
+ },
159
+
160
+
161
+ /**
162
+ * Creates a dashed geodesic MultiPolyline from given coordinates - under work
163
+ * @param {Object} latlngs - One or more polylines as an array. See Leaflet doc about MultiPolyline
164
+ * @returns (Object} An array of arrays of geographical points.
165
+ */
166
+ _generate_GeodesicDashed: function (latlngs) {
167
+ var _geo = [], _geocnt=0, s, poly, points;
168
+ // _geo = latlngs; // bypass
169
+
170
+ for(poly=0; poly<latlngs.length;poly++) {
171
+ _geo[_geocnt] = [];
172
+ for(points=0;points<(latlngs[poly].length-1);points++) {
173
+ var inverse = this._vincenty_inverse(latlngs[poly][points], latlngs[poly][points+1]);
174
+ var prev = latlngs[poly][points];
175
+ _geo[_geocnt].push(prev);
176
+ for(s=1; s<=this.options.steps; ) {
177
+ var direct = this._vincenty_direct(latlngs[poly][points], inverse.initialBearing, inverse.distance/this.options.steps*s-inverse.distance/this.options.steps*(1-this.options.dash));
178
+ var gp = new L.LatLng(direct.lat, direct.lng);
179
+ if(Math.abs(gp.lng-prev.lng) > 180) {
180
+ var sec = this._intersection(latlngs[poly][points], inverse.initialBearing, {lat: -89, lng:((gp.lng-prev.lng)>0)?-INTERSECT_LNG:INTERSECT_LNG}, 0);
181
+ if(sec) {
182
+ _geo[_geocnt].push(new L.LatLng(sec.lat, sec.lng));
183
+ _geocnt++;
184
+ _geo[_geocnt] = [];
185
+ prev = new L.LatLng(sec.lat, -sec.lng);
186
+ _geo[_geocnt].push(prev);
187
+ }
188
+ else {
189
+ _geocnt++;
190
+ _geo[_geocnt] = [];
191
+ _geo[_geocnt].push(gp);
192
+ prev = gp;
193
+ s++;
194
+ }
195
+ }
196
+ else {
197
+ _geo[_geocnt].push(gp);
198
+ _geocnt++;
199
+ var direct2 = this._vincenty_direct(latlngs[poly][points], inverse.initialBearing, inverse.distance/this.options.steps*s);
200
+ _geo[_geocnt] = [];
201
+ _geo[_geocnt].push(new L.LatLng(direct2.lat, direct2.lng));
202
+ s++;
203
+ }
204
+ }
205
+ }
206
+ _geocnt++;
207
+ }
208
+ return _geo;
209
+ },
210
+
211
+
212
+ /**
213
+ * Vincenty direct calculation.
214
+ * based on the work of Chris Veness (https://github.com/chrisveness/geodesy)
215
+ *
216
+ * @private
217
+ * @param {number} initialBearing - Initial bearing in degrees from north.
218
+ * @param {number} distance - Distance along bearing in metres.
219
+ * @returns (Object} Object including point (destination point), finalBearing.
220
+ */
221
+
222
+ _vincenty_direct : function (p1, initialBearing, distance) {
223
+ var φ1 = p1.lat.toRadians(), λ1 = p1.lng.toRadians();
224
+ var α1 = initialBearing.toRadians();
225
+ var s = distance;
226
+
227
+ var a = this.datum.ellipsoid.a, b = this.datum.ellipsoid.b, f = this.datum.ellipsoid.f;
228
+
229
+ var sinα1 = Math.sin(α1);
230
+ var cosα1 = Math.cos(α1);
231
+
232
+ var tanU1 = (1-f) * Math.tan(φ1), cosU1 = 1 / Math.sqrt((1 + tanU1*tanU1)), sinU1 = tanU1 * cosU1;
233
+ var σ1 = Math.atan2(tanU1, cosα1);
234
+ var sinα = cosU1 * sinα1;
235
+ var cosSqα = 1 - sinα*sinα;
236
+ var uSq = cosSqα * (a*a - b*b) / (b*b);
237
+ var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));
238
+ var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)));
239
+
240
+ var σ = s / (b*A), σʹ, iterations = 0;
241
+ do {
242
+ var cos2σM = Math.cos(2*σ1 + σ);
243
+ var sinσ = Math.sin(σ);
244
+ var cosσ = Math.cos(σ);
245
+ var Δσ = B*sinσ*(cos2σM+B/4*(cosσ*(-1+2*cos2σM*cos2σM)-
246
+ B/6*cos2σM*(-3+4*sinσ*sinσ)*(-3+4*cos2σM*cos2σM)));
247
+ σʹ = σ;
248
+ σ = s / (b*A) + Δσ;
249
+ } while (Math.abs(σ-σʹ) > 1e-12 && ++iterations);
250
+
251
+ var x = sinU1*sinσ - cosU1*cosσ*cosα1;
252
+ var φ2 = Math.atan2(sinU1*cosσ + cosU1*sinσ*cosα1, (1-f)*Math.sqrt(sinα*sinα + x*x));
253
+ var λ = Math.atan2(sinσ*sinα1, cosU1*cosσ - sinU1*sinσ*cosα1);
254
+ var C = f/16*cosSqα*(4+f*(4-3*cosSqα));
255
+ var L = λ - (1-C) * f * sinα *
256
+ (σ + C*sinσ*(cos2σM+C*cosσ*(-1+2*cos2σM*cos2σM)));
257
+ var λ2 = (λ1+L+3*Math.PI)%(2*Math.PI) - Math.PI; // normalise to -180...+180
258
+
259
+ var revAz = Math.atan2(sinα, -x);
260
+
261
+ return {lat: φ2.toDegrees(),
262
+ lng: λ2.toDegrees(),
263
+ finalBearing: revAz.toDegrees()
264
+ };
265
+ },
266
+
267
+ /**
268
+ * Vincenty inverse calculation.
269
+ * based on the work of Chris Veness (https://github.com/chrisveness/geodesy)
270
+ *
271
+ * @private
272
+ * @param {LatLng} p1 - Latitude/longitude of start point.
273
+ * @param {LatLng} p2 - Latitude/longitude of destination point.
274
+ * @returns {Object} Object including distance, initialBearing, finalBearing.
275
+ * @throws {Error} If formula failed to converge.
276
+ */
277
+ _vincenty_inverse: function (p1, p2) {
278
+ var φ1 = p1.lat.toRadians(), λ1 = p1.lng.toRadians();
279
+ var φ2 = p2.lat.toRadians(), λ2 = p2.lng.toRadians();
280
+
281
+ var a = this.datum.ellipsoid.a, b = this.datum.ellipsoid.b, f = this.datum.ellipsoid.f;
282
+
283
+ var L = λ2 - λ1;
284
+ var tanU1 = (1-f) * Math.tan(φ1), cosU1 = 1 / Math.sqrt((1 + tanU1*tanU1)), sinU1 = tanU1 * cosU1;
285
+ var tanU2 = (1-f) * Math.tan(φ2), cosU2 = 1 / Math.sqrt((1 + tanU2*tanU2)), sinU2 = tanU2 * cosU2;
286
+
287
+ var λ = L, λʹ, iterations = 0;
288
+ do {
289
+ var sinλ = Math.sin(λ), cosλ = Math.cos(λ);
290
+ var sinSqσ = (cosU2*sinλ) * (cosU2*sinλ) + (cosU1*sinU2-sinU1*cosU2*cosλ) * (cosU1*sinU2-sinU1*cosU2*cosλ);
291
+ var sinσ = Math.sqrt(sinSqσ);
292
+ if (sinσ==0) return 0; // co-incident points
293
+ var cosσ = sinU1*sinU2 + cosU1*cosU2*cosλ;
294
+ var σ = Math.atan2(sinσ, cosσ);
295
+ var sinα = cosU1 * cosU2 * sinλ / sinσ;
296
+ var cosSqα = 1 - sinα*sinα;
297
+ var cos2σM = cosσ - 2*sinU1*sinU2/cosSqα;
298
+ if (isNaN(cos2σM)) cos2σM = 0; // equatorial line: cosSqα=0 (§6)
299
+ var C = f/16*cosSqα*(4+f*(4-3*cosSqα));
300
+ λʹ = λ;
301
+ λ = L + (1-C) * f * sinα * (σ + C*sinσ*(cos2σM+C*cosσ*(-1+2*cos2σM*cos2σM)));
302
+ } while (Math.abs(λ-λʹ) > 1e-12 && ++iterations<100);
303
+ if (iterations>=100) {
304
+ console.log('Formula failed to converge. Altering target position.')
305
+ return this._vincenty_inverse(p1, {lat: p2.lat, lng:p2.lng-0.01})
306
+ // throw new Error('Formula failed to converge');
307
+ }
308
+
309
+ var uSq = cosSqα * (a*a - b*b) / (b*b);
310
+ var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));
311
+ var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)));
312
+ var Δσ = B*sinσ*(cos2σM+B/4*(cosσ*(-1+2*cos2σM*cos2σM)-
313
+ B/6*cos2σM*(-3+4*sinσ*sinσ)*(-3+4*cos2σM*cos2σM)));
314
+
315
+ var s = b*A*(σ-Δσ);
316
+
317
+ var fwdAz = Math.atan2(cosU2*sinλ, cosU1*sinU2-sinU1*cosU2*cosλ);
318
+ var revAz = Math.atan2(cosU1*sinλ, -sinU1*cosU2+cosU1*sinU2*cosλ);
319
+
320
+ s = Number(s.toFixed(3)); // round to 1mm precision
321
+ return { distance: s, initialBearing: fwdAz.toDegrees(), finalBearing: revAz.toDegrees() };
322
+ },
323
+
324
+
325
+ /**
326
+ * Returns the point of intersection of two paths defined by point and bearing.
327
+ * based on the work of Chris Veness (https://github.com/chrisveness/geodesy)
328
+ *
329
+ * @param {LatLon} p1 - First point.
330
+ * @param {number} brng1 - Initial bearing from first point.
331
+ * @param {LatLon} p2 - Second point.
332
+ * @param {number} brng2 - Initial bearing from second point.
333
+ * @returns {Object} containing lat/lng information of intersection.
334
+ *
335
+ * @example
336
+ * var p1 = LatLon(51.8853, 0.2545), brng1 = 108.55;
337
+ * var p2 = LatLon(49.0034, 2.5735), brng2 = 32.44;
338
+ * var pInt = LatLon.intersection(p1, brng1, p2, brng2); // pInt.toString(): 50.9078°N, 4.5084°E
339
+ */
340
+ _intersection : function(p1, brng1, p2, brng2) {
341
+ // see http://williams.best.vwh.net/avform.htm#Intersection
342
+
343
+ var φ1 = p1.lat.toRadians(), λ1 = p1.lng.toRadians();
344
+ var φ2 = p2.lat.toRadians(), λ2 = p2.lng.toRadians();
345
+ var θ13 = Number(brng1).toRadians(), θ23 = Number(brng2).toRadians();
346
+ var Δφ = φ2-φ1, Δλ = λ2-λ1;
347
+
348
+ var δ12 = 2*Math.asin( Math.sqrt( Math.sin(Δφ/2)*Math.sin(Δφ/2) +
349
+ Math.cos(φ1)*Math.cos(φ2)*Math.sin(Δλ/2)*Math.sin(Δλ/2) ) );
350
+ if (δ12 == 0) return null;
351
+
352
+ // initial/final bearings between points
353
+ var θ1 = Math.acos( ( Math.sin(φ2) - Math.sin(φ1)*Math.cos(δ12) ) /
354
+ ( Math.sin(δ12)*Math.cos(φ1) ) );
355
+ if (isNaN(θ1)) θ1 = 0; // protect against rounding
356
+ var θ2 = Math.acos( ( Math.sin(φ1) - Math.sin(φ2)*Math.cos(δ12) ) /
357
+ ( Math.sin(δ12)*Math.cos(φ2) ) );
358
+
359
+ if (Math.sin(λ2-λ1) > 0) {
360
+ var θ12 = θ1;
361
+ var θ21 = 2*Math.PI - θ2;
362
+ } else {
363
+ var θ12 = 2*Math.PI - θ1;
364
+ var θ21 = θ2;
365
+ }
366
+
367
+ var α1 = (θ13 - θ12 + Math.PI) % (2*Math.PI) - Math.PI; // angle 2-1-3
368
+ var α2 = (θ21 - θ23 + Math.PI) % (2*Math.PI) - Math.PI; // angle 1-2-3
369
+
370
+ if (Math.sin(α1)==0 && Math.sin(α2)==0) return null; // infinite intersections
371
+ if (Math.sin(α1)*Math.sin(α2) < 0) return null; // ambiguous intersection
372
+
373
+ //α1 = Math.abs(α1);
374
+ //α2 = Math.abs(α2);
375
+ // ... Ed Williams takes abs of α1/α2, but seems to break calculation?
376
+
377
+ var α3 = Math.acos( -Math.cos(α1)*Math.cos(α2) +
378
+ Math.sin(α1)*Math.sin(α2)*Math.cos(δ12) );
379
+ var δ13 = Math.atan2( Math.sin(δ12)*Math.sin(α1)*Math.sin(α2),
380
+ Math.cos(α2)+Math.cos(α1)*Math.cos(α3) )
381
+ var φ3 = Math.asin( Math.sin(φ1)*Math.cos(δ13) +
382
+ Math.cos(φ1)*Math.sin(δ13)*Math.cos(θ13) );
383
+ var Δλ13 = Math.atan2( Math.sin(θ13)*Math.sin(δ13)*Math.cos(φ1),
384
+ Math.cos(δ13)-Math.sin(φ1)*Math.sin(φ3) );
385
+ var λ3 = λ1 + Δλ13;
386
+ λ3 = (λ3+3*Math.PI) % (2*Math.PI) - Math.PI; // normalise to -180..+180º
387
+
388
+ return {lat: φ3.toDegrees(),
389
+ lng: λ3.toDegrees()
390
+ };
391
+ },
392
+
393
+ /**
394
+ * Overwrites obj1's values with obj2's and adds obj2's if non existent in obj1
395
+ * @param obj1
396
+ * @param obj2
397
+ * @returns obj3 a new object based on obj1 and obj2
398
+ */
399
+ _merge_options: function(obj1,obj2){
400
+ var obj3 = {};
401
+ for (var attrname in obj1) { obj3[attrname] = obj1[attrname]; }
402
+ for (var attrname in obj2) { obj3[attrname] = obj2[attrname]; }
403
+ return obj3;
404
+ }
405
+ });
406
+
407
+ L.geodesic = function(latlngs, options) {
408
+ return new L.Geodesic(latlngs, options);
409
+ };
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: leaflet-geodesic-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.7.0
5
+ platform: ruby
6
+ authors:
7
+ - Volker Wiegand
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-10-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: railties
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '3.1'
27
+ description: Rails engine for the Leaflet.Geodesic code
28
+ email:
29
+ - volker.wiegand@cvw.de
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - LICENSE.txt
35
+ - README.md
36
+ - lib/leaflet/geodesic/rails.rb
37
+ - lib/leaflet/geodesic/rails/version.rb
38
+ - vendor/assets/javascripts/leaflet.geodesic.js
39
+ homepage: https://github.com/volkerwiegand/leaflet-geodesic-rails
40
+ licenses:
41
+ - MIT
42
+ metadata: {}
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubyforge_project:
59
+ rubygems_version: 2.4.2
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: Add-on to draw geodesic lines with Leaflet.
63
+ test_files: []