import { GeometryType , getFeatureId } from "@here/harp-datasource-protocol" ; import { assert , LoggerManager } from "@here/harp-utils" ; import * as THREE from "three" ; import { Tile , TileFeatureData } from "../Tile" ; import { BufferedGeometryLineAccessor , BufferedGeometryObject3dAccessor , IGeometryAccessor , ILineAccessor , IndexedBufferedGeometryLineAccessor , IObject3dAccessor , isLineAccessor , isObject3dAccessor } from "./TileGeometry" ; const logger = LoggerManager . instance . create ( "TileDataAccessor" ) ; /**
 * Interface for a client visitor that is used to visit all `THREE.Object`s in a tile.
 */ export interface ITileDataVisitor { tile : Tile ; remarks wantsFeature ( featureId ) : boolean ; remarks wantsPoint ( featureId ) : boolean ; remarks wantsLine ( featureId ) : boolean ; remarks wantsArea ( featureId ) : boolean ; remarks wantsObject3D ( featureId ) : boolean ; remarks visitPoint ( featureId ) : void ; remarks visitLine ( featureId , lineAccessor ) : void ; remarks visitArea ( featureId ) : void ; remarks visitObject3D ( featureId , object3dAccessor ) : void ; } /**
 * An interface that provides options for  TileDataAccessor .
  export interface TileDataAccessorOptions { /** Limit to objects that have `featureID`s. */ onlyWithFeatureIds ? : boolean ; /** Sets and overrides `wantPoints`, `wantLines`, `wantAreas`, `wantObject3D`. */ wantsAll ? : boolean ; /** `true` to visit points. */ wantsPoints ? : boolean ; /** `true` to visit lines. */ wantsLines ? : boolean ; /** `true` to visit area objects. */ wantsAreas ? : boolean ; /** `true` to visit general 3D objects. */ wantsObject3D ? : boolean ; } remarks This class uses a client-provided  ITileDataVisitor * to visit all objects, based on filtering options specified
 * by both, the `TileDataAccessor` and
 * the visitor itself.
  export class TileDataAccessor { private readonly m_wantsPoints : boolean ; private readonly m_wantsLines : boolean ; private readonly m_wantsAreas : boolean ; private readonly m_wantsObject3D : boolean ; param tile param visitor param options constructor ( public tile , private readonly visitor , options ) { const wantsAll = options . wantsAll === true ; this . m_wantsPoints = wantsAll || ! ( options . wantsPoints === false ) ; this . m_wantsLines = wantsAll || ! ( options . wantsLines === false ) ; this . m_wantsAreas = wantsAll || ! ( options . wantsAreas === false ) ; this . m_wantsObject3D = wantsAll || ! ( options . wantsObject3D === false ) ; } /**
     * Calls the visitor on all objects in the tile.
     */ visitAll ( ) { const objects = this . tile . objects ; for ( const object of objects ) { this . visitObject ( object ) ; } } param object protected visitObject ( object ) { const featureData = object . userData !== undefined ? ( object . userData . feature as TileFeatureData ) : undefined ; if ( featureData === undefined || ( featureData . objInfos !== undefined && featureData . objInfos . length === 1 && ! this . visitor . wantsFeature ( getFeatureId ( featureData . objInfos [ 0 ] ) ) ) ) { return ; } const geometryType = featureData . geometryType ; if ( geometryType === undefined ) { logger . warn ( "#visitObject: visiting object failed, no geometryType" , object ) ; return ; } assert ( featureData . objInfos !== undefined , "featureData.ids missing" ) ; assert ( featureData . starts !== undefined , "featureData.starts missing" ) ; assert ( Array . isArray ( featureData . starts ) , "featureData.starts is not an array" ) ; if ( featureData . objInfos !== undefined && featureData . starts !== undefined ) { assert ( featureData . objInfos . length === featureData . starts . length , "featureData.ids and featureData.starts have unequal length" ) ; } switch ( geometryType ) { case GeometryType . Point : case GeometryType . Text : if ( ! this . m_wantsPoints ) { return ; } break ; case GeometryType . SolidLine : case GeometryType . ExtrudedLine : case GeometryType . TextPath : if ( ! this . m_wantsLines ) { return ; } break ; case GeometryType . Polygon : case GeometryType . ExtrudedPolygon : if ( ! this . m_wantsAreas ) { return ; } break ; case GeometryType . Object3D : if ( ! this . m_wantsObject3D ) { return ; } break ; default : logger . warn ( "#visitObject: invalid geometryType" ) ; } if ( object . type !== "Mesh" ) { logger . warn ( "#visitObject: visiting object failed, not of type 'Mesh'" , object ) ; return ; } const mesh = object as THREE . Mesh ; this . visitMesh ( mesh , featureData ) ; } param object returns protected getBufferGeometry ( object ) { const geometry = object . geometry ; if ( geometry . type !== "BufferGeometry" ) { logger . warn ( "#visitObject: object does not have BufferGeometry" ) ; return undefined ; } const bufferGeometry = geometry as THREE . BufferGeometry ; const position = bufferGeometry . getAttribute ( "position" ) as THREE . BufferAttribute ; if ( ! position ) { logger . warn ( "#visitLines: BufferGeometry has no position attribute" ) ; return undefined ; } return bufferGeometry ; } param geometryType param object param bufferGeometry returns protected getGeometryAccessor ( geometryType , object , bufferGeometry ) { switch ( geometryType ) { case GeometryType . Point : case GeometryType . Text : return undefined ; case GeometryType . SolidLine : case GeometryType . ExtrudedLine : case GeometryType . TextPath : return new BufferedGeometryLineAccessor ( object , geometryType , bufferGeometry ) ; case GeometryType . Polygon : case GeometryType . ExtrudedPolygon : return undefined ; case GeometryType . Object3D : return new BufferedGeometryObject3dAccessor ( object , geometryType , bufferGeometry ) ; default : logger . warn ( "#getGeometryAccessor: invalid geometryType" ) ; } return undefined ; } param geometryType param object param bufferGeometry returns protected getIndexedGeometryAccessor ( geometryType , object , bufferGeometry ) { switch ( geometryType ) { case GeometryType . Point : case GeometryType . Text : return undefined ; case GeometryType . SolidLine : case GeometryType . ExtrudedLine : case GeometryType . TextPath : return new IndexedBufferedGeometryLineAccessor ( object , geometryType , bufferGeometry ) ; case GeometryType . Polygon : case GeometryType . ExtrudedPolygon : return undefined ; case GeometryType . Object3D : return undefined ; default : logger . warn ( "#getIndexedGeometryAccessor: invalid geometryType" ) ; } return undefined ; } param meshObject param featureData protected visitMesh ( meshObject , featureData ) { const { objInfos , starts } = featureData ; const geometryType = featureData . geometryType ; if ( objInfos === undefined || starts === undefined || geometryType === undefined ) { return ; } let geometryAccessor ; for ( let featureIndex = 0 ; featureIndex < objInfos . length ; featureIndex ++ ) { const featureId = getFeatureId ( objInfos [ featureIndex ] ) ; if ( ! this . visitor . wantsFeature ( featureId ) ) { continue ; } const featureStart = starts [ featureIndex ] ; let featureEnd = - 1 ; if ( geometryAccessor === undefined ) { const bufferGeometry = this . getBufferGeometry ( meshObject ) ; if ( bufferGeometry === undefined ) { continue ; } if ( bufferGeometry . index !== null ) { geometryAccessor = this . getIndexedGeometryAccessor ( geometryType , meshObject , bufferGeometry ) ; } else { geometryAccessor = this . getGeometryAccessor ( geometryType , meshObject , bufferGeometry ) ; } if ( geometryAccessor === undefined ) { logger . warn ( "#visitObject: no accessor geometryType" , geometryType ) ; continue ; } } featureEnd = featureIndex < starts . length - 1 ? starts [ featureIndex + 1 ] : geometryAccessor . getCount ( ) ; geometryAccessor . setRange ( featureStart , featureEnd ) ; switch ( geometryType ) { case GeometryType . Point : case GeometryType . Text : this . visitor . visitPoint ( featureId ) ; break ; case GeometryType . SolidLine : case GeometryType . ExtrudedLine : case GeometryType . TextPath : assert ( isLineAccessor ( geometryAccessor ) ) ; this . visitor . visitLine ( featureId , ( geometryAccessor as any ) as ILineAccessor ) ; break ; case GeometryType . Polygon : case GeometryType . ExtrudedPolygon : this . visitor . visitArea ( featureId ) ; break ; case GeometryType . Object3D : assert ( isObject3dAccessor ( geometryAccessor ) ) ; this . visitor . visitObject3D ( featureId , ( geometryAccessor as any ) as IObject3dAccessor ) ; break ; default : logger . warn ( "#visitObject: invalid geometryType" ) ; } } } }