SVGの作図問題とコードゴルフ

  • 4
    いいね
  • 4
    コメント

はじめに

本稿はSVG Advent Calendar 2015 - Adventarの19日目の記事です。

SVGで特定の図形を描くための最小コード(→コードゴルフ)って考えられているのか、という疑問から始まり、
数学の作図問題のような厳密な記述が可能なのか(どのみち描画段階で丸められるのでしょうが)気になってしまい、ある程度頑張るに至りました。

コードゴルフに役立つTips

  • <svg>タグの属性は全削り可能
  • <svg>の閉じタグ(</svg>)は省略しても動作するが、HTML5の文法には違反(一応HTML的にvalidなものを目指します)
  • svg要素内の図形要素は閉じタグ不要
  • 上述の通り図形要素は閉じタグ不要だが、その場合"/"で終える必要あり(例: <path d="…" />)(※要出典)
  • 属性のダブルクォーテーションは一定の条件下で省略可(※要出典)
  • ダブルクォーテーションを省くため、スペースを回避する"+"や","が有用(参考 Thanks @rikuo
  • HTMLに埋め込む際のSVG要素のデフォルトサイズは300px×150px。(参考
  • pathを使うときはHコマンドとVコマンドを使うとかなり短縮できる
  • 塗りの場合、pathは最後にZコマンドを付けなくても閉じてくれる
  • pathの小文字コマンドは相対指定になり、役立つと思った割には現時点では活躍しなかった

プリミティブな図形

circle.png
円 :SVGコードゴルフ - jsdo.it

circle.svg
<svg><circle cx=55 cy=55 r=55 /></svg>

代替記述

circle_by_rect.svg
<svg><rect cx=55 cy=55 rx=55 ry=55 width=55 height=55 /></svg>

楕円

ellipse.png
楕円 :SVGコードゴルフ - jsdo.it

ellipse.svg
<svg><ellipse cx=89 cy=55 rx=89 ry=55 /></svg>

長方形

rectangle.png
長方形 :SVGコードゴルフ - jsdo.it

rectangle.svg
<svg><path d=M0,0H89V55H0 /></svg>

代替記述

rectangle_by_rect.svg
<svg><rect width=89 height=55 /></svg>

<rect>は短く書けそうでいて、<path>には及びませんでした。

rectangle_without_h-or-v.svg
<svg><path d="M0,0L89,0L89,55L0,55Z" /></svg>

HコマンドとVコマンドを使わないとこれだけ長くなってしまいます。

菱型

rhombus.png
菱型 :SVGコードゴルフ - jsdo.it

rhombus.svg
<svg><path d=M0,34L34,0L68,34L34,68 /></svg>

線分

線分といってもrect要素なのでちょっと頓智ではありますが。

line.png
線分 :SVGコードゴルフ - jsdo.it

line.svg
<svg><rect width=89 height=1 /></svg>

代替記述

こっちなら正しい線分ですが、
これらの描き方だとy座標が0なので水平線の上半分がなくなってしまいます。

line_by_line.svg
<svg><line x2=89 y2=0 stroke=red /></svg>
line_by_path.svg
<svg><path d=M0,0H89 stroke=red /></svg>

放物線

parabola.png
放物線: SVGコードゴルフ - jsdo.it

parabola.svg
<svg><path d=M0,0Q17,55+34,0 stroke=red fill=none /></svg>

今回のプリミティブな図形の中では変わりダネですが、貴重な厳密解です。
storoke属性とfill属性は避けられませんでしたが、色指定を申し訳程度にred(他に3文字の色は"tan"のみ?)として削っています。

正多角形(近似)

正3角形

triangle_approximate.png
正3角形(近似) :SVGコードゴルフ - jsdo.it

triangle_approximate.svg
<svg><path d=M0,0H52L26,45 /></svg>

正4角形(正方形)

これは厳密な描画が可能なので、後述を参照してください。

正5角形

pentagon_approximate.png
正5角形(近似) :SVGコードゴルフ - jsdo.it

pentagon_approximate.svg
<svg><path d=M0,77V18L56,0L90,48L56,95 /></svg>

今回気合が足りず、手抜きです。

正多角形(厳密)

正3角形

今回のヤマです。(無理数を座標指定することが不可能と判断し、3次元の変形をするに至りました。)

triangle_exact.png
正3角形(厳密) :SVGコードゴルフ - jsdo.it

triangle_exact.svg
<svg><path d=M0,0H68L34,68 style=transform:rotateX(30deg) /></svg>

解説

厳密に正3角形を書くためには無理数の座標指定か無理数のscaleをかけるなど、
SVGの文法で不可能な方法しかありません。
calcを使っても平方根は求められません。

それを克服するために3D変形を使ってみました。
底辺2、高さ2の3角形を平行投影で30度奥に傾ければ、高さ(=2)に相当する辺は見た目として高さ√3に縮小されます。

transform属性に3D指定ができるのはSVG2以降のようです(まだ草案)。

SVG Transforms 1.0, Part 2: Language

Coordinate Systems, Transformations and Units — SVG 2

モダンブラウザーではWebKitのみ、CSSのtransformプロパティにまだベンダープレフィックスが必要な環境がありますが、いずれなくなることを期待してベンダープレフィックスは付けませんでした。

参考:
ベンダーprefix(-webkit/-moz/-o/-ms)の要否まとめ 2015/6 [無料ホームページ作成クラウドサービス まめわざ]

正4角形(正方形)

square.png
正方形: SVGコードゴルフ - jsdo.it

square.svg
<svg><path d=M0,0H89V89H0 /></svg>

テクニックは長方形の時と同様です。

代替記述

square_by_rect.svg
<svg><rect width=89 height=89 /></svg>

↑ 長方形のとき同様、<rect>は短く書けそうでいて、<path>には及びませんでした。

square_without_h-or-v.svg
<svg><path d="M0,0L89,0L89,89L0,89Z" /></svg>

↑ 長方形のとき同様、HコマンドとVコマンドを使わないとこれだけ長くなってしまいます。

正5角形

今回気合が足りず、未解決です。
描画可能ではあると予想しています。

正6角形

これも描画可能ではあると予想しています。

正7角形

これはもしかしたら不可能なのでは?と思っています。

最後に

上述のコードゴルフより短いコード、
正5角形、または特に正7角形の厳密描画、
その他有用な図形の描画等、コメントor DMお待ちしています。