Skip to content

Commit

Permalink
fix querying circles with -pitch-scaling=viewport
Browse files Browse the repository at this point in the history
`"circle-pitch-scaling": "viewport"` adjsuts circle-radius based on the
distance from the center of the viewport. This incorporates this scaling
into the calculations used by feature querying.
  • Loading branch information
ansis committed Mar 6, 2018
1 parent b4d0f13 commit 3346dc6
Show file tree
Hide file tree
Showing 16 changed files with 273 additions and 20 deletions.
12 changes: 8 additions & 4 deletions src/data/feature_index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ const {FeatureIndexArray} = require('./array_types');
type QueryParameters = {
scale: number,
bearing: number,
cameraToCenterDistance: number,
posMatrix: Float32Array,
tileSize: number,
queryGeometry: Array<Array<Point>>,
queryPadding: number,
Expand Down Expand Up @@ -117,13 +119,13 @@ class FeatureIndex {

const matching = this.grid.query(minX - queryPadding, minY - queryPadding, maxX + queryPadding, maxY + queryPadding);
matching.sort(topDownFeatureComparator);
this.filterMatching(result, matching, this.featureIndexArray, queryGeometry, filter, params.layers, styleLayers, args.bearing, pixelsToTileUnits);
this.filterMatching(result, matching, this.featureIndexArray, queryGeometry, filter, params.layers, styleLayers, args.bearing, pixelsToTileUnits, args.cameraToCenterDistance, args.posMatrix);

const matchingSymbols = args.collisionIndex ?
args.collisionIndex.queryRenderedSymbols(queryGeometry, this.tileID, args.tileSize / EXTENT, args.collisionBoxArray, args.sourceID, args.bucketInstanceIds) :
[];
matchingSymbols.sort();
this.filterMatching(result, matchingSymbols, args.collisionBoxArray, queryGeometry, filter, params.layers, styleLayers, args.bearing, pixelsToTileUnits);
this.filterMatching(result, matchingSymbols, args.collisionBoxArray, queryGeometry, filter, params.layers, styleLayers, args.bearing, pixelsToTileUnits, args.cameraToCenterDistance, args.posMatrix);

return result;
}
Expand All @@ -137,7 +139,9 @@ class FeatureIndex {
filterLayerIDs: Array<string>,
styleLayers: {[string]: StyleLayer},
bearing: number,
pixelsToTileUnits: number
pixelsToTileUnits: number,
cameraToCenterDistance: number,
posMatrix: Float32Array
) {
let previousIndex;
for (let k = 0; k < matching.length; k++) {
Expand Down Expand Up @@ -175,7 +179,7 @@ class FeatureIndex {
if (!geometry) {
geometry = loadGeometry(feature);
}
if (!styleLayer.queryIntersectsFeature(queryGeometry, feature, geometry, this.z, bearing, pixelsToTileUnits)) {
if (!styleLayer.queryIntersectsFeature(queryGeometry, feature, geometry, this.z, bearing, pixelsToTileUnits, cameraToCenterDistance, posMatrix)) {
continue;
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/geo/transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,13 @@ class Transform {
this._posMatrixCache = {};
this._alignedPosMatrixCache = {};
}

getPitchScaleFactor() {
const coord = this.pointCoordinate(new Point(0, 0)).zoomTo(this.zoom);
const p = [coord.column * this.tileSize, coord.row * this.tileSize, 0, 1];
const topPoint = vec4.transformMat4(p, p, this.pixelMatrix);
return topPoint[3] / this.cameraToCenterDistance;
}
}

module.exports = Transform;
6 changes: 5 additions & 1 deletion src/source/query_features.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ exports.rendered = function(sourceCache: SourceCache,
zoom: number,
bearing: number,
collisionIndex: ?CollisionIndex) {
const tilesIn = sourceCache.tilesIn(queryGeometry);
const pitchScaleFactor = sourceCache.transform.getPitchScaleFactor();
const tilesIn = sourceCache.tilesIn(queryGeometry, pitchScaleFactor);

tilesIn.sort(sortTilesIn);

Expand All @@ -26,6 +27,9 @@ exports.rendered = function(sourceCache: SourceCache,
tileIn.scale,
params,
bearing,
sourceCache.transform.cameraToCenterDistance,
pitchScaleFactor,
sourceCache.transform.calculatePosMatrix(tileIn.tileID.toUnwrapped()),
sourceCache.id,
collisionIndex)
});
Expand Down
4 changes: 2 additions & 2 deletions src/source/source_cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@ class SourceCache extends Evented {
* @param queryGeometry coordinates of the corners of bounding rectangle
* @returns {Array<Object>} result items have {tile, minX, maxX, minY, maxY}, where min/max bounding values are the given bounds transformed in into the coordinate space of this tile.
*/
tilesIn(queryGeometry: Array<Coordinate>) {
tilesIn(queryGeometry: Array<Coordinate>, pitchScaleFactor: number) {
const tileResults = [];
const ids = this.getIds();

Expand All @@ -705,7 +705,7 @@ class SourceCache extends Evented {
const tile = this._tiles[ids[i]];
const tileID = tile.tileID;
const scale = Math.pow(2, this.transform.zoom - tile.tileID.overscaledZ);
const queryPadding = tile.queryPadding * EXTENT / tile.tileSize / scale;
const queryPadding = pitchScaleFactor * tile.queryPadding * EXTENT / tile.tileSize / scale;

const tileSpaceBounds = [
coordinateToTilePoint(tileID, new Coordinate(minX, minY, z)),
Expand Down
7 changes: 6 additions & 1 deletion src/source/tile.js
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,9 @@ class Tile {
scale: number,
params: { filter: FilterSpecification, layers: Array<string> },
bearing: number,
cameraToCenterDistance: number,
pitchScaleFactor: number,
posMatrix: Float32Array,
sourceID: string,
collisionIndex: ?CollisionIndex): {[string]: Array<{ featureIndex: number, feature: GeoJSONFeature }>} {
if (!this.featureIndex || !this.collisionBoxArray)
Expand All @@ -265,8 +268,10 @@ class Tile {
scale: scale,
tileSize: this.tileSize,
bearing: bearing,
cameraToCenterDistance: cameraToCenterDistance,
posMatrix: posMatrix,
params: params,
queryPadding: this.queryPadding,
queryPadding: this.queryPadding * pitchScaleFactor,
collisionBoxArray: this.collisionBoxArray,
sourceID: sourceID,
collisionIndex: collisionIndex,
Expand Down
4 changes: 3 additions & 1 deletion src/style/style_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ class StyleLayer extends Evented {
geometry: Array<Array<Point>>,
zoom: number,
bearing: number,
pixelsToTileUnits: number) => boolean;
pixelsToTileUnits: number,
cameraToCenterDistance: number,
posMatrix: Float32Array) => boolean;

constructor(layer: LayerSpecification, properties: {layout?: Properties<*>, paint: Properties<*>}) {
super();
Expand Down
24 changes: 21 additions & 3 deletions src/style/style_layer/circle_style_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

const StyleLayer = require('../style_layer');
const CircleBucket = require('../../data/bucket/circle_bucket');
const {multiPolygonIntersectsBufferedMultiPoint} = require('../../util/intersection_tests');
const {multiPolygonIntersectsBufferedPoint} = require('../../util/intersection_tests');
const {getMaximumPaintValue, translateDistance, translate} = require('../query_utils');
const properties = require('./circle_style_layer_properties');
const {vec4} = require('@mapbox/gl-matrix');

const {
Transitionable,
Expand Down Expand Up @@ -41,14 +42,31 @@ class CircleStyleLayer extends StyleLayer {
geometry: Array<Array<Point>>,
zoom: number,
bearing: number,
pixelsToTileUnits: number): boolean {
pixelsToTileUnits: number,
cameraToCenterDistance: number,
posMatrix: Float32Array): boolean {
const translatedPolygon = translate(queryGeometry,
this.paint.get('circle-translate'),
this.paint.get('circle-translate-anchor'),
bearing, 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);
const size = radius + stroke;

for (const ring of geometry) {
for (const point of ring) {
let adjustedSize = size;

if (this.paint.get('circle-pitch-scale') === 'viewport') {
const projectedCenter = vec4.transformMat4([], [point.x, point.y, 0, 1], posMatrix);
adjustedSize *= projectedCenter[3] / cameraToCenterDistance;
}

if (multiPolygonIntersectsBufferedPoint(translatedPolygon, point, adjustedSize)) return true;
}
}

return false;
}
}

Expand Down
21 changes: 13 additions & 8 deletions src/util/intersection_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const {isCounterClockwise} = require('./util');
import type Point from '@mapbox/point-geometry';

module.exports = {
multiPolygonIntersectsBufferedPoint,
multiPolygonIntersectsBufferedMultiPoint,
multiPolygonIntersectsMultiPolygon,
multiPolygonIntersectsBufferedMultiLine,
Expand Down Expand Up @@ -32,16 +33,20 @@ function polygonIntersectsPolygon(polygonA: Polygon, polygonB: Polygon) {
return false;
}

function multiPolygonIntersectsBufferedMultiPoint(multiPolygon: MultiPolygon, rings: Array<Ring>, radius: number) {
function multiPolygonIntersectsBufferedPoint(multiPolygon: MultiPolygon, point: Point, radius: number) {
for (let j = 0; j < multiPolygon.length; j++) {
const polygon = multiPolygon[j];
for (let i = 0; i < rings.length; i++) {
const ring = rings[i];
for (let k = 0; k < ring.length; k++) {
const point = ring[k];
if (polygonContainsPoint(polygon, point)) return true;
if (pointIntersectsBufferedLine(point, polygon, radius)) return true;
}
if (polygonContainsPoint(polygon, point)) return true;
if (pointIntersectsBufferedLine(point, polygon, radius)) return true;
}
return false;
}

function multiPolygonIntersectsBufferedMultiPoint(multiPolygon: MultiPolygon, rings: Array<Ring>, radius: number) {
for (let i = 0; i < rings.length; i++) {
const ring = rings[i];
for (let k = 0; k < ring.length; k++) {
if (multiPolygonIntersectsBufferedPoint(multiPolygon, ring[k], radius)) return true;
}
}
return false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[
{
"geometry": {
"type": "Point",
"coordinates": [
-84.3310546875,
33.92512970007199
]
},
"type": "Feature",
"properties": {}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"version": 8,
"metadata": {
"test": {
"height": 256,
"queryGeometry": [
292,
35
]
}
},
"center": [
-92.3780691249957,
-20
],
"zoom": 2,
"pitch": 60,
"sources": {
"geojson": {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-84.333565, 33.925575]
}
}]
}
}
},
"layers": [
{
"id": "road",
"type": "circle",
"source": "geojson",
"paint": {
"circle-pitch-alignment": "map",
"circle-pitch-scale": "map",
"circle-radius": 20
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"version": 8,
"metadata": {
"test": {
"height": 256,
"queryGeometry": [
295,
35
]
}
},
"center": [
-92.3780691249957,
-20
],
"zoom": 2,
"pitch": 60,
"sources": {
"geojson": {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-84.333565, 33.925575]
}
}]
}
}
},
"layers": [
{
"id": "road",
"type": "circle",
"source": "geojson",
"paint": {
"circle-pitch-alignment": "map",
"circle-pitch-scale": "map",
"circle-radius": 20
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[
{
"geometry": {
"type": "Point",
"coordinates": [
-84.3310546875,
33.92512970007199
]
},
"type": "Feature",
"properties": {}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"version": 8,
"metadata": {
"test": {
"height": 256,
"queryGeometry": [
300,
35
]
}
},
"center": [
-92.3780691249957,
-20
],
"zoom": 2,
"pitch": 60,
"sources": {
"geojson": {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [-84.333565, 33.925575]
}
}]
}
}
},
"layers": [
{
"id": "road",
"type": "circle",
"source": "geojson",
"paint": {
"circle-pitch-alignment": "map",
"circle-pitch-scale": "viewport",
"circle-radius": 20
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[]
Loading

0 comments on commit 3346dc6

Please sign in to comment.