Tehniline järelkontroll: kuidas me koostasime maailma uhkemaid automaatselt loodud ühistranspordi kaarte

autor Anton Dubrau

Kuus nädalat tagasi käivitasime Transit Maps ja kirjutasime selle ajaveebi postituse sellest, miks me võtsime vastu mammutiülesande luua automaatselt genereeritud, kuid esteetiliselt meeldivad kaardid. Avalik reaktsioon meie pingutustele õhutas meid, ehkki polnud nende loomiseks vajaliku aja, mõtte ja inspiratsiooni arvestades sugugi üllatunud. Täna täidame oma lubadust avaldada meie elanike kaardistamisviisardi Anton, kes tutvustas nende kaartide koostamiseks palju täpsemaid tehnilisi järelmeetmeid.

Kui mõelda Transitile, võiksite mõelda klanitud ja värvika liidese. Arvestades, et peame eriti eriliseks muuta rakendus võimalikult ilusaks ja kasutatavaks, pole see suur üllatus. Kuid kasutajaliides ei ole ainus asi, millega tegeleme: meie meeskond ulatub kaugemale ekspertide kujundajatest ja meie rakendus on palju enamat kui lihtsalt ilus. Pinna all on palju „kõva” tehnoloogiat, mis seda vaikselt juhib.

Esiteks kontrollib meie võimas taustprogrammi kvaliteet sadu transiidiandmete vooge, parandab automaatselt katkised andmed ja märgistab uurimist vajavad probleemid. See süsteem võimaldab meil väikese meeskonnaga hallata 350 transiidivoogu 125 linnas 125 linnas.

Siis on olemas meie pakkimisalgoritm. See kahandab transiidigraafikuid kuni 100 korda väiksemaks, kui ZIP-faile pakuvad transiidiagentuurid. See võimaldab Transitil alla laadida kasutaja kogu piirkonna sõiduplaanid, salvestada andmed kasutaja seadmesse ja tagastada otsingutulemid ... kõik aja jooksul, mis teistel rakendustel ühe ajakava taotlemiseks ja laadimiseks kulub. Ja kuigi meie kasutajad võivad funktsiooni esmakordsel kasutuselevõtul olla meie rakenduse kiirusega juba harjunud, vähendas see reageerimise aega mitmelt sekundilt 0,1 sekundile. See on kiire.

Kuid seal on üks konkreetne tehnoloogia, mille kallal oleme aastaid töötanud. Oma suureks rõõmuks (ja kergenduseks) käivitasime selle sel suvel lõpuks: automaatselt genereeritud transiitkaardid.

Transit Maps: Transit App (vasakul), Apple Maps (keskel) ja Google Maps (paremal)

Idee ise pole vaevalt uus: Google tõi nende transiitkaardid turule peaaegu kuus aastat tagasi. Kuid selgub, et see on üsna keeruline probleem lahendada ja Google (isegi pärast kõiki neid aastaid) ei suuda ikkagi luua väga ilusaid või isegi väga kasulikke transiidikaarte.

Kuidas me sellega hakkama saime? Higi, pisarate ja loova mõtlemisega.

1. Kujundid kaardil

Automaatselt genereeritud kaartide loomise idee on mind köitnud juba enne Transit Appiga liitumist kolm aastat tagasi. Sel ajal oli Google tööstuses ainus tegija ja ausalt öeldes olid nende transiitkaardid omamoodi jubedad. Olime just lõpetanud oma ülalnimetatud ülikompressioonialgoritmi ja tundsime end valmis uue probleemiga tegelema. Arvasime üsna naiivselt, et selleks kulub umbes kolm kuud. Vähe me teadsime ...

Esimene samm oli lähteandmete kuvamine kaardil. Paljud reiside aluseks olevad transiidiandmed sisaldasid juba kujundeid, mis tähistavad transiidisõidukite marsruute. Kui me lihtsalt joonistaksime kõigi reiside määratletud kujundid, saaksime lihtsustatud sorti transiidikaardi:

Meie tehnoloogia Transit Maps, umbes november 2014

Selle tegemine oli suhteliselt lihtne: püstitasime töötlemistorustiku, et kujundeid lähteandmetest eraldada; salvestas kujud andmevahetuse vormingus; taganud andmete kättesaadavuse seadmele; ja kasutas seadme kaardistamise teeke andmetega uue kihi joonistamiseks.

Lihtne. See oli meil valmis paari nädala jooksul.

Kuid kuigi see on lähedal, pole see tõeline ühistranspordi kaart. Kõik jooned tõmmati üksteise peale. Te ei saa öelda, millised read lähevad - ja ainus nähtav joon oli see, mis viimati tõmmati. Nõuetekohaste skemaatiliste kaartide saamiseks, kus saate sirgetega sõrmega jälgida, oleks vaja, et need tõmmatakse paralleelselt ja võimalikult vähese ristumisega.

2. Sobitamine OpenStreetMapiga

Kujudega kaartide koostamine tekitas muid probleeme: mida peaksime tegema, kui agentuur ei anna kuju kohta andmeid või kui agentuur pakub väga halbu kujundeid? Ainus geograafiline teave, mis meil sellistel juhtudel oleks, oleks peatuskohad. Muidugi, me võiksime tõmmata peatuste vahele sirgjooni, kuid see on kole, räpane ja segane.

See on probleem ka Google Transit Mapsis. Berliinis loob Google peatuste vahel sirgjoonelisi ühendusi; Londonis kasutavad nad mingisugust splaini-interpolatsiooni, mis ei järgi tegelikke lugusid; ja LA-s kasutavad nad agentuuri pakutavaid kujusid, kuigi kujude kvaliteet on tegelikult üsna halb.

Google Maps Berliinis (vasakul) ja Londonis (paremal)

Naljakas on see, et kaartidele suumides näete, et Google'il on sageli andmeid nende aluseks olevate raudteeliinide kohta, mis tekitab küsimuse: miks nad ei ühenda rööpaid kuju andmetega? Kas nad otsustasid, et see pole oluline?

Ehkki Google ei pruugi seda oluliseks pidada, teeme seda kindlasti. Muidugi, meil pole juurdepääsu Google'i rikkalikele kaardiandmetele, kuid saame kasutada järgmist parimat: OpenStreetMap (OSM). Ja tänu nende vabatahtlike kaardigooride kogukonnale on OSM-il praktiliselt kõik ühistranspordi raudteeliinid, mida meie rakenduses kasutame.

OpenStreetMap raudteeandmed

Luues OSM-i tänavavõrgule kuju, mis ühendab kõiki antud marsruudi punkte, võiksime luua oma transiidikujud! Nii lõime dünaamilise programmeerimisalgoritmi, mis jälgib teid või radu, mida tõenäoliselt kasutavad transiitliinid. Kuju kujundamise algoritm arvestab, millist tüüpi sõiduk liinil jookseb, ja minimeerib sobitusvead (st genereeritud kuju ja lähtepunktide tegelike asukohtade vahelised kaugused).

Siin on näide. Alloleval diagrammil on meil reis kolme peatusega ja mingit kuju käsitlevat teavet pole. Me eraldame OSM-ist (hallid jooned) reisi kasutatavate radade komplekti. Seejärel leiab meie sobitusalgoritm trajektoori (musta joone), mis järgib OSM-i, minimeerides selle pikkust ja peatuste vigu (e1, e2, e3).

Kuju-OSM-i sobitamise protsess

On keeruline, kui see algoritm töötab kõigil juhtudel, nii et mõnikord peame konkreetsete liinide toimimiseks lisama parameetrid. Üldiselt annab see meile kvaliteetse kuju kõigi täna vajalike ühistranspordi liinide jaoks ja enamiku nende jaoks, mida me tulevikus vajame - isegi arengumaades, kus OSM on sageli parimate kättesaadavate andmetega.

Üks näide, mis motiveerib OSM-i sobitamist ka siis, kui kujud on saadaval ja korraliku kvaliteediga: Montrealis-Westis ei jälgi pakutavad kujundid rada (vasakpoolsel pildil), nii et tänavatasemel tundub see kohutav. Pärast OSM-i sobitamist (paremal) on read palju sujuvamad.

3. Töötlemine piksliruumis: skeleti loomine

OSM andis meile kujundid, kuid jooned tõmmati ikkagi üksteise peale. Päris transiitkaartidel on jooned paralleelselt tõmmatud. Peame kindlaks tegema ühised lõigud, kus nad samal tänaval sõidavad, ja seejärel need read kokku tõmbama.

Kuidas Google seda teeb? Näib, et nad arvutavad jagatud segmente peatusi vaadates. Niikaua kui kahel liinil on samad peatused, ühendatakse need omavahel. Kuid kui järgmist peatust ei jagata, siis read eemaldatakse:

Google'i read unustavad, et tunnevad üksteist kohe viimases peatuses, kus nad koos peatuvad.

Kuid rongid ja bussid tegelikult ei sõida! Liinid püsivad enne lahkumist mingil kaugusel. Vajasime algoritmi, mis võimaldaks leida rea, kus read reaalses elus hargnema hakkavad.

Proovisime arvutada marsruudieraldusi vektorruumis, mis tundus alguses lihtne: võtke kaks rida, mis liiguvad tihedalt koos, ja leidke seejärel jagatud segmendi keskjoon. See osutus aga üllatavalt keeruliseks, kuna sattusime pidevalt lihtsate näidete juurde, mis rikuksid meie algoritmi. Väike silmus marsruudil viskaks keskjoonest lõpmatuseni välja ja meil oli vaja tegeleda ka mitme joone, mitme haru, erinevate peatusmustritega ...

Pärast kaks kuud aju klaviatuuride vastu peesitamist viskasime lõpuks rätiku sisse. Me lihtsalt ei suutnud leida stabiilset üldist lahendust, mis töötaks usaldusväärselt, kuni ...

Pixel ruumi päästmiseks!

Selle asemel, et jooni vektorruumis töödelda, otsustasime proovida midagi hullu. Kasutasime piksliruumi.

Tavaliselt toimub pikslipõhine töötlemine pildipõhiste andmete jaoks. GIS-töötlemisel on see väga ebatavaline, kuna eraldusvõimega 1 piksel meetri kohta oleks meie pilt 64 terabaiti. Mälu on tänapäeval odav ... aga mitte nii odav!

Kuidas me siis seda tegime? Rakendasime spetsiaalse hõreda pildikogu, mis saaks hakkama nende väga suurte monokromaatsete piltidega, millel on suhteliselt vähe valgeid alasid.

Seejärel lõime algoritmi, et joonistada transiitkujusid hiiglaslikule mustvalgele lõuendile, mis tähistab kogu maailma, kus iga piksel on võrdne ühe ruutmeetriga. Iga joon tõmmati lõuendile paksult, nii et kõikjal, kus jooned olid lähedal, sulandusid nende pikslid omavahel.

Kui kõik jooned olid joonistatud, kasutasime ridade järjestikuse õhendamise jaoks skeleti vormistamist, kuni mõlemad olid ainult ühe piksli paksused. Ehkki read enam ei ühendatud, püsisid nad omavahel ühendatud, säilitades sama topoloogia. Need õhukesed jooned tähistavad transiitliinide liikumist koos ja näitavad võrgu ülesehitust.

Valge tähistab tõmmatud transiidijooni. Skelett on punasega kaetud.

Ehkki meil olid nüüd võrgu keskjooned, olime hävitanud rohkem teavet, kui oleksime saanud. See, mis meil nüüd oli, oli hunnik piksleid, mis tähistasid luustikku, mis tähendas, et me teadsime, et iga joon peab mööda seda luustikku liikuma, kuid pidime ikkagi välja mõtlema, millised jooned kuhu liiguvad.

Skeleti abil ehitasime jooned ümber, vastupidiselt kujudele, mis meil varem olid. Seejärel töötlesime saadud võrgu läbi, et vabaneda luustiku tekitatud tõrgetest.

See samm oli pikk ja tüütu. Kokku kulus joonistamiseks, skeletoniseerimiseks, võrgu ehitamiseks ja tõrgete eemaldamiseks umbes kuus kuud. (Nii palju, et kogu asi sai tehtud kolmes!)

Kuid lõpptulemused olid rahuldavad. Meil oli koos liikuvate ja lahku liikuvate liinide sisekujundus. See nägi välja selline:

Kui jooned joondasime paralleelselt, saime selle:

Edu!

Päris hea 1. versiooni jaoks. Palju parem kui Google, nähes, kuidas saate enam-vähem piiluda, kuhu iga rida läheb. Olime valmis Transiitkaarte kasutusele võtma! Ja siis… Apple Maps juhtus.

Pärast parema aasta jooksul oma kaartide kallal töötamist 2015. aasta suvel olime lõpuks valmis vabastama oma esimese versiooni Transit Mapsist. Siis rullis Apple nende transiitkaardid lahti ja need olid tõesti ilusad.

Apple'i ilusad transiitkaardid

Nad tõstsid kohe riba, kuidas transiidikaardid välja nägema peaksid. Meie joonistel ja kavanditel oli lõppeesmärk midagi sarnast (või parem kui see), mille Apple hiljem välja andis, kuid plaanisime sinna jõuda pärast oma 1. versiooni avaldamist.

Võrreldes Apple'iga oli meie pakutud versioon 1 omamoodi keskpärane. Meie disainer-tegevjuht otsustas, et Google'i peksmine pole piisavalt hea - ka meie pidime vähemalt mängima Apple'iga samas liigas.

Pärast põhjalikumat uurimist püstitasime hüpoteesi, et Apple joonistas nende kaardid käsitsi. Uute linnade vabastamise vahel oli tohutu mahajäämus ja kaartide väljanägemises oli midagi kummalist - nagu oleks need joonistanud inimesed, mitte arvutid. See tähendas, et kuigi meie kaardid polnud päris ilusad, oli meie algoritm siiski nende omadest ees.

Sel hetkel teadsime ka, et raske osa on selja taga. Olime välja mõelnud võrgu, mis võimaldaks meil paralleelselt jooni tõmmata. Nüüd tuli vaid muuta see hea välimusega.

4. Transiitliinide tellimine täisarvu lineaarse programmeerimise abil

Enne oma kaartide avaldamist pidime vabanema inetuist, ebavajalikust joonte ristumisest, mis muutis need õudseks spagettideks.

Kui me saaksime ridu sorteerida, et vähendada ristmike lähedal visuaalset segadust, oleks meil avaldatav kaart. Selleks pidime otsustama, millised jooned lähevad vasakule ja millised paremale, et minimeerida nende ristumisi.

Google'il oli (ja on endiselt) sarnane probleem - välja arvatud nende read ristuvad üksteisega isegi seal, kus on ainult peatusi ja ristmikke pole.

Oh, tule Google'i! Liinid peaksid olema korras.

Meie jaoks toimus ristumine ainult seal, kus read tegelikult ühinesid ja lahkusid, nii et meil läks juba paremini kui Google'i algoritmil. Seda seetõttu, et salvestasime jagatud sektsioone, mis põhinesid geograafial.

Kuidas siis spagettidest lahti saime? Esiteks proovisime heuristilist lahendust - sorteerimisliinid selle järgi, kus nad lõpevad -, kuid see sageli ebaõnnestus, töötades mõnes kohas, kuid mitte teistes.

Heuristliku lahenduse täiustamiseks lõime matemaatilise mudeli, mis „skoorib” antud ridade järjestamist, karistades joonte ristumist ja muud visuaalset segadust.

Mitmed võimalikud ristmike stsenaariumid, tähistades karistuste allikaid punaste ringide abil

Nagu arvata võis, võib kaardil ühes kohas ristumise vältimine luua teise kusagil mujal. Kõik on ühendatud! Mida me siis tegime? Leidsime nende ridade tellimise, millel oli madalaim ülemaailmne karistuspunkt.

Terve lineaarne programmeerimine võimaldas meil uurida kõiki võimalusi ja leida lahendus, mis globaalselt vähendas karistusfunktsiooni. Kuid täisarv-lineaarse programmeerimise töötlemise aeg on probleemi suuruses eksponentsiaalne: ühe ülesande lahendamine võib võtta ühe sekundi; veel üks keerulisem probleem võib võtta aasta! See muutis selle kasutamise ohtlikuks isegi taustaühenduseta eeltöötluses.

Olime mures. Chicago andmete töötlemine võttis meil tunde. Suurem piirkond nagu Kirdekoridor (Bostoni ja Washingtoni vahel) võib võtta nädalaid! Õnneks leidsime erineva rünnakuplaani: sellise, mis võimaldas täisarvulise lineaarse programmeerimise lahendajal tõhusamalt uurida probleemiruumi ja leida kiiremini optimaalseid lahendusi. Mis varem võttis tunni, nüüd kulus 0,2 sekundit.

Niisuguse optimeerimise nägemine praktikas on vaieldamatu: kui näete, kuidas algoritm teeb otsuseid, on see nagu tunnistajaks mõnele säravale matemaatikule, kes lahendab vaevata probleeme selgeimate ja lühimate lahendustega.

Enne / pärast rea sortimist

Teiste töötlemisetappidega, mis olid serveris juba eeltöötluseks juba lõpule viidud, salvestati andmed nüüd binaarfailidesse ja saadeti seadmele kaartide tegelikuks renderdamiseks mis tahes soovitud suumi tasemel.

5. Liinide ringjooneline ümardamine

Me polnud ikka veel päris valmis. Käsitsi joonistatud skemaatilised transiitkaardid ei näe ikka tegelikult välja nagu ülaltoodud kaardid. Nende jooned on kenasti ümarad, ristmikel sujuvate üleminekutega. Tahtsime, et meie kaardid saaksid sarnase ümara väljanägemise.

Kui jooned nurkade ümber jäid, soovisime, et need püsiksid täiesti paralleelselt, isegi potentsiaalselt degeneratiivsete juhtumite korral, nagu näiteks Chicagos. Seal liigub teravate kõverate ümber suur arv jooni, nii et nende paralleelseks joonestamisel võib sirge painduda painde siseküljele.

Tavaliselt toimub ümardamine bezier-kõverate abil, mis näevad välja nagu kõverduvad. Kuid selleks, et jääda truuks skemaatilistele transiidikaartidele, ei olnud bezier-kõverad päris õiged. Transiitkaartidel on sirgjooned, mis langevad järsult ümmargusteks kaareosadeks. Nii kasutasime ümardamiseks kaare segmente.

Samuti, erinevalt bezier-kõveratest, on iga ringkaarega paralleelne joon ise ringkaar. Kuni raadius on piisavalt suur, garanteeriti, et meil pole degeneratiivseid juhtumeid.

Me tulime välja kohandatud algoritmiga, mis kuju järgi eemaldaks ümmarguse kaare segmentide abil selle ümardamise ja lisamise punktid. See tagab antud minimaalse raadiuse, lihtsustades vajadusel geomeetriat. Minimaalne raadius sõltub kõigi paralleelsete joonte kogulaiusest.

Saadud kuju on sile. See koosneb täielikult sirgjoontest ja kaaresegmentidest, mis tähendab, et jooni saab alati tõmmata paralleelselt, ilma mingite esemete ja degeneratiivsete juhtumiteta.

See lähenemisviis andis meile midagi sellist:

Ümardamine toimub ainult jagatud segmentide korral. Samuti võite märgata, et eemaldasime kõik ristmikud. Ristmikega tegelemine oli suur probleem, sest pidime tagama, et iga liin jätkub segmendist teise ja on korralikult ühendatud. Sama ümardatud väljanägemise korral kasutasime kaare genereerimise algoritmi. Lõpptulemus on järgmine:

Päris vahva, eks? Aga kuigi nad olid ilusad… nägid nad ikka imelikult alasti välja. Seda seetõttu, et neil puudusid peatused.

Niisiis otsustasime, et jätkame vabastamist veel kord - ja lisage veel üks samm.

6. Peatuste lisamine

Peatuste lisamine võib tunduda lihtne, kuid peatusteabe levitamiseks meie loodud pika torujuhtme kaudu nõuab see tõepoolest õiglast töötlemist.

Samuti leidsime palju juhtumeid, kus andmete mitu peatust vastasid tegelikult ühele füüsilisele jaamale, nii et meil oli vaja need kokku koondada ühte peatusesse.

Siin me tegime. Mitme joonega peatuste jaoks tõmbasime kõigi ribade äärde valge riba, millel oli must kontuur (kontrasti jaoks). Ühe liini peatuste jaoks joonistasime lihtsa ringi, kasutades selle konkreetse transiitliini värvi. Lisasime ka valge ülekatte, et vähendada alloleva kaardikihi kontrasti. See on lõpptulemus:

Lubamaks kasutajatel kasutajatel meie rakenduste seadete lehelt valikuliselt ridu sisse ja välja lülitada, otsustasime, et ümardamine, samuti teatav peatus töötlemine ja renderdamine peaks toimuma seadmes. Nii saate New Yorgis keelata kõik New Jersey-l põhinevad transiidiliinid (või kõik New Yorgi New Yorgi liinid). Kuna teatud piirkondades on nii palju transiitliine, võimaldab see kasutajatel luua täielikult kohandatud kaarte.

Pange tähele, kuidas read uuesti sõltuvalt sellest, milline rida on aktiivsed, ja kuidas stopp muudab värvi.

Järeldus

Nii me seda tegimegi. Automaatselt genereeritud transiitkaartide rakendamine võttis kindlasti palju tööd, kuid see oli seda väärt. Meie kaardid on palju võimsamad kui PDF-id, mida olete harjunud hankima agentuuridelt. Ärge kunagi unustage, et paberkaardid, mille te kokku voltite ja oma rahakotti kinni torkate. Millised on peamised erinevused?

Meie ühistranspordi kaardid on skaleeritavad, nii et saame hõlpsalt lisada samasse visuaalsesse stiili uusi linnu, kuhu iganes maailmas laieneme. Neid saab kohandada, nii et kasutajad saavad võrgud ja režiimid sisse ja välja lülitada, et luua oma isikupärastatud ühistranspordi kaardid. Ja need on ka kontekstuaalsed: erinevalt agentuuri kaardi PDF-ist sisaldavad meie kaardid teie asukohta, andes teile aimu, kus te lähedal olevate joonte suhtes olete, ja kohandades välimust sõltuvalt suumi tasemest.

Ja lõppkokkuvõttes pakuvad meie skemaatilised transiidikaardid enamat kui lihtsalt põhiteavet transiidisüsteemide kohta. Nad on sümboliseerinud linnu ennast: olulisi funktsionaalseid kunstiteoseid, mis seovad inimesi nende keskkonnaga. Tahame aidata luua seda ühendust ja usume, et meie uued ühistranspordi kaardid teevad just seda.

Oleme rõõmsad, et täiustame end pidevalt, kuid oleme senise tööga rahul. Alustasime 55 linnaga. Vastus meie ajaveebi postitusele, milles võrreldi meie kaarte Google'i ja Apple'i kaartidega, on olnud uskumatult positiivne. Taustaprogrammi meeskonna jaoks on tore, kui inimesed näevad ja hindavad meie tehtud tööd ja vaeva, mis juhib rakenduse kasutamist. See motiveerib meid oma tehnoloogiat edasi arendama.

Lisaks on meil veel palju „raskeid” probleeme lahendada. Me jätkame tööd kapoti all, mitte ainult selle nimel, et meil oleks kõige uhkem rakendus, millel on parim UI, vaid ka kõige funktsionaalsem, võimsam ja täpsem transiidirakendus.

Kas soovite meie kaartidega mängida?
Transiidi saate tasuta saada App Store'is ja Google Plays. Või lugege ettevõtte kohta lisateavet meie veebisaidil.

Kas tunnete end nagu elatusvõimaluste lahendamine? Me otsime töötajaid!