0
votes

I'm using OpenLayers 3 for deep-zooming into high resolution images (no geo-coordinates, only pixels).

And XYZ is the format that I need as projection, but I have a problem with adding one more tiled layer, because it should have different projection. I.e. my main layer has sizes (X) x (Y) in pixels, but second layer has sizes (X * k) x (Y * k). Therefore the layers don't correspond to each other. The tile size is the same in both cases.

Here is the code:

const imWidth = 100440;
const imHeight = 221312;

const primaryImageProjection = new ol.proj.Projection({
  code: 'PIXELS',
  units: 'pixels',
  extent: [0, 0, imWidth, imHeight],
  getPointResolution: function (resolution, point) {
    return resolution;
  }
});
ol.proj.addProjection(primaryImageProjection);

var heatMapProj = new ol.proj.Projection({
  code: 'HEATMAP',
  units: 'pixels',
  extent: [0, 0, imWidth, imWidth],
  getPointResolution: function (resolution, point) {
    return resolution;
  }
});
ol.proj.addProjection(heatMapProj);

const koef = 21.5;
ol.proj.addCoordinateTransforms('PIXELS', 'HEATMAP',
  function (coordinate) {
    return [coordinate[0] * koef, coordinate[1] * koef];
  },
  function (coordinate) {
    return [coordinate[0] / koef, coordinate[1] / koef];
  });

this.map = new ol.Map({
  layers: [
    new ol.layer.Tile({
      source: new ol.source.XYZ({
        crossOrigin: crossOrigin,
        tileSize: [512, 512],
        tileUrlFunction: (tileCoord, pixelRatio, projection) => {
          const tileUrlTemplate = 'http://.../?lvl={z}&tx={x}&ty={y}';
          const z = 9 - tileCoord[0];
          const tileUrl = tileUrlTemplate
            .replace("{z}", (z).toString())
            .replace("{x}", (tileCoord[1]).toString())
            .replace("{y}", (((-tileCoord[2]) - 1)).toString());
          return tileUrl;
        },
        projection: 'PIXELS'
      })
    }),
    new ol.layer.Tile({
      source: new ol.source.XYZ({
        crossOrigin: crossOrigin,
        tileSize: [512, 512],
        tileUrlFunction: (tileCoord, pixelRatio, projection) => {
          const heatMapUrlTemplate = 'http://...?lvl={z}&tx={x}&ty={y}';
          var z = 4 - tileCoord[0];
          const heatMapUrl = heatMapUrlTemplate
            .replace('{z}', (z).toString())
            .replace('{x}', (tileCoord[1]).toString())
            .replace('{y}', (((-tileCoord[2]) - 1)).toString());
          return heatMapUrl;
        },
        projection: 'HEATMAP'
      }),
      opacity: 0.5
    })
  ],
  controls: [],
  target: this.mapSelector,
  renderer: "canvas",
  view: new ol.View({
    projection: 'PIXELS'
  })
});

How can I solve this? Maybe projections are not the right way and it can be solved differently.

PS: also you can see that I'm using the function getPointResolution. Otherwise I see error messages in console: "transform should be defined". And after dubugging I found that OpenLayers makes some transformations internally from my projections into "EPSG:4326" and back. I wouldn't expect to have any spherical coordinates inside, since I'm using only flat images, but it looks that OpenLayers need it anyway.

1

1 Answers

0
votes

Raster reprojection (i.e. different projections for the layers of a map) is not an experimental feature. But to make it work for you, you need to register transformation functions between the projections of your layers, using ol.proj.addCoordinateTransforms. Without seeing your code it is hard to guess, but something like this should do the trick:

var proj1 = new ol.proj.Projection({
  code: 'ZOOMIFY1',
  units: 'pixels',
  extent: [0, -Y, X, 0]
});
var proj2 = new ol.proj.Projection({
  code: 'ZOOMIFY2',
  units: 'pixels',
  extent: [0, -Y * k, X * k, 0]
});

ol.proj.addCoordinateTransforms(proj1, proj2,
    function(coordinate) {
      return [coordinate[0] * k, coordinate[1] * k];
    },
    function(coordinate) {
      return [coordinate[1] / k, coordinate[2] / k];
    });

Now you can go ahead, configure your two Zoomify layers - the first with proj1 as projection and the second with proj2, and they should align just fine.

Note that the above is untested. If you can provide a working snippet or JSFiddle, I can refine my answer if something is not working.