Projection handling improvements

* The Map's private createProjection_ method is now a public
  method of the Projection. It is also used by TiledWMSSource
  to calculate the appropriate projection from the user
  configuration.
* ol.Projection.addProjection now adds the transformation for
  the source == target case. This makes it easy for the user
  to create custom projection maps without including proj4js and
  without adding a custom transformation, as long as the
  userProjection equals the projection.
* The TiledWMSSource now uses the same default resolutions as
  the map (i.e. the OSM resolutions)
* The modulo calculation for wrapping extents now works for all
  grid configurations, by not calculating the number of columns
  based on an assumption about the way the zoom levels relate to
  resolutions.
* The wms-custom-proj example now shows how to properly
  configure a custom resolution, i.e. by using the validity
  extent of the projection as its extent.
This commit is contained in:
ahocevar
2012-10-31 13:17:58 +01:00
parent 7af152cc49
commit eb4a8683e2
4 changed files with 47 additions and 35 deletions

View File

@@ -13,11 +13,12 @@ if (goog.DEBUG) {
goog.debug.Logger.getLogger('ol').setLevel(goog.debug.Logger.Level.INFO); goog.debug.Logger.getLogger('ol').setLevel(goog.debug.Logger.Level.INFO);
} }
var epsg21781 = new ol.Projection('EPSG:21781', ol.ProjectionUnits.METERS,
// Validity extent from http://spatialreference.org
new ol.Extent(485869.5728, 76443.1884, 837076.5648, 299941.7864));
ol.Projection.addProjection(epsg21781);
var extent = new ol.Extent(420000, 30000, 900000, 350000); var extent = new ol.Extent(420000, 30000, 900000, 350000);
var epsg21781 = new ol.Projection('EPSG:21781',
ol.ProjectionUnits.METERS, extent);
var layers = new ol.Collection([ var layers = new ol.Collection([
new ol.layer.TileLayer({ new ol.layer.TileLayer({
source: new ol.source.TiledWMS({ source: new ol.source.TiledWMS({
@@ -28,7 +29,8 @@ var layers = new ol.Collection([
'Pixelmap 1:1000000 / geo.admin.ch</a>')], 'Pixelmap 1:1000000 / geo.admin.ch</a>')],
crossOrigin: null, crossOrigin: null,
params: {'LAYERS': 'ch.swisstopo.pixelkarte-farbe-pk1000.noscale'}, params: {'LAYERS': 'ch.swisstopo.pixelkarte-farbe-pk1000.noscale'},
projection: epsg21781 projection: epsg21781,
extent: extent
}) })
}), }),
new ol.layer.TileLayer({ new ol.layer.TileLayer({
@@ -40,7 +42,8 @@ var layers = new ol.Collection([
'National parks / geo.admin.ch</a>')], 'National parks / geo.admin.ch</a>')],
crossOrigin: null, crossOrigin: null,
params: {'LAYERS': 'ch.bafu.schutzgebiete-paerke_nationaler_bedeutung'}, params: {'LAYERS': 'ch.bafu.schutzgebiete-paerke_nationaler_bedeutung'},
projection: epsg21781 projection: epsg21781,
extent: extent
}) })
}) })
]); ]);
@@ -49,6 +52,9 @@ var map = new ol.Map({
renderer: ol.RendererHint.DOM, renderer: ol.RendererHint.DOM,
center: new ol.Coordinate(660000, 190000), center: new ol.Coordinate(660000, 190000),
projection: epsg21781, projection: epsg21781,
// By setting userProjection to the same as projection, we do not need
// proj4js because we do not need any transforms.
userProjection: epsg21781,
layers: layers, layers: layers,
target: 'map', target: 'map',
zoom: 9 zoom: 9

View File

@@ -980,7 +980,7 @@ ol.Map.createOptionsInternal = function(mapOptions) {
values[ol.MapProperty.LAYERS] = goog.isDef(mapOptions.layers) ? values[ol.MapProperty.LAYERS] = goog.isDef(mapOptions.layers) ?
mapOptions.layers : new ol.Collection(); mapOptions.layers : new ol.Collection();
values[ol.MapProperty.PROJECTION] = ol.Map.createProjection_( values[ol.MapProperty.PROJECTION] = ol.Projection.createProjection(
mapOptions.projection, 'EPSG:3857'); mapOptions.projection, 'EPSG:3857');
if (goog.isDef(mapOptions.resolution)) { if (goog.isDef(mapOptions.resolution)) {
@@ -990,7 +990,7 @@ ol.Map.createOptionsInternal = function(mapOptions) {
ol.Projection.EPSG_3857_HALF_SIZE / (128 << mapOptions.zoom); ol.Projection.EPSG_3857_HALF_SIZE / (128 << mapOptions.zoom);
} }
values[ol.MapProperty.USER_PROJECTION] = ol.Map.createProjection_( values[ol.MapProperty.USER_PROJECTION] = ol.Projection.createProjection(
mapOptions.userProjection, 'EPSG:4326'); mapOptions.userProjection, 'EPSG:4326');
/** /**
@@ -1183,21 +1183,3 @@ ol.Map.createInteractions_ = function(mapOptions) {
return interactions; return interactions;
}; };
/**
* @private
* @param {ol.Projection|string|undefined} projection Projection.
* @param {string} defaultCode Default code.
* @return {ol.Projection} Projection.
*/
ol.Map.createProjection_ = function(projection, defaultCode) {
if (!goog.isDefAndNotNull(projection)) {
return ol.Projection.getFromCode(defaultCode);
} else if (goog.isString(projection)) {
return ol.Projection.getFromCode(projection);
} else {
goog.asserts.assert(projection instanceof ol.Projection);
return projection;
}
};

View File

@@ -137,8 +137,10 @@ ol.Projection.addEquivalentProjections_ = function(projections) {
ol.Projection.addProjections(projections); ol.Projection.addProjections(projections);
goog.array.forEach(projections, function(source) { goog.array.forEach(projections, function(source) {
goog.array.forEach(projections, function(destination) { goog.array.forEach(projections, function(destination) {
if (source !== destination) {
ol.Projection.addTransform( ol.Projection.addTransform(
source, destination, ol.Projection.cloneTransform); source, destination, ol.Projection.cloneTransform);
}
}); });
}); });
}; };
@@ -181,6 +183,8 @@ ol.Projection.addProjection = function(projection) {
var code = projection.getCode(); var code = projection.getCode();
goog.asserts.assert(!goog.object.containsKey(projections, code)); goog.asserts.assert(!goog.object.containsKey(projections, code));
projections[code] = projection; projections[code] = projection;
ol.Projection.addTransform(
projection, projection, ol.Projection.cloneTransform);
}; };
@@ -194,6 +198,23 @@ ol.Projection.addProjections = function(projections) {
}; };
/**
* @param {ol.Projection|string|undefined} projection Projection.
* @param {string} defaultCode Default code.
* @return {ol.Projection} Projection.
*/
ol.Projection.createProjection = function(projection, defaultCode) {
if (!goog.isDefAndNotNull(projection)) {
return ol.Projection.getFromCode(defaultCode);
} else if (goog.isString(projection)) {
return ol.Projection.getFromCode(projection);
} else {
goog.asserts.assert(projection instanceof ol.Projection);
return projection;
}
};
/** /**
* @param {ol.Projection} source Source. * @param {ol.Projection} source Source.
* @param {ol.Projection} destination Destination. * @param {ol.Projection} destination Destination.

View File

@@ -2,6 +2,7 @@
goog.provide('ol.source.TiledWMS'); goog.provide('ol.source.TiledWMS');
goog.require('goog.asserts'); goog.require('goog.asserts');
goog.require('goog.object'); goog.require('goog.object');
goog.require('ol.Attribution'); goog.require('ol.Attribution');
@@ -19,8 +20,8 @@ goog.require('ol.tilegrid.TileGrid');
* @param {ol.source.TiledWMSOptions} tiledWMSOptions options. * @param {ol.source.TiledWMSOptions} tiledWMSOptions options.
*/ */
ol.source.TiledWMS = function(tiledWMSOptions) { ol.source.TiledWMS = function(tiledWMSOptions) {
var projection = goog.isDef(tiledWMSOptions.projection) ? var projection = ol.Projection.createProjection(
tiledWMSOptions.projection : ol.Projection.getFromCode('EPSG:3857'); tiledWMSOptions.projection, 'EPSG:3857');
var projectionExtent = projection.getExtent(); var projectionExtent = projection.getExtent();
var extent = goog.isDef(tiledWMSOptions.extent) ? var extent = goog.isDef(tiledWMSOptions.extent) ?
@@ -39,7 +40,7 @@ ol.source.TiledWMS = function(tiledWMSOptions) {
tiledWMSOptions.maxZoom : 18; tiledWMSOptions.maxZoom : 18;
var resolutions = new Array(maxZoom + 1); var resolutions = new Array(maxZoom + 1);
for (var z = 0, zz = resolutions.length; z < zz; ++z) { for (var z = 0, zz = resolutions.length; z < zz; ++z) {
resolutions[z] = size / (256 << z); resolutions[z] = ol.Projection.EPSG_3857_HALF_SIZE / (128 << z);
} }
tileGrid = new ol.tilegrid.TileGrid({ tileGrid = new ol.tilegrid.TileGrid({
origin: projectionExtent.getTopLeft(), origin: projectionExtent.getTopLeft(),
@@ -85,15 +86,17 @@ ol.source.TiledWMS = function(tiledWMSOptions) {
return null; return null;
} }
var x = tileCoord.x; var x = tileCoord.x;
var tileExtent = tileGrid.getTileCoordExtent(tileCoord);
// FIXME do we want a wrapDateLine param? The code below will break maps // FIXME do we want a wrapDateLine param? The code below will break maps
// with projections that do not span the whole world width. // with projections that do not span the whole world width.
if (extent.minX === projectionExtent.minX && if (extent.minX === projectionExtent.minX &&
extent.maxX === projectionExtent.maxX) { extent.maxX === projectionExtent.maxX) {
var n = 1 << tileCoord.z; var numCols = Math.ceil(
x = goog.math.modulo(x, n); (extent.maxX - extent.minX) / (tileExtent.maxX - tileExtent.minX));
} x = goog.math.modulo(x, numCols);
var tileExtent = tileGrid.getTileCoordExtent( tileExtent = tileGrid.getTileCoordExtent(
new ol.TileCoord(tileCoord.z, x, tileCoord.y)); new ol.TileCoord(tileCoord.z, x, tileCoord.y));
}
// FIXME We shouldn't need a typecast here. // FIXME We shouldn't need a typecast here.
if (!tileExtent.intersects(/** @type {ol.Extent} */ (extent))) { if (!tileExtent.intersects(/** @type {ol.Extent} */ (extent))) {
return null; return null;