V úvodu tohoto blogu bych chtěl pozdravit všechny nadšence vyššího programovacího jazyka C++. V tomto blogu jsem si pro vás připravil téma z objektově orientovaného programování. Z aplikačního hlediska jsem si pro vás připravil implementaci třídy, která reprezentuje válec jako 3D geometrický útvar. To znamená, že se znovu budeme bavit v intencích analytické geometrie. To není z toho důvodu, že bych vás chtěl zatěžovat vyšší matematikou, ale z toho důvodu, že geometrické objekty lze pěkně reprezentovat třídami a objekty implementovanými v jazyce C++.
Už v předchozím kurzu jsem rozvinul myšlenku objektově orientovaného programování a mimo jiné jsem tvrdil, že objekt v jazyce C++ odráží vlastnosti a schopnosti objektu reálného světa. Za takový objekt můžeme považovat také válec, který si nemusíte skutečně sestrojit z nějakého materiálu, ale stačí se na něj dívat z pohledu analytické geometrie.
Takže na začátek si představíme trochu teorie, kterou musíme dotáhnout do konce právě proto, abyste rozuměli zdrojovému kódu, který jsem si pro vás připravil. Potom vás ještě pověřím vyřešením logického úkolu, který když chcete úspěšně splnit, musíte mít dobré poznatky ze základů analytické geometrie. Ale o tom pak...
Je třeba se tedy připravit a zvládnout pojmy jako jsou kartézský souřadnicový systém, bod, vektor, přímka, rovina, jejich algebrický popis, až po skalární či vektorový součin vektorů.
Pojďme ale pěkně popořádku. Na začátku vám položím otázku: Jak jsi ty představuješ válec v prostoru? Určitě bys věděl, jak vypadá jeho tvar, popřípadě bys ho uměl nakreslit. No dobře, z hlediska geometrie může být, ale za těmi čarami se skrývá i konkrétní matematický popis. Začněme tedy bodem.
Bod je základní geometrický útvar, který je ve 3D kartézském prostoru reprezentován třemi souřadnicemi. Souřadnice bodu mohou nabývat jakoukoli hodnotu z oboru reálných čísel. Proč mluvím právě o bodě? Je to z toho důvodu, abych vám usnadnil práci. Válec můžeme definovat právě dvěma body. Konkrétně jsou to body, které leží ve středu dvou podstav válce. To znamená, že střed dolní podstavy a střed horní podstavy válce jasně vymezují výšku válce. Když k tomu přidáme poloměr podstavy, máme přesnou představu, o který válec se jedná.
S tím usnadněním práce jsem to myslel opravdu vážně, asi byste přece nechtěli, kdybych vám definoval rovnici dvou kružnic, které by reprezentovaly podstavy válce, byť tato reprezentace by byla správná. K vysvětlení reprezentace válce, která je vlastní analytické geometrii, vám nabízím následující obrázek:
Na obrázku máte znázorněn 3D kartézský souřadnicový systém, který je vlastní výpočtem v analytické geometrii. Na okraj jen podotknu, že se jedná tedy o systém, který je ortogonální a zároveň ortonormální. V tomto souřadnicovém systému je zobrazen válec, který je jednoznačně určen dvěma body a poloměrem podstav válce. Zmíněné dva body reprezentují právě středy podstav válce.
Vraťme se nyní na chvíli do světa objektově orientovaného programování. Už víme, že chceme reprezentovat válec třídou. Definujme tedy vlastnosti a schopnosti válce. Z kurzů víte, že vlastnosti objektu jsou reprezentovány datovými členy třídy.
Já jsem položil požadavek na datové členy třídy následovně:
mějme datový člen, který bude reprezentovat střed dolní podstavy válce,
mějme datový člen, který bude reprezentovat střed horní podstavy válce,
mějme datový člen, který bude reprezentovat poloměr podstav válce.
Uvedené tři atributy jsou dostatečné k tomu, aby byl válec reprezentován jednoznačně. Já však kladu ještě další požadavky na datové členy třídy válec. Přestože další parametry válce jsou jasně určeny předchozími třemi, chci, aby byly explicitně dopočítány a uloženy do datových členů následující údaje:
výška válce, která je jasně určena vzdáleností středů podstav,
obsah povrchu válce, který je determinován poloměrem a výškou válce,
objem válce, který je také jasně určen poloměrem a výškou válce.
výchozí konstruktor, který bude užitečný při vytváření nové instance třídy a bude inicializovat všechny datové členy na nulové hodnoty,
druhý uživatelem definovaný konstruktor, který se také použije při vytváření nové instance třídy a bude inicializovat hodnoty datových členů na argumenty předávané přes parametry konstruktoru. Tento konstruktor bude tedy parametrický. Kromě inicializace základních tří atributů (středy podstav, poloměr podstav válce) bude dopočítávat atributy výška, obsah a objem válce,
destruktor, který bude dealokovat paměť vyhrazenou pro novou instanci této třídy,
členskou metodu, která bude sloužit k přestavování hodnot datových členů, to znamená, že z válce s původními rozměry a souřadnicemi vznikne jiný válec, který má nové souřadnice a nové rozměry,
členskou metodu, která bude vracet hodnotu souřadnic bodu, který reprezentuje střed dolní podstavy válce,
členskou metodu, která bude vracet hodnotu souřadnic bodu, který reprezentuje střed horní podstavy válce,
členskou metodu, která bude vracet hodnotu poloměru podstav válce,
členskou metodu, která bude vracet hodnotu obsahu povrchu válce,
členskou metodu, která bude vracet hodnotu objemu válce,
členskou metodu, která bude vracet informaci o tom, zda libovolně zvolený bod definovaný třemi souřadnicemi patří do prostoru (objemu válce) nebo ne.
Právě požadavek na poslední členskou metodu je analyticko-logická hádanka, kterou je třeba vyřešit, vyžaduje však širší znalosti z analytické geometrie. Této úloze se budu tedy podrobněji věnovat a to z toho důvodu, abyste řešení pochopili a neztratili se ve spleti matematických vztahů a implementačních detailech.
V úvodu jsme si tedy vysvětlili, že uvedu příklad z objektově orientovaného programování, který bude aplikován na oblast analytické geometrie a to konkrétně na geometrický objekt válec. Dále jsme si ukázali obrázek pro jasnější představu a pochopení úlohy, definovali jsme si požadavky na třídu, kterou lze implementovat a jako poslední jsem zadal úkol, který řeší problém průniku libovolně zvoleného bodu a prostoru válce. Bez dalších okolků vám na následujících řádcích nabízím zdrojový kód, který v sobě skrývá implementaci třídy reprezentující válec, třídu reprezentující bod ve 3D kartézském prostoru, členskou metodu třídy válec, která odpovídá na otázku, zda libovolný bod patří do prostoru válce nebo ne. No ak tomu funkci main(), ve které budeme novou instanci třídy válec používat.
Na řádku 001 je zavolána direktiva preprocesoru #include, která přidává hlavičkový soubor iostream do zdrojového kódu. Část této standardní knihovny potřebujeme, protože chceme používat objekt cout, pomocí kterého budeme zapisovat informaci do okna konzolové aplikace.
Podobně je na řádku 002 opět použita direktiva preprocesoru #include. Tentokrát ovšem kvůli přidání hlavičkového souboru cmath. Tento hlavičkový soubor je také součástí standardní knihovny jazyka C++ a potřebujeme jej, protože budeme používat funkce pow() a sqrt(). Jen pro ozřejmení funkci pow() budeme používat pro výpočet druhé mocniny námi zadaného argumentu a funkci sqrt() pro výpočet druhé odmocniny zadaného argumentu.
Na řádku 003 pomocí klíčového slova using definujeme, že budeme používat jmenný prostor std. Tento řádek jsem do kódu umístil proto, abychom nemuseli ke objektům, třídám a funkcím, které do tohoto prostoru patří, přistupovat přes std a operátor přístupu :: . Kromě toho, že funkce pow(), sqrt(), objekt cout a manipulátor endl přísluší nějakým hlavičkovým souborům, patří i do jmenného prostoru std.
Na řádku 005 je definována konstanta s identifikátorem pi. Ta reprezentuje Ludolfovo číslo a má hodnotu 3,14159. Tuto konstantu potřebujeme k výpočtu obsahu povrchu a objemu válce.
Pokračujeme řádkem 007, na kterém pomocí klíčového slova class deklarujeme třídu s identifikátorem cPoint3D. Tato třída nám bude v programu reprezentovat bod ve 3D karteziánském souřadnicovém systému.
Deklaraci zmíněné třídy začínáme na řádku 008 levou programovou závorkou, za kterou na řádku 009 následuje klíčové slovo public, kterým definujeme, že následujícím členům bude přidělen veřejný přístup.
Na řádcích 010 až 012 jsou tedy deklarovány tři členské metody třídy cPoint3D, přičemž jsou to speciální členské funkce a to konkrétně dva konstruktory a destruktor. Na řádku 010 je deklarován výchozí konstruktor, kterému nepřísluší žádné parametry. Tento konstruktor slouží k vytvoření nové instance třídy cPoint3D s tím, že inicializuje datové členy na nulové (výchozí) hodnoty.
Na řádku 011 je deklarován uživatelem definovaný konstruktor, který slouží také k vytvoření nové instance třídy, přičemž pomocí svých parametrů, přes které se předávají konkrétní argumenty (souřadnice bodu), inicializuje datové členy třídy. Rozdíl mezi prvním a druhým konstruktorem je ten, že první nepotřebuje parametry, protože inicializuje datové členy na 0, které lze pak přestavit jinou členskou metodou na konkrétní hodnoty, zatímco druhý konstruktor přiřazuje datovým členům nenulové hodnoty prostřednictvím argumentů předávaných přes parametry konstruktoru. K úplnosti textu uvádím, že druhý konstruktor má tři parametry x, y, az právě proto, že bod ve 3D prostoru má tři souřadnice ak tomu přísluší také tři členské proměnné třídy cPoint3D. Jsou to proměnné se stejným identifikátorem jako parametry konstruktoru, tedy x, y, z. Existují informační zdroje, které zpochybňují a nedoporučují totožnost identifikátorů parametrů konstruktorů a členských proměnných třídy. Já však toto názvosloví považuji za běžné a správné z toho důvodu, že existuje klíčové slovo this, které reprezentuje uvnitř objektu ukazatel na objekt a lze jeho prostřednictvím přistupovat k datovým členům. Tímto zápisem (syntaxou) se dá odlišit identifikace parametru a členské proměnné objektu. Je přece jasný rozdíl mezi x a this->x. První je parametr konstruktoru a druhé datový člen, ke kterému přistupujeme pomocí ukazatele.
Na řádku 012 je deklarován destruktor, který nám bude sloužit k dealokaci paměti vyhrazené pro novou instanci třídy cPoint3D po jejím vytvoření. Destruktory jsou speciální členské funkce tříd, které slouží právě ke zmíněnému účelu, jednoduše řečeno, mají za úkol uklidit po objektu v paměti.
Na řádcích 013 až 015 jsou deklarovány tři datové členy x, y az, kterým je přidělen typ double. Tyto reprezentují souřadnice bodu ve 3D kartézském souřadnicovém systému.
Na řádku 016 se uzavírá deklarace třídy cPoint3D pravou programovou závorkou a středníkem. Jen připomenu, že středník tam musí být uveden, je to jeden z ojedinělých případů v jazyce C++, kdy se používá středník za programovou závorkou.
Na řádku 018 začíná definice výchozího konstruktoru třídy cPoint3D.
Jedná se o bezparametrický konstruktor, který inicializuje datové členy na řádcích 020 až 022 na nulu.
Po tomto přiřazení se konstruktor ukončuje pravou programovou závorkou na řádku 023.
Na řádku 025 začíná definice druhého uživatelem definovaného konstruktoru téže třídy, který na rozdíl od prvního má tři parametry, jehož prostřednictvím se předávají argumenty reprezentující souřadnice bodu ve 3D karteziánském souřadnicovém systému.
Tyto se na řádku 027 až 029 přiřazují jednotlivým datovým členům.
Konstruktor končí na řádku 030 pravou programovou závorkou.
Na řádcích 032 až 035 je uvedena definice destruktoru třídy cPoint3D. Jeho tělo je prázdné a neobsahuje žádný kód tak, jak to bývá u většiny destruktorů. Pro zopakování úlohou destruktora je dealokovat (uvolnit) paměť, která byla konkrétní instanci třídy vyhrazena.
Ve zdrojovém kódu se na řádku 037 dále pokračuje deklarací třídy cCylinder, která nám bude reprezentovat právě geometrický objekt válec.
Na řádku 038 je uvedena levá programová závorka, která otevírá zmiňovanou deklaraci. Za ní je uvedeno klíčové slovo public, které slouží k přidělení veřejného přístupu k datovým členům a členským metodám, které jsou dále deklarovány. Zatímco třída cPoint3D měla pouze veřejné datové členy a členské metody, třída cCylinder obsahuje také členy soukromé. To znamená, že při této třídě budeme využívat techniku skrývání některých datových členů. Obor platnosti veřejného přístupu platí ve zdrojovém kódu po klíčové slovo private, tedy po klíčové slovo, které nastavuje jiný typ přístupu ke členům třídy. Pro úplnost informace dodám, že členům třídy může být přidělen ještě třetí typ přístupu protected, což v překladu znamená chráněný přístup. Tento typ přístupu však v tomto úkolu využívat nebudeme.
Vraťme se ale zpět ke zdrojovému kódu.
Na řádcích 040 až 050 jsou deklarovány všechny členské metody, kterým je přidělen veřejný přístup. Tyto si postupně rozebereme.
Na řádku 040 je uvedena deklarace výchozího konstruktoru, který má za úkol inicializovat všechny datové členy třídy na nulové hodnoty. Jako poznámku uvedu, že nevidím moc smysl těchto konstruktorů, ale v praxi se volí právě zmiňovaný postup. To znamená, že se vytvoří dva konstruktory, jeden bez parametrů, jehož funkcionalita byla zmíněna výše a druhý konstruktor s parametry, přes které můžete datovým členům přiřadit již konkrétní nenulové hodnoty. Ke výchozímu konstruktoru je třeba potom doprogramovat implementaci metody (tzv. setter), která má stejnou funkci jako konstruktor s parametry. Rozdíl oproti použití parametrického konstruktoru je ten, že inicializujete datové členy třídy ve dvou krocích. V prvním kroku definujete objekt s inicializací datových členů výchozími nulovými hodnotami a ve druhém kroku se pak tyto členy inicializují na uživatelem zadanou hodnotu. Pro úplnost doplním, že smysl používání výchozích konstruktorů vidím při pointrové aritmetice, to znamená v případech, kdy jsou datové členy deklarovány jako směrníky základních vestavěných typů nebo typů, které jsou definovány uživatelem. Tehdy slouží výchozí konstruktor kromě vytvoření objektu pro alokaci paměti (konkrétně haldy) pro daný typ pomocí operátora new.
Na řádku 041 je deklarován druhý konstruktor, který má tři parametry. První a druhý parametr jsou typu cPoint3D, ty reprezentují souřadnice středů podstav válce. Třetí parametr reprezentuje poloměr podstav válce. To jsou tři parametry, pomocí kterých lze jednoznačně definovat válec.
Na řádku 042 je deklarován destruktor třídy cCylinder. Stejně jako u předešlé třídy má za úkol dealokovat paměť, která je vyhrazena pro novou instanci této třídy.
Pokračujeme deklarací členské metody SetCylinder() na řádku 043. Jedná se o tvz. setter, neboli metodu, která má za úkol nastavit hodnoty členských dat třídy.
Na řádcích 044 a 045 jsou deklarovány členské metody GetV1() a GetV2(). Tyto metody nemají žádné parametry a vracejí typ cPoint3D. Úkolem první z nich je vracet informaci o souřadnicích středu dolní podstavy válce, druhá z nich vrací informaci o souřadnicích středu horní podstavy válce.
Na řádcích 046 až 049 jsou deklarovány členské metody GetRadius(), GetHeight(), GetContent() a GetVolume(). Jsou to gettery, které mají návratový typ double. V takovém pořadí, jak byly jmenovány, slouží k tomu, aby vraceli hodnotu členských dat, která reprezentují poloměr, výšku, obsah a objem válce.
Na řádku 050 je deklarována členská metoda BelongToCylinder(). Jako návratový typ vrací bool. Tato metoda slouží ke zjištění toho, zda libovolně zvolený bod ve 3D karteziánském souřadnicovém prostoru patří do prostoru (objemu) válce nebo ne. Podotýkám, že vyřešení tohoto logického úkolu je nejnáročnější, protože musíte znát hlubší souvislosti z analytické geometrie. Ostatní implementace třídy cCylinder je poměrně jednoduchá záležitost oproti zmiňovanému úkolu.
Na řádku 052 je uvedeno klíčové slovo jazyka C++ private, které zajistí, že dále deklarované datové členy budou mít soukromý přístup.
Na řádcích 053 a 054 jsou pak deklarovány datové členy V1 a V2, které reprezentují střed dolní a horní podstavy válce. Právě proto jim byl přidělen datový typ cPoint3D.
Dále jsou na řádcích 055 až 058 deklarovány datové členy radius, height, content a volume. Je jim přidělen datový typ double a ve stejném pořadí reprezentují poloměr, výšku, obsah a objem válce.
Na řádku 059 je uvedena pravá programová závorka a středníkem, které uzavírají deklaraci uživatelem definovaného typu (třídy) cCylindr. Implementační detaily (definice) této třídy pokračuje na dalších řádcích zdrojového kódu.
Na řádcích 061 až 069 je uvedena definice výchozího konstruktoru cCylinder. Konstruktor nemá žádné parametry, jeho úkolem je vytvářet novou instanci třídy cCylinder a inicializovat všechny datové členy této třídy na nulové hodnoty.
Na řádcích 071 až 079 je uvedena definice druhého uživatelem definovaného konstruktoru, která má tři parametry. První dva jsou typu cPoint3D, pomocí nichž se předávají souřadnice středů dolní a horní podstavy válce. Přes třetí parametr, který je typu double, se předává hodnota poloměru válce. Datovým členům V1, V2 a radius jsou přímo přiřazeny hodnoty příslušejících parametrů konstruktoru. Hodnota datového členu height, která reprezentuje výšku válce, je vypočtena ze souřadnic bodů podstav. Výše válce se totiž rovná vzdálenosti těchto bodů, která je geometricky dána jako druhá odmocnina součtu mocnin rozdílu jednotlivých souřadnic dvou bodů. Vztah pro výpočet vzdálenosti dvou bodů je následující:Hodnota datového členu content, který reprezentuje obsah povrchu válce, je determinován výškou válce a poloměrem podstavy válce. Vztah pro výpočet obsahu povrchu válce je následující:
Podle uvedeného vztahu se vypočítá obsah povrchu válce, jehož hodnota je přiřazena do členské proměnné content na řádku 077. Na řádku 078 je vypočtená hodnota objemu válce a přiřazena do členské proměnné volume. Objem válce je determinován také poloměrem a výškou válce podobně, jako tomu bylo při výpočtu obsahu povrchu válce. Vztah pro výpočet objemu válce je následující:
Na řádku 079 je uvedena pravá programová závorka, která uzavírá definici uživatelem definovaného konstruktoru třídy cCylinder.
Na řádcích 081 až 084 je uvedena definice destruktoru třídy cCylinder. Tělo destruktora je prázdné, jeho úkolem je dealokovat paměť, která byla vyhrazena pro novou instanci třídy cCylinder.
Na řádcích 086 až 094 je uvedena definice členské metody SetCylinder, která má návratový typ void, čili vrací absenci informace. Tato metoda je tzn. setter, který má za úkol nastavit (přestavit) hodnoty datových členů třídy cCylinder. Jeho funkcionalita je stejná jako u uživatelem definovaného konstruktoru s tím rozdílem, že tato metoda není volána při vytváření nové instance. Může být však aplikována na instanci, která již byla vytvořena. Při jejím volání se změní parametry válce, čili lze jí definovat jiný válec ve 3D kartézském prostoru.
Na řádcích 096 až 099 je definována členská metoda GetV1(). Má návratový typ cPoint3D, přičemž je to getter, který má za úkol vrátit souřadnice středu dolní podstavy válce, který je objektem třídy cCylindr reprezentován.
Na řádcích 101 až 104 je definována členská metoda GetV2(). Má také návratový typ cPoint3D a podobně jako předešlá metoda má za úkol vrátit souřadnice středu podstavy válce, v tomto případě se však jedná o horní podstavu.
Na řádcích 106 až 109 je definována členská metoda GetRadius(). Vrací návratový datový typ double, který reprezentuje poloměr podstavy válce.
Na řádcích 111 až 114 je definována členská metoda GetHeight(). Jejím úkolem je vrátit hodnotu datového člena height, který reprezentuje výšku válce.
Na řádcích 116 až 119 je definována členská metoda GetContent(). Tato metoda má za úkol vrátit hodnotu datového člena content, který reprezentuje vypočtený obsah povrchu válce.
Na řádcích 121 až 124 je definována členská metoda GetVolume(). Tato metoda má za úkol vrátit hodnotu datového člena volume, který reprezentuje vypočtený objem válce.
Na řádcích 126 až 157 je definována členská metoda BelongToCylinder(). Úkolem této metody je rozhodnout o tom, zda bod zadaný přes parametr patří do prostoru (objemu) válce nebo ne. Návratový typ této metody je bool, který reprezentuje právě pravdivostní hodnotu zmiňovaného rozhodnutí. Pokud bod se souřadnicemi zadanými přes parametr metody patří do prostoru válce, metoda vrací hodnotu true, ne-li, vrací hadnotu false. Na první pohled se zadaný úkol zdá jednoduchý, není tomu však tak. Právě proto uvedu následující předpoklady, které budeme potom analytickým postupem (výpočtem dokazovat):
patří-li bod do prostoru válce, musí být kolmá vzdálenost tohoto bodu od osy válce menší nanejvýš rovna poloměru podstavy válce,
patří-li bod do prostoru válce, musí být kolmá vzdálenost tohoto bodu od jeho dolní podstavy menší nanejvýš rovna výšce válce,
patří-li bod do prostoru válce, musí být kolmá vzdálenost tohoto bodu od jeho horní podstavy menší nanejvýš rovna výšce válce.
K uvedeným předpokladům ještě dodám, že nestačí splnění jednoho nebo dvou z nich. Pokud chceme potvrdit výrok, že konkrétní bod patří do prostoru válce, musí být splněny všechny tři uvedené podmínky. Úspěšné vyřešení úkolu, má následující postup:
1. Vypočítáme souřadnice směrového vektoru přímky, která prochází středy obou podstav válce. Této přímce říkáme osu válce, která je jasně definována zmíněnými dvěma body (střed dolní a horní postavy válce). Souřadnice vypočítáme odečtením dvou bodů, což znamená, že provedeme rozdíl příslušných souřadnic bodů podle následujících vztahů:
2. Dále sestrojíme rovinu, která je kolmá na osu válce a zároveň prochází bodem, o kterém rozhodujeme, zda patří do prostoru válce nebo ne. Jelikož směrový vektor osy válce je totožný s normálovým vektorem zmíněné roviny, umíme vyjádřit koeficienty a, b, c, které jsou součástí obecného tvaru rovnice roviny. Z uvedeného vyplývá, že potřebujeme dopočítat už jen koeficient d obecného tvaru rovnice roviny. Obecný tvar rovnice přímky je tedy následující:
Když z uvedené rovnice vyjádříme koeficient d, dostaneme následující matematický vztah:
Po vypočtení koeficientu d, pokračujeme následujícím krokem, ve kterém počítáme souřadnice bodu, který vznikne průnikem osy válce a rovinou, která je na ni kolmá a prochází bodem, o kterém rozhodujeme, zda patří do prostoru válce nebo ne.
3. Mějme tedy osu válce (přímku), která je dána následujícím parametrickým vyjádřením
Po rozvinutí pro jednotlivé souřadnice, vzniknou následující rovnice:
Protože počítáme průnik přímky a roviny, dosaďme rovnice 3.2, 3.3 a 3.4 do rovnice 2.1, vznikne nám následující matematický vztah.
Protože koeficienty a, b, c jsou souřadnice směrového vektoru osy válce, můžeme napsat:
Po úpravě rovnice 3.6 a vyjádření parametru t, dostaneme následující vztah:
4. Po vypočtení koeficientu t, můžeme vypočítat souřadnice bodu, který vznikne průnikem osy válce a zmíněné roviny podle následujících vztahů
5. Označme bod, o kterém rozhodujeme, zda patří do prostoru válce identifikátorem A, dále označme bod, který vznikne průnikem osy válce a zmiňované roviny jako bod B, vzdálenost těchto dvou bodů pak vypočítáme podle následujícího vztahu
Jak již bylo řečeno, je-li tato vzdálenost menší nanejvýš rovna poloměru podstavy válce, máme splněn první předpoklad, že zadaný bod patří do prostoru válce.
6. V tomto kroku budeme pokračovat analytickým způsobem, kterým budeme dokazovat, že bod splňuje druhý předpoklad, to znamená, že vzdálenost bodu od dolní podstavy válce je menší než výška válce. Budeme vycházet ze vztahu 2.2 a vypočítáme koeficient d pro rovinu, která je kolmá na osu válce, prochází však středem dolní podstavy válce. Tato rovina má stejný normálový vektor jako rovina, která procházela tím bodem, o kterém rozhodujeme, jestli patří do prostoru válce nebo ne. Koeficienty a, b, c, které vystupují v obecném tvaru rovnice roviny, přísluší tedy hodnotám souřadnic směrové vektoru osy válce. Z uvedené vyplývá, že když známe souřadnice normálového vektoru roviny a známe bod, který v ní leží (střed dolní podstavy válce), umíme vyčíslit hodnotu koeficienta d.
7. Po předchozím kroku nám už stačí dopočítat vzdálenost bodu od podstavy přímým vztahem, který je následující:
Pokud je tato vzdálenost menší nanejvýš rovna výšce válce, máme splněn druhý předpoklad, abychom mohli tvrdit, že bod patří do prostoru válce.
8. Pokračujeme výpočtem vzdálenosti bodu od horní podstavy válce. Sestrojíme tedy rovinu, která je kolmá na osu válce a prochází středem horní podstavy válce. K tomuto přijedeme stejným způsobem jako v kroku 6. Obdobně podle vztahu 7.1 vypočítáme předmětnou vzdálenost. Pokud je tato menší nanejvýš rovna výšce válce, máme splněn poslední předpoklad, pro tvrzení výroku, že zadaný bod patří do prostoru válce. Právě tento postup je zachován při implementaci řádků zdrojového kódu 128 až 156. K označení jednotlivých parametrů, které byly součástí průběžného výpočtu se pouze použily v některých případech jiné identifikátory.
Na řádku 128 je deklarována proměnná typu bool s identifikátorem flag. Do ní se uloží informace, která bude reprezentovat pravdivostní hodnotu výroku o tom, zda bod do prostoru válce patří či nikoli. Na začátku ji inicializujeme hodnotou true.
Na řádku 130 je deklarována proměnná u1, která reprezentuje x složku směrového vektoru osy válce, vypočtená je jako rozdíl x souřadnic bodu V2 a V1.
Na řádku 131 je deklarována proměnná u2, která reprezentuje y složku směrového vektoru osy válce, vypočtená je jako rozdíl y souřadnic bodu V2 a V1.
Na řádku 132 je deklarována proměnná u3, která reprezentuje ze složku směrového vektoru osy válce, vypočtená jako rozdíl ze souřadnic bodů V2 a V1. Pro doplnění informace, identifikátory V1 a V2 patří datovým členům třídy cCylinder, které reprezentují souřadnice středů podstav válce.
Na řádku 134 je vypočtena hodnota proměnné d1, která reprezentuje koeficient d v obecném tvaru roviny, která je kolmá na osu válce a prochází bodem X (bod, o kterém rozhodujeme). Tento koeficient je potřebný k tomu, aby byla kompletní rovnice roviny v prostoru. Potom lze vypočítat parametr t podle vztahu 3.7. Právě tento vztah modeluje přiřazovací příkaz na řádku 135.
Po výpočtu parametru t můžeme definovat bod XT (bod, který je kolmým průmětem bodu X na osu válce), který je typu cPoint3D. Ten je definován na řádku 137 tak, že se zavolá konstruktor třídy cPoint3D, kterému se předají hodnoty argumentů. Tyto hodnoty se vypočítávají podle vztahů pro výpočet souřadnic bodu ležícího na přímce, která je dána svým parametrickým vyjádřením (vztahy 4.1 až 4.3).
Na řádku 139 je deklarována proměnná dist_01, které se přiřazuje výpočet vzdálenosti bodu X od osy válce. Ta se vypočítá jako geometrická vzdálenost dvou bodů ve 3D kartézském prostoru, a to konkrétně bodu X a XT podle vztahu 5.1.
Na řádcích 141 a 142 jsou vypočteny hodnoty proměnných d2 a d3, které reprezentují koeficient d rovin, které procházejí středy podstav válce a jsou kolmé na osu x. Z těchto koeficientů, směrového vektoru a souřadnic bodů X se vypočítávají vzdálenosti bodu od horní a dolní postavy válce. Tyto vzdálenosti se ve zdrojovém kódu počítají na řádcích 144 a 145.
Na řádku 147 je uveden příkaz if, ve kterém je vyhodnocena pravdivost výrazu, který je tvořen třemi jednoduchými výroky. První z nich tvrdí, že vzdálenost bodu od osy válce je menší nebo rovna poloměru válce. Druhý z nich tvrdí, že vzdálenost bodu od dolní podstavy válce je menší nebo rovna výšce válce. A poslední z výroků obdobně tvrdí, že vzdálenost bodu od horní podstavy válce je menší nebo rovna než výška válce. Výroky jsou pospojovány logickým operátorem and, což znamená, že jsou-li současně všechny pravdivé, složený výrok je také pravdivý a řízení programu přejde na řádek 149, kde se hodnotě flag přiřadí pravdivostná hodnota true. Je-li jen jeden ze tří výroků nepravdivý, složený výrok je nepravdivý také, což znamená, že bod nepatří do prostoru válce a řízení programu přejde na řádek 153 do klauzule else, kde se přiřadí hodnotě flag pravdivostná hodnota false. Na řádku 156 se vrací hodnota proměnné flag pomocí klíčového slova return.
Na řádku 159 začíná definice funkce main(), kterou volá operační systém. V těle této funkce jsou na řádku 161 a 162 vytvořeny nové instance třídy cPoint3D, které reprezentují středy podstav válce. Na řádku 163 je vytvořena nová instance třídy cCylinder, kde se pomocí parametrů konstruktoru předávají argumenty reprezentující středy podstav a poloměr válce. Na řádcích 165 až 173 jsou do okna konzolové aplikace zapsány informace o tom, zda body, jejichž souřadnice zadané jako argumenty členské metody BelongToCylinder(), patří do prostoru válce nebo ne. Celkově jsme volali tuto členskou ve zdrojovém kódu 8krát. To znamená, že jsme prověřovali osm bodů. Jen pro informaci prvních pět patřilo do prostoru válce a další tři ne. Pro správnost programu si výsledky můžete ověřit analytickým postupem, který je v předchozím textu uveden.
Na řádku 175 se pouze přechází v okně konzolové aplikace na další řádek. Na řádcích 177 až 179 jsou již jen zavolány destruktory definovaných objektů z důvodu dealokace paměti. Na řádku 181 je vrácena hodnota 0 operačnímu systému. Na řádku 182 se ukončuje tělo funkce main() pravou programovou závorkou. V závěru vám chci poděkovat za přečtení blogu. Doufám, že vás článek, který se týkal objektově orientovaného programování a příkladu z analytické geometrie zaujal. Podstatnou přidanou hodnotou zdrojového kódu byla členská funkce, která rozhodla o tom, zda bod zadaný jako argument této funkce patří do prostoru válce či nikoli. Byl to skutečně náročnější úkol a proto jsem rád, že jste řešení pochopili a spolu se mnou tento úkol rozlouskli.
🥇 Sme jednotka v online vzdelávaní na Slovensku. Na našom webe nájdeš viac ako 300 rôznych videokurzov z oblastí ako programovanie, tvorba hier, testovanie softwaru, grafika, UX dizajn, online marketing, MS Office a pod. Vyber si kurz, ktorý ťa posunie vpred ⏩