Project

General

Profile

Download (10.8 KB) Statistics
| Branch: | Tag: | Revision:
1
/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
2
 * full list of contributors). Published under the 2-clause BSD license.
3
 * See license.txt in the OpenLayers distribution or repository for the
4
 * full text of the license. */
5

    
6
/**
7
 * @requires OpenLayers/BaseTypes/Class.js
8
 * @requires OpenLayers/Util.js
9
 */
10

    
11
/**
12
 * Namespace: OpenLayers.Projection
13
 * Methods for coordinate transforms between coordinate systems.  By default,
14
 *     OpenLayers ships with the ability to transform coordinates between
15
 *     geographic (EPSG:4326) and web or spherical mercator (EPSG:900913 et al.)
16
 *     coordinate reference systems.  See the <transform> method for details
17
 *     on usage.
18
 *
19
 * Additional transforms may be added by using the <proj4js at http://proj4js.org/>
20
 *     library.  If the proj4js library is included, the <transform> method 
21
 *     will work between any two coordinate reference systems with proj4js 
22
 *     definitions.
23
 *
24
 * If the proj4js library is not included, or if you wish to allow transforms
25
 *     between arbitrary coordinate reference systems, use the <addTransform>
26
 *     method to register a custom transform method.
27
 */
28
OpenLayers.Projection = OpenLayers.Class({
29

    
30
    /**
31
     * Property: proj
32
     * {Object} Proj4js.Proj instance.
33
     */
34
    proj: null,
35
    
36
    /**
37
     * Property: projCode
38
     * {String}
39
     */
40
    projCode: null,
41
    
42
    /**
43
     * Property: titleRegEx
44
     * {RegExp} regular expression to strip the title from a proj4js definition
45
     */
46
    titleRegEx: /\+title=[^\+]*/,
47

    
48
    /**
49
     * Constructor: OpenLayers.Projection
50
     * This class offers several methods for interacting with a wrapped 
51
     *     pro4js projection object. 
52
     *
53
     * Parameters:
54
     * projCode - {String} A string identifying the Well Known Identifier for
55
     *    the projection.
56
     * options - {Object} An optional object to set additional properties
57
     *     on the projection.
58
     *
59
     * Returns:
60
     * {<OpenLayers.Projection>} A projection object.
61
     */
62
    initialize: function(projCode, options) {
63
        OpenLayers.Util.extend(this, options);
64
        this.projCode = projCode;
65
        if (typeof Proj4js == "object") {
66
            this.proj = new Proj4js.Proj(projCode);
67
        }
68
    },
69
    
70
    /**
71
     * APIMethod: getCode
72
     * Get the string SRS code.
73
     *
74
     * Returns:
75
     * {String} The SRS code.
76
     */
77
    getCode: function() {
78
        return this.proj ? this.proj.srsCode : this.projCode;
79
    },
80
   
81
    /**
82
     * APIMethod: getUnits
83
     * Get the units string for the projection -- returns null if 
84
     *     proj4js is not available.
85
     *
86
     * Returns:
87
     * {String} The units abbreviation.
88
     */
89
    getUnits: function() {
90
        return this.proj ? this.proj.units : null;
91
    },
92

    
93
    /**
94
     * Method: toString
95
     * Convert projection to string (getCode wrapper).
96
     *
97
     * Returns:
98
     * {String} The projection code.
99
     */
100
    toString: function() {
101
        return this.getCode();
102
    },
103

    
104
    /**
105
     * Method: equals
106
     * Test equality of two projection instances.  Determines equality based
107
     *     soley on the projection code.
108
     *
109
     * Returns:
110
     * {Boolean} The two projections are equivalent.
111
     */
112
    equals: function(projection) {
113
        var p = projection, equals = false;
114
        if (p) {
115
            if (!(p instanceof OpenLayers.Projection)) {
116
                p = new OpenLayers.Projection(p);
117
            }
118
            if ((typeof Proj4js == "object") && this.proj.defData && p.proj.defData) {
119
                equals = this.proj.defData.replace(this.titleRegEx, "") ==
120
                    p.proj.defData.replace(this.titleRegEx, "");
121
            } else if (p.getCode) {
122
                var source = this.getCode(), target = p.getCode();
123
                equals = source == target ||
124
                    !!OpenLayers.Projection.transforms[source] &&
125
                    OpenLayers.Projection.transforms[source][target] ===
126
                        OpenLayers.Projection.nullTransform;
127
            }
128
        }
129
        return equals;   
130
    },
131

    
132
    /* Method: destroy
133
     * Destroy projection object.
134
     */
135
    destroy: function() {
136
        delete this.proj;
137
        delete this.projCode;
138
    },
139
    
140
    CLASS_NAME: "OpenLayers.Projection" 
141
});     
142

    
143
/**
144
 * Property: transforms
145
 * {Object} Transforms is an object, with from properties, each of which may
146
 * have a to property. This allows you to define projections without 
147
 * requiring support for proj4js to be included.
148
 *
149
 * This object has keys which correspond to a 'source' projection object.  The
150
 * keys should be strings, corresponding to the projection.getCode() value.
151
 * Each source projection object should have a set of destination projection
152
 * keys included in the object. 
153
 * 
154
 * Each value in the destination object should be a transformation function,
155
 * where the function is expected to be passed an object with a .x and a .y
156
 * property.  The function should return the object, with the .x and .y
157
 * transformed according to the transformation function.
158
 *
159
 * Note - Properties on this object should not be set directly.  To add a
160
 *     transform method to this object, use the <addTransform> method.  For an
161
 *     example of usage, see the OpenLayers.Layer.SphericalMercator file.
162
 */
163
OpenLayers.Projection.transforms = {};
164

    
165
/**
166
 * APIProperty: defaults
167
 * {Object} Defaults for the SRS codes known to OpenLayers (currently
168
 * EPSG:4326, CRS:84, urn:ogc:def:crs:EPSG:6.6:4326, EPSG:900913, EPSG:3857,
169
 * EPSG:102113 and EPSG:102100). Keys are the SRS code, values are units,
170
 * maxExtent (the validity extent for the SRS) and yx (true if this SRS is
171
 * known to have a reverse axis order).
172
 */
173
OpenLayers.Projection.defaults = {
174
    "EPSG:4326": {
175
        units: "degrees",
176
        maxExtent: [-180, -90, 180, 90],
177
        yx: true
178
    },
179
    "CRS:84": {
180
        units: "degrees",
181
        maxExtent: [-180, -90, 180, 90]
182
    },
183
    "EPSG:900913": {
184
        units: "m",
185
        maxExtent: [-20037508.34, -20037508.34, 20037508.34, 20037508.34]
186
    }
187
};
188

    
189
/**
190
 * APIMethod: addTransform
191
 * Set a custom transform method between two projections.  Use this method in
192
 *     cases where the proj4js lib is not available or where custom projections
193
 *     need to be handled.
194
 *
195
 * Parameters:
196
 * from - {String} The code for the source projection
197
 * to - {String} the code for the destination projection
198
 * method - {Function} A function that takes a point as an argument and
199
 *     transforms that point from the source to the destination projection
200
 *     in place.  The original point should be modified.
201
 */
202
OpenLayers.Projection.addTransform = function(from, to, method) {
203
    if (method === OpenLayers.Projection.nullTransform) {
204
        var defaults = OpenLayers.Projection.defaults[from];
205
        if (defaults && !OpenLayers.Projection.defaults[to]) {
206
            OpenLayers.Projection.defaults[to] = defaults;
207
        }
208
    }
209
    if(!OpenLayers.Projection.transforms[from]) {
210
        OpenLayers.Projection.transforms[from] = {};
211
    }
212
    OpenLayers.Projection.transforms[from][to] = method;
213
};
214

    
215
/**
216
 * APIMethod: transform
217
 * Transform a point coordinate from one projection to another.  Note that
218
 *     the input point is transformed in place.
219
 * 
220
 * Parameters:
221
 * point - {<OpenLayers.Geometry.Point> | Object} An object with x and y
222
 *     properties representing coordinates in those dimensions.
223
 * source - {OpenLayers.Projection} Source map coordinate system
224
 * dest - {OpenLayers.Projection} Destination map coordinate system
225
 *
226
 * Returns:
227
 * point - {object} A transformed coordinate.  The original point is modified.
228
 */
229
OpenLayers.Projection.transform = function(point, source, dest) {
230
    if (source && dest) {
231
        if (!(source instanceof OpenLayers.Projection)) {
232
            source = new OpenLayers.Projection(source);
233
        }
234
        if (!(dest instanceof OpenLayers.Projection)) {
235
            dest = new OpenLayers.Projection(dest);
236
        }
237
        if (source.proj && dest.proj) {
238
            point = Proj4js.transform(source.proj, dest.proj, point);
239
        } else {
240
            var sourceCode = source.getCode();
241
            var destCode = dest.getCode();
242
            var transforms = OpenLayers.Projection.transforms;
243
            if (transforms[sourceCode] && transforms[sourceCode][destCode]) {
244
                transforms[sourceCode][destCode](point);
245
            }
246
        }
247
    }
248
    return point;
249
};
250

    
251
/**
252
 * APIFunction: nullTransform
253
 * A null transformation - useful for defining projection aliases when
254
 * proj4js is not available:
255
 *
256
 * (code)
257
 * OpenLayers.Projection.addTransform("EPSG:3857", "EPSG:900913",
258
 *     OpenLayers.Projection.nullTransform);
259
 * OpenLayers.Projection.addTransform("EPSG:900913", "EPSG:3857",
260
 *     OpenLayers.Projection.nullTransform);
261
 * (end)
262
 */
263
OpenLayers.Projection.nullTransform = function(point) {
264
    return point;
265
};
266

    
267
/**
268
 * Note: Transforms for web mercator <-> geographic
269
 * OpenLayers recognizes EPSG:3857, EPSG:900913, EPSG:102113 and EPSG:102100.
270
 * OpenLayers originally started referring to EPSG:900913 as web mercator.
271
 * The EPSG has declared EPSG:3857 to be web mercator.
272
 * ArcGIS 10 recognizes the EPSG:3857, EPSG:102113, and EPSG:102100 as
273
 * equivalent.  See http://blogs.esri.com/Dev/blogs/arcgisserver/archive/2009/11/20/ArcGIS-Online-moving-to-Google-_2F00_-Bing-tiling-scheme_3A00_-What-does-this-mean-for-you_3F00_.aspx#12084.
274
 * For geographic, OpenLayers recognizes EPSG:4326, CRS:84 and
275
 * urn:ogc:def:crs:EPSG:6.6:4326. OpenLayers also knows about the reverse axis
276
 * order for EPSG:4326. 
277
 */
278
(function() {
279

    
280
    var pole = 20037508.34;
281

    
282
    function inverseMercator(xy) {
283
        xy.x = 180 * xy.x / pole;
284
        xy.y = 180 / Math.PI * (2 * Math.atan(Math.exp((xy.y / pole) * Math.PI)) - Math.PI / 2);
285
        return xy;
286
    }
287

    
288
    function forwardMercator(xy) {
289
        xy.x = xy.x * pole / 180;
290
        var y = Math.log(Math.tan((90 + xy.y) * Math.PI / 360)) / Math.PI * pole;
291
        xy.y = Math.max(-20037508.34, Math.min(y, 20037508.34));
292
        return xy;
293
    }
294

    
295
    function map(base, codes) {
296
        var add = OpenLayers.Projection.addTransform;
297
        var same = OpenLayers.Projection.nullTransform;
298
        var i, len, code, other, j;
299
        for (i=0, len=codes.length; i<len; ++i) {
300
            code = codes[i];
301
            add(base, code, forwardMercator);
302
            add(code, base, inverseMercator);
303
            for (j=i+1; j<len; ++j) {
304
                other = codes[j];
305
                add(code, other, same);
306
                add(other, code, same);
307
            }
308
        }
309
    }
310
    
311
    // list of equivalent codes for web mercator
312
    var mercator = ["EPSG:900913", "EPSG:3857", "EPSG:102113", "EPSG:102100"],
313
        geographic = ["CRS:84", "urn:ogc:def:crs:EPSG:6.6:4326", "EPSG:4326"],
314
        i;
315
    for (i=mercator.length-1; i>=0; --i) {
316
        map(mercator[i], geographic);
317
    }
318
    for (i=geographic.length-1; i>=0; --i) {
319
        map(geographic[i], mercator);
320
    }
321

    
322
})();
(18-18/35)