見出し画像

polygon-clippingライブラリと@turf/turfライブラリを使ってポリゴンの集合演算をやってみよう

こんにちわ。nap5です。


今回はpolygon-clippingライブラリと@turf/turfライブラリを使ってポリゴンの集合演算をやってみたので紹介したいと思います。


polygon-clippingライブラリはこちらです。


今回ポリゴンの集合演算として以下の4つを扱います。
差分シェイプに関しては方向を意識して区別します。(図形Aから図形Bを引いたシェイプと図形Bから図形Aを引いたシェイプ)

  • 2つのポリゴンの共通シェイプであるintersection

  • 2つのポリゴンの合成シェイプであるunion

  • 2つのポリゴンの排他和シェイプであるxor

  • 2つのポリゴンの差分シェイプであるdifference

集合演算関連で参考になるリンクを以下に載せます。


今回のプログラムです。

import polygonClipping from "polygon-clipping";
import * as turf from "@turf/turf";

const makePath = ({ coordinates }) => {
  let path = `M ${coordinates[0][0]},${coordinates[0][1]}`;
  for (let i = 1; i < coordinates.length; i++) {
    path = path + ` L ${coordinates[i][0]},${coordinates[i][1]}`;
  }
  path = path + ` Z`;
  return path;
};

const formatPoints = ({ points }) => {
  if (points[0].length === 1) {
    return points.flat(1);
  } else {
    return points;
  }
};

const createPolygonPath = ({ points }) => {
  points = formatPoints({ points });
  const polygon = turf.polygon(points);
  return makePath({ coordinates: polygon.geometry.coordinates.flat() });
};

const polyA = [
  [
    [0, 0],
    [2, 0],
    [0, 2],
    [0, 0],
  ],
];
const polyB = [
  [
    [-1, 0],
    [1, 0],
    [0, 1],
    [-1, 0],
  ],
];

const polyAPath = createPolygonPath({ points: polyA });
const polyBPath = createPolygonPath({ points: polyB });
const intersectionPloyPath = createPolygonPath({
  points: polygonClipping.intersection(polyA, polyB),
});
const unionPloyPath = createPolygonPath({
  points: polygonClipping.union(polyA, polyB),
});
const xorPloyPath = createPolygonPath({
  points: polygonClipping.xor(polyA, polyB),
});
const differenceABPloyPath = createPolygonPath({
  points: polygonClipping.difference(polyA, polyB),
});
const differenceBAPloyPath = createPolygonPath({
  points: polygonClipping.difference(polyB, polyA),
});

console.log(polyAPath);
console.log(polyBPath);
console.log(intersectionPloyPath);
console.log(unionPloyPath);
console.log(xorPloyPath);
console.log(differenceABPloyPath);
console.log(differenceBAPloyPath);


以下が実行結果になります。
1行目が図形Aのsvgパスコマンドです。
2行目が図形Bのsvgパスコマンドです。
3行目が図形Aと図形Bの共通シェイプであるsvgパスコマンドです。
4行目が図形Aと図形Bの合成シェイプであるsvgパスコマンドです。
5行目が図形Aと図形Bの排他和シェイプであるsvgパスコマンドです。
6行目が図形Aと図形Bの差分シェイプ(図形Aから図形Bを引いたシェイプ)であるsvgパスコマンドです。
7行目が図形Aと図形Bの差分シェイプ(図形Bから図形Aを引いたシェイプ)であるsvgパスコマンドです。

$ time node  index.js
M 0,0 L 2,0 L 0,2 L 0,0 Z
M -1,0 L 1,0 L 0,1 L -1,0 Z
M 0,0 L 1,0 L 0,1 L 0,0 Z
M -1,0 L 2,0 L 0,2 L 0,1 L -1,0 Z
M -1,0 L 0,0 L 0,1 L -1,0 L 0,1 L 1,0 L 2,0 L 0,2 L 0,1 Z
M 0,1 L 1,0 L 2,0 L 0,2 L 0,1 Z
M -1,0 L 0,0 L 0,1 L -1,0 Z

real    0m0.529s
user    0m0.589s
sys     0m0.064s


これらのsvgパスコマンドをsvg-path-editorに張り付けて眺めてみると、違いが分かると思います。


いろんなポリゴンで試してみると面白そうと思いました。


最近では、Twitterでモックアップ動画を公開しているので、こちらもよかったら、覗いてみてください。


最後に、Udemyでコースを公開しました。
良かったら覗いてみてください。


また、コースの内容紹介記事は以下になります。


簡単ですが、以上です。


この記事が気に入ったらサポートをしてみませんか?