2021-12-05 02:06:14 +01:00
|
|
|
import { SubstitutedTranslation } from "../../UI/SubstitutedTranslation"
|
|
|
|
import TagRenderingConfig from "./TagRenderingConfig"
|
|
|
|
import { ExtraFuncParams, ExtraFunctions } from "../../Logic/ExtraFunctions"
|
|
|
|
import LayerConfig from "./LayerConfig"
|
2022-11-02 14:44:06 +01:00
|
|
|
import { SpecialVisualization } from "../../UI/SpecialVisualization"
|
2021-12-05 02:06:14 +01:00
|
|
|
|
|
|
|
export default class DependencyCalculator {
|
|
|
|
public static GetTagRenderingDependencies(tr: TagRenderingConfig): string[] {
|
2022-01-26 21:40:38 +01:00
|
|
|
if (tr === undefined) {
|
2021-12-05 02:06:14 +01:00
|
|
|
throw "Got undefined tag rendering in getTagRenderingDependencies"
|
|
|
|
}
|
|
|
|
const deps: string[] = []
|
|
|
|
|
|
|
|
// All translated snippets
|
|
|
|
const parts: string[] = [].concat(...tr.EnumerateTranslations().map((tr) => tr.AllValues()))
|
|
|
|
|
|
|
|
for (const part of parts) {
|
|
|
|
const specialVizs: { func: SpecialVisualization; args: string[] }[] =
|
|
|
|
SubstitutedTranslation.ExtractSpecialComponents(part)
|
|
|
|
.map((o) => o.special)
|
|
|
|
.filter((o) => o?.func?.getLayerDependencies !== undefined)
|
|
|
|
for (const specialViz of specialVizs) {
|
|
|
|
deps.push(...specialViz.func.getLayerDependencies(specialViz.args))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return deps
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a set of all other layer-ids that this layer needs to function.
|
|
|
|
* E.g. if this layers does snap to another layer in the preset, this other layer id will be mentioned
|
|
|
|
*/
|
|
|
|
public static getLayerDependencies(
|
|
|
|
layer: LayerConfig
|
|
|
|
): { neededLayer: string; reason: string; context?: string; neededBy: string }[] {
|
|
|
|
const deps: { neededLayer: string; reason: string; context?: string; neededBy: string }[] =
|
|
|
|
[]
|
|
|
|
|
|
|
|
for (let i = 0; layer.presets !== undefined && i < layer.presets.length; i++) {
|
|
|
|
const preset = layer.presets[i]
|
|
|
|
preset.preciseInput?.snapToLayers?.forEach((id) => {
|
|
|
|
deps.push({
|
|
|
|
neededLayer: id,
|
|
|
|
reason: "a preset snaps to this layer",
|
|
|
|
context: "presets[" + i + "]",
|
|
|
|
neededBy: layer.id,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const tr of layer.AllTagRenderings()) {
|
|
|
|
for (const dep of DependencyCalculator.GetTagRenderingDependencies(tr)) {
|
|
|
|
deps.push({
|
|
|
|
neededLayer: dep,
|
|
|
|
reason: "a tagrendering needs this layer",
|
|
|
|
context: tr.id,
|
|
|
|
neededBy: layer.id,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (layer.calculatedTags?.length > 0) {
|
|
|
|
const obj = {
|
|
|
|
type: "Feature",
|
|
|
|
geometry: {
|
|
|
|
type: "Point",
|
|
|
|
coordinates: [0, 0],
|
|
|
|
},
|
|
|
|
properties: {
|
|
|
|
id: "node/1",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
let currentKey = undefined
|
|
|
|
let currentLine = undefined
|
|
|
|
const params: ExtraFuncParams = {
|
2021-12-07 17:46:57 +01:00
|
|
|
getFeatureById: (_) => undefined,
|
2021-12-05 02:06:14 +01:00
|
|
|
getFeaturesWithin: (layerId, _) => {
|
2022-01-26 21:40:38 +01:00
|
|
|
if (layerId === "*") {
|
2021-12-05 02:06:14 +01:00
|
|
|
// This is a wildcard
|
|
|
|
return []
|
|
|
|
}
|
2022-01-26 21:40:38 +01:00
|
|
|
|
2021-12-05 02:06:14 +01:00
|
|
|
// The important line: steal the dependencies!
|
|
|
|
deps.push({
|
2022-04-23 15:20:54 +02:00
|
|
|
neededLayer: layerId,
|
|
|
|
reason: "a calculated tag loads features from this layer",
|
2021-12-05 02:06:14 +01:00
|
|
|
context:
|
|
|
|
"calculatedTag[" +
|
|
|
|
currentLine +
|
|
|
|
"] which calculates the value for " +
|
|
|
|
currentKey,
|
|
|
|
neededBy: layer.id,
|
|
|
|
})
|
|
|
|
|
|
|
|
return []
|
|
|
|
},
|
|
|
|
memberships: undefined,
|
|
|
|
}
|
|
|
|
// Init the extra patched functions...
|
|
|
|
ExtraFunctions.FullPatchFeature(params, obj)
|
|
|
|
// ... Run the calculated tag code, which will trigger the getFeaturesWithin above...
|
|
|
|
for (let i = 0; i < layer.calculatedTags.length; i++) {
|
|
|
|
const [key, code] = layer.calculatedTags[i]
|
|
|
|
currentLine = i // Leak the state...
|
|
|
|
currentKey = key
|
|
|
|
try {
|
|
|
|
const func = new Function("feat", "return " + code + ";")
|
|
|
|
const result = func(obj)
|
|
|
|
obj.properties[key] = JSON.stringify(result)
|
|
|
|
} catch (e) {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return deps
|
|
|
|
}
|
|
|
|
}
|