forked from MapComplete/MapComplete
Fix: license info in 'nearby images' now works for mapillary, add bbox search for panoramax
This commit is contained in:
parent
14fd4e0f4f
commit
7f5544c1e5
6 changed files with 47 additions and 15 deletions
|
@ -8,7 +8,7 @@ export class LicenseInfo {
|
||||||
copyrighted?: boolean = false
|
copyrighted?: boolean = false
|
||||||
credit?: string = ""
|
credit?: string = ""
|
||||||
description?: string = ""
|
description?: string = ""
|
||||||
informationLocation?: URL = undefined
|
informationLocation?: URL | string = undefined
|
||||||
date?: Date
|
date?: Date
|
||||||
views?: number
|
views?: number
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,7 +192,12 @@ export class Mapillary extends ImageProvider {
|
||||||
license.license = "CC BY-SA 4.0"
|
license.license = "CC BY-SA 4.0"
|
||||||
// license.license = "Creative Commons Attribution-ShareAlike 4.0 International License";
|
// license.license = "Creative Commons Attribution-ShareAlike 4.0 International License";
|
||||||
license.attributionRequired = true
|
license.attributionRequired = true
|
||||||
license.date = new Date(response["captured_at"])
|
const date = response["captured_at"]
|
||||||
|
try {
|
||||||
|
license.date = new Date(date)
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("Could not parse captured_at date from mapillary image. The date is:", date)
|
||||||
|
}
|
||||||
return license
|
return license
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { Utils } from "../../Utils"
|
||||||
import { Point } from "geojson"
|
import { Point } from "geojson"
|
||||||
import { Imgur } from "../ImageProviders/Imgur"
|
import { Imgur } from "../ImageProviders/Imgur"
|
||||||
import { ImageData, Panoramax, PanoramaxXYZ } from "panoramax-js/dist"
|
import { ImageData, Panoramax, PanoramaxXYZ } from "panoramax-js/dist"
|
||||||
|
import { Mapillary } from "../ImageProviders/Mapillary"
|
||||||
|
|
||||||
interface ImageFetcher {
|
interface ImageFetcher {
|
||||||
/**
|
/**
|
||||||
|
@ -222,6 +223,11 @@ class ImagesFromPanoramaxFetcher implements ImageFetcher {
|
||||||
const promises: Promise<ImageData[]>[] = []
|
const promises: Promise<ImageData[]>[] = []
|
||||||
const maxRadius = this._radius
|
const maxRadius = this._radius
|
||||||
let prevRadius = 0
|
let prevRadius = 0
|
||||||
|
|
||||||
|
const nearby = this._panoramax.search({
|
||||||
|
bbox: new BBox([[lon, lat]]).pad(0.001).toLngLatFlat()
|
||||||
|
})
|
||||||
|
promises.push(nearby) // We do a nearby search with bbox, see https://source.mapcomplete.org/MapComplete/MapComplete/issues/2384
|
||||||
for (const radiusSetting of radiusSettings) {
|
for (const radiusSetting of radiusSettings) {
|
||||||
const promise = this._panoramax.search({
|
const promise = this._panoramax.search({
|
||||||
place: [lon, lat],
|
place: [lon, lat],
|
||||||
|
@ -265,7 +271,7 @@ class MapillaryFetcher implements ImageFetcher {
|
||||||
async fetchImages(lat: number, lon: number): Promise<P4CPicture[]> {
|
async fetchImages(lat: number, lon: number): Promise<P4CPicture[]> {
|
||||||
const boundingBox = new BBox([[lon, lat]]).padAbsolute(0.003)
|
const boundingBox = new BBox([[lon, lat]]).padAbsolute(0.003)
|
||||||
let url =
|
let url =
|
||||||
"https://graph.mapillary.com/images?fields=geometry,computed_geometry,creator,id,thumb_256_url,thumb_original_url,compass_angle&bbox=" +
|
"https://graph.mapillary.com/images?fields=geometry,computed_geometry,creator,id,captured_at,thumb_256_url,thumb_original_url,compass_angle&bbox=" +
|
||||||
[
|
[
|
||||||
boundingBox.getWest(),
|
boundingBox.getWest(),
|
||||||
boundingBox.getSouth(),
|
boundingBox.getSouth(),
|
||||||
|
@ -293,13 +299,14 @@ class MapillaryFetcher implements ImageFetcher {
|
||||||
const response = await Utils.downloadJson<{
|
const response = await Utils.downloadJson<{
|
||||||
data: {
|
data: {
|
||||||
id: string
|
id: string
|
||||||
creator: string
|
creator: { username: string }
|
||||||
geometry: Point
|
geometry: Point
|
||||||
computed_geometry: Point
|
computed_geometry: Point
|
||||||
is_pano: boolean
|
is_pano: boolean
|
||||||
thumb_256_url: string
|
thumb_256_url: string
|
||||||
thumb_original_url: string
|
thumb_original_url: string
|
||||||
compass_angle: number
|
compass_angle: number
|
||||||
|
captured_at: number
|
||||||
}[]
|
}[]
|
||||||
}>(url)
|
}>(url)
|
||||||
const pics: P4CPicture[] = []
|
const pics: P4CPicture[] = []
|
||||||
|
@ -308,6 +315,7 @@ class MapillaryFetcher implements ImageFetcher {
|
||||||
if (img.thumb_original_url === undefined) {
|
if (img.thumb_original_url === undefined) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
const [lon, lat] = img.computed_geometry.coordinates
|
||||||
pics.push({
|
pics.push({
|
||||||
pictureUrl: img.thumb_original_url,
|
pictureUrl: img.thumb_original_url,
|
||||||
provider: "Mapillary",
|
provider: "Mapillary",
|
||||||
|
@ -319,6 +327,12 @@ class MapillaryFetcher implements ImageFetcher {
|
||||||
details: {
|
details: {
|
||||||
isSpherical: this._panoramas === "only",
|
isSpherical: this._panoramas === "only",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
detailsUrl: Mapillary.singleton.visitUrl(img, { lon, lat }),
|
||||||
|
date: img.captured_at,
|
||||||
|
license: "CC-BY-SA",
|
||||||
|
author: img.creator.username,
|
||||||
|
direction: img.compass_angle
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return pics
|
return pics
|
||||||
|
@ -367,7 +381,6 @@ export class CombinedFetcher {
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const pics = await source.fetchImages(lat, lon)
|
const pics = await source.fetchImages(lat, lon)
|
||||||
console.log(source.name, "==>>", pics)
|
|
||||||
state.data[source.name] = "done"
|
state.data[source.name] = "done"
|
||||||
state.ping()
|
state.ping()
|
||||||
|
|
||||||
|
|
|
@ -246,5 +246,5 @@ export interface TagRenderingConfigJson {
|
||||||
* Note: if the theme already has a layer with this ID, the value is ignored
|
* Note: if the theme already has a layer with this ID, the value is ignored
|
||||||
* group: hidden
|
* group: hidden
|
||||||
*/
|
*/
|
||||||
requiredLayers: { id: string; minzoom?: number }[]
|
requiredLayers?: { id: string; minzoom?: number }[]
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,18 +37,29 @@
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const t = Translations.t.image.nearby
|
const t = Translations.t.image.nearby
|
||||||
|
|
||||||
|
let date: Date
|
||||||
|
if (image.date) {
|
||||||
|
try {
|
||||||
|
date = new Date(image.date)
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("Could not parse image date", image.date, "for", image.detailsUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let license: LicenseInfo = {
|
let license: LicenseInfo = {
|
||||||
artist: image.author,
|
artist: image.author,
|
||||||
license: image.license,
|
license: image.license,
|
||||||
date: new Date(image.date),
|
informationLocation: (image.detailsUrl ?? image.pictureUrl ?? image.thumbUrl),
|
||||||
informationLocation: image.detailsUrl,
|
date
|
||||||
}
|
}
|
||||||
|
console.log(">>> trying to create license info based on", image, license)
|
||||||
let providedImage: ProvidedImage = {
|
let providedImage: ProvidedImage = {
|
||||||
url: image.thumbUrl ?? image.pictureUrl,
|
url: image.thumbUrl ?? image.pictureUrl,
|
||||||
url_hd: image.pictureUrl,
|
url_hd: image.pictureUrl,
|
||||||
key: undefined,
|
key: undefined,
|
||||||
provider: AllImageProviders.byName(image.provider),
|
provider: AllImageProviders.byName(image.provider),
|
||||||
date: new Date(image.date),
|
date,
|
||||||
id: Object.values(image.osmTags)[0],
|
id: Object.values(image.osmTags)[0],
|
||||||
isSpherical: image.details.isSpherical,
|
isSpherical: image.details.isSpherical,
|
||||||
license,
|
license,
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
import type { SpecialVisualizationState } from "../SpecialVisualization"
|
import type { SpecialVisualizationState } from "../SpecialVisualization"
|
||||||
import type { P4CPicture } from "../../Logic/Web/NearbyImagesSearch"
|
import type { P4CPicture } from "../../Logic/Web/NearbyImagesSearch"
|
||||||
import LinkableImage from "./LinkableImage.svelte"
|
import LinkableImage from "./LinkableImage.svelte"
|
||||||
import type { Feature, Point } from "geojson"
|
import type { Feature, Geometry, Point } from "geojson"
|
||||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||||
import Loading from "../Base/Loading.svelte"
|
import Loading from "../Base/Loading.svelte"
|
||||||
import AllImageProviders from "../../Logic/ImageProviders/AllImageProviders"
|
import AllImageProviders from "../../Logic/ImageProviders/AllImageProviders"
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
import { BBox } from "../../Logic/BBox"
|
import { BBox } from "../../Logic/BBox"
|
||||||
import PanoramaxLink from "../BigComponents/PanoramaxLink.svelte"
|
import PanoramaxLink from "../BigComponents/PanoramaxLink.svelte"
|
||||||
import { GeoOperations } from "../../Logic/GeoOperations"
|
import { GeoOperations } from "../../Logic/GeoOperations"
|
||||||
import type { PanoramaView } from "../../Logic/ImageProviders/ImageProvider"
|
import type { HotspotProperties, PanoramaView } from "../../Logic/ImageProviders/ImageProvider"
|
||||||
|
|
||||||
export let tags: UIEventSource<OsmTags>
|
export let tags: UIEventSource<OsmTags>
|
||||||
export let state: SpecialVisualizationState
|
export let state: SpecialVisualizationState
|
||||||
|
@ -52,6 +52,7 @@
|
||||||
[loadedImages]
|
[loadedImages]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Panorama-views get a geojson feature to browse around
|
||||||
let asFeatures = result.map((p4cs) =>
|
let asFeatures = result.map((p4cs) =>
|
||||||
p4cs.map(
|
p4cs.map(
|
||||||
(p4c) =>
|
(p4c) =>
|
||||||
|
@ -147,25 +148,27 @@
|
||||||
highlighted.set(feature.properties.id)
|
highlighted.set(feature.properties.id)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
let nearbyFeatures: Store<Feature[]> = asFeatures.map((nearbyPoints) => {
|
|
||||||
|
let nearbyFeatures: Store<Feature<Geometry, HotspotProperties>[]> = asFeatures.map((nearbyPoints) => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
type: "Feature",
|
type: "Feature",
|
||||||
geometry: { type: "Point", coordinates: GeoOperations.centerpointCoordinates(feature) },
|
geometry: { type: "Point", coordinates: GeoOperations.centerpointCoordinates(feature) },
|
||||||
properties: {
|
properties: <HotspotProperties>{
|
||||||
name: layer.title?.GetRenderValue(feature.properties).Subs(feature.properties).txt,
|
name: layer.title?.GetRenderValue(feature.properties).Subs(feature.properties).txt,
|
||||||
focus: true,
|
focus: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
...nearbyPoints
|
...nearbyPoints
|
||||||
.filter((p) => p.properties.spherical === "yes")
|
.filter((p) => p.properties["spherical"] === "yes")
|
||||||
.map((f) => ({
|
.map((f) => ({
|
||||||
...f,
|
...f,
|
||||||
properties: {
|
properties: <HotspotProperties>{
|
||||||
name: "Nearby panorama",
|
name: "Nearby panorama",
|
||||||
pitch: "auto",
|
pitch: "auto",
|
||||||
type: "scene",
|
type: "scene",
|
||||||
gotoPanorama: f,
|
gotoPanorama: f,
|
||||||
|
focus: false
|
||||||
},
|
},
|
||||||
})),
|
})),
|
||||||
]
|
]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue