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

Add *-sort-key layout property for circle, fill, line #8467

Merged
merged 17 commits into from
Jul 18, 2019
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
3 changes: 2 additions & 1 deletion src/data/bucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ export type BucketFeature = {|
properties: Object,
type: 1 | 2 | 3,
id?: any,
+patterns: {[string]: {"min": string, "mid": string, "max": string}}
+patterns: {[string]: {"min": string, "mid": string, "max": string}},
sortKey?: number
|};

/**
Expand Down
48 changes: 43 additions & 5 deletions src/data/bucket/circle_bucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import EvaluationParameters from '../../style/evaluation_parameters';
import type {
Bucket,
BucketParameters,
BucketFeature,
IndexedFeature,
PopulateParameters
} from '../bucket';
Expand Down Expand Up @@ -74,17 +75,54 @@ class CircleBucket<Layer: CircleStyleLayer | HeatmapStyleLayer> implements Bucke
this.segments = new SegmentVector();
this.programConfigurations = new ProgramConfigurationSet(layoutAttributes, options.layers, options.zoom);
this.stateDependentLayerIds = this.layers.filter((l) => l.isStateDependent()).map((l) => l.id);

}

populate(features: Array<IndexedFeature>, options: PopulateParameters) {
const styleLayer = this.layers[0];
const bucketFeatures = [];
let circleSortKey = null;

// Heatmap layers are handled in this bucket and have no evaluated properties, so we check our access
if (styleLayer.type === 'circle') {
circleSortKey = ((styleLayer: any): CircleStyleLayer).layout.get('circle-sort-key');
}

for (const {feature, index, sourceLayerIndex} of features) {
if (this.layers[0]._featureFilter(new EvaluationParameters(this.zoom), feature)) {
const geometry = loadGeometry(feature);
this.addFeature(feature, geometry, index);
options.featureIndex.insert(feature, geometry, index, sourceLayerIndex, this.index);
const sortKey = circleSortKey ?
circleSortKey.evaluate(feature, {}) :
undefined;

const bucketFeature: BucketFeature = {
id: feature.id,
properties: feature.properties,
type: feature.type,
sourceLayerIndex,
index,
geometry,
patterns: {},
sortKey
};

bucketFeatures.push(bucketFeature);
}
}

if (circleSortKey) {
bucketFeatures.sort((a, b) => {
// a.sortKey is always a number when in use
return ((a.sortKey: any): number) - ((b.sortKey: any): number);
});
}

for (const bucketFeature of bucketFeatures) {
const {geometry, index, sourceLayerIndex} = bucketFeature;
const feature = features[index].feature;

this.addFeature(bucketFeature, geometry, index);
options.featureIndex.insert(feature, geometry, index, sourceLayerIndex, this.index);
}
}

update(states: FeatureStates, vtLayer: VectorTileLayer, imagePositions: {[string]: ImagePosition}) {
Expand Down Expand Up @@ -117,7 +155,7 @@ class CircleBucket<Layer: CircleStyleLayer | HeatmapStyleLayer> implements Bucke
this.segments.destroy();
}

addFeature(feature: VectorTileFeature, geometry: Array<Array<Point>>, index: number) {
addFeature(feature: BucketFeature, geometry: Array<Array<Point>>, index: number) {
for (const ring of geometry) {
for (const point of ring) {
const x = point.x;
Expand All @@ -135,7 +173,7 @@ class CircleBucket<Layer: CircleStyleLayer | HeatmapStyleLayer> implements Bucke
// │ 0 1 │
// └─────────┘

const segment = this.segments.prepareSegment(4, this.layoutVertexArray, this.indexArray);
const segment = this.segments.prepareSegment(4, this.layoutVertexArray, this.indexArray, feature.sortKey);
const index = segment.vertexLength;

addCircleVertex(this.layoutVertexArray, x, y, -1, -1);
Expand Down
50 changes: 34 additions & 16 deletions src/data/bucket/fill_bucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class FillBucket implements Bucket {
layerIds: Array<string>;
stateDependentLayers: Array<FillStyleLayer>;
stateDependentLayerIds: Array<string>;
patternFeatures: Array<BucketFeature>;

layoutVertexArray: FillLayoutArray;
layoutVertexBuffer: VertexBuffer;
Expand All @@ -53,7 +54,6 @@ class FillBucket implements Bucket {
segments: SegmentVector;
segments2: SegmentVector;
uploaded: boolean;
features: Array<BucketFeature>;

constructor(options: BucketParameters<FillStyleLayer>) {
this.zoom = options.zoom;
Expand All @@ -62,6 +62,7 @@ class FillBucket implements Bucket {
this.layerIds = this.layers.map(layer => layer.id);
this.index = options.index;
this.hasPattern = false;
this.patternFeatures = [];

this.layoutVertexArray = new FillLayoutArray();
this.indexArray = new TriangleIndexArray();
Expand All @@ -70,37 +71,55 @@ class FillBucket implements Bucket {
this.segments = new SegmentVector();
this.segments2 = new SegmentVector();
this.stateDependentLayerIds = this.layers.filter((l) => l.isStateDependent()).map((l) => l.id);

}

populate(features: Array<IndexedFeature>, options: PopulateParameters) {
this.features = [];
this.hasPattern = hasPattern('fill', this.layers, options);
const fillSortKey = this.layers[0].layout.get('fill-sort-key');
const bucketFeatures = [];

for (const {feature, index, sourceLayerIndex} of features) {
if (!this.layers[0]._featureFilter(new EvaluationParameters(this.zoom), feature)) continue;

const geometry = loadGeometry(feature);
const sortKey = fillSortKey ?
fillSortKey.evaluate(feature, {}) :
undefined;

const patternFeature: BucketFeature = {
const bucketFeature: BucketFeature = {
id: feature.id,
properties: feature.properties,
type: feature.type,
sourceLayerIndex,
index,
geometry,
properties: feature.properties,
type: feature.type,
patterns: {}
patterns: {},
sortKey
};

if (typeof feature.id !== 'undefined') {
patternFeature.id = feature.id;
}
bucketFeatures.push(bucketFeature);
}

if (fillSortKey) {
bucketFeatures.sort((a, b) => {
// a.sortKey is always a number when in use
return ((a.sortKey: any): number) - ((b.sortKey: any): number);
});
}

for (const bucketFeature of bucketFeatures) {
const {geometry, index, sourceLayerIndex} = bucketFeature;

if (this.hasPattern) {
this.features.push(addPatternDependencies('fill', this.layers, patternFeature, this.zoom, options));
const patternFeature = addPatternDependencies('fill', this.layers, bucketFeature, this.zoom, options);
// pattern features are added only once the pattern is loaded into the image atlas
// so are stored during populate until later updated with positions by tile worker in addFeatures
this.patternFeatures.push(patternFeature);
} else {
this.addFeature(patternFeature, geometry, index, {});
this.addFeature(bucketFeature, geometry, index, {});
}

const feature = features[index].feature;
options.featureIndex.insert(feature, geometry, index, sourceLayerIndex, this.index);
}
}
Expand All @@ -111,9 +130,8 @@ class FillBucket implements Bucket {
}

addFeatures(options: PopulateParameters, imagePositions: {[string]: ImagePosition}) {
for (const feature of this.features) {
const {geometry} = feature;
this.addFeature(feature, geometry, feature.index, imagePositions);
for (const feature of this.patternFeatures) {
this.addFeature(feature, feature.geometry, feature.index, imagePositions);
}
}

Expand Down Expand Up @@ -202,6 +220,6 @@ class FillBucket implements Bucket {
}
}

register('FillBucket', FillBucket, {omit: ['layers', 'features']});
register('FillBucket', FillBucket, {omit: ['layers', 'patternFeatures']});

export default FillBucket;
50 changes: 34 additions & 16 deletions src/data/bucket/line_bucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class LineBucket implements Bucket {
layerIds: Array<string>;
stateDependentLayers: Array<any>;
stateDependentLayerIds: Array<string>;
features: Array<BucketFeature>;
patternFeatures: Array<BucketFeature>;

layoutVertexArray: LineLayoutArray;
layoutVertexBuffer: VertexBuffer;
Expand All @@ -119,8 +119,8 @@ class LineBucket implements Bucket {
this.layers = options.layers;
this.layerIds = this.layers.map(layer => layer.id);
this.index = options.index;
this.features = [];
this.hasPattern = false;
this.patternFeatures = [];

this.layoutVertexArray = new LineLayoutArray();
this.indexArray = new TriangleIndexArray();
Expand All @@ -131,33 +131,52 @@ class LineBucket implements Bucket {
}

populate(features: Array<IndexedFeature>, options: PopulateParameters) {
this.features = [];
this.hasPattern = hasPattern('line', this.layers, options);
const lineSortKey = this.layers[0].layout.get('line-sort-key');
const bucketFeatures = [];

for (const {feature, index, sourceLayerIndex} of features) {
if (!this.layers[0]._featureFilter(new EvaluationParameters(this.zoom), feature)) continue;

const geometry = loadGeometry(feature);
const sortKey = lineSortKey ?
lineSortKey.evaluate(feature, {}) :
undefined;

const patternFeature: BucketFeature = {
const bucketFeature: BucketFeature = {
id: feature.id,
properties: feature.properties,
type: feature.type,
sourceLayerIndex,
index,
geometry,
properties: feature.properties,
type: feature.type,
patterns: {}
patterns: {},
sortKey
};

if (typeof feature.id !== 'undefined') {
patternFeature.id = feature.id;
}
bucketFeatures.push(bucketFeature);
}

if (lineSortKey) {
bucketFeatures.sort((a, b) => {
// a.sortKey is always a number when in use
return ((a.sortKey: any): number) - ((b.sortKey: any): number);
});
}

for (const bucketFeature of bucketFeatures) {
const {geometry, index, sourceLayerIndex} = bucketFeature;

if (this.hasPattern) {
this.features.push(addPatternDependencies('line', this.layers, patternFeature, this.zoom, options));
const patternBucketFeature = addPatternDependencies('line', this.layers, bucketFeature, this.zoom, options);
// pattern features are added only once the pattern is loaded into the image atlas
// so are stored during populate until later updated with positions by tile worker in addFeatures
this.patternFeatures.push(patternBucketFeature);
} else {
this.addFeature(patternFeature, geometry, index, {});
this.addFeature(bucketFeature, geometry, index, {});
}

const feature = features[index].feature;
options.featureIndex.insert(feature, geometry, index, sourceLayerIndex, this.index);
}
}
Expand All @@ -168,9 +187,8 @@ class LineBucket implements Bucket {
}

addFeatures(options: PopulateParameters, imagePositions: {[string]: ImagePosition}) {
for (const feature of this.features) {
const {geometry} = feature;
this.addFeature(feature, geometry, feature.index, imagePositions);
for (const feature of this.patternFeatures) {
this.addFeature(feature, feature.geometry, feature.index, imagePositions);
}
}

Expand Down Expand Up @@ -626,6 +644,6 @@ function calculateFullDistance(vertices: Array<Point>, first: number, len: numbe
return total;
}

register('LineBucket', LineBucket, {omit: ['layers', 'features']});
register('LineBucket', LineBucket, {omit: ['layers', 'patternFeatures']});

export default LineBucket;
Loading