# Bábofkátor 0.4

Nástroj pro korekci **podkosů a úkosů** 3D mesh modelu (STL) a automatickou tvorbu
**inverzní jednodílné formy** s definovanou tloušťkou stěny a lemem. Odlitek z takové
formy jde vyjmout prostým vysunutím podél osy kolmé na otevřenou plochu formy.

Aplikace běží lokálně na Macu, má webové rozhraní s 3D náhledem i příkazovou řádku,
a nepotřebuje žádnou externí CAD knihovnu ani připojení k internetu.

---

## Instalace na macOS

1. Rozbal archiv a přetáhni **`Bábofkátor.app`** do složky Aplikace.
2. **První spuštění provedeš pravým tlačítkem → Otevřít → Otevřít.** Aplikace není
   podepsaná u Applu, takže obyčejný dvojklik ji poprvé odmítne; přes tuhle cestu
   projde a od té chvíle už stačí dvojklik.
3. Objeví se okno s ukazatelem průběhu, které jednorázově stáhne výpočetní
   knihovny (~300 MB, pár minut) do `~/Library/Application Support/Babofkator`,
   samo se zavře a spustí aplikaci. Systémový Python se nemění a mimo tuto složku
   se nic nezapisuje; průběh se zapisuje do `instalace.log` v téže složce.
   Terminál se neotevírá — textová instalace zůstává jen jako záloha pro případ,
   že by v systémovém Pythonu chybělo tkinter.

Vyžaduje Python 3.9 nebo novější. Není-li v systému, instalátor to oznámí a otevře
stránku [python.org](https://www.python.org/downloads/macos/) — stačí balík
*macOS 64-bit universal2*.

Odinstalace: smazat `Bábofkátor.app` a složku `~/Library/Application Support/Babofkator`.
Smazáním téže složky se také vynutí čistá reinstalace při dalším spuštění.

---

## Jak se s tím pracuje

V levém panelu přetáhneš `.stl`, `.obj` nebo `.ply`, nastavíš parametry a stiskneš **Spočítat formu**.
V pravé části je 3D náhled (původní reliéf / korigovaný model / forma, včetně
drátového režimu) a záložka **Protokol a mapy** s číselným protokolem a barevnými
mapami výšky, úkosů, podkosů a provedené změny. Výsledná STL se stahují z levého
panelu.

Výsledky se ukládají tlačítkem **Uložit soubory na disk** — zapíše STL i protokol
do `~/Dokumenty/Bábofkátor/<název modelu>/` a nabídne otevření složky ve Finderu.
V nativním okně aplikace se předtím objeví systémový výběr složky. Odkazy ke
stažení pod ním fungují při práci přes prohlížeč; v nativním okně nikoli, protože
WKWebView stahování souborů nepodporuje.

Volba **Kvalita** řídí krok mřížky: *Rychlý náhled* (600 px) pro zkoušení parametrů,
*Standard* (1200 px) pro běžnou práci, *Jemná* (2000 px) a *Maximální* (3000 px) pro
finální export. U reliéfu 210 mm to odpovídá kroku 0,38 / 0,19 / 0,11 / 0,08 mm.
*Vlastní nastavení* odemkne přímé zadání kroku, tolerance zjednodušení sítě
a vyhlazení.

Příkazová řádka dělá totéž bez prohlížeče (cesta vznikne při instalaci):

```bash
"~/Library/Application Support/Babofkator/babofkator" model.stl -d 3 -w 3 -r 5 -o vystup --png
```

| přepínač | význam | výchozí |
|---|---|---|
| `-d, --draft` | požadovaný úhel úkosu ve stupních (odklon stěny od osy vyjmutí) | 3 |
| `-w, --wall` | tloušťka stěny formy (mm) | 3 |
| `-r, --rim` | šířka lemu (mm) | 5 |
| `--res` | krok mřížky (mm), 0 = automaticky | 0 |
| `--cells` | cílová hustota automatické mřížky (px na delší straně) | 1200 |
| `--mode` | `add` (přidat materiál) / `cut` (ubrat) / `balanced` | add |
| `--back` | `shell` (plášť kopíruje reliéf) / `flat` (rovný hřbet) | shell |
| `--rim-smooth` | zjednodušení obrysu lemu (mm); −1 = jako šířka lemu, 0 = vypnuto | −1 |
| `--up` | osa vyjmutí: `auto`/`z`/`y`/`x` | auto |
| `--smooth` | vyhlazení přechodů v pixelech | 0 |
| `--plane` | souřadnice Z dělící roviny | min Z modelu |
| `--png` | uložit i náhledové mapy | — |

Výstupy: `*_korigovany.stl`, `*_forma.stl`, `*_protokol.json` a volitelně mapy `*.png`.

---

## Vstupní předpoklady

Model je reliéf v poloprostoru nad dělící rovinou. Čtou se formáty **STL** (binární
i ASCII), **OBJ** a ASCII **PLY**. Osa vyjmutí se rozpozná automaticky — reliéf leží
na rovině, takže podél správné osy je u minima nahromaděno nejvíc vrcholů; OBJ
z Blenderu bývá Y-up a program to pozná sám. Ruční volba je v rozhraní i jako
přepínač `--up`. Dělící rovina se implicitně položí na nejnižší bod modelu, jinak
`--plane`. Vstup nemusí být dokonale uzavřený — algoritmus pracuje s horní obálkou
povrchu, ne s topologií vstupu.

---

## Co se uvnitř děje

### 1. Analýza úkosů

Úkos každé stěny je definován jako odklon stěny od osy vyjmutí:

```
δ = 90° − ∠(n, ẑ) = arcsin(n · ẑ)
```

Svislá stěna má tedy δ = 0°, vodorovná horní plocha δ = 90° a **podkos** je
každá stěna s δ < 0°. Aplikace spočítá plošně vážené rozdělení úkosů celé sítě,
podíl podkosů a podíl stěn s úkosem pod nastaveným prahem.

Lokální test podle normály je ovšem jen *nutnou* podmínkou odformovatelnosti —
neodhalí globální podkosy, kdy stěnu se správným úkosem zastiňuje jiná část modelu
(klasický „hřib“). Ty se řeší v dalším kroku.

### 2. Odstranění podkosů — horní obálka

Klíčové tvrzení, na kterém celý nástroj stojí:

> Těleso je odformovatelné jednodílnou formou ve směru +Z **právě tehdy**, když je
> popsatelné výškovým polem `h(x, y)`, tedy `Solid = { (x,y,z) : 0 ≤ z ≤ h(x,y) }`.

Řezy takového tělesa rovinami `z = konst` tvoří vnořenou klesající posloupnost,
dutina formy tedy směrem nahoru pouze roste a odlitek lze vysunout bez kolize.
Naopak, není-li těleso výškovým polem, existuje svislá přímka protínající ho ve
dvou oddělených intervalech a mezi nimi je materiál formy, který vysunutí brání.

Model se proto rasterizuje z-bufferem do výškového pole `h₀(x,y)` = maximum Z přes
všechny trojúhelníky nad daným bodem. Tato **horní obálka** je nejmenší možná
úprava, která odstraní všechny podkosy najednou — lokální i globální. Objem
materiálu, který obálka doplnila, se vypisuje v protokolu.

### 3. Korekce úkosů — Lipschitzova obálka

Výškové pole má v každém bodě úkos `δ = arctan(1 / |∇h|)`. Podmínka „všude alespoň
δ_req“ je proto přesně ekvivalentní tomu, že `h` je *s*-Lipschitzovská funkce
s `s = cot(δ_req)`. Minimální úpravy jsou dvě:

* **horní obálka** (režim `add`, přidání materiálu)
  `h_up(p) = max_q ( h(q) − s·|p − q| )` — nejmenší *s*-Lipschitzovská funkce ≥ h;
* **dolní obálka** (režim `cut`, odebrání materiálu)
  `h_lo(p) = min_q ( h(q) + s·|p − q| )` — největší *s*-Lipschitzovská funkce ≤ h;
* jejich aritmetický průměr je opět *s*-Lipschitzovský (režim `balanced`).

Úprava je z podstaty lokální: boční dosah je `Δh / s`, tedy pro 3° a výškový skok
10 mm pouhých 0,52 mm. Celkový tvar modelu se proto prakticky nemění — u zkušebního
aztéckého reliéfu (210 mm, objem 321 cm³) činila korekce úkosů 917 mm³, tedy 0,29 %
objemu, a dotkla se 0,6 % plochy.

Obálka se počítá chamfer „fast sweepingem“ s 16-okolím doplněným o **exaktní**
neomezené jednorozměrné scany (trik s kumulativním maximem), takže výpočet je
lineární v počtu pixelů. Zbytkovou anizotropii metriky nástroj neodhaduje, ale
**měří**: po každé iteraci spočítá skutečný maximální sklon výsledné trojúhelníkové
plochy a je-li požadavek nesplněn, zpřísní cíl a obálku přepočítá. Dodržení
zadaného úhlu tedy platí i po triangulaci, a to s minimální nutnou rezervou
(typicky 3,00° místo požadovaných 3,00°).

### 4. Inverzní forma

Forma je těleso `{ (x,y,z) : h(x,y) ≤ z ≤ O(x,y) }`, kde `h` je korigovaný reliéf
(dutina) a `O` je jeho **skutečný ekvidistantní offset** o tloušťku stěny `t`,
spočtený jako morfologická dilatace tělesa koulí o poloměru `t`:

```
O(p) = max_{|q−p| ≤ t} ( h(q) + √(t² − |q−p|²) )
```

Tím je zaručena tloušťka měřená kolmo k povrchu, nikoli jen svisle — u téměř
svislých stěn reliéfu by svislý offset dal blánu o tloušťce `t·cos θ`, tedy pro 3°
úkos jen 0,16 mm. Diskretizace je vedena tak, aby výsledek byl vždy *nejvýše
nepatrně silnější*, nikdy tenčí než zadaná hodnota.

Otevřená plocha formy je dělící rovina `z = 0`. **Lem** vzniká jako průnik reliéfu
s dělící rovinou (půdorysná silueta), roztažený o zadanou šířku; v této mezikruhové
oblasti je dno formy rovné a plášť má přesně nastavenou tloušťku. Půdorys formy tedy
kopíruje tvar předlohy — není to kvádr ani obálkový obdélník.

Na obrysu lemu se navíc provádí morfologické **uzavření** o zadaném poloměru
(implicitně rovném šířce lemu): zahladí úzké vruby a ostré vnitřní rohy, které by
v lemu vznikly u členitých siluet. Uzavření může doménu jen zvětšit, nikdy zmenšit,
takže lem nikde neztenčí pod zadanou šířku. Vypíná se `--rim-smooth 0`.

Volba `--back flat` nahradí kopírující plášť rovným hřbetem, aby forma při odlévání
stála.

### 5. Meshování a kontrola

Obě plochy se převádějí na trojúhelníkovou síť omezeným kvadrantovým stromem
(2 : 1 vyvážení, vějířová triangulace se vkládáním středů hran u jemnějšího
souseda). Rovinné oblasti — lem, ploché pozadí — se tak slučují do velkých bloků,
zatímco detail zůstává v plném rozlišení; oproti rovnoměrné síti to znamená zhruba
třetinu až pětinu trojúhelníků beze ztráty přesnosti (tolerance je nastavitelná
a implicitně 0,03 mm, tedy hluboko pod rozlišením tiskárny).

Konstrukce je z principu 2-manifold a vodotěsná: každá boční stěna se generuje
právě jednou a spodní i horní plocha používají tutéž triangulaci buněk. Každý
výstup se navíc automaticky kontroluje — počet volných hran, nemanifoldních hran,
konzistence orientace normál, Eulerova charakteristika, znaménko objemu — a
výsledek je součástí protokolu.

---

## Ověření

V adresáři `tests/` je sada kontrol (`python3 tests/test_all.py`) nad pěti
záludnými modely: kvádr se svislými stěnami, polokoule se svislou tečnou u paty,
„hřib“ s masivním globálním podkosem, rybinová lišta rozšiřující se vzhůru
a vlnitý reliéf s převislým pyskem a jehlami. Kontroluje se mimo jiné:

* shoda chamfer obálky s exaktním výpočtem hrubou silou (odchylka 1,3 %),
* dodržení zadaného úkosu měřené **na skutečných trojúhelnících** výstupu,
* vodotěsnost, manifoldnost, orientace normál a Eulerova charakteristika = 2,
* minimální tloušťka stěny formy,
* zpětná kontrola: vyexportovaný korigovaný model se znovu načte a musí mít nulový
  počet stěn se záporným úkosem a objem pod horní obálkou shodný s objemem tělesa
  (odchylka < 0,1 %) — což je přesně důkaz, že je výškovým polem, tedy odformovatelný.

Modely pro testy vygeneruje `python3 tests/make_test_models.py`.

---

## Struktura

```
babofkator/
  stlio.py     čtení STL / OBJ / ASCII PLY a zápis STL, bez závislostí
  analysis.py  úkosy po trojúhelnících, statistiky, detekce podkosů
  raster.py    z-buffer rasterizace do výškového pole (horní obálka)
  draft.py     Lipschitzovy obálky, měření skutečně dosaženého úkosu
  mold.py      ekvidistantní offset koulí, doména lemu, sestavení formy
  meshing.py   vodotěsné meshování dvojice výškových polí + kvadrantový strom
  validate.py  kontrola integrity sítě
  pipeline.py  celý řetězec a protokol
  preview.py   mapy a náhledy
  cli.py       příkazová řádka
  webapp.py    lokální webové rozhraní (Flask)
  desktop.py   spuštění v nativním okně (pywebview) s návratem do prohlížeče
  static/      rozhraní + lokální kopie three.js (funguje i bez internetu)
```

---

## Známá omezení

Jednodílná forma s jedním směrem vyjmutí je principiálně omezená: podkos nelze
odformovat, lze ho jen zaplnit. U modelů typu „hřib“ proto obálka doplní velký
objem materiálu — protokol to hlásí položkou *objem zaplněný obálkou*, ať je
zřejmé, co se stalo. Pro takové tvary je namístě buď dvoudílná forma, nebo pružná
silikonová forma s trhací stěnou; obojí je mimo záběr tohoto nástroje.

Výpočet pracuje na pravidelné mřížce, přesnost detailu je tedy dána jejím krokem.
Automatická volba míří na 1200 px na delší straně (u modelu 210 mm to je 0,19 mm);
jemnější krok se vybere v nabídce Kvalita, za cenu delšího výpočtu a většího STL.
Téměř svislé stěny jsou ve výškovém poli reprezentovány jen několika pixely, takže
právě u nich je rozlišení nejvíc znát.

Model se předpokládá orientovaný tak, že dělící rovina je rovina XY a osa vyjmutí
je Z. Natočení modelu do optimální polohy nástroj nehledá.

Historie verzí je v `CHANGELOG.md`. Licence MIT.
