BikeControl (SwiftControl)
使用 Zwift Click、Zwift Play、Shimano Di2 或任何藍牙控制器,搭配 MyWhoosh、Rouvy、Zwift 等。iOS、Android、Windows、macOS 均可免費試用。
AI 翻译
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证制作者的介绍仅有上面的一句话。 更多详情请阅读仓库 README。 仓库 README ↗
正在加载完整 README。
查看完整 README ↗Application web locale qui répartit les 36 équipes de PNM Grand Est en 3 poules de 12 en minimisant les déplacements (matchs aller-retour : chaque équipe reçoit et se déplace chez chacune des 11 autres équipes de sa poule).
static/vendor)./run.sh # Linux / macOS
run.bat # Windows
Alternatives si les dépendances sont déjà installées (pip install -r requirements.txt) :
uvicorn app.main:app --port 8000 ou fastapi run app/main.py.
Le script crée un environnement virtuel .venv, installe les dépendances (Python 3.10 ou plus),
démarre le serveur et ouvre http://127.0.0.1:8000/.
Les kilomètres s'affichent dès l'ouverture : l'application part des positions approximatives des
communes livrées dans data/communes.json, puis les affine en arrière-plan avec Nominatim (environ 40 s
au premier lancement, une requête par seconde) et calcule la version optimale. La progression s'affiche
en haut à droite. La version optimale est calculée dans la foulée (une quinzaine de secondes) et devient alors
cliquable. Une équipe sans localisation ne bloque rien : elle est signalée et compte 0 km tant qu'on
n'a pas indiqué sa salle dans l'onglet Géocodage.
L'écran principal reste simple : un tableau compare, pour chaque poule et au total, les km des rencontres aller-retour des trois répartitions (poules actuelles, version optimale, Ma version), avec l'écart par rapport aux poules actuelles. Le lien « rencontres » d'une poule détaille chaque paire d'équipes (distance et km des deux rencontres). Viennent ensuite la carte et les trois poules avec les km de chaque équipe. Le reste est rangé dans « Outils avancés ».
L'application fonctionne aussi sur Vercel (projet relié au dépôt GitHub). Elle détecte automatiquement l'environnement serverless et s'y adapte :
/tmp/pnmap (temporaire) ;data/communes.json et des
adresses du CSV, et les distances routières sont demandées à OSRM pendant la requête
(quelques secondes, puis gardées en mémoire tant que l'instance vit) ;vercel.json autorise 60 s par requête pour laisser le temps au calcul.Sur Vercel, les corrections faites dans l'onglet Géocodage ne sont pas conservées d'une instance
à l'autre : pour une correction durable, renseigner commune_geocodage ou adresse_salle dans
data/clubs.csv.
Trois versions côte à côte, toujours disponibles :
clubs.csv ;cache/optimal.json), recalculable avec le bouton Optimiser. Elle reste la référence, avec son
kilométrage total et son statut (« optimale prouvée » ou « meilleure trouvée », écart à la borne) ;Chaque carte de version indique ses km cumulés, l'écart en km et en % avec les deux autres, et les km par poule.
Carte OpenStreetMap
Fiche club (double-clic) : un double-clic sur une équipe (dans sa poule ou sur la carte) ouvre sa
fiche pour changer son nom ou l'adresse de sa salle. La nouvelle adresse est géocodée, les distances
routières et la version optimale sont recalculées. Ces modifications sont enregistrées dans le navigateur
(« Revenir aux données d'origine » les annule) et reprises dans les exports. Pour les rendre définitives
pour tout le monde, les reporter dans data/clubs.csv.
Modifier Ma version
Réglages de l'optimisation : critère distance (km) ou durée (heures) ; nombre d'équipes par poule (12 par défaut) ; équipes d'un même club séparées ; stabilité (pénalité en km, ou en minutes, par équipe qui change de poule) ; équité (curseur entre « total des km » et « pire équipe ») ; limite de temps (30 s par défaut) ; paires imposées (même poule) ou interdites.
Exports de la version choisie :
cache/tiles, ou fond neutre hors ligne), poules et km par équipe, matrices des distances ;Liste les équipes non géolocalisées (échec Nominatim, commune vide) et celles marquées
a_verifier = oui. Pour chacune :
Les corrections sont enregistrées dans data/corrections.json (à conserver) et la matrice est
recalculée automatiquement.
Distances (km) ou durées (minutes) aller simple, triées par poule affichée.
Variables : x[t,p] = 1 si l'équipe t est dans la poule p (une poule par équipe).
Coût saison d'une équipe i : somme, sur les adversaires j de sa poule, de l'aller-retour
r_ij = d(i→j) + d(j→i). Le total minimisé est la somme des coûts saison de toutes les équipes,
soit 2 × la somme, sur les paires d'une même poule, de la distance aller-retour.
Objectif : (1 − a) × total + a × N × max_i(coût_i) + pénalité_stabilité × nb_changements,
avec a le curseur d'équité (0 = total seul, 1 = pire cas seul) et N le nombre d'équipes.
Contraintes : taille exacte de chaque poule, équipes d'un même club séparées (le club est le nom
FFBB sans le suffixe « - 1 », « - 2 » ; une colonne club facultative dans le CSV le remplace),
verrous, paires interdites ou imposées. Une contrainte de renforcement (chaque équipe de la poule
p y a exactement taille − 1 partenaires) permet à CP-SAT de prouver l'optimalité en une
quinzaine de secondes sur les 36 équipes. Quand les étiquettes de poules sont interchangeables
(pas de verrou ni de stabilité), les poules trouvées sont renommées pour coller au mieux aux
poules actuelles.
| Fichier | Rôle |
|---|---|
data/clubs.csv | équipes (id, club_ffbb, poule_actuelle, commune_geocodage, a_verifier, et adresse_salle facultative : si elle est remplie, c'est elle qui est géocodée) |
data/communes.json | positions approximatives des communes, utilisées tant que Nominatim n'a pas répondu |
data/corrections.json | positions corrigées ou validées dans l'écran Géocodage |
cache/geocode.json | cache Nominatim (les échecs sont aussi mis en cache ; « Relancer le géocodage » les retente) |
cache/matrix.json | cache OSRM par paire de points (un point déplacé ne recalcule que ce qui manque) |
cache/optimal.json | version optimale de référence (recalculée si la matrice change) |
cache/tiles/ | tuiles OpenStreetMap utilisées pour la carte du PDF |
cache/ui_state.json | Ma version, historique, verrous, paires, réglages, version affichée |
Supprimer le dossier cache/ force un nouveau géocodage et un nouveau calcul de matrice.
| Variable | Défaut |
|---|---|
PORT (scripts de lancement) | 8000 |
PNMAP_CLUBS_CSV | data/clubs.csv |
PNMAP_CORRECTIONS | data/corrections.json |
PNMAP_CACHE_DIR | cache |
PNMAP_NOMINATIM_URL | https://nominatim.openstreetmap.org |
PNMAP_OSRM_URL | https://router.project-osrm.org |
PNMAP_TILE_URL | https://tile.openstreetmap.org/{z}/{x}/{y}.png (fond de carte du PDF) |
PNMAP_USER_AGENT | PNMap/1.0 (...) : à personnaliser avec un contact, comme le demande la politique Nominatim |
Le serveur public de démonstration OSRM suffit pour 36 équipes (une seule requête table, mise
en cache). Pour ne pas en dépendre :
mkdir osrm && cd osrm
# Extraits Geofabrik des trois anciennes régions, fusionnés avec osmium-tool
wget https://download.geofabrik.de/europe/france/alsace-latest.osm.pbf \
https://download.geofabrik.de/europe/france/lorraine-latest.osm.pbf \
https://download.geofabrik.de/europe/france/champagne-ardenne-latest.osm.pbf
osmium merge alsace-latest.osm.pbf lorraine-latest.osm.pbf champagne-ardenne-latest.osm.pbf -o grand-est.osm.pbf
IMG=ghcr.io/project-osrm/osrm-backend
docker run -t -v "$PWD:/data" $IMG osrm-extract -p /opt/car.lua /data/grand-est.osm.pbf
docker run -t -v "$PWD:/data" $IMG osrm-partition /data/grand-est.osrm
docker run -t -v "$PWD:/data" $IMG osrm-customize /data/grand-est.osrm
docker run -d -p 5000:5000 -v "$PWD:/data" $IMG osrm-routed --algorithm mld /data/grand-est.osrm
cd .. && PNMAP_OSRM_URL=http://localhost:5000 ./run.sh
Puis bouton « Recalculer la matrice (OSRM) » dans l'onglet Géocodage. Si OSRM est indisponible, l'application bascule sur la distance haversine × 1,3 (durée estimée à 80 km/h) et l'indique dans la barre de statut ; ces valeurs de repli ne sont pas mises en cache.
.venv/bin/python -m pytest # ou : python -m pytest
tests/test_optimizer.py : jeu de 6 équipes (Strasbourg, Colmar, Mulhouse / Reims, Châlons,
Troyes) dont la solution est connue, contrôle par énumération exhaustive, verrous, paires,
clubs, stabilité, équité, critère durée, cas infaisables.tests/test_api.py : géocodage, OSRM et tuiles simulés (aucun accès réseau), cache, écran de
correction, version optimale calculée au lancement et conservée, optimisation avec verrous,
évaluation et exports (CSV avec comparatif, PDF avec carte) via l'API.app/
config.py paramètres
data.py lecture du CSV, identification des clubs
geocode.py Nominatim + cache + limitation de débit
distances.py OSRM table + cache par paire + repli haversine
optimizer.py modèle CP-SAT
metrics.py indicateurs (km et heures par équipe et par poule)
exports.py CSV et PDF
pdfmap.py carte du PDF (tuiles OSM en cache, enveloppes, marqueurs)
state.py état de l'application et tâche de fond
main.py API FastAPI
static/ interface (HTML, CSS, JS, Leaflet embarqué)
tests/