Various fixes

This commit is contained in:
pietervdvn 2021-12-07 17:46:57 +01:00
parent 18044ff22b
commit 07fd8f404a
14 changed files with 154 additions and 60 deletions

View file

@ -10,6 +10,10 @@ export class BBox {
readonly minLat: number;
readonly minLon: number;
/***
* Coordinates should be [[lon, lat],[lon, lat]]
* @param coordinates
*/
constructor(coordinates) {
this.maxLat = -90;
this.maxLon = -180;
@ -45,6 +49,21 @@ export class BBox {
return feature.bbox;
}
static bboxAroundAll(bboxes: BBox[]): BBox{
let maxLat: number = -90;
let maxLon: number= -180;
let minLat: number= 80;
let minLon: number= 180;
for (const bbox of bboxes) {
maxLat = Math.max(maxLat, bbox.maxLat)
maxLon = Math.max(maxLon, bbox.maxLon)
minLat = Math.min(minLat, bbox.minLat)
minLon = Math.min(minLon, bbox.minLon)
}
return new BBox([[maxLon, maxLat],[minLon,minLat]])
}
static fromTile(z: number, x: number, y: number): BBox {
return new BBox(Tiles.tile_bounds_lon_lat(z, x, y))
}

View file

@ -14,6 +14,7 @@ export interface ExtraFuncParams {
*/
getFeaturesWithin: (layerId: string, bbox: BBox) => any[][],
memberships: RelationsTracker
getFeatureById: (id:string) => any
}
/**
@ -79,20 +80,19 @@ class DistanceToFunc implements ExtraFunction {
}
if (typeof arg0 === "number") {
// Feature._lon and ._lat is conveniently place by one of the other metatags
return GeoOperations.distanceBetween([arg0, lat], [feature._lon, feature._lat]);
return GeoOperations.distanceBetween([arg0, lat], GeoOperations.centerpointCoordinates(feature));
}
if (typeof arg0 === "string") {
// This is an identifier
// TODO FIXME
const feature = undefined // State.state.allElements.ContainingFeatures.get(arg0);
const feature = featuresPerLayer.getFeatureById(arg0)
if (feature === undefined) {
return undefined;
}
arg0 = feature;
}
// arg0 is probably a feature
return GeoOperations.distanceBetween(GeoOperations.centerpointCoordinates(arg0), [feature._lon, feature._lat])
// arg0 is probably a geojsonfeature
return GeoOperations.distanceBetween(GeoOperations.centerpointCoordinates(arg0), GeoOperations.centerpointCoordinates(feature))
}
}

View file

@ -448,11 +448,12 @@ export default class FeaturePipeline {
window.setTimeout(
() => {
const layerDef = src.layer.layerDef;
const somethingChanged = MetaTagging.addMetatags(
MetaTagging.addMetatags(
src.features.data,
{
memberships: this.relationTracker,
getFeaturesWithin: (layerId, bbox: BBox) => self.GetFeaturesWithin(layerId, bbox)
getFeaturesWithin: (layerId, bbox: BBox) => self.GetFeaturesWithin(layerId, bbox),
getFeatureById: (id:string) => self.state.allElements.ContainingFeatures.get(id)
},
layerDef,
{

View file

@ -178,8 +178,6 @@ export default class MetaTagging {
try {
const functions = MetaTagging.createFunctionsForFeature(layer.id, calculatedTags)
ExtraFunctions.FullPatchFeature(params, feature);
for (const f of functions) {
f(feature);

View file

@ -8,6 +8,7 @@ import {UIEventSource} from "../UIEventSource";
import MapState from "./MapState";
import SelectedFeatureHandler from "../Actors/SelectedFeatureHandler";
import Hash from "../Web/Hash";
import {BBox} from "../BBox";
export default class FeaturePipelineState extends MapState {
@ -29,6 +30,8 @@ export default class FeaturePipelineState extends MapState {
clusterCounter.addTile(source)
const sourceBBox = source.features.map(allFeatures => BBox.bboxAroundAll(allFeatures.map(f => BBox.get(f.feature))))
// Do show features indicates if the 'showDataLayer' should be shown
const doShowFeatures = source.features.map(
f => {
@ -44,7 +47,7 @@ export default class FeaturePipelineState extends MapState {
return false;
}
if (!source.bbox.overlapsWith(bounds)) {
if (!sourceBBox.data.overlapsWith(bounds)) {
// Not within range -> features are hidden
return false
}
@ -81,7 +84,7 @@ export default class FeaturePipelineState extends MapState {
return true
}, [this.currentBounds, source.layer.isDisplayed]
}, [this.currentBounds, source.layer.isDisplayed, sourceBBox]
)
new ShowDataLayer(

View file

@ -2,7 +2,7 @@ import {Utils} from "../Utils";
export default class Constants {
public static vNumber = "0.13.0-alpha-2";
public static vNumber = "0.13.0-alpha-3";
public static ImgurApiKey = '7070e7167f0a25a'
public static readonly mapillary_client_token_v4 = "MLY|4441509239301885|b40ad2d3ea105435bd40c7e76993ae85"

View file

@ -71,6 +71,7 @@ export default class DependencyCalculator {
let currentKey = undefined
let currentLine = undefined
const params: ExtraFuncParams = {
getFeatureById: _ => undefined,
getFeaturesWithin: (layerId, _) => {
if(layerId === '*'){

View file

@ -219,7 +219,7 @@ export interface LayoutConfigJson {
* If clustering is defined, defaults to 25
*/
minNeededElements?: number
},
} | false,
/**
* The URL of a custom CSS stylesheet to modify the layout

View file

@ -5,9 +5,9 @@ export default class SourceConfig {
public readonly osmTags?: TagsFilter;
public readonly overpassScript?: string;
public readonly geojsonSource?: string;
public readonly geojsonZoomLevel?: number;
public readonly isOsmCacheLayer: boolean;
public geojsonSource?: string;
public geojsonZoomLevel?: number;
public isOsmCacheLayer: boolean;
public readonly mercatorCrs: boolean;
constructor(params: {

View file

@ -212,7 +212,7 @@ Note that these values can be prepare with javascript in the theme by using a [c
}
if(v.InnerConstructElement !== undefined){
console.warn("SubstituteKeys received a BaseUIElement to substitute in - this is probably a bug and will be downcast to a string", v)
console.warn("SubstituteKeys received a BaseUIElement to substitute in - this is probably a bug and will be downcast to a string\nThe key is", key,"\nThe value is", v)
v = ( <HTMLElement> v.InnerConstructElement())?.innerText
}

View file

@ -0,0 +1,12 @@
[
{
"path": "townhall.svg",
"license": "CC0",
"authors": [
"Nebulon42"
],
"sources": [
"https://wiki.openstreetmap.org/wiki/File:Town-hall-16.svg"
]
}
]

View file

@ -13,7 +13,7 @@
"en"
],
"maintainer": "",
"icon": "./assets/svg/bug.svg",
"icon": "./assets/themes/postal_codes/townhall.svg",
"version": "0",
"startLat": 0,
"startLon": 0,
@ -21,13 +21,15 @@
"widenFactor": 0.05,
"socialImage": "",
"hideFromOverview": true,
"clustering": false,
"overpassTimeout": 180,
"layers": [
{
"id": "postal_codes",
"id": "postal_code_boundary",
"name": {
"en": "postal codes"
},
"minzoom": 12,
"minzoom": 8,
"title": {
"render": {
"en": "Postal code {postal_code}"
@ -42,11 +44,7 @@
}
}
],
"presets": [],
"source": {
"isOsmCache": true,
"geoJson": "http://127.0.0.1:8080/postal_codes_postal_codes_{z}_{x}_{y}.geojson",
"geoJsonZoomLevel": 1,
"osmTags": {
"or": [
"boundary=postal_code",
@ -61,12 +59,7 @@
},
"mapRendering": [
{
"icon": {
"render": "./assets/svg/bug.svg"
},
"iconSize": {
"render": "40,40,center"
},
"label": "<div class='text-xl bg-white rounded-full pl-2 pr-2 break-normal'>{postal_code}</div>",
"location": [
"point",
"centroid"
@ -77,8 +70,10 @@
"render": "#00f"
},
"width": {
"render": "8"
}
"render": "4"
},
"fill": "no",
"dashArray": "8 8"
}
],
"isShown": {
@ -90,34 +85,30 @@
}
},
{
"id": "town_halls",
"id": "town_hall",
"name": {
"en": "town halls"
},
"minzoom": 12,
"title": {
"render": {
"en": "Town halls"
"en": "Town hall {name}"
}
},
"calculatedTags": [
"_postal_code=feat.overlapWith('postal_codes')[0]?.feat?.properties?.postal_code"
],
"_postal_code_properties=(() => { const f = feat.overlapWith('postal_code_boundary'); if(f.length===0){return {};}; const p = f[0]?.feat?.properties; return {id:p.id, postal_code: p.postal_code, _closest_town_hall: p._closest_town_hall}; })()",
"_postal_code=feat.get('_postal_code_properties')?.postal_code",
"_postal_code_center_distance=feat.distanceTo(feat.get('_postal_code_properties').id)"
],
"description": {},
"tagRenderings": [
],
"presets": [],
"source": {
"isOsmCache": true,
"geoJson": "http://127.0.0.1:8080/postal_codes_town_hall_{z}_{x}_{y}.geojson",
"geoJsonZoomLevel": 1,
"osmTags": "amenity=townhall"
},
"mapRendering": [
{
"icon": {
"render": "./assets/svg/bug.svg"
},
{ "icon": "./assets/themes/postal_codes/townhall.svg",
"iconSize": {
"render": "40,40,center"
},
@ -125,14 +116,6 @@
"point",
"centroid"
]
},
{
"color": {
"render": "#00f"
},
"width": {
"render": "8"
}
}
],
"isShown": {

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width="16"
height="16"
viewBox="0 0 16 16"
id="svg2">
<metadata id="metadata8">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title/>
</cc:Work>
</rdf:RDF>
</metadata>
<defs id="defs6"/>
<rect width="16" height="16" x="0" y="0" id="canvas" style="fill:none;stroke:none;visibility:hidden"/>
<path d="M 7,0 C 6.75,0.0032 6.5,0.1644239 6.5,0.5 L 6.5,4.375 1,7 13,7 7.5,4.375 7.5,0.5 C 7.5,0.1516409 7.25,-0.0031957 7,0 z M 8,0 8,3 12,3 10,1.5 12,0 z m -7,8 0,1 1,0 0,4 -1,0 0,1 12,0 0,-1 -1,0 0,-4 1,0 0,-1 z m 6,1.5 c 1,0 2,0.5 2,1.5 l 0,2 -4,0 0,-2 C 5,10 6,9.5 7,9.5 z" id="town-hall" style="fill:#734a08;fill-opacity:1;stroke:none" transform="translate(1,1)"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -24,7 +24,6 @@ import {GeoOperations} from "../Logic/GeoOperations";
import SimpleMetaTaggers from "../Logic/SimpleMetaTagger";
import FilteringFeatureSource from "../Logic/FeatureSource/Sources/FilteringFeatureSource";
import Loc from "../Models/Loc";
ScriptUtils.fixUtils()
@ -181,6 +180,23 @@ function loadAllTiles(targetdir: string, r: TileRange, theme: LayoutConfig, extr
function sliceToTiles(allFeatures: FeatureSource, theme: LayoutConfig, relationsTracker: RelationsTracker, targetdir: string, pointsOnlyLayers: string[]) {
const skippedLayers = new Set<string>()
const indexedFeatures : Map<string, any> = new Map<string, any>()
let indexisBuilt = false;
function buildIndex(){
for (const ff of allFeatures.features.data) {
const f = ff.feature
indexedFeatures.set(f.properties.id, f)
}
indexisBuilt = true;
}
function getFeatureById(id){
if(!indexisBuilt){
buildIndex()
}
return indexedFeatures.get(id)
}
async function handleLayer(source: FeatureSourceForLayer) {
const layer = source.layer.layerDef;
const targetZoomLevel = layer.source.geojsonZoomLevel ?? 0
@ -199,7 +215,8 @@ function sliceToTiles(allFeatures: FeatureSource, theme: LayoutConfig, relations
memberships: relationsTracker,
getFeaturesWithin: _ => {
return [allFeatures.features.data.map(f => f.feature)]
}
},
getFeatureById: getFeatureById
},
layer,
{
@ -237,6 +254,7 @@ function sliceToTiles(allFeatures: FeatureSource, theme: LayoutConfig, relations
new UIEventSource<any>(undefined)
)
console.log("Tile "+layer.id+"."+tileIndex+" contains "+filteredTile.features.data.length+" features after filtering ("+tile.features.data.length+") features before")
if (filteredTile.features.data.length === 0) {
return
}
@ -252,7 +270,7 @@ function sliceToTiles(allFeatures: FeatureSource, theme: LayoutConfig, relations
const calculatedTagKeys = tile.layer.layerDef.calculatedTags.map(ct => ct[0])
featureCount++
for (const calculatedTagKey of calculatedTagKeys) {
const strict = feature.feature.properties[calculatedTagKey]
const strict = feature.feature.properties[calculatedTagKey]
feature.feature.properties[calculatedTagKey] =strict
strictlyCalculated ++;
if(strictlyCalculated % 100 === 0){
@ -292,7 +310,18 @@ function sliceToTiles(allFeatures: FeatureSource, theme: LayoutConfig, relations
// And, if needed, to create a points-only layer
if (pointsOnlyLayers.indexOf(layer.id) >= 0) {
const features = source.features.data.map(f => f.feature)
const filtered = new FilteringFeatureSource({
locationControl: new UIEventSource<Loc>(undefined),
allElements: undefined,
selectedElement: new UIEventSource<any>(undefined)
},
Tiles.tile_index(0,0,0),
source,
new UIEventSource<any>(undefined)
)
const features = filtered.features.data.map(f => f.feature)
const points = features.map(feature => GeoOperations.centerpoint(feature))
console.log("Writing points overview for ", layerId)
const targetPath = targetdir + "_" + layerId + "_points.geojson"
@ -325,7 +354,7 @@ async function main(args: string[]) {
console.log("Cache builder started with args ", args.join(", "))
if (args.length < 6) {
console.error("Expected arguments are: theme zoomlevel targetdirectory lat0 lon0 lat1 lon1 [--generate-point-overview layer-name,layer-name,...]\n" +
console.error("Expected arguments are: theme zoomlevel targetdirectory lat0 lon0 lat1 lon1 [--generate-point-overview layer-name,layer-name,...] [--force-zoom-level z] \n" +
"Note: a new directory named <theme> will be created in targetdirectory")
return;
}
@ -343,10 +372,7 @@ async function main(args: string[]) {
const lat1 = Number(args[5])
const lon1 = Number(args[6])
let generatePointLayersFor = []
if (args[7] == "--generate-point-overview") {
generatePointLayersFor = args[8].split(",")
}
const tileRange = Tiles.TileRangeBetween(zoomlevel, lat0, lon0, lat1, lon1)
@ -365,6 +391,32 @@ async function main(args: string[]) {
console.error("The theme " + theme + " was not found; try one of ", keys);
return
}
let generatePointLayersFor = []
if (args[7] == "--generate-point-overview") {
if(args[8] === undefined){
throw "--generate-point-overview needs a list of layers to generate the overview for (or * for all)"
}else if (args[8] === '*'){
generatePointLayersFor = theme.layers.map(l => l.id)
}else{
generatePointLayersFor = args[8].split(",")
}
console.log("Also generating a point overview for layers ", generatePointLayersFor.join(","))
}
{
const index = args.indexOf("--force-zoom-level")
if(index >= 0){
const forcedZoomLevel = Number(args[index + 1])
for (const layer of theme.layers) {
layer.source.geojsonSource = "https://127.0.0.1/cache_{layer}_{z}_{x}_{y}.geojson"
layer.source.isOsmCacheLayer = true
layer.source.geojsonZoomLevel = forcedZoomLevel
}
}
}
const relationTracker = new RelationsTracker()
let failed = 0;