├── .github ├── actions │ ├── install-tippecanoe │ │ └── action.yml │ ├── maproulette-buffers │ │ └── action.yml │ └── openstreetmap-buffers │ │ └── action.yml ├── dependabot.yml └── workflows │ ├── belgium-brussels.yml │ ├── belgium-flanders.yml │ ├── belgium-wallonia.yml │ ├── deploy-report-page.yml │ ├── luxembourg.yml │ ├── netherlands.yml │ ├── node.js-report.yml │ └── node.js-script.yml ├── .gitignore ├── LICENSE ├── README.md ├── data ├── belgium │ ├── belgium.sh │ ├── brussels │ │ ├── README.md │ │ ├── convert.json │ │ ├── difference │ │ │ ├── diff.geojson │ │ │ └── stats.json │ │ ├── filter.sql │ │ └── process.sh │ ├── flanders │ │ ├── README.md │ │ ├── convert.json │ │ ├── difference │ │ │ ├── diff.geojson │ │ │ └── stats.json │ │ ├── filter.sql │ │ └── process.sh │ └── wallonia │ │ ├── README.md │ │ ├── convert.json │ │ ├── difference │ │ ├── BRA │ │ │ ├── diff.geojson │ │ │ └── stats.json │ │ ├── HAI │ │ │ ├── diff.geojson │ │ │ └── stats.json │ │ ├── LIE │ │ │ ├── diff.geojson │ │ │ └── stats.json │ │ ├── LUX │ │ │ ├── diff.geojson │ │ │ └── stats.json │ │ ├── NAM │ │ │ ├── diff.geojson │ │ │ └── stats.json │ │ └── diff.geojson │ │ ├── filter.sql │ │ └── process.sh ├── kosovo │ ├── convert.json │ ├── difference │ │ ├── diff.geojson │ │ └── stats.json │ ├── filter.sql │ ├── kosovo.sh │ └── process.sh ├── luxembourg │ ├── README.md │ ├── build-extended-conversion.js │ ├── convert.json │ ├── create-uid.js │ ├── difference │ │ ├── .gitkeep │ │ ├── diff.geojson │ │ └── stats.json │ ├── filter.sql │ ├── luxembourg.sh │ └── process.sh └── netherlands │ ├── README.md │ ├── convert.json │ ├── difference │ ├── diff.geojson │ └── stats.json │ ├── filter.sql │ ├── netherlands.sh │ └── process.sh ├── report ├── .gitignore ├── README.md ├── astro.config.mjs ├── github │ ├── commit.mjs │ ├── commits.mjs │ ├── constants.mjs │ ├── content.mjs │ └── index.mjs ├── package-lock.json ├── package.json ├── public │ ├── assets │ │ └── .gitkeep │ ├── data │ │ └── .gitkeep │ └── robots.txt ├── src │ ├── components │ │ ├── Nav.astro │ │ ├── Report.astro │ │ ├── Statistics.astro │ │ └── Statistics │ │ │ ├── Chart.svelte │ │ │ └── History.svelte │ ├── env.d.ts │ ├── pages │ │ └── index.astro │ └── styles │ │ └── global.css └── tsconfig.json └── script ├── .eslintrc.yml ├── README.md ├── package-lock.json ├── package.json ├── src ├── buffer.ts ├── convert-tags.ts ├── difference.ts ├── difference │ └── buffer.ts ├── file-exists.ts └── typescript.d.ts └── tsconfig.json /.github/actions/install-tippecanoe/action.yml: -------------------------------------------------------------------------------- 1 | name: "Install Tippecanoe" 2 | description: "Install Tippecanoe from source (GitHub repository)" 3 | # inputs: 4 | # outputs: 5 | runs: 6 | using: "composite" 7 | steps: 8 | - name: Install dependencies 9 | run: sudo apt install libsqlite3-dev 10 | shell: bash 11 | - run: git clone https://github.com/mapbox/tippecanoe.git 12 | shell: bash 13 | - run: | 14 | cd tippecanoe 15 | make -j 16 | sudo make install 17 | shell: bash 18 | -------------------------------------------------------------------------------- /.github/actions/maproulette-buffers/action.yml: -------------------------------------------------------------------------------- 1 | name: "Generate MapRoulette buffers" 2 | description: "Download MapRoulette false positive and generate buffers" 3 | inputs: 4 | challenge-id: 5 | description: "MapRoulette challenge id" 6 | required: true 7 | # outputs: 8 | runs: 9 | using: "composite" 10 | steps: 11 | - name: Download MapRoulette false positive 12 | run: wget -O "maproulette.geojson" "https://maproulette.org/api/v2/challenge/view/${{ inputs.challenge-id }}?status=2" 13 | shell: bash 14 | - name: Generate MapRoulette buffers 15 | run: node "script/buffer.js" --radius=20 "maproulette.geojson" "maproulette-buffers.geojson" 16 | shell: bash 17 | -------------------------------------------------------------------------------- /.github/actions/openstreetmap-buffers/action.yml: -------------------------------------------------------------------------------- 1 | name: "Generate OpenStreetMap buffers" 2 | description: "Download OpenStreetMap extract, filter highways, and generate buffers" 3 | inputs: 4 | country: 5 | description: "Continent + Country (Format: `/`)" 6 | required: true 7 | # outputs: 8 | runs: 9 | using: "composite" 10 | steps: 11 | - name: Extract continent/country from input 12 | id: extract-country 13 | run: | 14 | echo "continent=$(echo ${{ inputs.country }} | cut -d'/' -f1)" >> $GITHUB_OUTPUT 15 | echo "country=$(echo ${{ inputs.country }} | cut -d'/' -f2)" >> $GITHUB_OUTPUT 16 | shell: bash 17 | - name: Get current date 18 | id: get-date 19 | run: echo "date=$(date '+%Y%m%d')" >> $GITHUB_OUTPUT 20 | shell: bash 21 | - name: Cache result 22 | id: cache-buffers 23 | uses: actions/cache@v4 24 | with: 25 | path: | 26 | openstreetmap-lines-buffers.geojson 27 | openstreetmap-polygons-buffers.geojson 28 | key: openstreetmap-buffers-${{ steps.extract-country.outputs.country }}-${{ steps.get-date.outputs.date }} 29 | - name: Download OpenStreetMap extract 30 | if: ${{ steps.cache-buffers.outputs.cache-hit != 'true' }} 31 | run: wget -O openstreetmap-latest.osm.pbf https://download.geofabrik.de/${{ inputs.country }}-latest.osm.pbf 32 | shell: bash 33 | - name: Convert (and filter) OpenStreetMap to GeoJSON 34 | if: ${{ steps.cache-buffers.outputs.cache-hit != 'true' }} 35 | run: | 36 | ogr2ogr -f "GeoJSON" -progress \ 37 | -sql "SELECT name, highway FROM lines WHERE highway IS NOT NULL" \ 38 | "openstreetmap-lines.geojson" \ 39 | "openstreetmap-latest.osm.pbf" 40 | ogr2ogr -f "GeoJSON" -progress \ 41 | -sql "SELECT name, hstore_get_value(other_tags, 'highway') AS highway FROM multipolygons WHERE hstore_get_value(other_tags, 'highway') is not null" \ 42 | "openstreetmap-polygons.geojson" \ 43 | "openstreetmap-latest.osm.pbf" 44 | shell: bash 45 | - name: Generate OpenStreetMap buffers 46 | if: ${{ steps.cache-buffers.outputs.cache-hit != 'true' }} 47 | run: | 48 | node "script/buffer.js" --radius=20 "openstreetmap-lines.geojson" "openstreetmap-lines-buffers.geojson" 49 | node "script/buffer.js" --radius=5 "openstreetmap-polygons.geojson" "openstreetmap-polygons-buffers.geojson" 50 | shell: bash 51 | # - name: Generate vector tiles 52 | # run: | 53 | # tippecanoe --force --no-feature-limit --no-tile-size-limit \ 54 | # --maximum-zoom=14 --minimum-zoom=14 \ 55 | # --layer="buffers" \ 56 | # --output="openstreetmap-buffers.mbtiles" \ 57 | # "openstreetmap-lines-buffers.geojson" "openstreetmap-polygons-buffers.geojson" 58 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: "/" 5 | schedule: 6 | interval: monthly 7 | - package-ecosystem: npm 8 | directory: "/report" 9 | labels: 10 | - "dependencies" 11 | # - "javascript" 12 | - "report" 13 | schedule: 14 | interval: monthly 15 | - package-ecosystem: npm 16 | directory: "/script" 17 | labels: 18 | - "dependencies" 19 | # - "javascript" 20 | - "script" 21 | schedule: 22 | interval: monthly 23 | -------------------------------------------------------------------------------- /.github/workflows/belgium-brussels.yml: -------------------------------------------------------------------------------- 1 | name: 🇧🇪 Brussels, Belgium 2 | 3 | on: 4 | workflow_dispatch: 5 | # Run every Sunday at 10:00 UTC 6 | schedule: 7 | - cron: "0 10 * * 0" 8 | push: 9 | paths: 10 | - ".github/workflows/belgium-brussels.yml" 11 | - ".github/actions/*/action.yml" 12 | - "script/**/*.ts" 13 | - "data/belgium/brussels/convert.json" 14 | - "data/belgium/brussels/filter.sql" 15 | pull_request: 16 | paths: 17 | - ".github/workflows/belgium-brussels.yml" 18 | - ".github/actions/*/action.yml" 19 | - "script/**/*.ts" 20 | - "data/belgium/brussels/convert.json" 21 | - "data/belgium/brussels/filter.sql" 22 | 23 | # Allow one concurrent deployment 24 | concurrency: 25 | group: ${{ github.workflow }}-${{ github.ref }} 26 | cancel-in-progress: true 27 | 28 | env: 29 | MAPROULETTE_CHALLENGE_ID: 14675 30 | 31 | jobs: 32 | 33 | diff: 34 | name: Generate difference for Brussels, Belgium 35 | runs-on: ubuntu-latest 36 | steps: 37 | - uses: actions/checkout@v4 38 | - name: Install GDAL 39 | run: | 40 | sudo apt-add-repository ppa:ubuntugis/ubuntugis-unstable 41 | sudo apt update 42 | sudo apt install gdal-bin 43 | - name: Install Tippecanoe 44 | uses: ./.github/actions/install-tippecanoe 45 | - name: Install dependencies 46 | run: npm install 47 | working-directory: script 48 | - name: Build 49 | run: npm run build 50 | working-directory: script 51 | - name: Generate OpenStreetMap buffers 52 | uses: ./.github/actions/openstreetmap-buffers 53 | with: 54 | country: europe/belgium 55 | - name: Download & Unzip UrbIS data 56 | run: | 57 | wget --no-check-certificate "https://urbisdownload.datastore.brussels/UrbIS/Vector/M7/2D/UrbAdm/Daily/SHP_LITE/UrbAdm_SHP.zip" 58 | unzip "UrbAdm_SHP.zip" "shp/UrbAdm_STREET_AXIS.*" 59 | - name: Convert (and filter) UrbIS to GeoJSON 60 | run: | 61 | ogr2ogr -f "GeoJSON" -progress \ 62 | -s_srs "EPSG:31370" -t_srs "EPSG:4326" \ 63 | -sql "@data/belgium/brussels/filter.sql" \ 64 | -lco COORDINATE_PRECISION=6 \ 65 | -fieldTypeToString "All" \ 66 | "UrbAdm_STREET_AXIS.geojson" \ 67 | "shp/UrbAdm_STREET_AXIS.shp" 68 | - name: Convert UrbIS fields to OpenStreetMap tags 69 | run: node "script/convert-tags.js" -c "data/belgium/brussels/convert.json" "UrbAdm_STREET_AXIS.geojson" "UrbAdm_STREET_AXISTagged.geojson" 70 | - name: Generate UrbIS vector tiles 71 | run: | 72 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 73 | --buffer=0 \ 74 | --maximum-zoom=14 --minimum-zoom=14 \ 75 | --layer="roads" \ 76 | --output="UrbAdm_STREET_AXISTagged.mbtiles" "UrbAdm_STREET_AXISTagged.geojson" 77 | - name: Generate MapRoulette buffers 78 | uses: ./.github/actions/maproulette-buffers 79 | with: 80 | challenge-id: ${{ env.MAPROULETTE_CHALLENGE_ID }} 81 | - name: Upload MapRoulette false positive 82 | uses: actions/upload-artifact@v4 83 | with: 84 | name: MapRoulette-FalsePositive 85 | path: maproulette.geojson 86 | - name: Merge MapRoulette buffers to OpenStreetMap buffers and generate vector tiles 87 | run: | 88 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 89 | --maximum-zoom=14 --minimum-zoom=14 \ 90 | --layer="buffers" \ 91 | --output="belgium-buffers.mbtiles" \ 92 | "openstreetmap-lines-buffers.geojson" "openstreetmap-polygons-buffers.geojson" "maproulette-buffers.geojson" 93 | - name: Difference 94 | run: node "script/difference.js" --output-dir="data/belgium/brussels/difference" "UrbAdm_STREET_AXISTagged.mbtiles" "belgium-buffers.mbtiles" 95 | - name: Upload difference 96 | uses: actions/upload-artifact@v4 97 | with: 98 | name: Brussels-Difference 99 | path: data/belgium/brussels/difference/diff.geojson 100 | - name: Upload statistics 101 | uses: actions/upload-artifact@v4 102 | with: 103 | name: Brussels-Statistics 104 | path: data/belgium/brussels/difference/stats.json 105 | 106 | commit: 107 | name: Commit & Push changes 108 | needs: diff 109 | if: ${{ github.event_name != 'pull_request' }} 110 | runs-on: ubuntu-latest 111 | steps: 112 | - uses: actions/checkout@v4 113 | - uses: actions/download-artifact@v4 114 | with: 115 | name: Brussels-Difference 116 | path: data/belgium/brussels/difference 117 | - uses: actions/download-artifact@v4 118 | with: 119 | name: Brussels-Statistics 120 | path: data/belgium/brussels/difference 121 | - name: Commit & Push 122 | run: | 123 | git config user.name github-actions[bot] 124 | git config user.email 41898282+github-actions[bot]@users.noreply.github.com 125 | git pull 126 | git add data/belgium/brussels/difference/diff.geojson 127 | git add data/belgium/brussels/difference/stats.json 128 | git commit -m "🗃 Update difference for Brussels, Belgium" 129 | git push 130 | 131 | mr-rebuild: 132 | name: Rebuild MapRoulette challenge 133 | needs: commit 134 | runs-on: ubuntu-latest 135 | steps: 136 | - name: Call MapRoulette API 137 | run: | 138 | curl -X "PUT" "https://maproulette.org/api/v2/challenge/${{ env.MAPROULETTE_CHALLENGE_ID }}/rebuild?removeUnmatched=true&skipSnapshot=false" \ 139 | -H "Accept: application/json" \ 140 | -H "apiKey: ${{ secrets.MAPROULETTE_API_KEY }}" 141 | -------------------------------------------------------------------------------- /.github/workflows/belgium-flanders.yml: -------------------------------------------------------------------------------- 1 | name: 🇧🇪 Flanders, Belgium 2 | 3 | on: 4 | workflow_dispatch: 5 | # Run at 12:00 UTC every 5 days (to make sure cache doesn't expire) 6 | schedule: 7 | - cron: "0 12 */5 * *" 8 | push: 9 | paths: 10 | - ".github/workflows/belgium-flanders.yml" 11 | - ".github/actions/*/action.yml" 12 | - "script/**/*.ts" 13 | - "data/belgium/flanders/convert.json" 14 | - "data/belgium/flanders/filter.sql" 15 | pull_request: 16 | paths: 17 | - ".github/workflows/belgium-flanders.yml" 18 | - ".github/actions/*/action.yml" 19 | - "script/**/*.ts" 20 | - "data/belgium/flanders/convert.json" 21 | - "data/belgium/flanders/filter.sql" 22 | 23 | # Allow one concurrent deployment 24 | concurrency: 25 | group: ${{ github.workflow }}-${{ github.ref }} 26 | cancel-in-progress: true 27 | 28 | env: 29 | MAPROULETTE_CHALLENGE_ID: 24090 30 | WEGENREGISTER_URL: "https://download.vlaanderen.be/bff/v1/Orders/337327/download/79c09c5d-e2c5-45c0-a5fa-52734128aa01" 31 | WEGENREGISTER_DATE: "20250130" 32 | 33 | jobs: 34 | 35 | diff: 36 | name: Generate difference for Flanders, Belgium 37 | runs-on: ubuntu-latest 38 | steps: 39 | - uses: actions/checkout@v4 40 | - name: Install GDAL 41 | run: | 42 | sudo apt-add-repository ppa:ubuntugis/ubuntugis-unstable 43 | sudo apt update 44 | sudo apt install gdal-bin 45 | - name: Install Tippecanoe 46 | uses: ./.github/actions/install-tippecanoe 47 | - name: Install dependencies 48 | run: npm install 49 | working-directory: script 50 | - name: Build 51 | run: npm run build 52 | working-directory: script 53 | - name: Generate OpenStreetMap buffers 54 | uses: ./.github/actions/openstreetmap-buffers 55 | with: 56 | country: europe/belgium 57 | - name: Cache WegenRegister data 58 | id: cache-wegenregister 59 | uses: actions/cache@v4 60 | with: 61 | path: Wegsegment.geojson 62 | key: wegenregister-${{ env.WEGENREGISTER_DATE }} 63 | - name: Download & Unzip Wegenregister data 64 | if: ${{ steps.cache-wegenregister.outputs.cache-hit != 'true' }} 65 | run: | 66 | wget --content-disposition ${{ env.WEGENREGISTER_URL }} 67 | unzip -j "Wegenregister_SHAPE_${{ env.WEGENREGISTER_DATE }}.zip" "Shapefile/Wegsegment.*" 68 | - name: Convert (and filter) Wegenregister to GeoJSON 69 | if: ${{ steps.cache-wegenregister.outputs.cache-hit != 'true' }} 70 | run: | 71 | ogr2ogr -f "GeoJSON" -progress \ 72 | --config SHAPE_ENCODING "ISO-8859-1" \ 73 | -s_srs "EPSG:31370" -t_srs "EPSG:4326" \ 74 | -sql "@data/belgium/flanders/filter.sql" \ 75 | -lco COORDINATE_PRECISION=6 \ 76 | -fieldTypeToString "All" \ 77 | "Wegsegment.geojson" \ 78 | "Wegsegment.shp" 79 | - name: Convert Wegenregister fields to OpenStreetMap tags 80 | run: node "script/convert-tags.js" -c "data/belgium/flanders/convert.json" "Wegsegment.geojson" "WegsegmentTagged.geojson" 81 | - name: Generate Wegenregister vector tiles 82 | run: | 83 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 84 | --buffer=0 \ 85 | --maximum-zoom=14 --minimum-zoom=14 \ 86 | --layer="roads" \ 87 | --output="WegsegmentTagged.mbtiles" "WegsegmentTagged.geojson" 88 | - name: Generate MapRoulette buffers 89 | uses: ./.github/actions/maproulette-buffers 90 | with: 91 | challenge-id: ${{ env.MAPROULETTE_CHALLENGE_ID }} 92 | - name: Upload MapRoulette false positive 93 | uses: actions/upload-artifact@v4 94 | with: 95 | name: MapRoulette-FalsePositive 96 | path: maproulette.geojson 97 | - name: Merge MapRoulette buffers to OpenStreetMap buffers and generate vector tiles 98 | run: | 99 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 100 | --maximum-zoom=14 --minimum-zoom=14 \ 101 | --layer="buffers" \ 102 | --output="belgium-buffers.mbtiles" \ 103 | "openstreetmap-lines-buffers.geojson" "openstreetmap-polygons-buffers.geojson" "maproulette-buffers.geojson" 104 | - name: Difference 105 | run: node "script/difference.js" --output-dir="data/belgium/flanders/difference" "WegsegmentTagged.mbtiles" "belgium-buffers.mbtiles" 106 | - name: Upload difference 107 | uses: actions/upload-artifact@v4 108 | with: 109 | name: Flanders-Difference 110 | path: data/belgium/flanders/difference/diff.geojson 111 | - name: Upload statistics 112 | uses: actions/upload-artifact@v4 113 | with: 114 | name: Flanders-Statistics 115 | path: data/belgium/flanders/difference/stats.json 116 | 117 | commit: 118 | name: Commit & Push changes 119 | needs: diff 120 | if: ${{ github.event_name != 'pull_request' }} 121 | runs-on: ubuntu-latest 122 | steps: 123 | - uses: actions/checkout@v4 124 | - uses: actions/download-artifact@v4 125 | with: 126 | name: Flanders-Difference 127 | path: data/belgium/flanders/difference 128 | - uses: actions/download-artifact@v4 129 | with: 130 | name: Flanders-Statistics 131 | path: data/belgium/flanders/difference 132 | - name: Commit & Push 133 | run: | 134 | git config user.name github-actions[bot] 135 | git config user.email 41898282+github-actions[bot]@users.noreply.github.com 136 | git pull 137 | git add data/belgium/flanders/difference/diff.geojson 138 | git add data/belgium/flanders/difference/stats.json 139 | git commit -m "🗃 Update difference for Flanders, Belgium" 140 | git push 141 | 142 | mr-rebuild: 143 | name: Rebuild MapRoulette challenge 144 | needs: commit 145 | runs-on: ubuntu-latest 146 | steps: 147 | - name: Call MapRoulette API 148 | run: | 149 | curl -X "PUT" "https://maproulette.org/api/v2/challenge/${{ env.MAPROULETTE_CHALLENGE_ID }}/rebuild?removeUnmatched=true&skipSnapshot=false" \ 150 | -H "Accept: application/json" \ 151 | -H "apiKey: ${{ secrets.MAPROULETTE_API_KEY }}" 152 | -------------------------------------------------------------------------------- /.github/workflows/belgium-wallonia.yml: -------------------------------------------------------------------------------- 1 | name: 🇧🇪 Wallonia, Belgium 2 | 3 | on: 4 | workflow_dispatch: 5 | # Run every Sunday at 12:00 UTC 6 | schedule: 7 | - cron: "0 12 * * 0" 8 | push: 9 | paths: 10 | - ".github/workflows/belgium-wallonia.yml" 11 | - ".github/actions/*/action.yml" 12 | - "script/**/*.ts" 13 | - "data/belgium/wallonia/convert.json" 14 | - "data/belgium/wallonia/filter.sql" 15 | pull_request: 16 | paths: 17 | - ".github/workflows/belgium-wallonia.yml" 18 | - ".github/actions/*/action.yml" 19 | - "script/**/*.ts" 20 | - "data/belgium/wallonia/convert.json" 21 | - "data/belgium/wallonia/filter.sql" 22 | 23 | # Allow one concurrent deployment 24 | concurrency: 25 | group: ${{ github.workflow }}-${{ github.ref }} 26 | cancel-in-progress: true 27 | 28 | env: 29 | MAPROULETTE_CHALLENGE_ID: 14681 30 | 31 | jobs: 32 | 33 | diff-bra: 34 | name: Generate difference for Brabant Wallon, Wallonia, Belgium 35 | runs-on: ubuntu-latest 36 | steps: 37 | - uses: actions/checkout@v4 38 | - name: Install GDAL 39 | run: | 40 | sudo apt-add-repository ppa:ubuntugis/ubuntugis-unstable 41 | sudo apt update 42 | sudo apt install gdal-bin 43 | - name: Install Tippecanoe 44 | uses: ./.github/actions/install-tippecanoe 45 | - name: Install dependencies 46 | run: npm install 47 | working-directory: script 48 | - name: Build 49 | run: npm run build 50 | working-directory: script 51 | - name: Generate OpenStreetMap buffers 52 | uses: ./.github/actions/openstreetmap-buffers 53 | with: 54 | country: europe/belgium 55 | - name: Download & Unzip PICC data 56 | run: | 57 | wget "https://geoservices.wallonie.be/geotraitement/spwdatadownload/get/b795de68-726c-4bdf-a62a-a42686aa5b6f/PICC_vDIFF_SHAPE_31370_PROV_BRABANT_WALLON.zip" 58 | unzip -j "PICC_vDIFF_SHAPE_31370_PROV_BRABANT_WALLON.zip" "VOIRIE_AXE.*" 59 | - name: Convert (and filter) PICC to GeoJSON 60 | run: | 61 | ogr2ogr -f "GeoJSON" -progress \ 62 | -s_srs "EPSG:31370" -t_srs "EPSG:4326" -dim "XY" \ 63 | -makevalid \ 64 | -sql "@data/belgium/wallonia/filter.sql" \ 65 | -lco COORDINATE_PRECISION=6 \ 66 | -fieldTypeToString "All" \ 67 | "BRA_VOIRIE_AXE.geojson" \ 68 | "VOIRIE_AXE.shp" 69 | - name: Convert PICC fields to OpenStreetMap tags 70 | run: node "script/convert-tags.js" -c "data/belgium/wallonia/convert.json" "BRA_VOIRIE_AXE.geojson" "BRA_VOIRIE_AXETagged.geojson" 71 | - name: Generate PICC vector tiles 72 | run: | 73 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 74 | --buffer=0 \ 75 | --maximum-zoom=14 --minimum-zoom=14 \ 76 | --layer="roads" \ 77 | --output="BRA_VOIRIE_AXETagged.mbtiles" "BRA_VOIRIE_AXETagged.geojson" 78 | - name: Generate MapRoulette buffers 79 | uses: ./.github/actions/maproulette-buffers 80 | with: 81 | challenge-id: ${{ env.MAPROULETTE_CHALLENGE_ID }} 82 | - name: Upload MapRoulette false positive 83 | uses: actions/upload-artifact@v4 84 | with: 85 | name: MapRoulette-FalsePositive 86 | path: maproulette.geojson 87 | - name: Merge MapRoulette buffers to OpenStreetMap buffers and generate vector tiles 88 | run: | 89 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 90 | --maximum-zoom=14 --minimum-zoom=14 \ 91 | --layer="buffers" \ 92 | --output="belgium-buffers.mbtiles" \ 93 | "openstreetmap-lines-buffers.geojson" "openstreetmap-polygons-buffers.geojson" "maproulette-buffers.geojson" 94 | - name: Difference 95 | run: node "script/difference.js" --output-dir="data/belgium/wallonia/difference/BRA" "BRA_VOIRIE_AXETagged.mbtiles" "belgium-buffers.mbtiles" 96 | - name: Upload difference 97 | uses: actions/upload-artifact@v4 98 | with: 99 | name: BrabantWallon-Difference 100 | path: data/belgium/wallonia/difference/BRA/diff.geojson 101 | - name: Upload statistics 102 | uses: actions/upload-artifact@v4 103 | with: 104 | name: BrabantWallon-Statistics 105 | path: data/belgium/wallonia/difference/BRA/stats.json 106 | 107 | diff-hai: 108 | name: Generate difference for Hainaut, Wallonia, Belgium 109 | runs-on: ubuntu-latest 110 | steps: 111 | - uses: actions/checkout@v4 112 | - name: Install GDAL 113 | run: | 114 | sudo apt-add-repository ppa:ubuntugis/ubuntugis-unstable 115 | sudo apt update 116 | sudo apt install gdal-bin 117 | - name: Install Tippecanoe 118 | uses: ./.github/actions/install-tippecanoe 119 | - name: Install dependencies 120 | run: npm install 121 | working-directory: script 122 | - name: Build 123 | run: npm run build 124 | working-directory: script 125 | - name: Generate OpenStreetMap buffers 126 | uses: ./.github/actions/openstreetmap-buffers 127 | with: 128 | country: europe/belgium 129 | - name: Download & Unzip PICC data 130 | run: | 131 | wget "https://geoservices.wallonie.be/geotraitement/spwdatadownload/get/b795de68-726c-4bdf-a62a-a42686aa5b6f/PICC_vDIFF_SHAPE_31370_PROV_HAINAUT.zip" 132 | unzip -j "PICC_vDIFF_SHAPE_31370_PROV_HAINAUT.zip" "VOIRIE_AXE.*" 133 | - name: Convert (and filter) PICC to GeoJSON 134 | run: | 135 | ogr2ogr -f "GeoJSON" -progress \ 136 | -s_srs "EPSG:31370" -t_srs "EPSG:4326" -dim "XY" \ 137 | -makevalid \ 138 | -sql "@data/belgium/wallonia/filter.sql" \ 139 | -lco COORDINATE_PRECISION=6 \ 140 | -fieldTypeToString "All" \ 141 | "HAI_VOIRIE_AXE.geojson" \ 142 | "VOIRIE_AXE.shp" 143 | - name: Convert PICC fields to OpenStreetMap tags 144 | run: node "script/convert-tags.js" -c "data/belgium/wallonia/convert.json" "HAI_VOIRIE_AXE.geojson" "HAI_VOIRIE_AXETagged.geojson" 145 | - name: Generate PICC vector tiles 146 | run: | 147 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 148 | --buffer=0 \ 149 | --maximum-zoom=14 --minimum-zoom=14 \ 150 | --layer="roads" \ 151 | --output="HAI_VOIRIE_AXETagged.mbtiles" "HAI_VOIRIE_AXETagged.geojson" 152 | - name: Generate MapRoulette buffers 153 | uses: ./.github/actions/maproulette-buffers 154 | with: 155 | challenge-id: ${{ env.MAPROULETTE_CHALLENGE_ID }} 156 | # - name: Upload MapRoulette false positive 157 | # uses: actions/upload-artifact@v4 158 | # with: 159 | # name: MapRoulette-FalsePositive 160 | # path: maproulette.geojson 161 | - name: Merge MapRoulette buffers to OpenStreetMap buffers and generate vector tiles 162 | run: | 163 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 164 | --maximum-zoom=14 --minimum-zoom=14 \ 165 | --layer="buffers" \ 166 | --output="belgium-buffers.mbtiles" \ 167 | "openstreetmap-lines-buffers.geojson" "openstreetmap-polygons-buffers.geojson" "maproulette-buffers.geojson" 168 | - name: Difference 169 | run: node "script/difference.js" --output-dir="data/belgium/wallonia/difference/HAI" "HAI_VOIRIE_AXETagged.mbtiles" "belgium-buffers.mbtiles" 170 | - name: Upload difference 171 | uses: actions/upload-artifact@v4 172 | with: 173 | name: Hainaut-Difference 174 | path: data/belgium/wallonia/difference/HAI/diff.geojson 175 | - name: Upload statistics 176 | uses: actions/upload-artifact@v4 177 | with: 178 | name: Hainaut-Statistics 179 | path: data/belgium/wallonia/difference/HAI/stats.json 180 | 181 | diff-lie: 182 | name: Generate difference for Liège, Wallonia, Belgium 183 | runs-on: ubuntu-latest 184 | steps: 185 | - uses: actions/checkout@v4 186 | - name: Install GDAL 187 | run: | 188 | sudo apt-add-repository ppa:ubuntugis/ubuntugis-unstable 189 | sudo apt update 190 | sudo apt install gdal-bin 191 | - name: Install Tippecanoe 192 | uses: ./.github/actions/install-tippecanoe 193 | - name: Install dependencies 194 | run: npm install 195 | working-directory: script 196 | - name: Build 197 | run: npm run build 198 | working-directory: script 199 | - name: Generate OpenStreetMap buffers 200 | uses: ./.github/actions/openstreetmap-buffers 201 | with: 202 | country: europe/belgium 203 | - name: Download & Unzip PICC data 204 | run: | 205 | wget "https://geoservices.wallonie.be/geotraitement/spwdatadownload/get/b795de68-726c-4bdf-a62a-a42686aa5b6f/PICC_vDIFF_SHAPE_31370_PROV_LIEGE.zip" 206 | unzip -j "PICC_vDIFF_SHAPE_31370_PROV_LIEGE.zip" "VOIRIE_AXE.*" 207 | - name: Convert (and filter) PICC to GeoJSON 208 | run: | 209 | ogr2ogr -f "GeoJSON" -progress \ 210 | -s_srs "EPSG:31370" -t_srs "EPSG:4326" -dim "XY" \ 211 | -makevalid \ 212 | -sql "@data/belgium/wallonia/filter.sql" \ 213 | -lco COORDINATE_PRECISION=6 \ 214 | -fieldTypeToString "All" \ 215 | "LIE_VOIRIE_AXE.geojson" \ 216 | "VOIRIE_AXE.shp" 217 | - name: Convert PICC fields to OpenStreetMap tags 218 | run: node "script/convert-tags.js" -c "data/belgium/wallonia/convert.json" "LIE_VOIRIE_AXE.geojson" "LIE_VOIRIE_AXETagged.geojson" 219 | - name: Generate PICC vector tiles 220 | run: | 221 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 222 | --buffer=0 \ 223 | --maximum-zoom=14 --minimum-zoom=14 \ 224 | --layer="roads" \ 225 | --output="LIE_VOIRIE_AXETagged.mbtiles" "LIE_VOIRIE_AXETagged.geojson" 226 | - name: Generate MapRoulette buffers 227 | uses: ./.github/actions/maproulette-buffers 228 | with: 229 | challenge-id: ${{ env.MAPROULETTE_CHALLENGE_ID }} 230 | # - name: Upload MapRoulette false positive 231 | # uses: actions/upload-artifact@v4 232 | # with: 233 | # name: MapRoulette-FalsePositive 234 | # path: maproulette.geojson 235 | - name: Merge MapRoulette buffers to OpenStreetMap buffers and generate vector tiles 236 | run: | 237 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 238 | --maximum-zoom=14 --minimum-zoom=14 \ 239 | --layer="buffers" \ 240 | --output="belgium-buffers.mbtiles" \ 241 | "openstreetmap-lines-buffers.geojson" "openstreetmap-polygons-buffers.geojson" "maproulette-buffers.geojson" 242 | - name: Difference 243 | run: node "script/difference.js" --output-dir="data/belgium/wallonia/difference/LIE" "LIE_VOIRIE_AXETagged.mbtiles" "belgium-buffers.mbtiles" 244 | - name: Upload difference 245 | uses: actions/upload-artifact@v4 246 | with: 247 | name: Liege-Difference 248 | path: data/belgium/wallonia/difference/LIE/diff.geojson 249 | - name: Upload statistics 250 | uses: actions/upload-artifact@v4 251 | with: 252 | name: Liege-Statistics 253 | path: data/belgium/wallonia/difference/LIE/stats.json 254 | 255 | diff-lux: 256 | name: Generate difference for Luxembourg, Wallonia, Belgium 257 | runs-on: ubuntu-latest 258 | steps: 259 | - uses: actions/checkout@v4 260 | - name: Install GDAL 261 | run: | 262 | sudo apt-add-repository ppa:ubuntugis/ubuntugis-unstable 263 | sudo apt update 264 | sudo apt install gdal-bin 265 | - name: Install Tippecanoe 266 | uses: ./.github/actions/install-tippecanoe 267 | - name: Install dependencies 268 | run: npm install 269 | working-directory: script 270 | - name: Build 271 | run: npm run build 272 | working-directory: script 273 | - name: Generate OpenStreetMap buffers 274 | uses: ./.github/actions/openstreetmap-buffers 275 | with: 276 | country: europe/belgium 277 | - name: Download & Unzip PICC data 278 | run: | 279 | wget "https://geoservices.wallonie.be/geotraitement/spwdatadownload/get/b795de68-726c-4bdf-a62a-a42686aa5b6f/PICC_vDIFF_SHAPE_31370_PROV_LUXEMBOURG.zip" 280 | unzip -j "PICC_vDIFF_SHAPE_31370_PROV_LUXEMBOURG.zip" "VOIRIE_AXE.*" 281 | - name: Convert (and filter) PICC to GeoJSON 282 | run: | 283 | ogr2ogr -f "GeoJSON" -progress \ 284 | -s_srs "EPSG:31370" -t_srs "EPSG:4326" -dim "XY" \ 285 | -makevalid \ 286 | -sql "@data/belgium/wallonia/filter.sql" \ 287 | -lco COORDINATE_PRECISION=6 \ 288 | -fieldTypeToString "All" \ 289 | "LUX_VOIRIE_AXE.geojson" \ 290 | "VOIRIE_AXE.shp" 291 | - name: Convert PICC fields to OpenStreetMap tags 292 | run: node "script/convert-tags.js" -c "data/belgium/wallonia/convert.json" "LUX_VOIRIE_AXE.geojson" "LUX_VOIRIE_AXETagged.geojson" 293 | - name: Generate PICC vector tiles 294 | run: | 295 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 296 | --buffer=0 \ 297 | --maximum-zoom=14 --minimum-zoom=14 \ 298 | --layer="roads" \ 299 | --output="LUX_VOIRIE_AXETagged.mbtiles" "LUX_VOIRIE_AXETagged.geojson" 300 | - name: Generate MapRoulette buffers 301 | uses: ./.github/actions/maproulette-buffers 302 | with: 303 | challenge-id: ${{ env.MAPROULETTE_CHALLENGE_ID }} 304 | # - name: Upload MapRoulette false positive 305 | # uses: actions/upload-artifact@v4 306 | # with: 307 | # name: MapRoulette-FalsePositive 308 | # path: maproulette.geojson 309 | - name: Merge MapRoulette buffers to OpenStreetMap buffers and generate vector tiles 310 | run: | 311 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 312 | --maximum-zoom=14 --minimum-zoom=14 \ 313 | --layer="buffers" \ 314 | --output="belgium-buffers.mbtiles" \ 315 | "openstreetmap-lines-buffers.geojson" "openstreetmap-polygons-buffers.geojson" "maproulette-buffers.geojson" 316 | - name: Difference 317 | run: node "script/difference.js" --output-dir="data/belgium/wallonia/difference/LUX" "LUX_VOIRIE_AXETagged.mbtiles" "belgium-buffers.mbtiles" 318 | - name: Upload difference 319 | uses: actions/upload-artifact@v4 320 | with: 321 | name: Luxembourg-Difference 322 | path: data/belgium/wallonia/difference/LUX/diff.geojson 323 | - name: Upload statistics 324 | uses: actions/upload-artifact@v4 325 | with: 326 | name: Luxembourg-Statistics 327 | path: data/belgium/wallonia/difference/LUX/stats.json 328 | 329 | diff-nam: 330 | name: Generate difference for Namur, Wallonia, Belgium 331 | runs-on: ubuntu-latest 332 | steps: 333 | - uses: actions/checkout@v4 334 | - name: Install GDAL 335 | run: | 336 | sudo apt-add-repository ppa:ubuntugis/ubuntugis-unstable 337 | sudo apt update 338 | sudo apt install gdal-bin 339 | - name: Install Tippecanoe 340 | uses: ./.github/actions/install-tippecanoe 341 | - name: Install dependencies 342 | run: npm install 343 | working-directory: script 344 | - name: Build 345 | run: npm run build 346 | working-directory: script 347 | - name: Generate OpenStreetMap buffers 348 | uses: ./.github/actions/openstreetmap-buffers 349 | with: 350 | country: europe/belgium 351 | - name: Download & Unzip PICC data 352 | run: | 353 | wget "https://geoservices.wallonie.be/geotraitement/spwdatadownload/get/b795de68-726c-4bdf-a62a-a42686aa5b6f/PICC_vDIFF_SHAPE_31370_PROV_NAMUR.zip" 354 | unzip -j "PICC_vDIFF_SHAPE_31370_PROV_NAMUR.zip" "VOIRIE_AXE.*" 355 | - name: Convert (and filter) PICC to GeoJSON 356 | run: | 357 | ogr2ogr -f "GeoJSON" -progress \ 358 | -s_srs "EPSG:31370" -t_srs "EPSG:4326" -dim "XY" \ 359 | -makevalid \ 360 | -sql "@data/belgium/wallonia/filter.sql" \ 361 | -lco COORDINATE_PRECISION=6 \ 362 | -fieldTypeToString "All" \ 363 | "NAM_VOIRIE_AXE.geojson" \ 364 | "VOIRIE_AXE.shp" 365 | - name: Convert PICC fields to OpenStreetMap tags 366 | run: node "script/convert-tags.js" -c "data/belgium/wallonia/convert.json" "NAM_VOIRIE_AXE.geojson" "NAM_VOIRIE_AXETagged.geojson" 367 | - name: Generate PICC vector tiles 368 | run: | 369 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 370 | --buffer=0 \ 371 | --maximum-zoom=14 --minimum-zoom=14 \ 372 | --layer="roads" \ 373 | --output="NAM_VOIRIE_AXETagged.mbtiles" "NAM_VOIRIE_AXETagged.geojson" 374 | - name: Generate MapRoulette buffers 375 | uses: ./.github/actions/maproulette-buffers 376 | with: 377 | challenge-id: ${{ env.MAPROULETTE_CHALLENGE_ID }} 378 | # - name: Upload MapRoulette false positive 379 | # uses: actions/upload-artifact@v4 380 | # with: 381 | # name: MapRoulette-FalsePositive 382 | # path: maproulette.geojson 383 | - name: Merge MapRoulette buffers to OpenStreetMap buffers and generate vector tiles 384 | run: | 385 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 386 | --maximum-zoom=14 --minimum-zoom=14 \ 387 | --layer="buffers" \ 388 | --output="belgium-buffers.mbtiles" \ 389 | "openstreetmap-lines-buffers.geojson" "openstreetmap-polygons-buffers.geojson" "maproulette-buffers.geojson" 390 | - name: Difference 391 | run: node "script/difference.js" --output-dir="data/belgium/wallonia/difference/NAM" "NAM_VOIRIE_AXETagged.mbtiles" "belgium-buffers.mbtiles" 392 | - name: Upload difference 393 | uses: actions/upload-artifact@v4 394 | with: 395 | name: Namur-Difference 396 | path: data/belgium/wallonia/difference/NAM/diff.geojson 397 | - name: Upload statistics 398 | uses: actions/upload-artifact@v4 399 | with: 400 | name: Namur-Statistics 401 | path: data/belgium/wallonia/difference/NAM/stats.json 402 | 403 | merge: 404 | name: Generate difference for Wallonia, Belgium (merge) 405 | runs-on: ubuntu-latest 406 | needs: [diff-bra, diff-hai, diff-lie, diff-lux, diff-nam] 407 | steps: 408 | - uses: actions/checkout@v4 409 | with: 410 | persist-credentials: false 411 | fetch-depth: 0 412 | - name: Install GDAL 413 | run: | 414 | sudo apt-add-repository ppa:ubuntugis/ubuntugis-unstable 415 | sudo apt update 416 | sudo apt install gdal-bin 417 | - name: Clean 418 | run: | 419 | if [ -f "data/belgium/wallonia/difference/BRA/diff.geojson" ]; then rm "data/belgium/wallonia/difference/BRA/diff.geojson"; fi 420 | if [ -f "data/belgium/wallonia/difference/HAI/diff.geojson" ]; then rm "data/belgium/wallonia/difference/HAI/diff.geojson"; fi 421 | if [ -f "data/belgium/wallonia/difference/LIE/diff.geojson" ]; then rm "data/belgium/wallonia/difference/LIE/diff.geojson"; fi 422 | if [ -f "data/belgium/wallonia/difference/LUX/diff.geojson" ]; then rm "data/belgium/wallonia/difference/LUX/diff.geojson"; fi 423 | if [ -f "data/belgium/wallonia/difference/NAM/diff.geojson" ]; then rm "data/belgium/wallonia/difference/NAM/diff.geojson"; fi 424 | if [ -f "data/belgium/wallonia/difference/BRA/stats.json" ]; then rm "data/belgium/wallonia/difference/BRA/stats.json"; fi 425 | if [ -f "data/belgium/wallonia/difference/HAI/stats.json" ]; then rm "data/belgium/wallonia/difference/HAI/stats.json"; fi 426 | if [ -f "data/belgium/wallonia/difference/LIE/stats.json" ]; then rm "data/belgium/wallonia/difference/LIE/stats.json"; fi 427 | if [ -f "data/belgium/wallonia/difference/LUX/stats.json" ]; then rm "data/belgium/wallonia/difference/LUX/stats.json"; fi 428 | if [ -f "data/belgium/wallonia/difference/NAM/stats.json" ]; then rm "data/belgium/wallonia/difference/NAM/stats.json"; fi 429 | - name: Download difference for Brabant Wallon, Wallonia, Belgium 430 | uses: actions/download-artifact@v4 431 | with: 432 | name: BrabantWallon-Difference 433 | path: data/belgium/wallonia/difference/BRA 434 | - name: Download difference for Hainaut, Wallonia, Belgium 435 | uses: actions/download-artifact@v4 436 | with: 437 | name: Hainaut-Difference 438 | path: data/belgium/wallonia/difference/HAI 439 | - name: Download difference for Liège, Wallonia, Belgium 440 | uses: actions/download-artifact@v4 441 | with: 442 | name: Liege-Difference 443 | path: data/belgium/wallonia/difference/LIE 444 | - name: Download difference for Luxembourg, Wallonia, Belgium 445 | uses: actions/download-artifact@v4 446 | with: 447 | name: Luxembourg-Difference 448 | path: data/belgium/wallonia/difference/LUX 449 | - name: Download difference for Namur, Wallonia, Belgium 450 | uses: actions/download-artifact@v4 451 | with: 452 | name: Namur-Difference 453 | path: data/belgium/wallonia/difference/NAM 454 | - name: Merge differences 455 | run: | 456 | if [ -f "data/belgium/wallonia/difference/diff.geojson" ]; then rm "data/belgium/wallonia/difference/diff.geojson"; fi 457 | ogr2ogr -f "GeoJSON" -progress "data/belgium/wallonia/difference/diff.geojson" "data/belgium/wallonia/difference/BRA/diff.geojson" 458 | ogr2ogr -f "GeoJSON" -progress -append "data/belgium/wallonia/difference/diff.geojson" "data/belgium/wallonia/difference/HAI/diff.geojson" 459 | ogr2ogr -f "GeoJSON" -progress -append "data/belgium/wallonia/difference/diff.geojson" "data/belgium/wallonia/difference/LIE/diff.geojson" 460 | ogr2ogr -f "GeoJSON" -progress -append "data/belgium/wallonia/difference/diff.geojson" "data/belgium/wallonia/difference/NAM/diff.geojson" 461 | ogr2ogr -f "GeoJSON" -progress -append "data/belgium/wallonia/difference/diff.geojson" "data/belgium/wallonia/difference/LUX/diff.geojson" 462 | - name: Upload difference 463 | uses: actions/upload-artifact@v4 464 | with: 465 | name: Wallonia-Difference 466 | path: data/belgium/wallonia/difference/diff.geojson 467 | 468 | commit: 469 | name: Commit & Push changes 470 | needs: merge 471 | if: ${{ github.event_name != 'pull_request' }} 472 | runs-on: ubuntu-latest 473 | steps: 474 | - uses: actions/checkout@v4 475 | - uses: actions/download-artifact@v4 476 | with: 477 | name: BrabantWallon-Difference 478 | path: data/belgium/wallonia/difference/BRA 479 | - uses: actions/download-artifact@v4 480 | with: 481 | name: BrabantWallon-Statistics 482 | path: data/belgium/wallonia/difference/BRA 483 | - uses: actions/download-artifact@v4 484 | with: 485 | name: Hainaut-Difference 486 | path: data/belgium/wallonia/difference/HAI 487 | - uses: actions/download-artifact@v4 488 | with: 489 | name: Hainaut-Statistics 490 | path: data/belgium/wallonia/difference/HAI 491 | - uses: actions/download-artifact@v4 492 | with: 493 | name: Liege-Difference 494 | path: data/belgium/wallonia/difference/LIE 495 | - uses: actions/download-artifact@v4 496 | with: 497 | name: Liege-Statistics 498 | path: data/belgium/wallonia/difference/LIE 499 | - uses: actions/download-artifact@v4 500 | with: 501 | name: Luxembourg-Difference 502 | path: data/belgium/wallonia/difference/LUX 503 | - uses: actions/download-artifact@v4 504 | with: 505 | name: Luxembourg-Statistics 506 | path: data/belgium/wallonia/difference/LUX 507 | - uses: actions/download-artifact@v4 508 | with: 509 | name: Namur-Difference 510 | path: data/belgium/wallonia/difference/NAM 511 | - uses: actions/download-artifact@v4 512 | with: 513 | name: Namur-Statistics 514 | path: data/belgium/wallonia/difference/NAM 515 | - uses: actions/download-artifact@v4 516 | with: 517 | name: Wallonia-Difference 518 | path: data/belgium/wallonia/difference 519 | - name: Commit & Push 520 | run: | 521 | git config user.name github-actions[bot] 522 | git config user.email 41898282+github-actions[bot]@users.noreply.github.com 523 | git pull 524 | git add data/belgium/wallonia/difference/*/diff.geojson 525 | git add data/belgium/wallonia/difference/*/stats.json 526 | git add data/belgium/wallonia/difference/diff.geojson 527 | git commit -m "🗃 Update difference for Wallonia, Belgium" 528 | git push 529 | 530 | mr-rebuild: 531 | name: Rebuild MapRoulette challenge 532 | needs: commit 533 | runs-on: ubuntu-latest 534 | steps: 535 | - name: Call MapRoulette API 536 | run: | 537 | curl -X "PUT" "https://maproulette.org/api/v2/challenge/${{ env.MAPROULETTE_CHALLENGE_ID }}/rebuild?removeUnmatched=true&skipSnapshot=false" \ 538 | -H "Accept: application/json" \ 539 | -H "apiKey: ${{ secrets.MAPROULETTE_API_KEY }}" 540 | -------------------------------------------------------------------------------- /.github/workflows/deploy-report-page.yml: -------------------------------------------------------------------------------- 1 | name: Build and Deploy report page 2 | 3 | on: 4 | push: 5 | paths: 6 | - ".github/workflows/deploy-report-page.yml" 7 | - "report/**" 8 | - "data/**/diff.geojson" 9 | - "data/**/stats.json" 10 | workflow_dispatch: 11 | 12 | # Allow one concurrent deployment 13 | concurrency: 14 | group: "pages" 15 | cancel-in-progress: true 16 | 17 | jobs: 18 | 19 | build: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v4 23 | - name: Setup Pages 24 | uses: actions/configure-pages@v5 25 | - run: npm install 26 | working-directory: report 27 | - run: npm run build 28 | working-directory: report 29 | env: 30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 31 | - name: Upload artifact 32 | uses: actions/upload-pages-artifact@v3 33 | with: 34 | path: report/dist 35 | 36 | deploy: 37 | runs-on: ubuntu-latest 38 | needs: build 39 | permissions: 40 | pages: write # to deploy to Pages 41 | id-token: write # to verify the deployment originates from an appropriate source 42 | environment: 43 | name: github-pages 44 | url: ${{ steps.deployment.outputs.page_url }} 45 | steps: 46 | - name: Deploy to GitHub Pages 47 | id: deployment 48 | uses: actions/deploy-pages@v4 49 | -------------------------------------------------------------------------------- /.github/workflows/luxembourg.yml: -------------------------------------------------------------------------------- 1 | name: 🇱🇺 Luxembourg 2 | 3 | on: 4 | workflow_dispatch: 5 | # Run every Monday at 16:00 UTC. Dataset gets updated at around 11 UTC. 6 | schedule: 7 | - cron: "0 16 * * 1" 8 | push: 9 | paths: 10 | - ".github/workflows/luxembourg.yml" 11 | - ".github/actions/*/action.yml" 12 | - "script/**/*.ts" 13 | - "data/luxembourg/convert.json" 14 | - "data/luxembourg/filter.sql" 15 | pull_request: 16 | paths: 17 | - ".github/workflows/luxembourg.yml" 18 | - ".github/actions/*/action.yml" 19 | - "script/**/*.ts" 20 | - "data/luxembourg/convert.json" 21 | - "data/luxembourg/filter.sql" 22 | 23 | # Allow one concurrent deployment 24 | concurrency: 25 | group: ${{ github.workflow }}-${{ github.ref }} 26 | cancel-in-progress: true 27 | 28 | env: 29 | MAPROULETTE_CHALLENGE_ID: 17749 30 | 31 | jobs: 32 | 33 | diff: 34 | name: Generate difference for Luxembourg 35 | runs-on: ubuntu-latest 36 | steps: 37 | - uses: actions/checkout@v4 38 | - name: Install GDAL 39 | run: | 40 | sudo apt-add-repository ppa:ubuntugis/ubuntugis-unstable 41 | sudo apt update 42 | sudo apt install gdal-bin 43 | - name: Install Tippecanoe 44 | uses: ./.github/actions/install-tippecanoe 45 | - name: Install dependencies 46 | run: npm install 47 | working-directory: script 48 | - name: Build 49 | run: npm run build 50 | working-directory: script 51 | - name: Generate OpenStreetMap buffers 52 | uses: ./.github/actions/openstreetmap-buffers 53 | with: 54 | country: europe/luxembourg 55 | - name: Download & Unzip source data 56 | run: | 57 | wget --no-check-certificate -O "transport-et-voies-de-communication-shape.zip" "https://data.public.lu/fr/datasets/r/e74aadad-77c2-441e-98fe-e08a441484a2" 58 | unzip "transport-et-voies-de-communication-shape.zip" "TRP_VC.*" 59 | - name: Convert (and filter) source data to GeoJSON 60 | run: | 61 | ogr2ogr -f "GeoJSON" -progress \ 62 | --config SHAPE_ENCODING "ISO-8859-1" \ 63 | -s_srs "EPSG:2169" -t_srs "EPSG:4326" \ 64 | -sql "@data/luxembourg/filter.sql" \ 65 | -lco COORDINATE_PRECISION=6 \ 66 | -fieldTypeToString "All" \ 67 | "trpvc.geojson" \ 68 | "TRP_VC.shp" 69 | - name: Download extra data 70 | run: | 71 | wget -O "csventrifuge_enhance_name.csv" "https://raw.githubusercontent.com/osmlu/csventrifuge/master/rules/luxembourg_addresses/rue.csv" 72 | wget -O "csventrifuge_enhance_id.csv" "https://raw.githubusercontent.com/osmlu/csventrifuge/master/enhance/luxembourg_addresses/id_caclr_rue/rue.csv" 73 | - name: Process extra data 74 | run: | 75 | node "data/luxembourg/build-extended-conversion.js" "csventrifuge_enhance_name.csv" "csventrifuge_enhance_id.csv" "data/luxembourg/convert.json" "convert-merged.json" 76 | - name: Convert fields to OpenStreetMap tags 77 | run: node "script/convert-tags.js" -c "convert-merged.json" "trpvc.geojson" "trpvcTagged.geojson" 78 | - name: Generate vector tiles 79 | run: | 80 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 81 | --buffer=0 \ 82 | --maximum-zoom=14 --minimum-zoom=14 \ 83 | --layer="roads" \ 84 | --output="trpvcTagged.mbtiles" "trpvcTagged.geojson" 85 | - name: Generate MapRoulette buffers 86 | uses: ./.github/actions/maproulette-buffers 87 | with: 88 | challenge-id: ${{ env.MAPROULETTE_CHALLENGE_ID }} 89 | - name: Upload MapRoulette false positive 90 | uses: actions/upload-artifact@v4 91 | with: 92 | name: MapRoulette-FalsePositive 93 | path: maproulette.geojson 94 | - name: Merge MapRoulette buffers to OpenStreetMap buffers and generate vector tiles 95 | run: | 96 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 97 | --maximum-zoom=14 --minimum-zoom=14 \ 98 | --layer="buffers" \ 99 | --output="luxembourg-buffers.mbtiles" \ 100 | "openstreetmap-lines-buffers.geojson" "openstreetmap-polygons-buffers.geojson" "maproulette-buffers.geojson" 101 | - name: Difference 102 | run: node "script/difference.js" --output-dir="data/luxembourg/difference" "trpvcTagged.mbtiles" "luxembourg-buffers.mbtiles" 103 | - name: Upload difference 104 | uses: actions/upload-artifact@v4 105 | with: 106 | name: Luxembourg-Difference 107 | path: data/luxembourg/difference/diff.geojson 108 | - name: Upload statistics 109 | uses: actions/upload-artifact@v4 110 | with: 111 | name: Luxembourg-Statistics 112 | path: data/luxembourg/difference/stats.json 113 | 114 | commit: 115 | name: Commit & Push changes 116 | needs: diff 117 | if: ${{ github.event_name != 'pull_request' }} 118 | runs-on: ubuntu-latest 119 | steps: 120 | - uses: actions/checkout@v4 121 | - uses: actions/download-artifact@v4 122 | with: 123 | name: Luxembourg-Difference 124 | path: data/luxembourg/difference 125 | - uses: actions/download-artifact@v4 126 | with: 127 | name: Luxembourg-Statistics 128 | path: data/luxembourg/difference 129 | - name: Commit & Push 130 | run: | 131 | git config user.name github-actions[bot] 132 | git config user.email 41898282+github-actions[bot]@users.noreply.github.com 133 | git pull 134 | git add data/luxembourg/difference/diff.geojson 135 | git add data/luxembourg/difference/stats.json 136 | git commit -m "🗃 Update difference for Luxembourg" 137 | git push 138 | 139 | # mr-rebuild: 140 | # name: Rebuild MapRoulette challenge 141 | # needs: commit 142 | # runs-on: ubuntu-latest 143 | # steps: 144 | # - name: Call MapRoulette API 145 | # run: | 146 | # curl -X "PUT" "https://maproulette.org/api/v2/challenge/${{ env.MAPROULETTE_CHALLENGE_ID }}/rebuild?removeUnmatched=true&skipSnapshot=false" \ 147 | # -H "Accept: application/json" \ 148 | # -H "apiKey: ${{ secrets.MAPROULETTE_API_KEY }}" 149 | -------------------------------------------------------------------------------- /.github/workflows/netherlands.yml: -------------------------------------------------------------------------------- 1 | name: 🇳🇱 Netherlands 2 | 3 | on: 4 | workflow_dispatch: 5 | # Run every Sunday at 12:00 UTC 6 | schedule: 7 | - cron: "0 12 * * 0" 8 | push: 9 | paths: 10 | - ".github/workflows/netherlands.yml" 11 | - ".github/actions/*/action.yml" 12 | - "script/**/*.ts" 13 | - "data/netherlands/convert.json" 14 | - "data/netherlands/filter.sql" 15 | pull_request: 16 | paths: 17 | - ".github/workflows/netherlands.yml" 18 | - ".github/actions/*/action.yml" 19 | - "script/**/*.ts" 20 | - "data/netherlands/convert.json" 21 | - "data/netherlands/filter.sql" 22 | 23 | # Allow one concurrent deployment 24 | concurrency: 25 | group: ${{ github.workflow }}-${{ github.ref }} 26 | cancel-in-progress: true 27 | 28 | env: 29 | MAPROULETTE_CHALLENGE_ID: 17332 30 | 31 | jobs: 32 | 33 | diff: 34 | name: Generate difference for Netherlands 35 | runs-on: ubuntu-latest 36 | steps: 37 | - uses: actions/checkout@v4 38 | - name: Install GDAL 39 | run: | 40 | sudo apt-add-repository ppa:ubuntugis/ubuntugis-unstable 41 | sudo apt update 42 | sudo apt install gdal-bin 43 | - name: Install Tippecanoe 44 | uses: ./.github/actions/install-tippecanoe 45 | - name: Install dependencies 46 | run: npm install 47 | working-directory: script 48 | - name: Build 49 | run: npm run build 50 | working-directory: script 51 | - name: Generate OpenStreetMap buffers 52 | uses: ./.github/actions/openstreetmap-buffers 53 | with: 54 | country: europe/netherlands 55 | - name: Download & Unzip NWB data 56 | run: | 57 | wget --no-check-certificate "https://downloads.rijkswaterstaatdata.nl/nwb-wegen/geogegevens/shapefile/Nederland_totaal/01-12-2022.zip" 58 | unzip -j "01-12-2022.zip" "01-12-2022/Wegvakken/Wegvakken.*" 59 | - name: Convert (and filter) NWB to GeoJSON 60 | run: | 61 | ogr2ogr -f "GeoJSON" -progress \ 62 | --config SHAPE_ENCODING "ISO-8859-1" \ 63 | -s_srs "EPSG:28992" -t_srs "EPSG:4326" \ 64 | -sql "@data/netherlands/filter.sql" \ 65 | -lco COORDINATE_PRECISION=6 \ 66 | -fieldTypeToString "All" \ 67 | "Wegvakken.geojson" \ 68 | "Wegvakken.shp" 69 | - name: Convert NWB fields to OpenStreetMap tags 70 | run: node "script/convert-tags.js" -c "data/netherlands/convert.json" "Wegvakken.geojson" "WegvakkenTagged.geojson" 71 | - name: Generate NWB vector tiles 72 | run: | 73 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 74 | --buffer=0 \ 75 | --maximum-zoom=14 --minimum-zoom=14 \ 76 | --layer="roads" \ 77 | --output="WegvakkenTagged.mbtiles" "WegvakkenTagged.geojson" 78 | - name: Generate MapRoulette buffers 79 | uses: ./.github/actions/maproulette-buffers 80 | with: 81 | challenge-id: ${{ env.MAPROULETTE_CHALLENGE_ID }} 82 | - name: Upload MapRoulette false positive 83 | uses: actions/upload-artifact@v4 84 | with: 85 | name: MapRoulette-FalsePositive 86 | path: maproulette.geojson 87 | - name: Merge MapRoulette buffers to OpenStreetMap buffers and generate vector tiles 88 | run: | 89 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 90 | --maximum-zoom=14 --minimum-zoom=14 \ 91 | --layer="buffers" \ 92 | --output="netherlands-buffers.mbtiles" \ 93 | "openstreetmap-lines-buffers.geojson" "openstreetmap-polygons-buffers.geojson" "maproulette-buffers.geojson" 94 | - name: Difference 95 | run: node "script/difference.js" --output-dir="data/netherlands/difference" "WegvakkenTagged.mbtiles" "netherlands-buffers.mbtiles" 96 | - name: Upload difference 97 | uses: actions/upload-artifact@v4 98 | with: 99 | name: Netherlands-Difference 100 | path: data/netherlands/difference/diff.geojson 101 | - name: Upload statistics 102 | uses: actions/upload-artifact@v4 103 | with: 104 | name: Netherlands-Statistics 105 | path: data/netherlands/difference/stats.json 106 | 107 | commit: 108 | name: Commit & Push changes 109 | needs: diff 110 | if: ${{ github.event_name != 'pull_request' }} 111 | runs-on: ubuntu-latest 112 | steps: 113 | - uses: actions/checkout@v4 114 | - uses: actions/download-artifact@v4 115 | with: 116 | name: Netherlands-Difference 117 | path: data/netherlands/difference 118 | - uses: actions/download-artifact@v4 119 | with: 120 | name: Netherlands-Statistics 121 | path: data/netherlands/difference 122 | - name: Commit & Push 123 | run: | 124 | git config user.name github-actions[bot] 125 | git config user.email 41898282+github-actions[bot]@users.noreply.github.com 126 | git pull 127 | git add data/netherlands/difference/diff.geojson 128 | git add data/netherlands/difference/stats.json 129 | git commit -m "🗃 Update difference for Netherlands" 130 | git push 131 | 132 | # mr-rebuild: 133 | # name: Rebuild MapRoulette challenge 134 | # needs: commit 135 | # runs-on: ubuntu-latest 136 | # steps: 137 | # - name: Call MapRoulette API 138 | # run: | 139 | # curl -X "PUT" "https://maproulette.org/api/v2/challenge/${{ env.MAPROULETTE_CHALLENGE_ID }}/rebuild?removeUnmatched=true&skipSnapshot=false" \ 140 | # -H "Accept: application/json" \ 141 | # -H "apiKey: ${{ secrets.MAPROULETTE_API_KEY }}" 142 | -------------------------------------------------------------------------------- /.github/workflows/node.js-report.yml: -------------------------------------------------------------------------------- 1 | name: "Node.js CI - Report" 2 | 3 | on: 4 | push: 5 | paths: 6 | - ".github/workflows/node.js-report.yml" 7 | - "report/**" 8 | pull_request: 9 | paths: 10 | - "report/**" 11 | 12 | jobs: 13 | build-report: 14 | runs-on: ubuntu-latest 15 | strategy: 16 | matrix: 17 | node-version: [16.x, 18.x] 18 | steps: 19 | - uses: actions/checkout@v4 20 | - name: Use Node.js ${{ matrix.node-version }} 21 | uses: actions/setup-node@v4 22 | with: 23 | node-version: ${{ matrix.node-version }} 24 | - run: npm install 25 | working-directory: report 26 | - run: npm run build 27 | working-directory: report 28 | env: 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | -------------------------------------------------------------------------------- /.github/workflows/node.js-script.yml: -------------------------------------------------------------------------------- 1 | name: "Node.js CI - Script" 2 | 3 | on: 4 | push: 5 | paths: 6 | - ".github/workflows/node.js-script.yml" 7 | - "script/**" 8 | pull_request: 9 | paths: 10 | - "script/**" 11 | 12 | jobs: 13 | build-script: 14 | runs-on: ubuntu-latest 15 | strategy: 16 | matrix: 17 | node-version: [16.x, 18.x] 18 | steps: 19 | - uses: actions/checkout@v4 20 | - name: Use Node.js ${{ matrix.node-version }} 21 | uses: actions/setup-node@v4 22 | with: 23 | node-version: ${{ matrix.node-version }} 24 | - run: npm install 25 | working-directory: script 26 | - run: npm run build 27 | working-directory: script 28 | 29 | lint-script: 30 | runs-on: ubuntu-latest 31 | steps: 32 | - uses: actions/checkout@v4 33 | - uses: actions/setup-node@v4 34 | - run: npm ci 35 | working-directory: script 36 | - run: npm run lint 37 | working-directory: script 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | data/**/source/ 2 | data/**/temp/ 3 | data/**/*.geojson 4 | !data/**/diff.geojson 5 | script/**/*.js 6 | node_modules/ 7 | *.osm.pbf 8 | *.mbtiles 9 | *.mbtiles-journal -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 OpenStreetMap Belgium 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Road Completion project 2 | 3 | *Software set-up inspired by ["Quality analysis for OpenStreetMap"](https://blog.mapbox.com/quality-analysis-for-openstreetmap-a9058eb79c9a) by [Matt Greene](https://github.com/MateoV) from [Mapbox](https://www.mapbox.com/)* 4 | 5 | ## Goals 6 | 7 | OpenStreetMap (OSM) is extremly good at quickly creating a usable map. It is less good at getting to 100% finished on a specific topic. The last 2% of roads might take forever to get mapped in OpenStreetMap. This project aims to find these 2% with the help of external road data. This can be governement data or machine learned data. We then offer the missing roads as microtasks to the mapping community. This means that after we have "finished" the work, the OpenStreetMap data will be at least as complete as the reference dataset - so any trust placed in that reference can now be place in OpenStreetMap as well! 8 | 9 | ## History of the project 10 | 11 | - [Diary post](https://www.openstreetmap.org/user/joost%20schouppe/diary/39250) and POC by [Joost Schouppe](https://github.com/joostschouppe) (8/2016) 12 | - [Birds of a feather session at State of the Map 2016](https://wiki.openstreetmap.org/wiki/State_Of_The_Map_2016/Informal_Sessions#Mapping_with_open_geodata) 13 | - [Project page in OpenStreetMap wiki](https://wiki.openstreetmap.org/wiki/WikiProject_Belgium/Road_completion_project) 14 | - [Talk at FOSS4G Belgium 2017](https://slides.com/benabelshausen-1/deck-1) by [Ben Abelshausen](https://github.com/xivk) 15 | - [Talk at State of the Map 2018](https://2018.stateofthemap.org/2018/T097-Road_Completion_in_Belgium_-_Mapping___verifying__all__the_roads_/) by [Ben Abelshausen](https://github.com/xivk) 16 | - [Open Summer of Code 2018](https://2018.summerofcode.be/roadcompletion.html) 17 | - [OpenStreetMap Foundation microgrant 2020](https://wiki.openstreetmap.org/wiki/Microgrants/Microgrants_2020/Proposal/Road_Completion_project) 18 | - [OpenStreetMap Foundation microgrant 2020 - Final report](https://wiki.openstreetmap.org/wiki/Microgrants/Microgrants_2020/Proposal/Road_Completion_project/Report) 19 | 20 | ## Process 21 | 22 | 1. Download OpenStreetMap data 23 | 1. Convert OpenStreetMap data to GeoJSON (keeping only `highway=*`) 24 | 1. Generate buffer around OpenStreetMap data 25 | 1. Download source data 26 | 1. Convert source data to GeoJSON (with optional filtering) 27 | 1. Convert source data to OpenStreetMap tags 28 | 1. Generate vector tiles from source data 29 | 1. Download false positive from [MapRoulette](https://maproulette.org/) challenge (*optional*) 30 | 1. Generate buffers around MapRoulette data (*optional*) 31 | 1. Generate vector tiles from OpenStreetMap (+ MapRoulette) buffers 32 | 1. Process difference : all the roads from the source data that are not in the OpenStreetMap (+ MapRoulette) buffers 33 | 1. Update MapRoulette challenge with latest data (*optional*) 34 | 35 | ## Requirements 36 | 37 | - [GDAL 2.1+](https://gdal.org/) 38 | - [tippecanoe](https://github.com/mapbox/tippecanoe) 39 | - (Python, might be needed during [TileReduce](https://github.com/mapbox/tile-reduce) install) 40 | 41 | ## Data 42 | 43 | 📉 [Statistics about datasets process](https://osmbe.github.io/road-completion/) 44 | 45 | | Country | Region | Source | MapRoulette | 46 | |-----------------------------------|------------------------------------------|---------------------------|-----------------------| 47 | | :belgium: Belgium | [Bruxelles/Brussel (Brussels)][be-bru-1] | [UrbIS-Adm][be-bru-2] | [Challenge][be-bru-3] | 48 | | :belgium: Belgium | [Vlaanderen (Flanders)][be-vla-1] | [Wegenregister][be-vla-2] | [Challenge][be-vla-3] | 49 | | :belgium: Belgium | [Wallonie (Wallonia)][be-wal-1] | [PICC][be-wal-2] | [Challenge][be-wal-3] | 50 | | :kosovo: [Kosovo][xk-1] | | [AKK][xk-2] | | 51 | | :luxembourg: [Luxembourg][lu-1] | | [TRP-VC][lu-2] | [Challenge][lu-3] | 52 | | :netherlands: [Netherlands][nl-1] | | [NWB][nl-2] | [Challenge][nl-3] | 53 | 54 | [be-bru-1]: https://github.com/osmbe/road-completion/tree/master/data/belgium/brussels 55 | [be-bru-2]: https://bric.brussels/en/our-solutions/urbis-solutions/urbis-data/urbis-adm 56 | [be-bru-3]: https://maproulette.org/browse/challenges/14675 57 | [be-vla-1]: https://github.com/osmbe/road-completion/tree/master/data/belgium/flanders 58 | [be-vla-2]: https://download.vlaanderen.be/product/10707-wegenregister-30012025 59 | [be-vla-3]: https://maproulette.org/browse/challenges/24090 60 | [be-wal-1]: https://github.com/osmbe/road-completion/tree/master/data/belgium/wallonia 61 | [be-wal-2]: http://geoportail.wallonie.be/catalogue/b795de68-726c-4bdf-a62a-a42686aa5b6f.html 62 | [be-wal-3]: https://maproulette.org/browse/challenges/14681 63 | [xk-1]: https://github.com/osmbe/road-completion/tree/master/data/kosovo 64 | [xk-2]: https://ak.rks-gov.net/en/ 65 | [lu-1]: https://github.com/osmbe/road-completion/tree/master/data/luxembourg 66 | [lu-2]: https://data.public.lu/en/datasets/transport-et-voies-de-communication/ 67 | [lu-3]: https://maproulette.org/browse/challenges/17749 68 | [nl-1]: https://github.com/osmbe/road-completion/tree/master/data/netherlands 69 | [nl-2]: https://nationaalwegenbestand.nl/ 70 | [nl-3]: https://maproulette.org/browse/challenges/17332 71 | 72 | ## Replicate 73 | 74 | If you want to run the comparison process in your country/region, you simply have to replicate one of the existing regions (for instance, [Flanders](https://github.com/osmbe/road-completion/tree/master/data/belgium/flanders)) : 75 | 76 | - `process.sh` is the comparison shell script (see [example](https://github.com/osmbe/road-completion/blob/master/data/belgium/flanders/process.sh)) 77 | - `filter.sql` is the SQL query to filter your data (see [example](https://github.com/osmbe/road-completion/blob/master/data/belgium/flanders/filter.sql) and [usage](https://github.com/osmbe/road-completion/blob/master/data/belgium/flanders/process.sh#L25-L31)) 78 | - `convert.json` is the tag conversion (from your data to OSM tag(s)) (see [documentation](https://github.com/osmbe/road-completion/blob/master/script/README.md#convert-source-field-to-openstreetmap-tag) and [example](https://github.com/osmbe/road-completion/blob/master/data/belgium/flanders/convert.json)) 79 | 80 | You can find more documentation about the scripts here : 81 | 82 | ## Scope 83 | 84 | This set-up is ideal if there are relatively few missing roads. If there are whole swats of network missing in OSM, you might consider a tool like [Cygnus](https://www.openstreetmap.org/user/mvexel/diary/36746) instead. 85 | 86 | The current matching is based on a simple buffer - so both OSM and the ref dataset need to be af high geometric quality to result in a reasonable amount of tasks. However, you are invited to create more advanced comparison processes. Next on our roadmap is adding attribute comparisons, for example to compare street names. 87 | -------------------------------------------------------------------------------- /data/belgium/belgium.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Make script directory working directory 4 | 5 | cd `dirname "$(realpath $0)"` 6 | 7 | # Download Belgium extract 8 | 9 | if [ -f "belgium-latest.osm.pbf" ]; then rm "belgium-latest.osm.pbf"; fi 10 | 11 | wget https://download.geofabrik.de/europe/belgium-latest.osm.pbf 12 | 13 | # Convert to GeoJSON 14 | 15 | if [ -f "./belgium-lines.geojson" ]; then rm "./belgium-lines.geojson"; fi 16 | if [ -f "./belgium-polygons.geojson" ]; then rm "./belgium-polygons.geojson"; fi 17 | 18 | ogr2ogr -f "GeoJSON" -progress \ 19 | -sql "SELECT name, highway FROM lines WHERE highway IS NOT NULL" \ 20 | "./belgium-lines.geojson" \ 21 | "./belgium-latest.osm.pbf" 22 | ogr2ogr -f "GeoJSON" -progress \ 23 | -sql "SELECT name, hstore_get_value(other_tags, 'highway') AS highway, place FROM multipolygons WHERE (hstore_get_value(other_tags, 'highway') is not null) OR (place = 'square')" \ 24 | "./belgium-polygons.geojson" \ 25 | "./belgium-latest.osm.pbf" 26 | 27 | # Generate buffer 28 | 29 | node "../../script/buffer.js" --radius=20 "./belgium-lines.geojson" "belgium-lines-buffers.geojson" 30 | node "../../script/buffer.js" --radius=5 "./belgium-polygons.geojson" "belgium-polygons-buffers.geojson" 31 | 32 | # Generate vector tiles 33 | 34 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 35 | --maximum-zoom=14 --minimum-zoom=14 \ 36 | --layer="buffers" \ 37 | --output="./belgium-buffers.mbtiles" \ 38 | "./belgium-lines-buffers.geojson" "./belgium-polygons-buffers.geojson" 39 | -------------------------------------------------------------------------------- /data/belgium/brussels/README.md: -------------------------------------------------------------------------------- 1 | # Road Completion - 🇧🇪 Belgium - Brussels 2 | 3 | [![🇧🇪 Brussels, Belgium](https://github.com/osmbe/road-completion/actions/workflows/belgium-brussels.yml/badge.svg)](https://github.com/osmbe/road-completion/actions/workflows/belgium-brussels.yml) 4 | 5 | > Source: 6 | 7 | ## Filters 8 | 9 | ### `TYPE` 10 | 11 | ```sql 12 | "TYPE" NOT IN ('M', 'O', 'MS', 'RS', 'RT', 'MT') 13 | ``` 14 | 15 | See below for values decription. 16 | 17 | ## Tags 18 | 19 | ### `TYPE` 20 | 21 | | Value | Description | Note | OSM Tag(s) | 22 | |-------|------------------------------|---------------------------------------------------|---------------------------------------------| 23 | | S | Section | Tronçon de rue | `highway=unclassified` | 24 | | I | Intersection | Carrefour | `highway=unclassified` | 25 | | T | Road Tunnel | Tunnel routier | `highway=unclassified` + `tunnel=yes` | 26 | | PT | Section | Pedestrian Tunnel | `highway=footway` + `tunnel=yes` | 27 | | B | Bridge | Pont/Viaduc routier | `highway=unclassified` + `bridge=yes` | 28 | | PB | Pedestrian Bridge | Pont piéton | `highway=footway` + `bridge=yes` | 29 | | A | Access ramp | Rampe d'accès | `highway=unclassified` | 30 | | P | Place | Place | `highway=unclassified` + `place=square` | 31 | | G | Galery | Galerie | `highway=pedestrian` + `covered=yes` | 32 | | W | Way | Chemin / ruelle / venelle | `highway=unclassified` | 33 | | M | Median | Terre-plein / berme / rond-point | | 34 | | C | Own site public transport | Site propre aménagé pour les transports en commun | `highway=unclassified` + `psv=designated` | 35 | | AC | Access Ramp public transport | Rampe d’accès pour les trams / bus | `highway=unclassified` + `psv=designated` | 36 | | IC | Intersection Common | Carrefour partagé avec des voies de trams | `highway=unclassified` | 37 | | K | Parking | Zone de parking en voirie en îlot | `highway=service` + `service=parking_aisle` | 38 | | SC | Section Common | Tronçon partagé avec des voies de tram | `highway=unclassified` | 39 | | IL | Intersection Level Crossing | Carrefour / passage à niveau | `highway=unclassified` | 40 | | O | Off-road | Terrain vague, en friche | | 41 | | MS | Metro Station | Station de métro | | 42 | | RS | Rail Station | Gare de chemin de fer | | 43 | | RT | Rail Tunnel | Tunnel SNCB | | 44 | | MT | Metro Tunnel | Tunnel de métro | | 45 | -------------------------------------------------------------------------------- /data/belgium/brussels/convert.json: -------------------------------------------------------------------------------- 1 | { 2 | "TYPE": { 3 | "S": { 4 | "highway": "unclassified" 5 | }, 6 | "I": { 7 | "highway": "unclassified" 8 | }, 9 | "T": { 10 | "highway": "unclassified", 11 | "tunnel": "yes" 12 | }, 13 | "PT": { 14 | "highway": "footway", 15 | "tunnel": "yes" 16 | }, 17 | "B": { 18 | "highway": "unclassified", 19 | "bridge": "yes" 20 | }, 21 | "PB": { 22 | "highway": "footway", 23 | "bridge": "yes" 24 | }, 25 | "A": { 26 | "highway": "unclassified" 27 | }, 28 | "P": { 29 | "highway": "unclassified", 30 | "place": "square" 31 | }, 32 | "G": { 33 | "highway": "pedestrian", 34 | "covered": "yes" 35 | }, 36 | "W": { 37 | "highway": "unclassified" 38 | }, 39 | "C": { 40 | "highway": "unclassified", 41 | "psv": "designated" 42 | }, 43 | "AC": { 44 | "highway": "unclassified", 45 | "psv": "designated" 46 | }, 47 | "IC": { 48 | "highway": "unclassified" 49 | }, 50 | "K": { 51 | "highway": "service", 52 | "service": "parking_aisle" 53 | }, 54 | "SC": { 55 | "highway": "unclassified" 56 | }, 57 | "IL": { 58 | "highway": "unclassified" 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /data/belgium/brussels/difference/diff.geojson: -------------------------------------------------------------------------------- 1 | {"type":"FeatureCollection","features":[ 2 | {"type":"Feature","properties":{"highway":"unclassified","psv":"designated","original:ID":"163939328","original:VERSIONID":"1","original:LENGTH":"219.54","original:SLOPE":"0","original:TYPE":"C","original:LEVEL_Z":"0","original:INSPIRE_ID":"BE.BRUSSELS.BRIC.ADM.SA.25544","original:BEGIN_LIFE":"2024/02/13"},"geometry":{"type":"LineString","coordinates":[[4.289689064025879,50.87223745883253],[4.289689064025879,50.87231870417287],[4.289705157279968,50.872355941573204],[4.289769530296326,50.87242703107307],[4.2898982763290405,50.87251504649407],[4.290289878845215,50.872731699130014],[4.291250109672546,50.87320900841513],[4.291942119598389,50.87354413754548]]}}, 3 | {"type":"Feature","properties":{"highway":"unclassified","original:ID":"11139135","original:VERSIONID":"2","original:SN_ID_B":"11139174","original:SN_ID_E":"11139172","original:LENGTH":"131.34","original:SLOPE":"1.15","original:TYPE":"W","original:LEVEL_Z":"0","original:INSPIRE_ID":"BE.BRUSSELS.BRIC.ADM.SA.22245","original:BEGIN_LIFE":"2016/03/30"},"geometry":{"type":"LineString","coordinates":[[4.339272379875183,50.786431154268485],[4.339444041252136,50.78639045680532],[4.33958888053894,50.786414196996475],[4.339642524719238,50.786414196996475],[4.339674711227417,50.78640402263031],[4.339706897735596,50.78638028243401],[4.339771270751953,50.786363325143554],[4.33984637260437,50.786363325143554],[4.339905381202698,50.78638028243401],[4.340318441390991,50.78644811153433],[4.340388178825378,50.78644811153433],[4.340457916259766,50.78643793717555],[4.340565204620361,50.78638367389138],[4.34059202671051,50.78638028243401],[4.340677857398987,50.78639045680532],[4.340752959251404,50.78644811153433],[4.340881705284119,50.786475243146924],[4.340962171554565,50.786482026047594],[4.340983629226685,50.786488808947325]]}}, 4 | {"type":"Feature","properties":{"highway":"unclassified","original:ID":"11106410","original:VERSIONID":"1","original:SN_ID_B":"11108289","original:SN_ID_E":"11108303","original:LENGTH":"132.23","original:SLOPE":"1.25","original:TYPE":"S","original:LEVEL_Z":"0","original:INSPIRE_ID":"BE.BRUSSELS.BRIC.ADM.SA.11438","original:BEGIN_LIFE":"2015/10/05"},"geometry":{"type":"LineString","coordinates":[[4.354979395866394,50.89470655248721],[4.355440735816956,50.894588126572074],[4.355751872062683,50.89452722169847],[4.3561917543411255,50.894466316745195],[4.356508255004883,50.89445616591192],[4.356797933578491,50.89446293313435]]}}, 5 | {"type":"Feature","properties":{"highway":"unclassified","original:ID":"11106440","original:VERSIONID":"1","original:SN_ID_B":"11108309","original:SN_ID_E":"11108314","original:LENGTH":"75.54000000000001","original:SLOPE":"2.59","original:TYPE":"S","original:LEVEL_Z":"0","original:INSPIRE_ID":"BE.BRUSSELS.BRIC.ADM.SA.11220","original:BEGIN_LIFE":"2015/10/05"},"geometry":{"type":"LineString","coordinates":[[4.357275366783142,50.894517070878436],[4.3574899435043335,50.8945610577492],[4.358278512954712,50.89476407353732]]}}, 6 | {"type":"Feature","properties":{"highway":"unclassified","original:ID":"11104106","original:VERSIONID":"1","original:SN_ID_B":"11104643","original:SN_ID_E":"11104661","original:LENGTH":"227.67","original:SLOPE":"1.73","original:TYPE":"S","original:LEVEL_Z":"0","original:INSPIRE_ID":"BE.BRUSSELS.BRIC.ADM.SA.20202","original:BEGIN_LIFE":"2015/10/05"},"geometry":{"type":"LineString","coordinates":[[4.375573396682739,50.88323475870649],[4.3756914138793945,50.883315984875736],[4.376024007797241,50.88347505238028],[4.376136660575867,50.883535971706266],[4.376329779624939,50.883671347701124],[4.3767160177230835,50.88399624848381],[4.377129077911377,50.8843922182493],[4.3772149085998535,50.884466673726735],[4.377391934394836,50.88458850970588],[4.377434849739075,50.88462573730263],[4.377504587173462,50.88469342376595],[4.3775475025177,50.88474757286585],[4.377579689025879,50.884815259152134]]}}, 7 | {"type":"Feature","properties":{"highway":"unclassified","original:ID":"11104088","original:VERSIONID":"1","original:SN_ID_B":"11104658","original:SN_ID_E":"11104664","original:LENGTH":"131.86","original:SLOPE":"1.05","original:TYPE":"S","original:LEVEL_Z":"0","original:INSPIRE_ID":"BE.BRUSSELS.BRIC.ADM.SA.18199","original:BEGIN_LIFE":"2015/10/05"},"geometry":{"type":"LineString","coordinates":[[4.376630187034607,50.88363073494398],[4.376678466796875,50.88370180724573],[4.376753568649292,50.8837458043306],[4.376952052116394,50.883884564095325],[4.377161264419556,50.884067320227985],[4.3772900104522705,50.88419931032243],[4.377456307411194,50.88440237127597],[4.377574324607849,50.88463927460319]]}}, 8 | {"type":"Feature","properties":{"highway":"unclassified","original:ID":"11104116","original:VERSIONID":"1","original:SN_ID_B":"11104643","original:SN_ID_E":"11104664","original:LENGTH":"213.19","original:SLOPE":"1.94","original:TYPE":"S","original:LEVEL_Z":"0","original:INSPIRE_ID":"BE.BRUSSELS.BRIC.ADM.SA.20204","original:BEGIN_LIFE":"2015/10/05"},"geometry":{"type":"LineString","coordinates":[[4.375573396682739,50.88323475870649],[4.375734329223633,50.883278756232414],[4.375820159912109,50.883315984875736],[4.376174211502075,50.88348859001516],[4.376335144042969,50.88359012215139],[4.376522898674011,50.88373565116086],[4.376785755157471,50.883962404757995],[4.377252459526062,50.88440913995919],[4.377574324607849,50.88463927460319]]}}, 9 | {"type":"Feature","properties":{"highway":"unclassified","original:ID":"8807519","original:VERSIONID":"2","original:SN_ID_B":"3104090","original:SN_ID_E":"8807540","original:LENGTH":"153.31","original:SLOPE":"3.35","original:TYPE":"W","original:LEVEL_Z":"0","original:INSPIRE_ID":"BE.BRUSSELS.BRIC.ADM.SA.17632","original:BEGIN_LIFE":"2016/03/30"},"geometry":{"type":"LineString","coordinates":[[4.37629759311676,50.805934726769095],[4.376243948936462,50.806073718151936],[4.376158118247986,50.8062059290836],[4.3760669231414795,50.806311019557256],[4.375739693641663,50.806599169643306],[4.375659227371216,50.80665340946072],[4.375712871551514,50.80676188890669]]}} 10 | ]} -------------------------------------------------------------------------------- /data/belgium/brussels/difference/stats.json: -------------------------------------------------------------------------------- 1 | [{"tile":[8385,5497,14],"roads":27,"buffers":121,"notWithin":0},{"tile":[8385,5498,14],"roads":59,"buffers":369,"notWithin":0},{"tile":[8385,5496,14],"roads":1,"buffers":363,"notWithin":0},{"tile":[8386,5495,14],"roads":18,"buffers":290,"notWithin":0},{"tile":[8386,5497,14],"roads":150,"buffers":537,"notWithin":0},{"tile":[8386,5496,14],"roads":129,"buffers":656,"notWithin":0},{"tile":[8386,5498,14],"roads":191,"buffers":966,"notWithin":0},{"tile":[8386,5494,14],"roads":45,"buffers":633,"notWithin":0},{"tile":[8387,5499,14],"roads":17,"buffers":673,"notWithin":0},{"tile":[8387,5498,14],"roads":197,"buffers":1021,"notWithin":0},{"tile":[8387,5497,14],"roads":410,"buffers":1550,"notWithin":0},{"tile":[8387,5495,14],"roads":251,"buffers":1104,"notWithin":0},{"tile":[8387,5496,14],"roads":492,"buffers":1424,"notWithin":0},{"tile":[8387,5493,14],"roads":67,"buffers":800,"notWithin":0},{"tile":[8388,5500,14],"roads":85,"buffers":675,"notWithin":0},{"tile":[8387,5492,14],"roads":3,"buffers":201,"notWithin":0},{"tile":[8387,5494,14],"roads":420,"buffers":1473,"notWithin":1},{"tile":[8388,5498,14],"roads":273,"buffers":1208,"notWithin":0},{"tile":[8388,5497,14],"roads":326,"buffers":1137,"notWithin":0},{"tile":[8388,5499,14],"roads":236,"buffers":1218,"notWithin":0},{"tile":[8388,5496,14],"roads":392,"buffers":1613,"notWithin":0},{"tile":[8388,5493,14],"roads":328,"buffers":1653,"notWithin":0},{"tile":[8388,5494,14],"roads":698,"buffers":1905,"notWithin":0},{"tile":[8388,5495,14],"roads":487,"buffers":1735,"notWithin":0},{"tile":[8389,5500,14],"roads":236,"buffers":830,"notWithin":1},{"tile":[8389,5501,14],"roads":57,"buffers":594,"notWithin":0},{"tile":[8389,5499,14],"roads":362,"buffers":1185,"notWithin":0},{"tile":[8388,5492,14],"roads":282,"buffers":1808,"notWithin":0},{"tile":[8389,5498,14],"roads":356,"buffers":1186,"notWithin":0},{"tile":[8389,5497,14],"roads":584,"buffers":2629,"notWithin":0},{"tile":[8389,5494,14],"roads":533,"buffers":2159,"notWithin":0},{"tile":[8390,5500,14],"roads":135,"buffers":426,"notWithin":0},{"tile":[8389,5496,14],"roads":718,"buffers":2981,"notWithin":0},{"tile":[8389,5495,14],"roads":792,"buffers":2879,"notWithin":0},{"tile":[8390,5501,14],"roads":45,"buffers":173,"notWithin":0},{"tile":[8389,5492,14],"roads":341,"buffers":2094,"notWithin":0},{"tile":[8389,5493,14],"roads":522,"buffers":3004,"notWithin":0},{"tile":[8390,5498,14],"roads":367,"buffers":1224,"notWithin":0},{"tile":[8390,5497,14],"roads":572,"buffers":1644,"notWithin":0},{"tile":[8390,5499,14],"roads":186,"buffers":771,"notWithin":0},{"tile":[8390,5493,14],"roads":146,"buffers":1027,"notWithin":0},{"tile":[8391,5500,14],"roads":114,"buffers":283,"notWithin":0},{"tile":[8390,5494,14],"roads":486,"buffers":2138,"notWithin":0},{"tile":[8391,5501,14],"roads":44,"buffers":160,"notWithin":0},{"tile":[8390,5496,14],"roads":813,"buffers":4643,"notWithin":0},{"tile":[8390,5492,14],"roads":311,"buffers":1860,"notWithin":2},{"tile":[8391,5497,14],"roads":529,"buffers":2340,"notWithin":0},{"tile":[8391,5499,14],"roads":209,"buffers":713,"notWithin":0},{"tile":[8391,5496,14],"roads":462,"buffers":3657,"notWithin":0},{"tile":[8391,5493,14],"roads":322,"buffers":1271,"notWithin":3},{"tile":[8392,5500,14],"roads":58,"buffers":172,"notWithin":0},{"tile":[8391,5492,14],"roads":266,"buffers":1991,"notWithin":0},{"tile":[8390,5495,14],"roads":856,"buffers":4911,"notWithin":0},{"tile":[8391,5502,14],"roads":2,"buffers":231,"notWithin":0},{"tile":[8392,5496,14],"roads":552,"buffers":2609,"notWithin":0},{"tile":[8392,5492,14],"roads":76,"buffers":653,"notWithin":0},{"tile":[8392,5499,14],"roads":340,"buffers":1448,"notWithin":0},{"tile":[8391,5495,14],"roads":602,"buffers":2877,"notWithin":0},{"tile":[8393,5499,14],"roads":200,"buffers":1021,"notWithin":0},{"tile":[8391,5498,14],"roads":409,"buffers":1696,"notWithin":1},{"tile":[8391,5491,14],"roads":37,"buffers":813,"notWithin":0},{"tile":[8392,5495,14],"roads":691,"buffers":2345,"notWithin":0},{"tile":[8391,5494,14],"roads":581,"buffers":2503,"notWithin":0},{"tile":[8392,5501,14],"roads":25,"buffers":75,"notWithin":0},{"tile":[8392,5498,14],"roads":350,"buffers":1997,"notWithin":0},{"tile":[8392,5491,14],"roads":58,"buffers":862,"notWithin":0},{"tile":[8393,5495,14],"roads":426,"buffers":1893,"notWithin":0},{"tile":[8393,5491,14],"roads":4,"buffers":703,"notWithin":0},{"tile":[8394,5497,14],"roads":269,"buffers":826,"notWithin":0},{"tile":[8395,5499,14],"roads":36,"buffers":211,"notWithin":0},{"tile":[8392,5494,14],"roads":474,"buffers":1699,"notWithin":0},{"tile":[8393,5501,14],"roads":9,"buffers":215,"notWithin":0},{"tile":[8395,5495,14],"roads":24,"buffers":1097,"notWithin":0},{"tile":[8392,5497,14],"roads":502,"buffers":2898,"notWithin":0},{"tile":[8393,5497,14],"roads":290,"buffers":1172,"notWithin":0},{"tile":[8393,5498,14],"roads":551,"buffers":2951,"notWithin":0},{"tile":[8393,5493,14],"roads":107,"buffers":897,"notWithin":0},{"tile":[8394,5499,14],"roads":41,"buffers":150,"notWithin":0},{"tile":[8392,5493,14],"roads":254,"buffers":1258,"notWithin":0},{"tile":[8393,5500,14],"roads":86,"buffers":243,"notWithin":0},{"tile":[8393,5494,14],"roads":111,"buffers":1126,"notWithin":0},{"tile":[8394,5500,14],"roads":30,"buffers":104,"notWithin":0},{"tile":[8394,5496,14],"roads":377,"buffers":1574,"notWithin":0},{"tile":[8395,5498,14],"roads":2,"buffers":162,"notWithin":0},{"tile":[8393,5496,14],"roads":516,"buffers":2286,"notWithin":0},{"tile":[8393,5492,14],"roads":130,"buffers":953,"notWithin":0},{"tile":[8394,5498,14],"roads":77,"buffers":456,"notWithin":0},{"tile":[8395,5500,14],"roads":4,"buffers":116,"notWithin":0},{"tile":[8395,5496,14],"roads":178,"buffers":772,"notWithin":0},{"tile":[8394,5495,14],"roads":254,"buffers":2794,"notWithin":0},{"tile":[8395,5497,14],"roads":110,"buffers":419,"notWithin":0}] -------------------------------------------------------------------------------- /data/belgium/brussels/filter.sql: -------------------------------------------------------------------------------- 1 | SELECT * FROM "UrbAdm_STREET_AXIS" WHERE 2 | "TYPE" NOT IN ('M', 'O', 'MS', 'RS', 'RT', 'MT') 3 | -------------------------------------------------------------------------------- /data/belgium/brussels/process.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | MAPROULETTE_CHALLENGE=14675 4 | 5 | # Make script directory working directory 6 | 7 | cd `dirname "$(realpath $0)"` 8 | 9 | # Download & unzip data 10 | 11 | mkdir -p "./source/" 12 | 13 | if [ ! -d "./source/UrbAdm_SHP" ]; then 14 | wget -O "./source/UrbAdm_SHP.zip" "https://urbisdownload.datastore.brussels/UrbIS/Vector/M7/2D/UrbAdm/Daily/SHP_LITE/UrbAdm_SHP.zip" 15 | unzip "./source/UrbAdm_SHP.zip" -d "./source/UrbAdm_SHP/" "shp/UrbAdm_STREET_AXIS.*" 16 | fi 17 | 18 | # Convert to GeoJSON 19 | 20 | if [ -d "./temp" ]; then rm -r "./temp/"; fi 21 | 22 | mkdir -p "./temp/" 23 | 24 | ogr2ogr -f "GeoJSON" -progress \ 25 | -s_srs "EPSG:31370" -t_srs "EPSG:4326" \ 26 | -sql "@filter.sql" \ 27 | -lco COORDINATE_PRECISION=6 \ 28 | -fieldTypeToString "All" \ 29 | "./temp/UrbAdm_STREET_AXIS.geojson" \ 30 | "./source/UrbAdm_SHP/shp/UrbAdm_STREET_AXIS.shp" 31 | 32 | # Convert fields to OpenStreetMap tags 33 | 34 | node "../../../script/convert-tags.js" -c "./convert.json" "./temp/UrbAdm_STREET_AXIS.geojson" "UrbAdm_STREET_AXISTagged.geojson" 35 | 36 | # Generate vector tiles 37 | 38 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 39 | --buffer=0 \ 40 | --maximum-zoom=14 --minimum-zoom=14 \ 41 | --layer="roads" \ 42 | --output="./temp/UrbAdm_STREET_AXISTagged.mbtiles" "./temp/UrbAdm_STREET_AXISTagged.geojson" 43 | 44 | # Generate MapRoulette NotAnIssue buffers vector tiles 45 | 46 | wget -O "./temp/maproulette.geojson" "https://maproulette.org/api/v2/challenge/view/$MAPROULETTE_CHALLENGE?status=2" 47 | 48 | node "../../../script/buffer.js" --radius=20 "./temp/maproulette.geojson" "maproulette-buffers.geojson" 49 | 50 | # Merge MapRoulette buffers to OpenStreetMap buffers 51 | 52 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 53 | --maximum-zoom=14 --minimum-zoom=14 \ 54 | --layer="buffers" \ 55 | --output="./temp/belgium-buffers.mbtiles" \ 56 | "../belgium-lines-buffers.geojson" "../belgium-polygons-buffers.geojson" "./temp/maproulette-buffers.geojson" 57 | 58 | # Difference 59 | 60 | if [ -d "./difference" ]; then rm -r "./difference/"; fi 61 | 62 | mkdir -p "./difference" 63 | 64 | node "../../../script/difference.js" --output-dir="./difference" "./temp/UrbAdm_STREET_AXISTagged.mbtiles" "./temp/belgium-buffers.mbtiles" 65 | -------------------------------------------------------------------------------- /data/belgium/flanders/README.md: -------------------------------------------------------------------------------- 1 | # Road Completion - 🇧🇪 Belgium - Flanders 2 | 3 | [![🇧🇪 Flanders, Belgium](https://github.com/osmbe/road-completion/actions/workflows/belgium-flanders.yml/badge.svg)](https://github.com/osmbe/road-completion/actions/workflows/belgium-flanders.yml) 4 | 5 | > Source: 6 | 7 | ## Filters 8 | 9 | ### `LSTRNM` + `RSTRNM` 10 | 11 | Filter out all the roads without a name. 12 | 13 | ### `STATUS` (*Status*) 14 | 15 | ```sql 16 | "STATUS" = 4 17 | ``` 18 | 19 | *De status van het wegsegment* 20 | 21 | | Value | Description | Note | 22 | |-------|---------------------------|-------------------------------------------------------------| 23 | | 1 | *vergunning aangevraagd* | *Weg komt voor op officieel document in behandeling* | 24 | | 2 | *bouwvergunning verleend* | *Weg komt voor op goedgekeurd, niet vervallen bouwdossier* | 25 | | 3 | *in aanbouw* | *Aanvang der werken is gemeld.* | 26 | | 4 | *in gebruik* | *Werken zijn opgeleverd.* | 27 | | 5 | *buiten gebruik* | *Fysieke weg is buiten gebruik gesteld maar niet gesloopt.* | 28 | | -8 | *niet gekend* | *Geen informatie beschikbaar* | 29 | 30 | ### `BEHEER` (*Beheer*) 31 | 32 | ```sql 33 | "BEHEER" <> -8 34 | ``` 35 | 36 | *De organisatie die verantwoordelijk is voor het fysieke onderhoud en beheer van de weg op het terrein.* 37 | 38 | | Value | Description | Note | 39 | |-------|---------------|-------------------------------------------| 40 | | -7 | *andere* | Description is extracted from `LBLBEHEER` | 41 | | -8 | *niet gekend* | Description is extracted from `LBLBEHEER` | 42 | | ... | | | 43 | 44 | ## Tags 45 | 46 | ### `MORF` (*Morfologische wegklasse*) 47 | 48 | `highway=unclassified` 49 | 50 | ### `TGBEP` (*Toegangsbeperking*) 51 | 52 | | Value | Description | Note | OSM Tag(s) | 53 | |-------|----------------------------|----------------------------------------------------------------------------------|------------------| 54 | | 1 | *openbare weg* | *Weg is publiek toegankelijk* | `access=yes` | 55 | | 2 | *onmogelijke toegang* | *Weg is niet toegankelijk vanwege de aanwezigheid van hindernissen of obstakels* | | 56 | | 3 | *verboden toegang* | *Toegang tot de weg is bij wet verboden* | `access=no` | 57 | | 4 | *privaatweg* | *Toegang tot de weg is beperkt aangezien deze een private eigenaar heeft* | `access=private` | 58 | | 5 | *seizoensgebonden toegang* | *Weg is afhankelijk van het seizoen (on)toegankelijk* | | 59 | | 6 | *tolweg* | *Toegang tot de weg is onderhevig aan tolheffingen* | | 60 | -------------------------------------------------------------------------------- /data/belgium/flanders/convert.json: -------------------------------------------------------------------------------- 1 | { 2 | "MORF": { 3 | "*": { 4 | "highway": "unclassified" 5 | } 6 | }, 7 | "TGBEP": { 8 | "1": { 9 | "access": "yes" 10 | }, 11 | "3": { 12 | "access": "no" 13 | }, 14 | "4": { 15 | "access": "private" 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /data/belgium/flanders/filter.sql: -------------------------------------------------------------------------------- 1 | SELECT * FROM "Wegsegment" WHERE 2 | "STATUS" = 4 3 | AND ("LSTRNM" <> '' OR "RSTRNM" <> '') 4 | AND ("BEHEER" <> '-8') 5 | -------------------------------------------------------------------------------- /data/belgium/flanders/process.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | FILENAME="Wegenregister_SHAPE_20250130" 4 | MAPROULETTE_CHALLENGE=24090 5 | 6 | # Make script directory working directory 7 | 8 | cd `dirname "$(realpath $0)"` 9 | 10 | # Download & unzip data 11 | 12 | mkdir -p "./source/" 13 | 14 | if [ ! -d "./source/$FILENAME" ]; then 15 | wget -O "./source/$FILENAME.zip" "https://download.vlaanderen.be/bff/v1/Orders/337327/download/79c09c5d-e2c5-45c0-a5fa-52734128aa01" 16 | unzip -j "./source/$FILENAME.zip" -d "./source/$FILENAME/" "$FILENAME/Shapefile/Wegsegment.*" 17 | fi 18 | 19 | # Convert to GeoJSON 20 | 21 | if [ -d "./temp" ]; then rm -r "./temp/"; fi 22 | 23 | mkdir -p "./temp/" 24 | 25 | ogr2ogr -f "GeoJSON" -progress \ 26 | --config SHAPE_ENCODING "ISO-8859-1" \ 27 | -s_srs "EPSG:31370" -t_srs "EPSG:4326" \ 28 | -sql "@filter.sql" \ 29 | -lco COORDINATE_PRECISION=6 \ 30 | -fieldTypeToString "All" \ 31 | "./temp/Wegsegment.geojson" \ 32 | "./source/$FILENAME/Wegsegment.shp" 33 | 34 | # Convert fields to OpenStreetMap tags 35 | 36 | node "../../../script/convert-tags.js" -c "./convert.json" "./temp/Wegsegment.geojson" "WegsegmentTagged.geojson" 37 | 38 | # Generate vector tiles 39 | 40 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 41 | --buffer=0 \ 42 | --maximum-zoom=14 --minimum-zoom=14 \ 43 | --layer="roads" \ 44 | --output="./temp/WegsegmentTagged.mbtiles" "./temp/WegsegmentTagged.geojson" 45 | 46 | # Generate MapRoulette NotAnIssue buffers vector tiles 47 | 48 | wget -O "./temp/maproulette.geojson" "https://maproulette.org/api/v2/challenge/view/$MAPROULETTE_CHALLENGE?status=2" 49 | 50 | node "../../../script/buffer.js" --radius=20 "./temp/maproulette.geojson" "maproulette-buffers.geojson" 51 | 52 | # Merge MapRoulette buffers to OpenStreetMap buffers 53 | 54 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 55 | --maximum-zoom=14 --minimum-zoom=14 \ 56 | --layer="buffers" \ 57 | --output="./temp/belgium-buffers.mbtiles" \ 58 | "../belgium-lines-buffers.geojson" "../belgium-polygons-buffers.geojson" "./temp/maproulette-buffers.geojson" 59 | 60 | # Difference 61 | 62 | if [ -d "./difference" ]; then rm -r "./difference/"; fi 63 | 64 | mkdir -p "./difference" 65 | 66 | node "../../../script/difference.js" --output-dir="./difference" "./temp/WegsegmentTagged.mbtiles" "./temp/belgium-buffers.mbtiles" 67 | -------------------------------------------------------------------------------- /data/belgium/wallonia/README.md: -------------------------------------------------------------------------------- 1 | # Road Completion - 🇧🇪 Belgium - Wallonia 2 | 3 | Source: 4 | 5 | ## Filters 6 | 7 | ### `RUE_NOM1` + `RUE_NOM2` 8 | 9 | Filter out all the roads without a name. 10 | 11 | ## Tags 12 | 13 | ### `NATUR_CODE` 14 | 15 | | Value | Description | Note | OSM Tag(s) | 16 | |-------|-------------------|------|-----------------------| 17 | | ATR | Autoroute | | `highway=motorway` | 18 | | CHA | Chemin ou sentier | | `highway=path` | 19 | | VCO | Communale | | `highway=residential` | 20 | | NTL | Nationale | | `highway=primary` | 21 | | RNG | Ring | | `highway=motorway` | 22 | -------------------------------------------------------------------------------- /data/belgium/wallonia/convert.json: -------------------------------------------------------------------------------- 1 | { 2 | "NATUR_CODE": { 3 | "ATR": { 4 | "highway":"motorway" 5 | }, 6 | "CHA": { 7 | "highway":"path" 8 | }, 9 | "VCO": { 10 | "highway":"residential" 11 | }, 12 | "NTL": { 13 | "highway":"primary" 14 | }, 15 | "RNG": { 16 | "highway":"motorway" 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /data/belgium/wallonia/difference/BRA/diff.geojson: -------------------------------------------------------------------------------- 1 | {"type":"FeatureCollection","features":[ 2 | {"type":"Feature","properties":{"highway":"residential","original:OBJECTID":"144189","original:GEOREF_ID":"BE.WL.GEOREF.4BD4DC70-1283-441C-97FB-08313B75CA02","original:NATUR_CODE":"VCO","original:NATUR_DESC":"Communale","original:PRECIS_XY":"0.50","original:PRECIS_Z":"0.12","original:TECH_LEVE":"Numérisation sur ortho","original:DATE_CREAT":"20240816092002","original:DATE_MODIF":"20240819210307","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0001","original:ICARRUEID1":"7774163","original:RUE_NOM1":"Allée Poulain","original:COMMU_NOM1":"Nivelles","original:COMMU_INS1":"25072","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.301292300224304,50.59476850249678],[4.302075505256653,50.59382521434031]]}}, 3 | {"type":"Feature","properties":{"highway":"residential","original:OBJECTID":"204065","original:GEOREF_ID":"BE.WL.GEOREF.6BE3E943-9360-4666-9182-DD290A1829E9","original:NATUR_CODE":"VCO","original:NATUR_DESC":"Communale","original:PRECIS_XY":"0.50","original:PRECIS_Z":"0.50","original:TECH_LEVE":"Numérisation sur ortho","original:DATE_CREAT":"20250402103716","original:DATE_MODIF":"20250402183115","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0001","original:ICARRUEID1":"7774940","original:RUE_NOM1":"Clos d'Hypocrate","original:COMMU_NOM1":"Braine-le-Château","original:COMMU_INS1":"25015","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.311034083366394,50.68168090582614],[4.310916066169739,50.681908641412974]]}}, 4 | {"type":"Feature","properties":{"highway":"residential","original:OBJECTID":"110400","original:GEOREF_ID":"BE.WL.GEOREF.55EDF870-E261-4151-B2B4-22536989B58F","original:NATUR_CODE":"VCO","original:NATUR_DESC":"Communale","original:PRECIS_XY":"0.3","original:PRECIS_Z":"0.3","original:TECH_LEVE":"Photogrammétrie","original:DATE_CREAT":"20150513170158","original:DATE_MODIF":"20250402103708","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0001","original:ICARRUEID1":"7774939","original:RUE_NOM1":"Rue du Faucon","original:COMMU_NOM1":"Braine-le-Château","original:COMMU_INS1":"25015","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.311034083366394,50.68168090582614],[4.311559796333313,50.68186105496375]]}}, 5 | {"type":"Feature","properties":{"highway":"residential","original:OBJECTID":"134135","original:GEOREF_ID":"BE.WL.GEOREF.66B903E2-B786-4E4C-8A2D-9F1D24BB19B0","original:NATUR_CODE":"VCO","original:NATUR_DESC":"Communale","original:PRECIS_XY":"0.3","original:PRECIS_Z":"0.3","original:TECH_LEVE":"Photogrammétrie","original:DATE_CREAT":"20250402103707","original:DATE_MODIF":"20250402103709","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0001","original:ICARRUEID1":"7774939","original:RUE_NOM1":"Rue du Faucon","original:COMMU_NOM1":"Braine-le-Château","original:COMMU_INS1":"25015","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.310610294342041,50.68153474658368],[4.311034083366394,50.68168090582614]]}}, 6 | {"type":"Feature","properties":{"highway":"path","original:OBJECTID":"208940","original:GEOREF_ID":"BE.WL.GEOREF.59DEC04A-1BC6-4F9D-9C0E-079DCB43736C","original:NATUR_CODE":"CHA","original:NATUR_DESC":"Chemin ou sentier","original:PRECIS_XY":"0.50","original:PRECIS_Z":"0.12","original:TECH_LEVE":"Numérisation sur ortho","original:DATE_CREAT":"20210726165337","original:DATE_MODIF":"20230828210202","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0070","original:ICARRUEID1":"7700400","original:RUE_NOM1":"Chemin du Vivier","original:COMMU_NOM1":"Braine-l'Alleud","original:COMMU_INS1":"25014","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.37255859375,50.64715088920809],[4.373073577880859,50.647086259763825],[4.373341798782349,50.64705904733964],[4.374457597732544,50.646916181854124],[4.374725818634033,50.64686175679296],[4.374881386756897,50.646814134812786],[4.375095963478088,50.64671208754979],[4.375632405281067,50.64635492038397],[4.375889897346497,50.646239265672165],[4.376699924468994,50.64584807850764],[4.377080798149109,50.6456916027299]]}}, 7 | {"type":"Feature","properties":{"highway":"path","original:OBJECTID":"165686","original:GEOREF_ID":"BE.WL.GEOREF.B476D912-59E9-4C0B-A4CA-663FBA35685D","original:NATUR_CODE":"CHA","original:NATUR_DESC":"Chemin ou sentier","original:PRECIS_XY":"0.50","original:PRECIS_Z":"0.50","original:TECH_LEVE":"Numérisation sur ortho","original:DATE_CREAT":"20230818085733","original:DATE_MODIF":"20250103160004","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0070","original:ICARRUEID1":"7700784","original:RUE_NOM1":"Sentier du Try Hennois","original:COMMU_NOM1":"Braine-l'Alleud","original:COMMU_INS1":"25014","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.387573599815369,50.64942646928233],[4.387895464897156,50.64900469594551],[4.388104677200317,50.64876659642192],[4.388490915298462,50.64837202884053],[4.388614296913147,50.64823256881658],[4.388759136199951,50.64803868468084],[4.388962984085083,50.64729375397994],[4.389129281044006,50.6466372527494]]}}, 8 | {"type":"Feature","properties":{"highway":"residential","original:OBJECTID":"189452","original:GEOREF_ID":"BE.WL.GEOREF.9AC351CF-16D8-40CB-A3F4-512A8117D98B","original:NATUR_CODE":"VCO","original:NATUR_DESC":"Communale","original:PRECIS_XY":"0.50","original:PRECIS_Z":"0.50","original:TECH_LEVE":"Numérisation sur ortho","original:DATE_CREAT":"20230112121142","original:DATE_MODIF":"20240326210151","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0001","original:ICARRUEID1":"7769629","original:RUE_NOM1":"Tienne de la Galvanisation","original:COMMU_NOM1":"Nivelles","original:COMMU_INS1":"25072","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.317954182624817,50.59924971435973],[4.318211674690247,50.599225879255044],[4.318501353263855,50.598783225117415],[4.319279193878174,50.598534655968706],[4.320105314254761,50.59873555442351],[4.319676160812378,50.59856189648741],[4.320282340049744,50.598664048292136]]}}, 9 | {"type":"Feature","properties":{"highway":"path","original:OBJECTID":"274685","original:GEOREF_ID":"BE.WL.GEOREF.31BF787E-30A8-4EDF-BC85-3C2A6BB888AD","original:NATUR_CODE":"CHA","original:NATUR_DESC":"Chemin ou sentier","original:PRECIS_XY":"0.5","original:PRECIS_Z":"Indéfinie","original:TECH_LEVE":"Numérisation sur ortho","original:DATE_CREAT":"20210720113814","original:DATE_MODIF":"20221227210214","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0070","original:ICARRUEID1":"7700776","original:RUE_NOM1":"Sentier du Mayeur","original:COMMU_NOM1":"Braine-l'Alleud","original:COMMU_INS1":"25014","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.355902075767517,50.63872109875098],[4.355934262275696,50.638731305222706],[4.355955719947815,50.638731305222706],[4.356213212013245,50.63868707716247],[4.356250762939453,50.63868707716247],[4.356293678283691,50.63869728364162],[4.356422424316406,50.6387755332413],[4.356755018234253,50.63901028125872]]}}, 10 | {"type":"Feature","properties":{"highway":"path","original:OBJECTID":"274685","original:GEOREF_ID":"BE.WL.GEOREF.31BF787E-30A8-4EDF-BC85-3C2A6BB888AD","original:NATUR_CODE":"CHA","original:NATUR_DESC":"Chemin ou sentier","original:PRECIS_XY":"0.5","original:PRECIS_Z":"Indéfinie","original:TECH_LEVE":"Numérisation sur ortho","original:DATE_CREAT":"20210720113814","original:DATE_MODIF":"20221227210214","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0070","original:ICARRUEID1":"7700776","original:RUE_NOM1":"Sentier du Mayeur","original:COMMU_NOM1":"Braine-l'Alleud","original:COMMU_INS1":"25014","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.356755018234253,50.63901028125872],[4.356873035430908,50.639095334598835],[4.357275366783142,50.63946616536319],[4.357484579086304,50.63964647651247],[4.357999563217163,50.640034313243916],[4.358144402503967,50.64016699349622],[4.358219504356384,50.640218024262765]]}}, 11 | {"type":"Feature","properties":{"highway":"path","original:OBJECTID":"202993","original:GEOREF_ID":"BE.WL.GEOREF.BB34C524-A9D2-400F-BB87-A24E5034E726","original:NATUR_CODE":"CHA","original:NATUR_DESC":"Chemin ou sentier","original:PRECIS_XY":"0.50","original:PRECIS_Z":"0.50","original:TECH_LEVE":"Numérisation sur ortho","original:DATE_CREAT":"20240626144927","original:DATE_MODIF":"20240701210214","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0070","original:ICARRUEID1":"7705704","original:RUE_NOM1":"Rue du Village","original:COMMU_NOM1":"Lasne","original:COMMU_INS1":"25119","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.477202296257019,50.67189742930995],[4.477819204330444,50.6720980144533],[4.477835297584534,50.6720980144533]]}}, 12 | {"type":"Feature","properties":{"highway":"path","original:OBJECTID":"253426","original:GEOREF_ID":"BE.WL.GEOREF.027EA7D7-BAFC-472F-AE45-C3555B583316","original:NATUR_CODE":"CHA","original:NATUR_DESC":"Chemin ou sentier","original:PRECIS_XY":"0.50","original:PRECIS_Z":"0.50","original:TECH_LEVE":"Numérisation sur ortho","original:DATE_CREAT":"20240314151855","original:DATE_MODIF":"20240318210143","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0070","original:ICARRUEID1":"7705545","original:RUE_NOM1":"Chemin du Musée","original:COMMU_NOM1":"Lasne","original:COMMU_INS1":"25119","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.501723051071167,50.701391236639466],[4.501771330833435,50.701245138796],[4.5018088817596436,50.701177186155604],[4.501873254776001,50.701105835777184],[4.5020341873168945,50.70097332764354],[4.50239360332489,50.700769468245255],[4.502565264701843,50.700725298592175],[4.502736926078796,50.7006947195772],[4.502795934677124,50.70069132190764],[4.502876400947571,50.7006981172465]]}}, 13 | {"type":"Feature","properties":{"highway":"path","original:OBJECTID":"141656","original:GEOREF_ID":"BE.WL.GEOREF.1E2C7387-927B-439E-B8F7-BA9A944509AB","original:NATUR_CODE":"CHA","original:NATUR_DESC":"Chemin ou sentier","original:PRECIS_XY":"0.50","original:PRECIS_Z":"0.12","original:TECH_LEVE":"Numérisation sur ortho","original:DATE_CREAT":"20220831113616","original:DATE_MODIF":"20230227210217","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0070","original:ICARRUEID1":"7706520","original:RUE_NOM1":"rue du Bruwart","original:COMMU_NOM1":"Ottignies-Louvain-la-Neuve","original:COMMU_INS1":"25121","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.523926377296448,50.66971813547889],[4.5238083600997925,50.669772534059945],[4.523288011550903,50.670435511700845],[4.522896409034729,50.670833293791276],[4.5224350690841675,50.67128546933915],[4.52161967754364,50.672200006570364],[4.521507024765015,50.67231219764315]]}}, 14 | {"type":"Feature","properties":{"highway":"residential","original:OBJECTID":"310540","original:GEOREF_ID":"BE.WL.GEOREF.62417CD3-E37C-4210-AC54-DD993086865C","original:NATUR_CODE":"VCO","original:NATUR_DESC":"Communale","original:PRECIS_XY":"0.50","original:PRECIS_Z":"0.50","original:TECH_LEVE":"Numérisation sur ortho","original:DATE_CREAT":"20240704151256","original:DATE_MODIF":"20240708210227","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0001","original:ICARRUEID1":"7705604","original:RUE_NOM1":"Route de Renipont","original:COMMU_NOM1":"Lasne","original:COMMU_INS1":"25119","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.473484754562378,50.70098012294156],[4.473715424537659,50.701105835777184],[4.473736882209778,50.70117039088615],[4.473763704299927,50.70140142949526]]}}, 15 | {"type":"Feature","properties":{"highway":"path","original:OBJECTID":"128899","original:GEOREF_ID":"BE.WL.GEOREF.FA737878-6F43-4EFC-9374-CC2C670C1992","original:NATUR_CODE":"CHA","original:NATUR_DESC":"Chemin ou sentier","original:PRECIS_XY":"0.50","original:PRECIS_Z":"0.50","original:TECH_LEVE":"Numérisation sur ortho","original:DATE_CREAT":"20220623133058","original:DATE_MODIF":"20240221210328","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0070","original:ICARRUEID1":"7703678","original:RUE_NOM1":"Sentier Marcel Ladrière","original:COMMU_NOM1":"Rixensart","original:COMMU_INS1":"25091","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.5078277587890625,50.71737091282003],[4.508020877838135,50.71755432135822],[4.508374929428101,50.71794491122361],[4.50863242149353,50.71837965089796],[4.508321285247803,50.718586830105124],[4.507822394371033,50.71890608807388],[4.5076292753219604,50.71879740475424],[4.507414698600769,50.71886872821119],[4.507162570953369,50.71900458211462],[4.506781697273254,50.71918119160031],[4.506663680076599,50.71924572182331],[4.506615400314331,50.71927968506287],[4.506556391716003,50.7193068556368],[4.506475925445557,50.719327233556925],[4.506443738937378,50.71934761146815],[4.5060789585113525,50.719514030745046],[4.505848288536072,50.71963969388901],[4.505660533905029,50.71972799751833],[4.50539767742157,50.71987403777089],[4.505295753479004,50.719918189385595],[4.50513482093811,50.7200166812992]]}}, 16 | {"type":"Feature","properties":{"highway":"path","original:OBJECTID":"270421","original:GEOREF_ID":"BE.WL.GEOREF.5BF55598-850B-4A0A-99BA-54A5E113DD40","original:NATUR_CODE":"CHA","original:NATUR_DESC":"Chemin ou sentier","original:PRECIS_XY":"0.50","original:PRECIS_Z":"0.12","original:TECH_LEVE":"Numérisation sur ortho","original:DATE_CREAT":"20220708151631","original:DATE_MODIF":"20230227210217","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0070","original:ICARRUEID1":"7769866","original:RUE_NOM1":"sentier n°64","original:COMMU_NOM1":"Ottignies-Louvain-la-Neuve","original:COMMU_INS1":"25121","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.589720964431763,50.667011726498174],[4.589635133743286,50.6670355272571],[4.589484930038452,50.66705592789802],[4.589340090751648,50.66708312873877],[4.589216709136963,50.667093329050005],[4.589012861251831,50.6670627281097],[4.5888519287109375,50.6671103295638],[4.588648080825806,50.66713413027273],[4.58854079246521,50.66707632853007],[4.588310122489929,50.66691652334177],[4.588235020637512,50.66688592228624],[4.588165283203125,50.6668723218107]]}}, 17 | {"type":"Feature","properties":{"highway":"residential","original:OBJECTID":"273267","original:GEOREF_ID":"BE.WL.GEOREF.AD42C1C5-FA2F-4A9F-A07A-46EF7481FD51","original:NATUR_CODE":"VCO","original:NATUR_DESC":"Communale","original:PRECIS_XY":"Indéfinie","original:PRECIS_Z":"Indéfinie","original:TECH_LEVE":"Dérivé (construit)","original:DATE_LEVE":"20200225000000","original:DATE_CREAT":"20200414085505","original:DATE_MODIF":"20250415104801","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0001","original:ICARRUEID1":"7702244","original:RUE_NOM1":"Chaussée de Charleroi","original:COMMU_NOM1":"Jodoigne","original:COMMU_INS1":"25048","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.839391708374023,50.68579017354216],[4.839279055595398,50.6857765785434],[4.838882088661194,50.68585135098792],[4.8387157917022705,50.685939718268685],[4.838147163391113,50.68633397026301],[4.838088154792786,50.68636795734878],[4.838034510612488,50.686364558641316]]}}, 18 | {"type":"Feature","properties":{"highway":"residential","original:OBJECTID":"140925","original:GEOREF_ID":"BE.WL.GEOREF.9B3191FB-CCAB-4033-BEFA-56100EC618B7","original:NATUR_CODE":"VCO","original:NATUR_DESC":"Communale","original:PRECIS_XY":"Indéfinie","original:PRECIS_Z":"Indéfinie","original:TECH_LEVE":"Dérivé (construit)","original:DATE_LEVE":"20250102000000","original:DATE_CREAT":"20250113114611","original:DATE_MODIF":"20250113114658","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0001","original:ICARRUEID1":"7702244","original:RUE_NOM1":"Chaussée de Charleroi","original:COMMU_NOM1":"Jodoigne","original:COMMU_INS1":"25048","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.839391708374023,50.68579017354216],[4.839434623718262,50.68584115475247],[4.83947217464447,50.68591252835387],[4.839617013931274,50.68605867396076]]}}, 19 | {"type":"Feature","properties":{"highway":"residential","original:OBJECTID":"245127","original:GEOREF_ID":"BE.WL.GEOREF.3A8A61A7-880E-4912-B25A-60AF269BC3DC","original:NATUR_CODE":"VCO","original:NATUR_DESC":"Communale","original:PRECIS_XY":"Indéfinie","original:PRECIS_Z":"Indéfinie","original:TECH_LEVE":"Dérivé (construit)","original:DATE_LEVE":"20250102000000","original:DATE_CREAT":"20250113114611","original:DATE_MODIF":"20250113114657","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0001","original:ICARRUEID1":"7702244","original:RUE_NOM1":"Chaussée de Charleroi","original:COMMU_NOM1":"Jodoigne","original:COMMU_INS1":"25048","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.839584827423096,50.6857052047352],[4.839391708374023,50.68579017354216]]}}, 20 | {"type":"Feature","properties":{"highway":"path","original:OBJECTID":"255317","original:GEOREF_ID":"BE.WL.GEOREF.732FD92D-F252-4CAA-8858-EFAF05F55DF8","original:NATUR_CODE":"CHA","original:NATUR_DESC":"Chemin ou sentier","original:PRECIS_XY":"0.50","original:PRECIS_Z":"0.50","original:TECH_LEVE":"Numérisation sur ortho","original:DATE_CREAT":"20220720144255","original:DATE_MODIF":"20230227210217","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0070","original:ICARRUEID1":"7706291","original:RUE_NOM1":"place Blaise Pascal","original:COMMU_NOM1":"Ottignies-Louvain-la-Neuve","original:COMMU_INS1":"25121","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.610137939453125,50.66970453582377],[4.610556364059448,50.66948014094572],[4.6106743812561035,50.66956853905603]]}}, 21 | {"type":"Feature","properties":{"highway":"path","original:OBJECTID":"296287","original:GEOREF_ID":"BE.WL.GEOREF.A6E33A65-D702-452C-9CCE-3808C4317443","original:NATUR_CODE":"CHA","original:NATUR_DESC":"Chemin ou sentier","original:PRECIS_XY":"0.3","original:PRECIS_Z":"0.3","original:TECH_LEVE":"Photogrammétrie","original:DATE_CREAT":"20160610150816","original:DATE_MODIF":"20231025210156","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0070","original:ICARRUEID1":"7705161","original:RUE_NOM1":"Venelle de l'Empereur","original:COMMU_NOM1":"Wavre","original:COMMU_INS1":"25112","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.617090225219727,50.68503224634881],[4.617953896522522,50.685521671587054]]}}, 22 | {"type":"Feature","properties":{"highway":"residential","original:OBJECTID":"168889","original:GEOREF_ID":"BE.WL.GEOREF.7E345B7C-036B-4869-884D-699DE5C89F32","original:NATUR_CODE":"VCO","original:NATUR_DESC":"Communale","original:PRECIS_XY":"0.3","original:PRECIS_Z":"0.3","original:TECH_LEVE":"Photogrammétrie","original:DATE_CREAT":"20160714134122","original:DATE_MODIF":"20240219210326","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0001","original:ICARRUEID1":"7701882","original:RUE_NOM1":"Rue du Gauwin","original:COMMU_NOM1":"Grez-Doiceau","original:COMMU_INS1":"25037","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.700549840927124,50.762304912638626],[4.7004640102386475,50.76231509224843],[4.700120687484741,50.76237956305917],[4.699970483779907,50.76242706781025],[4.699836373329163,50.76245760655328],[4.69965934753418,50.76247457251307],[4.699187278747559,50.76240670863709],[4.698581099510193,50.76233545146141],[4.698430895805359,50.7623116990454],[4.698269963264465,50.76229812623086],[4.698098301887512,50.76229133982213],[4.697953462600708,50.76229812623086],[4.6976637840271,50.76232866505811],[4.697502851486206,50.7623592038654],[4.697384834289551,50.76239313585012],[4.697288274765015,50.7624304610049],[4.69715416431427,50.76248814527645],[4.696810841560364,50.76265780448648],[4.69666600227356,50.76272227482502],[4.696274399757385,50.76287496737774],[4.696172475814819,50.7629088989884]]}}, 23 | {"type":"Feature","properties":{"highway":"residential","original:OBJECTID":"152123","original:GEOREF_ID":"BE.WL.GEOREF.E095A9AD-DF5D-4BAB-AB05-3F20304F26F7","original:NATUR_CODE":"VCO","original:NATUR_DESC":"Communale","original:PRECIS_XY":"0.3","original:PRECIS_Z":"0.3","original:TECH_LEVE":"Photogrammétrie","original:DATE_CREAT":"20160802093624","original:DATE_MODIF":"20220711210155","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0001","original:ICARRUEID1":"7701058","original:RUE_NOM1":"Chemin du Panorama","original:COMMU_NOM1":"Chaumont-Gistoux","original:COMMU_INS1":"25018","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.702357649803162,50.71528204272141],[4.702818989753723,50.715288835945785]]}}, 24 | {"type":"Feature","properties":{"highway":"path","original:OBJECTID":"174862","original:GEOREF_ID":"BE.WL.GEOREF.C498EFEA-7A19-42D8-B6AD-6C4D2F43D1B1","original:NATUR_CODE":"CHA","original:NATUR_DESC":"Chemin ou sentier","original:PRECIS_XY":"0.3","original:PRECIS_Z":"0.3","original:TECH_LEVE":"Photogrammétrie","original:DATE_CREAT":"20160610150816","original:DATE_MODIF":"20230227210217","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0070","original:ICARRUEID1":"7706553","original:RUE_NOM1":"rue du Morimont","original:COMMU_NOM1":"Ottignies-Louvain-la-Neuve","original:COMMU_INS1":"25121","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.593111276626587,50.656684459053935],[4.593138098716736,50.6567218684672],[4.593181014060974,50.6567388727361],[4.59328830242157,50.65673207102927],[4.593486785888672,50.656793286355224],[4.593873023986816,50.65693612180553],[4.594135880470276,50.65705855184575],[4.594468474388123,50.65718438238787],[4.594591856002808,50.657225192221034],[4.595160484313965,50.65749725686925]]}}, 25 | {"type":"Feature","properties":{"highway":"primary","original:OBJECTID":"345212","original:GEOREF_ID":"BE.WL.GEOREF.7008F400-72A2-48DF-A2DD-9F6FE46D380E","original:NATUR_CODE":"NTL","original:NATUR_DESC":"Nationale","original:PRECIS_XY":"Indéfinie","original:PRECIS_Z":"0.12","original:TECH_LEVE":"Dérivé (construit)","original:DATE_CREAT":"20250416092812","original:DATE_MODIF":"20250416170715","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0001","original:ICARRUEID1":"7702244","original:RUE_NOM1":"Chaussée de Charleroi","original:COMMU_NOM1":"Jodoigne","original:COMMU_INS1":"25048","original:GESTION":"Service public de Wallonie","original:VOIRIE_NOM":"N29","original:SENS_BK":"C","original:AMENAG":"RP"},"geometry":{"type":"LineString","coordinates":[[4.8636603355407715,50.71490841386435],[4.863746166229248,50.714898223944715],[4.863831996917725,50.71490501722471],[4.8639339208602905,50.71493558697256],[4.864014387130737,50.71498653650801],[4.864062666893005,50.715051072506725],[4.864073395729065,50.71508503878616],[4.864073395729065,50.71512240166507],[4.864062666893005,50.71515636789283],[4.864051938056946,50.71518354085728],[4.864025115966797,50.71521411042346]]}}, 26 | {"type":"Feature","properties":{"highway":"residential","original:OBJECTID":"309678","original:GEOREF_ID":"BE.WL.GEOREF.8C3039DC-0427-4035-914B-520E0C9178A3","original:NATUR_CODE":"VCO","original:NATUR_DESC":"Communale","original:PRECIS_XY":"Indéfinie","original:PRECIS_Z":"Indéfinie","original:TECH_LEVE":"Dérivé (construit)","original:DATE_LEVE":"20240115000000","original:DATE_CREAT":"20240219113044","original:DATE_MODIF":"20240805210209","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0001","original:ICARRUEID1":"7773749","original:RUE_NOM1":"desserte du Fourgon","original:COMMU_NOM1":"Ottignies-Louvain-la-Neuve","original:COMMU_INS1":"25121","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.622867703437805,50.67463075311636],[4.623103737831116,50.67447437321104],[4.623296856880188,50.67436898645923],[4.623355865478516,50.674345189418005],[4.623430967330933,50.674345189418005],[4.62350070476532,50.67436558688266],[4.623554348945618,50.674389383913535],[4.623640179634094,50.674470973642116]]}}, 27 | {"type":"Feature","properties":{"highway":"residential","original:OBJECTID":"136513","original:GEOREF_ID":"BE.WL.GEOREF.31F005F7-D6DF-4BCB-B0A7-C43225FBC1CF","original:NATUR_CODE":"VCO","original:NATUR_DESC":"Communale","original:PRECIS_XY":"Indéfinie","original:PRECIS_Z":"Indéfinie","original:TECH_LEVE":"Dérivé (construit)","original:DATE_LEVE":"20240730000000","original:DATE_CREAT":"20241004084704","original:DATE_MODIF":"20241007210253","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0001","original:ICARRUEID1":"7774282","original:RUE_NOM1":"Clos du Sabot","original:COMMU_NOM1":"Mont-Saint-Guibert","original:COMMU_INS1":"25068","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.641299843788147,50.642973603369455],[4.641401767730713,50.643038238470695],[4.641546607017517,50.64310287348306]]}}, 28 | {"type":"Feature","properties":{"highway":"residential","original:OBJECTID":"206367","original:GEOREF_ID":"BE.WL.GEOREF.42ED0BC2-4397-4C12-875E-31832DB809FE","original:NATUR_CODE":"VCO","original:NATUR_DESC":"Communale","original:PRECIS_XY":"Indéfinie","original:PRECIS_Z":"Indéfinie","original:TECH_LEVE":"Dérivé (construit)","original:DATE_LEVE":"20240730000000","original:DATE_CREAT":"20241004084941","original:DATE_MODIF":"20241007210253","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0001","original:ICARRUEID1":"7774282","original:RUE_NOM1":"Clos du Sabot","original:COMMU_NOM1":"Mont-Saint-Guibert","original:COMMU_INS1":"25068","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.641546607017517,50.64310287348306],[4.64171290397644,50.64321173225025],[4.641847014427185,50.64328317067921],[4.642007946968079,50.64331718894053]]}}, 29 | {"type":"Feature","properties":{"highway":"residential","original:OBJECTID":"273956","original:GEOREF_ID":"BE.WL.GEOREF.06607DDC-336C-4984-B394-663C4D0D009D","original:NATUR_CODE":"VCO","original:NATUR_DESC":"Communale","original:PRECIS_XY":"Indéfinie","original:PRECIS_Z":"Indéfinie","original:TECH_LEVE":"Dérivé (construit)","original:DATE_LEVE":"20240730000000","original:DATE_CREAT":"20241004084704","original:DATE_MODIF":"20241007210253","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0001","original:ICARRUEID1":"7774282","original:RUE_NOM1":"Clos du Sabot","original:COMMU_NOM1":"Mont-Saint-Guibert","original:COMMU_INS1":"25068","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.642168879508972,50.642657230275404],[4.641932845115662,50.64283752918146],[4.6418362855911255,50.642898762614806],[4.641804099082947,50.6429123700336],[4.641637802124023,50.643034836625475],[4.641605615615845,50.643065453223585],[4.641546607017517,50.64310287348306]]}}, 30 | {"type":"Feature","properties":{"highway":"residential","original:OBJECTID":"184513","original:GEOREF_ID":"BE.WL.GEOREF.717D6AB3-B12D-40A4-9EA6-7E0114115A97","original:NATUR_CODE":"VCO","original:NATUR_DESC":"Communale","original:PRECIS_XY":"Indéfinie","original:PRECIS_Z":"Indéfinie","original:TECH_LEVE":"Dérivé (construit)","original:DATE_LEVE":"20240730000000","original:DATE_CREAT":"20241004084704","original:DATE_MODIF":"20241007210253","original:DATE_TRANS":"20250510000000","original:CODE_WALTO":"WT_L_0001","original:ICARRUEID1":"7774282","original:RUE_NOM1":"Clos du Sabot","original:COMMU_NOM1":"Mont-Saint-Guibert","original:COMMU_INS1":"25068","original:GESTION":"Commune"},"geometry":{"type":"LineString","coordinates":[[4.642007946968079,50.64331718894053],[4.642083048820496,50.64331718894053],[4.642361998558044,50.64337501992824],[4.642404913902283,50.64337501992824],[4.642437100410461,50.64336821628635],[4.642533659934998,50.643303581638975],[4.642587304115295,50.643245750563324],[4.642882347106934,50.643028032934296]]}} 31 | ]} -------------------------------------------------------------------------------- /data/belgium/wallonia/filter.sql: -------------------------------------------------------------------------------- 1 | SELECT * FROM "VOIRIE_AXE" WHERE 2 | ("RUE_NOM1" <> '' AND "RUE_NOM1" IS NOT NULL) OR ("RUE_NOM2" <> '' AND "RUE_NOM2" IS NOT NULL) 3 | -------------------------------------------------------------------------------- /data/belgium/wallonia/process.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | MAPROULETTE_CHALLENGE=14681 4 | 5 | # Make script directory working directory 6 | 7 | cd `dirname "$(realpath $0)"` 8 | 9 | # Download & unzip data 10 | 11 | mkdir -p "./source/" 12 | 13 | URL="https://geoservices.wallonie.be/geotraitement/spwdatadownload/get/b795de68-726c-4bdf-a62a-a42686aa5b6f" 14 | FILENAME="PICC_vDIFF_SHAPE_31370_PROV_BRABANT_WALLON" 15 | if [ ! -d "./source/$FILENAME" ]; then 16 | wget -O "./source/$FILENAME.zip" "$URL/$FILENAME.zip" 17 | unzip "./source/$FILENAME.zip" -d "./source/$FILENAME/" "VOIRIE_AXE.*" 18 | fi 19 | FILENAME="PICC_vDIFF_SHAPE_31370_PROV_HAINAUT" 20 | if [ ! -d "./source/$FILENAME" ]; then 21 | wget -O "./source/$FILENAME.zip" "$URL/$FILENAME.zip" 22 | unzip "./source/$FILENAME.zip" -d "./source/$FILENAME/" "VOIRIE_AXE.*" 23 | fi 24 | FILENAME="PICC_vDIFF_SHAPE_31370_PROV_LIEGE" 25 | if [ ! -d "./source/$FILENAME" ]; then 26 | wget -O "./source/$FILENAME.zip" "$URL/$FILENAME.zip" 27 | unzip "./source/$FILENAME.zip" -d "./source/$FILENAME/" "VOIRIE_AXE.*" 28 | fi 29 | FILENAME="PICC_vDIFF_SHAPE_31370_PROV_NAMUR" 30 | if [ ! -d "./source/$FILENAME" ]; then 31 | wget -O "./source/$FILENAME.zip" "$URL/$FILENAME.zip" 32 | unzip "./source/$FILENAME.zip" -d "./source/$FILENAME/" "VOIRIE_AXE.*" 33 | fi 34 | FILENAME="PICC_vDIFF_SHAPE_31370_PROV_LUXEMBOURG" 35 | if [ ! -d "./source/$FILENAME" ]; then 36 | wget -O "./source/$FILENAME.zip" "$URL/$FILENAME.zip" 37 | unzip "./source/$FILENAME.zip" -d "./source/$FILENAME/" "VOIRIE_AXE.*" 38 | fi 39 | 40 | # Convert to GeoJSON 41 | 42 | if [ -d "./temp" ]; then rm -r "./temp/"; fi 43 | 44 | mkdir -p "./temp/" 45 | 46 | ogr2ogr -f "GeoJSON" -progress \ 47 | -s_srs "EPSG:31370" -t_srs "EPSG:4326" -dim "XY" \ 48 | -makevalid \ 49 | -sql "@filter.sql" \ 50 | -lco COORDINATE_PRECISION=6 \ 51 | -fieldTypeToString "All" \ 52 | "./temp/BRA_VOIRIE_AXE.geojson" \ 53 | "./source/PICC_vDIFF_SHAPE_31370_PROV_BRABANT_WALLON/VOIRIE_AXE.shp" 54 | ogr2ogr -f "GeoJSON" -progress \ 55 | -s_srs "EPSG:31370" -t_srs "EPSG:4326" -dim "XY" \ 56 | -makevalid \ 57 | -sql "@filter.sql" \ 58 | -lco COORDINATE_PRECISION=6 \ 59 | -fieldTypeToString "All" \ 60 | "./temp/HAI_VOIRIE_AXE.geojson" \ 61 | "./source/PICC_vDIFF_SHAPE_31370_PROV_HAINAUT/VOIRIE_AXE.shp" 62 | ogr2ogr -f "GeoJSON" -progress \ 63 | -s_srs "EPSG:31370" -t_srs "EPSG:4326" -dim "XY" \ 64 | -makevalid \ 65 | -sql "@filter.sql" \ 66 | -lco COORDINATE_PRECISION=6 \ 67 | -fieldTypeToString "All" \ 68 | "./temp/LIE_VOIRIE_AXE.geojson" \ 69 | "./source/PICC_vDIFF_SHAPE_31370_PROV_LIEGE/VOIRIE_AXE.shp" 70 | ogr2ogr -f "GeoJSON" -progress \ 71 | -s_srs "EPSG:31370" -t_srs "EPSG:4326" -dim "XY" \ 72 | -makevalid \ 73 | -sql "@filter.sql" \ 74 | -lco COORDINATE_PRECISION=6 \ 75 | -fieldTypeToString "All" \ 76 | "./temp/NAM_VOIRIE_AXE.geojson" \ 77 | "./source/PICC_vDIFF_SHAPE_31370_PROV_NAMUR/VOIRIE_AXE.shp" 78 | ogr2ogr -f "GeoJSON" -progress \ 79 | -s_srs "EPSG:31370" -t_srs "EPSG:4326" -dim "XY" \ 80 | -makevalid \ 81 | -sql "@filter.sql" \ 82 | -lco COORDINATE_PRECISION=6 \ 83 | -fieldTypeToString "All" \ 84 | "./temp/LUX_VOIRIE_AXE.geojson" \ 85 | "./source/PICC_vDIFF_SHAPE_31370_PROV_LUXEMBOURG/VOIRIE_AXE.shp" 86 | 87 | # Convert fields to OpenStreetMap tags 88 | 89 | node "../../../script/convert-tags.js" -c "./convert.json" "./temp/BRA_VOIRIE_AXE.geojson" "BRA_VOIRIE_AXETagged.geojson" 90 | node "../../../script/convert-tags.js" -c "./convert.json" "./temp/HAI_VOIRIE_AXE.geojson" "HAI_VOIRIE_AXETagged.geojson" 91 | node "../../../script/convert-tags.js" -c "./convert.json" "./temp/LIE_VOIRIE_AXE.geojson" "LIE_VOIRIE_AXETagged.geojson" 92 | node "../../../script/convert-tags.js" -c "./convert.json" "./temp/NAM_VOIRIE_AXE.geojson" "NAM_VOIRIE_AXETagged.geojson" 93 | node "../../../script/convert-tags.js" -c "./convert.json" "./temp/LUX_VOIRIE_AXE.geojson" "LUX_VOIRIE_AXETagged.geojson" 94 | 95 | # Generate vector tiles 96 | 97 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 98 | --buffer=0 \ 99 | --maximum-zoom=14 --minimum-zoom=14 \ 100 | --layer="roads" \ 101 | --output="./temp/BRA_VOIRIE_AXETagged.mbtiles" \ 102 | "./temp/BRA_VOIRIE_AXETagged.geojson" 103 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 104 | --buffer=0 \ 105 | --maximum-zoom=14 --minimum-zoom=14 \ 106 | --layer="roads" \ 107 | --output="./temp/HAI_VOIRIE_AXETagged.mbtiles" \ 108 | "./temp/HAI_VOIRIE_AXETagged.geojson" 109 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 110 | --buffer=0 \ 111 | --maximum-zoom=14 --minimum-zoom=14 \ 112 | --layer="roads" \ 113 | --output="./temp/LIE_VOIRIE_AXETagged.mbtiles" \ 114 | "./temp/LIE_VOIRIE_AXETagged.geojson" 115 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 116 | --buffer=0 \ 117 | --maximum-zoom=14 --minimum-zoom=14 \ 118 | --layer="roads" \ 119 | --output="./temp/NAM_VOIRIE_AXETagged.mbtiles" \ 120 | "./temp/NAM_VOIRIE_AXETagged.geojson" 121 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 122 | --buffer=0 \ 123 | --maximum-zoom=14 --minimum-zoom=14 \ 124 | --layer="roads" \ 125 | --output="./temp/LUX_VOIRIE_AXETagged.mbtiles" \ 126 | "./temp/LUX_VOIRIE_AXETagged.geojson" 127 | 128 | # Generate MapRoulette NotAnIssue buffers vector tiles 129 | 130 | wget -O "./temp/maproulette.geojson" "https://maproulette.org/api/v2/challenge/view/$MAPROULETTE_CHALLENGE?status=2" 131 | 132 | node "../../../script/buffer.js" --radius=20 "./temp/maproulette.geojson" "maproulette-buffers.geojson" 133 | 134 | # Merge MapRoulette buffers to OpenStreetMap buffers 135 | 136 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 137 | --maximum-zoom=14 --minimum-zoom=14 \ 138 | --layer="buffers" \ 139 | --output="./temp/belgium-buffers.mbtiles" \ 140 | "../belgium-lines-buffers.geojson" "../belgium-polygons-buffers.geojson" "./temp/maproulette-buffers.geojson" 141 | 142 | # Difference 143 | 144 | if [ -d "./difference/BRA" ]; then rm -r "./difference/BRA"; fi 145 | if [ -d "./difference/HAI" ]; then rm -r "./difference/HAI"; fi 146 | if [ -d "./difference/LIE" ]; then rm -r "./difference/LIE"; fi 147 | if [ -d "./difference/NAM" ]; then rm -r "./difference/NAM"; fi 148 | if [ -d "./difference/LUX" ]; then rm -r "./difference/LUX"; fi 149 | 150 | mkdir -p "./difference/BRA" 151 | mkdir -p "./difference/HAI" 152 | mkdir -p "./difference/LIE" 153 | mkdir -p "./difference/NAM" 154 | mkdir -p "./difference/LUX" 155 | 156 | node "../../../script/difference.js" --output-dir="./difference/BRA" "./temp/BRA_VOIRIE_AXETagged.mbtiles" "./temp/belgium-buffers.mbtiles" 157 | node "../../../script/difference.js" --output-dir="./difference/HAI" "./temp/HAI_VOIRIE_AXETagged.mbtiles" "./temp/belgium-buffers.mbtiles" 158 | node "../../../script/difference.js" --output-dir="./difference/LIE" "./temp/LIE_VOIRIE_AXETagged.mbtiles" "./temp/belgium-buffers.mbtiles" 159 | node "../../../script/difference.js" --output-dir="./difference/NAM" "./temp/NAM_VOIRIE_AXETagged.mbtiles" "./temp/belgium-buffers.mbtiles" 160 | node "../../../script/difference.js" --output-dir="./difference/LUX" "./temp/LUX_VOIRIE_AXETagged.mbtiles" "./temp/belgium-buffers.mbtiles" 161 | 162 | # Merge diff GeoJSON 163 | 164 | if [ -f "./difference/diff.geojson" ]; then rm "./difference/diff.geojson"; fi 165 | 166 | ogr2ogr -f "GeoJSON" -progress "./difference/diff.geojson" "./difference/BRA/diff.geojson" 167 | ogr2ogr -f "GeoJSON" -progress -append "./difference/diff.geojson" "./difference/HAI/diff.geojson" 168 | ogr2ogr -f "GeoJSON" -progress -append "./difference/diff.geojson" "./difference/LIE/diff.geojson" 169 | ogr2ogr -f "GeoJSON" -progress -append "./difference/diff.geojson" "./difference/NAM/diff.geojson" 170 | ogr2ogr -f "GeoJSON" -progress -append "./difference/diff.geojson" "./difference/LUX/diff.geojson" 171 | -------------------------------------------------------------------------------- /data/kosovo/convert.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /data/kosovo/filter.sql: -------------------------------------------------------------------------------- 1 | SELECT * FROM "VOIRIE_AXE" WHERE 2 | ("RUE_NOM1" <> '' AND "RUE_NOM1" IS NOT NULL) OR ("RUE_NOM2" <> '' AND "RUE_NOM2" IS NOT NULL) 3 | -------------------------------------------------------------------------------- /data/kosovo/kosovo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Make script directory working directory 4 | 5 | cd `dirname "$(realpath $0)"` 6 | 7 | # Download Kosovo extract 8 | 9 | if [ -f "kosovo-latest.osm.pbf" ]; then rm "kosovo-latest.osm.pbf"; fi 10 | 11 | wget https://download.geofabrik.de/europe/kosovo-latest.osm.pbf 12 | 13 | # Convert to GeoJSON 14 | 15 | if [ -f "./kosovo-lines.geojson" ]; then rm "./kosovo-lines.geojson"; fi 16 | if [ -f "./kosovo-polygons.geojson" ]; then rm "./kosovo-polygons.geojson"; fi 17 | 18 | ogr2ogr -f "GeoJSON" -progress \ 19 | -sql "SELECT name, highway FROM lines WHERE highway IS NOT NULL" \ 20 | "./kosovo-lines.geojson" \ 21 | "./kosovo-latest.osm.pbf" 22 | ogr2ogr -f "GeoJSON" -progress \ 23 | -sql "SELECT name, hstore_get_value(other_tags, 'highway') AS highway FROM multipolygons WHERE hstore_get_value(other_tags, 'highway') is not null" \ 24 | "./kosovo-polygons.geojson" \ 25 | "./kosovo-latest.osm.pbf" 26 | 27 | # Generate buffer 28 | 29 | node "../../script/buffer.js" --radius=20 "./kosovo-lines.geojson" "kosovo-lines-buffers.geojson" 30 | node "../../script/buffer.js" --radius=5 "./kosovo-polygons.geojson" "kosovo-polygons-buffers.geojson" 31 | 32 | # Generate vector tiles 33 | 34 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 35 | --maximum-zoom=14 --minimum-zoom=14 \ 36 | --layer="buffers" \ 37 | --output="./kosovo-buffers.mbtiles" \ 38 | "./kosovo-lines-buffers.geojson" "./kosovo-polygons-buffers.geojson" 39 | -------------------------------------------------------------------------------- /data/kosovo/process.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | MAPROULETTE_CHALLENGE=14761 4 | 5 | # Make script directory working directory 6 | 7 | cd `dirname "$(realpath $0)"` 8 | 9 | # Download & unzip data 10 | 11 | mkdir -p "./source/" 12 | 13 | # Convert to GeoJSON 14 | 15 | if [ -d "./temp" ]; then rm -r "./temp/"; fi 16 | 17 | mkdir -p "./temp/" 18 | 19 | for file in ./source/RoadSegmentView_*.gpkg ; do 20 | if [ -f $file ]; then 21 | fname=$(basename "$file" ".gpkg") 22 | 23 | ogr2ogr -f "GeoJSON" -progress \ 24 | -dim "XY" \ 25 | -lco COORDINATE_PRECISION=6 \ 26 | "./temp/$fname.geojson" \ 27 | "$file" 28 | fi 29 | done 30 | 31 | for file in ./temp/RoadSegmentView_*.geojson ; do 32 | if [ -f $file ]; then 33 | ogr2ogr -progress -append "./temp/RoadSegmentView.geojson" "$file" 34 | fi 35 | done 36 | 37 | # Convert fields to OpenStreetMap tags 38 | 39 | node "../../script/convert-tags.js" -c "./convert.json" "./temp/RoadSegmentView.geojson" "RoadSegmentViewTagged.geojson" 40 | 41 | # Generate vector tiles 42 | 43 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 44 | --buffer=0 \ 45 | --maximum-zoom=14 --minimum-zoom=14 \ 46 | --layer="roads" \ 47 | --output="./temp/RoadSegmentViewTagged.mbtiles" \ 48 | "./temp/RoadSegmentViewTagged.geojson" 49 | 50 | # Generate MapRoulette NotAnIssue buffers vector tiles 51 | 52 | wget -O "./temp/maproulette.geojson" "https://maproulette.org/api/v2/challenge/view/$MAPROULETTE_CHALLENGE?status=2" 53 | 54 | node "../../script/buffer.js" --radius=20 "./temp/maproulette.geojson" "maproulette-buffers.geojson" 55 | 56 | # Merge MapRoulette buffers to OpenStreetMap buffers 57 | 58 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 59 | --maximum-zoom=14 --minimum-zoom=14 \ 60 | --layer="buffers" \ 61 | --output="./temp/kosovo-buffers.mbtiles" \ 62 | "./kosovo-lines-buffers.geojson" "./kosovo-polygons-buffers.geojson" "./temp/maproulette-buffers.geojson" 63 | 64 | # Difference 65 | 66 | if [ -d "./difference" ]; then rm -r "./difference"; fi 67 | 68 | mkdir -p "./difference" 69 | 70 | node "../../script/difference.js" --output-dir="./difference" "./temp/RoadSegmentViewTagged.mbtiles" "./temp/kosovo-buffers.mbtiles" 71 | -------------------------------------------------------------------------------- /data/luxembourg/README.md: -------------------------------------------------------------------------------- 1 | # Road Completion - 🇱🇺 Luxembourg 2 | 3 | Source: 4 | 5 | Complete description of all attributes: 6 | 7 | ## Filters 8 | 9 | ```sql 10 | "NOM_RUE" <> '' AND ("TRP_CLAS_L" <> 'Chemin de fer' OR ("TRP_CLAS_L" <> 'Non codé' AND "TRP_CLAS_L" <> 'autre')) 11 | ``` 12 | 13 | Filtering out features without a name, and features which aren't streets (train tracks, forest tracks, and unknown classification). 14 | 15 | | Value | Description (original) | Description (translated) | 16 | |-------|------------------------|--------------------------| 17 | | NOM_RUE | Nom de la rue | Street name | 18 | | TRP_CLAS_L | Classification | Street Classification | 19 | 20 | ## Tags 21 | The tagging scheme follows the [convention used in Luxembourg](https://wiki.openstreetmap.org/wiki/WikiProject_Luxembourg/Roads#Overview). 22 | 23 | ### `TRP_CLAS_L` (*TRP_CLASS_LOOKUP*) 24 | | Value | Description | OSM Tags | 25 | |-------|-------------|----------| 26 | | Autoroute | Highway | `highway=motorway` | 27 | | Nationale | National road | `highway=primary` | 28 | | Chemin repris | State-managed road | `highway=secondary` | 29 | | Chemin vicinal | Residential road | `highway=residential` | 30 | | Chemin de fer | Train tracks | | 31 | | Non codé | Tracks | | 32 | | autre | Other | | 33 | 34 | ### `TRP_NIVE_L` (*TRP_NIVEAU_LOOKUP*) 35 | | Value | Description | OSM Tags | 36 | |-------|-------------|----------| 37 | |passage supérieur 1|Bridge|`bridge=yes` and `layer=1`| 38 | -------------------------------------------------------------------------------- /data/luxembourg/build-extended-conversion.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const fs = require('fs'); 4 | 5 | var args = process.argv.slice(2); 6 | const sourceA = args[0]; 7 | const sourceB = args[1]; 8 | const append = args[2]; 9 | const target = args[3]; 10 | 11 | function convert_csv_tuples_to_json(filePath) { 12 | const data = fs.readFileSync(filePath, 'utf8'); 13 | let inputRows = data.split(/\r?\n/); 14 | 15 | let result = {} 16 | 17 | inputRows.forEach(element => { 18 | if(element.charAt(0) === "#") { 19 | return; 20 | } 21 | var [id, name] = element.split(/\t/); 22 | result[id] = {"name": name}; 23 | }); 24 | 25 | return result; 26 | } 27 | 28 | let normalizeNames = { 29 | NOM_RUE: convert_csv_tuples_to_json(sourceA), 30 | ID_RUE_CAC: convert_csv_tuples_to_json(sourceB) 31 | }; 32 | 33 | const convertTags = JSON.parse(fs.readFileSync(append, 'utf8')); 34 | let data = JSON.stringify({ 35 | ...convertTags, 36 | ...normalizeNames 37 | }); 38 | 39 | fs.writeFileSync(target, data); -------------------------------------------------------------------------------- /data/luxembourg/convert.json: -------------------------------------------------------------------------------- 1 | { 2 | "TRP_CLAS_L": { 3 | "Autoroute": { 4 | "highway": "motorway" 5 | }, 6 | "Nationale": { 7 | "highway": "primary" 8 | }, 9 | "Chemin repris": { 10 | "highway": "secondary" 11 | }, 12 | "Chemin vicinal": { 13 | "highway": "residential" 14 | } 15 | }, 16 | "TRP_NIVE_L": { 17 | "passage supérieur 1": { 18 | "bridge": "yes", 19 | "layer": "1" 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /data/luxembourg/create-uid.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const fs = require('fs'); 4 | const crypto = require('crypto'); 5 | 6 | var args = process.argv.slice(2); 7 | const source = args[0]; 8 | const target = args[1]; 9 | 10 | const data = JSON.parse(fs.readFileSync(source, 'utf8')); 11 | 12 | data['features'].forEach(element => { 13 | let uid = hashProperties(element['geometry']); 14 | element['properties']['original:uid'] = uid; 15 | }); 16 | 17 | function hashProperties(properties) { 18 | let mergedCoordinates = ""; 19 | properties.coordinates.forEach(element => { 20 | mergedCoordinates += element[0] + element[1]; 21 | }); 22 | let hash = crypto.createHash('md5').update(mergedCoordinates).digest('hex'); 23 | return hash; 24 | } 25 | 26 | fs.writeFileSync(target, JSON.stringify(data)); -------------------------------------------------------------------------------- /data/luxembourg/difference/.gitkeep: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /data/luxembourg/difference/diff.geojson: -------------------------------------------------------------------------------- 1 | {"type":"FeatureCollection","features":[ 2 | {"type":"Feature","properties":{"highway":"residential","original:NOM_RUE":"Um Géiebierg","original:TRI_CACLR":"Géiebierg","original:RUE_ABBREV":"Um Géiebierg","original:ID_RUE_CAC":"9928","original:ID_LOCALIT":"1","original:TRP_TYPE":"0","original:TRP_TYPE_L":"axe","original:TRP_REVT":"1","original:TRP_REVT_L":"non aménagé","original:TRP_NIVEAU":"0","original:TRP_NIVE_L":"au sol","original:TRP_CLASS":"4","original:TRP_CLAS_L":"Chemin vicinal","original:TRP_USAGE":"1","original:TRP_USAG_L":"circulation publique","original:TRP_ETAT":"2","original:TRP_ETAT_L":"en projet","original:TRP_NBVOIE":"2","original:TRP_NBVO_L":"2 voies","original:TRP_CYCLE":"0","original:TRP_TRAM":"0","original:TRP_LARGEU":"3","original:TRP_LARG_L":"6,5 m - 7,5 m","original:NOM_LOCALI":"Luxembourg","original:CODE_POSTA":"1524","original:SHAPE_LEN":"49.4084523417806"},"geometry":{"type":"LineString","coordinates":[[6.10291063785553,49.59564252888441],[6.102229356765747,49.595670345650575]]}}, 3 | {"type":"Feature","properties":{"highway":"residential","original:NOM_RUE":"Am Guddebierg","original:TRI_CACLR":"Guddebierg","original:RUE_ABBREV":"Am Guddebierg","original:ID_RUE_CAC":"9927","original:ID_LOCALIT":"1","original:TRP_TYPE":"0","original:TRP_TYPE_L":"axe","original:TRP_REVT":"1","original:TRP_REVT_L":"non aménagé","original:TRP_NIVEAU":"0","original:TRP_NIVE_L":"au sol","original:TRP_CLASS":"4","original:TRP_CLAS_L":"Chemin vicinal","original:TRP_USAGE":"1","original:TRP_USAG_L":"circulation publique","original:TRP_ETAT":"2","original:TRP_ETAT_L":"en projet","original:TRP_NBVOIE":"2","original:TRP_NBVO_L":"2 voies","original:TRP_CYCLE":"0","original:TRP_TRAM":"0","original:TRP_LARGEU":"3","original:TRP_LARG_L":"6,5 m - 7,5 m","original:NOM_LOCALI":"Luxembourg","original:CODE_POSTA":"1524","original:SHAPE_LEN":"138.324590563862"},"geometry":{"type":"LineString","coordinates":[[6.102803349494934,49.59440118954291],[6.10291063785553,49.59564252888441]]}}, 4 | {"type":"Feature","properties":{"highway":"residential","original:NOM_RUE":"Um Géiebierg","original:TRI_CACLR":"Géiebierg","original:RUE_ABBREV":"Um Géiebierg","original:ID_RUE_CAC":"9928","original:ID_LOCALIT":"1","original:TRP_TYPE":"0","original:TRP_TYPE_L":"axe","original:TRP_REVT":"1","original:TRP_REVT_L":"non aménagé","original:TRP_NIVEAU":"0","original:TRP_NIVE_L":"au sol","original:TRP_CLASS":"4","original:TRP_CLAS_L":"Chemin vicinal","original:TRP_USAGE":"1","original:TRP_USAG_L":"circulation publique","original:TRP_ETAT":"2","original:TRP_ETAT_L":"en projet","original:TRP_NBVOIE":"2","original:TRP_NBVO_L":"2 voies","original:TRP_CYCLE":"0","original:TRP_TRAM":"0","original:TRP_LARGEU":"3","original:TRP_LARG_L":"6,5 m - 7,5 m","original:NOM_LOCALI":"Luxembourg","original:CODE_POSTA":"1524","original:SHAPE_LEN":"111.04722293256"},"geometry":{"type":"LineString","coordinates":[[6.10291063785553,49.59564252888441],[6.1038923263549805,49.59560428080502],[6.104262471199036,49.59559732660554],[6.104444861412048,49.59558689530448]]}}, 5 | {"type":"Feature","properties":{"highway":"residential","original:NOM_RUE":"Rue Marie-Paule von Roesgen","original:TRI_CACLR":"Roesgen","original:RUE_ABBREV":"Rue Marie-Paule von Roesgen","original:ID_RUE_CAC":"9926","original:ID_LOCALIT":"1","original:TRP_TYPE":"0","original:TRP_TYPE_L":"axe","original:TRP_REVT":"1","original:TRP_REVT_L":"non aménagé","original:TRP_NIVEAU":"0","original:TRP_NIVE_L":"au sol","original:TRP_CLASS":"4","original:TRP_CLAS_L":"Chemin vicinal","original:TRP_USAGE":"1","original:TRP_USAG_L":"circulation publique","original:TRP_ETAT":"2","original:TRP_ETAT_L":"en projet","original:TRP_NBVOIE":"2","original:TRP_NBVO_L":"2 voies","original:TRP_CYCLE":"0","original:TRP_TRAM":"0","original:TRP_LARGEU":"3","original:TRP_LARG_L":"6,5 m - 7,5 m","original:NOM_LOCALI":"Luxembourg","original:CODE_POSTA":"1524","original:SHAPE_LEN":"105.556029822074"},"geometry":{"type":"LineString","coordinates":[[6.103683114051819,49.59431773702519],[6.103833317756653,49.59485322153236],[6.1038655042648315,49.59518354995211],[6.103758215904236,49.595190504210564]]}}, 6 | {"type":"Feature","properties":{"highway":"residential","original:NOM_RUE":"Rue Michel Flammang","original:TRI_CACLR":"Flammang","original:RUE_ABBREV":"Rue Michel Flammang","original:ID_RUE_CAC":"6804","original:ID_LOCALIT":"1","original:TRP_TYPE":"0","original:TRP_TYPE_L":"axe","original:TRP_REVT":"0","original:TRP_REVT_L":"aménagé","original:TRP_NIVEAU":"0","original:TRP_NIVE_L":"au sol","original:TRP_CLASS":"4","original:TRP_CLAS_L":"Chemin vicinal","original:TRP_USAGE":"1","original:TRP_USAG_L":"circulation publique","original:TRP_ETAT":"0","original:TRP_ETAT_L":"en service","original:TRP_NBVOIE":"2","original:TRP_NBVO_L":"2 voies","original:TRP_TRAM":"0","original:TRP_LARGEU":"3","original:TRP_LARG_L":"6,5 m - 7,5 m","original:NOM_LOCALI":"Luxembourg","original:CODE_POSTA":"1524","original:SHAPE_LEN":"64.813378922951"},"geometry":{"type":"LineString","coordinates":[[6.103683114051819,49.59431773702519],[6.103473901748657,49.59436641767789],[6.103371977806091,49.59438032642689],[6.102803349494934,49.59440118954291]]}}, 7 | {"type":"Feature","properties":{"highway":"residential","original:NOM_RUE":"Rue Michel Flammang","original:TRI_CACLR":"Flammang","original:RUE_ABBREV":"Rue Michel Flammang","original:ID_RUE_CAC":"6804","original:ID_LOCALIT":"1","original:TRP_TYPE":"0","original:TRP_TYPE_L":"axe","original:TRP_REVT":"0","original:TRP_REVT_L":"aménagé","original:TRP_NIVEAU":"0","original:TRP_NIVE_L":"au sol","original:TRP_CLASS":"4","original:TRP_CLAS_L":"Chemin vicinal","original:TRP_USAGE":"1","original:TRP_USAG_L":"circulation publique","original:TRP_ETAT":"0","original:TRP_ETAT_L":"en service","original:TRP_NBVOIE":"2","original:TRP_NBVO_L":"2 voies","original:TRP_TRAM":"0","original:TRP_LARGEU":"3","original:TRP_LARG_L":"6,5 m - 7,5 m","original:NOM_LOCALI":"Luxembourg","original:CODE_POSTA":"1524","original:SHAPE_LEN":"59.432470948203"},"geometry":{"type":"LineString","coordinates":[[6.104337573051453,49.59407433303292],[6.10365629196167,49.594265579129114],[6.103683114051819,49.59431773702519]]}}, 8 | {"type":"Feature","properties":{"highway":"residential","original:NOM_RUE":"Rue Françoise Groben","original:TRI_CACLR":"Groben","original:RUE_ABBREV":"Rue Françoise Groben","original:ID_RUE_CAC":"9925","original:ID_LOCALIT":"1","original:TRP_TYPE":"0","original:TRP_TYPE_L":"axe","original:TRP_REVT":"1","original:TRP_REVT_L":"non aménagé","original:TRP_NIVEAU":"0","original:TRP_NIVE_L":"au sol","original:TRP_CLASS":"4","original:TRP_CLAS_L":"Chemin vicinal","original:TRP_USAGE":"1","original:TRP_USAG_L":"circulation publique","original:TRP_ETAT":"2","original:TRP_ETAT_L":"en projet","original:TRP_NBVOIE":"2","original:TRP_NBVO_L":"2 voies","original:TRP_CYCLE":"0","original:TRP_TRAM":"0","original:TRP_LARGEU":"3","original:TRP_LARG_L":"6,5 m - 7,5 m","original:NOM_LOCALI":"Luxembourg","original:CODE_POSTA":"1524","original:SHAPE_LEN":"71.3884575202781"},"geometry":{"type":"LineString","coordinates":[[6.104337573051453,49.59407433303292],[6.104369759559631,49.594102150693516],[6.104600429534912,49.594446392930394],[6.104584336280823,49.59445334729398],[6.104670166969299,49.594585480013706],[6.104562878608704,49.59461329738275]]}}, 9 | {"type":"Feature","properties":{"highway":"residential","original:NOM_RUE":"Rue Michel Flammang","original:TRI_CACLR":"Flammang","original:RUE_ABBREV":"Rue Michel Flammang","original:ID_RUE_CAC":"6804","original:ID_LOCALIT":"1","original:TRP_TYPE":"0","original:TRP_TYPE_L":"axe","original:TRP_REVT":"0","original:TRP_REVT_L":"aménagé","original:TRP_NIVEAU":"0","original:TRP_NIVE_L":"au sol","original:TRP_CLASS":"4","original:TRP_CLAS_L":"Chemin vicinal","original:TRP_USAGE":"1","original:TRP_USAG_L":"circulation publique","original:TRP_ETAT":"0","original:TRP_ETAT_L":"en service","original:TRP_NBVOIE":"2","original:TRP_NBVO_L":"2 voies","original:TRP_TRAM":"0","original:TRP_LARGEU":"3","original:TRP_LARG_L":"6,5 m - 7,5 m","original:NOM_LOCALI":"Luxembourg","original:CODE_POSTA":"1524","original:SHAPE_LEN":"57.1459157450469"},"geometry":{"type":"LineString","coordinates":[[6.105061769485474,49.59386917729603],[6.104337573051453,49.59407433303292]]}}, 10 | {"type":"Feature","properties":{"highway":"residential","original:NOM_RUE":"Rue Fernand Fox","original:TRI_CACLR":"Fox","original:RUE_ABBREV":"Rue Fernand Fox","original:ID_RUE_CAC":"9924","original:ID_LOCALIT":"1","original:TRP_TYPE":"0","original:TRP_TYPE_L":"axe","original:TRP_REVT":"1","original:TRP_REVT_L":"non aménagé","original:TRP_NIVEAU":"0","original:TRP_NIVE_L":"au sol","original:TRP_CLASS":"4","original:TRP_CLAS_L":"Chemin vicinal","original:TRP_USAGE":"1","original:TRP_USAG_L":"circulation publique","original:TRP_ETAT":"2","original:TRP_ETAT_L":"en projet","original:TRP_NBVOIE":"2","original:TRP_NBVO_L":"2 voies","original:TRP_CYCLE":"0","original:TRP_TRAM":"0","original:TRP_LARGEU":"3","original:TRP_LARG_L":"6,5 m - 7,5 m","original:NOM_LOCALI":"Luxembourg","original:CODE_POSTA":"1524","original:SHAPE_LEN":"60.1693523915648"},"geometry":{"type":"LineString","coordinates":[[6.105061769485474,49.59386917729603],[6.105346083641052,49.59429339668063],[6.105458736419678,49.59426210193405]]}}, 11 | {"type":"Feature","properties":{"highway":"residential","original:NOM_RUE":"Am Guddebierg","original:TRI_CACLR":"Guddebierg","original:RUE_ABBREV":"Am Guddebierg","original:ID_RUE_CAC":"9927","original:ID_LOCALIT":"1","original:TRP_TYPE":"0","original:TRP_TYPE_L":"axe","original:TRP_REVT":"1","original:TRP_REVT_L":"non aménagé","original:TRP_NIVEAU":"0","original:TRP_NIVE_L":"au sol","original:TRP_CLASS":"4","original:TRP_CLAS_L":"Chemin vicinal","original:TRP_USAGE":"1","original:TRP_USAG_L":"circulation publique","original:TRP_ETAT":"2","original:TRP_ETAT_L":"en projet","original:TRP_NBVOIE":"2","original:TRP_NBVO_L":"2 voies","original:TRP_CYCLE":"0","original:TRP_TRAM":"0","original:TRP_LARGEU":"3","original:TRP_LARG_L":"6,5 m - 7,5 m","original:NOM_LOCALI":"Luxembourg","original:CODE_POSTA":"1524","original:SHAPE_LEN":"336.494962486472"},"geometry":{"type":"LineString","coordinates":[[6.102803349494934,49.59440118954291],[6.102765798568726,49.59397349388024],[6.102787256240845,49.59390742673614],[6.102824807167053,49.593830927825906],[6.103227138519287,49.59354927171316],[6.103377342224121,49.59347624949251],[6.104187369346619,49.59317025042648],[6.104761362075806,49.59298247732187],[6.10514760017395,49.59286772673539],[6.105608940124512,49.59271472553348],[6.105780601501465,49.59264517937396],[6.105952262878418,49.592513041397666]]}}, 12 | {"type":"Feature","properties":{"highway":"residential","original:NOM_RUE":"Rue Michel Flammang","original:TRI_CACLR":"Flammang","original:RUE_ABBREV":"Rue Michel Flammang","original:ID_RUE_CAC":"6804","original:ID_LOCALIT":"1","original:TRP_TYPE":"0","original:TRP_TYPE_L":"axe","original:TRP_REVT":"0","original:TRP_REVT_L":"aménagé","original:TRP_NIVEAU":"0","original:TRP_NIVE_L":"au sol","original:TRP_CLASS":"4","original:TRP_CLAS_L":"Chemin vicinal","original:TRP_USAGE":"1","original:TRP_USAG_L":"circulation publique","original:TRP_ETAT":"0","original:TRP_ETAT_L":"en service","original:TRP_NBVOIE":"2","original:TRP_NBVO_L":"2 voies","original:TRP_TRAM":"0","original:TRP_LARGEU":"3","original:TRP_LARG_L":"6,5 m - 7,5 m","original:NOM_LOCALI":"Luxembourg","original:CODE_POSTA":"1524","original:SHAPE_LEN":"169.130315516831"},"geometry":{"type":"LineString","coordinates":[[6.106944680213928,49.59422732996987],[6.10689103603363,49.59420646677947],[6.106005907058716,49.59362577106518],[6.105131506919861,49.59386570007271],[6.105061769485474,49.59386917729603]]}}, 13 | {"type":"Feature","properties":{"highway":"residential","original:NOM_RUE":"Rëtschgriecht","original:TRI_CACLR":"Rëtsch","original:RUE_ABBREV":"Rëtschgriecht","original:ID_RUE_CAC":"9800","original:ID_LOCALIT":"502","original:TRP_TYPE":"0","original:TRP_TYPE_L":"axe","original:TRP_REVT":"1","original:TRP_REVT_L":"non aménagé","original:TRP_NIVEAU":"0","original:TRP_NIVE_L":"au sol","original:TRP_CLASS":"4","original:TRP_CLAS_L":"Chemin vicinal","original:TRP_USAGE":"1","original:TRP_USAG_L":"circulation publique","original:TRP_ETAT":"2","original:TRP_ETAT_L":"en projet","original:TRP_NBVOIE":"2","original:TRP_NBVO_L":"2 voies","original:TRP_CYCLE":"0","original:TRP_TRAM":"0","original:TRP_LARGEU":"1","original:TRP_LARG_L":"3,5 m - 4,5 m","original:NOM_LOCALI":"Beidweiler","original:CODE_POSTA":"6235","original:SHAPE_LEN":"42.783871552841"},"geometry":{"type":"LineString","coordinates":[[6.300567984580994,49.72675407943436],[6.3011473417282104,49.726844240589855]]}} 14 | ]} -------------------------------------------------------------------------------- /data/luxembourg/filter.sql: -------------------------------------------------------------------------------- 1 | SELECT * FROM "TRP_VC" 2 | WHERE 3 | -- Exclude ways where "NOM_RUE" is empty 4 | "NOM_RUE" <> '' 5 | -- Exclude ways where "TRP_CLAS_L" is 'Chemin de fer', 'Non codé', or 'autre' 6 | -- These are railroads or little paths. 7 | AND "TRP_CLAS_L" NOT IN ('Chemin de fer', 'Non codé', 'autre') 8 | -- Exclude rows where "shape_len" is equal to the lengths specified. 9 | -- These lengths have sub-atomic precision (10^-17 meters is smaller than the size of an atom!) 10 | -- and can therefore be used as convenient UIDs. Use these to filter razed roads. 11 | AND "shape_len" NOT IN ( 12 | 830.166626069713971, 13 | 131.914105731793, 14 | 113.935351615667, 15 | 143.610383935929, 16 | 298.383651161161, 17 | 43.3137167288205, 18 | 125.777662428269, 19 | 231.537716396734, 20 | 40.0327531241403, 21 | 6.31803767003648, 22 | 99.70996019701251, 23 | 202.849929945871 24 | ) 25 | -------------------------------------------------------------------------------- /data/luxembourg/luxembourg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Make script directory working directory 4 | 5 | cd `dirname "$(realpath $0)"` 6 | 7 | # Download Luxembourg extract 8 | 9 | if [ -f "luxembourg-latest.osm.pbf" ]; then rm "luxembourg-latest.osm.pbf"; fi 10 | 11 | wget https://download.geofabrik.de/europe/luxembourg-latest.osm.pbf 12 | 13 | # Convert to GeoJSON 14 | 15 | if [ -f "./luxembourg-lines.geojson" ]; then rm "./luxembourg-lines.geojson"; fi 16 | if [ -f "./luxembourg-polygons.geojson" ]; then rm "./luxembourg-polygons.geojson"; fi 17 | 18 | ogr2ogr -f "GeoJSON" -progress \ 19 | -sql "SELECT name, highway FROM lines WHERE highway IS NOT NULL" \ 20 | "./luxembourg-lines.geojson" \ 21 | "./luxembourg-latest.osm.pbf" 22 | ogr2ogr -f "GeoJSON" -progress \ 23 | -sql "SELECT name, hstore_get_value(other_tags, 'highway') AS highway, place FROM multipolygons WHERE (hstore_get_value(other_tags, 'highway') is not null) OR (place = 'square')" \ 24 | "./luxembourg-polygons.geojson" \ 25 | "./luxembourg-latest.osm.pbf" 26 | 27 | # Generate buffer 28 | 29 | node "../../script/buffer.js" --radius=20 "./luxembourg-lines.geojson" "luxembourg-lines-buffers.geojson" 30 | node "../../script/buffer.js" --radius=5 "./luxembourg-polygons.geojson" "luxembourg-polygons-buffers.geojson" 31 | 32 | # Generate vector tiles 33 | 34 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 35 | --maximum-zoom=14 --minimum-zoom=14 \ 36 | --layer="buffers" \ 37 | --output="./luxembourg-buffers.mbtiles" "./luxembourg-lines-buffers.geojson" "./luxembourg-polygons-buffers.geojson" 38 | -------------------------------------------------------------------------------- /data/luxembourg/process.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | FILENAME="transport-et-voies-de-communication-shape" 4 | MAPROULETTE_CHALLENGE=17749 5 | 6 | # Make script directory working directory 7 | 8 | cd `dirname "$(realpath $0)"` 9 | 10 | # Download & unzip data 11 | 12 | mkdir -p "./source/" 13 | 14 | if [ ! -d "./source/$FILENAME" ]; then 15 | wget -O "./source/$FILENAME.zip" "https://data.public.lu/fr/datasets/r/e74aadad-77c2-441e-98fe-e08a441484a2" 16 | unzip -j "./source/$FILENAME.zip" -d "./source/$FILENAME/" "TRP_VC.*" 17 | fi 18 | 19 | # Convert to GeoJSON 20 | 21 | if [ -d "./temp" ]; then rm -r "./temp/"; fi 22 | 23 | mkdir -p "./temp/" 24 | 25 | ogr2ogr -f "GeoJSON" -progress \ 26 | --config SHAPE_ENCODING "ISO-8859-1" \ 27 | -s_srs "EPSG:2169" -t_srs "EPSG:4326" \ 28 | -sql "@filter.sql" \ 29 | -lco COORDINATE_PRECISION=6 \ 30 | -fieldTypeToString "All" \ 31 | "./temp/trpvc.geojson" \ 32 | "./source/$FILENAME/TRP_VC.shp" 33 | 34 | 35 | # Before conferting the fields into OpenStreetMap tags, we extend convert.json with our street name standardization 36 | # Download our community-driven street name standardization tuples 37 | 38 | wget -O "./temp/csventrifuge_enhance_name.csv" "https://raw.githubusercontent.com/osmlu/csventrifuge/master/rules/luxembourg_addresses/rue.csv" 39 | wget -O "./temp/csventrifuge_enhance_id.csv" "https://raw.githubusercontent.com/osmlu/csventrifuge/master/enhance/luxembourg_addresses/id_caclr_rue/rue.csv" 40 | 41 | # Convert the tuples into JSON and merge them with convert.json 42 | 43 | node "./build-extended-conversion.js" "./temp/csventrifuge_enhance_name.csv" "./temp/csventrifuge_enhance_id.csv" "convert.json" "./temp/convert-merged.json" 44 | 45 | # Finally, convert fields to OpenStreetMap tags 46 | 47 | node "../../script/convert-tags.js" -c "./temp/convert-merged.json" "./temp/trpvc.geojson" "trpvcTagged.geojson" 48 | 49 | # Generate vector tiles 50 | 51 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 52 | --buffer=0 \ 53 | --maximum-zoom=14 --minimum-zoom=14 \ 54 | --layer="roads" \ 55 | --output="./temp/trpvcTagged.mbtiles" "./temp/trpvcTagged.geojson" 56 | 57 | # Generate MapRoulette NotAnIssue buffers vector tiles 58 | 59 | wget -O "./temp/maproulette.geojson" "https://maproulette.org/api/v2/challenge/view/$MAPROULETTE_CHALLENGE?status=2" 60 | 61 | node "../../script/buffer.js" --radius=20 "./temp/maproulette.geojson" "maproulette-buffers.geojson" 62 | 63 | # Merge MapRoulette buffers to OpenStreetMap buffers 64 | 65 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 66 | --maximum-zoom=14 --minimum-zoom=14 \ 67 | --layer="buffers" \ 68 | --output="./temp/luxembourg-buffers.mbtiles" \ 69 | "./luxembourg-lines-buffers.geojson" "./luxembourg-polygons-buffers.geojson" "./temp/maproulette-buffers.geojson" 70 | 71 | # Difference 72 | 73 | if [ -d "./difference" ]; then rm -r "./difference/"; fi 74 | 75 | mkdir -p "./difference" 76 | 77 | node "../../script/difference.js" --output-dir="./difference" "./temp/trpvcTagged.mbtiles" "./temp/luxembourg-buffers.mbtiles" 78 | 79 | # Our dataset doesn't have unique identifiers for segments of the same road, so we create one based on the geometry 80 | node "./create-uid.js" "./difference/diff.geojson" "./difference/diff.geojson" -------------------------------------------------------------------------------- /data/netherlands/README.md: -------------------------------------------------------------------------------- 1 | # Road Completion - 🇳🇱 Netherlands 2 | 3 | Sources: 4 | Direct Link: 5 | 6 | ## Filters 7 | 8 | ### `BST_CODE` (*Baansubsoort*) 9 | 10 | ```sql 11 | "BST_CODE" NOT IN ('VD', 'VV') 12 | ``` 13 | 14 | Filtering out features that are not considered roads in OSM, see Tags for more. 15 | 16 | *Classificering van de functie die een wegvak in het wegennetwerk heeft.* 17 | 18 | | Value | Description (original) | Description (Translated) | 19 | |-------|-----------------------------------------------------------|--------------------------------------------------------| 20 | | VV | Vliegverkeer | Air Traffic (runway or taxiway) | 21 | | VD | Veerdienst | Ferry | 22 | 23 | ## Tags 24 | 25 | ### `BST_CODE` (*Baansubsoort*) 26 | | Value | Description (original) | Description (Translated) | OSM Tags (if empty `highway=unclassified`) | 27 | |-------|-----------------------------------------------------------|--------------------------------------------------------|--------------------------------------------------------------------------------| 28 | | VWG | Ventweg | Parallel road in city | | 29 | | PAR | Parallelweg - niet ventweg | Parallel road | | 30 | | MRB | Minirotondebaan | Road on mini-roundabout | | 31 | | NRB | Normale rotondebaan - niet minirotondebaan | Road on roundabout | `highway=unclassified`, `junction=roundabout` and `oneway=yes` | 32 | | OPR | Toerit - synomien: Oprit | On ramp to road (OSM `_link`) | | 33 | | AFR | Afrit | Off ramp from road (OSM `_link`) | | 34 | | PST | Puntstuk = snijpunt verharding | Intersection | | 35 | | VBD | Verbindingsweg direct | Direct link road | | 36 | | VBI | Verbindingsweg indirect | Indirect link road | | 37 | | VBS | Verbindingsweg semi-direct | Semi-direct link road | | 38 | | VBR | Verbindingsweg rangeerbaan | Collector/Distributor Lane | | 39 | | VBK | Verbindingsweg kortsluitend | Link road connecting from at least one other link road | | 40 | | VBW | Verbindingsweg - overig | Miscellaneous link road | | 41 | | DST | Doorsteek | Bypass between roads | | 42 | | PKP | Verzorgingsbaan van/naar parkeerplaats | Slip road to/from parking lot | `highway=service` | 43 | | PKB | Verzorgingsbaan van/naar parkeerplaats bij benzinestation | Slip road to/from parking lot to petrol station | `highway=service` | 44 | | BST | Verzorgingsbaan van/naar benzinestation | Slip road to/from petrol station | `highway=service` | 45 | | YYY | Overig | Miscellaneous | | 46 | | BU | Busbaan | Bus road | `highway=service`, `access=no`, `psv=yes` and `fixme=Access for taxis` | 47 | | FP | Fietspad | Cycleway | `highway=cycleway` | 48 | | HR | Hoofdrijbaan | Road | | 49 | | TN | Tussenbaan | Road connecting slip roads | | 50 | | VP | Voetpad | Footway | `highway=footway` | 51 | | OVB | OV-baan | Public transport road (tramway, bus road, etc) | `highway=service`, `access=no` and `psv=yes` | 52 | | CADO | Calamiteiten doorgang | Emergency bypass | `highway=service`, `access=no`, `emergency=yes` and `service=emergency_access` | 53 | | TRB | Turborotondebaan | Road on turbo-roundabout | `highway=unclassified`, `junction=roundabout` and `oneway=yes` | 54 | | RP | Ruiterpad | Bridleway | `highway=bridleway` | 55 | | VV | Vliegverkeer | Air Traffic (runway or taxiway) | not used | 56 | | PP | Parkeerplaats | Road on parking lot | `highway=service` and `service=parking_aisle` | 57 | | PC | Parkeerplaats tbv carpool | Road on parking lot for carpool | `highway=service` and `service=parking_aisle` | 58 | | PR | Parkeerplaats P+R | Road on parking lot for P+R | `highway=service` and `service=parking_aisle` | 59 | | VD | Veerdienst | Ferry | not used | -------------------------------------------------------------------------------- /data/netherlands/convert.json: -------------------------------------------------------------------------------- 1 | { 2 | "BST_CODE":{ 3 | "*": { 4 | "highway": "unclassified" 5 | }, 6 | "BST": { 7 | "highway": "service" 8 | }, 9 | "BU": { 10 | "highway": "service", 11 | "access": "no", 12 | "psv": "yes", 13 | "fixme": "Access for taxis" 14 | }, 15 | "CADO": { 16 | "highway": "service", 17 | "access": "no", 18 | "emergency": "yes", 19 | "service": "emergency_access" 20 | }, 21 | "FP": { 22 | "highway": "cycleway" 23 | }, 24 | "NRB": { 25 | "highway": "unclassified", 26 | "junction": "roundabout", 27 | "oneway": "yes" 28 | }, 29 | "OVB": { 30 | "highway": "service", 31 | "access": "no", 32 | "psv": "yes" 33 | }, 34 | "PC": { 35 | "highway": "service", 36 | "service": "parking_aisle" 37 | }, 38 | "PKB": { 39 | "highway": "service" 40 | }, 41 | "PKP": { 42 | "highway": "service" 43 | }, 44 | "PP": { 45 | "highway": "service", 46 | "service": "parking_aisle" 47 | }, 48 | "PR": { 49 | "highway": "service", 50 | "service": "parking_aisle" 51 | }, 52 | "RP": { 53 | "highway": "bridleway" 54 | }, 55 | "TRB": { 56 | "highway": "unclassified", 57 | "junction": "roundabout", 58 | "oneway": "yes" 59 | }, 60 | "VP": { 61 | "highway": "footway" 62 | } 63 | 64 | } 65 | } -------------------------------------------------------------------------------- /data/netherlands/filter.sql: -------------------------------------------------------------------------------- 1 | SELECT * FROM "Wegvakken" WHERE 2 | "BST_CODE" NOT IN ('VD', 'VV') -------------------------------------------------------------------------------- /data/netherlands/netherlands.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Make script directory working directory 4 | 5 | cd `dirname "$(realpath $0)"` 6 | 7 | # Download Netherlands extract extract 8 | 9 | if [ -f "netherlands-latest.osm.pbf" ]; then rm "netherlands-latest.osm.pbf"; fi 10 | 11 | wget https://download.geofabrik.de/europe/netherlands-latest.osm.pbf 12 | 13 | # Convert to GeoJSON 14 | 15 | if [ -f "./netherlands-lines.geojson" ]; then rm "./netherlands-lines.geojson"; fi 16 | if [ -f "./netherlands-polygons.geojson" ]; then rm "./netherlands-polygons.geojson"; fi 17 | 18 | ogr2ogr -f "GeoJSON" -progress \ 19 | -sql "SELECT name, highway FROM lines WHERE highway IS NOT NULL" \ 20 | "./netherlands-lines.geojson" \ 21 | "./netherlands-latest.osm.pbf" 22 | ogr2ogr -f "GeoJSON" -progress \ 23 | -sql "SELECT name, hstore_get_value(other_tags, 'highway') AS highway, place FROM multipolygons WHERE (hstore_get_value(other_tags, 'highway') is not null) OR (place = 'square')" \ 24 | "./netherlands-polygons.geojson" \ 25 | "./netherlands-latest.osm.pbf" 26 | 27 | # Generate buffer 28 | 29 | node "../../script/buffer.js" --radius=20 "./netherlands-lines.geojson" "netherlands-lines-buffers.geojson" 30 | node "../../script/buffer.js" --radius=5 "./netherlands-polygons.geojson" "netherlands-polygons-buffers.geojson" 31 | 32 | # Generate vector tiles 33 | 34 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 35 | --maximum-zoom=14 --minimum-zoom=14 \ 36 | --layer="buffers" \ 37 | --output="./netherlands-buffers.mbtiles" \ 38 | "./netherlands-lines-buffers.geojson" "./netherlands-polygons-buffers.geojson" 39 | -------------------------------------------------------------------------------- /data/netherlands/process.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | FILENAME="05-01-2023" 4 | MAPROULETTE_CHALLENGE=17332 5 | 6 | # Make script directory working directory 7 | 8 | cd `dirname "$(realpath $0)"` 9 | 10 | # Download & unzip data 11 | 12 | mkdir -p "./source/" 13 | 14 | if [ ! -d "./source/$FILENAME" ]; then 15 | wget -O "./source/$FILENAME.zip" "https://www.rijkswaterstaat.nl/apps/geoservices/geodata/dmc/nwb-wegen/geogegevens/shapefile/Nederland_totaal/$FILENAME.zip" 16 | unzip -j "./source/$FILENAME.zip" -d "./source/$FILENAME/" "$FILENAME/Wegvakken/Wegvakken.*" 17 | fi 18 | 19 | # Convert to GeoJSON 20 | 21 | if [ -d "./temp" ]; then rm -r "./temp/"; fi 22 | 23 | mkdir -p "./temp/" 24 | 25 | ogr2ogr -f "GeoJSON" -progress \ 26 | --config SHAPE_ENCODING "ISO-8859-1" \ 27 | -s_srs "EPSG:28992" -t_srs "EPSG:4326" \ 28 | -sql "@filter.sql" \ 29 | -lco COORDINATE_PRECISION=6 \ 30 | -fieldTypeToString "All" \ 31 | "./temp/Wegvakken.geojson" \ 32 | "./source/$FILENAME/Wegvakken.shp" 33 | 34 | # Convert fields to OpenStreetMap tags 35 | 36 | node "../../../script/convert-tags.js" -c "./convert.json" "./temp/Wegvakken.geojson" "WegvakkenTagged.geojson" 37 | 38 | # Generate vector tiles 39 | 40 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 41 | --buffer=0 \ 42 | --maximum-zoom=14 --minimum-zoom=14 \ 43 | --layer="roads" \ 44 | --output="./temp/WegvakkenTagged.mbtiles" "./temp/WegvakkenTagged.geojson" 45 | 46 | # Generate MapRoulette NotAnIssue buffers vector tiles 47 | 48 | wget -O "./temp/maproulette.geojson" "https://maproulette.org/api/v2/challenge/view/$MAPROULETTE_CHALLENGE?status=2" 49 | 50 | node "../../../script/buffer.js" --radius=20 "./temp/maproulette.geojson" "maproulette-buffers.geojson" 51 | 52 | # Merge MapRoulette buffers to OpenStreetMap buffers 53 | 54 | tippecanoe --force --no-feature-limit --no-tile-size-limit \ 55 | --maximum-zoom=14 --minimum-zoom=14 \ 56 | --layer="buffers" \ 57 | --output="./temp/netherlands-buffers.mbtiles" \ 58 | "netherlands-lines-buffers.geojson" "netherlands-polygons-buffers.geojson" "./temp/maproulette-buffers.geojson" 59 | 60 | # Difference 61 | 62 | if [ -d "./difference" ]; then rm -r "./difference/"; fi 63 | 64 | mkdir -p "./difference" 65 | 66 | node "../../script/difference.js" --output-dir="./difference" "./temp/WegvakkenTagged.mbtiles" "./temp/netherlands-buffers.mbtiles" 67 | -------------------------------------------------------------------------------- /report/.gitignore: -------------------------------------------------------------------------------- 1 | # build output 2 | dist 3 | 4 | # dependencies 5 | node_modules/ 6 | 7 | # data 8 | public/data/*.json 9 | 10 | # logs 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | 15 | # environment variables 16 | .env 17 | .env.production 18 | 19 | # macOS-specific files 20 | .DS_Store 21 | -------------------------------------------------------------------------------- /report/README.md: -------------------------------------------------------------------------------- 1 | # Road Completion - Report 2 | -------------------------------------------------------------------------------- /report/astro.config.mjs: -------------------------------------------------------------------------------- 1 | import svelte from '@astrojs/svelte'; 2 | import { defineConfig } from 'astro/config' 3 | 4 | export default defineConfig({ 5 | site: 'https://osmbe.github.io', 6 | base: '/road-completion', 7 | integrations: [ 8 | svelte(), 9 | ] 10 | }); 11 | -------------------------------------------------------------------------------- /report/github/commit.mjs: -------------------------------------------------------------------------------- 1 | import { createActionAuth } from '@octokit/auth-action'; 2 | import { Octokit } from '@octokit/rest'; 3 | 4 | import { OWNER, REPOSITORY } from './constants.mjs'; 5 | 6 | export default async function (auth, ref) { 7 | const octokit = new Octokit({ 8 | authStrategy: createActionAuth, 9 | auth, 10 | }); 11 | 12 | const { data } = await octokit.repos.getCommit({ 13 | owner: OWNER, 14 | repo: REPOSITORY, 15 | ref 16 | }); 17 | 18 | return data; 19 | } 20 | -------------------------------------------------------------------------------- /report/github/commits.mjs: -------------------------------------------------------------------------------- 1 | import { createActionAuth } from '@octokit/auth-action'; 2 | import { Octokit } from '@octokit/rest'; 3 | 4 | import getCommit from './commit.mjs'; 5 | import getContent from './content.mjs'; 6 | 7 | import { OWNER, REPOSITORY } from './constants.mjs'; 8 | 9 | export default async function (path) { 10 | const auth = createActionAuth(); 11 | const authentication = await auth(); 12 | 13 | const octokit = new Octokit({ 14 | authStrategy: createActionAuth, 15 | auth: authentication, 16 | }); 17 | 18 | const { data } = await octokit.repos.listCommits({ 19 | owner: OWNER, 20 | repo: REPOSITORY, 21 | per_page: 52, 22 | path 23 | }); 24 | 25 | return Promise.all( 26 | data.map(async (commit) => { 27 | const content = await getContent(authentication, path, commit.sha); 28 | const details = await getCommit(authentication, commit.sha); 29 | 30 | const stats = { 31 | tiles: 0, 32 | roads: 0, 33 | buffers: 0, 34 | notWithin: 0 35 | }; 36 | content.forEach((s) => { 37 | stats.tiles++; 38 | stats.roads += s.roads; 39 | stats.buffers += s.buffers; 40 | stats.notWithin += s.notWithin; 41 | }); 42 | 43 | const files = details.files.map((file) => file.filename.replace(/.*\//, '')); 44 | const processChange = (files.indexOf('filter.sql') !== -1 || files.indexOf('process.sh') !== -1); 45 | 46 | const dirname = path.match(/.*\//); 47 | const diff = `https://github.com/${OWNER}/${REPOSITORY}/blob/${commit.sha}/${dirname}diff.geojson`; 48 | 49 | const title = commit.commit.message.substring(0, commit.commit.message.indexOf('\n')); 50 | const message = commit.commit.message.substring(commit.commit.message.indexOf('\n')); 51 | 52 | return { 53 | path, 54 | diff, 55 | datetime: new Date(commit.commit.author.date), 56 | title, 57 | message, 58 | sha: commit.sha, 59 | url: commit.html_url, 60 | stats, 61 | status: processChange ? 'script' : 'data' 62 | }; 63 | }) 64 | ); 65 | } 66 | -------------------------------------------------------------------------------- /report/github/constants.mjs: -------------------------------------------------------------------------------- 1 | export const OWNER = 'osmbe'; 2 | export const REPOSITORY = 'road-completion'; 3 | 4 | export const PATHS = { 5 | 'be-brussels': 'data/belgium/brussels/difference/stats.json', 6 | 'be-flanders': 'data/belgium/flanders/difference/stats.json', 7 | 'be-wallonia-bra': 'data/belgium/wallonia/difference/BRA/stats.json', 8 | 'be-wallonia-hai': 'data/belgium/wallonia/difference/HAI/stats.json', 9 | 'be-wallonia-lie': 'data/belgium/wallonia/difference/LIE/stats.json', 10 | 'be-wallonia-lux': 'data/belgium/wallonia/difference/LUX/stats.json', 11 | 'be-wallonia-nam': 'data/belgium/wallonia/difference/NAM/stats.json', 12 | 'lu-luxembourg': 'data/luxembourg/difference/stats.json', 13 | 'nl-netherlands': 'data/netherlands/difference/stats.json', 14 | 'xk-kosovo': 'data/kosovo/difference/stats.json' 15 | }; 16 | -------------------------------------------------------------------------------- /report/github/content.mjs: -------------------------------------------------------------------------------- 1 | import { createActionAuth } from '@octokit/auth-action'; 2 | import { Octokit } from '@octokit/rest'; 3 | 4 | import { OWNER, REPOSITORY } from './constants.mjs'; 5 | 6 | export default async function (auth, path, ref) { 7 | const octokit = new Octokit({ 8 | authStrategy: createActionAuth, 9 | auth, 10 | }); 11 | 12 | const { data } = await octokit.repos.getContent({ 13 | owner: OWNER, 14 | repo: REPOSITORY, 15 | path, 16 | ref 17 | }); 18 | 19 | return typeof data.content !== 'undefined' ? JSON.parse(Buffer.from(data.content, data.encoding).toString('utf-8')) : []; 20 | } 21 | -------------------------------------------------------------------------------- /report/github/index.mjs: -------------------------------------------------------------------------------- 1 | import { writeFile } from "fs"; 2 | 3 | import getCommits from "./commits.mjs"; 4 | 5 | import { PATHS } from "./constants.mjs"; 6 | 7 | Object.keys(PATHS).forEach(async (key) => { 8 | try { 9 | const data = await getCommits(PATHS[key]); 10 | const json = JSON.stringify(data); 11 | 12 | writeFile(`public/data/${key}.json`, json, (err) => { 13 | if (err) throw err; 14 | console.log(`✅ The file "${key}.json" has been saved!`); 15 | }); 16 | } catch (err) { 17 | console.error(`GitHub API request failed for "${key}": ${err}`); 18 | } 19 | }); 20 | -------------------------------------------------------------------------------- /report/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "road-completion-report", 3 | "scripts": { 4 | "prebuild": "node ./github/index.mjs", 5 | "dev": "astro dev", 6 | "start": "astro dev", 7 | "build": "astro build", 8 | "preview": "astro preview" 9 | }, 10 | "devDependencies": { 11 | "@astrojs/svelte": "^2.2.0", 12 | "@octokit/auth-action": "^2.1.1", 13 | "@octokit/rest": "^19.0.11", 14 | "astro": "^2.9.6" 15 | }, 16 | "dependencies": { 17 | "chart.js": "^4.4.8", 18 | "chartjs-adapter-moment": "^1.0.1", 19 | "moment": "^2.30.1" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /report/public/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osmbe/road-completion/f650ed6f41f6d0db1de732180060b5216f5b0e26/report/public/assets/.gitkeep -------------------------------------------------------------------------------- /report/public/data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osmbe/road-completion/f650ed6f41f6d0db1de732180060b5216f5b0e26/report/public/data/.gitkeep -------------------------------------------------------------------------------- /report/public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: / 3 | -------------------------------------------------------------------------------- /report/src/components/Nav.astro: -------------------------------------------------------------------------------- 1 | 11 | 12 | -------------------------------------------------------------------------------- /report/src/components/Report.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Statistics from './Statistics.astro'; 3 | 4 | const { id, title, ga } = Astro.props; 5 | --- 6 | 7 |
8 |
9 |

{title}

10 | 11 | {ga && ( 12 | 13 | GitHub Actions workflow 14 | 15 | )} 16 |
17 | 18 | 19 |
20 | 21 | 30 | -------------------------------------------------------------------------------- /report/src/components/Statistics.astro: -------------------------------------------------------------------------------- 1 | --- 2 | import Chart from './Statistics/Chart.svelte'; 3 | import History from './Statistics/History.svelte'; 4 | 5 | const { id } = Astro.props; 6 | --- 7 | 8 |
9 | 10 | 11 |
12 | -------------------------------------------------------------------------------- /report/src/components/Statistics/Chart.svelte: -------------------------------------------------------------------------------- 1 | 60 | 61 |
62 | 63 |
64 | -------------------------------------------------------------------------------- /report/src/components/Statistics/History.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 |
10 | {#await promise then commits} 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | {#each commits as commit} 24 | 25 | {#if commit.status == 'script'} 26 | 27 | {:else} 28 | 29 | {/if} 30 | 35 | 41 | 42 | 43 | 48 | 49 | 50 | {/each} 51 | 52 |
CommitDateRoadsOSM"Missing"Tiles
🔨 31 | 32 | { commit.title || commit.message } 33 | 34 | 36 | 40 | { commit.stats.roads }{ commit.stats.buffers } 44 | 45 | { commit.stats.notWithin } 46 | 47 | { commit.stats.tiles }
53 | {/await} 54 |
55 | -------------------------------------------------------------------------------- /report/src/env.d.ts: -------------------------------------------------------------------------------- 1 | /// -------------------------------------------------------------------------------- /report/src/pages/index.astro: -------------------------------------------------------------------------------- 1 | --- 2 | // Component Imports 3 | import Nav from '../components/Nav.astro'; 4 | import Report from '../components/Report.astro'; 5 | 6 | // Component Script: 7 | let title = 'Road Completion'; 8 | 9 | // Full Astro Component Syntax: 10 | // https://docs.astro.build/core-concepts/astro-components/ 11 | --- 12 | 13 | 14 | 15 | 16 | {title} 17 | 18 | 19 | 22 | 23 | 24 |
25 |
26 |

{title}

27 |
28 | 29 |
61 | 62 | 63 | -------------------------------------------------------------------------------- /report/src/styles/global.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | margin: 0; 4 | } 5 | 6 | body { 7 | background: #f9fafb; 8 | color: #111827; 9 | --color-light: #f3f4f6; 10 | } 11 | 12 | /* @media (prefers-color-scheme: dark) { 13 | body { 14 | background: #111827; 15 | color: #fff; 16 | --color-light: #1f2937; 17 | } 18 | } */ 19 | -------------------------------------------------------------------------------- /report/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /script/.eslintrc.yml: -------------------------------------------------------------------------------- 1 | env: 2 | browser: false 3 | es2021: true 4 | extends: 5 | - standard 6 | - eslint:recommended 7 | - 'plugin:@typescript-eslint/recommended' 8 | parser: '@typescript-eslint/parser' 9 | parserOptions: 10 | ecmaVersion: 12 11 | sourceType: module 12 | plugins: 13 | - '@typescript-eslint' 14 | rules: 15 | semi: [error, always] 16 | -------------------------------------------------------------------------------- /script/README.md: -------------------------------------------------------------------------------- 1 | # Road Completion - Scripts 2 | 3 | Scripts are built from TypeScript using `npm run build`. 4 | 5 | ## Generate buffers 6 | 7 | Scrip: `buffer.js` 8 | Source: [`src/buffer.ts`](./src/buffer.ts) 9 | 10 | ### Description 11 | 12 | The `buffer.js` script will generate a buffer (specified in meters) around each feature in a specified GeoJSON file. The result will be generated in the same folder as the specified GeoJSON file. 13 | 14 | ### Usage 15 | 16 | ```shell 17 | node "buffers.js" -r 10 "path/to/myfile.geojson" "buffers.geojson" 18 | ``` 19 | 20 | OR 21 | 22 | ```shell 23 | node "buffers.js" --radius=10 "path/to/myfile.geojson" "buffers.geojson" 24 | ``` 25 | 26 | ## Convert source field to OpenStreetMap tag 27 | 28 | Scrip: `convert-tags.js` 29 | Source: [`src/convert-tags.ts`](./src/convert-tags.ts) 30 | 31 | ### Description 32 | 33 | The `convert-tags.js` script will convert source data field (from a specified GeoJSON file) to OpenStreetMap tag(s) based on a configuration file. The result will be generated in the same folder as the specified GeoJSON file. 34 | 35 | ### Usage 36 | 37 | ```shell 38 | node "convert-tags.js" -c "path/to/convert.json" "path/to/mysource.geojson" "tagged.geojson" 39 | ``` 40 | 41 | ### Configuration file: `convert.json` 42 | 43 | ```json 44 | { 45 | "MYSOURCEFIELD": { 46 | "VALUE1": { 47 | "OSMTAG1": "OSMTAG1_VALUE", 48 | "OSMTAG2": "OSMTAG2_VALUE", 49 | ... 50 | }, 51 | "VALUES2": { 52 | ... 53 | }, 54 | ... 55 | }, 56 | ... 57 | } 58 | ``` 59 | 60 | You can use `*` as value (see `VALUE1` or `VALUE2` in the example above) to specify all values. 61 | 62 | See [Brussels, Belgium configuration file](../data/belgium/brussels/convert.json) or [Flanders, Belgium configuration file](../data/belgium/flanders/convert.json) for reference. 63 | 64 | ## Calculate difference (tile by tile) between source and OpenStreetMap 65 | 66 | Scrip: `difference.js` 67 | Source: [`src/difference.ts`](./src/difference.ts) 68 | 69 | ### Description 70 | 71 | Using [TileReduce](https://github.com/mapbox/tile-reduce), the process does tile by tile: 72 | 73 | 1. Normalize all roads and buffers in current tile 74 | 1. Flatten all roads and buffers in current tile 75 | 1. Merge all the OpenStreetMap (+ Map Roulette) with() in current tile 76 | 1. Get all roads that are not entirely within the merged buffer in current tile 77 | 78 | ### Usage 79 | 80 | ```shell 81 | node "difference.js" --output-dir="path/to/directory" "path/to/mysource.mbtiles" "path/to/mybuffers.mbtiles" 82 | ``` 83 | 84 | ### Result files 85 | 86 | #### `stats.json` 87 | 88 | Contains statistics about the difference process: 89 | 90 | - Coordinates of the tile (`[x, y, zoom_level]`) 91 | - Number of roads in the tile 92 | - Number of buffers in the tile 93 | - Number of roads that are not entirely within the merged buffer in the tile 94 | 95 | #### `diff.geojson` 96 | 97 | Contains all the roads that are not entirely within the buffers. 98 | -------------------------------------------------------------------------------- /script/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "road-completion", 3 | "version": "1.0.0", 4 | "description": "## Requirements", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "tsc --removeComments", 8 | "lint": "eslint --ext .ts \"src/**\"", 9 | "lint:fix": "eslint --fix --ext .ts \"src/**\"" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/osmbe/road-completion.git" 14 | }, 15 | "author": "", 16 | "license": "MIT", 17 | "bugs": { 18 | "url": "https://github.com/osmbe/road-completion/issues" 19 | }, 20 | "homepage": "https://github.com/osmbe/road-completion#readme", 21 | "dependencies": { 22 | "@mapbox/geojson-normalize": "0.0.1", 23 | "@mapbox/tile-reduce": "^3.3.1", 24 | "@turf/boolean-within": "^6.5", 25 | "@turf/buffer": "^6.5.0", 26 | "@turf/flatten": "^5.1.5", 27 | "@turf/helpers": "^6.5", 28 | "@turf/meta": "^6.5", 29 | "@turf/union": "^5.1", 30 | "event-stream": "^4.0.1", 31 | "jsonstream-next": "^3.0.0", 32 | "minimist": "^1.2.8" 33 | }, 34 | "devDependencies": { 35 | "@tsconfig/recommended": "^1.0.8", 36 | "@types/event-stream": "^4.0.5", 37 | "@types/geojson": "^7946.0.10", 38 | "@types/minimist": "^1.2.5", 39 | "@types/node": "^18.15.11", 40 | "@typescript-eslint/eslint-plugin": "^5.59.8", 41 | "@typescript-eslint/parser": "^5.59.8", 42 | "eslint": "^8.57.1", 43 | "eslint-config-standard": "^17.1.0", 44 | "eslint-plugin-import": "^2.31.0", 45 | "eslint-plugin-node": "^11.1.0", 46 | "eslint-plugin-promise": "^6.1.1", 47 | "typescript": "^4.9.5" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /script/src/buffer.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import buffer from '@turf/buffer'; 4 | import es from 'event-stream'; 5 | import fs from 'fs'; 6 | import { Feature } from 'geojson'; 7 | import JSONStream from 'jsonstream-next'; 8 | import minimist from 'minimist'; 9 | import path from 'path'; 10 | 11 | import fileExists from './file-exists'; 12 | 13 | const options = minimist(process.argv.slice(2)); 14 | const source = options._[0]; 15 | const target = options._[1]; 16 | const radius = options.r ?? options.radius; 17 | 18 | console.log(`Source: ${path.resolve(source)}`); 19 | console.log(`Radius: ${radius}m.`); 20 | 21 | if (fileExists(source) !== true) process.exit(1); 22 | 23 | const directory = path.dirname(source); 24 | 25 | console.log(path.resolve(directory, target)); 26 | 27 | fs.createReadStream(source) 28 | .pipe(JSONStream.parse('features.*')) 29 | .pipe( 30 | es.mapSync((feature: Feature) => buffer(feature, radius, { units: 'meters' })) 31 | ) 32 | .pipe( 33 | JSONStream.stringify( 34 | '{"type":"FeatureCollection","features":[\n', 35 | ',\n', 36 | '\n]}' 37 | ) 38 | ) 39 | .pipe(fs.createWriteStream(path.resolve(directory, target))); 40 | -------------------------------------------------------------------------------- /script/src/convert-tags.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import es from 'event-stream'; 4 | import fs from 'fs'; 5 | import { Feature } from 'geojson'; 6 | import JSONStream from 'jsonstream-next'; 7 | import minimist from 'minimist'; 8 | import path from 'path'; 9 | 10 | import fileExists from './file-exists'; 11 | 12 | const options = minimist(process.argv.slice(2)); 13 | const source = options._[0]; 14 | const target = options._[1]; 15 | 16 | console.log(`Source: ${path.resolve(source)}`); 17 | console.log(`Configuration: ${path.resolve(options.c)}`); 18 | 19 | if (fileExists(source, options.c) !== true) process.exit(1); 20 | 21 | const directory = path.dirname(source); 22 | 23 | console.log(path.resolve(directory, target)); 24 | 25 | const convert = JSON.parse(fs.readFileSync(options.c).toString()); 26 | const convertKeys = Object.keys(convert); 27 | 28 | fs.createReadStream(source) 29 | .pipe(JSONStream.parse('features.*')) 30 | .pipe( 31 | es.mapSync((feature: Feature) => { 32 | const properties: { [index: string]: any } = {}; 33 | let tags: { [index: string]: any } = {}; 34 | 35 | if (feature.properties !== null) { 36 | Object.keys(feature.properties).forEach((key: string) => { 37 | if (feature.properties !== null) { 38 | const value = feature.properties[key]; 39 | 40 | properties[`original:${key}`] = value; 41 | 42 | if (convertKeys.indexOf(key) !== -1) { 43 | if (typeof convert[key][value] !== 'undefined') { 44 | tags = Object.assign(tags, convert[key][value]); 45 | } else if (typeof convert[key]['*'] !== 'undefined') { 46 | tags = Object.assign(tags, convert[key]['*']); 47 | } 48 | } 49 | } 50 | }); 51 | } 52 | 53 | feature.properties = Object.assign(tags, properties); 54 | 55 | return feature; 56 | }) 57 | ) 58 | .pipe( 59 | JSONStream.stringify( 60 | '{"type":"FeatureCollection","features":[\n', 61 | ',\n', 62 | '\n]}' 63 | ) 64 | ) 65 | .pipe(fs.createWriteStream(path.resolve(directory, target))); 66 | -------------------------------------------------------------------------------- /script/src/difference.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import tileReduce from '@mapbox/tile-reduce'; 4 | import { Feature, FeatureCollection } from '@turf/helpers'; 5 | import fs from 'fs'; 6 | import minimist from 'minimist'; 7 | import path from 'path'; 8 | 9 | import fileExists from './file-exists'; 10 | 11 | const options = minimist(process.argv.slice(2)); 12 | const roads = options._[0]; 13 | const buffers = options._[1]; 14 | 15 | console.log(`Roads: ${path.resolve(roads)}`); 16 | console.log(`OSM Buffers: ${path.resolve(buffers)}`); 17 | 18 | if (fileExists(roads, buffers) !== true) process.exit(1); 19 | 20 | const directory = 21 | typeof options['output-dir'] !== 'undefined' 22 | ? path.resolve(options['output-dir']) 23 | : path.dirname(roads); 24 | 25 | const collectionNotWithin: FeatureCollection = { 26 | type: 'FeatureCollection', 27 | features: [] 28 | }; 29 | const stats: any[] = []; 30 | 31 | try { 32 | tileReduce({ 33 | sourceCover: 'road', 34 | log: true, 35 | map: path.resolve(__dirname, 'difference/buffer.js'), 36 | sources: [ 37 | { 38 | name: 'buffer', 39 | mbtiles: buffers, 40 | layers: ['buffers'] 41 | }, 42 | { 43 | name: 'road', 44 | mbtiles: roads, 45 | layers: ['roads'] 46 | } 47 | ] 48 | }) 49 | .on( 50 | 'reduce', 51 | (result: { 52 | stats: Array<{ 53 | tile: [number, number, number]; 54 | roads: number; 55 | buffers: number; 56 | notWithin: number; 57 | }>; 58 | featuresNotWithin: Feature[]; 59 | }) => { 60 | stats.push(result.stats); 61 | 62 | if (result.featuresNotWithin !== null) { 63 | collectionNotWithin.features = collectionNotWithin.features.concat( 64 | result.featuresNotWithin 65 | ); 66 | } 67 | } 68 | ) 69 | .on('end', function () { 70 | fs.writeFileSync(`${directory}/stats.json`, JSON.stringify(stats)); 71 | 72 | const file = path.resolve(directory, 'diff.geojson'); 73 | const stream = fs.createWriteStream(file); 74 | 75 | stream.write('{"type":"FeatureCollection","features":[\n'); 76 | 77 | collectionNotWithin.features.forEach((feature, index: number) => { 78 | stream.write(JSON.stringify(feature)); 79 | 80 | if (index < collectionNotWithin.features.length - 1) { 81 | stream.write(',\n'); 82 | } 83 | }); 84 | 85 | stream.write('\n]}'); 86 | stream.end(); 87 | 88 | console.log('Features count: %d', collectionNotWithin.features.length); 89 | console.log(`Result: ${file}`); 90 | }); 91 | } catch (err) { 92 | console.error(err); 93 | process.exit(1); 94 | } 95 | -------------------------------------------------------------------------------- /script/src/difference/buffer.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import normalize from '@mapbox/geojson-normalize'; 4 | import booleanWithin from '@turf/boolean-within'; 5 | import flatten from '@turf/flatten'; 6 | import { Feature, FeatureCollection, Polygon, Properties } from '@turf/helpers'; 7 | import union from '@turf/union'; 8 | 9 | module.exports = ( 10 | sources: Record< 11 | 'buffer' | 'road', 12 | Record<'buffers' | 'roads', FeatureCollection> 13 | >, 14 | tile: [number, number, number], 15 | write: any, 16 | done: any 17 | ) => { 18 | const stats = { 19 | tile, 20 | roads: 0, 21 | buffers: 0, 22 | notWithin: 0 23 | }; 24 | 25 | try { 26 | const roads: any = flatten(normalize(sources.road.roads)); 27 | const buffers: any = flatten(normalize(sources.buffer.buffers)); 28 | 29 | stats.roads = roads.features.length; 30 | stats.buffers = buffers.features.length; 31 | 32 | const mergedBuffers = union( 33 | ...(buffers.features as Feature[]) 34 | ); 35 | 36 | const featuresNotWithin = roads.features.filter( 37 | (feature: Feature) => booleanWithin(feature, mergedBuffers) !== true 38 | ); 39 | 40 | stats.notWithin = featuresNotWithin.length; 41 | 42 | done(null, { stats, featuresNotWithin }); 43 | } catch (err) { 44 | // @todo Should do something with the error 45 | done(null, { stats, featuresNotWithin: null }); 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /script/src/file-exists.ts: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import fs from 'fs'; 4 | import path from 'path'; 5 | 6 | export default function (...files: string[]): boolean { 7 | let exists = true; 8 | 9 | files.forEach((file) => { 10 | const fullPath = path.resolve(file); 11 | 12 | try { 13 | fs.accessSync(fullPath, fs.constants.F_OK | fs.constants.R_OK); 14 | } catch (err) { 15 | console.error(`File "${fullPath}" does not exist or is not readable.`); 16 | exists = false; 17 | } 18 | }); 19 | 20 | return exists; 21 | } 22 | -------------------------------------------------------------------------------- /script/src/typescript.d.ts: -------------------------------------------------------------------------------- 1 | declare module '@mapbox/geojson-normalize'; 2 | declare module '@mapbox/tile-reduce'; 3 | declare module '@turf/boolean-within'; 4 | declare module 'jsonstream-next'; 5 | -------------------------------------------------------------------------------- /script/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/recommended/tsconfig.json", 3 | "compilerOptions": { 4 | "pretty": true, 5 | "outDir": "." 6 | }, 7 | "include": [ 8 | "src/*.ts", 9 | "src/difference/*.ts" 10 | ], 11 | "exclude": [] 12 | } --------------------------------------------------------------------------------