Avoid clipping when rendering to tiles that don't exceed the clip extent
This commit is contained in:
@@ -55,27 +55,19 @@ const p4 = [];
|
||||
|
||||
class Executor extends Disposable {
|
||||
/**
|
||||
* @param {import("../../extent.js").Extent} maxExtent Maximum extent.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {boolean} overlaps The replay can have overlapping geometries.
|
||||
* @param {?} declutterTree Declutter tree.
|
||||
* @param {SerializableInstructions} instructions The serializable instructions
|
||||
*/
|
||||
constructor(maxExtent, resolution, pixelRatio, overlaps, declutterTree, instructions) {
|
||||
constructor(resolution, pixelRatio, overlaps, declutterTree, instructions) {
|
||||
super();
|
||||
/**
|
||||
* @type {?}
|
||||
*/
|
||||
this.declutterTree = declutterTree;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @const
|
||||
* @type {import("../../extent.js").Extent}
|
||||
*/
|
||||
this.maxExtent = maxExtent;
|
||||
|
||||
/**
|
||||
* @protected
|
||||
* @type {boolean}
|
||||
|
||||
@@ -28,7 +28,10 @@ const ORDER = [
|
||||
|
||||
class ExecutorGroup extends Disposable {
|
||||
/**
|
||||
* @param {import("../../extent.js").Extent} maxExtent Max extent.
|
||||
* @param {import("../../extent.js").Extent} maxExtent Max extent for clipping. When a
|
||||
* `maxExtent` was set on the Buillder for this executor group, the same `maxExtent`
|
||||
* should be set here, unless the target context does not exceet that extent (which
|
||||
* can be the case when rendering to tiles).
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {boolean} overlaps The executor group can have overlapping geometries.
|
||||
@@ -124,7 +127,7 @@ class ExecutorGroup extends Disposable {
|
||||
const instructionByZindex = allInstructions[zIndex];
|
||||
for (const builderType in instructionByZindex) {
|
||||
const instructions = instructionByZindex[builderType];
|
||||
executors[builderType] = new Executor(this.maxExtent_,
|
||||
executors[builderType] = new Executor(
|
||||
this.resolution_, this.pixelRatio_, this.overlaps_, this.declutterTree_, instructions);
|
||||
}
|
||||
}
|
||||
@@ -283,6 +286,9 @@ class ExecutorGroup extends Disposable {
|
||||
*/
|
||||
getClipCoords(transform) {
|
||||
const maxExtent = this.maxExtent_;
|
||||
if (!maxExtent) {
|
||||
return null;
|
||||
}
|
||||
const minX = maxExtent[0];
|
||||
const minY = maxExtent[1];
|
||||
const maxX = maxExtent[2];
|
||||
@@ -308,7 +314,7 @@ class ExecutorGroup extends Disposable {
|
||||
let executor = executors[builderType];
|
||||
if (executor === undefined) {
|
||||
// FIXME: it should not be possible to ask for an executor that does not exist
|
||||
executor = new Executor(this.maxExtent_,
|
||||
executor = new Executor(
|
||||
this.resolution_, this.pixelRatio_, this.overlaps_, {
|
||||
instructions: [],
|
||||
hitDetectionInstructions: [],
|
||||
@@ -353,8 +359,10 @@ class ExecutorGroup extends Disposable {
|
||||
|
||||
// setup clipping so that the parts of over-simplified geometries are not
|
||||
// visible outside the current extent when panning
|
||||
context.save();
|
||||
this.clip(context, transform);
|
||||
if (this.maxExtent_) {
|
||||
context.save();
|
||||
this.clip(context, transform);
|
||||
}
|
||||
|
||||
const builderTypes = opt_builderTypes ? opt_builderTypes : ORDER;
|
||||
let i, ii, j, jj, replays, replay;
|
||||
@@ -380,7 +388,9 @@ class ExecutorGroup extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
context.restore();
|
||||
if (this.maxExtent_) {
|
||||
context.restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -313,7 +313,11 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
}
|
||||
}
|
||||
const executorGroupInstructions = builderGroup.finish();
|
||||
const renderingReplayGroup = new CanvasExecutorGroup(sharedExtent, resolution,
|
||||
// no need to clip when the render tile is covered by a single source tile
|
||||
const replayExtent = layer.getDeclutter() && sourceTiles.length === 1 ?
|
||||
null :
|
||||
sharedExtent;
|
||||
const renderingReplayGroup = new CanvasExecutorGroup(replayExtent, resolution,
|
||||
pixelRatio, source.getOverlaps(), this.declutterTree_, executorGroupInstructions, layer.getRenderBuffer());
|
||||
tile.executorGroups[layerUid].push(renderingReplayGroup);
|
||||
}
|
||||
@@ -462,7 +466,6 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
const tiles = this.renderedTiles;
|
||||
const tileGrid = source.getTileGridForProjection(frameState.viewState.projection);
|
||||
const clips = [];
|
||||
const zs = [];
|
||||
for (let i = tiles.length - 1; i >= 0; --i) {
|
||||
const tile = /** @type {import("../../VectorRenderTile.js").default} */ (tiles[i]);
|
||||
if (tile.getState() == TileState.ABORT) {
|
||||
@@ -481,32 +484,38 @@ class CanvasVectorTileLayerRenderer extends CanvasTileLayerRenderer {
|
||||
continue;
|
||||
}
|
||||
const currentZ = tile.tileCoord[0];
|
||||
const currentClip = executorGroup.getClipCoords(transform);
|
||||
context.save();
|
||||
let zs, currentClip;
|
||||
if (!declutterReplays) {
|
||||
zs = [];
|
||||
currentClip = executorGroup.getClipCoords(transform);
|
||||
context.save();
|
||||
|
||||
// Create a clip mask for regions in this low resolution tile that are
|
||||
// already filled by a higher resolution tile
|
||||
for (let j = 0, jj = clips.length; j < jj; ++j) {
|
||||
const clip = clips[j];
|
||||
if (currentZ < zs[j]) {
|
||||
context.beginPath();
|
||||
// counter-clockwise (outer ring) for current tile
|
||||
context.moveTo(currentClip[0], currentClip[1]);
|
||||
context.lineTo(currentClip[2], currentClip[3]);
|
||||
context.lineTo(currentClip[4], currentClip[5]);
|
||||
context.lineTo(currentClip[6], currentClip[7]);
|
||||
// clockwise (inner ring) for higher resolution tile
|
||||
context.moveTo(clip[6], clip[7]);
|
||||
context.lineTo(clip[4], clip[5]);
|
||||
context.lineTo(clip[2], clip[3]);
|
||||
context.lineTo(clip[0], clip[1]);
|
||||
context.clip();
|
||||
// Create a clip mask for regions in this low resolution tile that are
|
||||
// already filled by a higher resolution tile
|
||||
for (let j = 0, jj = clips.length; j < jj; ++j) {
|
||||
const clip = clips[j];
|
||||
if (currentZ < zs[j]) {
|
||||
context.beginPath();
|
||||
// counter-clockwise (outer ring) for current tile
|
||||
context.moveTo(currentClip[0], currentClip[1]);
|
||||
context.lineTo(currentClip[2], currentClip[3]);
|
||||
context.lineTo(currentClip[4], currentClip[5]);
|
||||
context.lineTo(currentClip[6], currentClip[7]);
|
||||
// clockwise (inner ring) for higher resolution tile
|
||||
context.moveTo(clip[6], clip[7]);
|
||||
context.lineTo(clip[4], clip[5]);
|
||||
context.lineTo(clip[2], clip[3]);
|
||||
context.lineTo(clip[0], clip[1]);
|
||||
context.clip();
|
||||
}
|
||||
}
|
||||
}
|
||||
executorGroup.execute(context, transform, rotation, {}, hifi, replayTypes, declutterReplays);
|
||||
context.restore();
|
||||
clips.push(currentClip);
|
||||
zs.push(currentZ);
|
||||
if (!declutterReplays) {
|
||||
context.restore();
|
||||
clips.push(currentClip);
|
||||
zs.push(currentZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (declutterReplays) {
|
||||
|
||||
Reference in New Issue
Block a user