@@ -9,14 +9,16 @@ import {latFromMercatorY, lngFromMercatorX} from '../../../src/geo/mercator_coor
99import  EXTENT  from  '../../../src/style-spec/data/extent' ; 
1010import  { convertModelMatrixForGlobe ,  queryGeometryIntersectsProjectedAabb }  from  '../../util/model_util' ; 
1111import  Tiled3dModelBucket  from  '../../data/bucket/tiled_3d_model_bucket' ; 
12+ import  Feature  from  '../../../src/util/vectortile_to_geojson' ; 
13+ import  { type  Feature  as  ExpressionEvalFeature ,  type  FeatureState }  from  '../../../src/style-spec/expression/index' ; 
14+ import  ModelSource  from  '../../source/model_source' ; 
1215
1316import  type  { Layout ,  Transitionable ,  Transitioning ,  PossiblyEvaluated ,  PropertyValue ,  ConfigOptions }  from  '../../../src/style/properties' ; 
1417import  type  Point  from  '@mapbox/point-geometry' ; 
15- import  type  { LayerSpecification }  from  '../../../src/style-spec/types' ; 
18+ import  type  { LayerSpecification ,   ModelLayerSpecification }  from  '../../../src/style-spec/types' ; 
1619import  type  { PaintProps ,  LayoutProps }  from  './model_style_layer_properties' ; 
1720import  type  { BucketParameters ,  Bucket }  from  '../../../src/data/bucket' ; 
18- import  type  { TilespaceQueryGeometry }  from  '../../../src/style/query_geometry' ; 
19- import  type  { FeatureState }  from  '../../../src/style-spec/expression/index' ; 
21+ import  type  { QueryGeometry ,  TilespaceQueryGeometry }  from  '../../../src/style/query_geometry' ; 
2022import  type  Transform  from  '../../../src/geo/transform' ; 
2123import  type  ModelManager  from  '../../render/model_manager' ; 
2224import  type  { ModelNode }  from  '../../data/model' ; 
@@ -25,6 +27,8 @@ import type {CanonicalTileID} from '../../../src/source/tile_id';
2527import  type  { LUT }  from  "../../../src/util/lut" ; 
2628import  type  { EvaluationFeature }  from  '../../../src/data/evaluation_feature' ; 
2729import  type  { ProgramName }  from  '../../../src/render/program' ; 
30+ import  type  { QueryResult }  from  '../../../src/source/query_features' ; 
31+ import  type  SourceCache  from  '../../../src/source/source_cache' ; 
2832
2933class  ModelStyleLayer  extends  StyleLayer  { 
3034    override  type : 'model' ; 
@@ -37,13 +41,15 @@ class ModelStyleLayer extends StyleLayer {
3741    override  paint : PossiblyEvaluated < PaintProps > ; 
3842
3943    modelManager : ModelManager ; 
44+     layer : ModelLayerSpecification ; 
4045
4146    constructor ( layer : LayerSpecification ,  scope : string ,  lut : LUT  |  null ,  options ?: ConfigOptions  |  null )  { 
4247        const  properties  =  { 
4348            layout : getLayoutProperties ( ) , 
4449            paint : getPaintProperties ( ) 
4550        } ; 
4651        super ( layer ,  properties ,  scope ,  lut ,  options ) ; 
52+         this . layer  =  layer  as  ModelLayerSpecification ; 
4753        this . _stats  =  { numRenderedVerticesInShadowPass : 0 ,  numRenderedVerticesInTransparentPass : 0 } ; 
4854    } 
4955
@@ -79,6 +85,81 @@ class ModelStyleLayer extends StyleLayer {
7985        return  ( bucket  instanceof  Tiled3dModelBucket )  ? EXTENT  -  1  : 0 ; 
8086    } 
8187
88+     override  queryRenderedFeatures ( 
89+         queryGeometry : QueryGeometry , 
90+         sourceCache : SourceCache , 
91+         transform : Transform 
92+     ) : QueryResult  { 
93+         const  source  =  sourceCache . getSource < ModelSource > ( ) ; 
94+         if  ( ! source  ||  ! ( source  instanceof  ModelSource ) )  return  { } ; 
95+         const  modelSource : ModelSource  =  source ; 
96+ 
97+         const  result : QueryResult  =  { } ; 
98+         result [ this . id ]  =  [ ] ; 
99+         const  layerResult  =  result [ this . id ] ; 
100+ 
101+         let  modelFeatureIndex  =  0 ; 
102+         for  ( const  model  of  modelSource . models )  { 
103+             const  modelFeatureState  =  sourceCache . getFeatureState ( this . sourceLayer ,  model . id ) ; 
104+ 
105+             const  modelFeatureForEval : ExpressionEvalFeature  =  { 
106+                 type : 'Unknown' , 
107+                 id : model . id , 
108+                 properties : model . featureProperties 
109+             } ; 
110+             const  rotation  =  this . paint . get ( 'model-rotation' ) . evaluate ( modelFeatureForEval ,  modelFeatureState ) ; 
111+             const  scale  =  this . paint . get ( 'model-scale' ) . evaluate ( modelFeatureForEval ,  modelFeatureState ) ; 
112+             const  translation  =  this . paint . get ( 'model-translation' ) . evaluate ( modelFeatureForEval ,  modelFeatureState ) ; 
113+             const  elevationReference  =  this . paint . get ( 'model-elevation-reference' ) ; 
114+             const  shouldFollowTerrainSlope  =  elevationReference  ===  'ground' ; 
115+             const  shouldApplyElevation  =  elevationReference  ===  'ground' ; 
116+ 
117+             let  matrix : mat4  =  [ ] ; 
118+             calculateModelMatrix ( matrix , 
119+                                          model , 
120+                                          transform , 
121+                                          model . position , 
122+                                          rotation , 
123+                                          scale , 
124+                                          translation , 
125+                                          shouldApplyElevation , 
126+                                          shouldFollowTerrainSlope , 
127+                                          false ) ; 
128+ 
129+             if  ( transform . projection . name  ===  'globe' )  { 
130+                 matrix  =  convertModelMatrixForGlobe ( matrix ,  transform ) ; 
131+             } 
132+             const  worldViewProjection  =  mat4 . multiply ( [ ] ,  transform . projMatrix ,  matrix ) ; 
133+ 
134+             const  projectedQueryGeometry  =  queryGeometry . isPointQuery ( )  ? queryGeometry . screenBounds  : queryGeometry . screenGeometry ; 
135+ 
136+             const  depth  =  queryGeometryIntersectsProjectedAabb ( projectedQueryGeometry ,  transform ,  worldViewProjection ,  model . aabb ) ; 
137+             if  ( depth  !=  null )  { 
138+                 const  modelFeature : Feature  =  new  Feature ( undefined ,  0 ,  0 ,  0 ,  model . id ) ; 
139+                 modelFeature . layer  =  this . layer ; 
140+                 // Use unsafe assignment for now, due to restriction of GeoJSON/Feature properties to number, string and boolean. 
141+                 // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any 
142+                 modelFeature . properties  =  structuredClone ( model . featureProperties )  as  any ; 
143+                 modelFeature . properties [ 'layer' ]  =  this . id ; 
144+                 modelFeature . properties [ 'uri' ]  =  model . uri ; 
145+                 // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any 
146+                 modelFeature . properties [ 'orientation' ]  =  model . orientation  as  any ; 
147+                 modelFeature . sourceLayer  =  this . sourceLayer ; 
148+                 modelFeature . geometry  =  { 
149+                     type : 'Point' , 
150+                     coordinates : [ model . position . lng ,  model . position . lat ] 
151+                 } ; 
152+                 modelFeature . state  =  modelFeatureState ; 
153+                 modelFeature . source  =  this . source ; 
154+                 layerResult . push ( { featureIndex : modelFeatureIndex ,  feature : modelFeature ,  intersectionZ : depth } ) ; 
155+             } 
156+ 
157+             ++ modelFeatureIndex ; 
158+         } 
159+ 
160+         return  result ; 
161+     } 
162+ 
82163    override  queryIntersectsFeature ( 
83164        queryGeometry : TilespaceQueryGeometry , 
84165        feature : VectorTileFeature , 
0 commit comments