Class: PbfReverseGeocoder::PbfTileReader

Inherits:
Object
  • Object
show all
Defined in:
lib/pbf_reverse_geocoder/pbf_tile_reader.rb

Constant Summary collapse

LAYER_NAMES =

サポートするレイヤー名

  • 最新のN03タイルをそのまま使う場合: N03

  • 互換用: @geolonia/open-reverse-geocoder の japanese-admins

['N03', 'N03-2025', 'japanese-admins'].freeze

Class Method Summary collapse

Class Method Details

.normalize_properties(props) ⇒ Hash

N03形式のプロパティを標準化

  • N03_* を pref/municipality/ward などに正規化

  • city は municipality と ward を連結した互換フィールド

Parameters:

  • props (Hash)

Returns:

  • (Hash)


120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/pbf_reverse_geocoder/pbf_tile_reader.rb', line 120

def self.normalize_properties(props)
  prefecture = props['prefecture'] || props['N03_001']
  sub_prefecture = props['sub_prefecture'] || props['N03_002']
  county = props['county'] || props['N03_003']
  municipality = props['municipality'] || props['city'] || props['N03_004']
  ward = props['ward'] || props['N03_005']

  code = props['code'] || props['N03_007'] || props['id']
  code = code.to_i.to_s if code.is_a?(Integer)
  code = code.to_s.rjust(5, '0') if code

  if ward.to_s.empty? && municipality == props['city']
    # 分離されていない市+区の文字列を分割(例: 大阪市中央区)
    if municipality && (m = municipality.match(/\A(.+市)(.+区)\z/))
      municipality = m[1]
      ward = m[2]
    end
  end

  city = props['city'] || [municipality, ward].compact.join

  result = {}
  result['prefecture'] = prefecture if prefecture
  result['sub_prefecture'] = sub_prefecture if sub_prefecture
  result['county'] = county if county
  result['municipality'] = municipality if municipality
  result['ward'] = ward if ward
  result['city'] = city unless city.nil? || city.empty?
  result['code'] = code if code

  result
end

.read_tile(tile_path, tile_x, tile_y, zoom) ⇒ Array<Hash>

PBFタイルを読み込んでフィーチャー一覧を返す

Examples:

features = PbfTileReader.read_tile('/app/public/tiles/10/904/403.pbf', 904, 403, 10)

Parameters:

  • tile_path (String, Pathname)

    PBFファイルパス

  • tile_x (Integer)

    タイルX座標

  • tile_y (Integer)

    タイルY座標

  • zoom (Integer)

    ズームレベル

Returns:

  • (Array<Hash>)

    フィーチャー配列



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/pbf_reverse_geocoder/pbf_tile_reader.rb', line 28

def self.read_tile(tile_path, tile_x, tile_y, zoom)
  return [] unless File.exist?(tile_path)

  # バイナリ読み込み(gzipなら展開)
  pbf_data = File.binread(tile_path)
  if gzip?(pbf_data)
    begin
      pbf_data = Zlib::GzipReader.new(StringIO.new(pbf_data)).read
    rescue Zlib::GzipFile::Error
      warn "Failed to gunzip tile: #{tile_path}"
      return []
    end
  end

  # SimplePbfParserでパース
  tile = SimplePbfParser.parse(pbf_data)

  # japanese-admins レイヤーを抽出
  layer = find_layer(tile)
  return [] unless layer

  # フィーチャーをGeoJSON形式に変換
  layer[:features].map do |feature|
    geometry = GeometryDecoder.decode(feature[:geometry], tile_x, tile_y, zoom)
    properties = decode_properties(feature, layer)

    {
      geometry: geometry,
      properties: properties
    }
  end
rescue StandardError => e
  warn "Failed to read PBF tile: #{tile_path}, error: #{e.message}"
  warn e.backtrace.join("\n") if $DEBUG
  []
end