LoginSignup
7
8

More than 1 year has passed since last update.

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

Last updated at Posted at 2015-12-20

はじめに

本稿は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>

今回のプリミティブな図形の中では変わりダネですが、貴重な厳密解です。
stroke属性と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お待ちしています。

7
8
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
8