Skip to content

feat(renderer): concentric corner radii for co-turning parallel links #34

@konoe-akitoshi

Description

@konoe-akitoshi

概要

並走する複数のリンクが同じコーナーを曲がるとき、現在は全リンクが同じ cornerRadius=8 を使っている。
道路のカーブのように、外側のリンクほど大きなRを持つべき(同心円配置)。

現状

  • 全リンクのコーナーが A 8 8 で統一
  • 太い線(strokeWidth=3)では外側エッジと内側エッジのRが異なって見える
  • 並走リンクが同じRだとコーナーでの間隔が不均一に見える

設計方針(検証済み)

アーキテクチャ

render() でリンク描画前に 事前パス を走らせ、co-turningリンクをグルーピングしてR割当:

  1. 全リンクのコーナーを抽出 — bend vertex, turn direction (cross product sign), incoming direction
  2. 同じコーナーを通るリンクをクラスタリング — 同turnSignature + 距離ベース
  3. 内側法線への射影でソートdot(vertex, innerNormal) で inner/outer 判定
  4. R = R_base + offsetFromInner で同心円R割当
  5. buildFilletedCenterline にper-corner半径を渡す

API拡張ポイント

buildFilletedCenterline は既に cornerRadius を引数に取っているので、cornerRadiusMap?: Map<string, number>(vertexKey→radius)を追加すれば後方互換で拡張可能。

実装上の注意点

今回のプロトタイプで判明した落とし穴:

  • 量子化グリッドだけではクラスタリングできない — 並走リンクの間隔がレイアウト依存で大きい(50-100px)ため、固定グリッドでは誤グループ化/見逃しが起きる
  • 距離ベースクラスタリングでは同リンクの別コーナーを除外する必要がある — 同じリンクが同turnSignatureで2回曲がることがある
  • lanePitch は内側法線方向の射影差(perpendicular distance)で計算すべき — Euclidean距離だとxy方向の成分が混ざって巨大値に
  • projection計算に注意 — 入力方向と内側法線は直交するため dot(samplePoint - vertex, innerNormal) は常に0。頂点座標の絶対値を射影に使う
  • simplifyMicroJogs 後のインデックスずれ — perCornerRadiiをインデックスで渡すと壊れる。vertexKey(座標ベース)でlookupする設計が安全

既存の基盤(このPRで入ったもの)

  • ✅ SVG A(円弧)ベースのパス生成 (buildFilletedCenterline + centerlineToPath)
  • ✅ 同心円オフセット方式(帯域別parallel lines用)
  • ✅ micro-jogマージ (simplifyMicroJogs)
  • ✅ center-first arc計算(浮動小数点精度改善)

将来の発展

  • オプティカル補正(外側エッジ基準のR調整、opticalK パラメータ)
  • stroke-to-outline 方式(fillベース描画)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions