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

symbol-clip: dynamic filter style spec changes #10977

Merged
merged 40 commits into from
Sep 29, 2021

Conversation

arindam1993
Copy link
Contributor

@arindam1993 arindam1993 commented Aug 30, 2021

This PR adds the necessary changes in the style-spec to account for dynamic filters ( filters with ["pitch"] and ["distance-from-center"]). The diff looks a bit weird because its a diff against the symbol-clip branch which is the branch the original prototype was built in using the symbol-clip layout property.

This support is only being added to symbol-layers so, to communicate that this PR adds some new root-level properties in the style-spec v8.json.

  • These are root level properties with keys formatted like filter_${layerType}.
  • The value for these new entries is an expressionSpec object, exactly like the expression spec objects used to declare expression compatibility for paint/layout properties.
  • The updated style-spec validation code uses these new objects for filter validation, so there is a slight change in the formatting of error messages. 450ca3f and c8d7ed5 show some of the new error messages.

@arindam1993 arindam1993 marked this pull request as ready for review September 15, 2021 17:07
debug/index.html Outdated Show resolved Hide resolved
Copy link
Contributor

@rreusser rreusser left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mainly some wording and doc touchups, but overall looking good. Excited for this feature. 🎉

debug/index.html Outdated Show resolved Hide resolved
src/style-spec/reference/v8.json Outdated Show resolved Hide resolved
src/style-spec/reference/v8.json Show resolved Hide resolved
src/style-spec/reference/v8.json Outdated Show resolved Hide resolved
src/style-spec/reference/v8.json Outdated Show resolved Hide resolved
src/style-spec/reference/v8.json Outdated Show resolved Hide resolved
src/style-spec/reference/v8.json Outdated Show resolved Hide resolved
src/style-spec/reference/v8.json Outdated Show resolved Hide resolved
src/style-spec/reference/v8.json Outdated Show resolved Hide resolved
src/style-spec/reference/v8.json Outdated Show resolved Hide resolved
needGeometry
};
} else {
// This branch cannot happen but need to keep flow happy :(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like Flow is dictating the structure of this whole section at the expense of readability!
Would Flow be ok with a if (!filterFunc) {return;} so that you could unwrap the main return statement?
Or could you make filterFunc a const and use a try / catch?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, flow cannot detect early returns statically.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did a force cast instead, looks slightly cleaner.

@@ -652,7 +652,7 @@
},
"filter": {
"type": "filter",
"doc": "A expression specifying conditions on source features. Only features that match the filter are displayed. Zoom expressions in filters are only evaluated at integer zoom levels. The `feature-state` expression is not supported in filter expressions."
"doc": "An expression specifying conditions on source features. Only features that match the filter are displayed. Zoom expressions in filters are only evaluated at integer zoom levels. The `feature-state` expression is not supported in filter expressions. The `['pitch']` and `['distance-from-center']` expressions are supported only for filter expressions on the `symbol` layer."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"doc": "An expression specifying conditions on source features. Only features that match the filter are displayed. Zoom expressions in filters are only evaluated at integer zoom levels. The `feature-state` expression is not supported in filter expressions. The `['pitch']` and `['distance-from-center']` expressions are supported only for filter expressions on the `symbol` layer."
"doc": "An expression specifying conditions on source features. Only features that match the filter are displayed. [`zoom`](#zoom) expressions in filters are only evaluated at integer zoom levels. The [`feature-state`](#feature-state) expression is not supported in filter expressions. The [`pitch'](#pitch) and [`distance-from-center'`](distance-from-center) expressions are supported only for filter expressions on the [`symbol`](/mapbox-gl-js/style-spec/layers/#symbol) layer."

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good idea but i don't think we should do this manually, instead the docs codegen system should handle this, that way if the structure of the docs website changes it can account for it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds like a good idea to me!

@@ -2524,6 +2500,72 @@
"value": "*",
"doc": "A filter selects specific features from a layer."
},
"filter_symbol": {
"type": "boolean",
"doc": "Expression which determines whether or not to display a symbol. Symbols support `dynamic-filtering`, meaning this expression can use the `[\"pitch\"]` and `[\"distance-from-center\"]` expressions to reference the current state of the view.",
Copy link
Contributor

@SnailBones SnailBones Sep 21, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit:
Is dynamic-filtering a string that users will need to type? If not, I think should just be written in plain text as dynamic filtering.

I'm noticing that in the style-spec expressions are inconsistently formatted as: expression-name, 'expression-name', ["expression-name"], or [\"expression-name\"]. I'd love to hear from the docs team on this.

@@ -4713,9 +4755,6 @@
"doc": "Defines a gradient with which to color a line feature. Can only be used with GeoJSON sources that specify `\"lineMetrics\": true`.",
"transition": false,
"requires": [
{
"!": "line-dasharray"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch!

},
"filter_heatmap": {
"type": "boolean",
"doc": "Expression used to determine whether a point is being displayed or not. Heatmap layer does NOT support `dynamic-filtering`, meaning this expression can NOT use the `[\"pitch\"]` and `[\"distance-from-center\"]` expressions to reference the current state of the view.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rephrase for consistency

@@ -3183,6 +3225,24 @@
}
}
},
"pitch": {
"doc": "Gets the current pitch in degrees. `[\"pitch\"]` may only be used in the `filter` expression for a `symbol` layer.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: consider "Returns" instead of "Gets"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is consistent with the wording for ["zoom"], do you think we should change both?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think "Returns" is slightly more clear.


if (e instanceof CompoundExpression) {
if (disallowedParameters.has(e.name)) {
return [new ValidationError(options.key, options.value, `["${e.name}"] expression is not supported in a filter for a ${options.object.type} layer with id: ${options.object.id}`)];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stylistic question here! Do we prefer to put the correct-use-case return in a nested value and error returns (or throws) at the end? I usually do it the other way around. In any case I'd like to be consistent!

This applies to line 25 too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we have a hard rule. I think doing it a way that makes it easier to read a particular function is better. I personally like error handling/validation at the top and doing the meat of the logic after.

@SnailBones
Copy link
Contributor

Great work @arindam1993! I have a few nits about code styling and documentation syntax.
A nice-to-have would be more links in the documentation.
I think that we should get some eyes from the docs team on this. Do you think it's best to do that in one go after it's merged into the symbol-clip branch?

@arindam1993
Copy link
Contributor Author

Great work @arindam1993! I have a few nits about code styling and documentation syntax. A nice-to-have would be more links in the documentation. I think that we should get some eyes from the docs team on this. Do you think it's best to do that in one go after it's merged into the symbol-clip branch?

If we consistently name expressions, I think its something the docs-page-generation tooling should handle. That way it can account for changes to the website hierarchy without that having to be hardcoded in here.

@SnailBones
Copy link
Contributor

SnailBones commented Sep 28, 2021

Just tested this with the docs and it seems to be breaking.

types.js:40 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'sort')
    at types.js:40
    at Array.map (<anonymous>)
    at Module.T1xj (types.js:37)
    at __webpack_require__ (bootstrap:84)
    at Module.flda (mapbox-gl-js-api~mapbox-gl-js-api-events~mapbox-gl-js-api-geography~mapbox-gl-js-api-handlers~mapbox~559181ac.chunk.js:6205)
    at __webpack_require__ (bootstrap:84)
    at Module.1wO5 (mapbox-gl-js-api~mapbox-gl-js-api-events~mapbox-gl-js-api-geography~mapbox-gl-js-api-handlers~mapbox~559181ac.chunk.js:694)
    at __webpack_require__ (bootstrap:84)
    at Object.ZwM2 (query-terrain-elevation.md:22)
    at __webpack_require__ (bootstrap:84)

EDIT: This starts with this commit. Not directly caused by the changes here.

Arindam Bose and others added 2 commits September 29, 2021 13:48
Co-authored-by: Ricky Reusser <rreusser@users.noreply.github.com>
Co-authored-by: Ricky Reusser <rreusser@users.noreply.github.com>
@arindam1993 arindam1993 merged commit 0d3b8d5 into symbol-clip Sep 29, 2021
@arindam1993 arindam1993 deleted the dynamic-filter/style-spec-changes branch September 29, 2021 21:51
arindam1993 pushed a commit that referenced this pull request Oct 7, 2021
…rom-camera` expressions (#10795)

* Setup plumbing for pitch and distance-from-camera expressions

* Add symbol-clip with support for pitch and distance-from-camera expressions

* hackily working pitch expression

* distance clipping

* Track clipped state in JointPlacement and JointOpacity, reflect clipping using notUsed state in debug buffers

* Rename distance-from-camera to distance-from-center

* symbol-clip: splitting filter expressions into dynamic and static parts (#10923)

* symbol-clip: dynamic filter style spec changes (#10977)

* symbol-clip: Render tests, debug page and distance matrix rework (#11065)

* WIP dynamic filter splitting stage 1

* Add tests for isDynamicFilter

* More test cases for isDynamicFilter

* Existing static filters get passed through unmodified.

* WIP extracting static filters

* Working case -> any translation

* More tests for case -> any conversion

* Add support for match branches

* WIP: V0 of adding collapsing of dynamic expressions to true

* more test cases

* tests and some more refactoring

* remove temory inspection code from unit tests

* Fix dynamic filter detection

* Fix failing spec test

* Units tests hopefully :green: now

* Add test to cover for `null` in expressions

* Address CR comments and reduce number of temporary allocations

* remove gl-matrix as dependency of style-spec and inline a matrix multiplication function

* Fix lint issues

* Add better error messages for expression compilation failures

* Ensure location parameter is passed down

* Remove symbol-clip from the style-spec

* Remove unused property-expression type

* Move filterSpec to v8.json and replace symbol-clip with dynamic filter

* Fix unit tests

* Fix most flow errors

* finally flow is happy

* Add expression validation code

* Add api-supported tests for validation

* Fix some failing unit tests

* Ensure layer._featureFIlter is updated on main thread as well

* Ensure layerType is passed down to validation

* Fix flow and linting

* Fix unit tests

* Pass 1 of addressing CR comments

* Add basic placementTime metric

* Move to using total placement time

* Fix lint errors

* simplify placement time tracking

* Fix silent conflict in with SymbolInstanceStruct changes

* try benchmarking with filter splitting algorithm removed

* Fix versions microbenchmark page

* Revert "try benchmarking with filter splitting algorithm removed"

This reverts commit 865f354.

* Simplify by calculating distance using tile coordinates of the symbol directly

* Use new specific centerDistanceMatrix

* Sign flipping for consistency

* add new debug page with distance visualizer

* First set of pure distance based render tests

* Pitch thresholding tests

* Fix lint errors

* More tests

* Add first batch of point symbol render tests

* Increase threshold

* Increase allowed threshold for the correct tests 🤦

* remove flaky collision debug boxes instead

* Move geojson test data to be in separate files instead of inlined into styles

* Update flaky render test expectation

* Fix distanceMatrix comment

Co-authored-by: Aidan H <aidan.hendrickson@mapbox.com>

* Switch to linear scale and update line placement tests

* Update point placement tests

* Update test expectations

* Fix lint error

* Remove flaky collision boxes

Co-authored-by: Aidan H <aidan.hendrickson@mapbox.com>

* Remove frametime logging change

* Ensure that feature deserialization happens only when needed

* Fix matrixKey naming leftover from copying fogMatrix code

Co-authored-by: Karim Naaji <karim.naaji@gmail.com>

* Rename matrices as per CR comments

* Default layerType inside filter validation function.

* add `VectorTileFeature` deserialization cache

* Switch to matrix-free distance calculation

* Add cache in Transform

* Precompute bearing vector

* prescale by windowScaleFactor

* Inline `getSymbolFeature`

* Lazy filter compilation

* Move distance matrix calculation out to the debug page

Co-authored-by: Aidan H <aidan.hendrickson@mapbox.com>
Co-authored-by: Karim Naaji <karim.naaji@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants