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

Fix within expression issue with geometry crossing the 180th Meridian #9440

Merged
merged 8 commits into from
Mar 26, 2020
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
84 changes: 60 additions & 24 deletions src/style-spec/expression/definitions/within.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,9 @@ function twoSided(p1, p2, q1, q2) {
const y2 = p2[1] - q1[1];
const x3 = q2[0] - q1[0];
const y3 = q2[1] - q1[1];
if ((x1 * y3 - x3 * y1) * (x2 * y3 - x3 * y2) < 0) return true;
const det1 = (x1 * y3 - x3 * y1);
const det2 = (x2 * y3 - x3 * y2);
if ((det1 > 0 && det2 < 0) || (det1 < 0 && det2 > 0)) return true;
return false;
}
// a, b are end points for line segment1, c and d are end points for line segment2
Expand Down Expand Up @@ -160,32 +162,79 @@ function getTilePolygons(coordinates, bbox, canonical) {
return polygons;
}

function pointsWithinPolygons(ctx: EvaluationContext, polygonGeometry: GeoJSONPolygons) {
const pointBBox = [Infinity, Infinity, -Infinity, -Infinity];
const polyBBox = [Infinity, Infinity, -Infinity, -Infinity];
const canonical = ctx.canonicalID();
function updatePoint(p, bbox, polyBBox, worldSize) {
if (p[0] < polyBBox[0] || p[0] > polyBBox[2]) {
const halfWorldSize = worldSize * 0.5;
let shift = (p[0] - polyBBox[0] > halfWorldSize) ? -worldSize : (polyBBox[0] - p[0] > halfWorldSize) ? worldSize : 0;
if (shift === 0) {
shift = (p[0] - polyBBox[2] > halfWorldSize) ? -worldSize : (polyBBox[2] - p[0] > halfWorldSize) ? worldSize : 0;
}
p[0] += shift;
karimnaaji marked this conversation as resolved.
Show resolved Hide resolved
}
updateBBox(bbox, p);
}

function resetBBox(bbox) {
bbox[0] = bbox[1] = Infinity;
bbox[2] = bbox[3] = -Infinity;
}

function getTilePoints(geometry, pointBBox, polyBBox, canonical) {
const worldSize = Math.pow(2, canonical.z) * EXTENT;
const shifts = [canonical.x * EXTENT, canonical.y * EXTENT];
const tilePoints = [];

for (const points of ctx.geometry()) {
for (const points of geometry) {
for (const point of points) {
const p = [point.x + shifts[0], point.y + shifts[1]];
updateBBox(pointBBox, p);
updatePoint(p, pointBBox, polyBBox, worldSize);
tilePoints.push(p);
}
}
return tilePoints;
}

function getTileLines(geometry, lineBBox, polyBBox, canonical) {
const worldSize = Math.pow(2, canonical.z) * EXTENT;
const shifts = [canonical.x * EXTENT, canonical.y * EXTENT];
const tileLines = [];
for (const line of geometry) {
const tileLine = [];
for (const point of line) {
const p = [point.x + shifts[0], point.y + shifts[1]];
updateBBox(lineBBox, p);
tileLine.push(p);
}
tileLines.push(tileLine);
}
if (lineBBox[2] - lineBBox[0] <= worldSize / 2) {
resetBBox(lineBBox);
for (const line of tileLines) {
for (const p of line) {
updatePoint(p, lineBBox, polyBBox, worldSize);
}
}
}
return tileLines;
}

function pointsWithinPolygons(ctx: EvaluationContext, polygonGeometry: GeoJSONPolygons) {
const pointBBox = [Infinity, Infinity, -Infinity, -Infinity];
const polyBBox = [Infinity, Infinity, -Infinity, -Infinity];

const canonical = ctx.canonicalID();

if (polygonGeometry.type === 'Polygon') {
const tilePolygon = getTilePolygon(polygonGeometry.coordinates, polyBBox, canonical);
const tilePoints = getTilePoints(ctx.geometry(), pointBBox, polyBBox, canonical);
if (!boxWithinBox(pointBBox, polyBBox)) return false;

for (const point of tilePoints) {
if (!pointWithinPolygon(point, tilePolygon)) return false;
}
}

if (polygonGeometry.type === 'MultiPolygon') {
const tilePolygons = getTilePolygons(polygonGeometry.coordinates, polyBBox, canonical);
const tilePoints = getTilePoints(ctx.geometry(), pointBBox, polyBBox, canonical);
if (!boxWithinBox(pointBBox, polyBBox)) return false;

for (const point of tilePoints) {
Expand All @@ -201,39 +250,26 @@ function linesWithinPolygons(ctx: EvaluationContext, polygonGeometry: GeoJSONPol
const polyBBox = [Infinity, Infinity, -Infinity, -Infinity];

const canonical = ctx.canonicalID();
const shifts = [canonical.x * EXTENT, canonical.y * EXTENT];
const tileLines = [];

for (const line of ctx.geometry()) {
const tileLine = [];
for (const point of line) {
const p = [point.x + shifts[0], point.y + shifts[1]];
updateBBox(lineBBox, p);
tileLine.push(p);
}
tileLines.push(tileLine);
}

if (polygonGeometry.type === 'Polygon') {
const tilePolygon = getTilePolygon(polygonGeometry.coordinates, polyBBox, canonical);
const tileLines = getTileLines(ctx.geometry(), lineBBox, polyBBox, canonical);
if (!boxWithinBox(lineBBox, polyBBox)) return false;

for (const line of tileLines) {
if (!lineStringWithinPolygon(line, tilePolygon)) return false;
}
}

if (polygonGeometry.type === 'MultiPolygon') {
const tilePolygons = getTilePolygons(polygonGeometry.coordinates, polyBBox, canonical);

const tileLines = getTileLines(ctx.geometry(), lineBBox, polyBBox, canonical);
if (!boxWithinBox(lineBBox, polyBBox)) return false;

for (const line of tileLines) {
if (!lineStringWithinPolygons(line, tilePolygons)) return false;
}
}
return true;

}

class Within implements Expression {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"expression": ["within", {
"type": "Polygon",
"coordinates": [[[-190, 0], [-178, 0], [-178, 10], [-190, 10], [-190, 0]]]
}],
"inputs": [[{
"zoom": 0,
"canonicalID": {
"z": 0,
"x": 0,
"y": 0
}
}, {
"geometry": {
"type": "LineString",
"coordinates": [[-183, 5], [-179, 1]]
}
}], [{
"zoom": 0,
"canonicalID": {
"z": 0,
"x": 0,
"y": 0
}
}, {
"geometry": {
"type": "LineString",
"coordinates": [[-183, 5], [181, 1]]
}
}]],
"expected": {
"compiled": {
"type": "boolean",
"isFeatureConstant": false,
"isZoomConstant": true,
"result": "success"
},
"outputs": [true, false],
"serialized": ["within", {
"coordinates": [[[-190, 0], [-178, 0], [-178, 10], [-190, 10], [-190, 0]]],
"type": "Polygon"
}]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"expression": ["within", {
"type": "Polygon",
"coordinates": [[[-185.0, 60.0], [175.0, 60.0], [175.0, 65.0], [-185.0, 65.0], [-185.0, 60.0]]]
}],
"inputs": [[{
"zoom": 0,
"canonicalID": {
"z": 0,
"x": 0,
"y": 0
}
}, {
"geometry": {
"type": "LineString",
"coordinates": [[-183, 61], [-179, 62]]
}
}], [{
"zoom": 0,
"canonicalID": {
"z": 0,
"x": 0,
"y": 0
}
}, {
"geometry": {
"type": "LineString",
"coordinates": [[-183, 61], [181, 63]]
}
}], [{
"zoom": 0,
"canonicalID": {
"z": 0,
"x": 0,
"y": 0
}
}, {
"geometry": {
"type": "LineString",
"coordinates": [[-183, 62], [55, 63.5]]
}
}]],
"expected": {
"compiled": {
"type": "boolean",
"isFeatureConstant": false,
"isZoomConstant": true,
"result": "success"
},
"outputs": [true, false, true],
"serialized": ["within", {
"coordinates": [[[-185.0, 60.0], [175.0, 60.0], [175.0, 65.0], [-185.0, 65.0], [-185.0, 60.0]]],
"type": "Polygon"
}]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"expression": ["within", {
"type": "Polygon",
"coordinates": [[[-185.0, 60.0], [-175.0, 60.0], [-175.0, 65.0], [-185.0, 65.0], [-185.0, 60.0]]]
}],
"inputs": [[{
"zoom": 0,
"canonicalID": {
"z": 0,
"x": 0,
"y": 0
}
}, {
"geometry": {
"type": "MultiPoint",
"coordinates": [[-183, 62], [-179, 63]]
}
}], [{
"zoom": 0,
"canonicalID": {
"z": 0,
"x": 0,
"y": 0
}
}, {
"geometry": {
"type": "MultiPoint",
"coordinates": [[-183, 62], [181, 63]]
}
}], [{
"zoom": 3,
"canonicalID": {
"z": 3,
"x": 7,
"y": 2
}
}, {
"geometry": {
"type": "Point",
"coordinates": [177, 62.5]
}
}]],
"expected": {
"compiled": {
"type": "boolean",
"isFeatureConstant": false,
"isZoomConstant": true,
"result": "success"
},
"outputs": [true, true, true],
"serialized": ["within", {
"coordinates": [[[-185.0, 60.0], [-175.0, 60.0], [-175.0, 65.0], [-185.0, 65.0], [-185.0, 60.0]]],
"type": "Polygon"
}]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{
"expression": ["within", {
"type": "Polygon",
"coordinates": [[[-360.0, 60.0], [0.0, 60.0], [0.0, 65.0], [-360.0, 65.0], [-360.0, 60.0]]]
}],
"inputs": [[{
"zoom": 0,
"canonicalID": {
"z": 0,
"x": 0,
"y": 0
}
}, {
"geometry": {
"type": "Point",
"coordinates": [-183, 61]
}
}], [{
"zoom": 0,
"canonicalID": {
"z": 0,
"x": 0,
"y": 0
}
}, {
"geometry": {
"type": "Point",
"coordinates": [-361, 61]
}
}], [{
"zoom": 0,
"canonicalID": {
"z": 0,
"x": 0,
"y": 0
}
}, {
"geometry": {
"type": "Point",
"coordinates": [183, 62]
}
}], [{
"zoom": 0,
"canonicalID": {
"z": 0,
"x": 0,
"y": 0
}
}, {
"geometry": {
"type": "Point",
"coordinates": [55, 62]
}
}]],
"expected": {
"compiled": {
"type": "boolean",
"isFeatureConstant": false,
"isZoomConstant": true,
"result": "success"
},
"outputs": [true, true, true, true],
"serialized": ["within", {
"coordinates": [[[-360.0, 60.0], [0.0, 60.0], [0.0, 65.0], [-360.0, 65.0], [-360.0, 60.0]]],
"type": "Polygon"
}]
}
}