Продолжаем изучать географию столицы и как она влияет на комфорт жилья. В этой публикации подключим маршрутизацию и расчитаем пешеходные расстояния от входа в метрополитен до жилых зданий. В прошлый раз я анализировал жилье в городе на удаленность от негативных факторов и поделился инструкцией "Где в Москве жить «неплохо»". Теперь же перейдем на позитивные факторы выбора места квартиры и найдем в Москве жилые дома в шаговой доступности от метро.

Сделаем это c помощью Graphhopper, OpenStreetMap H3 и PostGIS. Если вы далеки от PostgreSQL/Java, то сразу пролистывайте в конец статьи.
Подготовка данных
Загружал геоданные Москвы в Ubuntu, где установлены git, wget, docker.io:
mkdir ~/moscow && cd ~/moscow wget https://download.geofabrik.de/russia/central-fed-district-latest.osm.pbf wget https://raw.githubusercontent.com/mapsme/omim/master/data/borders/Russia_Moscow.poly docker run -rm -it -w /wkd -v $(pwd):/wkd mschilde/osmium-tool osmium extract --polygon Russia_Moscow.poly central-fed-district-latest.osm.pbf -o moscow.osm.pbf git clone https://github.com/igor-suhorukov/openstreetmap_h3.git cd openstreetmap_h3 && docker build -t openstreetmap_h3 . cd postgis_docker-master && docker build -t postgres15_postgis . cd ~/moscow docker run -it --rm -w $(pwd) -v $(pwd):/$(pwd) -v /var/run/docker.sock:/var/run/docker.sock openstreetmap_h3:latest -source_pbf $(pwd)/moscow.osm.pbf -result_in_tsv true docker run --name postgis15-moscow --memory=12g --memory-swap=12g --memory-swappiness 0 --shm-size=1g -v $(pwd)/database:/var/lib/postgresql/data -v $(pwd)/moscow_loc_ways:/input -e POSTGRES_PASSWORD=osmworld -d -p 5432:5432 postgres15_postgis:latest -c checkpoint_timeout='15 min' -c checkpoint_completion_target=0.9 -c shared_buffers='4096 MB' -c wal_buffers=-1 -c bgwriter_delay=200ms -c bgwriter_lru_maxpages=100 -c bgwriter_lru_multiplier=2.0 -c bgwriter_flush_after=0 -c max_wal_size='32768 MB' -c min_wal_size='16384 MB'
После успешного подключения к базе данных командой:
psql -h 127.0.0.1 -p 5432 -U postgres -d osmworld
В первую очередь нужно найти входы в метро и МЦК по тегу railway=subway_entrance:
create temporary table subway_entrance as select id, centre, tags from geometry_global_view e where tags@>'railway=>subway_entrance';

Вспоминая школьные задачки про пешехода, идущего со скоростью 5км/ч, за 15 минут пешком обычно проходят расстояние 1250м. Поэтому для каждого входа в подземку найдем жилые здания в заданном радиусе, по прямой.
CREATE TYPE building_info AS (id bigint, type table_reference, x float8, y float8); create table living_building_near as select m.id subway_entrance_id,st_x(m.centre) subway_entrance_x,st_y(m.centre) subway_entrance_y, array_agg((b.id,b.type,st_x(b.centre),st_y(b.centre))::building_info) buildings from subway_entrance m inner join geometry_global_view b on b.tags?'building' and not(b.tags?'amenity') and not(b.tags?'shop') and b.tags->'building' not in --в перечисленных ниже зданиях не живут на постоянной основе ('service','garages','industrial','retail','office','roof','commercial','garage','kiosk','warehouse','church', 'parking','public','shed','hangar','train_station','guardhouse','transportation','terrace','greenhouse','bridge', 'government','chapel','gazebo','civic','ruins','supermarket','sports_centre','semidetached_house','toilets', 'sports_hall','clinic','farm_auxiliary','stable','grandstand','bunker','gatehouse','store','temple','ventilation_kiosk', 'carport','cowshed','barracks','shop','cabin','barn','cathedral','wall','townhouse','manufacture','shelter', 'fire_station','stadium','stands','sport_hall','theatre','storage_tank','checkpoint','houseboat','abandoned','dovecote', 'mosque','museum','military','container','observatory','lift','tent','factory','sport','mall','riding_hall','depot', 'prison','gate','triumphal_arch','water_works','public_building','pavilion','bank','institute','works','collapsed', 'car_repair','crossing_box','fuel','tree_house','presbytery','yesq','farm','outbuilding','police','porch','sauna', 'monastery','cinema','tower','boathouse','library','transformer_tower','heat_exchange_station','ice_rink','entrance','construction','transformer') and ST_DWithin(b.geom::geography,m.centre::geography,1250) group by 1,2,3; --select m.id subway_entrance_id,st_x(m.centre) subway_entrance_x,st_y(m.centre) subway_entrance_y,array_agg((b.id,b.type,st_x(b.centre),st_y(b.centre))::building_info) buildings from subway_entrance m inner join geometry_global_view b on b.tags?'_lb' and ST_DWithin(b.geom::geography,m.centre::geography,1250) group by group by 1,2,3;
В результате выполения запроса в базе создастся таблица, где для каждого входа в метро будет список зданий в радиусе 1250м по прямой с координатами их центров и ID:
osmworld=# \d living_building_near Table "public.living_building_near" Column | Type | Collation | Nullable | Default --------------------+------------------+-----------+----------+--------- subway_entrance_id | bigint | | | subway_entrance_x | double precision | | | subway_entrance_y | double precision | | | buildings | building_info[] | | |
Создадим таблицу, куда сохраним рассчитанные программой расстояний:
create table subway_distance( entrance_id bigint, building_id bigint, building_type table_reference, distance smallint, primary key(entrance_id,building_id,building_type) );
Расчет пешеходных расстояний
Выбрали дома в окрестностях, но расстояние по прямой обычно короче чем реальный путь. А чтобы его расчитать нужен либо сервис расчета маршрутов за деньги и с ограничением количества запросов, либо локльно запущенный роутер энджин. Для OpenStreetMap есть несколько Open Source движков маршрутизации. Но мне привычнее и удобнее использовать Graphhopper на Java. В чем основное преимущество перед API любого поставщика для прокладки маршрутов - отсутствие лимитов, сетевых задержек и платы за сервис. Например, для этой публикации программа расчитала 450032 расстояний "без регистраций и СМС". Также при желании Graphhopper позволяет настраивать веса и можно делать роутинг по правилам предпочитая например близость деревьев к дорожке и избегая мест где нет асфальта.
Основная проблема с расчетом расстояний - это время вычислений, в случае если сервис взаимодействует с программой как REST через TCP, поэтому я буду использовать Graphhopper 8.0 как библиотеку с in-process взаимодействием без вызовов по HTTP. Для этого добавлю в скрипт сборки программы зависимости graphhopper-core и postgresql jdbc драйвер:
Maven pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.github.igor-suhorukov</groupId> <artifactId>routing-example</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>com.graphhopper</groupId> <artifactId>graphhopper-core</artifactId> <version>8.0</version> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>42.6.0</version> </dependency> </dependencies> </project>
Моя Java программа извлекает из таблицы living_building_near идентификаторы входа в метро и здания в окрестностях а также их координаты, расчитывает пешеходную дистанцию и сохраняет ее в таблицу subway_distance. В процессе работы пропуская строения, пешеходное расстояния до которых больше чем 1250м.
package com.github.isuhorukov.routing; import com.graphhopper.GHRequest; import com.graphhopper.GHResponse; import com.graphhopper.GraphHopper; import com.graphhopper.ResponsePath; import com.graphhopper.config.CHProfile; import com.graphhopper.config.Profile; import org.postgresql.jdbc.PgArray; import org.postgresql.util.PGobject; import java.sql.*; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class Routing { public static void main(String[] args) throws Exception { GraphHopper hopper = getGraphHopper(); try (Connection connection = DriverManager.getConnection( System.getenv("jdbc_url"), System.getenv("user"), System.getenv("password"))) { connection.setAutoCommit(false); try { var distances = calculateDistances(connection, hopper); saveDistance(connection, distances); } catch (SQLException e) { connection.rollback(); throw e; } } } private static GraphHopper getGraphHopper() { var hopper = new GraphHopper(); hopper.setOSMFile(System.getenv("osm_file")); hopper.setGraphHopperLocation("route"); hopper.getCHPreparationHandler().setCHProfiles(new CHProfile("foot")); hopper.setProfiles(new Profile("foot").setVehicle("foot")); hopper.importOrLoad(); return hopper; } private static List<Distance> calculateDistances(Connection connection, GraphHopper hopper) throws SQLException { List<Distance> distances = new ArrayList<>(); try (Statement subwayQuery = connection.createStatement()){ int step=0; try (ResultSet livingBuilding = subwayQuery.executeQuery("select * from living_building_near")){ while (livingBuilding.next()){ long subwayEntranceId = livingBuilding.getLong("subway_entrance_id"); double subwayEntranceX = livingBuilding.getDouble("subway_entrance_x"); double subwayEntranceY = livingBuilding.getDouble("subway_entrance_y"); PgArray buildingsArray = (PgArray) livingBuilding.getArray("buildings"); List<Building> buildings = mapBuildings(buildingsArray); System.out.println(step++); distances.addAll(buildings.stream().map(building -> { short distance = calculateDistances(hopper, building, subwayEntranceY, subwayEntranceX); return new Distance(subwayEntranceId,building.buildingId, building.buildingType, distance); }).collect(Collectors.toList())); } } } return distances; } private static void saveDistance(Connection connection, List<Distance> distances) throws SQLException { try (PreparedStatement insert = connection.prepareStatement( "insert into subway_distance(entrance_id,building_id,building_type,distance) " + "values (?,?,?::table_reference,?)")){ distances.forEach(distance -> { if(distance.distance>1250) return; try { insert.setLong(1, distance.subwayEntranceId); insert.setLong(2, distance.buildingId); insert.setString(3, distance.buildingType); insert.setShort(4, distance.distance); insert.addBatch(); } catch (SQLException e) { throw new RuntimeException(e); } }); insert.executeBatch(); connection.commit(); } } private static List<Building> mapBuildings(PgArray buildingsArray) throws SQLException { return getPgObjects(buildingsArray).stream().map(pGobject -> { String value = pGobject.getValue(); if(value==null || value.length()<=2){ throw new IllegalArgumentException(); } String[] parts = value.substring(1, value.length() - 1).split(","); long buildingId = Long.parseLong(parts[0]); String buildingType = parts[1]; double buildingX = Double.parseDouble(parts[2]); double buildingY = Double.parseDouble(parts[3]); return new Building(buildingId, buildingType, buildingX, buildingY); }).collect(Collectors.toList()); } private static List<PGobject> getPgObjects(PgArray buildingsArray) throws SQLException { Object[] array = (Object[]) buildingsArray.getArray(); buildingsArray.free(); return Arrays.stream(array).map(object -> (PGobject) object).collect(Collectors.toList()); } private static short calculateDistances(GraphHopper hopper, Building building, double subwayEntranceY, double subwayEntranceX) { GHRequest request = new GHRequest(subwayEntranceY, subwayEntranceX, building.buildingY, building.buildingX); request.setProfile("foot"); GHResponse route = hopper.route(request); ResponsePath bestRoute = route.getBest(); return (short) Math.round(bestRoute.getDistance()); } private static class Building{ long buildingId; String buildingType; double buildingX; double buildingY; public Building(long buildingId, String buildingType, double buildingX, double buildingY) { this.buildingId = buildingId; this.buildingType = buildingType; this.buildingX = buildingX; this.buildingY = buildingY; } } private static class Distance{ long subwayEntranceId; long buildingId; String buildingType; short distance; public Distance(long subwayEntranceId, long buildingId, String buildingType, short distance) { this.subwayEntranceId = subwayEntranceId; this.buildingId = buildingId; this.buildingType = buildingType; this.distance = distance; } } }
Параметры программе передаются через переменные окружения jdbc_url, osm_file, password, user.
Центры зданий выгрузил в GeoJSON файл:
\copy (select json_build_object('type', 'FeatureCollection','features', json_agg(json_build_object('type', 'Feature','geometry', st_AsGeoJSON(centre)::json))) from (select distinct centre from subway_distance s inner join geometry_global_view b on b.id=s.building_id and b.type=s.building_type) buildings ) to '~/moscow_metro_footpath.json';
Когда хочется найти панельный дом в OpenStreetMap
Захотелось мне в параметрах домов добавить типовой проект дома, чтобы отличать панельки от современных зданий и тут я обнаружил кое-что интересное с неполнотой данных.

--все жилые дома select count(tags->'design:ref')*100.0/count(*) cnt, count(*) from geometry_global_view where tags?'_lb'; cnt | count ---------------------+-------- 18.7563917273088398 | 118317 --в 15минутах от метро select count(tags->'design:ref')*100.0/count(*) cnt, count(*) from (select distinct building_id, building_type, b.tags from subway_distance s inner join geometry_global_view b on b.id=s.building_id and b.type=s.building_type) b; cnt | count ---------------------+------- 38.1045937491921516 | 38683
Значения серий домов, указанные для Москвы в OpenStreetMap
select regexp_split_to_table(tags->'design:ref',';') design_ref, count(*) from geometry_global_view where tags?'_lb' group by 1 order by 2 desc;
design_ref | count ---------------------------------+------- II-18-01/12 | 1100 П44-1/17 тип 1 | 636 II-18-01/МИ вариант «Б» | 635 1-511-4/М | 627 П44Т-1/17 тип 1 | 534 П3-2/16 | 514 И-209А | 496 1-511-3/М | 464 1-515-4/М | 371 II-68-01/16Ю-2/78 | 361 II-49-04/Ю вариант «Д» | 331 II-14 | 309 КОПЭ-85 | 295 1-410 | 267 1-510-4/М23 | 265 СМ-6 | 252 1-515-04/9ЮЛ | 246 1-515-4/М37 | 243 П44-1/16 тип 1 | 242 П43/16 | 233 II-14-33 | 231 II-68-01/16Ю | 231 Башня Вулыха | 227 КТЖС-2 | 223 П47/12 | 222 1-410-9 | 219 1-515-3/Ю37 | 218 II-49-06/Ю вариант «Д» | 216 КТЖС-1 | 206 КТЖС-5 | 191 И-209 | 184 1-515-5/М | 181 II-01 | 180 П46-2/12В | 180 1-510-3/М23 | 171 1-515-3/Ю | 163 П44Т-4/17 тип 2 | 162 1-515-5/М37 | 157 1-515-04/9М | 155 II-18-11/МИ вариант «Б» | 151 1605АМ/12 | 151 П44-4/17 тип 2 | 147 II-49-08/Ю вариант «Д» | 145 1-511-4/М37 | 144 1-511-3/Ю | 141 II-14-31 | 140 II-29-41/37 | 135 II-18-21/12 | 134 П30-4/12 | 133 1-515-06/9ЮЛ | 131 1-510-4/М | 130 1605АМ-04/12Ю | 129 П55-4/12 | 124 II-68-03/12Ю | 122 П-44 | 118 1-511-3/��37 | 117 1-511-4/Ю | 114 II-57-03/12ЮА | 112 1-511-2/Ю | 108 1-511 | 106 1-510-4/Ю23 | 104 1-510-3/М | 103 П3-1/16 | 98 П30-3/12 | 97 II-29/37 | 94 П46М-2/14 | 94 II-18-31/12 | 94 1-515-06/9М | 92 Мг-1 | 90 КТЖС-9 | 89 II-18-01/МИ вариант «К» | 89 П44Т-4/17 тип 3 | 89 II-49-06/Ю вариант «П» | 89 II-49-04/Ю вариант «П» | 88 П44-4/17 тип 3 | 88 II-28-3 | 88 П46М | 87 П46-3/12 | 86 1-410-10 | 86 1-447С-5 | 85 II-49-02/Ю вариант «Д» | 84 II-18-31/12А | 83 II-14-32 | 81 II-49-06/М вариант «Д» | 81 П44Т-4/17 тип 5 | 81 1-447С-7 | 79 П30-1/12 | 79 П44-4/17 тип 4 | 79 II-28-4 | 78 П44Т-4/17 тип 4 | 75 II-29-03/Ю37 | 74 КОПЭ-2000 | 73 1-511-2/М | 72 П46/12 | 71 II-18-02/12 | 70 II-49-04/М вариант «Д» | 67 1-410 (общежития) | 67 Унифицированный каркас | 65 П44-4/16 тип 2 | 65 II-29-03/М37 | 63 ГМС-2001 | 61 II-29-04/М37 | 61 П30-2/12 | 61 1-511-3/Ю37 | 60 1-510-4/М37 | 59 4572А | 59 П44-4/17 тип 5 | 57 П46М-4/14 | 57 II-49/Ю вариант «Д» | 57 II-29-04/Ю37 | 57 II-68-02/16М | 55 1-510-3/Ю23 | 55 П44Т | 54 II-68-02/12К | 54 1-410-12 | 54 П3М-1/17 | 54 II-29 | 53 II-05-02А | 52 ИП46С | 52 П55-26/12 | 51 П3М | 51 И-522А | 50 П46М-4/9 | 48 II-18-01 вариант «Б» | 48 1-511-4/Ю37 | 47 И-155Б | 47 П55-25/12 | 46 КОПЭ-80 | 46 II-29-05/Ю37 | 45 П44 | 45 П3М-1/16 | 45 1-447С-8 | 42 П55-21/12 | 42 II-67 Смирновская | 42 П44К-1/17 | 42 II-29-14/Ю37 | 41 П30-6/12 | 41 II-57 | 40 П30/12 | 40 111М | 40 II-29-03/М | 40 1-511-14/М37 | 40 1-447С-3 | 40 II-04 | 39 II-49-08/Ю вариант «П» | 39 КОПЭ-М «Парус» | 39 1-515-178/9М | 39 И-III-3 | 38 СМ-3 | 38 II-29-04/М | 38 1605АМ/9 | 38 II-49/М вариант «Д» | 37 П55-23/12 | 37 БС 05-17М | 37 1-410-13 | 36 1-410-11 | 36 1Мг-601/Д | 36 II-49-08/М вариант «Д» | 35 1-510-4/Ю37 | 35 II-68 | 35 П3М-3/17 | 35 II-68-01/22-83 | 34 II-29-05/М | 33 П3/16 | 33 1Мг-601 | 32 П46М-22пр/14 | 32 4570 | 32 II-57-05/Ю | 31 1-515/9 | 31 II-29-15/М37 | 31 1-447С-1 | 31 1605АМ-04/9Ю | 30 1-510-3/Ю | 30 П30-5/12 | 30 П3М-4/17 | 29 1-510-3/М37 | 29 1-515-3/М | 29 Тип I | 29 П3М-2/16 | 29 1-511-2/Ю37 | 29 П46М-2/9 | 29 КТЖС 1п-25 | 29 II-05-01 | 28 1Мг-601/Ж | 28 II-29-14/М37 | 28 Тип IV | 28 II-29-05/М37 | 28 II-67 Москворецкая | 28 II-28-2 | 27 II-49-04/М вариант «П» | 27 П44-4/16 тип 5 | 27 П42/16 | 26 1-300-3 | 26 П3М-2/17 | 26 II-57-05/12ЮА | 26 1-410-5 | 26 1-335-1 | 26 П46М-22пр/9 | 26 II-57-07/Ю | 25 1-447С-2 | 25 П3МК | 25 П44-4/16 тип 3 | 24 П-111М | 24 II-29-04/Ю | 24 II-49/12 вариант «П» | 24 П31/12 | 24 II-49/Ю вариант «П» | 24 1-511-130/37 | 23 II-57-03/12МА | 23 ПИК-1 | 22 1-515-24/9М | 22 I-511(I-511/25БИ) | 22 1-510/23 | 22 И-155НБ | 22 СМ-3-3 | 22 1-447С-6 | 21 П44-4/16 тип 4 | 21 I-515(I-515/37) | 21 II-29-03/Ю | 21 II-18-01 вариант «К» | 21 II-20 | 21 II-29-15/Ю37 | 21 КТЖС-1ук | 20 1-335-2 | 20 П30 | 20 1605АМ-06/12Ю | 20 И-155Мк | 19 1-247С-1 | 19 П55-24/12 | 19 П3М-3/16 | 18 1605АМ/5 | 18 КТЖС 2п-25 | 18 1-447С-38 | 18 И-491А | 17 И-155-16К1 | 17 П46М-21/9 | 17 1-410-8 | 17 1-447С-40 | 17 П46М-21/14 | 17 II-07-19 | 17 II-49-02/М вариант «Д» | 17 И-1782/1 | 17 1605АМ-06/9Ю | 17 II-57-03/ЮА | 16 П3М-4/16 | 16 II-68-01/12-83 | 16 1605АМ-08/9М | 16 II-57-05/ЮА | 16 1-511/37 | 16 Пд4-1/12Н1 | 15 II-67-386 | 15 1-801 | 15 П3М-7/23 | 15 1-513 | 15 П46М-22л/9 | 15 П55М-4/14 | 15 1-515-26/9М | 15 1-515-3/М37 | 15 222-15/17 | 14 П44Т-1/14М тип 1 | 14 II-67 Тишинская | 14 II-29-160 | 14 1-510-3/Ю37 | 14 И-700 | 14 СМ-3-5 | 14 ПИК-2 | 14 ЛСР | 14 1-515/37 | 13 I-511(I-511/37) | 13 1-464А-15 | 13 II-49-06/М вариант «П» | 13 КОПЭ | 13 II-14-34 | 13 II-14-35 | 13 1-244-1 | 13 БС 05-16М | 13 II-57-07/ЮА | 13 II-57-05/12МА | 12 1МГ-601-Ж | 12 КОПЭ-87 | 12 П-3/17 | 12 П55/12 | 12 П3М-6/17 | 12 И-155Мм | 12 II-34 | 12 II-68-03/12Ю-2/76 | 12 1-467Д | 12 I-515(I-515/5) | 12 ШКД | 12 Мм1-3 | 12 II-18/12 | 12 1-467А-17 | 12 1-447С-4 | 11 1-233-2 | 11 И-1491-17 | 11 I-515-3/Ю37 | 11 П44К | 11 I-410 | 11 1-510-2/23 | 11 II-18-11/МИ вариант «К» | 11 1-510-4/Ю | 11 1-464А-17 | 11 1-204-113 | 11 222-02/17 | 11 1-447С-37 | 11 II-29-05/Ю | 11 Мг-2 | 11 1Р-447С-25 | 11 1Р-447С-26 | 11 П46М-22л/9И | 11 II-68-01/16-83 | 10 П22/25 | 10 П46 | 10 1Мг-600-1 | 10 1-515-4/Ю | 10 II-68-01/14-83 | 10 1-510/37 | 10 П44Т-1/25 | 10 1-204-5 | 10 4570-63 | 10 1-515/9М | 10 Пд4-1/16Н1 | 10 БС 08-17К | 10 П55М-2/14 | 10 И-155-16К2 | 10 I-410 (САКБ) | 9 П-46М | 9 П44М-1/17 | 9 Мм1-4 | 9 КТЖС-14 | 9 П55-22/12 | 9 П30(П30/12) | 9 Пд4-5/12Н1 | 9 И-700Н | 9 II-57-05/М | 9 I-515-4/М37 | 9 П30М | 9 1-225-109 | 9 И-155Б2 | 9 ЭК-1 | 8 КОПЭ-Башня(КОПЭ-Башня М-2) | 8 Пд4-5/16Н1 | 8 2-4-1 | 8 Пд4 | 8 Бекерон | 8 И-782 | 8 II-68-04/12М1 | 8 111 | 8 Пд4-1/10Н1 | 8 И-155-16М4 | 8 И-155 | 8 1-447С-39 | 8 1-511-2/М37 | 8 БС 07-17М | 8 И-1820 | 8 1Мг-601-441 | 8 И-155-22М3 | 8 II-66 | 8 И-155С | 7 II-49 | 7 1-801-1 | 7 И-155-9М2 | 7 П4/22 | 7 И-155-16К3 | 7 И-155-9М3 | 7 1605АМ-06/9М | 7 Пп83(83-305/28-503) | 7 II-08 | 7 индивидуальный проект | 7 И-1158 | 7 Пд4-1/12 | 7 П46М-21/9И | 7 II-29-208 | 7 Град-2М | 7 П55-2/12А | 7 И-155-16К8 | 7 СЭМ-2 | 7 II-07-04 | 7 1605АМ-04/9М | 7 1-467А-15 | 7 1-467А-12 | 7 ПД-4 | 7 П22К | 7 1605АМ/Э | 7 II-49-08/М вариант «П» | 7 1-515-142/9М | 7 I-410(I-410 (САКБ)) | 7 1605АМ-08/9Ю | 7 II-18/12(II-18-01/12) | 7 I-510/23БИ | 6 И-286 | 6 Пд4-5/10Н1 | 6 1-211-2 | 6 I-511 | 6 П3М-3/9 | 6 БАШНЯ М-1 | 6 Тип II | 6 П-44Т | 6 И-155-22М4 | 6 И-273 | 6 П55-2/12 | 6 И-155-9М4 | 6 СМ-3-4 | 6 БС 09-17К | 6 П3М-6 | 6 БОД-1 | 6 1605-АМ(1605АМ/12Ю) | 6 1-211-3 | 6 II-57-07/МА | 6 БС 08-17М | 6 222-12/25 | 6 П-44м | 6 П3-3/16 | 6 Пд4-2/16Н1 | 6 1Мг-600 | 5 220-М17-1122-РТ | 5 И-155-22М2 | 5 Пд4-1/8 | 5 I-515/9М | 5 СЭМ2 | 5 1-253А-7 | 5 1-235-1 | 5 1МГ-601(1МГ-601-Ж) | 5 ПБ-02 | 5 И-155Н | 5 1-515-5/Ю | 5 И-155-16М2 | 5 И-1751 | 5 1-515 | 5 П46М-10л/17 | 5 220-М25-1222-РТ | 5 ТМ-25 | 5 II-28 | 5 Призма (И-1630) | 5 1-234-1КБ | 5 I-447С-26 | 5 И-760А | 5 1МГ-601 | 5 I-515/9ЮЛ | 5 Пд3-02/22 | 5 КПД-4570-73/75 | 5 1-510 | 5 КОПЭ(КОПЭ-85) | 5 П3-4/16 | 5 1-801-3 | 5 II-18-32/12А | 5 П46М-2/14И | 5 I-511/25БИ | 5 СМ-3-2 | 5 П44Т-4/14М тип 4 | 5 Пд3-03/22 | 5 I-510(I-510/23БИ) | 5 МПСМ | 5 И-155-16М5 | 5 ПБ-01 | 4 П44ТМ | 4 1-253А-2 | 4 II-57-07/12ЮА | 4 II-18/12(II-18-21/12А) | 4 П44ТМ/25 | 4 222-11/17 | 4 II-49(II-49/Ю вариант Д) | 4 XI-36-01 | 4 1Мг-601/Е | 4 К7/16 | 4 БС 08-16К | 4 С-222-01/17 | 4 1605АМ/л | 4 1-446С-3 | 4 1-447С | 4 И-155-22М1 | 4 И-521А | 4 И-155-Б | 4 1-428-3 | 4 Мм1-2 | 4 I-515/37 | 4 И-1630(Призма) | 4 1605АМ-03/12Ю | 4 1-510-2/37 | 4 БС 12-17М | 4 БС 06-17М | 4 1-447С-34 | 4 П3М-1/9 | 4 И-1723 (ШКД) | 4 МЭС-84 | 4 Пд4-4/16Н1 | 4 Колос | 4 1-440С-1 | 4 Д-25 | 4 П22-1/16 | 4 1-447 | 4 1-260-3А | 4 220-М25-1223-УТ | 4 М-10 | 4 1-515-4/Ю37 | 4 И-155-9М5 | 3 П23/16 | 3 1-515-5/Ю37 | 3 П3 | 3 114-86 | 3 II-57-07/М | 3 Пд4-1/16 | 3 система КУБ | 3 ЕвроПа | 3 БС 09-17М | 3 1-440С-3 | 3 222-01/17 | 3 II-18-01/08 | 3 МЮ | 3 II-57-А/12 | 3 П44Т-4/14М тип 3 | 3 1-260-1 | 3 VII-40 | 3 КТЖС-13 | 3 И-1168 | 3 И-1194 | 3 1-253-3 | 3 БС 09-16К | 3 К4/16 | 3 П46ММ, И-1824 | 3 II-18-01/09 МИБ | 3 Пд4-2/16 | 3 КТЖС-16 | 3 И-155-16М1 | 3 И-1822/1 | 3 КОПЭ-М-Парус | 3 1-439А-5 | 3 П55М-30 | 3 1-228 | 3 1-467А-18 | 3 П30(85-07) | 3 И-155-9К1 | 3 222-08/17 | 3 И-155-22М7 | 3 I-447С | 3 VI-12А | 3 I-515-178/9М | 3 222-09/17 | 3 II-68-04/12М2 | 3 И-155-16М6 | 3 П44Т-4/14М тип 5 | 3 И-1414 | 3 II-49/М вариант Д | 3 Пд4-5/8 | 3 И-155-16М3 | 3 VII-42 | 3 И-1824 | 3 И-701 | 3 II-18-22/МИ вариант «Б» | 3 И-155-16К4 | 3 И-155-9К5 | 3 1-515-5 | 3 II-49(II-49/М вариант П) | 3 П46М-22пр/9И | 3 П46М(ИП46М) | 3 П-46 | 3 1-428-1 | 2 164-80-3 | 2 1-228-9 | 2 I-511-4/М | 2 II-18-01/09 МИ вариант К | 2 П-3М | 2 1-447С-47 | 2 П46М-22л/14ПР | 2 П46М-322/14 | 2 П46М-23пр/14 | 2 П46ММ | 2 220-М17-1234-РТ | 2 1-801-13 | 2 П-30 | 2 КТЖС 3п-25 | 2 1-447С-10 | 2 П55М | 2 VI-44 | 2 1-228-7 | 2 И-155-9К3 | 2 II-49(II-49/М вариант Д) | 2 1-447С-17 | 2 П3(П3/16) | 2 I-511-2/Ю | 2 I-515-06/9ЮЛ | 2 КТЖС-3 | 2 1-801-4 | 2 И-155-16К5 | 2 И-155-16К7 | 2 II-18 | 2 1-460-7 | 2 1-466К-4 | 2 И-155-22М6 | 2 1-260-2 | 2 1-277-1 | 2 П44К(П44Т,П44К) | 2 I-515-06/9М | 2 1-510-2 | 2 1МГ-601/Д | 2 II-05 | 2 1-467А-20 | 2 1-234-1 | 2 1-225-110 | 2 Пд4-2/12 | 2 П46М-23л/14 | 2 С-222-15/17 | 2 И-155-16М7 | 2 1-222-126 | 2 1-447С-46 | 2 1-300 | 2 ИП46М | 2 И-155-9М1 | 2 1-446С-1 | 2 1-467Д-20 | 2 1-447С-35 | 2 Пд3-01/22 | 2 П46М-302/14 | 2 II-68-04/12М | 2 1-447С-53 | 2 I-511/37 | 2 К-8-49Б | 2 II-57-02/12ЮА | 2 1-428-2 | 2 Пп70-07/17 | 2 1Р-447С-25М | 2 И-1782 | 2 XI-36-02 | 2 1-206-104 | 2 П44Т-4/14М тип 2 | 2 II-57-07/12МА | 2 И-155-9К2 | 2 1-204-112 | 2 II-57/17 | 2 II-18-01/09 | 2 II-18(II-18-01/09 МИБ) | 2 И-209A | 2 1-253А-6 | 2 I-511-3/М | 2 И-155-22К1 | 2 I-515-24/9М | 2 II-29-Б | 2 СУ-155 | 2 1-301-1 | 2 1-464А-1 | 2 1-102-12 | 2 I-510-4/М23 | 2 1-225-111 | 2 VI-52 вариант 1 | 1 1Р-303-2 | 1 II-49/М вариант «П» | 1 П-3/16 | 1 1-439А-7 | 1 П3М-2/9 | 1 Пд4-5/12 | 1 БАШНЯ М-2 | 1 1-447С-13 | 1 II-18/12(II-18-31/12А) | 1 VII-70 | 1 1С-01-1 | 1 Пд4-2/12Н1 | 1 П30(П31/12) | 1 1-464Д-105 | 1 1-410-4 | 1 II-07 | 1 1-255-5 | 1 1-515-5М | 1 Лебедь (унифицированный каркас) | 1 II-32-04 | 1 II-66/БС-36 | 1 КПД-4570(КПД-4570-I) | 1 1-460-10 | 1 I-515-5/М37 | 1 П46М-22пр/14ПР | 1 I-447С-1 | 1 К-7-3-5 | 1 C-222-01/17 | 1 II-32-05 | 1 П44Т(П44Т, П44К) | 1 II-57-А/09 | 1 ЦИТП № 51 | 1 1Р-303-17 | 1 1-439А-4 | 1 1-300-2 | 1 1-251-7 | 1 1-203-15 | 1 1-447С-12 | 1 1-301-2 | 1 И-155-22М5 | 1 I-335-5 | 1 П46М, И-1824 | 1 brown | 1 1-275-4 | 1 П46М-321/14 | 1 С-222-02/17 | 1 БС 10-17М | 1 II-57-05/МА | 1 II-49/Ю вариант Д | 1 Пд4-4/12Н1 | 1 II-38-03/1A | 1 К-7 (К7-3) | 1 I-447 | 1 II-49(II-49П/12 (И-294А)) | 1 1-418 | 1 II-66/БС-34 | 1 161-101-21 | 1 1-251А-17 | 1 1-460-9 | 1 I-467А-15 | 1 П30(П30/12*) | 1 I-447С-25 | 1 И-1849 | 1 БС 01-17К | 1 1-251-15 | 1 1-801-16 | 1 II-32-130 | 1 БС 07-16М | 1 1-447С-12А | 1 124-124-4 | 1 Пд4-5/14Н1 | 1 1-335-4 | 1 1-253-5 | 1 КОПЭ(монолит-кирпич) | 1 II-29-3(II-29-3(9)) | 1 II-49/Ю | 1 V-79 | 1 12 (Союзтранспроект) | 1 1-204-6 | 1 1-204-114 | 1 Т-3 | 1 II-57-02/12МА | 1 1-251 | 1 КПД-4572А | 1 1-242-103 | 1 I-335-4 | 1 Призма(И-1630) | 1 I-447С-38 | 1 Пд4-1/14Н1 | 1 П3М-4/9 | 1 I-515(сталинский) | 1 VI-13А | 1 КОПЭ(КОПЭ-2000)) | 1 И-1747 | 1 1-275-1 | 1 1-466А-2 | 1 222-10/17 | 1 БС 10-16М | 1 БС 06-16М | 1 I-510(I-510/37) | 1 II-51 | 1 П46М-302/14И | 1 П47(П47/12*) | 1 K-7(индивидуальный проект) | 1 И-1746 | 1 65-426/I | 1 VI-23 | 1 П-49 Д | 1 I-515/9 | 1 I-515-04/9ЮЛ | 1 П47(П47/12) | 1 1-253А-4 | 1 1-251-11 | 1 1-294-3 | 1 1-447С-54 | 1 VI-52/2 | 1 1-467Д-19 | 1 I-467А-4 | 1 2-5-6 | 1 1МГ-601-441 | 1 1-277-2 | 1 1-251-2 | 1 КПД-4570-I | 1 1-447С-44 | 1 П46М-23пр/9 | 1 I-511-130/37 | 1 II-18-21/12А | 1 С222 | 1 П-111М(П-111) | 1 1-464Д-102 | 1 1-447С-36 | 1 II-66/БС-35 | 1 ИП-46С | 1 С-222(222) | 1 white | 1 II-65 | 1 1-201-12 | 1 ПЗ | 1 П30/12* | 1 1-252-8 | 1 ДОМРИК тип 1 | 1 1-439А-3 | 1 1-447С-11А | 1 17 (Союзтранспроект) | 1 П46М-23л/9 | 1 И-155-22К5 | 1 1-447С-33 | 1 П-3м | 1 1-255-4 | 1 П46М-322/14И | 1 I-410 (тип I, IV) | 1 1-251-13 | 1 1-447С-9 | 1 I-447С-8 | 1 1-262 | 1 1-280 | 1 1-241-115 | 1 КОПЭ(КОПЭ-80) | 1 II-68-01 | 1 II-18-03/МИ вариант «Б» | 1 1-255-6 | 1 II-49(II-49/12 вариант П) | 1 П46М-23пр/14И | 1 П46М-22л/14 | 1 II-29-3(9) | 1 K-7 | 1 1-253-6 | 1 И-1483 | 1 П3М-2/19 | 1 (813 rows)
Всего-то вручную надо проверить 100 000 жилых зданий в Москве и указать design:ref где не указан... Бродить по джунглям бетонных коробок с OSMTracker, наслаждаясь атмосферой мелонхолии и флешбеками детства и студенчества. В этом есть что-то родное и одновременно грустное!
Для домов у метро процент design:ref = 35%, значит осталось проверить 23983 не размеченных этим тегом домов! Эх, если бы каждый Хабровчанин окинул взором свои окрестности и указал design:ref и год постройки для пары домов. Но пока я решил не включать этот параметр в аналитику.
Результаты
По данным OpenStreetMap 32% зданий в Москве расположены в 15 минутах пешком от метро. Рассмотреть расположение этих домов у метро можно по ссылке GitHub Gist, где карту можно масштабировать (там еще случайно оказалась пасхалочка в центре с домом).

Расчеты основаны на открытых геоданных используя только Open Source компоненты. Если вы нашли ошибку, в первую очередь проверьте на OpenStreetMap обозначена ли там пешеходная дорога от вашего дома к метро. Во вторую очередь попробуйте вручную построить маршрут на сайте и смотрите как прокладывается маршрут и какое расстояние. И если вдруг у вашего дома с моей карты "пропало метро", то пишите в коментариях - будем разбираться!
В следующих публикациях рассчитаем пешеходное расстояние от домов до магазинов, школ, детсадов, поликлиник. Удачного вам поиска комфортного жилья!
