Hlavní navigace

Modelujeme složitější tělesa ve VRML

Pavel Tišnovský 29. 11. 2007

Ve VRML je možné kromě základních těles jako krychle, koule, kužel a válec vytvářet i složité objekty pomocí takzvaných množin plošek (face set). Tvůrci VRML nezapomněli ani na podporu plošné vektorové grafiky, drátových modelů a také množin bodů, které lze využít při tvorbě částicových systémů.

Obsah

1. Seznam prostorových souřadnic
2. Množina vrcholů (bodů v prostoru)
3. První demonstrační příklad – body v prostoru
4. Množina polyčar (lomených čar)
5. Množina polygonů (plošek)
6. Druhý demonstrační příklad – použití prostorových úseček a plošek pro vytvoření složitějšího objektu
7. Výšková pole

1. Seznam prostorových souřadnic

V následujících kapitolách si popíšeme a na několika demonstračních příkladech ukážeme použití tří typů uzlů, které se mohou v souborech typu VRML 2 vyskytovat a které se velmi často používají při modelování složitějších objektů, jež není možné jednoduše popsat pomocí základních (primitivních) těles, tj. krychle, koule, kužele či válce. Jedná se o takzvané množiny vrcholů (PointSet), množiny polyčar (IndexedLineSet) a množiny rovinných plošek (IndexedFaceSet). Ve všech třech typech uzlů se geometrie objektů zapisuje s využitím seznamu prostorových souřadnic.

661

Základní (primitivní) tělesa, pro něž ve VRML 2 existují zvláštní typy uzlů

Seznamy prostorových souřadnic jsou ve VRML 2 reprezentovány zvláštním uzlem nazvaným Coordinate, který ve svém těle (datové části) obsahuje pole souřadnic bodů/vrcholů umístěných v prostoru. Pole souřadnic je pojmenované jednoduše point a zahrnuje pro každý bod či vrchol tři souřadnice oddělené bílým znakem, tj. typicky mezerou nebo více mezerami. Trojice souřadnic jsou od sebe pro přehlednost odděleny čárkou. Jak uvidíme v dalším textu, není tento způsob zápisu typický pouze pro úschovu polí souřadnic, ale používá se například i pro zápis pole barev nebo dokonce i polí indexů do jiných polí. Na dále uvedeném příkladu zápisu uzlu typu Coordinate si všimněte, že vždy po třech číslech typu SFFloat oddělených mezerou následuje čárka, za kterou je zapsána další trojice souřadnic. Čárka zde slouží jako oddělovací znak, ne jako znak ukončovací.

Coordinate {
    point [0 0 0, 2 2 2, 3.14 0.5 -5, 42 0 3]
} 

Pokud někomu vyhovuje zápis souřadnic každého bodu (vrcholu) na zvláštní řádek, může využít volného formátu VRML, což znamená, že syntaxe není závislá na umístění bílých znaků ani konců řádků. Touto vlastností se VRML dosti zásadním způsobem odlišuje například od, v tomto seriálu již popisovaného, formátu DXF. Mnoho exportních filtrů by předchozí příklad zapsalo například následujícím způsobem:

Coordinate {
    point [
        0 0 0,
        2 2 2,
        3.14 0.5 -5,
        42 0 3
    ]
} 

V některých případech jsou vynechány i mezery na začátku řádků, čímž dojde k citelnému snížení velikosti souboru. Uzel typu Coordinate je použitý buď samostatně, nebo (a to je v praxi mnohem častější) je použit jako nosič geometrických informací uvnitř uzlů typu PointSet, IndexedLineSet a IndexedFaceSet. Vše si ukážeme v dalších kapitolách.

2. Množina vrcholů (bodů v prostoru)

Pomocí uzlu nazvaného PointSet je možné do vytvářeného modelu vložit objekt složený z množiny bodů umístěných v trojrozměrném prostoru. Každému bodu zapsanému v tomto uzlu je přiřazena souřadnice v prostoru a v případě potřeby také barva (její zápis však není povinný). Všem bodům jako celku lze také přiřadit materiál pomocí nám již známého uzlu Material. V tomto případě je ovšem nutné dát si pozor na to, že body nemají specifikované normály, takže se pro ně nedá počítat plnohodnotné osvětlení podle Phongova osvětlovacího modelu. Z tohoto důvodu se většinou v uzlu Material specifikuje emisní složka světla, tj. body vyzařují zadanou barvu. Pokud by byla ponechaná implicitní barva (ta je černá), nebyly by body na černém pozadí viditelné. I v případě nastavení emisní složky světla na nějakou barvu se však nejedná o plnohodnotné světelné zdroje, to by ostatně nebylo při velkém počtu bodů výpočetně zvládnutelné. Samotná syntaxe zápisu uzlu PointSet je poměrně jednoduchá:

PointSet {
    color # pole barev
    coord # pole souřadnic uložených v uzlu typu Coordinate
} 

Kde se dají množiny bodů použít? Určitě se nejedná o prvek často využívaný v dnes preferované polygonální (hraniční) reprezentaci těles. Přesněji řečeno, existují situace, kdy se trojrozměrné objekty vykreslují pouze pomocí bodů, ale ty nenastávají často, zejména ne při použití moderních grafických akcelerátorů. Ale své využití tyto entity zcela jistě mají. Především je lze použít pro statický popis takzvaných částicových systémů. Částicové systémy (také nazývané systémy částic, anglicky particle systems) představují velice silnou modelovací a animační techniku určenou pro vytváření takových objektů, které není možné jednoduše reprezentovat svým povrchem nebo objemem. Jedná se například o objekty představující přírodní fenomény, jakými jsou sníh, déšť, oheň, mlha, dým nebo tekoucí voda. Kombinace částicových systémů s tělesy složenými z polygonů je dnes používána poměrně často, typicky ve hrách či aplikacích virtuální reality. Samotné částicové systémy se uplatňují například v různých vizualizačních algoritmech.

Druhé použití mají množiny bodů při přenosu základních informací o ještě nezpracovaných modelech těles. Například 3D skenery mohou získaná data ukládat právě jako množiny bodů s tím, že jejich další zpracování, tj. vytvoření povrchu složeného z polygonů nebo NURBS, je ponecháno na dalších aplikacích.

3. První demonstrační příklad – body v prostoru

Dnešní první demonstrační příklad, jehož zdrojový soubor si můžete stáhnout zde, ukazuje použití bodových entit při vykreslování objektů. Jako objekt, který se má zobrazovat pomocí bodů, jsem vybral původní zdrojová data světoznámé Newellovy čajové konvice, známé také pod názvem Utah Teapot. Jedná se o řídicí body použité pro vytvoření Bézierových plátů, z tohoto důvodu také není tvar konvice dobře viditelný (bodů je relativně málo). Na internetu se dají stáhnout i podrobnější modely, které vznikly rozdělením Bézierových plátů na menší polygony (plošky), ovšem množství dat a tím i velikost výsledného VRML souboru by neúměrně vzrostlo. Barvy bodů byly nastaveny na čistě bílou, aby byly na černém pozadí dobře viditelné.

#VRML V2.0 utf8
# verze 2.0 vyzaduje kodovani UTF-8

# ---------------------------------------------------------
# Prvni demonstracni priklad trojrozmerne sceny
# popsane jazykem VRML 2.0, ktera obsahuje teleso slozene
# z mnoziny bezrozmernych bodu.
#
# Priklad je soucasti serialu "Graficke formaty"
# (/serialy/graficke-formaty/)
# vychazejiciho na Root.cz (http://www.root.cz)
# ---------------------------------------------------------

WorldInfo {
    title "Prvni 3D scena s nekolika objekty a bodovym svetelnym zdrojem"
    info ["Autor: Pavel Tisnovsky, 2007"
         "sireno pod licenci GPL "
         "(zde mohou byt dalsi texty"]
}

# nastaveni cerneho pozadi sceny
Background {
    skyColor [0.0 0.0 0.0]
}

# nastaveni pozice pozorovatele
Viewpoint {
    position 0.0 2.0 10.0
}

# nastaveni svetelneho zdroje
PointLight {
    color    1.0 1.0 1.0 # barva svetla
    intensity 1.0        # intenzita bodoveho svetla
    location 0.0 4.0 1.0 # pozice svetelneho zdroje
}

Shape {
    # vzhled objektu - negeometricke informace
    appearance Appearance {
        material Material {
            emissiveColor 1 1 1   # vyzarovana slozka svetla
        }
    }
    # tvar objektu - geometricke informace
    geometry PointSet {
        # interni poduzel se souradnicemi bodu
        coord Coordinate {
            point [
    1.4 0.0 2.4,
    1.4 -0.784 2.4,

    # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    # v tomto miste by bylo uvedeno dalsich 555 :-) radku dat
    # o vrcholech; stahnete si prosim plnou verzi prikladu
    # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    -0.0539286 -0.999643 0.0178571,
    -0.000357143 -1 0.0,
    -0.000357143 -1 0.0,
    -0.000535714 -1 0.0178571,
    -0.000357143 -1 0.0178571,
            ]
        }
    }
}



# ---------------------------------------------------------
# finito
# --------------------------------------------------------- 
662

Screenshot prvního demonstračního příkladu

4. Množina polyčar (lomených čar)

V některých případech je zapotřebí přenášet v souborech typu VRML i informace o polyčarách (lomených čarách). Může se jednat jak o dvourozměrné vektorové kresby, tak i o tvorbu takzvaných drátových modelů (wireframe). Pro tyto účely byl zaveden uzel nazvaný IndexedLineSet, v jehož datové části je možné poměrně sofistikovaným a prostorově efektivním způsobem uložit informace o libovolném množství polyčar ležících v rovině (kreslicí rovinu je možné měnit pomocí již dříve popisovaných transformací).

Kromě vrcholů jednotlivých polyčar (tj. vlastních geometrických informací) lze specifikovat buď barvy celých polyčar nebo i barvy jednotlivých vrcholů s tím, že pokud mají dva sousední vrcholy rozdílné barvy, je úsečka mezi nimi zobrazena s gradientním přechodem. Výpočet gradientního přechodu je přitom velmi jednoduchý a rychlý, většinou je prováděný přímo na grafickém akcelerátoru s využitím stejných výpočetních jednotek, jaké jsou určeny na vykreslování stínovaných ploch. Syntaxe zápisu uzlu IndexedLineSet je následující:

IndexedLineSet {
    coord          # pole souřadnic uložených v uzlu typu Coordinate
    coordIndex     # indexy souřadnic reprezentujících vrcholy polyčar
    color          # pole barev
    colorIndex     # indexy do pole barev platných buď pro
                   # celou polyčáru nebo pro jednotlivé vrcholy
    colorPerVertex # hodnota TRUE či FALSE podle způsobu interpretace barev
} 

Pojďme si nyní říci, jakým způsobem se vlastně polyčáry zapisují, protože se jedná o docela zajímavý postup, který obecně vede ke snížení objemů (velikostí) VRML souborů. Veškeré informace o vrcholech, kterými jsou polyčáry tvořeny, jsou uloženy v poli coordIndex. Kladné hodnoty značí indexy do pole souřadnic (indexuje se od nuly) a speciální hodnota –1 od sebe odděluje jednotlivé polyčáry. To znamená, že v jednom uzlu typu IndexedLineSet je možné mít uloženo libovolné množství polyčar různých barev, což je poměrně objemově nenáročný způsob zápisu.

5. Množina polygonů (plošek)

Množina plošek, která je ve VRML zapisována do uzlu pojmenovaného IndexedFaceSet, se v mnohém podobá výše zmíněné množině polyčar. Každá ploška je zapsána pomocí libovolného počtu indexů do tabulky vrcholů (jedná se opět o uzel či poduzel typu Coordinate). Ploška musí být, jak už ostatně její název napovídá, planární, tj. všechny její vrcholy musí ležet v jedné rovině. Pokud by nějaký vrchol z roviny „vyčníval“, musí se provést buď manuální nebo automatické rozdělení celé plošky na menší části, ovšem automatické rozdělování může být poměrně zdlouhavé. Z tohoto důvodu mnoho aplikací svá prostorová data exportuje ve formě té nejjednodušší nedegenerované plošky – trojúhelníku – u trojúhelníku je totiž vždy zaručena planárnost a tím pádem i bezproblémové vykreslení s využitím moderních grafických akcelerátorů. Zápis uzlu IndexedFaceSet vypadá následovně:

IndexedFaceSet {
    coord          # pole souřadnic uložených v uzlu typu Coordinate
    coordIndex     # indexy souřadnic reprezentujících vrcholy plošek
    color          # pole barev
    colorIndex     # indexy do pole barev aplikovaných buď pro
                   # celou plošku nebo pro jednotlivé vrcholy
    colorPerVertex # hodnota TRUE či FALSE podle toho, zda se barva
                   # aplikuje na celou plošku nebo jednotlivé vrcholy
    ccw            # určení, zda se mají plošky vytvářet v orientaci
                   # po směru či proti směru hodinových ručiček
    convex         # povolení či zákaz automatické tesselace
                   # plošek na konvexní části
    creaseAngle    # mezní úhel – pokud bude úhel normál dvou
                   # sousedních plošek menší než zde zadaná hodnota,
                   # budou plošky vystínovány tak, aby nebyla viditelná
                   # hrana mezi nimi
    solid          # určuje, zda se má polygon zobrazit i při pohledu
                   # zespodu, tj. zda zobrazovat i odvrácené strany plošek
    texCoord       # koordináty v souřadném systému textury
                   # (více informací si povíme příště)
    normal         # specifikace normál přiřazovaných ploškám
                   # (lze dopočítat automaticky)
} 

Nejzajímavější je způsob interpolace barev při vykreslování plošek. Barvu je totiž možné specifikovat buď pro celou plošku (konstantní stínování, flat shading), nebo pro její jednotlivé vrcholy. Pokud se barva ve vrcholech liší (což je běžné), tak se barva interpoluje, čímž se do určité míry ztratí mnohdy nežádoucí hranatost modelu. Pomocí hodnoty zadané atributem creaseAngle je zadán mezní úhel. Pokud je vypočtený úhel mezi normálami dvou sousedních plošek menší než zde zadaná hodnota, je prováděna i interpolace po výpočtu osvětlení plošek, čímž opět dojde k optickému vyhlazení modelu (Gouraudovo či Phongovo stínování, Gouraud shading, Phong shading). O způsobu zadávání koordinát (souřadnic) v souřadném systému textury a normálových vektorů si řekneme v následující části tohoto seriálu.

Specifikace jednotlivých vrcholů plošek je podobná, jako v případě množin polyčar. Každý vrchol plošky je určen indexem do tabulky vrcholů (poduzel Coordinate), počet vrcholů pro jednu plošku je neomezený (s požadavkem planárnosti) a definice vrcholů pro každou plošku je ukončena indexem se speciální hodnotou –1.

6. Druhý demonstrační příklad – použití prostorových úseček a plošek pro vytvoření složitějšího objektu

Ve druhém demonstračním příkladu, ke kterému je opět dostupný zdrojový kód, je ukázáno použití uzlů typu IndexedLineSet a IndexedFaceSet. V modelu jsou vytvořeny dva objekty reprezentované dvojicí uzlů. První objekt je představován otevřenou krychlí vytvořenou z plošek. Vrcholy plošek tvoří osm vrcholů krychle. Dále jsou definovány čtyři plošky, takže výsledkem je krychle, které chybí dvě strany (celá krychle by musela mít šest stran). Ve druhém uzlu, který je typu IndexedLineSet, je definováno 13 vrcholů (některé jsou shodné s vrcholy krychle) a dále osm samostatných úseček, tj. polyčar, které mají pouze dva vrcholy.

663

Screenshot druhého demonstračního příkladu – pohled od nastavené pozice pozorovatele

Zdrojový kód druhého demonstračního příkladu má tvar:

#VRML V2.0 utf8
# verze 2.0 vyzaduje kodovani UTF-8

# ---------------------------------------------------------
# Druhy demonstracni priklad trojrozmerne sceny
# popsane jazykem VRML 2.0, ktera obsahuje teleso slozene
# z mnoziny usecek a mnoziny plosek.
#
# Priklad je soucasti serialu "Graficke formaty"
# (/serialy/graficke-formaty/)
# vychazejiciho na Root.cz (http://www.root.cz)
#
# (zalozeno na Floppy'sVRML97 Tutorial)
# ---------------------------------------------------------

WorldInfo {
    title "Prvni 3D scena s nekolika objekty a bodovym svetelnym zdrojem"
    info ["Autor: Pavel Tisnovsky, 2007"
         "sireno pod licenci GPL "
         "(zde mohou byt dalsi texty"]
}

# nastaveni barevneho prechodu na pozadi sceny
Background {
    skyColor [1 1 0,
              1 0 0]
    skyAngle [3.14]
}

# nastaveni pozice pozorovatele
Viewpoint {
    position 0.0 2.0 10.0
}

# nastaveni svetelneho zdroje
PointLight {
    color    1.0 1.0 1.0 # barva svetla
    intensity 1.0        # intenzita bodoveho svetla
    location 0.0 4.0 1.0 # pozice svetelneho zdroje
}

# teleso slozene z plosek
Shape {
    # vzhled objektu - negeometricke informace
    appearance Appearance {
        material Material {
            diffuseColor  0.5 1.0 0.5
            specularColor 1.0 1.0 1.0
        }
    }
    # tvar objektu - geometricke informace
    geometry IndexedFaceSet {
        # interni poduzel se souradnicemi bodu
        coord Coordinate {
            point [
                -2 0  2,
                 2 0  2,
                 2 0 -2,
                -2 0 -2
                -2 4  2,
                 2 4  2,
                 2 4 -2,
                -2 4 -2
            ]
        }
        # indexy do prechoziho pole
        # jednotlive plosky jsou oddeleny
        # indexem s hodnotou -1
        coordIndex [
            0 4 7 3 -1
            1 2 6 5 -1
            4 5 6 7 -1
            2 3 7 6 -1
        ]
        solid FALSE
    }
}

# teleso slozene z usecek
Shape {
    # vzhled objektu - negeometricke informace
    appearance Appearance {
        material Material {
            emissiveColor 0 0 1
        }
    }
    # tvar objektu - geometricke informace
    geometry IndexedLineSet {
        # interni poduzel se souradnicemi bodu
        coord Coordinate {
            point [
                -2 4   2,
               -10 2  10,
                 2 4   2,
                10 2  10,
                 2 4  -2,
                10 2 -10,
                -2 4  -2,
               -10 2 -10,
                -2 0   2,
                 2 0   2,
                 2 0  -2,
                -2 0  -2,
                 0 4   0
         ]
      }
        # indexy do predchoziho pole
        # (pouze usecky) oddelene
        # indexem s hodnotou -1
        coordIndex [
             0  1 -1
             2  3 -1
             4  5 -1
             6  7 -1
             8 12 -1
             9 12 -1
            10 12 -1
            11 12 -1
        ]
    }
}



# ---------------------------------------------------------
# finito
# --------------------------------------------------------- 
665

Další screenshot druhého demonstračního příkladu

664

Poslední screenshot druhého demonstračního příkladu

7. Výšková pole

Velmi zajímavým a přitom užitečným objektem, který je možné ve VRML 2 použít, je takzvané výškové pole (height field). V souborech typu VRML je výškové pole zapisováno do uzlu nazvaného ElevationGrid. Ve skutečnosti jsou totiž výšková pole obecnější než ve VRML použitá mřížka výšek, jak by zněl doslovný překlad jména tohoto uzlu. Výškové pole je ve VRML zapisováno skutečně ve formě mřížky bodů (z programátorského hlediska se jedná o normální dvojrozměrné pole) ležících v trojrozměrném prostoru, ovšem u těchto bodů jsou explicitně uvedeny pouze jejich y-ové souřadnice (výšky).

Ostatní dvě souřadnice, tj. x a z, jsou dopočítány automaticky z indexu bodu, tj. z jeho pozice v mřížce. Z tohoto popisu vyplývá, že kdyby byly u všech bodů zadány nulové výšky, ležely by všechny body v rovině X-Z, kde by vytvořily skutečnou pravidelnou mřížku. Počátek mřížky, tj. jeden z jejích rohů, leží v počátku souřadnic a mřížka se zvětšuje ve směru růstu os x a z.

Poznámka: zopakujme, že ve VRML je použit pravotočivý souřadný systém. Implicitní pozice pozorovatele (kamery) leží v bodě [0, 0, 10], přičemž pozorovatel/kamera je natočen tak, aby se díval na počátek souřadného systému. V této konfiguraci opravdu dochází k tomu, že osa y směřuje na obrazovce, tj. po promítnutí, směrem nahoru, což je pravděpodobně důvod, proč tvůrci VRML navrhli výšková pole, která leží v rovině X-Z a ne X-Y, jak je tomu například v některých editorech specializovaných pro vytváření „světů“.

Při vkládání uzlu ElevationGrid do vytvářeného modelu je možné specifikovat poměrně velké množství atributů s hodnotami, jejichž význam je uveden v následující tabulce:

Atribut Datový typ Význam
color SFNode specifikace barvy plošek vytvořených z výškového pole
normal SFNode specifikace normál přiřazovaných ploškám (lze dopočítat automaticky)
texCoord SFNode koordináty v souřadném systému textury (více informací si povíme příště)
xDimension SFInt32 velikost mřížky ve směru x-ové osy
xSpacing SFFloat vzdálenost mezi sousedními body měřená jako rozdíl x-ových souřadnic
zDimension SFInt32 velikost mřížky ve směru z-ové osy
zSpacing SFFloat vzdálenost mezi sousedními body měřená jako rozdíl z-ových souřadnic
colorPerVertex SFBool určení, zda se má barva plošek interpolovat či přiřadit celým ploškám
normalPerVertex SFBool dtto pro normálové vektory
height MFFloat hlavní datová část uzlu – vlastní 2D pole výšek
ccw SFBool určení, zda se mají plošky vytvářet v orientaci po směru či proti směru hodinových ručiček
convex SFBool povolení či zákaz automatické tesselace plošek na konvexní části
creaseAngle SFFloat mezní úhel – pokud bude úhel normál dvou sousedních plošek menší než zde zadaná hodnota, budou plošky vystínovány tak, aby nebyla viditelná hrana mezi nimi
solid SFBool určuje, zda se má výškové pole zobrazit i při pohledu zespodu, tj. zda zobrazovat i odvrácené strany plošek

Demonstrační příklady používající výškové pole budou uvedeny v navazující části tohoto seriálu.

Našli jste v článku chybu?
120na80.cz: Bojíte se encefalitidy?

Bojíte se encefalitidy?

Podnikatel.cz: K EET. Štamgast už peníze na stole nenechá

K EET. Štamgast už peníze na stole nenechá

DigiZone.cz: Česká televize mění schéma ČT :D

Česká televize mění schéma ČT :D

Lupa.cz: Slevové šílenství je tu. Kde nakoupit na Black Friday?

Slevové šílenství je tu. Kde nakoupit na Black Friday?

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

Měšec.cz: Zdravotní a sociální pojištění 2017: Připlatíte

Zdravotní a sociální pojištění 2017: Připlatíte

Podnikatel.cz: EET: Totálně nezvládli metodologii projektu

EET: Totálně nezvládli metodologii projektu

Vitalia.cz: To není kašel! Správná diagnóza zachrání život

To není kašel! Správná diagnóza zachrání život

DigiZone.cz: ČT má dalšího zástupce v EBU

ČT má dalšího zástupce v EBU

Vitalia.cz: Tesco: Chudá rodina si koupí levné polské kuře

Tesco: Chudá rodina si koupí levné polské kuře

120na80.cz: Rakovina oka. Jak ji poznáte?

Rakovina oka. Jak ji poznáte?

Vitalia.cz: Baletky propagují zdravotní superpostel

Baletky propagují zdravotní superpostel

Podnikatel.cz: Na poslední chvíli šokuje vyjímkami v EET

Na poslední chvíli šokuje vyjímkami v EET

Lupa.cz: UX přestává pro firmy být magie

UX přestává pro firmy být magie

Měšec.cz: Jak vymáhat výživné zadarmo?

Jak vymáhat výživné zadarmo?

120na80.cz: Pánové, pečujte o svoje přirození a prostatu

Pánové, pečujte o svoje přirození a prostatu

Vitalia.cz: Paštiky plné masa ho zatím neuživí

Paštiky plné masa ho zatím neuživí

Vitalia.cz: Láska na vozíku: Přitažliví jsme pro tzv. pečovatelky

Láska na vozíku: Přitažliví jsme pro tzv. pečovatelky

Lupa.cz: Avast po spojení s AVG propustí 700 lidí

Avast po spojení s AVG propustí 700 lidí

Podnikatel.cz: Víme první výsledky doby odezvy #EET

Víme první výsledky doby odezvy #EET