crs-zone-toolkit 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- crs_zone_toolkit-0.1.0/.github/workflows/ci.yml +41 -0
- crs_zone_toolkit-0.1.0/.gitignore +25 -0
- crs_zone_toolkit-0.1.0/CITATION.cff +29 -0
- crs_zone_toolkit-0.1.0/LICENSE +21 -0
- crs_zone_toolkit-0.1.0/PKG-INFO +279 -0
- crs_zone_toolkit-0.1.0/QUICKSTART.md +96 -0
- crs_zone_toolkit-0.1.0/README.md +245 -0
- crs_zone_toolkit-0.1.0/docs/ARCHITECTURE.md +121 -0
- crs_zone_toolkit-0.1.0/docs/CLI_UX.md +267 -0
- crs_zone_toolkit-0.1.0/docs/DATA_REFERENCE.md +158 -0
- crs_zone_toolkit-0.1.0/docs/SPEC.md +166 -0
- crs_zone_toolkit-0.1.0/docs/TEST_PLAN.md +82 -0
- crs_zone_toolkit-0.1.0/docs/calibrage/2026-07-19-calibrage-seuils.md +196 -0
- crs_zone_toolkit-0.1.0/docs/feuille_de_route.md +100 -0
- crs_zone_toolkit-0.1.0/docs/references.md +102 -0
- crs_zone_toolkit-0.1.0/pyproject.toml +147 -0
- crs_zone_toolkit-0.1.0/scripts/README.md +117 -0
- crs_zone_toolkit-0.1.0/scripts/publier_release.py +174 -0
- crs_zone_toolkit-0.1.0/scripts/regenerer_demos.py +583 -0
- crs_zone_toolkit-0.1.0/src/crs_zone_toolkit/__init__.py +178 -0
- crs_zone_toolkit-0.1.0/src/crs_zone_toolkit/affichage.py +220 -0
- crs_zone_toolkit-0.1.0/src/crs_zone_toolkit/cli.py +385 -0
- crs_zone_toolkit-0.1.0/src/crs_zone_toolkit/core/__init__.py +5 -0
- crs_zone_toolkit-0.1.0/src/crs_zone_toolkit/core/analysis.py +544 -0
- crs_zone_toolkit-0.1.0/src/crs_zone_toolkit/core/apply.py +315 -0
- crs_zone_toolkit-0.1.0/src/crs_zone_toolkit/core/decoupage.py +104 -0
- crs_zone_toolkit-0.1.0/src/crs_zone_toolkit/core/errors.py +46 -0
- crs_zone_toolkit-0.1.0/src/crs_zone_toolkit/core/gridgen.py +63 -0
- crs_zone_toolkit-0.1.0/src/crs_zone_toolkit/core/messages.py +762 -0
- crs_zone_toolkit-0.1.0/src/crs_zone_toolkit/core/profile.py +67 -0
- crs_zone_toolkit-0.1.0/src/crs_zone_toolkit/core/report.py +291 -0
- crs_zone_toolkit-0.1.0/src/crs_zone_toolkit/core/results.py +161 -0
- crs_zone_toolkit-0.1.0/src/crs_zone_toolkit/core/targets.py +47 -0
- crs_zone_toolkit-0.1.0/src/crs_zone_toolkit/py.typed +0 -0
- crs_zone_toolkit-0.1.0/src/crs_zone_toolkit/regions/__init__.py +4 -0
- crs_zone_toolkit-0.1.0/src/crs_zone_toolkit/regions/loader.py +256 -0
- crs_zone_toolkit-0.1.0/src/crs_zone_toolkit/regions/qc/grille_mtm_qc.geojson +16 -0
- crs_zone_toolkit-0.1.0/src/crs_zone_toolkit/regions/qc/limite_qc.geojson +8 -0
- crs_zone_toolkit-0.1.0/src/crs_zone_toolkit/regions/qc/profil.toml +135 -0
- crs_zone_toolkit-0.1.0/src/crs_zone_toolkit/templates/rapport.html.j2 +302 -0
- crs_zone_toolkit-0.1.0/tests/conftest.py +327 -0
- crs_zone_toolkit-0.1.0/tests/schemas/analyse_v1.schema.json +67 -0
- crs_zone_toolkit-0.1.0/tests/test_affichage_datum.py +98 -0
- crs_zone_toolkit-0.1.0/tests/test_affichage_hors_profil.py +153 -0
- crs_zone_toolkit-0.1.0/tests/test_affichage_maquette.py +192 -0
- crs_zone_toolkit-0.1.0/tests/test_analysis.py +215 -0
- crs_zone_toolkit-0.1.0/tests/test_analysis_alternative_split.py +145 -0
- crs_zone_toolkit-0.1.0/tests/test_analysis_cibles.py +36 -0
- crs_zone_toolkit-0.1.0/tests/test_analysis_distortion.py +20 -0
- crs_zone_toolkit-0.1.0/tests/test_analysis_identify.py +60 -0
- crs_zone_toolkit-0.1.0/tests/test_analysis_libelle_candidat.py +100 -0
- crs_zone_toolkit-0.1.0/tests/test_analysis_prepare.py +36 -0
- crs_zone_toolkit-0.1.0/tests/test_analysis_repartition.py +80 -0
- crs_zone_toolkit-0.1.0/tests/test_analysis_sampling.py +229 -0
- crs_zone_toolkit-0.1.0/tests/test_analyze_public.py +32 -0
- crs_zone_toolkit-0.1.0/tests/test_apply.py +259 -0
- crs_zone_toolkit-0.1.0/tests/test_apply_garde_datum.py +65 -0
- crs_zone_toolkit-0.1.0/tests/test_apply_journal.py +47 -0
- crs_zone_toolkit-0.1.0/tests/test_apply_majority.py +35 -0
- crs_zone_toolkit-0.1.0/tests/test_apply_public.py +41 -0
- crs_zone_toolkit-0.1.0/tests/test_apply_rapport.py +147 -0
- crs_zone_toolkit-0.1.0/tests/test_apply_reproject.py +35 -0
- crs_zone_toolkit-0.1.0/tests/test_apply_resolve.py +33 -0
- crs_zone_toolkit-0.1.0/tests/test_apply_tracabilite.py +175 -0
- crs_zone_toolkit-0.1.0/tests/test_apply_write.py +34 -0
- crs_zone_toolkit-0.1.0/tests/test_cli_analyze.py +111 -0
- crs_zone_toolkit-0.1.0/tests/test_cli_apply.py +207 -0
- crs_zone_toolkit-0.1.0/tests/test_cli_encodage.py +74 -0
- crs_zone_toolkit-0.1.0/tests/test_cli_grid.py +61 -0
- crs_zone_toolkit-0.1.0/tests/test_composition.py +70 -0
- crs_zone_toolkit-0.1.0/tests/test_decide_decoupage_utile.py +144 -0
- crs_zone_toolkit-0.1.0/tests/test_demarrage.py +29 -0
- crs_zone_toolkit-0.1.0/tests/test_errors.py +27 -0
- crs_zone_toolkit-0.1.0/tests/test_gridgen.py +94 -0
- crs_zone_toolkit-0.1.0/tests/test_json_schema.py +43 -0
- crs_zone_toolkit-0.1.0/tests/test_loader.py +169 -0
- crs_zone_toolkit-0.1.0/tests/test_messages.py +168 -0
- crs_zone_toolkit-0.1.0/tests/test_messages_restitution.py +296 -0
- crs_zone_toolkit-0.1.0/tests/test_no_hardcoded_epsg.py +84 -0
- crs_zone_toolkit-0.1.0/tests/test_readme_publie.py +93 -0
- crs_zone_toolkit-0.1.0/tests/test_report_carte.py +32 -0
- crs_zone_toolkit-0.1.0/tests/test_report_commande_repro.py +124 -0
- crs_zone_toolkit-0.1.0/tests/test_report_echelle.py +65 -0
- crs_zone_toolkit-0.1.0/tests/test_report_lisibilite.py +86 -0
- crs_zone_toolkit-0.1.0/tests/test_report_public.py +39 -0
- crs_zone_toolkit-0.1.0/tests/test_report_render.py +180 -0
- crs_zone_toolkit-0.1.0/tests/test_report_write.py +53 -0
- crs_zone_toolkit-0.1.0/tests/test_results.py +97 -0
- crs_zone_toolkit-0.1.0/tests/test_scripts_demos.py +294 -0
- crs_zone_toolkit-0.1.0/tests/test_scripts_publier.py +353 -0
- crs_zone_toolkit-0.1.0/tests/test_smoke.py +12 -0
- crs_zone_toolkit-0.1.0/tests/test_targets.py +81 -0
- crs_zone_toolkit-0.1.0/uv.lock +1800 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
strategy:
|
|
11
|
+
fail-fast: false
|
|
12
|
+
matrix:
|
|
13
|
+
os: [ubuntu-latest, windows-latest]
|
|
14
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
15
|
+
runs-on: ${{ matrix.os }}
|
|
16
|
+
env:
|
|
17
|
+
# setup-uv n'a pas d'entrée python-version fiable selon la version ;
|
|
18
|
+
# UV_PYTHON force uv à créer le venv et à exécuter avec CETTE version
|
|
19
|
+
# (téléchargée au besoin) — la matrice teste donc réellement 3.11/3.12/3.13.
|
|
20
|
+
UV_PYTHON: ${{ matrix.python-version }}
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v5
|
|
23
|
+
|
|
24
|
+
- name: Installer uv
|
|
25
|
+
uses: astral-sh/setup-uv@v6
|
|
26
|
+
with:
|
|
27
|
+
enable-cache: true
|
|
28
|
+
|
|
29
|
+
- name: Installer les dépendances
|
|
30
|
+
run: uv sync --group dev
|
|
31
|
+
|
|
32
|
+
- name: Lint (ruff)
|
|
33
|
+
run: |
|
|
34
|
+
uv run ruff check .
|
|
35
|
+
uv run ruff format --check .
|
|
36
|
+
|
|
37
|
+
- name: Types (mypy)
|
|
38
|
+
run: uv run mypy
|
|
39
|
+
|
|
40
|
+
- name: Tests (pytest)
|
|
41
|
+
run: uv run pytest
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Environnements et caches Python
|
|
2
|
+
.venv/
|
|
3
|
+
__pycache__/
|
|
4
|
+
*.py[cod]
|
|
5
|
+
.pytest_cache/
|
|
6
|
+
.ruff_cache/
|
|
7
|
+
.mypy_cache/
|
|
8
|
+
.coverage
|
|
9
|
+
htmlcov/
|
|
10
|
+
|
|
11
|
+
# Build / distribution
|
|
12
|
+
dist/
|
|
13
|
+
build/
|
|
14
|
+
*.egg-info/
|
|
15
|
+
|
|
16
|
+
# Sorties de l'outil pendant les essais
|
|
17
|
+
sorties/
|
|
18
|
+
*_analyse_crs*.html
|
|
19
|
+
*_journal.json
|
|
20
|
+
|
|
21
|
+
# IDE / OS
|
|
22
|
+
.vscode/
|
|
23
|
+
.idea/
|
|
24
|
+
Thumbs.db
|
|
25
|
+
.DS_Store
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "Si vous utilisez cet outil dans un travail ou une publication, merci de le citer ainsi."
|
|
3
|
+
type: software
|
|
4
|
+
title: "crs-zone-toolkit : analyse, recommandation et reprojection CRS pour les couches géospatiales du Québec"
|
|
5
|
+
authors:
|
|
6
|
+
- family-names: Moussahoudou
|
|
7
|
+
given-names: Issa
|
|
8
|
+
email: imoussahoudou@gmail.com
|
|
9
|
+
version: 0.1.0
|
|
10
|
+
date-released: "2026-08-02"
|
|
11
|
+
license: MIT
|
|
12
|
+
repository-code: "https://github.com/MascotteIssa/crs-zone-toolkit"
|
|
13
|
+
identifiers:
|
|
14
|
+
- type: doi
|
|
15
|
+
value: 10.5281/zenodo.21956685
|
|
16
|
+
keywords:
|
|
17
|
+
- gis
|
|
18
|
+
- crs
|
|
19
|
+
- epsg
|
|
20
|
+
- mtm
|
|
21
|
+
- quebec
|
|
22
|
+
- reprojection
|
|
23
|
+
- geopandas
|
|
24
|
+
abstract: >-
|
|
25
|
+
Outil en ligne de commande (crszone) qui analyse une couche géospatiale,
|
|
26
|
+
mesure la distorsion des projections candidates du profil régional (fuseaux
|
|
27
|
+
MTM et Québec Lambert pour le Québec), recommande la projection la moins
|
|
28
|
+
déformée avec sa justification chiffrée, et applique la reprojection ou le
|
|
29
|
+
découpage par fuseau avec un journal de décision traçable.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Issa Moussahoudou
|
|
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.
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: crs-zone-toolkit
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Analyse, recommandation et reprojection CRS pour les couches géospatiales du Québec (fuseaux MTM, Québec Lambert)
|
|
5
|
+
Project-URL: Homepage, https://github.com/MascotteIssa/crs-zone-toolkit
|
|
6
|
+
Project-URL: Repository, https://github.com/MascotteIssa/crs-zone-toolkit
|
|
7
|
+
Project-URL: Documentation, https://github.com/MascotteIssa/crs-zone-toolkit/blob/main/QUICKSTART.md
|
|
8
|
+
Project-URL: Issues, https://github.com/MascotteIssa/crs-zone-toolkit/issues
|
|
9
|
+
Author-email: Issa Moussahoudou <imoussahoudou@gmail.com>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: crs,epsg,geopandas,gis,mtm,quebec,reprojection
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Classifier: Natural Language :: French
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.11
|
|
25
|
+
Requires-Dist: geopandas>=1.0
|
|
26
|
+
Requires-Dist: jinja2>=3.1
|
|
27
|
+
Requires-Dist: matplotlib>=3.8
|
|
28
|
+
Requires-Dist: pyogrio>=0.8
|
|
29
|
+
Requires-Dist: pyproj>=3.6
|
|
30
|
+
Requires-Dist: rich>=13.0
|
|
31
|
+
Requires-Dist: shapely>=2.0
|
|
32
|
+
Requires-Dist: typer>=0.12
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# crs-zone-toolkit
|
|
36
|
+
|
|
37
|
+
[](https://github.com/MascotteIssa/crs-zone-toolkit/actions/workflows/ci.yml)
|
|
38
|
+
[](https://pypi.org/project/crs-zone-toolkit/)
|
|
39
|
+
[](https://pypi.org/project/crs-zone-toolkit/)
|
|
40
|
+
[](https://github.com/MascotteIssa/crs-zone-toolkit/blob/main/LICENSE)
|
|
41
|
+
[](https://doi.org/10.5281/zenodo.21956685)
|
|
42
|
+
|
|
43
|
+
**Quel système de coordonnées pour ma couche québécoise ?** `crszone` répond avec des
|
|
44
|
+
chiffres : il mesure la distorsion réellement encourue par chaque candidat, **recommande**
|
|
45
|
+
la projection la moins déformante — fuseau **MTM** ou **Québec Lambert** — et **reprojette**
|
|
46
|
+
si vous le lui demandez. L'outil recommande ; vous décidez.
|
|
47
|
+
|
|
48
|
+

|
|
49
|
+
|
|
50
|
+
## Pourquoi pas simplement `estimate_utm_crs()` ?
|
|
51
|
+
|
|
52
|
+
L'utilitaire de GeoPandas ne connaît que l'**UTM**. Il ignore les fuseaux **MTM** du Québec,
|
|
53
|
+
larges de 3° au lieu de 6° — et comme la distorsion croît avec le *carré* de l'écart au
|
|
54
|
+
méridien central, cette moitié de largeur vaut **quatre fois moins de distorsion** : aux
|
|
55
|
+
latitudes habitées du Québec, un fuseau MTM tient dans −100 à +72 ppm là où l'UTM s'étale
|
|
56
|
+
de −400 à +287 ppm. Il ignore aussi le **Québec Lambert**, et les familles de datum
|
|
57
|
+
canadiennes — NAD83 d'origine, NAD83(CSRS), NAD27 — qu'il ne faut jamais franchir en
|
|
58
|
+
silence. Il ne mesure aucune distorsion, ne justifie rien, et ne produit ni rapport, ni
|
|
59
|
+
découpage multi-fuseaux, ni journal de décision.
|
|
60
|
+
|
|
61
|
+
`crszone` fait exactement cela, et rien d'autre.
|
|
62
|
+
|
|
63
|
+
## Installation
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
pip install crs-zone-toolkit
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
uv tool install crs-zone-toolkit # commande isolée, disponible partout
|
|
71
|
+
uvx crs-zone-toolkit analyze ma_couche.gpkg # sans rien installer
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Python 3.11 ou plus. Aucune donnée de référence à télécharger : la grille des fuseaux, la
|
|
75
|
+
limite du Québec et le profil géodésique voyagent **dans le paquet**.
|
|
76
|
+
|
|
77
|
+
## En trente secondes
|
|
78
|
+
|
|
79
|
+
<!-- extrait:debut -->
|
|
80
|
+
```console
|
|
81
|
+
$ crszone --region qc analyze regio_s.shp
|
|
82
|
+
Analyse CRS : profil Québec (qc) crszone 0.1.0
|
|
83
|
+
───────────────────────────────────────────────────────────────────────────────────────────────────
|
|
84
|
+
Couche regio_s.shp (21 entités, polygones)
|
|
85
|
+
CRS déclaré EPSG:4269, NAD83 (géographique)
|
|
86
|
+
Emprise 79,77°O → 56,93°O · 44,99°N → 62,58°N
|
|
87
|
+
|
|
88
|
+
Répartition par fuseau MTM (part de la surface totale)
|
|
89
|
+
Fuseau 8 (MC −73,5°) ████ 22,2 %
|
|
90
|
+
Fuseau 9 (MC −76,5°) ████ 19,9 %
|
|
91
|
+
Fuseau 7 (MC −70,5°) ████ 19,3 %
|
|
92
|
+
Fuseau 6 (MC −67,5°) ███ 12,8 %
|
|
93
|
+
Fuseau 5 (MC −64,5°) ██ 10,0 %
|
|
94
|
+
Fuseau 4 (MC −61,5°) █ 7,4 %
|
|
95
|
+
Fuseau 10 (MC −79,5°) █ 5,4 %
|
|
96
|
+
Fuseau 3 (MC −58,5°) █ 3,0 %
|
|
97
|
+
Fuseau 2 (MC −56,0°) 0,0 %
|
|
98
|
+
|
|
99
|
+
Distorsion mesurée (187 points d'échantillonnage)
|
|
100
|
+
Candidat min moy max
|
|
101
|
+
MTM fuseau 8 (tout) EPSG:32188 −100 ppm +1564 ppm +14784 ppm ⚠ hors seuil
|
|
102
|
+
Québec Lambert EPSG:32198 −7458 ppm −2814 ppm +2149 ppm ⚠ hors seuil
|
|
103
|
+
|
|
104
|
+
→ Recommandation : reprojeter vers Québec Lambert (EPSG:32198, NAD83 d'origine)
|
|
105
|
+
Motif : Les données sont trop étendues pour le fuseau dominant (MTM 8 : 14784 ppm) : le Québec
|
|
106
|
+
Lambert est la projection unique la moins déformée (7458 ppm max). Découpage disponible en
|
|
107
|
+
alternative.
|
|
108
|
+
✓ Datum : entrée NAD83 d'origine → famille préservée (EPSG:32198).
|
|
109
|
+
Note : NAD83(CSRS) est le standard actuel des données québécoises (écart ≈ 1 m).
|
|
110
|
+
|
|
111
|
+
Alternative : découpage par fuseau (6 sorties, entités affectées au fuseau majoritaire).
|
|
112
|
+
|
|
113
|
+
✓ Rapport détaillé : regio_s_analyse_crs_20260728-130842.html
|
|
114
|
+
Pour appliquer : crszone apply regio_s.shp
|
|
115
|
+
```
|
|
116
|
+
<!-- extrait:fin -->
|
|
117
|
+
|
|
118
|
+
Puis, quand vous êtes d'accord :
|
|
119
|
+
|
|
120
|
+
<!-- apply:debut -->
|
|
121
|
+
```console
|
|
122
|
+
$ crszone apply montreal.gpkg --out sorties --auto
|
|
123
|
+
Analyse CRS : profil Québec (qc) crszone 0.1.0
|
|
124
|
+
───────────────────────────────────────────────────────────────────────────────────────────────────
|
|
125
|
+
Couche montreal.gpkg (1 entité, polygones)
|
|
126
|
+
CRS déclaré EPSG:4269, NAD83 (géographique)
|
|
127
|
+
Emprise 74,00°O → 73,47°O · 45,39°N → 45,71°N
|
|
128
|
+
|
|
129
|
+
→ Recommandation : reprojeter vers MTM fuseau 8 (EPSG:32188, NAD83 d'origine)
|
|
130
|
+
Motif : Les données tiennent dans un seul fuseau (MTM 8).
|
|
131
|
+
✓ Datum : entrée NAD83 d'origine → famille préservée (EPSG:32188).
|
|
132
|
+
Note : NAD83(CSRS) est le standard actuel des données québécoises (écart ≈ 1 m).
|
|
133
|
+
|
|
134
|
+
Mode --auto : application de la recommandation (MTM fuseau 8, EPSG:32188).
|
|
135
|
+
✓ Sortie : sorties\montreal_epsg32188.gpkg (EPSG:32188, 1 entité)
|
|
136
|
+
✓ Journal : sorties\montreal_journal.json
|
|
137
|
+
Pipeline PROJ : axis order change (2D) + MTM zone 8
|
|
138
|
+
```
|
|
139
|
+
<!-- apply:fin -->
|
|
140
|
+
|
|
141
|
+
Le **pipeline PROJ exact** est affiché puis journalisé : la transformation appliquée est
|
|
142
|
+
vérifiable, pas devinée. Démarrage complet : **[QUICKSTART.md](https://github.com/MascotteIssa/crs-zone-toolkit/blob/main/QUICKSTART.md)**.
|
|
143
|
+
|
|
144
|
+
## La règle de recommandation, en deux lignes
|
|
145
|
+
|
|
146
|
+
> **Un seul fuseau traversé → ce fuseau.** Plusieurs fuseaux → la **projection unique la
|
|
147
|
+
> moins déformée** entre le fuseau dominant et le Québec Lambert (le fuseau l'emporte à
|
|
148
|
+
> égalité). Le **découpage** par fuseau est toujours offert en alternative, jamais imposé.
|
|
149
|
+
|
|
150
|
+
Cette règle n'est pas une intuition : elle a été **calibrée sur données réelles**, le
|
|
151
|
+
jugement d'expertise servant d'étalon. La règle précédente gatait sur la part du fuseau
|
|
152
|
+
dominant *avant* de regarder la distorsion, et recommandait de ce fait la projection **la
|
|
153
|
+
plus déformée** pour les régions compactes — le Bas-Saint-Laurent mesure 407 ppm en MTM 6
|
|
154
|
+
contre 5106 ppm en Québec Lambert. Méthodologie, balayage et décision :
|
|
155
|
+
[`docs/calibrage/`](https://github.com/MascotteIssa/crs-zone-toolkit/blob/main/docs/calibrage/2026-07-19-calibrage-seuils.md) · formalisation :
|
|
156
|
+
[SPEC §4.3](https://github.com/MascotteIssa/crs-zone-toolkit/blob/main/docs/SPEC.md).
|
|
157
|
+
|
|
158
|
+
## Le rapport HTML
|
|
159
|
+
|
|
160
|
+
Chaque `analyze` écrit un rapport **autonome** : un seul fichier, aucune ressource externe,
|
|
161
|
+
carte et styles embarqués. Il s'ouvre hors ligne, s'archive, se joint à un courriel — et
|
|
162
|
+
suit le thème clair ou sombre de votre système, avec un bouton pour basculer.
|
|
163
|
+
|
|
164
|
+
<picture>
|
|
165
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/MascotteIssa/crs-zone-toolkit/main/docs/images/rapport-sombre.png">
|
|
166
|
+
<img alt="Rapport HTML : verdict en tête, couche analysée, situation dans les fuseaux MTM" src="https://raw.githubusercontent.com/MascotteIssa/crs-zone-toolkit/main/docs/images/rapport-clair.png">
|
|
167
|
+
</picture>
|
|
168
|
+
|
|
169
|
+
L'élément central est l'échelle de distorsion, **divergente et centrée sur 0 ppm**, qui
|
|
170
|
+
rend le compromis visible d'un coup d'œil — ici, la couche des 21 régions administratives,
|
|
171
|
+
trop étendue pour tout fuseau MTM. La cible sort en `EPSG:32198` parce que cette donnée est
|
|
172
|
+
en **NAD83 d'origine** : la famille d'entrée est préservée. Sur une entrée en NAD83(CSRS),
|
|
173
|
+
le standard actuel, le Québec Lambert visé serait `EPSG:6622`.
|
|
174
|
+
|
|
175
|
+
<picture>
|
|
176
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/MascotteIssa/crs-zone-toolkit/main/docs/images/rapport-distorsion-sombre.png">
|
|
177
|
+
<img alt="Échelle de distorsion divergente comparant MTM fuseau 8 et Québec Lambert" src="https://raw.githubusercontent.com/MascotteIssa/crs-zone-toolkit/main/docs/images/rapport-distorsion-clair.png">
|
|
178
|
+
</picture>
|
|
179
|
+
|
|
180
|
+
**[Ouvrir un rapport réel](https://raw.githubusercontent.com/MascotteIssa/crs-zone-toolkit/main/docs/exemple_rapport.html)** *(clic droit → enregistrer, puis
|
|
181
|
+
ouvrir dans un navigateur — GitHub n'exécute pas le HTML des dépôts).*
|
|
182
|
+
|
|
183
|
+
## Pour un script
|
|
184
|
+
|
|
185
|
+
`--json` écrit le résultat sur la sortie standard, le résumé humain sur l'erreur standard :
|
|
186
|
+
|
|
187
|
+
```console
|
|
188
|
+
$ crszone analyze montreal.gpkg --json | jq .recommandation
|
|
189
|
+
{
|
|
190
|
+
"action": "zone",
|
|
191
|
+
"cible_epsg": 32188,
|
|
192
|
+
"cible_libelle": "MTM fuseau 8",
|
|
193
|
+
"motif_code": "mono_zone",
|
|
194
|
+
"motif": "Les données tiennent dans un seul fuseau (MTM 8).",
|
|
195
|
+
"alternatives": []
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Le contrat est **versionné** (`schema_version`) et validé par un schéma JSON Schema dans la
|
|
200
|
+
suite de tests. L'API Python (`analyze`, `apply`, `report`) est typée et livre son marqueur
|
|
201
|
+
[PEP 561](https://peps.python.org/pep-0561/).
|
|
202
|
+
|
|
203
|
+
Codes de sortie : `0` succès · `1` erreur de données · `2` refus explicite (CRS absent,
|
|
204
|
+
sortie existante, non interactif sans choix).
|
|
205
|
+
|
|
206
|
+
> **Windows / PowerShell — préférez `--json-out` à `>`.** La redirection `>` de PowerShell
|
|
207
|
+
> ne transmet pas les octets du programme : elle les **décode** d'abord avec
|
|
208
|
+
> `[Console]::OutputEncoding`, puis les **réécrit** dans son propre encodage. Sur une console
|
|
209
|
+
> française laissée en cp850/cp1252, l'UTF-8 émis par `crszone` est mal décodé (`donn├®es`) —
|
|
210
|
+
> et PowerShell 5.1 écrit ensuite le fichier en **UTF-16LE**, pas en UTF-8. Le résultat est
|
|
211
|
+
> illisible pour la plupart des outils.
|
|
212
|
+
>
|
|
213
|
+
> **L'outil n'y est pour rien** : il émet bien de l'UTF-8 sur ses flux (DT-15), et le tuyau
|
|
214
|
+
> (`|`) passe sans dommage. Le remède tient en un mot : laissez `crszone` écrire le fichier
|
|
215
|
+
> lui-même, avec **`--json-out`** pour le JSON et **`--report`** pour le rapport HTML.
|
|
216
|
+
>
|
|
217
|
+
> Si vous tenez à rediriger, corrigez d'abord le décodage —
|
|
218
|
+
> `[Console]::OutputEncoding = [Text.Encoding]::UTF8` — puis écrivez avec
|
|
219
|
+
> `| Out-File -Encoding utf8`. *(Vérifié dans les deux sens : console en cp850 → fichier
|
|
220
|
+
> corrompu ; console en UTF-8 → fichier valide.)*
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
## Ce que l'outil ne fait pas
|
|
224
|
+
|
|
225
|
+
Il ne change **jamais** de famille de datum en silence : une transformation approximative
|
|
226
|
+
est soit refusée, soit exécutée avec un avertissement journalisé (NAD27 exige la grille
|
|
227
|
+
NTv2). Il ne recommande rien pour les données tombant hors du Québec — il le signale. Il
|
|
228
|
+
n'écrase aucun fichier sans `--overwrite`. Il ne produit ni PDF, ni sortie texte, et
|
|
229
|
+
n'accède **à aucun réseau**, ni à l'exécution ni dans ses tests.
|
|
230
|
+
|
|
231
|
+
Il n'est pas conçu pour les très gros volumes : le traitement est **en mémoire** et l'outil
|
|
232
|
+
vise des couches de l'ordre de 10⁴ à 10⁵ entités (12 580 lignes s'analysent en 6,1 s).
|
|
233
|
+
L'échantillonnage de distorsion est plafonné, mais la répartition par fuseau et le
|
|
234
|
+
découpage croissent avec le nombre d'entités : au-delà, prévoyez de découper la couche en
|
|
235
|
+
amont.
|
|
236
|
+
|
|
237
|
+
Le périmètre V1 est le Québec. Le noyau ne connaît aucun code EPSG : tous les faits
|
|
238
|
+
géodésiques viennent d'un **profil de région** (`regions/qc/`), ce que verrouille un test
|
|
239
|
+
dédié. C'est ce qui rendra possible l'extension au reste du Canada, puis ailleurs
|
|
240
|
+
([feuille de route](https://github.com/MascotteIssa/crs-zone-toolkit/blob/main/docs/feuille_de_route.md)).
|
|
241
|
+
|
|
242
|
+
## Documentation
|
|
243
|
+
|
|
244
|
+
| Document | Rôle |
|
|
245
|
+
|---|---|
|
|
246
|
+
| [`QUICKSTART.md`](https://github.com/MascotteIssa/crs-zone-toolkit/blob/main/QUICKSTART.md) | Les trois commandes, options utiles, garde-fous |
|
|
247
|
+
| [`docs/SPEC.md`](https://github.com/MascotteIssa/crs-zone-toolkit/blob/main/docs/SPEC.md) | Cahier des charges fonctionnel V1 |
|
|
248
|
+
| [`docs/DATA_REFERENCE.md`](https://github.com/MascotteIssa/crs-zone-toolkit/blob/main/docs/DATA_REFERENCE.md) | Source de vérité géodésique (codes EPSG vérifiés) |
|
|
249
|
+
| [`docs/calibrage/`](https://github.com/MascotteIssa/crs-zone-toolkit/blob/main/docs/calibrage/2026-07-19-calibrage-seuils.md) | Calibrage de la règle de décision sur données réelles |
|
|
250
|
+
| [`docs/ARCHITECTURE.md`](https://github.com/MascotteIssa/crs-zone-toolkit/blob/main/docs/ARCHITECTURE.md) | Noyau + adaptateurs, lois de dépendance, API |
|
|
251
|
+
| [`docs/CLI_UX.md`](https://github.com/MascotteIssa/crs-zone-toolkit/blob/main/docs/CLI_UX.md) | Maquette du flux terminal |
|
|
252
|
+
| [`docs/TEST_PLAN.md`](https://github.com/MascotteIssa/crs-zone-toolkit/blob/main/docs/TEST_PLAN.md) | Jeux de test et protocole de calibrage |
|
|
253
|
+
| [`docs/feuille_de_route.md`](https://github.com/MascotteIssa/crs-zone-toolkit/blob/main/docs/feuille_de_route.md) | Évolutions (Québec → Canada → international) |
|
|
254
|
+
| [`docs/references.md`](https://github.com/MascotteIssa/crs-zone-toolkit/blob/main/docs/references.md) | Bibliographie (APA 7) — toute décision est sourcée |
|
|
255
|
+
|
|
256
|
+
Les sigles `DT-xx` et `N-xx` cités au fil de ces pages sont les identifiants du registre de
|
|
257
|
+
dette technique et des observations du test manuel, tenus au dépôt de développement et non
|
|
258
|
+
publiés.
|
|
259
|
+
|
|
260
|
+
## Attributions
|
|
261
|
+
|
|
262
|
+
- **Codes EPSG** : registre EPSG (IOGP) via epsg.org / epsg.io ; usage québécois d'après
|
|
263
|
+
MERN/MRNF, *Codes EPSG des projections utilisées au Québec*, décembre 2020.
|
|
264
|
+
- **Grille des fuseaux et limite du Québec** : découpées d'après MRNF, *Découpages
|
|
265
|
+
administratifs*, Données Québec, licence **CC-BY 4.0**. Les captures et le rapport
|
|
266
|
+
d'exemple de ce README sont dérivés du même jeu.
|
|
267
|
+
|
|
268
|
+
## English summary
|
|
269
|
+
|
|
270
|
+
`crs-zone-toolkit` helps you choose a metric projection before spatial analysis in
|
|
271
|
+
Québec, Canada: it reports which MTM zones your data spans, measures the actual
|
|
272
|
+
distortion of each candidate CRS with `pyproj`, recommends the least-distorted single
|
|
273
|
+
projection, and reprojects or splits your layer with a full decision log. Unlike a
|
|
274
|
+
plain UTM guess, every recommendation comes with measured evidence and a self-contained
|
|
275
|
+
HTML report. **The command line, reports and documentation are in French.**
|
|
276
|
+
|
|
277
|
+
## Licence
|
|
278
|
+
|
|
279
|
+
MIT — voir [`LICENSE`](https://github.com/MascotteIssa/crs-zone-toolkit/blob/main/LICENSE). © 2026 Issa Moussahoudou.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# crszone — démarrage rapide
|
|
2
|
+
|
|
3
|
+
`crszone` analyse une couche vectorielle, **recommande** un système de coordonnées
|
|
4
|
+
adapté au Québec (fuseau MTM ou Québec Lambert), et **reprojette** sur demande.
|
|
5
|
+
L'outil recommande ; **vous décidez** (rien n'est reprojeté sans votre accord).
|
|
6
|
+
|
|
7
|
+
> Exemples préfixés `uv run` (environnement de développement). Après installation du
|
|
8
|
+
> paquet, la commande s'appelle directement `crszone`.
|
|
9
|
+
|
|
10
|
+
## Les 3 commandes
|
|
11
|
+
|
|
12
|
+
### 1. Analyser (lecture seule) — que faire de ma couche ?
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
uv run crszone analyze chemin/vers/couche.gpkg
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Affiche : CRS déclaré, emprise, répartition par fuseau MTM, distorsion des candidats,
|
|
19
|
+
et une **recommandation chiffrée**. Écrit aussi un rapport HTML autonome à côté de la couche.
|
|
20
|
+
|
|
21
|
+
Options utiles :
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# CRS non déclaré par le fichier ? Assignez-le (n'altère pas les coordonnées) :
|
|
25
|
+
uv run crszone analyze couche.shp --assume-crs EPSG:4269
|
|
26
|
+
|
|
27
|
+
# Rapport HTML dans un dossier précis :
|
|
28
|
+
uv run crszone analyze couche.gpkg --report dossier/rapports
|
|
29
|
+
|
|
30
|
+
# Sortie JSON pure (pour un script) — le résumé humain part sur stderr :
|
|
31
|
+
uv run crszone analyze couche.gpkg --json > resultat.json
|
|
32
|
+
uv run crszone analyze couche.gpkg --json-out resultat.json # écrit en UTF-8 garanti
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 2. Appliquer — reprojeter ou découper
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Interactif : l'outil propose, vous choisissez au menu
|
|
39
|
+
uv run crszone apply couche.gpkg --out dossier/sorties
|
|
40
|
+
|
|
41
|
+
# Non interactif : appliquer directement la recommandation
|
|
42
|
+
uv run crszone apply couche.gpkg --out dossier/sorties --auto
|
|
43
|
+
|
|
44
|
+
# Forcer un choix précis :
|
|
45
|
+
uv run crszone apply couche.gpkg --choice lambert # Québec Lambert
|
|
46
|
+
uv run crszone apply couche.gpkg --choice zone --zone 8 # fuseau MTM 8
|
|
47
|
+
uv run crszone apply couche.gpkg --choice split # un fichier par fuseau
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Chaque exécution écrit la ou les couches reprojetées **plus** un journal
|
|
51
|
+
`<nom>_journal.json` (pipeline PROJ exact appliqué, décision, avertissements).
|
|
52
|
+
|
|
53
|
+
Options : `--format gpkg|geojson|shp` · `--overwrite` (écraser une sortie existante) ·
|
|
54
|
+
`--assume-crs EPSG:xxxx` · `--json` / `--json-out`.
|
|
55
|
+
|
|
56
|
+
### 3. Générer la grille des fuseaux MTM (repère visuel)
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
uv run crszone grid --out grille_qc.geojson
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Lire la recommandation
|
|
63
|
+
|
|
64
|
+
L'outil recommande **la projection unique la moins déformée** entre le fuseau dominant
|
|
65
|
+
et le Québec Lambert (règle « distorsion d'abord », SPEC §4.3) :
|
|
66
|
+
|
|
67
|
+
| Motif | Sens | Que faire |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| `mono_zone` | données dans un seul fuseau | prenez ce fuseau MTM |
|
|
70
|
+
| `zone_dominante` | fuseau dominant, distorsion sous tolérance | prenez ce fuseau MTM (1 fichier) |
|
|
71
|
+
| `zone_moins_deformee` | fuseau dominant = le moins déformé, mais au-delà de la tolérance | fuseau MTM (1 fichier) **ou** découpez pour rester sous le seuil |
|
|
72
|
+
| `lambert_moins_deforme` | données trop étendues (province, grand nord) | prenez le Québec Lambert |
|
|
73
|
+
|
|
74
|
+
Le **découpage** est toujours proposé en alternative (un fichier par fuseau, distorsion
|
|
75
|
+
minimale) — utile si vous traiterez chaque morceau séparément, moins pratique pour garder
|
|
76
|
+
un fichier unique.
|
|
77
|
+
|
|
78
|
+
## Garde-fous à connaître
|
|
79
|
+
|
|
80
|
+
- **Pas de CRS déclaré** → l'outil refuse (sortie 2) et explique : relancez avec
|
|
81
|
+
`--assume-crs EPSG:xxxx` (assigne une étiquette, ne convertit rien).
|
|
82
|
+
- **Sortie déjà existante** → `apply` refuse d'écraser sans `--overwrite`.
|
|
83
|
+
- **Familles de datum préservées** : entrée NAD83 d'origine → cibles NAD83 ; entrée
|
|
84
|
+
WGS84 ou CRS non qualifié → CSRS par défaut ; jamais de changement de datum silencieux.
|
|
85
|
+
- **Windows / PowerShell** : n'utilisez pas `> fichier.json`. PowerShell décode la sortie
|
|
86
|
+
avec `[Console]::OutputEncoding` (souvent cp850 en français) puis la réécrit en UTF-16LE :
|
|
87
|
+
le fichier ressort en charabia. Utilisez **`--json-out`** et **`--report`**, qui font écrire
|
|
88
|
+
le fichier par l'outil lui-même. Le tuyau (`|`), lui, passe sans dommage.
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
## Codes de sortie
|
|
92
|
+
|
|
93
|
+
`0` succès · `1` erreur de données (fichier illisible, couche vide, région inconnue) ·
|
|
94
|
+
`2` refus explicite (CRS absent, sortie existante, non-interactif sans choix).
|
|
95
|
+
|
|
96
|
+
Aide complète : `uv run crszone --help`, `uv run crszone analyze --help`, etc.
|