UNPKG

@here/harp-mapview

Version:

Functionality needed to render a map.

159 lines 7.11 kB
"use strict"; /* * Copyright (C) 2020-2021 HERE Europe B.V. * Licensed under Apache 2.0, see full license in LICENSE * SPDX-License-Identifier: Apache-2.0 */ Object.defineProperty(exports, "__esModule", { value: true }); exports.PickListener = void 0; const harp_utils_1 = require("@here/harp-utils"); // Default sorting by: // 1. reversed data source order (higher first) // 2. distance to the camera (closer first) // 3. reversed render order (higher first) // // This criteria order is temporary, until HARP-16245 gets implemented. // Currently, rendering is configured in a way that makes 2D spatials occlude extruded buildings, // since spatials belong to a higher layer. Picking order reflects that, but comparison by distance should // happen first, once extruded buildings become rendered on top of spatials. function defaultSort(lhs, rhs) { var _a, _b; // HARP-14531: Compare by "dataSourceOrder" first, // to ensure that picking results are sorted according to their layers. // The bigger "dataSourceOrder" value is, the higher its stacked in the data model, // meaning the higher it should be appear in the resulting picking collection. // Defaulting "dataSourceOrder" to 0 (base layer) to not skip comparison when it's undefined - in that case // sorting results would not be consistent, as some objects become compared by different criteria. const lDataSourceOrder = (_a = lhs.dataSourceOrder) !== null && _a !== void 0 ? _a : 0; const rDataSourceOrder = (_b = rhs.dataSourceOrder) !== null && _b !== void 0 ? _b : 0; if (lDataSourceOrder !== rDataSourceOrder) { return rDataSourceOrder - lDataSourceOrder; } // HARP-14553: Set a distance tolerance to ignore small distance differences between 2D objects // that are supposed to lie on the same plane. 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; } /** * Collects results from a picking (intersection) test. * * @internal */ class PickListener { /** * Constructs a new `PickListener`. * * @param m_parameters - Optional parameters to customize picking behaviour. */ constructor(m_parameters) { this.m_parameters = m_parameters; this.m_results = []; this.m_sorted = true; this.m_finished = true; } /** * Adds a pick result. * * @param result - The result to be added. */ addResult(result) { // Add the result only if it's a different feature from the ones already collected. const foundFeatureIdx = this.m_results.findIndex(otherResult => { var _a, _b, _c, _d; const sameType = otherResult.type === result.type; const dataSource = (_b = (_a = result.intersection) === null || _a === void 0 ? void 0 : _a.object.userData) === null || _b === void 0 ? void 0 : _b.dataSource; const sameDataSource = dataSource && ((_d = (_c = otherResult.intersection) === null || _c === void 0 ? void 0 : _c.object.userData) === null || _d === void 0 ? void 0 : _d.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; } // 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; this.m_finished = 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() { 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 {@link IntersectParams.maxResultCount}. */ finish() { // Keep only the closest max results. 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. {@link PickListener.finish} should be called first to ensure * the proper sorting and result count. * @returns The pick results. */ get results() { harp_utils_1.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 * {@link PickListener.finish} * @returns The closest pick result, or `undefined` if no result was collected. */ get closestResult() { 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 * {@link PickListener.results} * @returns The furthest pick result, or `undefined` if no result was collected. */ get furthestResult() { this.sortResults(); return this.m_results.length > 0 ? this.m_results[this.m_results.length - 1] : undefined; } get maxResults() { var _a, _b; const maxCount = (_b = (_a = this.m_parameters) === null || _a === void 0 ? void 0 : _a.maxResultCount) !== null && _b !== void 0 ? _b : 0; return maxCount > 0 ? maxCount : undefined; } sortResults() { if (this.m_sorted) { return; } // HARP-14531: group zero-distance results first, // as screen-space objects (e.g. labels) are currently rendered on top. const zeroDistanceGroup = []; const nonZeroDistanceGroup = []; this.m_results .sort(defaultSort) .forEach(result => (result.distance === 0 ? zeroDistanceGroup : nonZeroDistanceGroup).push(result)); // both groups are sorted because "this.m_results" are sorted this.m_results = zeroDistanceGroup.concat(nonZeroDistanceGroup); this.m_sorted = true; } } exports.PickListener = PickListener; //# sourceMappingURL=PickListener.js.map