forked from MapComplete/MapComplete
LayerServer: fix some bugs in build_db-script, decode MVT-tilesource for more features
This commit is contained in:
parent
ee3e000cd1
commit
5b318236bf
8 changed files with 327 additions and 103 deletions
|
@ -59,7 +59,7 @@ export default class LayoutSource extends FeatureSourceMerger {
|
|||
zoom,
|
||||
featureSwitches
|
||||
)//*/
|
||||
|
||||
/*
|
||||
const osmApiSource = LayoutSource.setupOsmApiSource(
|
||||
osmLayers,
|
||||
bounds,
|
||||
|
@ -67,14 +67,14 @@ export default class LayoutSource extends FeatureSourceMerger {
|
|||
backend,
|
||||
featureSwitches,
|
||||
fullNodeDatabaseSource
|
||||
)
|
||||
)*/
|
||||
|
||||
const geojsonSources: FeatureSource[] = geojsonlayers.map((l) =>
|
||||
LayoutSource.setupGeojsonSource(l, mapProperties, isDisplayed(l.id))
|
||||
)
|
||||
|
||||
|
||||
super(osmApiSource, ...geojsonSources, ...fromCache, ...mvtSources)
|
||||
super(...geojsonSources, ...fromCache, ...mvtSources)
|
||||
|
||||
const self = this
|
||||
function setIsLoading() {
|
||||
|
@ -83,7 +83,7 @@ export default class LayoutSource extends FeatureSourceMerger {
|
|||
}
|
||||
|
||||
// overpassSource?.runningQuery?.addCallbackAndRun((_) => setIsLoading())
|
||||
osmApiSource?.isRunning?.addCallbackAndRun((_) => setIsLoading())
|
||||
// osmApiSource?.isRunning?.addCallbackAndRun((_) => setIsLoading())
|
||||
}
|
||||
|
||||
private static setupMvtSource(layer: LayerConfig, mapProperties: { zoom: Store<number>; bounds: Store<BBox> }, isActive?: Store<boolean>): FeatureSource{
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Store } from "../../UIEventSource"
|
||||
import DynamicTileSource, { PolygonSourceMerger } from "./DynamicTileSource"
|
||||
import DynamicTileSource from "./DynamicTileSource"
|
||||
import { Utils } from "../../../Utils"
|
||||
import { BBox } from "../../BBox"
|
||||
import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"
|
||||
|
@ -7,6 +7,8 @@ import MvtSource from "../Sources/MvtSource"
|
|||
import { Tiles } from "../../../Models/TileRange"
|
||||
import Constants from "../../../Models/Constants"
|
||||
import FeatureSourceMerger from "../Sources/FeatureSourceMerger"
|
||||
import { LineSourceMerger } from "./LineSourceMerger"
|
||||
import { PolygonSourceMerger } from "./PolygonSourceMerger"
|
||||
|
||||
|
||||
class PolygonMvtSource extends PolygonSourceMerger{
|
||||
|
@ -39,6 +41,36 @@ class PolygonMvtSource extends PolygonSourceMerger{
|
|||
}
|
||||
|
||||
|
||||
class LineMvtSource extends LineSourceMerger{
|
||||
constructor( layer: LayerConfig,
|
||||
mapProperties: {
|
||||
zoom: Store<number>
|
||||
bounds: Store<BBox>
|
||||
},
|
||||
options?: {
|
||||
isActive?: Store<boolean>
|
||||
}) {
|
||||
const roundedZoom = mapProperties.zoom.mapD(z => Math.min(Math.floor(z/2)*2, 14))
|
||||
super(
|
||||
roundedZoom,
|
||||
layer.minzoom,
|
||||
(zxy) => {
|
||||
const [z, x, y] = Tiles.tile_from_index(zxy)
|
||||
const url = Utils.SubstituteKeys(Constants.VectorTileServer,
|
||||
{
|
||||
z, x, y, layer: layer.id,
|
||||
type: "lines",
|
||||
})
|
||||
return new MvtSource(url, x, y, z)
|
||||
},
|
||||
mapProperties,
|
||||
{
|
||||
isActive: options?.isActive,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PointMvtSource extends DynamicTileSource {
|
||||
|
||||
constructor(
|
||||
|
@ -84,9 +116,9 @@ export default class DynamicMvtileSource extends FeatureSourceMerger {
|
|||
isActive?: Store<boolean>
|
||||
},
|
||||
) {
|
||||
const roundedZoom = mapProperties.zoom.mapD(z => Math.floor(z))
|
||||
super(
|
||||
new PointMvtSource(layer, mapProperties, options),
|
||||
new LineMvtSource(layer, mapProperties, options),
|
||||
new PolygonMvtSource(layer, mapProperties, options)
|
||||
|
||||
)
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
import { Store, Stores } from "../../UIEventSource"
|
||||
import { Tiles } from "../../../Models/TileRange"
|
||||
import { BBox } from "../../BBox"
|
||||
import { FeatureSource, FeatureSourceForTile } from "../FeatureSource"
|
||||
import { FeatureSource } from "../FeatureSource"
|
||||
import FeatureSourceMerger from "../Sources/FeatureSourceMerger"
|
||||
import { Feature } from "geojson"
|
||||
import { Utils } from "../../../Utils"
|
||||
import { GeoOperations } from "../../GeoOperations"
|
||||
|
||||
|
||||
/***
|
||||
|
@ -84,68 +81,3 @@ export default class DynamicTileSource<Src extends FeatureSource = FeatureSource
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* The PolygonSourceMerger receives various small pieces of bigger polygons and stitches them together.
|
||||
* This is used to reconstruct polygons of vector tiles
|
||||
*/
|
||||
export class PolygonSourceMerger extends DynamicTileSource<FeatureSourceForTile> {
|
||||
constructor(
|
||||
zoomlevel: Store<number>,
|
||||
minzoom: number,
|
||||
constructSource: (tileIndex: number) => FeatureSourceForTile,
|
||||
mapProperties: {
|
||||
bounds: Store<BBox>
|
||||
zoom: Store<number>
|
||||
},
|
||||
options?: {
|
||||
isActive?: Store<boolean>
|
||||
},
|
||||
) {
|
||||
super(zoomlevel, minzoom, constructSource, mapProperties, options)
|
||||
}
|
||||
|
||||
protected addDataFromSources(sources: FeatureSourceForTile[]) {
|
||||
sources = Utils.NoNull(sources)
|
||||
const all: Map<string, Feature> = new Map()
|
||||
const zooms: Map<string, number> = new Map()
|
||||
|
||||
for (const source of sources) {
|
||||
let z = source.z
|
||||
for (const f of source.features.data) {
|
||||
const id = f.properties.id
|
||||
if(id.endsWith("146616907")){
|
||||
console.log("Horeca totaal")
|
||||
}
|
||||
if (!all.has(id)) {
|
||||
// No other parts of this polygon have been seen before, simply add it
|
||||
all.set(id, f)
|
||||
zooms.set(id, z)
|
||||
continue
|
||||
}
|
||||
|
||||
// A part of this object has been seen before, eventually from a different zoom level
|
||||
const oldV = all.get(id)
|
||||
const oldZ = zooms.get(id)
|
||||
if (oldZ > z) {
|
||||
// The store contains more detailed information, so we ignore this part which has a lower accuraccy
|
||||
continue
|
||||
}
|
||||
if (oldZ < z) {
|
||||
// The old value has worse accuracy then what we receive now, we throw it away
|
||||
all.set(id, f)
|
||||
zooms.set(id, z)
|
||||
continue
|
||||
}
|
||||
const merged = GeoOperations.union(f, oldV)
|
||||
merged.properties = oldV.properties
|
||||
all.set(id, merged)
|
||||
zooms.set(id, z)
|
||||
}
|
||||
}
|
||||
|
||||
const newList = Array.from(all.values())
|
||||
this.features.setData(newList)
|
||||
this._featuresById.setData(all)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
import { FeatureSourceForTile } from "../FeatureSource"
|
||||
import { Store } from "../../UIEventSource"
|
||||
import { BBox } from "../../BBox"
|
||||
import { Utils } from "../../../Utils"
|
||||
import { Feature, LineString, MultiLineString, Position } from "geojson"
|
||||
import { Tiles } from "../../../Models/TileRange"
|
||||
import { GeoOperations } from "../../GeoOperations"
|
||||
import DynamicTileSource from "./DynamicTileSource"
|
||||
|
||||
/**
|
||||
* The PolygonSourceMerger receives various small pieces of bigger polygons and stitches them together.
|
||||
* This is used to reconstruct polygons of vector tiles
|
||||
*/
|
||||
export class LineSourceMerger extends DynamicTileSource<FeatureSourceForTile> {
|
||||
private readonly _zoomlevel: Store<number>
|
||||
|
||||
constructor(
|
||||
zoomlevel: Store<number>,
|
||||
minzoom: number,
|
||||
constructSource: (tileIndex: number) => FeatureSourceForTile,
|
||||
mapProperties: {
|
||||
bounds: Store<BBox>
|
||||
zoom: Store<number>
|
||||
},
|
||||
options?: {
|
||||
isActive?: Store<boolean>
|
||||
},
|
||||
) {
|
||||
super(zoomlevel, minzoom, constructSource, mapProperties, options)
|
||||
this._zoomlevel = zoomlevel
|
||||
}
|
||||
|
||||
protected addDataFromSources(sources: FeatureSourceForTile[]) {
|
||||
sources = Utils.NoNull(sources)
|
||||
const all: Map<string, Feature<MultiLineString>> = new Map()
|
||||
const currentZoom = this._zoomlevel?.data ?? 0
|
||||
for (const source of sources) {
|
||||
if(source.z != currentZoom){
|
||||
continue
|
||||
}
|
||||
const bboxCoors = Tiles.tile_bounds_lon_lat(source.z, source.x, source.y)
|
||||
const bboxGeo = new BBox(bboxCoors).asGeoJson({})
|
||||
for (const f of source.features.data) {
|
||||
const id = f.properties.id
|
||||
const coordinates : Position[][] = []
|
||||
if(f.geometry.type === "LineString"){
|
||||
coordinates.push(f.geometry.coordinates)
|
||||
}else if(f.geometry.type === "MultiLineString"){
|
||||
coordinates.push(...f.geometry.coordinates)
|
||||
}else {
|
||||
console.error("Invalid geometry type:", f.geometry.type)
|
||||
continue
|
||||
}
|
||||
const oldV = all.get(id)
|
||||
if(!oldV){
|
||||
|
||||
all.set(id, {
|
||||
type: "Feature",
|
||||
properties: f.properties,
|
||||
geometry:{
|
||||
type:"MultiLineString",
|
||||
coordinates
|
||||
}
|
||||
})
|
||||
continue
|
||||
}
|
||||
oldV.geometry.coordinates.push(...coordinates)
|
||||
}
|
||||
}
|
||||
|
||||
const keys = Array.from(all.keys())
|
||||
for (const key of keys) {
|
||||
all.set(key, <any> GeoOperations.attemptLinearize(<Feature<MultiLineString>>all.get(key)))
|
||||
}
|
||||
const newList = Array.from(all.values())
|
||||
this.features.setData(newList)
|
||||
this._featuresById.setData(all)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
import { FeatureSourceForTile } from "../FeatureSource"
|
||||
import { Store } from "../../UIEventSource"
|
||||
import { BBox } from "../../BBox"
|
||||
import { Utils } from "../../../Utils"
|
||||
import { Feature } from "geojson"
|
||||
import { GeoOperations } from "../../GeoOperations"
|
||||
import DynamicTileSource from "./DynamicTileSource"
|
||||
|
||||
/**
|
||||
* The PolygonSourceMerger receives various small pieces of bigger polygons and stitches them together.
|
||||
* This is used to reconstruct polygons of vector tiles
|
||||
*/
|
||||
export class PolygonSourceMerger extends DynamicTileSource<FeatureSourceForTile> {
|
||||
constructor(
|
||||
zoomlevel: Store<number>,
|
||||
minzoom: number,
|
||||
constructSource: (tileIndex: number) => FeatureSourceForTile,
|
||||
mapProperties: {
|
||||
bounds: Store<BBox>
|
||||
zoom: Store<number>
|
||||
},
|
||||
options?: {
|
||||
isActive?: Store<boolean>
|
||||
},
|
||||
) {
|
||||
super(zoomlevel, minzoom, constructSource, mapProperties, options)
|
||||
}
|
||||
|
||||
protected addDataFromSources(sources: FeatureSourceForTile[]) {
|
||||
sources = Utils.NoNull(sources)
|
||||
const all: Map<string, Feature> = new Map()
|
||||
const zooms: Map<string, number> = new Map()
|
||||
|
||||
for (const source of sources) {
|
||||
let z = source.z
|
||||
for (const f of source.features.data) {
|
||||
const id = f.properties.id
|
||||
if (id.endsWith("146616907")) {
|
||||
console.log("Horeca totaal")
|
||||
}
|
||||
if (!all.has(id)) {
|
||||
// No other parts of this polygon have been seen before, simply add it
|
||||
all.set(id, f)
|
||||
zooms.set(id, z)
|
||||
continue
|
||||
}
|
||||
|
||||
// A part of this object has been seen before, eventually from a different zoom level
|
||||
const oldV = all.get(id)
|
||||
const oldZ = zooms.get(id)
|
||||
if (oldZ > z) {
|
||||
// The store contains more detailed information, so we ignore this part which has a lower accuraccy
|
||||
continue
|
||||
}
|
||||
if (oldZ < z) {
|
||||
// The old value has worse accuracy then what we receive now, we throw it away
|
||||
all.set(id, f)
|
||||
zooms.set(id, z)
|
||||
continue
|
||||
}
|
||||
const merged = GeoOperations.union(f, oldV)
|
||||
merged.properties = oldV.properties
|
||||
all.set(id, merged)
|
||||
zooms.set(id, z)
|
||||
}
|
||||
}
|
||||
|
||||
const newList = Array.from(all.values())
|
||||
this.features.setData(newList)
|
||||
this._featuresById.setData(all)
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue