Update API to work with custom transforms, including proj4js
All transparent proj4js handling is now in ol.proj.get, and a new addCoordinateTransforms function makes it easy to configure custom transform functions. ol.Proj4jsProjection is no longer needed.
This commit is contained in:
@@ -275,34 +275,28 @@ olx.OverlayOptions.prototype.insertFirst;
|
||||
|
||||
|
||||
/**
|
||||
* Object literal with config options for the Proj4js projection.
|
||||
* @typedef {{code: string,
|
||||
* extent: (ol.Extent|undefined),
|
||||
* global: (boolean|undefined)}}
|
||||
* Object literal with forward and inverse coordinate transforms.
|
||||
* @typedef {{forward: function(ol.Coordinate): ol.Coordinate,
|
||||
* inverse: function(ol.Coordinate): ol.Coordinate}}
|
||||
* @api
|
||||
*/
|
||||
olx.Proj4jsProjectionOptions;
|
||||
olx.CoordinateTransforms;
|
||||
|
||||
|
||||
/**
|
||||
* The SRS identifier code, e.g. `EPSG:31256`.
|
||||
* @type {string}
|
||||
* The forward transform function that takes a {@link ol.Coordinate} as argument
|
||||
* and returns the transformed {@link ol.Coordinate}.
|
||||
* @type {function(ol.Coordinate): ol.Coordinate}
|
||||
*/
|
||||
olx.Proj4jsProjectionOptions.prototype.code;
|
||||
olx.CoordinateTransforms.prototype.forward;
|
||||
|
||||
|
||||
/**
|
||||
* The validity extent for the SRS.
|
||||
* @type {ol.Extent|undefined}
|
||||
* The inverse transform function that takes a {@link ol.Coordinate} as argument
|
||||
* and returns the transformed {@link ol.Coordinate}.
|
||||
* @type {function(ol.Coordinate): ol.Coordinate}
|
||||
*/
|
||||
olx.Proj4jsProjectionOptions.prototype.extent;
|
||||
|
||||
|
||||
/**
|
||||
* Whether the projection is valid for the whole globe. Default is `false`.
|
||||
* @type {boolean|undefined}
|
||||
*/
|
||||
olx.Proj4jsProjectionOptions.prototype.global;
|
||||
olx.CoordinateTransforms.prototype.inverse;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -64,10 +64,10 @@ ol.proj.METERS_PER_UNIT[ol.proj.Units.METERS] = 1;
|
||||
* geographic (EPSG:4326) and web or spherical mercator (EPSG:3857)
|
||||
* coordinate reference systems.
|
||||
*
|
||||
* Additional transforms may be added by using the
|
||||
* {@link http://proj4js.org/|proj4js} library. If the proj4js library is
|
||||
* included, the <transform> method will work between any two coordinate
|
||||
* reference systems with proj4js definitions.
|
||||
* Additional transforms may be added by using the {@link http://proj4js.org/}
|
||||
* library. If the proj4js library is loaded, transforms will work between any
|
||||
* coordinate reference systems with proj4js definitions. These definitions can
|
||||
* be obtained from {@link http://epsg.io/}.
|
||||
*
|
||||
* @constructor
|
||||
* @param {olx.ProjectionOptions} options Projection options.
|
||||
@@ -136,19 +136,6 @@ ol.proj.Projection.prototype.getExtent = function() {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get the resolution of the point in degrees. For projections with degrees as
|
||||
* the unit this will simply return the provided resolution. For other
|
||||
* projections the point resolution is estimated by transforming the center
|
||||
* pixel to EPSG:4326, measuring its width and height on the normal sphere,
|
||||
* and taking the average of the width and height.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {ol.Coordinate} point Point.
|
||||
* @return {number} Point resolution.
|
||||
*/
|
||||
ol.proj.Projection.prototype.getPointResolution = goog.abstractMethod;
|
||||
|
||||
|
||||
/**
|
||||
* Get the units of this projection.
|
||||
* @return {ol.proj.Units} Units.
|
||||
@@ -209,80 +196,42 @@ ol.proj.Projection.prototype.setDefaultTileGrid = function(tileGrid) {
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.proj.Projection}
|
||||
* @param {Proj4js.Proj} proj4jsProj Proj4js projection.
|
||||
* @param {olx.Proj4jsProjectionOptions} options Proj4js projection options.
|
||||
* @private
|
||||
* @struct
|
||||
* Set the validity extent for this projection.
|
||||
* @param {ol.Extent} extent Extent.
|
||||
* @api
|
||||
*/
|
||||
ol.Proj4jsProjection_ = function(proj4jsProj, options) {
|
||||
|
||||
var units = /** @type {ol.proj.Units} */ (proj4jsProj.units);
|
||||
|
||||
var config = /** @type {olx.ProjectionOptions} */ ({
|
||||
units: units,
|
||||
axisOrientation: proj4jsProj.axis
|
||||
});
|
||||
goog.object.extend(config, options);
|
||||
|
||||
goog.base(this, config);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Proj4js.Proj}
|
||||
*/
|
||||
this.proj4jsProj_ = proj4jsProj;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?ol.TransformFunction}
|
||||
*/
|
||||
this.toEPSG4326_ = null;
|
||||
|
||||
};
|
||||
goog.inherits(ol.Proj4jsProjection_, ol.proj.Projection);
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
ol.Proj4jsProjection_.prototype.getMetersPerUnit = function() {
|
||||
var metersPerUnit = this.proj4jsProj_.to_meter;
|
||||
if (!goog.isDef(metersPerUnit)) {
|
||||
metersPerUnit = ol.proj.METERS_PER_UNIT[this.units_];
|
||||
}
|
||||
return metersPerUnit;
|
||||
ol.proj.Projection.prototype.setExtent = function(extent) {
|
||||
this.extent_ = extent;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Get the resolution of the point in degrees. For projections with degrees as
|
||||
* the unit this will simply return the provided resolution. For other
|
||||
* projections the point resolution is estimated by transforming the center
|
||||
* pixel to EPSG:4326, measuring its width and height on the normal sphere,
|
||||
* and taking the average of the width and height.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {ol.Coordinate} point Point.
|
||||
* @return {number} Point resolution.
|
||||
*/
|
||||
ol.Proj4jsProjection_.prototype.getPointResolution =
|
||||
function(resolution, point) {
|
||||
ol.proj.Projection.prototype.getPointResolution = function(resolution, point) {
|
||||
if (this.getUnits() == ol.proj.Units.DEGREES) {
|
||||
return resolution;
|
||||
} else {
|
||||
// Estimate point resolution by transforming the center pixel to EPSG:4326,
|
||||
// measuring its width and height on the normal sphere, and taking the
|
||||
// average of the width and height.
|
||||
if (goog.isNull(this.toEPSG4326_)) {
|
||||
this.toEPSG4326_ = ol.proj.getTransformFromProjections(
|
||||
this, ol.proj.getProj4jsProjectionFromCode_({
|
||||
code: 'EPSG:4326',
|
||||
extent: null
|
||||
}));
|
||||
}
|
||||
var toEPSG4326 = ol.proj.getTransformFromProjections(
|
||||
this, ol.proj.get('EPSG:4326'));
|
||||
var vertices = [
|
||||
point[0] - resolution / 2, point[1],
|
||||
point[0] + resolution / 2, point[1],
|
||||
point[0], point[1] - resolution / 2,
|
||||
point[0], point[1] + resolution / 2
|
||||
];
|
||||
vertices = this.toEPSG4326_(vertices, vertices, 2);
|
||||
vertices = toEPSG4326(vertices, vertices, 2);
|
||||
var width = ol.sphere.NORMAL.haversineDistance(
|
||||
vertices.slice(0, 2), vertices.slice(2, 4));
|
||||
var height = ol.sphere.NORMAL.haversineDistance(
|
||||
@@ -298,21 +247,6 @@ ol.Proj4jsProjection_.prototype.getPointResolution =
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Proj4js.Proj} Proj4js projection.
|
||||
*/
|
||||
ol.Proj4jsProjection_.prototype.getProj4jsProj = function() {
|
||||
return this.proj4jsProj_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Object.<string, ol.Proj4jsProjection_>}
|
||||
*/
|
||||
ol.proj.proj4jsProjections_ = {};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Object.<string, ol.proj.Projection>}
|
||||
@@ -331,17 +265,21 @@ ol.proj.transforms_ = {};
|
||||
* Registers transformation functions that don't alter coordinates. Those allow
|
||||
* to transform between projections with equal meaning.
|
||||
*
|
||||
* @param {Array.<ol.proj.Projection>} projections Projections.
|
||||
* @param {Array.<ol.proj.Projection|olx.ProjectionOptions>} projections
|
||||
* Projections.
|
||||
* @return {Array.<ol.proj.Projection>} The added equivalent projections.
|
||||
* @api
|
||||
*/
|
||||
ol.proj.addEquivalentProjections = function(projections) {
|
||||
ol.proj.addProjections(projections);
|
||||
goog.array.forEach(projections, function(source) {
|
||||
goog.array.forEach(projections, function(destination) {
|
||||
var addedProjections = ol.proj.addProjections(projections);
|
||||
goog.array.forEach(addedProjections, function(source) {
|
||||
goog.array.forEach(addedProjections, function(destination) {
|
||||
if (source !== destination) {
|
||||
ol.proj.addTransform(source, destination, ol.proj.cloneTransform);
|
||||
}
|
||||
});
|
||||
});
|
||||
return addedProjections;
|
||||
};
|
||||
|
||||
|
||||
@@ -369,39 +307,37 @@ ol.proj.addEquivalentTransforms =
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.Proj4jsProjection_} proj4jsProjection Proj4js projection.
|
||||
* @private
|
||||
*/
|
||||
ol.proj.addProj4jsProjection_ = function(proj4jsProjection) {
|
||||
var proj4jsProjections = ol.proj.proj4jsProjections_;
|
||||
var code = proj4jsProjection.getCode();
|
||||
goog.asserts.assert(!goog.object.containsKey(proj4jsProjections, code));
|
||||
proj4jsProjections[code] = proj4jsProjection;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Add a Projection object to the list of supported projections.
|
||||
*
|
||||
* @param {ol.proj.Projection} projection Projection object.
|
||||
* @param {ol.proj.Projection|olx.ProjectionOptions} projection Projection
|
||||
* instance or configuration.
|
||||
* @return {ol.proj.Projection} The added projection.
|
||||
* @api
|
||||
*/
|
||||
ol.proj.addProjection = function(projection) {
|
||||
var projections = ol.proj.projections_;
|
||||
var code = projection.getCode();
|
||||
projections[code] = projection;
|
||||
ol.proj.addTransform(projection, projection, ol.proj.cloneTransform);
|
||||
var proj = projection instanceof ol.proj.Projection ?
|
||||
projection :
|
||||
new ol.proj.Projection(/** @type {olx.ProjectionOptions} */ (projection));
|
||||
var code = proj.getCode();
|
||||
projections[code] = proj;
|
||||
ol.proj.addTransform(proj, proj, ol.proj.cloneTransform);
|
||||
return proj;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<ol.proj.Projection>} projections Projections.
|
||||
* @param {Array.<ol.proj.Projection|olx.ProjectionOptions>} projections
|
||||
* Projections.
|
||||
* @return {Array.<ol.proj.Projection>} The added projections.
|
||||
*/
|
||||
ol.proj.addProjections = function(projections) {
|
||||
var addedProjections = [];
|
||||
goog.array.forEach(projections, function(projection) {
|
||||
ol.proj.addProjection(projection);
|
||||
addedProjections.push(ol.proj.addProjection(projection));
|
||||
});
|
||||
return addedProjections;
|
||||
};
|
||||
|
||||
|
||||
@@ -409,9 +345,6 @@ ol.proj.addProjections = function(projections) {
|
||||
* FIXME empty description for jsdoc
|
||||
*/
|
||||
ol.proj.clearAllProjections = function() {
|
||||
if (ol.ENABLE_PROJ4JS) {
|
||||
ol.proj.proj4jsProjections_ = {};
|
||||
}
|
||||
ol.proj.projections_ = {};
|
||||
ol.proj.transforms_ = {};
|
||||
};
|
||||
@@ -453,6 +386,62 @@ ol.proj.addTransform = function(source, destination, transformFn) {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Registers coordinate transform functions to convert coordinates between the
|
||||
* source projection and the destination projection.
|
||||
*
|
||||
* @param {ol.proj.ProjectionLike} source Source projection.
|
||||
* @param {ol.proj.ProjectionLike} destination Destination projection.
|
||||
* @param {olx.CoordinateTransforms} transforms Forward and inverse transform
|
||||
* functions.
|
||||
* @api
|
||||
*/
|
||||
ol.proj.addCoordinateTransforms = function(source, destination, transforms) {
|
||||
var sourceProj = ol.proj.get(source);
|
||||
var destProj = ol.proj.get(destination);
|
||||
var forward, inverse;
|
||||
if (sourceProj === destProj) {
|
||||
forward = ol.proj.cloneTransform;
|
||||
inverse = ol.proj.cloneTransform;
|
||||
} else {
|
||||
forward =
|
||||
ol.proj.createTransformFromCoordinateTransform(transforms.forward);
|
||||
inverse =
|
||||
ol.proj.createTransformFromCoordinateTransform(transforms.inverse);
|
||||
}
|
||||
ol.proj.addTransform(sourceProj, destProj, forward);
|
||||
ol.proj.addTransform(destProj, sourceProj, inverse);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Creates a {@link ol.TransformFunction} from a simple 2D coordinate transform
|
||||
* function.
|
||||
* @param {function(ol.Coordinate): ol.Coordinate} transform Coordinate
|
||||
* transform.
|
||||
* @return {ol.TransformFunction} Transform function.
|
||||
*/
|
||||
ol.proj.createTransformFromCoordinateTransform = function(transform) {
|
||||
return /** @type {ol.TransformFunction} */ (
|
||||
function(input, opt_output, opt_dimension) {
|
||||
var length = input.length;
|
||||
var dimension = goog.isDef(opt_dimension) ? opt_dimension : 2;
|
||||
var output = goog.isDef(opt_output) ? opt_output : new Array(length);
|
||||
var point, i, j;
|
||||
for (i = 0; i < length; i += dimension) {
|
||||
point = transform([input[i], input[i + 1]]);
|
||||
output[i] = point[0];
|
||||
output[i + 1] = point[1];
|
||||
for (j = dimension - 1; j >= 2; --j) {
|
||||
output[i + j] = input[i + j];
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Unregisters the conversion function to convert coordinates from the source
|
||||
* projection to the destination projection. This method is used to clean up
|
||||
@@ -493,16 +482,44 @@ ol.proj.get = function(projectionLike) {
|
||||
projection = projectionLike;
|
||||
} else if (goog.isString(projectionLike)) {
|
||||
var code = projectionLike;
|
||||
projection = ol.proj.projections_[code];
|
||||
var projections = ol.proj.projections_;
|
||||
projection = projections[code];
|
||||
if (ol.HAVE_PROJ4JS && !goog.isDef(projection)) {
|
||||
projection = ol.proj.getProj4jsProjectionFromCode_({
|
||||
code: code,
|
||||
extent: null
|
||||
});
|
||||
}
|
||||
if (!goog.isDef(projection)) {
|
||||
goog.asserts.assert(goog.isDef(projection));
|
||||
projection = null;
|
||||
var proj4jsProj;
|
||||
var def = proj4.defs[code];
|
||||
if (goog.isDef(def)) {
|
||||
proj4jsProj = new proj4.Proj(code);
|
||||
var units = proj4jsProj.units;
|
||||
if (!goog.isDef(units)) {
|
||||
if (goog.isDef(proj4jsProj.to_meter)) {
|
||||
units = proj4jsProj.to_meter.toString();
|
||||
ol.proj.METERS_PER_UNIT[units] = proj4jsProj.to_meter;
|
||||
}
|
||||
}
|
||||
projection = new ol.proj.Projection({
|
||||
code: code,
|
||||
units: units,
|
||||
axisOrientation: proj4jsProj.axis
|
||||
});
|
||||
ol.proj.addProjection(projection);
|
||||
var currentCode, currentDef, currentProj, currentProj4jsProj;
|
||||
for (currentCode in projections) {
|
||||
currentDef = proj4.defs[currentCode];
|
||||
if (goog.isDef(currentDef)) {
|
||||
currentProj4jsProj = new proj4.Proj(currentCode);
|
||||
currentProj = ol.proj.get(currentCode);
|
||||
if (currentDef === def) {
|
||||
ol.proj.addEquivalentProjections([currentProj, projection]);
|
||||
} else {
|
||||
ol.proj.addCoordinateTransforms(currentProj, projection,
|
||||
proj4(currentProj4jsProj, proj4jsProj));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
goog.asserts.assert(goog.isDef(projection));
|
||||
projection = null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
projection = null;
|
||||
@@ -511,32 +528,6 @@ ol.proj.get = function(projectionLike) {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {olx.Proj4jsProjectionOptions} options Proj4js projection options.
|
||||
* @private
|
||||
* @return {ol.Proj4jsProjection_} Proj4js projection.
|
||||
*/
|
||||
ol.proj.getProj4jsProjectionFromCode_ = function(options) {
|
||||
var code = options.code;
|
||||
var proj4jsProjections = ol.proj.proj4jsProjections_;
|
||||
var proj4jsProjection = proj4jsProjections[code];
|
||||
if (!goog.isDef(proj4jsProjection)) {
|
||||
var proj4jsProj = new Proj4js.Proj(code);
|
||||
var srsCode = proj4jsProj.srsCode;
|
||||
proj4jsProjection = proj4jsProjections[srsCode];
|
||||
if (!goog.isDef(proj4jsProjection)) {
|
||||
var config = /** @type {olx.Proj4jsProjectionOptions} */
|
||||
(goog.object.clone(options));
|
||||
config.code = srsCode;
|
||||
proj4jsProjection = new ol.Proj4jsProjection_(proj4jsProj, config);
|
||||
proj4jsProjections[srsCode] = proj4jsProjection;
|
||||
}
|
||||
proj4jsProjections[code] = proj4jsProjection;
|
||||
}
|
||||
return proj4jsProjection;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checks if two projections are the same, that is every coordinate in one
|
||||
* projection does represent the same geographic point as the same coordinate in
|
||||
@@ -596,61 +587,6 @@ ol.proj.getTransformFromProjections =
|
||||
goog.object.containsKey(transforms[sourceCode], destinationCode)) {
|
||||
transform = transforms[sourceCode][destinationCode];
|
||||
}
|
||||
if (ol.HAVE_PROJ4JS && !goog.isDef(transform)) {
|
||||
var proj4jsSource;
|
||||
if (sourceProjection instanceof ol.Proj4jsProjection_) {
|
||||
proj4jsSource = sourceProjection;
|
||||
} else {
|
||||
proj4jsSource =
|
||||
ol.proj.getProj4jsProjectionFromCode_({
|
||||
code: sourceCode,
|
||||
extent: null
|
||||
});
|
||||
}
|
||||
var sourceProj4jsProj = proj4jsSource.getProj4jsProj();
|
||||
var proj4jsDestination;
|
||||
if (destinationProjection instanceof ol.Proj4jsProjection_) {
|
||||
proj4jsDestination = destinationProjection;
|
||||
} else {
|
||||
proj4jsDestination =
|
||||
ol.proj.getProj4jsProjectionFromCode_({
|
||||
code: destinationCode,
|
||||
extent: null
|
||||
});
|
||||
}
|
||||
var destinationProj4jsProj = proj4jsDestination.getProj4jsProj();
|
||||
transform =
|
||||
/**
|
||||
* @param {Array.<number>} input Input coordinate values.
|
||||
* @param {Array.<number>=} opt_output Output array of coordinates.
|
||||
* @param {number=} opt_dimension Dimension.
|
||||
* @return {Array.<number>} Output coordinate values.
|
||||
*/
|
||||
function(input, opt_output, opt_dimension) {
|
||||
var length = input.length,
|
||||
dimension = opt_dimension > 1 ? opt_dimension : 2,
|
||||
output = opt_output;
|
||||
if (!goog.isDef(output)) {
|
||||
if (dimension > 2) {
|
||||
// preserve values beyond second dimension
|
||||
output = input.slice();
|
||||
} else {
|
||||
output = new Array(length);
|
||||
}
|
||||
}
|
||||
goog.asserts.assert(output.length % dimension === 0);
|
||||
var proj4jsPoint;
|
||||
for (var i = 0; i < length; i += dimension) {
|
||||
proj4jsPoint = new Proj4js.Point(input[i], input[i + 1]);
|
||||
proj4jsPoint = Proj4js.transform(
|
||||
sourceProj4jsProj, destinationProj4jsProj, proj4jsPoint);
|
||||
output[i] = proj4jsPoint.x;
|
||||
output[i + 1] = proj4jsPoint.y;
|
||||
}
|
||||
return output;
|
||||
};
|
||||
ol.proj.addTransform(sourceProjection, destinationProjection, transform);
|
||||
}
|
||||
if (!goog.isDef(transform)) {
|
||||
goog.asserts.assert(goog.isDef(transform));
|
||||
transform = ol.proj.identityTransform;
|
||||
@@ -749,15 +685,3 @@ ol.proj.transformWithProjections =
|
||||
sourceProjection, destinationProjection);
|
||||
return transformFn(point);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {olx.Proj4jsProjectionOptions} options Proj4js projection options.
|
||||
* @return {ol.proj.Projection} Proj4js projection.
|
||||
* @api
|
||||
*/
|
||||
ol.proj.configureProj4jsProjection = function(options) {
|
||||
goog.asserts.assert(!goog.object.containsKey(
|
||||
ol.proj.proj4jsProjections_, options.code));
|
||||
return ol.proj.getProj4jsProjectionFromCode_(options);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user