11 KiB
Remplissage par cercles (circle packing) — extension Inkscape
Table of content
Fonctionnalités
- Remplissage de
path,rect,circle,ellipse,polygon(les groupes sélectionnés sont explorés pour en extraire les formes ;lineetpolylinesont ignorées) - Forme déposée au choix : cercle (par défaut) ou forme personnalisée — le motif est le dernier objet sélectionné, chaque copie étant mise à l'échelle pour tenir dans le disque calculé, orientée au hasard et stylée comme le motif
- 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é « Remplissage par cercles » ; 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
- Cercles ordonnés de proche en proche (chaîne du plus proche voisin) : les logiciels de découpe laser qui suivent l'ordre du document minimisent leurs déplacements à vide
- Grille de hachage spatial : des dizaines de milliers de tentatives restent rapides
- Interface traduite en français et en anglais, selon la langue d'Inkscape (anglais pour toute autre langue)
- 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 :
.\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, packing_core.py,
images/parameters_en.png et le dossier locale/ 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 fichiers doivent rester
ensemble : circle_packing.py importe packing_core.py, l'onglet « Aide »
affiche images/parameters_en.png et locale/ porte les traductions.
Utilisation
- Sélectionner une ou plusieurs formes fermées.
- Extensions → AlexDesign → Remplissage par cercles (circle packing)… (Circle Packing Fill… en anglais)
- Régler les paramètres, puis Appliquer.
Remplir avec une forme personnalisée
Une extension Inkscape n'a pas accès au presse-papiers : la forme copiée doit d'abord être collée dans le document.
- Coller la forme voulue (Ctrl+V).
- Sélectionner les formes à remplir, puis ajouter le motif à la sélection en dernier (Maj+clic).
- Lancer l'extension, choisir « Forme déposée : Forme personnalisée ».
Le dernier objet sélectionné sert de motif et n'est pas rempli ; il reste en place même si « Conserver la forme d'origine » est décoché. Chaque copie est mise à l'échelle pour que son cercle circonscrit vaille le rayon calculé — la garantie de non-chevauchement et de non-débordement est donc conservée — puis orientée au hasard (reproductible à graine fixée) et stylée comme le motif. Les motifs très allongés donnent un remplissage plus lâche, leur cercle circonscrit étant large devant leur surface.
Le fichier tests/data/shapes.svg contient quatre cas d'essai : rectangle, cercle,
chemin courbe et chemin avec trou. L'image en tête de ce README en est le rendu
(graine 7, rayons de 0,6 à 12 mm, écart et marge de 0,4 mm, 40 000 tentatives,
forme d'origine supprimée).
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 |
|---|---|---|
| Forme déposée | Cercle | Cercle, ou forme personnalisée (dernier objet sélectionné) |
| 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 Boîte de dialogue Inkscape (textes source en anglais)
circle_packing.py Extension : lecture de la sélection, aplatissement des
chemins, écriture des <circle> dans le SVG
packing_core.py Noyau géométrique sans dépendance à inkex
i18n.py Chaîne de traduction (extract / update / compile)
po/ Modèle circlepacking.pot et catalogues en.po, fr.po
locale/ Catalogues compilés (.mo), déployés
images/parameters_en.png Schéma de l'onglet « Aide » (déployé)
docs/schema_parametres.py Générateur du schéma (fr pour le README, en pour le dialogue)
docs/parametres.png Schéma des paramètres du README (non déployé)
docs/rendu.png Image de présentation du README (non déployée)
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 |
bounding_circle(rings) |
Centre de la bbox et rayon circonscrit — sert à inscrire un motif dans le disque calculé |
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 |
order_by_proximity(circles) |
Réordonne en chaîne du plus proche voisin (départ au coin haut-gauche) |
pack_circles(rings, min_radius, max_radius, …) |
Boucle de packing, renvoie [(x, y, r), …] déjà ordonnés |
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 :
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 : 28 passés, 4 ignorés. Les tests ignorés sont ceux de bout en
bout, sautés quand inkex n'est pas importable. Pour les exécuter, ajouter le dossier
des extensions d'Inkscape au PYTHONPATH et installer les dépendances d'inkex
absentes d'un Python standard :
pip install lxml tinycss2 cssselect2 cssselect
$env:PYTHONPATH = 'C:\Program Files\Inkscape\share\inkscape\extensions'
python -m pytest test_packing.py -q # 32 passés
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. L'ordre de sortie est
comparé à une recherche du plus proche voisin en force brute et à la longueur du parcours
d'un ordre mélangé. S'y ajoutent les traductions (catalogues complets et recompilés) et la
cohérence entre le .inx, les arguments du script et les images de la boîte de dialogue.
Traductions
Les textes source (.inx et appels _() de circle_packing.py) sont en anglais ;
i18n.py les extrait et compile les catalogues, sans dépendance à gettext :
python i18n.py # extract + update + compile ; liste les msgstr manquants
Après modification d'un texte : lancer python i18n.py, compléter les msgstr
vides de po/fr.po, relancer. po/en.po se remplit tout seul ; ne jamais éditer
les .mo. Pour ajouter une langue, l'ajouter à LANGUAGES dans i18n.py.
Schéma des paramètres
python docs/schema_parametres.py # fr : docs/parametres.png (1400 px)
# en : images/parameters_en.png (900 px)
Les cercles du schéma sont calculés par packing_core, le dessin reste donc fidèle
au résultat réel. La version anglaise sert à l'onglet « Aide » de la boîte de
dialogue (Inkscape ne traduit pas le chemin d'une image). L'export PNG passe par
inkscape.com.
Aucun outil de lint n'est configuré dans le projet ; le code suit PEP 8.

