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
Filter can't be applied to type: MultiPolygon #3516
Comments
Have you tried |
Thanks for your help. Could you help me with expression? I'm a little out of my depth. The geoJSON is loaded like the example in my original post: Temporarily here is the page where I've deployed the code: https://stage2.postcodesandplaces.com/au/boroondara-2/ |
Hmm... This looks like a bug as it looks like geojson-vt support multipplygon: The following is the only test that checks
Feel free to try and tackle this, I hope it won't be complicated... |
Is that related to this: https://osmus.slack.com/archives/C031V9E9RMG/p1704407869123399?thread_ts=1704405329.375309&cid=C031V9E9RMG ? |
It is related, but it seems like a reverse behavior to what's reported here. |
Do you need to distinguish between MultiPolygon and Polygon? In the past when I was testing with buildings, the filter had to be "Polygon" even though the object was a MultiPolygon $type when i viewed in inspect. I just assumed it was matching without the "Multi", since it does't consider those valid geometry types (like shown here in slack https://github.com/maplibre/maplibre-style-spec/blob/main/src/expression/evaluation_context.ts#L6 ) |
The style spec contains two means to access the geometry type of an element, each has a different set of possible velues:
The values returned by On the other hand, the MVT format spec also says that a geometry MUST interpreted as a multi* geometry when the number of Note that once the |
I've done some research into the problem.
When filter is applied to features, it's applied to individual polygons; Multipolygon itself doesn't live to this moment. That's because of how geojson-vt works. Geojson-vt supports Multipolygon (MP) but in a very limited way. Basically it just flattens MP to individual Polygons (Ps). When filter is applied to features, they are retrieved from tiles already generated by geojson-vt. (geojson_worker_source:73). It returns only bare Ps. Then filter compares them to desired geometry_type ("MP") and it results in false. Actually geojson-vt gives a clue about an original MP. Some solution can be built around this knowledge. But passing it down to filter is really painful. Other walkarounds for a problem are also imaginable but none of them look simple and safe. I'd suggest a simple (but partial) fix: replace "MP" filter with "P" filter in the very beginning. It will not solve the problem completely but will solve it in most cases I think. The good thing is that: there is no error, and all Ps within MPs will be drawn. I'm not sure where exactly to make this swap. The most convenient place is here, before the validation of a layer (but is it ok to pollute style.ts with such stuff?). |
What's more interesting for me, is to understand if this happens to MPs in MVT. |
The problem, as far as I understand, is unrelated to GeoJSON. Here is an example where the vector tiles were created from OSM data by OpenMapTiles. Here is an inner member of an OSM nature reserve boundary relation where |
@HarelM, apparently it's a wider issue that also applies to mvt. Type "MP" gets lost with VT sources too. It gets lost not within Maplibre but supposedly when tiles are generated. I tried a couple of ways to generate tiles (tippecanoe from geojson, maptiler from osm data) and in both cases MP was stored as P, i.e. the "type" of a feature was renamed from "MP" to "P". Though the structure of an original MP is preserved. The resulting "P" (ex-MP) feature still contains multiple "lines" that correspond to original constituent Ps. (But not necessarily multiple. Depends on tiles' structure). On the frontend nothing intersting happens. @mapbox/vector-tile basically just decodes the fetched PBF and makes no assumptions about feature types. I.e., it just takes the hardcoded feature type ("3") from the appropriate index in PBF. I hope this answers your question. (#3516 (comment)). Does it mean that this problem should be solved in maplibre? |
The MVT Spec also says (my emphasis on MUST):
It looks like the interpretation required by the MVT Spec, using a count of external rings, is not performed at any point during the processing of the vector tiles. The numeric values provided are converted to their literal string names. On the other hand, VectorTileFeature.prototype.toGeoJSON() performs that check by classifying the rings and counting the number of outer rings. Similar treatment is done for MultiPoint and MultiLineString features. |
Here is a proposal to sort this out:
With this proposal,
Implementation thoughts
|
The above proposal seems right to me as it aligns the implantation to the spec. |
EDIT: Changed the code below to make the map view more informative I think we have been discussing this issue under an assumption that @dreadedhamish,
So far, I was unable to produce an example that shows a |
I've modified the "Maptiler Basic" style as described above. When opening this style in Maplibre Maputnik, the Inspect view says the On the other hand, the Map view says that both |
Summary of the approach taken in PR maplibre/maplibre-style-spec#519The style spec for The PR adds aligns the implementation of |
@HarelM The behavior of MapLibre Native is the same. Only |
@louwers in both cases native returns only non multi types? or does it behave differently for |
I don't know if solving a bug that aligns the product to the spec is a major or minor version change, in general, we just released version 4 of maplibre, so if this is considered a breaking change, we'll need to wait with it to version 5... |
It is the same for both. enum class FeatureType : uint8_t {
Unknown = 0,
Point = 1,
LineString = 2,
Polygon = 3
};
struct ToFeatureType {
FeatureType operator()(const EmptyGeometry &) const { return FeatureType::Unknown; }
template <class T>
FeatureType operator()(const Point<T> &) const {
return FeatureType::Point;
}
template <class T>
FeatureType operator()(const MultiPoint<T> &) const {
return FeatureType::Point;
}
template <class T>
FeatureType operator()(const LineString<T> &) const {
return FeatureType::LineString;
}
template <class T>
FeatureType operator()(const MultiLineString<T> &) const {
return FeatureType::LineString;
}
template <class T>
FeatureType operator()(const Polygon<T> &) const {
return FeatureType::Polygon;
}
template <class T>
FeatureType operator()(const MultiPolygon<T> &) const {
return FeatureType::Polygon;
}
template <class T>
FeatureType operator()(const mapbox::geometry::geometry_collection<T> &) const {
return FeatureType::Unknown;
}
}; |
It looks like the current Maplibre Native implementation above may also be different than the current maplibre-style-spec implementation.
If |
Monthly meeting conversation summary:
There is a strong bias towards not breaking the way styles will look, and changing the I have created the following poll to solicitate more feedback: Feel free to participate there. |
@HarelM I lost a bit track of this conversation. Maybe you can help me with an example: Say I have this filter: [
"in",
[
"geometry-type"
],
[
"literal",
[
"Polygon",
"MultiPolygon"
]
]
] What is the current behavior, what would be the proposed new behavior? |
For this filter, there will be no change in behavior if the "breaking" change would be implemented. Currently, |
Related to maplibre/maplibre-style-spec#519 and maplibre/maplibre-gl-js#3516 According to the Style Spec, `["geometry-type"]` is expected to distinguish between LineString and MultiLineString, while `"$type"` does not. For the transportation layer, the distinction is harmful. All of OMT style layers, except these two, use `"$type"`.
Related to maplibre/maplibre-style-spec#519 and maplibre/maplibre-gl-js#3516 According to the Style Spec, `["geometry-type"]` is expected to distinguish between LineString and MultiLineString, while `"$type"` does not. For the transportation layer, the distinction is harmful. All of OMT style layers, except these two, use `"$type"`.
Perhaps this is a feature request, but it seems like an existing function is incomplete.
The scenario is "Add multiple geometries from one GeoJSON source" (https://maplibre.org/maplibre-gl-js/docs/examples/multiple-geometries/) but where a Feature is a MultiPolygon.
When applying styling using a filter to a Feature that is of type = MultiPolygon:
map.addLayer({ 'id': 'park-boundary', 'type': 'fill', 'source': 'national-park', 'paint': { 'fill-color': '#888888', 'fill-opacity': 0.8 }, 'filter': ['==', '$type', 'MultiPolygon'] });
an error is thrown:
Error: layers.park-boundary.filter[2]: expected one of [Point, LineString, Polygon], "MultiPolygon" found
MultiPolygons are styled correctly when not using the filter.
The text was updated successfully, but these errors were encountered: