Продолжаем изучать географию столицы и как она влияет на комфорт жилья. В этой публикации подключим маршрутизацию и расчитаем пешеходные расстояния от входа в метрополитен до жилых зданий. В прошлый раз я анализировал жилье в городе на удаленность от негативных факторов и поделился инструкцией "Где в Москве жить «неплохо»". Теперь же перейдем на позитивные факторы выбора места квартиры и найдем в Москве жилые дома в шаговой доступности от метро.
Сделаем это 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 обозначена ли там пешеходная дорога от вашего дома к метро. Во вторую очередь попробуйте вручную построить маршрут на сайте и смотрите как прокладывается маршрут и какое расстояние. И если вдруг у вашего дома с моей карты "пропало метро", то пишите в коментариях - будем разбираться!
В следующих публикациях рассчитаем пешеходное расстояние от домов до магазинов, школ, детсадов, поликлиник. Удачного вам поиска комфортного жилья!