From 2c5e5cd55b51baaaaeb6ff6855ba9f7726954582 Mon Sep 17 00:00:00 2001 From: Zsolt Ero Date: Sun, 12 Jan 2025 15:11:11 +0100 Subject: [PATCH] Revert `geometry-type` implementation changes, bring spec in line with historic behavior (#966) * revert geometry-type changes * Revert "Fixes geometry type filter (#924)" This reverts commit 2ed393ec7b67ba862e447759b13ac06577ac8a5e. * update description * Update changelog, scratch out previous change. * Use backticks in v8.json * Update CHANGELOG.md --------- Co-authored-by: Bart Louwers Co-authored-by: Harel M --- CHANGELOG.md | 7 +- src/expression/compound_expression.ts | 4 +- src/expression/definitions/within.ts | 4 +- src/expression/evaluation_context.ts | 39 +-- src/feature_filter/convert.ts | 6 +- src/feature_filter/feature_filter.test.ts | 234 ++---------------- src/feature_filter/index.ts | 2 +- src/reference/v8.json | 4 +- src/util/classify_rings.ts | 24 -- .../geometry-type/multilinestring/test.json | 30 --- .../tests/geometry-type/multipoint/test.json | 30 --- .../geometry-type/multipolygon/test.json | 35 --- .../tests/geometry-type/point/test.json | 28 --- .../tests/geometry-type/polygon/test.json | 30 --- 14 files changed, 33 insertions(+), 444 deletions(-) delete mode 100644 test/integration/expression/tests/geometry-type/multilinestring/test.json delete mode 100644 test/integration/expression/tests/geometry-type/multipoint/test.json delete mode 100644 test/integration/expression/tests/geometry-type/multipolygon/test.json delete mode 100644 test/integration/expression/tests/geometry-type/point/test.json delete mode 100644 test/integration/expression/tests/geometry-type/polygon/test.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c07a9dd4..a636eac17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ ## main ### ✨ Features and improvements -- _...Add new stuff here..._ + +- Adjust `geometry-type` expression specification and MapLibre GL JS implementation to the historic behavior of only returning `Point`, `LineString` or `Polygon`, not the `Multi...` variants of these. This reverts a recent change to the implementation, which was causing issues in a [large number of styles](https://github.com/maplibre/maplibre-style-spec/issues/965). ### 🐞 Bug fixes - _...Add new stuff here..._ @@ -10,7 +11,7 @@ ### 🐞 Bug fixes -- Fix issue with `geomtry-type` filter ([#924](https://github.com/maplibre/maplibre-style-spec/pull/924)) +- ~~Fix issue with `geomtry-type` filter ([#924](https://github.com/maplibre/maplibre-style-spec/pull/924))~~ This was reverted in 23.0.0 due to causing issues in [a large number of styles](https://github.com/maplibre/maplibre-style-spec/issues/965). ## 22.0.0 @@ -33,7 +34,7 @@ ### ✨ Features and improvements -- Aligned the implementation of `["geometry-type"]` with [its spec](https://maplibre.org/maplibre-style-spec/expressions/#geometry-type). Now, when applicable, `["geometry-type"]` returns values not available while using `"$type"`: `"MultiPoint"`, `"MultiLineString"`, and `"MultiPolygon"`. The behaviour of `"$type"` has not changed. ([#519](https://github.com/maplibre/maplibre-style-spec/pull/519)) +- ~~Aligned the implementation of `["geometry-type"]` with [its spec](https://maplibre.org/maplibre-style-spec/expressions/#geometry-type). Now, when applicable, `["geometry-type"]` returns values not available while using `"$type"`: `"MultiPoint"`, `"MultiLineString"`, and `"MultiPolygon"`. The behaviour of `"$type"` has not changed. ([#519](https://github.com/maplibre/maplibre-style-spec/pull/519))~~ This was reverted in 23.0.0 due to causing issues in [a large number of styles](https://github.com/maplibre/maplibre-style-spec/issues/965). ## 20.4.0 diff --git a/src/expression/compound_expression.ts b/src/expression/compound_expression.ts index 152d77680..b08e11c28 100644 --- a/src/expression/compound_expression.ts +++ b/src/expression/compound_expression.ts @@ -461,7 +461,7 @@ CompoundExpression.register(expressions, { 'filter-type-==': [ BooleanType, [StringType], - (ctx, [v]) => ctx.geometryDollarType() === (v as any).value + (ctx, [v]) => ctx.geometryType() === (v as any).value ], 'filter-<': [ BooleanType, @@ -548,7 +548,7 @@ CompoundExpression.register(expressions, { 'filter-type-in': [ BooleanType, [array(StringType)], - (ctx, [v]) => (v as any).value.indexOf(ctx.geometryDollarType()) >= 0 + (ctx, [v]) => (v as any).value.indexOf(ctx.geometryType()) >= 0 ], 'filter-id-in': [ BooleanType, diff --git a/src/expression/definitions/within.ts b/src/expression/definitions/within.ts index e7e875c27..c46dec953 100644 --- a/src/expression/definitions/within.ts +++ b/src/expression/definitions/within.ts @@ -192,9 +192,9 @@ export class Within implements Expression { evaluate(ctx: EvaluationContext) { if (ctx.geometry() != null && ctx.canonicalID() != null) { - if (ctx.geometryDollarType() === 'Point') { + if (ctx.geometryType() === 'Point') { return pointsWithinPolygons(ctx, this.geometries); - } else if (ctx.geometryDollarType() === 'LineString') { + } else if (ctx.geometryType() === 'LineString') { return linesWithinPolygons(ctx, this.geometries); } } diff --git a/src/expression/evaluation_context.ts b/src/expression/evaluation_context.ts index 11fde481a..63437bede 100644 --- a/src/expression/evaluation_context.ts +++ b/src/expression/evaluation_context.ts @@ -1,19 +1,9 @@ import type {FormattedSection} from './types/formatted'; import type {GlobalProperties, Feature, FeatureState} from './index'; import {ICanonicalTileID} from '../tiles_and_coordinates'; -import {hasMultipleOuterRings} from '../util/classify_rings'; import {Color} from './types/color'; const geometryTypes = ['Unknown', 'Point', 'LineString', 'Polygon']; -const simpleGeometryType = { - 'Unknown': 'Unknown', - 'Point': 'Point', - 'MultiPoint': 'Point', - 'LineString': 'LineString', - 'MultiLineString': 'LineString', - 'Polygon': 'Polygon', - 'MultiPolygon': 'Polygon' -}; export class EvaluationContext { globals: GlobalProperties; @@ -24,7 +14,6 @@ export class EvaluationContext { canonical: ICanonicalTileID; _parseColorCache: {[_: string]: Color}; - _geometryType: string; constructor() { this.globals = null; @@ -40,33 +29,8 @@ export class EvaluationContext { return this.feature && 'id' in this.feature ? this.feature.id : null; } - geometryDollarType() { - return this.feature ? - typeof this.feature.type === 'number' ? geometryTypes[this.feature.type] : simpleGeometryType[this.feature.type] : - null; - } - geometryType() { - let geometryType = this.feature.type; - if (typeof geometryType !== 'number') { - return geometryType; - } - geometryType = geometryTypes[this.feature.type]; - if (geometryType === 'Unknown') { - return geometryType; - } - const geom = this.geometry(); - const len = geom.length; - if (len === 1) { - return geometryType; - } - if (geometryType !== 'Polygon') { - return `Multi${geometryType}`; - } - if (hasMultipleOuterRings(geom)) { - return 'MultiPolygon'; - } - return 'Polygon'; + return this.feature ? typeof this.feature.type === 'number' ? geometryTypes[this.feature.type] : this.feature.type : null; } geometry() { @@ -89,3 +53,4 @@ export class EvaluationContext { return cached; } } + diff --git a/src/feature_filter/convert.ts b/src/feature_filter/convert.ts index 65b926b3e..c1ca8f49f 100644 --- a/src/feature_filter/convert.ts +++ b/src/feature_filter/convert.ts @@ -128,7 +128,7 @@ function runtimeTypeChecks(expectedTypes: ExpectedTypes): ExpressionFilterSpecif function convertComparisonOp(property: string, value: any, op: string, expectedTypes?: ExpectedTypes | null): ExpressionFilterSpecification { let get; if (property === '$type') { - return convertInOp('$type', [value], op === '!='); + return [op, ['geometry-type'], value] as ExpressionFilterSpecification; } else if (property === '$id') { get = ['id']; } else { @@ -162,10 +162,6 @@ function convertInOp(property: string, values: Array, negate = false): Expr let get: ExpressionSpecification; if (property === '$type') { - const len = values.length; - for (let i = 0; i < len; i++) { - values.push(`Multi${values[i]}`); - } get = ['geometry-type']; } else if (property === '$id') { get = ['id']; diff --git a/src/feature_filter/feature_filter.test.ts b/src/feature_filter/feature_filter.test.ts index 4b54c7848..e16441033 100644 --- a/src/feature_filter/feature_filter.test.ts +++ b/src/feature_filter/feature_filter.test.ts @@ -171,30 +171,6 @@ describe('filter', () => { expect(withinFilter.filter({zoom: 3}, featureInTile, canonical)).toBe(false); }); - test('expression, geomtery-type point', () => { - const withinFilter = featureFilter(['==', ['geometry-type'], 'Point']); - expect(withinFilter.needGeometry).toBe(true); - const canonical = {z: 3, x: 3, y: 3} as ICanonicalTileID; - const featureInTile = { - type: 1, - geometry: [[{x: 0, y: 0}]], - properties: {} - } as Feature; - expect(withinFilter.filter({zoom: 3}, featureInTile, canonical)).toBe(true); - }); - - test('expression, geomtery-type multipoint', () => { - const withinFilter = featureFilter(['==', ['geometry-type'], 'MultiPoint']); - expect(withinFilter.needGeometry).toBe(true); - const canonical = {z: 3, x: 3, y: 3} as ICanonicalTileID; - const featureInTile = { - type: 1, - geometry: [[{x: 0, y: 0}], [{x: 1, y: 1}]], - properties: {} - } as Feature; - expect(withinFilter.filter({zoom: 3}, featureInTile, canonical)).toBe(true); - }); - legacyFilterTests(featureFilter); }); @@ -273,7 +249,7 @@ describe('convert legacy filters to expressions', () => { [ 'match', ['geometry-type'], - ['LineString', 'MultiLineString', 'MultiPoint', 'MultiPolygon', 'Point', 'Polygon'], + ['LineString', 'Point', 'Polygon'], true, false ], @@ -352,96 +328,10 @@ function legacyFilterTests(createFilterExpr) { expect(f({zoom: 0}, {properties: {}})).toBe(false); }); - const UnknownGeometry = {type: 0}; - const PointGeometry = {type: 1, geometry: [ - [{x: 0, y: 0}]]}; - const MultiPointGeometry = {type: 1, geometry: [ - [{x: 0, y: 0}], - [{x: 1, y: 1}]]}; - const LinestringGeometry = {type: 2, geometry: [ - [{x: 0, y: 0}, {x: 1, y: 1}]]}; - const MultiLineStringGeometry = {type: 2, geometry: [ - [{x: 0, y: 0}, {x: 1, y: 1}], - [{x: 2, y: 0}, {x: 1, y: 0}]]}; - const PolygonGeometry = {type: 3, geometry: [ - [{x: 0, y: 0}, {x: 3, y: 0}, {x: 3, y: 3}, {x: 0, y: 3}, {x: 0, y: 0}], - [{x: 0, y: 0}, {x: 0, y: 2}, {x: 2, y: 2}, {x: 2, y: 0}, {x: 0, y: 0}]]}; - const MultiPolygonGeometry = {type: 3, geometry: [ - [{x: 0, y: 0}, {x: 3, y: 0}, {x: 3, y: 3}, {x: 0, y: 3}, {x: 0, y: 0}], - [{x: 0, y: 0}, {x: 0, y: 2}, {x: 2, y: 2}, {x: 2, y: 0}, {x: 0, y: 0}], - [{x: 0, y: 0}, {x: 1, y: 0}, {x: 1, y: 1}, {x: 0, y: 1}, {x: 0, y: 0}]]}; - - test('==, $type, Point', () => { - const fPoint = createFilterExpr(['==', '$type', 'Point']).filter; - expect(fPoint({zoom: 0}, UnknownGeometry)).toBe(false); - expect(fPoint({zoom: 0}, PointGeometry)).toBe(true); - expect(fPoint({zoom: 0}, MultiPointGeometry)).toBe(true); - expect(fPoint({zoom: 0}, LinestringGeometry)).toBe(false); - expect(fPoint({zoom: 0}, MultiLineStringGeometry)).toBe(false); - expect(fPoint({zoom: 0}, PolygonGeometry)).toBe(false); - expect(fPoint({zoom: 0}, MultiPolygonGeometry)).toBe(false); - expect(fPoint({zoom: 0}, {type: 'Unknown'})).toBe(false); - expect(fPoint({zoom: 0}, {type: 'Point'})).toBe(true); - expect(fPoint({zoom: 0}, {type: 'MultiPoint'})).toBe(true); - expect(fPoint({zoom: 0}, {type: 'LineString'})).toBe(false); - expect(fPoint({zoom: 0}, {type: 'MultiLineString'})).toBe(false); - expect(fPoint({zoom: 0}, {type: 'Polygon'})).toBe(false); - expect(fPoint({zoom: 0}, {type: 'MultiPolygon'})).toBe(false); - }); - - test('==, $type, LineString', () => { - const fLineString = createFilterExpr(['==', '$type', 'LineString']).filter; - expect(fLineString({zoom: 0}, UnknownGeometry)).toBe(false); - expect(fLineString({zoom: 0}, PointGeometry)).toBe(false); - expect(fLineString({zoom: 0}, MultiPointGeometry)).toBe(false); - expect(fLineString({zoom: 0}, LinestringGeometry)).toBe(true); - expect(fLineString({zoom: 0}, MultiLineStringGeometry)).toBe(true); - expect(fLineString({zoom: 0}, PolygonGeometry)).toBe(false); - expect(fLineString({zoom: 0}, MultiPolygonGeometry)).toBe(false); - expect(fLineString({zoom: 0}, {type: 'Unknown'})).toBe(false); - expect(fLineString({zoom: 0}, {type: 'Point'})).toBe(false); - expect(fLineString({zoom: 0}, {type: 'MultiPoint'})).toBe(false); - expect(fLineString({zoom: 0}, {type: 'LineString'})).toBe(true); - expect(fLineString({zoom: 0}, {type: 'MultiLineString'})).toBe(true); - expect(fLineString({zoom: 0}, {type: 'Polygon'})).toBe(false); - expect(fLineString({zoom: 0}, {type: 'MultiPolygon'})).toBe(false); - }); - - test('==, $type, Polygon', () => { - - const fPolygon = createFilterExpr(['==', '$type', 'Polygon']).filter; - expect(fPolygon({zoom: 0}, UnknownGeometry)).toBe(false); - expect(fPolygon({zoom: 0}, PointGeometry)).toBe(false); - expect(fPolygon({zoom: 0}, MultiPointGeometry)).toBe(false); - expect(fPolygon({zoom: 0}, LinestringGeometry)).toBe(false); - expect(fPolygon({zoom: 0}, MultiLineStringGeometry)).toBe(false); - expect(fPolygon({zoom: 0}, PolygonGeometry)).toBe(true); - expect(fPolygon({zoom: 0}, MultiPolygonGeometry)).toBe(true); - expect(fPolygon({zoom: 0}, {type: 'Unknown'})).toBe(false); - expect(fPolygon({zoom: 0}, {type: 'Point'})).toBe(false); - expect(fPolygon({zoom: 0}, {type: 'MultiPoint'})).toBe(false); - expect(fPolygon({zoom: 0}, {type: 'LineString'})).toBe(false); - expect(fPolygon({zoom: 0}, {type: 'MultiLineString'})).toBe(false); - expect(fPolygon({zoom: 0}, {type: 'Polygon'})).toBe(true); - expect(fPolygon({zoom: 0}, {type: 'MultiPolygon'})).toBe(true); - }); - - test('==, $type, Unknown', () => { - const fUnknown = createFilterExpr(['==', '$type', 'Unknown']).filter; - expect(fUnknown({zoom: 0}, UnknownGeometry)).toBe(true); - expect(fUnknown({zoom: 0}, PointGeometry)).toBe(false); - expect(fUnknown({zoom: 0}, MultiPointGeometry)).toBe(false); - expect(fUnknown({zoom: 0}, LinestringGeometry)).toBe(false); - expect(fUnknown({zoom: 0}, MultiLineStringGeometry)).toBe(false); - expect(fUnknown({zoom: 0}, PolygonGeometry)).toBe(false); - expect(fUnknown({zoom: 0}, MultiPolygonGeometry)).toBe(false); - expect(fUnknown({zoom: 0}, {type: 'Unknown'})).toBe(true); - expect(fUnknown({zoom: 0}, {type: 'Point'})).toBe(false); - expect(fUnknown({zoom: 0}, {type: 'MultiPoint'})).toBe(false); - expect(fUnknown({zoom: 0}, {type: 'LineString'})).toBe(false); - expect(fUnknown({zoom: 0}, {type: 'MultiLineString'})).toBe(false); - expect(fUnknown({zoom: 0}, {type: 'Polygon'})).toBe(false); - expect(fUnknown({zoom: 0}, {type: 'MultiPolygon'})).toBe(false); + test('==, $type', () => { + const f = createFilterExpr(['==', '$type', 'LineString']).filter; + expect(f({zoom: 0}, {type: 1})).toBe(false); + expect(f({zoom: 0}, {type: 2})).toBe(true); }); test('==, $id', () => { @@ -483,76 +373,10 @@ function legacyFilterTests(createFilterExpr) { expect(f({zoom: 0}, {properties: {}})).toBe(true); }); - test('!=, $type, Point', () => { - const fPoint = createFilterExpr(['!=', '$type', 'Point']).filter; - expect(fPoint({zoom: 0}, UnknownGeometry)).toBe(true); - expect(fPoint({zoom: 0}, PointGeometry)).toBe(false); - expect(fPoint({zoom: 0}, MultiPointGeometry)).toBe(false); - expect(fPoint({zoom: 0}, LinestringGeometry)).toBe(true); - expect(fPoint({zoom: 0}, MultiLineStringGeometry)).toBe(true); - expect(fPoint({zoom: 0}, PolygonGeometry)).toBe(true); - expect(fPoint({zoom: 0}, MultiPolygonGeometry)).toBe(true); - expect(fPoint({zoom: 0}, {type: 'Unknown'})).toBe(true); - expect(fPoint({zoom: 0}, {type: 'Point'})).toBe(false); - expect(fPoint({zoom: 0}, {type: 'MultiPoint'})).toBe(false); - expect(fPoint({zoom: 0}, {type: 'LineString'})).toBe(true); - expect(fPoint({zoom: 0}, {type: 'MultiLineString'})).toBe(true); - expect(fPoint({zoom: 0}, {type: 'Polygon'})).toBe(true); - expect(fPoint({zoom: 0}, {type: 'MultiPolygon'})).toBe(true); - }); - - test('!=, $type, LineString', () => { - const fLineString = createFilterExpr(['!=', '$type', 'LineString']).filter; - expect(fLineString({zoom: 0}, UnknownGeometry)).toBe(true); - expect(fLineString({zoom: 0}, PointGeometry)).toBe(true); - expect(fLineString({zoom: 0}, MultiPointGeometry)).toBe(true); - expect(fLineString({zoom: 0}, LinestringGeometry)).toBe(false); - expect(fLineString({zoom: 0}, MultiLineStringGeometry)).toBe(false); - expect(fLineString({zoom: 0}, PolygonGeometry)).toBe(true); - expect(fLineString({zoom: 0}, MultiPolygonGeometry)).toBe(true); - expect(fLineString({zoom: 0}, {type: 'Unknown'})).toBe(true); - expect(fLineString({zoom: 0}, {type: 'Point'})).toBe(true); - expect(fLineString({zoom: 0}, {type: 'MultiPoint'})).toBe(true); - expect(fLineString({zoom: 0}, {type: 'LineString'})).toBe(false); - expect(fLineString({zoom: 0}, {type: 'MultiLineString'})).toBe(false); - expect(fLineString({zoom: 0}, {type: 'Polygon'})).toBe(true); - expect(fLineString({zoom: 0}, {type: 'MultiPolygon'})).toBe(true); - }); - - test('!=, $type, Polygon', () => { - const fPolygon = createFilterExpr(['!=', '$type', 'Polygon']).filter; - expect(fPolygon({zoom: 0}, UnknownGeometry)).toBe(true); - expect(fPolygon({zoom: 0}, PointGeometry)).toBe(true); - expect(fPolygon({zoom: 0}, MultiPointGeometry)).toBe(true); - expect(fPolygon({zoom: 0}, LinestringGeometry)).toBe(true); - expect(fPolygon({zoom: 0}, MultiLineStringGeometry)).toBe(true); - expect(fPolygon({zoom: 0}, PolygonGeometry)).toBe(false); - expect(fPolygon({zoom: 0}, MultiPolygonGeometry)).toBe(false); - expect(fPolygon({zoom: 0}, {type: 'Unknown'})).toBe(true); - expect(fPolygon({zoom: 0}, {type: 'Point'})).toBe(true); - expect(fPolygon({zoom: 0}, {type: 'MultiPoint'})).toBe(true); - expect(fPolygon({zoom: 0}, {type: 'LineString'})).toBe(true); - expect(fPolygon({zoom: 0}, {type: 'MultiLineString'})).toBe(true); - expect(fPolygon({zoom: 0}, {type: 'Polygon'})).toBe(false); - expect(fPolygon({zoom: 0}, {type: 'MultiPolygon'})).toBe(false); - }); - - test('!=, $type, Unknown', () => { - const fUnknown = createFilterExpr(['!=', '$type', 'Unknown']).filter; - expect(fUnknown({zoom: 0}, UnknownGeometry)).toBe(false); - expect(fUnknown({zoom: 0}, PointGeometry)).toBe(true); - expect(fUnknown({zoom: 0}, MultiPointGeometry)).toBe(true); - expect(fUnknown({zoom: 0}, LinestringGeometry)).toBe(true); - expect(fUnknown({zoom: 0}, MultiLineStringGeometry)).toBe(true); - expect(fUnknown({zoom: 0}, PolygonGeometry)).toBe(true); - expect(fUnknown({zoom: 0}, MultiPolygonGeometry)).toBe(true); - expect(fUnknown({zoom: 0}, {type: 'Unknown'})).toBe(false); - expect(fUnknown({zoom: 0}, {type: 'Point'})).toBe(true); - expect(fUnknown({zoom: 0}, {type: 'MultiPoint'})).toBe(true); - expect(fUnknown({zoom: 0}, {type: 'LineString'})).toBe(true); - expect(fUnknown({zoom: 0}, {type: 'MultiLineString'})).toBe(true); - expect(fUnknown({zoom: 0}, {type: 'Polygon'})).toBe(true); - expect(fUnknown({zoom: 0}, {type: 'MultiPolygon'})).toBe(true); + test('!=, $type', () => { + const f = createFilterExpr(['!=', '$type', 'LineString']).filter; + expect(f({zoom: 0}, {type: 1})).toBe(true); + expect(f({zoom: 0}, {type: 2})).toBe(false); }); test('<, number', () => { @@ -739,22 +563,15 @@ function legacyFilterTests(createFilterExpr) { test('in, $type', () => { const f = createFilterExpr(['in', '$type', 'LineString', 'Polygon']).filter; - expect(f({zoom: 0}, {type: 'Unknown'})).toBe(false); - expect(f({zoom: 0}, {type: 'Point'})).toBe(false); - expect(f({zoom: 0}, {type: 'MultiPoint'})).toBe(false); - expect(f({zoom: 0}, {type: 'LineString'})).toBe(true); - expect(f({zoom: 0}, {type: 'MultiLineString'})).toBe(true); - expect(f({zoom: 0}, {type: 'Polygon'})).toBe(true); - expect(f({zoom: 0}, {type: 'MultiPolygon'})).toBe(true); + expect(f({zoom: 0}, {type: 1})).toBe(false); + expect(f({zoom: 0}, {type: 2})).toBe(true); + expect(f({zoom: 0}, {type: 3})).toBe(true); const f1 = createFilterExpr(['in', '$type', 'Polygon', 'LineString', 'Point']).filter; - expect(f1({zoom: 0}, {type: 'Unknown'})).toBe(false); - expect(f1({zoom: 0}, {type: 'Point'})).toBe(true); - expect(f1({zoom: 0}, {type: 'MultiPoint'})).toBe(true); - expect(f1({zoom: 0}, {type: 'LineString'})).toBe(true); - expect(f1({zoom: 0}, {type: 'MultiLineString'})).toBe(true); - expect(f1({zoom: 0}, {type: 'Polygon'})).toBe(true); - expect(f1({zoom: 0}, {type: 'MultiPolygon'})).toBe(true); + expect(f1({zoom: 0}, {type: 1})).toBe(true); + expect(f1({zoom: 0}, {type: 2})).toBe(true); + expect(f1({zoom: 0}, {type: 3})).toBe(true); + }); test('!in, degenerate', () => { @@ -804,22 +621,9 @@ function legacyFilterTests(createFilterExpr) { test('!in, $type', () => { const f = createFilterExpr(['!in', '$type', 'LineString', 'Polygon']).filter; - expect(f({zoom: 0}, {type: 'Unknown'})).toBe(true); - expect(f({zoom: 0}, {type: 'Point'})).toBe(true); - expect(f({zoom: 0}, {type: 'MultiPoint'})).toBe(true); - expect(f({zoom: 0}, {type: 'LineString'})).toBe(false); - expect(f({zoom: 0}, {type: 'MultiLineString'})).toBe(false); - expect(f({zoom: 0}, {type: 'Polygon'})).toBe(false); - expect(f({zoom: 0}, {type: 'MultiPolygon'})).toBe(false); - - const f1 = createFilterExpr(['!in', '$type', 'Polygon', 'LineString', 'Point']).filter; - expect(f1({zoom: 0}, {type: 'Unknown'})).toBe(true); - expect(f1({zoom: 0}, {type: 'Point'})).toBe(false); - expect(f1({zoom: 0}, {type: 'MultiPoint'})).toBe(false); - expect(f1({zoom: 0}, {type: 'LineString'})).toBe(false); - expect(f1({zoom: 0}, {type: 'MultiLineString'})).toBe(false); - expect(f1({zoom: 0}, {type: 'Polygon'})).toBe(false); - expect(f1({zoom: 0}, {type: 'MultiPolygon'})).toBe(false); + expect(f({zoom: 0}, {type: 1})).toBe(true); + expect(f({zoom: 0}, {type: 2})).toBe(false); + expect(f({zoom: 0}, {type: 3})).toBe(false); }); test('any', () => { diff --git a/src/feature_filter/index.ts b/src/feature_filter/index.ts index 5b8dd1352..2a652e148 100644 --- a/src/feature_filter/index.ts +++ b/src/feature_filter/index.ts @@ -103,7 +103,7 @@ function compare(a, b) { function geometryNeeded(filter) { if (!Array.isArray(filter)) return false; - if (filter[0] === 'within' || filter[0] === 'distance' || filter[0] === 'geometry-type') return true; + if (filter[0] === 'within' || filter[0] === 'distance') return true; for (let index = 1; index < filter.length; index++) { if (geometryNeeded(filter[index])) return true; } diff --git a/src/reference/v8.json b/src/reference/v8.json index 427803edc..c3f11a169 100644 --- a/src/reference/v8.json +++ b/src/reference/v8.json @@ -3516,7 +3516,7 @@ } }, "geometry-type": { - "doc": "Gets the feature's geometry type: `Point`, `MultiPoint`, `LineString`, `MultiLineString`, `Polygon`, `MultiPolygon`.", + "doc": "Returns the feature's simple geometry type: `Point`, `LineString`, or `Polygon`. `MultiPoint`, `MultiLineString`, and `MultiPolygon` are returned as `Point`, `LineString`, and `Polygon`, respectively.", "example": { "syntax": { "method": [], @@ -6660,4 +6660,4 @@ "doc": "A name of a feature property to use as ID for feature state." } } -} \ No newline at end of file +} diff --git a/src/util/classify_rings.ts b/src/util/classify_rings.ts index 80849322d..6692f637d 100644 --- a/src/util/classify_rings.ts +++ b/src/util/classify_rings.ts @@ -69,27 +69,3 @@ function calculateSignedArea(ring: Point2D[]): number { } return sum; } - -/** - * Returns if there are multiple outer rings. - * The first ring is an outer ring. Its direction, cw or ccw, defines the direction of outer rings. - * - * @param rings - List of rings - * @returns Are there multiple outer rings - */ -export function hasMultipleOuterRings(rings: Point2D[][]): boolean { - // Following https://github.com/mapbox/vector-tile-js/blob/77851380b63b07fd0af3d5a3f144cc86fb39fdd1/lib/vectortilefeature.js#L197 - const len = rings.length; - for (let i = 0, direction; i < len; i++) { - const area = calculateSignedArea(rings[i]); - if (area === 0) continue; - if (direction === undefined) { - // Keep the direction of the first ring - direction = area < 0; - } else if (direction === area < 0) { - // Same direction as the first ring -> a second outer ring - return true; - } - } - return false; -} diff --git a/test/integration/expression/tests/geometry-type/multilinestring/test.json b/test/integration/expression/tests/geometry-type/multilinestring/test.json deleted file mode 100644 index 6e7ad9b86..000000000 --- a/test/integration/expression/tests/geometry-type/multilinestring/test.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "expression": [ - "geometry-type" - ], - "inputs": [ - [ - {}, - { - "geometry": { - "type": "MultiLineString", - "coordinates": [ - [[0, 0], [10, 10]], - [[10, 0], [0, 10]] - ] - } - } - ] - ], - "expected": { - "compiled": { - "result": "success", - "isFeatureConstant": false, - "isZoomConstant": true, - "type": "string" - }, - "outputs": [ - "MultiLineString" - ] - } -} diff --git a/test/integration/expression/tests/geometry-type/multipoint/test.json b/test/integration/expression/tests/geometry-type/multipoint/test.json deleted file mode 100644 index c73bbeb82..000000000 --- a/test/integration/expression/tests/geometry-type/multipoint/test.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "expression": [ - "geometry-type" - ], - "inputs": [ - [ - {}, - { - "geometry": { - "type": "MultiPoint", - "coordinates": [ - [10, 0], - [0,10] - ] - } - } - ] - ], - "expected": { - "compiled": { - "result": "success", - "isFeatureConstant": false, - "isZoomConstant": true, - "type": "string" - }, - "outputs": [ - "MultiPoint" - ] - } -} diff --git a/test/integration/expression/tests/geometry-type/multipolygon/test.json b/test/integration/expression/tests/geometry-type/multipolygon/test.json deleted file mode 100644 index 423f5ea60..000000000 --- a/test/integration/expression/tests/geometry-type/multipolygon/test.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "expression": [ - "geometry-type" - ], - "inputs": [ - [ - {}, - { - "geometry": { - "type": "MultiPolygon", - "coordinates": [ - [ - [[0, 0], [5, 0], [5, 5], [0, 5], [0, 0]], - [[1, 1], [1, 4], [4, 4], [4, 1], [1, 1]] - ], - [ - [[2, 2], [3, 2], [3, 3], [2, 3], [2, 2]] - ] - ] - } - } - ] - ], - "expected": { - "compiled": { - "result": "success", - "isFeatureConstant": false, - "isZoomConstant": true, - "type": "string" - }, - "outputs": [ - "MultiPolygon" - ] - } -} diff --git a/test/integration/expression/tests/geometry-type/point/test.json b/test/integration/expression/tests/geometry-type/point/test.json deleted file mode 100644 index 856f7ab85..000000000 --- a/test/integration/expression/tests/geometry-type/point/test.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "expression": [ - "geometry-type" - ], - "inputs": [ - [ - {}, - { - "geometry": { - "type": "Point", - "coordinates": - [10, 0] - } - } - ] - ], - "expected": { - "compiled": { - "result": "success", - "isFeatureConstant": false, - "isZoomConstant": true, - "type": "string" - }, - "outputs": [ - "Point" - ] - } -} diff --git a/test/integration/expression/tests/geometry-type/polygon/test.json b/test/integration/expression/tests/geometry-type/polygon/test.json deleted file mode 100644 index 2509833a5..000000000 --- a/test/integration/expression/tests/geometry-type/polygon/test.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "expression": [ - "geometry-type" - ], - "inputs": [ - [ - {}, - { - "geometry": { - "type": "Polygon", - "coordinates": [ - [[0, 0], [3, 0], [3, 3], [0, 3], [0, 0]], - [[1, 1], [1, 2], [2, 2], [2, 1], [1, 1]] - ] - } - } - ] - ], - "expected": { - "compiled": { - "result": "success", - "isFeatureConstant": false, - "isZoomConstant": true, - "type": "string" - }, - "outputs": [ - "Polygon" - ] - } -}