Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DV: Update tile selection to defer replace refinement until global selection #11

Merged
merged 2 commits into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
"bootstrap": {}
},
"npmClient": "yarn",
"useWorkspaces": true,
"exact": true,
"packages": [
"modules/*"
Expand Down
78 changes: 76 additions & 2 deletions modules/tiles/src/tileset/grouped-tiles.array.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,82 @@ export class GroupedTilesArray {
this.array.push(other);
}

addTilesOrGroups(other: GroupedTilesArray) {
this.array.push(...other.array);
/**
* Adds the content of another GroupedTilesArray instance to this one.
* Optionally, a maximum size can be specified which will add items in
* order of _displayPriority up until the maximum size is reached.
* @param other The other instance to read from
* @param maxSize Optional maximum size of this GroupedTilesArray after
* the operation.
*/
addTilesOrGroups(other: GroupedTilesArray, maxSize: number = 0) {
const totalItems = this.array.length + other.array.length;

if (maxSize <= 0 || totalItems <= maxSize) {
// unlimited, or enough space to append all elements
this.array = this.array.concat(other.array);
} else {
// add as many items as possible by display priority, up to the maximum size
const replacedTileIds = new Set<string>();
let itemsToAdd = maxSize - this.array.length;

// shallow copy of other array to not modify other group
const otherArray = other.array.slice();

// ensure array is sorted DESCENDING by priority
otherArray.sort((a, b) => b._displayPriority - a._displayPriority);

while (itemsToAdd > 0 && otherArray.length > 0) {
// popping off end means iterating the list ASCENDING in priority
const nextItem = otherArray.pop()!; // safe assertion as we just checked the length

const nextItemReplacedIds =
nextItem instanceof Tile3D
? [nextItem._replacedTileId]
: nextItem.tiles.map((tile) => tile._replacedTileId);

const tilesInItem = nextItem instanceof Tile3D ? 1 : nextItem.tiles.length;
if (tilesInItem > itemsToAdd) {
// can't add the next item as it'd make the list too long
break;
}

// add the item
this.array.push(nextItem);
itemsToAdd -= tilesInItem;

// update replaced tile Ids (and increase the count if needed)
for (let i = 0; i < nextItemReplacedIds.length; i++) {
const replacedTileId = nextItemReplacedIds[i];

if (replacedTileId !== undefined && !replacedTileIds.has(replacedTileId)) {
// we're replacing a new item, so we need to add an extra item
itemsToAdd++;
replacedTileIds.add(replacedTileId);
}
}
}

// splice out any replaced tiles
this.array = this.array
.map((tileOrGroup) => {
if (tileOrGroup instanceof TileGroup3D) {
const filteredGroup = new TileGroup3D();

for (let i = 0; i < tileOrGroup.tiles.length; i++) {
const tile = tileOrGroup.tiles[i];
if (!replacedTileIds.has(tile.id)) {
filteredGroup.addTile(tile);
}
}

return filteredGroup.tiles.length > 0 ? filteredGroup : null;
}

return !replacedTileIds.has(tileOrGroup.id) ? tileOrGroup : null;
})
.filter((item): item is Tile3D | TileGroup3D => item !== null);
}
}

numTiles() {
Expand Down
14 changes: 7 additions & 7 deletions modules/tiles/src/tileset/tileset-traverser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,12 @@ export class TilesetTraverser {

// replace tiles
} else if (tile.refine === TILE_REFINEMENT.REPLACE) {
// Always load tiles in the base traversal
// Select tiles that can't refine further
// Always load and select replacement tiles (so we can handle refinement at a global scale later)
// note (ck): This differs from the normal loadersgl implementation as we want to keep track of replaced
// root nodes so we can decide which level of detail to render based on the global tile budget rather than
// a per tile budget.
this.loadTile(tile, frameState);
if (stoppedRefining) {
this.selectTile(tile, frameState);
}
this.selectTile(tile, frameState);
}

// 3. update cache, most recent touched tiles have higher priority to be fetched from server
Expand Down Expand Up @@ -259,8 +259,8 @@ export class TilesetTraverser {
// only be necessary to set the replacedTileId once, on load.
if (tile.parent?.refine === TILE_REFINEMENT.REPLACE) {
// The root tile of a tileset does not have an ID, so when the tileset root is a REPLACE
// tile , its children set the _replacedTileId to the URL for the whole tileset.
tile._replacedTileId = tile.parent._replacedTileId ?? tile.parent.id ?? tile.tileset.url;
// tile, its children set the _replacedTileId to the URL for the whole tileset.
tile._replacedTileId = tile.parent.id ?? tile.tileset.url;
}
}
}
Expand Down
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,9 @@
"volta": {
"node": "18.19.0",
"yarn": "4.1.1"
}
},
"dependencies": {
"lerna": "^8.1.8"
},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
Loading