If an OSM-object does not exist anyore, ignore changes to this object. Fix #577

This commit is contained in:
pietervdvn 2021-12-05 05:19:59 +01:00
parent fc70909005
commit 76c84b3972

View file

@ -32,8 +32,8 @@ export class Changes {
private readonly previouslyCreated: OsmObject[] = [] private readonly previouslyCreated: OsmObject[] = []
private readonly _leftRightSensitive: boolean; private readonly _leftRightSensitive: boolean;
private _state : { allElements: ElementStorage; historicalUserLocations: FeatureSource } private _state: { allElements: ElementStorage; historicalUserLocations: FeatureSource }
constructor(leftRightSensitive: boolean = false) { constructor(leftRightSensitive: boolean = false) {
this._leftRightSensitive = leftRightSensitive; this._leftRightSensitive = leftRightSensitive;
@ -120,13 +120,13 @@ export class Changes {
}) })
} }
private calculateDistanceToChanges(change: OsmChangeAction, changeDescriptions: ChangeDescription[]){ private calculateDistanceToChanges(change: OsmChangeAction, changeDescriptions: ChangeDescription[]) {
if (this._state === undefined) { if (this._state === undefined) {
// No state loaded -> we can't calculate... // No state loaded -> we can't calculate...
return; return;
} }
if(!change.trackStatistics){ if (!change.trackStatistics) {
// Probably irrelevant, such as a new helper node // Probably irrelevant, such as a new helper node
return; return;
} }
@ -139,34 +139,34 @@ export class Changes {
const diff = (now.getTime() - visitTime.getTime()) / 1000 const diff = (now.getTime() - visitTime.getTime()) / 1000
return diff < Constants.nearbyVisitTime; return diff < Constants.nearbyVisitTime;
}) })
if(recentLocationPoints.length === 0){ if (recentLocationPoints.length === 0) {
// Probably no GPS enabled/no fix // Probably no GPS enabled/no fix
return; return;
} }
// The applicable points, contain information in their properties about location, time and GPS accuracy // The applicable points, contain information in their properties about location, time and GPS accuracy
// They are all GeoLocationPointProperties // They are all GeoLocationPointProperties
// We walk every change and determine the closest distance possible // We walk every change and determine the closest distance possible
// Only if the change itself does _not_ contain any coordinates, we fall back and search the original feature in the state // Only if the change itself does _not_ contain any coordinates, we fall back and search the original feature in the state
const changedObjectCoordinates : [number, number][] = [] const changedObjectCoordinates: [number, number][] = []
const feature = this._state.allElements.ContainingFeatures.get(change.mainObjectId) const feature = this._state.allElements.ContainingFeatures.get(change.mainObjectId)
if(feature !== undefined){ if (feature !== undefined) {
changedObjectCoordinates.push(GeoOperations.centerpointCoordinates(feature)) changedObjectCoordinates.push(GeoOperations.centerpointCoordinates(feature))
} }
for (const changeDescription of changeDescriptions) { for (const changeDescription of changeDescriptions) {
const chng : {lat: number, lon: number} | {coordinates : [number,number][]} | {members} = changeDescription.changes const chng: { lat: number, lon: number } | { coordinates: [number, number][] } | { members } = changeDescription.changes
if(chng === undefined){ if (chng === undefined) {
continue continue
} }
if(chng["lat"] !== undefined){ if (chng["lat"] !== undefined) {
changedObjectCoordinates.push([chng["lat"],chng["lon"]]) changedObjectCoordinates.push([chng["lat"], chng["lon"]])
} }
if(chng["coordinates"] !== undefined){ if (chng["coordinates"] !== undefined) {
changedObjectCoordinates.push(...chng["coordinates"]) changedObjectCoordinates.push(...chng["coordinates"])
} }
} }
return Math.min(...changedObjectCoordinates.map(coor => return Math.min(...changedObjectCoordinates.map(coor =>
@ -176,7 +176,7 @@ export class Changes {
})) }))
)) ))
} }
public async applyAction(action: OsmChangeAction): Promise<void> { public async applyAction(action: OsmChangeAction): Promise<void> {
const changeDescriptions = await action.Perform(this) const changeDescriptions = await action.Perform(this)
changeDescriptions[0].meta.distanceToObject = this.calculateDistanceToChanges(action, changeDescriptions) changeDescriptions[0].meta.distanceToObject = this.calculateDistanceToChanges(action, changeDescriptions)
@ -190,12 +190,12 @@ export class Changes {
this.allChanges.data.push(...changes) this.allChanges.data.push(...changes)
this.allChanges.ping() this.allChanges.ping()
} }
public useLocationHistory(state: { public useLocationHistory(state: {
allElements: ElementStorage, allElements: ElementStorage,
historicalUserLocations: FeatureSource historicalUserLocations: FeatureSource
}){ }) {
this._state= state this._state = state
} }
public registerIdRewrites(mappings: Map<string, string>): void { public registerIdRewrites(mappings: Map<string, string>): void {
@ -212,7 +212,13 @@ export class Changes {
private async flushSelectChanges(pending: ChangeDescription[]): Promise<boolean> { private async flushSelectChanges(pending: ChangeDescription[]): Promise<boolean> {
const self = this; const self = this;
const neededIds = Changes.GetNeededIds(pending) const neededIds = Changes.GetNeededIds(pending)
const osmObjects = await Promise.all(neededIds.map(id => OsmObject.DownloadObjectAsync(id)));
const osmObjects = Utils.NoNull(await Promise.all(neededIds.map(async id =>
OsmObject.DownloadObjectAsync(id).catch(e => {
console.error("Could not download OSM-object", id, " dropping it from the changes")
pending = pending.filter(ch => ch.type + "/" + ch.id !== id)
return undefined;
}))));
if (this._leftRightSensitive) { if (this._leftRightSensitive) {
osmObjects.forEach(obj => SimpleMetaTagger.removeBothTagging(obj.tags)) osmObjects.forEach(obj => SimpleMetaTagger.removeBothTagging(obj.tags))
@ -243,41 +249,41 @@ export class Changes {
key: descr.meta.changeType + ":" + descr.type + "/" + descr.id, key: descr.meta.changeType + ":" + descr.type + "/" + descr.id,
value: descr.meta.specialMotivation value: descr.meta.specialMotivation
})) }))
const distances = Utils.NoNull(pending.map(descr => descr.meta.distanceToObject)); const distances = Utils.NoNull(pending.map(descr => descr.meta.distanceToObject));
distances.sort((a, b) => a - b) distances.sort((a, b) => a - b)
const perBinCount = Constants.distanceToChangeObjectBins.map(_ => 0) const perBinCount = Constants.distanceToChangeObjectBins.map(_ => 0)
let j = 0; let j = 0;
const maxDistances = Constants.distanceToChangeObjectBins const maxDistances = Constants.distanceToChangeObjectBins
for (let i = 0; i < maxDistances.length; i++){ for (let i = 0; i < maxDistances.length; i++) {
const maxDistance = maxDistances[i]; const maxDistance = maxDistances[i];
// distances is sorted in ascending order, so as soon as one is to big, all the resting elements will be bigger too // distances is sorted in ascending order, so as soon as one is to big, all the resting elements will be bigger too
while(j < distances.length && distances[j] < maxDistance){ while (j < distances.length && distances[j] < maxDistance) {
perBinCount[i] ++ perBinCount[i]++
j++ j++
} }
} }
const perBinMessage = Utils.NoNull(perBinCount.map((count, i) => { const perBinMessage = Utils.NoNull(perBinCount.map((count, i) => {
if(count === 0){ if (count === 0) {
return undefined return undefined
} }
const maxD =maxDistances[i] const maxD = maxDistances[i]
let key = `change_within_${maxD}m` let key = `change_within_${maxD}m`
if(maxD === Number.MAX_VALUE){ if (maxD === Number.MAX_VALUE) {
key = `change_over_${maxDistances[i - 1]}m` key = `change_over_${maxDistances[i - 1]}m`
} }
return { return {
key , key,
value: count, value: count,
aggregate:true aggregate: true
} }
})) }))
// This method is only called with changedescriptions for this theme // This method is only called with changedescriptions for this theme
const theme = pending[0].meta.theme const theme = pending[0].meta.theme
const metatags : ChangesetTag[] = [{ const metatags: ChangesetTag[] = [{
key: "comment", key: "comment",
value: "Adding data with #MapComplete for theme #" + theme value: "Adding data with #MapComplete for theme #" + theme
}, },