年に一度くらい魔が差す時があるので。
元ネタ と異なり、文字の輪郭を忠実にポリゴンとして扱います。つまり「D」は穴あきポリゴンです。
const polygonD = {
"type":"Feature",
"properties":{},
"geometry":{
"type":"Polygon",
"coordinates":[ 省略 ]
}
};
const polygonG = {
"type":"Feature",
"properties":{ },
"geometry":{
"type":"Polygon",
"coordinates":[ 省略 ]
}
};
const polygonFrame = {
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [ 省略 ]
}
};
const map = new mapboxgl.Map({
container: 'map',
style: {
version: 8,
sources: {
OSM: {
type: "raster",
tiles: [ "https://a.tile.openstreetmap.org/{z}/{x}/{y}.png" ],
tileSize: 256,
attribution:
"OpenStreetMap",
},
sources: {
'type': 'geojson',
'data': {
"type": "FeatureCollection",
"features": []
}
},
results: {
'type': 'geojson',
'data': {
"type": "FeatureCollection",
"features": []
}
},
},
layers: [
{
id: "BASEMAP",
type: "raster",
source: "OSM",
minzoom: 0,
maxzoom: 18,
},
{
id: 'sources',
type: 'line',
source: 'sources',
paint: {
'line-color': '#088',
'line-width': 5,
'line-opacity': 0.8,
}
},
{
id: 'results',
type: 'fill',
source: 'results',
paint: {
'fill-color': 'red',
'fill-opacity': 1,
}
}
],
},
});
map.once('load', () => {
const sourceFeatures = [];
// 元図形
sourceFeatures.push({
d: polygonD,
g: polygonG,
frame: polygonFrame,
});
// 上左
sourceFeatures.push({
d: turf.transformTranslate(polygonD, 70, 90, { units: 'kilometers' }),
g: turf.transformTranslate(polygonG, 70, 90, { units: 'kilometers' }),
frame: turf.transformTranslate(polygonFrame, 70, 90, { units: 'kilometers' }),
});
// 上中
sourceFeatures.push({
d: turf.transformTranslate(polygonD, 140, 90, { units: 'kilometers' }),
g: turf.transformTranslate(polygonG, 140, 90, { units: 'kilometers' }),
frame: turf.transformTranslate(polygonFrame, 140, 90, { units: 'kilometers' }),
});
// 上右
sourceFeatures.push({
d: turf.transformTranslate(polygonD, 210, 90, { units: 'kilometers' }),
g: turf.transformTranslate(polygonG, 210, 90, { units: 'kilometers' }),
frame: turf.transformTranslate(polygonFrame, 210, 90, { units: 'kilometers' }),
});
// 下左
sourceFeatures.push({
d: turf.transformTranslate(sourceFeatures[1].d, 60, 180, { units: 'kilometers' }),
g: turf.transformTranslate(sourceFeatures[1].g, 60, 180, { units: 'kilometers' }),
frame: turf.transformTranslate(sourceFeatures[1].frame, 60, 180, { units: 'kilometers' }),
});
// 下中
sourceFeatures.push({
d: turf.transformTranslate(sourceFeatures[2].d, 60, 180, { units: 'kilometers' }),
g: turf.transformTranslate(sourceFeatures[2].g, 60, 180, { units: 'kilometers' }),
frame: turf.transformTranslate(sourceFeatures[2].frame, 60, 180, { units: 'kilometers' }),
});
// 下右
sourceFeatures.push({
d: turf.transformTranslate(sourceFeatures[3].d, 60, 180, { units: 'kilometers' }),
g: turf.transformTranslate(sourceFeatures[3].g, 60, 180, { units: 'kilometers' }),
frame: turf.transformTranslate(sourceFeatures[3].frame, 60, 180, { units: 'kilometers' }),
});
sourceFeatureCollection = turf.featureCollection(sourceFeatures.reduce((acc, x) => {
acc.push(x.d);
acc.push(x.g);
acc.push(x.frame);
return acc;
}, []));
map.getSource('sources').setData(sourceFeatureCollection);
// D AND G -> intersect
const DandG = turf.intersect(sourceFeatures[1].d, sourceFeatures[1].g);
// D OR G -> union
const DorG = turf.union(sourceFeatures[2].d, sourceFeatures[2].g);
// D XOR G -> (D - G) + (G - D)
const DminusG = turf.difference(sourceFeatures[3].d, sourceFeatures[3].g);
const GminusD = turf.difference(sourceFeatures[3].g, sourceFeatures[3].d);
const DxorG = turf.union(DminusG, GminusD);
// D NAND G -> frame - DandG
const DnandG = turf.difference(sourceFeatures[4].frame, turf.intersect(sourceFeatures[4].d, sourceFeatures[4].g));
// D NOR G -> frame - DorG
const DnorG = turf.difference(sourceFeatures[5].frame, turf.union(sourceFeatures[5].d, sourceFeatures[5].g));
// D NXOR G -> frame - DxorG
const tmpDminusG = turf.difference(sourceFeatures[6].d, sourceFeatures[6].g);
const tmpGminusD = turf.difference(sourceFeatures[6].g, sourceFeatures[6].d);
const DnxorG = turf.difference(sourceFeatures[6].frame, turf.union(tmpDminusG, tmpGminusD));
map.getSource('results').setData(turf.featureCollection([
DandG,
DorG,
DxorG,
DnandG,
DnorG,
DnxorG,
]));
map.fitBounds(turf.bbox(sourceFeatureCollection), { padding: { bottom: 200, top: 200, right: 200, left: 200 }});
});
また例によってだらだら長いコードになってしまったけど、論理演算を行っているのは、最下部のあたり。
turf.js の論理演算機能は、intersect
, union
, ''difference'' のみです。
intersect
は、2つの図形が共に重なり合う領域、つまり AND です。
union
は、2つの図形のいずれかの領域、つまり OR。
difference
は差分、つまり第一引数の図形から、第二引数の図形の領域を引いた領域です。
この3つだけでも、組み合わせるとそれなりの事はできますねーという例でした。