123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539 |
- import defined from "../Core/defined.js";
- import DeveloperError from "../Core/DeveloperError.js";
- import Rectangle from "../Core/Rectangle.js";
- import QuadtreeTileLoadState from "./QuadtreeTileLoadState.js";
- import TileSelectionResult from "./TileSelectionResult.js";
- /**
- * A single tile in a {@link QuadtreePrimitive}.
- *
- * @alias QuadtreeTile
- * @constructor
- * @private
- *
- * @param {number} options.level The level of the tile in the quadtree.
- * @param {number} options.x The X coordinate of the tile in the quadtree. 0 is the westernmost tile.
- * @param {number} options.y The Y coordinate of the tile in the quadtree. 0 is the northernmost tile.
- * @param {TilingScheme} options.tilingScheme The tiling scheme in which this tile exists.
- * @param {QuadtreeTile} [options.parent] This tile's parent, or undefined if this is a root tile.
- */
- function QuadtreeTile(options) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(options)) {
- throw new DeveloperError("options is required.");
- }
- if (!defined(options.x)) {
- throw new DeveloperError("options.x is required.");
- } else if (!defined(options.y)) {
- throw new DeveloperError("options.y is required.");
- } else if (options.x < 0 || options.y < 0) {
- throw new DeveloperError(
- "options.x and options.y must be greater than or equal to zero."
- );
- }
- if (!defined(options.level)) {
- throw new DeveloperError(
- "options.level is required and must be greater than or equal to zero."
- );
- }
- if (!defined(options.tilingScheme)) {
- throw new DeveloperError("options.tilingScheme is required.");
- }
- //>>includeEnd('debug');
- this._tilingScheme = options.tilingScheme;
- this._x = options.x;
- this._y = options.y;
- this._level = options.level;
- this._parent = options.parent;
- this._rectangle = this._tilingScheme.tileXYToRectangle(
- this._x,
- this._y,
- this._level
- );
- this._southwestChild = undefined;
- this._southeastChild = undefined;
- this._northwestChild = undefined;
- this._northeastChild = undefined;
- // TileReplacementQueue gets/sets these private properties.
- this.replacementPrevious = undefined;
- this.replacementNext = undefined;
- // The distance from the camera to this tile, updated when the tile is selected
- // for rendering. We can get rid of this if we have a better way to sort by
- // distance - for example, by using the natural ordering of a quadtree.
- // QuadtreePrimitive gets/sets this private property.
- this._distance = 0.0;
- this._loadPriority = 0.0;
- this._customData = [];
- this._frameUpdated = undefined;
- this._lastSelectionResult = TileSelectionResult.NONE;
- this._lastSelectionResultFrame = undefined;
- this._loadedCallbacks = {};
- /**
- * Gets or sets the current state of the tile in the tile load pipeline.
- * @type {QuadtreeTileLoadState}
- * @default {@link QuadtreeTileLoadState.START}
- */
- this.state = QuadtreeTileLoadState.START;
- /**
- * Gets or sets a value indicating whether or not the tile is currently renderable.
- * @type {boolean}
- * @default false
- */
- this.renderable = false;
- /**
- * Gets or set a value indicating whether or not the tile was entirely upsampled from its
- * parent tile. If all four children of a parent tile were upsampled from the parent,
- * we will render the parent instead of the children even if the LOD indicates that
- * the children would be preferable.
- * @type {boolean}
- * @default false
- */
- this.upsampledFromParent = false;
- /**
- * Gets or sets the additional data associated with this tile. The exact content is specific to the
- * {@link QuadtreeTileProvider}.
- * @type {object}
- * @default undefined
- */
- this.data = undefined;
- }
- /**
- * Creates a rectangular set of tiles for level of detail zero, the coarsest, least detailed level.
- *
- * @memberof QuadtreeTile
- *
- * @param {TilingScheme} tilingScheme The tiling scheme for which the tiles are to be created.
- * @returns {QuadtreeTile[]} An array containing the tiles at level of detail zero, starting with the
- * tile in the northwest corner and followed by the tile (if any) to its east.
- */
- QuadtreeTile.createLevelZeroTiles = function (tilingScheme) {
- //>>includeStart('debug', pragmas.debug);
- if (!defined(tilingScheme)) {
- throw new DeveloperError("tilingScheme is required.");
- }
- //>>includeEnd('debug');
- const numberOfLevelZeroTilesX = tilingScheme.getNumberOfXTilesAtLevel(0);
- const numberOfLevelZeroTilesY = tilingScheme.getNumberOfYTilesAtLevel(0);
- const result = new Array(numberOfLevelZeroTilesX * numberOfLevelZeroTilesY);
- let index = 0;
- for (let y = 0; y < numberOfLevelZeroTilesY; ++y) {
- for (let x = 0; x < numberOfLevelZeroTilesX; ++x) {
- result[index++] = new QuadtreeTile({
- tilingScheme: tilingScheme,
- x: x,
- y: y,
- level: 0,
- });
- }
- }
- return result;
- };
- QuadtreeTile.prototype._updateCustomData = function (
- frameNumber,
- added,
- removed
- ) {
- let customData = this.customData;
- let i;
- let data;
- let rectangle;
- if (defined(added) && defined(removed)) {
- customData = customData.filter(function (value) {
- return removed.indexOf(value) === -1;
- });
- this._customData = customData;
- rectangle = this._rectangle;
- for (i = 0; i < added.length; ++i) {
- data = added[i];
- if (Rectangle.contains(rectangle, data.positionCartographic)) {
- customData.push(data);
- }
- }
- this._frameUpdated = frameNumber;
- } else {
- // interior or leaf tile, update from parent
- const parent = this._parent;
- if (defined(parent) && this._frameUpdated !== parent._frameUpdated) {
- customData.length = 0;
- rectangle = this._rectangle;
- const parentCustomData = parent.customData;
- for (i = 0; i < parentCustomData.length; ++i) {
- data = parentCustomData[i];
- if (Rectangle.contains(rectangle, data.positionCartographic)) {
- customData.push(data);
- }
- }
- this._frameUpdated = parent._frameUpdated;
- }
- }
- };
- Object.defineProperties(QuadtreeTile.prototype, {
- /**
- * Gets the tiling scheme used to tile the surface.
- * @memberof QuadtreeTile.prototype
- * @type {TilingScheme}
- */
- tilingScheme: {
- get: function () {
- return this._tilingScheme;
- },
- },
- /**
- * Gets the tile X coordinate.
- * @memberof QuadtreeTile.prototype
- * @type {number}
- */
- x: {
- get: function () {
- return this._x;
- },
- },
- /**
- * Gets the tile Y coordinate.
- * @memberof QuadtreeTile.prototype
- * @type {number}
- */
- y: {
- get: function () {
- return this._y;
- },
- },
- /**
- * Gets the level-of-detail, where zero is the coarsest, least-detailed.
- * @memberof QuadtreeTile.prototype
- * @type {number}
- */
- level: {
- get: function () {
- return this._level;
- },
- },
- /**
- * Gets the parent tile of this tile.
- * @memberof QuadtreeTile.prototype
- * @type {QuadtreeTile}
- */
- parent: {
- get: function () {
- return this._parent;
- },
- },
- /**
- * Gets the cartographic rectangle of the tile, with north, south, east and
- * west properties in radians.
- * @memberof QuadtreeTile.prototype
- * @type {Rectangle}
- */
- rectangle: {
- get: function () {
- return this._rectangle;
- },
- },
- /**
- * An array of tiles that is at the next level of the tile tree.
- * @memberof QuadtreeTile.prototype
- * @type {QuadtreeTile[]}
- */
- children: {
- get: function () {
- return [
- this.northwestChild,
- this.northeastChild,
- this.southwestChild,
- this.southeastChild,
- ];
- },
- },
- /**
- * Gets the southwest child tile.
- * @memberof QuadtreeTile.prototype
- * @type {QuadtreeTile}
- */
- southwestChild: {
- get: function () {
- if (!defined(this._southwestChild)) {
- this._southwestChild = new QuadtreeTile({
- tilingScheme: this.tilingScheme,
- x: this.x * 2,
- y: this.y * 2 + 1,
- level: this.level + 1,
- parent: this,
- });
- }
- return this._southwestChild;
- },
- },
- /**
- * Gets the southeast child tile.
- * @memberof QuadtreeTile.prototype
- * @type {QuadtreeTile}
- */
- southeastChild: {
- get: function () {
- if (!defined(this._southeastChild)) {
- this._southeastChild = new QuadtreeTile({
- tilingScheme: this.tilingScheme,
- x: this.x * 2 + 1,
- y: this.y * 2 + 1,
- level: this.level + 1,
- parent: this,
- });
- }
- return this._southeastChild;
- },
- },
- /**
- * Gets the northwest child tile.
- * @memberof QuadtreeTile.prototype
- * @type {QuadtreeTile}
- */
- northwestChild: {
- get: function () {
- if (!defined(this._northwestChild)) {
- this._northwestChild = new QuadtreeTile({
- tilingScheme: this.tilingScheme,
- x: this.x * 2,
- y: this.y * 2,
- level: this.level + 1,
- parent: this,
- });
- }
- return this._northwestChild;
- },
- },
- /**
- * Gets the northeast child tile.
- * @memberof QuadtreeTile.prototype
- * @type {QuadtreeTile}
- */
- northeastChild: {
- get: function () {
- if (!defined(this._northeastChild)) {
- this._northeastChild = new QuadtreeTile({
- tilingScheme: this.tilingScheme,
- x: this.x * 2 + 1,
- y: this.y * 2,
- level: this.level + 1,
- parent: this,
- });
- }
- return this._northeastChild;
- },
- },
- /**
- * An array of objects associated with this tile.
- * @memberof QuadtreeTile.prototype
- * @type {Array}
- */
- customData: {
- get: function () {
- return this._customData;
- },
- },
- /**
- * Gets a value indicating whether or not this tile needs further loading.
- * This property will return true if the {@link QuadtreeTile#state} is
- * <code>START</code> or <code>LOADING</code>.
- * @memberof QuadtreeTile.prototype
- * @type {boolean}
- */
- needsLoading: {
- get: function () {
- return this.state < QuadtreeTileLoadState.DONE;
- },
- },
- /**
- * Gets a value indicating whether or not this tile is eligible to be unloaded.
- * Typically, a tile is ineligible to be unloaded while an asynchronous operation,
- * such as a request for data, is in progress on it. A tile will never be
- * unloaded while it is needed for rendering, regardless of the value of this
- * property. If {@link QuadtreeTile#data} is defined and has an
- * <code>eligibleForUnloading</code> property, the value of that property is returned.
- * Otherwise, this property returns true.
- * @memberof QuadtreeTile.prototype
- * @type {boolean}
- */
- eligibleForUnloading: {
- get: function () {
- let result = true;
- if (defined(this.data)) {
- result = this.data.eligibleForUnloading;
- if (!defined(result)) {
- result = true;
- }
- }
- return result;
- },
- },
- });
- QuadtreeTile.prototype.findLevelZeroTile = function (levelZeroTiles, x, y) {
- const xTiles = this.tilingScheme.getNumberOfXTilesAtLevel(0);
- if (x < 0) {
- x += xTiles;
- } else if (x >= xTiles) {
- x -= xTiles;
- }
- if (y < 0 || y >= this.tilingScheme.getNumberOfYTilesAtLevel(0)) {
- return undefined;
- }
- return levelZeroTiles.filter(function (tile) {
- return tile.x === x && tile.y === y;
- })[0];
- };
- QuadtreeTile.prototype.findTileToWest = function (levelZeroTiles) {
- const parent = this.parent;
- if (parent === undefined) {
- return this.findLevelZeroTile(levelZeroTiles, this.x - 1, this.y);
- }
- if (parent.southeastChild === this) {
- return parent.southwestChild;
- } else if (parent.northeastChild === this) {
- return parent.northwestChild;
- }
- const westOfParent = parent.findTileToWest(levelZeroTiles);
- if (westOfParent === undefined) {
- return undefined;
- } else if (parent.southwestChild === this) {
- return westOfParent.southeastChild;
- }
- return westOfParent.northeastChild;
- };
- QuadtreeTile.prototype.findTileToEast = function (levelZeroTiles) {
- const parent = this.parent;
- if (parent === undefined) {
- return this.findLevelZeroTile(levelZeroTiles, this.x + 1, this.y);
- }
- if (parent.southwestChild === this) {
- return parent.southeastChild;
- } else if (parent.northwestChild === this) {
- return parent.northeastChild;
- }
- const eastOfParent = parent.findTileToEast(levelZeroTiles);
- if (eastOfParent === undefined) {
- return undefined;
- } else if (parent.southeastChild === this) {
- return eastOfParent.southwestChild;
- }
- return eastOfParent.northwestChild;
- };
- QuadtreeTile.prototype.findTileToSouth = function (levelZeroTiles) {
- const parent = this.parent;
- if (parent === undefined) {
- return this.findLevelZeroTile(levelZeroTiles, this.x, this.y + 1);
- }
- if (parent.northwestChild === this) {
- return parent.southwestChild;
- } else if (parent.northeastChild === this) {
- return parent.southeastChild;
- }
- const southOfParent = parent.findTileToSouth(levelZeroTiles);
- if (southOfParent === undefined) {
- return undefined;
- } else if (parent.southwestChild === this) {
- return southOfParent.northwestChild;
- }
- return southOfParent.northeastChild;
- };
- QuadtreeTile.prototype.findTileToNorth = function (levelZeroTiles) {
- const parent = this.parent;
- if (parent === undefined) {
- return this.findLevelZeroTile(levelZeroTiles, this.x, this.y - 1);
- }
- if (parent.southwestChild === this) {
- return parent.northwestChild;
- } else if (parent.southeastChild === this) {
- return parent.northeastChild;
- }
- const northOfParent = parent.findTileToNorth(levelZeroTiles);
- if (northOfParent === undefined) {
- return undefined;
- } else if (parent.northwestChild === this) {
- return northOfParent.southwestChild;
- }
- return northOfParent.southeastChild;
- };
- /**
- * Frees the resources associated with this tile and returns it to the <code>START</code>
- * {@link QuadtreeTileLoadState}. If the {@link QuadtreeTile#data} property is defined and it
- * has a <code>freeResources</code> method, the method will be invoked.
- *
- * @memberof QuadtreeTile
- */
- QuadtreeTile.prototype.freeResources = function () {
- this.state = QuadtreeTileLoadState.START;
- this.renderable = false;
- this.upsampledFromParent = false;
- if (defined(this.data) && defined(this.data.freeResources)) {
- this.data.freeResources();
- }
- freeTile(this._southwestChild);
- this._southwestChild = undefined;
- freeTile(this._southeastChild);
- this._southeastChild = undefined;
- freeTile(this._northwestChild);
- this._northwestChild = undefined;
- freeTile(this._northeastChild);
- this._northeastChild = undefined;
- };
- function freeTile(tile) {
- if (defined(tile)) {
- tile.freeResources();
- }
- }
- export default QuadtreeTile;
|