O melhor empresário do mundo, Penultimo, tem outra ideia brilhante, que você precisa realizar. Ele acredita que o fluxo de turistas para a Ilha dos Educados aumentará se puder contar ao mundo quantas placas rodoviárias maravilhosas com longas inscrições existem na ilha. Você está convidado a criar um algoritmo que permite calcular o número total de letras em todos os sinais "Entrada para a cidade X" na ilha e, em seguida, aplicar o conhecimento adquirido para calcular uma métrica semelhante para a República da Bielorrússia. Preste atenção à linguagem usada para designar os povoados, bem como ao fato de que podem haver várias entradas para a cidade. O Penultimo também incentiva a iniciativa, para que você possa pesquisar esse tema para áreas específicas, fazer comparações com a quantidade de pessoas que vivem na áreae também conduza qualquer outra pesquisa que você achar interessante.
Abaixo do corte, mostrarei a solução exata para este e outros problemas semelhantes, por exemplo: "Quantos postos de gasolina estão localizados em Moscou?"
Método de solução geral
Se você olhar para o mapa do OpenStreetMap, a seguinte ideia vem imediatamente à mente: vamos pegar para cada cidade seus limites e as estradas dentro de seus limites, e então encontrar seus cruzamentos, nos quais haverá sinais! Como procuraremos cruzamentos: pegamos um segmento da fronteira, depois um segmento da estrada e vemos se eles se cruzam (um problema geométrico típico). E assim por diante até que todas as seções e cidades terminem.
Sobre a arquitetura de dados OSM
, : , .
ID, .
ID, .
- — , ID
- — ,
- — , , ,
Ultrapassar
OverPass - Esta é uma API para obter dados do OpenStreetMap. Ele tem sua própria linguagem para escrever consultas, você pode ler sobre isso em detalhes neste artigo .
Para tornar mais fácil e conveniente a composição de consultas, existe a ferramenta Overpass-turbo , onde o resultado da consulta pode ser visualizado de forma prática e interativa.
Usando a API OverPass em Python
Para processar dados do OSM em Python, você pode usar o pacote Overpy como um wrapper.
Para enviar solicitações e receber dados, você precisa fazer o seguinte:
import overpy
api = overpy.Overpass()
Data = api.query("""
* *
""")
onde a variável (?) Data contém tudo o que o servidor nos forneceu.
Como processar esses dados? Suponha que inserimos a seguinte solicitação para obter as fronteiras de Minsk:
relation["type"="boundary"]["boundary"="administrative"]["name:be"="і"];
//:
>; out skel qt;
Na saída, temos um arquivo XML (você pode escolher Json) com a seguinte estrutura:
<* *>
< >
<node id="277218521" lat="53.8605688" lon="27.3946601"/>
<node id="4623647835" lat="53.8603938" lon="27.3966685"/>
<node id="4713906615" lat="53.8605343" lon="27.3998220"/>
<node id="4713906616" lat="53.8605398" lon="27.3966820"/>
<node id="4713906617" lat="53.8605986" lon="27.3947987"/>
<node id="277050633" lat="53.8463790" lon="27.4431241"/>
<node id="277050634" lat="53.8455797" lon="27.4452681"/>
<node id="4713906607" lat="53.8460017" lon="27.4439797"/>
< ID , >
<way id="572768148">
<nd ref="5502433452"/>
<nd ref="277218520"/>
<nd ref="4713906620"/>
<nd ref="277218521"/>
<nd ref="4713906617"/>
<nd ref="4623647835"/>
<nd ref="4713906616"/>
</way>
<way id="29079842">
<nd ref="277212682"/>
<nd ref="277051005"/>
<nd ref="4739822889"/>
<nd ref="4739822888"/>
<nd ref="4739845423"/>
<nd ref="4739845422"/>
<nd ref="4739845421"/>
</way>
Vamos obter alguns dados:
import overpy
api = overpy.Overpass()
Data = api.query("""
relation["type"="boundary"]["boundary"="administrative"]["name:be"="і"];
>; out skel qt;
""")
Xa=Data.ways[0].nodes[0].lon #
Ya=Data.ways[0].nodes[0].lat #
Xb=Data.ways[0].nodes[1].lon
Yb=Data.ways[0].nodes[1].lat
NodeID=Data.ways[0]._node_ids[0] # ID
print(len(Data.nodes)) #
print(NodeID)
print(Xa,Ya)
print(Xb,Yb)
Do ponto de vista de trabalhar com OpenStreetMap em python, isso é tudo de que você precisa para obter os dados.
Vamos direto ao problema
Para resolver isso, o código foi escrito em Python, você pode vê-lo no spoiler. Por favor, não repreenda muito pela qualidade do código, este é o primeiro grande projeto nele.
Cabeçalho de spoiler
import overpy
###########################
def line_intersection(line1, line2): #
ax1 = line1[0][0]
ay1 = line1[0][1]
ax2 = line1[1][0]
ay2 = line1[1][1]
bx1 = line2[0][0]
by1 = line2[0][1]
bx2 = line2[1][0]
by2 = line2[1][1]
v1 = (bx2 - bx1) * (ay1 - by1) - (by2 - by1) * (ax1 - bx1)
v2 = (bx2 - bx1) * (ay2 - by1) - (by2 - by1) * (ax2 - bx1)
v3 = (ax2 - ax1) * (by1 - ay1) - (ay2 - ay1) * (bx1 - ax1)
v4 = (ax2 - ax1) * (by2 - ay1) - (ay2 - ay1) * (bx2 - ax1)
return (v1 * v2 < 0) & (v3 * v4 < 0)
#######################################
citytmp = []
city = []
Borderway = []
Roadway = []
Total = 0
A = [0, 0]
B = [0, 0]
C = [0, 0]
D = [0, 0]
amount = 0
progressbar = 0
ReadyData = open(' .txt','w')
with open(" .txt", "r", encoding='utf8') as file:
for i in range(115):
citytmp.append(file.readline())
citytmp = [line.rstrip() for line in citytmp]
for i in range(115):
city.append('"' + citytmp[i] + '"')
city[0]='"і"'
api = overpy.Overpass()
for number in range(0,115):# ,
borderstring = """(
relation["type"="boundary"]["boundary"="administrative"]["name:be"=""" + city[number] + """][place=town];
relation["type"="boundary"]["boundary"="administrative"]["name:be"=""" + city[number] + """][place=city];
);
>; out skel qt;"""
roadstring = """(
area[place=town]["name:be"=""" + city[number] + """];
way["highway"][highway!=service]["highway"!="footway"]["highway"!="track"]["highway"!="path"]
["highway"!="cycleway"]["highway"!="pedestrian"]["highway"!="steps"]["highway"!="residential"](area);
area[place=city]["name:be"=""" + city[number] + """];
way["highway"][highway!=service]["highway"!="footway"]["highway"!="track"]["highway"!="path"]
["highway"!="cycleway"]["highway"!="pedestrian"]["highway"!="steps"]["highway"!="residential"](area);
);
out body; >; out skel qt;"""
print('Getting data about', city[number],'...')
road = api.query(roadstring)
border = api.query(borderstring)
print('got data!, city:', city[number]) #
for w in range(len(border.ways)): #
for i in range(len(border.ways[w]._node_ids)):#
progressbar = i / len(border.ways[w]._node_ids) * 100
print(progressbar, "%;", w, "of", len(border.ways), "parts ready; city-", city[number])
A[0] = border.ways[w].nodes[i].lon
A[1] = border.ways[w].nodes[i].lat
if i == len(border.ways[w]._node_ids) - 1:
break
B[0] = border.ways[w].nodes[i+1].lon
B[1] = border.ways[w].nodes[i+1].lat
for j in range(len(road.ways)):
for k in range(len(road.ways[j]._node_ids)):
C[0] = road.ways[j].nodes[k].lon
C[1] = road.ways[j].nodes[k].lat
if k == len(road.ways[j]._node_ids) - 1:
break
D[0] = road.ways[j].nodes[k+1].lon
D[1] = road.ways[j].nodes[k+1].lat
if line_intersection((A, B), (C, D)) == 1:
amount += 1
print(road.ways[j]._node_ids[k])
print(amount)
Total += amount * len(city[number])
ReadyData.write(str(city[number]))
ReadyData.write(str(amount))
ReadyData.write('\n')
amount = 0
print('Total', Total) #
Notas de código
Fazia um pedido há muito tempo, escolhendo diferentes tipos de estradas para que fosse menos para contar e para não perder a sinalização. A consulta final simplesmente remove aquelas estradas em que não há sinais, por exemplo residencial, serviço, passeio, trilha, etc.
Analisei a lista de cidades da Wikipedia e salvei no formato. Se
o código está sendo executado há muito tempo, eu até tive um desejo uma vez reescrevê-lo em C ++, mas decidi deixar como está. Demorei dois dias, tudo por causa de problemas com a
Minha resposta para o problema
18981
O que quero dizer sobre a exatidão da figura: tudo depende da qualidade dos dados do próprio OSM, ou seja, há lugares onde, por exemplo, uma estrada cruza duas linhas de fronteira, ou em algum ponto no entroncamento a fronteira está desenhada um pouco errada e, como resultado, temos muito / interseção ausente. Mas esta é uma característica desta tarefa em particular que não tem significado prático, caso contrário, o OSM é a força.
Segunda tarefa
Agora vamos calcular o número de postos de gasolina em Moscou:
area[name=""];
(
node["amenity"="fuel"](area);
way["amenity"="fuel"](area);
relation["amenity"="fuel"](area);
);
out body;
>;
out skel qt;
O código
import overpy
api = overpy.Overpass()
Data = api.query("""
area[name=""];
(
node["amenity"="fuel"](area);
way["amenity"="fuel"](area);
relation["amenity"="fuel"](area);
);
out body;
>;
out skel qt;
""")
print(len(Data.nodes)) #
Resultado - 489 recheios:
