import { BBox } from "../BBox" import { Feature, Geometry } from "geojson" import { DefaultPinIcon } from "../../Models/Constants" import { Store } from "../UIEventSource" import * as search from "../../assets/generated/layers/search.json" import LayerConfig from "../../Models/ThemeConfig/LayerConfig" import { LayerConfigJson } from "../../Models/ThemeConfig/Json/LayerConfigJson" import FilterConfig, { FilterConfigOption } from "../../Models/ThemeConfig/FilterConfig" import { MinimalLayoutInformation } from "../../Models/ThemeConfig/LayoutConfig" import { GeoOperations } from "../GeoOperations" export type GeocodingCategory = "coordinate" | "city" | "house" | "street" | "locality" | "country" | "train_station" | "county" | "airport" | "shop" export type GeocodeResult = { /** * The name of the feature being displayed */ display_name: string /** * Some optional, extra information */ description?: string | Promise, feature?: Feature, lat: number lon: number /** * Format: * [lat, lat, lon, lon] */ boundingbox?: number[] osm_type?: "node" | "way" | "relation" osm_id: string, category?: GeocodingCategory, payload?: object, source?: string } export type FilterPayload = { option: FilterConfigOption, filter: FilterConfig, layer: LayerConfig, index: number } export type FilterResult = { category: "filter", osm_id: string, payload: FilterPayload } export type LayerResult = {category: "layer", osm_id: string, payload: LayerConfig} export type SearchResult = | FilterResult | { category: "theme", osm_id: string, payload: MinimalLayoutInformation } | LayerResult | GeocodeResult export interface GeocodingOptions { bbox?: BBox } export default interface GeocodingProvider { search(query: string, options?: GeocodingOptions): Promise /** * @param query * @param options */ suggest?(query: string, options?: GeocodingOptions): Store } export type ReverseGeocodingResult = Feature export interface ReverseGeocodingProvider { reverseSearch( coordinate: { lon: number; lat: number }, zoom: number, language?: string, ): Promise; } export class GeocodingUtils { public static searchLayer = GeocodingUtils.initSearchLayer() private static initSearchLayer(): LayerConfig { if (search["id"] === undefined) { // We are resetting the layeroverview; trying to parse is useless return undefined } return new LayerConfig(search, "search") } public static categoryToZoomLevel: Record = { city: 12, county: 10, coordinate: 16, country: 8, house: 16, locality: 14, street: 15, train_station: 14, airport: 13, shop: 16, } public static mergeSimilarResults(results: GeocodeResult[]){ const byName: Record = {} for (const result of results) { const nm = result.display_name if(!byName[nm]) { byName[nm] = [] } byName[nm].push(result) } const merged: GeocodeResult[] = [] for (const nm in byName) { const options = byName[nm] const added = options[0] merged.push(added) const centers: [number,number][] = [[added.lon, added.lat]] for (const other of options) { const otherCenter:[number,number] = [other.lon, other.lat] const nearbyFound= centers.some(center => GeoOperations.distanceBetween(center, otherCenter) < 500) if(!nearbyFound){ merged.push(other) centers.push(otherCenter) } } } return merged } public static categoryToIcon: Record = { city: "building_office_2", coordinate: "globe_alt", country: "globe_alt", house: "house", locality: "building_office_2", street: "globe_alt", train_station: "train", county: "building_office_2", airport: "airport", shop: "building_storefront", } }