Vandens telkinių etiketės

Prieš daugiau nei pusmetį buvo rašyta apie vieną iš variantų, kaip skaičiuoti vandens telkinių etikečių pozicijas. Tąkart aprašytas metodas gan paprastas, bet yra dvi problemos, kurių centro linijos sprendimas nesprendžia: etikečių šrifto dydis ir tarpai tarp raidžių. Centro linija gali puikiai praeiti pro siauriausią ežero vietą ir parinkti ją etiketei, kai kur nors toliau nuo centro yra platesnė ežero dalis, tinkama etiketei su didesniu šriftu.

Gerą mintį davė pagal OpenStreetMap duomenis kuriamo OpenTopoMap kūrėjai. Jie ežerų etiketėms sugalvojo naudoti „stačiakampių metodą“. Jie irgi pradėjo nuo centro linijų skaičiavimų, bet visgi pasirinko kvadratų metodą. Tai puikus variantas ir, nors OpenTopoMap jį panaudojo tik etiketės pozicijos paieškai, jį galima pritaikyti ir šrifto dydžio bei tarpo tarp raidžių nustatymui.

Pradinį principą naudojame tokį patį, kaip ir OpenTopoMap – ant vandens telkinio sudėliojame vienodo dydžio kvadratų matricą ir tada pašaliname tuos kvadratus, kurie nėra pilnai vandens telkinyje (šiek tiek pažaidę su buferiais, galime valdyti, kokio dydžio salos ir iškyšuliai daro/nedaro įtakos etiketei, taip pat kiek etiketė gali išsikišti už vandens telkinio ribų):

Kvadratai vandens telkinyje

Iš pradžių randame vidurinį kvadratą, tada randame toliausiai nuo jo esantį kvadratą K1, o tada toliausiai nuo K1 esantį kvadratą K2. Kelias per kvadratus, einantis nuo K1 iki K2 ir bus linija etiketei. Pastebėtina, kad tinkamiausias bus kelias nuo K1 iki K2, „einantis“ per labiausiai nuo kranto nutolusius kvadratus (pavaizduotus tamsesniu fonu). Panaudoję modifikuotą bangos principą paskaičiuojame tokį kelią.

Tai būtų daugmaž tai, ką padarė OpenTopoMap. Bet mes norime daugiau. Galime daryti prielaidą, kad kvadrato dydis kažkiek koreliuoja su raidžių dydžiu. Sakykime, kad jei norime nupaišyti 10 raidžių ilgio ežero pavadinimą, mums reikia, kad kelią nuo K1 iki K2 sudarytų bent 10 kvadratų. Taigi pradedame skaičiavimu su gan dideliu kvadratų dydžiu, jei kelias per trumpas (arba kvadratai netelpa į ežerą) – mažiname kvadratus ir kartojame skaičiavimą. Anksčiau ar vėliau rasime didžiausią kvadrato dydį, kai kelias jau yra pakankamo ilgio. Tada priklausomai nuo kvadrato dydžio galėsime paskaičiuoti, kokį šrifto dydį galima naudoti žemėlapyje. Jei kvadratų gavosi daugiau, nei reikia – galima bus ir tarpus tarp raidžių padidinti.

Gausime žemėlapį, kur etikečių šriftų dydžiai bus parinkti pagal realią vandens telkinio geometriją (žemiau pateikta bandymų nuotrauka, kur skaičiuotos tik dviejų ežerų etiketės):

Skirtingi etikečių dydžiai

Matome, kad Luodžio ežero etiketė yra mažesnė, nei Dysnų ežero, o Dysnų ežeras dar ir turi didesnius tarpus tarp raidžių (po etikete matosi pilka paskaičiuota etiketės pozicijos linija).

Toks yra esminis principas. Žinoma, galutiniam sprendimui reikia dar daug paprastų dalykų padaryti: paskaičiuoti, kuriuose masteliuose tokios etiketės apskritai gali atsirasti, kaip šrifto dydis keičiasi keičiantis masteliui, kvadratus tiesiogiai tapatinti su etiketės ilgiu irgi nėra teisinga, nes tarkim „M“ raidė gerokai platesnė už „i“. Bet tai jau techninės detalės, neįtakojančios bendro principo.

Ir visa tai padaroma atviromis priemonėmis (PostgreSQL+PostGIS), taigi puikiai tinka tokiems taikymams kaip OpenStreetMap, kur žemėlapis turi „pats“ (be žmogaus įsikišimo) gan dažnai persiskaičiuoti ir persibraižyti.

Pastatų generalizavimas

Yra daug pastatų generalizavimo operacijų, daug operacijų parametrų parinkimo variantų, daug operacijų atlikimo sekų variantų. Kol kas nepastebėjau, kad kas nors būtų radęs vieną teisingą variantą, tinkantį visoms situacijoms: skirtingiems masteliams ir skirtingo tankio ir/ar geometrijos pastatams (pvz. tankiai užstatytiems senamiesčiams, retai užstatytiems sodams ir dar rečiau užstatytoms laukų sodyboms).

Aprašysiu bandymus parinkti tinkamus parametrus generalizuojant pastatus 12 masteliui (kur 1 taško plotis yra ~40m). Tikiuosi, kad radus parametrų reikšmes (o tikriausiai ir patvarkius pačią generalizavimo seką), bus galima atitinkamai išdėlioti generalizaciją ir stambesniems masteliams.

Generalizavimo seka tokia:

  1. Į spiečius (multigeometrijas) sugrupuojami pastatai, esantys arčiau vienas kito nei N1 metrų (PostGIS funkcija St_ClusterWithin).
  2. Sugrupuotos geometrijos, kurių plotas didesnis už N2 m2, yra paprastinamos, pašalinant geometrijos elementus (briaunas), kurių dydis mažesnis už N3 metrus.
  3. Atrenkami pastatai, kurių plotas yra mažesnis už N2 m2. Apdorojami ploto mažėjimo tvarka. Su jais atliekami tokie veiksmai:
    1. paskaičiuojamas mažiausias apgaubiantis orientuotas stačiakampis (PostGIS funkcija St_OrientedEnvelope)
    2. jei gautas apgaubiantis stačiakampis yra mažesnis už N2 m2, tai jis padidinamas (nekeičiant orientacijos, į visas puses) iki N2 m2
    3. jei taip gautas stačiakampis su buferiu N4 nesikerta nei su vienu didesniu už jį pastatu – tokia geometrija ir naudojama. Jei kertasi – pastatas išimamas.

    Retesnių pastatų vietoje rezultatas toks:

    Sugeneralizuoti pastatai

    Šiame piešinyje:

    • geltonas pastatas – kurio plotas yra didesnis už N2 m2, jo geometrija supaprastinta (PostGIS metodu, kuris geometriją paprastina agresyviau nei ArcGIS’as).
    • žali pastatai – už N2m2 mažesni pastatai, kurių plotas buvo padidintas iki minimalaus – N2m2. Žalio ploto viduje matomas pradinis pastato ar pastatų dydis.
    • raudoni pastatai – išmesti iš mastelio rinkinio pastatai, nes padidinti iki minimalaus dydžio jie kirtosi su kitais pastatais.

    Žemėlapyje vaizdas toks:

    Pastatai žemėlapyje

    Konkrečiai šiam bandymui buvo naudotos tokios parametrų reikšmės:

    • N1 (grupavimo atstumas) – 10m
    • N2 (minimalus plotas) – 2000m2
    • N3 (pastatų geometrijos minimalus detalės dydis) – 40m
    • N4 (minimalus plotas) – 2000m2 (šiame bandyme sutampa su N2, bet tai nėra privaloma)

    Gauname gerokai supaprastintas pastatų geometrijas (kas svarbu vektorinėse kaladėlėse, smulkiuose masteliuose). Pastatų sankaupos vizualiai apvalytos, mažiau makalynės.

    Bet yra ir neišspręstų problemų:

    • Tipifikuojant pastatus jie nėra orientuojami pagal artimiausią/gretimą kelią.
    • Nesprendžiama problema, kad padidintas pastatas nesikirstų su kitais (ne pastatų) objektais – keliais, vandeniu, mišku ir pan.

    Stambesnių pastatų zonoje galima pastebėti nelabai teisingų rezultatų:

    Pastatų juosta

    Čia apibrėžta pastatų juosta, kuri taip generalizuojant buvo padalinta į mažesnius gabalus. Juosta būtų išlikusi, jei būtų naudota didesnė N1 reikšmė – tada visi juostos pastatai būtų patekę į vieną geometriją. Deja, didinant N1, mažų bet tankiai pristatytų pastatų zonoje susigrupuoja maži pastatai ir rezultate sudaro visokias neaiškias konstrukcijas (rezultatas N1 padidinus iki 20m):

    Per didelis pastatų sugrupavimas

    Galbūt, tokį per didelį sugrupavimą galima spręsti apribojant, kiek pastatų galima sudėti į vieną spiečių…

    Tokie pradiniai rezultatai. Parametrų reikšmės buvo parinktos empiriškai, norėtųsi labiau matematinio paskaičiavimo. Pradinė mintis, kad turint rezoliuciją 40 metrų taškui N1 ir N3 turėtų būti 40, o N2 ir N4 – 402 -> 1600, nepasiteisino. Kažką praleidau 🙂

    Pabaigai šiek techninių skaičių (bandymai daryti su OpenStreetMap duomenimis):

    • Pastatų (geometrijų) skaičius sumažintas nuo 65898 iki 15941, 76% sumažėjimas.
    • Viršūnių skaičius sumažintas nuo 442295 iki 84536, 81% sumažėjimas.

    Šitie parametrai svarbūs, nes tarkim GRPK duomenų Vilniaus kaladėlės 12 mastelyje siekia beveik 1Mb (supakuotos!). Taipogi visas šias geometrijas klientas turi apdoroti tiek pradinio paišymo, tiek ir pasukimo, pavertimo metu.