From 9d5da4e498ef2037e1ca5986e1f861e6245e3046 Mon Sep 17 00:00:00 2001 From: Josh Moore Date: Thu, 13 Mar 2025 14:26:39 +0000 Subject: [PATCH 1/7] Added support for a new model layout property: allow-density-reduction --- 3d-style/data/bucket/model_bucket.ts | 5 +++-- .../style_layer/model_style_layer_properties.ts | 2 ++ src/style-spec/reference/v8.json | 16 ++++++++++++++++ src/style-spec/types.ts | 1 + 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/3d-style/data/bucket/model_bucket.ts b/3d-style/data/bucket/model_bucket.ts index 04cf9bd3008..4a22c8ecaa2 100644 --- a/3d-style/data/bucket/model_bucket.ts +++ b/3d-style/data/bucket/model_bucket.ts @@ -1,4 +1,4 @@ -import EXTENT from '../../../src/style-spec/data/extent'; + import EXTENT from '../../../src/style-spec/data/extent'; import {register} from '../../../src/util/web_worker_transfer'; import loadGeometry from '../../../src/data/load_geometry'; import toEvaluationFeature from '../../../src/data/evaluation_feature'; @@ -445,6 +445,7 @@ class ModelBucket implements Bucket { ): string { const layer = this.layers[0]; const modelIdProperty = layer.layout.get('model-id'); + const modelAllowDensityReductionProperty = layer.layout.get('model-allow-density-reduction'); assert(modelIdProperty); const modelId = modelIdProperty.evaluate(evaluationFeature, {}, this.canonical); @@ -479,7 +480,7 @@ class ModelBucket implements Bucket { continue; // Clip on tile borders to prevent duplicates } // reduce density - if (this.lookupDim !== 0) { + if (this.lookupDim !== 0 || modelAllowDensityReductionProperty) { const tileToLookup = (this.lookupDim - 1.0) / EXTENT; const lookupIndex = this.lookupDim * ((point.y * tileToLookup) | 0) + (point.x * tileToLookup) | 0; if (this.lookup) { diff --git a/3d-style/style/style_layer/model_style_layer_properties.ts b/3d-style/style/style_layer/model_style_layer_properties.ts index ec7a54c172e..ccd6662c91d 100644 --- a/3d-style/style/style_layer/model_style_layer_properties.ts +++ b/3d-style/style/style_layer/model_style_layer_properties.ts @@ -19,11 +19,13 @@ import type {StylePropertySpecification} from '../../../src/style-spec/style-spe export type LayoutProps = { "visibility": DataConstantProperty<"visible" | "none">; "model-id": DataDrivenProperty; + "model-allow-density-reduction": DataConstantProperty; }; let layout: Properties; export const getLayoutProperties = (): Properties => layout || (layout = new Properties({ "visibility": new DataConstantProperty(styleSpec["layout_model"]["visibility"]), "model-id": new DataDrivenProperty(styleSpec["layout_model"]["model-id"]), + "model-allow-density-reduction": new DataConstantProperty(styleSpec["layout_model"]["model-allow-density-reduction"]), })); export type PaintProps = { diff --git a/src/style-spec/reference/v8.json b/src/style-spec/reference/v8.json index 7d8e1f3f87b..4125cbc6362 100644 --- a/src/style-spec/reference/v8.json +++ b/src/style-spec/reference/v8.json @@ -1828,6 +1828,22 @@ "vector" ] }] + }, + "model-allow-density-reduction": { + "type": "boolean", + "default": true, + "doc": "If true, the models will be reduced in density based on the zoom level. This is useful for large datasets that may be slow to render.", + "sdk-support": { + "basic functionality": { + "js": "0.10.0", + "android": "2.0.1", + "ios": "2.0.0" + } + }, + "expression": { + "interpolated": false + }, + "property-type": "data-constant" } }, "layout_clip": { diff --git a/src/style-spec/types.ts b/src/style-spec/types.ts index 713fd860e57..0073e10e62c 100644 --- a/src/style-spec/types.ts +++ b/src/style-spec/types.ts @@ -1361,6 +1361,7 @@ export type ModelLayerSpecification = { "layout"?: { "visibility"?: "visible" | "none" | ExpressionSpecification, "model-id"?: DataDrivenPropertyValueSpecification + "model-allow-density-reduction"?: PropertyValueSpecification, }, "paint"?: { "model-opacity"?: DataDrivenPropertyValueSpecification, From 4c8b1b4fb1d4d330a4ccd79783f625338679ce13 Mon Sep 17 00:00:00 2001 From: Josh Moore Date: Thu, 13 Mar 2025 15:20:10 +0000 Subject: [PATCH 2/7] fix lint --- 3d-style/data/bucket/model_bucket.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3d-style/data/bucket/model_bucket.ts b/3d-style/data/bucket/model_bucket.ts index 4a22c8ecaa2..8b1d9d5b47f 100644 --- a/3d-style/data/bucket/model_bucket.ts +++ b/3d-style/data/bucket/model_bucket.ts @@ -1,4 +1,4 @@ - import EXTENT from '../../../src/style-spec/data/extent'; +import EXTENT from '../../../src/style-spec/data/extent'; import {register} from '../../../src/util/web_worker_transfer'; import loadGeometry from '../../../src/data/load_geometry'; import toEvaluationFeature from '../../../src/data/evaluation_feature'; From 54ca978ff1964a562b2dae66172194b228c552e8 Mon Sep 17 00:00:00 2001 From: Josh Moore Date: Thu, 13 Mar 2025 15:44:49 +0000 Subject: [PATCH 3/7] fixed types --- src/style-spec/reference/v8.json | 4 +--- src/style-spec/types.ts | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/style-spec/reference/v8.json b/src/style-spec/reference/v8.json index 4125cbc6362..1918337b41c 100644 --- a/src/style-spec/reference/v8.json +++ b/src/style-spec/reference/v8.json @@ -1832,6 +1832,7 @@ "model-allow-density-reduction": { "type": "boolean", "default": true, + "transition": false, "doc": "If true, the models will be reduced in density based on the zoom level. This is useful for large datasets that may be slow to render.", "sdk-support": { "basic functionality": { @@ -1840,9 +1841,6 @@ "ios": "2.0.0" } }, - "expression": { - "interpolated": false - }, "property-type": "data-constant" } }, diff --git a/src/style-spec/types.ts b/src/style-spec/types.ts index 0073e10e62c..4b86a971790 100644 --- a/src/style-spec/types.ts +++ b/src/style-spec/types.ts @@ -1360,8 +1360,8 @@ export type ModelLayerSpecification = { "filter"?: FilterSpecification, "layout"?: { "visibility"?: "visible" | "none" | ExpressionSpecification, - "model-id"?: DataDrivenPropertyValueSpecification - "model-allow-density-reduction"?: PropertyValueSpecification, + "model-id"?: DataDrivenPropertyValueSpecification, + "model-allow-density-reduction"?: boolean }, "paint"?: { "model-opacity"?: DataDrivenPropertyValueSpecification, From ae148598146b7ec30e311c6c4ec0feeb2a5850e3 Mon Sep 17 00:00:00 2001 From: Isaac Besora Vilardaga Date: Sat, 29 Nov 2025 07:48:24 +0100 Subject: [PATCH 4/7] Add experimental tag to spec property --- src/style-spec/reference/v8.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/style-spec/reference/v8.json b/src/style-spec/reference/v8.json index 1918337b41c..93141d667db 100644 --- a/src/style-spec/reference/v8.json +++ b/src/style-spec/reference/v8.json @@ -1833,6 +1833,7 @@ "type": "boolean", "default": true, "transition": false, + "experimental": true, "doc": "If true, the models will be reduced in density based on the zoom level. This is useful for large datasets that may be slow to render.", "sdk-support": { "basic functionality": { From b00c610430ebfe9fab97be97aac0936c29e6c87b Mon Sep 17 00:00:00 2001 From: Isaac Besora Vilardaga Date: Mon, 1 Dec 2025 12:18:36 +0100 Subject: [PATCH 5/7] Rebase --- 3d-style/data/bucket/model_bucket.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3d-style/data/bucket/model_bucket.ts b/3d-style/data/bucket/model_bucket.ts index 8b1d9d5b47f..3a21f272962 100644 --- a/3d-style/data/bucket/model_bucket.ts +++ b/3d-style/data/bucket/model_bucket.ts @@ -480,7 +480,7 @@ class ModelBucket implements Bucket { continue; // Clip on tile borders to prevent duplicates } // reduce density - if (this.lookupDim !== 0 || modelAllowDensityReductionProperty) { + if (this.lookupDim !== 0 && modelAllowDensityReductionProperty) { const tileToLookup = (this.lookupDim - 1.0) / EXTENT; const lookupIndex = this.lookupDim * ((point.y * tileToLookup) | 0) + (point.x * tileToLookup) | 0; if (this.lookup) { From 86b3c7349cceaa778d98d5911e7d127dfb6eb5d5 Mon Sep 17 00:00:00 2001 From: Isaac Besora Vilardaga Date: Mon, 1 Dec 2025 12:18:41 +0100 Subject: [PATCH 6/7] Add render test --- test/integration/data/trees-dense.geojson | 1468 +++++++++++++++++ .../density-reduction/expected.png | Bin 0 -> 24053 bytes .../model-layer/density-reduction/style.json | 38 + 3 files changed, 1506 insertions(+) create mode 100644 test/integration/data/trees-dense.geojson create mode 100644 test/integration/render-tests/model-layer/density-reduction/expected.png create mode 100644 test/integration/render-tests/model-layer/density-reduction/style.json diff --git a/test/integration/data/trees-dense.geojson b/test/integration/data/trees-dense.geojson new file mode 100644 index 00000000000..0f1df4bf370 --- /dev/null +++ b/test/integration/data/trees-dense.geojson @@ -0,0 +1,1468 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40272006619924, + 37.78545648087558 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.4025289639477, + 37.785463193325654 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40255869096465, + 37.78519637297586 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40263937858208, + 37.78518630426457 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40266910559876, + 37.785104076404224 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40243341282206, + 37.78524168215965 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40238882229661, + 37.78506715774313 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40227628430408, + 37.78503023906357 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40231662811291, + 37.785107432644935 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40221683027042, + 37.7850151359622 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40222957042047, + 37.78493122978671 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40325939922002, + 37.78504534216188 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40318932839449, + 37.785087295196774 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40309377726884, + 37.78498492975018 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.4029812392763, + 37.78490437979028 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40290904509234, + 37.78485907039973 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40308316047697, + 37.784857392274176 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.4030279531599, + 37.78484564539005 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40307679040194, + 37.78476006089353 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.4030237064433, + 37.78470300450854 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40307679040194, + 37.78467112003834 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.4027965070998, + 37.78468622321 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.4027858902545, + 37.784601477699866 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40294832716819, + 37.78465266070684 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40306086516074, + 37.78458721357673 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40277056605453, + 37.78446612773041 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40264320981605, + 37.784432199971306 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.4025473348947, + 37.78444350922625 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40249147476368, + 37.78522668333707 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40238696947794, + 37.78519535537281 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40248066387208, + 37.78517257139035 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40257435826624, + 37.78514124340313 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40250588928596, + 37.78511845940402 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40260318731035, + 37.78509567539858 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40254552922167, + 37.785087131394576 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40247345661072, + 37.78506434737875 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40263922361581, + 37.78504441135891 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40270940451234, + 37.78507747320111 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40269304973967, + 37.78504677533205 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40258061067827, + 37.78504839100994 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40252336897413, + 37.78503869694369 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40243546207151, + 37.78503223423189 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40248248204266, + 37.785022540163496 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40256016721253, + 37.78503223423189 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40260718718369, + 37.785022540163496 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40266647323423, + 37.78500961473725 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40272575928478, + 37.78501769312882 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40263785238216, + 37.7849869952349 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40258674371796, + 37.784991842271594 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40252132462773, + 37.78500476770171 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40270122712602, + 37.784998304986985 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40236186559491, + 37.78502900287614 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40242319599213, + 37.785190570502664 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40243750641815, + 37.78516310403138 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40245590553724, + 37.78513563754912 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40243341772509, + 37.78510493970424 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40239866383334, + 37.78517441375568 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40239253079365, + 37.78515179430461 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40236390994157, + 37.78513402187315 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40232711170316, + 37.78503384991005 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40224942653353, + 37.784996689307945 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40230462389103, + 37.78500476770171 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40239866383334, + 37.78501284609382 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40243341772509, + 37.784998304986985 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40246817161662, + 37.784991842271594 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40255198982618, + 37.78498214819794 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40260514283705, + 37.784961144366974 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40267260627394, + 37.78496437572646 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40271758189844, + 37.784961144366974 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40263580803577, + 37.78494660324996 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.4026460297685, + 37.78492398372909 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40269100539302, + 37.78493206213005 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40267669496723, + 37.78488843875314 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40259083241101, + 37.78493367781043 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.4026133202234, + 37.78489974852026 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40263785238216, + 37.78486097216958 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40253563505351, + 37.78495306596925 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40252541332076, + 37.78491590532653 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40255607851924, + 37.78491105828485 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40257447763858, + 37.78487066625914 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40249065942899, + 37.78489328579633 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40247839334961, + 37.784969222764616 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40243750641815, + 37.78496276004674 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40242524033877, + 37.78492075236787 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40237413167432, + 37.7849869952349 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40232506735676, + 37.78496437572646 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40236186559491, + 37.78494821893001 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40230053519774, + 37.78492883076993 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40235777690187, + 37.78491590532653 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.4023863977537, + 37.78490782692384 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.4024456838045, + 37.78490136420059 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40252950201382, + 37.78487551330349 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.4026030984904, + 37.78483512125756 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40226169261292, + 37.78489490147754 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40232302301011, + 37.78489974852026 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40240888556608, + 37.78487066625914 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40245794988388, + 37.78486905057741 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.4024967924687, + 37.784844815350525 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40254176809322, + 37.78483673693928 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40235164386218, + 37.78486905057741 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40229644650469, + 37.784883591709686 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40242728468516, + 37.78484319966816 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40237413167432, + 37.78483996830421 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40231075693072, + 37.78485774080556 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40223920480054, + 37.78486905057741 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40245590553724, + 37.784820580115706 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40257038894528, + 37.78480603897101 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40251110289475, + 37.78480765465338 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40233120039645, + 37.78481734874998 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.4024027525264, + 37.78481734874998 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40227191434566, + 37.78484643103205 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.4026133202234, + 37.78481088601956 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40266034019454, + 37.7848157330678 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.4026971384327, + 37.78486905057741 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40272984797807, + 37.78493367781043 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40270327147265, + 37.784814117384855 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40273802536417, + 37.784902979881636 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40274415840412, + 37.78486743489559 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40274415840412, + 37.78483027421059 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40274415840412, + 37.78477534098921 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40268282800692, + 37.78478665077287 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40263580803577, + 37.78478988213999 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40252950201382, + 37.78478988213999 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40242932903182, + 37.7847882664564 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40247634900297, + 37.78479634487296 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40236595428823, + 37.78480927033651 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40228213607864, + 37.78482219579777 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40222898306779, + 37.784844815350525 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40219422917603, + 37.784820580115706 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40223102741444, + 37.78480927033651 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40226782565261, + 37.78478988213999 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.40259287675765, + 37.78477534098921 + ], + "type": "Point" + } + }, + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + -122.4024967924687, + 37.78477372530536 + ], + "type": "Point" + } + } + ] +} \ No newline at end of file diff --git a/test/integration/render-tests/model-layer/density-reduction/expected.png b/test/integration/render-tests/model-layer/density-reduction/expected.png new file mode 100644 index 0000000000000000000000000000000000000000..4fbc2ab0b973bd9dfad4cb7d479e147fe5fab2af GIT binary patch literal 24053 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㏻Yq=FZz|Bm0nul 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 literal 0 HcmV?d00001 diff --git a/test/integration/render-tests/model-layer/density-reduction/style.json b/test/integration/render-tests/model-layer/density-reduction/style.json new file mode 100644 index 00000000000..634ca30305b --- /dev/null +++ b/test/integration/render-tests/model-layer/density-reduction/style.json @@ -0,0 +1,38 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 512, + "height": 512 + } + }, + "center": [ + -122.402822, + 37.78503 + ], + "zoom": 16, + "pitch": 10, + "sources": { + "trees": { + "type": "geojson", + "data": "local://data/trees-dense.geojson" + } + }, + "models": { + "tree-diffuse": "local://models/tree-no-material.glb" + }, + "layers": [ + { + "id": "tree-layer-diffuse", + "type": "model", + "source": "trees", + "layout": { + "model-id": "tree-diffuse" + }, + "paint": { + "model-scale": [ 10, 10, 10], + "model-translation": [0, 0, 100] + } + } + ] +} \ No newline at end of file From 6007de6f74877caed93aa1154de7523c42aca27b Mon Sep 17 00:00:00 2001 From: Isaac Besora Vilardaga Date: Mon, 1 Dec 2025 12:30:54 +0100 Subject: [PATCH 7/7] Codegen --- src/style-spec/types.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/style-spec/types.ts b/src/style-spec/types.ts index 4b86a971790..8095640c691 100644 --- a/src/style-spec/types.ts +++ b/src/style-spec/types.ts @@ -1361,6 +1361,9 @@ export type ModelLayerSpecification = { "layout"?: { "visibility"?: "visible" | "none" | ExpressionSpecification, "model-id"?: DataDrivenPropertyValueSpecification, + /** + * @experimental This property is experimental and subject to change in future versions. + */ "model-allow-density-reduction"?: boolean }, "paint"?: {