Skip to content

Commit

Permalink
Remove globals parameter from PossiblyEvaluatedPropertyValue::evaluate
Browse files Browse the repository at this point in the history
Instead make it a member variable that gets set when the PossiblyEvaluated is created as a result of (possibly) evaluating properties at a certain zoom level. This makes it clear that you can't supply a different zoom level at the final evaluation step. The SymbolBucket constructor now creates individual PossiblyEvaluatedPropertyValues for all the necessary zoom levels. See code comment for details.
  • Loading branch information
jfirebaugh committed Nov 15, 2017
1 parent 52e9ab8 commit 0ed1c7a
Show file tree
Hide file tree
Showing 10 changed files with 125 additions and 77 deletions.
2 changes: 1 addition & 1 deletion src/data/bucket/line_bucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ class LineBucket implements Bucket {

addFeature(feature: VectorTileFeature, geometry: Array<Array<Point>>) {
const layout = this.layers[0].layout;
const join = layout.get('line-join').evaluate({zoom: this.zoom}, feature);
const join = layout.get('line-join').evaluate(feature);
const cap = layout.get('line-cap');
const miterLimit = layout.get('line-miter-limit');
const roundLimit = layout.get('line-round-limit');
Expand Down
59 changes: 52 additions & 7 deletions src/data/bucket/symbol_bucket.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// @flow

const Point = require('@mapbox/point-geometry');
const {SegmentVector} = require('../segment');
const VertexBuffer = require('../../gl/vertex_buffer');
Expand Down Expand Up @@ -27,6 +28,8 @@ import type {
} from '../../util/struct_array';
import type SymbolStyleLayer from '../../style/style_layer/symbol_style_layer';
import type {SymbolQuad} from '../../symbol/quads';
import type {SizeData} from '../../symbol/symbol_size';
import type {PossiblyEvaluatedPropertyValue} from '../../style/properties';

export type SingleCollisionBox = {
x1: number;
Expand Down Expand Up @@ -365,8 +368,29 @@ class SymbolBucket implements Bucket {
index: number;
sdfIcons: boolean;
iconsNeedLinear: boolean;
textSizeData: any;
iconSizeData: any;

// The symbol layout process needs `text-size` evaluated at up to five different zoom levels, and
// `icon-size` at up to three:
//
// 1. `text-size` at the zoom level of the bucket. Used to calculate a per-feature size for source `text-size`
// expressions, and to calculate the box dimensions for icon-text-fit.
// 2. `icon-size` at the zoom level of the bucket. Used to calculate a per-feature size for source `icon-size`
// expressions.
// 3. `text-size` and `icon-size` at the zoom level of the bucket, plus one. Used to calculate collision boxes.
// 4. `text-size` at zoom level 18. Used for something line-symbol-placement-related.
// 5. For composite `*-size` expressions: two zoom levels of curve stops that "cover" the zoom level of the
// bucket. These go into a vertex buffer and are used by the shader to interpolate the size at render time.
//
// (1) and (2) are stored in `this.layers[0].layout`. The remainder are below.
//
textSizeData: SizeData;
iconSizeData: SizeData;
layoutTextSize: PossiblyEvaluatedPropertyValue<number>; // (3)
layoutIconSize: PossiblyEvaluatedPropertyValue<number>; // (3)
textMaxSize: PossiblyEvaluatedPropertyValue<number>; // (4)
compositeTextSizes: [PossiblyEvaluatedPropertyValue<number>, PossiblyEvaluatedPropertyValue<number>]; // (5)
compositeIconSizes: [PossiblyEvaluatedPropertyValue<number>, PossiblyEvaluatedPropertyValue<number>]; // (5)

placedGlyphArray: StructArray;
placedIconArray: StructArray;
glyphOffsetArray: StructArray;
Expand Down Expand Up @@ -419,8 +443,29 @@ class SymbolBucket implements Bucket {

} else {
const layer: SymbolStyleLayer = this.layers[0];
this.textSizeData = getSizeData(this.zoom, layer._unevaluatedLayout._values['text-size']);
this.iconSizeData = getSizeData(this.zoom, layer._unevaluatedLayout._values['icon-size']);
const unevaluatedLayoutValues = layer._unevaluatedLayout._values;

this.textSizeData = getSizeData(this.zoom, unevaluatedLayoutValues['text-size']);
if (this.textSizeData.functionType === 'composite') {
const {min, max} = this.textSizeData.zoomRange;
this.compositeTextSizes = [
unevaluatedLayoutValues['text-size'].possiblyEvaluate({zoom: min}),
unevaluatedLayoutValues['text-size'].possiblyEvaluate({zoom: max})
];
}

this.iconSizeData = getSizeData(this.zoom, unevaluatedLayoutValues['icon-size']);
if (this.iconSizeData.functionType === 'composite') {
const {min, max} = this.iconSizeData.zoomRange;
this.compositeIconSizes = [
unevaluatedLayoutValues['icon-size'].possiblyEvaluate({zoom: min}),
unevaluatedLayoutValues['icon-size'].possiblyEvaluate({zoom: max})
];
}

this.layoutTextSize = unevaluatedLayoutValues['text-size'].possiblyEvaluate({zoom: this.zoom + 1});
this.layoutIconSize = unevaluatedLayoutValues['icon-size'].possiblyEvaluate({zoom: this.zoom + 1});
this.textMaxSize = unevaluatedLayoutValues['text-size'].possiblyEvaluate({zoom: 18});
}
}

Expand Down Expand Up @@ -464,13 +509,13 @@ class SymbolBucket implements Bucket {

let text;
if (hasText) {
text = layer.getValueAndResolveTokens('text-field', globalProperties, feature);
text = transformText(text, layer, globalProperties, feature);
text = layer.getValueAndResolveTokens('text-field', feature);
text = transformText(text, layer, feature);
}

let icon;
if (hasIcon) {
icon = layer.getValueAndResolveTokens('icon-image', globalProperties, feature);
icon = layer.getValueAndResolveTokens('icon-image', feature);
}

if (!text && !icon) {
Expand Down
9 changes: 5 additions & 4 deletions src/render/draw_background.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ function drawBackground(painter: Painter, sourceCache: SourceCache, layer: Backg
const transform = painter.transform;
const tileSize = transform.tileSize;
const image = layer.paint.get('background-pattern');
const globals = {zoom: transform.zoom};

const pass = (!image && color.a === 1 && opacity === 1) ? 'opaque' : 'translucent';
if (painter.renderPass !== pass) return;
Expand All @@ -31,23 +32,23 @@ function drawBackground(painter: Painter, sourceCache: SourceCache, layer: Backg

const properties = new PossiblyEvaluated({
'background-color': new PossiblyEvaluatedPropertyValue(
fillLayerPaintProperties['fill-color'], {kind: 'constant', value: color}),
fillLayerPaintProperties['fill-color'], {kind: 'constant', value: color}, globals),
'background-opacity': new PossiblyEvaluatedPropertyValue(
fillLayerPaintProperties['fill-opacity'], {kind: 'constant', value: opacity})
fillLayerPaintProperties['fill-opacity'], {kind: 'constant', value: opacity}, globals)
});

let program;
if (image) {
if (pattern.isPatternMissing(image, painter)) return;
const configuration = ProgramConfiguration.forBackgroundPattern(opacity);
program = painter.useProgram('fillPattern', configuration);
configuration.setUniforms(gl, program, properties, {zoom: painter.transform.zoom});
configuration.setUniforms(gl, program, properties, globals);
pattern.prepare(image, painter, program);
painter.tileExtentPatternVAO.bind(gl, program, painter.tileExtentBuffer);
} else {
const configuration = ProgramConfiguration.forBackgroundColor(color, opacity);
program = painter.useProgram('fill', configuration);
configuration.setUniforms(gl, program, properties, {zoom: painter.transform.zoom});
configuration.setUniforms(gl, program, properties, globals);
painter.tileExtentVAO.bind(gl, program, painter.tileExtentBuffer);
}

Expand Down
24 changes: 13 additions & 11 deletions src/style/properties.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ type TransitionParameters = {
};

export type EvaluationParameters = GlobalProperties & {
now: TimePoint,
defaultFadeDuration: number,
zoomHistory: ZoomHistory
now?: TimePoint,
defaultFadeDuration?: number,
zoomHistory?: ZoomHistory
};

export interface Property<T, R> {
Expand Down Expand Up @@ -166,7 +166,7 @@ class TransitioningPropertyValue<T, R> {
}

possiblyEvaluate(parameters: EvaluationParameters): R {
const now = parameters.now;
const now = parameters.now || 0;
const finalValue = this.value.possiblyEvaluate(parameters);
const prior = this.prior;
if (!prior) {
Expand Down Expand Up @@ -274,10 +274,12 @@ export type PossiblyEvaluatedValue<T> =
class PossiblyEvaluatedPropertyValue<T> {
property: DataDrivenProperty<T>;
value: PossiblyEvaluatedValue<T>;
globals: GlobalProperties;

constructor(property: DataDrivenProperty<T>, value: PossiblyEvaluatedValue<T>) {
constructor(property: DataDrivenProperty<T>, value: PossiblyEvaluatedValue<T>, globals: GlobalProperties) {
this.property = property;
this.value = value;
this.globals = globals;
}

isConstant(): boolean {
Expand All @@ -292,8 +294,8 @@ class PossiblyEvaluatedPropertyValue<T> {
}
}

evaluate(globals: GlobalProperties, feature: Feature): T {
return this.property.evaluate(this.value, globals, feature);
evaluate(feature: Feature): T {
return this.property.evaluate(this.value, this.globals, feature);
}
}

Expand Down Expand Up @@ -348,9 +350,9 @@ class DataDrivenProperty<T> implements Property<T, PossiblyEvaluatedPropertyValu
parameters = extend({}, parameters, {zoom: Math.floor(parameters.zoom)});
}
if (value.expression.kind === 'constant' || value.expression.kind === 'camera') {
return new PossiblyEvaluatedPropertyValue(this, {kind: 'constant', value: value.expression.evaluate(parameters)});
return new PossiblyEvaluatedPropertyValue(this, {kind: 'constant', value: value.expression.evaluate(parameters)}, parameters);
} else {
return new PossiblyEvaluatedPropertyValue(this, value.expression);
return new PossiblyEvaluatedPropertyValue(this, value.expression, parameters);
}
}

Expand All @@ -367,7 +369,7 @@ class DataDrivenProperty<T> implements Property<T, PossiblyEvaluatedPropertyValu

const interp: ?(a: T, b: T, t: number) => T = (interpolate: any)[this.specification.type];
if (interp) {
return new PossiblyEvaluatedPropertyValue(this, {kind: 'constant', value: interp(a.value.value, b.value.value, t)});
return new PossiblyEvaluatedPropertyValue(this, {kind: 'constant', value: interp(a.value.value, b.value.value, t)}, a.globals);
} else {
return a;
}
Expand Down Expand Up @@ -408,7 +410,7 @@ class CrossFadedProperty<T> implements Property<T, ?CrossFaded<T>> {
}
}

_calculate(min: T, mid: T, max: T, parameters: EvaluationParameters): ?CrossFaded<T> {
_calculate(min: T, mid: T, max: T, parameters: any): ?CrossFaded<T> {
const z = parameters.zoom;
const fraction = z - Math.floor(z);
const d = parameters.defaultFadeDuration;
Expand Down
4 changes: 2 additions & 2 deletions src/style/style_layer/circle_style_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ class CircleStyleLayer extends StyleLayer {
this.paint.get('circle-translate'),
this.paint.get('circle-translate-anchor'),
bearing, pixelsToTileUnits);
const radius = this.paint.get('circle-radius').evaluate({zoom}, feature) * pixelsToTileUnits;
const stroke = this.paint.get('circle-stroke-width').evaluate({zoom}, feature) * pixelsToTileUnits;
const radius = this.paint.get('circle-radius').evaluate(feature) * pixelsToTileUnits;
const stroke = this.paint.get('circle-stroke-width').evaluate(feature) * pixelsToTileUnits;
return multiPolygonIntersectsBufferedMultiPoint(translatedPolygon, geometry, radius + stroke);
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/style/style_layer/line_style_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ class LineStyleLayer extends StyleLayer {
this.paint.get('line-translate-anchor'),
bearing, pixelsToTileUnits);
const halfWidth = pixelsToTileUnits / 2 * getLineWidth(
this.paint.get('line-width').evaluate({zoom}, feature),
this.paint.get('line-gap-width').evaluate({zoom}, feature));
const lineOffset = this.paint.get('line-offset').evaluate({zoom}, feature);
this.paint.get('line-width').evaluate(feature),
this.paint.get('line-gap-width').evaluate(feature));
const lineOffset = this.paint.get('line-offset').evaluate(feature);
if (lineOffset) {
geometry = offsetLine(geometry, lineOffset * pixelsToTileUnits);
}
Expand Down
6 changes: 3 additions & 3 deletions src/style/style_layer/symbol_style_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const {

import type {BucketParameters} from '../../data/bucket';
import type {LayoutProperties, PaintProperties} from './symbol_style_layer_properties';
import type {GlobalProperties, Feature} from '../../style-spec/expression';
import type {Feature} from '../../style-spec/expression';
import type {EvaluationParameters} from '../properties';

class SymbolStyleLayer extends StyleLayer {
Expand Down Expand Up @@ -59,8 +59,8 @@ class SymbolStyleLayer extends StyleLayer {
}
}

getValueAndResolveTokens(name: *, globals: GlobalProperties, feature: Feature) {
const value = this.layout.get(name).evaluate(globals, feature);
getValueAndResolveTokens(name: *, feature: Feature) {
const value = this.layout.get(name).evaluate(feature);
const unevaluated = this._unevaluatedLayout._values[name];
if (!unevaluated.isDataDriven() && !isExpression(unevaluated.value)) {
return resolveTokens(feature.properties, value);
Expand Down
8 changes: 4 additions & 4 deletions src/symbol/quads.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ function getIconQuads(anchor: Anchor,
if (layout.get('icon-text-fit') !== 'none' && shapedText) {
const iconWidth = (right - left),
iconHeight = (bottom - top),
size = layout.get('text-size').evaluate(globalProperties, feature) / 24,
size = layout.get('text-size').evaluate(feature) / 24,
textLeft = shapedText.left * size,
textRight = shapedText.right * size,
textTop = shapedText.top * size,
Expand All @@ -98,7 +98,7 @@ function getIconQuads(anchor: Anchor,
bl = new Point(left, bottom);
}

const angle = layer.layout.get('icon-rotate').evaluate(globalProperties, feature) * Math.PI / 180;
const angle = layer.layout.get('icon-rotate').evaluate(feature) * Math.PI / 180;

if (angle) {
const sin = Math.sin(angle),
Expand Down Expand Up @@ -135,8 +135,8 @@ function getGlyphQuads(anchor: Anchor,
positions: {[number]: GlyphPosition}): Array<SymbolQuad> {

const oneEm = 24;
const textRotate = layer.layout.get('text-rotate').evaluate(globalProperties, feature) * Math.PI / 180;
const textOffset = layer.layout.get('text-offset').evaluate(globalProperties, feature).map((t)=> t * oneEm);
const textRotate = layer.layout.get('text-rotate').evaluate(feature) * Math.PI / 180;
const textOffset = layer.layout.get('text-offset').evaluate(feature).map((t)=> t * oneEm);

const positionedGlyphs = shaping.positionedGlyphs;
const quads = [];
Expand Down
Loading

0 comments on commit 0ed1c7a

Please sign in to comment.