This repository has been archived by the owner on Mar 8, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 197
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
HARP-10772: Support pick result count limit.
Add a parameters object to intersectMapObjects to allow for picking behaviour customization. So far, only the pick maximum number of results can be set. If set, this limit might be taken into account to accelerate picking by skipping unnecessary intersection tests. Signed-off-by: Andres Mandado <andres.mandado-almajano@here.com>
- Loading branch information
1 parent
fbb8ba3
commit 0114c81
Showing
6 changed files
with
539 additions
and
100 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
/* | ||
* Copyright (C) 2017-2020 HERE Europe B.V. | ||
* Licensed under Apache 2.0, see full license in LICENSE | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
/** | ||
* Parameters to customize behaviour of {@link (MapView.intersectMapObjects)}. | ||
*/ | ||
export interface IntersectParams { | ||
/** | ||
* The maximum number of results to be retrieved from the intersection test. If set, only the | ||
* first maxResultCount results will be returned, following an order by distance first, then | ||
* by reversed render order (topmost/highest render order first). | ||
*/ | ||
maxResultCount?: number; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
/* | ||
* Copyright (C) 2017-2020 HERE Europe B.V. | ||
* Licensed under Apache 2.0, see full license in LICENSE | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import { IntersectParams } from "./IntersectParams"; | ||
import { PickResult } from "./PickHandler"; | ||
|
||
// Default sorting by distance first and then by reversed render order. | ||
function defaultSort(lhs: PickResult, rhs: PickResult) { | ||
const distanceDiff = lhs.distance - rhs.distance; | ||
const haveRenderOrder = lhs.renderOrder !== undefined && rhs.renderOrder !== undefined; | ||
if (distanceDiff !== 0 || !haveRenderOrder) { | ||
return distanceDiff; | ||
} | ||
|
||
return rhs.renderOrder! - lhs.renderOrder!; | ||
} | ||
|
||
/** | ||
* Collects results from a picking (intersection) test. | ||
* | ||
* @internal | ||
*/ | ||
export class PickListener { | ||
private m_results: PickResult[] = []; | ||
private m_sorted: boolean = true; | ||
|
||
/** | ||
* Constructs a new `PickListener`. | ||
* | ||
* @param m_parameters - Optional parameters to customize picking behaviour. | ||
*/ | ||
constructor(private readonly m_parameters?: IntersectParams) {} | ||
|
||
/** | ||
* Adds a pick result. | ||
* | ||
* @param result - The result to be added. | ||
*/ | ||
addResult(result: PickResult): void { | ||
// Add the result only if it's a different feature from the ones already collected. | ||
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_results.push(result); | ||
return; | ||
} | ||
|
||
// Replace the result for the same feature if it's sorted after the new result. | ||
const oldResult = this.m_results[foundFeatureIdx]; | ||
if (defaultSort(result, oldResult) < 0) { | ||
this.m_results[foundFeatureIdx] = result; | ||
this.m_sorted = false; | ||
} | ||
} | ||
|
||
/** | ||
* Indicates whether the listener is satisfied with the results already provided. | ||
* @returns `True` if the listener doesn't expect more results, `False` otherwise. | ||
*/ | ||
get done(): boolean { | ||
return this.maxResults ? this.m_results.length >= this.maxResults : false; | ||
} | ||
|
||
/** | ||
* Returns the collected results, ordered by distance first, then by reversed render order | ||
* (topmost/highest render order first). | ||
* @returns The pick results. | ||
*/ | ||
get results(): PickResult[] { | ||
this.finish(); | ||
return this.m_results; | ||
} | ||
|
||
/** | ||
* Returns the closest result collected so far, following the order documented in | ||
* {@link PickListener.results} | ||
* @returns The closest pick result, or `undefined` if no result was collected. | ||
*/ | ||
get closestResult(): PickResult | undefined { | ||
this.sortResults(); | ||
return this.m_results.length > 0 ? this.m_results[0] : undefined; | ||
} | ||
|
||
/** | ||
* Returns the furtherst result collected so far, following the order documented in | ||
* {@link PickListener.results} | ||
* @returns The furthest pick result, or `undefined` if no result was collected. | ||
*/ | ||
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(): void { | ||
if (!this.m_sorted) { | ||
this.m_results.sort(defaultSort); | ||
this.m_sorted = true; | ||
} | ||
} | ||
|
||
private finish(): void { | ||
// Keep only the closest max results. | ||
this.sortResults(); | ||
if (this.maxResults && this.m_results.length > this.maxResults) { | ||
this.m_results.length = this.maxResults; | ||
} | ||
} | ||
} |
Oops, something went wrong.