Last active
January 13, 2025 04:30
-
-
Save ksasao/844fa3be90bcbcc6fcae34b7b64b8093 to your computer and use it in GitHub Desktop.
駅データ https://github.com/Seo-4d696b75/station_database/blob/main/README.md の station.json と路線のpolylineデータ(11332.jsonなど)を利用して、指定した路線に乗車したときに駅メモでチェックイン可能な駅一覧を取得します。 https://x.com/ksasao/status/1877353964657590593
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json | |
import argparse | |
from shapely.geometry import Point, Polygon | |
from shapely.strtree import STRtree | |
def read_json(file_path): | |
with open(file_path, 'r', encoding='utf-8') as file: | |
data = json.load(file) | |
return data | |
def list_stations_in_polygon(json_data, lat, lng, tree, station_geoms, geoms_list): | |
point = Point(lng, lat) | |
possible_match_indices = tree.query(point) | |
station_names = [] | |
# Use a set to track which geometries have been matched to avoid duplicates in the final list | |
matched_geoms = set() | |
for idx in possible_match_indices: | |
geom = geoms_list[idx] | |
if geom not in matched_geoms: | |
for station, station_geom in station_geoms.items(): | |
if station_geom is geom and point.within(geom): | |
station_names.append(station) | |
matched_geoms.add(geom) | |
break # Move to next geometry after finding a match | |
return station_names | |
def chain_segments(segments, start_station=None): | |
segment_map = {} | |
start_points = set() | |
end_points = set() | |
# Create a map from each point to its corresponding segment | |
for segment in segments: | |
start = segment['start'] | |
end = segment['end'] | |
points = segment['points'] | |
if start not in segment_map: | |
segment_map[start] = [] | |
segment_map[start].append((end, points)) | |
if end not in segment_map: | |
segment_map[end] = [] | |
segment_map[end].append((start, points[::-1])) | |
start_points.add(start) | |
end_points.add(end) | |
# Find the starting point | |
if start_station: | |
starting_point = start_station | |
else: | |
starting_point_candidates = start_points - end_points | |
if starting_point_candidates: | |
starting_point = starting_point_candidates.pop() | |
else: | |
# In case all segments form a closed loop, start from any point | |
starting_point = next(iter(start_points)) | |
# Function to chain segments from a given starting point | |
def chain_from_point(start_point): | |
ordered_points = [] | |
current_point = start_point | |
visited_segments = set() | |
visited_points = set() | |
visited_points.add(current_point) | |
while current_point in segment_map: | |
next_segments = segment_map[current_point] | |
segment_found = False | |
for next_segment in next_segments: | |
next_point, segment_points = next_segment | |
segment_key = (current_point, next_point) | |
if segment_key not in visited_segments and next_point not in visited_points: | |
visited_segments.add(segment_key) | |
ordered_points.extend(segment_points) | |
visited_points.add(current_point) | |
current_point = next_point | |
segment_found = True | |
break | |
if not segment_found: | |
break | |
return ordered_points, visited_segments | |
# Chain segments from the starting point | |
ordered_points, visited_segments = chain_from_point(starting_point) | |
# Process remaining unvisited segments | |
unvisited_segments = set(segment_map.keys()) - {seg[0] for seg in visited_segments} | |
while unvisited_segments: | |
next_starting_point = unvisited_segments.pop() | |
additional_points, additional_segments = chain_from_point(next_starting_point) | |
ordered_points.extend(additional_points) | |
visited_segments.update(additional_segments) | |
unvisited_segments -= {seg[0] for seg in additional_segments} | |
return ordered_points | |
# コマンドライン引数の設定 | |
parser = argparse.ArgumentParser(description='Station Finder') | |
parser.add_argument('point_data_path', type=str, help='Path to the point data JSON file') | |
parser.add_argument('--start_station', '-s', type=str, help='Optional starting station name', default=None) | |
args = parser.parse_args() | |
# JSONデータの読み込み | |
station_data = read_json('station.json') | |
point_data = read_json(args.point_data_path) | |
# ポリゴンジオメトリの作成 | |
station_geoms = {} | |
geoms_list = [] | |
for station in station_data: | |
polygon_coords = [coord for coord in station['voronoi']['geometry']['coordinates'][0] if isinstance(coord, list) and len(coord) == 2] | |
if len(polygon_coords) >= 3: | |
geom = Polygon(polygon_coords) | |
station_geoms[station["name"]] = geom | |
geoms_list.append(geom) | |
# 空間インデックスの作成 | |
tree = STRtree(geoms_list) | |
# セグメントをチェインして連続した経路を構築 | |
ordered_points = chain_segments(point_data['point_list'], args.start_station) | |
# 駅名をリストに追加して、順序を保持する | |
stations_in_order = [] | |
# pointsを順に参照して駅名を追加 | |
for point in ordered_points: | |
lat = point['lat'] | |
lng = point['lng'] | |
stations = list_stations_in_polygon(station_data, lat, lng, tree, station_geoms, geoms_list) | |
for station in stations: | |
if station not in stations_in_order: | |
stations_in_order.append(station) | |
# 駅名をカンマ区切りで表示 | |
print(f"{len(stations_in_order)} 駅:") | |
print(", ".join(stations_in_order)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment