11import { warnOnce } from "../util/util" ;
2+ import { getLngLatPoint } from "../style-spec/expression/definitions/distance" ;
3+ import { IndoorActiveFloorStrategy } from "../style/indoor_active_floor_strategy" ;
24
35import type { VectorTile , VectorTileFeature } from "@mapbox/vector-tile" ;
46import type { IndoorBuilding , IndoorData , IndoorTileOptions } from "../style/indoor_data" ;
57import type Actor from "../util/actor" ;
8+ import type { CanonicalTileID } from "../source/tile_id" ;
9+ import type { Polygon , MultiPolygon } from "geojson" ;
610
7- export function parseActiveFloors ( data : VectorTile , indoorTileOptions : IndoorTileOptions , actor : Actor ) : Set < string > | undefined {
11+ export function parseActiveFloors ( data : VectorTile , indoorTileOptions : IndoorTileOptions , actor : Actor , tileID : CanonicalTileID ) : Set < string > | undefined {
812 const activeFloorsVisible = indoorTileOptions . indoorState . activeFloorsVisible ;
913 if ( ! indoorTileOptions . sourceLayers ) {
1014 return activeFloorsVisible ? indoorTileOptions . indoorState . activeFloors : undefined ;
1115 }
1216 const sourceLayers = calculateIndoorSourceLayers ( indoorTileOptions . sourceLayers , new Set ( Object . keys ( data . layers ) ) ) ;
1317 const indoorState = indoorTileOptions . indoorState ;
14- const indoorData = parseData ( data , sourceLayers , indoorState . activeFloors , indoorState . selectedFloorId ) ;
18+ const indoorData = parseData ( data , sourceLayers , indoorState . activeFloors , indoorState . selectedFloorId , tileID ) ;
1519 actor . send ( 'setIndoorData' , indoorData ) ;
1620 return activeFloorsVisible ? indoorData . activeFloors : undefined ;
1721}
1822
19- // This function is used to parse the indoor data from the vector tile
20- // And resolve set of currently active floors based on lastActiveFloors and selectedFloorId
21- // 1. Parse the indoor data from the vector tile
22- // 2. selectedFloorId will be used to determine if the floor is active (either directly or via connected_floor_ids)
23- // 3. if lastActiveFloors is provided, we will also add floors from that set that are not conflicting with the new active floors from step 2
24- // 4. we also add default floors that are not conflicting with the new active floors from steps 2 and 3
25- // ResolveD data will be passed to the bucket and emitted to indoor manager to create new indoorState
2623function parseData (
2724 data : VectorTile ,
2825 sourceLayers : Set < string > ,
2926 lastActiveFloors : Set < string > ,
30- selectedFloorId : string
27+ selectedFloorId : string ,
28+ tileID : CanonicalTileID
3129) : IndoorData {
32- const newActiveFloors = new Set < string > ( ) ;
33- const allFloors = new Set < string > ( ) ;
34- const allDefaultFloors = new Set < string > ( ) ;
35-
36- const floorIdToConflicts = new Map < string , Set < string > > ( ) ;
3730 const buildings : Record < string , IndoorBuilding > = { } ;
3831
39- // If any active floor lists candidate as conflict, or candidate lists any active as conflict
40- const conflictsWithActive = ( candidateId : string ) : boolean => {
41- const candidateConflicts = floorIdToConflicts . get ( candidateId ) || new Set < string > ( ) ;
42- for ( const activeId of newActiveFloors ) {
43- const activeConflicts = floorIdToConflicts . get ( activeId ) || new Set < string > ( ) ;
44- if ( activeConflicts . has ( candidateId ) || candidateConflicts . has ( activeId ) ) return true ;
45- }
46- return false ;
47- } ;
48-
4932 for ( const layerId of sourceLayers ) {
5033 const sourceLayer = data . layers [ layerId ] ;
5134 if ( ! sourceLayer ) {
@@ -59,52 +42,21 @@ function parseData(
5942 if ( isValidBuildingFeature ( feature ) ) {
6043 const { id, center} = parseBuilding ( feature ) ;
6144 upsertBuilding ( buildings , id , center ) ;
62- newActiveFloors . add ( id ) ;
6345 continue ;
6446 }
6547
6648 // Next step: Introduce better logging in case of invalid feature with valid type
6749 if ( isValidFloorFeature ( feature ) ) {
68- const { id, isDefault, connections, conflicts, buildings : buildingIds , name, zIndex} = parseFloor ( feature ) ;
69- assignFloorToBuildings ( buildings , buildingIds , id , { name, zIndex} ) ;
70-
71- floorIdToConflicts . set ( id , conflicts ) ;
72-
73- const isActiveFloor = ( id === selectedFloorId ) || connections . has ( selectedFloorId ) ;
74- if ( isActiveFloor ) {
75- newActiveFloors . add ( id ) ;
76- }
77-
78- allFloors . add ( id ) ;
79- if ( isDefault ) {
80- allDefaultFloors . add ( id ) ;
81- }
50+ const floor = parseFloor ( feature , tileID ) ;
51+ assignFloorToBuildings ( buildings , floor . buildings , floor . id , floor ) ;
8252 }
8353 }
8454 }
8555
86- // Add last active floors that still exist and don't conflict with current active floors
87- if ( lastActiveFloors ) {
88- for ( const lastActiveFloorId of lastActiveFloors ) {
89- // lastActiveFloors may contain floors that are not in the current tile data, so we need to check if they exist and skip if they don't
90- if ( ! allFloors . has ( lastActiveFloorId ) ) continue ;
91- if ( ! conflictsWithActive ( lastActiveFloorId ) ) {
92- newActiveFloors . add ( lastActiveFloorId ) ;
93- }
94- }
95- }
96-
97- // Add default floors that don't conflict with the active floors
98- for ( const defaultFloorId of allDefaultFloors ) {
99- if ( newActiveFloors . has ( defaultFloorId ) ) continue ;
100- if ( ! conflictsWithActive ( defaultFloorId ) ) {
101- newActiveFloors . add ( defaultFloorId ) ;
102- }
103- }
104-
56+ const activeFloors = IndoorActiveFloorStrategy . calculate ( buildings , selectedFloorId , lastActiveFloors ) ;
10557 return {
10658 buildings,
107- activeFloors : newActiveFloors
59+ activeFloors
10860 } ;
10961}
11062
@@ -128,7 +80,7 @@ function assignFloorToBuildings(
12880 buildings : Record < string , IndoorBuilding > ,
12981 buildingIds : Set < string > ,
13082 floorId : string ,
131- floor : { name : string , zIndex : number }
83+ floor : { name : string , zIndex : number , connections : Set < string > , conflicts : Set < string > , isDefault : boolean , buildings : Set < string > }
13284) : void {
13385 for ( const buildingId of buildingIds ) {
13486 upsertBuilding ( buildings , buildingId ) ;
@@ -143,7 +95,7 @@ function parseBuilding(feature: VectorTileFeature): {id: string, center: [number
14395 return { id, center} ;
14496}
14597
146- function parseFloor ( feature : VectorTileFeature ) : { id : string , isDefault : boolean , connections : Set < string > , conflicts : Set < string > , buildings : Set < string > , zIndex : number , name : string } {
98+ function parseFloor ( feature : VectorTileFeature , tileID : CanonicalTileID ) : { id : string , isDefault : boolean , connections : Set < string > , conflicts : Set < string > , buildings : Set < string > , zIndex : number , name : string , geometry : Polygon | MultiPolygon | undefined } {
14799 const id = feature . properties . id . toString ( ) ;
148100 const isDefault = feature . properties . is_default ?
149101 feature . properties . is_default as boolean :
@@ -159,8 +111,23 @@ function parseFloor(feature: VectorTileFeature): {id: string, isDefault: boolean
159111 new Set ( ) ;
160112 const name = feature . properties . name . toString ( ) ;
161113 const zIndex = feature . properties . z_index as number ;
114+ const geometry = extractGeometry ( feature , tileID ) ;
115+ return { id, isDefault, connections, conflicts, buildings, name, zIndex, geometry} ;
116+ }
117+
118+ function extractGeometry ( feature : VectorTileFeature , tileID : CanonicalTileID ) : Polygon | MultiPolygon | undefined {
119+ const geometry = feature . loadGeometry ( ) ;
120+ if ( ! geometry || geometry . length === 0 ) return undefined ;
121+
122+ const coordinates = geometry . map ( ring => {
123+ return ring . map ( p => {
124+ return getLngLatPoint ( p , tileID , feature . extent ) ;
125+ } ) ;
126+ } ) ;
127+ if ( coordinates . length === 0 ) return undefined ;
162128
163- return { id, isDefault, connections, conflicts, buildings, name, zIndex} ;
129+ // Just construct a Polygon with the first ring as exterior.
130+ return { type : 'Polygon' , coordinates : [ coordinates [ 0 ] ] } ;
164131}
165132
166133function hasRequiredProperties ( feature : VectorTileFeature , requiredProps : string [ ] ) : boolean {
0 commit comments