Add 'steal' as special rendering, update 'multi', add entrance overview to onwheels layer

This commit is contained in:
pietervdvn 2022-07-29 20:04:36 +02:00
parent 181c5583d2
commit 7e32413113
11 changed files with 462 additions and 73 deletions

View file

@ -13,9 +13,9 @@ export interface ExtraFuncParams {
* Note that more features then requested can be given back. * Note that more features then requested can be given back.
* Format: [ [ geojson, geojson, geojson, ... ], [geojson, ...], ...] * 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 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 { class EnclosingFunc implements ExtraFunction {
_name = "enclosingFeatures" _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}[]`", "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)"] _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>) { _f(params: ExtraFuncParams, feat: Feature<Geometry, any>) {
return (...layerIds: string[]) => { return (...layerIds: string[]) => {
const result: { feat: any }[] = [] const result: { feat: any }[] = []
@ -51,14 +52,14 @@ class EnclosingFunc implements ExtraFunction {
} }
for (const otherFeatures of otherFeaturess) { for (const otherFeatures of otherFeaturess) {
for (const otherFeature of otherFeatures) { for (const otherFeature of otherFeatures) {
if(seenIds.has(otherFeature.properties.id)){ if (seenIds.has(otherFeature.properties.id)) {
continue continue
} }
seenIds.add(otherFeature.properties.id) seenIds.add(otherFeature.properties.id)
if(otherFeature.geometry.type !== "Polygon" && otherFeature.geometry.type !== "MultiPolygon"){ if (otherFeature.geometry.type !== "Polygon" && otherFeature.geometry.type !== "MultiPolygon") {
continue; continue;
} }
if(GeoOperations.completelyWithin(feat, <Feature<Polygon | MultiPolygon, any>> otherFeature)){ if (GeoOperations.completelyWithin(feat, <Feature<Polygon | MultiPolygon, any>>otherFeature)) {
result.push({feat: otherFeature}) result.push({feat: otherFeature})
} }
} }
@ -75,10 +76,10 @@ class OverlapFunc implements ExtraFunction {
_name = "overlapWith"; _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.", _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 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 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')`", "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) { _f(params, feat) {
return (...layerIds: string[]) => { return (...layerIds: string[]) => {
const result: { feat: any, overlap: number }[] = [] const result: { feat: any, overlap: number }[] = []
const seenIds = new Set<string>()
const bbox = BBox.get(feat) const bbox = BBox.get(feat)
for (const layerId of layerIds) { for (const layerId of layerIds) {
const otherFeaturess = params.getFeaturesWithin(layerId, bbox) const otherFeaturess = params.getFeaturesWithin(layerId, bbox)
@ -99,12 +101,18 @@ class OverlapFunc implements ExtraFunction {
continue; continue;
} }
for (const otherFeatures of otherFeaturess) { 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) result.sort((a, b) => b.overlap - a.overlap)
return result; return result;
} }
} }

View file

@ -35,6 +35,7 @@ export default class MetaTagging {
return; return;
} }
console.log("Recalculating metatags...")
const metatagsToApply: SimpleMetaTagger[] = [] const metatagsToApply: SimpleMetaTagger[] = []
for (const metatag of SimpleMetaTaggers.metatags) { for (const metatag of SimpleMetaTaggers.metatags) {
if (metatag.includesDates) { if (metatag.includesDates) {

View file

@ -93,7 +93,7 @@ export default class CreateNewNodeAction extends OsmCreateAction {
// Project the point onto the way // Project the point onto the way
console.log("Snapping a node onto an existing way...")
const geojson = this._snapOnto.asGeoJson() const geojson = this._snapOnto.asGeoJson()
const projected = GeoOperations.nearestPoint(geojson, [this._lon, this._lat]) const projected = GeoOperations.nearestPoint(geojson, [this._lon, this._lat])
const projectedCoor= <[number, number]>projected.geometry.coordinates const projectedCoor= <[number, number]>projected.geometry.coordinates

View file

@ -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. * 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 { protected static isPolygon(tags: any): boolean {
for (const tagsKey in tags) { for (const tagsKey in tags) {

View file

@ -378,6 +378,25 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> {
* const errors = [] * const errors = []
* RewriteSpecial.convertIfNeeded({"special": {}}, errors, "test") // => undefined * RewriteSpecial.convertIfNeeded({"special": {}}, errors, "test") // => undefined
* errors // => ["A 'special'-block should define 'type' to indicate which visualisation should be used"] * 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 { private static convertIfNeeded(input: (object & { special: { type: string } }) | any, errors: string[], context: string): any {
const special = input["special"] const special = input["special"]
@ -385,10 +404,6 @@ export class RewriteSpecial extends DesugaringStep<TagRenderingConfigJson> {
return input 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"] const type = special["type"]
if (type === undefined) { if (type === undefined) {
errors.push("A 'special'-block should define 'type' to indicate which visualisation should be used") 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 // Check for obsolete and misspelled arguments
errors.push(...Object.keys(special) errors.push(...Object.keys(special)
.filter(k => !argNames.has(k)) .filter(k => !argNames.has(k))
.filter(k => k !== "type") .filter(k => k !== "type" && k !== "before" && k !== "after")
.map(wrongArg => { .map(wrongArg => {
const byDistance = Utils.sortedByLevenshteinDistance(wrongArg, argNamesList, x => x) 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 // 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)}"}} ]} * const expected = {render: {'*': "{image_carousel(image)}"}, mappings: [{if: "other_image_key", then: {'*': "{image_carousel(other_image_key)}"}} ]}
* result // => expected * result // => expected
* *
* // Should put text before if specified
* const tr = { * const tr = {
* render: {special: {type: "image_carousel", image_key: "image"}, before: {en: "Some introduction"} }, * render: {special: {type: "image_carousel", image_key: "image"}, before: {en: "Some introduction"} },
* } * }
* const result = new RewriteSpecial().convert(tr,"test").result * const result = new RewriteSpecial().convert(tr,"test").result
* const expected = {render: {'en': "Some introduction{image_carousel(image)}"}} * const expected = {render: {'en': "Some introduction{image_carousel(image)}"}}
* result // => expected * 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[] } { convert(json: TagRenderingConfigJson, context: string): { result: TagRenderingConfigJson; errors?: string[]; warnings?: string[]; information?: string[] } {
const errors = [] const errors = []

View file

@ -42,7 +42,6 @@ import NoteCommentElement from "./Popup/NoteCommentElement";
import ImgurUploader from "../Logic/ImageProviders/ImgurUploader"; import ImgurUploader from "../Logic/ImageProviders/ImgurUploader";
import FileSelectorButton from "./Input/FileSelectorButton"; import FileSelectorButton from "./Input/FileSelectorButton";
import {LoginToggle} from "./Popup/LoginButton"; import {LoginToggle} from "./Popup/LoginButton";
import {start} from "repl";
import {SubstitutedTranslation} from "./SubstitutedTranslation"; import {SubstitutedTranslation} from "./SubstitutedTranslation";
import {TextField} from "./Input/TextField"; import {TextField} from "./Input/TextField";
import Wikidata, {WikidataResponse} from "../Logic/Web/Wikidata"; import Wikidata, {WikidataResponse} from "../Logic/Web/Wikidata";
@ -60,7 +59,8 @@ import Slider from "./Input/Slider";
import List from "./Base/List"; import List from "./Base/List";
import StatisticsPanel from "./BigComponents/StatisticsPanel"; import StatisticsPanel from "./BigComponents/StatisticsPanel";
import {OsmFeature} from "../Models/OsmFeature"; import {OsmFeature} from "../Models/OsmFeature";
import Link from "./Base/Link"; import EditableTagRendering from "./Popup/EditableTagRendering";
import TagRenderingConfig from "../Models/ThemeConfig/TagRenderingConfig";
export interface SpecialVisualization { export interface SpecialVisualization {
funcName: string, funcName: string,
@ -334,6 +334,13 @@ export default class SpecialVisualizations {
render: { render: {
special: { special: {
type: "some_special_visualisation", 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", "argname": "some_arg",
"message": { "message": {
en: "some other really long message", en: "some other really long message",
@ -1206,7 +1213,7 @@ export default class SpecialVisualizations {
{ {
funcName: "multi", 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", 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: { render: {
special: { special: {
type: "multi", type: "multi",
@ -1216,20 +1223,81 @@ export default class SpecialVisualizations {
} }
} }
} }
}, null, " ")+"```", }, null, " ") + "```",
args: [ args: [
{name: "key",
doc: "The property to read and to interpret as a list of properties"},
{ {
name:"tagrendering", name: "key",
doc: "An entire tagRenderingConfig" 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) { constr(state, featureTags, args) {
const [key, tr] = args const [key, tr] = args
console.log("MULTI: ", key, tr) const translation = new Translation({"*": tr})
return undefined 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]
} }
} }
] ]

View file

@ -47,33 +47,84 @@
} }
], ],
"calculatedTags": [ "calculatedTags": [
"_entrance_properties=feat.overlapWith('entrance')?.map(e => e.feat.properties).filter(p => p !== undefined).filter(p => p.width !== undefined)", "_entrance_properties=feat.overlapWith('entrance')?.map(e => e.feat.properties)?.filter(p => p !== undefined && p.indoor !== 'door')",
"_entrance:id=feat.get('_entrance_properties')?.map(e => e.id)?.at(0)", "_entrance_properties_with_width=feat.get('_entrance_properties')?.filter(p => p['width'] !== undefined)",
"_entrance:width=feat.get('_entrance_properties')?.map(e => e.width)?.at(0)" "_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", "appliesToKey": [
"render": { "width","_biggest_width"
"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>", "applicableUnits": [
"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": [
{ {
"if": "_entrance:width=", "canonicalDenomination": "m",
"then": { "alternativeDenomination": [
"en": "This entrance has no width information", "meter"
"de": "Der Eingang hat keine Informationen zur Durchgangsbreite", ],
"fr": "Cette entrée n'a pas d'informations sur sa largeur" "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~*"
}
] ]
} }

View file

@ -17,6 +17,12 @@
"startZoom": 14, "startZoom": 14,
"widenFactor": 2, "widenFactor": 2,
"layers": [ "layers": [
"indoors" "indoors",
{
"builtin": ["walls_and_buildings"],
"override": {
"shownByDefault": true
}
}
] ]
} }

View file

@ -366,15 +366,11 @@
], ],
"overrideAll": { "overrideAll": {
"+calculatedTags": [ "+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']})))", "_enclosing_building=feat.enclosingFeatures('walls_and_buildings')?.map(f => f.feat.properties.id)?.at(0)"
"_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"
], ],
"+tagRenderings": [ "tagRenderings+": [
{ {
"id": "_containing_poi_entrance:width", "id": "_stolen_entrances",
"condition": { "condition": {
"and": [ "and": [
"entrance=", "entrance=",
@ -383,21 +379,11 @@
"door=" "door="
] ]
}, },
"mappings": [{
"if": "_poi_walls_and_buildings_entrance_properties_with_width=[]",
"then": {
"en": "The containing building has {}"
}
}],
"render": { "render": {
"special": { "special": {
"type": "multi", "type": "steal",
"key": "_poi_walls_and_buildings_entrance_properties", "featureId": "_enclosing_building",
"tagrendering": { "tagRenderingId": "walls_and_buildings.entrance_info; walls_and_buildings.biggest_width"
"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>"
}
} }
} }
} }

View file

@ -1,6 +1,5 @@
import {describe} from 'mocha' import {describe} from 'mocha'
import {expect} from 'chai' import {expect} from 'chai'
import {Utils} from "../Utils";
describe("TestSuite", () => { describe("TestSuite", () => {

View 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
})
})