UNPKG

qwc2-lts

Version:
222 lines (221 loc) 8.24 kB
/** * Copyright 2015-2016 GeoSolutions Sas * Copyright 2016-2024 Sourcepole AG * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. */ import ConfigUtils from './ConfigUtils'; import CoordinatesUtils from './CoordinatesUtils'; var DEFAULT_SCREEN_DPI = 96; var METERS_PER_UNIT = { 'm': 1, 'degrees': 111194.87428468118, 'ft': 0.3048, 'us-ft': 1200 / 3937 }; var hooks = {}; var MapUtils = { GET_PIXEL_FROM_COORDINATES_HOOK: 'GET_PIXEL_FROM_COORDINATES_HOOK', GET_COORDINATES_FROM_PIXEL_HOOK: 'GET_COORDINATES_FROM_PIXEL_HOOK', GET_SNAPPED_COORDINATES_FROM_PIXEL_HOOK: 'GET_SNAPPED_COORDINATES_FROM_PIXEL_HOOK', GET_NATIVE_LAYER: 'GET_NATIVE_LAYER', GET_MAP: 'GET_MAP', registerHook: function registerHook(name, hook) { hooks[name] = hook; }, getHook: function getHook(name) { return hooks[name]; }, /** * @param dpi {number} dot per inch resolution * @return {number} dot per meter resolution */ dpi2dpm: function dpi2dpm(dpi) { return (dpi || DEFAULT_SCREEN_DPI) * (100 / 2.54); }, /** * @param dpi {number} screen resolution in dots per inch. * @param projection {string} map projection. * @return {number} dots per map unit. */ dpi2dpu: function dpi2dpu(dpi, projection) { var units = CoordinatesUtils.getUnits(projection); return METERS_PER_UNIT[units] * MapUtils.dpi2dpm(dpi); }, /** * Get a list of scales for each zoom level of the Google Mercator. * @param minZoom {number} min zoom level. * @param maxZoom {number} max zoom level. * @return {array} a list of scale for each zoom level in the given interval. */ getGoogleMercatorScales: function getGoogleMercatorScales(minZoom, maxZoom) { var dpi = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : DEFAULT_SCREEN_DPI; // Google mercator params var RADIUS = 6378137; var TILE_WIDTH = 256; var ZOOM_FACTOR = 2; var retval = []; for (var l = minZoom; l <= maxZoom; l++) { retval.push(2 * Math.PI * RADIUS / (TILE_WIDTH * Math.pow(ZOOM_FACTOR, l) / MapUtils.dpi2dpm(dpi))); } return retval; }, /** * @param scales {array} list of scales. * @param projection {string} map projection. * @param dpi {number} screen resolution in dots per inch. * @return {array} a list of resolutions corresponding to the given scales, projection and dpi. */ getResolutionsForScales: function getResolutionsForScales(scales, projection) { var dpi = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : DEFAULT_SCREEN_DPI; var dpu = MapUtils.dpi2dpu(dpi, projection); var resolutions = scales.map(function (scale) { return scale / dpu; }); return resolutions; }, /** * Calculates the best fitting zoom level for the given extent. * * @param extent {Array} [minx, miny, maxx, maxy] * @param resolutions {Array} The list of available map resolutions * @param mapSize {Object} current size of the map. * @param minZoom {number} min zoom level. * @param maxZoom {number} max zoom level. * @param dpi {number} screen resolution in dot per inch. * @return {Number} the zoom level fitting th extent */ getZoomForExtent: function getZoomForExtent(extent, resolutions, mapSize, minZoom, maxZoom) { var wExtent = extent[2] - extent[0]; var hExtent = extent[3] - extent[1]; var xResolution = Math.abs(wExtent / mapSize.width); var yResolution = Math.abs(hExtent / mapSize.height); var extentResolution = Math.max(xResolution, yResolution); if (ConfigUtils.getConfigProp("allowFractionalZoom") === true) { return Math.max(minZoom, Math.min(this.computeZoom(resolutions, extentResolution), maxZoom)); } else { var calc = resolutions.reduce(function (previous, resolution, index) { var diff = Math.abs(resolution - extentResolution); return diff > previous.diff ? previous : { diff: diff, zoom: index }; }, { diff: Number.POSITIVE_INFINITY, zoom: 0 }); return Math.max(minZoom, Math.min(calc.zoom, maxZoom)); } }, /** * Calculates the extent for the provided center and zoom level * @param center {Array} [x, y] * @param zoom {number} The zoom level * @param resolutions {Array} The list of map resolutions * @param mapSize {Object} The current size of the map */ getExtentForCenterAndZoom: function getExtentForCenterAndZoom(center, zoom, resolutions, mapSize) { if (ConfigUtils.getConfigProp("allowFractionalZoom") !== true) { zoom = Math.round(zoom); } var width = this.computeForZoom(resolutions, zoom) * mapSize.width; var height = this.computeForZoom(resolutions, zoom) * mapSize.height; return [center[0] - 0.5 * width, center[1] - 0.5 * height, center[0] + 0.5 * width, center[1] + 0.5 * height]; }, /** * Transform width and height specified in meters to the units of the specified projection * * @param projection {string} projection. * @param center {Array} Center of extent in EPSG:4326 coordinates. * @param width {number} Width in meters. * @param height {number} Height in meters. */ transformExtent: function transformExtent(projection, center, width, height) { var units = CoordinatesUtils.getUnits(projection); if (units === 'ft') { return { width: width / METERS_PER_UNIT.ft, height: height / METERS_PER_UNIT.ft }; } else if (units === 'us-ft') { return { width: width / METERS_PER_UNIT['us-ft'], height: height / METERS_PER_UNIT['us-ft'] }; } else if (units === 'degrees') { // https://en.wikipedia.org/wiki/Geographic_coordinate_system#Length_of_a_degree var phi = center[1] / 180 * Math.PI; var latPerM = 111132.92 - 559.82 * Math.cos(2 * phi) + 1.175 * Math.cos(4 * phi) - 0.0023 * Math.cos(6 * phi); var lonPerM = 111412.84 * Math.cos(phi) - 93.5 * Math.cos(3 * phi) + 0.118 * Math.cos(5 * phi); return { width: width / lonPerM, height: height / latPerM }; } return { width: width, height: height }; }, /** * Compute the scale or resolution matching a (possibly fractional) zoom level. * * @param list {Array} List of scales or resolutions. * @param zoomLevel (number) Zoom level (integer or fractional). * @return Scale of resolution matching zoomLevel */ computeForZoom: function computeForZoom(list, zoomLevel) { if (ConfigUtils.getConfigProp("allowFractionalZoom") !== true) { return list[Math.min(list.length - 1, Math.round(zoomLevel))]; } zoomLevel = Math.max(zoomLevel, 0); var upper = Math.ceil(zoomLevel); var lower = Math.floor(zoomLevel); if (upper >= list.length) { return list[list.length - 1]; } var frac = zoomLevel - lower; return list[lower] * (1 - frac) + list[upper] * frac; }, /** * Compute the (possibly fractional) zoom level matching the specified scale or resolution. * * @param list {Array} List of scales or resolutions. * @param value (number) Scale or resolution. * @return Zoom level matching the specified scale or resolution. */ computeZoom: function computeZoom(list, value) { if (ConfigUtils.getConfigProp("allowFractionalZoom") === true) { var index = 0; for (var i = 1; i < list.length - 1; ++i) { if (value <= list[i]) { index = i; } } return index + (value - list[index]) / (list[index + 1] - list[index]); } else { var closestVal = Math.abs(value - list[0]); var closestIdx = 0; for (var _i = 1; _i < list.length; ++_i) { var currVal = Math.abs(value - list[_i]); if (currVal < closestVal) { closestVal = currVal; closestIdx = _i; } } return closestIdx; } }, /** * Convert degrees to radians * @param degrees {number} * @return {number} in radians */ degreesToRadians: function degreesToRadians(degrees) { var pi = Math.PI; return degrees * (pi / 180); } }; export default MapUtils;