diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index cd438d5..90fc3f8 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -33,4 +33,7 @@ android:name="flutterEmbedding" android:value="2" /> + + + diff --git a/assets/datasets/bus-blinds.csv b/assets/datasets/bus-blinds.csv new file mode 100644 index 0000000..802245e --- /dev/null +++ b/assets/datasets/bus-blinds.csv @@ -0,0 +1,5164 @@ +Route,Blind,51.4309209,-0.0936496 +1,Tottenham Court Road,51.516765,-0.1308319 +1,Holborn,51.5179371,-0.1106193 +1,Aldwych,51.5117949,-0.1193297 +1,Waterloo,51.4309209,-0.0936496 +1,Elephant & Castle,51.49380679999999,-0.0977981 +1,Elephant & Castle,51.49380679999999,-0.0977981 +1,Bricklayer's Arms,51.4661409,-0.2174147 +1,Surrey Quays,51.4944172,-0.0383063 +1,Southwark Park Road,51.493047,-0.07343890000000002 +1,Canada Water,51.4971488,-0.0471107 +2,Marylebone,51.5188746,-0.1498955 +2,Marble Arch,51.5135032,-0.158161 +2,Hyde Park Corner,51.5029347,-0.1508562 +2,Victoria,51.4309209,-0.0936496 +2,Vauxhall,51.4309209,-0.0936496 +2,Stockwell,51.4309209,-0.0936496 +2,Brixton,51.4612794,-0.1156148 +2,Brixton,51.4612794,-0.1156148 +2,Tulse Hill Station,51.43986,-0.10505 +2,West Norwood,51.427905,-0.1002486 +3,Regent Street,51.5080333,-0.133591 +3,Piccadilly Circus,51.5101699,-0.1348241 +3,"Whitehall, Horse Guards",51.5048768,-0.1243897 +3,"Whitehall, Horse Guards",51.5048768,-0.1243897 +3,Parliament Square,51.5007668,-0.1261294 +3,Lambeth Bridge,51.4945633,-0.123211 +3,Kennington Lane,51.4911995,-0.1034744 +3,Kennington Church,51.5026934,-0.19148 +3,Brixton,51.4612794,-0.1156148 +3,Brixton,51.4612794,-0.1156148 +3,"Brixton, Morval Road",51.4560094,-0.1133047 +3,South Croxted Road,51.4354963,-0.09071219999999999 +3,Crystal Palace,51.4197233,-0.0830638 +4,Archway,51.4309209,-0.0936496 +4,"Holloway, Nag's Head",51.55724250000001,-0.1204364 +4,Finsbury Park Station,51.5646425,-0.1058553 +4,Highbury Barn,51.5569649,-0.0979656 +4,Highbury & Islington,51.5569649,-0.0979656 +4,"Islington, Angel",51.5366523,-0.1029852 +4,Barbican,51.5202077,-0.09378639999999999 +4,St. Paul's,51.6045473,-0.1873796 +4,Ludgate Circus,51.513956,-0.1045484 +4,Aldwych,51.5119745,-0.1189746 +4,Waterloo,51.5048541,-0.1136621 +4,Waterloo,51.5048541,-0.1136621 +5,Romford Market,51.5790739,0.1813886 +5,Romford Station,51.577076,0.178319 +5,Roneo Corner,51.5654396,0.1884167 +5,Becontree Heath,51.5609465,0.1488995 +5,Five Elms,51.5537943,0.1416476 +5,Bennett's Castle Lane,51.5613931,0.1248746 +5,Fair Cross,51.54162059999999,0.08352939999999999 +5,Barking,51.536563,0.075766 +5,Barking,51.536563,0.075766 +5,Newham Town Hall,51.53280239999999,0.0551608 +5,"East Ham, Newham Town Hall",51.53280239999999,0.0551608 +5,"Upton Park, Boleyn",51.5305005,0.0384915 +5,"Plaistow, Balaam Street",51.5226426,0.0223686 +5,"Canning Town, Barking Road",51.53044569999999,0.038323 +5,Canning Town,51.5189494,0.0132 +6,"Willesden, Bus Garage",51.5474482,-0.2394372 +6,Kensal Rise,51.5345071,-0.2250186 +6,Queen's Park,51.5345448,-0.2043853 +6,Edgware Road Station,51.51988249999999,-0.1678336 +6,Marble Arch,51.5132872,-0.1595743 +6,Portman Square,51.5160186,-0.1547182 +6,Oxford Circus,51.51651950000001,-0.1307199 +6,Oxford Circus,51.51651950000001,-0.1307199 +6,Oxford Circus,51.51651950000001,-0.1307199 +6,Piccadilly Circus,51.5101283,-0.1348339 +6,Trafalgar Square,51.5085695,-0.1272433 +6,Aldwych,51.51200499999999,-0.1189687 +7,East Acton,51.5127758,-0.2476803 +7,East Acton,51.5127758,-0.2476803 +7,North Pole Road,51.5199025,-0.2255136 +7,Ladbroke Grove,51.5082078,-0.2035147 +7,Chepstow Road,51.5159207,-0.1955695 +7,Paddington,51.4309209,-0.0936496 +7,Edgware Road Station,51.51988249999999,-0.1678336 +7,Marble Arch,51.5133592,-0.1594906 +7,Oxford Circus,51.5162288,-0.1319806 +8,Bow Church,51.5287753,-0.0167013 +8,Old Ford,51.53210989999999,-0.0429126 +8,"Roman Road, Grove Road",51.531048,-0.03955699999999999 +8,Shoreditch,51.5229106,-0.0777472 +8,Liverpool Street,51.5176795,-0.084275 +8,St. Paul's,51.60466,-0.1872059 +8,City Thameslink,51.5140438,-0.1033475 +8,Holborn,51.5180284,-0.1105998 +8,Holborn,51.5180284,-0.1105998 +8,Tottenham Court Road,51.5171962,-0.1308925 +8,Oxford Circus,51.5163033,-0.1311388 +9,Aldwych,51.5120957,-0.1189441 +9,Trafalgar Square,51.5085695,-0.1272433 +9,Green Park,51.4309209,-0.0936496 +9,Hyde Park Corner,51.5029347,-0.1508562 +9,Hyde Park Corner,51.5029347,-0.1508562 +9,Royal Albert Hall,51.5009088,-0.177366 +9,"Kensington, Palace Gate",51.5010142,-0.1843302 +9,"Kensington, Holland Road",51.49713879999999,-0.2069513 +9,Hammersmith,51.491187,-0.223731 +10,Hammersmith,51.4934634,-0.2236314 +10,"Kensington, Holland Road",51.49748289999999,-0.2066984 +10,"Kensington, Palace Gate",51.4999555,-0.1836283 +10,Royal Albert Hall,51.5009088,-0.177366 +10,Hyde Park Corner,51.5029347,-0.1508562 +10,Marble Arch,51.5133563,-0.1595136 +10,Oxford Circus,51.5165182,-0.1308243 +10,Euston,51.5314825,-0.1344752 +10,King's Cross,51.5347488,-0.1245845 +11,Fulham Broadway,51.4799039,-0.1958386 +11,Fulham Broadway,51.4799039,-0.1958386 +11,"Chelsea, World's End",51.4810423,-0.1786311 +11,Sloane Square,51.4928113,-0.156879 +11,"Victoria, Coach Station",51.4924744,-0.1482485 +11,Victoria,51.4309209,-0.0936496 +11,Parliament Square,51.5007668,-0.1261294 +11,"Whitehall, Horse Guards",51.5049558,-0.1254432 +11,Trafalgar Square,51.5085695,-0.1272433 +11,Aldwych,51.5122788,-0.1191599 +11,Ludgate Circus,51.51432699999999,-0.1038489 +11,Mansion House,51.5127309,-0.08894429999999999 +11,Liverpool Street,51.5188119,-0.0796944 +12,Oxford Circus,51.5165184,-0.1309686 +12,Piccadilly Circus,51.5101227,-0.1347793 +12,"Whitehall, Horseguards",51.5049111,-0.1273704 +12,Parliament Square,51.5007668,-0.1261294 +12,Lambeth North,51.4935082,-0.1178424 +12,Elephant & Castle,51.49358119999999,-0.0985682 +12,"Camberwell Road, Medlar Street",51.4793161,-0.0941097 +12,Camberwell Green,51.47460479999999,-0.0933951 +12,Peckham,51.47032369999999,-0.0673872 +12,Peckham Rye,51.4645765,-0.0657682 +12,Dulwich Library,51.4488677,-0.07447669999999999 +13,North Finchley,51.6135087,-0.1754198 +13,"Finchley, Church End",51.604606,-0.1882833 +13,Golders Green,51.5740013,-0.1987725 +13,Finchley Road & Frognal,51.5503454,-0.180462 +13,Swiss Cottage,51.5425872,-0.1724737 +13,St John's Wood,51.5343581,-0.1742065 +13,Baker Street Station,51.5231548,-0.156863 +13,Baker Street Station,51.5231548,-0.156863 +13,Baker Street Station,51.5231548,-0.156863 +13,Portman Square,51.5163404,-0.1549876 +13,Portman Square,51.5163404,-0.1549876 +13,Marble Arch,51.5134505,-0.1594581 +13,"Park Lane, Hilton Hotel",51.5055096,-0.1503864 +13,Victoria,51.4309209,-0.0936496 +14,Putney Heath,51.4366227,-0.2304487 +14,Putney Station,51.4611807,-0.2164913 +14,Putney Bridge,51.4679357,-0.2118155 +14,Fulham Broadway,51.4802127,-0.1969798 +14,South Kensington,51.4953291,-0.1789909 +14,Hyde Park Corner,51.4309209,-0.0936496 +14,Green Park,51.4309209,-0.0936496 +14,Piccadilly Circus,51.5103455,-0.13441 +14,Tottenham Court Road,51.5170065,-0.1305656 +14,Tottenham Court Road,51.5170065,-0.1305656 +14,Warren Street,51.5241056,-0.1390055 +14,Warren Street,51.5241056,-0.1390055 +15,Blackwall,51.486813,0.007257999999999999 +15,"Poplar, All Saints",51.5105521,-0.0118612 +15,"Limehouse, Burdett Road",51.5236032,-0.0343309 +15,"Stepney, Arbour Square",51.514508,-0.04844690000000001 +15,Aldgate,51.5150654,-0.075847 +15,Aldgate,51.5150654,-0.075847 +15,Tower Hill,51.50973920000001,-0.0785773 +15,Cannon Street,51.5126702,-0.09531519999999999 +15,St. Paul's,51.6050001,-0.187336 +15,Ludgate Circus,51.5140488,-0.1043187 +15,Aldwych,51.5122751,-0.1188606 +15,Trafalgar Square,51.508039,-0.128069 +16,Cricklewood Bus Garage,51.56195959999999,-0.2224221 +16,Cricklewood Broadway,51.5529089,-0.2104297 +16,Kilburn High Road Station,51.537243,-0.192318 +16,Kilburn High Road Station,51.537243,-0.192318 +16,Edgware Road Station,51.51988249999999,-0.1678336 +16,Marble Arch,51.51335049999999,-0.1595594 +16,"Park Lane, Hilton Hotel",51.5055096,-0.1503864 +16,Victoria,51.4309209,-0.0936496 +17,Archway,51.4309209,-0.0936496 +17,"Holloway, Nag's Head",51.55724250000001,-0.1204364 +17,King's Cross,51.5347488,-0.1245845 +17,King's Cross,51.5347488,-0.1245845 +17,Ludgate Circus,51.5140505,-0.1043191 +17,St. Paul's,51.6050631,-0.1872825 +17,London Bridge,51.5078788,-0.0877321 +18,Sudbury,51.5142858,0.0640934 +18,Wembley Stadium,51.55602469999999,-0.2796177 +18,Stonebridge Park,51.54571809999999,-0.2615303 +18,Craven Park,51.54065989999999,-0.2558117 +18,Craven Park,51.54065989999999,-0.2558117 +18,"Harlesden, Jubilee Clock",51.5354215,-0.2479155 +18,"Harrow Road, Elgin Avenue",51.520765,-0.1810053 +18,"Harrow Road, Elgin Avenue",51.520765,-0.1810053 +18,"Harrow Road, Warwick Avenue",51.5208194,-0.1809035 +18,Paddington Green,51.5207833,-0.1734463 +18,Baker Street Station,51.5231548,-0.156863 +18,Warren Street,51.52412,-0.1396242 +18,Euston,51.53017,-0.123333 +19,Finsbury Park Station,51.5646425,-0.1058553 +19,Highbury Barn,51.5569649,-0.0979656 +19,Highbury & Islington,51.5569649,-0.0979656 +19,Islington Green,51.5362387,-0.1019279 +19,Rosebery Avenue,51.5239515,-0.1113229 +19,Holborn,51.5178118,-0.1098122 +19,Holborn,51.5178118,-0.1098122 +19,Piccadilly Circus,51.5101323,-0.1350825 +19,Hyde Park Corner,51.5029347,-0.1508562 +19,Hyde Park Corner,51.5029347,-0.1508562 +19,Sloane Square,51.4938898,-0.1552165 +19,"Battersea Bridge, South Side",51.4811674,-0.1725411 +20,Walthamstow Central,51.5830128,-0.019886 +20,"Leyton, Bakers Arms",51.5749185,-0.013549 +20,Whipps Cross,51.581499,0.0001219 +20,Woodford Green,51.6092549,0.0405521 +20,Woodford Wells,51.6148287,0.0282889 +20,Loughton,51.655942,0.068161 +20,Debden,51.6042352,0.04159529999999999 +21,"Lewisham, Shopping Centre",51.46115090000001,-0.0073177 +21,"Lewisham, Jerrard Street",51.4650045,-0.0164722 +21,New Cross Gate,51.4749904,-0.0403466 +21,New Cross Gate,51.4749904,-0.0403466 +21,Bricklayer's Arms,51.4661409,-0.2174147 +21,London Bridge,51.5078788,-0.0877321 +21,"Moorgate, Finsbury Square",51.5202193,-0.08877170000000001 +21,"Hoxton, Baring Street",51.5370603,-0.0886892 +21,Newington Green,51.5513088,-0.0844365 +22,Putney Common,51.4674099,-0.2282218 +22,Putney Church,51.4596431,-0.2141257 +22,Putney Bridge,51.4582148,-0.1979725 +22,Parsons Green,51.4731883,-0.2008051 +22,"Chelsea, World's End",51.4810423,-0.1786311 +22,Sloane Square,51.4928113,-0.156879 +22,Knightsbridge,51.4991195,-0.1644394 +22,Hyde Park Corner,51.5029347,-0.1508562 +22,Green Park,51.4309209,-0.0936496 +22,Piccadilly Circus,51.5101327,-0.1350772 +23,Westbourne Park,51.52093499999999,-0.2007649 +23,"Ladbroke Grove, Sainsbury's",51.5256365,-0.215718 +23,"Notting Hill, Westbourne Grove",51.5155424,-0.1893047 +23,Paddington,51.4309209,-0.0936496 +23,Paddington,51.4309209,-0.0936496 +23,Paddington,51.4309209,-0.0936496 +23,Edgware Road Station,51.51988249999999,-0.1678336 +23,Marble Arch,51.5134632,-0.1593655 +23,Marble Arch,51.5134632,-0.1593655 +23,Oxford Circus,51.5162691,-0.1312544 +23,Oxford Circus,51.5162691,-0.1312544 +23,Piccadilly Circus,51.5101331,-0.1350718 +23,Trafalgar Square,51.508039,-0.128069 +23,Aldwych,51.5124243,-0.1190358 +23,Ludgate Circus,51.5140556,-0.1043203 +23,St. Paul's,51.5064502,-0.2935763 +23,Liverpool Street,51.517297,-0.0823724 +24,Pimlico,51.490744,-0.1403619 +24,Victoria,51.49554149999999,-0.1435602 +24,Parliament Square,51.5007668,-0.1261294 +24,Trafalgar Square,51.508039,-0.128069 +24,Tottenham Court Road,51.5180841,-0.1315221 +24,Tottenham Court Road,51.5180841,-0.1315221 +24,Warren Street,51.5237815,-0.1407361 +24,Mornington Crescent,51.5335427,-0.1406798 +24,Camden Town,51.5390261,-0.1425516 +24,Chalk Farm,51.5444834,-0.152158 +24,Hampstead Heath,51.5608294,-0.1629416 +25,Oxford Circus,51.5164398,-0.1324736 +25,Holborn,51.5181161,-0.1104144 +25,Holborn,51.5181161,-0.1104144 +25,City Thameslink,51.5140438,-0.1033475 +25,St. Paul's,51.50677959999999,-0.2927933 +25,Bank,51.4309209,-0.0936496 +25,Aldgate,51.5134081,-0.0770975 +25,Mile End,51.52354529999999,-0.0330122 +25,Bow Church,51.5287753,-0.0167013 +25,Bow Church,51.5287753,-0.0167013 +25,Stratford,51.5426313,-0.0010369 +25,"Forest Gate, Police Station",51.5467822,0.0309995 +25,Manor Park,51.4568223,-0.0013946 +25,Ilford Broadway,51.556619,0.076251 +25,Ilford,51.556619,0.076251 +26,Hackney Wick,51.544579,-0.0256935 +26,"Hackney, Well Street",51.5399525,-0.0546394 +26,Ash Grove,51.4069459,-0.0561859 +26,Shoreditch,51.5229106,-0.0777472 +26,Shoreditch,51.5229106,-0.0777472 +26,Liverpool Street,51.5172811,-0.0822137 +26,Mansion House,51.51300699999999,-0.08950899999999999 +26,Aldwych,51.5130774,-0.1162049 +26,Waterloo,51.5048541,-0.1136621 +27,"Chiswick, Business Park",51.4930604,-0.2748696 +27,"Stamford Brook, Bus Garage",51.4309209,-0.0936496 +27,Hammersmith,51.491187,-0.223731 +27,"Kensington, Holland Road",51.4975402,-0.2073943 +27,"Kensington, Holland Road",51.4975402,-0.2073943 +27,Notting Hill Gate,51.5091914,-0.1947424 +27,Paddington,51.4309209,-0.0936496 +27,Edgware Road Station,51.51988249999999,-0.1678336 +27,Baker Street Station,51.5231548,-0.156863 +27,Warren Street,51.5237196,-0.1409656 +27,Mornington Crescent,51.5338447,-0.1406486 +27,Camden Town,51.5390261,-0.1425516 +27,Chalk Farm,51.5444834,-0.152158 +28,Kensal Rise,51.5345071,-0.2250186 +28,"Harrow Road, Elgin Avenue",51.520765,-0.1810053 +28,Westbourne Park,51.51769299999999,-0.194941 +28,Notting Hill Gate,51.5096114,-0.1943814 +28,"Kensington, Holland Road",51.4978412,-0.2072414 +28,"North End Road, Lillie Road",51.4857738,-0.2013501 +28,Fulham Broadway,51.4803466,-0.1969636 +28,New Kings Road,51.4733974,-0.1978029 +28,"Wandsworth Bridge, South Side",51.4651939,-0.1880094 +28,"Wandsworth, Town Hall",51.4570227,-0.191114 +28,Wandsworth,51.45837299999999,-0.1891356 +29,Wood Green,51.5971722,-0.1098021 +29,Wood Green,51.5971722,-0.1098021 +29,Turnpike Lane Station,51.5904278,-0.1027587 +29,Finsbury Park Station,51.5646425,-0.1058553 +29,Finsbury Park Station,51.5646425,-0.1058553 +29,"Holloway, Nag's Head",51.55724250000001,-0.1204364 +29,"Holloway, Nag's Head",51.55724250000001,-0.1204364 +29,Camden Town,51.5390261,-0.1425516 +29,Mornington Crescent,51.533949,-0.1406149 +29,Warren Street,51.5236972,-0.141188 +29,Tottenham Court Road,51.5180123,-0.131601 +29,Trafalgar Square,51.508039,-0.128069 +29,Trafalgar Square,51.508039,-0.128069 +30,Marble Arch,51.51333700000001,-0.1596664 +30,Portman Square,51.5156011,-0.1569817 +30,Baker Street Station,51.5231548,-0.156863 +30,Warren Street,51.52360400000001,-0.1416947 +30,Euston,51.530473,-0.1232482 +30,King's Cross,51.5347488,-0.1245845 +30,Islington Angel,51.5357662,-0.1025254 +30,Islington Green,51.5357662,-0.1025254 +30,Highbury & Islington,51.5569649,-0.0979656 +30,Highbury & Islington,51.5569649,-0.0979656 +30,Mildmay Park,51.54806050000001,-0.0838744 +30,Hackney Central,51.5482344,-0.05738749999999999 +30,Hackney Wick,51.544579,-0.0256935 +31,Camden Town,51.5390261,-0.1425516 +31,Chalk Farm,51.5444834,-0.152158 +31,Swiss Cottage,51.5425872,-0.1724737 +31,Swiss Cottage,51.5425872,-0.1724737 +31,South Hampstead Station,51.4309209,-0.0936496 +31,Kilburn High Road Station,51.539813,-0.1985291 +31,Kilburn High Road Station,51.539813,-0.1985291 +31,Kilburn Park,51.4309209,-0.0936496 +31,"Maida Hill, The Chippenham",51.5243627,-0.2017331 +31,Westbourne Park,51.51769299999999,-0.194941 +31,Westbourne Park,51.51769299999999,-0.194941 +31,Notting Hill Gate,51.51029399999999,-0.1975027 +31,Holland Park Roundabout,51.5042925,-0.217039 +31,White City,51.51146199999999,-0.2376332 +32,Edgware,51.61548819999999,-0.2609598 +32,Burnt Oak Broadway,51.602753,-0.2700278 +32,"Colindale, Superstores",51.5942575,-0.2607018 +32,West Hendon Broadway,51.5772325,-0.2392682 +32,Staples Corner,51.5714404,-0.2319415 +32,Cricklewood Bus Garage,51.56195959999999,-0.2224221 +32,Cricklewood Broadway,51.5567072,-0.2153734 +32,Kilburn Park,51.53504119999999,-0.1938988 +33,"Fulwell, Stanley Road",51.4285891,-0.3426514 +33,Teddington,51.4268694,-0.3338681 +33,Twickenham,51.4453043,-0.3375429 +33,Richmond,51.4309209,-0.0936496 +33,"East Sheen, Queen's Road",51.46676369999999,-0.2595881 +33,Barnes Common,51.4681254,-0.2413995 +33,"Barnes, Red Lion",51.4755063,-0.2389859 +33,Hammersmith,51.491187,-0.223731 +34,Barnet Church,51.6526856,-0.1992227 +34,"Barnet, Odeon",51.64663059999999,-0.1865655 +34,Whetstone,51.4309209,-0.0936496 +34,New Southgate,51.61100099999999,-0.135469 +34,Arnos Grove,51.6222675,-0.1278413 +34,"Palmers Green, North Circular Road",51.6214872,-0.1075657 +34,"Edmonton, Cambridge Roundabout",51.4309209,-0.0936496 +34,North Middlesex Hospital,51.6131618,-0.0735832 +34,"Edmonton, Angel",51.6088564,-0.04952819999999999 +34,"Angel Road, Eleys Estate",51.6169024,-0.0460262 +34,"Walthamstow, Crooked Billet",51.601088,-0.0159737 +34,Walthamstow Central,51.5830128,-0.019886 +35,Clapham Junction,51.4651737,-0.1708113 +35,Clapham Common,51.4589252,-0.1493071 +35,Brixton,51.4612794,-0.1156148 +35,Brixton,51.4612794,-0.1156148 +35,Camberwell Green,51.47418649999999,-0.09230569999999999 +35,Elephant & Castle,51.49384080000001,-0.0979717 +35,Elephant & Castle,51.49384080000001,-0.0979717 +35,London Bridge,51.5078788,-0.0877321 +35,London Bridge,51.5078788,-0.0877321 +35,Shoreditch,51.5229106,-0.0777472 +36,Queen's Park,51.5345448,-0.2043853 +36,"Harrow Road, Elgin Avenue",51.520765,-0.1810053 +36,Paddington,51.4309209,-0.0936496 +36,Marble Arch,51.5133312,-0.1597123 +36,Hyde Park Corner,51.5029347,-0.1508562 +36,Vauxhall,51.4309209,-0.0936496 +36,Camberwell Green,51.47418649999999,-0.09230569999999999 +36,Peckham,51.47032369999999,-0.0673872 +36,Peckham,51.47032369999999,-0.0673872 +36,New Cross Gate,51.4749904,-0.0403466 +37,Putney Heath,51.4535043,-0.2295163 +37,Wandsworth,51.45837299999999,-0.1891356 +37,Clapham Junction,51.4651737,-0.1708113 +37,Clapham Junction,51.4651737,-0.1708113 +37,Clapham Common,51.4589252,-0.1493071 +37,Brixton,51.4612794,-0.1156148 +37,Herne Hill,51.4609208,-0.0985404 +37,East Dulwich,51.4545635,-0.0732101 +37,Peckham Rye,51.464316,-0.06563229999999999 +37,Peckham,51.47032369999999,-0.0673872 +38,Clapton Pond,51.5561061,-0.05490830000000001 +38,Hackney Central,51.5482344,-0.05738749999999999 +38,Mildmay Park,51.5483296,-0.0839477 +38,Islington Green,51.5356013,-0.1033279 +38,Islington Angel,51.5356013,-0.1033279 +38,Rosebery Avenue,51.5244006,-0.1107607 +38,Holborn,51.51811559999999,-0.1104102 +38,Piccadilly Circus,51.5112652,-0.1343363 +38,Hyde Park Corner,51.4309209,-0.0936496 +38,Victoria,51.4309209,-0.0936496 +39,Putney Bridge,51.4669712,-0.2129034 +39,Putney Station,51.4611807,-0.2164913 +39,Putney Heath,51.4535043,-0.2295163 +39,"Southfields, Granville Road",51.4497918,-0.2017799 +39,Wandsworth,51.45837299999999,-0.1891356 +39,Clapham Junction,51.4651737,-0.1708113 +40,Dulwich Library,51.4488677,-0.07447669999999999 +40,East Dulwich,51.4545635,-0.0732101 +40,Camberwell Green,51.4755856,-0.09233469999999999 +40,Elephant & Castle,51.4938192,-0.0981413 +40,Elephant & Castle,51.4938192,-0.0981413 +40,London Bridge,51.5078788,-0.0877321 +40,Aldgate,51.5133004,-0.0774081 +41,Archway,51.4694651,-0.2531938 +41,Hornsey Rise,51.5710037,-0.1243396 +41,Crouch End,51.5819979,-0.1221464 +41,Hornsey,51.5872715,-0.1103806 +41,West Green,51.586254,-0.0867628 +41,"Green Lanes, West Green Road",51.5841132,-0.07532190000000001 +41,Seven Sisters,51.582652,-0.0747232 +41,Tottenham Hale,51.5892808,-0.06105049999999999 +42,"East Dulwich, Sainsburys",51.4624191,-0.0834805 +42,Camberwell Green,51.4755856,-0.09233469999999999 +42,Camberwell Green,51.4755856,-0.09233469999999999 +42,Bricklayer's Arms,51.4661409,-0.2174147 +42,Tower Gateway,51.5106312,-0.0737553 +42,Aldgate,51.5169305,-0.064391 +42,Liverpool Street,51.5169921,-0.0810587 +43,Friern Barnet,51.6141967,-0.1540148 +43,Muswell Hill,51.5911816,-0.1443015 +43,Muswell Hill,51.5911816,-0.1443015 +43,Archway,51.4309209,-0.0936496 +43,"Holloway, Nag's Head",51.55724250000001,-0.1204364 +43,Highbury & Islington,51.5569649,-0.0979656 +43,Islington Angel,51.5354865,-0.103688 +43,Angel,51.4309209,-0.0936496 +43,Old Street Station,51.4309209,-0.0936496 +43,Moorgate,51.5163044,-0.0890892 +43,Bank Station,51.4309209,-0.0936496 +43,London Bridge,51.5078788,-0.0877321 +44,Victoria,51.4309209,-0.0936496 +44,Battersea Park Station,51.47696,-0.14751 +44,"Battersea, Latchmere Road",51.4701066,-0.1644671 +44,Wandsworth,51.45837299999999,-0.1891356 +44,Wandsworth,51.45837299999999,-0.1891356 +44,Wandsworth,51.45837299999999,-0.1891356 +44,"Garratt Lane, Wimbledon Road",51.4324265,-0.1823902 +44,Tooting Broadway,51.427867,-0.1678142 +44,Tooting Station,51.41986989999999,-0.16136 +45,King's Cross,51.5347488,-0.1245845 +45,"Farringdon Street, Smithfield",51.5179207,-0.1055172 +45,Ludgate Circus,51.5140743,-0.1043248 +45,Camberwell Green,51.4755856,-0.09233469999999999 +45,Brixton,51.4612794,-0.1156148 +45,Brixton,51.4612794,-0.1156148 +45,Clapham Park,51.4476066,-0.1431943 +46,Paddington,51.4309209,-0.0936496 +46,Warwick Avenue,51.5242448,-0.1861688 +46,Swiss Cottage,51.5425872,-0.1724737 +46,Hampstead Heath,51.5608294,-0.1629416 +46,King's Cross,51.5347488,-0.1245845 +46,King's Cross,51.5347488,-0.1245845 +46,St Bartholomew's Hospital,51.51749599999999,-0.1000463 +47,"Bellingham, Catford Bus Garage",51.434704,-0.017839 +47,"Lewisham, Shopping Centre",51.46175909999999,-0.0119106 +47,"Deptford, Church Street",51.4746631,-0.0239358 +47,Deptford Bridge,51.4744133,-0.0214318 +47,Surrey Quays,51.4944172,-0.0383063 +47,Canada Water,51.4962989,-0.0482742 +47,London Bridge,51.5072178,-0.1275862 +47,Liverpool Street,51.5169916,-0.08105749999999999 +47,"Tower Bridge Road, Druid Street",51.5003867,-0.07642150000000002 +47,Shoreditch,51.5229106,-0.0777472 +48,Walthamstow Central,51.5830128,-0.019886 +48,Leyton Bakers Arms,51.5749185,-0.013549 +48,Clapton Pond,51.5561061,-0.05490830000000001 +48,Clapton Pond,51.5561061,-0.05490830000000001 +48,Clapton Pond,51.5561061,-0.05490830000000001 +48,Hackney Well Street,51.5400447,-0.0529401 +48,Ash Grove,51.47989889999999,-0.3919869 +48,Shoreditch,51.5229106,-0.0777472 +48,Liverpool Street,51.5169915,-0.0810573 +48,Monument,51.4309209,-0.0936496 +48,London Bridge,51.50949749999999,-0.0872447 +48,London Bridge,51.50949749999999,-0.0872447 +49,Clapham Junction,51.4309209,-0.0936496 +49,"Battersea, Latchmere Road",51.4701063,-0.1641724 +49,"Battersea Bridge, South Side",51.4811674,-0.1725411 +49,South Kensington,51.4953291,-0.1789909 +49,"Kensington, Palace Gate",51.4997084,-0.1839913 +49,"Kensington, Holland Road",51.4981321,-0.2082809 +49,Holland Park Roundabout,51.5042925,-0.217039 +49,White City,51.51146199999999,-0.2376332 +50,Croydon Town Centre,51.3769529,-0.0956895 +50,West Croydon,51.3684193,-0.0998425 +50,"Thornton Heath, High Street",51.3985843,-0.0946916 +50,Norbury,51.4085878,-0.1213899 +50,"Streatham, Green Lane",51.40957599999999,-0.1064891 +50,Streatham Station,51.4259857,-0.131308 +50,Streatham Hill Station,51.4382009,-0.1270706 +50,Clapham Park,51.4476066,-0.1431943 +50,Clapham Common,51.4589252,-0.1493071 +50,Stockwell,51.4698988,-0.1203349 +51,Woolwich,51.4894752,0.06758829999999999 +51,Plumstead Common,51.4810415,0.0713811 +51,Welling Station,51.4648,0.10172 +51,Welling Corner,51.4626258,0.1081541 +51,Sidcup Station,51.4339345,0.1038351 +51,Foots Cray,51.4174447,0.1210622 +51,St Mary Cray Station,51.3957762,0.1071945 +51,"Orpington, Perry Hall Road",51.3822834,0.1033862 +51,Orpington War Memorial,51.373203,0.09753479999999999 +51,Orpington Station,51.37329,0.08911999999999999 +52,Victoria,51.5110756,-0.1077217 +52,Hyde Park Corner,51.5029347,-0.1508562 +52,Hyde Park Corner,51.5029347,-0.1508562 +52,Royal Albert Hall,51.5009088,-0.177366 +52,Notting Hill Gate,51.50948649999999,-0.1953925 +52,Notting Hill Gate,51.50948649999999,-0.1953925 +52,Notting Hill Gate,51.50948649999999,-0.1953925 +52,"Ladbroke Grove, Sainsbury's",51.5256365,-0.215718 +52,Kensal Rise,51.5345071,-0.2250186 +52,"Willesden, Bus Garage",51.5474482,-0.2394372 +53,Plumstead Station,51.4896774,0.0847463 +53,Plumstead Common,51.4823231,0.0695262 +53,Woolwich,51.4894752,0.06758829999999999 +53,Woolwich,51.4894752,0.06758829999999999 +53,Charlton Village,51.4309209,-0.0936496 +53,"Blackheath, Royal Standard",51.4779946,0.0202001 +53,"Blackheath, Royal Standard",51.4779946,0.0202001 +53,Deptford Bridge,51.4743135,-0.0215605 +53,New Cross,51.4769047,-0.0336897 +53,New Cross Gate,51.4749904,-0.0403466 +53,Bricklayer's Arms,51.4661409,-0.2174147 +53,Elephant & Castle,51.49384080000001,-0.0979717 +53,Lambeth North,51.4935082,-0.1178424 +53,Lambeth North,51.4935082,-0.1178424 +53,Parliament Square,51.5007668,-0.1261294 +53,"Whitehall, Horse Guards",51.506168,-0.1268165 +54,Elmers End,51.39749,-0.0474767 +54,"Beckenham, War Memorial",51.406914,-0.0320175 +54,"Beckenham, War Memorial",51.406914,-0.0320175 +54,"Bellingham, Catford Bus Garage",51.434704,-0.017839 +54,"Catford, Town Centre",51.4453954,-0.0160913 +54,"Catford, Town Centre",51.4453954,-0.0160913 +54,Lewisham Shopping Centre,51.46175909999999,-0.0119106 +54,Blackheath Village,51.4652738,0.0094822 +54,Charlton Village,51.4792826,0.0248846 +54,"Blackheath, Royal Standard",51.4779946,0.0202001 +54,Woolwich,51.4894752,0.06758829999999999 +55,"Leyton, Bakers Arms",51.5749185,-0.013549 +55,Clapton Pond,51.5561061,-0.05490830000000001 +55,Clapton Pond,51.5561061,-0.05490830000000001 +55,Clapton Pond,51.5561061,-0.05490830000000001 +55,Hackney Well Street,51.5409698,-0.0502274 +55,Ash Grove,51.6354767,-0.0751363 +55,Shoreditch,51.5229106,-0.0777472 +55,Old Street Station,51.5256719,-0.0874922 +55,Old Street Station,51.5256719,-0.0874922 +55,Clerkenwell Green,51.5227521,-0.1059866 +55,Holborn,51.5181148,-0.1104047 +55,Holborn,51.5181148,-0.1104047 +55,Oxford Circus,51.5161662,-0.1326994 +56,Whipps Cross,51.581499,0.0001219 +56,"Leyton, Bakers Arms",51.5749185,-0.013549 +56,Clapton Pond,51.5561061,-0.05490830000000001 +56,Clapton Pond,51.5561061,-0.05490830000000001 +56,Dalston Junction,51.5459999,-0.0751485 +56,Mildmay Park,51.54948479999999,-0.0842682 +56,Islington Green,51.5354865,-0.103688 +56,Islington Angel,51.5346761,-0.1042905 +56,Barbican,51.5202077,-0.09378639999999999 +56,St Bartholomew's Hospital,51.51749599999999,-0.1000463 +57,Kingston,51.41233,-0.300689 +57,Kingston Hospital,51.4148229,-0.2824061 +57,Coombe Lane,51.4098586,-0.2361138 +57,Raynes Park,51.4084257,-0.2298751 +57,Wimbledon,51.41833889999999,-0.2206288 +57,Wimbledon,51.41833889999999,-0.2206288 +57,Colliers Wood,51.41704439999999,-0.1778555 +57,"Merton, Bus Garage",51.4165431,-0.1813083 +57,"Merton, Bus Garage",51.4165431,-0.1813083 +57,Tooting Broadway,51.427867,-0.1678142 +57,"Streatham, St Leonard's Church",51.42926610000001,-0.1311095 +57,Streatham Hill Station,51.4382009,-0.1270706 +57,Clapham Park,51.4476066,-0.1431943 +58,"East Ham, Central Park",51.5293175,0.0527634 +58,"East Ham, Newham Town Hall",51.53280239999999,0.0551608 +58,"Upton Park, Boleyn",51.5305005,0.0384915 +58,"Forest Gate, Police Station",51.5467822,0.0309995 +58,Wanstead Park,51.5610723,0.0417191 +58,"Leyton, Downsell Road",51.553296,-0.0028916 +58,"Leyton, Grange Park Road",51.5651058,-0.0141172 +58,Markhouse Corner,51.5779407,-0.0304034 +58,Walthamstow Central,51.5830128,-0.019886 +59,"Streatham Hill, Telford Avenue",51.44235,-0.1305407 +59,Brixton,51.4612794,-0.1156148 +59,Brixton,51.4612794,-0.1156148 +59,Kennington Church,51.504101,-0.193068 +59,Waterloo,51.5045274,-0.1130244 +59,Aldwych,51.51324409999999,-0.1172819 +59,Holborn,51.5181147,-0.1104034 +59,Russell Square,51.5212546,-0.1242077 +59,Euston,51.5268812,-0.1315678 +59,King's Cross,51.5347488,-0.1245845 +60,Old Coulsdon,51.298482,-0.114175 +60,"Coulsdon, Chaldon Way",51.3107704,-0.1340667 +60,Coulsdon,51.319941,-0.141267 +60,Purley,51.339228,-0.119711 +60,Purley,51.339228,-0.119711 +60,"South Croydon, Bus Garage",51.3544903,-0.0968822 +60,"South Croydon, South End",51.36546999999999,-0.09921999999999999 +60,Croydon Town Centre,51.3769529,-0.0956895 +60,West Croydon,51.3684193,-0.0998425 +60,Thornton Heath Pond,51.3941232,-0.1146955 +60,Pollards Hill,51.4000406,-0.1332582 +60,Streatham Vale,51.4165952,-0.1384217 +60,Streatham Station,51.4259857,-0.131308 +61,Chislehurst,51.412626,0.077487 +61,"Orpington, Perry Hall Road",51.3822977,0.1023434 +61,Orpington Walnuts Centre,51.3773656,0.1007092 +61,Orpington War Memorial,51.373203,0.09753479999999999 +61,Orpington Station,51.374843,0.09421399999999999 +61,Locksbottom,51.3673231,0.0547259 +61,"Bromley Common, Bus Garage",51.38774,0.0363217 +61,"Bromley Common, Crown Lane",51.3890567,0.0384357 +61,Bromley South,51.406025,0.013156 +61,Bromley North,51.406025,0.013156 +62,Marks Gate,51.5901971,0.1424532 +62,Chadwell Heath,51.5722283,0.141995 +62,"Becontree, Green Lane",51.5589129,0.08329829999999999 +62,"Ripple Road, Lodge Avenue",51.5327114,0.1076005 +62,Fair Cross,51.5425708,0.0822502 +62,Barking,51.536563,0.075766 +62,"Barking, Gascoigne Estate",51.529678,0.08277400000000001 +63,Honor Oak,51.4494778,-0.0448232 +63,Peckham Rye,51.4635527,-0.06519749999999999 +63,Peckham,51.47032369999999,-0.0673872 +63,Bricklayer's Arms,51.4661409,-0.2174147 +63,NO BLIND DESCRIPTION (Departs only),51.4309209,-0.0936496 +63,Elephant & Castle,51.49384080000001,-0.0979717 +63,"Farringdon Street, Smithfield",51.5151388,-0.1048555 +63,Clerkenwell Green,51.5227521,-0.1059866 +63,King's Cross,51.5347488,-0.1245845 +64,Thornton Heath Pond,51.3941232,-0.1146955 +64,West Croydon,51.3684193,-0.0998425 +64,East Croydon,51.3769529,-0.0956895 +64,Selsdon,51.34372279999999,-0.061975 +64,Addington Village,51.35922559999999,-0.0286665 +64,New Addington,51.348184,-0.017094 +65,Chessington,51.363583,-0.296254 +65,Kingston,51.41233,-0.300689 +65,"Kingston, Cromwell Road",51.4952712,-0.1790609 +65,Ham,51.4309209,-0.0936496 +65,Richmond,51.46131099999999,-0.303742 +65,Richmond,51.46131099999999,-0.303742 +65,"Brentford, County Court",51.4842409,-0.3043609 +65,"Great West Road, Ealing Road",51.4913803,-0.3039856 +65,Ealing Broadway,51.5136997,-0.3031306 +66,Romford Station,51.57472449999999,0.1826519 +66,Romford Market,51.5790739,0.1813886 +66,Marks Gate,51.5901971,0.1424532 +66,Newbury Park,51.5734779,0.08897669999999999 +66,Gants Hill,51.5767812,0.0661732 +66,Redbridge Station,51.5763264,0.0453986 +66,Wanstead,51.5767971,0.0249881 +66,Leytonstone,51.5649624,0.0088141 +67,Wood Green,51.5971722,-0.1098021 +67,Wood Green,51.5971722,-0.1098021 +67,"Green Lanes, West Green Road",51.5844105,-0.0764614 +67,West Green,51.586254,-0.0867628 +67,Stamford Hill,51.5686382,-0.0731048 +67,Stoke Newington,51.561175,-0.08349229999999999 +67,Stoke Newington,51.561175,-0.08349229999999999 +67,Dalston Junction,51.5459999,-0.0751485 +67,Dalston,51.54704,-0.06940349999999999 +67,Shoreditch,51.5229106,-0.0777472 +67,Aldgate,51.5133004,-0.0774081 +68,West Norwood,51.427905,-0.1002486 +68,Tulse Hill Station,51.43986,-0.10505 +68,Herne Hill,51.4609208,-0.0985404 +68,Herne Hill,51.4609208,-0.0985404 +68,Camberwell Green,51.4756016,-0.0928896 +68,Camberwell Green,51.4756016,-0.0928896 +68,Elephant & Castle,51.4938279,-0.0981368 +68,Waterloo,51.5041898,-0.1122489 +68,Waterloo,51.5041898,-0.1122489 +68,Aldwych,51.5130911,-0.1164802 +68,Holborn,51.5181143,-0.1104004 +68,Russell Square,51.521869,-0.1246032 +68,Euston,51.5282715,-0.1289675 +69,Walthamstow Central,51.5830128,-0.019886 +69,"Leyton, Bakers Arms",51.5749185,-0.013549 +69,"Leyton, Grange Park Road",51.56521830000001,-0.0136752 +69,"Leyton, Downsell Road",51.55316999999999,-0.0025209 +69,Stratford,51.5426313,-0.0010369 +69,Plaistow,51.5268317,0.0308143 +69,"Canning Town, Hermit Road",51.5209368,0.0125057 +69,Canning Town,51.5189494,0.0132 +70,"Chiswick, Business Park",51.4930604,-0.2748696 +70,"Acton, High Street",51.5068505,-0.2673267 +70,East Acton Lane,51.5123715,-0.2543317 +70,East Acton,51.5127758,-0.2476803 +70,North Pole Road,51.51923009999999,-0.2273689 +70,"Ladbroke Grove, Sainsbury's",51.5256365,-0.215718 +70,Chepstow Road,51.5170993,-0.1955316 +70,Chepstow Road,51.5170993,-0.1955316 +70,Queensway,51.51257870000001,-0.1873839 +70,Notting Hill Gate,51.5091772,-0.1961953 +70,Royal Albert Hall,51.5009088,-0.177366 +70,South Kensington,51.4953291,-0.1789909 +71,Chessington,51.363583,-0.296254 +71,Copt Gilders,51.35919000000001,-0.29498 +71,"Hook, Bridge Road",51.4682792,0.1849895 +71,Hook Junction,51.3748795,-0.3038393 +71,Surbiton,51.39400999999999,-0.302662 +71,Surbiton,51.39400999999999,-0.302662 +71,Kingston,51.41233,-0.300689 +72,East Acton,51.5127758,-0.2476803 +72,"Wood Lane, Du Cane Road",51.5181773,-0.2356671 +72,Shepherd's Bush,51.5051913,-0.22469 +72,Shepherd's Bush,51.5051913,-0.22469 +72,Brook Green,51.4960545,-0.2190422 +72,Hammersmith,51.491187,-0.223731 +72,Hammersmith,51.491187,-0.223731 +72,"Hammersmith Bridge, North Side",51.48972029999999,-0.2289675 +72,Castelnau,51.4803332,-0.2367515 +72,"Barnes, Red Lion",51.4755063,-0.2389859 +72,Barnes Common,51.4681254,-0.2413995 +72,Roehampton,51.4484339,-0.2397592 +72,"Roehampton, Bessborough Road",51.4463277,-0.2386829 +73,Victoria,51.4309209,-0.0936496 +73,"Park Lane, Hilton Hotel",51.5055096,-0.1503864 +73,Marble Arch,51.5133234,-0.1597734 +73,Oxford Circus,51.5163602,-0.1328952 +73,Oxford Circus,51.5163602,-0.1328952 +73,Tottenham Court Road,51.5185,-0.1321613 +73,Tottenham Court Road,51.5185,-0.1321613 +73,Warren Street,51.524438,-0.1385486 +73,Warren Street,51.524438,-0.1385486 +73,Euston,51.52894329999999,-0.1261751 +73,King's Cross,51.5347488,-0.1245845 +73,Islington Angel,51.5346761,-0.1042905 +73,Islington Green,51.5354865,-0.103688 +73,Mildmay Park,51.5499786,-0.084878 +73,Newington Green,51.5511621,-0.0858874 +73,Albion Road,51.554547,-0.08466159999999999 +73,Stoke Newington,51.561175,-0.08349229999999999 +74,"Putney, High Street",51.4642989,-0.2153882 +74,"Putney, High Street",51.4642989,-0.2153882 +74,Putney Bridge,51.459722,-0.1983352 +74,West Brompton,51.483494,-0.196802 +74,Earl's Court,51.490331,-0.1958417 +74,South Kensington,51.4953291,-0.1789909 +74,Hyde Park Corner,51.5029347,-0.1508562 +74,Marble Arch,51.5133234,-0.1597734 +74,Marble Arch,51.5133234,-0.1597734 +74,Portman Square,51.515381,-0.1546695 +74,Baker Street Station,51.4309209,-0.0936496 +75,Lewisham Station,51.46115090000001,-0.0073177 +75,"Catford, Town Centre",51.4453954,-0.0160913 +75,"Catford, Town Centre",51.4453954,-0.0160913 +75,"Catford, St. Dunstan's",51.4430327,-0.0237655 +75,Penge,51.41388490000001,-0.0570112 +75,Norwood Junction,51.39731,-0.07501000000000001 +75,West Croydon,51.3684193,-0.0998425 +75,Croydon Town Centre,51.3769529,-0.0956895 +76,Tottenham Hale Bus Station,51.58841109999999,-0.061242 +76,Tottenham Town Hall,51.5872187,-0.0725467 +76,Stamford Hill,51.56690570000001,-0.0726724 +76,Stoke Newington,51.561175,-0.08349229999999999 +76,"Hoxton, Baring Street",51.5366266,-0.0886478 +76,"Hoxton, Baring Street",51.5366266,-0.0886478 +76,Dalston Junction,51.5459999,-0.0751485 +76,Old Street Station,51.5256719,-0.0874922 +76,Mansion House,51.51300699999999,-0.08950899999999999 +76,Ludgate Circus,51.5141007,-0.1043311 +76,Aldwych,51.5130912,-0.1164853 +76,Waterloo,51.5043961,-0.1130969 +77,Waterloo,51.5040874,-0.1117601 +77,St Thomas' Hospital,51.4991539,-0.1188859 +77,Vauxhall,51.4309209,-0.0936496 +77,Lambeth College,51.4587037,-0.1410873 +77,Clapham Junction,51.4651737,-0.1708113 +77,Clapham Junction,51.4651737,-0.1708113 +77,"Garratt Lane, Wimbledon Road",51.4409636,-0.1869488 +77,Tooting Broadway,51.427867,-0.1678142 +77,Tooting Station,51.41986989999999,-0.16136 +78,Shoreditch,51.5229106,-0.0777472 +78,Shoreditch,51.5229106,-0.0777472 +78,Liverpool Street,51.5169907,-0.0810552 +78,Aldgate,51.5133004,-0.0774081 +78,"Tower Bridge Road, Druid Street",51.4997177,-0.0753387 +78,"Old Kent Road, Tesco",51.4854662,-0.0700918 +78,Peckham,51.47032369999999,-0.0673872 +78,Peckham Rye,51.4644631,-0.06657249999999999 +78,Nunhead,51.4657341,-0.054919 +79,"Alperton, Sainsbury's",51.5383862,-0.3028583 +79,Alperton,51.539601,-0.2988365 +79,Wembley Central,51.55214429999999,-0.2965274 +79,Wembley High Road,51.5531196,-0.295206 +79,"Preston Road, East Lane",51.5622614,-0.29827 +79,Preston Road Station,51.57197,-0.29508 +79,Kingsbury Circle,51.5853429,-0.2812115 +79,Queensbury,51.5942132,-0.2853683 +79,Canons Park,51.6076736,-0.2962361 +79,Edgware Station,51.6134923,-0.2753661 +80,"Belmont, High Down & Downview",51.4309209,-0.0936496 +80,Sutton Station,51.3614279,-0.193961 +80,"Sutton, Bus Garage",51.369469,-0.1985923 +80,Morden,51.394943,-0.19446 +80,Morden,51.394943,-0.19446 +80,St Helier,51.395985,-0.1875555 +80,"Hackbridge, Reynold's Close",51.3751002,-0.1556286 +81,Slough,51.4309209,-0.0936496 +81,Langley Fire Station,51.4309209,-0.0936496 +81,Colnbrook,51.4973363,-0.1045651 +81,Poyle,51.4754669,-0.5118773000000001 +81,"Bath Road, Hatch Lane",51.486421,-0.4760167 +81,"Bath Road, Sipson Road",51.5003514,-0.4640708 +81,"Bath Road, Nobel Drive",51.4815821,-0.4302396 +81,Cranford,51.4720623,-0.4055896 +81,Hounslow West,51.469435,-0.3837709 +81,"Hounslow, Bell Corner",51.468569,-0.3666325 +81,"Hounslow, Bus Station",51.4708688,-0.3546457 +83,Golders Green,51.5740013,-0.1987725 +83,"Hendon, Queens Road",51.5841638,-0.2202724 +83,West Hendon Broadway,51.5752931,-0.2378247 +83,Kingsbury Green,51.5814409,-0.2619577 +83,Wembley Arena,51.558096,-0.282586 +83,Wembley Stadium,51.55602469999999,-0.2796177 +83,Alperton,51.539601,-0.2988365 +83,Alperton,51.539601,-0.2988365 +85,Kingston,51.41233,-0.300689 +85,Kingston,51.41233,-0.300689 +85,"Kingston Hill, Queens Road",51.4171617,-0.2825256 +85,Roehampton Vale,51.439021,-0.2484373 +85,Roehampton,51.4584564,-0.2425687 +85,Roehampton Vale,51.439021,-0.2484373 +85,Putney Heath,51.4524424,-0.2298485 +85,Putney Bridge,51.46112900000001,-0.2034236 +86,Stratford,51.5426313,-0.0010369 +86,"Woodgrange Park, Katherine Road",51.5346001,0.0467122 +86,Manor Park,51.4543709,-0.0001943 +86,Ilford Broadway,51.556619,0.076251 +86,Ilford Hill,51.5586041,0.07009270000000001 +86,Ilford,51.556619,0.076251 +86,Chadwell Heath,51.5722283,0.141995 +86,"Romford, North Street",51.5805763,0.1780317 +86,Romford Market,51.5790739,0.1813886 +86,Romford Station,51.57472449999999,0.1826519 +87,Wandsworth,51.45837299999999,-0.1891356 +87,Wandsworth,51.45837299999999,-0.1891356 +87,Stockwell,51.4689424,-0.1194031 +87,Vauxhall,51.4309209,-0.0936496 +87,Lambeth Bridge,51.4945633,-0.123211 +87,Parliament Square,51.5007668,-0.1261294 +87,"Whitehall, Horse Guards",51.5041686,-0.1258204 +87,Trafalgar Square,51.508039,-0.128069 +87,Aldwych,51.5130914,-0.1164923 +88,Camden Town,51.5390261,-0.1425516 +88,Mornington Crescent,51.4794391,-0.4063284 +88,Warren Street,51.5244002,-0.1383538 +88,Oxford Circus,51.5161415,-0.1334985 +88,"Whitehall, Horse Guards",51.5049111,-0.1273704 +88,Parliament Square,51.5007668,-0.1261294 +88,Vauxhall,51.4877795,-0.1169126 +88,Stockwell,51.4690257,-0.1195636 +88,Clapham Common,51.4589252,-0.1493071 +89,Lewisham Station,51.4652098,-0.0131213 +89,Blackheath Village,51.4652738,0.0094822 +89,"Shooters Hill Road, Sun-in-the-Sands",51.4746479,0.022129 +89,"Blackheath, Royal Standard",51.4779946,0.0202001 +89,"Shooters Hill, Eaglesfield Road",51.4689548,0.07025769999999999 +89,Welling Corner,51.4626258,0.1081541 +89,Welling Corner,51.4626258,0.1081541 +89,"Bexleyheath, Shopping Centre",51.45334099999999,0.13822 +89,"Bexleyheath, Bus Garage",51.45334099999999,0.13822 +89,"Northend Road, Thames Road",51.4872325,-0.2844694 +89,Slade Green,51.4695282,0.1928854 +90,Northolt,51.546615,-0.373103 +90,"Yeading, White Hart",51.4675324,-0.2541425 +90,"Hayes End, Lansbury Drive",51.5258519,-0.4193931 +90,Hayes End,51.5257,-0.4357732 +90,Hayes & Harlington Station,51.5029848,-0.4203779 +90,Harlington Corner,51.4809415,-0.434335 +90,Hatton Cross,51.4651031,-0.4157165 +90,Feltham,51.44414800000001,-0.410772 +91,Crouch End,51.5819979,-0.1221464 +91,Hornsey Rise,51.57271290000001,-0.1261329 +91,"Holloway, Nag's Head",51.55724250000001,-0.1204364 +91,King's Cross,51.5347488,-0.1245845 +91,Euston,51.5287996,-0.1265979 +91,Russell Square,51.5220614,-0.127641 +91,Aldwych,51.513388,-0.1154888 +91,Trafalgar Square,51.508039,-0.128069 +91,Trafalgar Square,51.508039,-0.128069 +92,Ealing Hospital,51.5075205,-0.3465216 +92,"Greenford, Iron Bridge",51.50977899999999,-0.357687 +92,Greenford Broadway,51.5283954,-0.3553102 +92,Greenford Station,51.5423355,-0.3463373 +92,Sudbury Town,51.5503085,-0.316207 +92,Wembley Central,51.55214429999999,-0.2965274 +92,Wembley Stadium,51.55602469999999,-0.2796177 +92,Wembley Trading Estate,51.550501,-0.3048409 +92,Brent Park,51.5742449,-0.2287648 +92,St Raphael's North,51.55207859999999,-0.2622574 +93,North Cheam,51.3619271,-0.2189255 +93,"Sutton Common Road, Woodstock",51.3795675,-0.2014588 +93,Morden,51.3984637,-0.1763977 +93,Morden,51.3984637,-0.1763977 +93,Wimbledon,51.41833889999999,-0.2206288 +93,Wimbledon Village,51.41833889999999,-0.2206288 +93,Wimbledon,51.41833889999999,-0.2206288 +93,Putney Heath,51.4524424,-0.2298485 +93,Putney Station,51.4611807,-0.2164913 +93,Putney Bridge,51.46118999999999,-0.2037456 +94,Acton Green,51.5030641,-0.2663253 +94,Acton Green,51.5030641,-0.2663253 +94,Goldhawk Road Station,51.5018056,-0.2264944 +94,Shepherd's Bush,51.5051913,-0.22469 +94,Notting Hill Gate,51.5091315,-0.197414 +94,Lancaster Gate,51.5112845,-0.1804758 +94,Marble Arch,51.5133234,-0.1597734 +94,Portman Square,51.515381,-0.1546695 +94,Oxford Circus,51.5159378,-0.1342798 +94,Piccadilly Circus,51.5059249,-0.1454693 +95,"Southall, Town Hall",51.5113272,-0.3751471 +95,Greenford Broadway,51.52833769999999,-0.3562134 +95,"Perivale, Central Parade",51.5847721,-0.3324285 +95,Hanger Lane Station,51.530061,-0.2929893000000001 +95,"North Acton, Gipsy Corner",51.5219526,-0.2580821 +95,"East Acton, Savoy Circus",51.5140035,-0.247772 +95,Shepherd's Bush,51.5051913,-0.22469 +96,Bluewater,51.4309209,-0.0936496 +96,Dartford,51.44621,0.216872 +96,Crayford,51.4501131,0.1822046 +96,"Bexleyheath, Shopping Centre",51.45334099999999,0.13822 +96,"Bexleyheath, Shopping Centre",51.45334099999999,0.13822 +96,Welling Corner,51.4626258,0.1081541 +96,Plumstead Station,51.4896774,0.0847463 +96,"Plumstead, Lakedale Road",51.4845804,0.09086029999999999 +96,Woolwich Market,51.4894752,0.06758829999999999 +96,Woolwich,51.4894752,0.06758829999999999 +97,Chingford Station,51.6320667,0.007362700000000001 +97,Chingford Mount,51.6113592,-0.0180674 +97,"Walthamstow, Crooked Billet",51.601088,-0.0159737 +97,Walthamstow Central,51.5830128,-0.019886 +97,Leyton Green,51.5754944,-0.0083377 +97,"Leyton, Grange Park Road",51.5658352,-0.0144275 +97,"Leyton, Downsell Road",51.553328,-0.0016243 +97,Stratford City,51.5440354,-0.0053088 +98,"Willesden, Bus Garage",51.5476301,-0.2369246 +98,"Willesden Lane, Coverdale Road",51.5441689,-0.2143084 +98,Kilburn High Road Station,51.537243,-0.192318 +98,Edgware Road Station,51.51988249999999,-0.1678336 +98,Marble Arch,51.5133234,-0.1597734 +98,Marble Arch,51.5133234,-0.1597734 +98,Portman Square,51.515381,-0.1546695 +98,Oxford Circus,51.51587929999999,-0.1356139 +98,Holborn,51.518113,-0.1103907 +99,Woolwich,51.4602922,0.1464941 +99,Plumstead Bus Garage,51.4913502,0.084419 +99,"Plumstead, Lakedale Road",51.4852476,0.0912847 +99,Upper Belvedere,51.4309209,-0.0936496 +99,Erith,51.480818,0.174675 +99,Slade Green,51.4695282,0.1928854 +99,Northend Road,51.4694963,0.1812364 +99,"Bexleyheath, Shopping Centre",51.45334099999999,0.13822 +100,"London Wall, Museum of London",51.5176183,-0.0967782 +100,Liverpool Street,51.517791,-0.0837724 +100,Aldgate,51.5135207,-0.0768032 +100,Aldgate,51.5135207,-0.0768032 +100,Tower Gateway,51.5106312,-0.0737553 +100,Wapping,51.5041774,-0.0563736 +100,Shadwell,51.53525819999999,-0.3737537 +101,Wanstead,51.5767971,0.0249881 +101,Aldersbrook,51.5582903,0.0432123 +101,Manor Park,51.4536631,0.0027204 +101,East Ham Station,51.5393698,0.0510659 +101,"East Ham, Newham Town Hall",51.53280239999999,0.0551608 +101,"East Ham, Central Park",51.5293175,0.0527634 +101,"East Ham, Ron Leighton Way",51.53700509999999,0.0515097 +101,Beckton Alps,51.5192628,0.0612645 +101,Beckton Station,51.5144016,0.06153319999999999 +101,Cyprus,51.5306764,-0.0486561 +101,Gallions Reach Station,51.5090228,0.07172769999999999 +101,"Gallions Reach, Shopping Park",51.4309209,-0.0936496 +102,Edmonton Green,51.6248126,-0.0581806 +102,North Middlesex Hospital,51.6131618,-0.0735832 +102,"Edmonton, Cambridge Roundabout",51.4309209,-0.0936496 +102,"Edmonton, Cambridge Roundabout",51.4309209,-0.0936496 +102,"Palmers Green, North Circular Road",51.6122666,-0.1091537 +102,Muswell Hill,51.5911816,-0.1443015 +102,East Finchley,51.592468,-0.1664342 +102,Henley's Corner,51.4309209,-0.0936496 +102,Golders Green,51.5740013,-0.1987725 +102,Golders Green,51.5740013,-0.1987725 +102,"Cricklewood, Pennine Drive",51.5658262,-0.2141234 +102,Brent Cross,51.5763589,-0.2236956 +103,Chase Cross,51.60164,0.17854 +103,"Romford, Parkside Avenue",51.5884474,0.1770259 +103,Romford North Street Bus Garage,51.5823836,0.1761951 +103,Romford Market,51.5790739,0.1813886 +103,Romford Station,51.57472449999999,0.1826519 +103,Becontree Heath,51.5609465,0.1488995 +103,Dagenham East,51.5402631,0.1482103 +103,"South Hornchurch, Newtons Corner",51.53084699999999,0.1871649 +103,Rainham Interchange,51.5168805,0.1911589 +104,Stratford,51.5339854,0.0168531 +104,Upton Park Station,51.5353424,0.0352766 +104,"Upton Park, Boleyn",51.5305005,0.0384915 +104,"East Ham, Ron Leighton Way",51.5370071,0.05151679999999999 +104,Beckton Alps,51.5192628,0.0612645 +104,"East Ham, Central Park",51.5293175,0.0527634 +104,"East Ham, Newham Town Hall",51.53280239999999,0.0551608 +104,East Ham Station,51.5393698,0.0510659 +104,Manor Park,51.4540626,0.0005865 +105,Greenford Station,51.5423355,-0.3463373 +105,Greenford Broadway,51.52833769999999,-0.3562134 +105,"Southall, Town Hall",51.5113272,-0.3751471 +105,"Southall, Brent Road",51.5007727,-0.3997526 +105,Cranford,51.4870278,-0.4320017 +105,Harlington Corner,51.4809415,-0.434335 +105,"Bath Road, Sipson Road",51.4989643,-0.4629989 +105,Heathrow Central,51.4724711,-0.4544586 +106,Finsbury Park Station,51.5646425,-0.1058553 +106,Stoke Newington,51.5540035,-0.0748071 +106,Stoke Newington,51.5540035,-0.0748071 +106,Clapton Pond,51.5561061,-0.05490830000000001 +106,Hackney Well Street,51.5409953,-0.04943699999999999 +106,Ash Grove,51.481438,-0.3919584 +106,Ash Grove,51.481438,-0.3919584 +106,Whitechapel,51.518398,-0.0628557 +107,Edgware,51.61548819999999,-0.2609598 +107,Borehamwood Station,51.657728,-0.272308 +107,"Borehamwood, Tesco",51.4309209,-0.0936496 +107,"Borehamwood, Warwick Road",51.49182570000001,-0.1990845 +107,Stirling Corner,51.643381,-0.2551272 +107,"Barnet, Arkley Hotel",51.6522231,-0.2204527 +107,"Barnet, Odeon",51.64663059999999,-0.1865655 +107,New Barnet,51.649276,-0.176187 +108,Stratford International Bus Station,51.5453665,-0.0099022 +108,Bow Church,51.5287753,-0.0167013 +108,"Poplar, All Saints",51.5105521,-0.0118612 +108,Canning Town,51.5189494,0.0132 +108,North Greenwich,51.4859576,0.007494900000000001 +108,East Greenwich,51.4309209,-0.0936496 +108,"Blackheath, Royal Standard",51.4779946,0.0202001 +108,Blackheath Village,51.4652738,0.0094822 +108,Lewisham Station,51.4652098,-0.0131213 +109,Croydon Town Centre,51.3769529,-0.0956895 +109,West Croydon,51.3684193,-0.0998425 +109,Thornton Heath Pond,51.39415080000001,-0.1149765 +109,Norbury,51.4086775,-0.1167542 +109,"Streatham, Green Lane",51.4118582,-0.1104441 +109,Streatham Station,51.4259857,-0.131308 +109,Streatham Hill Station,51.4382009,-0.1270706 +109,Brixton,51.4533088,-0.1205905 +110,Hounslow Bus Station,51.4708688,-0.3546457 +110,Hospital Bridge Roundabout,51.44267,-0.3652385 +110,Twickenham,51.4453043,-0.3375429 +110,Twickenham,51.4453043,-0.3375429 +110,West Middlesex Hospital,51.4734184,-0.3244425 +111,Kingston,51.41233,-0.300689 +111,Hampton Wick,51.413541,-0.321331 +111,Hampton Court Roundabout,51.4051753,-0.3417169 +111,Hampton Station,51.4158208,-0.3719119 +111,Hampton Station,51.4158208,-0.3719119 +111,"Hanworth, Main Street",51.4489479,-0.3829269 +111,"Hounslow, Bus Station",51.4708688,-0.3546457 +111,Heston,51.4309209,-0.0936496 +111,Cranford,51.486932,-0.4318624 +111,"Bath Road, Nobel Drive",51.4815821,-0.4302396 +111,"Bath Road, Sipson Road",51.4989341,-0.4618918 +111,Heathrow Central,51.4724711,-0.4544586 +112,Ealing Broadway,51.5135109,-0.3036571 +112,Hanger Lane Station,51.530061,-0.2929893000000001 +112,Stonebridge Park,51.5456178,-0.2617279 +112,Neasden Junction,51.5626819,-0.2536987 +112,Brent Cross,51.5763589,-0.2236956 +113,Edgware,51.5163626,-0.1651413 +113,Apex Corner,51.4369075,-0.3784005 +113,Hendon Central,51.583202,-0.226399 +113,Hendon Central,51.583202,-0.226399 +113,Finchley Road & Frognal,51.5585086,-0.1818591 +113,Swiss Cottage,51.5425872,-0.1724737 +113,Baker Street Station,51.5231548,-0.156863 +113,Baker Street Station,51.5231548,-0.156863 +113,Portman Square,51.515381,-0.1546695 +113,Portman Square,51.515381,-0.1546695 +113,Marble Arch,51.5133234,-0.1597734 +113,Oxford Circus,51.5158971,-0.1352142 +114,Mill Hill Broadway,51.6133816,-0.2463566 +114,Burnt Oak,51.602809,-0.266965 +114,Queensbury,51.5942132,-0.2853683 +114,"Kenton, Library",51.59262649999999,-0.3111454 +114,Harrow,51.580559,-0.341995 +114,South Harrow,51.5683717,-0.3553483 +114,"Field End Road, Victoria Road",51.5696578,-0.3900522 +114,"South Ruislip, Ruislip Manor",51.55507919999999,-0.399575 +114,Ruislip,51.5758719,-0.421236 +115,"East Ham, Central Park",51.5293175,0.0527634 +115,"East Ham, Newham Town Hall",51.53280239999999,0.0551608 +115,"Upton Park, Boleyn",51.5305005,0.0384915 +115,"Plaistow, Balaam street",51.5260131,0.0238468 +115,"Canning Town, Barking Road",51.5175196,0.0115068 +115,Canning Town,51.5189494,0.0132 +115,"Poplar, All Saints",51.5105521,-0.0118612 +115,"Limehouse, Burdett Road",51.5209123,-0.0327503 +115,"Stepney, Arbour Square",51.5140186,-0.0481747 +115,"Stepney, Arbour Square",51.5140186,-0.0481747 +115,Aldgate,51.5135207,-0.0768032 +116,Ashford Hospital,51.4309209,-0.0936496 +116,Bedfont Green,51.45109910000001,-0.4402292 +116,Hounslow Heath,51.4563954,-0.3849625 +116,"Hounslow, Bell Corner",51.468569,-0.3666325 +116,"Hounslow, Bus Station",51.46092179999999,-0.373149 +117,West Middlesex Hospital,51.4734184,-0.3244425 +117,Isleworth,51.467121,-0.329003 +117,Hounslow Heath,51.4563954,-0.3849625 +117,Hounslow,51.46092179999999,-0.373149 +117,Lower Feltham,51.436601,-0.426105 +117,Ashford,51.4309209,-0.0936496 +117,Fordbridge Park,51.4269571,-0.4764696 +117,Staines,51.45742550000001,-0.4085313 +118,Brixton,51.4612794,-0.1156148 +118,Brixton,51.4612794,-0.1156148 +118,"Streatham Hill, Christchurch Road",51.4402956,-0.1089125 +118,Streatham Hill Station,51.4307467,-0.1294977 +118,"Streatham, St Leonard's Church",51.42926610000001,-0.1311095 +118,Streatham,51.4307467,-0.1294977 +118,"Rowan Road, Manor Road",51.407602,-0.1415332 +118,"Rowan Road, Manor Road",51.407602,-0.1415332 +118,Mitcham,51.4242858,-0.1420112 +118,Mitcham,51.4242858,-0.1420112 +118,Morden,51.394943,-0.19446 +119,Bromley North,51.406025,0.013156 +119,Bromley South,51.406025,0.013156 +119,Hayes Station,51.37633599999999,0.010589 +119,Shirley,51.3784662,-0.0616112 +119,Shirley Inn,51.3744006,-0.05023610000000001 +119,"Addiscombe Road, Shirley Road",51.3750364,-0.0761587 +119,East Croydon,51.3769529,-0.0956895 +119,"South Croydon, South End",51.3639044,-0.0980944 +119,"Purley Way, Colonnades",51.3563828,-0.1135816 +120,Hounslow Bus Station,51.46092179999999,-0.373149 +120,"Hounslow, Bell Corner",51.468569,-0.3666325 +120,Lampton Corner,51.4309209,-0.0936496 +120,Norwood Green,51.4966737,-0.3743679 +120,"Southall, The Green",51.5023286,-0.3821557 +120,"Southall, Town Hall",51.5113272,-0.3751471 +120,"Lady Margaret Road, Ruislip Rd",51.5220189,-0.3747392 +120,"Yeading, White Hart",51.4668898,-0.2535508 +120,"Northolt, Western Avenue",51.5152423,-0.2565013 +120,Northolt,51.546615,-0.373103 +121,Enfield Island Village,51.66612199999999,-0.015382 +121,Enfield Lock Station,51.6708436,-0.0284106 +121,Enfield Highway,51.652918,-0.041145 +121,Ponders End Bus Garage,51.6452225,-0.04863729999999999 +121,Enfield,51.6532423,-0.1162248 +121,Oakwood,51.4996676,-0.2061929 +121,Southgate,51.5423535,-0.08493669999999999 +121,Palmers Green,51.6214872,-0.1075657 +121,"Palmers Green, North Circular Road",51.6122666,-0.1091537 +121,Wood Green,51.5971722,-0.1098021 +121,Turnpike Lane Station,51.5904278,-0.1027587 +122,Plumstead Bus Garage,51.4913502,0.084419 +122,Woolwich,51.4839216,0.1383058 +122,Woolwich,51.4839216,0.1383058 +122,Well Hall Roundabout,51.4549092,0.0512893 +122,Eltham Green,51.4533383,0.0356381 +122,"Lewisham, Shopping Centre",51.46175909999999,-0.0119106 +122,Brockley Rise,51.4492257,-0.0392146 +122,Forest Hill,51.4513909,-0.0593561 +122,Sydenham,51.3816463,-0.0940886 +122,Crystal Palace,51.45665589999999,-0.07155589999999999 +123,Wood Green,51.5971722,-0.1098021 +123,Turnpike Lane Station,51.5904278,-0.1027587 +123,Lordship Lane,51.4569725,-0.07542599999999999 +123,"Tottenham, Town Hall",51.5872187,-0.0725467 +123,Tottenham Hale Station,51.5890318,-0.05979599999999999 +123,"Walthamstow, Beacontree Avenue",51.5977897,0.0033351 +123,"Walthamstow, Beacontree Avenue",51.5977897,0.0033351 +123,Waterworks Corner,51.5961326,0.0104878 +123,Charlie Brown's Roundabout,51.5934938,0.0370989 +123,Charlie Brown's Roundabout,51.5934938,0.0370989 +123,Gants Hill,51.5791987,0.0640264 +123,Ilford,51.5546614,0.07253409999999999 +124,"Catford, St Dunstan's College",51.4434815,-0.0283657 +124,"Catford, Town Centre",51.4453954,-0.0160913 +124,"Downham, Shroffold Road",51.425638,0.0015921 +124,Grove Park,51.5922603,-0.2588401 +124,"Dunkery Road, Mottingham Road",51.4297244,0.0420724 +124,Mottingham,51.4342505,0.0468761 +124,Eltham Church,51.4506338,0.0570862 +124,"Eltham, Southend Crescent",51.44825729999999,0.0632853 +125,Winchmore Hill,51.6320279,-0.09580219999999999 +125,Eversley Park Road,51.64383729999999,-0.109846 +125,Southgate,51.5424973,-0.0848603 +125,Hampden Square,51.6323276,-0.1417747 +125,Whetstone,51.6300102,-0.1747954 +125,North Finchley,51.6135087,-0.1754198 +125,Finchley Central,51.601633,-0.193361 +126,Bromley Town Centre,51.406025,0.013156 +126,Bromley North,51.406025,0.013156 +126,Plaistow Green,51.4139535,0.0168425 +126,Plaistow Green,51.4139535,0.0168425 +126,Grove Park,51.4329249,0.021203 +126,Mottingham,51.4368565,0.0431531 +126,"Eltham, High Street",51.450685,0.0533581 +127,Purley,51.339228,-0.119711 +127,Woodcote Green,51.3479553,-0.1474798 +127,Wallington,51.363978,-0.151845 +127,Wallington,51.363978,-0.151845 +127,Wrythe Green,51.37563979999999,-0.1775913 +127,Hackbridge Corner,51.379288,-0.156685 +127,Mitcham,51.4234696,-0.1422232 +127,Mitcham,51.4234696,-0.1422232 +127,Tooting Broadway,51.427867,-0.1678142 +128,Romford Station,51.577076,0.178319 +128,"Romford, The Brewery",51.5757212,0.1798406 +128,Romford Market,51.5790739,0.1813886 +128,Romford Queens Hospital,51.5688117,0.1807796 +128,Becontree Heath,51.5609465,0.1488995 +128,Bennett's Castle Lane,51.5566204,0.1274857 +128,Bennett's Castle Lane,51.5566204,0.1274857 +128,"Goodmayes, Mayfield Road",51.564386,0.1293136 +128,Ilford,51.55345459999999,0.0728955 +128,Ilford,51.55345459999999,0.0728955 +128,Gants Hill,51.58065879999999,0.0672369 +128,"Barkingside, Tesco",51.58605319999999,0.08191999999999999 +128,"Barkingside, Fullwell Cross",51.59451199999999,0.08571999999999999 +128,Claybury Broadway,51.5886482,0.0519222 +129,"Greenwich, Cutty Sark",51.4828646,-0.0095917 +129,East Greenwich,51.4309209,-0.0936496 +129,East Greenwich,51.4309209,-0.0936496 +129,North Greenwich,51.4859576,0.007494900000000001 +130,New Addington,51.348184,-0.017094 +130,Addington Village,51.3587133,-0.0303994 +130,Shirley Park,51.3811242,-0.0613737 +130,Norwood Junction,51.39731,-0.07501000000000001 +130,"Thornton Heath, Parchmore Road",51.4044757,-0.1019415 +131,Kingston,51.41233,-0.300689 +131,"New Malden, Foundation Roundabout",51.40066299999999,-0.259263 +131,"New Malden, Fountain Roundabout",51.3978781,-0.2554973 +131,Shannon Corner,51.3993558,-0.2429132 +131,Raynes Park,51.4084257,-0.2298751 +131,Wimbledon,51.41833889999999,-0.2206288 +131,Wimbledon,51.41833889999999,-0.2206288 +131,Colliers Wood,51.41704439999999,-0.1778555 +131,Tooting Broadway,51.427867,-0.1678142 +132,North Greenwich,51.4859576,0.007494900000000001 +132,East Greenwich,51.4309209,-0.0936496 +132,"Shooters Hill Road, Sun-in-the-Sands",51.4751267,0.0286902 +132,Eltham Station,51.45564,0.0525 +132,Eltham,51.4506338,0.0570862 +132,Blendon,51.44793379999999,0.1220942 +132,Bexley,51.439933,0.154327 +132,"Bexleyheath, Shopping Centre",51.45334099999999,0.13822 +133,Streatham Station,51.4259857,-0.131308 +133,Streatham Hill Station,51.4382009,-0.1270706 +133,"Streatham Hill, Telford Avenue",51.4419108,-0.1355643 +133,Brixton,51.4533088,-0.1205905 +133,Brixton,51.4533088,-0.1205905 +133,Kennington Church,51.5074444,-0.1949528 +133,Elephant & Castle,51.4939906,-0.1005164 +133,London Bridge,51.5086048,-0.0875601 +133,Monument,51.50999,-0.0855373 +133,Liverpool Street,51.5151887,-0.07828249999999999 +134,North Finchley,51.6135087,-0.1754198 +134,Friern Barnet,51.6212348,-0.1632817 +134,Muswell Hill,51.5910045,-0.1411939 +134,Muswell Hill,51.5910045,-0.1411939 +134,Archway,51.5714491,-0.1388138 +134,Kentish Town,51.546046,-0.1415843 +134,Camden Town,51.5390261,-0.1425516 +134,Camden Town,51.5390261,-0.1425516 +134,Mornington Crescent,51.5344237,-0.1393683 +134,Warren Street,51.5244002,-0.1383538 +134,Tottenham Court Road Station,51.5162811,-0.1300406 +135,Crossharbour,51.4974839,-0.0151232 +135,Canary Wharf,51.5054306,-0.0235333 +135,"Limehouse, Burdett Road",51.5205334,-0.0320335 +135,"Stepney, Arbour Square",51.5140186,-0.0481747 +135,Aldgate,51.5135207,-0.0768032 +135,Liverpool Street,51.5174995,-0.08269399999999999 +135,Old Street Station,51.5256719,-0.0874922 +136,Grove Park,51.4329249,0.021203 +136,"Downham, Bromley Road",51.4369124,-0.0185613 +136,"Bellingham, Catford Bus Garage",51.434704,-0.017839 +136,"Catford, Town Centre",51.4453954,-0.0160913 +136,"Lewisham, Shopping Centre",51.46175909999999,-0.0119106 +136,New Cross,51.4769047,-0.0336897 +136,New Cross Gate,51.4749904,-0.0403466 +136,Peckham,51.47032369999999,-0.0673872 +136,Elephant & Castle,51.4938279,-0.0981368 +137,"Streatham Hill, Telford Avenue",51.4419108,-0.1355643 +137,Clapham Common,51.4762752,-0.1179147 +137,Clapham Park,51.459505,-0.1335192 +137,Queenstown Road Station,51.4749596,-0.1466578 +137,Battersea Park Station,51.47696,-0.14751 +137,Sloane Square,51.49299509999999,-0.1564588 +137,Sloane Square,51.49299509999999,-0.1564588 +137,Hyde Park Corner,51.5029347,-0.1508562 +137,Marble Arch,51.5133234,-0.1597734 +137,Oxford Circus,51.5157462,-0.1363802 +138,Bromley North,51.406025,0.013156 +138,Hayes Station,51.37633599999999,0.010589 +138,Coney Hall,51.3711435,-0.0014082 +139,Golders Green,51.5746226,-0.2025805 +139,"Finchley Road, Hendon Way",51.5680875,-0.2078815 +139,Baker Street Station,51.5231548,-0.156863 +139,Baker Street Station,51.5231548,-0.156863 +139,Portman Square,51.515381,-0.1546695 +139,Oxford Circus,51.51576240000001,-0.1364384 +139,Piccadilly Circus,51.50384099999999,-0.1495126 +139,Piccadilly Circus,51.50384099999999,-0.1495126 +139,Trafalgar Square,51.4881349,-0.0895747 +139,Aldwych,51.5116273,-0.1189037 +139,Waterloo,51.501682,-0.1088358 +140,Heathrow Central,51.4724711,-0.4544586 +140,"Bath Road, Sipson Road",51.4977762,-0.4624348 +140,Harlington Corner,51.4809415,-0.434335 +140,Hayes & Harlington Station,51.5029848,-0.4203779 +140,"Yeading, Willow Tree Lane",51.5291787,-0.3981875 +140,"Yeading, White Hart",51.4665681,-0.2534512 +140,"Northolt, Target Roundabout",51.5433066,-0.3777375 +140,Northolt,51.546615,-0.373103 +140,South Harrow,51.5683717,-0.3553483 +140,Harrow,51.580559,-0.341995 +140,Harrow & Wealdstone Station,51.59172359999999,-0.3343587 +140,Harrow Weald,51.6052581,-0.3380395 +141,"Palmers Green, North Circular Road",51.6122666,-0.1091537 +141,Wood Green,51.5971722,-0.1098021 +141,Wood Green,51.5971722,-0.1098021 +141,Turnpike Lane Station,51.5904278,-0.1027587 +141,"Harringay, Salisbury Road",51.5814632,-0.0989471 +141,"Green Lanes, Gloucester Drive",51.5670684,-0.0945309 +141,Newington Green,51.5511621,-0.0858874 +141,"Hoxton, Baring Street",51.5366266,-0.0886478 +141,Old Street Station,51.5256719,-0.0874922 +141,"Moorgate, Finsbury Circus",51.5185065,-0.0883728 +141,Mansion House,51.51300699999999,-0.08950899999999999 +141,London Bridge,51.5086048,-0.0875601 +142,Watford Junction,51.66112829999999,-0.3970199 +142,Bushey Station,51.4309209,-0.0936496 +142,Bushey Heath,51.640213,-0.344442 +142,Stanmore Station,51.6196885,-0.3031205 +142,Edgware,51.61548819999999,-0.2609598 +142,Burnt Oak,51.602809,-0.266965 +142,"Colindale, Superstores",51.5942575,-0.2607018 +142,West Hendon Broadway,51.5756924,-0.2375372 +142,Brent Cross,51.5763589,-0.2236956 +143,Brent Cross,51.5763589,-0.2236956 +143,Hendon Central,51.583202,-0.226399 +143,"Finchley, Church End",51.604606,-0.1882833 +143,East Finchley Schools,51.592468,-0.1664342 +143,East Finchley,51.592468,-0.1664342 +143,East Finchley,51.592468,-0.1664342 +143,Highgate Village,51.556431,-0.1463122 +143,Archway,51.5723646,-0.1402196 +144,Muswell Hill,51.5910059,-0.1411991 +144,"Alexandra Park, Park Road",51.5990742,-0.1335391 +144,Hornsey,51.57350109999999,-0.1302347 +144,Turnpike Lane Station,51.5904278,-0.1027587 +144,Wood Green,51.5971722,-0.1098021 +144,Wood Green,51.5971722,-0.1098021 +144,"Lordship Lane, Downhills Way",51.5958467,-0.0910619 +144,"Edmonton, Cambridge Roundabout",51.4309209,-0.0936496 +144,Edmonton,51.6241533,-0.0603899 +144,Edmonton Green,51.6248126,-0.0581806 +145,"Dagenham, Asda",51.5299749,0.1425747 +145,"Dagenham, New Road",51.5285492,0.1564976 +145,Dagenham Village,51.5362298,0.1408327 +145,"Becontree, Martins Corner",51.5625977,0.1224296 +145,Fair Cross,51.5435767,0.0795854 +145,Ilford,51.5539678,0.073196 +145,Redbridge Station,51.5763264,0.0453986 +145,Wanstead Station,51.5756323,0.0287819 +145,Leytonstone,51.5493318,0.0049165 +146,Bromley North,51.406025,0.013156 +146,Bromley South,51.406025,0.013156 +146,Downe,51.3286548,0.0553793 +147,Ilford,51.5539372,0.0732529 +147,Ilford Broadway,51.556619,0.076251 +147,"Little Ilford Lane, Romford Road",51.55046249999999,0.059298 +147,East Ham Station,51.5393698,0.0510659 +147,"East Ham, Newham Town Hall",51.53280239999999,0.0551608 +147,"Upton Park, Boleyn",51.5305005,0.0384915 +147,Prince Regent,51.5178274,0.0321034 +147,Canning Town,51.5189494,0.0132 +148,Camberwell Green,51.4756016,-0.0928896 +148,Elephant & Castle,51.4938058,-0.0977932 +148,Parliament Square,51.5010421,-0.1268514 +148,Victoria,51.4309209,-0.0936496 +148,Hyde Park Corner,51.5029347,-0.1508562 +148,Marble Arch,51.5132225,-0.1588937 +148,Lancaster Gate,51.5117363,-0.1777176 +148,Notting Hill Gate,51.5086865,-0.1995831 +148,Holland Park Roundabout,51.5042925,-0.217039 +148,Shepherd's Bush,51.5051913,-0.22469 +148,White City,51.51146199999999,-0.2376332 +148,White City,51.51146199999999,-0.2376332 +149,Edmonton Green,51.6248126,-0.0581806 +149,"Snells Park, Sainsburys",51.609054,-0.0691713 +149,"Tottenham, Town Hall",51.5872187,-0.0725467 +149,"Tottenham, Town Hall",51.5872187,-0.0725467 +149,Stamford Hill,51.57418759999999,-0.0729267 +149,Stoke Newington,51.5568488,-0.0748084 +149,"Dalston, Downham Road",51.5394245,-0.0870648 +149,Shoreditch,51.5256391,-0.07789499999999999 +149,Monument,51.50999,-0.0855373 +149,London Bridge,51.5086048,-0.0875601 +150,Becontree Heath,51.5609465,0.1488995 +150,Bennett's Castle Lane,51.5559895,0.127183 +150,"Goodmayes, Mayfield Road",51.564386,0.1293136 +150,"Ilford, High Road",51.55918,0.0747613 +150,Ilford Broadway,51.556619,0.076251 +150,Gants Hill,51.5804109,0.0663594 +150,"Barkingside, Fullwell Cross",51.59451199999999,0.08571999999999999 +150,"Barkingside, Tesco",51.58605319999999,0.08191999999999999 +150,"Hainault, The Lowe",51.6128423,0.1079703 +150,Chigwell Row,51.50930289999999,-0.0601111 +151,Wallington,51.5310335,0.0585672 +151,Wallington,51.5310335,0.0585672 +151,Hackbridge,51.3751002,-0.1556286 +151,Wrythe Green,51.3766213,-0.1780055 +151,"St Helier, Rose Hill",51.39381479999999,-0.1871983 +151,"Sutton, Bushey Road",51.3686485,-0.1992887 +151,"Sutton, Bushey Road",51.3686485,-0.1992887 +151,Sutton Town Centre,51.3614279,-0.193961 +151,Cheam,51.3592217,-0.2091238 +151,North Cheam,51.3619271,-0.2189255 +151,Worcester Park,51.38029,-0.24468 +152,Pollards Hill,51.4000406,-0.1332582 +152,Eastfields,51.4627155,-0.1967312 +152,Colliers Wood,51.41704439999999,-0.1778555 +152,Colliers Wood,51.41704439999999,-0.1778555 +152,Raynes Park,51.4084257,-0.2298751 +152,Raynes Park High School,51.4032764,-0.2394806 +152,Raynes Park High School,51.4032764,-0.2394806 +152,"New Malden, Fountain Roundabout",51.3978781,-0.2554973 +153,Finsbury Park Station,51.5646425,-0.1058553 +153,"Holloway, Nags Head",51.55724250000001,-0.1204364 +153,"Barnsbury, Offord Road",51.5441596,-0.1096795 +153,Islington Angel,51.5346761,-0.1042905 +153,Islington Angel,51.5346761,-0.1042905 +153,Barbican,51.5202077,-0.09378639999999999 +153,"Moorgate, Finsbury Square",51.5188228,-0.08795879999999999 +154,West Croydon,51.368451,-0.09966350000000002 +154,Croydon Town Centre,51.3769529,-0.0956895 +154,"Stafford Road, The Chase",51.3596298,-0.1389609 +154,Wallington,51.363978,-0.151845 +154,"Sutton, Bushey Road",51.3684787,-0.2003649 +154,"Sutton, Bushey Road",51.3684787,-0.2003649 +154,"St Helier, Rose Hill",51.393722,-0.1876929 +154,St Helier Station,51.3899,-0.19875 +154,Morden,51.394943,-0.19446 +155,"Tooting, St George's Hospital",51.42656299999999,-0.1752284 +155,Tooting Broadway,51.427867,-0.1678142 +155,Balham,51.4439889,-0.1494105 +155,Clapham Common,51.4589252,-0.1493071 +155,Stockwell,51.46557110000001,-0.1159728 +155,Kennington Church,51.50789830000001,-0.1952076 +155,Elephant & Castle,51.4938058,-0.0977932 +156,Wimbledon,51.41833889999999,-0.2206288 +156,"Haydons Road, Plough Lane",51.42148840000001,-0.18782 +156,Wandsworth,51.45837299999999,-0.1891356 +156,Clapham Junction,51.4651737,-0.1708113 +156,Nine Elms,51.4801974,-0.1396819 +156,Vauxhall,51.4309209,-0.0936496 +157,Crystal Palace,51.4558287,-0.0714344 +157,Anerley Station,51.4123847,-0.064941 +157,Norwood Junction,51.39731,-0.07501000000000001 +157,West Croydon,51.368451,-0.09966350000000002 +157,"Stafford Road, The Chase",51.3637156,-0.1194076 +157,Wallington,51.363978,-0.151845 +157,Wallington,51.363978,-0.151845 +157,Wrythe Green,51.3768184,-0.1780163 +157,"St Helier, Rose Hill",51.3936715,-0.1871751 +157,Morden,51.40799459999999,-0.192246 +158,Chingford Mount,51.612978,-0.0177167 +158,"Walthamstow, Crooked Billet",51.601088,-0.0159737 +158,"Walthamstow, Crooked Billet",51.601088,-0.0159737 +158,St James's Street,51.5051953,-0.138084 +158,Markhouse Corner,51.57516529999999,-0.0298297 +158,"Leyton, Grange Park Road",51.5672498,-0.0167708 +158,"Leyton, Downsell Road",51.55411369999999,0.0003557 +158,Stratford,51.5426313,-0.0010369 +159,Streatham Station,51.4259857,-0.131308 +159,Streatham Hill Station,51.4382009,-0.1270706 +159,Brixton,51.4533088,-0.1205905 +159,Brixton,51.4533088,-0.1205905 +159,Kennington Church,51.5079351,-0.1952207 +159,Lambeth North,51.4935082,-0.1178424 +159,Lambeth North,51.4935082,-0.1178424 +159,"Whitehall, Horse Guards",51.5049111,-0.1273704 +159,Piccadilly Circus,51.5077144,-0.1406648 +159,Oxford Circus,51.5156424,-0.137491 +159,Oxford Circus,51.5156424,-0.137491 +159,Marble Arch,51.5133224,-0.1589956 +160,Catford Bridge,51.4448458,-0.0247399 +160,Hither Green,51.4522987,-0.0073954 +160,"Eltham, Yorkshire Grey",51.4530696,0.0357541 +160,"Eltham, High Street",51.4507673,0.0560971 +160,New Eltham Station,51.43806,0.07056 +160,Chislehurst,51.412626,0.077487 +160,"Chislehurst, War Memorial",51.4124839,0.07390759999999999 +160,Queen Mary's Hospital,51.4556562,-0.2426609 +160,Sidcup Station,51.4339345,0.1038351 +161,"Chislehurst, War Memorial",51.4124839,0.07390759999999999 +161,Mottingham,51.4335607,0.0484827 +161,Eltham Station,51.45564,0.0525 +161,Queen Elizabeth Hospital,51.4778139,0.0505587 +161,Woolwich,51.4813345,0.1309026 +161,Charlton Station,51.4867404,0.0310491 +161,North Greenwich,51.4859576,0.007494900000000001 +162,Beckenham Junction,51.4109588,-0.0258909 +162,Park Langley,51.385466,-0.0087119 +162,Bromley South,51.406025,0.013156 +162,Chislehurst,51.3867511,0.0879358 +162,"New Eltham, Fiveways",51.4350775,0.0646125 +162,"Avery Hill Road,Halfway Street",51.4422936,0.0806182 +162,Eltham Station,51.4506338,0.0570862 +163,Morden,51.4075989,-0.1922691 +163,Lower Morden,51.390593,-0.2194281 +163,Lower Morden,51.390593,-0.2194281 +163,Raynes Park,51.4084257,-0.2298751 +163,Wimbledon,51.41833889999999,-0.2206288 +163,Wimbledon,51.41833889999999,-0.2206288 +164,Sutton Station,51.3596681,-0.1911606 +164,Sutton Green,51.5480724,0.2172356 +164,"St Helier, Rose Hill",51.3940683,-0.1875979 +164,Morden,51.4075989,-0.1922691 +164,Morden,51.4075989,-0.1922691 +164,"Bushey Road, Botsford Road",51.40868529999999,-0.2155818 +164,Wimbledon,51.41833889999999,-0.2206288 +164,Wimbledon,51.41833889999999,-0.2206288 +165,"Romford, The Brewery",51.5757212,0.1798406 +165,Romford Station,51.57472449999999,0.1826519 +165,Hornchurch Town Centre,51.562254,0.218605 +165,Elm Park,51.5520615,0.2016224 +165,Rainham Tesco,51.5200061,0.1907802 +165,Rainham War Memorial,51.5185366,0.1902033 +165,"Rainham, Abbey Wood Lane",51.5292975,0.2137483 +166,Epsom Hospital,51.3251497,-0.2732057 +166,Banstead,51.3221909,-0.205046 +166,Chipstead Valley,51.3194573,-0.145129 +166,Coulsdon,51.319941,-0.141267 +166,Purley,51.339228,-0.119711 +166,"South Croydon, Bus Garage",51.3544903,-0.0968822 +166,Croydon Town Centre,51.3769529,-0.0956895 +166,West Croydon,51.368451,-0.09966350000000002 +167,Ilford,51.556619,0.076251 +167,Ilford Broadway,51.556619,0.076251 +167,"Barkingside, Fullwell Cross",51.59451199999999,0.08571999999999999 +167,Gants Hill,51.5767812,0.0661732 +167,Buckhurst Hill,51.627572,0.034513 +167,Loughton,51.655942,0.068161 +168,Hampstead Heath,51.5608294,-0.1629416 +168,Chalk Farm,51.5422732,-0.1466907 +168,Camden Town,51.5390261,-0.1425516 +168,Euston,51.5275774,-0.130909 +168,Russell Square,51.5220582,-0.1276485 +168,Holborn,51.517893,-0.1085556 +168,Aldwych,51.5116716,-0.1189217 +168,Waterloo,51.5017711,-0.109428 +168,Waterloo,51.5017711,-0.109428 +168,Bricklayer's Arms,51.4661409,-0.2174147 +168,"Old Kent Road, Tesco",51.4854662,-0.0700918 +169,Clayhall,51.5918921,0.05992909999999999 +169,Barkingside,51.5899246,0.08387420000000001 +169,Newbury Park,51.5734779,0.08897669999999999 +169,Ilford,51.5531267,0.07355149999999999 +169,Ilford Broadway,51.556619,0.076251 +169,Barking,51.5287766,0.03377 +170,"Roehampton, Danebury Avenue",51.4498696,-0.2433181 +170,Putney Heath,51.4524424,-0.2298485 +170,Wandsworth,51.47715849999999,-0.1301676 +170,Wandsworth,51.47715849999999,-0.1301676 +170,"Wandsworth, East Hill",51.4573489,-0.1880728 +170,Clapham Junction,51.4651737,-0.1708113 +170,"Battersea Bridge, South Side",51.4811674,-0.1725411 +170,"Battersea Bridge, North Side",51.4811674,-0.1725411 +170,Victoria,51.5099822,-0.117819 +171,"Bellingham, Catford Bus Garage",51.434704,-0.017839 +171,Catford Town Centre,51.4453954,-0.0160913 +171,Brockley Rise,51.4497569,-0.039271 +171,New Cross Gate,51.4749942,-0.0465004 +171,Peckham,51.46075519999999,-0.06064029999999999 +171,Camberwell Green,51.4748827,-0.0921158 +171,Elephant & Castle,51.49402689999999,-0.1005177 +171,Waterloo,51.5007581,-0.1077651 +171,Aldwych,51.5116193,-0.1188998 +171,Holborn,51.51789309999999,-0.1085567 +172,Brockley Rise,51.45158259999999,-0.0387554 +172,Brockley Cross,51.465303,-0.0363334 +172,New Cross Gate,51.4749904,-0.0403466 +172,"Old Kent Road, Tesco",51.4854662,-0.0700918 +172,Bricklayer's Arms,51.4661409,-0.2174147 +172,New Kent Road,51.4938888,-0.0906269 +172,Elephant & Castle,51.4938058,-0.0977932 +172,Elephant & Castle,51.4938058,-0.0977932 +172,Waterloo,51.5016858,-0.1093259 +172,Waterloo,51.5016858,-0.1093259 +172,Aldwych,51.5116716,-0.1189217 +172,Ludgate Circus,51.51413830000001,-0.1043402 +172,Ludgate Circus,51.51413830000001,-0.1043402 +172,St. Paul's,51.4309209,-0.0936496 +173,Beckton Station,51.5144016,0.06153319999999999 +173,Ripple Road,51.53527949999999,0.0898127 +173,Ripple Road,51.53527949999999,0.0898127 +173,"Dagenham, Kent Avenue",51.5235188,0.1516733 +173,Becontree Heath,51.5609465,0.1488995 +173,Chadwell Heath,51.5722283,0.141995 +173,Little Heath,51.4854017,0.0495252 +173,King George Hospital,51.5789575,0.1124443 +174,"Harold Hill, Dagnam Park Square",51.6049149,0.2445527 +174,"Harold Hill, Gooshays Drive",51.60684579999999,0.2239714 +174,Gallows Corner,51.59188200000001,0.214546 +174,"Gallows Corner, Main Road",51.5922565,0.2142701 +174,Romford Market,51.5790739,0.1813886 +174,Romford Station,51.57472449999999,0.1826519 +174,"Dagenham Road, Eastbrook School",51.55144010000001,0.1635667 +174,Dagenham Hthway,51.53813710000001,0.1485571 +174,"Dagenham, New Road",51.5231641,0.1783295 +174,"Dagenham, Marsh Way",51.5170612,0.1696416 +175,Hillrise Estate,51.60715159999999,0.1723829 +175,Collier Row,51.5977138,0.1535519 +175,"Romford, Parkside Avenue",51.5903277,0.1801191 +175,Romford North Street Bus Garage,51.5823836,0.1761951 +175,Romford Station,51.57472449999999,0.1826519 +175,"Romford, Queen's Hospital",51.5688117,0.1807796 +175,Becontree Heath,51.5609465,0.1488995 +175,Dagenham Heathway,51.5378261,0.1479616 +175,"Dagenham, New Road",51.5281707,0.1574915 +176,Penge,51.41388490000001,-0.0570112 +176,Sydenham,51.3817082,-0.09405849999999999 +176,Forest Hill,51.4488504,-0.0544969 +176,Dulwich Library,51.4488677,-0.07447669999999999 +176,East Dulwich,51.455147,-0.084622 +176,Camberwell Green,51.4741358,-0.09309769999999999 +176,Camberwell Green,51.4741358,-0.09309769999999999 +176,Elephant & Castle,51.4940316,-0.1005179 +176,Waterloo,51.50135650000001,-0.1091323 +176,Aldwych,51.5116716,-0.1189217 +176,Trafalgar Square,51.4881451,-0.0887212 +176,Tottenham Court Road,51.5223956,-0.1356586 +177,Thamesmead,51.50575809999999,0.1100586 +177,"Thamesmead, Boiler House",51.50575809999999,0.1100586 +177,Plumstead Station,51.4896774,0.0847463 +177,"Plumstead, Lakedale Road",51.4827083,0.0910057 +177,Woolwich,51.48116,0.1300398 +177,Woolwich,51.48116,0.1300398 +177,Charlton,51.63522039999999,-0.0392038 +177,East Greenwich,51.4309209,-0.0936496 +177,"Greenwich, Cutty Sark",51.4828646,-0.0095917 +177,"Greenwich, Cutty Sark",51.4828646,-0.0095917 +177,Greenwich Station,51.4780469,-0.013361 +177,Deptford Bridge,51.4744304,-0.0224546 +177,New Cross,51.4748585,-0.0462917 +177,New Cross Gate,51.4748585,-0.0462917 +177,Peckham,51.4603742,-0.06051840000000001 +178,Woolwich,51.4622079,0.1474666 +178,Queen Elizabeth Hospital,51.4778139,0.0505587 +178,"Shooters Hill Road, Sun-in-the-Sands",51.4751637,0.025465 +178,Kidbrooke,51.46108479999999,0.0261346 +178,Lee Green,51.3916532,0.1019578 +178,Lewisham Station,51.4652098,-0.0131213 +179,Chingford Station,51.6331421,0.0098588 +179,Woodford Wells,51.6148389,0.0281739 +179,Woodford Green,51.59981939999999,0.0199759 +179,South Woodford,51.5912671,0.0264721 +179,Gants Hill,51.5791987,0.0640264 +179,Ilford Station,51.5587899,0.0691212 +179,Ilford,51.5528331,0.07363979999999999 +180,"Belvedere, Industrial Area",51.48516499999999,0.14827 +180,Abbey Wood,51.48967099999999,0.119721 +180,Thamesmead East,51.50575809999999,0.1100586 +180,Plumstead Bus Garage,51.4913502,0.084419 +180,Woolwich,51.462271,0.1474771 +180,Woolwich,51.462271,0.1474771 +180,Charlton,51.48365769999999,0.0398658 +180,East Greenwich,51.4309209,-0.0936496 +180,"Greenwich, Cutty Sark",51.4828646,-0.0095917 +180,Lewisham Station,51.4652098,-0.0131213 +180,"Lewisham, Shopping Centre",51.46175909999999,-0.0119106 +181,Lewisham Station,51.4652098,-0.0131213 +181,Ladywell,51.4566649,-0.0154446 +181,Hither Green,51.45276029999999,-0.0071555 +181,Catford,51.4453954,-0.0160913 +181,Catford,51.4453954,-0.0160913 +181,"Catford, St Dunstan's",51.4430327,-0.0237655 +181,Lower Sydenham,51.42603219999999,-0.0325314 +181,Lower Sydenham,51.42603219999999,-0.0325314 +181,"Downham, Bromley Road",51.4346845,-0.0176083 +181,Grove Park,51.5921921,-0.2590079 +182,"Harrow Weald, Oxhey Lane",51.6155169,-0.3609869 +182,Harrow Weald,51.6052581,-0.3380395 +182,Harrow & Wealdstone Station,51.59172359999999,-0.3343587 +182,Harrow,51.552225,-0.3025793 +182,Sudbury,51.561682,-0.3318179 +182,Wembley Arena,51.558096,-0.282586 +182,Wembley Stadium Station,51.55418960000001,-0.286004 +182,Brent Town Hall,51.5665579,-0.2736435 +182,"Neasden, Shopping Centre",51.5626819,-0.2536987 +182,Staples Corner,51.5714404,-0.2319415 +182,Brent Cross,51.5763589,-0.2236956 +183,Golders Green,51.57602559999999,-0.2052126 +183,"Hendon, Queens Road",51.5824283,-0.226999 +183,West Hendon Broadway,51.5777099,-0.2399904 +183,Kingsbury Circle,51.5850061,-0.2814251 +183,"Kingsbury, The Mall",51.5853499,-0.2782546 +183,Northwick Park Station,51.4309209,-0.0936496 +183,Harrow,51.552225,-0.3025793 +183,North Harrow,51.58412800000001,-0.3644343 +183,Pinner,51.6039322,-0.4148169 +184,Turnpike Lane Station,51.5904278,-0.1027587 +184,Wood Green,51.5971722,-0.1098021 +184,Alexandra Park School,51.602153,-0.1365257 +184,Alexandra Park School,51.602153,-0.1365257 +184,Arnos Grove,51.6203322,-0.1295261 +184,Hampden Square,51.6323276,-0.1417747 +184,New Barnet,51.649276,-0.176187 +184,Barnet Church,51.6526856,-0.1992227 +184,"Barnet, Chesterfield Road",51.64658110000001,-0.2149842 +185,Lewisham Station,51.4652098,-0.0131213 +185,"Catford, Town Centre",51.4453954,-0.0160913 +185,Forest Hill,51.4487815,-0.0539697 +185,Dulwich Library,51.4488677,-0.07447669999999999 +185,East Dulwich,51.45482630000001,-0.0851263 +185,East Dulwich,51.45482630000001,-0.0851263 +185,Camberwell Green,51.4748827,-0.0921158 +185,Camberwell Green,51.4748827,-0.0921158 +185,Vauxhall,51.4861671,-0.12172 +185,Victoria,51.4309209,-0.0936496 +186,Northwick Park Hospital,51.5753935,-0.3201711 +186,Harrow,51.580559,-0.341995 +186,Harrow & Wealdstone Station,51.59172359999999,-0.3343587 +186,Belmont Circle,51.6010493,-0.3180225 +186,Belmont Circle,51.6010493,-0.3180225 +186,Edgware,51.61548819999999,-0.2609598 +186,Edgware,51.61548819999999,-0.2609598 +186,Apex Corner,51.4369075,-0.3784005 +186,Mill Hill Broadway,51.6133816,-0.2463566 +186,Hendon Central,51.583202,-0.226399 +186,Brent Cross,51.5763589,-0.2236956 +187,Central Middlesex Hospital,51.530944,-0.2690778 +187,"Harlesden, Jubilee Clock",51.5354215,-0.2479155 +187,Kensal Rise,51.5345071,-0.2250186 +187,Queens Park,51.5345448,-0.2043853 +187,Warwick Avenue,51.5248259,-0.1882752 +187,Swiss Cottage,51.5425872,-0.1724737 +187,"Finchley Road, O2 Centre",51.5478286,-0.1814281 +188,North Greenwich,51.4859576,0.007494900000000001 +188,"Greenwich, Cutty Sark",51.4828646,-0.0095917 +188,Deptford Church Street,51.4778325,-0.0227861 +188,Surrey Quays,51.4944172,-0.0383063 +188,Canada Water,51.4962989,-0.0482742 +188,Elephant & Castle,51.4938058,-0.0977932 +188,Elephant & Castle,51.4938058,-0.0977932 +188,Bricklayer's Arms,51.4661409,-0.2174147 +188,New Kent Road,51.4938526,-0.0906279 +188,Waterloo,51.5010694,-0.1088086 +188,Aldwych,51.5116716,-0.1189217 +188,Russell Square,51.52205739999999,-0.1276504 +189,Brent Cross,51.5763589,-0.2236956 +189,"Cricklewood, Pennine Drive",51.5644748,-0.215895 +189,Cricklewood Broadway,51.5569668,-0.2159914 +189,Kilburn High Road Station,51.537243,-0.192318 +189,Baker Street Station,51.5231548,-0.156863 +189,Baker Street Station,51.5231548,-0.156863 +189,Portman Square,51.5161534,-0.1560125 +189,Marble Arch,51.5133224,-0.1589956 +190,Richmond,51.56304249999999,-0.002005100000000001 +190,North Sheen,51.4644443,-0.2733717 +190,"Chiswick, Edensor Road",51.4821173,-0.255696 +190,Hammersmith,51.4932648,-0.2207996 +190,Hammersmith,51.4932648,-0.2207996 +190,West Brompton,51.483494,-0.196802 +191,Edmonton Green,51.6248126,-0.0581806 +191,"Ponders End, Nag's Head Road",51.6452225,-0.04863729999999999 +191,Enfield,51.6522994,-0.0807119 +191,"Southbury, Dearsley Road",51.64991610000001,-0.06317049999999999 +191,Enfield,51.6522994,-0.0807119 +191,Carterhatch,51.6607085,-0.06135640000000001 +191,Enfield Highway,51.652918,-0.041145 +191,Brimsdown,51.6628622,-0.0308497 +192,Enfield,51.6522994,-0.0807119 +192,Enfield Town Station,51.6520903,-0.07934469999999999 +192,Great Cambridge Road,51.6466396,-0.06045279999999999 +192,Great Cambridge Road,51.6466396,-0.06045279999999999 +192,Bush Hill Park,51.6445559,-0.06559659999999999 +192,Edmonton Green,51.6248126,-0.0581806 +192,"Angel Road, Superstores",51.6130441,-0.0522623 +192,Tottenham Hale,51.5892808,-0.06105049999999999 +193,"Romford, Queens Hospital",51.5688117,0.1807796 +193,Romford Market,51.5790739,0.1813886 +193,Romford Station,51.57472449999999,0.1826519 +193,"Hornchurch, Town Centre",51.562254,0.218605 +193,Hornchurch Station,51.55406929999999,0.2190275 +193,"Hornchurch, Bevan Way",51.5504909,0.2293935 +193,County Park Estate,51.4309209,-0.0936496 +194,Lower Sydenham,51.42603219999999,-0.0325314 +194,Lower Sydenham,51.42603219999999,-0.0325314 +194,Penge,51.41388490000001,-0.0570112 +194,"Beckenham, War Memorial",51.406914,-0.0320175 +194,Elmers End Green,51.3987339,-0.0436577 +194,Eden Park,51.3959047,-0.0312291 +194,Shirley,51.4309209,-0.0936496 +194,Shirley Inn,51.3744006,-0.05023610000000001 +194,Shirley Park,51.4309209,-0.0936496 +194,East Croydon,51.3750493,-0.0926978 +194,West Croydon,51.368451,-0.09966350000000002 +195,Charville Lane Estate,51.53883769999999,-0.4249346 +195,"Hayes North, Brook House",51.5323301,-0.4196085 +195,"Uxbridge Road, Lansbury Drive",51.5157566,-0.3980216 +195,Hayes & Harlington Station,51.5029848,-0.4203779 +195,Bull's Bridge,51.4999134,-0.4066811 +195,"Southall, Town Hall",51.5113272,-0.3751471 +195,Ealing Hospital,51.5075205,-0.3465216 +195,Hanwell Broadway,51.5066369,-0.3383229 +195,Great West Road,51.4761743,-0.3832373 +195,"Brentford, County Court",51.4842409,-0.3043609 +196,Elephant & Castle,51.4940507,-0.1005186 +196,Kennington Lane,51.48738669999999,-0.1126558 +196,Vauxhall,51.4861671,-0.12172 +196,Stockwell,51.466345,-0.1167604 +196,Brixton,51.4722042,-0.1127279 +196,Herne Hill,51.46079049999999,-0.09614919999999999 +196,Herne Hill,51.46079049999999,-0.09614919999999999 +196,Tulse Hill Station,51.43986,-0.10505 +196,Upper Norwood,51.41376716037048, -0.09204081941649297 +196,Norwood Junction,51.39731,-0.07501000000000001 +197,Peckham,51.4599566,-0.05951149999999999 +197,Peckham Rye,51.4599566,-0.05951149999999999 +197,Dulwich Library,51.4488677,-0.07447669999999999 +197,Forest Hill,51.4487815,-0.0539697 +197,Penge,51.41330120000001,-0.0509863 +197,Norwood Junction,51.39731,-0.07501000000000001 +197,Lower Addiscombe Road,51.3796147,-0.0747988 +197,East Croydon,51.3769529,-0.0956895 +197,Croydon Town Centre,51.3769529,-0.0956895 +198,Shrublands,51.3660734,-0.0295354 +198,Shirley,51.4309209,-0.0936496 +198,Shirley Inn,51.3744006,-0.05023610000000001 +198,"Addiscombe Road, Shirley Road",51.3750364,-0.0761587 +198,West Croydon,51.368451,-0.09966350000000002 +198,Thornton Heath Pond,51.3941232,-0.1146955 +198,Thornton Heath Station,51.3985835,-0.1000937 +198,"Thornton Heath, High Street",51.396747,-0.105523 +199,Canada Water,51.4962989,-0.0482742 +199,Surrey Quays,51.4972243,-0.0505153 +199,Pepys Estate,51.4309209,-0.0936496 +199,"Deptford, Church Street",51.4807988,-0.0231099 +199,"Greenwich, Cutty Sark",51.4828646,-0.0095917 +199,Lewisham Centre,51.4606377,-0.0109996 +199,"Lewisham, Shopping Centre",51.46175909999999,-0.0119106 +199,"Bellingham, Catford Bus Garage",51.434704,-0.017839 +200,Raynes Park,51.4084257,-0.2298751 +200,Copse Hill,51.414603,-0.2468798 +200,Wimbledon,51.41833889999999,-0.2206288 +200,Wimbledon,51.41833889999999,-0.2206288 +200,Colliers Wood,51.41704439999999,-0.1778555 +200,Phipp's Bridge,51.4954779,-0.1463109 +200,Mitcham,51.42185670000001,-0.1448831 +201,Morden,51.40636560000001,-0.1919791 +201,Mitcham,51.4210631,-0.1450061 +201,Mitcham,51.4210631,-0.1450061 +201,"Streatham, St Leonard's Church",51.42926610000001,-0.1311095 +201,Streatham Hill Station,51.4382009,-0.1270706 +201,Tulse Hill Station,51.43986,-0.10505 +201,Herne Hill,51.4531448,-0.1008164 +202,Crystal Palace,51.4547456,-0.07225070000000001 +202,Sydenham,51.3826752,-0.0933617 +202,Lower Sydenham,51.42603219999999,-0.0325314 +202,"Catford, St. Dunstan's",51.4430327,-0.0237655 +202,"Catford, Town Centre",51.4453954,-0.0160913 +202,"Catford, Town Centre",51.4453954,-0.0160913 +202,Lee Green,51.3916532,0.1019578 +202,Blackheath Village,51.4657729,0.0091238 +202,"Blackheath, Royal Standard",51.4779946,0.0202001 +203,"Hounslow, Bus Station",51.4708688,-0.3546457 +203,"Hounslow, Bell Corner",51.468569,-0.3666325 +203,Hounslow West,51.469435,-0.3837709 +203,Hatton Cross,51.4651031,-0.4157165 +203,Hatton Cross,51.4651031,-0.4157165 +203,Bedfont Green,51.450743,-0.4215865 +203,Ashford Hospital,51.4309209,-0.0936496 +203,"Staines, Crooked Billet Roundabout",51.43148,-0.515525 +203,Staines,51.4567807,-0.4135941 +204,Sudbury,51.5556591,-0.3171114 +204,Wembley High Road,51.5534192,-0.2873889 +204,"Preston Road, East Lane",51.5632313,-0.3134248000000001 +204,Kingsbury Circle,51.5853429,-0.2812115 +204,Kingsbury Circle,51.5853429,-0.2812115 +204,Colindale,51.5896908,-0.2491029 +204,Grahame Park,51.6017283,-0.2444205 +204,Burnt Oak,51.602809,-0.266965 +204,Edgware,51.61548819999999,-0.2609598 +205,Paddington,51.515973,-0.174943 +205,Marylebone,51.5188746,-0.1498955 +205,Baker Street Station,51.5231548,-0.156863 +205,Warren Street,51.5240516,-0.1399547 +205,Warren Street,51.5240516,-0.1399547 +205,Euston,51.5256866,-0.1350478 +205,King's Cross,51.53073190000001,-0.1194466 +205,Islington Angel,51.5346761,-0.1042905 +205,Old Street Station,51.5256719,-0.0874922 +205,Aldgate,51.5134365,-0.0772463 +205,Aldgate,51.5134365,-0.0772463 +205,Whitechapel,51.518398,-0.0628557 +205,Mile End,51.52214499999999,-0.045741 +205,Bow Church,51.5287753,-0.0167013 +206,"Wembley Park, The Paddocks",51.5677761,-0.2721636 +206,"Brent Park, Superstores",51.55263000000001,-0.2568869 +206,Craven Park,51.5771634,-0.063669 +206,"Harlesden, Jubilee Clock",51.5354215,-0.2479155 +206,Queen's Park,51.5345448,-0.2043853 +206,Kilburn Park,51.5285878,-0.1958083 +207,Hayes By-Pass,51.51593,-0.398889 +207,Ealing Hospital,51.5075205,-0.3465216 +207,Ealing Broadway,51.514042,-0.3015746 +207,Southall Town Hall,51.5113272,-0.3751471 +207,"Acton, High Street",51.507503,-0.2729245 +207,Acton Vale,51.50837199999999,-0.27444 +207,Shepherd's Bush Market Station,51.5056503,-0.2262516 +207,White City,51.51146199999999,-0.2376332 +208,Lewisham Station,51.4652098,-0.0131213 +208,Ladywell,51.4566319,-0.0153652 +208,"Catford, Town Centre",51.4453954,-0.0160913 +208,"Bellingham, Catford Bus Garage",51.434704,-0.017839 +208,"Downham, Bromley Road",51.4336021,-0.0185754 +208,"Bromley, Market Square",51.4056858,0.0148563 +208,Bromley South,51.406025,0.013156 +208,Bromley South,51.406025,0.013156 +208,"Bromley Common, Crown Lane",51.3836929,0.03937239999999999 +208,Petts Wood,51.389636,0.08195 +208,"Orpington, War Memorial",51.373203,0.09753479999999999 +208,"Orpington, Perry Hall Road",51.38329659999999,0.0938267 +209,Mortlake,51.48258389999999,-0.286561 +209,Mortlake,51.48258389999999,-0.286561 +209,Barnes Pond,51.4731208,-0.2468688 +209,Hammersmith,51.5011022,-0.22881 +210,Finsbury Park Station,51.5646425,-0.1058553 +210,Hornsey Rise,51.5721143,-0.12519 +210,Archway,51.5738502,-0.1412403 +210,Highgate Village,51.5681273,-0.1396432 +210,Golders Green,51.5740013,-0.1987725 +210,Brent Cross,51.5763589,-0.2236956 +211,Hammersmith,51.491187,-0.223731 +211,Fulham Broadway,51.4800648,-0.1957697 +211,"Chelsea, Redcliffe Gardens",51.4890213,-0.1892602 +211,Sloane Square,51.4927684,-0.1570174 +211,"Victoria, Coach Station",51.4924744,-0.1482485 +211,Parliament Square,51.5010421,-0.1268514 +211,Waterloo,51.500072,-0.1074168 +212,Chingford Station,51.6331421,0.0098588 +212,Chingford Hatch,51.61703,-0.000263 +212,Highams Park,51.6083754,0.0014712 +212,"Walthamstow, Beacontree Avenue",51.595736,0.0045318 +212,Walthamstow Central,51.5830128,-0.019886 +212,St James Street,51.5064993,-0.1393328 +213,Kingston,51.4116616,-0.2080648 +213,Kingston,51.4116616,-0.2080648 +213,"New Malden, Coombe Road",51.4094312,-0.2586718 +213,"New Malden, Fountain Roundabout",51.3978781,-0.2554973 +213,Worcester Park,51.38029,-0.24468 +213,North Cheam,51.3619271,-0.2189255 +213,Cheam,51.3619271,-0.2189255 +213,"Sutton, Bushey Road",51.3684466,-0.2004401 +214,Highgate Village,51.5717035,-0.1501241 +214,Parliament Hill Fields,51.5594043,-0.151707 +214,Kentish Town,51.5482656,-0.1410885 +214,Camden Town,51.5390261,-0.1425516 +214,Camden Town,51.5390261,-0.1425516 +214,King's Cross,51.53088229999999,-0.1194892 +214,King's Cross,51.53088229999999,-0.1194892 +214,Islington Angel,51.5346761,-0.1042905 +214,Old Street Station,51.5256719,-0.0874922 +214,"Moorgate, Finsbury Square",51.5184165,-0.0889151 +215,Lee Valley Camp Site,51.65514599999999,-0.007160000000000001 +215,Yardley Lane,51.6418904,-0.0087819 +215,Chingford Mount,51.61505940000001,-0.0177717 +215,"Walthamstow, Crooked Billet",51.601088,-0.0159737 +215,Walthamstow Central,51.5830128,-0.019886 +216,Staines,51.4657839,-0.3748097 +216,"Staines, Crooked Billet Roundabout",51.43148,-0.515525 +216,Ashford Hospital,51.4309209,-0.0936496 +216,"Sunbury, Tesco",51.414472,-0.4167217 +216,Sunbury Cross,51.4309209,-0.0936496 +216,Sunbury Village,51.4309209,-0.0936496 +216,Hampton Station,51.4158208,-0.3719119 +216,Hampton Station,51.4158208,-0.3719119 +216,Hampton Court,51.5454747,-0.1036343 +216,Hampton Wick,51.4086385,-0.3365021 +216,Kingston,51.4116616,-0.2080648 +217,Waltham Cross,51.68584389999999,-0.0330964 +217,St Ignatius College,51.6739451,-0.0549748 +217,Carterhatch,51.6590165,-0.035367 +217,Enfield Retail Park,51.6541066,-0.0578729 +217,"Southbury, Dearsley Road",51.64991610000001,-0.06317049999999999 +217,"Edmonton, Cambridge Roundabout",51.4309209,-0.0936496 +217,Lordship Lane,51.454366,-0.0770907 +217,Turnpike Lane Station,51.5904278,-0.1027587 +219,Wimbledon,51.41833889999999,-0.2206288 +219,Wimbledon,51.41833889999999,-0.2206288 +219,"Merton, Bus Garage",51.4165431,-0.1813083 +219,Colliers Wood,51.41704439999999,-0.1778555 +219,Tooting Broadway,51.427867,-0.1678142 +219,Tooting Bec,51.4324334,-0.1522016 +219,Tooting Bec,51.4324334,-0.1522016 +219,Wandsworth Common,51.4581475,-0.1792287 +219,Clapham Junction,51.4651737,-0.1708113 +220,Willesden Junction,51.53211630000001,-0.2433689 +220,"Harlesden, Jubilee Clock",51.5354215,-0.2479155 +220,"College Park, Scrubs Lane",51.5206904,-0.2288875 +220,North Pole Road,51.5195492,-0.2265871 +220,Shepherd's Bush,51.5051913,-0.22469 +220,Shepherd's Bush,51.5051913,-0.22469 +220,Hammersmith,51.50056009999999,-0.2280682 +220,Brook Green,51.4963863,-0.2217637 +220,Hammersmith,51.50056009999999,-0.2280682 +220,Putney Bridge,51.4644547,-0.2131459 +220,Wandsworth,51.4754967,-0.1316509 +220,Wandsworth,51.4754967,-0.1316509 +221,Edgware,51.5193526,-0.1693003 +221,Mill Hill Broadway,51.6133816,-0.2463566 +221,Mill Hill East,51.60823,-0.20996 +221,Holders Hill Circus,51.6051942,-0.2078155 +221,North Finchley,51.6135087,-0.1754198 +221,Friern Barnet,51.6255032,-0.1699775 +221,New Southgate,51.61100099999999,-0.135469 +221,Wood Green,51.5971722,-0.1098021 +221,Wood Green,51.5971722,-0.1098021 +221,Wood Green,51.5971722,-0.1098021 +221,Turnpike Lane Station,51.5904278,-0.1027587 +222,Uxbridge,51.5485,-0.479611 +222,Cowley,51.525848,-0.4820508999999999 +222,West Drayton,51.502985,-0.4654099999999999 +222,"Bath Road, Sipson Road",51.49763,-0.4623274 +222,Harlington Corner,51.4809415,-0.434335 +222,Cranford,51.4720623,-0.4055896 +222,Hounslow West,51.469435,-0.3837709 +222,"Hounslow, Bell Corner",51.468569,-0.3666325 +222,"Hounslow, Bus Station",51.4708688,-0.3546457 +223,Harrow,51.580559,-0.341995 +223,Northwick Park Hospital,51.5753935,-0.3201711 +223,Preston Road Station,51.57197,-0.29508 +223,Wembley Park,51.5585935,-0.2796126 +223,Wembley Central,51.55214429999999,-0.2965274 +224,Wembley Stadium,51.55602469999999,-0.2796177 +224,Alperton,51.539601,-0.2988365 +224,"Alperton, Sainsbury's",51.5383862,-0.3028583 +224,"Park Royal, Asda",51.52781,-0.26989 +224,Central Middlesex Hospital,51.530944,-0.2690778 +224,Craven Park,51.57750739999999,-0.0630854 +224,St. Raphael's,51.55207859999999,-0.2622574 +225,Hither Green,51.45059,-0.005551899999999999 +225,"Lewisham, Shopping Centre",51.46175909999999,-0.0119106 +225,"Lewisham, Shopping Centre",51.46175909999999,-0.0119106 +225,New Cross,51.4768299,-0.0499381 +225,Surrey Quays,51.4944172,-0.0383063 +225,Canada Water,51.4962989,-0.0482742 +226,Ealing Broadway,51.514042,-0.3015746 +226,Hanger Lane,51.531478,-0.2932577000000001 +226,"Park Royal, First Central",51.5326143,-0.2854417 +226,"Park Royal, Asda",51.52781,-0.26989 +226,Central Middlesex Hospital,51.530944,-0.2690778 +226,"Harlesden, Jubilee Clock",51.5354215,-0.2479155 +226,"Harlesden, Jubilee Clock",51.5354215,-0.2479155 +226,Cricklewood Broadway,51.5587708,-0.2174545 +226,"Cricklewood, Pennine Drive",51.564752,-0.2161581 +226,Golders Green,51.5740013,-0.1987725 +227,Bromley North,51.406025,0.013156 +227,"Beckenham, War Memorial",51.406914,-0.0320175 +227,Penge,51.41388490000001,-0.0570112 +227,Penge West,51.41388490000001,-0.0570112 +227,Crystal Palace,51.4537304,-0.0720673 +228,Central Middlesex Hospital,51.530944,-0.2690778 +228,Willesden Junction,51.53211630000001,-0.2433689 +228,East Acton,51.5127758,-0.2476803 +228,"East Acton, Savoy Circus",51.5140035,-0.247772 +228,White City,51.51146199999999,-0.2376332 +228,"Ladbroke Grove, Sainsbury's",51.5256365,-0.215718 +228,"Maida Hill, The Chippenham",51.5243627,-0.2017331 +229,Thamesmead,51.50575809999999,0.1100586 +229,Abbey Wood,51.4926116,0.1188182 +229,Belvedere,51.5036113,-0.1173103 +229,Erith,51.4654014,0.1514523 +229,"Bexleyheath, Bus Garage",51.46006930000001,0.1534245 +229,"Bexleyheath, Shopping Centre",51.45334099999999,0.13822 +229,Bexley,51.4745106,0.1629532 +229,Sidcup Station,51.4339345,0.1038351 +229,Queen Mary's Hospital,51.4556562,-0.2426609 +230,Upper Walthamstow,51.5877489,0.0037911 +230,Whipps Cross,51.581499,0.0001219 +230,Walthamstow Central,51.5830128,-0.019886 +230,West Green,51.586254,-0.0867628 +230,Tottenham Hale Station,51.5890318,-0.05979599999999999 +230,Tottenham Town Hall,51.5872187,-0.0725467 +230,Turnpike Lane Station,51.5904278,-0.1027587 +230,"Green Lanes, West Green Road",51.58628849999999,-0.0860857 +230,Wood Green,51.5971722,-0.1098021 +230,Wood Green,51.5971722,-0.1098021 +231,Enfield Chase,51.65326,-0.09067 +231,Enfield,51.6522994,-0.0807119 +231,"Southbury, Dearsley Road",51.64991610000001,-0.06317049999999999 +231,"Edmonton, Cambridge Roundabout",51.4309209,-0.0936496 +231,Turnpike Lane Station,51.5904278,-0.1027587 +232,St Raphael's,51.55207859999999,-0.2622574 +232,"Brent Park, Superstores",51.55263000000001,-0.2568869 +232,"Neasden, Shopping Centre",51.5626819,-0.2536987 +232,Brent Cross,51.5763589,-0.2236956 +232,"North Circular, Colney Hatch",51.6034922,-0.1482548 +232,Colney Hatch Lane,51.6034922,-0.1482548 +232,Arnos Grove,51.619799,-0.1296871 +232,"Palmers Green, North Circular Road",51.61459499999999,-0.1012351 +232,Wood Green,51.5971722,-0.1098021 +232,Wood Green,51.5971722,-0.1098021 +232,Turnpike Lane Station,51.5904278,-0.1027587 +233,Eltham Station,51.4506338,0.0570862 +233,New Eltham,51.4322522,0.0658314 +233,Sidcup Station,51.4264863,0.1009392 +233,"Foots Cray, Ruxley Corner",51.4155255,0.1253275 +233,"Swanley, Asda",51.396609,0.17656 +233,Swanley,51.396531,0.177326 +234,"Barnet, The Spires",51.655492,-0.2033422 +234,Barnet Church,51.6526856,-0.1992227 +234,"Barnet, Odeon",51.64663059999999,-0.1865655 +234,Whetstone,51.6300102,-0.1747954 +234,Friern Barnet,51.6141967,-0.1540148 +234,Muswell Hill,51.5911816,-0.1443015 +234,East Finchley,51.592468,-0.1664342 +234,Highgate Wood,51.5827374,-0.1491754 +235,Sunbury Village,51.4309209,-0.0936496 +235,Sunbury Cross,51.4195309,-0.419749 +235,Lower Feltham,51.436601,-0.426105 +235,Hounslow Heath,51.4563954,-0.3849625 +235,"Hounslow, Bell Corner",51.468569,-0.3666325 +235,"Hounslow, Bus Station",51.4708688,-0.3546457 +235,Isleworth,51.467121,-0.329003 +235,Busch Corner,51.4788665,-0.3231269 +235,"Sunbury Village, Three Fishes",51.4191935,-0.4191503 +235,North Brentford Quarter,51.4835374,-0.3063676 +236,Finsbury Park Station,51.4309209,-0.0936496 +236,Highbury Barn,51.553813,-0.09808739999999999 +236,Newington Green,51.5514507,-0.0857535 +236,Ash Grove,51.4810279,-0.3902918 +236,Homerton,51.5478609,-0.0425903 +236,Hackney Wick,51.544579,-0.0256935 +237,Hounslow Heath,51.4563954,-0.3849625 +237,"Hounslow, Bell Corner",51.468569,-0.3666325 +237,"Hounslow, Bus Station",51.4708688,-0.3546457 +237,Busch Corner,51.4788665,-0.3231269 +237,"Brentford, Brent Lea",51.48131739999999,-0.3135051 +237,"Brentford, Half Acre",51.4844289,-0.3068293 +237,"Brentford, County Court",51.4842409,-0.3043609 +237,Chiswick Roundabout,51.4910362,-0.2816861 +237,Turnham Green,51.4953471,-0.2552808 +237,Goldhawk Road,51.4999246,-0.2373253 +237,Shepherd's Bush,51.5051913,-0.22469 +237,White City,51.51146199999999,-0.2376332 +238,Stratford,51.5426313,-0.0010369 +238,"Upton Park, Green Street",51.539482,0.0325224 +238,East Ham Station,51.5393698,0.0510659 +238,"East Ham, Ron Leighton Wat",51.5370273,0.0515902 +238,"East Ham, Newham Town Hall",51.53280239999999,0.0551608 +238,Barking,51.536563,0.075766 +240,Golders Green,51.5782699,-0.2076681 +240,"Hendon, Queens Road",51.5820274,-0.226689 +240,Mill Hill East,51.4309209,-0.0936496 +240,Mill Hill Broadway,51.6133816,-0.2463566 +240,Edgware,51.5190993,-0.1683807 +240,Edgware,51.5190993,-0.1683807 +241,Stratford City,51.5440354,-0.0053088 +241,Stratford,51.5426313,-0.0010369 +241,Plaistow,51.5268317,0.0308143 +241,Plaistow Abbey Arms,51.5222296,0.0225853 +241,Keir Hardie Estate,51.5678758,-0.0607466 +241,Canning Town,51.5189494,0.0132 +241,"Canning Town, Barking Road",51.5198077,0.0168462 +242,Homerton Hospital,51.5478609,-0.0425903 +242,"Clapton Park, Millfields",51.5575011,-0.0424329 +242,Hackney Central,51.5482344,-0.05738749999999999 +242,"Dalston, Downham Road",51.5396916,-0.0898268 +242,Dalston Junction,51.5459999,-0.0751485 +242,Shoreditch,51.5229106,-0.0777472 +242,Liverpool Street,51.5175001,-0.0826966 +242,St. Paul's,51.4309209,-0.0936496 +242,City Thameslink,51.5140438,-0.1033475 +242,Holborn,51.5175802,-0.1145147 +242,Tottenham Court Road,51.518301,-0.1317726 +243,Wood Green,51.5971722,-0.1098021 +243,"Lordship Lane, Downhills Way",51.5975545,-0.0922026 +243,"Tottenham, Town Hall",51.5872187,-0.0725467 +243,Stamford Hill,51.5696514,-0.0750199 +243,Stoke Newington,51.561175,-0.08349229999999999 +243,Stoke Newington,51.561175,-0.08349229999999999 +243,Dalston Junction,51.5459999,-0.0751485 +243,"Dalston, Downham Road",51.5394454,-0.0887965 +243,Shoreditch,51.5229106,-0.0777472 +243,Old Street Station,51.5256719,-0.0874922 +243,Clerkenwell Green,51.522739,-0.1060289 +243,Clerkenwell Green,51.522739,-0.1060289 +243,Holborn,51.5175802,-0.1145147 +243,Aldwych,51.5116193,-0.1188998 +243,Waterloo,51.49951129999999,-0.1064564 +244,Queen Elizabeth Hospital,51.4778139,0.0505587 +244,"Shooters Hill, Eaglesfield Road",51.468341,0.0723689 +244,Woolwich,51.4894752,0.06758829999999999 +244,Belmarsh,51.4967407,0.0927968 +244,Broadwater Estate,51.5944339,-0.0812275 +244,Thamesmead,51.50575809999999,0.1100586 +244,Abbey Wood,51.4926116,0.1188182 +245,"Alperton, Sainsbury's",51.5383862,-0.3028583 +245,Sudbury Town,51.5503085,-0.316207 +245,North Wembley,51.5625616,-0.3175595 +245,"Neasden, Shopping Centre",51.5626819,-0.2536987 +245,Cricklewood Bus Garage,51.56195959999999,-0.2224221 +245,Cricklewood Broadway,51.5584696,-0.2177538 +245,Golders Green,51.5784737,-0.2081693 +246,Bromley North,51.406025,0.013156 +246,Hayes,51.516758,-0.436786 +246,Hayes,51.516758,-0.436786 +246,Bromley Town Centre,51.406025,0.013156 +246,Biggin Hill,51.312059,0.032802 +246,Westerham,51.2945922,0.05822480000000001 +246,Chartwell,51.4309209,-0.0936496 +247,Barkingside,51.5899246,0.08387420000000001 +247,"Hainault, The Lowe",51.6099517,0.1092883 +247,Barkingside,51.5899246,0.08387420000000001 +247,Marks Gate,51.5901971,0.1424532 +247,Collier Row,51.5996927,0.1745949 +247,Collier Row,51.5996927,0.1745949 +247,"Romford, Parkside Avenue",51.5908267,0.1816681 +247,Romford North Street Bus Garage,51.5823836,0.1761951 +247,Romford Station,51.57472449999999,0.1826519 +248,Romford Market,51.5790739,0.1813886 +248,Romford Station,51.57472449999999,0.1826519 +248,Roneo Corner,51.5654177,0.1885364 +248,Hornchurch Town Centre,51.562254,0.218605 +248,Upminster,51.55591399999999,0.248894 +248,Upminster Park Estate,51.55591399999999,0.248894 +248,Cranham,51.5679469,0.2673702 +249,Clapham Common,51.4589252,-0.1493071 +249,Clapham Common,51.4589252,-0.1493071 +249,Balham,51.4439889,-0.1494105 +249,Tooting Bec,51.436753,-0.1618404 +249,"Streatham, St Leonards Church",51.42926610000001,-0.1311095 +249,"Norwood, Crown Point",41.4169806,-87.3653135 +249,Upper Norwood,51.41376716037048, -0.09204081941649297 +249,Crystal Palace,51.4197233,-0.0830638 +249,Anerley Station,51.4121559,-0.06571779999999999 +250,Brixton,51.4612794,-0.1156148 +250,"Streatham Hill, Telford Avenue",51.441526,-0.1353403 +250,Streatham Hill Station,51.4382009,-0.1270706 +250,Streatham Station,51.4259857,-0.131308 +250,"Streatham, Green Lane",51.4152538,-0.1182378 +250,"Thornton Heath, High Street",51.396747,-0.105523 +250,Thornton Heath Pond,51.3941232,-0.1146955 +250,West Croydon,51.368451,-0.09966350000000002 +250,Croydon Town Centre,51.3769529,-0.0956895 +251,Arnos Grove,51.622533,-0.1272224 +251,Totteridge & Whetstone,51.630241,-0.179144 +251,Highwood Hill,51.6268074,-0.2399921 +251,Mill Hill Broadway,51.6133816,-0.2463566 +251,Burnt Oak,51.4462445,0.1020482 +251,Edgware,51.588489,-0.2529778 +252,Collier Row,51.5968745,0.1643956 +252,Romford Market,51.5790739,0.1813886 +252,Romford Station,51.57472449999999,0.1826519 +252,Roneo Corner,51.5654177,0.1885364 +252,Roneo Corner,51.5654177,0.1885364 +252,Elm Park,51.55027399999999,0.1956364 +252,Sanders Draper School,51.5499174,0.215173 +252,"Hornchurch, Town Centre",51.562254,0.218605 +253,Hackney Central,51.5482344,-0.05738749999999999 +253,Clapton Pond,51.5561061,-0.05490830000000001 +253,Clapton Pond,51.5561061,-0.05490830000000001 +253,Stamford Hill,51.5696514,-0.0750199 +253,Manor House,51.4309209,-0.0936496 +253,Finsbury Park Station,51.5646425,-0.1058553 +253,Finsbury Park Station,51.5646425,-0.1058553 +253,"Holloway, Nags Head",51.55724250000001,-0.1204364 +253,"Camden Road, Brecknock Road",51.5501037,-0.1276357 +253,Camden Town,51.5390261,-0.1425516 +253,Mornington Crescent,51.479306,-0.4070643 +253,Euston,51.5250092,-0.1364643 +254,Aldgate,51.5134365,-0.0772463 +254,Whitechapel,51.5148198,-0.0650534 +254,Ash Grove,51.4803533,-0.3905511 +254,Ash Grove,51.4803533,-0.3905511 +254,Hackney Well Street,51.54482489999999,-0.04606610000000001 +254,Hackney Central,51.5482344,-0.05738749999999999 +254,Clapton Pond,51.5561061,-0.05490830000000001 +254,Stamford Hill,51.5743423,-0.0719958 +254,Manor House,51.4309209,-0.0936496 +254,Finsbury Park Station,51.5646425,-0.1058553 +254,"Holloway, Nags Head",51.55724250000001,-0.1204364 +255,Pollards Hill,51.4000406,-0.1332582 +255,Norbury,51.4085878,-0.1213899 +255,Streatham Station,51.4259857,-0.131308 +255,Streatham Hill Station,51.4382009,-0.1270706 +255,Balham,51.4439889,-0.1494105 +256,"Hornchurch, Miramar Way",51.5472385,0.2158209 +256,Hornchurch Town Centre,51.562254,0.218605 +256,Harold Wood,51.5910397,0.2328613 +256,Emerson Park,51.57201,0.225394 +256,"Harold Hill, Gooshays Drive",51.6081419,0.2227947 +256,Noak Hill,51.6218055,0.2263263 +256D,"Hornchurch, St George's Hospital",51.562254,0.218605 +256D,Noak Hill,51.6218055,0.2263263 +257,Stratford,51.5426313,-0.0010369 +257,Maryland,51.5477587,0.0005166999999999999 +257,"Leytonstone, Harrow Green",51.5582955,0.007356 +257,Leytonstone,51.5649624,0.0088141 +257,Whipps Cross,51.581499,0.0001219 +257,Walthamstow Central,51.5830128,-0.019886 +258,Watford Junction,51.66371280000001,-0.3964488 +258,Bushey Station,51.64583529999999,-0.3853817 +258,Bushey Heath,51.640213,-0.344442 +258,Harrow,51.580559,-0.341995 +258,South Harrow,51.5683717,-0.3553483 +259,Edmonton Green,51.6248126,-0.0581806 +259,"Snells Park, Sainsbury's",51.609054,-0.0691713 +259,"Tottenham, Town Hall",51.5872187,-0.0725467 +259,"Tottenham, Town Hall",51.5872187,-0.0725467 +259,Manor House,51.4309209,-0.0936496 +259,Finsbury Park Station,51.5646425,-0.1058553 +259,Finsbury Park Station,51.5646425,-0.1058553 +259,"Holloway, Nags Head",51.55724250000001,-0.1204364 +259,"Holloway, Nag's Head",51.55724250000001,-0.1204364 +259,King's Cross,51.5347488,-0.1245845 +260,White City,51.51146199999999,-0.2376332 +260,Shepherd's Bush,51.5051913,-0.22469 +260,"East Acton, Savoy Circus",51.5140035,-0.247772 +260,North Acton,51.5219526,-0.2580821 +260,North Acton,51.5219526,-0.2580821 +260,"Park Royal, Asda",51.52781,-0.26989 +260,"Harlesden, Jubilee Clock",51.5354215,-0.2479155 +260,"Harlesden, Jubilee Clock",51.5354215,-0.2479155 +260,Craven Park,51.577324,-0.0632167 +260,Craven Park,51.577324,-0.0632167 +260,"Willesden, Bus Garage",51.5474482,-0.2394372 +260,Cricklewood Broadway,51.55914019999999,-0.2181392 +260,Golders Green,51.5740013,-0.1987725 +261,Lewisham Station,51.4652098,-0.0131213 +261,Lee Green,51.4493331,0.0204837 +261,Grove Park,51.4329249,0.021203 +261,Bromley North,51.40833,0.01702 +261,Bromley South,51.406025,0.013156 +261,"Bromley Common, Crown Lane",51.3836942,0.0393714 +261,"Bromley Common, Bus Garage",51.38774,0.0363217 +261,Princess Royal Hospital,51.3661498,0.05819390000000001 +262,"East Beckton, Sainsbury's",51.5212249,0.0669226 +262,Gallions Reach Shopping Park,51.5166002,0.0783827 +262,Gallions Reach Station,51.5090228,0.07172769999999999 +262,Beckton Station,51.5144016,0.06153319999999999 +262,"Plaistow, Greengate Street",51.5260178,0.0281265 +262,Plaistow,51.5268317,0.0308143 +262,Stratford,51.5426313,-0.0010369 +263,Highbury & Islington,51.5569649,-0.0979656 +263,Highbury & Islington,51.5569649,-0.0979656 +263,Holloway Nags Head,51.55724250000001,-0.1204364 +263,Archway,51.4309209,-0.0936496 +263,East Finchley,51.592468,-0.1664342 +263,East Finchley,51.592468,-0.1664342 +263,North Finchley,51.6135087,-0.1754198 +263,Whetstone,51.6300102,-0.1747954 +263,"Barnet, Odeon",51.64663059999999,-0.1865655 +263,Barnet Church,51.6526856,-0.1992227 +263,Barnet Hospital,51.6508236,-0.2137361 +264,Croydon Town Centre,51.3769529,-0.0956895 +264,West Croydon,51.368451,-0.09966350000000002 +264,"Mitcham Road, Purley Way",51.38380189999999,-0.1175218 +264,Mitcham,51.402869,-0.166709 +264,Tooting Broadway,51.427867,-0.1678142 +264,"Tooting, St George's Hospital",51.42656299999999,-0.1752284 +265,Putney Bridge,51.4631911,-0.2111601 +265,Barnes Common,51.4681254,-0.2413995 +265,Barnes Common,51.4681254,-0.2413995 +265,Roehampton,51.4484339,-0.2397592 +265,"Roehampton, Bessborough Road",51.445746,-0.2391544 +265,"Roehampton, Bessborough Road",51.445746,-0.2391544 +265,Roehampton Vale,51.4388194,-0.2491381 +265,Shannon Corner,51.3993558,-0.2429132 +265,"New Malden, Fountain Roundabout",51.3978781,-0.2554973 +265,Tolworth,51.3821133,-0.2828034 +266,Hammersmith,51.491187,-0.223731 +266,Seven Stars Corner,51.4309209,-0.0936496 +266,Acton Vale,51.5065594,-0.2567913 +266,"Acton, High Street",51.5084951,-0.2754782000000001 +266,North Acton,51.5219526,-0.2580821 +266,North Acton,51.5219526,-0.2580821 +266,Willesden Junction,51.53211630000001,-0.2433689 +266,Craven Park,51.5769799,-0.0630819 +266,Craven Park,51.5769799,-0.0630819 +266,Cricklewood Broadway,51.559223,-0.2182346 +266,Staples Corner,51.5714404,-0.2319415 +266,Brent Cross,51.5763589,-0.2236956 +267,Hammersmith,51.491187,-0.223731 +267,Ravenscourt Park,51.4947984,-0.2396908 +267,"Stamford Brook, Chiswick Lane",51.49492,-0.24568 +267,Turnham Green,51.49203019999999,-0.2663174 +267,Chiswick Roundabout,51.4910362,-0.2816861 +267,"Brentford, County Court",51.4842409,-0.3043609 +267,"London Road, Chertsey Road",51.4483827,-0.3549402 +267,Twickenham,51.4535082,-0.3301491 +267,Fulwell,51.4331018,-0.3520137 +268,Golders Green,51.5740013,-0.1987725 +268,Whitestone Pond,51.5614553,-0.1799757 +268,Swiss Cottage,51.5425872,-0.1724737 +268,"Finchley Road, O2 Centre",51.5478286,-0.1814281 +269,"Bexleyheath, Shopping Centre",51.45334099999999,0.13822 +269,Bexleyheath Library,51.45587399999999,0.1439466 +269,Bexley,51.439933,0.154327 +269,"Albany Park, Foots Cray Lane",51.4372375,0.1193106 +269,Sidcup Station,51.4339345,0.1038351 +269,Queen Mary's Hospital,51.4556562,-0.2426609 +269,"Chislehurst, War Memorial",51.4124839,0.07390759999999999 +269,Bromley North,51.406025,0.013156 +270,Putney Bridge,51.4669613,-0.2129017 +270,Wandsworth,51.4741331,-0.1330686 +270,"Garratt Lane, Wimbledon Road",51.4409636,-0.1869488 +270,"Garratt Lane, Wimbledon Road",51.4409636,-0.1869488 +270,Tooting Broadway,51.427867,-0.1678142 +270,Tooting Station,51.41986989999999,-0.16136 +270,Mitcham,51.419721,-0.1471023 +270,Mitcham,51.419721,-0.1471023 +271,Highgate Village,51.5717035,-0.1501241 +271,Archway,51.4309209,-0.0936496 +271,"Holloway, Nag's Head",51.55724250000001,-0.1204364 +271,Highbury & Islington,51.5569649,-0.0979656 +271,Old Street Station,51.5256719,-0.0874922 +271,"Moorgate, Finsbury Square",51.5184165,-0.0889151 +272,"Chiswick, Grove Park",51.481631,-0.272505 +272,Turnham Green,51.49203019999999,-0.2663174 +272,Acton Vale,51.5065594,-0.2567913 +272,East Acton,51.5127758,-0.2476803 +272,White City,51.51146199999999,-0.2376332 +272,Shepherds Bush,51.5051913,-0.22469 +273,"Lewisham, Tesco",51.4414579,-0.0117006 +273,Lewisham Shopping Centre,51.46175909999999,-0.0119106 +273,Lee Green,51.4493331,0.0204837 +273,Grove Park,51.4329249,0.021203 +273,"Dunkery Road, Mottingham Road",51.4288147,0.050542 +273,"Chislehurst, War Memorial",51.4124839,0.07390759999999999 +273,St Marys Cray,51.385993,0.113061 +273,St Marys Cray,51.385993,0.113061 +273,Petts Wood,51.389636,0.08195 +274,Islington Angel,51.5346761,-0.1042905 +274,"Caledonian Road, Copenhagen Street",51.5389986,-0.1164184 +274,Market Road,51.5455568,-0.1249446 +274,Camden Town,51.5390261,-0.1425516 +274,Camden Town,51.5390261,-0.1425516 +274,London Zoo,51.5352875,-0.1534303 +274,Lord's Cricket Ground,51.52983099999999,-0.1721564 +274,Baker Street Station,51.5231548,-0.156863 +274,Portman Square,51.5161534,-0.1560125 +274,Marble Arch,51.5132225,-0.1588937 +275,St James Street,51.5064993,-0.1393328 +275,Walthamstow Central,51.5830128,-0.019886 +275,"Walthamstow, Beacontree Avenue",51.595736,0.0045318 +275,Mill lane,51.5521985,-0.1932197 +275,Highams Park,51.6083754,0.0014712 +275,Woodford Green,51.6016983,0.019011 +275,Woodford Bridge,51.6016983,0.019011 +275,Barkingside,51.5899246,0.08387420000000001 +275,Barkingside,51.5899246,0.08387420000000001 +276,Newham Hospital,51.5222415,0.0325405 +276,"Plaistow, Greengate Street",51.527444,0.027621 +276,"Canning Town, Barking Road",51.5202859,0.0185776 +276,West Ham Station,51.5278232,0.0042832 +276,Stratford,51.5426313,-0.0010369 +276,Bow Church,51.5287753,-0.0167013 +276,Bow Church,51.5287753,-0.0167013 +276,Hackney Wick,51.544579,-0.0256935 +276,Homerton Hospital,51.5478609,-0.0425903 +276,Stoke Newington,51.561175,-0.08349229999999999 +277,Highbury Corner,51.54602329999999,-0.1022688 +277,Mildmay Park,51.5488355,-0.0843157 +277,Dalston Junction,51.5459999,-0.0751485 +277,Hackney Well Street,51.5450519,-0.046374 +277,"South Hackney, Church Crescent",51.5882451,-0.1449718 +277,Mile End,51.52354529999999,-0.0330122 +277,"Limehouse, Burdett Road",51.5165953,-0.0296452 +277,Canary Wharf,51.5054306,-0.0235333 +277,Crossharbour,51.4958465,-0.0145118 +279,Waltham Cross,51.68584389999999,-0.0330964 +279,Enfield Highway,51.652918,-0.041145 +279,"Ponders End, Bus Garage",51.6452225,-0.04863729999999999 +279,Edmonton Green,51.6248126,-0.0581806 +279,"Snells Park, Sainsburys",51.609054,-0.0691713 +279,"Tottenham, Town Hall",51.5872187,-0.0725467 +279,Seven Sisters,51.582652,-0.0747232 +279,Manor House,51.4309209,-0.0936496 +280,"Tooting, St. George's Hospital",51.42656299999999,-0.1752284 +280,Tooting Broadway,51.427867,-0.1678142 +280,Mitcham,51.402869,-0.166709 +280,Mitcham,51.402869,-0.166709 +280,"St Helier, Rose Hill",51.3881851,-0.1893768 +280,Sutton Town Centre,51.3614279,-0.193961 +280,Sutton Station,51.3614279,-0.193961 +280,Belmont,51.601249,-0.3192749 +281,Tolworth,51.3801004,-0.2861237 +281,"Tolworth, Red Lion Road",51.3788084,-0.2915515 +281,Surbiton,51.39400999999999,-0.302662 +281,"Kingston, Brook Street",51.41233,-0.300689 +281,Kingston,51.41233,-0.300689 +281,Hampton Wick,51.413541,-0.321331 +281,Teddington,51.4268694,-0.3338681 +281,Fulwell,51.4331018,-0.3520137 +281,Twickenham,51.4453043,-0.3375429 +281,"Twickenham, Rugby Stadium",51.4453043,-0.3375429 +281,Hospital Bridge Roundabout,51.44267,-0.3652385 +281,Whitton Church,51.4538478,-0.3732651 +281,"Hounslow, Bus Station",51.4708688,-0.3546457 +282,Ealing Hospital,51.5075205,-0.3465216 +282,"Iron Bridge, Uxbridge Road",51.509837,-0.3549224 +282,Greenford Broadway,51.5279556,-0.3540139 +282,"Yeading, White Hart",51.60520289999999,-0.0790162 +282,Northolt,51.546615,-0.373103 +282,"Field End Road, Victoria Road",51.5696578,-0.3900522 +282,Eastcote,51.5512622,-0.3732052 +282,Northwood Hills,51.6004243,-0.4098652 +282,Northwood Station,51.61028899999999,-0.428278 +282,Mount Vernon Hospital,51.6153975,-0.4455072 +283,East Acton,51.5127758,-0.2476803 +283,"Wood Lane, Du Cane Road",51.5151603,-0.2492864 +283,Shepherd's Bush,51.5051913,-0.22469 +283,"White City, Leisure Centre",51.51146199999999,-0.2376332 +283,Hammersmith,51.491187,-0.223731 +284,Lewisham Station,51.4652098,-0.0131213 +284,Ladywell,51.45589709999999,-0.0219523 +284,"Catford, Town Centre",51.4453954,-0.0160913 +284,Downham,51.4241172,0.009519699999999999 +284,Grove Park,51.4329249,0.021203 +284,Grove Park Cemetery,51.4246215,0.0364068 +285,Heathrow Central,51.4724711,-0.4544586 +285,"Bath Road, Sipson Road",51.4911429,-0.4575516 +285,Harlington Corner,51.4809415,-0.434335 +285,Hatton Cross,51.4651031,-0.4157165 +285,Feltham Station,51.4480215,-0.4090095 +285,"Hanworth, Apex Corner",51.4369075,-0.3784005 +285,"Hanworth, Apex Corner",51.4369075,-0.3784005 +285,"Hampton, Sainsbury's",51.4264198,-0.3776108 +285,Teddington,51.4268694,-0.3338681 +285,Hampton Wick,51.413541,-0.321331 +285,Kingston,51.41233,-0.300689 +286,"Greenwich, Cutty Sark",51.4828646,-0.0095917 +286,East Greenwich,51.4309209,-0.0936496 +286,"Blackheath, Royal Standard",51.4779946,0.0202001 +286,Eltham Station,51.45564,0.0525 +286,"Eltham, High Street",51.450501,0.0628537 +286,Avery Hill,51.451434,0.076128 +286,Sidcup Station,51.4339345,0.1038351 +286,Queen Mary's Hospital,51.4556562,-0.2426609 +287,Barking,51.536563,0.075766 +287,"Barking, London Road",51.5372918,0.0714076 +287,"Ripple Road, Lodge Avenue",51.5416682,0.1129179 +287,"Dagenham, Asda",51.5299749,0.1425747 +287,"Dagenham, New Road",51.5275921,0.1595252 +287,Rainham Tesco,51.5200061,0.1907802 +287,Rainham Tesco,51.5200061,0.1907802 +287,Rainham War Memorial,51.5185366,0.1902033 +287,"Rainham, Abbey Wood Lane",51.5292975,0.2137483 +288,"Queensbury, Morrison's",51.5942132,-0.2853683 +288,Queensbury,51.5942132,-0.2853683 +288,Burnt Oak Broadway,51.607471,-0.2749745 +288,Edgware,51.61548819999999,-0.2609598 +288,Edgware,51.61548819999999,-0.2609598 +288,Broadfields Estate,51.6267303,-0.2729243 +289,Elmers End,51.39749,-0.0474767 +289,Long Lane,51.5501784,-0.4490557 +289,Ashburton Park,51.3855119,-0.0654191 +289,West Croydon,51.368451,-0.09966350000000002 +289,Thornton Hth Pd,51.4309209,-0.0936496 +289,Waddon Marsh,51.3769818,-0.1179077 +289,"Purley Way, Colonnades",51.3563828,-0.1135816 +289,Purley,51.339228,-0.119711 +290,Staines,51.4555302,-0.4223853 +290,"Ashford, Woodthorpe Road",51.4269867,-0.4801537999999999 +290,Ashford,51.5288186,-0.0827738 +290,Sunbury Cross,51.4309209,-0.0936496 +290,"Hampton, Sainsbury's",51.4264198,-0.3776108 +290,Twickenham,51.46206979999999,-0.3316404 +291,Queen Elizabeth Hospital,51.4778139,0.0505587 +291,Woolwich,51.4894752,0.06758829999999999 +291,Woolwich,51.4894752,0.06758829999999999 +291,Woolwich,51.4894752,0.06758829999999999 +291,Plumstead Common,51.4801905,0.08438269999999999 +291,Woodlands Estate,51.4309209,-0.0936496 +292,"Borehamwood, Rossington Avenue",51.4309209,-0.0936496 +292,Borehamwood Station,51.657728,-0.272308 +292,"Borehamwood, Tesco",51.4309209,-0.0936496 +292,Stirling Corner,51.643381,-0.2551272 +292,Edgware,51.61548819999999,-0.2609598 +292,Burnt Oak,51.602809,-0.266965 +292,Apex Corner,51.4369075,-0.3784005 +292,"Colindale, Superstores",51.5942575,-0.2607018 +293,Morden,51.394943,-0.19446 +293,Lower Morden,51.3907209,-0.2248662 +293,North Cheam,51.3619271,-0.2189255 +293,Ewell Village,51.3506319,-0.2533376 +293,Epsom,51.4309209,-0.0936496 +293,Epsom Hospital,51.3251497,-0.2732057 +294,Havering Park,51.607707,0.157121 +294,Collier Row,51.5996927,0.1745949 +294,"Romford, Parkside Avenue",51.5905318,0.1818613 +294,Romford North Street Bus Garage,51.5823836,0.1761951 +294,Romford Market,51.5790739,0.1813886 +294,Romford Market,51.5790739,0.1813886 +294,Romford Station,51.57472449999999,0.1826519 +294,Gidea Park Station,51.5792473,0.2076649 +294,Harold wood,51.5910397,0.2328613 +294,"Harold Wood, Gooshays Drive",51.6081419,0.2227947 +294,Noak Hill,51.6218055,0.2263263 +295,"Ladbroke Grove, Sainsbury's",51.5256365,-0.215718 +295,Latimer Road Station,51.5134548,-0.2177014 +295,Shepherd's Bush,51.5051913,-0.22469 +295,Brook Green,51.4963863,-0.2217637 +295,Hammersmith,51.491187,-0.223731 +295,Fulham Broadway,51.4802664,-0.1966965 +295,Fulham Broadway,51.4802664,-0.1966965 +295,"Wandsworth Bridge, South Side",51.4651939,-0.1880094 +295,Clapham Junction,51.4651737,-0.1708113 +296,Romford Station,51.57472449999999,0.1826519 +296,Romford Market,51.5790739,0.1813886 +296,Romford North Street Bus Garage,51.5823836,0.1761951 +296,Marks Gate,51.5901971,0.1424532 +296,Little Heath,51.583227,0.120603 +296,Newbury Park,51.5734779,0.08897669999999999 +296,Gants Hill,51.5767812,0.0661732 +296,Ilford Broadway,51.4582445,0.1341027 +296,Ilford Broadway,51.4582445,0.1341027 +297,"Willesden, Bus Garage",51.5474482,-0.2394372 +297,"Neasden, Shopping Centre",51.5626819,-0.2536987 +297,Brent Town Hall,51.5665579,-0.2736435 +297,Wembley Park,51.5585935,-0.2796126 +297,Wembley Central,51.55214429999999,-0.2965274 +297,"Alperton, Sainsbury's",51.5383862,-0.3028583 +297,Perivale Station,51.53667979999999,-0.3237969 +297,"West Ealing, Scotch Common",51.5248572,-0.3210551 +297,Ealing Broadway,51.514042,-0.3015746 +298,Arnos Grove,51.619799,-0.1296871 +298,Southgate,51.62476119999999,-0.1240456 +298,Cockfosters,51.647851,-0.151255 +298,Potters Bar Station,51.6972971,-0.1923315 +298,"Potters Bar, Cranborne Road",51.4309209,-0.0936496 +299,Muswell Hill,51.5911816,-0.1443015 +299,Bounds Green,51.6086813,-0.1274673 +299,Southgate,51.62476119999999,-0.1240456 +299,Cockfosters,51.647851,-0.151255 +300,East Ham Station,51.5393698,0.0510659 +300,"East Ham, Newham Town Hall",51.53280239999999,0.0551608 +300,"East Ham, Newham Town Hall",51.53280239999999,0.0551608 +300,Beckton Alps,51.5192628,0.0612645 +300,Beckton Station,51.4309209,-0.0936496 +300,Prince Regent,51.5178274,0.0321034 +300,"Plaistow, Greengate Street",51.527444,0.027621 +300,"Plaistow, Balaam Street",51.529212,0.0243676 +300,"Canning Town, Barking Road",51.5208364,0.0191093 +300,Canning Town,51.5189494,0.0132 +302,Mill Hill Broadway,51.6129292,-0.2487871 +302,Burnt Oak,51.602809,-0.266965 +302,Burnt Oak,51.602809,-0.266965 +302,Kingsbury Green,51.5814409,-0.2619577 +302,"Neasden, Shopping Centre",51.5626819,-0.2536987 +302,"Willesden, Bus Garage",51.5474482,-0.2394372 +302,Kensal Rise,51.5345071,-0.2250186 +303,Edgware,51.61548819999999,-0.2609598 +303,Mill Hill Broadway,51.6129292,-0.2487871 +303,Mill Hill Broadway,51.6129292,-0.2487871 +303,Grahame Park,51.6017283,-0.2444205 +303,"Colindale, Superstores",51.5942575,-0.2607018 +305,Edgware,51.5215981,-0.1726091 +305,Burnt Oak,51.4484998,0.0997395 +305,Burnt Oak,51.4484998,0.0997395 +305,Burnt Oak,51.4484998,0.0997395 +305,Kingsbury Circle,51.5850061,-0.2814251 +307,Brimsdown,51.65642219999999,-0.0272713 +307,"Southbury, Great Cambridge Road",51.6492397,-0.0591129 +307,Enfield,51.6622909,-0.1180651 +307,Oakwood,51.6481224,-0.1309298 +307,New Barnet,51.649276,-0.176187 +307,"Barnet, Odeon",51.64663059999999,-0.1865655 +307,Barnet Hospital,51.6508236,-0.2137361 +308,Wanstead,51.5767971,0.0249881 +308,Wanstead Park,51.568725,0.0433573 +308,Stratford,51.5426313,-0.0010369 +308,Stratford City,51.5440354,-0.0053088 +308,Homerton Hospital,51.5478609,-0.0425903 +308,Clapton Pond,51.5561061,-0.05490830000000001 +309,Canning Town,51.5189494,0.0132 +309,Aberfeldy Estate,51.4309209,-0.0936496 +309,"Poplar, All Saints",51.5105521,-0.0118612 +309,"Poplar, Cordelia Street",51.5137347,-0.0174897 +309,Stepney High Street,51.517287,-0.0426262 +309,"Bethnal Green, Chest Hospital",51.53196500000001,-0.0497284 +312,"South Croydon, Bus Garage",51.3544903,-0.0968822 +312,"South Croydon, South End",51.3650199,-0.099012 +312,Croydon Town Centre,51.3769529,-0.0956895 +312,East Croydon,51.3750493,-0.0926978 +312,Lower Addiscombe Road,51.38227269999999,-0.0674548 +312,Ashburton Park,51.3855119,-0.0654191 +312,Norwood Junction,51.39731,-0.07501000000000001 +313,Chingford Station,51.6331421,0.0098588 +313,"Ponders End, Mollison Avenue",51.6792707,-0.0252251 +313,"Ponders End, Bus Garage",51.6452225,-0.04863729999999999 +313,Enfield,51.6522994,-0.0807119 +313,Chase Farm Hospital,51.66689239999999,-0.1028125 +313,Potters Bar Station,51.696636,-0.175948 +313,Dame Alice Owen's School,51.6907953,-0.2071661 +314,Eltham Station,51.45564,0.0525 +314,"Eltham, Footscray Road",51.440054,0.0695436 +314,"Five Ways, Green Lane",51.6193019,-0.1068853 +314,Elmstead Woods,51.42242050000001,0.04166810000000001 +314,Plaistow Green,51.4139535,0.0168425 +314,Bromley North,51.406025,0.013156 +314,Bromley South,51.406025,0.013156 +314,Hayes Station,51.37633599999999,0.010589 +314,Coney Hall,51.3711435,-0.0014082 +314,Addington Village,51.358673,-0.0312539 +314,New Addington,51.348184,-0.017094 +315,West Norwood,51.427905,-0.1002486 +315,"Streatham, St Leonards Church",51.42926610000001,-0.1311095 +315,"Streatham, St. Leonard's Church",51.42926610000001,-0.1311095 +315,Balham,51.4439889,-0.1494105 +316,Cricklewood Bus Garage,51.5581887,-0.2163581 +316,Cricklewood Broadway,51.5595363,-0.2184213 +316,Kilburn High Road Station,51.537243,-0.192318 +316,Kilburn Park,51.53504119999999,-0.1938988 +316,Queen's Park,51.5345448,-0.2043853 +316,"Ladbroke Grove, Sainsbury's",51.5256365,-0.215718 +316,North Kensington,51.5246698,-0.2138884 +316,White City,51.51146199999999,-0.2376332 +317,Waltham Cross,51.68584389999999,-0.0330964 +317,St Ignatius College,51.6739451,-0.0549748 +317,Carterhatch,51.66345949999999,-0.0658526 +317,"Southbury, Dearsley Road",51.64991610000001,-0.06317049999999999 +317,Enfield,51.6522994,-0.0807119 +318,North Middlesex Hospital,51.6131618,-0.0735832 +318,Northumberland Park,51.6024517,-0.0676958 +318,"Tottenham, Town Hall",51.5872187,-0.0725467 +318,Stamford Hill,51.5696514,-0.0750199 +319,"Streatham Hill, Telford Avenue",51.4421746,-0.1300019 +319,Streatham Hill Station,51.4307467,-0.1294977 +319,"Streatham, St Leonards Church",51.42926610000001,-0.1311095 +319,Tooting Bec,51.436753,-0.1618404 +319,Tooting Bec,51.436753,-0.1618404 +319,Clapham Junction,51.4651737,-0.1708113 +319,Clapham Junction,51.4651737,-0.1708113 +319,"Battersea, Latchmere Road",51.4646957,-0.161959 +319,"Battersea Bridge, South Side",51.4811674,-0.1725411 +319,"Chelsea, Beaufort Street",51.4846097,-0.1758684 +319,Sloane Square,51.4927684,-0.1570174 +320,Biggin Hill Valley,51.312059,0.032802 +320,Biggin Hill Airport,51.3317877,0.0287812 +320,"Bromley Common, Crown Lane",51.3895022,0.0355797 +320,Bromley South,51.406025,0.013156 +320,Bromley North,51.406025,0.013156 +320,"Downham, Bromley Road",51.4307442,-0.0152414 +320,"Bellingham, Catford Bus Garage",51.434704,-0.017839 +320,Catford Bridge,51.4448458,-0.0247399 +321,"Foots Cray, Tesco",51.4127689,0.121733 +321,Foots Cray,51.4174447,0.1210622 +321,"Sidcup, Police Station",51.4336673,0.1024815 +321,"Eltham, High Street",51.45091499999999,0.0633415 +321,Eltham Church,51.4506338,0.0570862 +321,Eltham Green,51.4533383,0.0356381 +321,Lewisham Station,51.4652098,-0.0131213 +321,New Cross,51.4769047,-0.0336897 +321,New Cross Gate,51.4749904,-0.0403466 +322,Crystal Palace,51.4197233,-0.0830638 +322,Gipsy Hill,51.4238202,-0.0835265 +322,West Norwood,51.427905,-0.1002486 +322,Tulse Hill Station,51.43986,-0.10505 +322,Herne Hill,51.4609208,-0.0985404 +322,Herne Hill,51.4609208,-0.0985404 +322,Brixton,51.4612794,-0.1156148 +322,Clapham North,51.4658813,-0.1413263 +322,Clapham Common,51.4589252,-0.1493071 +323,Canning Town,51.5189494,0.0132 +323,East London Mail Centre,51.55633,0.0655092 +323,Mile End,51.52354529999999,-0.0330122 +324,Stanmore Station,51.617676,-0.311451 +324,Queensbury Station,51.5942132,-0.2853683 +324,Kingsbury,51.5853499,-0.2782546 +324,Colindale,51.5896908,-0.2491029 +324,Hendon Central,51.583202,-0.226399 +324,Brent Cross,51.5763589,-0.2236956 +324,"Brent Cross, Tesco",51.5741621,-0.2146762 +325,"East Beckton, Sainsbury's",51.5212249,0.0669226 +325,"East Ham, Newham Town Hall",51.53280239999999,0.0551608 +325,East Ham Station,51.5393698,0.0510659 +325,"East Ham, Plashet Grove",51.5395772,0.0460004 +325,"Forest Gate, Police Station",51.5467822,0.0309995 +325,"Plaistow, Broadway",51.529163,0.024332 +325,Plaistow Abbey Arms,51.5222296,0.0225853 +325,Prince Regent,51.4309209,-0.0936496 +326,"Barnet, The Spires",51.655492,-0.2033422 +326,Barnet Church,51.6526856,-0.1992227 +326,New Barnet,51.649276,-0.176187 +326,Dollis Valley,51.5957933,-0.209576 +326,Totteridge & Whetstone,51.630241,-0.179144 +326,"Finchley, Church End",51.604606,-0.1882833 +326,Hendon Central,51.583202,-0.226399 +326,Brent Cross,51.5763589,-0.2236956 +327,Waltham Cross,51.68584389999999,-0.0330964 +327,Elsinge Estate,51.6793634,-0.04655339999999999 +328,Golders Green,51.5740013,-0.1987725 +328,"Finchley Road, Hendon Way",51.5824058,-0.2269962 +328,West Hampstead,51.5490183,-0.1971205 +328,"Kilburn, Quex Road",51.5404545,-0.1937492 +328,Kilburn High Road Station,51.537243,-0.192318 +328,Kilburn Park,51.53504119999999,-0.1938988 +328,"Maida Hill, The Chippenham",51.5243627,-0.2017331 +328,Westbourne Park,51.51769299999999,-0.194941 +328,Westbourne Park,51.51769299999999,-0.194941 +328,Notting Hill Gate,51.5086878,-0.2005318 +328,"Kensington, High Street",51.4976157,-0.2037023 +328,"Kensington, Cromwell Road",51.4949065,-0.1953115 +328,Earl's Court,51.490331,-0.1958417 +328,"Chelsea, Redcliffe Gardens",51.4867031,-0.1875171 +328,"Chelsea, World's End",51.4810423,-0.1786311 +328,"Chelsea, World's End",51.4810423,-0.1786311 +329,Enfield,51.6522994,-0.0807119 +329,Winchmore Hill,51.6320279,-0.09580219999999999 +329,Winchmore Hill,51.6320279,-0.09580219999999999 +329,"Palmers Green, Hedge Lane",51.6173228,-0.0874008 +329,"Palmers Green, North Circular Road",51.6122666,-0.1091537 +329,Wood Green,51.5971722,-0.1098021 +329,Wood Green,51.5971722,-0.1098021 +330,Wanstead Park Station,51.551239,0.0251455 +330,"Forest Gate, Police Station",51.5467822,0.0309995 +330,Upton Park Station,51.5353424,0.0352766 +330,"Upton Park, Boleyn",51.5305005,0.0384915 +330,"Plaistow, Balaam Street",51.529212,0.0243676 +330,"Canning Town, Barking Road",51.521274,0.0207211 +330,Canning Town,51.5189494,0.0132 +331,Ruislip,51.5758719,-0.421236 +331,Ruislip Lido,51.59114049999999,-0.4304918 +331,Northwood Station,51.6112297,-0.423889 +331,Mount Vernon Hospital,51.6153975,-0.4455072 +331,Uxbridge,51.5485,-0.479611 +332,"Brent Park, Superstores",51.55263000000001,-0.2568869 +332,"Neasden, Shopping Centre",51.5626819,-0.2536987 +332,Cricklewood Bus Garage,51.56195959999999,-0.2224221 +332,Cricklewood Broadway,51.5597831,-0.2188271 +332,Kilburn High Road Station,51.537243,-0.192318 +332,Kilburn High Road Station,51.537243,-0.192318 +332,Edgware Road Station,51.51988249999999,-0.1678336 +332,Paddington,51.515973,-0.174943 +333,Tooting Broadway,51.427867,-0.1678142 +333,"Streatham, St. Leonard's Church",51.42926610000001,-0.1311095 +333,"Streatham Hill, Telford Avenue",51.4421746,-0.1300019 +333,"Brixton Hill, Christchurch Road",51.4458253,-0.124245 +333,Stockwell,51.4647668,-0.1144344 +333,Brixton,51.4722042,-0.1127279 +333,Brixton,51.4722042,-0.1127279 +333,Kennington Church,51.50875809999999,-0.1954048 +333,Elephant & Castle,51.4938058,-0.0977932 +336,Catford Bridge,51.4448458,-0.0247399 +336,Downham,51.4243854,0.0122988 +336,Plaistow Green,51.4139535,0.0168425 +336,"Bromley Common, Bus Garage",51.38774,0.0363217 +336,Bromley North,51.40833,0.01702 +336,Bromley South,51.406025,0.013156 +336,Bickley,51.38994700000001,0.0492904 +336,Locksbottom,51.3673231,0.0547259 +337,Clapham Junction,51.4651737,-0.1708113 +337,Wandsworth,51.45837299999999,-0.1891356 +337,Putney Station,51.4611807,-0.2164913 +337,Putney Station,51.4611807,-0.2164913 +337,Putney Station,51.4611807,-0.2164913 +337,Barnes Common,51.4681254,-0.2413995 +337,"East Sheen, Queen's Road",51.4663301,-0.2595362 +337,Richmond,51.46131099999999,-0.303742 +339,Leytonstone,51.5649624,0.0088141 +339,Stratford City,51.5440354,-0.0053088 +339,"Thatched House, Crownfield Road",51.5511521,-0.0040387 +339,"Bow, Fish Island",51.5363622,-0.0238479 +339,Mile End,51.52354529999999,-0.0330122 +339,Shadwell,51.51450620000001,-0.05711619999999999 +340,Edgware,51.61548819999999,-0.2609598 +340,Stanmore Broadway,51.6176414,-0.3095879 +340,Harrow Weald Bus Garage,51.6064297,-0.3405434 +340,Harrow,51.580559,-0.341995 +341,"Angel Road, Superstores",51.6130441,-0.0522623 +341,Northumberland Park,51.6024517,-0.0676958 +341,"Tottenham, Town Hall",51.5872187,-0.0725467 +341,West Green,51.586254,-0.0867628 +341,"Harringay, Salisbury Road",51.5814632,-0.0989471 +341,Newington Green,51.5514507,-0.0857535 +341,Islington Angel,51.5346761,-0.1042905 +341,Rosebery Avenue,51.5299565,-0.1055196 +341,Holborn Circus,51.5177959,-0.1075978 +341,Aldwych,51.5132441,-0.1172819 +341,Waterloo,51.5048541,-0.1136621 +343,City Hall,51.4309209,-0.0936496 +343,Elephant & Castle,51.4938058,-0.0977932 +343,Peckham,51.47032369999999,-0.0673872 +343,Peckham Rye,51.4657456,-0.0660497 +343,Brockley,51.46377160000001,-0.0366031 +343,New Cross Gate,51.4749904,-0.0403466 +344,Clapham Junction,51.4651737,-0.1708113 +344,Nine Elms,51.4801974,-0.1396819 +344,Vauxhall,51.4861671,-0.12172 +344,Elephant & Castle,51.4938058,-0.0977932 +344,London Bridge,51.5078788,-0.0877321 +344,Liverpool Street,51.5175001,-0.0826966 +345,Peckham,51.47032369999999,-0.0673872 +345,Camberwell Green,51.4748827,-0.0921158 +345,Brixton,51.4612794,-0.1156148 +345,Clapham Common,51.4589252,-0.1493071 +345,Clapham Junction,51.4651737,-0.1708113 +345,"Battersea, Latchmere Road",51.4646957,-0.161959 +345,"Battersea Bridge, South Side",51.4811674,-0.1725411 +345,South Kensington,51.4953291,-0.1789909 +346,Upminster Station,51.5589642,0.2506216 +346,Upminster Park Estate,51.570667,0.26893 +347,Romford Station,51.57472449999999,0.1826519 +347,Upminster,51.55591399999999,0.248894 +347,Ockendon,51.5444086,-0.0888143 +349,"Ponders End, Bus Garage",51.6452225,-0.04863729999999999 +349,Edmonton Green,51.6248126,-0.0581806 +349,Edmonton Green,51.6248126,-0.0581806 +349,"Angel, Edmonton",51.6100108,-0.0474714 +349,"Snells Park, Sainsburys",51.609054,-0.0691713 +349,"Tottenham, Town Hall",51.5872187,-0.0725467 +349,Stamford Hill,51.5696514,-0.0750199 +350,"Hayes, Asda",51.5010485,-0.4251519 +350,Stockley Park,51.5119958,-0.4500708 +350,West Drayton,51.502985,-0.4654099999999999 +350,West Drayton,51.502985,-0.4654099999999999 +350,Harmondsworth,51.487453,-0.475554 +350,Heathrow Terminal 5,51.471466,-0.4879806 +352,Bromley North,51.40833,0.01702 +352,"Beckenham, War Memorial",51.406914,-0.0320175 +352,Beckenham Junction,51.4109588,-0.0258909 +352,Lower Sydenham,51.42603219999999,-0.0325314 +353,Ramsden Estate,51.3754771,0.1224719 +353,"Orpington, Walnuts Centre",51.3773656,0.1007092 +353,"Orpington, Perry Hall Road",51.3823992,0.0998353 +353,Locksbottom,51.3673231,0.0547259 +353,Hayes Station,51.37633599999999,0.010589 +353,Forestdale,51.345018,-0.0380398 +354,Penge,51.41388490000001,-0.0570112 +354,"Beckenham, War Memorial",51.406914,-0.0320175 +354,Beckenham Junction,51.4109588,-0.0258909 +354,Bromley North,51.406025,0.013156 +355,Mitcham,51.402869,-0.166709 +355,Mitcham,51.402869,-0.166709 +355,Tooting Station,51.41986989999999,-0.16136 +355,Tooting Broadway,51.427867,-0.1678142 +355,Tooting Bec,51.436753,-0.1618404 +355,Tooting Bec,51.436753,-0.1618404 +355,Balham,51.4439889,-0.1494105 +355,Clapham Park,51.4476066,-0.1431943 +355,Brixton,51.4612794,-0.1156148 +356,Upper Sydenham,51.43066,-0.071188 +356,Forest Hill,51.4397781,-0.0546416 +356,Lower Sydenham,51.42603219999999,-0.0325314 +356,Elmers End Green,51.3987339,-0.0436577 +356,Shirley,51.3751931,-0.0488993 +357,Chingford Hatch,51.61703,-0.000263 +357,Chingford Mount,51.6185735,-0.0180318 +357,"Walthamstow, Crooked Billet",51.601088,-0.0159737 +357,Walthamstow Central,51.5830128,-0.019886 +357,Whipps Cross,51.581499,0.0001219 +357,Whipps Cross Hospital,51.5778196,0.0032545 +358,Orpington Station,51.37329,0.08911999999999999 +358,"Orpington, Walnuts Centre",51.3773656,0.1007092 +358,Green Street Green,51.3535363,0.0890088 +358,Locksbottom,51.3673231,0.0547259 +358,Bromley South,51.406025,0.013156 +358,Bromley North,51.406025,0.013156 +358,"Bromley Common, Crown Lane",51.3895022,0.0355797 +358,Park Langley,51.385466,-0.0087119 +358,Elmers End,51.39749,-0.0474767 +358,"Beckenham, War Memorial",51.406914,-0.0320175 +358,Penge,51.41388490000001,-0.0570112 +358,Crystal Palace,51.4197233,-0.0830638 +359,Purley,51.339228,-0.119711 +359,Addington Village,51.358673,-0.0312539 +360,Elephant & Castle,51.4938058,-0.0977932 +360,Vauxhall,51.4861671,-0.12172 +360,Pimlico,51.490744,-0.1403619 +360,Sloane Square,51.4927684,-0.1570174 +360,South Kensington,51.4953291,-0.1789909 +360,Royal Albert Hall,51.5009088,-0.177366 +362,Grange Hill,51.4309209,-0.0936496 +362,"Hainault, The Lowe",51.6099517,0.1092883 +362,Marks Gate,51.5901971,0.1424532 +362,Chadwell Heath,51.5722283,0.141995 +362,Little Heath,51.583227,0.120603 +362,King George Hospital,51.5802748,0.1115243 +363,Crystal Palace,51.4197233,-0.0830638 +363,Upper Sydenham,51.43066,-0.071188 +363,Honor Oak,51.4489977,-0.0457341 +363,Peckham Rye,51.4657456,-0.0660497 +363,Peckham,51.47032369999999,-0.0673872 +363,Bricklayer's Arms,51.4661409,-0.2174147 +363,Elephant & Castle,51.4938058,-0.0977932 +364,Ilford,51.556619,0.076251 +364,Ilford Broadway,51.5584078,0.07077839999999999 +364,Bennett's Castle Lane,51.5514521,0.1235038 +364,Goodmayes,51.5662262,0.1102974 +364,Dagenham East,51.5402631,0.1482103 +365,Orchard Village,51.5296853,0.1699365 +365,"South Hornchurch, Cherry Tree Lane",51.5288841,0.1890788 +365,Elm Park,51.548497,0.1999531 +365,Roneo Corner,51.5654177,0.1885364 +365,Roneo Corner,51.5654177,0.1885364 +365,Romford Station,51.57472449999999,0.1826519 +365,Romford Market,51.5790739,0.1813886 +365,"Romford, Parkside Avenue",51.5908267,0.1816681 +365,"Romford, Queens Hospital",51.5688117,0.1807796 +365,Collier Row,51.5996927,0.1745949 +365,Havering Park,51.607707,0.157121 +366,Redbridge,51.5748179,0.0507539 +366,Redbridge Station,51.5763264,0.0453986 +366,Ilford,51.556619,0.076251 +366,"Barking, London Road",51.5738007,0.1543557 +366,"East Beckton, Sainsbury's",51.5212249,0.0669226 +366,Gallions Reach Station,51.5090228,0.07172769999999999 +366,Gallions Reach Shopping Park,51.5166002,0.0783827 +366,Beckton Station,51.5144016,0.06153319999999999 +367,West Croydon,51.368451,-0.09966350000000002 +367,East Croydon,51.3769529,-0.0956895 +367,Monks Orchard,51.385291,-0.037641 +367,Elmers End,51.39749,-0.0474767 +367,Beckenham Junction,51.4109588,-0.0258909 +367,"Beckenham, High Street",51.40687,-0.0318188 +367,Bromley South,51.406025,0.013156 +367,Bromley North,51.406025,0.013156 +368,Chadwell Heath,51.5722283,0.141995 +368,Bennett's Castle Lane,51.5514521,0.1235038 +368,"Lodge Avenue, Ripple Road",51.53554829999999,0.0936497 +368,Barking,51.536563,0.075766 +368,"Barking, Harts Lane",51.5414506,0.0726712 +370,Romford Market,51.5790739,0.1813886 +370,Romford Station,51.57472449999999,0.1826519 +370,Hornchurch Town Centre,51.562254,0.218605 +370,Upminster,51.55591399999999,0.248894 +370,Corbets Tey,51.543329,0.2505335 +370,Lakeside,51.4309209,-0.0936496 +371,Kingston,51.41233,-0.300689 +371,"Kingston Hill, Queens Road",51.4386928,-0.2909764 +371,Ham,51.4299232,-0.2984002 +371,Richmond Hill,51.4539315,-0.2997198 +371,Richmond,51.46131099999999,-0.303742 +371,"Richmond, Manor Circus",51.4677844,-0.2883524 +372,Hornchurch Town Centre,51.562254,0.218605 +372,Elm Park,51.548497,0.1999531 +372,Rainham Tesco,51.5200061,0.1907802 +372,Averley,51.499018,0.2519159 +372,Wennington,51.5075862,0.2137575 +372,Lakeside,51.403305,-0.0200916 +375,Romford Station,51.57472449999999,0.1826519 +375,Passingford Bridge,51.656024,0.168335 +376,Beckton Station,51.5144016,0.06153319999999999 +376,Winsor Park,51.4818292,-0.4225758 +376,Cyprus,51.5091192,0.0633823 +376,Newham Hospital,51.5222415,0.0325405 +376,"Upton Park, Boleyn",51.5305005,0.0384915 +376,Upton Park Station,51.5353424,0.0352766 +376,"East Ham, Plashet Grove",51.540111,0.0488804 +376,"East Ham, Newham Town Hall",51.53280239999999,0.0551608 +377,"Ponders End, Bus Garage",51.6452225,-0.04863729999999999 +377,Bush Hill Park,51.6445559,-0.06559659999999999 +377,Bush Hill Park,51.6445559,-0.06559659999999999 +377,Enfield,51.6522994,-0.0807119 +377,Oakwood,51.6481224,-0.1309298 +379,Chingford Station,51.6331421,0.0098588 +379,Yardley Lane,51.6418904,-0.0087819 +380,Belmarsh,51.4967407,0.0927968 +380,Broadwater Estate,51.5944339,-0.0812275 +380,Plumstead Station,51.4896774,0.0847463 +380,Woolwich,51.4894752,0.06758829999999999 +380,Woolwich,51.4894752,0.06758829999999999 +380,Charlton Village,51.4900403,0.0307737 +380,"Blackheath, Royal Standard",51.4779946,0.0202001 +380,Blackheath Village,51.4657729,0.0091238 +380,"Lewisham, Shopping Centre",51.46175909999999,-0.0119106 +381,Peckham,51.47032369999999,-0.0673872 +381,Surrey Quays,51.4944172,-0.0383063 +381,Canada Water,51.4962989,-0.0482742 +381,Rotherhithe,51.49628999999999,-0.0411931 +381,Rotherhithe,51.49628999999999,-0.0411931 +381,"Tower Bridge Road, Druid Street",51.4996634,-0.07507899999999999 +381,Southwark Bridge Road,51.4968084,-0.1000501 +381,Waterloo,51.5048541,-0.1136621 +382,Southgate,51.62476119999999,-0.1240456 +382,Arnos Grove,51.619799,-0.1296871 +382,Hampden Square,51.6323276,-0.1417747 +382,Friern Barnet,51.6141967,-0.1540148 +382,Finchley Central,51.601633,-0.193361 +382,Millbrook Park,51.6112324,-0.2073392 +383,"Barnet, The Spires",51.655492,-0.2033422 +383,Barnet Church,51.6526856,-0.1992227 +383,New Barnet,51.649276,-0.176187 +383,Oakleigh Park,51.62524879999999,-0.1697717 +383,Totteridge & Whetstone,51.630241,-0.179144 +383,Woodside Park,51.6162352,-0.1874339 +384,"Barnet, Quinta Drive",51.6467413,-0.2233541 +384,Barnet Hospital,51.6508236,-0.2137361 +384,"Barnet, The Spires",51.655492,-0.2033422 +384,Barnet Church,51.6526856,-0.1992227 +384,"Barnet, Odeon",51.64663059999999,-0.1865655 +384,New Barnet Station,51.64857,-0.17297 +384,"New Barnet, Castlewood Road",51.6540941,-0.16659 +384,Cockfosters,51.647851,-0.151255 +385,Chingford Station,51.6331421,0.0098588 +385,"Crooked Billet, Sainsbury's",51.601088,-0.0159737 +386,Woolwich,51.4894752,0.06758829999999999 +386,Queen Elizabeth Hospital,51.4778139,0.0505587 +386,"Blackheath, Royal Standard",51.4779946,0.0202001 +386,"Woolwich Road, Vanbrugh Hill",51.48505249999999,0.0081975 +386,"Greenwich, Cutty Sark",51.4828646,-0.0095917 +386,Blackheath Village,51.4657729,0.0091238 +388,Stratford City,51.5440354,-0.0053088 +388,Hackney Wick,51.544579,-0.0256935 +388,"South Hackney, Church Crescent",51.5882451,-0.1449718 +388,Ash Grove,51.4797615,-0.3899081 +388,Liverpool Street,51.5175001,-0.0826966 +388,St. Paul's,51.5138453,-0.0983506 +388,Blackfriars,51.51199200000001,-0.1038617 +388,Elephant & Castle,51.4938058,-0.0977932 +389,"Barnet, The Spires",51.655492,-0.2033422 +389,"Barnet, Western Way",51.6405093,-0.1874788 +390,Archway,51.4309209,-0.0936496 +390,"Camden Road, Brecknock Road",51.5566952,-0.137981 +390,King's Cross,51.5347488,-0.1245845 +390,Euston,51.5239197,-0.1433825 +390,Warren Street,51.5240516,-0.1399547 +390,Warren Street,51.5240516,-0.1399547 +390,Tottenham Court Road,51.5166043,-0.1304303 +390,Oxford Circus,51.5143582,-0.1510547 +390,Marble Arch,51.5132225,-0.1588937 +390,Marble Arch,51.5132225,-0.1588937 +390,Marble Arch,51.5132225,-0.1588937 +390,Lancaster Gate,51.5115786,-0.1802482 +390,Notting Hill Gate,51.5090534,-0.1966727 +391,Richmond,51.46131099999999,-0.303742 +391,"North Sheen, Manor Circus",51.4653637,-0.2863842 +391,Kew Gardens Station,51.47714509999999,-0.2850662 +391,Chiswick Roundabout,51.4910362,-0.2816861 +391,Turnham Green,51.49203019999999,-0.2663174 +391,"Stamford Brook, Chiswick Lane",51.49492,-0.24568 +391,Stamford Brook Bus Garage,51.493069,-0.2493815 +391,Ravenscourt Park,51.4952687,-0.2397848 +391,Hammersmith,51.491187,-0.223731 +391,"North End Road, Lillie Road",51.4857738,-0.2013501 +391,Fulham Broadway,51.4801685,-0.1968672 +391,"Fulham, Sands End",51.4731566,-0.1822545 +393,Clapton Pond,51.5561061,-0.05490830000000001 +393,Clapton Pond,51.5561061,-0.05490830000000001 +393,Stoke Newington,51.561175,-0.08349229999999999 +393,Albion Road,51.5611171,-0.08349229999999999 +393,Highbury New Park,51.5598259,-0.0919793 +393,Highbury & Islington,51.5569649,-0.0979656 +393,"Holloway, Nag's Head",51.55724250000001,-0.1204364 +393,"Camden Road, Brecknock Road",51.55676690000001,-0.1382933 +393,Kentish Town,51.5516806,-0.1410992 +393,Chalk Farm,51.5444834,-0.152158 +394,Homerton Hospital,51.5478609,-0.0425903 +394,Hackney Central,51.5482344,-0.05738749999999999 +394,Ash Grove,51.4797615,-0.3899081 +394,"Hoxton, Baring Street",51.5368127,-0.0882585 +394,Islington Angel,51.5346761,-0.1042905 +395,Harrow,51.580559,-0.341995 +395,South Harrow,51.5683717,-0.3553483 +395,Northolt,51.546615,-0.373103 +395,"Greenford, Westway Cross",51.5424454,-0.3406048 +396,King George Hospital,51.5802748,0.1115243 +396,Little Heath,51.583227,0.120603 +396,Newbury Park,51.5734779,0.08897669999999999 +396,Gants Hill,51.5767812,0.0661732 +396,Ilford Broadway,51.5584078,0.07077839999999999 +397,"Crooked Billet, Sainsbury's",51.601088,-0.0159737 +397,Chingford Mount,51.6185735,-0.0180318 +397,Chingford Station,51.6331421,0.0098588 +397,Loughton,51.655942,0.068161 +397,Debden,51.5417031,0.2034589 +398,Ruislip,51.5758719,-0.421236 +398,Rayners Lane Station,51.5751034,-0.3708618 +398,South Harrow,51.5683717,-0.3553483 +398,Wood End,51.3486429,-0.1545569 +399,"Barnet, The Spires",51.655492,-0.2033422 +399,Hadley Wood Station,51.668411,-0.1764367 +401,Thamesmead,51.50575809999999,0.1100586 +401,Thamesmead East,51.50575809999999,0.1100586 +401,Belvedere,51.48516499999999,0.14827 +401,Belvedere,51.48516499999999,0.14827 +401,"Bexleyheath, Shopping Centre",51.45334099999999,0.13822 +403,West Croydon,51.368451,-0.09966350000000002 +403,Croydon Town Centre,51.3769529,-0.0956895 +403,"South Croydon, South End",51.3650199,-0.099012 +403,Sanderstead Church,51.33693299999999,-0.07585349999999999 +403,Warlingham Green,51.3093239,-0.055901 +403,Warlingham,51.3093239,-0.055901 +404,Coulsdon,51.319941,-0.141267 +404,Caterham-on-the-Hill,51.28029600000001,-0.08161589999999999 +405,Redhill,51.4210856,0.0635313 +405,Hooley,51.4309209,-0.0936496 +405,Coulsdon,51.319941,-0.141267 +405,Purley,51.339228,-0.119711 +405,"Purley Way, Colonnades",51.3563828,-0.1135816 +405,"South Croydon, South End",51.3650199,-0.099012 +405,West Croydon,51.368451,-0.09966350000000002 +406,Kingston,51.41233,-0.300689 +406,Kingston,51.41233,-0.300689 +406,Surbiton,51.39400999999999,-0.302662 +406,Tolworth,51.3801004,-0.2861237 +406,Ewell,51.38217210000001,-0.285232 +406,Epsom,51.4309209,-0.0936496 +406,Epsom Hospital,51.3251497,-0.2732057 +407,Sutton Town Centre,51.3614279,-0.193961 +407,Sutton Station,51.3596681,-0.1911606 +407,"Carshalton, High Street",51.365212,-0.1614104 +407,Beddington Library,51.3669545,-0.1318798 +407,West Croydon,51.368451,-0.09966350000000002 +407,Croydon Town Centre,51.3769529,-0.0956895 +407,Croydon Town Centre,51.3769529,-0.0956895 +407,"South Croydon, South End",51.3650199,-0.099012 +407,Purley,51.339228,-0.119711 +407,Purley,51.339228,-0.119711 +407,Whyteleafe,51.3017577,-0.079251 +407,Whyteleafe South,51.3033428,-0.0769221 +407,Caterham,51.28029600000001,-0.08161589999999999 +410,Crystal Palace,51.4197233,-0.0830638 +410,Norwood Junction,51.39731,-0.07501000000000001 +410,Davidson Road,51.3875213,-0.08113229999999999 +410,West Croydon,51.368451,-0.09966350000000002 +410,Beddington Library,51.3669545,-0.1318798 +410,Wallington,51.363978,-0.151845 +411,Kingston,51.4309209,-0.0936496 +411,"Kingston Bridge, West Side",51.4309209,-0.0936496 +411,Hampton Court,51.4036128,-0.3377623 +411,West Molesey,51.400766,-0.3562949 +412,Purley,51.339228,-0.119711 +412,Sanderstead Church,51.33693299999999,-0.07585349999999999 +412,Sanderstead Church,51.33693299999999,-0.07585349999999999 +412,Selsdon,51.34372279999999,-0.061975 +412,"South Croydon, South End",51.3650199,-0.099012 +412,Croydon Town Centre,51.3769529,-0.0956895 +412,West Croydon,51.368451,-0.09966350000000002 +413,"Sutton, Bushey Road",51.3697877,-0.1980526 +413,Lower Morden,51.3893002,-0.2219715 +413,Morden,51.394943,-0.19446 +414,Putney Bridge,51.4669712,-0.2129034 +414,Fulham Palace Road,51.4789858,-0.2177446 +414,Fulham Broadway,51.4799723,-0.1956774 +414,Chelsea & Westminster Hospital,51.4839583,-0.1813397 +414,South Kensington,51.4953291,-0.1789909 +414,Hyde Park Corner,51.5029347,-0.1508562 +414,Marble Arch,51.5132225,-0.1588937 +414,Edgware Road Station,51.51988249999999,-0.1678336 +414,Warwick Avenue,51.5063258,-0.3039068 +414,"Maida Hill, The Chippenham",51.5243627,-0.2017331 +415,Tulse Hill Station,51.43986,-0.10505 +415,Brixton,51.4612794,-0.1156148 +415,Brixton,51.4612794,-0.1156148 +415,Kennington Church,51.50875809999999,-0.1954048 +415,"Old Kent Road, Tesco",51.4854662,-0.0700918 +417,Crystal Palace,51.4197233,-0.0830638 +417,"Norwood, Crown Point",51.4309209,-0.0936496 +417,"Crown Dale, Norwood School",51.4228251,-0.0995052 +417,"Crown Dale, Norwood School",51.4228251,-0.0995052 +417,Streatham Hill Station,51.4382009,-0.1270706 +417,Clapham Park,51.4476066,-0.1431943 +417,Clapham Common,51.4556465,-0.1385544 +418,Kingston,51.41233,-0.300689 +418,Kingston,51.41233,-0.300689 +418,Surbiton,51.39400999999999,-0.302662 +418,Tolworth,51.3801004,-0.2861237 +418,Epsom,51.4309209,-0.0936496 +419,Richmond,51.46131099999999,-0.303742 +419,"Mortlake, High Street",51.4698327,-0.2611355 +419,Hammersmith,51.491187,-0.223731 +422,North Greenwich,51.4859576,0.007494900000000001 +422,East Greenwich,51.4859576,0.007494900000000001 +422,"Blackheath, Royal Standard",51.4779946,0.0202001 +422,Woolwich,51.4894752,0.06758829999999999 +422,Woolwich,51.4894752,0.06758829999999999 +422,Plumstead,51.4873853,0.08650139999999999 +422,"East Wickham, Brampton Road",51.4771799,0.1236485 +422,"Bexleyheath, Shopping Centre",51.45334099999999,0.13822 +422,"Bexleyheath, Bus Garage",51.46006930000001,0.1534245 +423,"Hounslow, Bus Station",51.4708688,-0.3546457 +423,"Hounslow, Bell Corner",51.468569,-0.3666325 +423,Hounslow Heath,51.4563954,-0.3849625 +423,Hatton Cross,51.4651031,-0.4157165 +423,"Bath Road, Nobel Drive",51.4806378,-0.4287598 +423,"Bath Road, Sipson Road",51.4876827,-0.4558443 +423,"Bath Road, Hatch Lane",51.4816932,-0.475493 +423,Heathrow Terminal 5,51.471466,-0.4879806 +424,Putney Heath,51.4524424,-0.2298485 +424,Putney Station,51.4611807,-0.2164913 +424,Putney High Street,51.4632453,-0.2158717 +424,Putney Bridge,51.4669712,-0.2129034 +424,Hurlingham,51.4701125,-0.2048867 +424,Fulham Broadway,51.4799723,-0.1956774 +424,"Fulham, Craven Cottage",51.47490029999999,-0.2216078 +424,"Fulham, Craven Cottage",51.47490029999999,-0.2216078 +425,Stratford,51.5426313,-0.0010369 +425,Bow Church,51.5287753,-0.0167013 +425,Mile End,51.52354529999999,-0.0330122 +425,"Hackney, Lauriston Road",51.5394045,-0.0455494 +425,Homerton Hospital,51.5478609,-0.0425903 +425,Clapton Pond,51.5561061,-0.05490830000000001 +425,"Clapton, Nightingale Road",51.5589881,-0.0597757 +427,Uxbridge,51.5485,-0.479611 +427,Coney Green,51.534156,-0.4588592 +427,Hayes End,51.5257,-0.4357732 +427,Hayes By-Pass,51.51593,-0.398889 +427,"Southall, Town Hall",51.5113272,-0.3751471 +427,Southall Park,51.5094438,-0.3697251 +427,Ealing Hospital,51.5075205,-0.3465216 +427,Ealing Broadway,51.5146192,-0.3022912 +427,"Acton, High Street",51.5083364,-0.2761329 +428,Erith,51.480818,0.174675 +428,Slade Green,51.4695282,0.1928854 +428,Crayford,51.4501131,0.1822046 +428,Crayford,51.4501131,0.1822046 +428,Dartford,51.44621,0.216872 +428,Dartford,51.44621,0.216872 +428,Darenth Valley Hospital,51.4353592,0.2586714 +428,Bluewater,51.4309209,-0.0936496 +430,"Roehampton, Danebury Avenue",51.4524056,-0.2483895 +430,Roehampton,51.4484339,-0.2397592 +430,Putney High Street,51.4596431,-0.2141257 +430,Putney Bridge,51.4669712,-0.2129034 +430,West Brompton,51.483494,-0.196802 +430,South Kensington,51.4953291,-0.1789909 +432,Brixton,51.4612794,-0.1156148 +432,Tulse Hill Station,51.43986,-0.10505 +432,West Norwood,51.427905,-0.1002486 +432,West Norwood,51.427905,-0.1002486 +432,Crystal Palace,51.4197233,-0.0830638 +432,Anerley Station,51.4121559,-0.06571779999999999 +433,Addington Village,51.358673,-0.0312539 +433,Selsdon,51.34372279999999,-0.061975 +433,East Croydon,51.3769529,-0.0956895 +433,East Croydon,51.3769529,-0.0956895 +433,West Croydon,51.368451,-0.09966350000000002 +434,"Coulsdon, Ridgemount Avenue",51.3140905,-0.1559805 +434,Coulsdon,51.319941,-0.141267 +434,Purley,51.339228,-0.119711 +434,Purley,51.339228,-0.119711 +434,Purley,51.339228,-0.119711 +434,Whyteleafe South,51.3033428,-0.0769221 +436,"Lewisham, Shopping Centre",51.46175909999999,-0.0119106 +436,Lewisham Station,51.4652098,-0.0131213 +436,"Lewisham, Jerrard Street",51.4653963,-0.0162157 +436,New Cross Gate,51.4749904,-0.0403466 +436,Peckham,51.47032369999999,-0.0673872 +436,Camberwell Green,51.4741388,-0.09304699999999999 +436,Vauxhall,51.4861671,-0.12172 +436,Battersea Park Station,51.47696,-0.14751 +440,Chiswick Power Road,51.4933973,-0.2809573 +440,Turnham Green,51.49203019999999,-0.2663174 +440,"Acton, High Street",51.50850639999999,-0.2770654 +440,"Acton, Horn Lane",51.5193766,-0.2653401 +440,North Acton,51.5219526,-0.2580821 +440,"Park Royal, Asda",51.52781,-0.26989 +440,Stonebridge Park,51.5445824,-0.2608244 +444,Turnpike Lane Station,51.5904278,-0.1027587 +444,Lordship Lane,51.44687709999999,-0.07245370000000001 +444,North Middlesex Hospital,51.6131618,-0.0735832 +444,"Hall Lane, Cork Tree Retail Park",51.6130849,-0.03223 +444,"Angel Road, Eleys Estate",51.6169024,-0.0460262 +444,"Edmonton, Angel",51.6100108,-0.0474714 +444,"Edmonton, Sterling Way",51.6146137,-0.0702872 +444,Chingford Mount,51.6185735,-0.0180318 +444,Chingford Hatch,51.61703,-0.000263 +444,Chingford Station,51.6331421,0.0098588 +450,West Croydon,51.368451,-0.09966350000000002 +450,"Thornton Heath, High Street",51.3976238,-0.0930168 +450,Upper Norwood,51.41376716037048, -0.09204081941649297 +450,Crystal Palace,51.4197233,-0.0830638 +450,"Westwood Hill, Fountain Drive",51.4268086,-0.0652016 +450,Sydenham,51.4267225,-0.0412072 +450,Lower Sydenham,51.42603219999999,-0.0325314 +452,Kensal Rise,51.5345071,-0.2250186 +452,"Ladbroke Grove, Sainsbury's",51.5256365,-0.215718 +452,Notting Hill Gate,51.5090534,-0.1966727 +452,Royal Albert Hall,51.5009088,-0.177366 +452,Knightsbridge,51.4991195,-0.1644394 +452,Sloane Square,51.4927684,-0.1570174 +452,Sloane Square,51.4927684,-0.1570174 +452,Battersea Park Station,51.47696,-0.14751 +452,Queenstown Road Station,51.4749596,-0.1466578 +452,Vauxhall,51.4861671,-0.12172 +453,Deptford Bridge,51.4744304,-0.0224546 +453,New Cross Gate,51.4749904,-0.0403466 +453,"Old Kent Road, Tesco",51.4854662,-0.0700918 +453,Bricklayer's Arms,51.4661322,-0.2166946 +453,Elephant & Castle,51.4938058,-0.0977932 +453,Lambeth North,51.4989177,-0.1121086 +453,Parliament Square,51.5010421,-0.1268514 +453,"Whitehall, Horse Guards",51.5049111,-0.1273704 +453,Piccadilly Circus,51.5099734,-0.13497 +453,Oxford Circus,51.5137535,-0.1539375 +453,Great Portland Street,51.5236775,-0.1441862 +453,Baker Street Station,51.5231548,-0.156863 +453,Marylebone,51.5188746,-0.1498955 +455,"Purley, Old Lodge Lane",51.3156465,-0.1147698 +455,Purley,51.339228,-0.119711 +455,Purley,51.339228,-0.119711 +455,"South Croydon, South End",51.3650199,-0.099012 +455,Croydon Town Centre,51.3769529,-0.0956895 +455,Croydon Town Centre,51.3769529,-0.0956895 +455,West Croydon,51.368451,-0.09966350000000002 +455,Valley Park,51.4309209,-0.0936496 +455,"Beddington, Asda",51.375982,-0.1309075 +455,Beddington Library,51.3669545,-0.1318798 +455,Roundshaw,51.3533066,-0.1269329 +455,Wallington Station,51.36038,-0.15081 +460,"Willesden, Bus Garage",51.5474482,-0.2394372 +460,Cricklewood Broadway,51.5600397,-0.2190578 +460,Golders Green,51.5740013,-0.1987725 +460,"Finchley, Church End",51.604606,-0.1882833 +460,North Finchley,51.6135087,-0.1754198 +462,Limes Farm Estate,51.4309209,-0.0936496 +462,Grange Hill,51.4309209,-0.0936496 +462,"Barkingside, Fullwell Cross",51.59451199999999,0.08571999999999999 +462,Gants Hill,51.5767812,0.0661732 +462,Ilford,51.556619,0.076251 +463,Coulsdon South,51.31583,-0.13786 +463,Clockhouse Farm,51.4309209,-0.0936496 +463,Wallington,51.363978,-0.151845 +463,"Beddington, Asda",51.375982,-0.1309075 +463,Eastfields,51.4076056,-0.1545941 +463,Pollards Hill,51.4000406,-0.1332582 +464,Tatsfield,51.290898,0.02795 +464,Biggin Hill,51.312059,0.032802 +464,New Addington,51.348184,-0.017094 +465,Kingston,51.41233,-0.300689 +465,Hook Junction,51.3751056,-0.3042808 +465,Hook Junction,51.3751056,-0.3042808 +465,Chessington,51.363583,-0.296254 +465,Leatherhead,51.33560139999999,-0.3202492 +465,Dorking,51.232202,-0.332378 +466,Addington Village,51.358673,-0.0312539 +466,"Addiscombe Road, Shirley Road",51.3750364,-0.0761587 +466,Croydon Town Centre,51.3769529,-0.0956895 +466,Croydon Town Centre,51.3769529,-0.0956895 +466,"South Croydon, Bus Garage",51.3544903,-0.0968822 +466,Purley,51.339228,-0.119711 +466,Purley,51.339228,-0.119711 +466,Old Coulsdon,51.298482,-0.114175 +466,"Coulsdon, Lacey Drive",51.2994337,-0.1144192 +466,Caterham-on-the-Hill,51.28029600000001,-0.08161589999999999 +467,Hinchley Wood School,51.37953599999999,-0.3322176 +467,Hook,51.3682509,-0.305081 +467,Copt Gilders,51.35919000000001,-0.29498 +467,Ewell,51.3805035,-0.2803562 +467,Epsom,51.4309209,-0.0936496 +467,Epsom Hospital,51.3251497,-0.2732057 +468,"South Croydon, South End",51.3650199,-0.099012 +468,Croydon Town Centre,51.3769529,-0.0956895 +468,"Thornton Heath, High Street",51.3976238,-0.0930168 +468,Upper Norwood,51.41376716037048, -0.09204081941649297 +468,Tulse Hill Station,51.43986,-0.10505 +468,Herne Hill,51.4609208,-0.0985404 +468,Herne Hill,51.4609208,-0.0985404 +468,Camberwell Green,51.4741388,-0.09304699999999999 +468,Elephant & Castle,51.4938058,-0.0977932 +469,Queen Elizabeth Hospital,51.4778139,0.0505587 +469,Woolwich,51.4894752,0.06758829999999999 +469,Abbey Wood,51.4926116,0.1188182 +469,Belvedere,51.48516499999999,0.14827 +469,Erith,51.480818,0.174675 +470,Colliers Wood,51.41704439999999,-0.1778555 +470,Morden,51.394943,-0.19446 +470,Sutton Town Centre,51.3614279,-0.193961 +470,Sutton Station,51.3596681,-0.1911606 +470,Cheam,51.3619271,-0.2189255 +470,Ewell,51.3812341,-0.2811869 +470,Ewell East,51.3452748,-0.2415609 +470,Epsom,51.4309209,-0.0936496 +472,North Greenwich,51.4859576,0.007494900000000001 +472,Charlton,51.4900403,0.0307737 +472,Charlton,51.4900403,0.0307737 +472,Woolwich,51.4894752,0.06758829999999999 +472,Woolwich,51.4894752,0.06758829999999999 +472,Plumstead Station,51.4896774,0.0847463 +472,"Thamesmead, Boiler House",51.50575809999999,0.1100586 +472,Thamesmead,51.50575809999999,0.1100586 +473,North Woolwich,51.5008658,0.0626916 +473,London City Airport,51.5048437,0.049518 +473,Prince Regent,51.4309209,-0.0936496 +473,"Plaistow, Greengate Street",51.527444,0.027621 +473,Plaistow,51.5268317,0.0308143 +473,Stratford,51.5426313,-0.0010369 +474,"Canning Town, Barking Road",51.52364720000001,0.0258453 +474,Canning Town,51.5189494,0.0132 +474,London City Airport,51.5048437,0.049518 +474,North Woolwich,51.5008658,0.0626916 +474,Cyprus,51.5091192,0.0633823 +474,Beckton Station,51.5144016,0.06153319999999999 +474,Beckton Alps,51.5192628,0.0612645 +474,"East Ham, Central Park",51.5293175,0.0527634 +474,"East Ham, Newham Town Hall",51.53280239999999,0.0551608 +474,East Ham,51.5333972,0.04991139999999999 +474,Manor Park,51.550487,0.0514117 +476,Northumberland Park,51.6024517,-0.0676958 +476,"Tottenham, Town Hall",51.5872187,-0.0725467 +476,Stamford Hill,51.5696514,-0.0750199 +476,Stoke Newington,51.561175,-0.08349229999999999 +476,Albion Road,51.5609591,-0.0832395 +476,Newington Green,51.5514507,-0.0857535 +476,Islington Angel,51.5346761,-0.1042905 +476,King's Cross,51.5347488,-0.1245845 +476,Euston,51.5239197,-0.1433825 +481,Kingston,51.41233,-0.300689 +481,Teddington,51.4268694,-0.3338681 +481,"Fulwell, Stanley Road",51.43500909999999,-0.3471814 +481,"Ivybridge, Tesco",51.4309209,-0.0936496 +481,West Middlesex Hospital,51.4734184,-0.3244425 +482,"Southall, Town Hall",51.5113272,-0.3751471 +482,"Southall, The Green",51.5035525,-0.3802476 +482,Convent Way,51.4933467,-0.3886524 +482,Hounslow West,51.469435,-0.3837709 +482,Hatton Cross,51.4651031,-0.4157165 +482,Heathrow Terminal 4,51.4596965,-0.4473622 +482,Heathrow Terminal 5,51.471466,-0.4879806 +483,Ealing Hospital,51.5075205,-0.3465216 +483,Ealing Broadway,51.5146192,-0.3022912 +483,Ealing Broadway,51.5146192,-0.3022912 +483,"Alperton, Sainsbury's",51.5383862,-0.3028583 +483,Alperton,51.539601,-0.2988365 +483,Wembley Stadium Station,51.55418960000001,-0.286004 +483,Northwick Park Hospital,51.5753935,-0.3201711 +483,North Wembley,51.5625616,-0.3175595 +483,Harrow,51.580559,-0.341995 +484,Lewisham Station,51.4652098,-0.0131213 +484,Ladywell,51.45589709999999,-0.0219523 +484,Brockley Cross,51.465303,-0.0363334 +484,Frendsbury Road,51.4602263,-0.0435112 +484,Peckham Rye,51.45848609999999,-0.0541815 +484,East Dulwich,51.4545635,-0.0732101 +484,Camberwell Green,51.4741388,-0.09304699999999999 +485,Hammersmith,51.491187,-0.223731 +485,Barnes Pond,51.4731208,-0.2468688 +485,Putney Common,51.4676836,-0.228221 +485,Wandsworth,51.45837299999999,-0.1891356 +486,North Greenwich,51.4859576,0.007494900000000001 +486,Charlton,51.4900403,0.0307737 +486,Queen Elizabeth Hospital,51.4778139,0.0505587 +486,"Shooters Hill, Eaglesfield Road",51.4668419,0.0810982 +486,"Shooters Hill, Eaglesfield Road",51.4668419,0.0810982 +486,Welling Corner,51.4626258,0.1081541 +486,"Bexleyheath, Shopping Centre",51.45334099999999,0.13822 +487,South Harrow,51.5683717,-0.3553483 +487,Northolt Park,51.555711,-0.3594899 +487,"Alperton, Sainsbury's",51.5383862,-0.3028583 +487,Hanger Lane Station,51.530061,-0.2929893000000001 +487,North Acton,51.5219526,-0.2580821 +487,North Acton,51.5219526,-0.2580821 +487,Central Middlesex Hospital,51.530944,-0.2690778 +487,Willesden Junction,51.53211630000001,-0.2433689 +488,Bromley-By-Bow Tesco,51.5266315,-0.0097847 +488,Bow Church,51.5287753,-0.0167013 +488,Hackney Wick,51.544579,-0.0256935 +488,Homerton Hospital,51.5478609,-0.0425903 +488,Clapton Pond,51.5561061,-0.05490830000000001 +488,Dalston Junction,51.5459999,-0.0751485 +490,"Richmond, Pools on the Park",51.4650191,-0.306508 +490,Richmond,51.46131099999999,-0.303742 +490,Richmond Bus Station,51.4591284,-0.3044753000000001 +490,Twickenham,51.4453043,-0.3375429 +490,Feltham Station,51.4480215,-0.4090095 +490,"Hanworth, , Apex Corner",51.4369075,-0.3784005 +490,Hatton Cross,51.4651031,-0.4157165 +490,Heathrow Terminal 4,51.4596965,-0.4473622 +490,Heathrow Cargo Area,51.46351809999999,-0.4558444 +490,Heathrow Terminal 5,51.471466,-0.4879806 +491,Waltham Cross,51.68584389999999,-0.0330964 +491,Enfield Island Village,51.66612199999999,-0.015382 +491,Innova Business Park,51.6768385,-0.0221269 +491,"Brimsdown, Suez Road",51.6526403,-0.029266 +491,Edmonton Green,51.6248126,-0.0581806 +491,North Middlesex Hospital,51.6131618,-0.0735832 +492,Sidcup Station,51.4339345,0.1038351 +492,Foots Cray,51.4174447,0.1210622 +492,Bexley Village,51.439933,0.154327 +492,"Bexleyheath, Shopping Centre",51.45334099999999,0.13822 +492,Crayford,51.4501131,0.1822046 +492,Dartford,51.44621,0.216872 +492,Dartford,51.44621,0.216872 +492,Bluewater,51.4309209,-0.0936496 +493,"Tooting, St George's Hospital",51.42656299999999,-0.1752284 +493,Wimbledon Stadium,51.41833889999999,-0.2206288 +493,Wimbledon,51.41833889999999,-0.2206288 +493,Wimbledon,51.41833889999999,-0.2206288 +493,Wimbledon,51.41833889999999,-0.2206288 +493,Wimbledon Village,51.41833889999999,-0.2206288 +493,Putney Heath,51.4524424,-0.2298485 +493,Barnes Common,51.4681254,-0.2413995 +493,"East Sheen, Queen's Road",51.4663301,-0.2595362 +493,Richmond,51.46131099999999,-0.303742 +493,"Richmond, Manor Circus",51.4677844,-0.2883524 +496,Harold Wood,51.5910397,0.2328613 +496,"Harold Hill, Dagnam Park Square",51.6049149,0.2445527 +496,Gallows Corner,51.59188200000001,0.214546 +496,"Gallows Corner, Main Road",51.5922565,0.2142701 +496,Romford Station,51.57472449999999,0.1826519 +496,Romford Market,51.5790739,0.1813886 +496,"Romford, Queen's Hospital",51.5688117,0.1807796 +498,"Romford, Queen's Hospital",51.5688117,0.1807796 +498,Romford Station,51.57472449999999,0.1826519 +498,Harold Wood,51.5910397,0.2328613 +498,Brentwood,51.4309209,-0.0936496 +499,"Gallows Corner, Tesco",51.5922522,0.219687 +499,Romford Market,51.5790739,0.1813886 +499,Romford Station,51.57472449999999,0.1826519 +499,Romford Queens Hospital,51.5688117,0.1807796 +499,Heath Park Estate,51.5664718,0.1367814 +507,Waterloo,51.5048541,-0.1136621 +507,Millbank,51.4917605,-0.1298473 +507,Victoria,51.49554149999999,-0.1435602 +508,Wansted Park,51.568725,0.0433573 +508,Stratford City,51.5440354,-0.0053088 +521,Waterloo,51.5048541,-0.1136621 +521,Aldwych,51.5132441,-0.1172819 +521,Holborn,51.5175802,-0.1145147 +521,St. Paul's,51.5138453,-0.0983506 +521,London Bridge,51.5078788,-0.0877321 +541,Keir Hardie Estate,51.5678758,-0.0607466 +541,Prince Regent,51.4309209,-0.0936496 +549,South Woodford,51.5912671,0.0264721 +549,Buckhurst Hill,51.627572,0.034513 +549,Loughton,51.655942,0.068161 +601,Thamesmead,51.50575809999999,0.1100586 +601,Bexley,51.439933,0.154327 +601,Wilmington Schools,51.4309209,-0.0936496 +601,Wilmington Schools,51.4309209,-0.0936496 +602,Thamesmead,51.50575809999999,0.1100586 +602,Townley Grammar School,51.4505566,0.1410445 +603,Muswell Hill,51.5911816,-0.1443015 +603,Swiss Cottage,51.5425872,-0.1724737 +605,Edgware,51.61548819999999,-0.2609598 +605,Burnt Oak Station,51.6028241,-0.2640713 +605,Mill Hill County High School,51.6301469,-0.2484735 +605,Totteridge & Whetstone Station,51.63030699999999,-0.1782731 +606,Queensbury,51.5942132,-0.2853683 +606,Edgware,51.61548819999999,-0.2609598 +606,Barnet Church,51.6526856,-0.1992227 +606,Totteridge Academy,51.6393804,-0.1997726 +607,Uxbridge,51.5485,-0.479611 +607,Hillingdon Heath,51.5302584,-0.4469482 +607,"Hayes End, Angel Lane",51.5257,-0.4357732 +607,"Southall, Town Hall",51.5113272,-0.3751471 +607,Ealing Hospital,51.5075205,-0.3465216 +607,Ealing Broadway,51.5146192,-0.3022912 +607,"Acton, High Street",51.5083364,-0.2761329 +607,"Acton, High Street",51.5083364,-0.2761329 +607,Acton Vale,51.5065594,-0.2567913 +607,White City,51.51146199999999,-0.2376332 +608,Gallows Corner,51.59188200000001,0.214546 +608,Shenfield High School,51.6383612,0.3294556 +609,Mortlake,51.4687363,-0.2627417 +609,Harrodian School,51.4817443,-0.2469094 +609,Hammersmith,51.491187,-0.223731 +611,East Finchley Schools,51.592468,-0.1664342 +611,Stonebridge Park,51.5445824,-0.2608244 +612,Selsdon,51.34372279999999,-0.061975 +612,Wallington Grammar School,51.3692254,-0.1488237 +613,Glenthorne School,51.38058789999999,-0.2004546 +613,Tolworth,51.3801004,-0.2861237 +616,Edmonton Green,51.6248126,-0.0581806 +616,Winchmore Hill,51.6320279,-0.09580219999999999 +617,Turnpike Lane Station,51.5904278,-0.1027587 +617,St Ignatius College,51.6739451,-0.0549748 +618,Mill Hill Broadway,51.6129292,-0.2487871 +618,Avanti House School,51.60847620000001,-0.3036894 +619,Edgware Station,51.6134923,-0.2753661 +619,Avanti House School,51.60847620000001,-0.3036894 +621,Lewisham Station,51.4652098,-0.0131213 +621,Crown Woods School,51.4538453,0.07588829999999999 +624,Grove Park,51.4329249,0.021203 +624,Crown Woods College,51.4538453,0.07588829999999999 +624,Welling Corner,51.4626258,0.1081541 +625,Plumstead Common,51.4829577,0.07860199999999999 +625,"Chislehurst, War Memorial",51.4124839,0.07390759999999999 +626,Finchley Central,51.601633,-0.193361 +626,Dame Alice Owen's School,51.6907953,-0.2071661 +627,Worcester Park,51.38029,-0.24468 +627,Wallington High School,51.3692254,-0.1488237 +628,"Kingsbury, The Mall",51.5853499,-0.2782546 +628,Southgate,51.62476119999999,-0.1240456 +629,Wood Green,51.5971722,-0.1098021 +629,St Ignatius College,51.6739451,-0.0549748 +631,Golders Green,51.5740013,-0.1987725 +631,Henrietta Barnett School,51.5812815,-0.1886809 +632,"Grahame Park, Corner Mead",51.6017283,-0.2444205 +632,Cricklewood Broadway,51.5600397,-0.2190578 +632,Kilburn Park,51.53504119999999,-0.1938988 +633,Coulsdon South,51.31583,-0.13786 +633,Beddington Church,51.3692339,-0.1270687 +634,Muswell Hill,51.5911816,-0.1443015 +634,"Barnet, Arkley Hotel",51.6522231,-0.2204527 +635,St. Paul's School,51.4884697,-0.2387089 +635,Hounslow Bus Station,51.4708688,-0.3546457 +636,Kemnal Technology College,51.4121053,0.1104831 +636,Grove Park,51.4329249,0.021203 +637,Kemnal Technology College,51.4121053,0.1104831 +637,Grove Park,51.4329249,0.021203 +638,Coney Hall,51.3711435,-0.0014082 +638,Bromley South,51.406025,0.013156 +638,Bromley South,51.406025,0.013156 +638,Bromley North,51.406025,0.013156 +638,Grove Park,51.4329249,0.021203 +638,Eltham College,51.43804009999999,0.038777 +638,Beaverwood School,51.418709,0.089561 +638,Kemnal Technology College,51.4121053,0.1104831 +639,"Roehampton, Danebury Avenue",51.4524056,-0.2483895 +639,St John Bosco College,51.4750653,-0.1714743 +640,Bentley Wood School,51.6173654,-0.3323515 +640,South Harrow,51.5683717,-0.3553483 +641,West Molesey,51.400766,-0.3562949 +641,Teddington Schools,51.423413,-0.3112775 +642,West Hendon Broadway,51.5803328,-0.2424749 +642,London Academy,51.6227086,-0.2894634 +643,Brent Cross,51.5763589,-0.2236956 +643,East Finchley Schools,51.592468,-0.1664342 +646,Noak Hill,51.6218055,0.2263263 +646,Cranham,51.5679469,0.2673702 +648,Romford Market,51.5790739,0.1813886 +648,Cranham,51.5679469,0.2673702 +649,"Romford, Parkside Avenue",51.5885038,0.1772523 +649,Campion School,51.5813295,0.2311271 +650,"Romford, Parkside Avenue",51.5885038,0.1772523 +650,Emerson Park School,51.5692864,0.2427946 +651,Romford Station,51.57472449999999,0.1826519 +651,Bower Park School,51.6054757,0.1802434 +652,"Rainham, Abbey Wood Lane",51.5292975,0.2137483 +652,Upminster,51.55591399999999,0.248894 +653,Muswell Hill,51.5911816,-0.1443015 +653,"Kingsbury, The Mall",51.5853499,-0.2782546 +654,Addington Village,51.358673,-0.0312539 +654,Ramsden Estate,51.3754771,0.1224719 +655,Mitcham,51.402869,-0.166709 +655,Raynes Park High School,51.4032764,-0.2394806 +656,Emerson Park School,51.5692864,0.2427946 +656,"Gallows Corner, Tesco",51.5922522,0.219687 +657,"Crooked Billet, Sainsbury's",51.601088,-0.0159737 +657,Bancroft's School,51.6196768,0.0266543 +658,Crown Woods College,51.4538453,0.07588829999999999 +658,Woolwich,51.4894752,0.06758829999999999 +660,"Bellingham, Catford Bus Garage",51.434704,-0.017839 +660,Crown Woods School,51.4538453,0.07588829999999999 +661,Petts Wood,51.389636,0.08195 +661,"Chislehurst, War Memorial",51.4124839,0.07390759999999999 +662,Surbiton Station,51.39255679999999,-0.3044465 +662,Holy Cross School,51.3979182,-0.2616608 +663,Thornton Heath Station,51.3985835,-0.1000937 +663,"Purley, Harris Academy",51.353583,-0.1092537 +664,Charles Darwin School,51.3161242,0.0438115 +664,"New Addington, Homestead Way",51.3353819,-0.010778 +665,Surbiton,51.39400999999999,-0.302662 +665,Holy Cross School,51.3979182,-0.2616608 +667,Ilford,51.556619,0.076251 +667,West Hatch School,51.6124802,0.0629344 +669,Thamesmead,51.50575809999999,0.1100586 +669,Erith Station,51.4816474,0.1753649 +669,Cleeve Park School,51.4289531,0.1195632 +670,"Roehampton, Danebury Avenue",51.4524056,-0.2483895 +670,St John Bosco College,51.4750653,-0.1714743 +671,Tiffin Girls' School,51.4251983,-0.3030517 +671,Chessington South,51.3565368,-0.3080208 +672,NO BLIND DESCRIPTION (Departs only),51.4309209,-0.0936496 +672,Woolwich,51.4894752,0.06758829999999999 +673,NO BLIND DESCRIPTION (Departs only),51.4309209,-0.0936496 +673,Beckton Station,51.5144016,0.06153319999999999 +674,"Harold Hill, Dagnam Park Square",51.6049149,0.2445527 +674,Romford Station,51.57472449999999,0.1826519 +675,St James Street,51.5064993,-0.1393328 +675,Woodbridge School,51.4309209,-0.0936496 +678,Stratford,51.5426313,-0.0010369 +678,NO BLIND DESCRIPTION (Departs only),51.4309209,-0.0936496 +678,NO BLIND DESCRIPTION (Departs only),51.4309209,-0.0936496 +678,Beckton Station,51.5144016,0.06153319999999999 +679,NO BLIND DESCRIPTION (Departs only),51.4309209,-0.0936496 +679,Woodford Wells,51.6148389,0.0281739 +679,Ilford,51.556619,0.076251 +679,Goodmayes,51.5662262,0.1102974 +681,"Hounslow, Bus Station",51.4708688,-0.3546457 +681,Teddington Schools,51.423413,-0.3112775 +683,Friern Barnet,51.6141967,-0.1540148 +683,"Kingsbury, The Mall",51.5853499,-0.2782546 +684,Orpington Station,51.37329,0.08911999999999999 +684,Charles Darwin School,51.3161242,0.0438115 +685,NO BLIND DESCRIPTION (Departs only),51.4309209,-0.0936496 +685,Selsdon,51.34372279999999,-0.061975 +686,St Edward's School,51.4309209,-0.0936496 +686,Romford Market,51.5790739,0.1813886 +686,"Harold Hill, Dagnam Park Square",51.6049149,0.2445527 +686,Romford Station,51.57472449999999,0.1826519 +687,Dagenham Park School,51.5402631,0.1482103 +687,Barking,51.536563,0.075766 +688,Southgate,51.62476119999999,-0.1240456 +688,"Kingsbury, The Mall",51.5853499,-0.2782546 +689,West Croydon,51.3769529,-0.0956895 +689,Monks Orchard,51.385291,-0.037641 +690,West Norwood,51.427905,-0.1002486 +690,Burntwood School,51.4383279,-0.1797715 +692,NO BLIND DESCRIPTION (Departs only),51.4309209,-0.0936496 +692,Winchmore Hill,51.6320279,-0.09580219999999999 +696,"Hayes, Bourne Avenue",51.5026304,-0.438024 +696,Bishop Ramsey School,51.5792096,-0.4080951 +697,"Hayes End, Lansbury Drive",51.537245,-0.423534 +697,Ickenham,51.563966,-0.442299 +698,West Drayton,51.502985,-0.4654099999999999 +698,Ickenham,51.563966,-0.442299 +699,Winchmore Hill,51.6320279,-0.09580219999999999 +699,Southgate,51.62476119999999,-0.1240456 +699,Dame Alice Owen's School,51.6907953,-0.2071661 +965,Riverhill,51.3768604,-0.2692885 +965,"Kingston, Sainsburys",51.4098232,-0.303191 +969,"Whitton, Gladstone Avenue",51.5961721,-0.1019864 +969,Roehampton Vale,51.4388194,-0.2491381 +A10,Uxbridge,51.5485,-0.479611 +A10,Coney Green,51.5979514,-0.0744009 +A10,Stockley Business Park,51.5979514,-0.0744009 +A10,Stockley Park,51.51153850000001,-0.444799 +A10,Heathrow Central,51.5979514,-0.0744009 +B11,"Bexleyheath, Bus Garage",51.45334099999999,0.13822 +B11,"Bexleyheath, Shopping Centre",51.45334099999999,0.13822 +B11,East Wickham,51.474263,0.112381 +B11,East Wickham,51.474263,0.112381 +B11,Abbey Wood,51.4926116,0.1188182 +B11,"Thamesmead, Boiler House",51.50575809999999,0.1100586 +B11,Thamesmead,51.50575809999999,0.1100586 +B12,Erith,51.480818,0.174675 +B12,"Bexleyheath, Shopping Centre",51.45334099999999,0.13822 +B12,"Bexleyheath, Shopping Centre",51.45334099999999,0.13822 +B12,Bexley Village,51.439933,0.154327 +B12,Joydens Wood,51.4269166,0.1566507 +B12,Joydens Wood,51.4269166,0.1566507 +B12,Joydens Wood,51.4269166,0.1566507 +B13,"Bexleyheath, Shopping Centre",51.45334099999999,0.13822 +B13,"Avery Hill Road,Halfway Street",51.4449166,0.0820603 +B13,New Eltham,51.4322522,0.0658314 +B14,"Bexleyheath, Shopping Centre",51.45334099999999,0.13822 +B14,Blendon,51.44663509999999,0.1240471 +B14,Queen Mary's Hospital,51.4556562,-0.2426609 +B14,St. Mary Cray,51.385993,0.113061 +B14,Orpington,51.374843,0.09421399999999999 +B14,Orpington,51.374843,0.09421399999999999 +B14,Orpington Station,51.37329,0.08911999999999999 +B15,"Bexleyheath, Shopping Centre",51.45334099999999,0.13822 +B15,Welling Corner,51.4622529,0.109744 +B15,Welling Corner,51.4622529,0.109744 +B15,Eltham Church,51.4506338,0.0570862 +B15,Horn Park,51.45056599999999,0.029106 +B16,"Bexleyheath, Bus Garage",51.45334099999999,0.13822 +B16,"Bexleyheath, Shopping Centre",51.45334099999999,0.13822 +B16,Welling Corner,51.4622529,0.109744 +B16,Falconwood,51.4585461,0.0946553 +B16,Eltham High Street,51.4507726,0.0561761 +B16,Eltham Green,51.4533383,0.0356381 +B16,Kidbrooke,51.46199840000001,0.0277477 +C1,Victoria,51.49554149999999,-0.1435602 +C1,Sloane Square,51.4927684,-0.1570174 +C1,"Earl's Court, Tesco",51.490331,-0.1958417 +C1,South Kensington,51.4953291,-0.1789909 +C1,Shepherd's Bush,51.5051913,-0.22469 +C1,White City,51.51146199999999,-0.2376332 +C2,Parliament Hill Fields,51.5594043,-0.151707 +C2,Kentish Town,51.4309209,-0.0936496 +C2,Camden Town,51.52203979999999,-0.1279844 +C2,Camden Town,51.52203979999999,-0.1279844 +C2,Great Portland Street,51.5199714,-0.1426427 +C2,Berkeley Square,51.5098475,-0.1453298 +C2,Hyde Park Corner,51.5029347,-0.1508562 +C2,Victoria,51.49554149999999,-0.1435602 +C3,Clapham Junction,51.4651737,-0.1708113 +C3,"Wandsworth Bridge, South Side",51.4651939,-0.1880094 +C3,Chelsea Harbour,51.476111,-0.1826413 +C3,West Brompton,51.483494,-0.196802 +C3,Earl's Court,51.490331,-0.1958417 +C3,"Earl's Court, Tesco",51.490331,-0.1958417 +C10,Canada Water,51.4962989,-0.0482742 +C10,Rotherhithe,51.49628999999999,-0.0411931 +C10,Elephant & Castle,51.4938058,-0.0977932 +C10,St George's Circus,51.4984377,-0.1045086 +C10,Millbank,51.4917605,-0.1298473 +C10,Tate Britain,51.4910621,-0.1277886 +C10,Pimlico Station,51.4891,-0.13374 +C10,Victoria Coach Station,51.49554149999999,-0.1435602 +C10,Victoria,51.49554149999999,-0.1435602 +C11,Archway,51.5648883,-0.1323808 +C11,Parliament Hill Fields,51.5594043,-0.151707 +C11,Hampstead Heath,51.5608294,-0.1629416 +C11,Swiss Cottage,51.5425872,-0.1724737 +C11,Finchley Road Station,51.5469174,-0.179986 +C11,West Hampstead,51.5490183,-0.1971205 +C11,"Cricklewood, Pennine Drive",51.5645787,-0.2144717 +C11,Brent Cross,51.5763589,-0.2236956 +D3,"Bethnal Green, Bonner Road",51.5320692,-0.0509221 +D3,Whitechapel,51.5148198,-0.0650534 +D3,"Limehouse, Burdett Road",51.5150014,-0.0285662 +D3,Canary Wharf,51.5054306,-0.0235333 +D3,Leamouth,51.512039,0.001899 +D6,Ash Grove,51.5358094,-0.0581907 +D6,Mile End,51.52354529999999,-0.0330122 +D6,"Limehouse, Burdett Road",51.5150014,-0.0285662 +D6,"Poplar, All Saints",51.5123792,-0.0087975 +D6,Blackwall,51.5079838,-0.007195699999999999 +D6,Crossharbour,51.4958465,-0.0145118 +D7,"Poplar, All Saints",51.5123792,-0.0087975 +D7,Cubitt Town,51.497186,-0.009047 +D7,Cubitt Town,51.497186,-0.009047 +D7,Canary Wharf,51.5054306,-0.0235333 +D7,"Limehouse, Burdett Road",51.5150014,-0.0285662 +D7,Mile End,51.52354529999999,-0.0330122 +D8,Stratford,51.5426313,-0.0010369 +D8,Bromley-By-Bow,51.5278208,-0.0128373 +D8,"Poplar, All Saints",51.5123792,-0.0087975 +D8,Canary Wharf,51.5054306,-0.0235333 +D8,Crossharbour,51.4958465,-0.0145118 +E1,Greenford Broadway,51.5279556,-0.3540139 +E1,Drayton Green,51.515364,-0.3257264 +E1,"West Ealing, Sutherland Avenue",51.5165248,-0.3208564 +E1,Ealing Broadway,51.5132537,-0.3043136 +E2,"Brentford, Commerce Road",51.4836006,-0.313864 +E2,"Brentford, County Court",51.4835374,-0.3063676 +E2,West Ealing,51.51141,-0.3180165 +E2,Ealing Broadway,51.5132537,-0.3043136 +E2,"West Ealing, Scotch Common",51.5248572,-0.3210551 +E2,Greenford Broadway,51.5279556,-0.3540139 +E3,Greenford Broadway,51.5279556,-0.3540139 +E3,Hanwell Broadway,51.5066369,-0.3383229 +E3,West Ealing,51.5281483,-0.0205416 +E3,"Acton, Horn Lane",51.5150958,-0.2686528 +E3,"Acton, High Street",51.5071042,-0.270558 +E3,Turnham Green,51.49203019999999,-0.2663174 +E3,"Chiswick, Edensor Road",51.4821173,-0.255696 +E5,"Southall, Toplocks Estate",51.511073,-0.377232 +E5,"Southall, Town Hall",51.5113272,-0.3751471 +E5,Greenford Broadway,51.5279556,-0.3540139 +E5,"Perivale, Medway Estate",51.5364116,-0.3327652 +E5,Perivale Tesco,51.532222,-0.324477 +E6,Greenford Station,51.5255068,0.05870810000000001 +E6,Greenford Broadway,51.5279556,-0.3540139 +E6,"Glencoe Road, Tesco",51.524364,-0.3880442 +E6,"Yeading, Willow Tree Lane",51.52749319999999,-0.3991509 +E6,"Hayes, Grapes",51.5255068,0.05870810000000001 +E6,Hayes & Harlington Station,51.5029848,-0.4203779 +E6,Hayes & Harlington Station,51.5029848,-0.4203779 +E6,Bull's Bridge,51.4999134,-0.4066811 +E7,Ruislip,51.5758719,-0.421236 +E7,Ruislip Gardens,51.5518094,0.0293728 +E7,"Yeading, White Hart",51.536823,-0.389446 +E7,Greenford Broadway,51.5279556,-0.3540139 +E7,"West Ealing, Sutherland Avenue",51.5165248,-0.3208564 +E7,West Ealing Broadway,51.514042,-0.3015746 +E7,Ealing Broadway,51.5146192,-0.3022912 +E8,Hounslow Bell Corner,51.468569,-0.3666325 +E8,Hounslow Bus Station,51.46092179999999,-0.373149 +E8,Isleworth,51.467121,-0.329003 +E8,Brentford Bus Garage,51.4845841,-0.3155602000000001 +E8,"Brentford, County Court",51.4835374,-0.3063676 +E8,"Brentford, County Court",51.4835374,-0.3063676 +E8,Hanwell Broadway,51.5090444,-0.3376352 +E8,Hanwell Broadway,51.5090444,-0.3376352 +E8,West Ealing,51.51141,-0.3180165 +E8,"West Ealing,Scotch Common",51.5248572,-0.3210551 +E8,Ealing Broadway,51.5132537,-0.3043136 +E9,"Yeading, Barnhill Estate",51.52291,-0.3880247000000001 +E9,"Yeading, White Hart",51.536823,-0.389446 +E9,Greenford Broadway,51.5279556,-0.3540139 +E9,"West Ealing, Scotch Common",51.5248572,-0.3210551 +E9,Ealing Broadway,51.5132537,-0.3043136 +E10,"Northolt, Islip Manor",51.5473716,-0.379684 +E10,Smiths Farm,51.5649619,-0.0146911 +E10,Greenford Broadway,51.5279556,-0.3540139 +E10,"West Ealing, Scotch Common",51.5248572,-0.3210551 +E10,Ealing Broadway,51.5146192,-0.3022912 +E11,Greenford Broadway,51.5279556,-0.3540139 +E11,Drayton Green,51.515364,-0.3257264 +E11,West Ealing,51.5728525,0.0176348 +E11,Ealing Broadway,51.5728525,0.0176348 +E11,"Ealing, Warwick Dene",51.507913,-0.2956596 +EL1,Ilford Station,51.556619,0.076251 +EL1,Barking,51.536563,0.075766 +EL1,Barking,51.536563,0.075766 +EL1,"River Road, Waverley Gardens",51.5343317,-0.2891878 +EL1,"River Road, Waverley Gardens",51.5343317,-0.2891878 +EL1,Barking Riverside,51.536563,0.075766 +EL2,Becontree Heath,51.5609465,0.1488995 +EL2,Five Elms,51.3697855,0.0259964 +EL2,Bennett's Castle Lane,51.5562949,0.1276031 +EL2,Barking,51.536563,0.075766 +EL2,Barking,51.536563,0.075766 +EL2,"River Road, Waverley Gardens",51.5343317,-0.2891878 +EL2,"River Road, Waverley Gardens",51.5343317,-0.2891878 +EL2,Dagenham Dock,51.5402631,0.1482103 +EL3,Little Heath,51.583227,0.120603 +EL3,King George Hospital,51.5802748,0.1115243 +EL3,"Goodmayes, Goodmayes Lane",51.5620979,0.1095257 +EL3,Barking,51.536563,0.075766 +EL3,Creekmouth,51.517381,0.102234 +EL3,Barking,51.536563,0.075766 +EL3,Barking Riverside,51.536563,0.075766 +G1,"Streatham, Green Lane",51.4147104,-0.1158693 +G1,"Streatham, St Leonard's Church",51.4307467,-0.1294977 +G1,Tooting Broadway,51.427867,-0.1678142 +G1,Tooting Broadway,51.427867,-0.1678142 +G1,"Tooting, St George's Hospital",51.42656299999999,-0.1752284 +G1,Springfield Hospital,51.4385846,-0.1718014 +G1,Clapham Junction,51.4651737,-0.1708113 +G1,"Battersea, Shaftesbury Estate",51.47220069999999,-0.165547 +H2,Golders Green,51.5740013,-0.1987725 +H3,Golders Green,51.5740013,-0.1987725 +H3,East Finchley,51.592468,-0.1664342 +H9,Harrow,51.580559,-0.341995 +H9,Northwick Park Hospital,51.5753935,-0.3201711 +H9,"Kenton, Library",51.59262649999999,-0.3111454 +H9,Wealdstone,51.5960603,-0.3334858 +H9,Rayners Lane Station,51.5762173,-0.3702536 +H9,North Harrow,51.58412800000001,-0.3644343 +H10,Harrow,51.580559,-0.341995 +H10,Rayners Lane Station,51.5751034,-0.3708618 +H10,Wealdstone,51.5960603,-0.3334858 +H10,"Kenton, Library",51.59262649999999,-0.3111454 +H10,Northwick Park Hospital,51.5753935,-0.3201711 +H10,North Harrow,51.58412800000001,-0.3644343 +H11,Harrow,51.580559,-0.341995 +H11,Pinner,51.595172,-0.378002 +H11,Northwood Hills,51.6004243,-0.4098652 +H11,Northwood Station,51.6112297,-0.423889 +H11,Mount Vernon Hospital,51.6153975,-0.4455072 +H12,Stanmore Station,51.6196885,-0.3031205 +H12,Stanmore Church,51.6164857,-0.3153133 +H12,Harrow Weald Bus Garage,51.606117,-0.3400905 +H12,Pinner,51.595172,-0.378002 +H12,Rayners Lane Station,51.5751034,-0.3708618 +H12,South Harrow,51.5683717,-0.3553483 +H13,"Northwood Hills, St Vincent's",51.6004243,-0.4098652 +H13,Northwood Hills,51.6004243,-0.4098652 +H13,Pinner,51.595172,-0.378002 +H13,Ruislip,51.5758719,-0.421236 +H13,Ruislip,51.5758719,-0.421236 +H13,Ruislip Lido,51.59114049999999,-0.4304918 +H14,Hatch End,51.6104236,-0.370708 +H14,Courtenay Avenue,51.5747587,-0.1682409 +H14,Harrow,51.580559,-0.341995 +H14,Northwick Park Hospital,51.5753935,-0.3201711 +H17,Harrow,51.580559,-0.341995 +H17,Sudbury,51.5556591,-0.3171114 +H17,Sudbury Hill,51.5539267,-0.337085 +H17,Wembley Central,51.550501,-0.3048409 +H18,Harrow,51.580559,-0.341995 +H18,"Harrow Weald, Long Elmes",51.6044001,-0.3401289 +H18,Belmont Circle,51.6010493,-0.3180225 +H19,Harrow,51.580559,-0.341995 +H19,"Harrow Weald, Long Elmes",51.6044001,-0.3401289 +H19,Belmont Circle,51.6010493,-0.3180225 +H20,"Hounslow, Civic Centre",51.4737233,-0.36638 +H20,"Hounslow, Bell Corner",51.468569,-0.3666325 +H20,Whitton Dene,51.4576828,-0.3517485 +H20,"Ivybridge, Tesco",51.4309209,-0.0936496 +H22,Hounslow Bell Corner,51.468569,-0.3666325 +H22,"Hounslow, Bus Station",51.4708688,-0.3546457 +H22,Whitton Dene,51.4576828,-0.3517485 +H22,Hospital Bridge,51.44267,-0.3652385 +H22,Twickenham,51.4453043,-0.3375429 +H22,Richmond,51.46131099999999,-0.303742 +H22,Richmond,51.46131099999999,-0.303742 +H22,"Richmond, Manor Circus",51.4677844,-0.2883524 +H25,Butts Farm,51.4309209,-0.0936496 +H25,"Hanworth, Main Street",51.4489479,-0.3829269 +H25,"Hanworth, Sunbury Way",51.4311625,-0.4003865 +H25,Feltham,51.44414800000001,-0.410772 +H25,Feltham Station,51.4480215,-0.4090095 +H25,Bedfont Green,51.45109910000001,-0.4402292 +H25,Hatton Cross,51.4651031,-0.4157165 +H26,"Feltham, Sparrow Farm",51.4525059,-0.3975703 +H26,Feltham,51.44414800000001,-0.410772 +H26,Lower Feltham,51.436601,-0.426105 +H26,Bedfont Lakes,51.4469846,-0.4441649 +H26,Bedfont Green,51.45109910000001,-0.4402292 +H26,Hatton Cross,51.4651031,-0.4157165 +H28,Bull's Bridge,51.4999134,-0.4066811 +H28,Heston,51.48420170000001,-0.3719867 +H28,"Hounslow, Bus Station",51.4708688,-0.3546457 +H28,Osterly,51.4819722,-0.3494553 +H28,West Middlesex Hospital,51.4734184,-0.3244425 +H28,Osterley Tesco,51.48580430000001,-0.3301428 +H32,Hounslow Bus Station,51.4708688,-0.3546457 +H32,"Hounslow, Bell Corner",51.468569,-0.3666325 +H32,Hounslow West,51.469435,-0.3837709 +H32,Convent Way,51.4945787,-0.3939649 +H32,"Southall, The Green",51.5035525,-0.3802476 +H32,"Southall, Town Hall",51.5113272,-0.3751471 +H37,"Hounslow, Blenheim Centre",51.4706766,-0.3621538 +H37,"Hounslow, Bus Station",51.4708688,-0.3546457 +H37,"Isleworth, Fire Station",51.467121,-0.329003 +H37,"St Margarets, Chertsey Road",51.4567895,-0.3273389 +H37,Richmond,51.4309209,-0.0936496 +H37,"Richmond, Manor Circus",51.4677844,-0.2883524 +H91,Hounslow West,51.469435,-0.3837709 +H91,Osterley Station,51.48103039999999,-0.3519527 +H91,"Great West Road, Syon Lane",51.4832374,-0.326929 +H91,"Great West Road, Ealing Road",51.4913803,-0.3039856 +H91,Chiswick Roundabout,51.4910362,-0.2816861 +H91,Turnham Green,51.49203019999999,-0.2663174 +H91,"Stamford Brook, Chiswick Lane",51.49492,-0.24568 +H91,"Stamford Brook, Bus Garage",51.493069,-0.2493815 +H91,Ravenscourt Park,51.4952687,-0.2397848 +H91,Hammersmith,51.491187,-0.223731 +H98,"Hounslow, Bus Station",51.4708688,-0.3546457 +H98,"Hounslow, Bell Corner",51.468569,-0.3666325 +H98,Hounslow West,51.469435,-0.3837709 +H98,Cranford,51.4720623,-0.4055896 +H98,"Bath Road, Nobel Drive",51.4806378,-0.4287598 +H98,Harlington Corner,51.4809415,-0.434335 +H98,Hayes & Harlington Station,51.5029848,-0.4203779 +H98,"Uxbridge Road, Lansbury Drive",51.52294149999999,-0.422019 +H98,"Hayes, Church End",51.516758,-0.436786 +H98,Hayes End,51.5257,-0.4357732 +K1,New Malden,51.40066299999999,-0.259263 +K1,Malden Manor Station,51.38473639999999,-0.2611812000000001 +K1,Tolworth,51.3801004,-0.2861237 +K1,"Tolworth, Red Lion Road",51.3807794,-0.2901602 +K1,Hook Junction,51.3751056,-0.3042808 +K1,Surbiton Station,51.39255679999999,-0.3044465 +K1,Surbiton,51.39400999999999,-0.302662 +K1,Kingston,51.41233,-0.300689 +K2,Kingston Hospital,51.4148229,-0.2824061 +K2,"Kingston, Cromwell Road",51.4123016,-0.2986358 +K2,Surbiton,51.39400999999999,-0.302662 +K2,Berrylands,51.3922147,-0.2932239 +K2,"Tolworth, Red Lion Road",51.3807794,-0.2901602 +K2,Tolworth Broadway,51.3806898,-0.2823801 +K2,"Chessington, Industrial Estate",51.3681597,-0.2865138 +K2,Hook,51.3682509,-0.305081 +K3,Roehampton Vale,51.4388194,-0.2491381 +K3,Kingston,51.41233,-0.300689 +K3,"Kingston Vale, Robin Hood Way",51.4253374,-0.2551612 +K3,Kingston Hospital,51.4148229,-0.2824061 +K3,Surbiton Station,51.39255679999999,-0.3044465 +K3,Surbiton,51.39400999999999,-0.302662 +K3,Claygate,51.360219,-0.340969 +K3,"Esher, Trinity School",51.369487,-0.365927 +K3,Esher,51.369487,-0.365927 +K4,Kingston Hospital,51.4148229,-0.2824061 +K4,Kingston,51.41233,-0.300689 +K4,Surbiton,51.39400999999999,-0.302662 +K4,Hook Junction,51.3751056,-0.3042808 +K4,"Hook, Bridge Road",51.420021,-0.1940527 +K4,Mansfield Park,51.4309209,-0.0936496 +K5,Ham,51.4299232,-0.2984002 +K5,Kingston,51.41233,-0.300689 +K5,"New Malden, Fountain Roundabout",51.40066299999999,-0.259263 +K5,Raynes Park,51.4084257,-0.2298751 +K5,Morden,51.394943,-0.19446 +P4,Lewisham Station,51.4652098,-0.0131213 +P4,Ladywell,51.45589709999999,-0.0219523 +P4,Brockley Rise,51.4473951,-0.0416563 +P4,"Forest Hill, Horniman Museum",51.4410762,-0.0612925 +P4,Dulwich Village,51.4506584,-0.0855299 +P4,North Dulwich,51.4433257,-0.0675547 +P4,Loughborough Junction,51.4660641,-0.102184 +P4,Brixton,51.4612794,-0.1156148 +P4,Brixton,51.4612794,-0.1156148 +P5,Elephant & Castle,51.4938058,-0.0977932 +P5,Brixton,51.4612794,-0.1156148 +P5,Stockwell,51.4760412,-0.1263271 +P5,Patmore Estate,51.4763262,-0.1396515 +P12,Surrey Quays,51.4944172,-0.0383063 +P12,Canada Water,51.4962989,-0.0482742 +P12,South Bermondsey,51.48697379999999,-0.0537171 +P12,Peckham,51.47032369999999,-0.0673872 +P12,Peckham Rye,51.4603208,-0.0603961 +P12,Brenchley Gardens,51.4530377,-0.0506801 +P12,Brockley Rise,51.4473951,-0.0416563 +P13,Streatham Station,51.4259857,-0.131308 +P13,Streatham Hill Station,51.4382009,-0.1270706 +P13,Tulse Hill Station,51.43986,-0.10505 +P13,East Dulwich,51.4545635,-0.0732101 +P13,Peckham,51.47032369999999,-0.0673872 +P13,New Cross Gate,51.4749904,-0.0403466 +R1,St Paul's Cray,51.396136,0.1103591 +R1,St Mary Cray,51.385993,0.113061 +R1,"Orpington, Walnuts Centre",51.3773656,0.1007092 +R1,Chelsfield Station,51.35728049999999,0.1063505 +R1,Green Street Green,51.3535363,0.0890088 +R2,"Orpington, Walnuts Centre",51.3773656,0.1007092 +R2,Orpington Station,51.37329,0.08911999999999999 +R2,Locksbottom,51.3673231,0.0547259 +R2,Biggin Hill Airport,51.312059,0.032802 +R2,Biggin Hill Valley,51.312059,0.032802 +R3,Princess Royal Hospital,51.3661498,0.05819390000000001 +R3,Petts Wood,51.389636,0.08195 +R3,"Orpington, Perry Hall Road",51.3823992,0.0998353 +R3,"Orpington, Walnuts Centre",51.3773656,0.1007092 +R3,Orpington Station,51.37329,0.08911999999999999 +R4,Pauls Cray Hill,51.385307,0.114227 +R4,Cockmannings,51.3819698,0.1233517 +R4,Ramsden Estate,51.3754771,0.1224719 +R4,"Orpington, Perry Hall Road",51.3823992,0.0998353 +R4,"Orpington, Walnuts Centre",51.3773656,0.1007092 +R4,Orpington Station,51.37329,0.08911999999999999 +R4,Locksbottom,51.3673231,0.0547259 +R4,Princess Royal Hospital,51.3661498,0.05819390000000001 +R5,Orpington Station,51.37329,0.08911999999999999 +R5,Knockholt,51.311086,0.1062 +R6,Orpington Station,51.37329,0.08911999999999999 +R6,St Mary Cray Station,51.3957762,0.1071945 +R7,Chislehurst,51.412626,0.077487 +R7,"Orpington, Walnuts Centre",51.3773656,0.1007092 +R7,Petts Wood,51.389636,0.08195 +R7,"Bickley, Aquila",51.38994700000001,0.0492904 +R7,Chelsfield Village,51.3562794,0.1254019 +R8,Orpington Station.,51.37329,0.08911999999999999 +R8,Biggin Hill,51.312059,0.032802 +R9,Orpington Station,51.37329,0.08911999999999999 +R9,"Orpington, Walnuts Centre",51.3773656,0.1007092 +R9,Ramsden Estate,51.3754771,0.1224719 +R10,Orpington Station,51.37329,0.08911999999999999 +R10,Knockholt,51.311086,0.1062 +R11,Queen Mary's Hospital,51.4556562,-0.2426609 +R11,Foots Cray,51.4174447,0.1210622 +R11,St Marys Cray,51.385993,0.113061 +R11,"Orpington, Walnuts Centre",51.3773656,0.1007092 +R11,Green Street Green,51.3535363,0.0890088 +R68,Kew Retail Park,51.4778962,-0.2791853 +R68,"Richmond, Manor Circus",51.4677844,-0.2883524 +R68,Richmond,51.46131099999999,-0.303742 +R68,Richmond Bus Station,51.4591284,-0.3044753000000001 +R68,Twickenham,51.4453043,-0.3375429 +R68,Teddington,51.4268694,-0.3338681 +R68,Hampton Church,51.4133939,-0.366712 +R68,Hampton Court,51.4036128,-0.3377623 +R70,"Hampton, The Avenue",51.4133939,-0.366712 +R70,"Fulwell, Cock & Bull",51.4331018,-0.3520137 +R70,Twickenham,51.4453043,-0.3375429 +R70,Richmond Bus Station,51.4591284,-0.3044753000000001 +R70,Richmond,51.46131099999999,-0.303742 +R70,"Richmond, Manor Circus",51.4677844,-0.2883524 +R70,Fulwell,51.4331018,-0.3520137 +R70,"Richmond, Manor Circus",51.4677844,-0.2883524 +RB1,Woolwich Pier,51.4894752,0.06758829999999999 +RB1,North Greenwich Pier,51.5022201,0.0091621 +RB1,Westminster Pier,51.4974948,-0.1356583 +RB1X,Woolwich Pier,51.4894752,0.06758829999999999 +RB1X,North Greenwich Pier,51.5022201,0.0091621 +RB1X,Westminster Pier,51.4974948,-0.1356583 +RB2,London Bridge Pier,51.4966529,-0.0299834 +RB2,Bankside,51.5081373,-0.0951836 +RB2,Millbank,51.4917605,-0.1298473 +RB4,Hilton Pier,51.4309209,-0.0936496 +RB4,Canary Wharf,51.5054306,-0.0235333 +RB5,Woolwich Arsenal,51.4894752,0.06758829999999999 +RB5,North Greenwich,51.4859576,0.007494900000000001 +RB6,Putney,51.4596431,-0.2141257 +RB6,Plantation Wharf,51.46679899999999,-0.1810273 +RB6,Blackfriars,51.51199200000001,-0.1038617 +RB6,Blackfriars,51.51199200000001,-0.1038617 +RB6,Bankside,51.5081373,-0.0951836 +RB6,Canary Wharf,51.5054306,-0.0235333 +RB6A,Canary Wharf,51.5054306,-0.0235333 +RB6A,Putney,51.4596431,-0.2141257 +RT1,Westminster Pier,51.4974948,-0.1356583 +RT1,Tower Pier,51.5073034,-0.07875549999999999 +RT1,Greenwich Pier,51.4933675,0.0098214 +RT3,Westminster Pier,51.4974948,-0.1356583 +RT3,St. Katherine's Pier,51.5064168,-0.0718167 +RT3,Greenwich Pier,51.4933675,0.0098214 +RT5,Bankside Pier,51.5085251,-0.0962555 +RT7,Embankment,51.4309209,-0.0936496 +RT7,North Greenwich,51.4859576,0.007494900000000001 +RT7,Woolwich Arsenal,51.4894752,0.06758829999999999 +RT8,St George Wharf,51.4848424,-0.1274566 +RT8,Bankside,51.5081373,-0.0951836 +RT10,Woolwich Arsenal,51.4894752,0.06758829999999999 +RT10,North Greenwich,51.4859576,0.007494900000000001 +RT11,Putney,51.4596431,-0.2141257 +RT11,Plantation Wharf,51.46679899999999,-0.1810273 +RT11,Blackfriars,51.51199200000001,-0.1038617 +RT11,Bankside,51.5081373,-0.0951836 +RT11,Canary Wharf,51.5054306,-0.0235333 +RT12,Canary Wharf,51.5054306,-0.0235333 +RT12,Putney,51.4596431,-0.2141257 +RV1,Covent Garden,51.5116571,-0.1240436 +RV1,Waterloo,51.5048541,-0.1136621 +RV1,London Bridge,51.5072178,-0.1275862 +RV1,City Hall,51.4309209,-0.0936496 +RV1,Tower Gateway,51.5106312,-0.0737553 +S1,Banstead,51.3221909,-0.205046 +S1,Belmont,51.601249,-0.3192749 +S1,Sutton Station,51.3614279,-0.193961 +S1,Sutton Town Centre,51.3614279,-0.193961 +S1,St Helier Hospital,51.3805311,-0.18442 +S1,Middleton Circle,51.4309209,-0.0936496 +S1,Lavender Fields,51.4309209,-0.0936496 +S3,Sutton Hospital,51.3614279,-0.193961 +S3,Sutton Station,51.3614279,-0.193961 +S3,Sutton Town Centre,51.3614279,-0.193961 +S3,"North Cheam, Sainsbury's",51.3723635,-0.2259143 +S3,Worchester Park,51.38029,-0.24468 +S3,Malden Manor,51.40066299999999,-0.259263 +S4,Roundshaw,51.3533066,-0.1269329 +S4,Wallington,51.363978,-0.151845 +S4,Belmont,51.601249,-0.3192749 +S4,Sutton Station,51.3614279,-0.193961 +S4,Sutton Town Centre,51.3614279,-0.193961 +S4,St Helier Station,51.3899,-0.19875 +U1,Ruislip,51.5758719,-0.421236 +U1,Uxbridge,51.5485,-0.479611 +U1,Hillingdon Hospital,51.5252078,-0.4612385 +U1,West Drayton,51.502985,-0.4654099999999999 +U2,Brunel University,51.5321389,-0.4727493 +U2,Hillingdon Station,51.5537882,-0.4499684 +U2,"Uxbridge, Lees Road",51.5285284,-0.4494669 +U2,Uxbridge,51.5485,-0.479611 +U3,Uxbridge,51.5485,-0.479611 +U3,Hillingdon Hospital,51.5252078,-0.4612385 +U3,West Drayton,51.502985,-0.4654099999999999 +U3,West Drayton,51.502985,-0.4654099999999999 +U3,Harmondsworth,51.487453,-0.475554 +U3,Heathrow Central,51.4724711,-0.4544586 +U4,"Hayes, Prologis Park",51.516758,-0.436786 +U4,"Hayes, Bourne Avenue",51.5026304,-0.438024 +U4,"Hayes, Station Road",51.501625,-0.4236355 +U4,"Hayes, Barra Hall Circus",51.516758,-0.436786 +U4,Hayes & Harlington Station,51.5029848,-0.4203779 +U4,"Hayes, Asda",51.516758,-0.436786 +U4,"Hayes, Barra Hall Circus",51.516758,-0.436786 +U4,"Hillingdon, Kingston Lane",51.532082,-0.4665415 +U4,Uxbridge,51.5485,-0.479611 +U5,Uxbridge,51.5485,-0.479611 +U5,Hillingdon Hospital,51.5252078,-0.4612385 +U5,West Drayton,51.502985,-0.4654099999999999 +U5,West Drayton,51.502985,-0.4654099999999999 +U5,Stockley Estate,51.5053199,-0.4501722 +U5,Stockley Park,51.51153850000001,-0.444799 +U5,Hayes & Harlington Station,51.5029848,-0.4203779 +U7,Uxbridge,51.5485,-0.479611 +U7,"Hillingdon, Kingston Lane",51.532082,-0.4665415 +U7,"Hillingdon, Pield Heath Road",51.5266189,-0.4608675 +U7,Charville Lane Estate,51.5378301,-0.4293177 +U7,"Hayes, Sainsbury's",51.516758,-0.436786 +U9,Uxbridge,51.5485,-0.479611 +U9,Harefield Hospital,51.6067699,-0.4827023999999999 +U10,Uxbridge,51.5485,-0.479611 +U10,Ickenham High Road,51.5670568,-0.4417871 +U10,Ruislip,51.5758719,-0.421236 +U10,"Ruislip, Heathfield Rise",51.5764892,-0.4378024 +UL1,Hammersmith,51.491187,-0.223731 +UL1,Baker Street,51.520568,-0.1567804 +UL2,Camden Road,51.5479475,-0.1303297 +UL2,Hampstead Heath,51.5608294,-0.1629416 +UL2,Willesden Junction,51.53211630000001,-0.2433689 +UL2,Willesden Junction,51.53211630000001,-0.2433689 +UL2,Willesden Junction,51.53211630000001,-0.2433689 +UL2,Gunnersbury,51.49335199999999,-0.278887 +UL2,Richmond,51.46131099999999,-0.303742 +UL3,Clapham Junction,51.4651737,-0.1708113 +UL3,Canada Water,51.4962989,-0.0482742 +UL4,High Barnet,51.6569225,-0.1949252 +UL4,Finchley Central,51.5971434,-0.1979547 +UL4,Archway,51.5648883,-0.1323808 +UL5,Acton,51.50837199999999,-0.27444 +UL5,Rayners Lane Station,51.5762173,-0.3702536 +UL6,Baker Street Station,51.5231548,-0.156863 +UL6,Willesden Green,51.5476301,-0.2369246 +UL6,Wembley Park,51.5585935,-0.2796126 +UL7,Barking,51.536563,0.075766 +UL7,East Ham,51.5333972,0.04991139999999999 +UL7,Walthamstow Central,51.5901769,-0.0173437 +UL8,Seven Sisters,51.582652,-0.0747232 +UL8,Seven Sisters,51.582652,-0.0747232 +UL8,Gospel Oak,51.5563205,-0.1492765 +UL9,Hammersmith,51.491187,-0.223731 +UL9,Turnham Green,51.49203019999999,-0.2663174 +UL9,Richmond,51.46131099999999,-0.303742 +UL10,Chingford Station,51.6320667,0.007362700000000001 +UL10,Hackney Downs,51.5553095,-0.06908249999999999 +UL10,Liverpool Street,51.5175001,-0.0826966 +UL11,Canary Wharf,51.5054306,-0.0235333 +UL11,Stratford,51.5426313,-0.0010369 +UL12,Loughton,51.655942,0.068161 +UL12,Snaresbrook,51.58567859999999,0.0084531 +UL12,Leyton,51.5702225,-0.0146938 +UL12,Stratford,51.5426313,-0.0010369 +UL12,Mile End,51.52354529999999,-0.0330122 +UL13,Harrow & Wealdstone Station,51.59172359999999,-0.3343587 +UL13,Watford Junction,51.66371280000001,-0.3964488 +UL14,Harrow-on-the-Hill,51.5706321,-0.3396363 +UL14,Wembley Park,51.5585935,-0.2796126 +UL15,Stanmore Station,51.617676,-0.311451 +UL15,Wembley Park,51.5585935,-0.2796126 +UL15,Stonebridge Park,51.5445824,-0.2608244 +UL16,Stratford,51.5426313,-0.0010369 +UL16,Ilford,51.556619,0.076251 +UL16,Romford,51.577076,0.178319 +UL17,Stanmore Station,51.617676,-0.311451 +UL17,Wembley Park,51.5585935,-0.2796126 +UL17,Willesden Green,51.5476301,-0.2369246 +UL18,Liverpool Street,51.5175001,-0.0826966 +UL18,Seven Sisters,51.582652,-0.0747232 +UL18,Enfield Town,51.6522994,-0.0807119 +UL18,Cheshunt,51.70264050000001,-0.0343787 +UL19,Harrow & Wealdstone Station,51.59172359999999,-0.3343587 +UL19,Wembley Central,51.550501,-0.3048409 +UL19,Stonebridge Park,51.5445824,-0.2608244 +UL19,Queen's Park,51.5345448,-0.2043853 +UL20,Tower Hill,51.5095757,-0.0760083 +UL20,Canning Town,51.5189494,0.0132 +UL20,Stratford,51.5426313,-0.0010369 +UL20,Stratford,51.5426313,-0.0010369 +UL20,East Ham,51.5333972,0.04991139999999999 +UL20,Barking,51.536563,0.075766 +UL21,Stratford,51.5426313,-0.0010369 +UL21,Hackney Central,51.5482344,-0.05738749999999999 +UL21,Camden Road,51.5479475,-0.1303297 +UL22,Stratford,51.5426313,-0.0010369 +UL22,Hampstead Heath,51.5608294,-0.1629416 +UL23,Dalston Kingsland,51.5481846,-0.05471409999999999 +UL23,Shadwell,51.51450620000001,-0.05711619999999999 +UL24,Dagenham East,51.5402631,0.1482103 +UL24,Barking,51.536563,0.075766 +UL25,Upminster,51.55591399999999,0.248894 +UL25,Barking,51.536563,0.075766 +UL26,Wimbledon,51.41833889999999,-0.2206288 +UL26,Wimbledon,51.41833889999999,-0.2206288 +UL26,Fulham Broadway,51.4801568,-0.1962971 +UL29,Osterley,51.4819722,-0.3494553 +UL29,Hammersmith,51.491187,-0.223731 +UL27,Finchley Central,51.5971434,-0.1979547 +UL27,Mill Hill East,51.6078622,-0.2082474 +UL28,Boston Manor,51.495767,-0.3247429000000001 +UL28,Hammersmith,51.491187,-0.223731 +UL30,South Wimbledon,51.41570919999999,-0.192514 +UL30,Fulham Broadway,51.4801568,-0.1962971 +UL31,All Saints,51.4309209,-0.0936496 +UL31,Bank,51.4309209,-0.0936496 +UL32,Arnos Grove,51.619799,-0.1296871 +UL32,High Barnet,51.6569225,-0.1949252 +UL33,Warren Street,51.5240516,-0.1399547 +UL33,Finchley Road,51.5611866,-0.197096 +UL34,Finchley Central,51.5971434,-0.1979547 +UL34,Arnos Grove,51.619799,-0.1296871 +UL34,Arnos Grove,51.619799,-0.1296871 +UL35,Finsbury Park,51.56457839999999,-0.1047257 +UL35,Walthamstow Central,51.5901769,-0.0173437 +UL35,Walthamstow Central,51.5901769,-0.0173437 +UL37,Victoria,51.49554149999999,-0.1435602 +UL37,Brixton,51.4612794,-0.1156148 +UL40,Chingford,51.6320667,0.007362700000000001 +UL40,Hackney Downs,51.5553095,-0.06908249999999999 +UL41,Morden,51.394943,-0.19446 +UL41,Tooting Broadway,51.427867,-0.1678142 +UL42,Stratford,51.5426313,-0.0010369 +UL42,Highbury & Islington,51.5569649,-0.0979656 +UL42,Camden Road,51.5479475,-0.1303297 +UL43,Wimbledon,51.41833889999999,-0.2206288 +UL43,Hammersmith,51.491187,-0.223731 +UL44,Stratford,51.5426313,-0.0010369 +UL44,Highbury & Islington,51.5569649,-0.0979656 +UL55,Chalk Farm,51.5444834,-0.152158 +UL55,Canons Park,51.6076736,-0.2962361 +UL56,Chalk Farm,51.5444834,-0.152158 +UL56,Hendon Central,51.583202,-0.226399 +W3,Northumberland Park,51.6024517,-0.0676958 +W3,White Hart Lane Station,51.6061468,-0.0884635 +W3,"White Hart Lane, Fenton Road",51.6067192,-0.0913817 +W3,Wood Green,51.5971722,-0.1098021 +W3,"Alexandra Park, Park Road",51.4309209,-0.0936496 +W3,Crouch End,51.5819979,-0.1221464 +W3,Finsbury Park Station,51.5646425,-0.1058553 +W4,Oakthorpe Park,51.4309209,-0.0936496 +W4,"Wood Green, Wolves Lane",51.6058398,-0.1036382 +W4,Wood Green,51.5971722,-0.1098021 +W4,Wood Green,51.5971722,-0.1098021 +W4,Turnpike Lane Station,51.5904278,-0.1027587 +W4,"Green Lanes, West Green Road",51.5889244,-0.1020963 +W4,Tottenham Town Hall,51.5872187,-0.0725467 +W4,Bruce Grove,51.596249,-0.0723585 +W4,Bruce Grove,51.596249,-0.0723585 +W4,Tottenham Hale,51.5892808,-0.06105049999999999 +W4,"Tottenham Hale, Ferry Lane",51.5880499,-0.0605514 +W5,Archway,51.5648883,-0.1323808 +W5,Crouch End,51.5819979,-0.1221464 +W5,Crouch End,51.5819979,-0.1221464 +W5,Harringay Station,51.5773498,-0.1050857 +W5,"Harringay, Superstores",51.582426,-0.09966 +W6,Southgate,51.4911405,-0.2261411 +W6,"Palmers Green, Hedge Lane",51.6224407,-0.0997349 +W6,"Edmonton, Cambridge",51.4309209,-0.0936496 +W6,Edmonton Green,51.6248126,-0.0581806 +W7,Muswell Hill,51.5911816,-0.1443015 +W7,"Alexandra Park, Park Road",51.4309209,-0.0936496 +W7,Crouch End,51.5819979,-0.1221464 +W7,Finsbury Park Station,51.5646425,-0.1058553 +W8,Chase Farm Hospital,51.66689239999999,-0.1028125 +W8,Enfield,51.6522994,-0.0807119 +W8,Edmonton Green,51.6248126,-0.0581806 +W8,Lee Valley Leisure Complex,51.6318241,-0.0376722 +W9,Chase Farm Hospital,51.66689239999999,-0.1028125 +W9,Enfield,51.6522994,-0.0807119 +W9,Highlands Village,51.6464013,-0.1111452 +W9,Southgate,51.5280043,-0.18519 +W10,Crews Hill,51.6843047,-0.1105717 +W10,"Enfield Town, Cecil Road",51.6507162,-0.0802953 +W11,Chingford Hall Estate,51.609421,-0.025236 +W11,"Walthamstow, Crooked Billet",51.601088,-0.0159737 +W11,Walthamstow Central,51.5830128,-0.019886 +W12,"Walthamstow, Coppermill Lane",51.5803038,-0.0403725 +W12,Walthamstow Central,51.5830128,-0.019886 +W12,St James Street,51.5064993,-0.1393328 +W12,Whipps Cross,51.5095281,-0.229236 +W12,South Woodford,51.5095281,-0.229236 +W12,Wanstead,51.5767971,0.0249881 +W13,Leytonstone,51.51719869999999,-0.3207339 +W13,Wanstead,51.5767971,0.0249881 +W13,South Woodford,51.5912671,0.0264721 +W13,Woodford Green,51.6092549,0.0405521 +W13,Woodford Wells,51.51719869999999,-0.3207339 +W14,Woodford Bridge,51.6057309,0.0544589 +W14,Charlie Brown's Roundabout,51.5934938,0.0370989 +W14,South Woodford,51.4964278,-0.2085211 +W14,Wanstead,51.4964278,-0.2085211 +W14,Green Man Roundabout,51.5705591,0.0145584 +W14,Leytonstone,51.4964278,-0.2085211 +W14,"Leytonstone, Harrow Green",51.5582955,0.007356 +W14,Leyton,51.4964278,-0.2085211 +W14,"Leyton, Superstores",51.5558965,-0.0093311 +W15,"Higham Hill, Cogan Avenue",51.6012336,-0.0363719 +W15,"Forest Road, Palmerston Road",51.5858953,-0.0292291 +W15,Walthamstow Central,51.5830128,-0.019886 +W15,"Leyton, Bakers Arms",51.5749185,-0.013549 +W15,Whipps Cross,51.581499,0.0001219 +W15,Leytonstone,51.5649624,0.0088141 +W15,"Leyton, Town Hall",51.5702225,-0.0146938 +W15,Spitalfields Market,51.5197441,-0.07606879999999999 +W15,Spitalfields Market,51.5197441,-0.07606879999999999 +W15,Homerton Hospital,51.5478609,-0.0425903 +W15,Hackney Town Hall,51.54507210000001,-0.0563459 +W16,Chingford Mount,51.6185735,-0.0180318 +W16,Chingford Hatch,51.420389,-0.1287668 +W16,Highams Park,51.6083754,0.0014712 +W16,"Walthamstow, Wood Street",51.5864747,-0.0026968 +W16,"Leyton, Bakers Arms",51.5749185,-0.013549 +W16,Leytonstone,51.5649624,0.0088141 +W19,"Walthamstow, Argall Avenue",51.5701165,-0.0387872 +W19,St James Street,51.5064993,-0.1393328 +W19,Walthamstow Central,51.5830128,-0.019886 +W19,Whipps Cross,51.4255297,-0.2050566 +W19,Leytonstone,51.5649624,0.0088141 +W19,"Wanstead, Centre Road",51.5596482,0.0253062 +W19,Manor Park,51.550487,0.0514117 +W19,Ilford Broadway,51.4191743,-0.2000351 +W19,Ilford,51.4255297,-0.2050566 +X26,Heathrow Central,51.471184,-0.4527179999999999 +X26,Hatton Cross,51.4651031,-0.4157165 +X26,Kingston,51.41233,-0.300689 +X26,Sutton Town Centre,51.3614279,-0.193961 +X26,Wallington Green,51.3669885,-0.1543945 +X26,West Croydon,51.3769529,-0.0956895 +X68,"West Croydon, Limited Stop",51.3769529,-0.0956895 +X68,"Russell Square, Limited Stop",51.4309209,-0.0936496 +N1,Tottenham Court Road,51.5203145,-0.1340121 +N1,Aldwych,51.5132441,-0.1172819 +N1,Waterloo,51.5048541,-0.1136621 +N1,Elephant & Castle,51.4938058,-0.0977932 +N1,Bricklayer's Arms,51.4661409,-0.2174147 +N1,Surrey Quays,51.4944172,-0.0383063 +N1,"Greenwich, Cutty Sark",51.4933675,0.0098214 +N1,Charlton,51.4900403,0.0307737 +N1,Woolwich,51.4894752,0.06758829999999999 +N1,Plumstead Station,51.4896774,0.0847463 +N1,Abbey Wood,51.4926116,0.1188182 +N1,Thamesmead,51.50575809999999,0.1100586 +N2,Crystal Palace,51.4197233,-0.0830638 +N2,West Norwood,51.427905,-0.1002486 +N2,Tulse Hill Station,51.43986,-0.10505 +N2,"Brixton, Morval Road",51.456008,-0.1128301 +N2,Brixton,51.4612794,-0.1156148 +N2,Stockwell,51.4760412,-0.1263271 +N2,Vauxhall,51.4861671,-0.12172 +N2,Victoria,51.49554149999999,-0.1435602 +N2,Hyde Park Corner,51.5029347,-0.1508562 +N2,Marble Arch,51.5132225,-0.1588937 +N2,Marylebone,51.5188746,-0.1498955 +N3,Oxford Circus,51.5152543,-0.1420395 +N3,Piccadilly Circus,51.5099734,-0.13497 +N3,"Whitehall, Horse Guards",51.5049889,-0.1265748 +N3,Parliament Square,51.5010421,-0.1268514 +N3,Kennington Lane,51.4884765,-0.1112969 +N3,Kennington Church,51.5055111,-0.1940999 +N3,Brixton,51.4612794,-0.1156148 +N3,Brixton,51.4612794,-0.1156148 +N3,"Brixton, Morval Road",51.456008,-0.1128301 +N3,Herne Hill,51.4609208,-0.0985404 +N3,South Croxted Road,51.432326,-0.0894342 +N3,Crystal Palace,51.4197233,-0.0830638 +N3,Penge,51.41388490000001,-0.0570112 +N3,Beckenham Junction,51.40817,-0.025813 +N3,Bromley North,51.406025,0.013156 +N5,Edgware,51.61548819999999,-0.2609598 +N5,Colindale,51.5896908,-0.2491029 +N5,Burnt Oak Broadway,51.602753,-0.2700278 +N5,Hendon Central,51.583202,-0.226399 +N5,Golders Green,51.5740013,-0.1987725 +N5,Camden Town,51.5390261,-0.1425516 +N5,Camden Town,51.5390261,-0.1425516 +N5,Mornington Crescent,51.5334445,-0.1404782 +N5,Warren Street,51.5240516,-0.1399547 +N5,Tottenham Court Road,51.5203145,-0.1340121 +N5,Trafalgar Square,51.508039,-0.128069 +N7,Northolt,51.546615,-0.373103 +N7,Greenford Broadway,51.5279556,-0.3540139 +N7,Ealing Broadway,51.5132537,-0.3043136 +N7,"Acton, High Street",51.5071042,-0.270558 +N7,East Acton,51.5127758,-0.2476803 +N7,East Acton,51.5127758,-0.2476803 +N7,North Pole Road,51.5195492,-0.2265871 +N7,Ladbroke Grove,51.5178769,-0.2103321 +N7,Chepstow Road,51.5167339,-0.1955587 +N7,Chepstow Road,51.5167339,-0.1955587 +N7,Edgware Road Station,51.51988249999999,-0.1678336 +N7,Marble Arch,51.5132225,-0.1588937 +N7,Oxford Circus,51.5152543,-0.1420395 +N8,"Hainault, The Lowe",51.6099517,0.1092883 +N8,Barkingside,51.5833118,-0.1236257 +N8,Gants Hill,51.5767812,0.0661732 +N8,Redbridge Station,51.5763264,0.0453986 +N8,Wanstead,51.5833118,-0.1236257 +N8,Leytonstone,51.5833118,-0.1236257 +N8,Stratford,51.5833118,-0.1236257 +N8,Bow Interchange,51.52974,-0.0140839 +N8,Old Ford,51.535812,-0.021259 +N8,"Roman Road, Grove Road",51.531048,-0.03955699999999999 +N8,Shoreditch,51.5229106,-0.0777472 +N8,Liverpool Street,51.5175001,-0.0826966 +N8,St. Paul's,51.5833118,-0.1236257 +N8,City Thameslink,51.5140438,-0.1033475 +N8,Holborn,51.5833118,-0.1236257 +N8,Tottenham Court Road,51.5203145,-0.1340121 +N8,Oxford Circus,51.51521169999999,-0.1418553 +N9,Aldwych,51.5132441,-0.1172819 +N9,Trafalgar Square,51.508039,-0.128069 +N9,Green Park,51.62810440000001,-0.0559765 +N9,Hyde Park Corner,51.5029347,-0.1508562 +N9,Hyde Park Corner,51.5029347,-0.1508562 +N9,Royal Albert Hall,51.5009088,-0.177366 +N9,Hammersmith,51.62810440000001,-0.0559765 +N9,Turnham Green,51.49203019999999,-0.2663174 +N9,Chiswick Roundabout,51.4910362,-0.2816861 +N9,"Brentford, County Court",51.4842409,-0.3043609 +N9,"Hounslow, Bus Station",51.4708688,-0.3546457 +N9,Hounslow West,51.469435,-0.3837709 +N9,Heathrow Central,51.62810440000001,-0.0559765 +N9,Heathrow Terminal 5,51.471466,-0.4879806 +N11,Ealing Broadway,51.5146192,-0.3022912 +N11,Northfields,51.5041461,-0.3186474 +N11,"Acton, High Street",51.5071042,-0.270558 +N11,Hammersmith,51.6175062,-0.1385339 +N11,"Chelsea, World's End",51.6175062,-0.1385339 +N11,"Whitehall, Horse Guards",51.5049889,-0.1265748 +N11,Aldwych,51.5132441,-0.1172819 +N11,Ludgate Circus,51.5140306,-0.1043143 +N11,Liverpool Street,51.5175001,-0.0826966 +N15,Romford Market,51.5790739,0.1813886 +N15,Roneo Corner,51.5655709,0.1869165 +N15,Becontree Heath,51.5609465,0.1488995 +N15,Bennett's Castle Lane,51.5562949,0.1276031 +N15,Fair Cross,51.5833519,-0.07649299999999999 +N15,Barking,51.5833519,-0.07649299999999999 +N15,Barking,51.5833519,-0.07649299999999999 +N15,"East Ham, Newham Town Hall",51.53280239999999,0.0551608 +N15,Upton Park,51.53471750000001,0.0337596 +N15,"Canning Town, Barking Road",51.5180017,0.0130984 +N15,Canning Town,51.5189494,0.0132 +N15,"Poplar, All Saints",51.5105521,-0.0118612 +N15,"Limehouse, Burdett Road",51.5150014,-0.0285662 +N15,Aldgate,51.5134365,-0.0772463 +N15,Cannon Street,51.5119949,-0.091962 +N15,Ludgate Circus,51.5140306,-0.1043143 +N15,Aldwych,51.5132441,-0.1172819 +N15,Trafalgar Square,51.508039,-0.128069 +N16,Edgware,51.5623078,-0.0764353 +N16,Burnt Oak Broadway,51.602753,-0.2700278 +N16,Cricklewood Bus Garage,51.56195959999999,-0.2224221 +N16,Cricklewood Broadway,51.5567072,-0.2153734 +N16,Kilburn High Road Station,51.537243,-0.192318 +N16,Kilburn High Road Station,51.537243,-0.192318 +N16,Edgware Road Station,51.51988249999999,-0.1678336 +N16,Marble Arch,51.5132225,-0.1588937 +N16,"Park Lane, Hilton Hotel",51.5623078,-0.0764353 +N16,Victoria,51.49554149999999,-0.1435602 +N18,"Harrow Weald, Bus Garage",51.6064297,-0.3405434 +N18,Harrow,51.61493060000001,-0.0765796 +N18,Sudbury,51.5556591,-0.3171114 +N18,Craven Park,51.5409981,-0.2563872 +N18,"Harlesden, Jubilee Clock",51.5354215,-0.2479155 +N18,"Harrow Road, Police Station",51.552225,-0.3025793 +N18,"Harrow Road, Warwick Avenue",51.521152,-0.1806301 +N18,Paddington Green,51.5207075,-0.1737114 +N18,Baker Street Station,51.5231548,-0.156863 +N18,Oxford Circus,51.51521169999999,-0.1418553 +N18,Piccadilly Circus,51.5099734,-0.13497 +N18,Trafalgar Square,51.508039,-0.128069 +N19,Finsbury Park Station,51.5646425,-0.1058553 +N19,Highbury Barn,51.553813,-0.09808739999999999 +N19,Highbury & Islington,51.5648883,-0.1323808 +N19,Islington Green,51.5359664,-0.1028448 +N19,Rosebery Avenue,51.5262828,-0.1094047 +N19,Holborn,51.5648883,-0.1323808 +N19,Piccadilly Circus,51.5099734,-0.13497 +N19,Hyde Park Corner,51.5029347,-0.1508562 +N19,Hyde Park Corner,51.5029347,-0.1508562 +N19,Sloane Square,51.4927684,-0.1570174 +N19,Sloane Square,51.4927684,-0.1570174 +N19,"Battersea Bridge, South Side",51.4811674,-0.1725411 +N19,Clapham Junction,51.4651737,-0.1708113 +N20,Barnet Church,51.6526856,-0.1992227 +N20,Totteridge & Whetstone,51.630241,-0.179144 +N20,North Finchley,51.6135087,-0.1754198 +N20,East Finchley,51.592468,-0.1664342 +N20,East Finchley,51.592468,-0.1664342 +N20,Archway,51.63585519999999,-0.1947779 +N20,Camden Town,51.63585519999999,-0.1947779 +N20,Camden Town,51.63585519999999,-0.1947779 +N20,Mornington Crescent,51.5343501,-0.1388961 +N20,Euston,51.5280408,-0.1333271 +N20,Warren Street,51.63585519999999,-0.1947779 +N20,Trafalgar Square,51.508039,-0.128069 +N21,"Bexleyheath, Shopping Centre",51.6359737,-0.1002426 +N21,Blendon,51.6359737,-0.1002426 +N21,"Eltham, High Street",51.4507726,0.0561761 +N21,"Lewisham, Shopping Centre",51.46175909999999,-0.0119106 +N21,New Cross,51.4769047,-0.0336897 +N21,New Cross Gate,51.4749904,-0.0403466 +N21,New Cross Gate,51.4749904,-0.0403466 +N21,Bricklayer's Arms,51.4661322,-0.2166946 +N21,London Bridge,51.6359737,-0.1002426 +N21,Ludgate Circus,51.5140306,-0.1043143 +N21,Aldwych,51.5132441,-0.1172819 +N21,Trafalgar Square,51.508039,-0.128069 +N22,Fulwell,51.6017398,-0.1148607 +N22,Richmond,51.6017398,-0.1148607 +N22,"North Sheen, Manor Circus",51.4653637,-0.2863842 +N22,Putney Bridge,51.4669712,-0.2129034 +N22,Parsons Green,51.4747689,-0.2002723 +N22,"Chelsea, World's End",51.6017398,-0.1148607 +N22,Sloane Square,51.4927684,-0.1570174 +N22,Knightsbridge,51.4991195,-0.1644394 +N22,Hyde Park Corner,51.5029347,-0.1508562 +N22,Green Park,51.6017398,-0.1148607 +N22,Piccadilly Circus,51.5099734,-0.13497 +N26,Trafalgar Square,51.508039,-0.128069 +N26,Ludgate Circus,51.5140306,-0.1043143 +N26,Liverpool Street,51.5175001,-0.0826966 +N26,Shoreditch,51.5229106,-0.0777472 +N26,Ash Grove,51.5358094,-0.0581907 +N26,"Hackney, Well Street",51.5424028,-0.0488388 +N26,Hackney Wick,51.544579,-0.0256935 +N26,Walthamstow Central,51.5901769,-0.0173437 +N26,"Walthamstow, Crooked Billet",51.601088,-0.0159737 +N26,Chingford Mount,51.6185735,-0.0180318 +N26,Chingford Station,51.6320667,0.007362700000000001 +N28,Camden Town,51.53328,-0.1734435 +N28,Chalk Farm,51.5444834,-0.152158 +N28,Swiss Cottage,51.53328,-0.1734435 +N28,Swiss Cottage,51.53328,-0.1734435 +N28,South Hampstead Stn,51.5412969,-0.1790611 +N28,Kilburn Park,51.53504119999999,-0.1938988 +N28,"Maida Hill, The Chippenham",51.5272288,-0.1769259 +N28,Westbourne Park,51.53328,-0.1734435 +N28,Notting Hill Gate,51.5092063,-0.1962355 +N28,"Kensington, Holland Road",51.5010095,-0.1932794 +N28,West Brompton,51.483494,-0.196802 +N28,Fulham Broadway,51.4803328,-0.1943638 +N28,"Wandsworth Bridge, South Side",51.4651939,-0.1880094 +N28,Wandsworth,51.53328,-0.1734435 +N29,Enfield,51.6522994,-0.0807119 +N29,Wood Green,51.5971722,-0.1098021 +N29,Turnpike Lane Station,51.5904278,-0.1027587 +N29,Finsbury Park Station,51.5646425,-0.1058553 +N29,"Holloway, Nag's Head",51.55724250000001,-0.1204364 +N29,"Holloway, Nag's Head",51.55724250000001,-0.1204364 +N29,Mornington Crescent,51.5334445,-0.1404782 +N29,Warren Street,51.5240516,-0.1399547 +N29,Trafalgar Square,51.508039,-0.128069 +N31,Camden Town,51.5390261,-0.1425516 +N31,Chalk Farm,51.5444834,-0.152158 +N31,Swiss Cottage,51.5425872,-0.1724737 +N31,South Hampstead Station,51.5412969,-0.1790611 +N31,Kilburn High Road Station,51.537243,-0.192318 +N31,Kilburn Park,51.53504119999999,-0.1938988 +N31,"Maida Hill, The Chippenham",51.5243627,-0.2017331 +N31,Notting Hill Gate,51.5090534,-0.1966727 +N31,Westbourne Park,51.51769299999999,-0.194941 +N31,"Kensington, Commonwealth Institute",51.5010095,-0.1932794 +N31,Earls Court Station,51.4915677,-0.1939564 +N31,Clapham Junction,51.4651737,-0.1708113 +N38,Walthamstow Central,51.5901769,-0.0173437 +N38,Clapton Pond,51.5561061,-0.05490830000000001 +N38,Mildmay Park,51.5488355,-0.0843157 +N38,Islington Angel,51.5346761,-0.1042905 +N38,Rosebery Avenue,51.5262828,-0.1094047 +N38,Piccadilly Circus,51.5099734,-0.13497 +N38,Hyde Park Corner,51.5029347,-0.1508562 +N38,Victoria,51.49554149999999,-0.1435602 +N41,Trafalgar Square,51.508039,-0.128069 +N41,Holborn,51.5175802,-0.1145147 +N41,Rosebery Avenue,51.5262828,-0.1094047 +N41,Islington Angel,51.5346761,-0.1042905 +N41,Islington Green,51.5359664,-0.1028448 +N41,Highbury & Islington,51.5569649,-0.0979656 +N41,"Holloway, Nag's Head",51.55724250000001,-0.1204364 +N41,Archway,51.5648883,-0.1323808 +N41,Hornsey Rise,51.5721143,-0.12519 +N41,Hornsey,51.5872715,-0.1103806 +N41,West Green,51.586254,-0.0867628 +N41,Turnpike Lane Station,51.5904278,-0.1027587 +N41,Seven Sisters,51.582652,-0.0747232 +N41,Tottenham Hale,51.5892808,-0.06105049999999999 +N44,Aldwych,51.5132441,-0.1172819 +N44,Victoria,51.49554149999999,-0.1435602 +N44,Battersea Park Station,51.47220069999999,-0.165547 +N44,Wandsworth,51.45837299999999,-0.1891356 +N44,Tooting Station,51.41986989999999,-0.16136 +N44,Mitcham,51.402869,-0.166709 +N44,Sutton Station,51.3614279,-0.193961 +N55,Woodford Wells,51.6148287,0.0282889 +N55,South Woodford,51.5912671,0.0264721 +N55,Wanstead,51.5767971,0.0249881 +N55,Whipps Cross,51.581499,0.0001219 +N55,"Leyton, Bakers Arms",51.5749185,-0.013549 +N55,Clapton Pond,51.5561061,-0.05490830000000001 +N55,Hackney Well Street,51.5424028,-0.0488388 +N55,Ash Grove,51.5358094,-0.0581907 +N55,Shoreditch,51.5229106,-0.0777472 +N55,Old Street Station,51.5256719,-0.0874922 +N55,Old Street Station,51.5256719,-0.0874922 +N55,Clerkenwell Green,51.522739,-0.1060289 +N55,Holborn,51.5175802,-0.1145147 +N55,Holborn,51.5175802,-0.1145147 +N55,Oxford Circus,51.5152543,-0.1420395 +N55,"Leyton, Bakers Arms",51.5749185,-0.013549 +N63,Crystal Palace,51.4197233,-0.0830638 +N63,Honor Oak,51.4489977,-0.0457341 +N63,Peckham Rye,51.4603208,-0.0603961 +N63,Peckham,51.47032369999999,-0.0673872 +N63,Elephant & Castle,51.4938058,-0.0977932 +N63,Clerkenwell Green,51.522739,-0.1060289 +N63,King's Cross,51.5347488,-0.1245845 +N68,Old Coulsdon,51.298482,-0.114175 +N68,Coulsdon,51.319941,-0.141267 +N68,Purley,51.339228,-0.119711 +N68,"South Croydon, South End",51.3650199,-0.099012 +N68,Croydon Town Centre,51.3769529,-0.0956895 +N68,Upper Norwood,51.41376716037048, -0.09204081941649297 +N68,Upper Norwood,51.41376716037048, -0.09204081941649297 +N68,Tulse Hill Station,51.43986,-0.10505 +N68,Herne Hill,51.4609208,-0.0985404 +N68,Camberwell Green,51.4748827,-0.0921158 +N68,Elephant & Castle,51.4938058,-0.0977932 +N68,Waterloo,51.5048541,-0.1136621 +N68,Aldwych,51.5132441,-0.1172819 +N68,Tottenham Court Road,51.5203145,-0.1340121 +N73,Victoria,51.49554149999999,-0.1435602 +N73,"Park Lane, Hilton Hotel",51.5083331,-0.1547189 +N73,Marble Arch,51.5132225,-0.1588937 +N73,Oxford Circus,51.5152543,-0.1420395 +N73,Euston,51.5280408,-0.1333271 +N73,King's Cross,51.5347488,-0.1245845 +N73,Islington Angel,51.5346761,-0.1042905 +N73,Newington Green,51.5514507,-0.0857535 +N73,Stoke Newington,51.561175,-0.08349229999999999 +N73,Stamford Hill,51.5696514,-0.0750199 +N73,"Tottenham, Town Hall",51.5872187,-0.0725467 +N73,Tottenham Hale,51.5892808,-0.06105049999999999 +N73,Walthamstow Central,51.5901769,-0.0173437 +N74,"Roehampton, Danebury Avenue",51.451943,-0.247966 +N74,Putney Bridge,51.4669712,-0.2129034 +N74,West Brompton,51.483494,-0.196802 +N74,Earl's Court,51.490331,-0.1958417 +N74,Hyde Park Corner,51.5029347,-0.1508562 +N74,Marble Arch,51.5132225,-0.1588937 +N74,Portman Square,51.5161534,-0.1560125 +N74,Baker Street Station,51.5231548,-0.156863 +N83,Golders Green,51.5740013,-0.1987725 +N83,"Hendon, Queens Road",51.5833703,-0.222686 +N83,West Hendon Broadway,51.5772325,-0.2392682 +N83,Kingsbury Green,51.5814409,-0.2619577 +N83,Wembley Arena,51.550501,-0.3048409 +N83,Wembley Stadium,51.55602469999999,-0.2796177 +N83,Alperton,51.539601,-0.2988365 +N83,"Alperton, Sainsbury's",51.5383862,-0.3028583 +N83,Ealing Broadway,51.5132537,-0.3043136 +N83,Ealing Broadway,51.5132537,-0.3043136 +N83,Ealing Hospital,51.5075205,-0.3465216 +N86,Stratford,51.5426313,-0.0010369 +N86,"Woodgrange Park, Katherine Road",51.5391367,0.0407963 +N86,Manor Park,51.550487,0.0514117 +N86,Ilford Broadway,51.5584078,0.07077839999999999 +N86,Ilford,51.556619,0.076251 +N86,Chadwell Heath,51.5722283,0.141995 +N86,Romford North Street Bus Garage,51.5823836,0.1761951 +N86,Romford Market,51.577076,0.178319 +N86,Romford Station,51.57472449999999,0.1826519 +N86,"Gallows Corner, Main Road",51.5922565,0.2142701 +N86,Gallows Corner,51.59188200000001,0.214546 +N86,"Harold Hill, Dagnam Park Square",51.6049149,0.2445527 +N87,Kingston,51.41233,-0.300689 +N87,"New Malden, Fountain Roundabout",51.40066299999999,-0.259263 +N87,Raynes Park,51.4084257,-0.2298751 +N87,Wimbledon,51.41833889999999,-0.2206288 +N87,Wandsworth,51.45837299999999,-0.1891356 +N87,Clapham Junction,51.4651737,-0.1708113 +N87,Clapham Junction,51.4651737,-0.1708113 +N87,Vauxhall,51.4861671,-0.12172 +N87,"Whitehall, Horse Guards",51.5049889,-0.1265748 +N87,Aldwych,51.5132441,-0.1172819 +N89,Trafalgar Square,51.508039,-0.128069 +N89,New Cross Gate,51.4749904,-0.0403466 +N89,Blackheath Village,51.4657729,0.0091238 +N89,"Blackheath, Royal Standard",51.4658393,0.0090338 +N89,"Shooters Hill Road, Sun-In-The-Sands",51.4745909,0.0240901 +N89,"Shooters Hill, Eaglesfield Road",51.4686795,0.06966449999999999 +N89,Welling Corner,51.4626258,0.1081541 +N89,"Bexleyheath, Shopping Centre",51.45334099999999,0.13822 +N89,"Bexleyheath, Bus Garage",51.46006930000001,0.1534245 +N89,"Northend Road, Thames Road",51.4686147,0.1810608 +N89,Slade Green,51.4695282,0.1928854 +N89,Erith,51.480818,0.174675 +N91,Cockfosters,51.647851,-0.151255 +N91,Oakwood,51.6481224,-0.1309298 +N91,Southgate,51.62476119999999,-0.1240456 +N91,Arnos Grove,51.619799,-0.1296871 +N91,Wood Green Station,51.5971722,-0.1098021 +N91,Turnpike Lane Station,51.5904278,-0.1027587 +N91,Crouch End,51.5819979,-0.1221464 +N91,"Holloway, Nag's Head",51.55724250000001,-0.1204364 +N91,King's Cross,51.5347488,-0.1245845 +N91,Russell Square,51.5221667,-0.1249807 +N91,Aldwych,51.5132441,-0.1172819 +N91,Trafalgar Square,51.508039,-0.128069 +N97,Hammersmith,51.491187,-0.223731 +N97,Earl's Court,51.490331,-0.1958417 +N97,Hyde Park Corner,51.5029347,-0.1508562 +N97,Hyde Park Corner,51.5029347,-0.1508562 +N97,Green Park,51.5039052,-0.1438484 +N97,Piccadilly Circus,51.5099734,-0.13497 +N97,Trafalgar Square,51.508039,-0.128069 +N98,Stanmore Station,51.617676,-0.311451 +N98,Queensbury Station,51.5942415,-0.2861271 +N98,Kingsbury Circle,51.5853429,-0.2812115 +N98,"Neasden, Shopping Centre",51.5626819,-0.2536987 +N98,"Willesden, Bus Garage",51.5474482,-0.2394372 +N98,/,51.4309209,-0.0936496 +N98,Kilburn Park,51.53504119999999,-0.1938988 +N98,Marble Arch,51.5132225,-0.1588937 +N98,Marble Arch,51.5132225,-0.1588937 +N98,Oxford Circus,51.5152543,-0.1420395 +N98,Holborn,51.5175802,-0.1145147 +N109,Croydon Town Centre,51.3769529,-0.0956895 +N109,West Croydon,51.3769529,-0.0956895 +N109,Thornton Heath Pond,51.3941232,-0.1146955 +N109,"Streatham, Green Lane",51.4147104,-0.1158693 +N109,Streatham Station,51.4259857,-0.131308 +N109,Streatham Hill Station,51.4382009,-0.1270706 +N109,Kennington Church,51.5055111,-0.1940999 +N109,Kennington Lane,51.4884765,-0.1112969 +N109,Trafalgar Square,51.508039,-0.128069 +N109,Oxford Circus,51.5152543,-0.1420395 +N113,Edgware,51.61548819999999,-0.2609598 +N113,Apex Corner,51.4369075,-0.3784005 +N113,Hendon Central,51.583202,-0.226399 +N113,Hendon Central,51.583202,-0.226399 +N113,Swiss Cottage,51.5425872,-0.1724737 +N113,Baker Street Station,51.5231548,-0.156863 +N113,Trafalgar Square,51.508039,-0.128069 +N133,Morden,51.394943,-0.19446 +N133,Mitcham,51.402869,-0.166709 +N133,"Rowan Road, Manor Road",51.4039785,-0.136848 +N133,"Streatham, St. Leonard's Church",51.42926610000001,-0.1311095 +N133,Streatham Hill Station,51.4382009,-0.1270706 +N133,Brixton,51.4612794,-0.1156148 +N133,Kennington Church,51.5055111,-0.1940999 +N133,Elephant & Castle,51.4938058,-0.0977932 +N133,London Bridge,51.5078788,-0.0877321 +N133,Monument,51.4309209,-0.0936496 +N133,Liverpool Street,51.5175001,-0.0826966 +N136,Oxford Circus,51.5152543,-0.1420395 +N136,Piccadilly Circus,51.5099734,-0.13497 +N136,"Whitehall, Horse Guards",51.5049111,-0.1273704 +N136,Vauxhall,51.4861671,-0.12172 +N136,Camberwell Green,51.4748827,-0.0921158 +N136,Peckham,51.47032369999999,-0.0673872 +N136,New Cross Gate,51.4749904,-0.0403466 +N136,New Cross,51.4769047,-0.0336897 +N136,"Lewisham, Shopping Centre",51.46175909999999,-0.0119106 +N136,"Catford, Town Centre",51.4453954,-0.0160913 +N136,"Downham, Bromley Road",51.4249009,-0.0042485 +N136,"Bellingham, Catford Bus Garage",51.434704,-0.017839 +N136,Grove Park,51.4329249,0.021203 +N136,"Chislehurst, War Memorial",51.4124839,0.07390759999999999 +N137,Crystal Palace,51.4197233,-0.0830638 +N137,"Norwood, Crown Point",41.4169806,-87.3653135 +N137,Streatham Hill Station,51.4382009,-0.1270706 +N137,"Streatham Hill, Telford Avenue",51.4421746,-0.1300019 +N137,Clapham Common,51.4556465,-0.1385544 +N137,Clapham Park,51.4476066,-0.1431943 +N137,Queenstown Road Station,51.4749596,-0.1466578 +N137,Battersea Park Station,51.47696,-0.14751 +N137,Sloane Square,51.4927684,-0.1570174 +N137,Sloane Square,51.4927684,-0.1570174 +N137,Hyde Park Corner,51.5029347,-0.1508562 +N137,Marble Arch,51.5132225,-0.1588937 +N137,Oxford Circus,51.5152543,-0.1420395 +N155,Morden,51.394943,-0.19446 +N155,Tooting Broadway,51.427867,-0.1678142 +N155,Clapham Common,51.4556465,-0.1385544 +N155,Stockwell,51.4760412,-0.1263271 +N155,Elephant & Castle,51.4938058,-0.0977932 +N155,"Whitehall, Horse Guards",51.5049111,-0.1273704 +N155,Aldwych,51.5132441,-0.1172819 +N171,Hither Green Station,51.4519061,-0.0007435 +N171,"Catford, Town Centre",51.4453954,-0.0160913 +N171,Brockley Rise,51.4473951,-0.0416563 +N171,New Cross Gate,51.4749904,-0.0403466 +N171,Peckham,51.47032369999999,-0.0673872 +N171,Camberwell Green,51.4748827,-0.0921158 +N171,Elephant & Castle,51.4938058,-0.0977932 +N171,Waterloo,51.5048541,-0.1136621 +N171,Aldwych,51.5132441,-0.1172819 +N171,Tottenham Court Road,51.5203145,-0.1340121 +N199,Trafalgar Square,51.508039,-0.128069 +N199,Aldwych,51.5132441,-0.1172819 +N199,London Bridge,51.5078788,-0.0877321 +N199,Canada Water,51.4962989,-0.0482742 +N199,Surrey Quays,51.4944172,-0.0383063 +N199,Deptford,51.4807988,-0.0231099 +N199,"Greenwich, Cutty Sark",51.4828646,-0.0095917 +N199,Lewisham,51.46115090000001,-0.0073177 +N199,"Lewisham, Shopping Centre",51.46175909999999,-0.0119106 +N199,"Bellingham, Catford Bus Garage",51.434704,-0.017839 +N199,Bromley South,51.406025,0.013156 +N199,Petts Wood,51.389636,0.08195 +N199,"Orpington, Perry Hall Road",51.3823992,0.0998353 +N199,St. Mary Cray Station,51.3957762,0.1071945 +N205,Paddington,51.515973,-0.174943 +N205,Marylebone,51.5188746,-0.1498955 +N205,Baker Street Station,51.5231548,-0.156863 +N205,Warren Street,51.5240516,-0.1399547 +N205,Warren Street,51.5240516,-0.1399547 +N205,Euston,51.5280408,-0.1333271 +N205,King's Cross,51.5347488,-0.1245845 +N205,Islington Angel,51.5346761,-0.1042905 +N205,Old Street Station,51.5256719,-0.0874922 +N205,Liverpool Street,51.5175001,-0.0826966 +N205,Aldgate,51.5134365,-0.0772463 +N205,Whitechapel,51.5148198,-0.0650534 +N205,Mile End,51.52354529999999,-0.0330122 +N205,Bow Church,51.5287753,-0.0167013 +N205,Leyton Downsell Road,51.5533905,-0.0020391 +N207,Uxbridge,51.5485,-0.479611 +N207,Coney Green,51.534156,-0.4588592 +N207,Hayes End,51.5257,-0.4357732 +N207,Hayes By-Pass,51.51593,-0.398889 +N207,"Southall, Town Hall",51.5113272,-0.3751471 +N207,Southall Park,51.5094438,-0.3697251 +N207,Ealing Hospital,51.5075205,-0.3465216 +N207,Ealing Broadway,51.5146192,-0.3022912 +N207,"Acton, High Street",51.5071042,-0.270558 +N207,Acton Vale,51.5065594,-0.2567913 +N207,Shepherd's Bush,51.5051913,-0.22469 +N207,Notting Hill Gate,51.5090534,-0.1966727 +N207,Lancaster Gate,51.5115786,-0.1802482 +N207,Marble Arch,51.5132225,-0.1588937 +N207,Oxford Circus,51.5152543,-0.1420395 +N207,Holborn,51.5175802,-0.1145147 +N253,Aldgate,51.5134365,-0.0772463 +N253,Ash Grove,51.5358094,-0.0581907 +N253,Hackney Central,51.5482344,-0.05738749999999999 +N253,Clapton Pond,51.5561061,-0.05490830000000001 +N253,Stamford Hill,51.5696514,-0.0750199 +N253,Manor House,51.4309209,-0.0936496 +N253,Finsbury Park Station,51.5646425,-0.1058553 +N253,"Holloway, Nags Head",51.55724250000001,-0.1204364 +N253,"Camden Road, Brecknock Road",51.5488418,-0.1290968 +N253,Camden Town,51.5390261,-0.1425516 +N253,Mornington Crescent,51.5334445,-0.1404782 +N253,Euston,51.5280408,-0.1333271 +N253,Warren Street,51.5240516,-0.1399547 +N253,Tottenham Court Road,51.5203145,-0.1340121 +N279,Waltham Cross,51.68584389999999,-0.0330964 +N279,Enfield Highway,51.652918,-0.041145 +N279,Edmonton Green,51.6248126,-0.0581806 +N279,"Snells Park, Sainsburys",51.609054,-0.0691713 +N279,"Tottenham, Town Hall",51.5872187,-0.0725467 +N279,"Tottenham, Town Hall",51.5872187,-0.0725467 +N279,Manor House,51.4309209,-0.0936496 +N279,Finsbury Park Station,51.5646425,-0.1058553 +N279,Finsbury Park Station,51.5646425,-0.1058553 +N279,"Holloway, Nag's Head",51.55724250000001,-0.1204364 +N279,"Camden Road, Brecknock Road",51.5488418,-0.1290968 +N279,Camden Town,51.5390261,-0.1425516 +N279,Mornington Crescent,51.5334445,-0.1404782 +N279,Warren Street,51.5240516,-0.1399547 +N279,Trafalgar Square,51.508039,-0.128069 +N343,Trafalgar Square,51.508039,-0.128069 +N343,Aldwych,51.5132441,-0.1172819 +N343,London Bridge,51.5078788,-0.0877321 +N343,Elephant & Castle,51.4938058,-0.0977932 +N343,Brockley,51.46377160000001,-0.0366031 +N343,New Cross Gate,51.4749904,-0.0403466 +N381,Peckham,51.47032369999999,-0.0673872 +N381,Rotherhithe,51.49628999999999,-0.0411931 +N381,Waterloo,51.5048541,-0.1136621 +N381,"Whitehall, Horse Guards",51.5049111,-0.1273704 +N550,Trafalgar Square,51.508039,-0.128069 +N550,Aldgate,51.5134365,-0.0772463 +N550,Cannon Street,51.5119949,-0.091962 +N550,"Limehouse, Burdett Road",51.5150014,-0.0285662 +N550,"Poplar, All Saints",51.5105521,-0.0118612 +N550,Canning Town,51.5189494,0.0132 +N551,Trafalgar Square,51.508039,-0.128069 +N551,Aldwych,51.5132441,-0.1172819 +N551,Aldgate,51.5134365,-0.0772463 +N551,Limehouse,51.5110598,-0.0366652 +N551,"Poplar, All Saints",51.5105521,-0.0118612 +N551,Canning Town,51.5189494,0.0132 +N551,Keir Hardie Estate,51.5678758,-0.0607466 +N551,Prince Regent,51.4309209,-0.0936496 +N551,Beckton Station,51.5144016,0.06153319999999999 +N551,"Gallions Reach, Shopping Park",51.5166002,0.0783827 diff --git a/lib/audio_cache.dart b/lib/audio_cache.dart index a455fc4..ed17ff6 100644 --- a/lib/audio_cache.dart +++ b/lib/audio_cache.dart @@ -13,8 +13,15 @@ class AudioCache { return _audioCache.keys.toList(); } - Uint8List operator [](String key) { - return _audioCache[key]!; + Uint8List? operator [](String key) { + // ignore case + key = key.toLowerCase(); + for (var k in _audioCache.keys) { + if (k.toLowerCase() == key) { + return _audioCache[k]; + } + } + return null; } } @@ -22,7 +29,21 @@ class AnnouncementCache extends AudioCache { String _assetLocation = "assets/ibus_recordings.zip"; - Future loadAnnouncements(List Announcements) async { + Future loadAnnouncements(List announcements) async { + + List _announements = []; + + + // remove any announcements that are already loaded + for (var announcement in announcements) { + if (!_audioCache.containsKey(announcement.toLowerCase())) { + _announements.add(announcement); + } + } + + if (_announements.length == 0) { + return; + } final bytes = await rootBundle.load(_assetLocation); final archive = ZipDecoder().decodeBytes(bytes.buffer.asUint8List()); @@ -34,9 +55,9 @@ class AnnouncementCache extends AudioCache { filename = filename.split("/").last; } - if (Announcements.contains(filename)) { - _audioCache[filename] = file.content; - print("Loaded announcement: ${filename}"); + if (_announements.contains(filename)) { + _audioCache[filename.toLowerCase()] = file.content; + print("Loaded announcement: $filename"); } } } @@ -62,7 +83,7 @@ class AnnouncementCache extends AudioCache { filename = filename.split("/").last; } - _audioCache[filename] = file.content; + _audioCache[filename.toLowerCase()] = file.content; } print("Done loading all announcements."); diff --git a/lib/auth/api_constants.dart b/lib/auth/api_constants.dart index 07afed2..559eb5e 100644 --- a/lib/auth/api_constants.dart +++ b/lib/auth/api_constants.dart @@ -8,6 +8,7 @@ class ApiConstants { static const String MANUAL_Q_COLLECTION_ID = "65de9f2f925562a2eda8"; static const String INFORMATION_Q_COLLECTION_ID = "65de9f1b6282fd209bdb"; static const String DEST_Q_COLLECTION_ID = "65de9ef464bfa5a0693d"; + static const String COMMANDS_COLLECTION_ID = "65e035c82dbae432bafe"; diff --git a/lib/backend/live_information.dart b/lib/backend/live_information.dart new file mode 100644 index 0000000..b59de26 --- /dev/null +++ b/lib/backend/live_information.dart @@ -0,0 +1,179 @@ + +// Singleton +import 'dart:async'; +import 'dart:convert'; + +import 'package:appwrite/appwrite.dart' as appwrite; +import 'package:appwrite/models.dart' as models; +import 'package:bus_infotainment/audio_cache.dart'; +import 'package:bus_infotainment/auth/api_constants.dart'; +import 'package:bus_infotainment/auth/auth_api.dart'; +import 'package:bus_infotainment/backend/modules/announcement.dart'; +import 'package:bus_infotainment/backend/modules/commands.dart'; +import 'package:bus_infotainment/backend/modules/synced_time.dart'; +import 'package:bus_infotainment/backend/modules/tracker.dart'; +import 'package:bus_infotainment/tfl_datasets.dart'; +import 'package:bus_infotainment/utils/audio%20wrapper.dart'; +import 'package:bus_infotainment/utils/delegates.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; +import 'package:http/http.dart' as http; +import 'package:ntp/ntp.dart'; +import 'package:permission_handler/permission_handler.dart'; + +class LiveInformation { + + static final LiveInformation _singleton = LiveInformation._internal(); + + factory LiveInformation() { + return _singleton; + } + + LiveInformation._internal(); + + Future initialize() async { + + { + // By default, load the bus sequences from the assets + print("Loading bus sequences from assets"); + busSequences = BusSequences.fromCSV( + await rootBundle.loadString("assets/datasets/bus-blinds.csv"), + await rootBundle.loadString("assets/datasets/bus-sequences.csv") + ); + print("Loaded bus sequences from assets"); + + try { + + http.Response response = await http.get(Uri.parse('https://tfl.gov.uk/bus-sequences.csv')); + + busSequences = BusSequences.fromCSV( + await rootBundle.loadString("assets/datasets/bus-blinds.csv"), + response.body + ); + + print("Loaded bus sequences from TFL"); + + } catch (e) { + print("Failed to load bus sequences from TFL. Using local copy."); + } + + String sessionID = "test"; + + commandModule = CommandModule(sessionID); + + } + + // Initialise modules + syncedTimeModule = SyncedTimeModule(); + announcementModule = AnnouncementModule(); + + // Tracker module is not supported on desktop + if (defaultTargetPlatform != TargetPlatform.windows || defaultTargetPlatform != TargetPlatform.linux || defaultTargetPlatform != TargetPlatform.macOS) { + // Tracker module is not supported on web + await Permission.location.request(); + trackerModule = TrackerModule(); + } + } + + // Auth + AuthAPI auth = AuthAPI(); + + // Modules + late CommandModule commandModule; + late BusSequences busSequences; + late AnnouncementModule announcementModule; + late SyncedTimeModule syncedTimeModule; + late TrackerModule trackerModule; + + // Important variables + BusRouteVariant? _currentRouteVariant; + + // Events + EventDelegate routeVariantDelegate = EventDelegate(); + + // Internal methods + + + + + + Future setRouteVariant_Internal(BusRouteVariant routeVariant) async { + + // Set the current route variant + _currentRouteVariant = routeVariant; + + // Let everyone know that the route variant has been set/changed + routeVariantDelegate.trigger(routeVariant); + + // Get all of the files that need to be cached + List audioFiles = []; + + for (BusRouteStop stop in routeVariant.busStops) { + audioFiles.add(stop.getAudioFileName()); + } + + // Cache/Load the audio files + await announcementModule + .announcementCache + .loadAnnouncements(audioFiles); + } + + // Public methods + + BusRouteVariant? getRouteVariant() { + return _currentRouteVariant; + } + + Future setRouteVariant(BusRouteVariant routeVariant) async { + await commandModule.executeCommand( + "setroute ${routeVariant.busRoute.routeNumber} ${routeVariant.busRoute.routeVariants.values.toList().indexOf(routeVariant)}" + ); + } + + + + + + + + + /* + Everything under this will be considered legacy code + */ + + + + + +} + +class AnnouncementQueueEntry { + final String displayText; + final List audioSources; + bool sendToServer = true; + DateTime? scheduledTime; + DateTime? timestamp; + + AnnouncementQueueEntry({required this.displayText, required this.audioSources, this.sendToServer = true, this.scheduledTime, this.timestamp}); +} + +class NamedAnnouncementQueueEntry extends AnnouncementQueueEntry { + final String shortName; + + NamedAnnouncementQueueEntry({ + required this.shortName, + required String displayText, + required List audioSources, + DateTime? scheduledTime, + DateTime? timestamp, + bool sendToServer = true, + }) : super( + displayText: displayText, + audioSources: audioSources, + sendToServer: sendToServer, + scheduledTime: scheduledTime, + timestamp: timestamp, + ); +} + +var abs = (int value) => value < 0 ? -value : value; \ No newline at end of file diff --git a/lib/backend/modules/announcement.dart b/lib/backend/modules/announcement.dart new file mode 100644 index 0000000..6d68e89 --- /dev/null +++ b/lib/backend/modules/announcement.dart @@ -0,0 +1,330 @@ + +import 'dart:async'; +import 'dart:typed_data'; + +import 'package:bus_infotainment/audio_cache.dart'; +import 'package:bus_infotainment/backend/live_information.dart'; +import 'package:bus_infotainment/tfl_datasets.dart'; +import 'package:bus_infotainment/utils/audio%20wrapper.dart'; +import 'package:bus_infotainment/utils/delegates.dart'; + +import 'info_module.dart'; + +class AnnouncementModule extends InfoModule { + + AnnouncementCache announcementCache = AnnouncementCache(); + + // Constructor + AnnouncementModule() { + refreshTimer(); + } + + // Queue + List queue = []; + AnnouncementQueueEntry? currentAnnouncement; + DateTime? currentAnnouncementTimeStamp; + String defaultText = "*** NO MESSAGE ***"; + bool isPlaying = false; + + // Audio + AudioWrapper audioPlayer = AudioWrapper(); + + // Events + final EventDelegate onAnnouncement = EventDelegate(); + + // Timer + Timer refreshTimer() => Timer.periodic(const Duration(milliseconds: 200), (timer) async { + + if (!isPlaying) { + + if (queue.isNotEmpty) { + isPlaying = true; + AnnouncementQueueEntry nextAnnouncement = queue.first; + + bool proceeding = await _internalAccountForInconsistentTime( + announcement: nextAnnouncement, + timerInterval: const Duration(milliseconds: 200), + callback: () { + queue.removeAt(0); + print("Announcement proceeding"); + } + ); + + if (!proceeding) { + isPlaying = false; + print("Announcement not proceeding"); + print("Queue: ${queue.length}"); + return; + } + + currentAnnouncement = nextAnnouncement; + currentAnnouncementTimeStamp = liveInformation.syncedTimeModule.Now(); + + onAnnouncement.trigger(currentAnnouncement!); + + if (currentAnnouncement!.audioSources.isNotEmpty) { + try { + for (AudioWrapperSource source in currentAnnouncement!.audioSources) { + + await audioPlayer.loadSource(source); + + Duration? duration = await audioPlayer.play(); + await Future.delayed(duration!); + if (currentAnnouncement?.audioSources.last != source) { + await Future.delayed(const Duration(milliseconds: 100)); + } + } + audioPlayer.stop(); + + } catch (e) { + // Do nothing + print("Error playing announcement: $e"); + } + } else { + if (queue.isNotEmpty) { + await Future.delayed(const Duration(seconds: 5)); + } + } + + isPlaying = false; + + } + + } + + + }); + + // Will call the callback function if the announcement will be proceeding + Future _internalAccountForInconsistentTime({ + required AnnouncementQueueEntry announcement, + required Duration timerInterval, + required Function() callback + }) async { + DateTime now = liveInformation.syncedTimeModule.Now(); + if (announcement.scheduledTime != null) { + + if (now.isAfter(announcement.scheduledTime!)) { + callback(); + return true; + } + + int milisecondDifference = abs(now.millisecondsSinceEpoch - announcement.scheduledTime!.millisecondsSinceEpoch); + if (milisecondDifference <= timerInterval.inMilliseconds) { + // Account for the time lost by the periodic timer + callback(); + await Future.delayed(Duration(milliseconds: timerInterval.inMilliseconds - milisecondDifference)); + return true; + } else { + return false; + } + } else { + callback(); + return true; + } + } + + // Configuration + int get defaultAnnouncementDelay => liveInformation.auth.isAuthenticated() ? 2 : 0; + + // Methods + Future queueAnnounceByAudioName({ + required String displayText, + List audioNames = const [], + DateTime? scheduledTime = null, + bool sendToServer = true + }) async { + + if (sendToServer) { + + scheduledTime ??= liveInformation.syncedTimeModule.Now().add(Duration(seconds: defaultAnnouncementDelay)); + + String audioNamesString = ""; + + for (var audioName in audioNames) { + audioNamesString += "\"$audioName\" "; + } + + liveInformation.commandModule.executeCommand( + "announce manual \"$displayText\" ${audioNamesString} ${scheduledTime?.millisecondsSinceEpoch ?? ""}" + ); + + return; + } + + // Cache the announcements + await announcementCache.loadAnnouncements(audioNames); + + List sources = []; + + print("Audio names: $audioNames"); + + for (var audioName in audioNames) { + Uint8List? audioData = announcementCache[audioName]; + + if (audioData == null) { + continue; + } + + sources.add(AudioWrapperByteSource(audioData)); + + } + + queue.add( + AnnouncementQueueEntry( + displayText: displayText, + audioSources: sources, + scheduledTime: scheduledTime + ) + ); + + } + + void queueAnnounementByInfoIndex({ + int infoIndex = -1, + DateTime? scheduledTime = null, + bool sendToServer = true + }) { + + if (sendToServer) { + + scheduledTime ??= liveInformation.syncedTimeModule.Now().add(Duration(seconds: defaultAnnouncementDelay)); + + liveInformation.commandModule.executeCommand( + "announce info $infoIndex ${scheduledTime?.millisecondsSinceEpoch ?? ""}" + ); + return; + } + + NamedAnnouncementQueueEntry clone = NamedAnnouncementQueueEntry( + shortName: manualAnnouncements[infoIndex].shortName, + displayText: manualAnnouncements[infoIndex].displayText, + audioSources: manualAnnouncements[infoIndex].audioSources, + scheduledTime: scheduledTime + ); + + queue.add(clone); + } + + Future queueAnnouncementByRouteVariant({ + required BusRouteVariant routeVariant, + DateTime? scheduledTime = null, + bool sendToServer = true + }) async { + + if (sendToServer) { + + scheduledTime ??= liveInformation.syncedTimeModule.Now().add(Duration(seconds: defaultAnnouncementDelay)); + + liveInformation.commandModule.executeCommand( + "announce dest \"${routeVariant.busRoute.routeNumber}\" ${routeVariant.busRoute.routeVariants.values.toList().indexOf(routeVariant)} ${scheduledTime?.millisecondsSinceEpoch ?? ""}" + ); + return; + } + + String routeNumber = routeVariant.busRoute.routeNumber; + String destination = routeVariant.destination!.destination; + + String audioRoute = "R_${routeVariant.busRoute.routeNumber}_001.mp3"; + + await announcementCache.loadAnnouncements([audioRoute]); + + AudioWrapperSource sourceRoute = AudioWrapperByteSource(announcementCache[audioRoute]!); + AudioWrapperSource sourceDestination = AudioWrapperByteSource(await routeVariant.destination!.getAudioBytes()); + + AnnouncementQueueEntry announcement = AnnouncementQueueEntry( + displayText: "$routeNumber to $destination", + audioSources: [sourceRoute, AudioWrapperAssetSource("audio/to_destination.wav"), sourceDestination], + scheduledTime: scheduledTime + ); + + queue.add(announcement); + } + + // Constants + + final List manualAnnouncements = [ + NamedAnnouncementQueueEntry( + shortName: "Driver Change", + displayText: "Driver Change", + audioSources: [AudioWrapperAssetSource("audio/manual_announcements/driverchange.mp3")], + ), + NamedAnnouncementQueueEntry( + shortName: "No Standing Upr Deck", + displayText: "No standing on the upper deck", + audioSources: [AudioWrapperAssetSource("audio/manual_announcements/nostanding.mp3")], + ), + NamedAnnouncementQueueEntry( + shortName: "Face Covering", + displayText: "Please wear a face covering!", + audioSources: [AudioWrapperAssetSource("audio/manual_announcements/facecovering.mp3")], + ), + NamedAnnouncementQueueEntry( + shortName: "Seats Upstairs", + displayText: "Seats are available upstairs", + audioSources: [AudioWrapperAssetSource("audio/manual_announcements/seatsupstairs.mp3")], + ), + NamedAnnouncementQueueEntry( + shortName: "Bus Terminates Here", + displayText: "Bus terminates here. Please take your belongings with you", + audioSources: [AudioWrapperAssetSource("audio/manual_announcements/busterminateshere.mp3")], + ), + NamedAnnouncementQueueEntry( + shortName: "Bus On Diversion", + displayText: "Bus on diversion. Please listen for further announcements", + audioSources: [AudioWrapperAssetSource("audio/manual_announcements/busondiversion.mp3")], + ), + NamedAnnouncementQueueEntry( + shortName: "Destination Change", + displayText: "Destination Changed - please listen for further instructions", + audioSources: [AudioWrapperAssetSource("audio/manual_announcements/destinationchange.mp3")], + ), + NamedAnnouncementQueueEntry( + shortName: "Wheelchair Space", + displayText: "Wheelchair space requested", + audioSources: [AudioWrapperAssetSource("audio/manual_announcements/wheelchairspace1.mp3")], + ), + NamedAnnouncementQueueEntry( + shortName: "Move Down The Bus", + displayText: "Please move down the bus", + audioSources: [AudioWrapperAssetSource("audio/manual_announcements/movedownthebus.mp3")], + ), + NamedAnnouncementQueueEntry( + shortName: "Next Stop Closed", + displayText: "The next bus stop is closed", + audioSources: [AudioWrapperAssetSource("audio/manual_announcements/nextstopclosed.wav")], + ), + NamedAnnouncementQueueEntry( + shortName: "CCTV In Operation", + displayText: "CCTV is in operation on this bus", + audioSources: [AudioWrapperAssetSource("audio/manual_announcements/cctvoperation.mp3")], + ), + NamedAnnouncementQueueEntry( + shortName: "Safe Door Opening", + displayText: "Driver will open the doors when it is safe to do so", + audioSources: [AudioWrapperAssetSource("audio/manual_announcements/safedooropening.mp3")], + ), + NamedAnnouncementQueueEntry( + shortName: "Buggy Safety", + displayText: "For your child's safety, please remain with your buggy", + audioSources: [AudioWrapperAssetSource("audio/manual_announcements/buggysafety.mp3")], + ), + NamedAnnouncementQueueEntry( + shortName: "Wheelchair Space 2", + displayText: "Wheelchair priority space required", + audioSources: [AudioWrapperAssetSource("audio/manual_announcements/wheelchairspace2.mp3")], + ), + NamedAnnouncementQueueEntry( + shortName: "Service Regulation", + displayText: "Regulating service - please listen for further information", + audioSources: [AudioWrapperAssetSource("audio/manual_announcements/serviceregulation.mp3")], + ), + NamedAnnouncementQueueEntry( + shortName: "Bus Ready To Depart", + displayText: "This bus is ready to depart", + audioSources: [AudioWrapperAssetSource("audio/manual_announcements/readytodepart.mp3")], + ), + ]; + + +} \ No newline at end of file diff --git a/lib/backend/modules/commands.dart b/lib/backend/modules/commands.dart new file mode 100644 index 0000000..516ec20 --- /dev/null +++ b/lib/backend/modules/commands.dart @@ -0,0 +1,224 @@ + +import 'dart:convert'; + +import 'package:bus_infotainment/auth/api_constants.dart'; +import 'package:bus_infotainment/backend/live_information.dart'; +import 'package:bus_infotainment/tfl_datasets.dart'; +import 'package:bus_infotainment/utils/audio%20wrapper.dart'; +import 'package:bus_infotainment/utils/delegates.dart'; +import 'package:appwrite/appwrite.dart' as appwrite; +import 'package:appwrite/models.dart' as models; +import 'package:uuid/uuid.dart'; + +import '../../auth/auth_api.dart'; +import 'info_module.dart'; + +class CommandModule extends InfoModule { + + final String sessionID; + late final String clientID; + + List _commandHistory = []; + get commandHistory => _commandHistory; + EventDelegate onCommandReceived = EventDelegate(); + + CommandModule(this.sessionID){ + // generate a random client ID + var uuid = Uuid(); + + clientID = uuid.v4(); + + if (liveInformation.auth.isAuthenticated()){ + print("Auth is authenticated"); + _setupListener(); + } else { + print("Auth is not authenticated"); + liveInformation.auth.onLogin.addListener((value) { + _setupListener(); + }); + } + } + + // Will execute the command an event which is triggered when a response is received + Future executeCommand(String command) async { + EventDelegate delegate = EventDelegate(); + + final client = liveInformation.auth.client; + + final databases = appwrite.Databases(client); + + if (liveInformation.auth.status == AuthStatus.AUTHENTICATED) { + final document = await databases.createDocument( + databaseId: ApiConstants.INFO_Q_DATABASE_ID, + collectionId: ApiConstants.COMMANDS_COLLECTION_ID, + documentId: appwrite.ID.unique(), + data: { + "session_id": sessionID, + "command": command, + "client_id": clientID, + } + ); + } + + _onCommandReceived(CommandInfo(command, clientID)); + + return delegate; + } + + Future _onCommandReceived(CommandInfo commandInfo) async { + + commandHistory.add(commandInfo); + onCommandReceived.trigger(commandInfo); + + print("Received command: ${commandInfo.command}"); + + List commandParts = splitCommand(commandInfo.command); + String command = commandParts[0]; + List args = commandParts.sublist(1); + + if (command == "Response:") { + + } + else if (command == "announce") { + + final displayText = args[1]; + + if (args[0] == "manual") { + // announce manual ... + + + List audioFileNames = args.sublist(2); + try { + if (int.parse(audioFileNames.last) != null) { + audioFileNames.removeLast(); + } + } catch (e) {} + + DateTime scheduledTime = LiveInformation().syncedTimeModule.Now().add(Duration(seconds: 1)); + try { + if (int.parse(args.last) != null) { + scheduledTime = DateTime.fromMillisecondsSinceEpoch(int.parse(args.last)); + } + } catch (e) {} + + liveInformation.announcementModule.queueAnnounceByAudioName( + displayText: displayText, + audioNames: audioFileNames, + scheduledTime: scheduledTime, + sendToServer: false + ); + + } + else if (args[0] == "info") { + + int InfoIndex = int.parse(args[1]); + + DateTime scheduledTime = LiveInformation().syncedTimeModule.Now(); + try { + if (int.parse(args.last) != null) { + scheduledTime = DateTime.fromMillisecondsSinceEpoch(int.parse(args.last)); + } + } catch (e) {} + + liveInformation.announcementModule.queueAnnounementByInfoIndex( + infoIndex: InfoIndex, + scheduledTime: scheduledTime, + sendToServer: false + ); + } + else if (args[0].startsWith("dest")) { + // announce destination + + String routeNumber = args[1]; + int routeVariantIndex = int.parse(args[2]); + + DateTime scheduledTime = LiveInformation().syncedTimeModule.Now(); + try { + if (int.parse(args.last) != null) { + scheduledTime = DateTime.fromMillisecondsSinceEpoch(int.parse(args.last)); + } + } catch (e) {} + + BusRoute route = LiveInformation().busSequences.routes[routeNumber]!; + BusRouteVariant routeVariant = route.routeVariants.values.toList()[routeVariantIndex]; + + liveInformation.announcementModule.queueAnnouncementByRouteVariant( + routeVariant: routeVariant, + scheduledTime: scheduledTime, + sendToServer: false + ); + + } + + } + else if (command == "setroute") { + // setroute + + LiveInformation liveInformation = LiveInformation(); + + String routeNumber = args[0]; + int routeVariantIndex = int.parse(args[1]); + + BusRoute route = liveInformation.busSequences.routes[routeNumber]!; + BusRouteVariant routeVariant = route.routeVariants.values.toList()[routeVariantIndex]; + + liveInformation.setRouteVariant_Internal( + routeVariant + ); + executeCommand("Response: v \"Client $clientID set its route to ($routeNumber to ${routeVariant.busStops.last.formattedStopName})\""); + + } + + } + + appwrite.RealtimeSubscription? _subscription; + Future _setupListener() async { + if (_subscription != null) { + return; + } + + final realtime = appwrite.Realtime(LiveInformation().auth.client); + + _subscription = realtime.subscribe( + ['databases.${ApiConstants.INFO_Q_DATABASE_ID}.collections.${ApiConstants.COMMANDS_COLLECTION_ID}.documents'] + ); + _subscription!.stream.listen((event) { + print(jsonEncode(event.payload)); + + // Only do something if the document was created or updated + if (!(event.events.first.contains("create") || event.events.first.contains("update"))) { + return; + } + + final commandInfo = CommandInfo(event.payload['command'], event.payload['client_id']); + + if (commandInfo.clientID != clientID) { + _onCommandReceived(commandInfo); + } + + }); + + print("Listening for commands"); + + await Future.delayed(Duration(seconds: 90)); + + await _subscription!.close(); + _subscription = null; + _setupListener(); + + } + +} + +class CommandInfo { + final String command; + final String clientID; + + CommandInfo(this.command, this.clientID); +} + +List splitCommand(String command) { + var regex = RegExp(r'([^\s"]+)|"([^"]*)"'); + var matches = regex.allMatches(command); + return matches.map((match) => match.group(0)!.replaceAll('"', '')).toList(); +} \ No newline at end of file diff --git a/lib/backend/modules/info_module.dart b/lib/backend/modules/info_module.dart new file mode 100644 index 0000000..2ea7012 --- /dev/null +++ b/lib/backend/modules/info_module.dart @@ -0,0 +1,8 @@ + +import 'package:bus_infotainment/backend/live_information.dart'; + +abstract class InfoModule { + + LiveInformation get liveInformation => LiveInformation(); + +} \ No newline at end of file diff --git a/lib/backend/modules/synced_time.dart b/lib/backend/modules/synced_time.dart new file mode 100644 index 0000000..7b7ae92 --- /dev/null +++ b/lib/backend/modules/synced_time.dart @@ -0,0 +1,36 @@ + +import 'dart:async'; +import 'dart:convert'; +import 'package:http/http.dart' as http; + +import 'info_module.dart'; + +class SyncedTimeModule extends InfoModule { + + int timeOffset = -1; + DateTime lastUpdate = DateTime.now().add(const Duration(seconds: -15)); + + SyncedTimeModule() { + refreshTimer(); + } + + Timer refreshTimer() => Timer.periodic(const Duration(seconds: 10), (timer) async { + var res = await http.get(Uri.parse('http://worldtimeapi.org/api/timezone/Europe/London')); + if (res.statusCode == 200) { + var json = jsonDecode(res.body); + DateTime time = DateTime.parse(json['datetime']); + timeOffset = time.millisecondsSinceEpoch - DateTime.now().millisecondsSinceEpoch; + lastUpdate = DateTime.now(); + print("Time offset: $timeOffset"); + } else { + print("Failed to get time from worldtimeapi.org"); + } + }); + + DateTime Now() { + if (timeOffset == -1) { + return DateTime.now(); + } + return DateTime.now().add(Duration(milliseconds: timeOffset)); + } +} \ No newline at end of file diff --git a/lib/backend/modules/tracker.dart b/lib/backend/modules/tracker.dart new file mode 100644 index 0000000..96123aa --- /dev/null +++ b/lib/backend/modules/tracker.dart @@ -0,0 +1,199 @@ + +import 'dart:async'; +import 'dart:math'; +import 'dart:typed_data'; + +import 'package:bus_infotainment/backend/live_information.dart'; +import 'package:bus_infotainment/backend/modules/info_module.dart'; +import 'package:bus_infotainment/tfl_datasets.dart'; +import 'package:bus_infotainment/utils/OrdinanceSurveyUtils.dart'; +import 'package:bus_infotainment/utils/audio%20wrapper.dart'; +import 'package:geolocator/geolocator.dart'; +import 'package:vector_math/vector_math.dart'; + +class TrackerModule extends InfoModule { + + + TrackerModule() { + locationStream(); + Geolocator.getLastKnownPosition().then((Position? position) { + this._position = position; + updateNearestStop(); + }); + liveInformation.routeVariantDelegate.addListener((routeVariant) { + print("Route variant changed"); + updateNearestStop(); + }); + } + + + Position? _position; + Position? get position => _position; + + StreamSubscription locationStream() => Geolocator.getPositionStream( + locationSettings: const LocationSettings( + accuracy: LocationAccuracy.high, + distanceFilter: 1, + ) + ).listen((Position position) { + + if (position == null) { + return; + } + + this._position = position; + updateNearestStop(); + }); + + Timer refreshTimer() => Timer.periodic(Duration(seconds: 1), (timer) async { + _position = await Geolocator.getCurrentPosition(); + }); + + BusRouteStop? nearestStop; + bool hasArrived = false; + + Future updateNearestStop() async { + if (liveInformation.getRouteVariant() == null) { + return; + } + + // Get the closest stop + BusRouteStop closestStop = liveInformation.getRouteVariant()!.busStops.first; + double closestDistance = OSGrid + .toNorthingEasting(_position!.latitude, _position!.longitude) + .distanceTo(Vector2(closestStop.easting.toDouble(), closestStop.northing.toDouble())); + + for (BusRouteStop stop in liveInformation.getRouteVariant()!.busStops) { + double distance = OSGrid + .toNorthingEasting(_position!.latitude, _position!.longitude) + .distanceTo(Vector2(stop.easting.toDouble(), stop.northing.toDouble())); + + if (distance < closestDistance) { + closestStop = stop; + closestDistance = distance; + } + } + + double relativeDistance = _calculateRelativeDistance(closestStop, _position!.latitude, _position!.longitude); + + + + if (relativeDistance < -10) { + print("Closest stop is behind us: ${closestStop.formattedStopName}"); + print("Relative distance: $relativeDistance"); + + int stopIndex = liveInformation.getRouteVariant()!.busStops.indexOf(closestStop); + + closestStop = liveInformation.getRouteVariant()!.busStops[stopIndex + 1]; + + print("Closest stop is now: ${closestStop.formattedStopName}"); + } else { + print("Closest stop is in front of us: ${closestStop.formattedStopName}"); + } + + bool preExisting = true; + + if (nearestStop != closestStop) { + nearestStop = closestStop; + hasArrived = false; + preExisting = false; + } + + print("Closest stop is the same as before"); + + double distance = OSGrid + .toNorthingEasting(_position!.latitude, _position!.longitude) + .distanceTo(Vector2(nearestStop!.easting.toDouble(), nearestStop!.northing.toDouble())); + + // get the speed in mph + double speed = _position!.speed * 2.23694; + print("Speed: $speed"); + + Duration? duration; + { + // Testing some audio stuff + Uint8List? audioBytes = liveInformation.announcementModule.announcementCache[nearestStop!.getAudioFileName()]; + AudioWrapperByteSource audioSource = AudioWrapperByteSource(audioBytes!); + + AudioWrapper audio = AudioWrapper(); + + await audio.loadSource(audioSource); + + duration = await audio.getDuration(); + + print("Duration of audio: $duration"); + } + + // get the estimated distance travelled in 5 seconds, in meters + double distanceTravelled = speed * (3 + duration!.inSeconds); + + // adjust for the it takes to send the announcement to other devices + distance -= distanceTravelled; + + // get the time to the stop in seconds + double timeToStop = distance / speed; + + print("Distance to stop: $distance"); + print("Time to stop: $timeToStop"); + + int secondsBefore = 7; + + print("Seconds before: $secondsBefore"); + + if ((timeToStop < secondsBefore ) && !hasArrived && relativeDistance > 0) { + print("We are at the stop"); + hasArrived = true; + liveInformation.announcementModule.queueAnnounceByAudioName( + displayText: "${nearestStop!.formattedStopName}", + audioNames: [ + // "A_NEXT_STOP_001.mp3", + nearestStop!.getAudioFileName() + ], + sendToServer: true + ); + } + + + if (!hasArrived && !preExisting) { + liveInformation.announcementModule.queueAnnounceByAudioName( + displayText: "${closestStop.formattedStopName}", + audioNames: [], + sendToServer: true + ); + } + + + + print("Closest stop: ${closestStop.formattedStopName} in ${closestDistance.round()} meters"); + } + + +} + +double _calculateRelativeDistance(BusRouteStop stop, double latitude, double longitude) { + + List toLatLong = OSGrid.toLatLong(stop.northing.toDouble(), stop.easting.toDouble()); + + Vector2 stopPoint = OSGrid.toNorthingEasting(toLatLong[0], toLatLong[1]); + Vector2 currentPoint = OSGrid.toNorthingEasting(latitude, longitude); + + // calculate the heading from the current point to the stop point + // 0 degrees is north, 90 degrees is east, 180 degrees is south, 270 degrees is west + double toHeading = degrees(atan2(stopPoint.x - currentPoint.x, stopPoint.y - currentPoint.y)); + toHeading = (toHeading + 360) % 360; + + // get the dot product of the heading and the stop heading + double dotProduct = cos(radians(toHeading)) * cos(radians(stop.heading.toDouble())) + sin(radians(toHeading)) * sin(radians(stop.heading.toDouble())); + + return (dotProduct.sign) * _calculateDistance(latitude, longitude, toLatLong[0], toLatLong[1]); +} + +double _calculateDistance(double lat1, double lon1, double lat2, double lon2) { + + // Convert to eastings and northings + Vector2 point1 = OSGrid.toNorthingEasting(lat1, lon1); + Vector2 point2 = OSGrid.toNorthingEasting(lat2, lon2); + + return point1.distanceTo(point2); + +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 92ff6fd..58ed02d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,15 +2,32 @@ import 'dart:io'; import 'package:bus_infotainment/pages/audio_cache_test.dart'; import 'package:bus_infotainment/pages/tfl_dataset_test.dart'; -import 'package:bus_infotainment/singletons/live_information.dart'; +import 'package:bus_infotainment/backend/live_information.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:window_manager/window_manager.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); + if (defaultTargetPlatform == TargetPlatform.windows && !kIsWeb) { + await windowManager.ensureInitialized(); + + WindowOptions options = WindowOptions( + size: Size(411.4, 850.3), + ); + + windowManager.setAspectRatio(411.4 / 850.3); + + await windowManager.waitUntilReadyToShow(options, () async { + await windowManager.show(); + await windowManager.focus(); + }); + } + LiveInformation liveInformation = LiveInformation(); - await liveInformation.Initialize(); + await liveInformation.initialize(); // Disalow screen to turn off on android await SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); @@ -30,6 +47,10 @@ class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { + + // Permission.location.onGrantedCallback(() => null).request(); + + print("Window size: ${MediaQuery.of(context).size}"); return MaterialApp( title: 'Flutter Demo', theme: ThemeData( diff --git a/lib/pages/components/ibus_display.dart b/lib/pages/components/ibus_display.dart index cd5dfd7..99693a4 100644 --- a/lib/pages/components/ibus_display.dart +++ b/lib/pages/components/ibus_display.dart @@ -1,9 +1,10 @@ import 'dart:async'; -import 'package:bus_infotainment/singletons/live_information.dart'; +import 'package:bus_infotainment/backend/live_information.dart'; import 'package:bus_infotainment/utils/delegates.dart'; import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; import 'package:text_scroll/text_scroll.dart'; class ibus_display extends StatefulWidget { @@ -21,13 +22,14 @@ class ibus_display extends StatefulWidget { class _ibus_displayState extends State { String topLine = "*** NO MESSAGE ***"; + String bottomLine = ""; late final ListenerReceipt _receipt; _ibus_displayState(){ LiveInformation liveInformation = LiveInformation(); - _receipt = liveInformation.announcementDelegate.addListener((value) { + _receipt = liveInformation.announcementModule.onAnnouncement.addListener((value) { if (topLine == value.displayText){ return; @@ -38,7 +40,7 @@ class _ibus_displayState extends State { }); }); - topLine = liveInformation.currentAnnouncement; + topLine = liveInformation.announcementModule.currentAnnouncement?.displayText ?? liveInformation.announcementModule.defaultText; } @@ -55,6 +57,8 @@ class _ibus_displayState extends State { prefix += " "; } + input = input.replaceAll("©", "(c)"); + return prefix + input + suffix; } @@ -62,7 +66,7 @@ class _ibus_displayState extends State { @override void dispose() { - LiveInformation().announcementDelegate.removeListener(_receipt); + LiveInformation().announcementModule.onAnnouncement.removeListener(_receipt); super.dispose(); @@ -75,19 +79,45 @@ class _ibus_displayState extends State { return Container( width: double.infinity, + color: Colors.black, child: FittedBox( alignment: Alignment.center, child: Stack( children: [ + + Positioned.fill( + child: Container( + + alignment: Alignment.bottomCenter, + + margin: EdgeInsets.all(1), + + child: Text( + "© ImBenji.net - all rights reserved | © Transport for London - all rights reserved", + style: GoogleFonts.teko( + fontSize: 10, + color: Colors.white.withOpacity(0.01), + height: 1, + shadows: [ + Shadow( + color: Colors.black, + blurRadius: 5, + ) + ] + ) + ), + + ), + ), + Container( // width: double.infinity, // height: 100, decoration: BoxDecoration( - color: Colors.black, border: widget.hasBorder ? Border.all(color: Colors.grey.shade900, width: 2) : null, ), @@ -127,17 +157,27 @@ class _ibus_displayState extends State { ), Transform.translate( - offset: Offset(0, -7), - child: Text( - "", - style: const TextStyle( - fontSize: 20, - color: Colors.orange, - fontFamily: "ibus", - height: 1.5 + offset: Offset(0, -6), + child: Container( + alignment: Alignment.center, + width: 32*4*3, + child: TextScroll( + _padString(bottomLine), + velocity: Velocity(pixelsPerSecond: Offset(120, 0)), + style: const TextStyle( + fontSize: 20, + color: Colors.orange, + fontFamily: "ibus", + shadows: [ + Shadow( + color: Colors.orange, + blurRadius: 5, + ), + ], + ), ), ), - ) + ), ], ), ), @@ -145,6 +185,8 @@ class _ibus_displayState extends State { ), + + Positioned.fill( child: Container( decoration: BoxDecoration( diff --git a/lib/pages/display.dart b/lib/pages/display.dart index 20995ff..144fd60 100644 --- a/lib/pages/display.dart +++ b/lib/pages/display.dart @@ -3,6 +3,7 @@ import 'package:bus_infotainment/pages/components/ibus_display.dart'; import 'package:bus_infotainment/pages/tfl_dataset_test.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:google_fonts/google_fonts.dart'; class pages_Display extends StatefulWidget { @@ -30,23 +31,29 @@ class _pages_DisplayState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ + Expanded( + child: RotatedBox( + quarterTurns: 1, + child: Stack( + alignment: Alignment.center, + children: [ + ibus_display( + hasBorder: false, + ), - if (MediaQuery.of(context).size.width < 600) - Expanded( - child: RotatedBox( - quarterTurns: 1, - child: ibus_display( - hasBorder: false, - ), - ), - ) - else - Expanded( - child: ibus_display( - hasBorder: false, + if (widget._tfL_Dataset_TestState.hideUI) + Container( + alignment: Alignment.bottomLeft, + height: double.infinity, + width: double.infinity, + + margin: EdgeInsets.all(5), + + ) + ], ), ), - + ) ], ), ), diff --git a/lib/pages/home.dart b/lib/pages/home.dart index 70eacf0..285995b 100644 --- a/lib/pages/home.dart +++ b/lib/pages/home.dart @@ -1,11 +1,15 @@ +import 'dart:async'; + import 'package:bus_infotainment/pages/components/ibus_display.dart'; -import 'package:bus_infotainment/singletons/live_information.dart'; +import 'package:bus_infotainment/backend/live_information.dart'; import 'package:bus_infotainment/tfl_datasets.dart'; +import 'package:bus_infotainment/utils/OrdinanceSurveyUtils.dart'; import 'package:bus_infotainment/utils/audio%20wrapper.dart'; import 'package:bus_infotainment/utils/delegates.dart'; import 'package:flutter/material.dart'; +import 'package:geolocator/geolocator.dart'; import 'package:google_fonts/google_fonts.dart'; class pages_Home extends StatelessWidget { @@ -18,226 +22,343 @@ class pages_Home extends StatelessWidget { - child: SingleChildScrollView( - child: Column( - children: [ - - Container( - height: 2, - color: Colors.white70, - ), - - Container( - - decoration: BoxDecoration( - color: Colors.grey.shade900, - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.3), - blurRadius: 2, - spreadRadius: 4 - ) - ] - ), - - margin: EdgeInsets.all(20), - - child: ibus_display(), - - ), - - Container( - height: 2, - color: Colors.white70, - ), - - Container( - - margin: EdgeInsets.all(20), - - child: Container( - - decoration: BoxDecoration( - color: Colors.grey.shade900, - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.3), - blurRadius: 2, - spreadRadius: 4 - ) - ] - ), - - child: ManualAnnouncementPicker( - backgroundColor: Colors.grey.shade900, - outlineColor: Colors.white70, - announcements: [ - ...LiveInformation().manualAnnouncements - ], - ), - ), - - ), - - Container( - height: 2, - color: Colors.white70, - ), - - Container( - - margin: EdgeInsets.all(20), - - child: Container( - - decoration: BoxDecoration( - color: Colors.grey.shade900, - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.3), - blurRadius: 2, - spreadRadius: 4 - ) - ] - ), - - child: DelegateBuilder( - delegate: LiveInformation().routeVariantDelegate, - builder: (context, routeVariant) { - print("rebuilt stop announcement picker"); - return StopAnnouncementPicker( - routeVariant: routeVariant, + child: Column( + children: [ + + Row( + + children: [ + + Speedometer(), + + ], + + ), + + Container( + height: 2, + color: Colors.white70, + ), + + SingleChildScrollView( + child: Column( + children: [ + + Container( + + margin: EdgeInsets.all(10), + + child: Container( + + decoration: BoxDecoration( + color: Colors.grey.shade900, + ), + + child: AnnouncementPicker( backgroundColor: Colors.grey.shade900, outlineColor: Colors.white70, - ); - }, - defaultBuilder: (context) { - BusRouteVariant? routeVariant = LiveInformation().getRouteVariant(); - if (routeVariant == null) { - return Container( - color: Colors.grey.shade900, - child: Center( - child: Text( - "No route selected", - style: GoogleFonts.teko( - fontSize: 25, - color: Colors.white70 - ), - ), - ), - ); - } else { - return StopAnnouncementPicker( - routeVariant: routeVariant, - backgroundColor: Colors.grey.shade900, - outlineColor: Colors.white70, - ); - } - }, + announcements: [ + for (NamedAnnouncementQueueEntry announcement in LiveInformation().announcementModule.manualAnnouncements) + _AnnouncementEntry( + label: announcement.shortName, + index: LiveInformation().announcementModule.manualAnnouncements.indexOf(announcement), + outlineColor: Colors.white70, + onPressed: (){ + LiveInformation liveInformation = LiveInformation(); + liveInformation.announcementModule.queueAnnounementByInfoIndex( + infoIndex: liveInformation.announcementModule.manualAnnouncements.indexOf(announcement), + sendToServer: true + ); + }, + ) + ], + ), + ), + ), - ), - + + Container( + height: 2, + color: Colors.white70, + ), + + Container( + + margin: EdgeInsets.all(10), + + child: Container( + decoration: BoxDecoration( + color: Colors.grey.shade900, + ), + + child: DelegateBuilder( + delegate: LiveInformation().routeVariantDelegate, + builder: (context, routeVariant) { + print("rebuilt stop announcement picker"); + return StopAnnouncementPicker( + routeVariant: routeVariant, + backgroundColor: Colors.grey.shade900, + outlineColor: Colors.white70, + ); + }, + defaultBuilder: (context) { + BusRouteVariant? routeVariant = LiveInformation().getRouteVariant(); + if (routeVariant == null) { + return Container( + color: Colors.grey.shade900, + child: Center( + child: Text( + "No route selected", + style: GoogleFonts.teko( + fontSize: 25, + color: Colors.white70 + ), + ), + ), + ); + } else { + return StopAnnouncementPicker( + routeVariant: routeVariant, + backgroundColor: Colors.grey.shade900, + outlineColor: Colors.white70, + ); + } + }, + ), + ), + + ), + + ElevatedButton( + onPressed: () async { + LiveInformation liveInformation = LiveInformation(); + final commandModule = liveInformation.commandModule; + + // commandModule.executeCommand( + // "announce dest" + // ); + + liveInformation.announcementModule.queueAnnouncementByRouteVariant( + routeVariant: liveInformation.getRouteVariant()! + ); + + }, + child: Text("Announce current destination"), + ), + + + // Container( + // + // margin: EdgeInsets.all(20), + // + // height: 300-45, + // + // child: ListView( + // + // scrollDirection: Axis.vertical, + // + // children: [ + // + // ElevatedButton( + // onPressed: () async { + // LiveInformation liveInformation = LiveInformation(); + // liveInformation.queueAnnouncement(await liveInformation.getDestinationAnnouncement(liveInformation.getRouteVariant()!, sendToServer: false)); + // }, + // child: Text("Test announcement"), + // ), + // + // ElevatedButton( + // onPressed: () { + // LiveInformation liveInformation = LiveInformation(); + // liveInformation.updateServer(); + // }, + // child: Text("Update server"), + // ), + // + // SizedBox( + // + // width: 100, + // + // child: TextField( + // onChanged: (String value) { + // LiveInformation liveInformation = LiveInformation(); + // // liveInformation.documentID = value; + // }, + // ), + // ), + // + // SizedBox( + // + // width: 200, + // + // child: TextField( + // onSubmitted: (String value) { + // LiveInformation liveInformation = LiveInformation(); + // liveInformation.queueAnnouncement(AnnouncementQueueEntry( + // displayText: value, + // audioSources: [] + // )); + // }, + // ), + // ), + // + // ElevatedButton( + // onPressed: () { + // LiveInformation liveInformation = LiveInformation(); + // liveInformation.pullServer(); + // }, + // child: Text("Pull server"), + // ), + // + // ], + // + // ), + // + // ), + + ], ), - - ElevatedButton( - onPressed: () async { - LiveInformation liveInformation = LiveInformation(); - liveInformation.queueAnnouncement(await liveInformation.getDestinationAnnouncement(liveInformation.getRouteVariant()!, sendToServer: true)); - }, - child: Text("Announce Destination"), - ), - - - // Container( - // - // margin: EdgeInsets.all(20), - // - // height: 300-45, - // - // child: ListView( - // - // scrollDirection: Axis.vertical, - // - // children: [ - // - // ElevatedButton( - // onPressed: () async { - // LiveInformation liveInformation = LiveInformation(); - // liveInformation.queueAnnouncement(await liveInformation.getDestinationAnnouncement(liveInformation.getRouteVariant()!, sendToServer: false)); - // }, - // child: Text("Test announcement"), - // ), - // - // ElevatedButton( - // onPressed: () { - // LiveInformation liveInformation = LiveInformation(); - // liveInformation.updateServer(); - // }, - // child: Text("Update server"), - // ), - // - // SizedBox( - // - // width: 100, - // - // child: TextField( - // onChanged: (String value) { - // LiveInformation liveInformation = LiveInformation(); - // // liveInformation.documentID = value; - // }, - // ), - // ), - // - // SizedBox( - // - // width: 200, - // - // child: TextField( - // onSubmitted: (String value) { - // LiveInformation liveInformation = LiveInformation(); - // liveInformation.queueAnnouncement(AnnouncementQueueEntry( - // displayText: value, - // audioSources: [] - // )); - // }, - // ), - // ), - // - // ElevatedButton( - // onPressed: () { - // LiveInformation liveInformation = LiveInformation(); - // liveInformation.pullServer(); - // }, - // child: Text("Pull server"), - // ), - // - // ], - // - // ), - // - // ), - - ], - ), + ), + ], ) ); } } -class ManualAnnouncementPicker extends StatefulWidget { +class Speedometer extends StatefulWidget { + + @override + State createState() => _SpeedometerState(); +} + + + +class _SpeedometerState extends State { + + double speed = 0; + double arrivalTime = 0; + + BusRouteStop? nearestStop; + double speed2 = 0; + + _SpeedometerState(){ + + + + } + + @override + void initState() { + // TODO: implement initState + super.initState(); + + Timer.periodic(Duration(milliseconds: 250), (timer) { + + Position? newPosition = LiveInformation().trackerModule.position; + + speed = newPosition?.speed ?? 0; + + arrivalTime -= 0.25; + arrivalTime = arrivalTime < 0 ? 0 : arrivalTime; + + setState(() { + + }); + }); + + } + + @override + Widget build(BuildContext context) { + // TODO: implement build + return Container( + + margin: EdgeInsets.all(8), + + height: 74, + + child: Row( + children: [ + Container( + // width: 60, + height: double.infinity, + alignment: Alignment.center, + decoration: BoxDecoration( + border: Border.all( + color: Colors.white70, + width: 2 + ) + ), + padding: const EdgeInsets.all(8), + child: Column( + + mainAxisSize: MainAxisSize.min, + + children: [ + + Container( + + decoration: BoxDecoration( + border: Border.all( + color: Colors.white70, + width: 2 + ) + ), + + width: 30, + height: 30, + + alignment: Alignment.center, + + child: Text( + "${((speed) * 2.237).toInt()}", + style: GoogleFonts.teko( + fontSize: 20, + color: Colors.white70, + height: 1 + ), + ) + ), + + const SizedBox( + height: 4, + ), + + Text( + "MPH", + style: GoogleFonts.teko( + fontSize: 20, + color: Colors.white70, + height: 1 + ), + ), + + ], + + ), + ), + + ], + ), + + ); + } +} + +class AnnouncementPicker extends StatefulWidget { final Color backgroundColor; final Color outlineColor; - final List announcements; + final List announcements; - const ManualAnnouncementPicker({super.key, required this.backgroundColor, required this.outlineColor, required this.announcements}); + const AnnouncementPicker({super.key, required this.backgroundColor, required this.outlineColor, required this.announcements}); @override - State createState() => _ManualAnnouncementPickerState(); + State createState() => _AnnouncementPickerState(); } -class _ManualAnnouncementPickerState extends State { +class _AnnouncementPickerState extends State { List announcementWidgets = []; @@ -255,13 +376,9 @@ class _ManualAnnouncementPickerState extends State { } int i = 0; - for (NamedAnnouncementQueueEntry announcement in widget.announcements!) { + for (Widget announcement in widget.announcements!) { announcementWidgets.add( - _ManualAnnouncementEntry( - announcement: announcement, - index: i, - outlineColor: Colors.white70 - ) + announcement ); i++; } @@ -436,7 +553,7 @@ class _ManualAnnouncementPickerState extends State { Positioned.fill( child: ElevatedButton( onPressed: () { - _currentIndex = wrap(_currentIndex - 4, 0, announcementWidgets.length); + _currentIndex = wrap(_currentIndex - 4, 0, announcementWidgets.length, increment: 4); setState(() {}); print(_currentIndex); }, @@ -489,7 +606,7 @@ class _ManualAnnouncementPickerState extends State { Positioned.fill( child: ElevatedButton( onPressed: () { - _currentIndex = wrap(_currentIndex + 4, 0, announcementWidgets.length); + _currentIndex = wrap(_currentIndex + 4, 0, announcementWidgets.length, increment: 4); setState(() {}); print(_currentIndex); }, @@ -529,7 +646,7 @@ class _ManualAnnouncementPickerState extends State { } } -class StopAnnouncementPicker extends ManualAnnouncementPicker { +class StopAnnouncementPicker extends AnnouncementPicker { final BusRouteVariant routeVariant; StopAnnouncementPicker({ @@ -542,29 +659,52 @@ class StopAnnouncementPicker extends ManualAnnouncementPicker { backgroundColor: backgroundColor, outlineColor: outlineColor, announcements: [ - for (BusRouteStops stop in routeVariant.busStops) - ManualAnnouncementEntry( - shortName: stop.formattedStopName, - informationText: stop.formattedStopName, - audioFileNames: [ - stop.getAudioFileName() - ] + for (BusRouteStop stop in routeVariant.busStops) + _AnnouncementEntry( + label: stop.formattedStopName, + onPressed: () { + LiveInformation liveInformation = LiveInformation(); + liveInformation.announcementModule.queueAnnounceByAudioName( + displayText: stop.formattedStopName, + audioNames: [stop.getAudioFileName()], + ); + }, + index: routeVariant.busStops.indexOf(stop), + outlineColor: outlineColor, + alert: LiveInformation().announcementModule.announcementCache[stop.getAudioFileName()] == null, ) ] ); } -int wrap(int i, int j, int length) { - return ((i - j) % length + length) % length; +int wrap(int i, int j, int length, {int increment = -1}) { + if (increment == -1) { + return ((i - j) % length + length) % length; + } else { + if (i >= length) { + return 0; + } else if (i < 0) { + double d = length / increment; + int n = d.toInt(); + + return (n-1) * increment; + } else { + return i; + } + } } -class _ManualAnnouncementEntry extends StatelessWidget { +class _AnnouncementEntry extends StatelessWidget { - final NamedAnnouncementQueueEntry announcement; + final String label; + + final Function onPressed; final int index; final Color outlineColor; - _ManualAnnouncementEntry({super.key, required this.announcement, required this.index, required this.outlineColor}); + bool alert = false; + + _AnnouncementEntry({super.key, required this.label, required this.onPressed, required this.index, required this.outlineColor, this.alert = false}); @override Widget build(BuildContext context) { @@ -591,35 +731,60 @@ class _ManualAnnouncementEntry extends StatelessWidget { width: double.infinity, - child: Transform.translate( + child: Row( + children: [ + Row( + children: [ + Container( - offset: Offset(0, 4), - - child: Row( - children: [ - Text( - announcement.shortName, - style: GoogleFonts.teko( - fontSize: 25, - color: outlineColor, - ) - ), - Expanded( - child: Container( - - alignment: Alignment.centerRight, + constraints: const BoxConstraints( + maxWidth: 260 + ), child: Text( - (index+1).toString(), + label, style: GoogleFonts.teko( fontSize: 25, color: outlineColor, - ) + ), + overflow: TextOverflow.ellipsis, ), ), - ) - ], - ), + + if (alert) + const SizedBox( + width: 4, + ), + + if (alert) + Icon( + Icons.error, + color: Colors.red.shade800, + size: 25, + shadows: const [ + Shadow( + color: Colors.black, + blurRadius: 2, + ) + ], + ) + ], + ), + Expanded( + child: Container( + + alignment: Alignment.centerRight, + + child: Text( + (index+1).toString(), + style: GoogleFonts.teko( + fontSize: 25, + color: outlineColor, + ) + ), + ), + ) + ], ) ), @@ -627,8 +792,7 @@ class _ManualAnnouncementEntry extends StatelessWidget { Positioned.fill( child: ElevatedButton( onPressed: () { - LiveInformation liveInformation = LiveInformation(); - liveInformation.queueAnnouncement(announcement); + onPressed(); }, style: ElevatedButton.styleFrom( diff --git a/lib/pages/routes.dart b/lib/pages/routes.dart index 91cdfab..eb756da 100644 --- a/lib/pages/routes.dart +++ b/lib/pages/routes.dart @@ -1,5 +1,6 @@ -import 'package:bus_infotainment/singletons/live_information.dart'; +import 'package:bus_infotainment/backend/live_information.dart'; +import 'package:bus_infotainment/pages/components/ibus_display.dart'; import 'package:bus_infotainment/tfl_datasets.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; @@ -20,7 +21,19 @@ class _pages_RoutesState extends State { LiveInformation liveInformation = LiveInformation(); List routes = []; - routes.add(SizedBox(height: 10)); + // routes.add(Container( + // width: double.infinity, + // height: 16, + // decoration: BoxDecoration( + // color: Colors.grey.shade900, + // border: const Border.symmetric( + // horizontal: BorderSide( + // color: Colors.white70, + // width: 2, + // ), + // ) + // ), + // )); for (BusRoute route in liveInformation.busSequences!.routes.values) { if (!route.routeNumber.toLowerCase().contains(_controller.text.toLowerCase())) { @@ -28,53 +41,81 @@ class _pages_RoutesState extends State { } routes.add(_Route(route, this)); - routes.add(SizedBox(height: 10)); + routes.add(Container( + width: double.infinity, + height: 16, + decoration: BoxDecoration( + color: Colors.grey.shade900, + border: const Border.symmetric( + horizontal: BorderSide( + color: Colors.white70, + width: 2, + ), + ) + ), + )); + } + if(!routes.isEmpty){ + routes.removeLast(); } return Container( - color: Theme.of(context).colorScheme.background, - width: double.infinity, - // padding: const EdgeInsets.symmetric(horizontal: 10), - child: Column( - children: [ + decoration: BoxDecoration( + color: Colors.grey.shade900, + ), + width: double.infinity, + child: Column( - Container( + children: [ - padding: const EdgeInsets.all(10), + Container( + margin: const EdgeInsets.all(10), - - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.background, - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.5), - spreadRadius: 2, - blurRadius: 4, - ), - ], - ), - - child: TextField( - controller: _controller, - onChanged: (String value) { - setState(() {}); - }, + child: TextField( + controller: _controller, + decoration: InputDecoration( + hintText: ">", ), + onChanged: (String value) { + setState(() {}); + }, ), + ), + Container( + width: double.infinity, + height: 2, + color: Colors.white70, + ), + + if (routes.isNotEmpty) Expanded( child: ListView( children: routes, ), - ), + ) + else + Expanded( + child: Center( + child: Text( + "No routes found", + style: GoogleFonts.teko( + fontSize: 50, + fontWeight: FontWeight.bold, + color: Colors.white70, + height: 1 + ), + ), + ), + ) - ], + ], - ) + ) ); } @@ -93,28 +134,23 @@ class _Route extends StatelessWidget { List Variants = []; for (BusRouteVariant variant in route.routeVariants.values) { - Variants.add(const SizedBox(height: 10)); Variants.add(_Variant(route, variant, tfL_Dataset_TestState)); + + if (route.routeVariants.values.last != variant) { + Variants.add(Container( + width: double.infinity, + height: 2, + color: Colors.white70, + )); + } + } return Container( alignment: Alignment.center, - decoration: BoxDecoration( - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.5), - spreadRadius: 2, - blurRadius: 4, - ), - ], - color: Colors.grey.shade900, - borderRadius: BorderRadius.circular(10), - ), - - margin: const EdgeInsets.symmetric(horizontal: 10), - padding: const EdgeInsets.all(10), + color: Colors.grey.shade900, width: 100, @@ -125,21 +161,27 @@ class _Route extends StatelessWidget { children: [ + + Container( decoration: BoxDecoration( - color: Colors.grey.shade800, - borderRadius: BorderRadius.circular(5), + color: Colors.transparent, + border: Border.all( + color: Colors.white70, + width: 2, + ), ), padding: const EdgeInsets.all(8), + margin: const EdgeInsets.all(4), child: Text( "Route: ${route.routeNumber}", - style: GoogleFonts.montserrat( - fontSize: 20, + style: GoogleFonts.teko( + fontSize: 25, fontWeight: FontWeight.bold, - color: Colors.white, + color: Colors.white70, height: 1 ), @@ -147,12 +189,35 @@ class _Route extends StatelessWidget { ), - ListView( - children: Variants, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), + Container( + width: double.infinity, + height: 2, + color: Colors.white70 + ), + Container( + + decoration: BoxDecoration( + color: Colors.transparent, + border: Border.all( + color: Colors.white70, + width: 2, + ), + ), + + margin: const EdgeInsets.all(4), + + child: ListView( + children: Variants, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + ), + ), + + + + ], ), @@ -181,7 +246,7 @@ class _Variant extends StatelessWidget { Container( decoration: BoxDecoration( - color: Colors.grey.shade800, + color: Colors.transparent, borderRadius: BorderRadius.circular(5), ), @@ -198,10 +263,10 @@ class _Variant extends StatelessWidget { children: [ Text( "Start:", - style: GoogleFonts.montserrat( - fontSize: 15, + style: GoogleFonts.teko( + fontSize: 20, fontWeight: FontWeight.bold, - color: Colors.white, + color: Colors.white70, height: 1, ), ), @@ -210,14 +275,14 @@ class _Variant extends StatelessWidget { Expanded( child: TextScroll( - "${variant.busStops.first.formattedStopName}", + variant.busStops.first.formattedStopName, mode: TextScrollMode.bouncing, pauseBetween: const Duration(seconds: 2), pauseOnBounce: const Duration(seconds: 2), - style: GoogleFonts.montserrat( - fontSize: 15, + style: GoogleFonts.teko( + fontSize: 20, fontWeight: FontWeight.normal, - color: Colors.white, + color: Colors.white70, height: 1, ), ), @@ -232,10 +297,11 @@ class _Variant extends StatelessWidget { children: [ Text( "End:", - style: GoogleFonts.montserrat( - fontSize: 15, + style: GoogleFonts.teko( + fontSize: 20, fontWeight: FontWeight.bold, - color: Colors.white, + color: Colors.white70, + height: 1, ), ), @@ -247,10 +313,10 @@ class _Variant extends StatelessWidget { mode: TextScrollMode.bouncing, pauseBetween: const Duration(seconds: 2), pauseOnBounce: const Duration(seconds: 2), - style: GoogleFonts.montserrat( - fontSize: 15, + style: GoogleFonts.teko( + fontSize: 20, fontWeight: FontWeight.normal, - color: Colors.white, + color: Colors.white70, height: 1, ), ), @@ -338,13 +404,12 @@ class _Variant extends StatelessWidget { Navigator.of(context).pop(); LiveInformation liveInformation = LiveInformation(); - liveInformation.setRouteVariant(variant); + await liveInformation.setRouteVariant(variant); - liveInformation.queueAnnouncement( - await liveInformation.getDestinationAnnouncement( - variant, - sendToServer: true, - ) + liveInformation.announcementModule.queueAnnouncementByRouteVariant( + routeVariant: variant, + scheduledTime: liveInformation.syncedTimeModule.Now(), + sendToServer: false ); tfL_Dataset_TestState.setState(() {}); diff --git a/lib/pages/settings.dart b/lib/pages/settings.dart index 3614015..24bd460 100644 --- a/lib/pages/settings.dart +++ b/lib/pages/settings.dart @@ -1,9 +1,12 @@ -import 'package:bus_infotainment/singletons/live_information.dart'; +import 'package:bus_infotainment/backend/live_information.dart'; +import 'package:bus_infotainment/backend/modules/commands.dart'; +import 'package:bus_infotainment/utils/delegates.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; +import 'package:text_scroll/text_scroll.dart'; import 'package:url_launcher/url_launcher_string.dart'; class pages_Settings extends StatefulWidget { @@ -14,22 +17,87 @@ class pages_Settings extends StatefulWidget { class _pages_SettingsState extends State { + late final Widget _loginPage; + + @override + void initState() { + // TODO: implement initState + super.initState(); + + if (!LiveInformation().auth.isAuthenticated()){ + _loginPage = _LoginPage( + onLogin: () { + setState(() {}); + }, + ); + } else { + _loginPage = Container( + padding: const EdgeInsets.all(8), + child: ElevatedButton( + onPressed: (){ + setState(() {}); + LiveInformation().auth.deleteSession(); + + }, + + // make the corner radius 4, background color match the theme, and text colour white, fill to width of parent + style: ElevatedButton.styleFrom( + backgroundColor: Theme.of(context).colorScheme.primary, + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(4) + ), + minimumSize: Size(double.infinity, 48) + ), + + child: Text( + "Sign out", + style: GoogleFonts.interTight( + fontSize: 15, + fontWeight: FontWeight.w600, + color: Colors.white, + letterSpacing: 0.5 + ) + ) + ), + ); + } + } + @override Widget build(BuildContext context) { - if (LiveInformation().auth.isAuthenticated()){ - return Container( + return Container( + child: SingleChildScrollView( + child: Column( + + children: [ + + Container( + margin: const EdgeInsets.all(8), + child: Console() + ), + Container( + height: 2, + width: double.infinity, + color: Colors.white70, + ), - ); - } else { - return _LoginPage( - onLogin: () { + Container( - }, - ); - } + padding: const EdgeInsets.all(8), + + child: _loginPage, + ) + + ], + + ), + ) + + ); } } @@ -626,4 +694,118 @@ class PW_TextField extends StatelessWidget { ); } +} + +// Console widget +class Console extends StatefulWidget { + + Console({super.key}); + + @override + State createState() => _ConsoleState(); +} + +class _ConsoleState extends State { + + ListenerReceipt? _listenerReceipt; + + @override + void initState() { + // TODO: implement initState + super.initState(); + + _listenerReceipt = LiveInformation().commandModule.onCommandReceived.addListener((p0) { + print("Command received, updating console"); + + setState(() {}); + }); + + } + + @override + void dispose() { + // TODO: implement dispose + super.dispose(); + } + + @override + Widget build(BuildContext context) { + + List commands = []; + + TextEditingController commandController = TextEditingController(); + + commands.add( + Text("Command History:") + ); + + for (int i = 0; i < LiveInformation().commandModule.commandHistory.length; i++){ + CommandInfo command = LiveInformation().commandModule.commandHistory[i]; + + commands.add( + TextScroll( + command.command, + style: GoogleFonts.teko( + fontSize: 15, + fontWeight: FontWeight.w400, + color: Colors.grey.shade300, + letterSpacing: 0.1, + ), + mode: TextScrollMode.bouncing, + pauseBetween: const Duration(seconds: 2), + pauseOnBounce: const Duration(seconds: 1), + ) + ); + } + + return Container( + + decoration: BoxDecoration( + border: Border.all(color: Colors.white70, width: 2), + color: Colors.black, + ), + + child: Column( + + children: [ + + Container( + padding: const EdgeInsets.all(8), + + height: 300, + + child: ListView( + children: commands, + ), + ), + + Container( + height: 2, + width: double.infinity, + color: Colors.white70, + ), + + Container( + height: 50, + padding: const EdgeInsets.all(8), + child: TextField( + controller: commandController, + decoration: const InputDecoration( + hintText: ">", + ), + style: GoogleFonts.teko( + height: 1, + ), + onSubmitted: (value) { + commandController.clear(); + LiveInformation().commandModule.executeCommand(value); + }, + ), + ) + + ], + + ), + ); + } } \ No newline at end of file diff --git a/lib/pages/tfl_dataset_test.dart b/lib/pages/tfl_dataset_test.dart index cf70193..b464716 100644 --- a/lib/pages/tfl_dataset_test.dart +++ b/lib/pages/tfl_dataset_test.dart @@ -5,11 +5,15 @@ import 'package:bus_infotainment/pages/display.dart'; import 'package:bus_infotainment/pages/home.dart'; import 'package:bus_infotainment/pages/routes.dart'; import 'package:bus_infotainment/pages/settings.dart'; -import 'package:bus_infotainment/singletons/live_information.dart'; +import 'package:bus_infotainment/backend/live_information.dart'; import 'package:bus_infotainment/tfl_datasets.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:text_scroll/text_scroll.dart'; +import 'package:window_manager/window_manager.dart'; + +import 'components/ibus_display.dart'; class TfL_Dataset_Test extends StatefulWidget { @@ -19,11 +23,13 @@ class TfL_Dataset_Test extends StatefulWidget { class TfL_Dataset_TestState extends State { - int _selectedIndex = 0; + int _selectedIndex = 1; bool hideUI = false; + bool shouldCurve = false; + bool rotated = false; - late final List Pages; + late final List Pages; TfL_Dataset_TestState() { Pages = [ @@ -42,111 +48,434 @@ class TfL_Dataset_TestState extends State { _selectedIndex = min(_selectedIndex, Pages.length - 1); _selectedIndex = max(_selectedIndex, 0); + hideUI = _selectedIndex == 2 ? hideUI : false; + + // print the window size + + if (defaultTargetPlatform == TargetPlatform.android) { + shouldCurve = true; + } else { + rotated = _selectedIndex == 2; + + print("Window size: ${MediaQuery.of(context).size}"); + + windowManager.getSize().then((value) { + double aspectRatio = value.width / value.height; + double targetAspectRatio = rotated ? 850.3 / 411.4 : 411.4 / 850.3; + + if ((aspectRatio - targetAspectRatio).abs() > 0.01) { // Add a tolerance value + if (aspectRatio != targetAspectRatio) { + windowManager.setSize(Size(value.height * targetAspectRatio, value.height)); + } + } + }); + } + + return Scaffold( - appBar: !hideUI ? AppBar( + // appBar: !hideUI ? AppBar( + // + // surfaceTintColor: Colors.transparent, + // + // title: Container( + // + // child: Column( + // + // crossAxisAlignment: CrossAxisAlignment.start, + // + // children: [ + // + // Text( + // "Bus Infotainment", + // style: GoogleFonts.teko( + // fontSize: 25, + // fontWeight: FontWeight.bold, + // color: Colors.white, + // height: 1, + // ), + // ), + // + // Row( + // + // children: [ + // + // Text( + // "Selected: ", + // style: GoogleFonts.teko( + // fontSize: 20, + // fontWeight: FontWeight.w600, + // color: Colors.white, + // height: 1, + // ), + // ), + // + // if (liveInformation.getRouteVariant() != null) + // Container( + // + // decoration: BoxDecoration( + // color: Colors.black, + // ), + // + // padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 2), + // + // child: Text( + // "${liveInformation.getRouteVariant()!.busRoute.routeNumber} to ${liveInformation.getRouteVariant()!.busStops.last.formattedStopName}", + // style: GoogleFonts.montserrat( + // fontSize: 20, + // fontWeight: FontWeight.w500, + // color: Colors.orange.shade900, + // ), + // ), + // + // ) + // else + // Text( + // "None", + // style: GoogleFonts.teko( + // fontSize: 20, + // fontWeight: FontWeight.w500, + // color: Colors.white, + // ), + // ), + // ], + // + // ) + // + // ], + // + // ), + // ), + // ) : null, + body: Container( - surfaceTintColor: Colors.transparent, + width: double.infinity, + height: double.infinity, - title: Container( + child: RotatedBox( + quarterTurns: rotated ? 3 : 0, + child: FittedBox( - child: Column( + alignment: Alignment.topCenter, + fit: BoxFit.fitWidth, - crossAxisAlignment: CrossAxisAlignment.start, + child: Container( - children: [ - - Text( - "Bus Infotainment", - style: GoogleFonts.teko( - fontSize: 25, - fontWeight: FontWeight.bold, - color: Colors.white, - height: 1, - ), + constraints: const BoxConstraints( + maxWidth: 411.4, + maxHeight: 850.3, ), - Row( + child: Container( - children: [ - - Text( - "Selected: ", - style: GoogleFonts.teko( - fontSize: 20, - fontWeight: FontWeight.w600, - color: Colors.white, - height: 1, - ), + decoration: BoxDecoration( + borderRadius: shouldCurve ? const BorderRadius.only( + bottomLeft: Radius.circular(15), + bottomRight: Radius.circular(15), + ) : null, + border: Border.all( + color: Colors.white70, + width: 2, ), + color: Colors.grey.shade900, + ), - if (liveInformation.getRouteVariant() != null) + margin: const EdgeInsets.all(6), + + + child: Column( + + children: [ + + if (!hideUI) Container( - decoration: BoxDecoration( - color: Colors.black, - ), + margin: const EdgeInsets.all(6), - padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 2), + child: ibus_display(), + ), - child: Text( - "${liveInformation.getRouteVariant()!.busRoute.routeNumber} to ${liveInformation.getRouteVariant()!.busStops.last.formattedStopName}", - style: GoogleFonts.montserrat( - fontSize: 20, - fontWeight: FontWeight.w500, - color: Colors.orange.shade900, + if (!hideUI) + Container( + width: double.infinity, + height: 2, + color: Colors.white70, + ), + + Expanded( + child: Container( + + margin: const EdgeInsets.all(8), + + decoration: BoxDecoration( + border: Border.all( + color: Colors.white70, + width: 2, + ), + color: Colors.grey.shade900, + borderRadius: hideUI && shouldCurve ? const BorderRadius.only( + bottomLeft: Radius.circular(7), + bottomRight: Radius.circular(7), + ) : null, ), - ), - ) - else - Text( - "None", - style: GoogleFonts.teko( - fontSize: 20, - fontWeight: FontWeight.w500, - color: Colors.white, + child: ClipRRect( + + // curved corners + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(7), + bottomRight: Radius.circular(7), + ), + + child: Pages[_selectedIndex], + ) ), ), - ], - ) + if (!hideUI) + Container( + width: double.infinity, + height: 2, + color: Colors.white70, + ), - ], + if (!hideUI) + Container( + height: 50, + child: Row( + + children: [ + + Expanded( + child: Stack( + children: [ + Container( + alignment: Alignment.center, + margin: const EdgeInsets.all(10), + child: Text( + "Home", + style: GoogleFonts.teko( + color: Colors.white70, + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ) + ), + Positioned.fill( + child: ElevatedButton( + onPressed: () { + setState(() { + _selectedIndex = 0; + }); + }, + + style: ElevatedButton.styleFrom( + backgroundColor: Colors.transparent, + shadowColor: Colors.transparent, + surfaceTintColor: Colors.transparent, + foregroundColor: Colors.transparent, + + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(0), + ), + + ), + + child: Container() + ), + ) + ], + ), + ), + + Container( + width: 2, + height: double.infinity, + color: Colors.white70, + ), + + Expanded( + child: Stack( + children: [ + Container( + alignment: Alignment.center, + margin: const EdgeInsets.all(10), + child: Text( + "Routes", + style: GoogleFonts.teko( + color: Colors.white70, + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ) + ), + Positioned.fill( + child: ElevatedButton( + onPressed: () { + setState(() { + _selectedIndex = 1; + }); + }, + + style: ElevatedButton.styleFrom( + backgroundColor: Colors.transparent, + shadowColor: Colors.transparent, + surfaceTintColor: Colors.transparent, + foregroundColor: Colors.transparent, + + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(0), + ), + + ), + + child: Container() + ), + ) + ], + ), + ), + + Container( + width: 2, + height: double.infinity, + color: Colors.white70, + ), + + Expanded( + child: Stack( + children: [ + Container( + alignment: Alignment.center, + margin: const EdgeInsets.all(10), + child: Text( + "Display", + style: GoogleFonts.teko( + color: Colors.white70, + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ) + ), + Positioned.fill( + child: ElevatedButton( + onPressed: () { + setState(() { + _selectedIndex = 2; + }); + }, + + style: ElevatedButton.styleFrom( + backgroundColor: Colors.transparent, + shadowColor: Colors.transparent, + surfaceTintColor: Colors.transparent, + foregroundColor: Colors.transparent, + + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(0), + ), + + ), + + child: Container() + ), + ) + ], + ), + ), + + Container( + width: 2, + height: double.infinity, + color: Colors.white70, + ), + + Expanded( + child: Stack( + children: [ + Container( + alignment: Alignment.center, + margin: const EdgeInsets.all(10), + child: Text( + "Settings", + style: GoogleFonts.teko( + color: Colors.white70, + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ) + ), + Positioned.fill( + child: ElevatedButton( + onPressed: () { + setState(() { + _selectedIndex = 3; + }); + }, + + style: ElevatedButton.styleFrom( + backgroundColor: Colors.transparent, + shadowColor: Colors.transparent, + surfaceTintColor: Colors.transparent, + foregroundColor: Colors.transparent, + + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(0), + ), + + ), + + child: Container() + ), + ) + ], + ), + ), + + + ], + + ), + ) + + ], + + ) + ), + ), ), ), - ) : null, - body: Pages[_selectedIndex], + ), - bottomNavigationBar: !hideUI ? NavigationBar( - selectedIndex: _selectedIndex, - destinations: const [ - NavigationDestination( - icon: Icon(Icons.home), - label: "Home", - ), - NavigationDestination( - icon: Icon(Icons.bus_alert), - label: "Routes", - ), - NavigationDestination( - icon: Icon(Icons.tv), - label: "Display", - ), - NavigationDestination( - icon: Icon(Icons.settings), - label: "Settings", - ), - ], - onDestinationSelected: (int index) { - setState(() { - _selectedIndex = index; - }); - }, - - ) : null, + // bottomNavigationBar: !hideUI ? NavigationBar( + // selectedIndex: _selectedIndex, + // destinations: const [ + // NavigationDestination( + // icon: Icon(Icons.home), + // label: "Home", + // ), + // NavigationDestination( + // icon: Icon(Icons.bus_alert), + // label: "Routes", + // ), + // NavigationDestination( + // icon: Icon(Icons.tv), + // label: "Display", + // ), + // NavigationDestination( + // icon: Icon(Icons.settings), + // label: "Settings", + // ), + // ], + // onDestinationSelected: (int index) { + // setState(() { + // _selectedIndex = index; + // }); + // }, + // + // ) : null, ); } } diff --git a/lib/singletons/live_information.dart b/lib/singletons/live_information.dart deleted file mode 100644 index ae23eaa..0000000 --- a/lib/singletons/live_information.dart +++ /dev/null @@ -1,855 +0,0 @@ - -// Singleton -import 'dart:async'; -import 'dart:convert'; - -import 'package:appwrite/appwrite.dart' as appwrite; -import 'package:appwrite/models.dart' as models; -import 'package:bus_infotainment/audio_cache.dart'; -import 'package:bus_infotainment/auth/api_constants.dart'; -import 'package:bus_infotainment/auth/auth_api.dart'; -import 'package:bus_infotainment/tfl_datasets.dart'; -import 'package:bus_infotainment/utils/audio%20wrapper.dart'; -import 'package:bus_infotainment/utils/delegates.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:http/http.dart' as http; -import 'package:ntp/ntp.dart'; - -class LiveInformation { - - static final LiveInformation _singleton = LiveInformation._internal(); - - factory LiveInformation() { - return _singleton; - } - - LiveInformation._internal(); - - Future Initialize() async { - - { - // Load the bus sequences - - try { - - http.Response response = await http.get(Uri.parse('https://tfl.gov.uk/bus-sequences.csv')); - - busSequences = BusSequences.fromCSV(response.body); - - print("Loaded bus sequences from TFL"); - - } catch (e) { - - String csv = await rootBundle.loadString("assets/datasets/bus-sequences.csv"); - - busSequences = BusSequences.fromCSV(csv); - - print("Loaded bus sequences from assets"); - } - - if (auth.isAuthenticated()){ - print("Auth is authenticated"); - setupRealtime(); - } else { - print("Auth is not authenticated"); - auth.onLogin.addListener((value) { - setupRealtime(); - }); - } - - } - - refreshTimer(); - } - - - Timer refreshTimer() => Timer.periodic(const Duration(milliseconds: 100), (timer) async { - await updateNtpOffset(); - _handleAnnouncementQueue(); - }); - - - int ntpOffset = -1; - DateTime lastNtpUpdate = DateTime.now().add(const Duration(seconds: -15)); - /// updates the NTP offset from DateTime.now() - Future updateNtpOffset() async { - - // Only update the NTP offset every 10 seconds - if (DateTime.now().difference(lastNtpUpdate).inSeconds < 10) { - return; - } - - var res = await http.get(Uri.parse('http://worldtimeapi.org/api/timezone/Europe/London')); - if (res.statusCode == 200) { - var json = jsonDecode(res.body); - DateTime time = DateTime.parse(json['datetime']); - ntpOffset = time.millisecondsSinceEpoch - DateTime.now().millisecondsSinceEpoch; - lastNtpUpdate = DateTime.now(); - - } - } - - DateTime getNow() { - if (ntpOffset == -1) { - throw Exception("NTP offset not set"); - } - return DateTime.now().add(Duration(milliseconds: ntpOffset)); - } - - - AudioWrapper audioPlayer = AudioWrapper(); - AnnouncementCache announcementCache = AnnouncementCache(); - List announcementQueue = []; - DateTime lastAnnouncementTimeStamp = DateTime.now().toUtc(); - EventDelegate announcementDelegate = EventDelegate(); - String _currentAnnouncement = "*** NO MESSAGE ***"; - - String get currentAnnouncement => _currentAnnouncement; - void set currentAnnouncement(String value) { - _currentAnnouncement = value; - } - - bool isPlayingAnnouncement = false; - void _handleAnnouncementQueue() async { - - int timerInterval = 100; - - // print("Handling announcement queue"); - if (!isPlayingAnnouncement) { - if (announcementQueue.isNotEmpty) { - - print("Handling announcement queue"); - - AnnouncementQueueEntry announcement = announcementQueue.first; - - print("Queue length: ${announcementQueue.length}"); - - { - DateTime now = getNow(); - if (announcement.scheduledTime != null) { - int milisecondDifference = abs(now.millisecondsSinceEpoch - announcement.scheduledTime!.millisecondsSinceEpoch); - // print("Q Difference: ${milisecondDifference}"); - if (milisecondDifference <= timerInterval) { - // Account for the time lost by the periodic timer - announcementQueue.remove(announcement); - await Future.delayed(Duration(milliseconds: timerInterval - milisecondDifference)); - } else { - print("Due in: ${milisecondDifference}ms"); - return; - } - } - } - - isPlayingAnnouncement = true; - - if (kIsWeb) { - await Future.delayed(Duration(milliseconds: 100)); - } - - - print("Displaying announcement: ${announcement.displayText}"); - announcementDelegate.trigger(announcement); - _currentAnnouncement = announcement.displayText; - - lastAnnouncementTimeStamp = getNow(); - - if (announcement.audioSources.isNotEmpty) { - try { - for (AudioWrapperSource source in announcement.audioSources) { - - Duration? duration = await audioPlayer.play(source); - await Future.delayed(duration!); - if (announcement.audioSources.last != source) { - await Future.delayed(Duration(milliseconds: 500)); - } - } - audioPlayer.stop(); - } catch (e) { - - } - } else { - if (announcementQueue.isNotEmpty) { - await Future.delayed(Duration(seconds: 5)); - } - } - - if (announcementQueue.contains(announcement)) { - announcementQueue.remove(announcement); - } - - isPlayingAnnouncement = false; - print("Popped announcement queue"); - print("Queue length after: ${announcementQueue.length}"); - } - } - } - - Future _getDestinationAnnouncement(BusRouteVariant routeVariant, {bool sendToServer = false}) async { - - String display = "${routeVariant.busRoute.routeNumber} to ${routeVariant.busStops.last.formattedStopName}"; - - String audio_route = "R_${routeVariant.busRoute.routeNumber}_001.mp3"; - String audio_destination = routeVariant.busStops.last.getAudioFileName(); - - // Cache the audio files - await announcementCache.loadAnnouncements([audio_route, audio_destination]); - - AudioWrapperSource source_route = AudioWrapperByteSource(announcementCache[audio_route]); - AudioWrapperSource source_destination = AudioWrapperByteSource(announcementCache[audio_destination]); - - return AnnouncementQueueEntry( - sendToServer: sendToServer, - - displayText: display, - audioSources: [source_route, AudioWrapperAssetSource("audio/to_destination.wav"), source_destination] - ); - - } - - Future getDestinationAnnouncement(BusRouteVariant routeVariant, {bool sendToServer = true}) async { - return DestinationAnnouncementEntry( - routeVariant: routeVariant, - audioSources: [], - sendToServer: sendToServer, - ); - } - - late BusSequences busSequences; - BusRouteVariant? _currentRouteVariant; - EventDelegate routeVariantDelegate = EventDelegate(); - - Future setRouteVariant(BusRouteVariant routeVariant) async { - _currentRouteVariant = routeVariant; - routeVariantDelegate.trigger(routeVariant); - - // cache all of the stop announcements - - List audioFiles = []; - - for (BusRouteStops stop in routeVariant.busStops) { - audioFiles.add(stop.getAudioFileName()); - print("Cached stop audio: ${stop.getAudioFileName()}"); - } - - await announcementCache.loadAnnouncements(audioFiles); - - - } - - BusRouteVariant? getRouteVariant() { - return _currentRouteVariant; - } - - void queueAnnouncement(AnnouncementQueueEntry announcement) async { - - - // Make sure the timestamp of the announcement is after the last announcement - // If so, dont queue it - // If timestamp is null, then skip this check - if (announcement.timestamp != null && announcement.timestamp!.toUtc().isBefore(lastAnnouncementTimeStamp)) { - print("Announcement is too old"); - - print("LastAnnouncement: $lastAnnouncementTimeStamp"); - print("Announcement: ${announcement.timestamp}"); - - int difference = announcement.timestamp!.difference(lastAnnouncementTimeStamp).inMilliseconds; - print("Difference: $difference"); - return; - } else if (announcement.timestamp == null) { - print("Announcement `${announcement.displayText}` does not have timestamp"); - } - - - - // If there is an announcement in the queue with the same timestamp, dont queue it - if (announcementQueue.any((element) => element.timestamp == announcement.timestamp)) { - print("Announcement with same timestamp already in queue"); - return; - } - - if (!announcement.sendToServer) { - - if (announcement is DestinationAnnouncementEntry) { - - BusRouteVariant routeVariant = announcement.routeVariant; - - if (getRouteVariant() != routeVariant) { - setRouteVariant(routeVariant); - } - - announcementQueue.add( - await _getDestinationAnnouncement( - routeVariant, - sendToServer: false - ) - ); - - print("Queued destination announcement: ${announcement.displayText}"); - print("Audios: ${announcement.audioSources.length}"); - return; - - } else if (announcement is ManualAnnouncementEntry) { - - List audioSources = []; - - for (String filename in announcement.audioFileNames) { - audioSources.add(AudioWrapperByteSource(announcementCache[filename])); - } - - announcementQueue.add( - ManualAnnouncementEntry( - shortName: announcement.shortName, - informationText: announcement.displayText, - audioFileNames: announcement.audioFileNames, - audioSources: audioSources, - sendToServer: false, - ) - ); - - print("Queued manual announcement: ${announcement.displayText} (no server)"); - return; - } - - announcementQueue.add(announcement); - print("Queued announcement: ${announcement.displayText} (no server)"); - return; - } - - final databases = appwrite.Databases(auth.client); - - print("Queuing announcement: ${announcement.displayText} (server)"); - print("Announcement type: ${announcement.runtimeType}"); - - if (announcement.runtimeType == InformationAnnouncementEntry) { - announcement as InformationAnnouncementEntry; - print("Queing to InformationAnnouncementEntry"); - - // 5 sedonds in the future - DateTime scheduledTime = (await getNow()).add(Duration(seconds: 1)); - - - final document = databases.createDocument( - documentId: appwrite.ID.unique(), - databaseId: ApiConstants.INFO_Q_DATABASE_ID, - collectionId: ApiConstants.INFORMATION_Q_COLLECTION_ID, - data: { - "ManualAnnouncementIndex": manualAnnouncements.indexOf(announcement), - "ScheduledTime": scheduledTime.toIso8601String(), - "SessionID": sessionID, - } - ); - - print("Queued manual announcement: ${announcement.shortName} (server)"); - - } else if (announcement.runtimeType == ManualAnnouncementEntry) { - announcement as ManualAnnouncementEntry; - print("Queing to ManualAnnouncementEntry"); - - // 5 sedonds in the future - DateTime scheduledTime = (await getNow()).add(Duration(seconds: 1)); - - final document = databases.createDocument( - documentId: appwrite.ID.unique(), - databaseId: ApiConstants.INFO_Q_DATABASE_ID, - collectionId: ApiConstants.MANUAL_Q_COLLECTION_ID, - data: { - "DisplayText": announcement.displayText, - "AudioFileNames": announcement.audioFileNames, - - "ScheduledTime": scheduledTime.toIso8601String(), - "SessionID": sessionID, - } - ); - - print("Queued manual announcement: ${announcement.shortName}"); - - } else if (announcement.runtimeType == DestinationAnnouncementEntry) { - announcement as DestinationAnnouncementEntry; - print("Queing to DestinationAnnouncementEntry"); - - // 5 sedonds in the future - DateTime scheduledTime = (getNow()).add(Duration(seconds: 2)); - - final document = databases.createDocument( - documentId: appwrite.ID.unique(), - databaseId: ApiConstants.INFO_Q_DATABASE_ID, - collectionId: ApiConstants.DEST_Q_COLLECTION_ID, - data: { - "RouteNumber": announcement.routeVariant.busRoute.routeNumber, - "RouteVariantIndex": announcement.routeVariant.routeVariant, - - "ScheduledTime": scheduledTime.toIso8601String(), - "SessionID": sessionID, - } - ); - - print("Queued manual announcement: ${announcement.shortName} (server)"); - - } - - } - - List manualAnnouncements = [ - InformationAnnouncementEntry( - shortName: "Driver Change", - informationText: "Driver Change", - audioSources: [AudioWrapperAssetSource("audio/manual_announcements/driverchange.mp3")], - ), - InformationAnnouncementEntry( - shortName: "No Standing Upr Deck", - informationText: "No standing on the upper deck", - audioSources: [AudioWrapperAssetSource("audio/manual_announcements/nostanding.mp3")], - ), - InformationAnnouncementEntry( - shortName: "Face Covering", - informationText: "Please wear a face covering!", - audioSources: [AudioWrapperAssetSource("audio/manual_announcements/facecovering.mp3")], - ), - InformationAnnouncementEntry( - shortName: "Seats Upstairs", - informationText: "Seats are available upstairs", - audioSources: [AudioWrapperAssetSource("audio/manual_announcements/seatsupstairs.mp3")], - ), - InformationAnnouncementEntry( - shortName: "Bus Terminates Here", - informationText: "Bus terminates here. Please take your belongings with you", - audioSources: [AudioWrapperAssetSource("audio/manual_announcements/busterminateshere.mp3")], - ), - InformationAnnouncementEntry( - shortName: "Bus On Diversion", - informationText: "Bus on diversion. Please listen for further announcements", - audioSources: [AudioWrapperAssetSource("audio/manual_announcements/busondiversion.mp3")], - ), - InformationAnnouncementEntry( - shortName: "Destination Change", - informationText: "Destination Changed - please listen for further instructions", - audioSources: [AudioWrapperAssetSource("audio/manual_announcements/destinationchange.mp3")], - ), - InformationAnnouncementEntry( - shortName: "Wheelchair Space", - informationText: "Wheelchair space requested", - audioSources: [AudioWrapperAssetSource("audio/manual_announcements/wheelchairspace1.mp3")], - ), - InformationAnnouncementEntry( - shortName: "Move Down The Bus", - informationText: "Please move down the bus", - audioSources: [AudioWrapperAssetSource("audio/manual_announcements/movedownthebus.mp3")], - ), - InformationAnnouncementEntry( - shortName: "Next Stop Closed", - informationText: "The next bus stop is closed", - audioSources: [AudioWrapperAssetSource("audio/manual_announcements/nextstopclosed.wav")], - ), - InformationAnnouncementEntry( - shortName: "CCTV In Operation", - informationText: "CCTV is in operation on this bus", - audioSources: [AudioWrapperAssetSource("audio/manual_announcements/cctvoperation.mp3")], - ), - InformationAnnouncementEntry( - shortName: "Safe Door Opening", - informationText: "Driver will open the doors when it is safe to do so", - audioSources: [AudioWrapperAssetSource("audio/manual_announcements/safedooropening.mp3")], - ), - InformationAnnouncementEntry( - shortName: "Buggy Safety", - informationText: "For your child's safety, please remain with your buggy", - audioSources: [AudioWrapperAssetSource("audio/manual_announcements/buggysafety.mp3")], - ), - InformationAnnouncementEntry( - shortName: "Wheelchair Space 2", - informationText: "Wheelchair priority space required", - audioSources: [AudioWrapperAssetSource("audio/manual_announcements/wheelchairspace2.mp3")], - ), - InformationAnnouncementEntry( - shortName: "Service Regulation", - informationText: "Regulating service - please listen for further information", - audioSources: [AudioWrapperAssetSource("audio/manual_announcements/serviceregulation.mp3")], - ), - InformationAnnouncementEntry( - shortName: "Bus Ready To Depart", - informationText: "This bus is ready to depart", - audioSources: [AudioWrapperAssetSource("audio/manual_announcements/readytodepart.mp3")], - ), - ]; - - AuthAPI auth = AuthAPI(); - String sessionID = "65de648aa7f44684ecce"; - void updateServer() async { - - - - final databases = appwrite.Databases(auth.client); - - // final document = databases.updateDocument( - // databaseId: ApiConstants.INFO_DATABASE_ID, - // collectionId: ApiConstants.INFO_COLLECTION_ID, - // documentId: documentID, - // data: { - // "Display": _currentAnnouncement, - // } - // ); - - print("Updated server with announcement: $_currentAnnouncement"); - - } - void pullServer() async { - - if (auth.status == AuthStatus.UNAUTHENTICATED) { - return; - } - - final databases = appwrite.Databases(auth.client); - - // final document = await databases.getDocument( - // databaseId: ApiConstants.INFO_DATABASE_ID, - // collectionId: ApiConstants.INFO_COLLECTION_ID, - // documentId: documentID, - // ); - - // queueAnnouncement(AnnouncementQueueEntry( - // displayText: document.data['Display'], - // audioSources: [], - // sendToServer: false, // Don't send this back to the server, else we'll get an infinite loop - // )); - - // print("Pulled announcement from server: ${document.data['Display']}"); - } - - bool purgeRunning = false; - Future deleteAllManualQueueEntries() async { - - if (purgeRunning) { - return; - } - purgeRunning = true; - - final databases = appwrite.Databases(auth.client); - int offset = 0; - const int limit = 25; // Maximum number of documents that can be fetched at once - - while (true) { - // Fetch a page of documents from the manual queue collection - print("Deleting manual queue entries"); - final manual_q = await databases.listDocuments( - databaseId: ApiConstants.INFO_Q_DATABASE_ID, - collectionId: ApiConstants.MANUAL_Q_COLLECTION_ID, - queries: [ - appwrite.Query.search("SessionID", sessionID), - appwrite.Query.limit(limit), - appwrite.Query.offset(offset), - appwrite.Query.orderDesc('\$createdAt') - ] - ); - - // If there are no documents in the fetched page, break the loop - if (manual_q.documents.isEmpty) { - break; - } - - // Delete each document in the fetched page - for (models.Document doc in manual_q.documents) { - await databases.deleteDocument( - databaseId: ApiConstants.INFO_Q_DATABASE_ID, - collectionId: ApiConstants.MANUAL_Q_COLLECTION_ID, - documentId: doc.$id, - ); - } - - // Go to the next page - offset += limit; - } - - print("Deleted all manual queue entries"); - } - - void pullQueue() async { - - if (auth.status == AuthStatus.UNAUTHENTICATED) { - return; - } - - List queue = []; - - final databases = appwrite.Databases(auth.client); - - // Pull the information queue - { - final manual_q = await databases.listDocuments( - databaseId: ApiConstants.INFO_Q_DATABASE_ID, - collectionId: ApiConstants.INFORMATION_Q_COLLECTION_ID, - queries: [ - appwrite.Query.search("SessionID", sessionID), - appwrite.Query.limit(25), - appwrite.Query.offset(0), - appwrite.Query.orderDesc('\$createdAt') - ] - ); - - for (models.Document doc in manual_q.documents) { - int index = doc.data['ManualAnnouncementIndex']; - - InformationAnnouncementEntry announcement_clone = - InformationAnnouncementEntry( - shortName: manualAnnouncements[index].shortName, - informationText: manualAnnouncements[index].displayText, - audioSources: manualAnnouncements[index].audioSources, - scheduledTime: doc.data["ScheduledTime"] != null - ? DateTime.parse(doc.data["ScheduledTime"]) - : null, - timestamp: DateTime.parse(doc.$createdAt), - sendToServer: false, - ); - - // sort the queue by timestamp, so the oldest announcements are at the front - - queue.add(announcement_clone); - } - } - - // pull the destination queue - { - final dest_q = await databases.listDocuments( - databaseId: ApiConstants.INFO_Q_DATABASE_ID, - collectionId: ApiConstants.DEST_Q_COLLECTION_ID, - queries: [ - appwrite.Query.search("SessionID", sessionID), - appwrite.Query.limit(25), - appwrite.Query.offset(0), - appwrite.Query.orderDesc('\$createdAt') - ] - ); - - for (models.Document doc in dest_q.documents) { - - BusRoute? route = busSequences.routes[doc.data["RouteNumber"]]; - - BusRouteVariant? routeVariant = route!.routeVariants[doc.data["RouteVariantIndex"]]; - - - DestinationAnnouncementEntry announcement_clone = - DestinationAnnouncementEntry( - routeVariant: routeVariant!, - scheduledTime: doc.data["ScheduledTime"] != null - ? DateTime.parse(doc.data["ScheduledTime"]) - : null, - timestamp: DateTime.parse(doc.$createdAt), - sendToServer: false, - audioSources: [], - ); - - // sort the queue by timestamp, so the oldest announcements are at the front - - queue.add(announcement_clone); - } - } - - // Pull the manual queue - { - final manual_q = await databases.listDocuments( - databaseId: ApiConstants.INFO_Q_DATABASE_ID, - collectionId: ApiConstants.MANUAL_Q_COLLECTION_ID, - queries: [ - appwrite.Query.search("SessionID", sessionID), - appwrite.Query.limit(25), - appwrite.Query.offset(0), - appwrite.Query.orderDesc('\$createdAt') - ] - ); - - for (models.Document doc in manual_q.documents) { - - - - List audioFileNames = doc.data["AudioFileNames"].cast(); - - ManualAnnouncementEntry announcement_clone = - ManualAnnouncementEntry( - sendToServer: false, - - shortName: "", - informationText: doc.data["DisplayText"], - audioFileNames: audioFileNames, - - scheduledTime: doc.data["ScheduledTime"] != null - ? DateTime.parse(doc.data["ScheduledTime"]) - : null, - - ); - - // sort the queue by timestamp, so the oldest announcements are at the front - - queue.add(announcement_clone); - } - } - - for (AnnouncementQueueEntry entry in queue) { - - // Dont queue announcements that are older than now - if (entry.scheduledTime != null && entry.scheduledTime!.isBefore(await getNow())) { - continue; - } - - queueAnnouncement(entry); - } - - } - - - - appwrite.RealtimeSubscription? information_q_subscription; - appwrite.RealtimeSubscription? manual_q_subscription; - appwrite.RealtimeSubscription? destination_q_subscription; - - Future setupRealtime() async { - - if (information_q_subscription != null) { - return; - } - - // await deleteAllManualQueueEntries(); //todo - - print("Setting up realtime"); - - // Websocket - appwrite.Realtime realtime = appwrite.Realtime(auth.client); - - information_q_subscription = realtime.subscribe( - ['databases.${ApiConstants.INFO_Q_DATABASE_ID}.collections.${ApiConstants.INFORMATION_Q_COLLECTION_ID}.documents'], - ); - information_q_subscription?.stream.listen((event) { - print("Manual queue entry added"); - - pullQueue(); - }); - - manual_q_subscription = realtime.subscribe( - ['databases.${ApiConstants.INFO_Q_DATABASE_ID}.collections.${ApiConstants.MANUAL_Q_COLLECTION_ID}.documents'], - ); - manual_q_subscription?.stream.listen((event) { - print("Manual queue entry added"); - - pullQueue(); - }); - - destination_q_subscription = realtime.subscribe( - ['databases.${ApiConstants.INFO_Q_DATABASE_ID}.collections.${ApiConstants.DEST_Q_COLLECTION_ID}.documents'], - ); - destination_q_subscription?.stream.listen((event) { - print("Destination queue entry added"); - - pullQueue(); - }); - - print("Subscribed to servers"); - - await Future.delayed(Duration(seconds: 90)); - - information_q_subscription?.close(); - information_q_subscription = null; - manual_q_subscription?.close(); - manual_q_subscription = null; - destination_q_subscription?.close(); - destination_q_subscription = null; - print("Restarting realtime"); - setupRealtime(); - - } - - - -} - -class AnnouncementQueueEntry { - final String displayText; - final List audioSources; - bool sendToServer = true; - DateTime? scheduledTime; - DateTime? timestamp; - - AnnouncementQueueEntry({required this.displayText, required this.audioSources, this.sendToServer = true, this.scheduledTime, this.timestamp}); -} - -class NamedAnnouncementQueueEntry extends AnnouncementQueueEntry { - final String shortName; - - NamedAnnouncementQueueEntry({ - required this.shortName, - required String displayText, - required List audioSources, - DateTime? scheduledTime, - DateTime? timestamp, - bool sendToServer = true, - }) : super( - displayText: displayText, - audioSources: audioSources, - sendToServer: sendToServer, - scheduledTime: scheduledTime, - timestamp: timestamp, - ); -} - -class ManualAnnouncementEntry extends NamedAnnouncementQueueEntry { - - final List audioFileNames; - - ManualAnnouncementEntry({ - required String shortName, - required String informationText, - required this.audioFileNames, - List audioSources = const [], - DateTime? scheduledTime, - DateTime? timestamp, - bool sendToServer = true, - }) : super( - shortName: shortName, - displayText: informationText, - audioSources: audioSources, - sendToServer: sendToServer, - scheduledTime: scheduledTime, - timestamp: timestamp, - ); -} - -class InformationAnnouncementEntry extends NamedAnnouncementQueueEntry { - - - InformationAnnouncementEntry({ - required String shortName, - required String informationText, - required List audioSources, - DateTime? scheduledTime, - DateTime? timestamp, - bool sendToServer = true, - }) : super( - shortName: shortName, - displayText: informationText, - audioSources: audioSources, - sendToServer: sendToServer, - scheduledTime: scheduledTime, - timestamp: timestamp, - ); -} - -class DestinationAnnouncementEntry extends NamedAnnouncementQueueEntry { - - final BusRouteVariant routeVariant; - - DestinationAnnouncementEntry({ - required this.routeVariant, - required List audioSources, - DateTime? scheduledTime, - DateTime? timestamp, - bool sendToServer = true, - }) : super( - shortName: "Destination", - displayText: "${routeVariant.busRoute.routeNumber} to ${routeVariant.busStops.last.formattedStopName}", - audioSources: audioSources, - sendToServer: sendToServer, - scheduledTime: scheduledTime, - timestamp: timestamp, - ); - -} - -var abs = (int value) => value < 0 ? -value : value; \ No newline at end of file diff --git a/lib/tfl_datasets.dart b/lib/tfl_datasets.dart index 7ca6c0b..cacf7ac 100644 --- a/lib/tfl_datasets.dart +++ b/lib/tfl_datasets.dart @@ -3,24 +3,64 @@ import 'dart:typed_data'; import 'package:bus_infotainment/audio_cache.dart'; +import 'package:bus_infotainment/backend/live_information.dart'; +import 'package:bus_infotainment/backend/modules/info_module.dart'; import 'package:bus_infotainment/utils/NameBeautify.dart'; +import 'package:bus_infotainment/utils/OrdinanceSurveyUtils.dart'; import 'package:csv/csv.dart'; +import 'package:vector_math/vector_math.dart'; -class BusSequences { +class BusSequences extends InfoModule { Map routes = {}; - BusSequences.fromCSV(String csv) { + Map destinations = {}; - List> rowsAsListOfValues = const CsvToListConverter().convert(csv); + BusSequences.fromCSV(String destinationsCSV, String busSequencesCSV) { - rowsAsListOfValues.removeAt(0); - - for (int i = 0; i < rowsAsListOfValues.length; i++) { + // Init the bus destinations + List> destinationRows = const CsvToListConverter().convert(destinationsCSV); + destinationRows.removeAt(0); + for (int i = 0; i < destinationRows.length; i++) { try { - List entries = rowsAsListOfValues[i]; + List entries = destinationRows[i]; + + String routeNumber = entries[0].toString(); + + BusRoute route = routes.containsKey(routeNumber) ? routes[routeNumber]! : BusRoute(routeNumber: routeNumber); + + String blind = entries[1].toString(); + + double lat = double.parse(entries[2].toString()); + double long = double.parse(entries[3].toString()); + + Vector2 grid = OSGrid.toNorthingEasting(lat, long); + + BusDestination destination = BusDestination(); + destination.destination = blind; + destination.easting = grid.x; + destination.northing = grid.y; + + route.destinations.add(destination); + + routes[routeNumber] = route; + destinations[blind] = destination; + } catch (e) {} + } + + // Init the bus routes + + List> busSequenceRows = const CsvToListConverter().convert(busSequencesCSV); + busSequenceRows.removeAt(0); + + for (int i = 0; i < busSequenceRows.length; i++) { + + try + { + + List entries = busSequenceRows[i]; String routeNumber = entries[0].toString(); @@ -28,25 +68,28 @@ class BusSequences { int routeVariant = entries[1]; - BusRouteVariant variant = route.routeVariants.containsKey(routeVariant) ? route.routeVariants[routeVariant]! : BusRouteVariant(routeVariant: routeVariant, busRoute: route); - - BusRouteStops stop = BusRouteStops(); + BusRouteStop stop = BusRouteStop(); stop.stopName = entries[6].toString(); stop.stopCode = entries[4].toString(); stop.easting = entries[7]; stop.northing = entries[8]; + stop.heading = entries[9] != "" ? entries[9] : -1; + + BusRouteVariant variant = route.routeVariants.containsKey(routeVariant) ? route.routeVariants[routeVariant]! : BusRouteVariant(routeVariant: routeVariant, busRoute: route); variant.busStops.add(stop); + route.routeVariants[routeVariant] = variant; routes[routeNumber] = route; - } catch (e) { - // print("Error parsing bus sequence: $e"); } - + catch (e) { + print("Error parsing bus sequence: $e"); + } } + } } @@ -55,6 +98,8 @@ class BusRoute { String routeNumber = ""; + List destinations = []; + AnnouncementCache? announcementCache; Map routeVariants = {}; @@ -70,7 +115,7 @@ class BusRouteVariant { int routeVariant = -1; - List busStops = []; + List busStops = []; late BusRoute busRoute; @@ -78,14 +123,66 @@ class BusRouteVariant { this.routeVariant = -1, required this.busRoute, }); + + BusDestination? _destination; + BusDestination? get destination { + if (_destination == null) { + + // Get the nearest destination + BusDestination? nearestDestinationA; + double nearestDistanceA = double.infinity; + + Vector2 stopLocation = Vector2(busStops.last.northing.toDouble(), busStops.last.easting.toDouble()); + + for (BusDestination destination in busRoute.destinations) { + + Vector2 destinationLocation = Vector2(destination.northing.toDouble(), destination.easting.toDouble()); + + double distance = stopLocation.distanceTo(destinationLocation); + + if (distance < nearestDistanceA) { + nearestDestinationA = destination; + nearestDistanceA = distance; + } + + } + + // get the nearest destination from global pool of destinations + BusDestination? nearestDestinationB; + double nearestDistanceB = double.infinity; + + for (BusDestination destination in LiveInformation().busSequences.destinations.values) { + + Vector2 destinationLocation = Vector2(destination.northing.toDouble(), destination.easting.toDouble()); + + double distance = stopLocation.distanceTo(destinationLocation); + + if (distance < nearestDistanceB) { + nearestDestinationB = destination; + nearestDistanceB = distance; + } + + } + + // Choose the nearest destination + if (nearestDistanceA < nearestDistanceB) { + _destination = nearestDestinationA; + } else { + _destination = nearestDestinationB; + } + + } + return _destination; + } } -class BusRouteStops { +class BusRouteStop { String stopName = ""; int easting = -1; int northing = -1; + int heading = -1; String stopCode = ""; @@ -122,4 +219,60 @@ class BusRouteStops { } +} + +class BusDestination { + + String destination = ""; + + double easting = -1; + double northing = -1; + + Future getAudioBytes() async { + + // Convert the stop name to all caps + String name = destination.toUpperCase(); + + name = NameBeautify.beautifyStopName(name); + + // replace & with N + name = name.replaceAll('&', 'N'); + + name = name.replaceAll('/', ''); + + name = name.replaceAll('\'', ''); + + name = name.replaceAll(' ', ' '); + + // Replace space with underscore + name = name.replaceAll(' ', '_'); + + // convert to all caps + name = name.toUpperCase(); + + String audioNameA = "D_${name}_001.mp3"; + String audioNameB = "S_${name}_001.mp3"; + String audioNameC = "A_${name}_001.mp3"; + + print("Audio name A: $audioNameA"); + print("Audio name B: $audioNameB"); + print("Audio name C: $audioNameC"); + + await LiveInformation().announcementModule.announcementCache.loadAnnouncements([audioNameA, audioNameB, audioNameC]); + + Uint8List? audioBytesA = LiveInformation().announcementModule.announcementCache[audioNameA]; + Uint8List? audioBytesB = LiveInformation().announcementModule.announcementCache[audioNameB]; + Uint8List? audioBytesC = LiveInformation().announcementModule.announcementCache[audioNameC]; + + if (audioBytesA != null) return audioBytesA; + if (audioBytesB != null) return audioBytesB; + if (audioBytesC != null) return audioBytesC; + + print("No audio bytes found for $name"); + + return Uint8List(0); + + } + + } \ No newline at end of file diff --git a/lib/utils/OrdinanceSurveyUtils.dart b/lib/utils/OrdinanceSurveyUtils.dart new file mode 100644 index 0000000..23145c9 --- /dev/null +++ b/lib/utils/OrdinanceSurveyUtils.dart @@ -0,0 +1,35 @@ +import 'dart:math' as math; +import 'package:proj4dart/proj4dart.dart' as proj4; +import 'package:vector_math/vector_math.dart'; + + +class OSGrid { + + static List toLatLong(double northing, double easting) { + + final sourceProjection = proj4.Projection.parse('+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 ' + '+x_0=400000 +y_0=-100000 +ellps=airy +datum=OSGB36 +units=m +no_defs'); // British National Grid + final destinationProjection = proj4.Projection.WGS84;// WGS84 + + final point = proj4.Point(x: easting, y: northing); + final transformedPoint = sourceProjection.transform(destinationProjection, point); + + + + return [transformedPoint.y, transformedPoint.x]; + } + + static Vector2 toNorthingEasting(double latitude, double longitude) { + + final sourceProjection = proj4.Projection.WGS84;// WGS84 + final destinationProjection = proj4.Projection.parse('+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 ' + '+x_0=400000 +y_0=-100000 +ellps=airy +datum=OSGB36 +units=m +no_defs'); // British National Grid + + final point = proj4.Point(x: longitude, y: latitude); + final transformedPoint = sourceProjection.transform(destinationProjection, point); + + return Vector2(transformedPoint.x, transformedPoint.y); + } + +} + diff --git a/lib/utils/audio wrapper.dart b/lib/utils/audio wrapper.dart index 8b6d3f7..e4c0699 100644 --- a/lib/utils/audio wrapper.dart +++ b/lib/utils/audio wrapper.dart @@ -3,6 +3,11 @@ import 'package:audioplayers/audioplayers.dart' as audioplayers; import 'package:flutter/foundation.dart'; import 'package:just_audio/just_audio.dart' as justaudio; +enum AudioWrapper_Mode { + Web, + Mobile +} + enum AudioWrapper_State { Playing, NotPlaying @@ -13,6 +18,16 @@ class AudioWrapper { audioplayers.AudioPlayer _audioPlayer_AudioPlayer = audioplayers.AudioPlayer(); justaudio.AudioPlayer _justAudio_AudioPlayer = justaudio.AudioPlayer(); + AudioWrapper_Mode mode = kIsWeb ? AudioWrapper_Mode.Web : AudioWrapper_Mode.Mobile; + + AudioWrapper() { + // mode = AudioWrapper_Mode.Web; + + print("AudioWrapper mode: $mode"); + + // mode = AudioWrapper_Mode.Mobile; + } + justaudio.AudioSource _convertSource_JustAudio(AudioWrapperSource source){ if (source is AudioWrapperByteSource){ return _ByteSource(source.bytes); @@ -33,45 +48,94 @@ class AudioWrapper { } } - Future play(AudioWrapperSource source) async { - Duration? duration; - - if (kIsWeb) { + Future loadSource(AudioWrapperSource source) async { + if (mode == AudioWrapper_Mode.Web) { // Use just_audio justaudio.AudioSource audioSource = _convertSource_JustAudio(source); - duration = await _justAudio_AudioPlayer.setAudioSource(audioSource); + await _justAudio_AudioPlayer.setAudioSource(audioSource); - _justAudio_AudioPlayer.play(); - - - } else { + } else if (mode == AudioWrapper_Mode.Mobile) { // Use audioplayers audioplayers.Source audioSource = _convertSource_AudioPlayers(source); - await _audioPlayer_AudioPlayer.play(audioSource); + await _audioPlayer_AudioPlayer.setSource(audioSource); + // await _audioPlayer_AudioPlayer.play(audioSource); + } + } + Future getDuration() async { + if (mode == AudioWrapper_Mode.Web) { + return _justAudio_AudioPlayer.duration; + } else if (mode == AudioWrapper_Mode.Mobile) { + return await _audioPlayer_AudioPlayer.getDuration(); + } + } + + Future play() async { + + Duration? duration; + + if (mode == AudioWrapper_Mode.Web) { + _justAudio_AudioPlayer.play(); + duration = _justAudio_AudioPlayer.duration; + } else if (mode == AudioWrapper_Mode.Mobile) { + _audioPlayer_AudioPlayer.resume(); duration = await _audioPlayer_AudioPlayer.getDuration(); } - - - return duration; } + // Future play(AudioWrapperSource source) async { + // + // Duration? duration; + // + // if (mode == AudioWrapper_Mode.Web) { + // // Use just_audio + // + // justaudio.AudioSource audioSource = _convertSource_JustAudio(source); + // + // duration = await _justAudio_AudioPlayer.setAudioSource(audioSource); + // + // _justAudio_AudioPlayer.play(); + // + // + // } else if (mode == AudioWrapper_Mode.Mobile) { + // // Use audioplayers + // + // audioplayers.Source audioSource = _convertSource_AudioPlayers(source); + // + // await _audioPlayer_AudioPlayer.play(audioSource); + // + // duration = await _audioPlayer_AudioPlayer.getDuration(); + // } + // + // + // + // return duration; + // } + void stop(){ - if (kIsWeb) { + if (mode == AudioWrapper_Mode.Web) { _justAudio_AudioPlayer.stop(); - } else { + try { + _justAudio_AudioPlayer.dispose(); + } catch (e) {} + _justAudio_AudioPlayer = justaudio.AudioPlayer(); + } else if (mode == AudioWrapper_Mode.Mobile) { _audioPlayer_AudioPlayer.stop(); + try { + _audioPlayer_AudioPlayer.dispose(); + } catch (e) {} + _audioPlayer_AudioPlayer = audioplayers.AudioPlayer(); } } AudioWrapper_State get state { - if (kIsWeb) { + if (mode == AudioWrapper_Mode.Web) { if (_justAudio_AudioPlayer.playing){ return AudioWrapper_State.Playing; } else { diff --git a/lib/utils/delegates.dart b/lib/utils/delegates.dart index d6d3a73..fcbbe73 100644 --- a/lib/utils/delegates.dart +++ b/lib/utils/delegates.dart @@ -11,7 +11,7 @@ class ListenerReceipt { } class EventDelegate { - final List> _receipts = []; + final List> _receipts = []; ListenerReceipt addListener(Function(T) listener) { final receipt = ListenerReceipt(listener); @@ -26,14 +26,16 @@ class EventDelegate { void trigger(T event) { print("triggering event"); - for (var receipt in _receipts) { - print("triggering listener"); - try { - receipt.listener(event); - } catch (e) { - print("Error in listener: $e"); - removeListener(receipt); + try { + for (var receipt in _receipts) { + print("triggering listener"); + try { + receipt.listener(event); + } catch (e) { + } } + } catch (e) { + print("Error in trigger: $e"); } } } diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 1da8b5b..55cb301 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -7,16 +7,24 @@ #include "generated_plugin_registrant.h" #include +#include #include +#include #include void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) audioplayers_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "AudioplayersLinuxPlugin"); audioplayers_linux_plugin_register_with_registrar(audioplayers_linux_registrar); + g_autoptr(FlPluginRegistrar) screen_retriever_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverPlugin"); + screen_retriever_plugin_register_with_registrar(screen_retriever_registrar); g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); + g_autoptr(FlPluginRegistrar) window_manager_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "WindowManagerPlugin"); + window_manager_plugin_register_with_registrar(window_manager_registrar); g_autoptr(FlPluginRegistrar) window_to_front_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "WindowToFrontPlugin"); window_to_front_plugin_register_with_registrar(window_to_front_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 69df1f4..d8082e0 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -4,7 +4,9 @@ list(APPEND FLUTTER_PLUGIN_LIST audioplayers_linux + screen_retriever url_launcher_linux + window_manager window_to_front ) diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 85b576f..3e8cf8a 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -9,11 +9,14 @@ import audio_session import audioplayers_darwin import device_info_plus import flutter_web_auth_2 +import geolocator_apple import just_audio import package_info_plus import path_provider_foundation +import screen_retriever import shared_preferences_foundation import url_launcher_macos +import window_manager import window_to_front func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { @@ -21,10 +24,13 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) FlutterWebAuth2Plugin.register(with: registry.registrar(forPlugin: "FlutterWebAuth2Plugin")) + GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) + WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin")) WindowToFrontPlugin.register(with: registry.registrar(forPlugin: "WindowToFrontPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 66d53d1..109d35a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -272,6 +272,54 @@ packages: description: flutter source: sdk version: "0.0.0" + geolocator: + dependency: "direct main" + description: + name: geolocator + sha256: "694ec58afe97787b5b72b8a0ab78c1a9244811c3c10e72c4362ef3c0ceb005cd" + url: "https://pub.dev" + source: hosted + version: "11.0.0" + geolocator_android: + dependency: transitive + description: + name: geolocator_android + sha256: "136f1c97e1903366393bda514c5d9e98843418baea52899aa45edae9af8a5cd6" + url: "https://pub.dev" + source: hosted + version: "4.5.2" + geolocator_apple: + dependency: transitive + description: + name: geolocator_apple + sha256: "2f2d4ee16c4df269e93c0e382be075cc01d5db6703c3196e4af20a634fe49ef4" + url: "https://pub.dev" + source: hosted + version: "2.3.6" + geolocator_platform_interface: + dependency: transitive + description: + name: geolocator_platform_interface + sha256: "009a21c4bc2761e58dccf07c24f219adaebe0ff707abdfd40b0a763d4003fab9" + url: "https://pub.dev" + source: hosted + version: "4.2.2" + geolocator_web: + dependency: transitive + description: + name: geolocator_web + sha256: "49d8f846ebeb5e2b6641fe477a7e97e5dd73f03cbfef3fd5c42177b7300fb0ed" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + geolocator_windows: + dependency: transitive + description: + name: geolocator_windows + sha256: a92fae29779d5c6dc60e8411302f5221ade464968fe80a36d330e80a71f087af + url: "https://pub.dev" + source: hosted + version: "0.2.2" google_fonts: dependency: "direct main" description: @@ -496,6 +544,54 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.1" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + sha256: "74e962b7fad7ff75959161bb2c0ad8fe7f2568ee82621c9c2660b751146bfe44" + url: "https://pub.dev" + source: hosted + version: "11.3.0" + permission_handler_android: + dependency: transitive + description: + name: permission_handler_android + sha256: "1acac6bae58144b442f11e66621c062aead9c99841093c38f5bcdcc24c1c3474" + url: "https://pub.dev" + source: hosted + version: "12.0.5" + permission_handler_apple: + dependency: transitive + description: + name: permission_handler_apple + sha256: bdafc6db74253abb63907f4e357302e6bb786ab41465e8635f362ee71fd8707b + url: "https://pub.dev" + source: hosted + version: "9.4.0" + permission_handler_html: + dependency: transitive + description: + name: permission_handler_html + sha256: "54bf176b90f6eddd4ece307e2c06cf977fb3973719c35a93b85cc7093eb6070d" + url: "https://pub.dev" + source: hosted + version: "0.1.1" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + sha256: "23dfba8447c076ab5be3dee9ceb66aad345c4a648f0cac292c77b1eb0e800b78" + url: "https://pub.dev" + source: hosted + version: "4.2.0" + permission_handler_windows: + dependency: transitive + description: + name: permission_handler_windows + sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" + url: "https://pub.dev" + source: hosted + version: "0.2.1" platform: dependency: transitive description: @@ -544,6 +640,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.27.7" + screen_retriever: + dependency: transitive + description: + name: screen_retriever + sha256: "6ee02c8a1158e6dae7ca430da79436e3b1c9563c8cf02f524af997c201ac2b90" + url: "https://pub.dev" + source: hosted + version: "0.1.9" shared_preferences: dependency: "direct main" description: @@ -774,7 +878,7 @@ packages: source: hosted version: "3.1.1" uuid: - dependency: transitive + dependency: "direct main" description: name: uuid sha256: cd210a09f7c18cbe5a02511718e0334de6559871052c90a90c0cca46a4aa81c8 @@ -782,7 +886,7 @@ packages: source: hosted version: "4.3.3" vector_math: - dependency: transitive + dependency: "direct main" description: name: vector_math sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" @@ -821,6 +925,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.2" + window_manager: + dependency: "direct main" + description: + name: window_manager + sha256: b3c895bdf936c77b83c5254bec2e6b3f066710c1f89c38b20b8acc382b525494 + url: "https://pub.dev" + source: hosted + version: "0.3.8" window_to_front: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 186bcb8..b456929 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -44,6 +44,12 @@ dependencies: shared_preferences: ^2.2.2 url_launcher: ^6.2.2 ntp: ^2.0.0 + uuid: ^4.3.3 + window_manager: ^0.3.8 + geolocator: ^11.0.0 + vector_math: ^2.1.4 + permission_handler: ^11.3.0 + # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. @@ -78,6 +84,7 @@ flutter: - assets/fonts/ibus/london-buses-ibus.ttf - assets/audio/manual_announcements/ - assets/audio/to_destination.wav + - assets/datasets/bus-blinds.csv # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 4d83633..24fcf1e 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -7,17 +7,29 @@ #include "generated_plugin_registrant.h" #include +#include #include +#include +#include #include +#include #include void RegisterPlugins(flutter::PluginRegistry* registry) { AudioplayersWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin")); + GeolocatorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("GeolocatorWindows")); JustAudioWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("JustAudioWindowsPlugin")); + PermissionHandlerWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); + ScreenRetrieverPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ScreenRetrieverPlugin")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); + WindowManagerPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("WindowManagerPlugin")); WindowToFrontPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("WindowToFrontPlugin")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 40b0733..a9dab9a 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -4,8 +4,12 @@ list(APPEND FLUTTER_PLUGIN_LIST audioplayers_windows + geolocator_windows just_audio_windows + permission_handler_windows + screen_retriever url_launcher_windows + window_manager window_to_front )