Files
claude-projects/limbach/folie3.py
T
marcus hinz 52ce98626c initial
2026-06-12 10:40:47 +02:00

269 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""Folie 3 LIS mit Umsystemen (Adapter, links/rechts) und andockenden Modulen
(unten), unter einer Steuerungs-/Governance-Schicht; weitere LIS angedeutet."""
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.enum.shapes import MSO_SHAPE
INK = RGBColor(0x2A, 0x2F, 0x3A)
NAVY = RGBColor(0x1F, 0x3A, 0x5F)
ACCENT = RGBColor(0xC0, 0x49, 0x2F)
TEAL = RGBColor(0x2F, 0x8F, 0x83)
AMBER = RGBColor(0xA9, 0x73, 0x22)
MUTE = RGBColor(0x8A, 0x93, 0xA0)
LINEC = RGBColor(0xC3, 0xC9, 0xD1)
HINT = RGBColor(0xEE, 0xF1, 0xF4)
HINTL = RGBColor(0xCB, 0xD2, 0xDA)
TINT_T = RGBColor(0xDD, 0xEC, 0xEA)
TINT_A = RGBColor(0xF3, 0xE8, 0xD2)
UMS = RGBColor(0xEC, 0xEE, 0xF1)
BG = RGBColor(0xFF, 0xFF, 0xFF)
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
F = "Calibri"
prs = Presentation()
prs.slide_width = Inches(13.333)
prs.slide_height = Inches(7.5)
s = prs.slides.add_slide(prs.slide_layouts[6])
bgr = s.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, 0, prs.slide_width, prs.slide_height)
bgr.fill.solid(); bgr.fill.fore_color.rgb = BG; bgr.line.fill.background()
bgr.shadow.inherit = False
def shp(kind, x, y, w, h, fill=None, line=None, lw=Pt(1), rot=0):
sh = s.shapes.add_shape(kind, x, y, w, h)
if fill is None: sh.fill.background()
else: sh.fill.solid(); sh.fill.fore_color.rgb = fill
if line is None: sh.line.fill.background()
else: sh.line.color.rgb = line; sh.line.width = lw
if rot: sh.rotation = rot
sh.shadow.inherit = False
return sh
def boxtext(sh, t, size=14, color=INK, bold=False):
tf = sh.text_frame; tf.word_wrap = True
tf.vertical_anchor = MSO_ANCHOR.MIDDLE
tf.margin_left = tf.margin_right = Pt(3); tf.margin_top = tf.margin_bottom = Pt(1)
p = tf.paragraphs[0]; p.alignment = PP_ALIGN.CENTER
r = p.add_run(); r.text = t
r.font.size = Pt(size); r.font.bold = bold; r.font.name = F; r.font.color.rgb = color
def txt(x, y, w, h, t, size=14, color=INK, bold=False, italic=False,
align=PP_ALIGN.LEFT, spc=None):
tb = s.shapes.add_textbox(x, y, w, h); tf = tb.text_frame
tf.word_wrap = True; tf.vertical_anchor = MSO_ANCHOR.MIDDLE
tf.margin_left = tf.margin_right = tf.margin_top = tf.margin_bottom = Pt(0)
p = tf.paragraphs[0]; p.alignment = align
r = p.add_run(); r.text = t
r.font.size = Pt(size); r.font.bold = bold; r.font.italic = italic
r.font.name = F; r.font.color.rgb = color
if spc: r.font._rPr.set('spc', str(spc))
return tb
def hline(x, y, w, color=LINEC, weight=Pt(1.4)):
shp(MSO_SHAPE.RECTANGLE, x, y - weight / 2, w, weight, fill=color)
def vline(x, y, h, color=LINEC, weight=Pt(1.4)):
shp(MSO_SHAPE.RECTANGLE, x - weight / 2, y, weight, h, fill=color)
# ---- Kopf ------------------------------------------------------------------
txt(Inches(0.95), Inches(0.32), Inches(8), Inches(0.35), "ARCHITEKTUR",
size=12.5, color=ACCENT, bold=True, spc=240)
txt(Inches(0.95), Inches(0.62), Inches(11), Inches(0.85), "Offen und gesteuert",
size=31, color=NAVY, bold=True)
shp(MSO_SHAPE.RECTANGLE, Inches(0.95), Inches(1.34), Inches(0.6), Pt(4), fill=ACCENT)
x0, x1 = Inches(0.95), Inches(12.38)
# ===========================================================================
# GOVERNANCE Icon-Karten + Strich
# ===========================================================================
def card(cx, label):
cw_, ch_ = Inches(2.05), Inches(1.25)
x, y = cx - cw_ / 2, Inches(1.5)
shp(MSO_SHAPE.ROUNDED_RECTANGLE, x, y, cw_, ch_, fill=BG, line=LINEC, lw=Pt(1.25))
txt(x, y + ch_ - Inches(0.4), cw_, Inches(0.34), label,
size=14, color=NAVY, bold=True, align=PP_ALIGN.CENTER)
return cx, y + Inches(0.42)
def regler(cx, cy):
tw = Inches(0.62)
left = cx - tw / 2
for j, frac in enumerate([0.30, 0.68, 0.48]):
ty = cy - Inches(0.18) + j * Inches(0.18)
shp(MSO_SHAPE.ROUNDED_RECTANGLE, left, ty - Inches(0.022), tw, Inches(0.045), fill=LINEC)
kx = left + Inches(0.62 * frac)
shp(MSO_SHAPE.OVAL, kx - Inches(0.07), ty - Inches(0.07),
Inches(0.14), Inches(0.14), fill=NAVY)
cx1, cy1 = card(Inches(4.75), "Steuerung")
cx2, cy2 = card(Inches(6.95), "Reporting")
cx3, cy3 = card(Inches(9.15), "Governance")
regler(cx1, cy1)
# Reporting Zahlenreihen
nb = s.shapes.add_textbox(cx2 - Inches(0.85), cy2 - Inches(0.36), Inches(1.7), Inches(0.72))
tf = nb.text_frame; tf.word_wrap = False; tf.vertical_anchor = MSO_ANCHOR.MIDDLE
tf.margin_left = tf.margin_right = tf.margin_top = tf.margin_bottom = Pt(0)
for i, row in enumerate(["3 8 1 4 7", "6 0 9 2 5", "5 7 2 8 1"]):
p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
p.alignment = PP_ALIGN.CENTER; p.line_spacing = 0.95
r = p.add_run(); r.text = row
r.font.size = Pt(11); r.font.name = "Consolas"; r.font.color.rgb = MUTE
# Governance §
gtb = s.shapes.add_textbox(cx3 - Inches(0.6), cy3 - Inches(0.42), Inches(1.2), Inches(0.8))
gtf = gtb.text_frame; gtf.vertical_anchor = MSO_ANCHOR.MIDDLE
gp = gtf.paragraphs[0]; gp.alignment = PP_ALIGN.CENTER
gr = gp.add_run(); gr.text = "§"; gr.font.size = Pt(34); gr.font.bold = True
gr.font.name = F; gr.font.color.rgb = NAVY
gov_y = Inches(3.05)
shp(MSO_SHAPE.ROUNDED_RECTANGLE, x0, gov_y - Inches(0.07), x1 - x0, Inches(0.14), fill=NAVY)
for cc in (cx1, cx2, cx3):
vline(cc, Inches(2.75), gov_y - Inches(0.07) - Inches(2.75), color=LINEC, weight=Pt(1))
# ===========================================================================
# LIS + Umsysteme (Adapter links/rechts) + Module (andocken, unten)
# ===========================================================================
core_x, core_w = Inches(3.7), Inches(2.3)
core_y, core_h = Inches(4.3), Inches(1.2)
core_cx = core_x + core_w / 2
core_by = core_y + core_h
def adapter(xc, yc):
shp(MSO_SHAPE.ROUNDED_RECTANGLE, xc - Inches(0.10), yc - Inches(0.11),
Inches(0.16), Inches(0.22), fill=ACCENT)
shp(MSO_SHAPE.RECTANGLE, xc + Inches(0.06), yc - Inches(0.055), Inches(0.1), Pt(2.4), fill=ACCENT)
shp(MSO_SHAPE.RECTANGLE, xc + Inches(0.06), yc + Inches(0.03), Inches(0.1), Pt(2.4), fill=ACCENT)
def dock(xc, yc):
shp(MSO_SHAPE.ROUNDED_RECTANGLE, xc - Inches(0.1), yc - Inches(0.1),
Inches(0.2), Inches(0.2), fill=NAVY)
shp(MSO_SHAPE.OVAL, xc - Inches(0.055), yc - Inches(0.055), Inches(0.11), Inches(0.11),
fill=ACCENT)
def icon_truck(ix, iy): # Anlieferung
shp(MSO_SHAPE.ROUNDED_RECTANGLE, ix - Inches(0.20), iy - Inches(0.10),
Inches(0.24), Inches(0.16), fill=NAVY)
shp(MSO_SHAPE.ROUNDED_RECTANGLE, ix + Inches(0.05), iy - Inches(0.035),
Inches(0.12), Inches(0.095), fill=NAVY)
for wx in (ix - Inches(0.11), ix + Inches(0.08)):
shp(MSO_SHAPE.OVAL, wx - Inches(0.038), iy + Inches(0.05),
Inches(0.076), Inches(0.076), fill=NAVY)
def icon_device(ix, iy): # Gerät
shp(MSO_SHAPE.ROUNDED_RECTANGLE, ix - Inches(0.16), iy - Inches(0.14),
Inches(0.32), Inches(0.28), fill=NAVY)
shp(MSO_SHAPE.RECTANGLE, ix - Inches(0.11), iy - Inches(0.10),
Inches(0.22), Inches(0.085), fill=RGBColor(0x34, 0x4E, 0x70))
shp(MSO_SHAPE.OVAL, ix - Inches(0.085), iy + Inches(0.03), Inches(0.055), Inches(0.055), fill=TEAL)
shp(MSO_SHAPE.OVAL, ix + Inches(0.03), iy + Inches(0.03), Inches(0.055), Inches(0.055), fill=AMBER)
def icon_dfu(ix, iy): # DFÜ
shp(MSO_SHAPE.RIGHT_ARROW, ix - Inches(0.16), iy - Inches(0.12), Inches(0.32), Inches(0.095),
fill=NAVY)
shp(MSO_SHAPE.LEFT_ARROW, ix - Inches(0.16), iy + Inches(0.025), Inches(0.32), Inches(0.095),
fill=ACCENT)
# Governance -> LIS
vline(core_cx, gov_y + Inches(0.07), core_y - (gov_y + Inches(0.07)), color=LINEC, weight=Pt(1))
uw, uh = Inches(1.55), Inches(0.6)
def ums_box(bx, yc, name, icon_fn):
shp(MSO_SHAPE.ROUNDED_RECTANGLE, bx, yc - uh / 2, uw, uh, fill=UMS, line=LINEC)
icon_fn(bx + Inches(0.32), yc)
txt(bx + Inches(0.58), yc - Inches(0.16), uw - Inches(0.64), Inches(0.32), name,
size=12, color=INK, align=PP_ALIGN.LEFT)
# Umsysteme links
lx = Inches(0.8)
ums_box(lx, Inches(4.6), "Anlieferung", icon_truck)
ums_box(lx, Inches(5.2), "DFÜ", icon_dfu)
for yc in (Inches(4.6), Inches(5.2)):
hline(lx + uw, yc, core_x - (lx + uw))
adapter(core_x - Inches(0.16), yc)
# Umsystem rechts
gx = Inches(6.65)
ums_box(gx, Inches(4.9), "Geräte", icon_device)
hline(core_x + core_w, Inches(4.9), gx - (core_x + core_w))
adapter(core_x + core_w + Inches(0.16), Inches(4.9))
# LIS (kompakt, solide)
shp(MSO_SHAPE.ROUNDED_RECTANGLE, core_x, core_y, core_w, core_h, fill=NAVY)
sh = shp(MSO_SHAPE.ROUNDED_RECTANGLE, core_x, core_y, core_w, core_h, fill=NAVY)
boxtext(sh, "LIS", size=22, color=WHITE, bold=True)
# Module unten (andockend)
mw, mh = Inches(1.7), Inches(0.6)
my = Inches(6.05)
for nm, fill, tc, mcx in [("Hochdurchsatz", TINT_T, TEAL, Inches(3.85)),
("Spezial", TINT_A, AMBER, Inches(5.85))]:
vline(mcx, core_by, my - core_by, color=LINEC, weight=Pt(1))
dock(mcx, core_by + (my - core_by) / 2)
sh = shp(MSO_SHAPE.ROUNDED_RECTANGLE, mcx - mw / 2, my, mw, mh, fill=fill, line=tc, lw=Pt(1.25))
boxtext(sh, nm, size=12.5, color=tc, bold=True)
txt(Inches(2.9), my + mh + Inches(0.12), Inches(4.0), Inches(0.3), "eigene Module",
size=12, color=MUTE, bold=True, align=PP_ALIGN.CENTER)
# ===========================================================================
# WEITERE LIS überlappend, nur angedeutet
# ===========================================================================
hw_, hh_ = Inches(1.8), Inches(2.0)
def mini_lis(hx, hy, faded=False):
fill = RGBColor(0xF4, 0xF6, 0xF8) if faded else HINT
shp(MSO_SHAPE.ROUNDED_RECTANGLE, hx, hy, hw_, hh_, fill=fill, line=HINTL, lw=Pt(1.25))
hdc = shp(MSO_SHAPE.ROUNDED_RECTANGLE, hx, hy, hw_, Inches(0.46),
fill=HINTL if not faded else RGBColor(0xDF, 0xE4, 0xEA))
boxtext(hdc, "LIS", size=14, color=NAVY, bold=True)
for k in range(3):
yy = hy + Inches(0.66) + k * Inches(0.4)
shp(MSO_SHAPE.ROUNDED_RECTANGLE, hx + Inches(0.2), yy, hw_ - Inches(0.4),
Inches(0.28), fill=WHITE, line=HINTL, lw=Pt(0.75))
mini_lis(Inches(10.5), Inches(4.35), faded=True)
mini_lis(Inches(10.0), Inches(4.75), faded=False)
vline(Inches(10.0) + hw_ / 2, gov_y + Inches(0.07), Inches(4.75) - (gov_y + Inches(0.07)),
color=LINEC, weight=Pt(1))
txt(Inches(9.9), Inches(4.35) + hh_ + Inches(0.2), Inches(2.4), Inches(0.35), "weitere LIS",
size=13, color=MUTE, align=PP_ALIGN.CENTER)
# ---- Mini-Legende ----------------------------------------------------------
ly = Inches(7.05)
adapter(Inches(7.35), ly)
txt(Inches(7.55), ly - Inches(0.16), Inches(2.1), Inches(0.32), "Adapter (Umsysteme)",
size=11.5, color=MUTE)
dock(Inches(9.65), ly)
txt(Inches(9.85), ly - Inches(0.16), Inches(2.1), Inches(0.32), "Andocken (Module)",
size=11.5, color=MUTE)
out = "/home/marcuh/claude-projects/limbach/Folie3.pptx"
prs.save(out)
print("saved", out)