diff --git a/Docs/Tags_format.md b/Docs/Tags_format.md index 25db913cd6..7531d89b6c 100644 --- a/Docs/Tags_format.md +++ b/Docs/Tags_format.md @@ -88,4 +88,6 @@ To mitigate this, use: "hideInAnswer": "some_other_key=" } ] -``` \ No newline at end of file +``` + +One can use `key!:=prefix-{other_key}-postfix` as well, to match if `key` is _not_ the same as `prefix-{other_key}-postfix` (with other_key substituted by the value) \ No newline at end of file diff --git a/Logic/FeatureSource/FeaturePipeline.ts b/Logic/FeatureSource/FeaturePipeline.ts index 93bc53a748..32e7ed0aef 100644 --- a/Logic/FeatureSource/FeaturePipeline.ts +++ b/Logic/FeatureSource/FeaturePipeline.ts @@ -58,6 +58,7 @@ export default class FeaturePipeline { private readonly osmSourceZoomLevel private readonly localStorageSavers = new Map() + private readonly metataggingRecalculated = new UIEventSource(undefined) constructor( handleFeatureSource: (source: FeatureSourceForLayer & Tiled) => void, @@ -95,11 +96,13 @@ export default class FeaturePipeline { const perLayerHierarchy = new Map() this.perLayerHierarchy = perLayerHierarchy + // Given a tile, wraps it and passes it on to render (handled by 'handleFeatureSource' function patchedHandleFeatureSource (src: FeatureSourceForLayer & IndexedFeatureSource & Tiled) { // This will already contain the merged features for this tile. In other words, this will only be triggered once for every tile const srcFiltered = new FilteringFeatureSource(state, src.tileIndex, - new ChangeGeometryApplicator(src, state.changes) + new ChangeGeometryApplicator(src, state.changes), + self.metataggingRecalculated ) handleFeatureSource(srcFiltered) @@ -472,6 +475,7 @@ export default class FeaturePipeline { self.applyMetaTags(tile) }) }) + self.metataggingRecalculated.ping() } diff --git a/Logic/FeatureSource/Sources/FilteringFeatureSource.ts b/Logic/FeatureSource/Sources/FilteringFeatureSource.ts index d5ed4dc717..eba746d3e1 100644 --- a/Logic/FeatureSource/Sources/FilteringFeatureSource.ts +++ b/Logic/FeatureSource/Sources/FilteringFeatureSource.ts @@ -28,7 +28,8 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti allElements: ElementStorage }, tileIndex, - upstream: FeatureSourceForLayer + upstream: FeatureSourceForLayer, + metataggingUpdated: UIEventSource ) { this.name = "FilteringFeatureSource(" + upstream.name + ")" this.tileIndex = tileIndex @@ -53,11 +54,15 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti self.update() } }) + + metataggingUpdated.addCallback(_ => { + self._is_dirty.setData(true) + }) this.update(); } - public update() { + private update() { const self = this; const layer = this.upstream.layer; const features: { feature: any; freshness: Date }[] = this.upstream.features.data; @@ -106,13 +111,11 @@ export default class FilteringFeatureSource implements FeatureSourceForLayer, Ti return } this._alreadyRegistered.add(src) - if (layer.isShown !== undefined) { const self = this; - src.map(tags => layer.isShown?.GetRenderValue(tags, "yes").txt).addCallbackAndRunD(isShown => { + src.addCallbackAndRunD(isShown => { self._is_dirty.setData(true) }) - } } } diff --git a/Logic/GeoOperations.ts b/Logic/GeoOperations.ts index 4d89faa9f2..87a2d21714 100644 --- a/Logic/GeoOperations.ts +++ b/Logic/GeoOperations.ts @@ -80,7 +80,7 @@ export class GeoOperations { continue; } - const intersection = this.calculateInstersection(feature, otherFeature, featureBBox) + const intersection = GeoOperations.calculateInstersection(feature, otherFeature, featureBBox) if (intersection === null) { continue } @@ -353,7 +353,7 @@ export class GeoOperations { * Returns 0 if both are linestrings * Returns null if the features are not intersecting */ - private static calculateInstersection(feature, otherFeature, featureBBox: BBox, otherFeatureBBox?: BBox): number { + static calculateInstersection(feature, otherFeature, featureBBox: BBox, otherFeatureBBox?: BBox): number { try { if (feature.geometry.type === "LineString") { @@ -433,7 +433,7 @@ export class GeoOperations { } } catch (exception) { - console.warn("EXCEPTION CAUGHT WHILE INTERSECTING: ", exception); + console.warn("EXCEPTION CAUGHT WHILE INTERSECTING: ", exception,"\nThe considered objects are",feature, otherFeature); return undefined } return undefined; diff --git a/Logic/Osm/Actions/CreateWayWithPointReuseAction.ts b/Logic/Osm/Actions/CreateWayWithPointReuseAction.ts index 0ed45ae3d3..2d81fa80f8 100644 --- a/Logic/Osm/Actions/CreateWayWithPointReuseAction.ts +++ b/Logic/Osm/Actions/CreateWayWithPointReuseAction.ts @@ -291,6 +291,10 @@ export default class CreateWayWithPointReuseAction extends OsmChangeAction { if (other.closebyNodes === undefined || other.closebyNodes[0] === undefined) { continue } + + if(coorInfo.closebyNodes[0] === undefined){ + continue + } if (other.closebyNodes[0].node === coorInfo.closebyNodes[0].node) { conflictFree = false diff --git a/Logic/Tags/SubstitutingTag.ts b/Logic/Tags/SubstitutingTag.ts index 567693c78e..f776d0a407 100644 --- a/Logic/Tags/SubstitutingTag.ts +++ b/Logic/Tags/SubstitutingTag.ts @@ -12,13 +12,14 @@ import {TagsFilter} from "./TagsFilter"; export default class SubstitutingTag implements TagsFilter { private readonly _key: string; private readonly _value: string; - - constructor(key: string, value: string) { +private readonly _invert: boolean + constructor(key: string, value: string, invert = false) { this._key = key; this._value = value; + this._invert = invert } - public static substituteString(template: string, dict: any): string { + private static substituteString(template: string, dict: any): string { for (const k in dict) { template = template.replace(new RegExp("\\{" + k + "\\}", 'g'), dict[k]) } @@ -26,7 +27,7 @@ export default class SubstitutingTag implements TagsFilter { } asHumanString(linkToWiki: boolean, shorten: boolean, properties) { - return this._key + "=" + SubstitutingTag.substituteString(this._value, properties); + return this._key + (this._invert ? '!' : '') + "=" + SubstitutingTag.substituteString(this._value, properties); } asOverpass(): string[] { @@ -37,11 +38,11 @@ export default class SubstitutingTag implements TagsFilter { if (!(other instanceof SubstitutingTag)) { return false; } - return other._key === this._key && other._value === this._value; + return other._key === this._key && other._value === this._value && other._invert === this._invert; } isUsableAsAnswer(): boolean { - return true; + return !this._invert; } matchesProperties(properties: any): boolean { @@ -50,7 +51,7 @@ export default class SubstitutingTag implements TagsFilter { return false; } const expectedValue = SubstitutingTag.substituteString(this._value, properties); - return value === expectedValue; + return (value === expectedValue) !== this._invert; } usedKeys(): string[] { @@ -58,6 +59,7 @@ export default class SubstitutingTag implements TagsFilter { } asChange(properties: any): { k: string; v: string }[] { + if(this._invert){throw "An inverted substituting tag can not be used to create a change"} const v = SubstitutingTag.substituteString(this._value, properties); if (v.match(/{.*}/) !== null) { throw "Could not calculate all the substitutions: still have " + v diff --git a/Logic/Tags/TagUtils.ts b/Logic/Tags/TagUtils.ts index 474fbc54e7..e662beca66 100644 --- a/Logic/Tags/TagUtils.ts +++ b/Logic/Tags/TagUtils.ts @@ -226,6 +226,10 @@ export class TagUtils { new RegExp("^" + split[1] + "$") ); } + if (tag.indexOf("!:=") >= 0) { + const split = Utils.SplitFirst(tag, "!:="); + return new SubstitutingTag(split[0], split[1], true); + } if (tag.indexOf(":=") >= 0) { const split = Utils.SplitFirst(tag, ":="); return new SubstitutingTag(split[0], split[1]); diff --git a/UI/SpecialVisualizations.ts b/UI/SpecialVisualizations.ts index a6760f5d55..aaad5f500c 100644 --- a/UI/SpecialVisualizations.ts +++ b/UI/SpecialVisualizations.ts @@ -553,7 +553,7 @@ export default class SpecialVisualizations { doc: "If specified, applies the the tags onto _another_ object. The id will be read from properties[id_of_object_to_apply_this_one] of the selected object. The tags are still calculated based on the tags of the _selected_ element" } ], - example: "`{tag_apply(survey_date:=$_now:date, Surveyed today!)}`", + example: "`{tag_apply(survey_date=$_now:date, Surveyed today!)}`, `{tag_apply(addr:street=$addr:street, Apply the address, apply_icon.svg, _closest_osm_id)", constr: (state, tags, args) => { const tagsToApply = SpecialVisualizations.generateTagsToApply(args[0], tags) const msg = args[1] @@ -650,6 +650,13 @@ export default class SpecialVisualizations { } return kv }) + + for (const spec of tgsSpec) { + if(spec[0].endsWith(':')){ + throw "A tag specification for import or apply ends with ':'. The theme author probably wrote key:=otherkey instead of key=$otherkey" + } + } + return tagSource.map(tags => { const newTags: Tag [] = [] for (const [key, value] of tgsSpec) { diff --git a/UI/i18n/Translation.ts b/UI/i18n/Translation.ts index a962410a2d..76d4cc9f21 100644 --- a/UI/i18n/Translation.ts +++ b/UI/i18n/Translation.ts @@ -124,45 +124,7 @@ export class Translation extends BaseUIElement { continue; } let template: string = this.translations[lang]; - for (const k in text) { - if (!text.hasOwnProperty(k)) { - continue - } - const combined: (string)[] = []; - const parts = template.split("{" + k + "}"); - const el: string | BaseUIElement = text[k]; - if (el === undefined) { - continue; - } - let rtext: string = ""; - if (typeof (el) === "string") { - rtext = el; - } else if (typeof (el) === "number") { - // HUH? Where did that number come from? It might be a version number or something calculated - rtext = "" + el; - } else if (el["toISOString"] != undefined) { - // This is a date, probably the timestamp of the object - // @ts-ignore - const date: Date = el; - rtext = date.toLocaleString(); - } else if (el.ConstructElement === undefined) { - console.error("ConstructElement is not defined", el); - throw "ConstructElement is not defined, you are working with a " + (typeof el) + ":" + (el.constructor.name) - } else if (el["textFor"] !== undefined) { - // @ts-ignore - rtext = el.textFor(lang) - } else { - rtext = el.ConstructElement().innerHTML; - - } - for (let i = 0; i < parts.length - 1; i++) { - combined.push(parts[i]); - combined.push(rtext) - } - combined.push(parts[parts.length - 1]); - template = combined.join("") - } - newTranslations[lang] = template; + newTranslations[lang] = Utils.SubstituteKeys(template, text); } return new Translation(newTranslations); diff --git a/Utils.ts b/Utils.ts index 1141259267..bd9cfda2af 100644 --- a/Utils.ts +++ b/Utils.ts @@ -203,6 +203,19 @@ Note that these values can be prepare with javascript in the theme by using a [c const key = match[1] let v = tags[key] if(v !== undefined ){ + + if (v["toISOString"] != undefined) { + // This is a date, probably the timestamp of the object + // @ts-ignore + const date: Date = el; + v = date.toISOString() + } + + 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) + v = ( v.InnerConstructElement())?.innerText + } + if(typeof v !== "string"){ v = ""+v } diff --git a/assets/layers/crab_address/crab_address.json b/assets/layers/crab_address/crab_address.json index 07dd7a6cb9..50fd4c694f 100644 --- a/assets/layers/crab_address/crab_address.json +++ b/assets/layers/crab_address/crab_address.json @@ -1,6 +1,6 @@ { "id": "crab_address", - "description": "Address data for Flanders by the governement, suited for import into OpenStreetMap. Datadump from 2021-10-26. This layer contains only visualisation logic. Import buttons should be added via an override.", + "description": "Address data for Flanders by the governement, suited for import into OpenStreetMap. Datadump from 2021-10-26. This layer contains only visualisation logic. Import buttons should be added via an override. Note that HNRLABEL contains the original value, whereas _HNRLABEL contains a slightly cleaned version", "source": { "osmTags": "HUISNR~*", "geoJson": "https://pietervdvn.github.io/CRAB_2021_10_26/tile_{z}_{x}_{y}.geojson", @@ -18,15 +18,18 @@ "iconSize": "50,50,center", "icon": "./assets/layers/crab_address/housenumber_blank.svg", "label": { - "render": "
{HNRLABEL}
" + "render": "
{_HNRLABEL}
" } } ], + "calculatedTags": [ + "_HNRLABEL=(() => {const lbl = feat.properties.HNRLABEL?.split('-')?.map(l => Number(l))?.filter(i => !isNaN (i)) ;if(lbl?.length != 2) {return feat.properties.HNRLABEL}; const addresses = []; for(let i = lbl[0]; i <= lbl[1]; i += 1){addresses.push(''+i);}; return addresses.join(';') })()" + ], "tagRenderings": [ { "id": "render_crab", "render": { - "nl": "Volgens het CRAB ligt hier {STRAATNM} {HUISNR} (label: {HNRLABEL})" + "nl": "Volgens het CRAB ligt hier {STRAATNM} {HUISNR} (label: {_HNRLABEL})" } } ] diff --git a/assets/themes/grb_import/grb.json b/assets/themes/grb_import/grb.json index 4f051d6c3d..4eaefabe9b 100644 --- a/assets/themes/grb_import/grb.json +++ b/assets/themes/grb_import/grb.json @@ -349,26 +349,43 @@ "_embedding_street=feat.get('_embedded_in')['addr:street']", "_embedding_id=feat.get('_embedded_in').id", "_closeby_addresses=feat.closestn('address',10,undefined,50).map(f => f.feat).filter(addr => addr.properties['addr:street'] == feat.properties['STRAATNM'] && feat.properties['HNRLABEL'] == addr.properties['addr:housenumber'] + (addr.properties['addr:unit']??'') ).length", - "_has_identical_closeby_address=feat.get('_closeby_addresses') >= 1 ? 'yes' : 'no'" + "_has_identical_closeby_address=feat.get('_closeby_addresses') >= 1 ? 'yes' : 'no'", + "_embedded_in_grb=feat.overlapWith('GRB')[0]?.feat?.properties ?? {}", + "_embedding_nr_grb=feat.get('_embedded_in_grb')['addr:housenumber']", + "_embedding_street_grb=feat.get('_embedded_in_grb')['addr:street']" ], - "isShown": { - "render": "yes", - "mappings": [ - { - "if": { - "and": [ - "_embedding_nr:={HUISNR}", - "_embedding_street:={STRAATNM}" - ] + "filter": [ + { + "id": "show_matched_addresses", + "options": [ + { + "question": "Show all CRAB-addresses (including already matched ones)" }, - "then": "no" - }, - { - "if": "_has_identical_closeby_address=yes", - "then": "no" - } - ] - }, + { + "question": "Only show unmatched addresses", + "osmTags": { + "and": [ + "_has_identical_closeby_address!=yes", + { + "#": "Matches the embedding OSM object", + "or": [ + "_embedding_nr!:={HUISNR}", + "_embedding_street!:={STRAATNM}" + ] + }, + { "#": "Matches the embedding GRB object", + + "or": [ + "_embedding_nr_grb!:={HUISNR}", + "_embedding_street_grb!:={STRAATNM}" + ] + } + ] + } + } + ] + } + ], "tagRenderings+": [ { "id": "render_embedded", @@ -388,7 +405,7 @@ }, { "id": "apply-button", - "render": "{tag_apply(addr:street=$STRAATNM; addr:housenumber=$HUISNR,Apply this address on the OSM-building,,_embedding_id)}", + "render": "{tag_apply(addr:street=$STRAATNM; addr:housenumber=$_HNRLABEL,Apply this address on the OSM-building,,_embedding_id)}", "condition": "_embedding_id!=" }, { @@ -417,13 +434,15 @@ "name": "GRB geometries", "title": "GRB outline", "calculatedTags": [ - "_overlaps_with=feat.overlapWith('OSM-buildings').filter(f => f.overlap > 1 && (feat.get('_surface') < 20 || f.overlap / feat.get('_surface')) > 0.5)[0] ?? null", + "_overlaps_with=feat.overlapWith('OSM-buildings').filter(f => f.overlap > 1 && (feat.get('_surface') < 20 || f.overlap / feat.get('_surface')) > 0.5)[0] ?? ''", "_overlap_absolute=feat.get('_overlaps_with')?.overlap", "_overlap_percentage=Math.round(100 * feat.get('_overlap_absolute') / feat.get('_surface')) ", "_osm_obj:source:ref=feat.get('_overlaps_with')?.feat?.properties['source:geometry:ref']", "_osm_obj:source:date=feat.get('_overlaps_with')?.feat?.properties['source:geometry:date'].replace(/\\//g, '-')", - "_osm_obj:building=feat.get('_overlaps_with')?.feat?.properties.building", - "_osm_obj:id=feat.get('_overlaps_with')?.feat?.properties.id", + "_osm_obj:building=feat.get('_overlaps_with')?.feat?.properties?.building", + "_osm_obj:id=feat.get('_overlaps_with')?.feat?.properties?.id", + "_osm_obj:addr:street=(feat.get('_overlaps_with')?.feat?.properties ?? {})['addr:street']", + "_osm_obj:addr:housenumber=(feat.get('_overlaps_with')?.feat?.properties ?? {})['addr:housenumber']", "_grb_ref=feat.properties['source:geometry:entity'] + '/' + feat.properties['source:geometry:oidn']", "_imported_osm_object_found= feat.properties['_osm_obj:source:ref'] == feat.properties._grb_ref", "_grb_date=feat.properties['source:geometry:date'].replace(/\\//g,'-')", @@ -432,21 +451,86 @@ "_building:min_level= feat.properties['fixme']?.startsWith('verdieping, correct the building tag, add building:level and building:min_level before upload in JOSM!') ? '1' : ''" ], "tagRenderings": [ + { + "id": "Import-button", + "render": "{import_button(OSM-buildings,building=$building; source:geometry:date=$_grb_date; source:geometry:ref=$_grb_ref; addr:street=$addr:street; addr:housenumber=$addr:housenumber; building:min_level=$_building:min_level, Upload this building to OpenStreetMap)}", + "mappings": [ + { + "if": {"and": + [ + "_overlaps_with!=", + "_osm_obj:addr:street=", + "_osm_obj:addr:housenumber=", + "addr:street~*", + "addr:housenumber~*" + + ] + }, + "then": "{import_button(OSM-buildings,building=$_target_building_type; source:geometry:date=$_grb_date; source:geometry:ref=$_grb_ref; addr:street=$addr:street; addr:housenumber=$addr:housenumber, Replace the geometry in OpenStreetMap and add the address,,,_osm_obj:id)}" + }, + { + "if": "_overlaps_with!=", + "then": "{import_button(OSM-buildings,building=$_target_building_type; source:geometry:date=$_grb_date; source:geometry:ref=$_grb_ref, Replace the geometry in OpenStreetMap,,,_osm_obj:id)}" + } + ] + }, { "id": "Building info", "render": "This is a {building} detected by {detection_method}" }, + { + "id": "overlapping building address", + "render": "The overlapping openstreetmap-building has no address information at all", + "mappings": [ + { + "if": { + "and": [ + "_osm_obj:addr:street~*", + "_osm_obj:addr:housenumber~*" + ] + }, + "then": "The overlapping openstreetmap-building has address {_osm_obj:addr:street} {_osm_obj:addr:housenumber}" + }, + { + "if": "_osm_obj:addr:street~*", + "then": "The overlapping building only has a street known: {_osm_obj:addr:street}" + }, + { + "if": "_osm_obj:addr:housenumber~*", + "then": "The overlapping building only has a housenumber known: {_osm_obj:addr:housenumber}" + } + ], + "conditon": "_osm_obj:id~*" + }, + { + "id": "grb_address_diff", + "render": "
The overlapping openstreetmap-building has a different address then this GRB-object: {addr:street} {addr:housenumber}
{tag_apply(addr:street=$addr:street; addr:housenumber=$addr:housenumber,Copy the GRB-address onto the OSM-object,,_osm_obj:id)}", + "condition": { + "and": [ + "_osm_obj:id~*", + "addr:street~*", + "addr:housenumber~*", + { + "or": [ + "addr:street!:={_osm_obj:addr:street}", + "addr:housenumber!:={_osm_obj:addr:housenumber}" + ] + } + ] + } + }, { "id": "overlapping building type", - "render": "
The overlapping openstreetmap-building is a {_osm_obj:building} and covers {_overlap_percentage}% of the GRB building

GRB geometry:

{minimap(21, id):height:10rem;border-radius:1rem;overflow:hidden}

OSM geometry:

{minimap(21,_osm_obj:id):height:10rem;border-radius:1rem;overflow:hidden}", - "condition": "_overlaps_with!=null" + "render": "
The overlapping openstreetmap-building is a {_osm_obj:building} and covers {_overlap_percentage}% of the GRB building

GRB geometry:

{minimap(21, id):height:10rem;border-radius:1rem;overflow:hidden}

OSM geometry:

{minimap(21,_osm_obj:id):height:10rem;border-radius:1rem;overflow:hidden}", + "condition": "_overlaps_with!=" }, { "id": "apply-id", "render": "{tag_apply(source:geometry:date=$_grb_date; source:geometry:ref=$_grb_ref,Mark the OSM-building as imported,,_osm_obj:id)}", "condition": { "and": [ - "_overlaps_with!=null" + "_overlaps_with!=", + "_imported!=yes" ] } }, @@ -455,23 +539,12 @@ "render": "{tag_apply(building=$building,Use the building type from GRB,,_osm_obj:id)}", "condition": { "and": [ - "_overlaps_with!=null", + "_overlaps_with!=", "_osm_obj:building=yes", "building!=yes" ] } - }, - { - "id": "Import-button", - "render": "{import_button(OSM-buildings,building=$building; source:geometry:date=$_grb_date; source:geometry:ref=$_grb_ref; addr:street=$addr:street; addr:housenumber=$addr:housenumber; building:min_level=$_building:min_level, Upload this building to OpenStreetMap)}", - "mappings": [ - { - "if": "_overlaps_with!=null", - "then": "{import_button(OSM-buildings,building=$_target_building_type; source:geometry:date=$_grb_date; source:geometry:ref=$_grb_ref, Replace the geometry in OpenStreetMap,,,_osm_obj:id)}" - } - ] - }, - "all_tags" + } ], "isShown": { "render": "yes", @@ -489,9 +562,41 @@ }, "mapRendering": [ { + "label": { + "render": "
{addr:housenumber}
", + "condition": "addr:housenumber~*" + }, + "iconSize": "50,50,center", + "icon": { + "render": "./assets/themes/grb_import/housenumber_blank.svg", + "mappings": [ + { + "if": "addr:housenumber=", + "then": "" + } + ] + }, + "location": [ + "point", + "centroid" + ] + }, + { "width": { + "render": 5, + "mappings": [ + { + "if": "_imported=yes", + "then": "1" + } + ] + }, "color": { "render": "#00a", "mappings": [ + { + "if": "_imported=yes", + "then":"#00ff00" + }, { "if": { "and": [ diff --git a/assets/themes/grb_import/housenumber_blank.svg b/assets/themes/grb_import/housenumber_blank.svg new file mode 100644 index 0000000000..9d4ed27c18 --- /dev/null +++ b/assets/themes/grb_import/housenumber_blank.svg @@ -0,0 +1,63 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/assets/themes/grb_import/license_info.json b/assets/themes/grb_import/license_info.json new file mode 100644 index 0000000000..8ea1617ec5 --- /dev/null +++ b/assets/themes/grb_import/license_info.json @@ -0,0 +1,10 @@ +[ + { + "path": "housenumber_blank.svg", + "license": "CC0", + "authors": [ + "Pieter Vander Vennet" + ], + "sources": [] + } +] \ No newline at end of file diff --git a/langs/nl.json b/langs/nl.json index cdba7145ca..1d633fa7d5 100644 --- a/langs/nl.json +++ b/langs/nl.json @@ -52,12 +52,12 @@ "confirmButton": "Voeg hier een {category} toe
Je toevoeging is voor iedereen zichtbaar
", "openLayerControl": "Open de laag-instellingen", "layerNotEnabled": "De laag {layer} is gedeactiveerd. Activeer deze om een punt toe te voegen", - "presetInfo": "Het nieuwe punt krijgt de attributen {tags}", + "presetInfo": "Het nieuwe object krijgt de attributen {tags}", "disableFiltersExplanation": "Interessepunten kunnen verborgen zijn door een filter", "disableFilters": "Zet alle filters af", - "hasBeenImported": "Dit punt is reeds geimporteerd", + "hasBeenImported": "Dit object is reeds geimporteerd", "warnVisibleForEveryone": "Je toevoeging is voor iedereen zichtbaar", - "zoomInMore": "Zoom meer in om dit punt te importeren" + "zoomInMore": "Zoom meer in om dit object te importeren" }, "pickLanguage": "Kies je taal: ", "about": "Bewerk en voeg data toe aan OpenStreetMap over een specifiek onderwerp op een gemakkelijke manier", diff --git a/test/GeoOperations.spec.ts b/test/GeoOperations.spec.ts index a615efb0c8..c63564fcc3 100644 --- a/test/GeoOperations.spec.ts +++ b/test/GeoOperations.spec.ts @@ -187,7 +187,179 @@ export default class GeoOperationsSpec extends T { equal(51.5292513551899, bbox.minLat) equal(51.53266860674158, bbox.maxLat) } - ] + ], + ["Regression test: intersection/overlap", () => { + + const polyGrb ={ + "type": "Feature", + "properties": { + "osm_id": "25189153", + "size_grb_building": "217.14", + "addr:housenumber": "173", + "addr:street": "Kortrijksestraat", + "building": "house", + "source:geometry:entity": "Gbg", + "source:geometry:date": "2015/02/27", + "source:geometry:oidn": "1729460", + "source:geometry:uidn": "8713648", + "H_DTM_MIN": "17.28", + "H_DTM_GEM": "17.59", + "H_DSM_MAX": "29.04", + "H_DSM_P99": "28.63", + "HN_MAX": "11.45", + "HN_P99": "11.04", + "detection_method": "from existing OSM building source: house ,hits (3)", + "auto_building": "house", + "size_shared": "210.68", + "size_source_building": "212.63", + "id": "https://betadata.grbosm.site/grb?bbox=360935.6475626023,6592540.815539878,361088.52161917265,6592693.689596449/37", + "_lat": "50.83736194999996", + "_lon": "3.2432137000000116", + "_layer": "GRB", + "_length": "48.51529464293261", + "_length:km": "0.0", + "_now:date": "2021-12-05", + "_now:datetime": "2021-12-05 21:51:40", + "_loaded:date": "2021-12-05", + "_loaded:datetime": "2021-12-05 21:51:40" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 3.2431059999999974, + 50.83730270000021 + ], + [ + 3.243174299999987, + 50.83728850000007 + ], + [ + 3.2432116000000173, + 50.83736910000003 + ], + [ + 3.2433214000000254, + 50.83740350000011 + ], + [ + 3.24329779999996, + 50.837435399999855 + ], + [ + 3.2431881000000504, + 50.83740090000025 + ], + [ + 3.243152699999997, + 50.83738980000017 + ], + [ + 3.2431059999999974, + 50.83730270000021 + ] + ] + ] + }, + "id": "https://betadata.grbosm.site/grb?bbox=360935.6475626023,6592540.815539878,361088.52161917265,6592693.689596449/37", + "_lon": 3.2432137000000116, + "_lat": 50.83736194999996, + "bbox": { + "maxLat": 50.837435399999855, + "maxLon": 3.2433214000000254, + "minLat": 50.83728850000007, + "minLon": 3.2431059999999974 + } + } + const polyHouse = { + "type": "Feature", + "id": "way/594963177", + "properties": { + "timestamp": "2021-12-05T04:04:55Z", + "version": 3, + "changeset": 114571409, + "user": "Pieter Vander Vennet", + "uid": 3818858, + "addr:housenumber": "171", + "addr:street": "Kortrijksestraat", + "building": "house", + "source:geometry:date": "2018-10-22", + "source:geometry:ref": "Gbg/5096537", + "_last_edit:contributor": "Pieter Vander Vennet", + "_last_edit:contributor:uid": 3818858, + "_last_edit:changeset": 114571409, + "_last_edit:timestamp": "2021-12-05T04:04:55Z", + "_version_number": 3, + "id": "way/594963177", + "_backend": "https://www.openstreetmap.org", + "_lat": "50.83736395", + "_lon": "3.2430937", + "_layer": "OSM-buildings", + "_length": "43.561938680928506", + "_length:km": "0.0", + "_now:date": "2021-12-05", + "_now:datetime": "2021-12-05 21:51:40", + "_loaded:date": "2021-12-05", + "_loaded:datetime": "2021-12-05 21:51:39", + "_surface": "93.32785810484549", + "_surface:ha": "0" + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + [ + [ + 3.2429993, + 50.8373243 + ], + [ + 3.243106, + 50.8373027 + ], + [ + 3.2431527, + 50.8373898 + ], + [ + 3.2431881, + 50.8374009 + ], + [ + 3.2431691, + 50.8374252 + ], + [ + 3.2430936, + 50.837401 + ], + [ + 3.243046, + 50.8374112 + ], + [ + 3.2429993, + 50.8373243 + ] + ] + ] + }, + "_lon": 3.2430937, + "_lat": 50.83736395, + "bbox": { + "maxLat": 50.8374252, + "maxLon": 3.2431881, + "minLat": 50.8373027, + "minLon": 3.2429993 + } + } + + const overlaps = GeoOperations.calculateOverlap(polyGrb, [polyHouse]) + Assert.equal(overlaps.length, 1) + const overlapsRev= GeoOperations.calculateOverlap(polyHouse, [polyGrb]) + Assert.equal(overlaps.length, 1) + + }] ] )