import { FlatTheme , Theme , ValueMap } from "@here/harp-datasource-protocol" ; import { ExprPool } from "@here/harp-datasource-protocol/lib/ExprPool" ; import { Projection , TileKey , TilingScheme } from "@here/harp-geoutils" ; import { assert , LoggerManager } from "@here/harp-utils" ; import * as THREE from "three" ; import { MapView } from "./MapView" ; import { Tile } from "./Tile" ; const logger = LoggerManager . instance . create ( "DataSource" ) ; /**
 * Options for a  DataSource .
  export interface DataSourceOptions { /**
     * The unique name of a  DataSource instance.
      name ? : string ; /**
     * The name of the [[StyleSet]] to evaluate for the decoding.
     */ styleSetName ? : string ; /**
     * Used to configure the languages used by the `DataSource` according to priority;
     * the first language in the array has the highest priority.
     *
     *  An array of ISO 639-1 language codes.
     */ languages ? : string [ ] ; /**
     * The minimum zoom level at which data is available or displayed at
     * (depending on  DataSource subclass).
     *  deprecated minZoomLevel ? : number ; /**
     * The maximum zoom level at which data is available or displayed at
     * (depending on  DataSource subclass).
     *  deprecated maxZoomLevel ? : number ; /**
     * The minimum zoom level at which data is available.
     */ minDataLevel ? : number ; /**
     * The maximum zoom level at which data is available.
     */ maxDataLevel ? : number ; /**
     * The minimum zoom level at which  DataSource is displayed.
      minDisplayLevel ? : number ; /**
     * The maximum zoom level at which  DataSource is displayed.
      maxDisplayLevel ? : number ; /**
     * Storage level offset applied to this `DataSource`.
     */ storageLevelOffset ? : number ; default allowOverlappingTiles ? : boolean ; /**
     * Whether features from these data source can picked by calling
     *  MapView . intersectMapObjects . Disabling picking for data sources that don't need it
     * will improve picking performance.
     *  default enablePicking ? : boolean ; /**
     * Maximum geometry height above ground level this  DataSource can produce.
     *
     *  remarks Used in first stage of frustum culling before  Tile data is
     * available.
     *
     *  default maxGeometryHeight ? : number ; /**
     * Minimum geometry height below ground level this  DataSource can produce. Negative
     * values describe height below ground.
     *
     *  remarks Used in first stage of frustum culling before  Tile data is
     * available.
     *
     *  default minGeometryHeight ? : number ; /**
     * Number used to order [DataSource]'s relative to each other, see
     *  DataSource . dataSourceOrder dataSourceOrder ? : number ; } /**
 * Derive a class from `DataSource` to contribute data and geometries to the  MapView .
  export abstract class DataSource extends THREE . EventDispatcher { /**
     * Keep the update event here to avoid a global reference to the datasource (and thus prevent garbage collection).
     */ private readonly UPDATE_EVENT = { type : "update" } ; /**
     * A counter to generate unique names for each `DataSource`, if no name is provided in the
     * constructor.
     */ private static uniqueNameCounter : number = 0 ; /**
     * Set to `true` if this `DataSource` is enabled; `false` otherwise.
     */ enabled : boolean = true ; /**
     * Set to `true` if the  MapView can cache tiles produced by this `DataSource`.
      cacheable : boolean = false ; /**
     * Set to `true` if the loader should be used to get the tile contents.
     */ useGeometryLoader : boolean = false ; /**
     * The unique name of a `DataSource` instance.
     */ name : string ; /**
     * Whether the datasource should have a ground plane (this plane covers the tile entirely and
     * has the minimum possible renderOrder), this can be required in some cases when fallback
     * parent tiles need to be covered by the children, otherwise the content will overlap.
     * Default is false
     */ addGroundPlane : boolean = false ; /**
     * The minimum zoom level at which data is available.
     */ minDataLevel : number = 1 ; /**
     * The maximum zoom level at which data is available.
     */ maxDataLevel : number = 20 ; /**
     * The minimum zoom level at which  DataSource is displayed.
      minDisplayLevel : number = 1 ; /**
     * The maximum zoom level at which  DataSource is displayed.
      maxDisplayLevel : number = 20 ; allowOverlappingTiles : boolean = true ; enablePicking : boolean = true ; remarks defaultValue dataSourceOrder : number = 0 ; internal hidden readonly exprPool = new ExprPool ( ) ; /**
     * The  MapView instance holding a reference to this `DataSource`.
      private m_mapView ? : MapView ; /**
     * The name of the [[StyleSet]] to evaluate for the decoding.
     */ private m_styleSetName ? : string ; /**
     * Current value of [[maxGeometryHeight]] property.
     */ private m_maxGeometryHeight = 0 ; /**
     * Current value of [[minGeometryHeight]] property.
     */ private m_minGeometryHeight = 0 ; /**
     * Storage level offset applied to this `DataSource`.
     */ private m_storageLevelOffset : number = 0 ; private readonly m_featureStateMap = new Map < number | string , ValueMap > ( ) ; /**
     *  An array of ISO 639-1 language codes.
     */ protected languages ? : string [ ] ; param options constructor ( options = { } ) { super ( ) ; let { name } = options ; const { styleSetName , languages , minZoomLevel , maxZoomLevel , minDataLevel , maxDataLevel , minDisplayLevel , maxDisplayLevel , storageLevelOffset , allowOverlappingTiles , enablePicking , minGeometryHeight , maxGeometryHeight , dataSourceOrder } = options ; if ( name === undefined || name . length === 0 ) { name = `anonymous-datasource#${ ++ DataSource . uniqueNameCounter }` ; } this . name = name ; this . styleSetName = styleSetName ; if ( languages !== undefined ) { this . languages = languages ; } if ( minDataLevel !== undefined ) { this . minDataLevel = minDataLevel ; } if ( maxDataLevel !== undefined ) { this . maxDataLevel = maxDataLevel ; } if ( minZoomLevel !== undefined ) { this . minZoomLevel = minZoomLevel ; } if ( maxZoomLevel !== undefined ) { this . maxZoomLevel = maxZoomLevel ; } if ( minDisplayLevel !== undefined ) { this . minDisplayLevel = minDisplayLevel ; } if ( maxDisplayLevel !== undefined ) { this . maxDisplayLevel = maxDisplayLevel ; } if ( storageLevelOffset !== undefined ) { this . m_storageLevelOffset = storageLevelOffset ; } if ( allowOverlappingTiles !== undefined ) { this . allowOverlappingTiles = allowOverlappingTiles ; } if ( enablePicking !== undefined ) { this . enablePicking = enablePicking ; } if ( minGeometryHeight !== undefined ) { this . minGeometryHeight = minGeometryHeight ; } if ( maxGeometryHeight !== undefined ) { this . maxGeometryHeight = maxGeometryHeight ; } if ( dataSourceOrder ) { this . dataSourceOrder = dataSourceOrder ; } } param featureId getFeatureState ( featureId ) { return this . m_featureStateMap . get ( featureId ) ; } /**
     * Clears the state of all the features of this  DataSource .
      clearFeatureState ( ) { this . m_featureStateMap . clear ( ) ; } param featureId param state setFeatureState ( featureId , state ) { this . m_featureStateMap . set ( featureId , state ) ; } param featureId removeFeatureState ( featureId ) { this . m_featureStateMap . delete ( featureId ) ; } /**
     * Returns the name of the [[StyleSet]] to use for the decoding.
     */ get styleSetName ( ) : string | undefined { return this . m_styleSetName ; } /**
     * Sets the name of the [[StyleSet]] to use for the decoding.
     * If this  DataSource is already
     * attached to a  MapView , this setter then reapplies
     * [[StyleSet]] with this name found in
     *  MapView s theme.
      set styleSetName ( styleSetName ) { if ( styleSetName !== this . m_styleSetName ) { this . m_styleSetName = styleSetName ; this . clearCache ( ) ; this . requestUpdate ( ) ; } } /**
     * Destroys this `DataSource`.
     */ dispose ( ) { } /**
     * Purges all the caching done by this `DataSource`
     */ clearCache ( ) { } /**
     * Boolean which says whether a  DataSource produces
     * tiles that fully cover the tile, i.e.
     * tiles underneath are completely hidden. Must be
     * overridden for  DataSource 's that don't
     * have a ground plane, but which still fully
     * cover the tile, e.g. web tiles.
      isFullyCovering ( ) { return this . addGroundPlane ; } /**
     * Returns `true` if this `DataSource` is ready
     * and the  MapView can invoke `getTile()` to
     * start requesting data.
      ready ( ) { return true ; } /**
     * The  MapView that is holding this `DataSource`.
      get mapView ( ) : MapView { if ( this . m_mapView === undefined ) { throw new Error ( "This DataSource was not added to MapView" ) ; } return this . m_mapView ; } /**
     * The  {@link @here/harp-geoutils#Projection} used by
     * the  MapView that is holding this `DataSource`.
     *
     * An `Error` is thrown if you call this method
     * before this `DataSource` has been added
     * to a  MapView .
      get projection ( ) : Projection { return this . mapView . projection ; } /**
     * This method is called when the `DataSource` is added to a  MapView . Override this
     * method to provide any custom initialization, such as, to establish a network connection,
     * or to initialize complex data structures.
      async connect ( ) { } /**
     * Returns the  {@link @here/harp-geoutils#TilingScheme} used by this `DataSource`.
      abstract getTilingScheme ( ) ; /**
     * This method is called when this `DataSource` is added to a  MapView .
     *
     * Overrides of this method must invoke the definition of the super class.
     *
     *  param mapView - The instance of the  MapView .
      attach ( mapView ) { this . m_mapView = mapView ; } /**
     * This method is called when this `DataSource` is removed from a  MapView .
     *
     * Overrides of this method must invoke the definition of the super class.
     *
     *  param mapView - The instance of the  MapView .
      detach ( mapView ) { assert ( this . m_mapView === mapView ) ; this . m_mapView = undefined ; } return isDetached ( ) { return this . m_mapView === undefined ; } /**
     * Apply the  {@link @here/harp-datasource-protocol#Theme} to this data source.
     *
     * If `DataSource` depends on a `styleSet` defined by this theme or `languages`, it must update
     * its tiles' geometry.
     *
     *  param theme async setTheme ( theme ) ; /**
     * Apply the  {@link @here/harp-datasource-protocol#Theme} to this data source.
     *
     * If `DataSource` depends on a `styleSet` defined by this theme or `languages`, it must update
     * its tiles' geometry.
     *
     *  param theme param languages deprecated async setTheme ( theme , languages ? ) { } param languages setLanguages ( languages ? ) { this . languages = languages ; } note param pov setPoliticalView ( pov ? ) { } /**
     * This method is called when  MapView needs to visualize or preload the content of a
     *  {@link @here/harp-geoutils#TileKey} .
     *
     *  param tileKey param delayLoad default abstract getTile ( tileKey , delayLoad ? ) ; /**
     * This method is called by  MapView before the
     * tile needs to be updated, for example after
     * a theme change.
     *
     *  param tile - The  Tile to update.
      updateTile ( tile ) { } /**
     * This method is called by the  MapView to determine if the content of the surrounding
     * tiles must be preloaded.
     *
     *  returns `true` if the  MapView should try to preload tiles surrounding the visible
     * tiles; `false` otherwise. The default is `false`.
      shouldPreloadTiles ( ) { return false ; } /**
     * The minimum zoom level at which data is available or displayed at
     * (depending on  DataSource subclass).
     *  deprecated get minZoomLevel ( ) : number { logger . warn ( "DataSource.minZoomLevel is deprecated. Use minDataLevel and maxDataLevel instead." ) ; return this . minDataLevel ; } set minZoomLevel ( level ) { logger . warn ( "DataSource.minZoomLevel is deprecated. Use minDataLevel and minDisplayLevel instead." ) ; this . minDataLevel = level ; } /**
     * The maximum zoom level at which data is available or displayed at
     * (depending on  DataSource subclass).
     *  deprecated get maxZoomLevel ( ) : number { logger . warn ( "DataSource.maxZoomLevel is deprecated. Use maxDataLevel and maxDisplayLevel instead." ) ; return this . maxDataLevel ; } set maxZoomLevel ( level ) { logger . warn ( "DataSource.maxZoomLevel is deprecated. Use maxDataLevel and maxDisplayLevel instead." ) ; this . maxDataLevel = level ; } /**
     * Maximum geometry height above ground level this `DataSource` can produce.
     *
     * Used in first stage of frustum culling before
     *  Tile . maxGeometryHeight data is available.
     *
     *  default get maxGeometryHeight ( ) { return this . m_maxGeometryHeight ; } set maxGeometryHeight ( value ) { this . m_maxGeometryHeight = value ; } /**
     * Minimum geometry height below ground level this `DataSource` can produce. A negative number
     * specifies a value below ground level.
     *
     * Used in first stage of frustum culling before
     *  Tile . minGeometryHeight data is available.
     *
     *  default get minGeometryHeight ( ) { return this . m_minGeometryHeight ; } set minGeometryHeight ( value ) { this . m_minGeometryHeight = value ; } /**
     * The difference between storage level and display level of tile.
     *
     * Storage level offset is a value applied (added) to current zoom level giving
     * a final tile level being displayed. This way we may differentiate current
     * zoom level from the storage level that is displayed, giving fine grained
     * control over the tiles being decoded an displayed.
     */ get storageLevelOffset ( ) { return this . m_storageLevelOffset ; } param levelOffset set storageLevelOffset ( levelOffset ) { this . m_storageLevelOffset = levelOffset ; } param value setEnableElevationOverlay ( enable ) { } param zoomLevel - The zoom level of the  MapView .
     *  returns getDataZoomLevel ( zoomLevel ) { return THREE . MathUtils . clamp ( zoomLevel + this . m_storageLevelOffset , this . minDataLevel , this . maxDataLevel ) ; } /**
     * Returns `true` if  DataSource should be displayed for the zoom level.
     *  param zoomLevel - The zoom level of the  MapView .
      isVisible ( zoomLevel ) { return zoomLevel >= this . minDisplayLevel && zoomLevel <= this . maxDisplayLevel ; } /**
     * Returns `true` if  DataSource can load tile with
     * given  {@link @here/harp-geoutils#TileKey} and zoom level.
     *
     *  param zoomLevel - The zoom level of the  MapView .
     *  param tileKey returns `true` if the tile for the given  {@link @here/harp-geoutils#TileKey} can be loaded.
      canGetTile ( zoomLevel , tileKey ) { return tileKey . level <= zoomLevel ; } /**
     * Returns `true` if  MapView should traverse tiles
     * further with given  {@link @here/harp-geoutils#TileKey} and
     * zoom level.
     *
     *  param zoomLevel - The zoom level of the  MapView .
     *  param tileKey returns `true` if the subtiles of the given  {@link @here/harp-geoutils#TileKey} should be
     * checked for collisions.
      shouldSubdivide ( zoomLevel , tileKey ) { return tileKey . level <= zoomLevel ; } /**
     * Returns `true` if  MapView should render the text
     * elements with the given  {@link @here/harp-geoutils#TileKey} and
     * zoom level.
     *
     *  remarks param zoomLevel param tileKey returns `true` if the text elements created for the
     *          given  {@link @here/harp-geoutils#TileKey} should be rendered.
      shouldRenderText ( zoomLevel , tileKey ) { return true ; } /**
     * Sends a request to the  MapView to redraw the scene.
      requestUpdate ( ) { this . dispatchEvent ( this . UPDATE_EVENT ) ; } }