mirror of
https://forge.chapril.org/tykayn/wololo
synced 2025-06-20 01:34:42 +02:00
add config maxspeed and Echirolles, up script get datasets, start conflation of geojsons
This commit is contained in:
parent
9b5baab032
commit
aa35803a0b
5 changed files with 518 additions and 82 deletions
382
conflate_geojson_with_osm.ts
Normal file
382
conflate_geojson_with_osm.ts
Normal file
|
@ -0,0 +1,382 @@
|
||||||
|
/**
|
||||||
|
* conflate_geojson_with_osm.ts
|
||||||
|
*
|
||||||
|
* Réalise une conflation entre un fichier GeoJSON local et des données OSM via Overpass
|
||||||
|
* en fusionnant les points proches (distance configurable).
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* npx ts-node conflate_geojson_with_osm.ts <geojson_file> <distance_max_en_metres> <overpass_request>
|
||||||
|
*
|
||||||
|
* Exemple:
|
||||||
|
* npx ts-node conflate_geojson_with_osm.ts data/bornes.geojson 100 "area[name='Limours']->.a;nwr[amenity=charging_station](area.a);"
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import axios from 'axios';
|
||||||
|
import * as turf from '@turf/turf';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
interface GeoJSONGeometry {
|
||||||
|
type: string;
|
||||||
|
coordinates: number[] | number[][] | number[][][] | number[][][][];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GeoJSONProperties {
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GeoJSONFeature {
|
||||||
|
type: string;
|
||||||
|
id?: string | number;
|
||||||
|
geometry: GeoJSONGeometry;
|
||||||
|
properties: GeoJSONProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GeoJSONCollection {
|
||||||
|
type: string;
|
||||||
|
features: GeoJSONFeature[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OverpassElement {
|
||||||
|
type: string;
|
||||||
|
id: number;
|
||||||
|
lat?: number;
|
||||||
|
lon?: number;
|
||||||
|
tags?: {
|
||||||
|
[key: string]: string;
|
||||||
|
};
|
||||||
|
nodes?: number[];
|
||||||
|
geometry?: {
|
||||||
|
lat: number;
|
||||||
|
lon: number;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OverpassResponse {
|
||||||
|
version: number;
|
||||||
|
generator: string;
|
||||||
|
osm3s: {
|
||||||
|
timestamp_osm_base: string;
|
||||||
|
copyright: string;
|
||||||
|
};
|
||||||
|
elements: OverpassElement[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MatchedFeaturePair {
|
||||||
|
localFeature: GeoJSONFeature;
|
||||||
|
osmFeature: GeoJSONFeature;
|
||||||
|
distance: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vérifie les arguments et retourne les valeurs
|
||||||
|
*/
|
||||||
|
function checkArguments(): { filePath: string, distance: number, overpassQuery: string } {
|
||||||
|
if (process.argv.length < 5) {
|
||||||
|
console.error("Usage: npx ts-node conflate_geojson_with_osm.ts <geojson_file> <distance_max_en_metres> <overpass_request>");
|
||||||
|
console.error("Exemple: npx ts-node conflate_geojson_with_osm.ts data/bornes.geojson 100 \"area[name='Limours']->.a;nwr[amenity=charging_station](area.a);\"");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const filePath = process.argv[2];
|
||||||
|
const distance = parseFloat(process.argv[3]);
|
||||||
|
const overpassQuery = process.argv[4];
|
||||||
|
|
||||||
|
if (isNaN(distance)) {
|
||||||
|
console.error("La distance doit être un nombre (en mètres)");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { filePath, distance, overpassQuery };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Charge les données GeoJSON à partir d'un fichier
|
||||||
|
*/
|
||||||
|
function loadLocalGeoJSON(filePath: string): GeoJSONCollection {
|
||||||
|
try {
|
||||||
|
const fileContent = fs.readFileSync(filePath, 'utf8');
|
||||||
|
const data = JSON.parse(fileContent);
|
||||||
|
|
||||||
|
if (data.type !== 'FeatureCollection' || !Array.isArray(data.features)) {
|
||||||
|
console.error("Le fichier ne semble pas être un GeoJSON valide avec des features");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Erreur lors du chargement du fichier: ${error}`);
|
||||||
|
process.exit(1);
|
||||||
|
throw error; // Pour TypeScript
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Récupère les données depuis Overpass API
|
||||||
|
*/
|
||||||
|
async function fetchOverpassData(query: string): Promise<GeoJSONCollection> {
|
||||||
|
try {
|
||||||
|
console.log("Récupération des données depuis Overpass API...");
|
||||||
|
console.log(`Requête: ${query}`);
|
||||||
|
|
||||||
|
const encodedQuery = encodeURIComponent(query);
|
||||||
|
const url = `https://overpass-api.de/api/interpreter?data=[out:json][timeout:25];${encodedQuery}out body geom;`;
|
||||||
|
|
||||||
|
const response = await axios.get(url);
|
||||||
|
const overpassData: OverpassResponse = response.data;
|
||||||
|
|
||||||
|
console.log(`${overpassData.elements.length} éléments récupérés depuis Overpass`);
|
||||||
|
|
||||||
|
// Convertir les données Overpass en GeoJSON
|
||||||
|
return convertOverpassToGeoJSON(overpassData);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Erreur lors de la récupération des données Overpass:", error);
|
||||||
|
process.exit(1);
|
||||||
|
throw error; // Pour TypeScript
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convertit les données Overpass en GeoJSON
|
||||||
|
*/
|
||||||
|
function convertOverpassToGeoJSON(overpassData: OverpassResponse): GeoJSONCollection {
|
||||||
|
const features: GeoJSONFeature[] = [];
|
||||||
|
|
||||||
|
overpassData.elements.forEach(element => {
|
||||||
|
let geometry: GeoJSONGeometry;
|
||||||
|
let properties: GeoJSONProperties = { ...element.tags, id_osm: element.id, type_osm: element.type };
|
||||||
|
|
||||||
|
// Nœud (point)
|
||||||
|
if (element.type === 'node' && element.lat !== undefined && element.lon !== undefined) {
|
||||||
|
geometry = {
|
||||||
|
type: 'Point',
|
||||||
|
coordinates: [element.lon, element.lat]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Chemin (ligne ou polygone)
|
||||||
|
else if (element.type === 'way' && element.geometry) {
|
||||||
|
const coordinates = element.geometry.map(point => [point.lon, point.lat]);
|
||||||
|
|
||||||
|
// Si le premier et le dernier point sont identiques, c'est un polygone
|
||||||
|
if (element.nodes && element.nodes[0] === element.nodes[element.nodes.length - 1]) {
|
||||||
|
geometry = {
|
||||||
|
type: 'Polygon',
|
||||||
|
coordinates: [coordinates]
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
geometry = {
|
||||||
|
type: 'LineString',
|
||||||
|
coordinates: coordinates
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Relation (multipolygon, etc.)
|
||||||
|
else if (element.type === 'relation') {
|
||||||
|
// Pour les relations, on crée un point à partir du centre de la géométrie si disponible
|
||||||
|
// Une gestion complète des relations nécessiterait plus de logique
|
||||||
|
if (element.lat !== undefined && element.lon !== undefined) {
|
||||||
|
geometry = {
|
||||||
|
type: 'Point',
|
||||||
|
coordinates: [element.lon, element.lat]
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return; // Skip this element
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return; // Skip this element
|
||||||
|
}
|
||||||
|
|
||||||
|
features.push({
|
||||||
|
type: 'Feature',
|
||||||
|
id: element.id,
|
||||||
|
geometry,
|
||||||
|
properties
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'FeatureCollection',
|
||||||
|
features
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trouve les paires de points correspondants entre local et OSM
|
||||||
|
*/
|
||||||
|
function findMatchingFeatures(localGeoJSON: GeoJSONCollection, osmGeoJSON: GeoJSONCollection, maxDistance: number): MatchedFeaturePair[] {
|
||||||
|
const matches: MatchedFeaturePair[] = [];
|
||||||
|
|
||||||
|
// Pour chaque feature locale, trouver la feature OSM la plus proche
|
||||||
|
localGeoJSON.features.forEach(localFeature => {
|
||||||
|
if (localFeature.geometry.type !== 'Point') return;
|
||||||
|
|
||||||
|
let closestOsmFeature: GeoJSONFeature | null = null;
|
||||||
|
let minDistance = Infinity;
|
||||||
|
|
||||||
|
osmGeoJSON.features.forEach(osmFeature => {
|
||||||
|
// Si ce n'est pas un point, on passe
|
||||||
|
if (osmFeature.geometry.type !== 'Point') return;
|
||||||
|
|
||||||
|
// Calculer la distance
|
||||||
|
const from = turf.point(localFeature.geometry.coordinates as [number, number]);
|
||||||
|
const to = turf.point(osmFeature.geometry.coordinates as [number, number]);
|
||||||
|
const distance = turf.distance(from, to, { units: 'meters' });
|
||||||
|
|
||||||
|
// Mettre à jour si c'est la distance minimale trouvée
|
||||||
|
if (distance < minDistance) {
|
||||||
|
minDistance = distance;
|
||||||
|
closestOsmFeature = osmFeature;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Si on a trouvé une feature proche, l'ajouter aux correspondances
|
||||||
|
if (closestOsmFeature && minDistance <= maxDistance) {
|
||||||
|
matches.push({
|
||||||
|
localFeature,
|
||||||
|
osmFeature: closestOsmFeature,
|
||||||
|
distance: minDistance
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fusionne les propriétés de deux features
|
||||||
|
*/
|
||||||
|
function mergeProperties(localProps: GeoJSONProperties, osmProps: GeoJSONProperties): GeoJSONProperties {
|
||||||
|
const result: GeoJSONProperties = { ...localProps };
|
||||||
|
|
||||||
|
// Ajouter les propriétés OSM qui n'existent pas dans les données locales
|
||||||
|
// ou dont la valeur est vide
|
||||||
|
Object.entries(osmProps).forEach(([key, value]) => {
|
||||||
|
// Si la propriété n'existe pas ou est vide localement, on prend celle d'OSM
|
||||||
|
if (result[key] === undefined || result[key] === '' || result[key] === null) {
|
||||||
|
result[key] = value;
|
||||||
|
}
|
||||||
|
// Si les deux ont une valeur, on peut préférer celle d'OSM pour certaines clés
|
||||||
|
else if (['name', 'operator', 'opening_hours', 'website', 'phone', 'brand'].includes(key)) {
|
||||||
|
// On garde l'info qu'il y a une différence
|
||||||
|
result[`local_${key}`] = result[key];
|
||||||
|
result[key] = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Marquer comme ayant été fusionné
|
||||||
|
result.conflated = true;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Génère le GeoJSON final après conflation
|
||||||
|
*/
|
||||||
|
function generateConflatedGeoJSON(
|
||||||
|
localGeoJSON: GeoJSONCollection,
|
||||||
|
osmGeoJSON: GeoJSONCollection,
|
||||||
|
matches: MatchedFeaturePair[]
|
||||||
|
): GeoJSONCollection {
|
||||||
|
const conflatedFeatures: GeoJSONFeature[] = [];
|
||||||
|
const localFeaturesMatched = new Set<GeoJSONFeature>();
|
||||||
|
const osmFeaturesMatched = new Set<GeoJSONFeature>();
|
||||||
|
|
||||||
|
// 1. Ajouter les features fusionnées
|
||||||
|
matches.forEach(match => {
|
||||||
|
const mergedProps = mergeProperties(match.localFeature.properties, match.osmFeature.properties);
|
||||||
|
mergedProps.conflated_distance = match.distance;
|
||||||
|
|
||||||
|
// On utilise la géométrie d'OSM (plus précise)
|
||||||
|
const conflatedFeature: GeoJSONFeature = {
|
||||||
|
type: 'Feature',
|
||||||
|
geometry: match.osmFeature.geometry,
|
||||||
|
properties: mergedProps
|
||||||
|
};
|
||||||
|
|
||||||
|
conflatedFeatures.push(conflatedFeature);
|
||||||
|
localFeaturesMatched.add(match.localFeature);
|
||||||
|
osmFeaturesMatched.add(match.osmFeature);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2. Ajouter les features locales non matchées
|
||||||
|
localGeoJSON.features
|
||||||
|
.filter(feature => !localFeaturesMatched.has(feature))
|
||||||
|
.forEach(feature => {
|
||||||
|
const props = { ...feature.properties, source: 'local_only' };
|
||||||
|
conflatedFeatures.push({
|
||||||
|
type: 'Feature',
|
||||||
|
geometry: feature.geometry,
|
||||||
|
properties: props
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 3. Ajouter les features OSM non matchées
|
||||||
|
osmGeoJSON.features
|
||||||
|
.filter(feature => !osmFeaturesMatched.has(feature))
|
||||||
|
.forEach(feature => {
|
||||||
|
const props = { ...feature.properties, source: 'osm_only' };
|
||||||
|
conflatedFeatures.push({
|
||||||
|
type: 'Feature',
|
||||||
|
geometry: feature.geometry,
|
||||||
|
properties: props
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: 'FeatureCollection',
|
||||||
|
features: conflatedFeatures
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Écrit le GeoJSON dans un fichier
|
||||||
|
*/
|
||||||
|
function writeGeoJSONToFile(geojson: GeoJSONCollection, filename: string): void {
|
||||||
|
fs.writeFileSync(filename, JSON.stringify(geojson, null, 2));
|
||||||
|
console.log(`Fichier écrit: ${filename}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fonction principale
|
||||||
|
*/
|
||||||
|
async function main(): Promise<void> {
|
||||||
|
// Récupérer les arguments
|
||||||
|
const { filePath, distance, overpassQuery } = checkArguments();
|
||||||
|
|
||||||
|
// Charger les données locales
|
||||||
|
console.log(`Chargement des données depuis ${filePath}...`);
|
||||||
|
const localGeoJSON = loadLocalGeoJSON(filePath);
|
||||||
|
console.log(`${localGeoJSON.features.length} features chargées depuis le fichier local`);
|
||||||
|
|
||||||
|
// Récupérer les données OSM
|
||||||
|
const osmGeoJSON = await fetchOverpassData(overpassQuery);
|
||||||
|
|
||||||
|
// Trouver les correspondances
|
||||||
|
console.log(`Recherche des correspondances (distance max: ${distance}m)...`);
|
||||||
|
const matches = findMatchingFeatures(localGeoJSON, osmGeoJSON, distance);
|
||||||
|
console.log(`${matches.length} correspondances trouvées`);
|
||||||
|
|
||||||
|
// Générer le GeoJSON conflated
|
||||||
|
console.log("Génération du GeoJSON après conflation...");
|
||||||
|
const conflatedGeoJSON = generateConflatedGeoJSON(localGeoJSON, osmGeoJSON, matches);
|
||||||
|
|
||||||
|
// Statistiques
|
||||||
|
const localOnly = conflatedGeoJSON.features.filter(f => f.properties.source === 'local_only').length;
|
||||||
|
const osmOnly = conflatedGeoJSON.features.filter(f => f.properties.source === 'osm_only').length;
|
||||||
|
const conflated = conflatedGeoJSON.features.filter(f => f.properties.conflated).length;
|
||||||
|
|
||||||
|
console.log("\n=== Résultats de la conflation ===");
|
||||||
|
console.log(`Total des features: ${conflatedGeoJSON.features.length}`);
|
||||||
|
console.log(`- Features fusionnées: ${conflated}`);
|
||||||
|
console.log(`- Features locales uniquement: ${localOnly}`);
|
||||||
|
console.log(`- Features OSM uniquement: ${osmOnly}`);
|
||||||
|
|
||||||
|
// Écrire les résultats dans des fichiers
|
||||||
|
const basename = path.basename(filePath, path.extname(filePath));
|
||||||
|
writeGeoJSONToFile(localGeoJSON, `${basename}_local.geojson`);
|
||||||
|
writeGeoJSONToFile(osmGeoJSON, `${basename}_osm.geojson`);
|
||||||
|
writeGeoJSONToFile(conflatedGeoJSON, `${basename}_conflated.geojson`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exécuter le programme
|
||||||
|
main().catch(console.error);
|
|
@ -22,6 +22,9 @@ interface Options {
|
||||||
hasHeaders: boolean;
|
hasHeaders: boolean;
|
||||||
}
|
}
|
||||||
let counter = 0;
|
let counter = 0;
|
||||||
|
let counter_features = 0;
|
||||||
|
let counter_missing_lat = 0;
|
||||||
|
let counter_missing_lon = 0;
|
||||||
function csvToGeoJSON(options: Options): FeatureCollection<Point> {
|
function csvToGeoJSON(options: Options): FeatureCollection<Point> {
|
||||||
const { dir, file, latColumn, lonColumn, hasHeaders } = options;
|
const { dir, file, latColumn, lonColumn, hasHeaders } = options;
|
||||||
|
|
||||||
|
@ -38,13 +41,12 @@ function csvToGeoJSON(options: Options): FeatureCollection<Point> {
|
||||||
let headers: string[] = [];
|
let headers: string[] = [];
|
||||||
let headersFound = false;
|
let headersFound = false;
|
||||||
|
|
||||||
let limitOffset = 100;
|
let limitOffset = 30000000;
|
||||||
|
|
||||||
console.log(`hasHeaders: ${hasHeaders}`);
|
|
||||||
fs.createReadStream(filePath)
|
fs.createReadStream(filePath)
|
||||||
.pipe(csvParser({ headers: hasHeaders }))
|
.pipe(csvParser({ headers: hasHeaders }))
|
||||||
.on('data', (row) => {
|
.on('data', (row) => {
|
||||||
counter++;
|
counter += 1;
|
||||||
if (!headersFound && hasHeaders) {
|
if (!headersFound && hasHeaders) {
|
||||||
let keys = Object.keys(row);
|
let keys = Object.keys(row);
|
||||||
keys.forEach((key) => {
|
keys.forEach((key) => {
|
||||||
|
@ -56,11 +58,7 @@ function csvToGeoJSON(options: Options): FeatureCollection<Point> {
|
||||||
if (counter > limitOffset) {
|
if (counter > limitOffset) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (headers.indexOf(latColumn)) {
|
if (headers.indexOf(latColumn) && headers.indexOf(lonColumn)) {
|
||||||
console.log(`latColumn: ${latColumn}`);
|
|
||||||
console.log(`headers latColumn: ${headers.indexOf(latColumn)}`);
|
|
||||||
console.log(`headers.indexOf(latColumn): `, headers.indexOf(latColumn));
|
|
||||||
console.log('row', row);
|
|
||||||
const lat = parseFloat(row['_' + headers.indexOf(latColumn)]);
|
const lat = parseFloat(row['_' + headers.indexOf(latColumn)]);
|
||||||
const lon = parseFloat(row['_' + headers.indexOf(lonColumn)]);
|
const lon = parseFloat(row['_' + headers.indexOf(lonColumn)]);
|
||||||
|
|
||||||
|
@ -83,21 +81,28 @@ function csvToGeoJSON(options: Options): FeatureCollection<Point> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// filtrer la ligne du header si présente
|
// filtrer la ligne du header si présente
|
||||||
if (hasHeaders && counter > 1 || !hasHeaders || counter > limitOffset) {
|
if (lon && lat) {
|
||||||
features.push({
|
if (hasHeaders && counter > 1 || !hasHeaders || counter > limitOffset) {
|
||||||
type: 'Feature',
|
features.push({
|
||||||
geometry: {
|
type: 'Feature',
|
||||||
type: 'Point',
|
geometry: {
|
||||||
coordinates: [lon, lat],
|
type: 'Point',
|
||||||
},
|
coordinates: [lon, lat],
|
||||||
properties: row,
|
},
|
||||||
});
|
properties: row,
|
||||||
|
});
|
||||||
|
counter_features += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (headers.indexOf(latColumn) === -1) {
|
||||||
|
console.log('!!! no latColumn', row);
|
||||||
|
counter_missing_lat += 1;
|
||||||
|
}
|
||||||
|
if (headers.indexOf(lonColumn) === -1) {
|
||||||
|
console.log('!!! no lonColumn', row);
|
||||||
|
counter_missing_lon += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
console.log('!!! no latColumn', row);
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
})
|
||||||
.on('end', () => {
|
.on('end', () => {
|
||||||
geoJSON = {
|
geoJSON = {
|
||||||
|
@ -106,9 +111,12 @@ function csvToGeoJSON(options: Options): FeatureCollection<Point> {
|
||||||
};
|
};
|
||||||
fs.writeFileSync(`${dir}/${file}.geojson`, JSON.stringify(geoJSON, null, 2));
|
fs.writeFileSync(`${dir}/${file}.geojson`, JSON.stringify(geoJSON, null, 2));
|
||||||
console.log(`GeoJSON créé avec succès : ${file}.geojson`);
|
console.log(`GeoJSON créé avec succès : ${file}.geojson`);
|
||||||
|
console.log(`geoJSON lines: ${counter}`);
|
||||||
|
console.log(`geoJSON lines missing lat: ${counter_missing_lat}`);
|
||||||
|
console.log(`geoJSON lines missing lon: ${counter_missing_lon}`);
|
||||||
|
console.log(`geoJSON lines features: ${counter_features}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`geoJSON lines: ${counter}`);
|
|
||||||
return geoJSON;
|
return geoJSON;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,7 +154,26 @@ function checkFile(args: Options) {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
function countGeoJSONFeatures(args: Options) {
|
||||||
|
const filePath = path.join(args.dir, `${args.file}.geojson`);
|
||||||
|
|
||||||
|
// Vérifier si le fichier GeoJSON existe
|
||||||
|
if (!fs.existsSync(filePath)) {
|
||||||
|
console.log(`Le fichier GeoJSON ${filePath} n'existe pas`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lire et parser le fichier GeoJSON
|
||||||
|
const geoJSON = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
||||||
|
|
||||||
|
// Compter le nombre de features
|
||||||
|
const featureCount = geoJSON.features?.length || 0;
|
||||||
|
|
||||||
|
console.log(`Nombre de features dans le GeoJSON : ${featureCount}`);
|
||||||
|
return featureCount;
|
||||||
|
}
|
||||||
|
|
||||||
console.log(`args: `, args);
|
|
||||||
checkFile(args);
|
checkFile(args);
|
||||||
csvToGeoJSON(args);
|
csvToGeoJSON(args);
|
||||||
|
// Appeler la fonction après la création du GeoJSON
|
||||||
|
countGeoJSONFeatures(args);
|
||||||
|
|
|
@ -17,7 +17,10 @@ const MappingArbresEchirolles: MappingConfigType = {
|
||||||
// source: undefined,
|
// source: undefined,
|
||||||
config_name: 'Mapping des arbres d\'Echirolles',
|
config_name: 'Mapping des arbres d\'Echirolles',
|
||||||
config_author: 'tykayn <contact+geojson2osm@cipherbliss.com>',
|
config_author: 'tykayn <contact+geojson2osm@cipherbliss.com>',
|
||||||
default_properties_of_point: {natural: 'tree', source : 'Échirolles Métropole'},
|
default_properties_of_point: {
|
||||||
|
natural: 'tree',
|
||||||
|
source: 'Échirolles Métropole'
|
||||||
|
},
|
||||||
tags: {
|
tags: {
|
||||||
// ******* booléens
|
// ******* booléens
|
||||||
// ******* nombres
|
// ******* nombres
|
||||||
|
@ -27,27 +30,27 @@ const MappingArbresEchirolles: MappingConfigType = {
|
||||||
"nom_latin": {
|
"nom_latin": {
|
||||||
key_converted: "species",
|
key_converted: "species",
|
||||||
conditional_values: {
|
conditional_values: {
|
||||||
"Platanus acerifolia": {'tags_to_add': {"species:wikidata": "Q24853030"}},
|
"Platanus acerifolia": { 'tags_to_add': { "species:wikidata": "Q24853030" } },
|
||||||
"Tilia cordata": {'tags_to_add': {"wikidata": "species:Q158746"}},
|
"Tilia cordata": { 'tags_to_add': { "wikidata": "species:Q158746" } },
|
||||||
"Liriodendron tulipifera": {'tags_to_add': {"species:wikidata": "Q158783"}},
|
"Liriodendron tulipifera": { 'tags_to_add': { "species:wikidata": "Q158783" } },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// - CADUC_PERS : leaf_cycle=evergreen pour persistant , deciduous pour caduque
|
// - CADUC_PERS : leaf_cycle=evergreen pour persistant , deciduous pour caduque
|
||||||
// "caduc_pers": {
|
// "caduc_pers": {
|
||||||
// conditional_values: {
|
// conditional_values: {
|
||||||
// "Persistant ": {
|
// "Persistant ": {
|
||||||
// 'tags_to_add':{
|
// 'tags_to_add':{
|
||||||
// "leaf_cycle": "evergreen",
|
// "leaf_cycle": "evergreen",
|
||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
// "Caduc ": {
|
// "Caduc ": {
|
||||||
// 'tags_to_add':{
|
// 'tags_to_add':{
|
||||||
// "leaf_cycle": "deciduous",
|
// "leaf_cycle": "deciduous",
|
||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
// - FEUIL_CONI : feuillu leaf_type=broadleaved / connifère leaf_type=needleleaved
|
// - FEUIL_CONI : feuillu leaf_type=broadleaved / connifère leaf_type=needleleaved
|
||||||
// "feuil_coni": {
|
// "feuil_coni": {
|
||||||
// conditional_values: {
|
// conditional_values: {
|
||||||
|
@ -63,7 +66,7 @@ const MappingArbresEchirolles: MappingConfigType = {
|
||||||
// },
|
// },
|
||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
// - PARTICULAR : Majeur, Remarquable : historic=monument
|
// - PARTICULAR : Majeur, Remarquable : historic=monument
|
||||||
|
|
||||||
// "particular": {
|
// "particular": {
|
||||||
// conditional_values: {
|
// conditional_values: {
|
||||||
|
@ -80,27 +83,27 @@ const MappingArbresEchirolles: MappingConfigType = {
|
||||||
// },
|
// },
|
||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
// - FORME: tree_shape = curtain / free / half_free <= Architecturé, rideau / Libre / Semi-libre
|
// - FORME: tree_shape = curtain / free / half_free <= Architecturé, rideau / Libre / Semi-libre
|
||||||
// "forme": {
|
// "forme": {
|
||||||
// key_converted: "tree_shape",
|
// key_converted: "tree_shape",
|
||||||
// conditional_values: {
|
// conditional_values: {
|
||||||
// "Architecturé, rideau ": {
|
// "Architecturé, rideau ": {
|
||||||
// 'tags_to_add':{
|
// 'tags_to_add':{
|
||||||
// "tree_shape": "curtain",
|
// "tree_shape": "curtain",
|
||||||
// },
|
// },
|
||||||
// },
|
// },
|
||||||
// "Semi-libre ": {
|
// "Semi-libre ": {
|
||||||
// 'tags_to_add':{
|
// 'tags_to_add':{
|
||||||
// "tree_shape": "half_free",
|
// "tree_shape": "half_free",
|
||||||
// },
|
// },
|
||||||
// },
|
// },
|
||||||
// "Libre ": {
|
// "Libre ": {
|
||||||
// 'tags_to_add':{
|
// 'tags_to_add':{
|
||||||
// "tree_shape": "free",
|
// "tree_shape": "free",
|
||||||
// },
|
// },
|
||||||
// },
|
// },
|
||||||
// }
|
// }
|
||||||
// },
|
// },
|
||||||
|
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
40
mappings/converters/configPanneauxMaxSpeed.ts
Normal file
40
mappings/converters/configPanneauxMaxSpeed.ts
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/**
|
||||||
|
* panneaux de vitesse détectés sur panoramax
|
||||||
|
* utilisation:
|
||||||
|
*/
|
||||||
|
import { constrainedMemory } from "process";
|
||||||
|
import MappingConfigType from "../mapping-config.type";
|
||||||
|
|
||||||
|
const MappingPanneauxMaxSpeed: MappingConfigType = {
|
||||||
|
config_name: "MappingPanneauxMaxSpeed",
|
||||||
|
config_author: "tk",
|
||||||
|
default_properties_of_point: {
|
||||||
|
"traffic_sign": "FR:B14",
|
||||||
|
"maxspeed:source": "panoramax"
|
||||||
|
},
|
||||||
|
source: {
|
||||||
|
geojson_path: '',
|
||||||
|
url: ''
|
||||||
|
},
|
||||||
|
filters: {
|
||||||
|
// exclude_point_if_tag_not_empty: ['id_osm'], // exclure les points ayant déjà un id_osm pour éviter les doublons
|
||||||
|
// offset: 1
|
||||||
|
},
|
||||||
|
add_not_mapped_tags_too: false,
|
||||||
|
boolean_keys: [],
|
||||||
|
tags_to_ignore_if_value_is: ['Non renseigne'],
|
||||||
|
tags: {
|
||||||
|
"SourceFile": {
|
||||||
|
key_converted: 'maxspeed',
|
||||||
|
transform_function: (value: string) => {
|
||||||
|
let explode = value.split('-');
|
||||||
|
if (explode.length > 1) {
|
||||||
|
return explode[1];
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MappingPanneauxMaxSpeed;
|
|
@ -16,23 +16,12 @@ wget https://www.data.gouv.fr/fr/datasets/r/8d9398ae-3037-48b2-be19-412c24561fbb
|
||||||
|
|
||||||
echo "- OK IRVE"
|
echo "- OK IRVE"
|
||||||
echo "- récupérer les données présentes dans OpenStreetMap"
|
echo "- récupérer les données présentes dans OpenStreetMap"
|
||||||
curl --header "Content-Type: plain/text" --data @content_irve_geojson.txt --trace-ascii website-data.log "https://overpass-api.de/api/interpreter" > "irve_osm_latest.geojson"
|
curl --header "Content-Type: plain/text" --data @content_irve_geojson.txt --trace-ascii website-data.log "https://overpass-api.de/api/interpreter" >"irve_osm_latest.geojson"
|
||||||
|
|
||||||
echo "- récupérer les données présentes dans Osmose"
|
echo "- récupérer les données présentes dans Osmose"
|
||||||
wget "https://osmose.openstreetmap.fr/api/0.3/issues.geojson?full=true&status=open&item=8410&limit=20000" -O "osmose-item-irve-8411-intégrables.json"
|
wget "https://osmose.openstreetmap.fr/api/0.3/issues.geojson?full=true&status=open&item=8410&limit=20000" -O "osmose-item-irve-8411-intégrables.json"
|
||||||
echo "- OK Osmose"
|
echo "- OK Osmose"
|
||||||
|
|
||||||
##################
|
|
||||||
# moving datasets to the source folder etalab_data
|
|
||||||
##################
|
|
||||||
echo " - déplacement des datasets des IRVE dans le dossier etalab_data/irve_bornes_recharge"
|
|
||||||
mv latest.json ../etalab_data/irve_bornes_recharge/
|
|
||||||
#mv finess_idf.json ../etalab_data/finess/
|
|
||||||
mv irve_osm_latest.geojson ../etalab_data/irve_bornes_recharge/
|
|
||||||
mv clean_french_irve.csv ../etalab_data/irve_bornes_recharge/
|
|
||||||
mv osmose-item-irve-8411-intégrables.json ../etalab_data/irve_bornes_recharge/
|
|
||||||
|
|
||||||
|
|
||||||
##################
|
##################
|
||||||
# other sources of data should be placed in data_other folder
|
# other sources of data should be placed in data_other folder
|
||||||
##################
|
##################
|
||||||
|
@ -44,11 +33,6 @@ wget "https://data.issy.com/api/explore/v2.1/catalog/datasets/arbres-remarquable
|
||||||
echo "- récupérer les données de cyclabilité de Rouen"
|
echo "- récupérer les données de cyclabilité de Rouen"
|
||||||
wget "https://data.metropole-rouen-normandie.fr/api/explore/v2.1/catalog/datasets/liste-des-stationnements-cyclables-metropole-rouen-normandie/exports/geojson?lang=fr&timezone=Europe%2FBerlin" -O "rouen_parking_velos.json"
|
wget "https://data.metropole-rouen-normandie.fr/api/explore/v2.1/catalog/datasets/liste-des-stationnements-cyclables-metropole-rouen-normandie/exports/geojson?lang=fr&timezone=Europe%2FBerlin" -O "rouen_parking_velos.json"
|
||||||
|
|
||||||
mv "issy_les_mx_arbres.json" ../data_other/arbres/issy_les_mx_arbres.json
|
|
||||||
mv "geojson?lang=fr" ../data_other/cyclabilité/issy_les_mx_cyclabilité.json
|
|
||||||
mv "rouen_parking_velos.json" ../data_other/cyclabilité/rouen_parking_velos.json
|
|
||||||
|
|
||||||
|
|
||||||
# clean logs and finish
|
# clean logs and finish
|
||||||
rm website-data.log
|
rm website-data.log
|
||||||
cd ..
|
cd ..
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue