Add one-shot scripts (plan maison, généalogie, OAuth, etc.)

This commit is contained in:
2026-08-05 12:31:35 +02:00
parent 1936ded08f
commit 4ed3756cd0
9 changed files with 2683 additions and 3 deletions
+342
View File
@@ -0,0 +1,342 @@
#!/usr/bin/env python3
"""Plan d'étage — murs en traits épais, ouvertures nettes."""
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib.patches import FancyBboxPatch, Arc, Circle, Rectangle
import numpy as np
fig, ax = plt.subplots(1, 1, figsize=(26, 20))
ax.set_aspect('equal')
ax.axis('off')
# ── Palette ────────────────────────────────────────────────────
MUR = '#3a3a5c'
MUR_EXT = '#1a1a2e'
PIECE = {
'salon': '#fff8e7', 'cuisine': '#eef5e8', 'chambre': '#eaf0f8',
'sdb': '#e0ecf2', 'wc': '#f5ecec', 'bureau': '#f0f0f5',
'it': '#e8e8f0', 'couloir': '#f5f3ee',
}
MEUBLE = '#8b7355'
MEUBLE_IT = '#4a4a6a'
PORTE_C = '#8b4513'
FENETRE_C = '#7ec8e3'
COTE = '#888888'
TEXTE = '#1a1a2e'
LW = 8.0 # linewidth pour murs (épais, bien visible)
LW_EXT = 10.0 # murs extérieurs plus épais
# ═══════════════════════════════════════════════════════════════
# LAYOUT
# ═══════════════════════════════════════════════════════════════
# Bas (y=0..8) : Salon(0-8) | Cuisine(8-13) | SalleIT(13-15.5) | Ch1(15.5-20)
# Couloir (8..9.5)
# Haut (9.5..15) : SDB(0-4) | WC(4-6) | Ch2(6-11) | Ch3(11-16) | Bureau(16-20)
# ── Fond des pièces ────────────────────────────────────────────
for (x, y, w, h, c) in [
(0, 0, 8, 8, PIECE['salon']), (8, 0, 5, 8, PIECE['cuisine']),
(13, 0, 2.5, 8, PIECE['it']), (15.5, 0, 4.5, 8, PIECE['chambre']),
(0, 8, 20, 1.5, PIECE['couloir']),
(0, 9.5, 4, 5.5, PIECE['sdb']), (4, 9.5, 2, 5.5, PIECE['wc']),
(6, 9.5, 5, 5.5, PIECE['chambre']), (11, 9.5, 5, 5.5, PIECE['chambre']),
(16, 9.5, 4, 5.5, PIECE['bureau']),
]:
ax.add_patch(Rectangle((x, y), w, h, facecolor=c, edgecolor='none', zorder=1))
# ── Helpers ────────────────────────────────────────────────────
def mur_ligne(x1, y1, x2, y2, lw=LW):
"""Mur en trait épais avec bouts plats (solid_capstyle='butt')."""
ax.plot([x1, x2], [y1, y2], color=MUR, linewidth=lw,
solid_capstyle='butt', zorder=3)
def mur_ext_ligne(x1, y1, x2, y2):
"""Mur extérieur en trait très épais."""
ax.plot([x1, x2], [y1, y2], color=MUR_EXT, linewidth=LW_EXT,
solid_capstyle='butt', zorder=3)
def porte_h(x, y, largeur=0.9):
"""Porte dans un mur horizontal — battant vers le haut."""
ax.plot([x, x], [y, y+largeur], color=PORTE_C, linewidth=2.5, zorder=5)
arc = Arc((x, y), largeur*2, largeur*2, angle=90, theta1=0, theta2=90,
color=PORTE_C, linewidth=1.2, linestyle='--', zorder=4)
ax.add_patch(arc)
ax.add_patch(Circle((x, y), 0.06, facecolor=PORTE_C, edgecolor='none', zorder=5))
def porte_v(x, y, largeur=0.9):
"""Porte dans un mur vertical — battant vers la droite."""
ax.plot([x, x+largeur], [y, y], color=PORTE_C, linewidth=2.5, zorder=5)
arc = Arc((x, y), largeur*2, largeur*2, angle=0, theta1=0, theta2=90,
color=PORTE_C, linewidth=1.2, linestyle='--', zorder=4)
ax.add_patch(arc)
ax.add_patch(Circle((x, y), 0.06, facecolor=PORTE_C, edgecolor='none', zorder=5))
def fenetre_h(x1, x2, y):
"""Fenêtre dans un mur horizontal extérieur."""
# Petits traits de mur aux extrémités
for x in [x1, x2]:
ax.plot([x, x], [y-0.15, y+0.15], color=MUR_EXT, linewidth=2, zorder=4)
ax.plot([x1, x2], [y, y], color=FENETRE_C, linewidth=4, solid_capstyle='butt', zorder=4)
def fenetre_v(y1, y2, x):
"""Fenêtre dans un mur vertical extérieur."""
for y in [y1, y2]:
ax.plot([x-0.15, x+0.15], [y, y], color=MUR_EXT, linewidth=2, zorder=4)
ax.plot([x, x], [y1, y2], color=FENETRE_C, linewidth=4, solid_capstyle='butt', zorder=4)
def meuble(x, y, w, h, label='', couleur=MEUBLE, txt_color='white'):
ax.add_patch(FancyBboxPatch((x, y), w, h, boxstyle="round,pad=0.04",
facecolor=couleur, edgecolor='#3d2e1a', linewidth=0.8, alpha=0.75, zorder=6))
if label:
ax.text(x+w/2, y+h/2, label, ha='center', va='center',
fontsize=6.5, color=txt_color, fontweight='bold', zorder=7)
def label_piece(x, y, nom, surface, sz_nom=11, sz_surf=8):
ax.text(x, y+0.35, nom, ha='center', va='center', fontsize=sz_nom,
color=TEXTE, fontweight='bold', zorder=8)
ax.text(x, y-0.35, surface, ha='center', va='center', fontsize=sz_surf, color=COTE, zorder=8)
def cote(x1, y1, x2, y2, label, decal=0.5):
ax.plot([x1, x2], [y1, y2], color=COTE, linewidth=0.7, zorder=2)
dx, dy = x2-x1, y2-y1
L = np.sqrt(dx*dx+dy*dy)
if L > 0:
nx, ny = -dy/L*0.12, dx/L*0.12
ax.plot([x1+nx, x1-nx], [y1+ny, y1-ny], color=COTE, linewidth=0.7, zorder=2)
ax.plot([x2+nx, x2-nx], [y2+ny, y2-ny], color=COTE, linewidth=0.7, zorder=2)
mx, my = (x1+x2)/2, (y1+y2)/2
px, py = (-dy/L*decal, dx/L*decal) if L > 0 else (0, decal)
ax.text(mx+px, my+py, label, ha='center', va='center', fontsize=7.5, color=COTE, zorder=2)
# ═══════════════════════════════════════════════════════════════
# MURS EXTÉRIEURS (traits épais, segments avec gaps)
# ═══════════════════════════════════════════════════════════════
# Bas (y=0)
mur_ext_ligne(0, 0, 2, 0) # coin → fenêtre salon
mur_ext_ligne(6, 0, 9.1, 0) # fenêtre salon → porte entrée
mur_ext_ligne(10, 0, 13, 0) # porte entrée → fenêtre cuisine
mur_ext_ligne(13, 0, 14, 0) # → fenêtre IT
mur_ext_ligne(15, 0, 17, 0) # fenêtre IT → fenêtre ch1
mur_ext_ligne(19, 0, 20, 0) # fenêtre ch1 → coin
# Droite (x=20)
mur_ext_ligne(20, 0, 20, 2)
mur_ext_ligne(20, 6, 20, 11)
mur_ext_ligne(20, 13.5, 20, 15)
# Haut (y=15)
mur_ext_ligne(0, 15, 5, 15)
mur_ext_ligne(5.5, 15, 8, 15)
mur_ext_ligne(10, 15, 13, 15)
mur_ext_ligne(15, 15, 20, 15)
# Gauche (x=0)
mur_ext_ligne(0, 0, 0, 2)
mur_ext_ligne(0, 5, 0, 11)
mur_ext_ligne(0, 13.5, 0, 15)
# ═══════════════════════════════════════════════════════════════
# MURS INTÉRIEURS (traits épais, segments avec gaps pour portes)
# ═══════════════════════════════════════════════════════════════
# Salon | Cuisine (x=8)
mur_ligne(8, 0, 8, 8)
# Cuisine | Salle IT (x=13)
mur_ligne(13, 0, 13, 8)
# Salle IT | Chambre 1 (x=15.5)
mur_ligne(15.5, 0, 15.5, 8)
# Couloir BAS (y=8) — segments avec gaps pour portes
mur_ligne(0, 8, 3.05, 8) # gauche → porte salon
mur_ligne(3.95, 8, 9.55, 8) # porte salon → porte cuisine
mur_ligne(10.45, 8, 13.55, 8) # porte cuisine → porte IT
mur_ligne(14.45, 8, 17.05, 8) # porte IT → porte ch1
mur_ligne(17.95, 8, 20, 8) # porte ch1 → droite
# Couloir HAUT (y=9.5) — segments avec gaps pour portes
mur_ligne(0, 9.5, 1.55, 9.5) # gauche → porte SDB
mur_ligne(2.45, 9.5, 4.55, 9.5) # porte SDB → porte WC
mur_ligne(5.45, 9.5, 8.05, 9.5) # porte WC → porte ch2
mur_ligne(8.95, 9.5, 13.05, 9.5) # porte ch2 → porte ch3
mur_ligne(13.95, 9.5, 17.55, 9.5) # porte ch3 → porte bureau
mur_ligne(18.45, 9.5, 20, 9.5) # porte bureau → droite
# Murs verticaux partie haute
mur_ligne(4, 9.5, 4, 15) # SDB | WC
mur_ligne(6, 9.5, 6, 15) # WC | Ch2
mur_ligne(11, 9.5, 11, 15) # Ch2 | Ch3
mur_ligne(16, 9.5, 16, 15) # Ch3 | Bureau
# ═══════════════════════════════════════════════════════════════
# PORTES
# ═══════════════════════════════════════════════════════════════
# Entrée (mur du bas)
porte_v(9.55, 0)
# Couloir bas → pièces
porte_h(3.5, 8) # salon
porte_h(10, 8) # cuisine
porte_h(14, 8) # salle IT
porte_h(17.5, 8) # chambre 1
# Couloir haut → pièces
porte_h(2, 9.5) # SDB
porte_h(5, 9.5) # WC
porte_h(8.5, 9.5) # chambre 2
porte_h(13.5, 9.5) # chambre 3
porte_h(18, 9.5) # bureau
# ═══════════════════════════════════════════════════════════════
# FENÊTRES
# ═══════════════════════════════════════════════════════════════
fenetre_h(2, 6, 0) # salon — baie vitrée
fenetre_v(2, 5, 0) # salon — côté gauche
fenetre_h(10, 13, 0) # cuisine
fenetre_h(14, 15, 0) # salle IT
fenetre_h(17, 19, 0) # chambre 1
fenetre_v(2, 6, 20) # chambre 1 — côté droit
fenetre_v(11, 13.5, 0) # SDB
fenetre_h(5, 5.5, 15) # WC — haut
fenetre_h(8, 10, 15) # chambre 2 — haut
fenetre_h(13, 15, 15) # chambre 3 — haut
fenetre_v(11, 13.5, 20) # bureau — côté droit
# ═══════════════════════════════════════════════════════════════
# MEUBLES
# ═══════════════════════════════════════════════════════════════
# Salon
meuble(1, 1.5, 3, 1, 'Canapé d\'angle')
meuble(1.5, 3.2, 1.2, 0.6, 'Table basse')
meuble(5.5, 1.5, 1.8, 0.7, 'Meuble TV')
meuble(1, 5, 1.5, 0.6, 'Bibliothèque')
meuble(3, 5, 1.5, 0.6, 'Bibliothèque')
# Cuisine
meuble(9, 1.5, 2.5, 0.6, 'Plan de travail')
meuble(9, 2.5, 1, 0.6, 'Évier')
meuble(10.5, 2.5, 1, 0.6, 'Plaques')
meuble(9, 3.8, 2.5, 1, 'Îlot central')
meuble(12, 1.5, 0.8, 0.6, 'Frigo')
meuble(9, 5.5, 1.5, 0.6, 'Cellier')
# Salle IT
meuble(13.5, 1, 1.5, 0.6, 'Rack 42U', couleur=MEUBLE_IT)
meuble(13.5, 2.2, 1.5, 0.6, 'Rack 24U', couleur=MEUBLE_IT)
meuble(13.5, 3.5, 1, 0.6, 'Onduleur', couleur=MEUBLE_IT)
meuble(14.5, 3.5, 0.8, 0.6, 'NAS', couleur=MEUBLE_IT)
meuble(13.5, 5, 1.2, 0.5, 'Bureau IT', couleur=MEUBLE_IT)
# Chambre 1
meuble(16.5, 1.5, 1.6, 2, 'Lit 160')
meuble(18.5, 1.5, 0.5, 0.5, '')
meuble(19.5, 1.5, 0.5, 0.5, '')
meuble(16.5, 5, 1.2, 0.5, 'Commode')
meuble(18.5, 5, 1, 0.5, 'Bureau')
# Salle de bain
meuble(0.5, 10.5, 1.5, 0.8, 'Douche ital.')
meuble(2.5, 10.5, 1, 0.6, 'Lavabo')
meuble(0.5, 12, 1.5, 0.7, 'Baignoire')
meuble(2.5, 12.5, 0.8, 0.6, 'WC')
# WC
meuble(4.5, 10.5, 0.8, 0.6, 'WC')
meuble(4.5, 12, 0.6, 0.5, 'Lavabo')
# Chambre 2
meuble(7, 10.5, 1.4, 1.9, 'Lit 140')
meuble(8.5, 10.5, 0.5, 0.5, '')
meuble(7, 13, 1.2, 0.5, 'Commode')
meuble(9, 13, 1, 0.5, 'Bureau')
# Chambre 3
meuble(12, 10.5, 1.6, 2, 'Lit 160')
meuble(14, 10.5, 0.5, 0.5, '')
meuble(15, 10.5, 0.5, 0.5, '')
meuble(12, 13.5, 1.2, 0.5, 'Armoire')
# Bureau
meuble(17, 10.5, 1.8, 0.7, 'Bureau')
meuble(17, 12, 1, 0.5, 'Étagère')
meuble(18.5, 12, 0.8, 0.5, 'Imprimante')
# ═══════════════════════════════════════════════════════════════
# ÉTIQUETTES
# ═══════════════════════════════════════════════════════════════
label_piece(4, 4, 'SALON / SÉJOUR', '32 m²')
label_piece(10.5, 4, 'CUISINE', '20 m²')
label_piece(14.25,4, 'SALLE IT', '10 m²', sz_nom=10)
label_piece(17.75,4, 'CHAMBRE 1', '18 m²')
label_piece(2, 12.5, 'SALLE DE BAIN', '11 m²', sz_nom=9)
label_piece(5, 12.5, 'WC', '5.5 m²', sz_nom=9)
label_piece(8.5, 12.5, 'CHAMBRE 2', '13.5 m²')
label_piece(13.5, 12.5, 'CHAMBRE 3', '13.5 m²')
label_piece(18, 12.5, 'BUREAU', '11 m²')
# Entrée
ax.text(9.55, -0.5, 'ENTRÉE', ha='center', fontsize=10, fontweight='bold', color=TEXTE, zorder=8)
ax.plot(9.55, -0.25, marker='v', color=PORTE_C, markersize=8, zorder=5)
# ═══════════════════════════════════════════════════════════════
# COTES
# ═══════════════════════════════════════════════════════════════
cote(0, -1.2, 20, -1.2, '20.00 m')
cote(-1.2, 0, -1.2, 15, '15.00 m')
cote(0, -0.7, 8, -0.7, '8.00 m')
cote(8, -0.7, 13, -0.7, '5.00 m')
cote(13, -0.7, 15.5, -0.7, '2.50 m')
cote(15.5, -0.7, 20, -0.7, '4.50 m')
# ═══════════════════════════════════════════════════════════════
# LÉGENDE
# ═══════════════════════════════════════════════════════════════
lx, ly = 21.5, 14
ax.text(lx, ly, 'LÉGENDE', fontsize=10, fontweight='bold', color=TEXTE, zorder=9)
items = [
(MUR_EXT, 'Mur extérieur'),
(MUR, 'Mur intérieur'),
(FENETRE_C, 'Fenêtre'),
(PORTE_C, 'Porte'),
(MEUBLE_IT, 'Équipement IT'),
]
for i, (c, lbl) in enumerate(items):
y = ly - 0.7 - i*0.6
if lbl == 'Fenêtre':
ax.plot([lx, lx+1.5], [y, y], color=c, linewidth=4, zorder=9)
elif lbl == 'Porte':
ax.plot([lx, lx+0.8], [y, y], color=c, linewidth=2.5, zorder=9)
ax.add_patch(Circle((lx, y), 0.06, facecolor=c, edgecolor='none', zorder=9))
elif lbl == 'Mur extérieur':
ax.plot([lx, lx+1.5], [y, y], color=c, linewidth=LW_EXT, solid_capstyle='butt', zorder=9)
elif lbl == 'Mur intérieur':
ax.plot([lx, lx+1.5], [y, y], color=c, linewidth=LW, solid_capstyle='butt', zorder=9)
else:
ax.add_patch(Rectangle((lx, y-0.15), 1.5, 0.3, facecolor=c, edgecolor='none', zorder=9))
ax.text(lx+1.8, y, lbl, fontsize=7.5, color=TEXTE, va='center', zorder=9)
# ═══════════════════════════════════════════════════════════════
# TITRE
# ═══════════════════════════════════════════════════════════════
ax.text(10, 16.2, 'PLAN D\'ÉTAGE — MAISON FAMILIALE AVEC SALLE IT', ha='center',
fontsize=16, fontweight='bold', color=TEXTE, zorder=9)
ax.text(10, 15.7, 'Rez-de-chaussée | Surface totale : ~150 m² | Échelle indicative',
ha='center', fontsize=9, color=COTE, zorder=9)
ax.set_facecolor('#f0ede5')
fig.patch.set_facecolor('#e8e4dc')
ax.set_xlim(-2, 24)
ax.set_ylim(-2, 17.5)
output = '/root/workspace/plan_grande_maison.pdf'
plt.savefig(output, format='pdf', dpi=200, bbox_inches='tight',
facecolor=fig.get_facecolor(), edgecolor='none')
plt.close()
print(f"✅ PDF : {output}")