Skip to content

TortoiseCore: テキスト描画コマンド write() の検討(描画語彙に残る唯一の穴) #54

Description

@temoki

背景

#53 で Python turtle との差分を整理した結果、write()(テキスト描画)が描画語彙に残る
唯一の本質的な穴
であることが分かった。

このライブラリの描画コマンドは primitive なものに絞る方針で、「既存の primitive の
組み合わせで到達できるものは入れない」(組み合わせて考えるのは利用者、特に子供の仕事)
という基準で判断している。Python turtle にあってこちらに無いもののうち、
dot(size, color) の色引数、color(pen, fill)、circle(steps=) はいずれも組み合わせで
書けるので、入れないことに理由がある。

テキストだけは、どう組み合わせても到達できない。 だからこれは穴であり、primitive 側に
属する機能として検討する価値がある。

図にラベルを付ける、座標軸に数値を振る、作品にタイトルを入れる、といったことが現状
一切できない。

Python turtle の挙動(参考)

turtle.write("Hello", move=False, align="left", font=("Arial", 8, "normal"))
  • align: "left" / "center" / "right"
  • move: True なら書き終わりの位置にタートルが移動する
  • テキストは常に水平で、タートルの heading には追従しない
  • ペンの上下に関係なく描かれる

難しいところ

素直に入れられないので未着手になっている。論点は以下。

1. Core は Foundation のみ・Linux 対応

TortoiseCore にはプラットフォーム API が無い。フォントのメトリクス(各文字の送り幅、
ベースライン、カーニング)を解決する手段がそもそも無い。

2. 2 つのレンダラーが一致しない

  • TortoiseSVG の <text> は、閲覧環境にあるフォントで描画される。同じ SVG が別の
    マシンで違う幅になる
  • TortoiseUI の Canvas は実フォントでラスタライズする

同じコマンドが 2 つのレンダラーで違う見た目になり、ゴールデンテスト
(DrawingScenarioSVGTests / DrawingScenarioCanvasTests)が構造的に一致しない。

3. ワイヤーフォーマットが 2.x で凍結されている

フォントをどう持つか(family 名の文字列? サイズだけ? 何も持たない?)を一度決めたら、
2.x の間は変更できない。フォント名を持たせると、その名前のフォントが無い環境での
挙動まで仕様になる。

4. DrawingBounds が測れない

テキストの外接矩形が分からないと ViewportMode.autoFit が壊れる。文字を含む描画で
ビューが正しくフィットしなくなる。

方針の選択肢

A. 単線ベクタフォントを Core に内蔵する(推奨)

Hershey フォントのような線分の集まりで定義された単線フォントのデータを
TortoiseCore に持ち、write を内部的にストロークの集合として展開する。

  • ✅ Core 内で完結し、プラットフォーム API に依存しない → Linux OK
  • ✅ 2 つのレンダラーが同じストロークを受け取るので、見た目が完全に一致する
  • ✅ DrawingBounds が正確に計算できる(ただの線分なので)
  • ✅ 思想に合う。 タートルが線で文字を書くのであって、文字を貼り付けるのではない。
    出力が primitive(線)のままになる
  • ❌ 表現は限られる(書体を選べない、日本語は現実的でない)
  • ❌ フォントデータの分だけバイナリが増える
  • ❌ ライセンスの確認が必要

B. プラットフォームのフォントに委ねる

  • ❌ Linux で破綻する
  • ❌ SVG と Canvas で見た目が変わる
  • ❌ ゴールデンテストが書けない

C. Core は文字列とサイズだけ保持し、解決はレンダラーに任せる

  • ❌ SVG は閲覧環境依存のまま。同じ描画が環境によって変わる、という性質が
    「コマンドストリームは再現可能な記録である」という設計と衝突する

決めるべきこと

  • 方針 A / B / C のどれを採るか(A を推す)
  • A の場合: フォントデータの出典とライセンス
  • A の場合: 対応文字範囲(ASCII のみ? Latin-1 まで?)と、範囲外の文字の扱い
  • align / move を Python turtle に合わせるか
  • テキストをタートルの heading に沿って回転させるか(turtle は常に水平。
    ただしタートルが線で書くなら回転するほうが自然かもしれない)
  • 文字の色と太さは penColor / penWidth に従うのか、独立させるのか
  • ワイヤーフォーマット上の表現({"write":{...}} のペイロード)

優先度について

需要が実際に出ているわけではないので急がないが、描画語彙に残る唯一の穴であり、
新しい描画コマンドの追加を検討するときは常にこれが最優先候補になる、という位置づけ。

関連

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions