Skip to content

Commit

Permalink
update unit tests, fix point within polygon
Browse files Browse the repository at this point in the history
  • Loading branch information
zmiao committed Feb 28, 2020
1 parent e9fc60a commit cfd8a51
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 81 deletions.
18 changes: 14 additions & 4 deletions src/style-spec/expression/definitions/within.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ function getLngLatPoints(line, canonical) {
return coords;
}

function onBoundary(p, p1, p2) {
const x1 = p[0] - p1[0];
const y1 = p[1] - p1[1];
const x2 = p[0] - p2[0];
const y2 = p[1] - p2[1];
return (x1 * y2 - x2 * y1 === 0) && (x1 * x2 <= 0) && (y1 * y2 <= 0);
}

function rayIntersect(p, p1, p2) {
return ((p1[1] > p[1]) !== (p2[1] > p[1])) && (p[0] < (p2[0] - p1[0]) * (p[1] - p1[1]) / (p2[1] - p1[1]) + p1[0]);
}
Expand All @@ -80,8 +88,9 @@ function pointWithinPolygon(point, rings) {
let inside = false;
for (let i = 0, len = rings.length; i < len; i++) {
const ring = rings[i];
for (let j = 0, len2 = ring.length, k = len2 - 1; j < len2; k = j++) {
if (rayIntersect(point, ring[j], ring[k])) inside = !inside;
for (let j = 0, len2 = ring.length; j < len2 - 1; j++) {
if (onBoundary(point, ring[j], ring[j + 1])) return false;
if (rayIntersect(point, ring[j], ring[j + 1])) inside = !inside;
}
}
return inside;
Expand Down Expand Up @@ -173,8 +182,9 @@ function pointsWithinPolygons(ctx: EvaluationContext, polygonGeometry: GeoJSONPo
const lngLatPoints = [];
for (const points of ctx.geometry()) {
for (const point of points) {
lngLatPoints.push(getLngLatPoint(point, ctx.canonicalID()));
updateBBox(pointBBox, point);
const p = getLngLatPoint(point, ctx.canonicalID());
lngLatPoints.push(p);
updateBBox(pointBBox, p);
}
}
if (!boxWithinBox(pointBBox, polyBBox)) return false;
Expand Down
3 changes: 1 addition & 2 deletions src/style-spec/feature_filter/convert.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,7 @@ export default function convertFilter(filter: FilterSpecification): mixed {
* produce a `false` result.
*/
function _convertFilter(filter: FilterSpecification, expectedTypes: ExpectedTypes): mixed {
const needGeo = false;
if (isExpressionFilter(filter, needGeo)) { return filter; }
if (isExpressionFilter(filter)) { return filter; }

if (!filter) return true;
const op = filter[0];
Expand Down
27 changes: 16 additions & 11 deletions src/style-spec/feature_filter/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,15 @@ import type {GlobalProperties, Feature} from '../expression';
import type {CanonicalTileID} from '../../source/tile_id';

type FilterExpression = (globalProperties: GlobalProperties, feature: Feature, canonical?: CanonicalTileID) => boolean;
export type FeatureFilter ={filter: FilterExpression,
needGeometry: boolean};
export type FeatureFilter ={filter: FilterExpression, needGeometry: boolean};

export default createFilter;
export {isExpressionFilter};

function isExpressionFilter(filter: any, needGeometry: boolean) {
function isExpressionFilter(filter: any) {
if (filter === true || filter === false) {
return true;
}

if (!Array.isArray(filter) || filter.length === 0) {
return false;
}
Expand All @@ -41,14 +39,11 @@ function isExpressionFilter(filter: any, needGeometry: boolean) {
case 'any':
case 'all':
for (const f of filter.slice(1)) {
if (!isExpressionFilter(f, needGeometry) && typeof f !== 'boolean') {
if (!isExpressionFilter(f) && typeof f !== 'boolean') {
return false;
}
}
return true;
case 'within':
needGeometry = true;
return true;
default:
return true;
}
Expand Down Expand Up @@ -79,18 +74,28 @@ function createFilter(filter: any): FeatureFilter {
return {filter: () => true, needGeometry: false};
}

const withinExpr = false;
if (!isExpressionFilter(filter, withinExpr)) {
if (!isExpressionFilter(filter)) {
filter = convertFilter(filter);
}

const compiled = createExpression(filter, filterSpec);
if (compiled.result === 'error') {
throw new Error(compiled.value.map(err => `${err.key}: ${err.message}`).join(', '));
} else {
const needGeometry = filterNeedGeometry(filter);
return {filter: (globalProperties: GlobalProperties, feature: Feature, canonical?: CanonicalTileID) => compiled.value.evaluate(globalProperties, feature, {}, canonical),
needGeometry: withinExpr};
needGeometry};
}
}

function filterNeedGeometry(filter) {
if (filter === true || filter === false) {
return false;
}
if (!Array.isArray(filter) || filter.length === 0) {
return false;
}
return filter[0] === 'within';
}

// Comparison function to sort numbers and strings
Expand Down
Loading

0 comments on commit cfd8a51

Please sign in to comment.