import CustomMercatorProjection from './CustomMercatorProjection.js'; /** * A tiling scheme for geometry referenced to a {@link WebMercatorProjection}, EPSG:3857. This is * the tiling scheme used by Google Maps, Microsoft Bing Maps, and most of ESRI ArcGIS Online. * * @alias BJ2000TilingScheme2 * @constructor * * @param {Object} [options] Object with the following properties: * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid whose surface is being tiled. Defaults to * the WGS84 ellipsoid. * @param {Number} [options.numberOfLevelZeroTilesX=1] The number of tiles in the X direction at level zero of * the tile tree. * @param {Number} [options.numberOfLevelZeroTilesY=1] The number of tiles in the Y direction at level zero of * the tile tree. * @param {Cartesian2} [options.rectangleSouthwestInMeters] The southwest corner of the rectangle covered by the * tiling scheme, in meters. If this parameter or rectangleNortheastInMeters is not specified, the entire * globe is covered in the longitude direction and an equal distance is covered in the latitude * direction, resulting in a square projection. * @param {Cartesian2} [options.rectangleNortheastInMeters] The northeast corner of the rectangle covered by the * tiling scheme, in meters. If this parameter or rectangleSouthwestInMeters is not specified, the entire * globe is covered in the longitude direction and an equal distance is covered in the latitude * direction, resulting in a square projection. */ var Cesium = null; function Bj2000TilingScheme(options) { Cesium = options.SmartEarth; options = Cesium.defaultValue(options, Cesium.defaultValue.EMPTY_OBJECT); this._ellipsoid = Cesium.defaultValue(options.ellipsoid, Cesium.Ellipsoid.WGS84); this._numberOfLevelZeroTilesX = Cesium.defaultValue( options.numberOfLevelZeroTilesX, 1 ); this._numberOfLevelZeroTilesY = Cesium.defaultValue( options.numberOfLevelZeroTilesY, 1 ); if(options.customEPSG){ this._projection = new CustomMercatorProjection(options.customEPSG,this._ellipsoid,Cesium,options.proj); }else { this._projection = new Cesium.WebMercatorProjection(this._ellipsoid); } if ( Cesium.defined(options.rectangleSouthwestInMeters) && Cesium.defined(options.rectangleNortheastInMeters) ) { this._rectangleSouthwestInMeters = options.rectangleSouthwestInMeters; this._rectangleNortheastInMeters = options.rectangleNortheastInMeters; } else { const semimajorAxisTimesPi = this._ellipsoid.maximumRadius * Math.PI; this._rectangleSouthwestInMeters = new Cesium.Cartesian2( -semimajorAxisTimesPi, -semimajorAxisTimesPi ); this._rectangleNortheastInMeters = new Cesium.Cartesian2( semimajorAxisTimesPi, semimajorAxisTimesPi ); } const southwest = this._projection.unproject( this._rectangleSouthwestInMeters ); const northeast = this._projection.unproject( this._rectangleNortheastInMeters ); this._rectangle = new Cesium.Rectangle( southwest.longitude, southwest.latitude, northeast.longitude, northeast.latitude ); this._resolutions = Cesium.defaultValue(options.resolutions,[0]); this._origin = Cesium.defaultValue(options.origin, [0,0]); this.tileWidth = Cesium.defaultValue(options.tileWidth, 256); this.tileHeight = Cesium.defaultValue(options.tileHeight, 256); } Object.defineProperties(Bj2000TilingScheme.prototype, { /** * Gets the ellipsoid that is tiled by this tiling scheme. * @memberof Bj2000TilingScheme.prototype * @type {Ellipsoid} */ ellipsoid: { get: function () { return this._ellipsoid; }, }, /** * Gets the rectangle, in radians, covered by this tiling scheme. * @memberof Bj2000TilingScheme.prototype * @type {Rectangle} */ rectangle: { get: function () { return this._rectangle; }, }, /** * Gets the map projection used by this tiling scheme. * @memberof Bj2000TilingScheme.prototype * @type {MapProjection} */ projection: { get: function () { return this._projection; }, }, rectangleNortheastInMeters:{ get: function() { return this._rectangleNortheastInMeters; } }, rectangleSouthwestInMeters:{ get: function() { return this._rectangleSouthwestInMeters; } }, }); /** * Gets the total number of tiles in the X direction at a specified level-of-detail. * * @param {Number} level The level-of-detail. * @returns {Number} The number of tiles in the X direction at the given level. */ Bj2000TilingScheme.prototype.getNumberOfXTilesAtLevel = function (level) { return this._numberOfLevelZeroTilesX << level; }; /** * Gets the total number of tiles in the Y direction at a specified level-of-detail. * * @param {Number} level The level-of-detail. * @returns {Number} The number of tiles in the Y direction at the given level. */ Bj2000TilingScheme.prototype.getNumberOfYTilesAtLevel = function (level) { return this._numberOfLevelZeroTilesY << level; }; /** * Transforms a rectangle specified in geodetic radians to the native coordinate system * of this tiling scheme. * * @param {Rectangle} rectangle The rectangle to transform. * @param {Rectangle} [result] The instance to which to copy the result, or undefined if a new instance * should be created. * @returns {Rectangle} The specified 'result', or a new object containing the native rectangle if 'result' * is undefined. */ Bj2000TilingScheme.prototype.rectangleToNativeRectangle = function ( rectangle, result ) { const projection = this._projection; const southwest = projection.project(Cesium.Rectangle.southwest(rectangle)); const northeast = projection.project(Cesium.Rectangle.northeast(rectangle)); if (!Cesium.defined(result)) { return new Cesium.Rectangle(southwest.x, southwest.y, northeast.x, northeast.y); } result.west = southwest.x; result.south = southwest.y; result.east = northeast.x; result.north = northeast.y; return result; }; /** * Converts tile x, y coordinates and level to a rectangle expressed in the native coordinates * of the tiling scheme. * * @param {Number} x The integer x coordinate of the tile. * @param {Number} y The integer y coordinate of the tile. * @param {Number} level The tile level-of-detail. Zero is the least detailed. * @param {Object} [result] The instance to which to copy the result, or undefined if a new instance * should be created. * @returns {Rectangle} The specified 'result', or a new object containing the rectangle * if 'result' is undefined. */ Bj2000TilingScheme.prototype.tileXYToNativeRectangle = function ( x, y, level, result ) { level +=6; const xTiles = this.getNumberOfXTilesAtLevel(level); const yTiles = this.getNumberOfYTilesAtLevel(level); const resolution = this._resolutions[level]; const eastFromOrigin = this._rectangleNortheastInMeters.x - this._origin[0]; const southFromOrigin = this._origin[1] - this._rectangleSouthwestInMeters.y; const xTileWidth = eastFromOrigin / xTiles; const yTileHeight = southFromOrigin / yTiles; // let west = this._origin[0] + x * xTileWidth; // let east = this._origin[0] + (x + 1) * xTileWidth; // if(west < this._rectangleSouthwestInMeters.x){ // west = this._rectangleSouthwestInMeters.x; // } // if(east >= this._rectangleNortheastInMeters.x) { // east = this._rectangleNortheastInMeters.x; // } const west = this._origin[0] + x * this.tileWidth * resolution; const east = west + this.tileWidth * resolution; // let north = this._origin[1] - y * yTileHeight; // let south = this._origin[1] - (y + 1) * yTileHeight; // if(south < this._rectangleSouthwestInMeters.y) { // south = this._rectangleSouthwestInMeters.y; // } // if(north > this._rectangleNortheastInMeters.y) { // north = this._rectangleNortheastInMeters.y; // } const south = this._origin[1] - (y + 1) * this.tileHeight * resolution; const north = south + this.tileHeight * resolution; if (!Cesium.defined(result)) { return new Cesium.Rectangle(west, south, east, north); } result.west = west; result.south = south; result.east = east; result.north = north; return result; }; /** * Converts tile x, y coordinates and level to a cartographic rectangle in radians. * * @param {Number} x The integer x coordinate of the tile. * @param {Number} y The integer y coordinate of the tile. * @param {Number} level The tile level-of-detail. Zero is the least detailed. * @param {Object} [result] The instance to which to copy the result, or undefined if a new instance * should be created. * @returns {Rectangle} The specified 'result', or a new object containing the rectangle * if 'result' is undefined. */ Bj2000TilingScheme.prototype.tileXYToRectangle = function ( x, y, level, result ) { const nativeRectangle = this.tileXYToNativeRectangle(x, y, level, result); const projection = this._projection; const southwest = projection.unproject( new Cesium.Cartesian2(nativeRectangle.west, nativeRectangle.south) ); const northeast = projection.unproject( new Cesium.Cartesian2(nativeRectangle.east, nativeRectangle.north) ); nativeRectangle.west = southwest.longitude; nativeRectangle.south = southwest.latitude; nativeRectangle.east = northeast.longitude; nativeRectangle.north = northeast.latitude; return nativeRectangle; }; /** * Calculates the tile x, y coordinates of the tile containing * a given cartographic position. * * @param {Cartographic} position The position. * @param {Number} level The tile level-of-detail. Zero is the least detailed. * @param {Cartesian2} [result] The instance to which to copy the result, or undefined if a new instance * should be created. * @returns {Cartesian2} The specified 'result', or a new object containing the tile x, y coordinates * if 'result' is undefined. */ Bj2000TilingScheme.prototype.positionToTileXY = function ( position, level, result ) { const rectangle = this._rectangle; if (!Cesium.Rectangle.contains(rectangle, position)) { // outside the bounds of the tiling scheme return undefined; } level +=6; const xTiles = this.getNumberOfXTilesAtLevel(level); const yTiles = this.getNumberOfYTilesAtLevel(level); // // const overallWidth = // this._rectangleNortheastInMeters.x - this._rectangleSouthwestInMeters.x; // const xTileWidth = overallWidth / xTiles; // const overallHeight = // this._rectangleNortheastInMeters.y - this._rectangleSouthwestInMeters.y; // const yTileHeight = overallHeight / yTiles; const projection = this._projection; const webMercatorPosition = projection.project(position); const resolution = this._resolutions[level]; const realTileWidth = resolution * this.tileWidth; const realTileHeight = resolution * this.tileHeight; let xTileCoordinate = (webMercatorPosition.x - this._origin[0]) / resolution / this.tileWidth; let yTileCoordinate = (this._origin[1] - webMercatorPosition.y) / resolution / this.tileHeight; xTileCoordinate = Math.floor(xTileCoordinate); yTileCoordinate = Math.floor(yTileCoordinate); // const westFromOrigin = this._rectangleSouthwestInMeters.x - this._origin[0]; // const eastFromOrigin = this._rectangleNortheastInMeters.x - this._origin[0]; // const northFromOrigin = this._origin[1] - this._rectangleNortheastInMeters.y; // const southFromOrigin = this._origin[1] - this._rectangleSouthwestInMeters.y; // const xTileWidth = eastFromOrigin / xTiles; // const yTileHeight = southFromOrigin / yTiles; // let xTileMin = Math.floor(westFromOrigin / realTileWidth) | 0; // if (xTileMin >= xTiles) { // xTileMin = xTiles - 1; // } // let xTileMax = Math.floor(eastFromOrigin / realTileWidth) | 0; // if ( xTileMax >= xTiles) { // xTileMax = xTiles - 1; // } // let yTileMin = Math.floor(northFromOrigin / realTileHeight) | 0; // if (yTileMin >= yTiles) { // yTileMin = yTiles - 1; // } // let yTileMax = Math.floor(southFromOrigin / realTileHeight) | 0; // if(yTileMax >= yTiles) { // yTileMax = yTiles - 1; // } // const distanceFromWest = webMercatorPosition.x - this._origin[0]; // const distanceFromNorth = this._origin[1] - webMercatorPosition.y; // let xTileCoordinate = (distanceFromWest / xTileWidth) | 0; // if (xTileCoordinate < xTileMin) { // xTileCoordinate = xTileMin; // // return undefined; // } // if ( xTileCoordinate > xTileMax ) { // xTileCoordinate = xTileMax; // // return undefined; // } // if (xTileCoordinate >= xTiles) { // xTileCoordinate = xTiles - 1; // } // let yTileCoordinate = (distanceFromNorth / yTileHeight) | 0; // if (yTileCoordinate < yTileMin) { // yTileCoordinate = yTileMin; // // return undefined; // } // if (yTileCoordinate > yTileMax) { // yTileCoordinate = yTileMax; // // return undefined; // } // if (yTileCoordinate >= yTiles) { // yTileCoordinate = yTiles - 1; // } if (!Cesium.defined(result)) { return new Cesium.Cartesian2(xTileCoordinate, yTileCoordinate); } result.x = xTileCoordinate; result.y = yTileCoordinate; return result; }; export default Bj2000TilingScheme;