Most Generála Lišky
generovat.py
Původní podklad zpřístupněný přímo na webu.
"""Reprodukovatelné vektorové podklady. Python: reportlab, svglib.
Spuštění: python generovat.py. Nevytváří ani neposuzuje dopravní projekt.
"""
from pathlib import Path
from html import escape
from io import BytesIO
from reportlab.pdfgen import canvas
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from svglib.svglib import svg2rlg
from reportlab.graphics import renderPDF
OUT=Path(__file__).resolve().parent
FONT=Path('/System/Library/Fonts/Supplemental')
if (FONT/'Arial.ttf').exists():
pdfmetrics.registerFont(TTFont('Arial',str(FONT/'Arial.ttf')))
pdfmetrics.registerFont(TTFont('Arial-Bold',str(FONT/'Arial Bold.ttf')))
pdfmetrics.registerFontFamily('Arial',normal='Arial',bold='Arial-Bold',italic='Arial',boldItalic='Arial-Bold')
BG='#f7f6f2'; INK='#182b35'; MUT='#53656d'; WALK='#e4c991'; BIKE='#a4d6bf'; CAR='#d8dfe3'; WARN='#c47c30'; WATER='#d7eaf0'
parts=[]; pages=[]
def rect(x,y,w,h,fill,stroke='none',sw=1):
parts.append(f'<rect x="{x}" y="{y}" width="{w}" height="{h}" fill="{fill}" stroke="{stroke}" stroke-width="{sw}"/>')
def line(x1,y1,x2,y2,color=INK,sw=1,dash=''):
parts.append(f'<line x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" stroke="{color}" stroke-width="{sw}" stroke-dasharray="{dash}"/>')
def txt(x,y,s,size=16,color=INK,bold=False,anchor='start'):
parts.append(f'<text x="{x}" y="{y}" font-family="Arial" font-size="{size}" font-weight="{"bold" if bold else "normal"}" text-anchor="{anchor}" fill="{color}">{escape(str(s))}</text>')
def lines(x,y,ss,size=16,color=MUT,step=24):
for i,s in enumerate(ss):txt(x,y+i*step,s,size,color)
def circle(x,y,r,fill,stroke='none'):
parts.append(f'<circle cx="{x}" cy="{y}" r="{r}" fill="{fill}" stroke="{stroke}"/>')
def dim(x,y,w,label):
line(x,y,x+w,y,MUT);line(x,y-5,x,y+5,MUT);line(x+w,y-5,x+w,y+5,MUT)
txt(x+w/2,y-9,label,14,anchor='middle')
def page(n,title,sub):
global parts
parts=[];rect(0,0,1200,850,BG)
txt(48,37,'BRANDÝS NAD LABEM–STARÁ BOLESLAV / MOST GENERÁLA LIŠKY',12,MUT,True)
txt(48,86,title,32,bold=True);txt(48,118,sub,16,MUT)
line(48,145,1152,145,'#ccd4d6')
line(48,798,1152,798,'#ccd4d6')
txt(48,824,'12/2022 • Aktualizace k 5. 9. 2026 • Koncepční podklad. Rozměry a nejistoty viz list 5.',12,MUT)
txt(1152,824,f'{n} / 5',12,MUT,anchor='end')
def save(name):
svg='<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="850" viewBox="0 0 1200 850">'+''.join(parts)+'</svg>'
(OUT/(name+'.svg')).write_text(svg)
pages.append((name,svg))
def strip(y,items,x=120,scale=80,h=65):
cur=x
for label,width,col in items:
w=width*scale;rect(cur,y,w,h,col,BG,1)
txt(cur+w/2,y+25,label,13,bold=True,anchor='middle')
txt(cur+w/2,y+48,f'{width:.2f}'.replace('.',',')+' m',16,anchor='middle')
cur+=w
return cur
def note(y,title,body):
txt(48,y,title,18,bold=True);lines(48,y+27,body)
page(1,'Čtyři možnosti pro stejné přemostění','Srovnání šířkového rozdělení. Všechny pásy stávajícího profilu mají stejné vodorovné měřítko.')
txt(48,181,'0 STAV PODLE STUDIE 2019',17,bold=True)
strip(197,[('Chodník',1.75,WALK),('Auta + kola',4.25,CAR),('Auta + kola',4.25,CAR),('Chodník',1.75,WALK)])
txt(120,283,'V20 je piktogramový koridor uvnitř vozovky; není vyhrazeným cyklopruhem.',15,MUT)
txt(48,323,'A VYHRAZENÉ CYKLOPRUHY • ODDĚLENÍ ZNAČENÍM',17,bold=True)
strip(339,[('Chodník',1.75,WALK),('Kolo →',1.25,BIKE),('Auta →',3,CAR),('← Auta',3,CAR),('← Kolo',1.25,BIKE),('Chodník',1.75,WALK)])
txt(120,425,'Minimální skladba 8,50 m podle TP 179. Bez rezervy; použitelnost na mostě není potvrzena.',15,MUT)
txt(48,465,'C ODDĚLENÁ STEZKA • PRACOVNÍ PROSTOROVÝ ROZPOČET',17,bold=True)
strip(481,[('Chodník',2,WALK),('Kola obousměrně',3,BIKE),('Auta →',3,CAR),('← Auta',3,CAR),('?',1,'#f0d7b6')])
txt(120,567,'Oranžový 1 m je souhrn zbývající šířky. Jeho poloha neoznačuje umístění oddělení.',15,MUT)
txt(48,607,'L SAMOSTATNÉ LÁVKY • DALŠÍ TRASA MIMO SILNIČNÍ PROFIL',17,bold=True)
strip(623,[('Chodník',1.75,WALK),('Auta + kola',4.25,CAR),('Auta + kola',4.25,CAR),('Chodník',1.75,WALK)],h=58)
txt(120,706,'Stávající profil ponechán jako reference; nová pěší a cyklistická trasa viz situační list 4.',15,MUT)
dim(120,752,960,'12,00 m = součet šířek ve studii; nejde o celkovou konstrukční šířku')
save('01-srovnani-variant')
page(2,'Varianta A: kde vzniká prostor pro kola','Kótovaný pásový řez + ilustrace statické obálky vozidel. Výšky a konstrukce mostu nejsou zakresleny.')
dim(120,202,960,'12,00 m celkem')
strip(221,[('Chodník',1.75,WALK),('Kolo →',1.25,BIKE),('Auta →',3,CAR),('← Auta',3,CAR),('← Kolo',1.25,BIKE),('Chodník',1.75,WALK)],h=68)
dim(260,322,680,'8,50 m vozovka = 1,25 + 3,00 + 3,00 + 1,25 m')
txt(48,372,'Detail dvou automobilových pruhů • stejné vodorovné měřítko jako nahoře',18,bold=True)
# 6 m road; illustrative front silhouettes width 2.55, not design vehicles
rect(360,394,480,143,CAR);line(600,394,600,537,'white',3,'12 9')
for x in (378,618):
rect(x,411,204,103,'#677b87',INK);rect(x+13,421,178,36,'#c5e0e9');rect(x+10,507,25,18,INK);rect(x+169,507,25,18,INK)
txt(x+102,485,'2,55 m',20,'white',True,'middle')
dim(x,565,204,'zvolená obálka')
lines(888,427,['3,00 − 2,55 = 0,45 m','Při vystředění zbývá','0,225 m na každém boku.'],16,step=25)
line(839,462,877,462,WARN,2)
lines(48,614,['Obálka 2,55 m je ilustrační předpoklad, nikoli ověřený rozměr místního autobusu včetně zrcátek.',
'Výkres nezahrnuje vybočení v oblouku, pohyb při jízdě, zrcátka ani potřebné bezpečnostní odstupy.',
'Cyklopruh 1,25 m není čistá jízdní stopa: čáry a odstupy se musí vyřešit podle přesného detailu TP 179.'],16)
rect(48,704,1104,62,'#f0d7b6')
txt(67,730,'ROZHODUJÍCÍ OVĚŘENÍ',13,WARN,True)
txt(67,753,'Míjení autobusů a nákladních vozidel bez pravidelného zásahu do vyhrazených cyklopruhů.',17)
save('02-cyklopruhy-detail')
page(3,'Varianta C: kolik zbývá na oddělení','Pracovní rozpočet šířky. Toto není stavební příčný řez a neurčuje rozmístění obrub či svodidel.')
strip(190,[('Chodník',2,WALK),('Kola obousměrně',3,BIKE),('Auta →',3,CAR),('← Auta',3,CAR),('?',1,'#f0d7b6')],h=80)
dim(120,305,880,'11,00 m pracovně přidělených šířek')
dim(1000,305,80,'1,00 m')
lines(48,352,['Rozpočet 1,00 m musí pokrýt vše nezahrnuté do ostatních šířek: oddělení druhů dopravy,',
'boční odstupy a konstrukční detaily. Potřebná šířka ani její rozdělení zatím nejsou ověřeny.'],18)
txt(48,431,'Citlivost na celkové dodatečné prostorové nároky',21,bold=True)
for y,extra,result,col in [(465,.5,'zbývá 0,50 m','#d8e9df'),(531,1,'přesně 12,00 m; bez rezervy','#f0d7b6'),(597,1.5,'chybí 0,50 m','#edc8c4')]:
rect(48,y,1104,52,col)
txt(66,y+32,f'11,00 m + {extra:.2f} m'.replace('.',','),19,bold=True)
txt(355,y+32,f'= {11+extra:.2f} m'.replace('.',','),19)
txt(590,y+32,result,19)
lines(48,695,['Hodnoty 0,50 / 1,00 / 1,50 m jsou zvolené scénáře, nikoli normová minima.',
'Prověřit: přesun obrub, odvodnění, zatížení a kotvení; bezpečné napojení jednostranného chodníku.',
'Zrcadlové uspořádání stezky je další možnost. Volba strany závisí na návaznostech a přecházení.'],16)
save('03-oddelena-stezka-rozpocet')
page(4,'Situace: řešit celou cestu mezi břehy','Topologické schéma podle studie 2019. Není mapa: polohy, délky, úhly a šířky nejsou v měřítku.')
# Traversal diagram, deliberately topological. Labels avoid compass or exact bridge alignment.
rect(287,180,145,391,WATER);rect(772,180,104,391,WATER)
txt(359,204,'HLAVNÍ TOK LABE',13,MUT,True,'middle');txt(824,226,'KANÁL',13,MUT,True,'middle')
txt(80,251,'BRANDÝS',19,bold=True);txt(555,251,'OSTROV',19,bold=True);txt(947,251,'STARÁ BOLESLAV',19,bold=True)
line(112,330,1090,330,'#9caab2',20)
line(268,330,896,330,INK,3,'9 7')
txt(601,302,'STÁVAJÍCÍ SILNIČNÍ SPOJENÍ • VARIANTY A / C',15,INK,True,'middle')
txt(359,371,'most přes Labe',14,anchor='middle');txt(824,371,'most přes kanál',14,anchor='middle')
# new route as independent conceptual chain
pts=[(120,468),(249,488),(432,488),(648,488),(756,448),(893,448),(1082,476)]
for a,b in zip(pts,pts[1:]):line(*a,*b,'#267b64',7,'10 6')
txt(142,438,'zámek',16,bold=True);txt(346,529,'lávka č. 1',17,'#267b64',True,'middle')
txt(582,529,'cesty na ostrově',16,anchor='middle');txt(824,419,'lávka č. 2',17,'#267b64',True,'middle')
txt(1002,529,'Husova alej',16,anchor='middle')
for x,y,n in [(248,330,'1'),(616,330,'2'),(905,330,'3')]:
circle(x,y,18,WARN);txt(x,y+6,n,17,'white',True,'middle')
lines(48,603,['1 Brandýský přístup: souvislé napojení cyklistů, přechody a vazba na centrum i zámek.',
'2 Ostrov a přístupy: křižovatky, zastávky, boční napojení; neztratit oddělení mezi mostními objekty.',
'3 Boleslavský přístup: pokračování trasy a bezpečné přecházení při jednostranném řešení.'],17,step=30)
rect(48,710,1104,64,'#e7eceb')
lines(66,736,['L = koncepce dvou samostatných lávek podle studie 2019. Schéma nepřebírá přesnou trasu ani aktuální stav stavby.',
'Úprava mostu a lávky nemají totožné návaznosti. Srovnat bezpečnost i délku a pohodlí celé cesty.'],15,step=23)
save('04-situace-navaznosti')
page(5,'Co obrázky dokládají a co ještě chybí','Podklad k zadání variantní studie. Grafická přesnost nesmí být zaměněna za projektové ověření.')
for x,value,label in [(48,'8,50 m','vozovka podle studie 2019'),(425,'13 926','vozidel / den, přepis CSD 2025'),(802,'709','těžkých vozidel / den, tentýž zdroj')]:
rect(x,175,350,99,'#e7eceb');txt(x+18,220,value,32,bold=True);txt(x+18,250,label,14,MUT)
txt(48,313,'Varianta',15,bold=True);txt(285,313,'Co lze nyní porovnat',15,bold=True);txt(720,313,'Rozhodující neověřený bod',15,bold=True)
rows=[('0 Stávající stav','Nominální rozdělení profilu ze studie','Dnešní volné šířky a stav konstrukce'),('A Vyhrazené pruhy','Součet minimální skladby = 8,50 m','Průjezdnost, odstupy a soulad na mostě'),('C Oddělená stezka','11,00 m + dodatečné prostorové nároky','Zda 1,00 m stačí; stavební proveditelnost'),('L Samostatné lávky','Samostatná trasa a jiné návaznosti','Aktuální projekt, srovnatelné náklady')]
for i,(a,b,c) in enumerate(rows):
y=330+i*46;rect(48,y,1104,43,'#ffffff' if i%2==0 else '#edf0ed');txt(61,y+28,a,16,bold=True);txt(285,y+28,b,15);txt(720,y+28,c,15)
lines(48,548,['Podklady: re:architekti, Přemostění Labe, 2019, str. 14–15 (profil), 32–33 a 40–41 (lávky).',
'TP 179 (2017), obr. 11: zdroj minimální skladby varianty A; nejde o úplné ověření mostních předpisů.',
'doprava/data/podklady_rsd.json: profil 1-0521, staženo 1. 8. 2026, rok 2025 označen jako předběžný.',
'Právní a technické zdroje, jejich dostupnost a omezení: navazující rozbor v docs (odkaz v README).'],15,step=25)
lines(48,669,['Další krok: zaměření celého spojení + průjezdnost vozidel + mostní posouzení + sčítání pěších a kol.',
'Model dopravy poskytuje intenzity; neposuzuje geometrii, vlečné křivky ani fyzické oddělení.',
'Žádná z navržených variant zde nemá potvrzenou schvalitelnost, cenu ani konečnou realizovatelnost.'],16,step=26)
save('05-podklady-a-rozhodovani')
pdf=canvas.Canvas(str(OUT/'most-generala-lisky-varianty.pdf'),pagesize=(1200,850))
pdf.setTitle('Most Generála Lišky - srovnání koncepčních variant')
pdf.setAuthor('Pracovní podklad k místní rešerši')
for name,svg in pages:
drawing=svg2rlg(BytesIO(svg.encode()))
pdf.saveState();pdf.scale(1200/drawing.width,850/drawing.height)
renderPDF.draw(drawing,pdf,0,0);pdf.restoreState();pdf.showPage()
pdf.save()
# Standalone browser gallery: vectors embedded, no external libraries or assets.
html='''<!doctype html><html lang="cs"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Most Generála Lišky | varianty</title><style>body{margin:0;background:#dfe5e5;color:#182b35;font:16px Arial,sans-serif}header{padding:24px;max-width:1200px;margin:auto}h1{font-size:25px}a{color:#155c4b}nav{display:flex;flex-wrap:wrap;gap:16px}section{max-width:1200px;margin:24px auto;background:#f7f6f2;box-shadow:0 4px 18px #182b3522}svg{display:block;width:100%;height:auto}footer{padding:24px;text-align:center}@media print{header,footer{display:none}section{margin:0;box-shadow:none;break-after:page}@page{size:A3 landscape;margin:8mm}}</style><header><h1>Most Generála Lišky: koncepční varianty</h1><p>Pět vektorových listů pro porovnání možností. Rozměry doložené studií a pracovní předpoklady jsou rozlišeny v popiscích.</p><nav><a href="most-generala-lisky-varianty.pdf">Stáhnout PDF</a><a href="../most-generala-lisky-cyklopruhy-a-alternativa-lavky.md">Podrobný rozbor</a>'''
for i,(name,svg) in enumerate(pages,1):html+=f'<a href="#list-{i}">List {i}</a>'
html+='</nav></header>'
for i,(name,svg) in enumerate(pages,1):html+=f'<section id="list-{i}" aria-label="List {i}">{svg}</section>'
html+='<footer>12/2022 • Aktualizace k 5. 9. 2026 • Koncepční podklad. Nejde o realizační dokumentaci.</footer></html>'
(OUT/'index.html').write_text(html)
print('Vytvořeno 5 SVG, galerie HTML a 5stránkové PDF.')