import { assert } from "@here/harp-utils" ; import { IntersectParams } from "./IntersectParams" ; import { PickResult } from "./PickHandler" ; function defaultSort ( lhs , rhs ) { const lDataSourceOrder = lhs . dataSourceOrder ?? 0 ; const rDataSourceOrder = rhs . dataSourceOrder ?? 0 ; if ( lDataSourceOrder !== rDataSourceOrder ) { return rDataSourceOrder - lDataSourceOrder ; } const eps = 1e-4 ; const distanceDiff = lhs . distance - rhs . distance ; const haveRenderOrder = lhs . renderOrder !== undefined && rhs . renderOrder !== undefined ; if ( Math . abs ( distanceDiff ) > eps || ! haveRenderOrder ) { return distanceDiff ; } return rhs . renderOrder ! - lhs . renderOrder ! ; } internal export class PickListener { private m_results : PickResult [ ] = [ ] ; private m_sorted : boolean = true ; private m_finished : boolean = true ; param m_parameters constructor ( private readonly m_parameters ? ) { } param result addResult ( result ) { const foundFeatureIdx = this . m_results . findIndex ( otherResult => { const sameType = otherResult . type === result . type ; const dataSource = result . intersection ?. object . userData ?. dataSource ; const sameDataSource = dataSource && otherResult . intersection ?. object . userData ?. dataSource === dataSource ; const sameId = result . featureId !== undefined && otherResult . featureId === result . featureId ; const noId = result . featureId === undefined && otherResult . featureId === undefined ; const sameUserData = result . userData && otherResult . userData === result . userData ; return sameType && sameDataSource && ( sameId || ( noId && sameUserData ) ) ; } ) ; if ( foundFeatureIdx < 0 ) { this . m_sorted = false ; this . m_finished = false ; this . m_results . push ( result ) ; return ; } const oldResult = this . m_results [ foundFeatureIdx ] ; if ( defaultSort ( result , oldResult ) < 0 ) { this . m_results [ foundFeatureIdx ] = result ; this . m_sorted = false ; this . m_finished = false ; } } returns get done ( ) : boolean { return this . maxResults ? this . m_results . length >= this . maxResults : false ; } /**
     * Orders the collected results by distance first, then by reversed render order
     * (topmost/highest render order first), and limits the number of results to the maximum
     * accepted number, see  IntersectParams . maxResultCount .
      finish ( ) { this . sortResults ( ) ; if ( this . maxResults && this . m_results . length > this . maxResults ) { this . m_results . length = this . maxResults ; } this . m_finished = true ; } /**
     * Returns the collected results.  PickListener . finish should be called first to ensure
     * the proper sorting and result count.
     *  returns get results ( ) : PickResult [ ] { assert ( this . m_finished , "finish() was not called before getting the results" ) ; return this . m_results ; } /**
     * Returns the closest result collected so far, following the order documented in
     *  PickListener . finish returns get closestResult ( ) : PickResult | undefined { this . sortResults ( ) ; return this . m_results . length > 0 ? this . m_results [ 0 ] : undefined ; } /**
     * Returns the furthest result collected so far, following the order documented in
     *  PickListener . results returns get furthestResult ( ) : PickResult | undefined { this . sortResults ( ) ; return this . m_results . length > 0 ? this . m_results [ this . m_results . length - 1 ] : undefined ; } private get maxResults ( ) : number | undefined { const maxCount = this . m_parameters ?. maxResultCount ?? 0 ; return maxCount > 0 ? maxCount : undefined ; } private sortResults ( ) { if ( this . m_sorted ) { return ; } const zeroDistanceGroup = [ ] ; const nonZeroDistanceGroup = [ ] ; this . m_results . sort ( defaultSort ) . forEach ( result => ( result . distance === 0 ? zeroDistanceGroup : nonZeroDistanceGroup ) . push ( result ) ) ; this . m_results = zeroDistanceGroup . concat ( nonZeroDistanceGroup ) ; this . m_sorted = true ; } }