4. Reaktivní strom rozdělující binární prostor

Zatím žádná ze struktur prezentovaných v této práci nekombinovala geometrické schopnosti spolu vícenásobnými úrovněmi detailů. To je proto, že zatím nebyla prezentována žádná reaktivní datová struktura. V této kapitole uvedeme první reaktivní datovou strukturu. Bude se jednat o hlavní paměťovou strukturu (Main Memory Structure), která je modifikací BSP stromu (Binary Space Partitioning Tree). BSP-strom je jednou z mála prostorových datových struktur, která neuspořádává prostor do obdélníků. Byl implementován systém, na němž se ukázalo, že stromy rozdělující binární prostor skutečných map mají složitost ukládání O(n) oproti teoreticky nejhoršímu případu O(n2), kde n je počet liniových úseků v mapě. [1]

4.1. BSP-strom a některé jeho variace

Dále budeme prezentovat popis originálního BSP-stromu spolu s modifikacemi pro prostředí GIS. Začneme originálním BSP-stromem a dále popíšeme dvě jeho modifikace pro GIS, a tedy objektový BSP strom a multi-objektový BSP-strom. To jsou úložné struktury pro polylinie a polygony. Dále ukážeme, jak pomocí BSP-stromu mohou být efektivně implementovány základní prostorové operace, a poukážeme na důležitost začlenění úrovní detailů.

4.1.1. Původní BSP-strom

Původní BSP-strom se využíval v 3D počítačové grafice. Používal ho Fuchs k vytvoření skrytého povrchu obrázku statické 3D scény. Po fázi předzpracovaní je možné vytvořit obraz z jakéhokoliv směru pohledu v O(n) čase, kde n je počet polygonů v BSP-stromu. [1]

Obrázek 7. Vytvoření BSP-stromu. [1]

Vytvoření BSP-stromu. [1]

BSP-strom může být používán pro strukturované uchovávání geometrických dat. Jedná se o datovou strukturu, která není založena na obdélníkovém rozdělování prostoru. Využívá liniových úseků polylinií a okrajů polygonů k rozdělení prostoru rekurzivním způsobem. BSP-strom odráží toto rekurzivní dělení prostoru. Prostor (případně podprostor) je pokaždé rozdělen do dvou podprostorů takzvaným rozdělovacím primitivem (splitting primitive) a odpovídající uzel je přidán do stromu. BSP-strom reprezentuje organizaci prostoru souborem konvexních podprostorů v binárním stromu. Strom je užitečný během prostorového vyhledávání a ostatních prostorových operací. Obrázek 7a zobrazuje 2D prostor s některými usměrněnými liniovými úseky. (2D prostor je zde použit pro snazší ilustraci, ale princip u 3D prostoru zůstává stejný.) Levá strana liniového úseku je označena šipkou. Z této scény je vybrán liniový úsek a. 2D prostor je rozdělen do dvou částí a podporuje linii a, která je znázorněna čárkovanou linií na obrázku 7b. Tento proces se opakuje pro každý ze dvou podprostorů i s ostatními liniovými úseky. Rozdělování prostoru pokračuje, dokud liniové úseky jsou přítomné. Poznamenejme, že rozdělování prostoru občas naznačuje, že liniový úsek (který ještě nebyl použit pro rozdělování jako takový), je již na dvě části rozdělen. Linie d je například je rozdělena do d1 a d2. Obrázek 7b ukazuje výslednou organizaci prostoru, jako soubor (pravděpodobně otevřených) konvexních podprostorů. Odpovídající BSP-strom je nakreslen na obrázku 7c. Ve 3D případě se používají podpůrné roviny plochých polygonů k rozdělení prostoru místo linií.

Vytváření stromu je velice ovlivněno volbou liniového úseku pro rozdělení prostoru. Preferované je mít vyvážený BSP-strom s co nejméně uzly, jak jen je možné. A to je velmi obtížně splnitelný požadavek, protože vyvažování stromu potřebuje, aby k rozdělení prostoru byly používány liniové úseky ze středu souboru dat. Tyto liniové úseky pravděpodobně rozdělí další liniové úseky. Každé rozdělení liniového úseku vytváří navíc uzel v BSP-stromu. Diskuse ohledně vyvažování tohoto stromu viz [1]. Následuje ukázka programu, který tvoří BSP-strom. Kód je syntakticky podobný Pascalu.

Program BuildTree;
type BSP = ^node; 
     node = record segm: Line; 
                   l, r: BSP 
            end; 
var root: BSP; 
    newsegm: Line; 

function AddLine(tree:BSP; segm:Line): BSP; 
var Lsegm, Rsegm: Line; 
begin 
   if (tree = nil) then tree := CreateNode(tree, segm) 
   else case LinePosition(tree,segm) of 
        LEFT: tree^.l := AddLine(tree^.l, segm); 
        RIGHT: tree^.r := AddLine(tree^.r, segm); 
        SPLIT: SplitLine(tree, segm, Lsegm, Rsegm); 
               tree^.l := AddLine(tree^.l, Lsegm); 
               tree^.r := AddLine(tree^.r, Rsegm); 
   AddLine:=tree; 
end; 
begin 
   root := nil; 
   while GetLine(newsegm) do root := AddLine(root, newsegm); 
end.

Program BuildTree je variací tradiční (neinkrementující) metody pro stavbu BSP-stromu. Procedura SplitLine, funkce LinePosition, CreateNode a GetLine nejsou zahrnuty, protože jejich implementace je zřejmá. Uzel v BSP-stromu je reprezentován záznamem (record) typu uzel (node), který obsahuje liniový úsek a ukazatele na levého a pravého potomka. Zpočátku je strom prázdný. A to trvá dokud GetLine nepřivolá nový liniový úsek, který se přidá do BSP-stromu zavoláním funkce AddLine. AddLine kontroluje, jestli byla v BSP-stromu nalezena správná pozice. Výsledek je true, pokud ukazatel na strom v BSP-stromu ukazuje na nil. V tom případě se vytvoří nový uzel a přidá do stromu. Jinak LinePosition určí, ve kterém podstromu bude liniový úsek uložen. Uložení liniového úseku je implementováno rekurzivním voláním AddLine. Je možné, že liniový úsek musí být nejprve rozdělen.

Rozdělování liniových úseků má vážný nedostatek. Pokud máme na scéně n liniových úseků, pak je možné, že dosáhneme složitosti O(n2) uzlů ve stromu. Tato složitost, jak již bylo řečeno, je v GIS aplikacích nepřijatelná. V GIS aplikacích se totiž běžně setkáváme s 10 000 a více liniovými úseky. Skutečný počet uzlů nebude tak veliký, protože uvažujeme nejhorší případ. BSP-strom je myšlený pro interaktivní aplikace, ve kterých jsou vyžadovány rychlé odezvy. Minimalizace využívání paměti je pokládána za méně důležitou, proto se jí zde příliš věnovat nebudeme. Typické využití paměti je kolem 3 až 4 krát velikosti originálních mapových dat. Pro to existují 3 důvody: místo v paměti vyžadované pro ukazatele, pro rozdělování liniových úseků a pro replikaci bodů. Konec jednoho liniového úseku je často začátek dalšího.

4.1.2. Objektový BPS-strom

Dosud probíraný BSP-strom sloužil pouze k ukládání kolekcí dat (nesouvisejících) liniových úseků. V modelovacím systému musí být možné reprezentovat uzavřený objekt, ve 2D případě například interiér polygonu. Objektový BSP-strom je rozšířením BSP-stromu s možností reprezentace objektů. Ukládá liniové úseky, které dohromady tvoří hranici polygonu. Objektový BSP-strom má explicitní koncové uzly, které už neobsahují liniové úseky k dalšímu rozdělování podprostorů. Koncové uzly odpovídají konvexnímu podprostoru, který je vytvořený BSP-stromem. Datový typ boolean v koncovém uzlu značí, zdali je konvexní podprostor uvnitř anebo vně objektu.

Objektový BSP-strom je na univerzitě v Leidenu používán k 3D grafickému modelování. [1] Díky jeho prostorové organizaci mohou být skryté povrchy odstraněny při O(n) složitosti, kde n značí počet polygonů ve stromu. Objektový BSP-strom je rovněž vhodný k vykonávání souboru operací jako je union, difference a intersection, tak jako se používají v CSG (Constructive Solid Geometry) systémech. Operce mapového překrytí (map overaly operation) v GIS má silnou návaznost na tento soubor operací.

4.1.3. Multi-objektový BSP-strom

V GIS, kde obvykle pracujeme s 2D mapami, si přejeme využívat prostorovou organizaci BSP-stromu. Liniové úseky originální databáze jsou používány k rekurzivnímu rozdělení prostoru. Používáním dat spojených s řešením problému organizace prostoru, očekáváme lepší prostorovou organizaci (v porovnání se situací, kde jsou použity fixně rozdělené linie, jako například v čtyřstomu). Mapy vždy obsahují vícenásobné objekty, například země na mapě Evropy. K tomu, abychom se vypořádali s vícenásobnými objekty, musíme pozměnit koncept objektového BSP-stromu. Místo datového typu boolean, koncové uzly budou obsahovat identifikační tag se jménem. Tento identifikační tag nám řekne, kterému objektu bude patřit konvexní podprostor, reprezentovaný koncovým uzlem. Tomuto typu BSP-stromu říkáme multi objektový BPS-strom.

Obrázek 8. Stavba multi objektového BPS stromu. [1]

Stavba multi objektového BPS stromu. [1]

Obrázek 8a reprezentuje 2D prostor se dvěma objekty, trojúhelníkem T se stranami a, b, c, a obdélníkem R se stranami d, e, f, g. Metoda rozděluje prostor v konvexních podprostorech obrázku 8b. BSP-strom obrázku 8c je rozšířen určitými uzly, kde každý reprezentuje konvexní část prostoru. Pokud konvexní podprostor odpovídá oblasti zvenku, není vykreslena žádná jmenovka (label), viz obrázek 8c. Pokud je dovolen maximálně jeden identifikační tag na list, mohou být uchovány v multi-objektovém BSP stromu pouze vzájemně vylučující se objekty. Jinak by totiž bylo možné setkat se s objekty, které se překrývají. Nevýhodou tohoto BSP stromu je, že reprezentace jednoho objektu je rozptýlena přes několik listů, například obdélník R na obrázku 8. Obrázek 9 ukazuje využití BSP-stromu pro jednoduchou polygonální mapu.

Obrázek 9. BSP-strom pro jednoduchou polygonální mapu. [1]

BSP-strom pro jednoduchou polygonální mapu. [1]

Jako obvykle, vnitřní uzly obsahují linie úseků a koncové uzly reprezentují konvexní části podprostoru. Nevýhody BSP-stromu jsou zřejmé z obrázku 9. Občas je nutné rozdělit liniové úseky (okraje f) a další nevýhodou je, že polygon může být rozdělen do dvou nebo více koncových uzlů (region II do listů 6, 7 a 9). Následující seznam shrnuje vlastnosti multi objektového BSP stromu:

  • každý uzel ve stromu odpovídá konvexnímu podprostoru

  • každý vnitřní uzel rozděluje konvexní podprostor na dvě části: levou a pravou. Čím jdeme níže do stromu, tím jsou konvexní podprostory menší. Každý vnitřní uzel obsahuje jeden liniový úsek.

  • Každý koncový uzel odpovídá konvexnímu podprostoru, ve kterém už nebude dále dělen. Koncový uzel neobsahuje liniový úsek, ale obsahuje identifikaci objektu.

4.2. Základní prostorové operace

Základními prostorovými operacemi jsou získání informací o objektu (pick) a vyhledávání v obdélníku (rectangle search)

4.2.1. Získání informací o objektu

Uvažujme systém, který zobrazuje mapu na obrazovce. Uživatel vybere bod P = (x, y) vstupním zařízením, například myší, a chce vědět, na který bod zrovna ukázal. K vyřešení tohoto problému nalezneme bod P sestupováním po BSP-stromu, dokud nenarazíme na koncový uzel. Koncový uzel obsahuje identifikační tag objektu. Sestupování stromem je jednoduché: pokud na vnitřním uzlu leží bod P na levé straně liniového úseku, pak následujeme levou větev, jinak pravou. Tato strategie má za důsledek jednu konkrétní cestu od kořene až ke koncovému uzlu. V případě vyvažování stromu s n vnitřními uzly zabere vyhledávání O(log n) času. Tento výsledek je pravděpodobně nejlepším možným.

4.2.2. Obdélníkový výběr

V mnoha aplikacích uživatel chce vybrat všechny objekty uvnitř nějakého obdélníku R. Vyhledávání pomocí obdélníků je nutné pro zobrazení části mapy na obrazovce. Průchod stromem je v podstatě stejný jako u operace pick. Pokud je překrytí mezi obdélníkem R a levým podprostorem, pak je na vnitřním uzlu následována levá větev; pravá větev je následována, pokud je překrytí mezi pravým podprostorem a obdélníkem R. Pokud je překrytí v obou podprostorech, pak musí být následovány obě větve. Toto zařídí jednoduchá rekurzivní funkce. Operace jsou efektivní, protože části stromu jsou přeskakovány. V nestrukturované kolekci dat bychom museli navštívit každou položku a testovat pokud ji přijmeme na základě jejích geometrických vlastností. Při používání BSP-stromu nemusíme zkoumat data, která neleží v oblasti našeho zájmu.

4.3. Úrovně detailů

Pokud chceme vytvářet interaktivní GIS, tak potřebujeme úrovně detailů. Úrovně detailů navíc nesmí být uloženy redundantně, ale musí být kombinovány s prostorovou datovou strukturou. Nejenom geometrická data musí být organizována s úrovněmi detailů, ale to samé platí i k souvisejícím tematickým datům. (Ačkoliv se budeme zaměřovat hlavně na geometrická data.)

Nejprve budeme pozorovat BSP-strom vytvořený funkcí AddLine. Na začátku vložený liniový úsek zřejmě skončí v jedné z nejvyšších úrovní BSP-stromu. Liniový úsek, vložený déle, musí nejprve cestovat stromem dolů (a pokud je potřeba, tak být rozdělen, a to i několikrát) než dosáhne správného umístění v nižší úrovni BPS-stromu. Těchto vlastností využíváme k vytvoření reaktivního BSP-stromu. Pokud víme, tak reaktivní BSP-strom je první reaktivní datovou strukturou vůbec kdy prezentovanou [1]. Pakliže globální data jsou vložena do BSP-stromu dříve, skončí ve vyšší úrovni. Lokální data (detailní) jsou vložena později, a tak skončí v nižších úrovních BSP-stromu. Obrázek 10 ukazuje tuto situaci na mapě Nizozemí. Obdélník v globální mapě ukazuje pozici detailu mapy. Objekt vypadající jako hora reprezentuje celý BSP-strom a šedá oblast značí část BSP-stromu, která obsahuje data odpovídající dané mapě.

Obrázek 10. Umístění globálních a lokálních dat. [1]

Umístění globálních a lokálních dat. [1]

K ilustraci, jak funguje reaktivní BSP-strom, použijeme příklad prezentace dat ze sčítání lidu v Nizozemí. V Nizozemí existuje množství hierarchických úrovní administrativních jednotek od obcí (nejnižší úroveň) až přes provincie až po celou zemi (nejvyšší úroveň), viz obrázek 11. Vkládáme hranice administrativních jednotek do BSP-stromu tak, že začneme na nejvyšší úrovni, pak na další vyšší a tak dále. Během zobrazení mapy, počet zobrazených úrovní detailů závisí na velikosti vybrané oblasti. Čím větší oblast potřebujeme zobrazit, tím se zobrazí méně detailů. Heuristické pravidlo praví: „Celkové množství zobrazených geometrických dat by mělo být konstantní“. (Měřené podle počtu souřadnic, které jsou zahrnuty.) Řečeno více formálně: „Obrazová informační hustota musí být konstantní.“

Obrázek 11. Obce a provincie. [1]

Obce a provincie. [1]

BSP-strom procházíme uzpůsobeným algoritmem obdélníkového vyhledávání a zobrazujeme všechny objekty v určité oblasti podle určité úrovně detailů. Algoritmus musí vědět, kde jedna detailní úroveň končí a kde začíná další. Tohoto může být dosaženo rozšířením BSP-stromu podle jednoho z následujících dvou bodů:

  • Přidáme každému uzlu jmenovku (label) s odpovídající úrovní detailů. Pokud během procházení BSP-stromu je dosaženo úrovně detailů, která je nižší než ta, která nás zajímá, můžeme tuto větev přeskočit, protože obsahuje data pouze z nižší úrovně.

  • Přidáme speciální zastavovací uzly (level stop nodes), po vložení globálních dat (nejvyšší úrovně) do BSP-stromu. Tyto uzly neobsahují žádné rozdělovací úseky linií a jsou srovnatelné s koncovými uzly BSP-stromu, viz oddíl 4.1.3 multi-objektový BSP strom. Potom další vyšší úroveň je přidána do BSP-stromu, znovu následována zastavovacími uzly. Tento proces se opakuje pro každou danou úroveň detailů. Obrázek 12 ukazuje reaktivní BSP-strom s dvěma úrovněmi detailů.

Obrázek 12. Reaktivní BSP strom. [1]

Reaktivní BSP strom. [1]

Nevýhodou reaktivního BSP-stromu je, že podporuje pouze část generalizačního mapového procesu. Umí odstraňovat nepotřebné linie, ale ty potřebné kreslí se stejným počtem definičních bodů při každém měřítku. Pokud víme, tak neexistuje elegantní řešení pro tento problém pro případ BPS-stromu. [1] Je tedy možné uchovávat generalizovanou verzi linie na vícenásobných úrovních detailů ve stejném BSP-stromu, byť tedy toto uchování představuje nechtěnou redundantnost. Generalizovaná verze linie může být spočtena explicitně pro každou úroveň liniovým generalizačním algoritmem, například pomocí Douglas-Peuckerova algoritmu. [1]