Skip to content

Commit

Permalink
fix fill extrusion querying for colinear points (#9454)
Browse files Browse the repository at this point in the history
When checking for intersections with a fill-extrusion it has to
calculate the distance to the plane the polygon exist on. If the first
points of the geometry were colinear this calculation would fail.

It now:
- finds two distinct starting points a, b
- loops over all the remaining vertices looking for a value that is not
colinear with a, b

Usually this will be the first vertex it encounters.
  • Loading branch information
ansis authored Mar 24, 2020
1 parent eeab959 commit 0e04a3a
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 20 deletions.
46 changes: 26 additions & 20 deletions src/style/style_layer/fill_extrusion_style_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,34 +81,40 @@ export function getIntersectionDistance(projectedQueryGeometry: Array<Point>, pr
// Check whether points are coincident and use other points if they are.
let i = 0;
const a = projectedFace[i++];
let b, c;
let b;
while (!b || a.equals(b)) {
b = projectedFace[i++];
if (!b) return Infinity;
}
while (!c || a.equals(c) || b.equals(c)) {
c = projectedFace[i++];
if (!c) return Infinity;
}

const p = projectedQueryGeometry[0];
// Loop until point `c` is not colinear with points `a` and `b`.
for (; i < projectedFace.length; i++) {
const c = projectedFace[i];

const p = projectedQueryGeometry[0];

const ab = b.sub(a);
const ac = c.sub(a);
const ap = p.sub(a);

const ab = b.sub(a);
const ac = c.sub(a);
const ap = p.sub(a);
const dotABAB = dot(ab, ab);
const dotABAC = dot(ab, ac);
const dotACAC = dot(ac, ac);
const dotAPAB = dot(ap, ab);
const dotAPAC = dot(ap, ac);
const denom = dotABAB * dotACAC - dotABAC * dotABAC;

const dotABAB = dot(ab, ab);
const dotABAC = dot(ab, ac);
const dotACAC = dot(ac, ac);
const dotAPAB = dot(ap, ab);
const dotAPAC = dot(ap, ac);
const denom = dotABAB * dotACAC - dotABAC * dotABAC;
const v = (dotACAC * dotAPAB - dotABAC * dotAPAC) / denom;
const w = (dotABAB * dotAPAC - dotABAC * dotAPAB) / denom;
const u = 1 - v - w;
const v = (dotACAC * dotAPAB - dotABAC * dotAPAC) / denom;
const w = (dotABAB * dotAPAC - dotABAC * dotAPAB) / denom;
const u = 1 - v - w;

// Use the barycentric weighting along with the original triangle z coordinates to get the point of intersection.
const distance = a.z * u + b.z * v + c.z * w;

if (isFinite(distance)) return distance;
}

// Use the barycentric weighting along with the original triangle z coordinates to get the point of intersection.
return a.z * u + b.z * v + c.z * w;
return Infinity;

} else {
// The counts as closest is less clear when the query is a box. This
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
[
{
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-19.9951171875,
-40.01078714046552
],
[
-19.9951171875,
40.01078714046551
],
[
-19.9951171875,
59.99898612060443
],
[
19.9951171875,
20.014645445341372
],
[
-19.9951171875,
-40.01078714046552
]
]
]
},
"type": "Feature",
"properties": {
"layer": "extrusion_colinear_points"
},
"source": "extrusion_colinear_points",
"state": {}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
{
"version": 8,
"metadata": {
"test": {
"debug": true,
"width": 200,
"height": 200,
"queryGeometry": [
100,
40
]
}
},
"pitch": 0,
"center": [
0,
0
],
"zoom": 0,
"sources": {
"extrusion_colinear_points": {
"type": "geojson",
"tolerance": 0,
"data": {
"type": "Feature",
"properties": {
"layer": "extrusion_colinear_points"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
-20,
-40
],
[
-20,
40
],
[
-20,
60
],
[
20,
20
],
[
-20,
-40
]
]
]
}
}
}
},
"layers": [
{
"id": "extrusion_colinear_points",
"type": "fill-extrusion",
"source": "extrusion_colinear_points",
"paint": {
"fill-extrusion-color": "#ecc",
"fill-extrusion-height": 0
}
}
]
}

0 comments on commit 0e04a3a

Please sign in to comment.