Skip to content

Commit

Permalink
Merge pull request #128 from etalab/merge-epci-geojson-v2
Browse files Browse the repository at this point in the history
Merge epci geojson v2
  • Loading branch information
ThomasG77 authored Apr 18, 2023
2 parents fa02bb5 + b62c27d commit da996d8
Show file tree
Hide file tree
Showing 16 changed files with 310 additions and 139 deletions.
40 changes: 31 additions & 9 deletions bin/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,20 @@ import {createRequire} from 'node:module'
import {resolve} from 'node:path'
import program from 'commander'

import importPciCmd from '../lib/commands/import-pci.js'
import extractPciCmd from '../lib/commands/extract-pci.js'
import extractEmsCmd from '../lib/commands/extract-ems.js'
import mergeCmd from '../lib/commands/merge.js'
import mergeEpciCmd from '../lib/commands/merge-epci.js'
import generateShpCmd from '../lib/commands/generate-shp.js'
import recreateEdigeoArchiveCmd from '../lib/commands/recreate-edigeo-archive.js'

import {BUNDLE_TYPES} from '../lib/bundle-types.js'

const require = createRequire(import.meta.url)
const pkg = require('../package.json')

const BUNDLE_TYPES = require('../lib/bundle-types.js').BUNDLE_TYPES.map(bt => bt.name)
const BUNDLE_TYPES_NAMES = BUNDLE_TYPES.map(bt => bt.name)

program
.version(pkg.version)
Expand All @@ -23,11 +33,11 @@ program
if (!archivesDir) throw new Error('archivesDir is required')
archivesDir = resolve(archivesDir)
if (!bundle) throw new Error('--bundle est un paramètre obligatoire')
if (!BUNDLE_TYPES.includes(bundle)) {
throw new Error('Le type de bundle doit être parmi : ' + BUNDLE_TYPES.join(', '))
if (!BUNDLE_TYPES_NAMES.includes(bundle)) {
throw new Error('Le type de bundle doit être parmi : ' + BUNDLE_TYPES_NAMES.join(', '))
}

require('../lib/commands/import-pci.js')(archivesDir, workDir, bundle, image).catch(boom)
importPciCmd(archivesDir, workDir, bundle, image).catch(boom)
})

program
Expand All @@ -37,7 +47,7 @@ program
if (!workDir) throw new Error('workDir is required')
workDir = resolve(workDir)

require('../lib/commands/extract-pci.js')(workDir)
extractPciCmd(workDir)
})

program
Expand All @@ -64,7 +74,7 @@ program

destPath = resolve(destPath)

require('../lib/commands/extract-ems.js')({rtsPath: rts, parcellairePath: parcellaire}, destPath).catch(boom)
extractEmsCmd({rtsPath: rts, parcellairePath: parcellaire}, destPath).catch(boom)
})

program
Expand All @@ -74,7 +84,19 @@ program
if (!workDir) throw new Error('workDir is required')
workDir = resolve(workDir)

require('../lib/commands/merge.js')(workDir).catch(boom)
mergeCmd(workDir).catch(boom)
})

program
.command('merge-epci <workDir>')
.option('--from <bundleType>', 'Type d’archive source : etalab ou pci')
.description('merge communes into EPCI')
.action((workDir, {from}) => {
if (!workDir) throw new Error('workDir is required')
workDir = resolve(workDir)
if (!from || !['etalab', 'pci'].includes(from)) throw new Error('from est obligatoire et doit être choisi parmi etalab ou pci')

mergeEpciCmd(workDir, from).catch(boom)
})

program
Expand All @@ -84,7 +106,7 @@ program
if (!workDir) throw new Error('workDir is required')
workDir = resolve(workDir)

require('../lib/commands/generate-shp.js')(workDir).catch(boom)
generateShpCmd(workDir).catch(boom)
})

program
Expand All @@ -100,7 +122,7 @@ program
if (!from || !['L93', 'CC'].includes(from)) throw new Error('from est obligatoire et doit être choisi parmi L93 ou CC')
if (!dep) throw new Error('dep is required')

require('../lib/commands/recreate-edigeo-archive.js')(src, dest, from, dep).catch(boom)
recreateEdigeoArchiveCmd(src, dest, from, dep).catch(boom)
})

program
Expand Down
12 changes: 6 additions & 6 deletions lib/commands/extract-ems.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import {recreateDirectory} from '../util/fs.js'
import {createAggregate} from '../aggregate/index.js'
import postprocessPrefixesSections from '../post-processing/prefixes-sections.js'
import {writeLayeredFeatures} from '../writers/geojson.js'
import rts from '../convert/ems-rts.js'
import ems from '../convert/ems-cadastre.js'
import {prepareCommune, prepareBatiment} from '../convert/ems-rts.js'
import {prepareSection, prepareParcelle, validateParcelle} from '../convert/ems-cadastre.js'

const communesToIgnore = new Set([
'67001',
Expand All @@ -21,10 +21,10 @@ const communesToIgnore = new Set([
])

const LAYERS_MAPPING = {
rg_r2m_commune: {layer: 'communes', convertFn: rts.prepareCommune},
rg_r2m_bati_fusionne: {layer: 'batiments', convertFn: rts.prepareBatiment},
rg_cad_section: {layer: 'sections', convertFn: ems.prepareSection},
rg_cad_parcelle: {layer: 'parcelles', convertFn: ems.prepareParcelle, validateFn: ems.validateParcelle},
rg_r2m_commune: {layer: 'communes', convertFn: prepareCommune},
rg_r2m_bati_fusionne: {layer: 'batiments', convertFn: prepareBatiment},
rg_cad_section: {layer: 'sections', convertFn: prepareSection},
rg_cad_parcelle: {layer: 'parcelles', convertFn: prepareParcelle, validateFn: validateParcelle},
}

async function handler({rtsPath, parcellairePath}, distPath) {
Expand Down
10 changes: 4 additions & 6 deletions lib/commands/extract-pci.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import process from 'node:process'
import os from 'node:os'
import bluebird from 'bluebird'
import {extractDepartement, stopWorkers} from '../extract/departement.js'
import {extractDepartement} from '../extract/departement.js'
import {Tree} from '../dist/pci.js'

const concurrency = Math.floor(os.cpus().length / 8) || 1
Expand All @@ -25,15 +25,13 @@ async function doStuff(basePath) {
function handler(basePath) {
doStuff(basePath)
.then(() => {
stopWorkers()
console.log('Terminé avec succès !')
process.exit(0)
})
.catch(error => {
console.log(error)
stopWorkers(() => {
console.log('Échec :(')
process.exit(1)
})
console.log('Échec :(')
process.exit(1)
})
}

Expand Down
4 changes: 1 addition & 3 deletions lib/commands/generate-shp.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {ensureDir, pathExists} from 'fs-extra'
import bluebird from 'bluebird'
import {getLegalCrsCode} from '../util/crs.js'
import {getShapefilePath, getGeoJSONPath, listDepartementsFromDepartements} from '../dist/simple.js'
import {convertToShape, stopWorkers} from '../shp/index.js'
import {convertToShape} from '../shp/index.js'

const DEPARTEMENT_LAYERS = [
'batiments',
Expand Down Expand Up @@ -73,8 +73,6 @@ async function handler(workDir) {

console.timeEnd(' terminé')

await stopWorkers()

console.log()
console.log('Finished!')
}
Expand Down
149 changes: 149 additions & 0 deletions lib/commands/merge-epci.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/* eslint unicorn/no-process-exit: off */
import process from 'node:process'
import {join} from 'node:path'
import {createRequire} from 'node:module'

import {pathExists} from 'fs-extra'
import bluebird from 'bluebird'
import {ensureDirectoryExists} from '../util/fs.js'
import {mergeGeoJSONFiles} from '../merge/index.js'
import {getGeoJSONPath} from '../dist/simple.js'
import {Tree, FORMATS} from '../dist/pci.js'
import {WritableZipFile} from '../util/zip.js'

const require = createRequire(import.meta.url)

const epci = require('@etalab/decoupage-administratif/data/epci.json')

// eslint-disable-next-line unicorn/no-array-reduce
const epciCommunesMembers = epci.reduce((acc, curr) => {
acc[curr.code] = curr.membres.map(membre => membre.code)
return acc
}, {})

// eslint-disable-next-line unicorn/no-array-callback-reference
const asyncFilter = async (array, predicate) => Promise.all(array.map(predicate)).then(results => array.filter((_v, index) => results[index]))

const GEOJSON_LAYERS = [
'batiments',
'parcelles',
'feuilles',
'sections',
'communes',
'lieux_dits',
'subdivisions_fiscales',
'prefixes_sections',
]

const GEOJSON_RAW_LAYERS = [
'commune',
'section',
'subdsect',
'parcelle',
'subdfisc',
'charge',
'voiep',
'tronfluv',
'ptcanv',
'batiment',
'zoncommuni',
'numvoie',
'tronroute',
'borne',
'croix',
'boulon',
'symblim',
'lieudit',
'tpoint',
'tline',
'tsurf',
'label',
]

async function handler(workDir, from) {
if (from === 'etalab') {
await Promise.all(Object.entries(epciCommunesMembers).map(async ([epci, communes]) => {
console.log(' merging epci %s', epci)
console.time(' merged epci ' + epci)

await Promise.all(GEOJSON_LAYERS.map(async layer => {
const files = communes.map(commune => {
const departement = `${commune.startsWith('97') ? commune.slice(0, 3) : commune.slice(0, 2)}`
return join(getGeoJSONPath(workDir), 'communes', departement, `${commune}`, `cadastre-${commune}-${layer}.json.gz`)
})
const filteredFiles = await asyncFilter(files, pathExists)
const targetDir = join(getGeoJSONPath(workDir), 'epci', epci)
await ensureDirectoryExists(targetDir)
const targetPath = join(getGeoJSONPath(workDir), 'epci', epci, `epci-${epci}-${layer}.json.gz`)
await mergeGeoJSONFiles({srcFiles: filteredFiles, destPath: targetPath})
console.log(` ${epci} | merged ${layer}`)
}))

console.timeEnd(' merged epci ' + epci)
}))

await Promise.all(Object.entries(epciCommunesMembers).map(async ([epci, communes]) => {
console.log(' [raw] merging epci %s', epci)
console.time(' [raw] merged epci ' + epci)

await Promise.all(GEOJSON_RAW_LAYERS.map(async layer => {
const files = communes.map(commune => {
const departement = `${commune.startsWith('97') ? commune.slice(0, 3) : commune.slice(0, 2)}`
return join(getGeoJSONPath(workDir), 'communes', departement, `${commune}`, 'raw', `cadastre-${commune}-${layer}.json.gz`)
})
const filteredFiles = await asyncFilter(files, pathExists)
const targetDir = join(getGeoJSONPath(workDir), 'epci', epci, 'raw')
await ensureDirectoryExists(targetDir)
const targetPath = join(getGeoJSONPath(workDir), 'epci', epci, 'raw', `epci-${epci}-${layer}.json.gz`)
await mergeGeoJSONFiles({srcFiles: filteredFiles, destPath: targetPath})
console.log(` ${epci} | merged ${layer}`)
}))

console.timeEnd(' [raw] merged epci ' + epci)
}))
}

if (from === 'pci') {
await bluebird.map(Object.entries(epciCommunesMembers), async ([epci, communes]) => {
await Promise.all(FORMATS.filter(formatInfos => formatInfos.name !== 'tiff').map(formatInfos => formatInfos.name).map(async format => {
console.log(' merging epci %s format %s', epci, format)
console.time(` merging epci ${epci} files ${format}`)

const tree = new Tree(workDir, 'dgfip-pci-vecteur', format)
const filteredCommunes = await asyncFilter(communes, async commune => {
const departement = `${commune.startsWith('97') ? commune.slice(0, 3) : commune.slice(0, 2)}`
return pathExists(`${tree.getFeuillesBasePath()}/${departement}/${commune}`)
})
const feuillesCommunes = await Promise.all(filteredCommunes.map(async codeCommune => ({
code: codeCommune,
feuilles: await tree.listFeuillesByCommune(codeCommune),
})))
// eslint-disable-next-line unicorn/no-array-reduce
const filesToZip = feuillesCommunes.reduce((acc, feuillesCommune) => {
acc = [...acc, ...feuillesCommune.feuilles.map(feuille => {
const dest = `${tree.getFeuillePathInArchive(feuille)}`
return [tree.getFeuillePath(feuille), dest]
})]
return acc
}, [])
const targetDir = `${tree.treeBasePath}/epci/`

const destArchive = new WritableZipFile(`${targetDir}/cadastre-${epci}-${format}.zip`)
await bluebird.map(filesToZip, async fileInfos => {
const [file, dest] = fileInfos
destArchive.addFile(file, dest, {compress: false})
}, {concurrency: 4})
await destArchive.end()
console.log('end zip')

console.timeEnd(` merging epci ${epci} files ${format}`)
}))
}, {concurrency: 4})
}

console.log('Finished!')

process.exit(0)
}

export default handler
10 changes: 7 additions & 3 deletions lib/commands/merge.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import process from 'node:process'
import {join} from 'node:path'
import {mergeGeoJSONFiles} from '../merge/index.js'
import {globPromisified} from '../util/fs.js'
import {getGeoJSONPath, listDepartements, departementLayerPath, franceLayerPath} from '../dist/simple.js'

const DEPARTEMENT_LAYERS = [
Expand Down Expand Up @@ -56,7 +57,8 @@ async function handler(workDir) {

await Promise.all(DEPARTEMENT_LAYERS.map(async layer => {
const srcPattern = join(getGeoJSONPath(workDir), 'communes', departement, '*', `cadastre-*-${layer}.json.gz`)
await mergeGeoJSONFiles(srcPattern, departementLayerPath(workDir, layer, departement))
const srcFiles = await globPromisified(srcPattern)
await mergeGeoJSONFiles({srcFiles, destPath: departementLayerPath(workDir, layer, departement)})
console.log(` ${departement} | merged ${layer}`)
}))

Expand All @@ -70,7 +72,8 @@ async function handler(workDir) {
await Promise.all(DEPARTEMENT_RAW_LAYERS.map(async layer => {
const srcPattern = join(getGeoJSONPath(workDir), 'communes', departement, '*', 'raw', `pci-*-${layer}.json.gz`)
const targetPath = join(getGeoJSONPath(workDir), 'departements', departement, 'raw', `pci-${departement}-${layer}.json.gz`)
await mergeGeoJSONFiles(srcPattern, targetPath)
const srcFiles = await globPromisified(srcPattern)
await mergeGeoJSONFiles({srcFiles, destPath: targetPath})
console.log(` ${departement} | merged ${layer}`)
}))

Expand All @@ -82,7 +85,8 @@ async function handler(workDir) {

await Promise.all(FRANCE_LAYERS.map(async layer => {
const srcPattern = join(getGeoJSONPath(workDir), 'departements', '*', `cadastre-*-${layer}.json.gz`)
await mergeGeoJSONFiles(srcPattern, franceLayerPath(workDir, layer))
const srcFiles = await globPromisified(srcPattern)
await mergeGeoJSONFiles({srcFiles, destPath: franceLayerPath(workDir, layer)})
console.log(` france | merged ${layer}`)
}))

Expand Down
2 changes: 1 addition & 1 deletion lib/commands/recreate-edigeo-archive.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import bluebird from 'bluebird'
import decompress from 'decompress'
import {reprojectArchive} from 'edigeo-reproject'
import {reprojectArchive} from '@etalab/edigeo-reproject'
import {WritableZipFile} from '../util/zip.js'

async function handler(src, dest, from, dep) {
Expand Down
Loading

0 comments on commit da996d8

Please sign in to comment.