LoginSignup
3
2

More than 3 years have passed since last update.

ポリゴン内の位置を返すさまざまな関数「center, centroid, centerOfMass, pointOnFeature」

Last updated at Posted at 2020-12-05

建物や地形のポリゴンの「中に」マーカーを立てたいケースはいろいろあります。
turf.js で用意されているポリゴン内の位置を返す様々な機能を見ていきましょう。

image.png

  • 黒: center
  • 青: centroid
  • 緑: centerOfMass
  • 赤: pointOnFeature

黒:center

関数名の通り、図形の「中心」を返します。
穴あきや「コの字」だった場合は、図形外になる可能性があります。

青:centroid

こちらは図形の「重心」を返します。
これも、穴あきや「コの字」だった場合は、図形外になる可能性があります。

緑:centerOfMass

ちょっとよく分かりません。API Doc には、

Takes any Feature or a FeatureCollection and returns its center of mass using this formula: Centroid of Polygon.

とあるので、centroid と同じと思いきや、若干異なる地点を示しています。

赤:pointOnFeature

関数名の通り「地物内の位置」を返します。
これが唯一、穴あきや「コの字」でもポリゴン内の位置を示しています。
しかし見た目上「いい感じ」とは言えないようです。

まとめ

ポリゴンにマーカーを立てたい時、中心や重心にマーカーが表示されるのが自然ですが、ポリゴンの形状によっては中心や重心はポリゴン外になる可能性があります。
pointOnFeature はポリゴン内の点を保証しますが、自然な位置とは言い難いです。

中心や重心がポリゴン内かをチェックしポリゴン内ならそれを採用、ポリゴン外ならば pointOnFeature を使う、という二段構えが良さそうです。

コードなど

const polygon1 = {
  "type": "Feature",
  "properties": {},
  "geometry": {
    "type": "Polygon",
    "coordinates": [
      [
        [ 137.796, 34.940 ],
        [ 137.748, 34.882 ],
        [ 137.887, 34.888 ],
        [ 137.796, 34.940 ]
      ],
      [
        [ 137.812, 34.926 ],
        [ 137.779, 34.892 ],
        [ 137.855, 34.897 ],
        [ 137.812, 34.926 ]
      ]
    ]
  }
};

const polygon2 = {
  "type": "Feature",
  "properties": {},
  "geometry": {
    "type": "Polygon",
    "coordinates": [
      [
        [137.8877,34.9171],
        [137.8867,34.8922],
        [137.9134,34.8915],
        [137.9135,34.8956],
        [137.8918,34.8963],
        [137.8923,34.9138],
        [137.9057,34.9134],
        [137.9058,34.9172],
        [137.8877,34.9171]
      ]
    ]
  }
};

const dataSource = {
  'type': 'geojson',
  'data': {

      "type": "FeatureCollection",
      "features": [
        polygon1,
        polygon2,
      ]

  }
};

const lineFeature = {
  type: 'FeatureCollection',
  features: [
    {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "type":"LineString",
        "coordinates": []
      }
    }
  ]
};

let marker;

const bounds = turf.bbox(dataSource.data);

const map = new mapboxgl.Map({
  container: 'map',
  bounds: bounds,
  style: {
    version: 8,
    sources: {
      OSM: {
        type: "raster",
        tiles: [
          "https://a.tile.openstreetmap.org/{z}/{x}/{y}.png",
        ],
        tileSize: 256,
        attribution:
        "OpenStreetMap",
      },
    },
    layers: [{
      id: "BASEMAP",
      type: "raster",
      source: "OSM",
      minzoom: 0,
      maxzoom: 18,
    }],
  },      
});

map.once('load', () => {

  map.fitBounds(bounds, { padding: { bottom: 50, top: 50, right: 50, left: 50 }});

  map.addSource('route', dataSource);

  map.addLayer({
    'id': 'route',
    'type': 'fill',
    'source': 'route',
    'paint': {
      'fill-color': '#088',
      'fill-opacity': 0.8      
    }
  });

  const addMarker = (lnglat, colorHex) => {
    const el = document.createElement('img');
    el.src =  `https://img.icons8.com/material/32/${colorHex}/marker--v1.png`;
    new mapboxgl.Marker(el, { anchor: 'bottom' })
      .setLngLat(lnglat)
      .addTo(map);
  };

  const center1 = turf.center(polygon1);
  addMarker(center1.geometry.coordinates, '555555');

  const centroid1 = turf.centroid(polygon1);
  addMarker(centroid1.geometry.coordinates, '0000FF');

  const centerOfMass1 = turf.centerOfMass(polygon1);
  addMarker(centerOfMass1.geometry.coordinates, '00FF00');

  const pointOnFeature1 = turf.pointOnFeature(polygon1);
  addMarker(pointOnFeature1.geometry.coordinates, 'FF0000');

  const center2 = turf.center(polygon2);
  addMarker(center2.geometry.coordinates, '555555');

  const centroid2 = turf.centroid(polygon2);
  addMarker(centroid2.geometry.coordinates, '0000FF');

  const centerOfMass2 = turf.centerOfMass(polygon2);
  addMarker(centerOfMass2.geometry.coordinates, '00FF00');

  const pointOnFeature2 = turf.pointOnFeature(polygon2);
  addMarker(pointOnFeature2.geometry.coordinates, 'FF0000');

});

3
2
0

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
3
2