Pravidlo č. 1)
Předpočítat co nejvíce hodnot předem. Při vykreslování už jen použijeme vypočtené hodnoty.
Celý níže uvedený postup je vlastně 3D koule v prostoru a její jednotlivé pixely přenesené do 2D plochy - na papír.
Začneme samotnou kružnicí
Abych dokázal nakreslit kouli, musím umět nakreslit kružnici.
Vyjdu ze vzorce:
r2 = x2 + y2
a v cyklu
y=1, y< Poloměr koule*2
(poloměr koule je dán, je to jediná fixně zadaná hodnota - velikost koule)
vypočítám veškeré hodnoty, které budu používat.
tj.
PoloměrKružnicevŘezu = Math.Sqrt ( PolomerKoule2 - ( PolomerKoule - y)2 )
Říká, kolik bodů je v každém řezu kružnice(*2, jde o poloměr). Pro každý takový bod budu potom počítat velikost kruhové výseče, jak v ose X, tak ose Y. Tj. samotnou deformaci.
ObvodKružnicevŘezu = 2 * π * PoloměrKružnicevŘezu
Aby byla koule koulí a ne bramborou, potřebuji tuto hodnotu. Velikost kruhového oblouku se vztahuje k prostorovému objektu. My máme ale 2D monitory a tak musím ve výsledku obvod kružnice dostat do správného měřítka. Do správného poměru. viz hodnota PoměrX
PočetPixelůkZačátkuKružnice = PolomerKoule - PoloměrKružnicevŘezu
Pro samotné vykreslení kružnice. Na této pozici začínám kreslit kouli.
PoměrX = (PoloměrKružnicevŘezu * 2) / (ObvodKružnicevŘezu / 2)
Hodnota o které jsem mluvil. Délka kruhové výseče * tento poměř = index do bitmapy.
Nyní mám kružnici, přejdu k výpočtu samotných kruhových oblouků.
Kruhový oblouk, to je to zelené a červené :)
Procházíme všechny řezy koule.Nejprve v ose Y, potom v ose X.
V každém takovém řezu spočítáme velikost kruhového oblouku pro každý bod poloměru kružnice v řezu.
Dále tuto hodnotu vynásobím poměremX a mám ukazatel do bitmapy pro každý bod kružnice.
Velice důležité jsou hodnoty p1 a p2, což jsou nezbytné pomocné proměnné, které budou níže použity při překlopení os X a Y. Jde vlastně o výpočet okrajů. Bude vysvětleno podrobněji níže.
Začneme tedy osou Y:
Základní cyklus, směr odshora dolů a zleva doprava do půlky koule.
y=1; y< poloměr koule*2
zde počítám všechny proměnné jako:
PoloměrKružnicevŘezu, ObvodKružnicevŘezu , PočetPixelůkZačátkuKružnice , PoměrX
x=0; x< PolomerKruznicVrezu
Procházím všechny body řezu koule a počítám výseče.
Ty šipky naznačují jednotlivé cykly.
Obrázek b) je vlastně pohled shora.
Abychom mohli spočítat kruhovou výšeč, musíme pro ně znát jednotlivé uhly.
v jednom cyklu počítáme najednou levou a pravou stranu.
Pro levou to je
COS alfa = přilehlá ku přeponě
alfa = ACOS (PoloměrKružnicevŘezu - x) / PoloměrKružnicevŘezu
L = (ObvodKružnicevŘezu / 2π) * alfa
LcacheX[y, x] = L * PoměrX ;
Pro pravou to je
SIN beta = protilehlá ku přeponě
beta = ASIN (x / PoloměrKružnicevŘezu)
L = (ObvodKružnicevŘezu / 2π) * beta
k hodnotě L ale ještě připočteme 1/4 obvodu kružnice, protože potřebujeme celou délku oblouku, viz dlouhá zelená čára.
ukládáme do bufferu takto:
LcacheX[y, x + PoloměrKružnicevŘezu] = (L + ObvodKružnicevŘezu /4) * PoměrX ;
Už nyní bychom mohli výsledek zobrazit. Kulovitý efekt se projeví již nyní. My se ale s deformací jen v ose X nespokojíme a zdeformujeme i Y :) Viz obrázek c)
Výpočet je naprosto identický, jen osově převrácený. Má to ale jeden háček a to jsou okraje.
Musí být vypočítány kvůli správnému uložení na pozici bufferu.
Spodní okraj je stejný pro celý cyklus.
SpodníOkraj = PoloměrKoule - PoloměrKružnicevŘezu
Levý okraj se počítá extra pro každý bod zvlášt
Modifikovaný výpočet délky kruhového oblouku
Oblouk podle spodní části obrázku
Pro to je
COS alfa = přilehlá ku přeponě
alfa = ACOS (PoloměrKružnicevŘezu - x) / PoloměrKružnicevŘezu
LevýOkraj = PoloměrKoule - SQRT ( PoloměrKoule2 - ( r- x )2 )
L = (ObvodKružnicevŘezu / 2π) * alfa
LcacheY[SpodníOkraj + x, y - LevýOkraj ] = L * PoměrY + SpodníOkraj
zde si povšimněte prohození os. X ukládám do Y a Y do X.
Oblouk podle horní části obrázku
SIN beta = protilehlá ku přeponě
beta = ASIN (x / PoloměrKružnicevŘezu)
LevýOkraj = PoloměrKoule - SQRT ( PoloměrKoule2 - x2 )
L = (ObvodKružnicevŘezu / 2π) * beta
k hodnotě L ale ještě připočteme 1/4 obvodu kružnice, protože potřebujeme celou délku oblouku, viz dlouhá zelená čára.
ukládáme do bufferu takto:
LcacheY[SpodníOkraj + x + PoloměrKružnicevŘezu, y - LevýOkraj ] = (L + ObvodKružnicevŘezu /4) * PoměrY + SpodníOkraj
Je to trochu komplikované, člověk se v tom snadno ztratí. Sám jsem musel využít mozkovou kapacitu do posledního neuronu, abych to všechno vymyslel :) Pro lepší pochopení ještě jedno schéma.
Algoritmus počítá kruhové oblouky a ukládá je do dvou rozměrného pole[y,x]
jenže to X začíná v poli na hodnotě 0 a tak jsou ty oblouky v poli uložené tak, jak ukazuje zelená čára níže.
Tak jak je ukládám, tak je potom i čtu a samotnou kouli vykresluji.
Když počítám tu obrácenou osu, musím toto uložení / vykreslování respektovat, musím posunout okraje. Ty deformace v obou osách musí odpovídat identické hodnotě X, Y.
Ještě k samotnému vykreslování.
Jak už obrázek napovídá, jsou to dva vnořené cykly.
y=1; y< poloměr koule*2
x=0; x< PolomerKruznicVrezu
Lx = lcacheX[ y, x ];
Ly = lcacheY[ y, x ];
barva = BmpArraySrc[PoziceY + Ly , PoziceX + Lx + PočetPixelůkZačátkuKružnice ]
Závěrem : Možná by bylo lepší, ukládat ty oblouky do pole ne od 0, ale na pozici, kde začíná kružnice. Odpadly by pak komplikace s okraji. Asi ano. No, to už nechám k posouzení koňovi. Za mě hotovo
© Bura.cz