1
|
/*
|
2
|
proj4js.js -- Javascript reprojection library.
|
3
|
|
4
|
Author: Mike Adair madairATdmsolutions.ca
|
5
|
Richard Greenwood rich@greenwoodmap.com
|
6
|
License: LGPL as per: http://www.gnu.org/copyleft/lesser.html
|
7
|
Note: This program is an almost direct port of the C library
|
8
|
Proj4.
|
9
|
*/
|
10
|
/* ======================================================================
|
11
|
proj4js.js
|
12
|
====================================================================== */
|
13
|
|
14
|
/*
|
15
|
Author: Mike Adair madairATdmsolutions.ca
|
16
|
Richard Greenwood rich@greenwoodmap.com
|
17
|
License: LGPL as per: http://www.gnu.org/copyleft/lesser.html
|
18
|
Note: This program is an almost direct port of the C library Proj4.
|
19
|
$Id: Proj.js 2956 2007-07-09 12:17:52Z steven $
|
20
|
*/
|
21
|
|
22
|
/**
|
23
|
* Provides methods for coordinate transformations between map projections and
|
24
|
* longitude/latitude, including datum transformations.
|
25
|
*
|
26
|
* Initialization of Proj objects is with a projection code, usually EPSG codes.
|
27
|
* The code passed in will be stripped of colons (':') and converted to uppercase
|
28
|
* for internal use.
|
29
|
* If you know what map projections your application will be dealing with, the
|
30
|
* definition for the projections can be included with the script tag when the
|
31
|
* application is being coded. Otherwise, practically any projection definition
|
32
|
* can be loaded dynamically at run-time with an AJAX request to a lookup service
|
33
|
* such as spatialreference.org.
|
34
|
* The actual code supporting the forward and inverse tansformations for each
|
35
|
* projection class is loaded dynamically at run-time. These may also be
|
36
|
* specified when the application is coded if the projections to be used are known
|
37
|
* beforehand.
|
38
|
* A projection object has properties for units and title strings.
|
39
|
* All coordinates are handled as points which is a 2 element array where x is
|
40
|
* the first element and y is the second.
|
41
|
* For the transform() method pass in mapXY and a destination projection object
|
42
|
* and it returns a map XY coordinate in the other projection
|
43
|
*/
|
44
|
|
45
|
/**
|
46
|
* Global namespace object for Proj4js library to use
|
47
|
*/
|
48
|
Proj4js = {
|
49
|
|
50
|
/**
|
51
|
* Property: defaultDatum
|
52
|
* The datum to use when no others a specified
|
53
|
*/
|
54
|
defaultDatum: 'WGS84', //default datum
|
55
|
|
56
|
/**
|
57
|
* Property: proxyScript
|
58
|
* A proxy script to execute AJAX requests in other domains.
|
59
|
*/
|
60
|
proxyScript: null, //TBD: customize this for spatialreference.org output
|
61
|
|
62
|
/**
|
63
|
* Property: defsLookupService
|
64
|
* AJAX service to retreive projection definition parameters from
|
65
|
*/
|
66
|
defsLookupService: 'http://spatialreference.org/ref',
|
67
|
|
68
|
/**
|
69
|
* Property: libPath
|
70
|
* internal: http server path to library code.
|
71
|
* TBD figure this out automatically
|
72
|
*/
|
73
|
libPath: '../lib/',
|
74
|
|
75
|
/**
|
76
|
* Method: transform(source, dest, point)
|
77
|
* Transform a point coordinate from one map projection to another.
|
78
|
*
|
79
|
* Parameters:
|
80
|
* source - {Proj4js.Proj} source map projection for the transformation
|
81
|
* dest - {Proj4js.Proj} destination map projection for the transformation
|
82
|
* point - {Object} point to transform, may be geodetic (long, lat) or
|
83
|
* projected Cartesian (x,y), but should always have x,y properties.
|
84
|
*/
|
85
|
transform : function(source, dest, point) {
|
86
|
if (!source.readyToUse || !dest.readyToUse) {
|
87
|
this.reportError("Proj4js initialization for "+source.srsCode+" not yet complete");
|
88
|
return;
|
89
|
}
|
90
|
|
91
|
if (point.transformed) {
|
92
|
this.log("point already transformed");
|
93
|
return;
|
94
|
}
|
95
|
|
96
|
// Workaround for Spherical Mercator
|
97
|
if ((source.srsProjNumber =="900913" && dest.datumCode != "WGS84") ||
|
98
|
(dest.srsProjNumber == "900913" && source.datumCode != "WGS84")) {
|
99
|
var wgs84 = Proj4js.WGS84;
|
100
|
this.transform(source, wgs84, point);
|
101
|
point.transformed = false;
|
102
|
source = wgs84;
|
103
|
}
|
104
|
|
105
|
// Transform source points to long/lat, if they aren't already.
|
106
|
if ( source.projName=="longlat") {
|
107
|
point.x *= Proj4js.common.D2R; // convert degrees to radians
|
108
|
point.y *= Proj4js.common.D2R;
|
109
|
} else {
|
110
|
if (source.to_meter) {
|
111
|
point.x *= source.to_meter;
|
112
|
point.y *= source.to_meter;
|
113
|
}
|
114
|
source.inverse(point); // Convert Cartesian to longlat
|
115
|
}
|
116
|
|
117
|
// Adjust for the prime meridian if necessary
|
118
|
if (source.from_greenwich) {
|
119
|
point.x += source.from_greenwich;
|
120
|
}
|
121
|
|
122
|
// Convert datums if needed, and if possible.
|
123
|
point = this.datum_transform( source.datum, dest.datum, point );
|
124
|
|
125
|
// Adjust for the prime meridian if necessary
|
126
|
if (dest.from_greenwich) {
|
127
|
point.x -= dest.from_greenwich;
|
128
|
}
|
129
|
|
130
|
if( dest.projName=="longlat" ) {
|
131
|
// convert radians to decimal degrees
|
132
|
point.x *= Proj4js.common.R2D;
|
133
|
point.y *= Proj4js.common.R2D;
|
134
|
} else { // else project
|
135
|
dest.forward(point);
|
136
|
if (dest.to_meter) {
|
137
|
point.x /= dest.to_meter;
|
138
|
point.y /= dest.to_meter;
|
139
|
}
|
140
|
}
|
141
|
point.transformed = true;
|
142
|
return point;
|
143
|
}, // transform()
|
144
|
|
145
|
/** datum_transform()
|
146
|
source coordinate system definition,
|
147
|
destination coordinate system definition,
|
148
|
point to transform in geodetic coordinates (long, lat, height)
|
149
|
*/
|
150
|
datum_transform : function( source, dest, point ) {
|
151
|
|
152
|
// Short cut if the datums are identical.
|
153
|
if( source.compare_datums( dest ) ) {
|
154
|
return point; // in this case, zero is sucess,
|
155
|
// whereas cs_compare_datums returns 1 to indicate TRUE
|
156
|
// confusing, should fix this
|
157
|
}
|
158
|
|
159
|
// Explicitly skip datum transform by setting 'datum=none' as parameter for either source or dest
|
160
|
if( source.datum_type == Proj4js.common.PJD_NODATUM
|
161
|
|| dest.datum_type == Proj4js.common.PJD_NODATUM) {
|
162
|
return point;
|
163
|
}
|
164
|
|
165
|
// If this datum requires grid shifts, then apply it to geodetic coordinates.
|
166
|
if( source.datum_type == Proj4js.common.PJD_GRIDSHIFT )
|
167
|
{
|
168
|
alert("ERROR: Grid shift transformations are not implemented yet.");
|
169
|
/*
|
170
|
pj_apply_gridshift( pj_param(source.params,"snadgrids").s, 0,
|
171
|
point_count, point_offset, x, y, z );
|
172
|
CHECK_RETURN;
|
173
|
|
174
|
src_a = SRS_WGS84_SEMIMAJOR;
|
175
|
src_es = 0.006694379990;
|
176
|
*/
|
177
|
}
|
178
|
|
179
|
if( dest.datum_type == Proj4js.common.PJD_GRIDSHIFT )
|
180
|
{
|
181
|
alert("ERROR: Grid shift transformations are not implemented yet.");
|
182
|
/*
|
183
|
dst_a = ;
|
184
|
dst_es = 0.006694379990;
|
185
|
*/
|
186
|
}
|
187
|
|
188
|
// Do we need to go through geocentric coordinates?
|
189
|
if( source.es != dest.es || source.a != dest.a
|
190
|
|| source.datum_type == Proj4js.common.PJD_3PARAM
|
191
|
|| source.datum_type == Proj4js.common.PJD_7PARAM
|
192
|
|| dest.datum_type == Proj4js.common.PJD_3PARAM
|
193
|
|| dest.datum_type == Proj4js.common.PJD_7PARAM)
|
194
|
{
|
195
|
|
196
|
// Convert to geocentric coordinates.
|
197
|
source.geodetic_to_geocentric( point );
|
198
|
// CHECK_RETURN;
|
199
|
|
200
|
// Convert between datums
|
201
|
if( source.datum_type == Proj4js.common.PJD_3PARAM || source.datum_type == Proj4js.common.PJD_7PARAM ) {
|
202
|
source.geocentric_to_wgs84(point);
|
203
|
// CHECK_RETURN;
|
204
|
}
|
205
|
|
206
|
if( dest.datum_type == Proj4js.common.PJD_3PARAM || dest.datum_type == Proj4js.common.PJD_7PARAM ) {
|
207
|
dest.geocentric_from_wgs84(point);
|
208
|
// CHECK_RETURN;
|
209
|
}
|
210
|
|
211
|
// Convert back to geodetic coordinates
|
212
|
dest.geocentric_to_geodetic( point );
|
213
|
// CHECK_RETURN;
|
214
|
}
|
215
|
|
216
|
// Apply grid shift to destination if required
|
217
|
if( dest.datum_type == Proj4js.common.PJD_GRIDSHIFT )
|
218
|
{
|
219
|
alert("ERROR: Grid shift transformations are not implemented yet.");
|
220
|
// pj_apply_gridshift( pj_param(dest.params,"snadgrids").s, 1, point);
|
221
|
// CHECK_RETURN;
|
222
|
}
|
223
|
return point;
|
224
|
}, // cs_datum_transform
|
225
|
|
226
|
/**
|
227
|
* Function: reportError
|
228
|
* An internal method to report errors back to user. Should be overridden
|
229
|
* by applications to deliver error messages.
|
230
|
*/
|
231
|
reportError: function(msg) {
|
232
|
},
|
233
|
|
234
|
/**
|
235
|
* Function: log
|
236
|
* An internal method to log events.
|
237
|
*/
|
238
|
log: function(msg) {
|
239
|
},
|
240
|
|
241
|
loadProjDefinition : function(proj) {
|
242
|
|
243
|
//check in memory
|
244
|
if (this.defs[proj.srsCode]) return this.defs[proj.srsCode];
|
245
|
|
246
|
//set AJAX options
|
247
|
var options = {
|
248
|
method: 'get',
|
249
|
asynchronous: false, //need to wait until defs are loaded before proceeding
|
250
|
onSuccess: this.defsLoadedFromDisk.bind(this,proj.srsCode)
|
251
|
}
|
252
|
|
253
|
//else check for def on the server
|
254
|
var url = this.libPath + 'defs/' + proj.srsAuth.toUpperCase() + proj.srsProjNumber + '.js';
|
255
|
new OpenLayers.Ajax.Request(url, options);
|
256
|
if ( this.defs[proj.srsCode] ) return this.defs[proj.srsCode];
|
257
|
|
258
|
//else load from web service via AJAX request
|
259
|
if (this.proxyScript) {
|
260
|
var url = this.proxyScript + this.defsLookupService +'/' + proj.srsAuth +'/'+ proj.srsProjNumber + '/proj4';
|
261
|
options.onSuccess = this.defsLoadedFromService.bind(this,proj.srsCode)
|
262
|
options.onFailure = this.defsFailed.bind(this,proj.srsCode);
|
263
|
new OpenLayers.Ajax.Request(url, options);
|
264
|
}
|
265
|
|
266
|
//may return null here if the defs are not found
|
267
|
return this.defs[proj.srsCode];
|
268
|
},
|
269
|
|
270
|
defsLoadedFromDisk: function(srsCode, transport) {
|
271
|
eval(transport.responseText);
|
272
|
},
|
273
|
|
274
|
defsLoadedFromService: function(srsCode, transport) {
|
275
|
this.defs[srsCode] = transport.responseText;
|
276
|
// save this also in the prototype, so we don't need to fetch it again
|
277
|
Proj4js.defs[srsCode] = transport.responseText;
|
278
|
},
|
279
|
|
280
|
defsFailed: function(srsCode) {
|
281
|
this.reportError('failed to load projection definition for: '+srsCode);
|
282
|
OpenLayers.Util.extend(this.defs[srsCode], this.defs['WGS84']); //set it to something so it can at least continue
|
283
|
},
|
284
|
|
285
|
loadProjCode : function(projName) {
|
286
|
if (this.Proj[projName]) return;
|
287
|
|
288
|
//set AJAX options
|
289
|
var options = {
|
290
|
method: 'get',
|
291
|
asynchronous: false, //need to wait until defs are loaded before proceeding
|
292
|
onSuccess: this.loadProjCodeSuccess.bind(this, projName),
|
293
|
onFailure: this.loadProjCodeFailure.bind(this, projName)
|
294
|
};
|
295
|
|
296
|
//load the projection class
|
297
|
var url = this.libPath + 'projCode/' + projName + '.js';
|
298
|
new OpenLayers.Ajax.Request(url, options);
|
299
|
},
|
300
|
|
301
|
loadProjCodeSuccess : function(projName, transport) {
|
302
|
eval(transport.responseText);
|
303
|
if (this.Proj[projName].dependsOn){
|
304
|
this.loadProjCode(this.Proj[projName].dependsOn);
|
305
|
}
|
306
|
},
|
307
|
|
308
|
loadProjCodeFailure : function(projName) {
|
309
|
Proj4js.reportError("failed to find projection file for: " + projName);
|
310
|
//TBD initialize with identity transforms so proj will still work
|
311
|
}
|
312
|
|
313
|
};
|
314
|
|
315
|
/**
|
316
|
* Class: Proj4js.Proj
|
317
|
* Projection objects provide coordinate transformation methods for point coordinates
|
318
|
* once they have been initialized with a projection code.
|
319
|
*/
|
320
|
Proj4js.Proj = OpenLayers.Class({
|
321
|
|
322
|
/**
|
323
|
* Property: readyToUse
|
324
|
* Flag to indicate if initialization is complete for this Proj object
|
325
|
*/
|
326
|
readyToUse : false,
|
327
|
|
328
|
/**
|
329
|
* Property: title
|
330
|
* The title to describe the projection
|
331
|
*/
|
332
|
title: null,
|
333
|
|
334
|
/**
|
335
|
* Property: projName
|
336
|
* The projection class for this projection, e.g. lcc (lambert conformal conic,
|
337
|
* or merc for mercator. These are exactly equicvalent to their Proj4
|
338
|
* counterparts.
|
339
|
*/
|
340
|
projName: null,
|
341
|
/**
|
342
|
* Property: units
|
343
|
* The units of the projection. Values include 'm' and 'degrees'
|
344
|
*/
|
345
|
units: null,
|
346
|
/**
|
347
|
* Property: datum
|
348
|
* The datum specified for the projection
|
349
|
*/
|
350
|
datum: null,
|
351
|
|
352
|
/**
|
353
|
* Constructor: initialize
|
354
|
* Constructor for Proj4js.Proj objects
|
355
|
*
|
356
|
* Parameters:
|
357
|
* srsCode - a code for map projection definition parameters. These are usually
|
358
|
* (but not always) EPSG codes.
|
359
|
*/
|
360
|
initialize : function(srsCode) {
|
361
|
this.srsCode = srsCode.toUpperCase();
|
362
|
if (this.srsCode.indexOf("EPSG") == 0) {
|
363
|
this.srsCode = this.srsCode;
|
364
|
this.srsAuth = 'epsg';
|
365
|
this.srsProjNumber = this.srsCode.substring(5);
|
366
|
} else {
|
367
|
this.srsAuth = '';
|
368
|
this.srsProjNumber = this.srsCode;
|
369
|
}
|
370
|
|
371
|
var defs = Proj4js.loadProjDefinition(this);
|
372
|
if (defs) {
|
373
|
this.parseDefs(defs);
|
374
|
Proj4js.loadProjCode(this.projName);
|
375
|
this.callInit();
|
376
|
}
|
377
|
|
378
|
},
|
379
|
|
380
|
callInit : function() {
|
381
|
Proj4js.log('projection script loaded for:' + this.projName);
|
382
|
OpenLayers.Util.extend(this, Proj4js.Proj[this.projName]);
|
383
|
this.init();
|
384
|
this.mapXYToLonLat = this.inverse;
|
385
|
this.lonLatToMapXY = this.forward;
|
386
|
this.readyToUse = true;
|
387
|
},
|
388
|
|
389
|
parseDefs : function(proj4opts) {
|
390
|
this.defData = proj4opts;
|
391
|
var paramName, paramVal;
|
392
|
var paramArray=this.defData.split("+");
|
393
|
|
394
|
for (var prop=0; prop<paramArray.length; prop++) {
|
395
|
var property = paramArray[prop].split("=");
|
396
|
paramName = property[0].toLowerCase();
|
397
|
paramVal = property[1];
|
398
|
|
399
|
switch (paramName.replace(/\s/gi,"")) { // trim out spaces
|
400
|
case "": break; // throw away nameless parameter
|
401
|
case "title": this.title = paramVal; break;
|
402
|
case "proj": this.projName = paramVal.replace(/\s/gi,""); break;
|
403
|
case "units": this.units = paramVal.replace(/\s/gi,""); break;
|
404
|
case "datum": this.datumCode = paramVal.replace(/\s/gi,""); break;
|
405
|
case "nadgrids": this.nagrids = paramVal.replace(/\s/gi,""); break;
|
406
|
case "ellps": this.ellps = paramVal.replace(/\s/gi,""); break;
|
407
|
case "a": this.a = parseFloat(paramVal); break; // semi-major radius
|
408
|
case "b": this.b = parseFloat(paramVal); break; // semi-minor radius
|
409
|
case "lat_0": this.lat0 = paramVal*Proj4js.common.D2R; break; // phi0, central latitude
|
410
|
case "lat_1": this.lat1 = paramVal*Proj4js.common.D2R; break; //standard parallel 1
|
411
|
case "lat_2": this.lat2 = paramVal*Proj4js.common.D2R; break; //standard parallel 2
|
412
|
case "lat_ts": this.lat_ts = paramVal*Proj4js.common.D2R; break; //used in merc
|
413
|
case "lon_0": this.long0 = paramVal*Proj4js.common.D2R; break; // lam0, central longitude
|
414
|
case "x_0": this.x0 = parseFloat(paramVal); break; // false easting
|
415
|
case "y_0": this.y0 = parseFloat(paramVal); break; // false northing
|
416
|
case "k_0": this.k0 = parseFloat(paramVal); break; // projection scale factor
|
417
|
case "k": this.k0 = parseFloat(paramVal); break; // both forms returned
|
418
|
case "R_A": this.R = parseFloat(paramVal); break; //Spheroid radius
|
419
|
case "zone": this.zone = parseInt(paramVal); break; // UTM Zone
|
420
|
case "south": this.utmSouth = true; break; // UTM north/south
|
421
|
case "towgs84":this.datum_params = paramVal.split(","); break;
|
422
|
case "to_meter": this.to_meter = parseFloat(paramVal); break; // cartesian scaling
|
423
|
case "from_greenwich": this.from_greenwich = paramVal*Proj4js.common.D2R; break;
|
424
|
case "pm": paramVal = paramVal.replace(/\s/gi,"");
|
425
|
this.from_greenwich = Proj4js.PrimeMeridian[paramVal] ?
|
426
|
Proj4js.PrimeMeridian[paramVal]*Proj4js.common.D2R : 0.0; break;
|
427
|
case "no_defs": break;
|
428
|
default: Proj4js.log("Unrecognized parameter: " + paramName);
|
429
|
} // switch()
|
430
|
} // for paramArray
|
431
|
this.deriveConstants();
|
432
|
},
|
433
|
|
434
|
deriveConstants : function() {
|
435
|
if (this.nagrids == '@null') this.datumCode = 'none';
|
436
|
if (this.datumCode && this.datumCode != 'none') {
|
437
|
var datumDef = Proj4js.Datum[this.datumCode];
|
438
|
if (datumDef) {
|
439
|
this.datum_params = datumDef.towgs84.split(',');
|
440
|
this.ellps = datumDef.ellipse;
|
441
|
this.datumName = datumDef.datumName;
|
442
|
}
|
443
|
}
|
444
|
if (!this.a) { // do we have an ellipsoid?
|
445
|
var ellipse = Proj4js.Ellipsoid[this.ellps] ? Proj4js.Ellipsoid[this.ellps] : Proj4js.Ellipsoid['WGS84'];
|
446
|
OpenLayers.Util.extend(this, ellipse);
|
447
|
}
|
448
|
if (this.rf && !this.b) this.b = (1.0 - 1.0/this.rf) * this.a;
|
449
|
if (Math.abs(this.a - this.b)<Proj4js.common.EPSLN) this.sphere = true;
|
450
|
this.a2 = this.a * this.a; // used in geocentric
|
451
|
this.b2 = this.b * this.b; // used in geocentric
|
452
|
this.es = (this.a2-this.b2)/this.a2; // e ^ 2
|
453
|
//this.es=1-(Math.pow(this.b,2)/Math.pow(this.a,2));
|
454
|
this.e = Math.sqrt(this.es); // eccentricity
|
455
|
this.ep2=(this.a2-this.b2)/this.b2; // used in geocentric
|
456
|
if (!this.k0) this.k0 = 1.0; //default value
|
457
|
|
458
|
this.datum = new Proj4js.datum(this);
|
459
|
}
|
460
|
});
|
461
|
|
462
|
Proj4js.Proj.longlat = {
|
463
|
init : function() {
|
464
|
//no-op for longlat
|
465
|
},
|
466
|
forward : function(pt) {
|
467
|
//identity transform
|
468
|
return pt;
|
469
|
},
|
470
|
inverse : function(pt) {
|
471
|
//identity transform
|
472
|
return pt;
|
473
|
}
|
474
|
};
|
475
|
|
476
|
/**
|
477
|
Proj4js.defs is a collection of coordinate system definition objects in the
|
478
|
Proj4 command line format.
|
479
|
Generally a def is added by means of a separate .js file for example:
|
480
|
|
481
|
<SCRIPT type="text/javascript" src="defs/EPSG26912.js"></SCRIPT>
|
482
|
|
483
|
def is a CS definition in PROJ.4 WKT format, for example:
|
484
|
+proj="tmerc" //longlat, etc.
|
485
|
+a=majorRadius
|
486
|
+b=minorRadius
|
487
|
+lat0=somenumber
|
488
|
+long=somenumber
|
489
|
*/
|
490
|
Proj4js.defs = {
|
491
|
// These are so widely used, we'll go ahead and throw them in
|
492
|
// without requiring a separate .js file
|
493
|
'WGS84': "+title=long/lat:WGS84 +proj=longlat +ellps=WGS84 +datum=WGS84",
|
494
|
'EPSG:4326': "+title=long/lat:WGS84 +proj=longlat +a=6378137.0 +b=6356752.31424518 +ellps=WGS84 +datum=WGS84",
|
495
|
'EPSG:4269': "+title=long/lat:NAD83 +proj=longlat +a=6378137.0 +b=6356752.31414036 +ellps=GRS80 +datum=NAD83"
|
496
|
};
|
497
|
//+a=6378137.0 +b=6356752.31424518 +ellps=WGS84 +datum=WGS84",
|
498
|
Proj4js.common = {
|
499
|
PI : Math.PI,
|
500
|
HALF_PI : Math.PI*0.5,
|
501
|
TWO_PI : Math.PI*2,
|
502
|
FORTPI : 0.78539816339744833,
|
503
|
R2D : 57.2957795131,
|
504
|
D2R : 0.0174532925199,
|
505
|
SEC_TO_RAD : 4.84813681109535993589914102357e-6, /* SEC_TO_RAD = Pi/180/3600 */
|
506
|
EPSLN : 1.0e-10,
|
507
|
MAX_ITER : 20,
|
508
|
// following constants from geocent.c
|
509
|
COS_67P5 : 0.38268343236508977, /* cosine of 67.5 degrees */
|
510
|
AD_C : 1.0026000, /* Toms region 1 constant */
|
511
|
|
512
|
/* datum_type values */
|
513
|
PJD_UNKNOWN : 0,
|
514
|
PJD_3PARAM : 1,
|
515
|
PJD_7PARAM : 2,
|
516
|
PJD_GRIDSHIFT: 3,
|
517
|
PJD_WGS84 : 4, // WGS84 or equivalent
|
518
|
PJD_NODATUM : 5, // WGS84 or equivalent
|
519
|
SRS_WGS84_SEMIMAJOR : 6378137.0, // only used in grid shift transforms
|
520
|
|
521
|
// Function to compute the constant small m which is the radius of
|
522
|
// a parallel of latitude, phi, divided by the semimajor axis.
|
523
|
// -----------------------------------------------------------------
|
524
|
msfnz : function(eccent, sinphi, cosphi) {
|
525
|
var con = eccent * sinphi;
|
526
|
return cosphi/(Math.sqrt(1.0 - con * con));
|
527
|
},
|
528
|
|
529
|
// Function to compute the constant small t for use in the forward
|
530
|
// computations in the Lambert Conformal Conic and the Polar
|
531
|
// Stereographic projections.
|
532
|
// -----------------------------------------------------------------
|
533
|
tsfnz : function(eccent, phi, sinphi) {
|
534
|
var con = eccent * sinphi;
|
535
|
var com = .5 * eccent;
|
536
|
con = Math.pow(((1.0 - con) / (1.0 + con)), com);
|
537
|
return (Math.tan(.5 * (this.HALF_PI - phi))/con);
|
538
|
},
|
539
|
|
540
|
// Function to compute the latitude angle, phi2, for the inverse of the
|
541
|
// Lambert Conformal Conic and Polar Stereographic projections.
|
542
|
// ----------------------------------------------------------------
|
543
|
phi2z : function(eccent, ts) {
|
544
|
var eccnth = .5 * eccent;
|
545
|
var con, dphi;
|
546
|
var phi = this.HALF_PI - 2 * Math.atan(ts);
|
547
|
for (i = 0; i <= 15; i++) {
|
548
|
con = eccent * Math.sin(phi);
|
549
|
dphi = this.HALF_PI - 2 * Math.atan(ts *(Math.pow(((1.0 - con)/(1.0 + con)),eccnth))) - phi;
|
550
|
phi += dphi;
|
551
|
if (Math.abs(dphi) <= .0000000001) return phi;
|
552
|
}
|
553
|
alert("phi2z has NoConvergence");
|
554
|
return (-9999);
|
555
|
},
|
556
|
|
557
|
/* Function to compute constant small q which is the radius of a
|
558
|
parallel of latitude, phi, divided by the semimajor axis.
|
559
|
------------------------------------------------------------*/
|
560
|
qsfnz : function(eccent,sinphi,cosphi) {
|
561
|
var con;
|
562
|
if (eccent > 1.0e-7) {
|
563
|
con = eccent * sinphi;
|
564
|
return (( 1.0- eccent * eccent) * (sinphi /(1.0 - con * con) - (.5/eccent)*Math.log((1.0 - con)/(1.0 + con))));
|
565
|
} else {
|
566
|
return(2.0 * sinphi);
|
567
|
}
|
568
|
},
|
569
|
|
570
|
/* Function to eliminate roundoff errors in asin
|
571
|
----------------------------------------------*/
|
572
|
asinz : function(x) {
|
573
|
if (Math.abs(x)>1.0) {
|
574
|
x=(x>1.0)?1.0:-1.0;
|
575
|
}
|
576
|
return Math.asin(x);
|
577
|
},
|
578
|
|
579
|
// following functions from gctpc cproj.c for transverse mercator projections
|
580
|
e0fn : function(x) {return(1.0-0.25*x*(1.0+x/16.0*(3.0+1.25*x)));},
|
581
|
e1fn : function(x) {return(0.375*x*(1.0+0.25*x*(1.0+0.46875*x)));},
|
582
|
e2fn : function(x) {return(0.05859375*x*x*(1.0+0.75*x));},
|
583
|
e3fn : function(x) {return(x*x*x*(35.0/3072.0));},
|
584
|
mlfn : function(e0,e1,e2,e3,phi) {return(e0*phi-e1*Math.sin(2.0*phi)+e2*Math.sin(4.0*phi)-e3*Math.sin(6.0*phi));},
|
585
|
|
586
|
srat : function(esinp, exp) {
|
587
|
return(Math.pow((1.0-esinp)/(1.0+esinp), exp));
|
588
|
},
|
589
|
|
590
|
// Function to return the sign of an argument
|
591
|
sign : function(x) { if (x < 0.0) return(-1); else return(1);},
|
592
|
|
593
|
// Function to adjust longitude to -180 to 180; input in radians
|
594
|
adjust_lon : function(x) {
|
595
|
x = (Math.abs(x) < this.PI) ? x: (x - (this.sign(x)*this.TWO_PI) );
|
596
|
return x;
|
597
|
}
|
598
|
|
599
|
};
|
600
|
|
601
|
/** datum object
|
602
|
*/
|
603
|
Proj4js.datum = OpenLayers.Class({
|
604
|
|
605
|
initialize : function(proj) {
|
606
|
this.datum_type = Proj4js.common.PJD_WGS84; //default setting
|
607
|
if (proj.datumCode && proj.datumCode == 'none') {
|
608
|
this.datum_type = Proj4js.common.PJD_NODATUM;
|
609
|
}
|
610
|
if (proj && proj.datum_params) {
|
611
|
for (var i=0; i<proj.datum_params.length; i++) {
|
612
|
proj.datum_params[i]=parseFloat(proj.datum_params[i]);
|
613
|
}
|
614
|
if (proj.datum_params[0] != 0 || proj.datum_params[1] != 0 || proj.datum_params[2] != 0 ) {
|
615
|
this.datum_type = Proj4js.common.PJD_3PARAM;
|
616
|
}
|
617
|
if (proj.datum_params.length > 3) {
|
618
|
if (proj.datum_params[3] != 0 || proj.datum_params[4] != 0 ||
|
619
|
proj.datum_params[5] != 0 || proj.datum_params[6] != 0 ) {
|
620
|
this.datum_type = Proj4js.common.PJD_7PARAM;
|
621
|
proj.datum_params[3] *= Proj4js.common.SEC_TO_RAD;
|
622
|
proj.datum_params[4] *= Proj4js.common.SEC_TO_RAD;
|
623
|
proj.datum_params[5] *= Proj4js.common.SEC_TO_RAD;
|
624
|
proj.datum_params[6] = (proj.datum_params[6]/1000000.0) + 1.0;
|
625
|
}
|
626
|
}
|
627
|
}
|
628
|
if (proj) {
|
629
|
this.a = proj.a; //datum object also uses these values
|
630
|
this.b = proj.b;
|
631
|
this.es = proj.es;
|
632
|
this.ep2 = proj.ep2;
|
633
|
this.datum_params = proj.datum_params;
|
634
|
}
|
635
|
},
|
636
|
|
637
|
/****************************************************************/
|
638
|
// cs_compare_datums()
|
639
|
// Returns 1 (TRUE) if the two datums match, otherwise 0 (FALSE).
|
640
|
compare_datums : function( dest ) {
|
641
|
if( this.datum_type != dest.datum_type ) {
|
642
|
return false; // false, datums are not equal
|
643
|
} else if (this.a != dest.a || Math.abs(this.es-dest.es) > 0.000000000050) {
|
644
|
// the tolerence for es is to ensure that GRS80 and WGS84
|
645
|
// are considered identical
|
646
|
return false;
|
647
|
} else if( this.datum_type == Proj4js.common.PJD_3PARAM ) {
|
648
|
return (this.datum_params[0] == dest.datum_params[0]
|
649
|
&& this.datum_params[1] == dest.datum_params[1]
|
650
|
&& this.datum_params[2] == dest.datum_params[2]);
|
651
|
} else if( this.datum_type == Proj4js.common.PJD_7PARAM ) {
|
652
|
return (this.datum_params[0] == dest.datum_params[0]
|
653
|
&& this.datum_params[1] == dest.datum_params[1]
|
654
|
&& this.datum_params[2] == dest.datum_params[2]
|
655
|
&& this.datum_params[3] == dest.datum_params[3]
|
656
|
&& this.datum_params[4] == dest.datum_params[4]
|
657
|
&& this.datum_params[5] == dest.datum_params[5]
|
658
|
&& this.datum_params[6] == dest.datum_params[6]);
|
659
|
} else if( this.datum_type == Proj4js.common.PJD_GRIDSHIFT ) {
|
660
|
return strcmp( pj_param(this.params,"snadgrids").s,
|
661
|
pj_param(dest.params,"snadgrids").s ) == 0;
|
662
|
} else {
|
663
|
return true; // datums are equal
|
664
|
}
|
665
|
}, // cs_compare_datums()
|
666
|
|
667
|
/*
|
668
|
* The function Convert_Geodetic_To_Geocentric converts geodetic coordinates
|
669
|
* (latitude, longitude, and height) to geocentric coordinates (X, Y, Z),
|
670
|
* according to the current ellipsoid parameters.
|
671
|
*
|
672
|
* Latitude : Geodetic latitude in radians (input)
|
673
|
* Longitude : Geodetic longitude in radians (input)
|
674
|
* Height : Geodetic height, in meters (input)
|
675
|
* X : Calculated Geocentric X coordinate, in meters (output)
|
676
|
* Y : Calculated Geocentric Y coordinate, in meters (output)
|
677
|
* Z : Calculated Geocentric Z coordinate, in meters (output)
|
678
|
*
|
679
|
*/
|
680
|
geodetic_to_geocentric : function(p) {
|
681
|
var Longitude = p.x;
|
682
|
var Latitude = p.y;
|
683
|
var Height = p.z ? p.z : 0; //Z value not always supplied
|
684
|
var X; // output
|
685
|
var Y;
|
686
|
var Z;
|
687
|
|
688
|
var Error_Code=0; // GEOCENT_NO_ERROR;
|
689
|
var Rn; /* Earth radius at location */
|
690
|
var Sin_Lat; /* Math.sin(Latitude) */
|
691
|
var Sin2_Lat; /* Square of Math.sin(Latitude) */
|
692
|
var Cos_Lat; /* Math.cos(Latitude) */
|
693
|
|
694
|
/*
|
695
|
** Don't blow up if Latitude is just a little out of the value
|
696
|
** range as it may just be a rounding issue. Also removed longitude
|
697
|
** test, it should be wrapped by Math.cos() and Math.sin(). NFW for PROJ.4, Sep/2001.
|
698
|
*/
|
699
|
if (Latitude < -Proj4js.common.HALF_PI && Latitude > -1.001 * Proj4js.common.HALF_PI ) {
|
700
|
Latitude = -Proj4js.common.HALF_PI;
|
701
|
} else if (Latitude > Proj4js.common.HALF_PI && Latitude < 1.001 * Proj4js.common.HALF_PI ) {
|
702
|
Latitude = Proj4js.common.HALF_PI;
|
703
|
} else if ((Latitude < -Proj4js.common.HALF_PI) || (Latitude > Proj4js.common.HALF_PI)) {
|
704
|
/* Latitude out of range */
|
705
|
Proj4js.reportError('geocent:lat out of range:'+Latitude);
|
706
|
return null;
|
707
|
}
|
708
|
|
709
|
if (Longitude > Proj4js.common.PI) Longitude -= (2*Proj4js.common.PI);
|
710
|
Sin_Lat = Math.sin(Latitude);
|
711
|
Cos_Lat = Math.cos(Latitude);
|
712
|
Sin2_Lat = Sin_Lat * Sin_Lat;
|
713
|
Rn = this.a / (Math.sqrt(1.0e0 - this.es * Sin2_Lat));
|
714
|
X = (Rn + Height) * Cos_Lat * Math.cos(Longitude);
|
715
|
Y = (Rn + Height) * Cos_Lat * Math.sin(Longitude);
|
716
|
Z = ((Rn * (1 - this.es)) + Height) * Sin_Lat;
|
717
|
|
718
|
p.x = X;
|
719
|
p.y = Y;
|
720
|
p.z = Z;
|
721
|
return Error_Code;
|
722
|
}, // cs_geodetic_to_geocentric()
|
723
|
|
724
|
geocentric_to_geodetic : function (p) {
|
725
|
/* local defintions and variables */
|
726
|
/* end-criterium of loop, accuracy of sin(Latitude) */
|
727
|
var genau = 1.E-12;
|
728
|
var genau2 = (genau*genau);
|
729
|
var maxiter = 30;
|
730
|
|
731
|
var P; /* distance between semi-minor axis and location */
|
732
|
var RR; /* distance between center and location */
|
733
|
var CT; /* sin of geocentric latitude */
|
734
|
var ST; /* cos of geocentric latitude */
|
735
|
var RX;
|
736
|
var RK;
|
737
|
var RN; /* Earth radius at location */
|
738
|
var CPHI0; /* cos of start or old geodetic latitude in iterations */
|
739
|
var SPHI0; /* sin of start or old geodetic latitude in iterations */
|
740
|
var CPHI; /* cos of searched geodetic latitude */
|
741
|
var SPHI; /* sin of searched geodetic latitude */
|
742
|
var SDPHI; /* end-criterium: addition-theorem of sin(Latitude(iter)-Latitude(iter-1)) */
|
743
|
var At_Pole; /* indicates location is in polar region */
|
744
|
var iter; /* # of continous iteration, max. 30 is always enough (s.a.) */
|
745
|
|
746
|
var X =p.x;
|
747
|
var Y = p.y;
|
748
|
var Z = p.z ? p.z : 0.0; //Z value not always supplied
|
749
|
var Longitude;
|
750
|
var Latitude;
|
751
|
var Height;
|
752
|
|
753
|
At_Pole = false;
|
754
|
P = Math.sqrt(X*X+Y*Y);
|
755
|
RR = Math.sqrt(X*X+Y*Y+Z*Z);
|
756
|
|
757
|
/* special cases for latitude and longitude */
|
758
|
if (P/this.a < genau) {
|
759
|
|
760
|
/* special case, if P=0. (X=0., Y=0.) */
|
761
|
At_Pole = true;
|
762
|
Longitude = 0.0;
|
763
|
|
764
|
/* if (X,Y,Z)=(0.,0.,0.) then Height becomes semi-minor axis
|
765
|
* of ellipsoid (=center of mass), Latitude becomes PI/2 */
|
766
|
if (RR/this.a < genau) {
|
767
|
Latitude = Proj4js.common.HALF_PI;
|
768
|
Height = -this.b;
|
769
|
return;
|
770
|
}
|
771
|
} else {
|
772
|
/* ellipsoidal (geodetic) longitude
|
773
|
* interval: -PI < Longitude <= +PI */
|
774
|
Longitude=Math.atan2(Y,X);
|
775
|
}
|
776
|
|
777
|
/* --------------------------------------------------------------
|
778
|
* Following iterative algorithm was developped by
|
779
|
* "Institut f?r Erdmessung", University of Hannover, July 1988.
|
780
|
* Internet: www.ife.uni-hannover.de
|
781
|
* Iterative computation of CPHI,SPHI and Height.
|
782
|
* Iteration of CPHI and SPHI to 10**-12 radian resp.
|
783
|
* 2*10**-7 arcsec.
|
784
|
* --------------------------------------------------------------
|
785
|
*/
|
786
|
CT = Z/RR;
|
787
|
ST = P/RR;
|
788
|
RX = 1.0/Math.sqrt(1.0-this.es*(2.0-this.es)*ST*ST);
|
789
|
CPHI0 = ST*(1.0-this.es)*RX;
|
790
|
SPHI0 = CT*RX;
|
791
|
iter = 0;
|
792
|
|
793
|
/* loop to find sin(Latitude) resp. Latitude
|
794
|
* until |sin(Latitude(iter)-Latitude(iter-1))| < genau */
|
795
|
do
|
796
|
{
|
797
|
iter++;
|
798
|
RN = this.a/Math.sqrt(1.0-this.es*SPHI0*SPHI0);
|
799
|
|
800
|
/* ellipsoidal (geodetic) height */
|
801
|
Height = P*CPHI0+Z*SPHI0-RN*(1.0-this.es*SPHI0*SPHI0);
|
802
|
|
803
|
RK = this.es*RN/(RN+Height);
|
804
|
RX = 1.0/Math.sqrt(1.0-RK*(2.0-RK)*ST*ST);
|
805
|
CPHI = ST*(1.0-RK)*RX;
|
806
|
SPHI = CT*RX;
|
807
|
SDPHI = SPHI*CPHI0-CPHI*SPHI0;
|
808
|
CPHI0 = CPHI;
|
809
|
SPHI0 = SPHI;
|
810
|
}
|
811
|
while (SDPHI*SDPHI > genau2 && iter < maxiter);
|
812
|
|
813
|
/* ellipsoidal (geodetic) latitude */
|
814
|
Latitude=Math.atan(SPHI/Math.abs(CPHI));
|
815
|
|
816
|
p.x = Longitude;
|
817
|
p.y =Latitude;
|
818
|
p.z = Height;
|
819
|
return p;
|
820
|
},
|
821
|
|
822
|
/** Convert_Geocentric_To_Geodetic
|
823
|
* The method used here is derived from 'An Improved Algorithm for
|
824
|
* Geocentric to Geodetic Coordinate Conversion', by Ralph Toms, Feb 1996
|
825
|
*/
|
826
|
geocentric_to_geodetic_noniter : function (p) {
|
827
|
var X =p.x;
|
828
|
var Y = p.y;
|
829
|
var Z = p.z ? p.z : 0; //Z value not always supplied
|
830
|
var Longitude;
|
831
|
var Latitude;
|
832
|
var Height;
|
833
|
|
834
|
var W; /* distance from Z axis */
|
835
|
var W2; /* square of distance from Z axis */
|
836
|
var T0; /* initial estimate of vertical component */
|
837
|
var T1; /* corrected estimate of vertical component */
|
838
|
var S0; /* initial estimate of horizontal component */
|
839
|
var S1; /* corrected estimate of horizontal component */
|
840
|
var Sin_B0; /* Math.sin(B0), B0 is estimate of Bowring aux variable */
|
841
|
var Sin3_B0; /* cube of Math.sin(B0) */
|
842
|
var Cos_B0; /* Math.cos(B0) */
|
843
|
var Sin_p1; /* Math.sin(phi1), phi1 is estimated latitude */
|
844
|
var Cos_p1; /* Math.cos(phi1) */
|
845
|
var Rn; /* Earth radius at location */
|
846
|
var Sum; /* numerator of Math.cos(phi1) */
|
847
|
var At_Pole; /* indicates location is in polar region */
|
848
|
|
849
|
X = parseFloat(X); // cast from string to float
|
850
|
Y = parseFloat(Y);
|
851
|
Z = parseFloat(Z);
|
852
|
|
853
|
At_Pole = false;
|
854
|
if (X != 0.0)
|
855
|
{
|
856
|
Longitude = Math.atan2(Y,X);
|
857
|
}
|
858
|
else
|
859
|
{
|
860
|
if (Y > 0)
|
861
|
{
|
862
|
Longitude = Proj4js.common.HALF_PI;
|
863
|
}
|
864
|
else if (Y < 0)
|
865
|
{
|
866
|
Longitude = -Proj4js.common.HALF_PI;
|
867
|
}
|
868
|
else
|
869
|
{
|
870
|
At_Pole = true;
|
871
|
Longitude = 0.0;
|
872
|
if (Z > 0.0)
|
873
|
{ /* north pole */
|
874
|
Latitude = Proj4js.common.HALF_PI;
|
875
|
}
|
876
|
else if (Z < 0.0)
|
877
|
{ /* south pole */
|
878
|
Latitude = -Proj4js.common.HALF_PI;
|
879
|
}
|
880
|
else
|
881
|
{ /* center of earth */
|
882
|
Latitude = Proj4js.common.HALF_PI;
|
883
|
Height = -this.b;
|
884
|
return;
|
885
|
}
|
886
|
}
|
887
|
}
|
888
|
W2 = X*X + Y*Y;
|
889
|
W = Math.sqrt(W2);
|
890
|
T0 = Z * Proj4js.common.AD_C;
|
891
|
S0 = Math.sqrt(T0 * T0 + W2);
|
892
|
Sin_B0 = T0 / S0;
|
893
|
Cos_B0 = W / S0;
|
894
|
Sin3_B0 = Sin_B0 * Sin_B0 * Sin_B0;
|
895
|
T1 = Z + this.b * this.ep2 * Sin3_B0;
|
896
|
Sum = W - this.a * this.es * Cos_B0 * Cos_B0 * Cos_B0;
|
897
|
S1 = Math.sqrt(T1*T1 + Sum * Sum);
|
898
|
Sin_p1 = T1 / S1;
|
899
|
Cos_p1 = Sum / S1;
|
900
|
Rn = this.a / Math.sqrt(1.0 - this.es * Sin_p1 * Sin_p1);
|
901
|
if (Cos_p1 >= Proj4js.common.COS_67P5)
|
902
|
{
|
903
|
Height = W / Cos_p1 - Rn;
|
904
|
}
|
905
|
else if (Cos_p1 <= -Proj4js.common.COS_67P5)
|
906
|
{
|
907
|
Height = W / -Cos_p1 - Rn;
|
908
|
}
|
909
|
else
|
910
|
{
|
911
|
Height = Z / Sin_p1 + Rn * (this.es - 1.0);
|
912
|
}
|
913
|
if (At_Pole == false)
|
914
|
{
|
915
|
Latitude = Math.atan(Sin_p1 / Cos_p1);
|
916
|
}
|
917
|
|
918
|
p.x = Longitude;
|
919
|
p.y =Latitude;
|
920
|
p.z = Height;
|
921
|
return p;
|
922
|
}, // cs_geocentric_to_geodetic()
|
923
|
|
924
|
/****************************************************************/
|
925
|
// pj_geocentic_to_wgs84( p )
|
926
|
// p = point to transform in geocentric coordinates (x,y,z)
|
927
|
geocentric_to_wgs84 : function ( p ) {
|
928
|
|
929
|
if( this.datum_type == Proj4js.common.PJD_3PARAM )
|
930
|
{
|
931
|
// if( x[io] == HUGE_VAL )
|
932
|
// continue;
|
933
|
p.x += this.datum_params[0];
|
934
|
p.y += this.datum_params[1];
|
935
|
p.z += this.datum_params[2];
|
936
|
|
937
|
}
|
938
|
else // if( this.datum_type == Proj4js.common.PJD_7PARAM )
|
939
|
{
|
940
|
var Dx_BF =this.datum_params[0];
|
941
|
var Dy_BF =this.datum_params[1];
|
942
|
var Dz_BF =this.datum_params[2];
|
943
|
var Rx_BF =this.datum_params[3];
|
944
|
var Ry_BF =this.datum_params[4];
|
945
|
var Rz_BF =this.datum_params[5];
|
946
|
var M_BF =this.datum_params[6];
|
947
|
// if( x[io] == HUGE_VAL )
|
948
|
// continue;
|
949
|
var x_out = M_BF*( p.x - Rz_BF*p.y + Ry_BF*p.z) + Dx_BF;
|
950
|
var y_out = M_BF*( Rz_BF*p.x + p.y - Rx_BF*p.z) + Dy_BF;
|
951
|
var z_out = M_BF*(-Ry_BF*p.x + Rx_BF*p.y + p.z) + Dz_BF;
|
952
|
p.x = x_out;
|
953
|
p.y = y_out;
|
954
|
p.z = z_out;
|
955
|
}
|
956
|
}, // cs_geocentric_to_wgs84
|
957
|
|
958
|
/****************************************************************/
|
959
|
// pj_geocentic_from_wgs84()
|
960
|
// coordinate system definition,
|
961
|
// point to transform in geocentric coordinates (x,y,z)
|
962
|
geocentric_from_wgs84 : function( p ) {
|
963
|
|
964
|
if( this.datum_type == Proj4js.common.PJD_3PARAM )
|
965
|
{
|
966
|
//if( x[io] == HUGE_VAL )
|
967
|
// continue;
|
968
|
p.x -= this.datum_params[0];
|
969
|
p.y -= this.datum_params[1];
|
970
|
p.z -= this.datum_params[2];
|
971
|
|
972
|
}
|
973
|
else // if( this.datum_type == Proj4js.common.PJD_7PARAM )
|
974
|
{
|
975
|
var Dx_BF =this.datum_params[0];
|
976
|
var Dy_BF =this.datum_params[1];
|
977
|
var Dz_BF =this.datum_params[2];
|
978
|
var Rx_BF =this.datum_params[3];
|
979
|
var Ry_BF =this.datum_params[4];
|
980
|
var Rz_BF =this.datum_params[5];
|
981
|
var M_BF =this.datum_params[6];
|
982
|
var x_tmp = (p.x - Dx_BF) / M_BF;
|
983
|
var y_tmp = (p.y - Dy_BF) / M_BF;
|
984
|
var z_tmp = (p.z - Dz_BF) / M_BF;
|
985
|
//if( x[io] == HUGE_VAL )
|
986
|
// continue;
|
987
|
|
988
|
p.x = x_tmp + Rz_BF*y_tmp - Ry_BF*z_tmp;
|
989
|
p.y = -Rz_BF*x_tmp + y_tmp + Rx_BF*z_tmp;
|
990
|
p.z = Ry_BF*x_tmp - Rx_BF*y_tmp + z_tmp;
|
991
|
} //cs_geocentric_from_wgs84()
|
992
|
}
|
993
|
});
|
994
|
|
995
|
/** point object, nothing fancy, just allows values to be
|
996
|
passed back and forth by reference rather than by value.
|
997
|
Other point classes may be used as long as they have
|
998
|
x and y properties, which will get modified in the transform method.
|
999
|
*/
|
1000
|
Proj4js.Point = OpenLayers.Class({
|
1001
|
|
1002
|
initialize : function(x,y,z) {
|
1003
|
if (typeof x == 'object') {
|
1004
|
this.x = x[0];
|
1005
|
this.y = x[1];
|
1006
|
this.z = x[2] || 0.0;
|
1007
|
} else {
|
1008
|
this.x = x;
|
1009
|
this.y = y;
|
1010
|
this.z = z || 0.0;
|
1011
|
}
|
1012
|
},
|
1013
|
|
1014
|
clone : function() {
|
1015
|
return new Proj4js.Point(this.x, this.y, this.z);
|
1016
|
},
|
1017
|
|
1018
|
/**
|
1019
|
* Method: toString
|
1020
|
* Return a readable string version of the lonlat
|
1021
|
*
|
1022
|
* Return:
|
1023
|
* {String} String representation of Proj4js.Point object.
|
1024
|
* (ex. <i>"x=5,y=42"</i>)
|
1025
|
*/
|
1026
|
toString:function() {
|
1027
|
return ("x=" + this.x + ",y=" + this.y);
|
1028
|
},
|
1029
|
|
1030
|
/**
|
1031
|
* APIMethod: toShortString
|
1032
|
*
|
1033
|
* Return:
|
1034
|
* {String} Shortened String representation of Proj4js.Point object.
|
1035
|
* (ex. <i>"5, 42"</i>)
|
1036
|
*/
|
1037
|
toShortString:function() {
|
1038
|
return (this.x + ", " + this.y);
|
1039
|
}
|
1040
|
});
|
1041
|
|
1042
|
Proj4js.PrimeMeridian = {
|
1043
|
"greenwich": 0.0, //"0dE",
|
1044
|
"lisbon": -9.131906111111, //"9d07'54.862\"W",
|
1045
|
"paris": 2.337229166667, //"2d20'14.025\"E",
|
1046
|
"bogota": -74.080916666667, //"74d04'51.3\"W",
|
1047
|
"madrid": -3.687938888889, //"3d41'16.58\"W",
|
1048
|
"rome": 12.452333333333, //"12d27'8.4\"E",
|
1049
|
"bern": 7.439583333333, //"7d26'22.5\"E",
|
1050
|
"jakarta": 106.807719444444, //"106d48'27.79\"E",
|
1051
|
"ferro": -17.666666666667, //"17d40'W",
|
1052
|
"brussels": 4.367975, //"4d22'4.71\"E",
|
1053
|
"stockholm": 18.058277777778, //"18d3'29.8\"E",
|
1054
|
"athens": 23.7163375, //"23d42'58.815\"E",
|
1055
|
"oslo": 10.722916666667 //"10d43'22.5\"E"
|
1056
|
};
|
1057
|
|
1058
|
Proj4js.Ellipsoid = {
|
1059
|
"MERIT": {a:6378137.0, rf:298.257, ellipseName:"MERIT 1983"},
|
1060
|
"SGS85": {a:6378136.0, rf:298.257, ellipseName:"Soviet Geodetic System 85"},
|
1061
|
"GRS80": {a:6378137.0, rf:298.257222101, ellipseName:"GRS 1980(IUGG, 1980)"},
|
1062
|
"IAU76": {a:6378140.0, rf:298.257, ellipseName:"IAU 1976"},
|
1063
|
"airy": {a:6377563.396, b:6356256.910, ellipseName:"Airy 1830"},
|
1064
|
"APL4.": {a:6378137, rf:298.25, ellipseName:"Appl. Physics. 1965"},
|
1065
|
"NWL9D": {a:6378145.0, rf:298.25, ellipseName:"Naval Weapons Lab., 1965"},
|
1066
|
"mod_airy": {a:6377340.189, b:6356034.446, ellipseName:"Modified Airy"},
|
1067
|
"andrae": {a:6377104.43, rf:300.0, ellipseName:"Andrae 1876 (Den., Iclnd.)"},
|
1068
|
"aust_SA": {a:6378160.0, rf:298.25, ellipseName:"Australian Natl & S. Amer. 1969"},
|
1069
|
"GRS67": {a:6378160.0, rf:298.2471674270, ellipseName:"GRS 67(IUGG 1967)"},
|
1070
|
"bessel": {a:6377397.155, rf:299.1528128, ellipseName:"Bessel 1841"},
|
1071
|
"bess_nam": {a:6377483.865, rf:299.1528128, ellipseName:"Bessel 1841 (Namibia)"},
|
1072
|
"clrk66": {a:6378206.4, b:6356583.8, ellipseName:"Clarke 1866"},
|
1073
|
"clrk80": {a:6378249.145, rf:293.4663, ellipseName:"Clarke 1880 mod."},
|
1074
|
"CPM": {a:6375738.7, rf:334.29, ellipseName:"Comm. des Poids et Mesures 1799"},
|
1075
|
"delmbr": {a:6376428.0, rf:311.5, ellipseName:"Delambre 1810 (Belgium)"},
|
1076
|
"engelis": {a:6378136.05, rf:298.2566, ellipseName:"Engelis 1985"},
|
1077
|
"evrst30": {a:6377276.345, rf:300.8017, ellipseName:"Everest 1830"},
|
1078
|
"evrst48": {a:6377304.063, rf:300.8017, ellipseName:"Everest 1948"},
|
1079
|
"evrst56": {a:6377301.243, rf:300.8017, ellipseName:"Everest 1956"},
|
1080
|
"evrst69": {a:6377295.664, rf:300.8017, ellipseName:"Everest 1969"},
|
1081
|
"evrstSS": {a:6377298.556, rf:300.8017, ellipseName:"Everest (Sabah & Sarawak)"},
|
1082
|
"fschr60": {a:6378166.0, rf:298.3, ellipseName:"Fischer (Mercury Datum) 1960"},
|
1083
|
"fschr60m": {a:6378155.0, rf:298.3, ellipseName:"Fischer 1960"},
|
1084
|
"fschr68": {a:6378150.0, rf:298.3, ellipseName:"Fischer 1968"},
|
1085
|
"helmert": {a:6378200.0, rf:298.3, ellipseName:"Helmert 1906"},
|
1086
|
"hough": {a:6378270.0, rf:297.0, ellipseName:"Hough"},
|
1087
|
"intl": {a:6378388.0, rf:297.0, ellipseName:"International 1909 (Hayford)"},
|
1088
|
"kaula": {a:6378163.0, rf:298.24, ellipseName:"Kaula 1961"},
|
1089
|
"lerch": {a:6378139.0, rf:298.257, ellipseName:"Lerch 1979"},
|
1090
|
"mprts": {a:6397300.0, rf:191.0, ellipseName:"Maupertius 1738"},
|
1091
|
"new_intl": {a:6378157.5, b:6356772.2, ellipseName:"New International 1967"},
|
1092
|
"plessis": {a:6376523.0, rf:6355863.0, ellipseName:"Plessis 1817 (France)"},
|
1093
|
"krass": {a:6378245.0, rf:298.3, ellipseName:"Krassovsky, 1942"},
|
1094
|
"SEasia": {a:6378155.0, b:6356773.3205, ellipseName:"Southeast Asia"},
|
1095
|
"walbeck": {a:6376896.0, b:6355834.8467, ellipseName:"Walbeck"},
|
1096
|
"WGS60": {a:6378165.0, rf:298.3, ellipseName:"WGS 60"},
|
1097
|
"WGS66": {a:6378145.0, rf:298.25, ellipseName:"WGS 66"},
|
1098
|
"WGS72": {a:6378135.0, rf:298.26, ellipseName:"WGS 72"},
|
1099
|
"WGS84": {a:6378137.0, rf:298.257223563, ellipseName:"WGS 84"},
|
1100
|
"sphere": {a:6370997.0, b:6370997.0, ellipseName:"Normal Sphere (r=6370997)"}
|
1101
|
};
|
1102
|
|
1103
|
Proj4js.Datum = {
|
1104
|
"WGS84": {towgs84: "0,0,0", ellipse: "WGS84", datumName: ""},
|
1105
|
"GGRS87": {towgs84: "-199.87,74.79,246.62", ellipse: "GRS80", datumName: "Greek_Geodetic_Reference_System_1987"},
|
1106
|
"NAD83": {towgs84: "0,0,0", ellipse: "GRS80", datumName: "North_American_Datum_1983"},
|
1107
|
"NAD27": {nadgrids: "@conus,@alaska,@ntv2_0.gsb,@ntv1_can.dat", ellipse: "clrk66", datumName: "North_American_Datum_1927"},
|
1108
|
"potsdam": {towgs84: "606.0,23.0,413.0", ellipse: "bessel", datumName: "Potsdam Rauenberg 1950 DHDN"},
|
1109
|
"carthage": {towgs84: "-263.0,6.0,431.0", ellipse: "clark80", datumName: "Carthage 1934 Tunisia"},
|
1110
|
"hermannskogel": {towgs84: "653.0,-212.0,449.0", ellipse: "bessel", datumName: "Hermannskogel"},
|
1111
|
"ire65": {towgs84: "482.530,-130.596,564.557,-1.042,-0.214,-0.631,8.15", ellipse: "mod_airy", datumName: "Ireland 1965"},
|
1112
|
"nzgd49": {towgs84: "59.47,-5.04,187.44,0.47,-0.1,1.024,-4.5993", ellipse: "intl", datumName: "New Zealand Geodetic Datum 1949"},
|
1113
|
"OSGB36": {towgs84: "446.448,-125.157,542.060,0.1502,0.2470,0.8421,-20.4894", ellipse: "airy", datumName: "Airy 1830"}
|
1114
|
};
|
1115
|
|
1116
|
Proj4js.WGS84 = new Proj4js.Proj('WGS84');
|
1117
|
Proj4js.Datum['OSB36'] = Proj4js.Datum['OSGB36']; //as returned from spatialreference.org
|
1118
|
/* ======================================================================
|
1119
|
projCode/sterea.js
|
1120
|
====================================================================== */
|
1121
|
|
1122
|
|
1123
|
Proj4js.Proj.sterea = {
|
1124
|
dependsOn : 'gauss',
|
1125
|
|
1126
|
init : function() {
|
1127
|
Proj4js.Proj['gauss'].init.apply(this);
|
1128
|
if (!this.rc) {
|
1129
|
Proj4js.reportError("sterea:init:E_ERROR_0");
|
1130
|
return;
|
1131
|
}
|
1132
|
this.sinc0 = Math.sin(this.phic0);
|
1133
|
this.cosc0 = Math.cos(this.phic0);
|
1134
|
this.R2 = 2.0 * this.rc;
|
1135
|
if (!this.title) this.title = "Oblique Stereographic Alternative";
|
1136
|
},
|
1137
|
|
1138
|
forward : function(p) {
|
1139
|
p.x = Proj4js.common.adjust_lon(p.x-this.long0); /* adjust del longitude */
|
1140
|
Proj4js.Proj['gauss'].forward.apply(this, [p]);
|
1141
|
sinc = Math.sin(p.y);
|
1142
|
cosc = Math.cos(p.y);
|
1143
|
cosl = Math.cos(p.x);
|
1144
|
k = this.k0 * this.R2 / (1.0 + this.sinc0 * sinc + this.cosc0 * cosc * cosl);
|
1145
|
p.x = k * cosc * Math.sin(p.x);
|
1146
|
p.y = k * (this.cosc0 * sinc - this.sinc0 * cosc * cosl);
|
1147
|
p.x = this.a * p.x + this.x0;
|
1148
|
p.y = this.a * p.y + this.y0;
|
1149
|
return p;
|
1150
|
},
|
1151
|
|
1152
|
inverse : function(p) {
|
1153
|
var lon,lat;
|
1154
|
p.x = (p.x - this.x0) / this.a; /* descale and de-offset */
|
1155
|
p.y = (p.y - this.y0) / this.a;
|
1156
|
|
1157
|
p.x /= this.k0;
|
1158
|
p.y /= this.k0;
|
1159
|
if ( (rho = Math.sqrt(p.x*p.x + p.y*p.y)) ) {
|
1160
|
c = 2.0 * Math.atan2(rho, this.R2);
|
1161
|
sinc = Math.sin(c);
|
1162
|
cosc = Math.cos(c);
|
1163
|
lat = Math.asin(cosc * this.sinc0 + p.y * sinc * this.cosc0 / rho);
|
1164
|
lon = Math.atan2(p.x * sinc, rho * this.cosc0 * cosc - p.y * this.sinc0 * sinc);
|
1165
|
} else {
|
1166
|
lat = this.phic0;
|
1167
|
lon = 0.;
|
1168
|
}
|
1169
|
|
1170
|
p.x = lon;
|
1171
|
p.y = lat;
|
1172
|
Proj4js.Proj['gauss'].inverse.apply(this,[p]);
|
1173
|
p.x = Proj4js.common.adjust_lon(p.x + this.long0); /* adjust longitude to CM */
|
1174
|
return p;
|
1175
|
}
|
1176
|
};
|
1177
|
|
1178
|
/* ======================================================================
|
1179
|
projCode/aea.js
|
1180
|
====================================================================== */
|
1181
|
|
1182
|
/*******************************************************************************
|
1183
|
NAME ALBERS CONICAL EQUAL AREA
|
1184
|
|
1185
|
PURPOSE: Transforms input longitude and latitude to Easting and Northing
|
1186
|
for the Albers Conical Equal Area projection. The longitude
|
1187
|
and latitude must be in radians. The Easting and Northing
|
1188
|
values will be returned in meters.
|
1189
|
|
1190
|
PROGRAMMER DATE
|
1191
|
---------- ----
|
1192
|
T. Mittan, Feb, 1992
|
1193
|
|
1194
|
ALGORITHM REFERENCES
|
1195
|
|
1196
|
1. Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
|
1197
|
Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
|
1198
|
State Government Printing Office, Washington D.C., 1987.
|
1199
|
|
1200
|
2. Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
|
1201
|
U.S. Geological Survey Professional Paper 1453 , United State Government
|
1202
|
Printing Office, Washington D.C., 1989.
|
1203
|
*******************************************************************************/
|
1204
|
|
1205
|
|
1206
|
Proj4js.Proj.aea = {
|
1207
|
init : function() {
|
1208
|
|
1209
|
if (Math.abs(this.lat1 + this.lat2) < Proj4js.common.EPSLN) {
|
1210
|
Proj4js.reportError("aeaInitEqualLatitudes");
|
1211
|
return;
|
1212
|
}
|
1213
|
this.temp = this.b / this.a;
|
1214
|
this.es = 1.0 - Math.pow(this.temp,2);
|
1215
|
this.e3 = Math.sqrt(this.es);
|
1216
|
|
1217
|
this.sin_po=Math.sin(this.lat1);
|
1218
|
this.cos_po=Math.cos(this.lat1);
|
1219
|
this.t1=this.sin_po
|
1220
|
this.con = this.sin_po;
|
1221
|
this.ms1 = Proj4js.common.msfnz(this.e3,this.sin_po,this.cos_po);
|
1222
|
this.qs1 = Proj4js.common.qsfnz(this.e3,this.sin_po,this.cos_po);
|
1223
|
|
1224
|
this.sin_po=Math.sin(this.lat2);
|
1225
|
this.cos_po=Math.cos(this.lat2);
|
1226
|
this.t2=this.sin_po;
|
1227
|
this.ms2 = Proj4js.common.msfnz(this.e3,this.sin_po,this.cos_po);
|
1228
|
this.qs2 = Proj4js.common.qsfnz(this.e3,this.sin_po,this.cos_po);
|
1229
|
|
1230
|
this.sin_po=Math.sin(this.lat0);
|
1231
|
this.cos_po=Math.cos(this.lat0);
|
1232
|
this.t3=this.sin_po;
|
1233
|
this.qs0 = Proj4js.common.qsfnz(this.e3,this.sin_po,this.cos_po);
|
1234
|
|
1235
|
if (Math.abs(this.lat1 - this.lat2) > Proj4js.common.EPSLN) {
|
1236
|
this.ns0 = (this.ms1 * this.ms1 - this.ms2 *this.ms2)/ (this.qs2 - this.qs1);
|
1237
|
} else {
|
1238
|
this.ns0 = this.con;
|
1239
|
}
|
1240
|
this.c = this.ms1 * this.ms1 + this.ns0 * this.qs1;
|
1241
|
this.rh = this.a * Math.sqrt(this.c - this.ns0 * this.qs0)/this.ns0;
|
1242
|
},
|
1243
|
|
1244
|
/* Albers Conical Equal Area forward equations--mapping lat,long to x,y
|
1245
|
-------------------------------------------------------------------*/
|
1246
|
forward: function(p){
|
1247
|
|
1248
|
var lon=p.x;
|
1249
|
var lat=p.y;
|
1250
|
|
1251
|
this.sin_phi=Math.sin(lat);
|
1252
|
this.cos_phi=Math.cos(lat);
|
1253
|
|
1254
|
var qs = Proj4js.common.qsfnz(this.e3,this.sin_phi,this.cos_phi);
|
1255
|
var rh1 =this.a * Math.sqrt(this.c - this.ns0 * qs)/this.ns0;
|
1256
|
var theta = this.ns0 * Proj4js.common.adjust_lon(lon - this.long0);
|
1257
|
var x = rh1 * Math.sin(theta) + this.x0;
|
1258
|
var y = this.rh - rh1 * Math.cos(theta) + this.y0;
|
1259
|
|
1260
|
p.x = x;
|
1261
|
p.y = y;
|
1262
|
return p;
|
1263
|
},
|
1264
|
|
1265
|
|
1266
|
inverse: function(p) {
|
1267
|
var rh1,qs,con,theta,lon,lat;
|
1268
|
|
1269
|
p.x -= this.x0;
|
1270
|
p.y = this.rh - p.y + this.y0;
|
1271
|
if (this.ns0 >= 0) {
|
1272
|
rh1 = Math.sqrt(p.x *p.x + p.y * p.y);
|
1273
|
con = 1.0;
|
1274
|
} else {
|
1275
|
rh1 = -Math.sqrt(p.x * p.x + p.y *p.y);
|
1276
|
con = -1.0;
|
1277
|
}
|
1278
|
theta = 0.0;
|
1279
|
if (rh1 != 0.0) {
|
1280
|
theta = Math.atan2(con * p.x, con * p.y);
|
1281
|
}
|
1282
|
con = rh1 * this.ns0 / this.a;
|
1283
|
qs = (this.c - con * con) / this.ns0;
|
1284
|
if (this.e3 >= 1e-10) {
|
1285
|
con = 1 - .5 * (1.0 -this.es) * Math.log((1.0 - this.e3) / (1.0 + this.e3))/this.e3;
|
1286
|
if (Math.abs(Math.abs(con) - Math.abs(qs)) > .0000000001 ) {
|
1287
|
lat = this.phi1z(this.e3,qs);
|
1288
|
} else {
|
1289
|
if (qs >= 0) {
|
1290
|
lat = .5 * PI;
|
1291
|
} else {
|
1292
|
lat = -.5 * PI;
|
1293
|
}
|
1294
|
}
|
1295
|
} else {
|
1296
|
lat = this.phi1z(e3,qs);
|
1297
|
}
|
1298
|
|
1299
|
lon = Proj4js.common.adjust_lon(theta/this.ns0 + this.long0);
|
1300
|
p.x = lon;
|
1301
|
p.y = lat;
|
1302
|
return p;
|
1303
|
},
|
1304
|
|
1305
|
/* Function to compute phi1, the latitude for the inverse of the
|
1306
|
Albers Conical Equal-Area projection.
|
1307
|
-------------------------------------------*/
|
1308
|
phi1z: function (eccent,qs) {
|
1309
|
var con, com, dphi;
|
1310
|
var phi = Proj4js.common.asinz(.5 * qs);
|
1311
|
if (eccent < Proj4js.common.EPSLN) return phi;
|
1312
|
|
1313
|
var eccnts = eccent * eccent;
|
1314
|
for (var i = 1; i <= 25; i++) {
|
1315
|
sinphi = Math.sin(phi);
|
1316
|
cosphi = Math.cos(phi);
|
1317
|
con = eccent * sinphi;
|
1318
|
com = 1.0 - con * con;
|
1319
|
dphi = .5 * com * com / cosphi * (qs / (1.0 - eccnts) - sinphi / com + .5 / eccent * Math.log((1.0 - con) / (1.0 + con)));
|
1320
|
phi = phi + dphi;
|
1321
|
if (Math.abs(dphi) <= 1e-7) return phi;
|
1322
|
}
|
1323
|
Proj4js.reportError("aea:phi1z:Convergence error");
|
1324
|
return null;
|
1325
|
}
|
1326
|
|
1327
|
};
|
1328
|
|
1329
|
|
1330
|
|
1331
|
/* ======================================================================
|
1332
|
projCode/poly.js
|
1333
|
====================================================================== */
|
1334
|
|
1335
|
/* Function to compute, phi4, the latitude for the inverse of the
|
1336
|
Polyconic projection.
|
1337
|
------------------------------------------------------------*/
|
1338
|
function phi4z (eccent,e0,e1,e2,e3,a,b,c,phi) {
|
1339
|
var sinphi, sin2ph, tanph, ml, mlp, con1, con2, con3, dphi, i;
|
1340
|
|
1341
|
phi = a;
|
1342
|
for (i = 1; i <= 15; i++) {
|
1343
|
sinphi = Math.sin(phi);
|
1344
|
tanphi = Math.tan(phi);
|
1345
|
c = tanphi * Math.sqrt (1.0 - eccent * sinphi * sinphi);
|
1346
|
sin2ph = Math.sin (2.0 * phi);
|
1347
|
/*
|
1348
|
ml = e0 * *phi - e1 * sin2ph + e2 * sin (4.0 * *phi);
|
1349
|
mlp = e0 - 2.0 * e1 * cos (2.0 * *phi) + 4.0 * e2 * cos (4.0 * *phi);
|
1350
|
*/
|
1351
|
ml = e0 * phi - e1 * sin2ph + e2 * Math.sin (4.0 * phi) - e3 * Math.sin (6.0 * phi);
|
1352
|
mlp = e0 - 2.0 * e1 * Math.cos (2.0 * phi) + 4.0 * e2 * Math.cos (4.0 * phi) - 6.0 * e3 * Math.cos (6.0 * phi);
|
1353
|
con1 = 2.0 * ml + c * (ml * ml + b) - 2.0 * a * (c * ml + 1.0);
|
1354
|
con2 = eccent * sin2ph * (ml * ml + b - 2.0 * a * ml) / (2.0 *c);
|
1355
|
con3 = 2.0 * (a - ml) * (c * mlp - 2.0 / sin2ph) - 2.0 * mlp;
|
1356
|
dphi = con1 / (con2 + con3);
|
1357
|
phi += dphi;
|
1358
|
if (Math.abs(dphi) <= .0000000001 ) return(phi);
|
1359
|
}
|
1360
|
Proj4js.reportError("phi4z: No convergence");
|
1361
|
return null;
|
1362
|
}
|
1363
|
|
1364
|
|
1365
|
/* Function to compute the constant e4 from the input of the eccentricity
|
1366
|
of the spheroid, x. This constant is used in the Polar Stereographic
|
1367
|
projection.
|
1368
|
--------------------------------------------------------------------*/
|
1369
|
function e4fn(x) {
|
1370
|
var con, com;
|
1371
|
con = 1.0 + x;
|
1372
|
com = 1.0 - x;
|
1373
|
return (Math.sqrt((Math.pow(con,con))*(Math.pow(com,com))));
|
1374
|
}
|
1375
|
|
1376
|
|
1377
|
|
1378
|
|
1379
|
|
1380
|
/*******************************************************************************
|
1381
|
NAME POLYCONIC
|
1382
|
|
1383
|
PURPOSE: Transforms input longitude and latitude to Easting and
|
1384
|
Northing for the Polyconic projection. The
|
1385
|
longitude and latitude must be in radians. The Easting
|
1386
|
and Northing values will be returned in meters.
|
1387
|
|
1388
|
PROGRAMMER DATE
|
1389
|
---------- ----
|
1390
|
T. Mittan Mar, 1993
|
1391
|
|
1392
|
ALGORITHM REFERENCES
|
1393
|
|
1394
|
1. Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
|
1395
|
Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
|
1396
|
State Government Printing Office, Washington D.C., 1987.
|
1397
|
|
1398
|
2. Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
|
1399
|
U.S. Geological Survey Professional Paper 1453 , United State Government
|
1400
|
Printing Office, Washington D.C., 1989.
|
1401
|
*******************************************************************************/
|
1402
|
|
1403
|
Proj4js.Proj.poly = {
|
1404
|
|
1405
|
/* Initialize the POLYCONIC projection
|
1406
|
----------------------------------*/
|
1407
|
init: function() {
|
1408
|
var temp; /* temporary variable */
|
1409
|
if (this.lat0=0) this.lat0=90;//this.lat0 ca
|
1410
|
|
1411
|
/* Place parameters in static storage for common use
|
1412
|
-------------------------------------------------*/
|
1413
|
this.temp = this.b / this.a;
|
1414
|
this.es = 1.0 - Math.pow(this.temp,2);// devait etre dans tmerc.js mais n y est pas donc je commente sinon retour de valeurs nulles
|
1415
|
this.e = Math.sqrt(this.es);
|
1416
|
this.e0 = Proj4js.common.e0fn(this.es);
|
1417
|
this.e1 = Proj4js.common.e1fn(this.es);
|
1418
|
this.e2 = Proj4js.common.e2fn(this.es);
|
1419
|
this.e3 = Proj4js.common.e3fn(this.es);
|
1420
|
this.ml0 = Proj4js.common.mlfn(this.e0, this.e1,this.e2, this.e3, this.lat0);//si que des zeros le calcul ne se fait pas
|
1421
|
//if (!this.ml0) {this.ml0=0;}
|
1422
|
},
|
1423
|
|
1424
|
|
1425
|
/* Polyconic forward equations--mapping lat,long to x,y
|
1426
|
---------------------------------------------------*/
|
1427
|
forward: function(p) {
|
1428
|
var sinphi, cosphi; /* sin and cos value */
|
1429
|
var al; /* temporary values */
|
1430
|
var c; /* temporary values */
|
1431
|
var con, ml; /* cone constant, small m */
|
1432
|
var ms; /* small m */
|
1433
|
var x,y;
|
1434
|
|
1435
|
var lon=p.x;
|
1436
|
var lat=p.y;
|
1437
|
|
1438
|
con = Proj4js.common.adjust_lon(lon - this.long0);
|
1439
|
if (Math.abs(lat) <= .0000001) {
|
1440
|
x = this.x0 + this.a * con;
|
1441
|
y = this.y0 - this.a * this.ml0;
|
1442
|
} else {
|
1443
|
sinphi = Math.sin(lat);
|
1444
|
cosphi = Math.cos(lat);
|
1445
|
|
1446
|
ml = Proj4js.common.mlfn(this.e0, this.e1, this.e2, this.e3, lat);
|
1447
|
ms = Proj4js.common.msfnz(this.e,sinphi,cosphi);
|
1448
|
con = sinphi;
|
1449
|
x = this.x0 + this.a * ms * Math.sin(con)/sinphi;
|
1450
|
y = this.y0 + this.a * (ml - this.ml0 + ms * (1.0 - Math.cos(con))/sinphi);
|
1451
|
}
|
1452
|
|
1453
|
p.x=x;
|
1454
|
p.y=y;
|
1455
|
return p;
|
1456
|
},
|
1457
|
|
1458
|
|
1459
|
/* Inverse equations
|
1460
|
-----------------*/
|
1461
|
inverse: function(p) {
|
1462
|
var sin_phi, cos_phi; /* sin and cos value */
|
1463
|
var al; /* temporary values */
|
1464
|
var b; /* temporary values */
|
1465
|
var c; /* temporary values */
|
1466
|
var con, ml; /* cone constant, small m */
|
1467
|
var iflg; /* error flag */
|
1468
|
var lon,lat;
|
1469
|
p.x -= this.x0;
|
1470
|
p.y -= this.y0;
|
1471
|
al = this.ml0 + p.y/this.a;
|
1472
|
iflg = 0;
|
1473
|
|
1474
|
if (Math.abs(al) <= .0000001) {
|
1475
|
lon = p.x/this.a + this.long0;
|
1476
|
lat = 0.0;
|
1477
|
} else {
|
1478
|
b = al * al + (p.x/this.a) * (p.x/this.a);
|
1479
|
iflg = phi4z(this.es,this.e0,this.e1,this.e2,this.e3,this.al,b,c,lat);
|
1480
|
if (iflg != 1) return(iflg);
|
1481
|
lon = Proj4js.common.adjust_lon((asinz(p.x * c / this.a) / Math.sin(lat)) + this.long0);
|
1482
|
}
|
1483
|
|
1484
|
p.x=lon;
|
1485
|
p.y=lat;
|
1486
|
return p;
|
1487
|
}
|
1488
|
};
|
1489
|
|
1490
|
|
1491
|
|
1492
|
/* ======================================================================
|
1493
|
projCode/equi.js
|
1494
|
====================================================================== */
|
1495
|
|
1496
|
/*******************************************************************************
|
1497
|
NAME EQUIRECTANGULAR
|
1498
|
|
1499
|
PURPOSE: Transforms input longitude and latitude to Easting and
|
1500
|
Northing for the Equirectangular projection. The
|
1501
|
longitude and latitude must be in radians. The Easting
|
1502
|
and Northing values will be returned in meters.
|
1503
|
|
1504
|
PROGRAMMER DATE
|
1505
|
---------- ----
|
1506
|
T. Mittan Mar, 1993
|
1507
|
|
1508
|
ALGORITHM REFERENCES
|
1509
|
|
1510
|
1. Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
|
1511
|
Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
|
1512
|
State Government Printing Office, Washington D.C., 1987.
|
1513
|
|
1514
|
2. Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
|
1515
|
U.S. Geological Survey Professional Paper 1453 , United State Government
|
1516
|
Printing Office, Washington D.C., 1989.
|
1517
|
*******************************************************************************/
|
1518
|
Proj4js.Proj.equi = {
|
1519
|
|
1520
|
init: function() {
|
1521
|
if(!this.x0) this.x0=0;
|
1522
|
if(!this.y0) this.y0=0;
|
1523
|
if(!this.lat0) this.lat0=0;
|
1524
|
if(!this.long0) this.long0=0;
|
1525
|
///this.t2;
|
1526
|
},
|
1527
|
|
1528
|
|
1529
|
|
1530
|
/* Equirectangular forward equations--mapping lat,long to x,y
|
1531
|
---------------------------------------------------------*/
|
1532
|
forward: function(p) {
|
1533
|
|
1534
|
var lon=p.x;
|
1535
|
var lat=p.y;
|
1536
|
|
1537
|
var dlon = Proj4js.common.adjust_lon(lon - this.long0);
|
1538
|
var x = this.x0 +this. a * dlon *Math.cos(this.lat0);
|
1539
|
var y = this.y0 + this.a * lat;
|
1540
|
|
1541
|
this.t1=x;
|
1542
|
this.t2=Math.cos(this.lat0);
|
1543
|
p.x=x;
|
1544
|
p.y=y;
|
1545
|
return p;
|
1546
|
}, //equiFwd()
|
1547
|
|
1548
|
|
1549
|
|
1550
|
/* Equirectangular inverse equations--mapping x,y to lat/long
|
1551
|
---------------------------------------------------------*/
|
1552
|
inverse: function(p) {
|
1553
|
|
1554
|
p.x -= this.x0;
|
1555
|
p.y -= this.y0;
|
1556
|
var lat = p.y /this. a;
|
1557
|
|
1558
|
if ( Math.abs(lat) > Proj4js.common.HALF_PI) {
|
1559
|
Proj4js.reportError("equi:Inv:DataError");
|
1560
|
}
|
1561
|
var lon = Proj4js.common.adjust_lon(this.long0 + p.x / (this.a * Math.cos(this.lat0)));
|
1562
|
p.x=lon;
|
1563
|
p.y=lat;
|
1564
|
}//equiInv()
|
1565
|
};
|
1566
|
|
1567
|
|
1568
|
/* ======================================================================
|
1569
|
projCode/merc.js
|
1570
|
====================================================================== */
|
1571
|
|
1572
|
/*******************************************************************************
|
1573
|
NAME MERCATOR
|
1574
|
|
1575
|
PURPOSE: Transforms input longitude and latitude to Easting and
|
1576
|
Northing for the Mercator projection. The
|
1577
|
longitude and latitude must be in radians. The Easting
|
1578
|
and Northing values will be returned in meters.
|
1579
|
|
1580
|
PROGRAMMER DATE
|
1581
|
---------- ----
|
1582
|
D. Steinwand, EROS Nov, 1991
|
1583
|
T. Mittan Mar, 1993
|
1584
|
|
1585
|
ALGORITHM REFERENCES
|
1586
|
|
1587
|
1. Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
|
1588
|
Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
|
1589
|
State Government Printing Office, Washington D.C., 1987.
|
1590
|
|
1591
|
2. Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
|
1592
|
U.S. Geological Survey Professional Paper 1453 , United State Government
|
1593
|
Printing Office, Washington D.C., 1989.
|
1594
|
*******************************************************************************/
|
1595
|
|
1596
|
//static double r_major = a; /* major axis */
|
1597
|
//static double r_minor = b; /* minor axis */
|
1598
|
//static double lon_center = long0; /* Center longitude (projection center) */
|
1599
|
//static double lat_origin = lat0; /* center latitude */
|
1600
|
//static double e,es; /* eccentricity constants */
|
1601
|
//static double m1; /* small value m */
|
1602
|
//static double false_northing = y0; /* y offset in meters */
|
1603
|
//static double false_easting = x0; /* x offset in meters */
|
1604
|
//scale_fact = k0
|
1605
|
|
1606
|
Proj4js.Proj.merc = {
|
1607
|
init : function() {
|
1608
|
//?this.temp = this.r_minor / this.r_major;
|
1609
|
//this.temp = this.b / this.a;
|
1610
|
//this.es = 1.0 - Math.sqrt(this.temp);
|
1611
|
//this.e = Math.sqrt( this.es );
|
1612
|
//?this.m1 = Math.cos(this.lat_origin) / (Math.sqrt( 1.0 - this.es * Math.sin(this.lat_origin) * Math.sin(this.lat_origin)));
|
1613
|
//this.m1 = Math.cos(0.0) / (Math.sqrt( 1.0 - this.es * Math.sin(0.0) * Math.sin(0.0)));
|
1614
|
if (this.lat_ts) {
|
1615
|
if (this.sphere) {
|
1616
|
this.k0 = Math.cos(this.lat_ts);
|
1617
|
} else {
|
1618
|
this.k0 = Proj4js.common.msfnz(this.es, Math.sin(this.lat_ts), Math.cos(this.lat_ts));
|
1619
|
}
|
1620
|
}
|
1621
|
},
|
1622
|
|
1623
|
/* Mercator forward equations--mapping lat,long to x,y
|
1624
|
--------------------------------------------------*/
|
1625
|
|
1626
|
forward : function(p) {
|
1627
|
//alert("ll2m coords : "+coords);
|
1628
|
var lon = p.x;
|
1629
|
var lat = p.y;
|
1630
|
// convert to radians
|
1631
|
if ( lat*Proj4js.common.R2D > 90.0 &&
|
1632
|
lat*Proj4js.common.R2D < -90.0 &&
|
1633
|
lon*Proj4js.common.R2D > 180.0 &&
|
1634
|
lon*Proj4js.common.R2D < -180.0) {
|
1635
|
Proj4js.reportError("merc:forward: llInputOutOfRange: "+ lon +" : " + lat);
|
1636
|
return null;
|
1637
|
}
|
1638
|
|
1639
|
var x,y;
|
1640
|
if(Math.abs( Math.abs(lat) - Proj4js.common.HALF_PI) <= Proj4js.common.EPSLN) {
|
1641
|
Proj4js.reportError("merc:forward: ll2mAtPoles");
|
1642
|
return null;
|
1643
|
} else {
|
1644
|
if (this.sphere) {
|
1645
|
x = this.x0 + this.a * this.k0 * Proj4js.common.adjust_lon(lon - this.long0);
|
1646
|
y = this.y0 + this.a * this.k0 * Math.log(Math.tan(Proj4js.common.FORTPI + 0.5*lat));
|
1647
|
} else {
|
1648
|
var sinphi = Math.sin(lat);
|
1649
|
var ts = Proj4js.common.tsfnz(this.e,lat,sinphi);
|
1650
|
x = this.x0 + this.a * this.k0 * Proj4js.common.adjust_lon(lon - this.long0);
|
1651
|
y = this.y0 - this.a * this.k0 * Math.log(ts);
|
1652
|
}
|
1653
|
p.x = x;
|
1654
|
p.y = y;
|
1655
|
return p;
|
1656
|
}
|
1657
|
},
|
1658
|
|
1659
|
|
1660
|
/* Mercator inverse equations--mapping x,y to lat/long
|
1661
|
--------------------------------------------------*/
|
1662
|
inverse : function(p) {
|
1663
|
|
1664
|
var x = p.x - this.x0;
|
1665
|
var y = p.y - this.y0;
|
1666
|
var lon,lat;
|
1667
|
|
1668
|
if (this.sphere) {
|
1669
|
lat = Proj4js.common.HALF_PI - 2.0 * Math.atan(Math.exp(-y / this.a * this.k0));
|
1670
|
} else {
|
1671
|
var ts = Math.exp(-y / (this.a * this.k0));
|
1672
|
lat = Proj4js.common.phi2z(this.e,ts);
|
1673
|
if(lat == -9999) {
|
1674
|
Proj4js.reportError("merc:inverse: lat = -9999");
|
1675
|
return null;
|
1676
|
}
|
1677
|
}
|
1678
|
lon = Proj4js.common.adjust_lon(this.long0+ x / (this.a * this.k0));
|
1679
|
|
1680
|
p.x = lon;
|
1681
|
p.y = lat;
|
1682
|
return p;
|
1683
|
}
|
1684
|
};
|
1685
|
|
1686
|
|
1687
|
/* ======================================================================
|
1688
|
projCode/utm.js
|
1689
|
====================================================================== */
|
1690
|
|
1691
|
/*******************************************************************************
|
1692
|
NAME TRANSVERSE MERCATOR
|
1693
|
|
1694
|
PURPOSE: Transforms input longitude and latitude to Easting and
|
1695
|
Northing for the Transverse Mercator projection. The
|
1696
|
longitude and latitude must be in radians. The Easting
|
1697
|
and Northing values will be returned in meters.
|
1698
|
|
1699
|
ALGORITHM REFERENCES
|
1700
|
|
1701
|
1. Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
|
1702
|
Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
|
1703
|
State Government Printing Office, Washington D.C., 1987.
|
1704
|
|
1705
|
2. Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
|
1706
|
U.S. Geological Survey Professional Paper 1453 , United State Government
|
1707
|
Printing Office, Washington D.C., 1989.
|
1708
|
*******************************************************************************/
|
1709
|
|
1710
|
|
1711
|
/**
|
1712
|
Initialize Transverse Mercator projection
|
1713
|
*/
|
1714
|
|
1715
|
Proj4js.Proj.utm = {
|
1716
|
dependsOn : 'tmerc',
|
1717
|
|
1718
|
init : function() {
|
1719
|
if (!this.zone) {
|
1720
|
Proj4js.reportError("utm:init: zone must be specified for UTM");
|
1721
|
return;
|
1722
|
}
|
1723
|
this.lat0 = 0.0;
|
1724
|
this.long0 = ((6 * Math.abs(this.zone)) - 183) * Proj4js.common.D2R;
|
1725
|
this.x0 = 500000.0;
|
1726
|
this.y0 = this.utmSouth ? 10000000.0 : 0.0;
|
1727
|
this.k0 = 0.9996;
|
1728
|
|
1729
|
Proj4js.Proj['tmerc'].init.apply(this);
|
1730
|
this.forward = Proj4js.Proj['tmerc'].forward;
|
1731
|
this.inverse = Proj4js.Proj['tmerc'].inverse;
|
1732
|
}
|
1733
|
};
|
1734
|
/* ======================================================================
|
1735
|
projCode/eqdc.js
|
1736
|
====================================================================== */
|
1737
|
|
1738
|
/*******************************************************************************
|
1739
|
NAME EQUIDISTANT CONIC
|
1740
|
|
1741
|
PURPOSE: Transforms input longitude and latitude to Easting and Northing
|
1742
|
for the Equidistant Conic projection. The longitude and
|
1743
|
latitude must be in radians. The Easting and Northing values
|
1744
|
will be returned in meters.
|
1745
|
|
1746
|
PROGRAMMER DATE
|
1747
|
---------- ----
|
1748
|
T. Mittan Mar, 1993
|
1749
|
|
1750
|
ALGORITHM REFERENCES
|
1751
|
|
1752
|
1. Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
|
1753
|
Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
|
1754
|
State Government Printing Office, Washington D.C., 1987.
|
1755
|
|
1756
|
2. Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
|
1757
|
U.S. Geological Survey Professional Paper 1453 , United State Government
|
1758
|
Printing Office, Washington D.C., 1989.
|
1759
|
*******************************************************************************/
|
1760
|
|
1761
|
/* Variables common to all subroutines in this code file
|
1762
|
-----------------------------------------------------*/
|
1763
|
|
1764
|
Proj4js.Proj.eqdc = {
|
1765
|
|
1766
|
/* Initialize the Equidistant Conic projection
|
1767
|
------------------------------------------*/
|
1768
|
init: function() {
|
1769
|
|
1770
|
/* Place parameters in static storage for common use
|
1771
|
-------------------------------------------------*/
|
1772
|
|
1773
|
if(!this.mode) this.mode=0;//chosen default mode
|
1774
|
this.temp = this.b / this.a;
|
1775
|
this.es = 1.0 - Math.pow(this.temp,2);
|
1776
|
this.e = Math.sqrt(this.es);
|
1777
|
this.e0 = Proj4js.common.e0fn(this.es);
|
1778
|
this.e1 = Proj4js.common.e1fn(this.es);
|
1779
|
this.e2 = Proj4js.common.e2fn(this.es);
|
1780
|
this.e3 = Proj4js.common.e3fn(this.es);
|
1781
|
|
1782
|
this.sinphi=Math.sin(this.lat1);
|
1783
|
this.cosphi=Math.cos(this.lat1);
|
1784
|
|
1785
|
this.ms1 = Proj4js.common.msfnz(this.e,this.sinphi,this.cosphi);
|
1786
|
this.ml1 = Proj4js.common.mlfn(this.e0, this.e1, this.e2,this.e3, this.lat1);
|
1787
|
|
1788
|
/* format B
|
1789
|
---------*/
|
1790
|
if (this.mode != 0) {
|
1791
|
if (Math.abs(this.lat1 + this.lat2) < Proj4js.common.EPSLN) {
|
1792
|
Proj4js.reportError("eqdc:Init:EqualLatitudes");
|
1793
|
//return(81);
|
1794
|
}
|
1795
|
this.sinphi=Math.sin(this.lat2);
|
1796
|
this.cosphi=Math.cos(this.lat2);
|
1797
|
|
1798
|
this.ms2 = Proj4js.common.msfnz(this.e,this.sinphi,this.cosphi);
|
1799
|
this.ml2 = Proj4js.common.mlfn(this.e0, this.e1, this.e2, this.e3, this.lat2);
|
1800
|
if (Math.abs(this.lat1 - this.lat2) >= Proj4js.common.EPSLN) {
|
1801
|
this.ns = (this.ms1 - this.ms2) / (this.ml2 - this.ml1);
|
1802
|
} else {
|
1803
|
this.ns = this.sinphi;
|
1804
|
}
|
1805
|
} else {
|
1806
|
this.ns = this.sinphi;
|
1807
|
}
|
1808
|
this.g = this.ml1 + this.ms1/this.ns;
|
1809
|
this.ml0 = Proj4js.common.mlfn(this.e0, this.e1,this. e2, this.e3, this.lat0);
|
1810
|
this.rh = this.a * (this.g - this.ml0);
|
1811
|
},
|
1812
|
|
1813
|
|
1814
|
/* Equidistant Conic forward equations--mapping lat,long to x,y
|
1815
|
-----------------------------------------------------------*/
|
1816
|
forward: function(p) {
|
1817
|
var lon=p.x;
|
1818
|
var lat=p.y;
|
1819
|
|
1820
|
/* Forward equations
|
1821
|
-----------------*/
|
1822
|
var ml = Proj4js.common.mlfn(this.e0, this.e1, this.e2, this.e3, lat);
|
1823
|
var rh1 = this.a * (this.g - ml);
|
1824
|
var theta = this.ns * Proj4js.common.adjust_lon(lon - this.long0);
|
1825
|
|
1826
|
var x = this.x0 + rh1 * Math.sin(theta);
|
1827
|
var y = this.y0 + this.rh - rh1 * Math.cos(theta);
|
1828
|
p.x=x;
|
1829
|
p.y=y;
|
1830
|
return p;
|
1831
|
},
|
1832
|
|
1833
|
/* Inverse equations
|
1834
|
-----------------*/
|
1835
|
inverse: function(p) {
|
1836
|
p.x -= this.x0;
|
1837
|
p.y = this.rh - p.y + this.y0;
|
1838
|
var con, rh1;
|
1839
|
if (this.ns >= 0) {
|
1840
|
var rh1 = Math.sqrt(p.x *p.x + p.y * p.y);
|
1841
|
var con = 1.0;
|
1842
|
} else {
|
1843
|
rh1 = -Math.sqrt(p.x *p. x +p. y * p.y);
|
1844
|
con = -1.0;
|
1845
|
}
|
1846
|
var theta = 0.0;
|
1847
|
if (rh1 != 0.0) theta = Math.atan2(con *p.x, con *p.y);
|
1848
|
var ml = this.g - rh1 /this.a;
|
1849
|
var lat = this.phi3z(this.ml,this.e0,this.e1,this.e2,this.e3);
|
1850
|
var lon = Proj4js.common.adjust_lon(this.long0 + theta / this.ns);
|
1851
|
|
1852
|
p.x=lon;
|
1853
|
p.y=lat;
|
1854
|
return p;
|
1855
|
},
|
1856
|
|
1857
|
/* Function to compute latitude, phi3, for the inverse of the Equidistant
|
1858
|
Conic projection.
|
1859
|
-----------------------------------------------------------------*/
|
1860
|
phi3z: function(ml,e0,e1,e2,e3) {
|
1861
|
var phi;
|
1862
|
var dphi;
|
1863
|
|
1864
|
phi = ml;
|
1865
|
for (var i = 0; i < 15; i++) {
|
1866
|
dphi = (ml + e1 * Math.sin(2.0 * phi) - e2 * Math.sin(4.0 * phi) + e3 * Math.sin(6.0 * phi))/ e0 - phi;
|
1867
|
phi += dphi;
|
1868
|
if (Math.abs(dphi) <= .0000000001) {
|
1869
|
return phi;
|
1870
|
}
|
1871
|
}
|
1872
|
Proj4js.reportError("PHI3Z-CONV:Latitude failed to converge after 15 iterations");
|
1873
|
return null;
|
1874
|
}
|
1875
|
|
1876
|
|
1877
|
};
|
1878
|
/* ======================================================================
|
1879
|
projCode/tmerc.js
|
1880
|
====================================================================== */
|
1881
|
|
1882
|
/*******************************************************************************
|
1883
|
NAME TRANSVERSE MERCATOR
|
1884
|
|
1885
|
PURPOSE: Transforms input longitude and latitude to Easting and
|
1886
|
Northing for the Transverse Mercator projection. The
|
1887
|
longitude and latitude must be in radians. The Easting
|
1888
|
and Northing values will be returned in meters.
|
1889
|
|
1890
|
ALGORITHM REFERENCES
|
1891
|
|
1892
|
1. Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
|
1893
|
Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
|
1894
|
State Government Printing Office, Washington D.C., 1987.
|
1895
|
|
1896
|
2. Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
|
1897
|
U.S. Geological Survey Professional Paper 1453 , United State Government
|
1898
|
Printing Office, Washington D.C., 1989.
|
1899
|
*******************************************************************************/
|
1900
|
|
1901
|
|
1902
|
/**
|
1903
|
Initialize Transverse Mercator projection
|
1904
|
*/
|
1905
|
|
1906
|
Proj4js.Proj.tmerc = {
|
1907
|
init : function() {
|
1908
|
this.e0 = Proj4js.common.e0fn(this.es);
|
1909
|
this.e1 = Proj4js.common.e1fn(this.es);
|
1910
|
this.e2 = Proj4js.common.e2fn(this.es);
|
1911
|
this.e3 = Proj4js.common.e3fn(this.es);
|
1912
|
this.ml0 = this.a * Proj4js.common.mlfn(this.e0, this.e1, this.e2, this.e3, this.lat0);
|
1913
|
},
|
1914
|
|
1915
|
/**
|
1916
|
Transverse Mercator Forward - long/lat to x/y
|
1917
|
long/lat in radians
|
1918
|
*/
|
1919
|
forward : function(p) {
|
1920
|
var lon = p.x;
|
1921
|
var lat = p.y;
|
1922
|
|
1923
|
var delta_lon = Proj4js.common.adjust_lon(lon - this.long0); // Delta longitude
|
1924
|
var con; // cone constant
|
1925
|
var x, y;
|
1926
|
var sin_phi=Math.sin(lat);
|
1927
|
var cos_phi=Math.cos(lat);
|
1928
|
|
1929
|
if (this.sphere) { /* spherical form */
|
1930
|
var b = cos_phi * Math.sin(delta_lon);
|
1931
|
if ((Math.abs(Math.abs(b) - 1.0)) < .0000000001) {
|
1932
|
Proj4js.reportError("tmerc:forward: Point projects into infinity");
|
1933
|
return(93);
|
1934
|
} else {
|
1935
|
x = .5 * this.a * this.k0 * Math.log((1.0 + b)/(1.0 - b));
|
1936
|
con = Math.acos(cos_phi * Math.cos(delta_lon)/Math.sqrt(1.0 - b*b));
|
1937
|
if (lat < 0) con = - con;
|
1938
|
y = this.a * this.k0 * (con - this.lat0);
|
1939
|
}
|
1940
|
} else {
|
1941
|
var al = cos_phi * delta_lon;
|
1942
|
var als = Math.pow(al,2);
|
1943
|
var c = this.ep2 * Math.pow(cos_phi,2);
|
1944
|
var tq = Math.tan(lat);
|
1945
|
var t = Math.pow(tq,2);
|
1946
|
con = 1.0 - this.es * Math.pow(sin_phi,2);
|
1947
|
var n = this.a / Math.sqrt(con);
|
1948
|
var ml = this.a * Proj4js.common.mlfn(this.e0, this.e1, this.e2, this.e3, lat);
|
1949
|
|
1950
|
x = this.k0 * n * al * (1.0 + als / 6.0 * (1.0 - t + c + als / 20.0 * (5.0 - 18.0 * t + Math.pow(t,2) + 72.0 * c - 58.0 * this.ep2))) + this.x0;
|
1951
|
y = this.k0 * (ml - this.ml0 + n * tq * (als * (0.5 + als / 24.0 * (5.0 - t + 9.0 * c + 4.0 * Math.pow(c,2) + als / 30.0 * (61.0 - 58.0 * t + Math.pow(t,2) + 600.0 * c - 330.0 * this.ep2))))) + this.y0;
|
1952
|
|
1953
|
}
|
1954
|
p.x = x; p.y = y;
|
1955
|
return p;
|
1956
|
}, // tmercFwd()
|
1957
|
|
1958
|
/**
|
1959
|
Transverse Mercator Inverse - x/y to long/lat
|
1960
|
*/
|
1961
|
inverse : function(p) {
|
1962
|
var con, phi; /* temporary angles */
|
1963
|
var delta_phi; /* difference between longitudes */
|
1964
|
var i;
|
1965
|
var max_iter = 6; /* maximun number of iterations */
|
1966
|
var lat, lon;
|
1967
|
|
1968
|
if (this.sphere) { /* spherical form */
|
1969
|
var f = Math.exp(p.x/(this.a * this.k0));
|
1970
|
var g = .5 * (f - 1/f);
|
1971
|
var temp = this.lat0 + p.y/(this.a * this.k0);
|
1972
|
var h = Math.cos(temp);
|
1973
|
con = Math.sqrt((1.0 - h * h)/(1.0 + g * g));
|
1974
|
lat = Math.asinz(con);
|
1975
|
if (temp < 0)
|
1976
|
lat = -lat;
|
1977
|
if ((g == 0) && (h == 0)) {
|
1978
|
lon = this.long0;
|
1979
|
} else {
|
1980
|
lon = Proj4js.common.adjust_lon(Math.atan2(g,h) + this.long0);
|
1981
|
}
|
1982
|
} else { // ellipsoidal form
|
1983
|
var x = p.x - this.x0;
|
1984
|
var y = p.y - this.y0;
|
1985
|
|
1986
|
con = (this.ml0 + y / this.k0) / this.a;
|
1987
|
phi = con;
|
1988
|
for (i=0;;i++) {
|
1989
|
delta_phi=((con + this.e1 * Math.sin(2.0*phi) - this.e2 * Math.sin(4.0*phi) + this.e3 * Math.sin(6.0*phi)) / this.e0) - phi;
|
1990
|
phi += delta_phi;
|
1991
|
if (Math.abs(delta_phi) <= Proj4js.common.EPSLN) break;
|
1992
|
if (i >= max_iter) {
|
1993
|
Proj4js.reportError("tmerc:inverse: Latitude failed to converge");
|
1994
|
return(95);
|
1995
|
}
|
1996
|
} // for()
|
1997
|
if (Math.abs(phi) < Proj4js.common.HALF_PI) {
|
1998
|
// sincos(phi, &sin_phi, &cos_phi);
|
1999
|
var sin_phi=Math.sin(phi);
|
2000
|
var cos_phi=Math.cos(phi);
|
2001
|
var tan_phi = Math.tan(phi);
|
2002
|
var c = this.ep2 * Math.pow(cos_phi,2);
|
2003
|
var cs = Math.pow(c,2);
|
2004
|
var t = Math.pow(tan_phi,2);
|
2005
|
var ts = Math.pow(t,2);
|
2006
|
con = 1.0 - this.es * Math.pow(sin_phi,2);
|
2007
|
var n = this.a / Math.sqrt(con);
|
2008
|
var r = n * (1.0 - this.es) / con;
|
2009
|
var d = x / (n * this.k0);
|
2010
|
var ds = Math.pow(d,2);
|
2011
|
lat = phi - (n * tan_phi * ds / r) * (0.5 - ds / 24.0 * (5.0 + 3.0 * t + 10.0 * c - 4.0 * cs - 9.0 * this.ep2 - ds / 30.0 * (61.0 + 90.0 * t + 298.0 * c + 45.0 * ts - 252.0 * this.ep2 - 3.0 * cs)));
|
2012
|
lon = Proj4js.common.adjust_lon(this.long0 + (d * (1.0 - ds / 6.0 * (1.0 + 2.0 * t + c - ds / 20.0 * (5.0 - 2.0 * c + 28.0 * t - 3.0 * cs + 8.0 * this.ep2 + 24.0 * ts))) / cos_phi));
|
2013
|
} else {
|
2014
|
lat = Proj4js.common.HALF_PI * Proj4js.common.sign(y);
|
2015
|
lon = this.long0;
|
2016
|
}
|
2017
|
}
|
2018
|
p.x = lon;
|
2019
|
p.y = lat;
|
2020
|
return p;
|
2021
|
} // tmercInv()
|
2022
|
};
|
2023
|
/* ======================================================================
|
2024
|
defs/GOOGLE.js
|
2025
|
====================================================================== */
|
2026
|
|
2027
|
Proj4js.defs["GOOGLE"]="+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs";
|
2028
|
Proj4js.defs["EPSG:900913"]=Proj4js.defs["GOOGLE"];
|
2029
|
/* ======================================================================
|
2030
|
projCode/ortho.js
|
2031
|
====================================================================== */
|
2032
|
|
2033
|
/*******************************************************************************
|
2034
|
NAME ORTHOGRAPHIC
|
2035
|
|
2036
|
PURPOSE: Transforms input longitude and latitude to Easting and
|
2037
|
Northing for the Orthographic projection. The
|
2038
|
longitude and latitude must be in radians. The Easting
|
2039
|
and Northing values will be returned in meters.
|
2040
|
|
2041
|
PROGRAMMER DATE
|
2042
|
---------- ----
|
2043
|
T. Mittan Mar, 1993
|
2044
|
|
2045
|
ALGORITHM REFERENCES
|
2046
|
|
2047
|
1. Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
|
2048
|
Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
|
2049
|
State Government Printing Office, Washington D.C., 1987.
|
2050
|
|
2051
|
2. Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
|
2052
|
U.S. Geological Survey Professional Paper 1453 , United State Government
|
2053
|
Printing Office, Washington D.C., 1989.
|
2054
|
*******************************************************************************/
|
2055
|
|
2056
|
Proj4js.Proj.ortho = {
|
2057
|
|
2058
|
/* Initialize the Orthographic projection
|
2059
|
-------------------------------------*/
|
2060
|
init: function(def) {
|
2061
|
//double temp; /* temporary variable */
|
2062
|
|
2063
|
/* Place parameters in static storage for common use
|
2064
|
-------------------------------------------------*/;
|
2065
|
this.sin_p14=Math.sin(this.lat0);
|
2066
|
this.cos_p14=Math.cos(this.lat0);
|
2067
|
},
|
2068
|
|
2069
|
|
2070
|
/* Orthographic forward equations--mapping lat,long to x,y
|
2071
|
---------------------------------------------------*/
|
2072
|
forward: function(p) {
|
2073
|
var sinphi, cosphi; /* sin and cos value */
|
2074
|
var dlon; /* delta longitude value */
|
2075
|
var coslon; /* cos of longitude */
|
2076
|
var ksp; /* scale factor */
|
2077
|
var g;
|
2078
|
var lon=p.x;
|
2079
|
var lat=p.y;
|
2080
|
/* Forward equations
|
2081
|
-----------------*/
|
2082
|
dlon = Proj4js.common.adjust_lon(lon - this.long0);
|
2083
|
|
2084
|
sinphi=Math.sin(lat);
|
2085
|
cosphi=Math.cos(lat);
|
2086
|
|
2087
|
coslon = Math.cos(dlon);
|
2088
|
g = this.sin_p14 * sinphi + this.cos_p14 * cosphi * coslon;
|
2089
|
ksp = 1.0;
|
2090
|
if ((g > 0) || (Math.abs(g) <= Proj4js.common.EPSLN)) {
|
2091
|
var x = this.a * ksp * cosphi * Math.sin(dlon);
|
2092
|
var y = this.y0 + this.a * ksp * (this.cos_p14 * sinphi - this.sin_p14 * cosphi * coslon);
|
2093
|
} else {
|
2094
|
Proj4js.reportError("orthoFwdPointError");
|
2095
|
}
|
2096
|
p.x=x;
|
2097
|
p.y=y;
|
2098
|
return p;
|
2099
|
},
|
2100
|
|
2101
|
|
2102
|
inverse: function(p) {
|
2103
|
var rh; /* height above ellipsoid */
|
2104
|
var z; /* angle */
|
2105
|
var sinz,cosz; /* sin of z and cos of z */
|
2106
|
var temp;
|
2107
|
var con;
|
2108
|
var lon , lat;
|
2109
|
/* Inverse equations
|
2110
|
-----------------*/
|
2111
|
p.x -= this.x0;
|
2112
|
p.y -= this.y0;
|
2113
|
rh = Math.sqrt(p.x * p.x + p.y * p.y);
|
2114
|
if (rh > this.a + .0000001) {
|
2115
|
Proj4js.reportError("orthoInvDataError");
|
2116
|
}
|
2117
|
z = Proj4js.common.asinz(rh / this.a);
|
2118
|
|
2119
|
sinz=Math.sin(z);
|
2120
|
cosi=Math.cos(z);
|
2121
|
|
2122
|
lon = this.long0;
|
2123
|
if (Math.abs(rh) <= Proj4js.common.EPSLN) {
|
2124
|
lat = this.lat0;
|
2125
|
}
|
2126
|
lat = Proj4js.common.asinz(cosz * this.sin_p14 + (y * sinz * this.cos_p14)/rh);
|
2127
|
con = Math.abs(lat0) - Proj4js.common.HALF_PI;
|
2128
|
if (Math.abs(con) <= Proj4js.common.EPSLN) {
|
2129
|
if (this.lat0 >= 0) {
|
2130
|
lon = Proj4js.common.adjust_lon(this.long0 + Math.atan2(p.x, -p.y));
|
2131
|
} else {
|
2132
|
lon = Proj4js.common.adjust_lon(this.long0 -Math.atan2(-p.x, p.y));
|
2133
|
}
|
2134
|
}
|
2135
|
con = cosz - this.sin_p14 * Math.sin(lat);
|
2136
|
if ((Math.abs(con) >= Proj4js.common.EPSLN) || (Math.abs(x) >= Proj4js.common.EPSLN)) {
|
2137
|
lon = Proj4js.common.adjust_lon(this.long0 + Math.atan2((p.x * sinz * this.cos_p14), (con * rh)));
|
2138
|
}
|
2139
|
p.x=lon;
|
2140
|
p.y=lat;
|
2141
|
return p;
|
2142
|
}
|
2143
|
};
|
2144
|
|
2145
|
|
2146
|
/* ======================================================================
|
2147
|
projCode/stere.js
|
2148
|
====================================================================== */
|
2149
|
|
2150
|
|
2151
|
// Initialize the Stereographic projection
|
2152
|
|
2153
|
Proj4js.Proj.stere = {
|
2154
|
ssfn_: function(phit, sinphi, eccen) {
|
2155
|
sinphi *= eccen;
|
2156
|
return (Math.tan (.5 * (Proj4js.common.HALF_PI + phit)) * Math.pow((1. - sinphi) / (1. + sinphi), .5 * eccen));
|
2157
|
},
|
2158
|
TOL: 1.e-8,
|
2159
|
NITER: 8,
|
2160
|
CONV: 1.e-10,
|
2161
|
S_POLE: 0,
|
2162
|
N_POLE: 1,
|
2163
|
OBLIQ: 2,
|
2164
|
EQUIT: 3,
|
2165
|
|
2166
|
init : function() {
|
2167
|
this.phits = this.lat_ts ? this.lat_ts : Proj4js.common.HALF_PI;
|
2168
|
var t = Math.abs(this.lat0);
|
2169
|
if ((Math.abs(t) - Proj4js.common.HALF_PI) < Proj4js.common.EPSLN) {
|
2170
|
this.mode = this.lat0 < 0. ? this.S_POLE : this.N_POLE;
|
2171
|
} else {
|
2172
|
this.mode = t > Proj4js.common.EPSLN ? this.OBLIQ : this.EQUIT;
|
2173
|
}
|
2174
|
this.phits = Math.abs(this.phits);
|
2175
|
if (this.es) {
|
2176
|
var X;
|
2177
|
|
2178
|
switch (this.mode) {
|
2179
|
case this.N_POLE:
|
2180
|
case this.S_POLE:
|
2181
|
if (Math.abs(this.phits - Proj4js.common.HALF_PI) < Proj4js.common.EPSLN) {
|
2182
|
this.akm1 = 2. * this.k0 / Math.sqrt(Math.pow(1+this.e,1+this.e)*Math.pow(1-this.e,1-this.e));
|
2183
|
} else {
|
2184
|
t = Math.sin(this.phits);
|
2185
|
this.akm1 = Math.cos(this.phits) / Proj4js.common.tsfnz(this.e, this.phits, t);
|
2186
|
t *= this.e;
|
2187
|
this.akm1 /= Math.sqrt(1. - t * t);
|
2188
|
}
|
2189
|
break;
|
2190
|
case this.EQUIT:
|
2191
|
this.akm1 = 2. * this.k0;
|
2192
|
break;
|
2193
|
case this.OBLIQ:
|
2194
|
t = Math.sin(this.lat0);
|
2195
|
X = 2. * Math.atan(this.ssfn_(this.lat0, t, this.e)) - Proj4js.common.HALF_PI;
|
2196
|
t *= this.e;
|
2197
|
this.akm1 = 2. * this.k0 * Math.cos(this.lat0) / Math.sqrt(1. - t * t);
|
2198
|
this.sinX1 = Math.sin(X);
|
2199
|
this.cosX1 = Math.cos(X);
|
2200
|
break;
|
2201
|
}
|
2202
|
} else {
|
2203
|
switch (this.mode) {
|
2204
|
case this.OBLIQ:
|
2205
|
this.sinph0 = Math.sin(this.lat0);
|
2206
|
this.cosph0 = Math.cos(this.lat0);
|
2207
|
case this.EQUIT:
|
2208
|
this.akm1 = 2. * this.k0;
|
2209
|
break;
|
2210
|
case this.S_POLE:
|
2211
|
case this.N_POLE:
|
2212
|
this.akm1 = Math.abs(this.phits - Proj4js.common.HALF_PI) >= Proj4js.common.EPSLN ?
|
2213
|
Math.cos(this.phits) / Math.tan(Proj4js.common.FORTPI - .5 * this.phits) :
|
2214
|
2. * this.k0 ;
|
2215
|
break;
|
2216
|
}
|
2217
|
}
|
2218
|
},
|
2219
|
|
2220
|
// Stereographic forward equations--mapping lat,long to x,y
|
2221
|
forward: function(p) {
|
2222
|
var lon = p.x;
|
2223
|
var lat = p.y;
|
2224
|
var x, y
|
2225
|
|
2226
|
if (this.sphere) {
|
2227
|
var sinphi, cosphi, coslam, sinlam;
|
2228
|
|
2229
|
sinphi = Math.sin(lat);
|
2230
|
cosphi = Math.cos(lat);
|
2231
|
coslam = Math.cos(lon);
|
2232
|
sinlam = Math.sin(lon);
|
2233
|
switch (this.mode) {
|
2234
|
case this.EQUIT:
|
2235
|
y = 1. + cosphi * coslam;
|
2236
|
if (y <= Proj4js.common.EPSLN) {
|
2237
|
F_ERROR;
|
2238
|
}
|
2239
|
y = this.akm1 / y;
|
2240
|
x = y * cosphi * sinlam;
|
2241
|
y *= sinphi;
|
2242
|
break;
|
2243
|
case this.OBLIQ:
|
2244
|
y = 1. + this.sinph0 * sinphi + this.cosph0 * cosphi * coslam;
|
2245
|
if (y <= Proj4js.common.EPSLN) {
|
2246
|
F_ERROR;
|
2247
|
}
|
2248
|
y = this.akm1 / y;
|
2249
|
x = y * cosphi * sinlam;
|
2250
|
y *= this.cosph0 * sinphi - this.sinph0 * cosphi * coslam;
|
2251
|
break;
|
2252
|
case this.N_POLE:
|
2253
|
coslam = -coslam;
|
2254
|
lat = -lat;
|
2255
|
//Note: no break here so it conitnues through S_POLE
|
2256
|
case this.S_POLE:
|
2257
|
if (Math.abs(lat - Proj4js.common.HALF_PI) < this.TOL) {
|
2258
|
F_ERROR;
|
2259
|
}
|
2260
|
y = this.akm1 * Math.tan(Proj4js.common.FORTPI + .5 * lat)
|
2261
|
x = sinlam * y;
|
2262
|
y *= coslam;
|
2263
|
break;
|
2264
|
}
|
2265
|
} else {
|
2266
|
coslam = Math.cos(lon);
|
2267
|
sinlam = Math.sin(lon);
|
2268
|
sinphi = Math.sin(lat);
|
2269
|
if (this.mode == this.OBLIQ || this.mode == this.EQUIT) {
|
2270
|
X = 2. * Math.atan(this.ssfn_(lat, sinphi, this.e));
|
2271
|
sinX = Math.sin(X - Proj4js.common.HALF_PI);
|
2272
|
cosX = Math.cos(X);
|
2273
|
}
|
2274
|
switch (this.mode) {
|
2275
|
case this.OBLIQ:
|
2276
|
A = this.akm1 / (this.cosX1 * (1. + this.sinX1 * sinX + this.cosX1 * cosX * coslam));
|
2277
|
y = A * (this.cosX1 * sinX - this.sinX1 * cosX * coslam);
|
2278
|
x = A * cosX;
|
2279
|
break;
|
2280
|
case this.EQUIT:
|
2281
|
A = 2. * this.akm1 / (1. + cosX * coslam);
|
2282
|
y = A * sinX;
|
2283
|
x = A * cosX;
|
2284
|
break;
|
2285
|
case this.S_POLE:
|
2286
|
lat = -lat;
|
2287
|
coslam = - coslam;
|
2288
|
sinphi = -sinphi;
|
2289
|
case this.N_POLE:
|
2290
|
x = this.akm1 * Proj4js.common.tsfnz(this.e, lat, sinphi);
|
2291
|
y = - x * coslam;
|
2292
|
break;
|
2293
|
}
|
2294
|
x = x * sinlam;
|
2295
|
}
|
2296
|
p.x = x*this.a + this.x0;
|
2297
|
p.y = y*this.a + this.y0;
|
2298
|
return p;
|
2299
|
},
|
2300
|
|
2301
|
|
2302
|
//* Stereographic inverse equations--mapping x,y to lat/long
|
2303
|
inverse: function(p) {
|
2304
|
var x = (p.x - this.x0)/this.a; /* descale and de-offset */
|
2305
|
var y = (p.y - this.y0)/this.a;
|
2306
|
var lon, lat
|
2307
|
|
2308
|
var cosphi, sinphi, tp=0.0, phi_l=0.0, rho, halfe=0.0, pi2=0.0;
|
2309
|
var i;
|
2310
|
|
2311
|
if (this.sphere) {
|
2312
|
var c, rh, sinc, cosc;
|
2313
|
|
2314
|
rh = Math.sqrt(x*x + y*y);
|
2315
|
c = 2. * Math.atan(rh / this.akm1);
|
2316
|
sinc = Math.sin(c);
|
2317
|
cosc = Math.cos(c);
|
2318
|
lon = 0.;
|
2319
|
switch (this.mode) {
|
2320
|
case this.EQUIT:
|
2321
|
if (Math.abs(rh) <= Proj4js.common.EPSLN) {
|
2322
|
lat = 0.;
|
2323
|
} else {
|
2324
|
lat = Math.asin(y * sinc / rh);
|
2325
|
}
|
2326
|
if (cosc != 0. || x != 0.) lon = Math.atan2(x * sinc, cosc * rh);
|
2327
|
break;
|
2328
|
case this.OBLIQ:
|
2329
|
if (Math.abs(rh) <= Proj4js.common.EPSLN) {
|
2330
|
lat = this.phi0;
|
2331
|
} else {
|
2332
|
lat = Math.asin(cosc * sinph0 + y * sinc * cosph0 / rh);
|
2333
|
}
|
2334
|
c = cosc - sinph0 * Math.sin(lat);
|
2335
|
if (c != 0. || x != 0.) {
|
2336
|
lon = Math.atan2(x * sinc * cosph0, c * rh);
|
2337
|
}
|
2338
|
break;
|
2339
|
case this.N_POLE:
|
2340
|
y = -y;
|
2341
|
case this.S_POLE:
|
2342
|
if (Math.abs(rh) <= Proj4js.common.EPSLN) {
|
2343
|
lat = this.phi0;
|
2344
|
} else {
|
2345
|
lat = Math.asin(this.mode == this.S_POLE ? -cosc : cosc);
|
2346
|
}
|
2347
|
lon = (x == 0. && y == 0.) ? 0. : Math.atan2(x, y);
|
2348
|
break;
|
2349
|
}
|
2350
|
} else {
|
2351
|
rho = Math.sqrt(x*x + y*y);
|
2352
|
switch (this.mode) {
|
2353
|
case this.OBLIQ:
|
2354
|
case this.EQUIT:
|
2355
|
tp = 2. * Math.atan2(rho * this.cosX1 , this.akm1);
|
2356
|
cosphi = Math.cos(tp);
|
2357
|
sinphi = Math.sin(tp);
|
2358
|
if( rho == 0.0 ) {
|
2359
|
phi_l = Math.asin(cosphi * this.sinX1);
|
2360
|
} else {
|
2361
|
phi_l = Math.asin(cosphi * this.sinX1 + (y * sinphi * this.cosX1 / rho));
|
2362
|
}
|
2363
|
|
2364
|
tp = Math.tan(.5 * (Proj4js.common.HALF_PI + phi_l));
|
2365
|
x *= sinphi;
|
2366
|
y = rho * this.cosX1 * cosphi - y * this.sinX1* sinphi;
|
2367
|
pi2 = Proj4js.common.HALF_PI;
|
2368
|
halfe = .5 * this.e;
|
2369
|
break;
|
2370
|
case this.N_POLE:
|
2371
|
y = -y;
|
2372
|
case this.S_POLE:
|
2373
|
tp = - rho / this.akm1
|
2374
|
phi_l = Proj4js.common.HALF_PI - 2. * Math.atan(tp);
|
2375
|
pi2 = -Proj4js.common.HALF_PI;
|
2376
|
halfe = -.5 * this.e;
|
2377
|
break;
|
2378
|
}
|
2379
|
for (i = this.NITER; i--; phi_l = lat) { //check this
|
2380
|
sinphi = this.e * Math.sin(phi_l);
|
2381
|
lat = 2. * Math.atan(tp * Math.pow((1.+sinphi)/(1.-sinphi), halfe)) - pi2;
|
2382
|
if (Math.abs(phi_l - lat) < this.CONV) {
|
2383
|
if (this.mode == this.S_POLE) lat = -lat;
|
2384
|
lon = (x == 0. && y == 0.) ? 0. : Math.atan2(x, y);
|
2385
|
p.x = lon;
|
2386
|
p.y = lat
|
2387
|
return p;
|
2388
|
}
|
2389
|
}
|
2390
|
}
|
2391
|
}
|
2392
|
};
|
2393
|
/* ======================================================================
|
2394
|
projCode/mill.js
|
2395
|
====================================================================== */
|
2396
|
|
2397
|
/*******************************************************************************
|
2398
|
NAME MILLER CYLINDRICAL
|
2399
|
|
2400
|
PURPOSE: Transforms input longitude and latitude to Easting and
|
2401
|
Northing for the Miller Cylindrical projection. The
|
2402
|
longitude and latitude must be in radians. The Easting
|
2403
|
and Northing values will be returned in meters.
|
2404
|
|
2405
|
PROGRAMMER DATE
|
2406
|
---------- ----
|
2407
|
T. Mittan March, 1993
|
2408
|
|
2409
|
This function was adapted from the Lambert Azimuthal Equal Area projection
|
2410
|
code (FORTRAN) in the General Cartographic Transformation Package software
|
2411
|
which is available from the U.S. Geological Survey National Mapping Division.
|
2412
|
|
2413
|
ALGORITHM REFERENCES
|
2414
|
|
2415
|
1. "New Equal-Area Map Projections for Noncircular Regions", John P. Snyder,
|
2416
|
The American Cartographer, Vol 15, No. 4, October 1988, pp. 341-355.
|
2417
|
|
2418
|
2. Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
|
2419
|
Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
|
2420
|
State Government Printing Office, Washington D.C., 1987.
|
2421
|
|
2422
|
3. "Software Documentation for GCTP General Cartographic Transformation
|
2423
|
Package", U.S. Geological Survey National Mapping Division, May 1982.
|
2424
|
*******************************************************************************/
|
2425
|
|
2426
|
Proj4js.Proj.mill = {
|
2427
|
|
2428
|
/* Initialize the Miller Cylindrical projection
|
2429
|
-------------------------------------------*/
|
2430
|
init: function() {
|
2431
|
//no-op
|
2432
|
},
|
2433
|
|
2434
|
|
2435
|
/* Miller Cylindrical forward equations--mapping lat,long to x,y
|
2436
|
------------------------------------------------------------*/
|
2437
|
forward: function(p) {
|
2438
|
var lon=p.x;
|
2439
|
var lat=p.y;
|
2440
|
/* Forward equations
|
2441
|
-----------------*/
|
2442
|
dlon = Proj4js.common.adjust_lon(lon -this.long0);
|
2443
|
var x = this.x0 +this.R * dlon;
|
2444
|
var y = this.y0 + this.R *Math.log(Math.tan((Proj4js.common.PI / 4.0) + (lat / 2.5))) * 1.25;
|
2445
|
|
2446
|
p.x=x;
|
2447
|
p.y=y;
|
2448
|
return p;
|
2449
|
},//millFwd()
|
2450
|
|
2451
|
/* Miller Cylindrical inverse equations--mapping x,y to lat/long
|
2452
|
------------------------------------------------------------*/
|
2453
|
inverse: function(p) {
|
2454
|
p. x -= this.x0;
|
2455
|
p. y -= this.y0;
|
2456
|
|
2457
|
var lon = Proj4js.common.adjust_lon(this.long0 + p.x /this.R);
|
2458
|
var lat = 2.5 * (Math.atan(Math.exp(p.y/ this.R / 1.25)) - Proj4js.common.PI / 4.0);
|
2459
|
|
2460
|
p.x=lon;
|
2461
|
p.y=lat;
|
2462
|
return p;
|
2463
|
}//millInv()
|
2464
|
};
|
2465
|
/* ======================================================================
|
2466
|
projCode/sinu.js
|
2467
|
====================================================================== */
|
2468
|
|
2469
|
/*******************************************************************************
|
2470
|
NAME SINUSOIDAL
|
2471
|
|
2472
|
PURPOSE: Transforms input longitude and latitude to Easting and
|
2473
|
Northing for the Sinusoidal projection. The
|
2474
|
longitude and latitude must be in radians. The Easting
|
2475
|
and Northing values will be returned in meters.
|
2476
|
|
2477
|
PROGRAMMER DATE
|
2478
|
---------- ----
|
2479
|
D. Steinwand, EROS May, 1991
|
2480
|
|
2481
|
This function was adapted from the Sinusoidal projection code (FORTRAN) in the
|
2482
|
General Cartographic Transformation Package software which is available from
|
2483
|
the U.S. Geological Survey National Mapping Division.
|
2484
|
|
2485
|
ALGORITHM REFERENCES
|
2486
|
|
2487
|
1. Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
|
2488
|
Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
|
2489
|
State Government Printing Office, Washington D.C., 1987.
|
2490
|
|
2491
|
2. "Software Documentation for GCTP General Cartographic Transformation
|
2492
|
Package", U.S. Geological Survey National Mapping Division, May 1982.
|
2493
|
*******************************************************************************/
|
2494
|
|
2495
|
Proj4js.Proj.sinu = {
|
2496
|
|
2497
|
/* Initialize the Sinusoidal projection
|
2498
|
------------------------------------*/
|
2499
|
init: function() {
|
2500
|
/* Place parameters in static storage for common use
|
2501
|
-------------------------------------------------*/
|
2502
|
this.R = 6370997.0; //Radius of earth
|
2503
|
},
|
2504
|
|
2505
|
/* Sinusoidal forward equations--mapping lat,long to x,y
|
2506
|
-----------------------------------------------------*/
|
2507
|
forward: function(p) {
|
2508
|
var x,y,delta_lon;
|
2509
|
var lon=p.x;
|
2510
|
var lat=p.y;
|
2511
|
/* Forward equations
|
2512
|
-----------------*/
|
2513
|
delta_lon = Proj4js.common.adjust_lon(lon - this.long0);
|
2514
|
x = this.R * delta_lon * Math.cos(lat) + this.x0;
|
2515
|
y = this.R * lat + this.y0;
|
2516
|
|
2517
|
p.x=x;
|
2518
|
p.y=y;
|
2519
|
return p;
|
2520
|
},
|
2521
|
|
2522
|
inverse: function(p) {
|
2523
|
var lat,temp,lon;
|
2524
|
|
2525
|
/* Inverse equations
|
2526
|
-----------------*/
|
2527
|
p.x -= this.x0;
|
2528
|
p.y -= this.y0;
|
2529
|
lat = p.y / this.R;
|
2530
|
if (Math.abs(lat) > Proj4js.common.HALF_PI) {
|
2531
|
Proj4js.reportError("sinu:Inv:DataError");
|
2532
|
}
|
2533
|
temp = Math.abs(lat) - Proj4js.common.HALF_PI;
|
2534
|
if (Math.abs(temp) > Proj4js.common.EPSLN) {
|
2535
|
temp = this.long0+ p.x / (this.R *Math.cos(lat));
|
2536
|
lon = Proj4js.common.adjust_lon(temp);
|
2537
|
} else {
|
2538
|
lon = this.long0;
|
2539
|
}
|
2540
|
|
2541
|
p.x=lon;
|
2542
|
p.y=lat;
|
2543
|
return p;
|
2544
|
}
|
2545
|
};
|
2546
|
|
2547
|
|
2548
|
/* ======================================================================
|
2549
|
projCode/geocent.js
|
2550
|
====================================================================== */
|
2551
|
|
2552
|
/*
|
2553
|
Author: Richard Greenwood rich@greenwoodmap.com
|
2554
|
License: LGPL as per: http://www.gnu.org/copyleft/lesser.html
|
2555
|
*/
|
2556
|
|
2557
|
/**
|
2558
|
* convert between geodetic coordinates (longitude, latitude, height)
|
2559
|
* and gecentric coordinates (X, Y, Z)
|
2560
|
* ported from Proj 4.9.9 geocent.c
|
2561
|
*/
|
2562
|
|
2563
|
|
2564
|
// following constants #define'd in geocent.h
|
2565
|
// var GEOCENT_NO_ERROR = 0x0000;
|
2566
|
var GEOCENT_LAT_ERROR = 0x0001;
|
2567
|
// var GEOCENT_LON_ERROR = 0x0002;
|
2568
|
// var cs.a_ERROR = 0x0004;
|
2569
|
// var cs.b_ERROR = 0x0008;
|
2570
|
// var cs.a_LESS_B_ERROR = 0x0010;
|
2571
|
|
2572
|
// following constants from geocent.c
|
2573
|
var COS_67P5 = 0.38268343236508977; /* cosine of 67.5 degrees */
|
2574
|
var AD_C = 1.0026000; /* Toms region 1 constant */
|
2575
|
|
2576
|
function cs_geodetic_to_geocentric (cs, p) {
|
2577
|
|
2578
|
/*
|
2579
|
* The function Convert_Geodetic_To_Geocentric converts geodetic coordinates
|
2580
|
* (latitude, longitude, and height) to geocentric coordinates (X, Y, Z),
|
2581
|
* according to the current ellipsoid parameters.
|
2582
|
*
|
2583
|
* Latitude : Geodetic latitude in radians (input)
|
2584
|
* Longitude : Geodetic longitude in radians (input)
|
2585
|
* Height : Geodetic height, in meters (input)
|
2586
|
* X : Calculated Geocentric X coordinate, in meters (output)
|
2587
|
* Y : Calculated Geocentric Y coordinate, in meters (output)
|
2588
|
* Z : Calculated Geocentric Z coordinate, in meters (output)
|
2589
|
*
|
2590
|
*/
|
2591
|
|
2592
|
var Longitude = p.x;
|
2593
|
var Latitude = p.y;
|
2594
|
var Height = p.z;
|
2595
|
var X; // output
|
2596
|
var Y;
|
2597
|
var Z;
|
2598
|
|
2599
|
var Error_Code=0; // GEOCENT_NO_ERROR;
|
2600
|
var Rn; /* Earth radius at location */
|
2601
|
var Sin_Lat; /* Math.sin(Latitude) */
|
2602
|
var Sin2_Lat; /* Square of Math.sin(Latitude) */
|
2603
|
var Cos_Lat; /* Math.cos(Latitude) */
|
2604
|
|
2605
|
/*
|
2606
|
** Don't blow up if Latitude is just a little out of the value
|
2607
|
** range as it may just be a rounding issue. Also removed longitude
|
2608
|
** test, it should be wrapped by Math.cos() and Math.sin(). NFW for PROJ.4, Sep/2001.
|
2609
|
*/
|
2610
|
if( Latitude < -HALF_PI && Latitude > -1.001 * HALF_PI )
|
2611
|
Latitude = -HALF_PI;
|
2612
|
else if( Latitude > HALF_PI && Latitude < 1.001 * HALF_PI )
|
2613
|
Latitude = HALF_PI;
|
2614
|
else if ((Latitude < -HALF_PI) || (Latitude > HALF_PI))
|
2615
|
{ /* Latitude out of range */
|
2616
|
Error_Code |= GEOCENT_LAT_ERROR;
|
2617
|
}
|
2618
|
|
2619
|
if (!Error_Code)
|
2620
|
{ /* no errors */
|
2621
|
if (Longitude > PI)
|
2622
|
Longitude -= (2*PI);
|
2623
|
Sin_Lat = Math.sin(Latitude);
|
2624
|
Cos_Lat = Math.cos(Latitude);
|
2625
|
Sin2_Lat = Sin_Lat * Sin_Lat;
|
2626
|
Rn = cs.a / (Math.sqrt(1.0e0 - cs.es * Sin2_Lat));
|
2627
|
X = (Rn + Height) * Cos_Lat * Math.cos(Longitude);
|
2628
|
Y = (Rn + Height) * Cos_Lat * Math.sin(Longitude);
|
2629
|
Z = ((Rn * (1 - cs.es)) + Height) * Sin_Lat;
|
2630
|
|
2631
|
}
|
2632
|
|
2633
|
p.x = X;
|
2634
|
p.y = Y;
|
2635
|
p.z = Z;
|
2636
|
return Error_Code;
|
2637
|
} // cs_geodetic_to_geocentric()
|
2638
|
|
2639
|
|
2640
|
/** Convert_Geocentric_To_Geodetic
|
2641
|
* The method used here is derived from 'An Improved Algorithm for
|
2642
|
* Geocentric to Geodetic Coordinate Conversion', by Ralph Toms, Feb 1996
|
2643
|
*/
|
2644
|
|
2645
|
function cs_geocentric_to_geodetic (cs, p) {
|
2646
|
|
2647
|
var X =p.x;
|
2648
|
var Y = p.y;
|
2649
|
var Z = p.z;
|
2650
|
var Longitude;
|
2651
|
var Latitude;
|
2652
|
var Height;
|
2653
|
|
2654
|
var W; /* distance from Z axis */
|
2655
|
var W2; /* square of distance from Z axis */
|
2656
|
var T0; /* initial estimate of vertical component */
|
2657
|
var T1; /* corrected estimate of vertical component */
|
2658
|
var S0; /* initial estimate of horizontal component */
|
2659
|
var S1; /* corrected estimate of horizontal component */
|
2660
|
var Sin_B0; /* Math.sin(B0), B0 is estimate of Bowring aux variable */
|
2661
|
var Sin3_B0; /* cube of Math.sin(B0) */
|
2662
|
var Cos_B0; /* Math.cos(B0) */
|
2663
|
var Sin_p1; /* Math.sin(phi1), phi1 is estimated latitude */
|
2664
|
var Cos_p1; /* Math.cos(phi1) */
|
2665
|
var Rn; /* Earth radius at location */
|
2666
|
var Sum; /* numerator of Math.cos(phi1) */
|
2667
|
var At_Pole; /* indicates location is in polar region */
|
2668
|
|
2669
|
X = parseFloat(X); // cast from string to float
|
2670
|
Y = parseFloat(Y);
|
2671
|
Z = parseFloat(Z);
|
2672
|
|
2673
|
At_Pole = false;
|
2674
|
if (X != 0.0)
|
2675
|
{
|
2676
|
Longitude = Math.atan2(Y,X);
|
2677
|
}
|
2678
|
else
|
2679
|
{
|
2680
|
if (Y > 0)
|
2681
|
{
|
2682
|
Longitude = HALF_PI;
|
2683
|
}
|
2684
|
else if (Y < 0)
|
2685
|
{
|
2686
|
Longitude = -HALF_PI;
|
2687
|
}
|
2688
|
else
|
2689
|
{
|
2690
|
At_Pole = true;
|
2691
|
Longitude = 0.0;
|
2692
|
if (Z > 0.0)
|
2693
|
{ /* north pole */
|
2694
|
Latitude = HALF_PI;
|
2695
|
}
|
2696
|
else if (Z < 0.0)
|
2697
|
{ /* south pole */
|
2698
|
Latitude = -HALF_PI;
|
2699
|
}
|
2700
|
else
|
2701
|
{ /* center of earth */
|
2702
|
Latitude = HALF_PI;
|
2703
|
Height = -cs.b;
|
2704
|
return;
|
2705
|
}
|
2706
|
}
|
2707
|
}
|
2708
|
W2 = X*X + Y*Y;
|
2709
|
W = Math.sqrt(W2);
|
2710
|
T0 = Z * AD_C;
|
2711
|
S0 = Math.sqrt(T0 * T0 + W2);
|
2712
|
Sin_B0 = T0 / S0;
|
2713
|
Cos_B0 = W / S0;
|
2714
|
Sin3_B0 = Sin_B0 * Sin_B0 * Sin_B0;
|
2715
|
T1 = Z + cs.b * cs.ep2 * Sin3_B0;
|
2716
|
Sum = W - cs.a * cs.es * Cos_B0 * Cos_B0 * Cos_B0;
|
2717
|
S1 = Math.sqrt(T1*T1 + Sum * Sum);
|
2718
|
Sin_p1 = T1 / S1;
|
2719
|
Cos_p1 = Sum / S1;
|
2720
|
Rn = cs.a / Math.sqrt(1.0 - cs.es * Sin_p1 * Sin_p1);
|
2721
|
if (Cos_p1 >= COS_67P5)
|
2722
|
{
|
2723
|
Height = W / Cos_p1 - Rn;
|
2724
|
}
|
2725
|
else if (Cos_p1 <= -COS_67P5)
|
2726
|
{
|
2727
|
Height = W / -Cos_p1 - Rn;
|
2728
|
}
|
2729
|
else
|
2730
|
{
|
2731
|
Height = Z / Sin_p1 + Rn * (cs.es - 1.0);
|
2732
|
}
|
2733
|
if (At_Pole == false)
|
2734
|
{
|
2735
|
Latitude = Math.atan(Sin_p1 / Cos_p1);
|
2736
|
}
|
2737
|
|
2738
|
p.x = Longitude;
|
2739
|
p.y =Latitude;
|
2740
|
p.z = Height;
|
2741
|
return 0;
|
2742
|
} // cs_geocentric_to_geodetic()
|
2743
|
|
2744
|
|
2745
|
|
2746
|
/****************************************************************/
|
2747
|
// pj_geocentic_to_wgs84(defn, p )
|
2748
|
// defn = coordinate system definition,
|
2749
|
// p = point to transform in geocentric coordinates (x,y,z)
|
2750
|
function cs_geocentric_to_wgs84( defn, p ) {
|
2751
|
|
2752
|
if( defn.datum_type == PJD_3PARAM )
|
2753
|
{
|
2754
|
// if( x[io] == HUGE_VAL )
|
2755
|
// continue;
|
2756
|
p.x += defn.datum_params[0];
|
2757
|
p.y += defn.datum_params[1];
|
2758
|
p.z += defn.datum_params[2];
|
2759
|
|
2760
|
}
|
2761
|
else // if( defn.datum_type == PJD_7PARAM )
|
2762
|
{
|
2763
|
var Dx_BF =defn.datum_params[0];
|
2764
|
var Dy_BF =defn.datum_params[1];
|
2765
|
var Dz_BF =defn.datum_params[2];
|
2766
|
var Rx_BF =defn.datum_params[3];
|
2767
|
var Ry_BF =defn.datum_params[4];
|
2768
|
var Rz_BF =defn.datum_params[5];
|
2769
|
var M_BF =defn.datum_params[6];
|
2770
|
// if( x[io] == HUGE_VAL )
|
2771
|
// continue;
|
2772
|
var x_out = M_BF*( p.x - Rz_BF*p.y + Ry_BF*p.z) + Dx_BF;
|
2773
|
var y_out = M_BF*( Rz_BF*p.x + p.y - Rx_BF*p.z) + Dy_BF;
|
2774
|
var z_out = M_BF*(-Ry_BF*p.x + Rx_BF*p.y + p.z) + Dz_BF;
|
2775
|
p.x = x_out;
|
2776
|
p.y = y_out;
|
2777
|
p.z = z_out;
|
2778
|
}
|
2779
|
} // cs_geocentric_to_wgs84
|
2780
|
|
2781
|
/****************************************************************/
|
2782
|
// pj_geocentic_from_wgs84()
|
2783
|
// coordinate system definition,
|
2784
|
// point to transform in geocentric coordinates (x,y,z)
|
2785
|
function cs_geocentric_from_wgs84( defn, p ) {
|
2786
|
|
2787
|
if( defn.datum_type == PJD_3PARAM )
|
2788
|
{
|
2789
|
//if( x[io] == HUGE_VAL )
|
2790
|
// continue;
|
2791
|
p.x -= defn.datum_params[0];
|
2792
|
p.y -= defn.datum_params[1];
|
2793
|
p.z -= defn.datum_params[2];
|
2794
|
|
2795
|
}
|
2796
|
else // if( defn.datum_type == PJD_7PARAM )
|
2797
|
{
|
2798
|
var Dx_BF =defn.datum_params[0];
|
2799
|
var Dy_BF =defn.datum_params[1];
|
2800
|
var Dz_BF =defn.datum_params[2];
|
2801
|
var Rx_BF =defn.datum_params[3];
|
2802
|
var Ry_BF =defn.datum_params[4];
|
2803
|
var Rz_BF =defn.datum_params[5];
|
2804
|
var M_BF =defn.datum_params[6];
|
2805
|
var x_tmp = (p.x - Dx_BF) / M_BF;
|
2806
|
var y_tmp = (p.y - Dy_BF) / M_BF;
|
2807
|
var z_tmp = (p.z - Dz_BF) / M_BF;
|
2808
|
//if( x[io] == HUGE_VAL )
|
2809
|
// continue;
|
2810
|
|
2811
|
p.x = x_tmp + Rz_BF*y_tmp - Ry_BF*z_tmp;
|
2812
|
p.y = -Rz_BF*x_tmp + y_tmp + Rx_BF*z_tmp;
|
2813
|
p.z = Ry_BF*x_tmp - Rx_BF*y_tmp + z_tmp;
|
2814
|
}
|
2815
|
} //cs_geocentric_from_wgs84()
|
2816
|
/* ======================================================================
|
2817
|
projCode/vandg.js
|
2818
|
====================================================================== */
|
2819
|
|
2820
|
/*******************************************************************************
|
2821
|
NAME VAN DER GRINTEN
|
2822
|
|
2823
|
PURPOSE: Transforms input Easting and Northing to longitude and
|
2824
|
latitude for the Van der Grinten projection. The
|
2825
|
Easting and Northing must be in meters. The longitude
|
2826
|
and latitude values will be returned in radians.
|
2827
|
|
2828
|
PROGRAMMER DATE
|
2829
|
---------- ----
|
2830
|
T. Mittan March, 1993
|
2831
|
|
2832
|
This function was adapted from the Van Der Grinten projection code
|
2833
|
(FORTRAN) in the General Cartographic Transformation Package software
|
2834
|
which is available from the U.S. Geological Survey National Mapping Division.
|
2835
|
|
2836
|
ALGORITHM REFERENCES
|
2837
|
|
2838
|
1. "New Equal-Area Map Projections for Noncircular Regions", John P. Snyder,
|
2839
|
The American Cartographer, Vol 15, No. 4, October 1988, pp. 341-355.
|
2840
|
|
2841
|
2. Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
|
2842
|
Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
|
2843
|
State Government Printing Office, Washington D.C., 1987.
|
2844
|
|
2845
|
3. "Software Documentation for GCTP General Cartographic Transformation
|
2846
|
Package", U.S. Geological Survey National Mapping Division, May 1982.
|
2847
|
*******************************************************************************/
|
2848
|
|
2849
|
Proj4js.Proj.vandg = {
|
2850
|
|
2851
|
/* Initialize the Van Der Grinten projection
|
2852
|
----------------------------------------*/
|
2853
|
init: function() {
|
2854
|
this.R = 6370997.0; //Radius of earth
|
2855
|
},
|
2856
|
|
2857
|
forward: function(p) {
|
2858
|
|
2859
|
var lon=p.x;
|
2860
|
var lat=p.y;
|
2861
|
|
2862
|
/* Forward equations
|
2863
|
-----------------*/
|
2864
|
var dlon = Proj4js.common.adjust_lon(lon - this.long0);
|
2865
|
var x,y;
|
2866
|
|
2867
|
if (Math.abs(lat) <= Proj4js.common.EPSLN) {
|
2868
|
x = this.x0 + this.R * dlon;
|
2869
|
y = this.y0;
|
2870
|
}
|
2871
|
var theta = Proj4js.common.asinz(2.0 * Math.abs(lat / Proj4js.common.PI));
|
2872
|
if ((Math.abs(dlon) <= Proj4js.common.EPSLN) || (Math.abs(Math.abs(lat) - Proj4js.common.HALF_PI) <= Proj4js.common.EPSLN)) {
|
2873
|
x = this.x0;
|
2874
|
if (lat >= 0) {
|
2875
|
y = this.y0 + Proj4js.common.PI * this.R * Math.tan(.5 * theta);
|
2876
|
} else {
|
2877
|
y = this.y0 + Proj4js.common.PI * this.R * - Math.tan(.5 * theta);
|
2878
|
}
|
2879
|
// return(OK);
|
2880
|
}
|
2881
|
var al = .5 * Math.abs((Proj4js.common.PI / dlon) - (dlon / Proj4js.common.PI));
|
2882
|
var asq = al * al;
|
2883
|
var sinth = Math.sin(theta);
|
2884
|
var costh = Math.cos(theta);
|
2885
|
|
2886
|
var g = costh / (sinth + costh - 1.0);
|
2887
|
var gsq = g * g;
|
2888
|
var m = g * (2.0 / sinth - 1.0);
|
2889
|
var msq = m * m;
|
2890
|
var con = Proj4js.common.PI * this.R * (al * (g - msq) + Math.sqrt(asq * (g - msq) * (g - msq) - (msq + asq) * (gsq - msq))) / (msq + asq);
|
2891
|
if (dlon < 0) {
|
2892
|
con = -con;
|
2893
|
}
|
2894
|
x = this.x0 + con;
|
2895
|
con = Math.abs(con / (Proj4js.common.PI * this.R));
|
2896
|
if (lat >= 0) {
|
2897
|
y = this.y0 + Proj4js.common.PI * this.R * Math.sqrt(1.0 - con * con - 2.0 * al * con);
|
2898
|
} else {
|
2899
|
y = this.y0 - Proj4js.common.PI * this.R * Math.sqrt(1.0 - con * con - 2.0 * al * con);
|
2900
|
}
|
2901
|
p.x = x;
|
2902
|
p.y = y;
|
2903
|
return p;
|
2904
|
},
|
2905
|
|
2906
|
/* Van Der Grinten inverse equations--mapping x,y to lat/long
|
2907
|
---------------------------------------------------------*/
|
2908
|
inverse: function(p) {
|
2909
|
var dlon;
|
2910
|
var xx,yy,xys,c1,c2,c3;
|
2911
|
var al,asq;
|
2912
|
var a1;
|
2913
|
var m1;
|
2914
|
var con;
|
2915
|
var th1;
|
2916
|
var d;
|
2917
|
|
2918
|
/* inverse equations
|
2919
|
-----------------*/
|
2920
|
p.x -= this.x0;
|
2921
|
p.y -= this.y0;
|
2922
|
con = Proj4js.common.PI * this.R;
|
2923
|
xx = p.x / con;
|
2924
|
yy =p.y / con;
|
2925
|
xys = xx * xx + yy * yy;
|
2926
|
c1 = -Math.abs(yy) * (1.0 + xys);
|
2927
|
c2 = c1 - 2.0 * yy * yy + xx * xx;
|
2928
|
c3 = -2.0 * c1 + 1.0 + 2.0 * yy * yy + xys * xys;
|
2929
|
d = yy * yy / c3 + (2.0 * c2 * c2 * c2 / c3 / c3 / c3 - 9.0 * c1 * c2 / c3 /c3) / 27.0;
|
2930
|
a1 = (c1 - c2 * c2 / 3.0 / c3) / c3;
|
2931
|
m1 = 2.0 * Math.sqrt( -a1 / 3.0);
|
2932
|
con = ((3.0 * d) / a1) / m1;
|
2933
|
if (Math.abs(con) > 1.0) {
|
2934
|
if (con >= 0.0) {
|
2935
|
con = 1.0;
|
2936
|
} else {
|
2937
|
con = -1.0;
|
2938
|
}
|
2939
|
}
|
2940
|
th1 = Math.acos(con) / 3.0;
|
2941
|
if (p.y >= 0) {
|
2942
|
lat = (-m1 *Math.cos(th1 + Proj4js.common.PI / 3.0) - c2 / 3.0 / c3) * Proj4js.common.PI;
|
2943
|
} else {
|
2944
|
lat = -(-m1 * Math.cos(th1 + PI / 3.0) - c2 / 3.0 / c3) * Proj4js.common.PI;
|
2945
|
}
|
2946
|
|
2947
|
if (Math.abs(xx) < Proj4js.common.EPSLN) {
|
2948
|
lon = this.long0;
|
2949
|
}
|
2950
|
lon = Proj4js.common.adjust_lon(this.long0 + Proj4js.common.PI * (xys - 1.0 + Math.sqrt(1.0 + 2.0 * (xx * xx - yy * yy) + xys * xys)) / 2.0 / xx);
|
2951
|
|
2952
|
p.x=lon;
|
2953
|
p.y=lat;
|
2954
|
return p;
|
2955
|
}
|
2956
|
};
|
2957
|
/* ======================================================================
|
2958
|
projCode/gauss.js
|
2959
|
====================================================================== */
|
2960
|
|
2961
|
|
2962
|
Proj4js.Proj.gauss = {
|
2963
|
|
2964
|
init : function() {
|
2965
|
sphi = Math.sin(this.lat0);
|
2966
|
cphi = Math.cos(this.lat0);
|
2967
|
cphi *= cphi;
|
2968
|
this.rc = Math.sqrt(1.0 - this.es) / (1.0 - this.es * sphi * sphi);
|
2969
|
this.C = Math.sqrt(1.0 + this.es * cphi * cphi / (1.0 - this.es));
|
2970
|
this.phic0 = Math.asin(sphi / this.C);
|
2971
|
this.ratexp = 0.5 * this.C * this.e;
|
2972
|
this.K = Math.tan(0.5 * this.phic0 + Proj4js.common.FORTPI) / (Math.pow(Math.tan(0.5*this.lat0 + Proj4js.common.FORTPI), this.C) * Proj4js.common.srat(this.e*sphi, this.ratexp));
|
2973
|
},
|
2974
|
|
2975
|
forward : function(p) {
|
2976
|
var lon = p.x;
|
2977
|
var lat = p.y;
|
2978
|
|
2979
|
p.y = 2.0 * Math.atan( this.K * Math.pow(Math.tan(0.5 * lat + Proj4js.common.FORTPI), this.C) * Proj4js.common.srat(this.e * Math.sin(lat), this.ratexp) ) - Proj4js.common.HALF_PI;
|
2980
|
p.x = this.C * lon;
|
2981
|
return p;
|
2982
|
},
|
2983
|
|
2984
|
inverse : function(p) {
|
2985
|
var DEL_TOL = 1e-14;
|
2986
|
var lon = p.x / this.C;
|
2987
|
var lat = p.y;
|
2988
|
num = Math.pow(Math.tan(0.5 * lat + Proj4js.common.FORTPI)/this.K, 1./this.C);
|
2989
|
for (var i = Proj4js.common.MAX_ITER; i>0; --i) {
|
2990
|
lat = 2.0 * Math.atan(num * Proj4js.common.srat(this.e * Math.sin(p.y), -0.5 * this.e)) - Proj4js.common.HALF_PI;
|
2991
|
if (Math.abs(lat - p.y) < DEL_TOL) break;
|
2992
|
p.y = lat;
|
2993
|
}
|
2994
|
/* convergence failed */
|
2995
|
if (!i) {
|
2996
|
Proj4js.reportError("gauss:inverse:convergence failed");
|
2997
|
return null;
|
2998
|
}
|
2999
|
p.x = lon;
|
3000
|
p.y = lat;
|
3001
|
return p;
|
3002
|
}
|
3003
|
};
|
3004
|
|
3005
|
/* ======================================================================
|
3006
|
projCode/omerc.js
|
3007
|
====================================================================== */
|
3008
|
|
3009
|
/*******************************************************************************
|
3010
|
NAME OBLIQUE MERCATOR (HOTINE)
|
3011
|
|
3012
|
PURPOSE: Transforms input longitude and latitude to Easting and
|
3013
|
Northing for the Oblique Mercator projection. The
|
3014
|
longitude and latitude must be in radians. The Easting
|
3015
|
and Northing values will be returned in meters.
|
3016
|
|
3017
|
PROGRAMMER DATE
|
3018
|
---------- ----
|
3019
|
T. Mittan Mar, 1993
|
3020
|
|
3021
|
ALGORITHM REFERENCES
|
3022
|
|
3023
|
1. Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
|
3024
|
Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
|
3025
|
State Government Printing Office, Washington D.C., 1987.
|
3026
|
|
3027
|
2. Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
|
3028
|
U.S. Geological Survey Professional Paper 1453 , United State Government
|
3029
|
Printing Office, Washington D.C., 1989.
|
3030
|
*******************************************************************************/
|
3031
|
|
3032
|
Proj4js.Proj.omerc = {
|
3033
|
|
3034
|
/* Initialize the Oblique Mercator projection
|
3035
|
------------------------------------------*/
|
3036
|
init: function() {
|
3037
|
if (!this.mode) this.mode=0;
|
3038
|
if (!this.lon1) {this.lon1=0;this.mode=1;}
|
3039
|
if (!this.lon2) this.lon2=0;
|
3040
|
if (!this.lat2) this.lat2=0;
|
3041
|
|
3042
|
/* Place parameters in static storage for common use
|
3043
|
-------------------------------------------------*/
|
3044
|
var temp = this.b/ this.a;
|
3045
|
var es = 1.0 - Math.pow(temp,2);
|
3046
|
var e = Math.sqrt(es);
|
3047
|
|
3048
|
this.sin_p20=Math.sin(this.lat0);
|
3049
|
this.cos_p20=Math.cos(this.lat0);
|
3050
|
|
3051
|
this.con = 1.0 - this.es * this.sin_p20 * this.sin_p20;
|
3052
|
this.com = Math.sqrt(1.0 - es);
|
3053
|
this.bl = Math.sqrt(1.0 + this.es * Math.pow(this.cos_p20,4.0)/(1.0 - es));
|
3054
|
this.al = this.a * this.bl * this.k0 * this.com / this.con;
|
3055
|
if (Math.abs(this.lat0) < Proj4js.common.EPSLN) {
|
3056
|
this.ts = 1.0;
|
3057
|
this.d = 1.0;
|
3058
|
this.el = 1.0;
|
3059
|
} else {
|
3060
|
this.ts = Proj4js.common.tsfnz(this.e,this.lat0,this.sin_p20);
|
3061
|
this.con = Math.sqrt(this.con);
|
3062
|
this.d = this.bl * this.com / (this.cos_p20 * this.con);
|
3063
|
if ((this.d * this.d - 1.0) > 0.0) {
|
3064
|
if (this.lat0 >= 0.0) {
|
3065
|
this.f = this.d + Math.sqrt(this.d * this.d - 1.0);
|
3066
|
} else {
|
3067
|
this.f = this.d - Math.sqrt(this.d * this.d - 1.0);
|
3068
|
}
|
3069
|
} else {
|
3070
|
this.f = this.d;
|
3071
|
}
|
3072
|
this.el = this.f * Math.pow(this.ts,this.bl);
|
3073
|
}
|
3074
|
|
3075
|
//this.longc=52.60353916666667;
|
3076
|
|
3077
|
if (this.mode != 0) {
|
3078
|
this.g = .5 * (this.f - 1.0/this.f);
|
3079
|
this.gama = Proj4js.common.asinz(Math.sin(this.alpha) / this.d);
|
3080
|
this.longc= this.longc - Proj4js.common.asinz(this.g * Math.tan(this.gama))/this.bl;
|
3081
|
|
3082
|
/* Report parameters common to format B
|
3083
|
-------------------------------------*/
|
3084
|
//genrpt(azimuth * R2D,"Azimuth of Central Line: ");
|
3085
|
//cenlon(lon_origin);
|
3086
|
// cenlat(lat_origin);
|
3087
|
|
3088
|
this.con = Math.abs(this.lat0);
|
3089
|
if ((this.con > Proj4js.common.EPSLN) && (Math.abs(this.con - Proj4js.common.HALF_PI) > Proj4js.common.EPSLN)) {
|
3090
|
this.singam=Math.sin(this.gama);
|
3091
|
this.cosgam=Math.cos(this.gama);
|
3092
|
|
3093
|
this.sinaz=Math.sin(this.alpha);
|
3094
|
this.cosaz=Math.cos(this.alpha);
|
3095
|
|
3096
|
if (this.lat0>= 0) {
|
3097
|
this.u = (this.al / this.bl) * Math.atan(Math.sqrt(this.d*this.d - 1.0)/this.cosaz);
|
3098
|
} else {
|
3099
|
this.u = -(this.al / this.bl) *Math.atan(Math.sqrt(this.d*this.d - 1.0)/this.cosaz);
|
3100
|
}
|
3101
|
} else {
|
3102
|
Proj4js.reportError("omerc:Init:DataError");
|
3103
|
}
|
3104
|
} else {
|
3105
|
this.sinphi =Math. sin(this.at1);
|
3106
|
this.ts1 = Proj4js.common.tsfnz(this.e,this.lat1,this.sinphi);
|
3107
|
this.sinphi = Math.sin(this.lat2);
|
3108
|
this.ts2 = Proj4js.common.tsfnz(this.e,this.lat2,this.sinphi);
|
3109
|
this.h = Math.pow(this.ts1,this.bl);
|
3110
|
this.l = Math.pow(this.ts2,this.bl);
|
3111
|
this.f = this.el/this.h;
|
3112
|
this.g = .5 * (this.f - 1.0/this.f);
|
3113
|
this.j = (this.el * this.el - this.l * this.h)/(this.el * this.el + this.l * this.h);
|
3114
|
this.p = (this.l - this.h) / (this.l + this.h);
|
3115
|
this.dlon = this.lon1 - this.lon2;
|
3116
|
if (this.dlon < -Proj4js.common.PI) this.lon2 = this.lon2 - 2.0 * Proj4js.common.PI;
|
3117
|
if (this.dlon > Proj4js.common.PI) this.lon2 = this.lon2 + 2.0 * Proj4js.common.PI;
|
3118
|
this.dlon = this.lon1 - this.lon2;
|
3119
|
this.longc = .5 * (this.lon1 + this.lon2) -Math.atan(this.j * Math.tan(.5 * this.bl * this.dlon)/this.p)/this.bl;
|
3120
|
this.dlon = Proj4js.common.adjust_lon(this.lon1 - this.longc);
|
3121
|
this.gama = Math.atan(Math.sin(this.bl * this.dlon)/this.g);
|
3122
|
this.alpha = Proj4js.common.asinz(this.d * Math.sin(this.gama));
|
3123
|
|
3124
|
/* Report parameters common to format A
|
3125
|
-------------------------------------*/
|
3126
|
|
3127
|
if (Math.abs(this.lat1 - this.lat2) <= Proj4js.common.EPSLN) {
|
3128
|
Proj4js.reportError("omercInitDataError");
|
3129
|
//return(202);
|
3130
|
} else {
|
3131
|
this.con = Math.abs(this.lat1);
|
3132
|
}
|
3133
|
if ((this.con <= Proj4js.common.EPSLN) || (Math.abs(this.con - HALF_PI) <= Proj4js.common.EPSLN)) {
|
3134
|
Proj4js.reportError("omercInitDataError");
|
3135
|
//return(202);
|
3136
|
} else {
|
3137
|
if (Math.abs(Math.abs(this.lat0) - Proj4js.common.HALF_PI) <= Proj4js.common.EPSLN) {
|
3138
|
Proj4js.reportError("omercInitDataError");
|
3139
|
//return(202);
|
3140
|
}
|
3141
|
}
|
3142
|
|
3143
|
this.singam=Math.sin(this.gam);
|
3144
|
this.cosgam=Math.cos(this.gam);
|
3145
|
|
3146
|
this.sinaz=Math.sin(this.alpha);
|
3147
|
this.cosaz=Math.cos(this.alpha);
|
3148
|
|
3149
|
|
3150
|
if (this.lat0 >= 0) {
|
3151
|
this.u = (this.al/this.bl) * Math.atan(Math.sqrt(this.d * this.d - 1.0)/this.cosaz);
|
3152
|
} else {
|
3153
|
this.u = -(this.al/this.bl) * Math.atan(Math.sqrt(this.d * this.d - 1.0)/this.cosaz);
|
3154
|
}
|
3155
|
}
|
3156
|
},
|
3157
|
|
3158
|
|
3159
|
/* Oblique Mercator forward equations--mapping lat,long to x,y
|
3160
|
----------------------------------------------------------*/
|
3161
|
forward: function(p) {
|
3162
|
var theta; /* angle */
|
3163
|
var sin_phi, cos_phi;/* sin and cos value */
|
3164
|
var b; /* temporary values */
|
3165
|
var c, t, tq; /* temporary values */
|
3166
|
var con, n, ml; /* cone constant, small m */
|
3167
|
var q,us,vl;
|
3168
|
var ul,vs;
|
3169
|
var s;
|
3170
|
var dlon;
|
3171
|
var ts1;
|
3172
|
|
3173
|
var lon=p.x;
|
3174
|
var lat=p.y;
|
3175
|
/* Forward equations
|
3176
|
-----------------*/
|
3177
|
sin_phi = Math.sin(lat);
|
3178
|
dlon = Proj4js.common.adjust_lon(lon - this.longc);
|
3179
|
vl = Math.sin(this.bl * dlon);
|
3180
|
if (Math.abs(Math.abs(lat) - Proj4js.common.HALF_PI) > Proj4js.common.EPSLN) {
|
3181
|
ts1 = Proj4js.common.tsfnz(this.e,lat,sin_phi);
|
3182
|
q = this.el / (Math.pow(ts1,this.bl));
|
3183
|
s = .5 * (q - 1.0 / q);
|
3184
|
t = .5 * (q + 1.0/ q);
|
3185
|
ul = (s * this.singam - vl * this.cosgam) / t;
|
3186
|
con = Math.cos(this.bl * dlon);
|
3187
|
if (Math.abs(con) < .0000001) {
|
3188
|
us = this.al * this.bl * dlon;
|
3189
|
} else {
|
3190
|
us = this.al * Math.atan((s * this.cosgam + vl * this.singam) / con)/this.bl;
|
3191
|
if (con < 0) us = us + Proj4js.common.PI * this.al / this.bl;
|
3192
|
}
|
3193
|
} else {
|
3194
|
if (lat >= 0) {
|
3195
|
ul = this.singam;
|
3196
|
} else {
|
3197
|
ul = -this.singam;
|
3198
|
}
|
3199
|
us = this.al * lat / this.bl;
|
3200
|
}
|
3201
|
if (Math.abs(Math.abs(ul) - 1.0) <= Proj4js.common.EPSLN) {
|
3202
|
//alert("Point projects into infinity","omer-for");
|
3203
|
Proj4js.reportError("omercFwdInfinity");
|
3204
|
//return(205);
|
3205
|
}
|
3206
|
vs = .5 * this.al * Math.log((1.0 - ul)/(1.0 + ul)) / this.bl;
|
3207
|
us = us - this.u;
|
3208
|
var x = this.x0 + vs * this.cosaz + us * this.sinaz;
|
3209
|
var y = this.y0 + us * this.cosaz - vs * this.sinaz;
|
3210
|
|
3211
|
p.x=x;
|
3212
|
p.y=y;
|
3213
|
return p;
|
3214
|
},
|
3215
|
|
3216
|
inverse: function(p) {
|
3217
|
var delta_lon; /* Delta longitude (Given longitude - center */
|
3218
|
var theta; /* angle */
|
3219
|
var delta_theta; /* adjusted longitude */
|
3220
|
var sin_phi, cos_phi;/* sin and cos value */
|
3221
|
var b; /* temporary values */
|
3222
|
var c, t, tq; /* temporary values */
|
3223
|
var con, n, ml; /* cone constant, small m */
|
3224
|
var vs,us,q,s,ts1;
|
3225
|
var vl,ul,bs;
|
3226
|
var dlon;
|
3227
|
var flag;
|
3228
|
|
3229
|
/* Inverse equations
|
3230
|
-----------------*/
|
3231
|
p.x -= this.x0;
|
3232
|
p.y -= this.y0;
|
3233
|
flag = 0;
|
3234
|
vs = p.x * this.cosaz - p.y * this.sinaz;
|
3235
|
us = p.y * this.cosaz + p.x * this.sinaz;
|
3236
|
us = us + this.u;
|
3237
|
q = Math.exp(-this.bl * vs / this.al);
|
3238
|
s = .5 * (q - 1.0/q);
|
3239
|
t = .5 * (q + 1.0/q);
|
3240
|
vl = Math.sin(this.bl * us / this.al);
|
3241
|
ul = (vl * this.cosgam + s * this.singam)/t;
|
3242
|
if (Math.abs(Math.abs(ul) - 1.0) <= Proj4js.common.EPSLN)
|
3243
|
{
|
3244
|
lon = this.longc;
|
3245
|
if (ul >= 0.0) {
|
3246
|
lat = Proj4js.common.HALF_PI;
|
3247
|
} else {
|
3248
|
lat = -Proj4js.common.HALF_PI;
|
3249
|
}
|
3250
|
} else {
|
3251
|
con = 1.0 / this.bl;
|
3252
|
ts1 =Math.pow((this.el / Math.sqrt((1.0 + ul) / (1.0 - ul))),con);
|
3253
|
lat = Proj4js.common.phi2z(this.e,ts1);
|
3254
|
//if (flag != 0)
|
3255
|
//return(flag);
|
3256
|
//~ con = Math.cos(this.bl * us /al);
|
3257
|
theta = this.longc - Math.atan2((s * this.cosgam - vl * this.singam) , con)/this.bl;
|
3258
|
lon = Proj4js.common.adjust_lon(theta);
|
3259
|
}
|
3260
|
p.x=lon;
|
3261
|
p.y=lat;
|
3262
|
return p;
|
3263
|
}
|
3264
|
};
|
3265
|
/* ======================================================================
|
3266
|
projCode/lcc.js
|
3267
|
====================================================================== */
|
3268
|
|
3269
|
/*******************************************************************************
|
3270
|
NAME LAMBERT CONFORMAL CONIC
|
3271
|
|
3272
|
PURPOSE: Transforms input longitude and latitude to Easting and
|
3273
|
Northing for the Lambert Conformal Conic projection. The
|
3274
|
longitude and latitude must be in radians. The Easting
|
3275
|
and Northing values will be returned in meters.
|
3276
|
|
3277
|
|
3278
|
ALGORITHM REFERENCES
|
3279
|
|
3280
|
1. Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
|
3281
|
Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
|
3282
|
State Government Printing Office, Washington D.C., 1987.
|
3283
|
|
3284
|
2. Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
|
3285
|
U.S. Geological Survey Professional Paper 1453 , United State Government
|
3286
|
*******************************************************************************/
|
3287
|
|
3288
|
|
3289
|
//<2104> +proj=lcc +lat_1=10.16666666666667 +lat_0=10.16666666666667 +lon_0=-71.60561777777777 +k_0=1 +x0=-17044 +x0=-23139.97 +ellps=intl +units=m +no_defs no_defs
|
3290
|
|
3291
|
// Initialize the Lambert Conformal conic projection
|
3292
|
// -----------------------------------------------------------------
|
3293
|
|
3294
|
//Proj4js.Proj.lcc = Class.create();
|
3295
|
Proj4js.Proj.lcc = {
|
3296
|
init : function() {
|
3297
|
|
3298
|
// array of: r_maj,r_min,lat1,lat2,c_lon,c_lat,false_east,false_north
|
3299
|
//double c_lat; /* center latitude */
|
3300
|
//double c_lon; /* center longitude */
|
3301
|
//double lat1; /* first standard parallel */
|
3302
|
//double lat2; /* second standard parallel */
|
3303
|
//double r_maj; /* major axis */
|
3304
|
//double r_min; /* minor axis */
|
3305
|
//double false_east; /* x offset in meters */
|
3306
|
//double false_north; /* y offset in meters */
|
3307
|
|
3308
|
if (!this.lat2){this.lat2=this.lat0;}//if lat2 is not defined
|
3309
|
if (!this.k0) this.k0 = 1.0;
|
3310
|
|
3311
|
// Standard Parallels cannot be equal and on opposite sides of the equator
|
3312
|
if (Math.abs(this.lat1+this.lat2) < Proj4js.common.EPSLN) {
|
3313
|
Proj4js.reportError("lcc:init: Equal Latitudes");
|
3314
|
return;
|
3315
|
}
|
3316
|
|
3317
|
var temp = this.b / this.a;
|
3318
|
this.e = Math.sqrt(1.0 - temp*temp);
|
3319
|
|
3320
|
var sin1 = Math.sin(this.lat1);
|
3321
|
var cos1 = Math.cos(this.lat1);
|
3322
|
var ms1 = Proj4js.common.msfnz(this.e, sin1, cos1);
|
3323
|
var ts1 = Proj4js.common.tsfnz(this.e, this.lat1, sin1);
|
3324
|
|
3325
|
var sin2 = Math.sin(this.lat2);
|
3326
|
var cos2 = Math.cos(this.lat2);
|
3327
|
var ms2 = Proj4js.common.msfnz(this.e, sin2, cos2);
|
3328
|
var ts2 = Proj4js.common.tsfnz(this.e, this.lat2, sin2);
|
3329
|
|
3330
|
var ts0 = Proj4js.common.tsfnz(this.e, this.lat0, Math.sin(this.lat0));
|
3331
|
|
3332
|
if (Math.abs(this.lat1 - this.lat2) > Proj4js.common.EPSLN) {
|
3333
|
this.ns = Math.log(ms1/ms2)/Math.log(ts1/ts2);
|
3334
|
} else {
|
3335
|
this.ns = sin1;
|
3336
|
}
|
3337
|
this.f0 = ms1 / (this.ns * Math.pow(ts1, this.ns));
|
3338
|
this.rh = this.a * this.f0 * Math.pow(ts0, this.ns);
|
3339
|
if (!this.title) this.title = "Lambert Conformal Conic";
|
3340
|
},
|
3341
|
|
3342
|
|
3343
|
// Lambert Conformal conic forward equations--mapping lat,long to x,y
|
3344
|
// -----------------------------------------------------------------
|
3345
|
forward : function(p) {
|
3346
|
|
3347
|
var lon = p.x;
|
3348
|
var lat = p.y;
|
3349
|
|
3350
|
// convert to radians
|
3351
|
if ( lat <= 90.0 && lat >= -90.0 && lon <= 180.0 && lon >= -180.0) {
|
3352
|
//lon = lon * Proj4js.common.D2R;
|
3353
|
//lat = lat * Proj4js.common.D2R;
|
3354
|
} else {
|
3355
|
Proj4js.reportError("lcc:forward: llInputOutOfRange: "+ lon +" : " + lat);
|
3356
|
return null;
|
3357
|
}
|
3358
|
|
3359
|
var con = Math.abs( Math.abs(lat) - Proj4js.common.HALF_PI);
|
3360
|
var ts;
|
3361
|
if (con > Proj4js.common.EPSLN) {
|
3362
|
ts = Proj4js.common.tsfnz(this.e, lat, Math.sin(lat) );
|
3363
|
rh1 = this.a * this.f0 * Math.pow(ts, this.ns);
|
3364
|
} else {
|
3365
|
con = lat * this.ns;
|
3366
|
if (con <= 0) {
|
3367
|
Proj4js.reportError("lcc:forward: No Projection");
|
3368
|
return null;
|
3369
|
}
|
3370
|
rh1 = 0;
|
3371
|
}
|
3372
|
var theta = this.ns * Proj4js.common.adjust_lon(lon - this.long0);
|
3373
|
p.x = this.k0 * (rh1 * Math.sin(theta)) + this.x0;
|
3374
|
p.y = this.k0 * (this.rh - rh1 * Math.cos(theta)) + this.y0;
|
3375
|
|
3376
|
return p;
|
3377
|
},
|
3378
|
|
3379
|
// Lambert Conformal Conic inverse equations--mapping x,y to lat/long
|
3380
|
// -----------------------------------------------------------------
|
3381
|
inverse : function(p) {
|
3382
|
|
3383
|
var rh1, con, ts;
|
3384
|
var lat, lon;
|
3385
|
x = (p.x - this.x0)/this.k0;
|
3386
|
y = (this.rh - (p.y - this.y0)/this.k0);
|
3387
|
if (this.ns > 0) {
|
3388
|
rh1 = Math.sqrt (x * x + y * y);
|
3389
|
con = 1.0;
|
3390
|
} else {
|
3391
|
rh1 = -Math.sqrt (x * x + y * y);
|
3392
|
con = -1.0;
|
3393
|
}
|
3394
|
var theta = 0.0;
|
3395
|
if (rh1 != 0) {
|
3396
|
theta = Math.atan2((con * x),(con * y));
|
3397
|
}
|
3398
|
if ((rh1 != 0) || (this.ns > 0.0)) {
|
3399
|
con = 1.0/this.ns;
|
3400
|
ts = Math.pow((rh1/(this.a * this.f0)), con);
|
3401
|
lat = Proj4js.common.phi2z(this.e, ts);
|
3402
|
if (lat == -9999) return null;
|
3403
|
} else {
|
3404
|
lat = -Proj4js.common.HALF_PI;
|
3405
|
}
|
3406
|
lon = Proj4js.common.adjust_lon(theta/this.ns + this.long0);
|
3407
|
|
3408
|
p.x = lon;
|
3409
|
p.y = lat;
|
3410
|
return p;
|
3411
|
}
|
3412
|
};
|
3413
|
|
3414
|
|
3415
|
|
3416
|
|
3417
|
/* ======================================================================
|
3418
|
projCode/laea.js
|
3419
|
====================================================================== */
|
3420
|
|
3421
|
/*******************************************************************************
|
3422
|
NAME LAMBERT AZIMUTHAL EQUAL-AREA
|
3423
|
|
3424
|
PURPOSE: Transforms input longitude and latitude to Easting and
|
3425
|
Northing for the Lambert Azimuthal Equal-Area projection. The
|
3426
|
longitude and latitude must be in radians. The Easting
|
3427
|
and Northing values will be returned in meters.
|
3428
|
|
3429
|
PROGRAMMER DATE
|
3430
|
---------- ----
|
3431
|
D. Steinwand, EROS March, 1991
|
3432
|
|
3433
|
This function was adapted from the Lambert Azimuthal Equal Area projection
|
3434
|
code (FORTRAN) in the General Cartographic Transformation Package software
|
3435
|
which is available from the U.S. Geological Survey National Mapping Division.
|
3436
|
|
3437
|
ALGORITHM REFERENCES
|
3438
|
|
3439
|
1. "New Equal-Area Map Projections for Noncircular Regions", John P. Snyder,
|
3440
|
The American Cartographer, Vol 15, No. 4, October 1988, pp. 341-355.
|
3441
|
|
3442
|
2. Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
|
3443
|
Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
|
3444
|
State Government Printing Office, Washington D.C., 1987.
|
3445
|
|
3446
|
3. "Software Documentation for GCTP General Cartographic Transformation
|
3447
|
Package", U.S. Geological Survey National Mapping Division, May 1982.
|
3448
|
*******************************************************************************/
|
3449
|
|
3450
|
Proj4js.Proj.laea = {
|
3451
|
|
3452
|
|
3453
|
/* Initialize the Lambert Azimuthal Equal Area projection
|
3454
|
------------------------------------------------------*/
|
3455
|
init: function() {
|
3456
|
this.sin_lat_o=Math.sin(this.lat0);
|
3457
|
this.cos_lat_o=Math.cos(this.lat0);
|
3458
|
},
|
3459
|
|
3460
|
/* Lambert Azimuthal Equal Area forward equations--mapping lat,long to x,y
|
3461
|
-----------------------------------------------------------------------*/
|
3462
|
forward: function(p) {
|
3463
|
|
3464
|
/* Forward equations
|
3465
|
-----------------*/
|
3466
|
var lon=p.x;
|
3467
|
var lat=p.y;
|
3468
|
var delta_lon = Proj4js.common.adjust_lon(lon - this.long0);
|
3469
|
|
3470
|
//v 1.0
|
3471
|
var sin_lat=Math.sin(lat);
|
3472
|
var cos_lat=Math.cos(lat);
|
3473
|
|
3474
|
var sin_delta_lon=Math.sin(delta_lon);
|
3475
|
var cos_delta_lon=Math.cos(delta_lon);
|
3476
|
|
3477
|
var g =this.sin_lat_o * sin_lat +this.cos_lat_o * cos_lat * cos_delta_lon;
|
3478
|
if (g == -1.0) {
|
3479
|
Proj4js.reportError("laea:fwd:Point projects to a circle of radius "+ 2.0 * R);
|
3480
|
return null;
|
3481
|
}
|
3482
|
var ksp = this.a * Math.sqrt(2.0 / (1.0 + g));
|
3483
|
var x = ksp * cos_lat * sin_delta_lon + this.x0;
|
3484
|
var y = ksp * (this.cos_lat_o * sin_lat - this.sin_lat_o * cos_lat * cos_delta_lon) + this.x0;
|
3485
|
p.x = x;
|
3486
|
p.y = y
|
3487
|
return p;
|
3488
|
},//lamazFwd()
|
3489
|
|
3490
|
/* Inverse equations
|
3491
|
-----------------*/
|
3492
|
inverse: function(p) {
|
3493
|
p.x -= this.x0;
|
3494
|
p.y -= this.y0;
|
3495
|
|
3496
|
var Rh = Math.sqrt(p.x *p.x +p.y * p.y);
|
3497
|
var temp = Rh / (2.0 * this.a);
|
3498
|
|
3499
|
if (temp > 1) {
|
3500
|
Proj4js.reportError("laea:Inv:DataError");
|
3501
|
return null;
|
3502
|
}
|
3503
|
|
3504
|
var z = 2.0 * Proj4js.common.asinz(temp);
|
3505
|
var sin_z=Math.sin(z);
|
3506
|
var cos_z=Math.cos(z);
|
3507
|
|
3508
|
var lon =this.long0;
|
3509
|
if (Math.abs(Rh) > Proj4js.common.EPSLN) {
|
3510
|
var lat = Proj4js.common.asinz(this.sin_lat_o * cos_z +this. cos_lat_o * sin_z *p.y / Rh);
|
3511
|
var temp =Math.abs(this.lat0) - Proj4js.common.HALF_PI;
|
3512
|
if (Math.abs(temp) > Proj4js.common.EPSLN) {
|
3513
|
temp = cos_z -this.sin_lat_o * Math.sin(lat);
|
3514
|
if(temp!=0.0) lon=Proj4js.common.adjust_lon(this.long0+Math.atan2(p.x*sin_z*this.cos_lat_o,temp*Rh));
|
3515
|
} else if (this.lat0 < 0.0) {
|
3516
|
lon = Proj4js.common.adjust_lon(this.long0 - Math.atan2(-p.x,p.y));
|
3517
|
} else {
|
3518
|
lon = Proj4js.common.adjust_lon(this.long0 + Math.atan2(p.x, -p.y));
|
3519
|
}
|
3520
|
} else {
|
3521
|
lat = this.lat0;
|
3522
|
}
|
3523
|
//return(OK);
|
3524
|
p.x = lon;
|
3525
|
p.y = lat;
|
3526
|
return p;
|
3527
|
}//lamazInv()
|
3528
|
};
|
3529
|
|
3530
|
|
3531
|
|
3532
|
/* ======================================================================
|
3533
|
projCode/aeqd.js
|
3534
|
====================================================================== */
|
3535
|
|
3536
|
Proj4js.Proj.aeqd = {
|
3537
|
|
3538
|
init : function() {
|
3539
|
this.sin_p12=Math.sin(this.lat0)
|
3540
|
this.cos_p12=Math.cos(this.lat0)
|
3541
|
},
|
3542
|
|
3543
|
forward: function(p) {
|
3544
|
var lon=p.x;
|
3545
|
var lat=p.y;
|
3546
|
var ksp;
|
3547
|
|
3548
|
var sinphi=Math.sin(p.y);
|
3549
|
var cosphi=Math.cos(p.y);
|
3550
|
var dlon = Proj4js.common.adjust_lon(lon - this.long0);
|
3551
|
var coslon = Math.cos(dlon);
|
3552
|
var g = this.sin_p12 * sinphi + this.cos_p12 * cosphi * coslon;
|
3553
|
if (Math.abs(Math.abs(g) - 1.0) < Proj4js.common.EPSLN) {
|
3554
|
ksp = 1.0;
|
3555
|
if (g < 0.0) {
|
3556
|
Proj4js.reportError("aeqd:Fwd:PointError");
|
3557
|
return;
|
3558
|
}
|
3559
|
} else {
|
3560
|
var z = Math.acos(g);
|
3561
|
ksp = z/Math.sin(z);
|
3562
|
}
|
3563
|
p.x = this.x0 + this.a * ksp * cosphi * Math.sin(dlon);
|
3564
|
p.y = this.y0 + this.a * ksp * (this.cos_p12 * sinphi - this.sin_p12 * cosphi * coslon);
|
3565
|
return p;
|
3566
|
},
|
3567
|
|
3568
|
inverse: function(p){
|
3569
|
p.x -= this.x0;
|
3570
|
p.y -= this.y0;
|
3571
|
|
3572
|
var rh = Math.sqrt(p.x * p.x + p.y *p.y);
|
3573
|
if (rh > (2.0 * Proj4js.common.HALF_PI * this.a)) {
|
3574
|
Proj4js.reportError("aeqdInvDataError");
|
3575
|
return;
|
3576
|
}
|
3577
|
var z = rh / this.a;
|
3578
|
|
3579
|
var sinz=Math.sin(z)
|
3580
|
var cosz=Math.cos(z)
|
3581
|
|
3582
|
var lon = this.long0;
|
3583
|
var lat;
|
3584
|
if (Math.abs(rh) <= Proj4js.common.EPSLN) {
|
3585
|
lat = this.lat0;
|
3586
|
} else {
|
3587
|
lat = Proj4js.common.asinz(cosz * this.sin_p12 + (p.y * sinz * this.cos_p12) / rh);
|
3588
|
var con = Math.abs(this.lat0) - Proj4js.common.HALF_PI;
|
3589
|
if (Math.abs(con) <= Proj4js.common.EPSLN) {
|
3590
|
if (lat0 >= 0.0) {
|
3591
|
lon = Proj4js.common.adjust_lon(this.long0 + Math.atan2(p.x , -p.y));
|
3592
|
} else {
|
3593
|
lon = Proj4js.common.adjust_lon(this.long0 - Math.atan2(-p.x , p.y));
|
3594
|
}
|
3595
|
} else {
|
3596
|
con = cosz - this.sin_p12 * Math.sin(lat);
|
3597
|
if ((Math.abs(con) < Proj4js.common.EPSLN) && (Math.abs(p.x) < Proj4js.common.EPSLN)) {
|
3598
|
//no-op, just keep the lon value as is
|
3599
|
} else {
|
3600
|
var temp = Math.atan2((p.x * sinz * this.cos_p12), (con * rh));
|
3601
|
lon = Proj4js.common.adjust_lon(this.long0 + Math.atan2((p.x * sinz * this.cos_p12), (con * rh)));
|
3602
|
}
|
3603
|
}
|
3604
|
}
|
3605
|
|
3606
|
p.x = lon;
|
3607
|
p.y = lat;
|
3608
|
return p;
|
3609
|
}
|
3610
|
};
|
3611
|
/* ======================================================================
|
3612
|
projCode/moll.js
|
3613
|
====================================================================== */
|
3614
|
|
3615
|
/*******************************************************************************
|
3616
|
NAME MOLLWEIDE
|
3617
|
|
3618
|
PURPOSE: Transforms input longitude and latitude to Easting and
|
3619
|
Northing for the MOllweide projection. The
|
3620
|
longitude and latitude must be in radians. The Easting
|
3621
|
and Northing values will be returned in meters.
|
3622
|
|
3623
|
PROGRAMMER DATE
|
3624
|
---------- ----
|
3625
|
D. Steinwand, EROS May, 1991; Updated Sept, 1992; Updated Feb, 1993
|
3626
|
S. Nelson, EDC Jun, 2993; Made corrections in precision and
|
3627
|
number of iterations.
|
3628
|
|
3629
|
ALGORITHM REFERENCES
|
3630
|
|
3631
|
1. Snyder, John P. and Voxland, Philip M., "An Album of Map Projections",
|
3632
|
U.S. Geological Survey Professional Paper 1453 , United State Government
|
3633
|
Printing Office, Washington D.C., 1989.
|
3634
|
|
3635
|
2. Snyder, John P., "Map Projections--A Working Manual", U.S. Geological
|
3636
|
Survey Professional Paper 1395 (Supersedes USGS Bulletin 1532), United
|
3637
|
State Government Printing Office, Washington D.C., 1987.
|
3638
|
*******************************************************************************/
|
3639
|
|
3640
|
Proj4js.Proj.moll = {
|
3641
|
|
3642
|
/* Initialize the Mollweide projection
|
3643
|
------------------------------------*/
|
3644
|
init: function(){
|
3645
|
//no-op
|
3646
|
},
|
3647
|
|
3648
|
/* Mollweide forward equations--mapping lat,long to x,y
|
3649
|
----------------------------------------------------*/
|
3650
|
forward: function(p) {
|
3651
|
|
3652
|
/* Forward equations
|
3653
|
-----------------*/
|
3654
|
var lon=p.x;
|
3655
|
var lat=p.y;
|
3656
|
|
3657
|
var delta_lon = Proj4js.common.adjust_lon(lon - this.long0);
|
3658
|
var theta = lat;
|
3659
|
var con = Proj4js.common.PI * Math.sin(lat);
|
3660
|
|
3661
|
/* Iterate using the Newton-Raphson method to find theta
|
3662
|
-----------------------------------------------------*/
|
3663
|
for (var i=0;;i++) {
|
3664
|
var delta_theta = -(theta + Math.sin(theta) - con)/ (1.0 + Math.cos(theta));
|
3665
|
theta += delta_theta;
|
3666
|
if (Math.abs(delta_theta) < Proj4js.common.EPSLN) break;
|
3667
|
if (i >= 50) {
|
3668
|
Proj4js.reportError("moll:Fwd:IterationError");
|
3669
|
//return(241);
|
3670
|
}
|
3671
|
}
|
3672
|
theta /= 2.0;
|
3673
|
|
3674
|
/* If the latitude is 90 deg, force the x coordinate to be "0 + false easting"
|
3675
|
this is done here because of precision problems with "cos(theta)"
|
3676
|
--------------------------------------------------------------------------*/
|
3677
|
if (Proj4js.common.PI/2 - Math.abs(lat) < Proj4js.common.EPSLN) delta_lon =0;
|
3678
|
var x = 0.900316316158 * this.R * delta_lon * Math.cos(theta) + this.x0;
|
3679
|
var y = 1.4142135623731 * this.R * Math.sin(theta) + this.y0;
|
3680
|
|
3681
|
p.x=x;
|
3682
|
p.y=y;
|
3683
|
return p;
|
3684
|
},
|
3685
|
|
3686
|
inverse: function(p){
|
3687
|
var theta;
|
3688
|
var arg;
|
3689
|
|
3690
|
/* Inverse equations
|
3691
|
-----------------*/
|
3692
|
p.x-= this.x0;
|
3693
|
//~ p.y -= this.y0;
|
3694
|
var arg = p.y / (1.4142135623731 * this.R);
|
3695
|
|
3696
|
/* Because of division by zero problems, 'arg' can not be 1.0. Therefore
|
3697
|
a number very close to one is used instead.
|
3698
|
-------------------------------------------------------------------*/
|
3699
|
if(Math.abs(arg) > 0.999999999999) arg=0.999999999999;
|
3700
|
var theta =Math.asin(arg);
|
3701
|
var lon = Proj4js.common.adjust_lon(this.long0 + (p.x / (0.900316316158 * this.R * Math.cos(theta))));
|
3702
|
if(lon < (-Proj4js.common.PI)) lon= -Proj4js.common.PI;
|
3703
|
if(lon > Proj4js.common.PI) lon= Proj4js.common.PI;
|
3704
|
arg = (2.0 * theta + Math.sin(2.0 * theta)) / Proj4js.common.PI;
|
3705
|
if(Math.abs(arg) > 1.0)arg=1.0;
|
3706
|
var lat = Math.asin(arg);
|
3707
|
//return(OK);
|
3708
|
|
3709
|
p.x=lon;
|
3710
|
p.y=lat;
|
3711
|
return p;
|
3712
|
}
|
3713
|
};
|
3714
|
|