PHY: 座標を親からの相対に統一し、回転中心パラメータを廃止
クラスター単位の移動・回転を親ノード1つの書き換えで済ませるため、 各ノードは親から見た変換 (x, y, rotation) を持つことにし、絶対座標は 保持しないことにした。回転軸は常に自分自身のローカル原点に固定し、 KLE の rotation_x / rotation_y に相当するパラメータは持たない。 あわせてスナップの基準系をローカル座標系と明記し、親の変換を受けない w, h を Transform から分離した。KLE出力時の行のまとまりは未解決の問い として未確認事項に立てた。 Journal: journal/2026-09-18-phy-coordinate-model.md Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MdLT5x5ka5y6CaWLeE3EKb
This commit is contained in:
+54
-24
@@ -18,28 +18,44 @@ PHYレイヤーは、キースイッチやキーキャップ、その他周辺
|
|||||||
ユニットサイズ(1Uが何mmか、x軸・y軸それぞれ)を規定。
|
ユニットサイズ(1Uが何mmか、x軸・y軸それぞれ)を規定。
|
||||||
ビジュアル表現として、内側へのオフセット位置及びオフセット距離(mm or U単位)・R(U単位)を規定。
|
ビジュアル表現として、内側へのオフセット位置及びオフセット距離(mm or U単位)・R(U単位)を規定。
|
||||||
|
|
||||||
### キーの座標
|
### 座標と回転
|
||||||
|
|
||||||
キーキャップの左上角をローカル原点とする。
|
各ノードは、親ノードから見た相対的な配置を持つ。絶対座標は保持しない。
|
||||||
座標単位はU。1Uのサイズは別途指定する。
|
クラスター単位の移動・回転を親ノード1つの書き換えで済ませるため、相対座標を正本とする。
|
||||||
回転中心はローカル原点からの相対座標で表す。グローバル
|
|
||||||
座標・回転角度は0.25U単位・15度単位でスナップするが正規化しない。
|
配置は「親の座標系で θ 回転してから (x, y) 平行移動」と定義する。
|
||||||
|
|
||||||
|
```txt
|
||||||
|
p_parent = Translate(x, y) · Rotate(θ) · p_child
|
||||||
|
```
|
||||||
|
|
||||||
|
この定義により、(x, y) は自分のローカル原点が親座標系のどこに来るかを表し、θ は自分の向きを表す。
|
||||||
|
回転軸は常に自分自身のローカル原点であり、パラメータとしては持たない。
|
||||||
|
キーもクラスターも同じ変換を持つため、キーごとに向きが異なる配置のためにクラスターを作る必要はない。
|
||||||
|
|
||||||
|
ローカル原点はキーキャップの左上角とする。座標単位はU。1Uのサイズはプロファイルで指定する。
|
||||||
|
|
||||||
|
座標・回転角度は、ローカル座標系で0.25U単位・15度単位でスナップするが正規化しない。
|
||||||
|
|
||||||
|
KLE JSONやPCB向けの出力は、階層を畳んで絶対座標に変換した導出物として生成する。
|
||||||
|
|
||||||
### キーのサイズ
|
### キーのサイズ
|
||||||
|
|
||||||
0.25U単位でスナップするが正規化しない。
|
0.25U単位でスナップするが正規化しない。
|
||||||
|
サイズはローカルの値であり、親の変換を受けない。
|
||||||
|
|
||||||
### グルーピング
|
### グルーピング
|
||||||
|
|
||||||
複数のキーを「クラスター」としてまとめて運用することができる。
|
複数のキーを「クラスター」としてまとめて運用することができる。
|
||||||
クラスターのみにフォーカスして編集が可能。
|
クラスターのみにフォーカスして編集が可能。
|
||||||
クラスターごとの回転中心を設定できる。
|
クラスターの原点が、配下のノードの回転中心になる。
|
||||||
|
|
||||||
**内部処理での利用**:
|
**内部処理での利用**:
|
||||||
|
|
||||||
- クラスターごとの一括編集・移動・回転
|
- クラスターごとの一括編集・移動・回転
|
||||||
- 階層構造による管理(クラスターの入れ子構造)
|
- 階層構造による管理(クラスターの入れ子構造)
|
||||||
- 編集時のフォーカス制御
|
- 編集時のフォーカス制御
|
||||||
|
- 回転中心を保存したい場合はクラスターにする(ノード自身は回転中心を持たないため)
|
||||||
|
|
||||||
**外部連携での扱い**:
|
**外部連携での扱い**:
|
||||||
|
|
||||||
@@ -51,28 +67,28 @@ PHYレイヤーは、キースイッチやキーキャップ、その他周辺
|
|||||||
|
|
||||||
## 保存形式
|
## 保存形式
|
||||||
|
|
||||||
キーごとに絶対座標を持つ。
|
各ノードは親から見た変換を持つ。キーとクラスターを混在させた木構造として保持する。
|
||||||
全てのキー、またはキー及びクラスターをまとめたクラスターを配列として持つ
|
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
type Position={
|
type Transform = {
|
||||||
x:number,
|
x: number, // 親座標系での位置
|
||||||
y:number,
|
y: number,
|
||||||
w:number,
|
rotation: number // 親座標系での回転角度(度)
|
||||||
h:number,
|
|
||||||
rx:number,
|
|
||||||
ry:number,
|
|
||||||
ra:number
|
|
||||||
}
|
}
|
||||||
type Key={
|
type Size = {
|
||||||
position:Position,
|
w: number, // ローカル値。親の変換を受けない
|
||||||
profile:Profile
|
h: number
|
||||||
}
|
}
|
||||||
type Cluster={
|
type Key = {
|
||||||
position:Position,
|
transform: Transform,
|
||||||
clusters:(Key[]|Cluster[])
|
size: Size,
|
||||||
|
profile: Profile
|
||||||
}
|
}
|
||||||
const keys:(Key|Cluster)[]=[]
|
type Cluster = {
|
||||||
|
transform: Transform,
|
||||||
|
children: (Key | Cluster)[]
|
||||||
|
}
|
||||||
|
const root: (Key | Cluster)[] = []
|
||||||
```
|
```
|
||||||
|
|
||||||
## 連携用出力形式
|
## 連携用出力形式
|
||||||
@@ -186,3 +202,17 @@ interface ClusterData {
|
|||||||
3. **段階的移行**:既存のKLEユーザーが段階的に拡張機能を利用可能
|
3. **段階的移行**:既存のKLEユーザーが段階的に拡張機能を利用可能
|
||||||
4. **ツール間連携**:KLE標準形式での出力により、他のキーボード設計ツールとの相互運用性を確保
|
4. **ツール間連携**:KLE標準形式での出力により、他のキーボード設計ツールとの相互運用性を確保
|
||||||
5. **データの軽量化**:KLE出力時に不要な情報を含めず、ファイルサイズを最小化
|
5. **データの軽量化**:KLE出力時に不要な情報を含めず、ファイルサイズを最小化
|
||||||
|
|
||||||
|
## 検討済み・非採用
|
||||||
|
|
||||||
|
- キーごとの絶対座標保持 (journal/2026-09-18-phy-coordinate-model.md)
|
||||||
|
- 相対座標と絶対座標の併記 (journal/2026-09-18-phy-coordinate-model.md)
|
||||||
|
- ノードごとの回転中心パラメータ (journal/2026-09-18-phy-coordinate-model.md)
|
||||||
|
|
||||||
|
## 未確認事項
|
||||||
|
|
||||||
|
### P-1 KLE JSONへ書き出した配置が行のまとまりを保てるか
|
||||||
|
|
||||||
|
- 位置づけ: 本文が前提にしているものではない。連携用出力形式の設計に関わる未解決の問い
|
||||||
|
- 現状の認識: 階層を畳んでKLEに読み込ませると行のまとまりが崩れる。他レイヤーの情報を使ってでも行ごとにまとめたいが、方法は未検討
|
||||||
|
- 格上げ条件: 回転を含むPHYデータをKLE JSONに変換してKLE本家に読み込ませ、rotation groupと行配列がどう再構成されるかを確認する
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
# PHY座標モデル: 相対座標 + 回転中心パラメータなし
|
||||||
|
|
||||||
|
## 結論
|
||||||
|
|
||||||
|
- 各ノードは親から見た変換 (x, y, rotation) を持つ。絶対座標は保持しない
|
||||||
|
- 回転中心のパラメータは持たない。回転軸は常に自分自身のローカル原点
|
||||||
|
- Key も Cluster も同じ変換を持つ。per-key回転のためにクラスターを作る必要はない
|
||||||
|
- スナップ(0.25U / 15度)はローカル座標系での話
|
||||||
|
- w, h は Transform から分離する(親の変換を受けないため)
|
||||||
|
|
||||||
|
## 案の比較
|
||||||
|
|
||||||
|
### 座標系
|
||||||
|
|
||||||
|
| 案 | 利点 | 欠点 |
|
||||||
|
|---|---|---|
|
||||||
|
| 絶対座標 | KLEとの往復が素直。保存値がそのまま最終位置 | クラスターのpositionと二重管理になる。階層が実質的に選択範囲の記録にしかならない |
|
||||||
|
| 相対座標(採用) | クラスターの移動・回転が親1ノードの書き換えで済む | 畳む処理が要る。KLE再インポート時に逆変換で端数が出る |
|
||||||
|
| 相対+絶対を併記 | 読み出しに変換が不要 | 二重管理の問題がそのまま残る |
|
||||||
|
|
||||||
|
### 回転中心
|
||||||
|
|
||||||
|
| 案 | 利点 | 欠点 |
|
||||||
|
|---|---|---|
|
||||||
|
| ノードごとに回転中心を持つ(KLE方式) | 任意のピボットを保存できる | グループ回転で全キーが同じrx/ryを共有する必要がある。移動のたびに全キー更新 |
|
||||||
|
| 自分の原点に固定(採用) | パラメータが消え、式が Translate·Rotate だけになる | 共通ピボットを残したい場合はクラスターを作る必要がある |
|
||||||
|
|
||||||
|
## 根拠
|
||||||
|
|
||||||
|
### 絶対座標を採らない理由
|
||||||
|
|
||||||
|
キーが絶対座標を持つ状態でクラスターにも position があると、同じ情報が2箇所に存在する。
|
||||||
|
クラスターを回すときにクラスターの角度を書き換えるのか配下の全キーを再計算するのかが定まらず、
|
||||||
|
片方だけ更新されたファイルが生まれる。元の保存形式でクラスターの position の意味が
|
||||||
|
書かれていなかったのは、この行き場のなさが未解決のままだったためと思われる。
|
||||||
|
|
||||||
|
また絶対座標を正本にすると、入れ子構造は「選択範囲の記録」以上の意味を持たない。
|
||||||
|
それならフラット配列 + clusterId の方が構造として正直で、階層クラスターの要求と噛み合わない。
|
||||||
|
|
||||||
|
畳んで絶対座標にする処理は KLE出力・PCB出力のためにどのみち必要。
|
||||||
|
絶対座標を正本にしてもクラスター操作のために逆方向が要るので、結局両方向を書くことになる。
|
||||||
|
|
||||||
|
### per-key回転とクラスター数
|
||||||
|
|
||||||
|
平面上の剛体配置の自由度は、位置2 + 向き1 = 3。
|
||||||
|
ノードが (x, y, rotation) を持つならちょうど3自由度なので、どんな配置でも
|
||||||
|
全キーを同じ親の直下に並べて表現できる。キーごとに角度が違ってもクラスターは増えない。
|
||||||
|
|
||||||
|
当初 Alice を per-key回転の例として挙げたが、Alice は左右のアルファ部がそれぞれ一体で傾いた
|
||||||
|
2クラスターであり、per-key回転の例ではない(ユーザーによる訂正)。
|
||||||
|
代わりに GRIN系 の指摘があったが、実際のジオメトリを確認していないため保留。
|
||||||
|
上の自由度の議論は形状に依存しないので、結論は変わらない。
|
||||||
|
|
||||||
|
### ピボットは編集操作の状態であってデータではない
|
||||||
|
|
||||||
|
ピボットは「θを変えたとき何が動かないか」を決めているだけで、
|
||||||
|
結果として得られる配置は (x, y, rotation) で表現できる。
|
||||||
|
扇状配置のような共通ピボットは、エディタ側の操作として結果の数値を焼き込めばよい。
|
||||||
|
後から開き具合を編集し直したい場合だけ、その扇をクラスターにする(クラスター原点 = ピボット)。
|
||||||
|
ピボットを永続データとして持つと、KLE の rotation_x / rotation_y と同じものになる。
|
||||||
|
|
||||||
|
### row/col への影響
|
||||||
|
|
||||||
|
放射状に並べるとrowの概念が崩れるのではないかという懸念があったが、
|
||||||
|
PHYレイヤーはrow/colを扱わないため問題にならない。
|
||||||
|
matrix情報は任意の付加情報で、正本はIDX/ELC側にある。幾何がmatrixに制約されることはない。
|
||||||
|
KLEでrowが崩壊するのは物理配置から論理的な行を推定しているためで、
|
||||||
|
その推定をやめることがレイヤー分離の目的そのもの。
|
||||||
|
|
||||||
|
## 捨てた案
|
||||||
|
|
||||||
|
- 相対座標を正本にしつつ絶対座標をキャッシュとして併記する。二重管理の問題が再発する
|
||||||
|
|
||||||
|
## 未決のまま残したもの
|
||||||
|
|
||||||
|
- KLE出力時に行ごとにまとめたいという要求。方法未検討のため未確認事項として残した
|
||||||
|
- Key.profile を実体で持つか参照IDで持つか。今回の決定の範囲外なので元のまま Profile 実体を残した
|
||||||
Reference in New Issue
Block a user