0.5度スキャンと二分法の2段階で解くチェーン角度逆問題の実装詳細

2026年2月23日

回転の順問題と逆問題の非対称性

チェーンチェッカーの計算には2つの方向がある。「角度を指定して点間距離を求める」順問題は、回転行列を掛けて座標変換するだけなので直接計算可能。しかし「チェーン長(距離)から角度を求める」逆問題は、距離関数 d(θ) が非線形であるため解析的な逆関数が存在しない場合が多い。

さらに厄介なのは複数解の存在。回転によって同じ距離になる角度が2つ以上存在するケースがある。たとえば対称な配置では、ある角度とその補角の両方で同じ距離が得られる。単純な等間隔スキャンだけでは、刻み幅の間に根が隠れて取りこぼすリスクがある。

この記事では、0.5度の粗スキャンで候補区間を抽出し、二分法で許容誤差まで収束させる2段階方式の理論的根拠、計算例、エッジケース処理を示す。

候補方式の比較

逆問題の数値解法として、以下の2方式を検討した。

| 属性 | 全探索(0.1度刻み) | 2段階(0.5度+二分法) | |------|---------------------|----------------------| | 実装の単純さ | 高い | 中 | | 計算量(単軸) | 3,600サンプル | 720+二分法 | | 精度調整 | 刻みを細かくする | 二分法の反復で制御 | | 複数解検出 | 全域評価で可能 | 粗スキャンで区間分離後に可能 | | 理論的保証 | なし(探索的) | 中間値の定理に基づく収束保証 |

全探索方式(不採用)

0.1度刻みで360度を走査し、距離関数の値が目標に最も近いサンプルを解とする方式。実装は単純だが、3軸回転の組み合わせでは評価点数が指数的に増加する。各軸3,600サンプルの直積をとると現実的な応答時間を確保できない。また、離散サンプルの間に根が隠れる可能性があり、刻みを細かくしてもコスト効率が悪い。

2段階方式(採用)

0.5度刻みの粗スキャン(720サンプル)で距離差関数 f(θ) = d(θ) - L の符号変化を検出し、符号が変わる区間ごとに二分法を適用して精密化する方式。二分法は連続関数に対して中間値の定理に基づく収束保証があり、理論的根拠が明確。複数解がある場合も、粗スキャンで区間を分離できれば各区間で独立に二分法を適用できる。

なぜ2段階方式を選んだか

全探索は3軸化でスケーラビリティが破綻する。2段階方式なら粗スキャンのコストは720サンプルに固定され、二分法の反復は初期区間幅0.5度に対して許容誤差0.01度なら log2(0.5/0.01) ≒ 6回で収束する。計算効率と精度の両立が可能であり、ブラウザ内でのリアルタイム応答が求められる場面に適合する。

実装の詳細

計算フロー

  1. 入力を受け取る: 固定点A、回転中心O、初期点B、チェーン長L
  2. 粗スキャン: 0度〜360度を0.5度刻みで走査し、f(θ) = d(θ) - L を評価
  3. 符号変化の検出: 隣接サンプルで f の符号が変わる区間を候補として抽出
  4. 二分法: 各候補区間で最大100反復、許容誤差0.01度で収束
  5. 角度正規化: 結果を0度〜360度に統一(((θ % 360) + 360) % 360
  6. エッジケース処理: 半径が極小(< 1e-9)なら回転による変化を無視

回転行列と距離関数

Z軸回転を例にとると、角度θで点B = (x, y, z) を回転させた後の座標B'は以下のようになる。

Z軸回転:
  B'_x = x × cos(θ) - y × sin(θ)
  B'_y = x × sin(θ) + y × cos(θ)
  B'_z = z(変化なし)

距離関数:
  d(θ) = sqrt((B'_x - A_x)² + (B'_y - A_y)² + (B'_z - A_z)²)

距離差関数:
  f(θ) = d(θ) - L
  f > 0 → チェーンが足りない(距離が目標より遠い)
  f < 0 → チェーンが余る(距離が目標より近い)
  f = 0 → 解

粗スキャンと二分法の数値例

入力:
  固定点 A = (1.0, 0.0, 0.0)
  回転中心 O = (0.0, 0.0, 0.0)
  初期点 B = (2.0, 0.0, 0.0)  ← 半径2.0
  チェーン長 L = 1.5
  粗スキャン刻み = 0.5度、許容誤差 = 0.01度

粗スキャン(一部抜粋):
  θ = 0.0° → B' = (2.0, 0.0, 0.0) → d = 1.0 → f = -0.5
  θ = 30.0° → d ≒ 1.239 → f ≒ -0.261
  θ = 45.0° → d ≒ 1.473 → f ≒ -0.027
  θ = 45.5° → d ≒ 1.487 → f ≒ -0.013
  θ = 46.0° → d ≒ 1.501 → f ≒ +0.001  ← 符号変化!

候補区間: [45.5°, 46.0°]

二分法:
  反復1: mid = 45.75° → f ≒ -0.006 → 区間 [45.75°, 46.0°]
  反復2: mid = 45.875° → f ≒ -0.002 → 区間 [45.875°, 46.0°]
  反復3: mid = 45.9375° → f ≒ -0.001 → 区間 [45.9375°, 46.0°]
  反復4: mid = 45.96875° → f ≒ +0.0002 → 区間 [45.9375°, 45.96875°]
  反復5: mid = 45.953125° → 区間幅 0.015625° < 0.01° → 未達
  反復6: mid ≒ 45.95° → 区間幅 < 0.01° → 収束

  解: θ ≒ 45.95°(許容誤差0.01度以内)

スキャン刻み0.5度の根拠

0.5度刻みだと360度で720サンプル。ブラウザ内でMath.cos/Math.sinを720回呼ぶ計算負荷は数ミリ秒未満に収まる。刻みを0.1度に細かくすると3,600サンプルに増えるが、二分法の精密化があるため粗スキャンを細かくするメリットは薄い。0.5度刻みで根の存在区間を見落とすリスクは、距離関数の変動が0.5度あたり十分に小さい(通常の配置で局所勾配が急激に変わらない)ことから許容範囲と判断した。

角度正規化

二分法で得られた角度を ((θ % 360) + 360) % 360 で0度〜360度に正規化する。これにより負の角度や360度超えの値が出た場合でも一貫した表記になり、複数解のソートや重複除去が容易になる。

検証結果

ケース1: 単軸回転・単一解

半径2.0の点をZ軸回転し、距離1.5の角度を求めるケース。

入力値:

  • A = (1.0, 0.0, 0.0)、B = (2.0, 0.0, 0.0)、L = 1.5

計算結果:

  • 粗スキャンで候補区間: [45.5°, 46.0°]
  • 二分法収束: θ ≒ 45.95°(6反復で収束)

解釈: 粗スキャンの符号変化検出で候補区間を1つ特定し、二分法で6反復以内に収束。全探索(0.1度刻み3,600サンプル)に比べて評価点数は約720+6で圧倒的に少なく、同等以上の精度を達成。

ケース2: 対称配置・複数解

固定点をX軸上の0.5に配置し、対称性から2つの解が存在するケース。

入力値:

  • A = (0.5, 0.0, 0.0)、B = (2.0, 0.0, 0.0)、L = 1.5

計算結果:

  • 粗スキャンで候補区間2つ: [〜45°付近] と [〜315°付近]
  • 二分法で2解: θ1 ≒ 47.2°、θ2 ≒ 312.8°

解釈: 対称性から2つの角度で同じ距離が得られることを確認。粗スキャンが区間分離に有効であり、各区間で独立に二分法を適用することで複数解を確実に検出できる。

エッジケース: 回転軸上の点(半径 ≒ 0)

入力値:

  • B = (0.0, 0.0, 0.0)(回転中心と一致)

計算結果:

  • 半径 r = 0 < 1e-9 → 回転による位置変化なし
  • 固定点との距離 d = |A| = 一定値
  • d ≒ L なら「全角度で成立」、d ≠ L なら「解なし」

解釈: 半径が極小の場合、回転しても座標が変わらないため数値的な誤差で偽の根が検出されるリスクがある。閾値判定(r < 1e-9)で早期に分岐させ、固定距離とチェーン長の比較のみで判定する。

よくある質問(FAQ)

Q: スキャン刻みや許容誤差はどう決めればよいか

応答時間と精度のトレードオフで決まる。リアルタイム操作を重視するなら0.5度で十分。バッチ処理で高精度が必要なら0.1度まで細かくできるが、二分法の精密化があるため粗スキャンを細かくするメリットは小さい。許容誤差は二分法の反復回数から逆算でき、初期区間幅w度に対して log2(w / 許容誤差) 回で収束する。

Q: 二分法は必ず収束するのか

区間内で距離差関数 f(θ) が連続かつ符号変化がある場合、中間値の定理により根の存在が保証され、二分法は確実に収束する。ただし数値的に不連続な状況(浮動小数点の丸め誤差が支配的な領域)では前提が崩れるため、反復上限(100回)を設けて無限ループを防止している。

Q: データはサーバーに送信される?

すべてブラウザ内で処理される。入力した座標やチェーン長がサーバーに送信されることはない。ブラウザを閉じれば入力内容は消える。

Q: 三角関数の丸め誤差が心配な場合の対処は

JavaScriptのMath.cos/Math.sinはIEEE 754準拠の倍精度浮動小数点で計算されるため、通常の角度範囲では実用上の問題はない。ただし角度が非常に小さい(0.001度未満)場合や、回転軸付近で半径が極小の場合は丸め誤差の影響が大きくなる。閾値判定(半径 < 1e-9)で早期分岐させることが対策となる。

まとめ

角度→距離の順問題は回転行列で直接計算可能だが、距離→角度の逆問題は非線形で解析解が存在しない。0.5度の粗スキャンで符号変化区間を抽出し、二分法で許容誤差まで収束させる2段階方式は、計算効率(720サンプル+数回の反復)と理論的保証(中間値の定理)を両立する合理的なアプローチ。

実際に試したいときはチェーンチェッカーを使ってみて。数値的な安定性や断面計算という関連テーマでは、鋼材断面のコンシェルジュもJIS鋼材の数値処理を扱っている。


不具合や要望があれば、お問い合わせページから気軽に教えてほしい。

M

Mahiro

Mahiro Appの開発者。チェーン駆動の角度ソルバーアルゴリズムを技術的に解説した記事の著者。

運営者情報を見る

© 2026 Mahiro App