Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
2
Help us understand the problem. What are the problem?

posted at

updated at

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

建物や地形のポリゴンの「中に」マーカーを立てたいケースはいろいろあります。
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');

});

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
2
Help us understand the problem. What are the problem?