PageSourceSearch

https://www.apostaseis.gr/loc_ap/scripts/arc.js

js apostaseis.gr collected 2026-09-24 10:01:48 UTC 9,407 bytes, 261 lines download raw bytes

1'use strict';
2
3var D2R = Math.PI / 180;
4var R2D = 180 / Math.PI;
5
6var Coord = function(lon,lat) {
7    this.lon = lon;
8    this.lat = lat;
9    this.x = D2R * lon;
10    this.y = D2R * lat;
11};
12
13Coord.prototype.view = function() {
14    return String(this.lon).slice(0, 4) + ',' + String(this.lat).slice(0, 4);
15};
16
17Coord.prototype.antipode = function() {
18    var anti_lat = -1 * this.lat;
19    var anti_lon = (this.lon < 0) ? 180 + this.lon : (180 - this.lon) * -1;
20    return new Coord(anti_lon, anti_lat);
21};
22
23var LineString = function() {
24    this.coords = [];
25    this.length = 0;
26};
27
28LineString.prototype.move_to = function(coord) {
29    this.length++;
30    this.coords.push(coord);
31};
32
33var Arc = function(properties) {
34    this.properties = properties || {};
35    this.geometries = [];
36};
37
38Arc.prototype.json = function() {
39    if (this.geometries.length <= 0) {
40        return {'geometry': { 'type': 'LineString', 'coordinates': null },
41                'type': 'Feature', 'properties': this.properties
42               };
43    } else if (this.geometries.length == 1) {
44        return {'geometry': { 'type': 'LineString', 'coordinates': this.geometries[0].coords },
45                'type': 'Feature', 'properties': this.properties
46               };
47    } else {
48        var multiline = [];
49        for (var i = 0; i < this.geometries.length; i++) {
50            multiline.push(this.geometries[i].coords);
51        }
52        return {'geometry': { 'type': 'MultiLineString', 'coordinates': multiline },
53                'type': 'Feature', 'properties': this.properties
54               };
55    }
56};
57
58// TODO - output proper multilinestring
59Arc.prototype.wkt = function() {
60    var wkt_string = '';
61    var wkt = 'LINESTRING(';
62    var collect = function(c) { wkt += c[0] + ' ' + c[1] + ','; };
63    for (var i = 0; i < this.geometries.length; i++) {
64        if (this.geometries[i].coords.length === 0) {
65            return 'LINESTRING(empty)';
66        } else {
67            var coords = this.geometries[i].coords;
68            coords.forEach(collect);
69            wkt_string += wkt.substring(0, wkt.length - 1) + ')';
70        }
71    }
72    return wkt_string;
73};
74
75/*
76 * http://en.wikipedia.org/wiki/Great-circle_distance
77 *
78 */
79var GreatCircle = function(start,end,properties) {
80    if (!start || start.x === undefined || start.y === undefined) {
81        throw new Error("GreatCircle constructor expects two args: start and end objects with x and y properties");
82    }
83    if (!end || end.x === undefined || end.y === undefined) {
84        throw new Error("GreatCircle constructor expects two args: start and end objects with x and y properties");
85    }
86    this.start = new Coord(start.x,start.y);
87    this.end = new Coord(end.x,end.y);
88    this.properties = properties || {};
89
90    var w = this.start.x - this.end.x;
91    var h = this.start.y - this.end.y;
92    var z = Math.pow(Math.sin(h / 2.0), 2) +
93                Math.cos(this.start.y) *
94                   Math.cos(this.end.y) *
95                     Math.pow(Math.sin(w / 2.0), 2);
96    this.g = 2.0 * Math.asin(Math.sqrt(z));
97
98    if (this.g == Math.PI) {
99        throw new Error('it appears ' + start.view() + ' and ' + end.view() + " are 'antipodal', e.g diametrically opposite, thus there is no single route but rather infinite");
100    } else if (isNaN(this.g)) {
101        throw new Error('could not calculate great circle between ' + start + ' and ' + end);
102    }
103};
104
105/*
106 * http://williams.best.vwh.net/avform.htm#Intermediate
107 */
108GreatCircle.prototype.interpolate = function(f) {
109    var A = Math.sin((1 - f) * this.g) / Math.sin(this.g);
110    var B = Math.sin(f * this.g) / Math.sin(this.g);
111    var x = A * Math.cos(this.start.y) * Math.cos(this.start.x) + B * Math.cos(this.end.y) * Math.cos(this.end.x);
112    var y = A * Math.cos(this.start.y) * Math.sin(this.start.x) + B * Math.cos(this.end.y) * Math.sin(this.end.x);
113    var z = A * Math.sin(this.start.y) + B * Math.sin(this.end.y);
114    var lat = R2D * Math.atan2(z, Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)));
115    var lon = R2D * Math.atan2(y, x);
116    return [lon, lat];
117};
118
119
120
121/*
122 * Generate points along the great circle
123 */
124GreatCircle.prototype.Arc = function(npoints,options) {
125    var first_pass = [];
126    if (!npoints || npoints <= 2) {
127        first_pass.push([this.start.lon, this.start.lat]);
128        first_pass.push([this.end.lon, this.end.lat]);
129    } else {
130        var delta = 1.0 / (npoints - 1);
131        for (var i = 0; i < npoints; ++i) {
132            var step = delta * i;
133            var pair = this.interpolate(step);
134            first_pass.push(pair);
135        }
136    }
137    /* partial port of dateline handling from:
138      gdal/ogr/ogrgeometryfactory.cpp
139
140      TODO - does not handle all wrapping scenarios yet
141    */
142    var bHasBigDiff = false;
143    var dfMaxSmallDiffLong = 0;
144    // from http://www.gdal.org/ogr2ogr.html
145    // -datelineoffset:
146    // (starting with GDAL 1.10) offset from dateline in degrees (default long. = +/- 10deg, geometries within 170deg to -170deg will be splited)
147    var dfDateLineOffset = options && options.offset ? options.offset : 10;
148    var dfLeftBorderX = 180 - dfDateLineOffset;
149    var dfRightBorderX = -180 + dfDateLineOffset;
150    var dfDiffSpace = 360 - dfDateLineOffset;
151
152    // https://github.com/OSGeo/gdal/blob/7bfb9c452a59aac958bff0c8386b891edf8154ca/gdal/ogr/ogrgeometryfactory.cpp#L2342
153    for (var j = 1; j < first_pass.length; ++j) {
154        var dfPrevX = first_pass[j-1][0];
155        var dfX = first_pass[j][0];
156        var dfDiffLong = Math.abs(dfX - dfPrevX);
157        if (dfDiffLong > dfDiffSpace &&
158            ((dfX > dfLeftBorderX && dfPrevX < dfRightBorderX) || (dfPrevX > dfLeftBorderX && dfX < dfRightBorderX))) {
159            bHasBigDiff = true;
160        } else if (dfDiffLong > dfMaxSmallDiffLong) {
161            dfMaxSmallDiffLong = dfDiffLong;
162        }
163    }
164
165    var poMulti = [];
166    if (bHasBigDiff && dfMaxSmallDiffLong < dfDateLineOffset) {
167        var poNewLS = [];
168        poMulti.push(poNewLS);
169        for (var k = 0; k < first_pass.length; ++k) {
170            var dfX0 = parseFloat(first_pass[k][0]);
171            if (k > 0 &&  Math.abs(dfX0 - first_pass[k-1][0]) > dfDiffSpace) {
172                var dfX1 = parseFloat(first_pass[k-1][0]);
173                var dfY1 = parseFloat(first_pass[k-1][1]);
174                var dfX2 = parseFloat(first_pass[k][0]);
175                var dfY2 = parseFloat(first_pass[k][1]);
176                if (dfX1 > -180 && dfX1 < dfRightBorderX && dfX2 == 180 &&
177                    k+1 < first_pass.length &&
178                   first_pass[k-1][0] > -180 && first_pass[k-1][0] < dfRightBorderX)
179                {
180                     poNewLS.push([-180, first_pass[k][1]]);
181                     k++;
182                     poNewLS.push([first_pass[k][0], first_pass[k][1]]);
183                     continue;
184                } else if (dfX1 > dfLeftBorderX && dfX1 < 180 && dfX2 == -180 &&
185                     k+1 < first_pass.length &&
186                     first_pass[k-1][0] > dfLeftBorderX && first_pass[k-1][0] < 180)
187                {
188                     poNewLS.push([180, first_pass[k][1]]);
189                     k++;
190                     poNewLS.push([first_pass[k][0], first_pass[k][1]]);
191                     continue;
192                }
193
194                if (dfX1 < dfRightBorderX && dfX2 > dfLeftBorderX)
195                {
196                    // swap dfX1, dfX2
197                    var tmpX = dfX1;
198                    dfX1 = dfX2;
199                    dfX2 = tmpX;
200                    // swap dfY1, dfY2
201                    var tmpY = dfY1;
202                    dfY1 = dfY2;
203                    dfY2 = tmpY;
204                }
205                if (dfX1 > dfLeftBorderX && dfX2 < dfRightBorderX) {
206                    dfX2 += 360;
207                }
208
209                if (dfX1 <= 180 && dfX2 >= 180 && dfX1 < dfX2)
210                {
211                    var dfRatio = (180 - dfX1) / (dfX2 - dfX1);
212                    var dfY = dfRatio * dfY2 + (1 - dfRatio) * dfY1;
213                    poNewLS.push([first_pass[k-1][0] > dfLeftBorderX ? 180 : -180, dfY]);
214                    poNewLS = [];
215                    poNewLS.push([first_pass[k-1][0] > dfLeftBorderX ? -180 : 180, dfY]);
216                    poMulti.push(poNewLS);
217                }
218                else
219                {
220                    poNewLS = [];
221                    poMulti.push(poNewLS);
222                }
223                poNewLS.push([dfX0, first_pass[k][1]]);
224            } else {
225                poNewLS.push([first_pass[k][0], first_pass[k][1]]);
226            }
227        }
228    } else {
229        // add normally
230        var poNewLS0 = [];
231        poMulti.push(poNewLS0);
232        for (var l = 0; l < first_pass.length; ++l) {
233            poNewLS0.push([first_pass[l][0],first_pass[l][1]]);
234        }
235    }
236
237    var arc = new Arc(this.properties);
238    for (var m = 0; m < poMulti.length; ++m) {
239        var line = new LineString();
240        arc.geometries.push(line);
241        var points = poMulti[m];
242        for (var j0 = 0; j0 < points.length; ++j0) {
243            line.move_to(points[j0]);
244        }
245    }
246    return arc;
247};
248
249if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
250  // nodejs
251  module.exports.Coord = Coord;
252  module.exports.Arc = Arc;
253  module.exports.GreatCircle = GreatCircle;
254
255} else {
256  // browser
257  var arc = {};
258  arc.Coord = Coord;
259  arc.Arc = Arc;
260  arc.GreatCircle = GreatCircle;
261}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.