Try harder to get the projection from GeoTIFF headers
This commit is contained in:
@@ -8,6 +8,11 @@
|
|||||||
* @enum {string}
|
* @enum {string}
|
||||||
*/
|
*/
|
||||||
const Units = {
|
const Units = {
|
||||||
|
/**
|
||||||
|
* Radians
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
RADIANS: 'radians',
|
||||||
/**
|
/**
|
||||||
* Degrees
|
* Degrees
|
||||||
* @api
|
* @api
|
||||||
@@ -40,6 +45,26 @@ const Units = {
|
|||||||
USFEET: 'us-ft',
|
USFEET: 'us-ft',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See http://duff.ess.washington.edu/data/raster/drg/docs/geotiff.txt
|
||||||
|
* @type {Object<number, Units>}
|
||||||
|
*/
|
||||||
|
const unitByCode = {
|
||||||
|
'9001': Units.METERS,
|
||||||
|
'9002': Units.FEET,
|
||||||
|
'9003': Units.USFEET,
|
||||||
|
'9101': Units.RADIANS,
|
||||||
|
'9102': Units.DEGREES,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} code Unit code.
|
||||||
|
* @return {Units} Units.
|
||||||
|
*/
|
||||||
|
export function fromCode(code) {
|
||||||
|
return unitByCode[code];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Meters per unit lookup table.
|
* Meters per unit lookup table.
|
||||||
* @const
|
* @const
|
||||||
@@ -48,6 +73,7 @@ const Units = {
|
|||||||
*/
|
*/
|
||||||
export const METERS_PER_UNIT = {};
|
export const METERS_PER_UNIT = {};
|
||||||
// use the radius of the Normal sphere
|
// use the radius of the Normal sphere
|
||||||
|
METERS_PER_UNIT[Units.RADIANS] = 6370997 / (2 * Math.PI);
|
||||||
METERS_PER_UNIT[Units.DEGREES] = (2 * Math.PI * 6370997) / 360;
|
METERS_PER_UNIT[Units.DEGREES] = (2 * Math.PI * 6370997) / 360;
|
||||||
METERS_PER_UNIT[Units.FEET] = 0.3048;
|
METERS_PER_UNIT[Units.FEET] = 0.3048;
|
||||||
METERS_PER_UNIT[Units.METERS] = 1;
|
METERS_PER_UNIT[Units.METERS] = 1;
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ import DataTile from './DataTile.js';
|
|||||||
import State from './State.js';
|
import State from './State.js';
|
||||||
import TileGrid from '../tilegrid/TileGrid.js';
|
import TileGrid from '../tilegrid/TileGrid.js';
|
||||||
import {Pool, fromUrl as tiffFromUrl, fromUrls as tiffFromUrls} from 'geotiff';
|
import {Pool, fromUrl as tiffFromUrl, fromUrls as tiffFromUrls} from 'geotiff';
|
||||||
|
import {Projection, get as getCachedProjection} from '../proj.js';
|
||||||
import {create as createDecoderWorker} from '../worker/geotiff-decoder.js';
|
import {create as createDecoderWorker} from '../worker/geotiff-decoder.js';
|
||||||
import {getIntersection} from '../extent.js';
|
import {getIntersection} from '../extent.js';
|
||||||
import {get as getProjection} from '../proj.js';
|
|
||||||
import {toSize} from '../size.js';
|
import {toSize} from '../size.js';
|
||||||
|
import {fromCode as unitsFromCode} from '../proj/Units.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} SourceInfo
|
* @typedef {Object} SourceInfo
|
||||||
@@ -25,10 +26,22 @@ import {toSize} from '../size.js';
|
|||||||
* near-infrared band, configure `bands: [4]`.
|
* near-infrared band, configure `bands: [4]`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} GeoKeys
|
||||||
|
* @property {number} GTModelTypeGeoKey Model type.
|
||||||
|
* @property {number} GTRasterTypeGeoKey Raster type.
|
||||||
|
* @property {number} GeogAngularUnitsGeoKey Angular units.
|
||||||
|
* @property {number} GeogInvFlatteningGeoKey Inverse flattening.
|
||||||
|
* @property {number} GeogSemiMajorAxisGeoKey Semi-major axis.
|
||||||
|
* @property {number} GeographicTypeGeoKey Geographic coordinate system code.
|
||||||
|
* @property {number} ProjLinearUnitsGeoKey Projected linear unit code.
|
||||||
|
* @property {number} ProjectedCSTypeGeoKey Projected coordinate system code.
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} GeoTIFFImage
|
* @typedef {Object} GeoTIFFImage
|
||||||
* @property {Object} fileDirectory The file directory.
|
* @property {Object} fileDirectory The file directory.
|
||||||
* @property {Object} geoKeys The parsed geo-keys.
|
* @property {GeoKeys} geoKeys The parsed geo-keys.
|
||||||
* @property {boolean} littleEndian Uses little endian byte order.
|
* @property {boolean} littleEndian Uses little endian byte order.
|
||||||
* @property {Object} tiles The tile cache.
|
* @property {Object} tiles The tile cache.
|
||||||
* @property {boolean} isTiled The image is tiled.
|
* @property {boolean} isTiled The image is tiled.
|
||||||
@@ -91,6 +104,49 @@ function getResolution(image, referenceImage) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {GeoTIFFImage} image A GeoTIFF.
|
||||||
|
* @return {import("../proj/Projection.js").default} The image projection.
|
||||||
|
*/
|
||||||
|
function getProjection(image) {
|
||||||
|
const geoKeys = image.geoKeys;
|
||||||
|
if (!geoKeys) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (geoKeys.ProjectedCSTypeGeoKey) {
|
||||||
|
const code = 'EPSG:' + geoKeys.ProjectedCSTypeGeoKey;
|
||||||
|
let projection = getCachedProjection(code);
|
||||||
|
if (!projection) {
|
||||||
|
const units = unitsFromCode(geoKeys.ProjLinearUnitsGeoKey);
|
||||||
|
if (units) {
|
||||||
|
projection = new Projection({
|
||||||
|
code: code,
|
||||||
|
units: units,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return projection;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (geoKeys.GeographicTypeGeoKey) {
|
||||||
|
const code = 'EPSG:' + geoKeys.GeographicTypeGeoKey;
|
||||||
|
let projection = getCachedProjection(code);
|
||||||
|
if (!projection) {
|
||||||
|
const units = unitsFromCode(geoKeys.GeogAngularUnitsGeoKey);
|
||||||
|
if (units) {
|
||||||
|
projection = new Projection({
|
||||||
|
code: code,
|
||||||
|
units: units,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return projection;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {import("geotiff/src/geotiff.js").GeoTIFF|import("geotiff/src/geotiff.js").MultiGeoTIFF} tiff A GeoTIFF.
|
* @param {import("geotiff/src/geotiff.js").GeoTIFF|import("geotiff/src/geotiff.js").MultiGeoTIFF} tiff A GeoTIFF.
|
||||||
* @return {Promise<Array<import("geotiff/src/geotiffimage.js").GeoTIFFImage>>} Resolves to a list of images.
|
* @return {Promise<Array<import("geotiff/src/geotiffimage.js").GeoTIFFImage>>} Resolves to a list of images.
|
||||||
@@ -419,14 +475,10 @@ class GeoTIFFSource extends DataTile {
|
|||||||
const firstSource = sources[0];
|
const firstSource = sources[0];
|
||||||
for (let i = firstSource.length - 1; i >= 0; --i) {
|
for (let i = firstSource.length - 1; i >= 0; --i) {
|
||||||
const image = firstSource[i];
|
const image = firstSource[i];
|
||||||
if (image.geoKeys) {
|
const projection = getProjection(image);
|
||||||
const code =
|
if (projection) {
|
||||||
image.geoKeys.ProjectedCSTypeGeoKey ||
|
this.projection = projection;
|
||||||
image.geoKeys.GeographicTypeGeoKey;
|
break;
|
||||||
if (code) {
|
|
||||||
this.projection = getProjection('EPSG:' + code);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import GeoTIFFSource from '../../../../../src/ol/source/GeoTIFF.js';
|
|||||||
import State from '../../../../../src/ol/source/State.js';
|
import State from '../../../../../src/ol/source/State.js';
|
||||||
import TileState from '../../../../../src/ol/TileState.js';
|
import TileState from '../../../../../src/ol/TileState.js';
|
||||||
|
|
||||||
describe('ol.source.GeoTIFF', function () {
|
describe('ol/source/GeoTIFF', function () {
|
||||||
/** @type {GeoTIFFSource} */
|
/** @type {GeoTIFFSource} */
|
||||||
let source;
|
let source;
|
||||||
beforeEach(function () {
|
beforeEach(function () {
|
||||||
@@ -30,6 +30,7 @@ describe('ol.source.GeoTIFF', function () {
|
|||||||
expect(source.nodataValues_).to.eql([[0]]);
|
expect(source.nodataValues_).to.eql([[0]]);
|
||||||
expect(source.getTileGrid().getResolutions().length).to.be(1);
|
expect(source.getTileGrid().getResolutions().length).to.be(1);
|
||||||
expect(source.projection.getCode()).to.be('EPSG:4326');
|
expect(source.projection.getCode()).to.be('EPSG:4326');
|
||||||
|
expect(source.projection.getUnits()).to.be('degrees');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user