forked from MapComplete/MapComplete
		
	GeoOperations.distanceBetween now uses meters, fix GPS tracking
This commit is contained in:
		
							parent
							
								
									79012c42ab
								
							
						
					
					
						commit
						680e56397d
					
				
					 10 changed files with 40 additions and 40 deletions
				
			
		|  | @ -90,7 +90,7 @@ export class ExtraFunction { | |||
|     private static readonly DistanceToFunc = new ExtraFunction( | ||||
|         { | ||||
|             name: "distanceTo", | ||||
|             doc: "Calculates the distance between the feature and a specified point in kilometer. The input should either be a pair of coordinates, a geojson feature or the ID of an object", | ||||
|             doc: "Calculates the distance between the feature and a specified point in meter. The input should either be a pair of coordinates, a geojson feature or the ID of an object", | ||||
|             args: ["feature OR featureID OR longitude", "undefined OR latitude"] | ||||
|         }, | ||||
|         (featuresPerLayer, feature) => { | ||||
|  |  | |||
|  | @ -30,12 +30,12 @@ export class GeoOperations { | |||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns the distance between the two points in kilometers | ||||
|      * Returns the distance between the two points in meters | ||||
|      * @param lonlat0 | ||||
|      * @param lonlat1 | ||||
|      */ | ||||
|     static distanceBetween(lonlat0: [number, number], lonlat1: [number, number]) { | ||||
|         return turf.distance(lonlat0, lonlat1) | ||||
|         return turf.distance(lonlat0, lonlat1) * 1000 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  |  | |||
|  | @ -111,12 +111,12 @@ export default class CreateNewNodeAction extends OsmChangeAction { | |||
|         // We check that it isn't close to an already existing point
 | ||||
|         let reusedPointId = undefined; | ||||
|         const prev = <[number, number]>geojson.geometry.coordinates[index] | ||||
|         if (GeoOperations.distanceBetween(prev, <[number, number]>projected.geometry.coordinates) * 1000 < this._reusePointDistance) { | ||||
|         if (GeoOperations.distanceBetween(prev, <[number, number]>projected.geometry.coordinates) < this._reusePointDistance) { | ||||
|             // We reuse this point instead!
 | ||||
|             reusedPointId = this._snapOnto.nodes[index] | ||||
|         } | ||||
|         const next = <[number, number]>geojson.geometry.coordinates[index + 1] | ||||
|         if (GeoOperations.distanceBetween(next, <[number, number]>projected.geometry.coordinates) * 1000 < this._reusePointDistance) { | ||||
|         if (GeoOperations.distanceBetween(next, <[number, number]>projected.geometry.coordinates) < this._reusePointDistance) { | ||||
|             // We reuse this point instead!
 | ||||
|             reusedPointId = this._snapOnto.nodes[index + 1] | ||||
|         } | ||||
|  |  | |||
|  | @ -225,7 +225,7 @@ export default class CreateWayWithPointReuseAction extends OsmChangeAction { | |||
|             const coor = coordinates[i] | ||||
|             // Check closeby (and probably identical) point further in the coordinate list, mark them as duplicate
 | ||||
|             for (let j = i + 1; j < coordinates.length; j++) { | ||||
|                 if (1000 * GeoOperations.distanceBetween(coor, coordinates[j]) < 0.1) { | ||||
|                 if (GeoOperations.distanceBetween(coor, coordinates[j]) < 0.1) { | ||||
|                     coordinateInfo[j] = { | ||||
|                         lngLat: coor, | ||||
|                         identicalTo: i | ||||
|  | @ -244,7 +244,7 @@ export default class CreateWayWithPointReuseAction extends OsmChangeAction { | |||
|             }[] = [] | ||||
|             for (const node of allNodes) { | ||||
|                 const center = node.geometry.coordinates | ||||
|                 const d = 1000 * GeoOperations.distanceBetween(coor, center) | ||||
|                 const d = GeoOperations.distanceBetween(coor, center) | ||||
|                 if (d > maxDistance) { | ||||
|                     continue | ||||
|                 } | ||||
|  |  | |||
|  | @ -62,7 +62,7 @@ export default class ReplaceGeometryAction extends OsmChangeAction { | |||
|                 continue | ||||
|             } | ||||
|             for (let j = i + 1; j < coordinates.length; j++) { | ||||
|                 const d = 1000 * GeoOperations.distanceBetween(coordinates[i], coordinates[j]) | ||||
|                 const d = GeoOperations.distanceBetween(coordinates[i], coordinates[j]) | ||||
|                 if (d < 0.1) { | ||||
|                     console.log("Identical coordinates detected: ", i, " and ", j, ": ", coordinates[i], coordinates[j], "distance is", d) | ||||
|                     this.identicalTo[j] = i | ||||
|  |  | |||
|  | @ -172,7 +172,7 @@ export class Changes { | |||
|         return Math.min(...changedObjectCoordinates.map(coor => | ||||
|             Math.min(...recentLocationPoints.map(gpsPoint => { | ||||
|                 const otherCoor = GeoOperations.centerpointCoordinates(gpsPoint) | ||||
|                 return GeoOperations.distanceBetween(coor, otherCoor) * 1000 | ||||
|                 return GeoOperations.distanceBetween(coor, otherCoor) | ||||
|             })) | ||||
|         )) | ||||
|     } | ||||
|  |  | |||
|  | @ -57,7 +57,7 @@ export default class MapState extends UserRelatedState { | |||
|     /** | ||||
|      * The number of seconds that the GPS-locations are stored in memory | ||||
|      */ | ||||
|     public gpsLocationHistoryRetentionTime = new UIEventSource(7 * 24 * 60 * 60, "gps_location_retention" ) | ||||
|     public gpsLocationHistoryRetentionTime = new UIEventSource(7 * 24 * 60 * 60, "gps_location_retention") | ||||
|     public historicalUserLocationsTrack: FeatureSourceForLayer & Tiled; | ||||
| 
 | ||||
|     /** | ||||
|  | @ -77,7 +77,7 @@ export default class MapState extends UserRelatedState { | |||
|      */ | ||||
|     public overlayToggles: { config: TilesourceConfig, isDisplayed: UIEventSource<boolean> }[] | ||||
| 
 | ||||
|    | ||||
| 
 | ||||
|     constructor(layoutToUse: LayoutConfig) { | ||||
|         super(layoutToUse); | ||||
| 
 | ||||
|  | @ -139,7 +139,7 @@ export default class MapState extends UserRelatedState { | |||
| 
 | ||||
|         this.lockBounds() | ||||
|         this.AddAllOverlaysToMap(this.leafletMap) | ||||
|          | ||||
| 
 | ||||
|         this.initHomeLocation() | ||||
|         this.initGpsLocation() | ||||
|         this.initUserLocationTrail() | ||||
|  | @ -187,15 +187,15 @@ export default class MapState extends UserRelatedState { | |||
|             }) | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     private initGpsLocation(){ | ||||
| 
 | ||||
|     private initGpsLocation() { | ||||
|         // Initialize the gps layer data. This is emtpy for now, the actual writing happens in the Geolocationhandler
 | ||||
|         let gpsLayerDef: FilteredLayer = this.filteredLayers.data.filter(l => l.layerDef.id === "gps_location")[0] | ||||
|         this.currentUserLocation = new SimpleFeatureSource(gpsLayerDef, Tiles.tile_index(0, 0, 0)); | ||||
|     } | ||||
|      | ||||
|     private initUserLocationTrail(){ | ||||
|         const features = LocalStorageSource.GetParsed<{feature: any, freshness: Date}[]>("gps_location_history", []) | ||||
| 
 | ||||
|     private initUserLocationTrail() { | ||||
|         const features = LocalStorageSource.GetParsed<{ feature: any, freshness: Date }[]>("gps_location_history", []) | ||||
|         const now = new Date().getTime() | ||||
|         features.data = features.data | ||||
|             .map(ff => ({feature: ff.feature, freshness: new Date(ff.freshness)})) | ||||
|  | @ -204,59 +204,59 @@ export default class MapState extends UserRelatedState { | |||
|         const self = this; | ||||
|         let i = 0 | ||||
|         this.currentUserLocation.features.addCallbackAndRunD(([location]) => { | ||||
|             if(location === undefined){ | ||||
|             if (location === undefined) { | ||||
|                 return; | ||||
|             } | ||||
|              | ||||
| 
 | ||||
|             const previousLocation = features.data[features.data.length - 1] | ||||
|             if(previousLocation !== undefined){ | ||||
|             if (previousLocation !== undefined) { | ||||
|                 const d = GeoOperations.distanceBetween( | ||||
|                     previousLocation.feature.geometry.coordinates, | ||||
|                     location.feature.geometry.coordinates | ||||
| 
 | ||||
|                 ) | ||||
|                 if(d < 20){ | ||||
|                 let timeDiff = Number.MAX_VALUE // in seconds
 | ||||
|                 const olderLocation = features.data[features.data.length - 2] | ||||
|                 if (olderLocation !== undefined) { | ||||
|                     timeDiff = (previousLocation.freshness.getTime() - olderLocation.freshness.getTime()) / 1000 | ||||
|                 } | ||||
|                 if (d < 20 && timeDiff < 60) { | ||||
|                     // Do not append changes less then 20m - it's probably noise anyway
 | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|              | ||||
| 
 | ||||
|             const feature = JSON.parse(JSON.stringify(location.feature)) | ||||
|             feature.properties.id = "gps/"+features.data.length | ||||
|             feature.properties.id = "gps/" + features.data.length | ||||
|             i++ | ||||
|             features.data.push({feature, freshness: new Date()}) | ||||
|             features.ping() | ||||
|         }) | ||||
|          | ||||
|          | ||||
| 
 | ||||
| 
 | ||||
|         let gpsLayerDef: FilteredLayer = this.filteredLayers.data.filter(l => l.layerDef.id === "gps_location_history")[0] | ||||
|         this.historicalUserLocations = new SimpleFeatureSource(gpsLayerDef, Tiles.tile_index(0, 0, 0), features); | ||||
|         this.changes.useLocationHistory(this) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         | ||||
|          | ||||
|         const asLine = features.map(allPoints => { | ||||
|             if(allPoints === undefined || allPoints.length < 2){ | ||||
|             if (allPoints === undefined || allPoints.length < 2) { | ||||
|                 return [] | ||||
|             } | ||||
| 
 | ||||
|             const feature = { | ||||
|                 type: "Feature", | ||||
|                 properties:{ | ||||
|                     "id":"location_track", | ||||
|                 properties: { | ||||
|                     "id": "location_track", | ||||
|                     "_date:now": new Date().toISOString(), | ||||
|                 }, | ||||
|                 geometry:{ | ||||
|                 geometry: { | ||||
|                     type: "LineString", | ||||
|                     coordinates: allPoints.map(ff => ff.feature.geometry.coordinates) | ||||
|                 } | ||||
|             } | ||||
|              | ||||
| 
 | ||||
|             self.allElements.ContainingFeatures.set(feature.properties.id, feature) | ||||
|              | ||||
| 
 | ||||
|             return [{ | ||||
|                 feature, | ||||
|                 freshness: new Date() | ||||
|  | @ -286,7 +286,7 @@ export default class MapState extends UserRelatedState { | |||
|                 feature: { | ||||
|                     "type": "Feature", | ||||
|                     "properties": { | ||||
|                         "id":"home", | ||||
|                         "id": "home", | ||||
|                         "user:home": "yes", | ||||
|                         "_lon": homeLonLat[0], | ||||
|                         "_lat": homeLonLat[1] | ||||
|  |  | |||
|  | @ -136,7 +136,7 @@ export default class LengthInput extends InputElement<string> { | |||
|                 if (leaflet) { | ||||
|                     const first = leaflet.layerPointToLatLng(firstClickXY) | ||||
|                     const last = leaflet.layerPointToLatLng([dx, dy]) | ||||
|                     const geoDist = Math.floor(GeoOperations.distanceBetween([first.lng, first.lat], [last.lng, last.lat]) * 10000) / 10 | ||||
|                     const geoDist = Math.floor(GeoOperations.distanceBetween([first.lng, first.lat], [last.lng, last.lat]) * 10) / 10 | ||||
|                     self.value.setData("" + geoDist) | ||||
|                 } | ||||
| 
 | ||||
|  |  | |||
|  | @ -93,7 +93,7 @@ export default class SplitRoadWizard extends Toggle { | |||
|         function onMapClick(coordinates) { | ||||
|             // First, we check if there is another, already existing point nearby
 | ||||
|             const points = splitPoints.data.map((f, i) => [f.feature, i]) | ||||
|                 .filter(p => GeoOperations.distanceBetween(p[0].geometry.coordinates, coordinates) * 1000 < 5) | ||||
|                 .filter(p => GeoOperations.distanceBetween(p[0].geometry.coordinates, coordinates) < 5) | ||||
|                 .map(p => p[1]) | ||||
|                 .sort((a, b) => a - b) | ||||
|                 .reverse() | ||||
|  |  | |||
|  | @ -34,7 +34,7 @@ | |||
|   "calculatedTags": [ | ||||
|     "_closest_other_drinking_water=feat.closestn('drinking_water', 1, undefined, 5000).map(f => ({id: f.feat.id, distance: ''+f.distance}))[0]", | ||||
|     "_closest_other_drinking_water_id=JSON.parse(feat.properties._closest_other_drinking_water)?.id", | ||||
|     "_closest_other_drinking_water_distance=Math.floor(Number(JSON.parse(feat.properties._closest_other_drinking_water)?.distance) * 1000)" | ||||
|     "_closest_other_drinking_water_distance=Math.floor(Number(JSON.parse(feat.properties._closest_other_drinking_water)?.distance))" | ||||
|   ], | ||||
|   "minzoom": 13, | ||||
|   "presets": [ | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue