Skip to content

Instantly share code, notes, and snippets.

@ksasao
Last active January 13, 2025 04:30
Show Gist options
  • Save ksasao/844fa3be90bcbcc6fcae34b7b64b8093 to your computer and use it in GitHub Desktop.
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
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