# Remplissage par cercles (circle packing) — extension Inkscape Extension Inkscape 1.x qui remplit la surface d'une forme fermée avec des cercles non chevauchants, selon la technique du *greedy random circle packing* : des points sont tirés au hasard dans la forme, et sur chacun on place le plus grand cercle possible qui ne déborde pas du contour et ne touche aucun cercle déjà posé. ## Table of content - [Fonctionnalités](#fonctionnalités) - [Installation](#installation) - [Utilisation](#utilisation) - [Paramètres](#paramètres) - [Structure du projet](#structure-du-projet) - [Développement](#développement) ## Fonctionnalités - Remplissage de `path`, `rect`, `circle`, `ellipse`, `polygon` (les groupes sélectionnés sont explorés pour en extraire les formes ; `line` et `polyline` sont ignorées) - Gestion des trous : les sous-chemins internes sont exclus (règle pair-impair) - Rayons minimal et maximal réglables, écart entre cercles (*gap*) et marge intérieure au contour, exprimés dans l'unité de votre choix - Les cercles héritent du style (fond, contour) de la forme source - Résultat placé dans un groupe nommé « Circle packing » ; forme d'origine conservée par défaut - Transformations respectées : le groupe généré annule celle de son parent - Graine aléatoire pour un résultat reproductible - Grille de hachage spatial : des dizaines de milliers de tentatives restent rapides - Script de déploiement PowerShell (installation, mise à jour, désinstallation) ## Installation Aucune dépendance externe : l'extension utilise `inkex`, fourni avec Inkscape. ### Windows — script de déploiement Inkscape fermé, depuis le dossier du projet : ```powershell .\deploy.ps1 # copie vers %APPDATA%\inkscape\extensions\circlePacking .\deploy.ps1 -Uninstall # retire le sous-dossier de l'extension .\deploy.ps1 -Force # passe outre le contrôle « Inkscape ouvert » .\deploy.ps1 -FolderName 'mes-cercles' -ExtensionsDir 'D:\autre\chemin' ``` Le script crée le sous-dossier, remplace les fichiers existants, nettoie le `__pycache__` obsolète et supprime les traces d'une ancienne installation posée à plat à la racine des extensions. Redémarrer Inkscape ensuite. ### Installation manuelle Copier `circle_packing.inx`, `circle_packing.py` et `packing_core.py` dans un sous-dossier (par exemple `circlePacking`) du dossier des extensions utilisateur, puis redémarrer Inkscape : - Windows : `%APPDATA%\inkscape\extensions` - Linux : `~/.config/inkscape/extensions` - macOS : `~/Library/Application Support/org.inkscape.Inkscape/config/inkscape/extensions` Inkscape explore récursivement ce dossier ; les trois fichiers doivent rester ensemble, `circle_packing.py` important `packing_core.py`. ## Utilisation 1. Sélectionner une ou plusieurs formes fermées. 2. **Extensions → Rendu → Remplissage par cercles (circle packing)…** 3. Régler les paramètres, puis **Appliquer**. Le fichier `tests/data/shapes.svg` contient quatre cas d'essai : rectangle, cercle, chemin courbe et chemin avec trou. Conseils de réglage : - densité insuffisante → augmenter le nombre de tentatives, réduire le rayon minimal, l'écart ou la marge - calcul trop long → réduire le nombre de tentatives ou plafonner le nombre de cercles - aucun cercle placé → un message l'indique ; le rayon minimal + la marge dépassent probablement la largeur de la forme ## Paramètres | Paramètre | Défaut | Rôle | |---|---|---| | Rayon minimal | 1.0 | En dessous, le cercle candidat est rejeté | | Rayon maximal | 20.0 | Taille maximale d'un cercle | | Écart entre cercles | 0.5 | Distance imposée entre deux cercles voisins | | Marge intérieure au contour | 0.5 | Distance imposée entre un cercle et le bord | | Unité | mm | Unité des quatre longueurs ci-dessus (mm, cm, px, pt, in) | | Nombre de tentatives | 20000 | Plus il est élevé, plus le remplissage est dense (et lent) | | Nombre maximal de cercles | 5000 | Garde-fou ; 0 = illimité | | Graine aléatoire | 0 | 0 = aléatoire ; toute autre valeur rend le résultat reproductible | | Finesse d'échantillonnage | 0.2 | Précision de l'aplatissement des courbes de Bézier | | Conserver la forme d'origine | oui | Sinon la forme source est supprimée | Le remplissage greedy atteint typiquement 60 à 75 % de couverture. ## Structure du projet ``` circle_packing.inx Description de la boîte de dialogue Inkscape circle_packing.py Extension : lecture de la sélection, aplatissement des chemins, écriture des dans le SVG packing_core.py Noyau géométrique sans dépendance à inkex deploy.ps1 Déploiement / désinstallation sous Windows test_packing.py Tests pytest tests/data/shapes.svg Formes d'exemple ``` API de `packing_core.py` (utilisable seule, hors Inkscape) : | Fonction | Rôle | |---|---| | `rings_bbox(rings)` | Boîte englobante d'un contour | | `point_in_rings(x, y, rings)` | Point dans la forme, règle pair-impair | | `distance_point_segment(px, py, x1, y1, x2, y2)` | Distance point → segment | | `distance_to_rings(x, y, rings)` | Distance au contour le plus proche | | `SpatialGrid(cell_size)` | Grille de hachage des cercles posés | | `pack_circles(rings, min_radius, max_radius, …)` | Boucle de packing, renvoie `[(x, y, r), …]` | Un contour (`rings`) est une liste d'anneaux, chaque anneau étant une liste de points `(x, y)` fermée implicitement. ## Développement Le noyau `packing_core.py` ne dépend pas d'Inkscape et se teste avec un Python standard : ```powershell python -m venv .venv .venv\Scripts\activate # Linux/macOS : source .venv/bin/activate pip install pytest python -m pytest test_packing.py -q ``` Résultat attendu : **14 passés, 1 ignoré**. Le test ignoré est celui de bout en bout, sauté quand `inkex` n'est pas importable. Pour l'exécuter, ajouter le dossier des extensions d'Inkscape au `PYTHONPATH` : ```powershell $env:PYTHONPATH = 'C:\Program Files\Inkscape\share\inkscape\extensions' python -m pytest test_packing.py -q ``` Les tests couvrent l'appartenance à une forme trouée, les distances au contour, la grille spatiale, et les invariants du packing : aucun chevauchement, rayons dans les bornes, cercles tous intérieurs, reproductibilité à graine fixée. Aucun outil de lint n'est configuré dans le projet ; le code suit PEP 8.