0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

two-eleven の modify.js への実装

Last updated at Posted at 2018-11-18

ハンズオン準備の第8回です。第7回で設計したベクトルタイルスキーマ two-eleven を、ベクトルタイル生産のハンズオン教材 spinel-produce の modify.js に実装していきます。

実装方針

modify.js は、地物を受け取って地物を返す関数を export するものです。なので、地物の内容をチェックして、必要なデータ操作を行い、その地物を return するのが基本になります。

natural タグの地物に対する返し方 を材料に、模式的に書くと、次のようになります。

module.exports = (f) => {
  if (f.properties.natural) {
    f.tippecanoe = { 
      layer: 'natural', 
      minzoom: 11,
      maxzoom: 15
    }
    return f
  }
  return null // 引数で与えられた地物を破棄する場合
}

実装

国連ベクトルタイルツールキット開発のこれまでの経験を反映して、modify.js を実装しました。このエントリ執筆時点の modify.js は次のようになっています。

const geojsonArea = require('@mapbox/geojson-area')

// the flap function:
// a function to return a function to dynamically assign maximum and minimim
// zoom levels from the area of the polygon geometry.
const flap = (minzoom, maxzoom, F) => {
  if (!F) F = 19 // default flap constant
  return (f) => {
    if (f.geometry.type !== 'MultiPolygon') return f
    f.tippecanoe.minzoom = Math.floor(
      F - Math.log2(geojsonArea.geometry(f.geometry)) / 2
    )
    if (f.tippecanoe.minzoom <= minzoom) {
      if (minzoom === 0) {
        // tippecanoe requires that minzoom should not be 0.
        delete f.tippecanoe.minzoom
      } else {
        f.tippecanoe.minzoom = minzoom
      }
    }
    if (f.tippecanoe.minzoom >= maxzoom) f.tippecanoe.minzoom = maxzoom
    return f
  }
}

// flap cache
const flaps = {
  area: flap(11, 15, 17),
  building: flap(13, 15, 18)
}

// the modify function to export
module.exports = f => {
  // For Global Map Sri Lanka 2.0
  switch (f.properties.f_code) {
    case 'BA010': // coastl
      f.tippecanoe = { layer: 'coastl', minzoom: 6, maxzoom: 10 }
      return f
    case 'AP030': // roadl
      // f.tippecanoe = { layer: 'roadl', minzoom: 6, maxzoom: 7 }
      return null // we do not use roadl
    case 'BH140': // riverl
      f.tippecanoe = { layer: 'riverl', minzoom: 6, maxzoom: 10 }
      return f
    case 'BH000': // inwatera
      f.tippecanoe = { layer: 'inwatera', minzoom: 6, maxzoom: 10 }
      return f
    case 'FA000': // polbndl
      f.tippecanoe = { layer: 'polbndl', minzoom: 6, maxzoom: 15 }
      return f
    case 'AN010': // raill
      f.tippecanoe = { layer: 'raill', minzoom: 6, maxzoom: 10 }
      return f
    case 'GB005': // airp
      f.tippecanoe = { layer: 'airp', minzoom: 6, maxzoom: 15 }
      return f
    case 'AL020': // builtupp
      f.tippecanoe = { layer: 'builtupp', minzoom: 6, maxzoom: 10 }
      return f
    case 'FA001': // polbnda
      return null // we do not use polbnda
    default:
      break
  }

  // For OpenStreetMap - 'two-eleven' schema
  if (f.properties.landuse) {
    f.tippecanoe = { layer: 'landuse', minzoom: 11, maxzoom: 15 }
    return flaps.area(f)
  }
  if (f.properties.natural) {
    f.tippecanoe = { layer: 'natural', minzoom: 11, maxzoom: 15 }
    return flaps.area(f)
  }
  if (f.properties.boundary) {
    if (f.properties.boundary === 'national_park') {
      f.tippecanoe = { layer: 'boundary', minzoom: 11, maxzoom: 15 }
      return flaps.area(f)
    } else {
      return null
    }
  }
  if (f.properties.waterway) {
    f.tippecanoe = { layer: 'waterway', minzoom: 11, maxzoom: 15 }
    return f
  }
  if (f.properties.highway) {
    f.tippecanoe = { layer: 'highway', minzoom: 15, maxzoom: 15 }
    // OpenMapTiles was used as a reference for the grouping of tags.
    switch (f.properties.highway) {
      case 'path':
      case 'pedestrian':
      case 'footway':
      case 'cycleway':
      case 'steps':
      case 'bridleway':
        f.tippecanoe.minzoom = 15
        break
      case 'service':
      case 'track':
        f.tippecanoe.minzoom = 14
        break
      case 'unclassified':
      case 'residential':
      case 'living_street':
      case 'road':
      case 'tertiary_link':
        f.tippecanoe.minzoom = 13
        break
      case 'tertiary':
      case 'secondary_link':
        f.tippecanoe.minzoom = 12
        break
      case 'secondary':
      case 'primary_link':
        f.tippecanoe.minzoom = 11
        break
      case 'primary':
      case 'trunk_link':
        f.tippecanoe.minzoom = 10
        break
      case 'trunk':
      case 'motorway_link':
        f.tippecanoe.minzoom = 9
        break
      case 'motorway':
        f.tippecanoe.minzoom = 8
        break
    }
    return f
  }
  if (f.properties.building) {
    f.tippecanoe = { layer: 'building', minzoom: 11, maxzoom: 15 }
    return flaps.building(f)
  }
  if (f.properties.railway) {
    f.tippecanoe = { layer: 'railway', minzoom: 11, maxzoom: 15 }
    return flaps.building(f)
  }
  if (f.properties.route) {
    f.tippecanoe = { layer: 'route', minzoom: 11, maxzoom: 15 }
    return f
  }
  if (f.properties.aeroway) {
    f.tippecanoe = { layer: 'aeroway', minzoom: 11, maxzoom: 15 }
    return flaps.building(f)
  }
  if (f.properties.place) {
    f.tippecanoe = { layer: 'place', minzoom: 14, maxzoom: 15 }
    switch (f.properties.place) {
      case 'island':
        return null
      case 'city':
        f.tippecanoe.minzoom = 8
        break
      case 'town':
        f.tippecanoe.minzoom = 10
        break
      case 'villege':
        f.tippecanoe.minzoom = 12
        break
    }
    if (f.properties.capital === 'yes') {
      f.tippecanoe.minzoom = 6
    }
    return flaps.area(f)
  }
  if (f.properties.leisure) {
    f.tippecanoe = { layer: 'leisure', minzoom: 11, maxzoom: 15 }
    return flaps.area(f)
  }

  if (f.properties.amenity) {
    f.tippecanoe = { layer: 'amenity', minzoom: 14, maxzoom: 15 }
    return flaps.building(f)
  }
  if (f.properties.historic) {
    f.tippecanoe = { layer: 'historic', minzoom: 13, maxzoom: 15 }
    return flaps.area(f)
  }
  if (f.properties.military) {
    f.tippecanoe = { layer: 'military', minzoom: 13, maxzoom: 15 }
    return flaps.area(f)
  }
  if (f.properties.man_made) {
    f.tippecanoe = { layer: 'man_made', minzoom: 13, maxzoom: 15 }
    return f
  }
  if (f.properties.power) {
    f.tippecanoe = { layer: 'power', minzoom: 13, maxzoom: 15 }
    return f
  }
  if (f.properties.sport) {
    f.tippecanoe = { layer: 'sport', minzoom: 13, maxzoom: 15 }
    return f
  }
  if (f.properties.office) {
    f.tippecanoe = { layer: 'office', minzoom: 13, maxzoom: 15 }
    return f
  }
  if (f.properties.craft) {
    f.tippecanoe = { layer: 'craft', minzoom: 14, maxzoom: 15 }
    return f
  }
  if (f.properties.public_transport) {
    f.tippecanoe = { layer: 'public_transport', minzoom: 11, maxzoom: 15 }
    return flaps.building(f)
  }
  if (f.properties.tourism) {
    f.tippecanoe = { layer: 'tourism', minzoom: 14, maxzoom: 15 }
    return f
  }
  if (f.properties.shop) {
    f.tippecanoe = { layer: 'shop', minzoom: 14, maxzoom: 15 }
    return f
  }

  // DEFAULT
  // f.tippecanoe = { layer: 'default', minzoom: 11, maxzoom: 15 }
  // return f
  return null
}

関数 flap は、ポリゴンの面積に応じて最小ズームレベルを変更する関数です。

次回

次回は、次のいずれかになると思います。

  1. 現在の生産スクリプトはズームレベル6のモジュールを作るためのスクリプトなので、ズームレベル5以下をカバーしません。ズームレベル5以下をカバーするリファレンス用の mbtiles ファイルである 0-0-0.mbtiles を簡単につくるかもしれません。類似の作業は、Ruby ベースですでに実施済みですが、最大ズームレベルの設定などが少し違うので、簡単に作り直せればと思っています。
  2. 作成した mbtiles をホストするサーバ spinel を整理するかもしれません。こちらが、ハンズオン準備としては本流の流れなので、1. を先に処理するかは残り時間とのバランスで決めると思います。spinel が整理できれば、テストサーバを公開することも可能になってきます。
0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?