Add 'steal' as special rendering, update 'multi', add entrance overview to onwheels layer
This commit is contained in:
parent
181c5583d2
commit
7e32413113
11 changed files with 462 additions and 73 deletions
|
@ -13,9 +13,9 @@ export interface ExtraFuncParams {
|
|||
* Note that more features then requested can be given back.
|
||||
* Format: [ [ geojson, geojson, geojson, ... ], [geojson, ...], ...]
|
||||
*/
|
||||
getFeaturesWithin: (layerId: string, bbox: BBox) => Feature<Geometry, {id: string}>[][],
|
||||
getFeaturesWithin: (layerId: string, bbox: BBox) => Feature<Geometry, { id: string }>[][],
|
||||
memberships: RelationsTracker
|
||||
getFeatureById: (id: string) => Feature<Geometry, {id: string}>
|
||||
getFeatureById: (id: string) => Feature<Geometry, { id: string }>
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -31,10 +31,11 @@ interface ExtraFunction {
|
|||
|
||||
class EnclosingFunc implements ExtraFunction {
|
||||
_name = "enclosingFeatures"
|
||||
_doc = ["Gives a list of all features in the specified layers which fully contain this object. Returned features will always be (multi)polygons. (LineStrings and Points from the other layers are ignored)","",
|
||||
_doc = ["Gives a list of all features in the specified layers which fully contain this object. Returned features will always be (multi)polygons. (LineStrings and Points from the other layers are ignored)", "",
|
||||
"The result is a list of features: `{feat: Polygon}[]`",
|
||||
"This function will never return the feature itself."].join("\n")
|
||||
"This function will never return the feature itself."].join("\n")
|
||||
_args = ["...layerIds - one or more layer ids of the layer from which every feature is checked for overlap)"]
|
||||
|
||||
_f(params: ExtraFuncParams, feat: Feature<Geometry, any>) {
|
||||
return (...layerIds: string[]) => {
|
||||
const result: { feat: any }[] = []
|
||||
|
@ -51,14 +52,14 @@ class EnclosingFunc implements ExtraFunction {
|
|||
}
|
||||
for (const otherFeatures of otherFeaturess) {
|
||||
for (const otherFeature of otherFeatures) {
|
||||
if(seenIds.has(otherFeature.properties.id)){
|
||||
if (seenIds.has(otherFeature.properties.id)) {
|
||||
continue
|
||||
}
|
||||
seenIds.add(otherFeature.properties.id)
|
||||
if(otherFeature.geometry.type !== "Polygon" && otherFeature.geometry.type !== "MultiPolygon"){
|
||||
if (otherFeature.geometry.type !== "Polygon" && otherFeature.geometry.type !== "MultiPolygon") {
|
||||
continue;
|
||||
}
|
||||
if(GeoOperations.completelyWithin(feat, <Feature<Polygon | MultiPolygon, any>> otherFeature)){
|
||||
if (GeoOperations.completelyWithin(feat, <Feature<Polygon | MultiPolygon, any>>otherFeature)) {
|
||||
result.push({feat: otherFeature})
|
||||
}
|
||||
}
|
||||
|
@ -75,10 +76,10 @@ class OverlapFunc implements ExtraFunction {
|
|||
|
||||
_name = "overlapWith";
|
||||
_doc = ["Gives a list of features from the specified layer which this feature (partly) overlaps with. A point which is embedded in the feature is detected as well.",
|
||||
"If the current feature is a point, all features that this point is embeded in are given." ,
|
||||
"If the current feature is a point, all features that this point is embeded in are given.",
|
||||
"",
|
||||
"The returned value is `{ feat: GeoJSONFeature, overlap: number}[]` where `overlap` is the overlapping surface are (in m²) for areas, the overlapping length (in meter) if the current feature is a line or `undefined` if the current feature is a point." ,
|
||||
"The resulting list is sorted in descending order by overlap. The feature with the most overlap will thus be the first in the list." ,
|
||||
"The returned value is `{ feat: GeoJSONFeature, overlap: number}[]` where `overlap` is the overlapping surface are (in m²) for areas, the overlapping length (in meter) if the current feature is a line or `undefined` if the current feature is a point.",
|
||||
"The resulting list is sorted in descending order by overlap. The feature with the most overlap will thus be the first in the list.",
|
||||
"",
|
||||
"For example to get all objects which overlap or embed from a layer, use `_contained_climbing_routes_properties=feat.overlapWith('climbing_route')`",
|
||||
"",
|
||||
|
@ -89,6 +90,7 @@ class OverlapFunc implements ExtraFunction {
|
|||
_f(params, feat) {
|
||||
return (...layerIds: string[]) => {
|
||||
const result: { feat: any, overlap: number }[] = []
|
||||
const seenIds = new Set<string>()
|
||||
const bbox = BBox.get(feat)
|
||||
for (const layerId of layerIds) {
|
||||
const otherFeaturess = params.getFeaturesWithin(layerId, bbox)
|
||||
|
@ -99,12 +101,18 @@ class OverlapFunc implements ExtraFunction {
|
|||
continue;
|
||||
}
|
||||
for (const otherFeatures of otherFeaturess) {
|
||||
result.push(...GeoOperations.calculateOverlap(feat, otherFeatures));
|
||||
const overlap = GeoOperations.calculateOverlap(feat, otherFeatures)
|
||||
for (const overlappingFeature of overlap) {
|
||||
if(seenIds.has(overlappingFeature.feat.properties.id)){
|
||||
continue
|
||||
}
|
||||
seenIds.add(overlappingFeature.feat.properties.id)
|
||||
result.push(overlappingFeature)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.sort((a, b) => b.overlap - a.overlap)
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ export default class MetaTagging {
|
|||
return;
|
||||
}
|
||||
|
||||
console.log("Recalculating metatags...")
|
||||
const metatagsToApply: SimpleMetaTagger[] = []
|
||||
for (const metatag of SimpleMetaTaggers.metatags) {
|
||||
if (metatag.includesDates) {
|
||||
|
|
|
@ -93,7 +93,7 @@ export default class CreateNewNodeAction extends OsmCreateAction {
|
|||
|
||||
|
||||
// Project the point onto the way
|
||||
|
||||
console.log("Snapping a node onto an existing way...")
|
||||
const geojson = this._snapOnto.asGeoJson()
|
||||
const projected = GeoOperations.nearestPoint(geojson, [this._lon, this._lat])
|
||||
const projectedCoor= <[number, number]>projected.geometry.coordinates
|
||||
|
|
|
@ -219,6 +219,9 @@ export abstract class OsmObject {
|
|||
|
||||
/**
|
||||
* Uses the list of polygon features to determine if the given tags are a polygon or not.
|
||||
*
|
||||
* OsmObject.isPolygon({"building":"yes"}) // => true
|
||||
* OsmObject.isPolygon({"highway":"residential"}) // => false
|
||||
* */
|
||||
protected static isPolygon(tags: any): boolean {
|
||||
for (const tagsKey in tags) {
|
||||
|
|
|
@ -378,6 +378,25 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> {
|
|||
* const errors = []
|
||||
* RewriteSpecial.convertIfNeeded({"special": {}}, errors, "test") // => undefined
|
||||
* errors // => ["A 'special'-block should define 'type' to indicate which visualisation should be used"]
|
||||
*
|
||||
*
|
||||
* // an actual test
|
||||
* const special = {"special": {
|
||||
* "type": "multi",
|
||||
* "before": {
|
||||
* "en": "<h3>Entrances</h3>This building has {_entrances_count} entrances:"
|
||||
* },
|
||||
* "after": {
|
||||
* "en": "{_entrances_count_without_width_count} entrances don't have width information yet"
|
||||
* },
|
||||
* "key": "_entrance_properties_with_width",
|
||||
* "tagrendering": {
|
||||
* "en": "An <a href='#{id}'>entrance</a> of {canonical(width)}"
|
||||
* }
|
||||
* }}
|
||||
* const errors = []
|
||||
* RewriteSpecial.convertIfNeeded(special, errors, "test") // => {"en": "<h3>Entrances</h3>This building has {_entrances_count} entrances: {multi(_entrance_properties_with_width,An <a href='#&LBRACEid&RBRACE'>entrance</a> of &LBRACEcanonical&LPARENSwidth&RPARENS&RBRACE)}An <a href='#{id}'>entrance</a> of {canonical(width)}"}
|
||||
* errors // => []
|
||||
*/
|
||||
private static convertIfNeeded(input: (object & { special: { type: string } }) | any, errors: string[], context: string): any {
|
||||
const special = input["special"]
|
||||
|
@ -385,10 +404,6 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> {
|
|||
return input
|
||||
}
|
||||
|
||||
for (const wrongKey of Object.keys(input).filter(k => k !== "special" && k !== "before" && k !== "after")) {
|
||||
errors.push(`At ${context}: Unexpected key in a special block: ${wrongKey}`)
|
||||
}
|
||||
|
||||
const type = special["type"]
|
||||
if (type === undefined) {
|
||||
errors.push("A 'special'-block should define 'type' to indicate which visualisation should be used")
|
||||
|
@ -406,10 +421,10 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> {
|
|||
// Check for obsolete and misspelled arguments
|
||||
errors.push(...Object.keys(special)
|
||||
.filter(k => !argNames.has(k))
|
||||
.filter(k => k !== "type")
|
||||
.filter(k => k !== "type" && k !== "before" && k !== "after")
|
||||
.map(wrongArg => {
|
||||
const byDistance = Utils.sortedByLevenshteinDistance(wrongArg, argNamesList, x => x)
|
||||
return `Unexpected argument with name '${wrongArg}'. Did you mean ${byDistance[0]}?\n\tAll known arguments are ${argNamesList.join(", ")}`;
|
||||
return `Unexpected argument in special block at ${context} with name '${wrongArg}'. Did you mean ${byDistance[0]}?\n\tAll known arguments are ${argNamesList.join(", ")}`;
|
||||
}))
|
||||
|
||||
// Check that all obligated arguments are present. They are obligated if they don't have a preset value
|
||||
|
@ -496,12 +511,21 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> {
|
|||
* const expected = {render: {'*': "{image_carousel(image)}"}, mappings: [{if: "other_image_key", then: {'*': "{image_carousel(other_image_key)}"}} ]}
|
||||
* result // => expected
|
||||
*
|
||||
* // Should put text before if specified
|
||||
* const tr = {
|
||||
* render: {special: {type: "image_carousel", image_key: "image"}, before: {en: "Some introduction"} },
|
||||
* }
|
||||
* const result = new RewriteSpecial().convert(tr,"test").result
|
||||
* const expected = {render: {'en': "Some introduction{image_carousel(image)}"}}
|
||||
* result // => expected
|
||||
*
|
||||
* // Should put text after if specified
|
||||
* const tr = {
|
||||
* render: {special: {type: "image_carousel", image_key: "image"}, after: {en: "Some footer"} },
|
||||
* }
|
||||
* const result = new RewriteSpecial().convert(tr,"test").result
|
||||
* const expected = {render: {'en': "{image_carousel(image)}Some footer"}}
|
||||
* result // => expected
|
||||
*/
|
||||
convert(json: TagRenderingConfigJson, context: string): { result: TagRenderingConfigJson; errors?: string[]; warnings?: string[]; information?: string[] } {
|
||||
const errors = []
|
||||
|
|
|
@ -42,7 +42,6 @@ import NoteCommentElement from "./Popup/NoteCommentElement";
|
|||
import ImgurUploader from "../Logic/ImageProviders/ImgurUploader";
|
||||
import FileSelectorButton from "./Input/FileSelectorButton";
|
||||
import {LoginToggle} from "./Popup/LoginButton";
|
||||
import {start} from "repl";
|
||||
import {SubstitutedTranslation} from "./SubstitutedTranslation";
|
||||
import {TextField} from "./Input/TextField";
|
||||
import Wikidata, {WikidataResponse} from "../Logic/Web/Wikidata";
|
||||
|
@ -60,7 +59,8 @@ import Slider from "./Input/Slider";
|
|||
import List from "./Base/List";
|
||||
import StatisticsPanel from "./BigComponents/StatisticsPanel";
|
||||
import {OsmFeature} from "../Models/OsmFeature";
|
||||
import Link from "./Base/Link";
|
||||
import EditableTagRendering from "./Popup/EditableTagRendering";
|
||||
import TagRenderingConfig from "../Models/ThemeConfig/TagRenderingConfig";
|
||||
|
||||
export interface SpecialVisualization {
|
||||
funcName: string,
|
||||
|
@ -334,6 +334,13 @@ export default class SpecialVisualizations {
|
|||
render: {
|
||||
special: {
|
||||
type: "some_special_visualisation",
|
||||
before: {
|
||||
en: "Some text to prefix before the special element (e.g. a title)",
|
||||
nl: "Een tekst om voor het element te zetten (bv. een titel)"
|
||||
},
|
||||
after: {
|
||||
en: "Some text to put after the element, e.g. a footer"
|
||||
},
|
||||
"argname": "some_arg",
|
||||
"message": {
|
||||
en: "some other really long message",
|
||||
|
@ -1206,7 +1213,7 @@ export default class SpecialVisualizations {
|
|||
{
|
||||
funcName: "multi",
|
||||
docs: "Given an embedded tagRendering (read only) and a key, will read the keyname as a JSON-list. Every element of this list will be considered as tags and rendered with the tagRendering",
|
||||
example: "```json\n"+JSON.stringify({
|
||||
example: "```json\n" + JSON.stringify({
|
||||
render: {
|
||||
special: {
|
||||
type: "multi",
|
||||
|
@ -1216,20 +1223,81 @@ export default class SpecialVisualizations {
|
|||
}
|
||||
}
|
||||
}
|
||||
}, null, " ")+"```",
|
||||
}, null, " ") + "```",
|
||||
args: [
|
||||
{name: "key",
|
||||
doc: "The property to read and to interpret as a list of properties"},
|
||||
{
|
||||
name:"tagrendering",
|
||||
doc: "An entire tagRenderingConfig"
|
||||
name: "key",
|
||||
doc: "The property to read and to interpret as a list of properties",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: "tagrendering",
|
||||
doc: "An entire tagRenderingConfig",
|
||||
required: true
|
||||
}
|
||||
]
|
||||
,
|
||||
,
|
||||
constr(state, featureTags, args) {
|
||||
const [key, tr] = args
|
||||
console.log("MULTI: ", key, tr)
|
||||
return undefined
|
||||
const translation = new Translation({"*": tr})
|
||||
return new VariableUiElement(featureTags.map(tags => {
|
||||
const properties: object[] = JSON.parse(tags[key])
|
||||
const elements = []
|
||||
for (const property of properties) {
|
||||
const subsTr = new SubstitutedTranslation(translation, new UIEventSource<any>(property), state)
|
||||
elements.push(subsTr)
|
||||
}
|
||||
return new List(elements)
|
||||
}))
|
||||
}
|
||||
},
|
||||
{
|
||||
funcName: "steal",
|
||||
docs: "Shows a tagRendering from a different object as if this was the object itself",
|
||||
args: [{
|
||||
name: "featureId",
|
||||
doc: "The key of the attribute which contains the id of the feature from which to use the tags",
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: "tagRenderingId",
|
||||
doc: "The layer-id and tagRenderingId to render. Can be multiple value if ';'-separated (in which case every value must also contain the layerId, e.g. `layerId.tagRendering0; layerId.tagRendering1`). Note: this can cause layer injection",
|
||||
required: true
|
||||
}],
|
||||
constr(state, featureTags, args) {
|
||||
const [featureIdKey, layerAndtagRenderingIds] = args
|
||||
const tagRenderings: [LayerConfig, TagRenderingConfig][] = []
|
||||
for (const layerAndTagRenderingId of layerAndtagRenderingIds.split(";")) {
|
||||
const [layerId, tagRenderingId] = layerAndTagRenderingId.trim().split(".")
|
||||
const layer = state.layoutToUse.layers.find(l => l.id === layerId)
|
||||
const tagRendering = layer.tagRenderings.find(tr => tr.id === tagRenderingId)
|
||||
tagRenderings.push([layer, tagRendering])
|
||||
}
|
||||
return new VariableUiElement(featureTags.map(tags => {
|
||||
const featureId = tags[featureIdKey]
|
||||
if (featureId === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
const otherTags = state.allElements.getEventSourceById(featureId)
|
||||
const elements: BaseUIElement[] = []
|
||||
for (const [layer, tagRendering] of tagRenderings) {
|
||||
const el = new EditableTagRendering(otherTags, tagRendering, layer.units, state, {})
|
||||
elements.push(el)
|
||||
}
|
||||
if (elements.length === 1) {
|
||||
return elements[0]
|
||||
}
|
||||
return new Combine(elements).SetClass("flex flex-col");
|
||||
}))
|
||||
},
|
||||
|
||||
getLayerDependencies(args): string[] {
|
||||
const [_, tagRenderingId] = args
|
||||
if (tagRenderingId.indexOf(".") < 0) {
|
||||
throw "Error: argument 'layerId.tagRenderingId' of special visualisation 'steal' should contain a dot"
|
||||
}
|
||||
const [layerId, __] = tagRenderingId.split(".")
|
||||
return [layerId]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -47,33 +47,84 @@
|
|||
}
|
||||
],
|
||||
"calculatedTags": [
|
||||
"_entrance_properties=feat.overlapWith('entrance')?.map(e => e.feat.properties).filter(p => p !== undefined).filter(p => p.width !== undefined)",
|
||||
"_entrance:id=feat.get('_entrance_properties')?.map(e => e.id)?.at(0)",
|
||||
"_entrance:width=feat.get('_entrance_properties')?.map(e => e.width)?.at(0)"
|
||||
"_entrance_properties=feat.overlapWith('entrance')?.map(e => e.feat.properties)?.filter(p => p !== undefined && p.indoor !== 'door')",
|
||||
"_entrance_properties_with_width=feat.get('_entrance_properties')?.filter(p => p['width'] !== undefined)",
|
||||
"_entrances_count=feat.get('_entrance_properties').length",
|
||||
"_entrances_count_without_width_count= feat.get('_entrances_count') - feat.get('_entrance_properties_with_width').length",
|
||||
"_biggest_width= Math.max( feat.get('_entrance_properties').map(p => p.width))",
|
||||
"_biggest_width_properties= /* Can be a list! */ feat.get('_entrance_properties').filter(p => p.width === feat.get('_biggest_width'))",
|
||||
"_biggest_width_id=feat.get('_biggest_width_properties').id"
|
||||
],
|
||||
"tagRenderings": [
|
||||
"units": [
|
||||
{
|
||||
"id": "_entrance:width",
|
||||
"render": {
|
||||
"en": "<a href ='#{_entrance:id} '>This door has a width of {canonical(_entrance:width)} meters </a>",
|
||||
"nl": "<a href ='#{_entrance:id} '>Deze deur heeft een breedte van {canonical(_entrance:width)} meter </a>",
|
||||
"de": "<a href ='#{_entrance:id} '>Diese Tür hat eine Durchgangsbreite von {canonical(_entrance:width)} Meter </a>",
|
||||
"es": "<a href ='#{_entrance:id} '>Esta puerta tiene una ancho de {canonical(_entrance:width)} metros </a>",
|
||||
"fr": "<a href ='#{_entrance:id} '>Cette porte a une largeur de {canonical(_entrance:width)} mètres </a>"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "_entrance:width"
|
||||
},
|
||||
"mappings": [
|
||||
"appliesToKey": [
|
||||
"width","_biggest_width"
|
||||
],
|
||||
"applicableUnits": [
|
||||
{
|
||||
"if": "_entrance:width=",
|
||||
"then": {
|
||||
"en": "This entrance has no width information",
|
||||
"de": "Der Eingang hat keine Informationen zur Durchgangsbreite",
|
||||
"fr": "Cette entrée n'a pas d'informations sur sa largeur"
|
||||
"canonicalDenomination": "m",
|
||||
"alternativeDenomination": [
|
||||
"meter"
|
||||
],
|
||||
"human": {
|
||||
"en": "meter",
|
||||
"fr": "mètre",
|
||||
"de": "Meter"
|
||||
}
|
||||
},
|
||||
{
|
||||
"default": true,
|
||||
"canonicalDenomination": "cm",
|
||||
"alternativeDenomination": [
|
||||
"centimeter",
|
||||
"cms"
|
||||
],
|
||||
"human": {
|
||||
"en": "centimeter",
|
||||
"fr": "centimètre",
|
||||
"de": "Zentimeter"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tagRenderings": [
|
||||
{
|
||||
"id": "entrance_info",
|
||||
"render": {
|
||||
"before": {
|
||||
"en": "<h3>Entrances</h3>This building has {_entrances_count} entrances:"
|
||||
},
|
||||
"after": {
|
||||
"en": "{_entrances_count_without_width_count} entrances don't have width information yet"
|
||||
},
|
||||
"special": {
|
||||
"type": "multi",
|
||||
"key": "_entrance_properties_with_width",
|
||||
"tagrendering": {
|
||||
"en": "An <a href='#{id}'>entrance</a> of {canonical(width)}"
|
||||
}
|
||||
}
|
||||
},
|
||||
"mappings": [
|
||||
{
|
||||
"if": "_entrances_count=0",
|
||||
"then": {
|
||||
"en": "No entrance has been marked"
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": "_entrances_count_without_width:=_entrances_count",
|
||||
"then": {
|
||||
"en": "None of the {_entrance_count} entrances have width information yet"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "biggest_width",
|
||||
"render": "The <a href='#{_biggest_width_id}'>entrance with the biggest width</a> is {canonical(_biggest_width)} wide",
|
||||
"condition": "_biggest_width_id~*"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -17,6 +17,12 @@
|
|||
"startZoom": 14,
|
||||
"widenFactor": 2,
|
||||
"layers": [
|
||||
"indoors"
|
||||
"indoors",
|
||||
{
|
||||
"builtin": ["walls_and_buildings"],
|
||||
"override": {
|
||||
"shownByDefault": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -366,15 +366,11 @@
|
|||
],
|
||||
"overrideAll": {
|
||||
"+calculatedTags": [
|
||||
"_poi_walls_and_buildings_entrance_properties=[].concat(...feat.closestn('walls_and_buildings',1, undefined, 500).map(w => ({id: w.feat.properties.id, width: w.feat.properties['_entrance_properties']})))",
|
||||
"_poi_walls_and_buildings_entrance_count=[].concat(...feat.overlapWith('walls_and_buildings').map(w => ({id: w.feat.properties.id, width: w.feat.properties['_entrance_properties']})))",
|
||||
"_poi_walls_and_buildings_entrance_properties_with_width=feat.get('_poi_walls_and_buildings_entrance_properties').filter(p => p['width'] !== undefined)",
|
||||
"_poi_entrance:id=JSON.parse(feat.properties._poi_walls_and_buildings_entrance_properteis)?.id",
|
||||
"_poi_entrance:width=JSON.parse(feat.properties._poi_walls_and_buildings_entrance_properties)?.width"
|
||||
"_enclosing_building=feat.enclosingFeatures('walls_and_buildings')?.map(f => f.feat.properties.id)?.at(0)"
|
||||
],
|
||||
"+tagRenderings": [
|
||||
"tagRenderings+": [
|
||||
{
|
||||
"id": "_containing_poi_entrance:width",
|
||||
"id": "_stolen_entrances",
|
||||
"condition": {
|
||||
"and": [
|
||||
"entrance=",
|
||||
|
@ -383,21 +379,11 @@
|
|||
"door="
|
||||
]
|
||||
},
|
||||
"mappings": [{
|
||||
"if": "_poi_walls_and_buildings_entrance_properties_with_width=[]",
|
||||
"then": {
|
||||
"en": "The containing building has {}"
|
||||
}
|
||||
}],
|
||||
"render": {
|
||||
"special": {
|
||||
"type": "multi",
|
||||
"key": "_poi_walls_and_buildings_entrance_properties",
|
||||
"tagrendering": {
|
||||
"en": "The containing building can be entered via <a href='#{_poi_entrance:id}'>a door of {canonical(_poi_entrance:width)}</a>",
|
||||
"fr": "On peut entrer dans ce batiment via <a href='#{_poi_entrance:id}'>une porte de {canonical(_poi_entrance:width)}</a>",
|
||||
"de": "Das Gebäude kann über <a href='#{_poi_entrance:id}'>durch eine Tür von {canonical(_poi_entrance:width)} betreten werden.</a>"
|
||||
}
|
||||
"type": "steal",
|
||||
"featureId": "_enclosing_building",
|
||||
"tagRenderingId": "walls_and_buildings.entrance_info; walls_and_buildings.biggest_width"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import {describe} from 'mocha'
|
||||
import {expect} from 'chai'
|
||||
import {Utils} from "../Utils";
|
||||
|
||||
describe("TestSuite", () => {
|
||||
|
||||
|
|
243
test/Logic/ExtraFunctions.spec.ts
Normal file
243
test/Logic/ExtraFunctions.spec.ts
Normal file
|
@ -0,0 +1,243 @@
|
|||
import {describe} from 'mocha'
|
||||
import {expect} from 'chai'
|
||||
import {ExtraFuncParams, ExtraFunctions} from "../../Logic/ExtraFunctions";
|
||||
import {OsmFeature} from "../../Models/OsmFeature";
|
||||
|
||||
|
||||
describe("OverlapFunc", () => {
|
||||
|
||||
it("should give doors on the edge", () => {
|
||||
const door: OsmFeature = {
|
||||
"type": "Feature",
|
||||
"id": "node/9909268725",
|
||||
"properties": {
|
||||
"automatic_door": "no",
|
||||
"door": "hinged",
|
||||
"indoor": "door",
|
||||
"kerb:height": "0 cm",
|
||||
"width": "1",
|
||||
"id": "node/9909268725",
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": [
|
||||
4.3494436,
|
||||
50.8657928
|
||||
]
|
||||
},
|
||||
}
|
||||
|
||||
const hermanTeirlinck = {
|
||||
"type": "Feature",
|
||||
"id": "way/444059131",
|
||||
"properties": {
|
||||
"timestamp": "2022-07-27T15:15:01Z",
|
||||
"version": 27,
|
||||
"changeset": 124146283,
|
||||
"user": "Pieter Vander Vennet",
|
||||
"uid": 3818858,
|
||||
"addr:city": "Bruxelles - Brussel",
|
||||
"addr:housenumber": "88",
|
||||
"addr:postcode": "1000",
|
||||
"addr:street": "Avenue du Port - Havenlaan",
|
||||
"building": "government",
|
||||
"building:levels": "5",
|
||||
"name": "Herman Teirlinckgebouw",
|
||||
"operator": "Vlaamse overheid",
|
||||
"wikidata": "Q47457146",
|
||||
"wikipedia": "nl:Herman Teirlinckgebouw",
|
||||
"id": "way/444059131",
|
||||
"_backend": "https://www.openstreetmap.org",
|
||||
"_lat": "50.86622355",
|
||||
"_lon": "4.3501212",
|
||||
"_layer": "walls_and_buildings",
|
||||
"_length": "380.5933566256343",
|
||||
"_length:km": "0.4",
|
||||
"_now:date": "2022-07-29",
|
||||
"_now:datetime": "2022-07-29 14:19:25",
|
||||
"_loaded:date": "2022-07-29",
|
||||
"_loaded:datetime": "2022-07-29 14:19:25",
|
||||
"_last_edit:contributor": "Pieter Vander Vennet",
|
||||
"_last_edit:contributor:uid": 3818858,
|
||||
"_last_edit:changeset": 124146283,
|
||||
"_last_edit:timestamp": "2022-07-27T15:15:01Z",
|
||||
"_version_number": 27,
|
||||
"_geometry:type": "Polygon",
|
||||
"_surface": "7461.252251355437",
|
||||
"_surface:ha": "0.7",
|
||||
"_country": "be"
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[
|
||||
[
|
||||
4.3493369,
|
||||
50.8658274
|
||||
],
|
||||
[
|
||||
4.3493393,
|
||||
50.8658266
|
||||
],
|
||||
[
|
||||
4.3494436,
|
||||
50.8657928
|
||||
],
|
||||
[
|
||||
4.3495272,
|
||||
50.8657658
|
||||
],
|
||||
[
|
||||
4.349623,
|
||||
50.8657348
|
||||
],
|
||||
[
|
||||
4.3497442,
|
||||
50.8656956
|
||||
],
|
||||
[
|
||||
4.3498441,
|
||||
50.8656632
|
||||
],
|
||||
[
|
||||
4.3500768,
|
||||
50.8655878
|
||||
],
|
||||
[
|
||||
4.3501619,
|
||||
50.8656934
|
||||
],
|
||||
[
|
||||
4.3502113,
|
||||
50.8657551
|
||||
],
|
||||
[
|
||||
4.3502729,
|
||||
50.8658321
|
||||
],
|
||||
[
|
||||
4.3503063,
|
||||
50.8658737
|
||||
],
|
||||
[
|
||||
4.3503397,
|
||||
50.8659153
|
||||
],
|
||||
[
|
||||
4.3504159,
|
||||
50.8660101
|
||||
],
|
||||
[
|
||||
4.3504177,
|
||||
50.8660123
|
||||
],
|
||||
[
|
||||
4.3504354,
|
||||
50.8660345
|
||||
],
|
||||
[
|
||||
4.3505348,
|
||||
50.8661584
|
||||
],
|
||||
[
|
||||
4.3504935,
|
||||
50.866172
|
||||
],
|
||||
[
|
||||
4.3506286,
|
||||
50.8663405
|
||||
],
|
||||
[
|
||||
4.3506701,
|
||||
50.8663271
|
||||
],
|
||||
[
|
||||
4.3508563,
|
||||
50.8665592
|
||||
],
|
||||
[
|
||||
4.3509055,
|
||||
50.8666206
|
||||
],
|
||||
[
|
||||
4.3506278,
|
||||
50.8667104
|
||||
],
|
||||
[
|
||||
4.3504502,
|
||||
50.8667675
|
||||
],
|
||||
[
|
||||
4.3503132,
|
||||
50.8668115
|
||||
],
|
||||
[
|
||||
4.3502162,
|
||||
50.8668427
|
||||
],
|
||||
[
|
||||
4.3501645,
|
||||
50.8668593
|
||||
],
|
||||
[
|
||||
4.3499296,
|
||||
50.8665664
|
||||
],
|
||||
[
|
||||
4.3498821,
|
||||
50.8665073
|
||||
],
|
||||
[
|
||||
4.3498383,
|
||||
50.8664527
|
||||
],
|
||||
[
|
||||
4.3498126,
|
||||
50.8664207
|
||||
],
|
||||
[
|
||||
4.3497459,
|
||||
50.8663376
|
||||
],
|
||||
[
|
||||
4.3497227,
|
||||
50.8663086
|
||||
],
|
||||
[
|
||||
4.3496517,
|
||||
50.8662201
|
||||
],
|
||||
[
|
||||
4.3495158,
|
||||
50.8660507
|
||||
],
|
||||
[
|
||||
4.3493369,
|
||||
50.8658274
|
||||
]
|
||||
]
|
||||
]
|
||||
},
|
||||
"bbox": {
|
||||
"maxLat": 50.8668593,
|
||||
"maxLon": 4.3509055,
|
||||
"minLat": 50.8655878,
|
||||
"minLon": 4.3493369
|
||||
}
|
||||
}
|
||||
|
||||
const params: ExtraFuncParams = {
|
||||
getFeatureById: id => undefined,
|
||||
getFeaturesWithin: () => [[door]],
|
||||
memberships: undefined
|
||||
}
|
||||
|
||||
|
||||
ExtraFunctions.FullPatchFeature(params, hermanTeirlinck)
|
||||
const overlap = (<any>hermanTeirlinck).overlapWith("*")
|
||||
console.log(JSON.stringify(overlap))
|
||||
expect(overlap[0].feat == door).true
|
||||
|
||||
})
|
||||
|
||||
})
|
Loading…
Reference in a new issue