ユーザーがパス(一連の接続された直線)を描画し、このパスが特定のGeoJSONレイヤーのフィーチャと交差しない可能性があるアプリケーションがあります。
これらの線に沿った点が、端点だけでなく、GeoJSONレイヤーと交差していないことを確認する必要があります。
このチェックを実行するにはどうすればよいですか?
ユーザーがパス(一連の接続された直線)を描画し、このパスが特定のGeoJSONレイヤーのフィーチャと交差しない可能性があるアプリケーションがあります。
これらの線に沿った点が、端点だけでなく、GeoJSONレイヤーと交差していないことを確認する必要があります。
このチェックを実行するにはどうすればよいですか?
回答:
あなたはTurfライブラリとintersectのような方法を試すことができます:http://turfjs.org/docs/#intersect
これがそのライブラリのコード例です。
var poly1 = {
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[
[-122.801742, 45.48565],
[-122.801742, 45.60491],
[-122.584762, 45.60491],
[-122.584762, 45.48565],
[-122.801742, 45.48565]
]]
}
}
var poly2 = {
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[
[-122.520217, 45.535693],
[-122.64038, 45.553967],
[-122.720031, 45.526554],
[-122.669906, 45.507309],
[-122.723464, 45.446643],
[-122.532577, 45.408574],
[-122.487258, 45.477466],
[-122.520217, 45.535693]
]]
}
}
var intersection = turf.intersect(poly1, poly2);
編集:turf.jsを使用したより簡単でより良い解決策については、上記のコメントからghybsのフィドルを参照してください。元の答えは次のとおりです:
以下は、geoJson-js-utilsライブラリの交差ルーチンの変更バージョンで、GeoJSONラインストリングを入力として受け取り、交差のGeoJSONポイントを出力として生成します。
function lineStringsIntersect(l1, l2) {
var intersects = [];
for (var i = 0; i <= l1.coordinates.length - 2; ++i) {
for (var j = 0; j <= l2.coordinates.length - 2; ++j) {
var a1Latlon = L.latLng(l1.coordinates[i][1], l1.coordinates[i][0]),
a2Latlon = L.latLng(l1.coordinates[i + 1][1], l1.coordinates[i + 1][0]),
b1Latlon = L.latLng(l2.coordinates[j][1], l2.coordinates[j][0]),
b2Latlon = L.latLng(l2.coordinates[j + 1][1], l2.coordinates[j + 1][0]),
a1 = L.Projection.SphericalMercator.project(a1Latlon),
a2 = L.Projection.SphericalMercator.project(a2Latlon),
b1 = L.Projection.SphericalMercator.project(b1Latlon),
b2 = L.Projection.SphericalMercator.project(b2Latlon),
ua_t = (b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x),
ub_t = (a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x),
u_b = (b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y);
if (u_b != 0) {
var ua = ua_t / u_b,
ub = ub_t / u_b;
if (0 <= ua && ua <= 1 && 0 <= ub && ub <= 1) {
var pt_x = a1.x + ua * (a2.x - a1.x),
pt_y = a1.y + ua * (a2.y - a1.y),
pt_xy = {"x": pt_x, "y": pt_y},
pt_latlon = L.Projection.SphericalMercator.unproject(pt_xy);
intersects.push({
'type': 'Point',
'coordinates': [pt_latlon.lng, pt_latlon.lat]
});
}
}
}
}
if (intersects.length == 0) intersects = false;
return intersects;
}
元の関数は緯度と経度のみから交差を計算し、平面上の単なる座標であるかのように修正されたため、不正確な結果が生成されました(特に、高緯度または長距離にわたって)。を使用L.Projection
して、計算中に等角投影(またはこの場合はほぼ等角投影)投影座標系に変換すると、これが修正されます。
LineStringだけでなく、Leafletジオメトリオブジェクトを受け入れるようにさらに変更することもできますが、代わりにこの扱いにくい関数を使用して、交差関数に渡されるLineStringを作成しました。
function lineify(inputGeom) {
var outputLines = {
"type": "GeometryCollection",
"geometries": []
}
switch (inputGeom.type) {
case "GeometryCollection":
for (var i in inputGeom.geometries) {
var geomLines = lineify(inputGeom.geometries[i]);
if (geomLines) {
for (var j in geomLines.geometries) {
outputLines.geometries.push(geomLines.geometries[j]);
}
} else {
outputLines = false;
}
}
break;
case "Feature":
var geomLines = lineify(inputGeom.geometry);
if (geomLines) {
for (var j in geomLines.geometries) {
outputLines.geometries.push(geomLines.geometries[j]);
}
} else {
outputLines = false;
}
break;
case "FeatureCollection":
for (var i in inputGeom.features) {
var geomLines = lineify(inputGeom.features[i].geometry);
if (geomLines) {
for (var j in geomLines.geometries) {
outputLines.geometries.push(geomLines.geometries[j]);
}
} else {
outputLines = false;
}
}
break;
case "LineString":
outputLines.geometries.push(inputGeom);
break;
case "MultiLineString":
case "Polygon":
for (var i in inputGeom.coordinates) {
outputLines.geometries.push({
"type": "LineString",
"coordinates": inputGeom.coordinates[i]
});
}
break;
case "MultiPolygon":
for (var i in inputGeom.coordinates) {
for (var j in inputGeom.coordinates[i]) {
outputLines.geometries.push({
"type": "LineString",
"coordinates": inputGeom.coordinates[i][j]
});
}
}
break;
default:
outputLines = false;
}
return outputLines;
}
この関数は、Leafletオブジェクトを取得し、それらをLineStringに変換して、交差をチェックします。
function crossCheck(baseLayer, drawLayer) {
var baseJson = baseLayer.toGeoJSON(),
drawJson = drawLayer.toGeoJSON(),
baseLines = lineify(baseJson),
drawLines = lineify(drawJson),
crossPoints = {
type: "GeometryCollection",
geometries: []
};
if (baseLines && drawLines) {
for (var i in drawLines.geometries) {
for (var j in baseLines.geometries) {
var crossTest = lineStringsIntersect(drawLines.geometries[i], baseLines.geometries[j]);
if (crossTest) {
for (var k in crossTest) {
crossPoints.geometries.push(crossTest[k]);
}
}
}
}
}
return crossPoints;
}
これは、Leaflet.drawでこれを使用するフィドルの例です。
http://fiddle.jshell.net/nathansnider/egzxw86h/
オブジェクトの描画が完了すると、描画されたオブジェクトがベースジオメトリと交差するポイントにマップ上のマーカーが配置されます。Leaflet.drawは描画の進行中に使用するイベントハンドラーを提供しないため、パスが描画されている間は交差点を確認できません。ただし、ドローイベントが完了するとすぐにチェックされます。
また、これは、チェック対象のポリゴン内に完全にあるパスの交差を検出しないことにも注意してください。turf.jsを使用してこれらのチェックを実行できます(おそらくturf.explodeとturf.withinを組み合わせます)。