点座標から凹包を近似計算
凸包は便利ですが、点群を必要以上に大きく囲むことがあります。この凹包近似では、まず信頼できる外周として凸包を求め、未使用の内点を使って長い辺を細分化します。指定したしきい値に達するか、安全に挿入できる点がなくなるまで処理を続けます。決定論的な結果には、順序付き境界、各辺の長さ、周長、面積、短縮できなかった辺の数が含まれます。そのため、厳密な幾何学解と誤認せず、近似の妥当性を具体的に確認できます。
無料で実行
座標と意味のあるしきい値を指定します
数値の x 座標と y 座標で表した平面上の点を3個以上と、辺の長さに対する正のしきい値を指定してください。座標には、投影済みの地図位置、作図単位、計測値など、任意の2次元直交座標系を利用できます。ただし、すべて同じ尺度でなければなりません。しきい値に物理的な意味を持たせたい場合、経度の度数とメートル単位の距離を混在させないでください。小さいしきい値では利用可能な点をより細かくたどり、大きい値では凸包の輪郭を多く残します。しきい値は目標であり、必ず達成される値ではありません。点がまばらな場合、特定の辺を分割できる安全な内点が存在しないことがあります。重複座標は無視されます。直線だけでは多角形を作れないため、最終的に3個以上の一意で同一直線上にない点が必要です。緯度と経度を扱い、距離単位のしきい値を使う場合は、事前に適切な座標系へ投影してください。本機能は平面幾何を計算し、球体や楕円体の地球モデルは適用しません。意味のある空白と判断する点間隔に近い値から始め、出力境界を元の点群に重ねて確認することをおすすめします。
境界を細分化する仕組みを確認します
最初に、単調連鎖法によって決定論的な凸包を計算します。次に、指定したしきい値より長い境界辺を、長いものから順に調べます。各辺について、現在の多角形の内部にあり、別の境界線分と交差せずに元の辺を2本の短い線分へ置き換えられる未使用点を検索します。候補のうち、置換後の長い方の線分が最短になる点を選びます。同値の場合は、置換線分の合計長、元の入力順という安定した基準で決定します。点を1個挿入するたびに多角形が変わるため、辺の選択を最初からやり直します。すべての辺が目標を満たすか、残りの点では長い辺を安全に改善できなくなると終了します。この方法は、凹包に存在する複数の厳密な定義をすべて解決したと主張するものではなく、予測しやすく説明可能な結果を重視しています。頂点を新しく作ったり、座標を動かしたり、無作為抽出や外部サービスを使ったりしません。返される hull は、最後の点から最初の点への接続を暗黙に含む、開いた順序付き頂点リストです。辺長も同じ巡回順です。
多角形を利用する前に制約を確認します
しきい値が業務上重要な場合は、必ず unresolved_long_edges を確認してください。値が0なら、返されたすべての境界辺が目標を満たしています。正の値なら、交差、外向きの移動、または辺を短くできない置換を避けつつ目標を満たすだけの点配置ではなかったことを示します。これは隠れた失敗ではなく、判断に役立つ情報です。また、本近似はアルファシェイプ、最近傍法による包、三角形分割フィルター、海岸線専用手法とは異なる境界を返す場合があります。位相が法的、科学的、安全上の影響を持つ用途では、複数の手法を比較してください。面積と周長は、入力された座標系における返却平面多角形の値であり、測地距離ではありません。順序付き hull を元の点群に重ね、選んだしきい値が意図するまとまりやくぼみを捉えているか確認してください。境界が広すぎる場合は代表点を追加するか値を下げ、細かすぎる場合は値を上げます。反復する交差判定を有限に保ち、ブラウザーと決定論的な API 自動処理の両方で扱えるよう、入力は最大500項目です。
活用例
標本地点の外周を作成
投影済みの測量点やセンサー点を囲み、目に見えるくぼみも残した検証可能な境界を作成します。
地図プレビューを準備
専門的な GIS 処理へ渡す前に、中規模の点群を順序付き多角形へ変換します。
境界の感度を比較
複数のしきい値で面積、周長、挿入頂点、未解決辺を比較し、目的に合う近似を選びます。
よくある質問
厳密な凹包を求める機能ですか?
いいえ。凹包には複数の定義があり、本手法は安全な内点を使って凸包の長い辺を決定論的に細分化します。
料金はいくらですか?
API リクエスト1回につき $0.002 です。同じ決定論的計算をブラウザーでも実行できます。
すべての辺がしきい値以下になりますか?
必ずしもなりません。利用可能な点で安全に短縮できなかった辺は unresolved_long_edges に示されます。
緯度と経度を直接使えますか?
計算はできますが、距離と面積は平面上の角度値のままです。物理単位が必要な場合は事前に投影してください。
先頭の hull 点は末尾にも入りますか?
いいえ。hull は開いた順序付きリストであり、末尾の点から先頭の点への接続は暗黙に扱います。
重複点や同一直線上の点はどう扱いますか?
完全に同じ座標は無視します。一意な点がすべて同一直線上にある場合、多角形を定義できないため拒否します。
開発者向け — APIアクセス
このページの機能はすべてAPIからも利用できます。自社システムに組み込みたいチーム向けのセクションです。それ以外の方は上のツールをそのままお使いください。
エンドポイント
Bearerトークンで認証し、POST1回でタスクをキューに登録します。結果はWebhookまたは署名付きリンクで受け取れます。
お使いのスタックから呼び出す
curl -X POST https://api.kit.forhosting.com/geo/concave-hull-approx \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"points":[{"x":0,"y":0},{"x":4,"y":0},{"x":4,"y":4},{"x":2,"y":1},{"x":0,"y":4}],"threshold":3}'const res = await fetch("https://api.kit.forhosting.com/geo/concave-hull-approx", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"points": [
{
"x": 0,
"y": 0
},
{
"x": 4,
"y": 0
},
{
"x": 4,
"y": 4
},
{
"x": 2,
"y": 1
},
{
"x": 0,
"y": 4
}
],
"threshold": 3
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/geo/concave-hull-approx",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"points": [
{
"x": 0,
"y": 0
},
{
"x": 4,
"y": 0
},
{
"x": 4,
"y": 4
},
{
"x": 2,
"y": 1
},
{
"x": 0,
"y": 4
}
],
"threshold": 3
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/geo/concave-hull-approx", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"points":[{"x":0,"y":0},{"x":4,"y":0},{"x":4,"y":4},{"x":2,"y":1},{"x":0,"y":4}],"threshold":3}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"points":[{"x":0,"y":0},{"x":4,"y":0},{"x":4,"y":4},{"x":2,"y":1},{"x":0,"y":4}],"threshold":3}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/geo/concave-hull-approx", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)リクエスト例
{
"points": [
{
"x": 0,
"y": 0
},
{
"x": 4,
"y": 0
},
{
"x": 4,
"y": 4
},
{
"x": 2,
"y": 1
},
{
"x": 0,
"y": 4
}
],
"threshold": 3
}レスポンス例
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "geo.concave_hull_approx",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}非同期APIです。task_idは即時に返ります。ポーリングは1秒あたり1リクエストまでです。
料金
単価はすべて公開しています。トークン換算や独自クレジットはありません。失敗したタスクは課金されません。
制限
max_items | 500 |
エラー
| HTTP | コード | 意味 |
|---|---|---|
401 | unauthorized | APIキーが無効か、指定されていません。Authorizationヘッダーを確認してください。 |
402 | insufficient_balance | 残高が不足しています。チャージ後に再度お試しください。 |
404 | unknown_type | 指定されたタスクタイプは存在しません。タイプ名を確認してください。 |
429 | rate_limited | リクエストが多すぎます。しばらく待ってから再度お試しください。 |