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

171 lines
6.8 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 4 Eventstream als Quelle; Aussagen links, Lupen rechts, Strecke unten."""
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(0xC8, 0x8A, 0x3A)
MUTE = RGBColor(0x8A, 0x93, 0xA0)
GLASS = RGBColor(0xF2, 0xF5, 0xF8)
BELT = RGBColor(0xD7, 0xDC, 0xE2)
DARK = RGBColor(0x33, 0x39, 0x44)
LINEC = RGBColor(0xC3, 0xC9, 0xD1)
THIN = RGBColor(0xDD, 0xE2, 0xE8)
STREAM = RGBColor(0x24, 0x37, 0x52)
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)
SW, SH = prs.slide_width, prs.slide_height
s = prs.slides.add_slide(prs.slide_layouts[6])
bgr = s.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, 0, SW, SH)
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 txt(x, y, w, h, t, size=16, 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
# ---- Kopf (ganz oben) ------------------------------------------------------
txt(Inches(0.95), Inches(0.32), Inches(8), Inches(0.35), "MODELL",
size=12.5, color=ACCENT, bold=True, spc=240)
txt(Inches(0.95), Inches(0.62), Inches(11), Inches(0.85), "Zustand oder Ereignis",
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(1.0), Inches(12.33)
beltw = x1 - x0
# ---- Aussagen links --------------------------------------------------------
claims = [
"Eventstream = einzige Quelle der Wahrheit",
"kann nicht überschrieben werden",
"vollständige 3D-Sicht auf Maschine / Strang",
]
cy = Inches(1.95)
for i, c in enumerate(claims):
y = cy + Inches(0.6) * i
shp(MSO_SHAPE.RECTANGLE, Inches(0.95), y + Inches(0.1), Inches(0.14), Inches(0.14), fill=ACCENT)
bold = (i == 0)
txt(Inches(1.28), y, Inches(4.6), Inches(0.45), c,
size=16.5, color=INK, bold=bold)
# ===========================================================================
# LUPEN (Projektionen) nach rechts gerückt
# ===========================================================================
def lupe(cx, label, label_w):
cy = Inches(2.45)
d = Inches(0.9)
shp(MSO_SHAPE.OVAL, cx - d / 2, cy - d / 2, d, d, fill=WHITE, line=NAVY, lw=Pt(4))
shp(MSO_SHAPE.OVAL, cx - d / 2 + Inches(0.13), cy - d / 2 + Inches(0.12),
Inches(0.17), Inches(0.13), fill=RGBColor(0xED,0xF1,0xF5))
hw, hh = Inches(0.48), Inches(0.15)
hcx, hcy = cx + d * 0.52, cy + d * 0.52
shp(MSO_SHAPE.ROUNDED_RECTANGLE, hcx - hw / 2, hcy - hh / 2, hw, hh, fill=NAVY, rot=45)
txt(cx - label_w / 2, cy + d / 2 + Inches(0.16), label_w, Inches(0.6),
label, size=14, color=NAVY, bold=True, align=PP_ALIGN.CENTER)
return cy + d / 2
lupes = [
(Inches(7.05), "Gruppen-Reporting", Inches(2.3)),
(Inches(9.45), "Optimierung der Auslastung", Inches(2.3)),
(Inches(11.55), "Abrechnungen", Inches(1.9)),
]
lens_bottoms = [lupe(cx, lb, lw) for cx, lb, lw in lupes]
# ===========================================================================
# EVENTSTREAM (Pfeil)
# ===========================================================================
ay, ah = Inches(4.45), Inches(0.46)
shp(MSO_SHAPE.RIGHT_ARROW, x0, ay, beltw, ah, fill=STREAM)
acx = ay + ah / 2
txt(Inches(5.65), ay + Inches(0.04), Inches(2.0), ah - Inches(0.08),
"Eventstream", size=14, color=WHITE, bold=True, align=PP_ALIGN.CENTER)
# Verbinder Lupe -> Strom
for (cx, _, _), lb_y in zip(lupes, lens_bottoms):
shp(MSO_SHAPE.RECTANGLE, cx - Pt(0.5), lb_y, Pt(1), ay - lb_y, fill=LINEC)
# ===========================================================================
# RÖHRCHEN-STRECKE durch Maschine unten
# ===========================================================================
belt_top = Inches(6.1)
belt_h = Inches(0.30)
for rx in (x0 - Inches(0.18), x1 - Inches(0.32)):
shp(MSO_SHAPE.OVAL, rx, belt_top - Inches(0.10), Inches(0.5), Inches(0.5),
fill=BELT, line=LINEC)
shp(MSO_SHAPE.ROUNDED_RECTANGLE, x0, belt_top, beltw, belt_h, fill=BELT)
mx, mw = Inches(5.45), Inches(2.45)
my, mh = Inches(5.2), Inches(1.5)
shp(MSO_SHAPE.ROUNDED_RECTANGLE, mx, my, mw, mh, fill=NAVY)
shp(MSO_SHAPE.ROUNDED_RECTANGLE, mx + Inches(0.3), my + Inches(0.22),
mw - Inches(0.6), Inches(0.32), fill=RGBColor(0x34,0x4E,0x70))
shp(MSO_SHAPE.OVAL, mx + Inches(0.35), my + Inches(0.74), Inches(0.15), Inches(0.15), fill=TEAL)
shp(MSO_SHAPE.OVAL, mx + Inches(0.6), my + Inches(0.74), Inches(0.15), Inches(0.15), fill=AMBER)
shp(MSO_SHAPE.RECTANGLE, mx - Inches(0.02), belt_top - Inches(0.02),
Inches(0.14), belt_h + Inches(0.04), fill=DARK)
shp(MSO_SHAPE.RECTANGLE, mx + mw - Inches(0.12), belt_top - Inches(0.02),
Inches(0.14), belt_h + Inches(0.04), fill=DARK)
def tube(cx, liquid):
bw, bh = Inches(0.22), Inches(0.6)
bx, by = cx - bw / 2, belt_top - bh
shp(MSO_SHAPE.ROUNDED_RECTANGLE, bx, by, bw, bh, fill=GLASS, line=LINEC, lw=Pt(0.75))
lh = Inches(0.25)
shp(MSO_SHAPE.ROUNDED_RECTANGLE, bx + Pt(1), belt_top - lh, bw - Pt(2), lh, fill=liquid)
cw, ch = Inches(0.26), Inches(0.12)
shp(MSO_SHAPE.ROUNDED_RECTANGLE, cx - cw / 2, by - Inches(0.06), cw, ch, fill=DARK)
cols = [ACCENT, TEAL, AMBER]
pre_x = [1.55, 2.1, 2.65, 3.2, 3.75, 4.3, 4.85]
post_x = [8.25, 8.8, 9.35, 9.9, 10.45, 11.0]
for i, xv in enumerate(pre_x + post_x):
tube(Inches(xv), cols[i % 3])
tube_top = belt_top - Inches(0.6)
for xv in pre_x + post_x:
shp(MSO_SHAPE.RECTANGLE, Inches(xv) - Pt(0.4), ay + ah,
Pt(0.8), tube_top - (ay + ah), fill=THIN)
shp(MSO_SHAPE.OVAL, Inches(xv) - Inches(0.05), acx - Inches(0.05),
Inches(0.1), Inches(0.1), fill=AMBER)
out = "/home/marcuh/claude-projects/limbach/Folie4.pptx"
prs.save(out)
print("saved", out)