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

## はじめに

本稿は[SVG Advent Calendar 2015 - Adventar](http://www.adventar.org/calendars/731)の19日目の記事です。

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


## コードゴルフに役立つTips

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

## プリミティブな図形

### 円

![circle.png](https://qiita-image-store.s3.amazonaws.com/0/6117/f331e3ed-3535-7277-a885-6dd5f545783a.png)
[円 :SVGコードゴルフ - jsdo.it](http://jsdo.it/butchi/AHdN)

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

#### 代替記述
```svg:circle_by_rect.svg
<svg><rect cx=55 cy=55 rx=55 ry=55 width=55 height=55 /></svg>
```

### 楕円

![ellipse.png](https://qiita-image-store.s3.amazonaws.com/0/6117/947b3be7-5b3a-bce3-5c9d-324c690d1e95.png)
[楕円 :SVGコードゴルフ - jsdo.it](http://jsdo.it/butchi/QiF0)

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

### 長方形

![rectangle.png](https://qiita-image-store.s3.amazonaws.com/0/6117/094c5dd6-acd2-9a55-ca9d-529584234252.png)
[長方形 :SVGコードゴルフ - jsdo.it](http://jsdo.it/butchi/Mhss)

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

#### 代替記述

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

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

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

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

### 菱型

![rhombus.png](https://qiita-image-store.s3.amazonaws.com/0/6117/0d028332-37d0-aa4d-a7d0-94bd2fd32007.png)
[菱型 :SVGコードゴルフ - jsdo.it](http://jsdo.it/butchi/ALrD)

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

### 線分

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

![line.png](https://qiita-image-store.s3.amazonaws.com/0/6117/ee276b5e-4ce2-1756-4c53-01c104ae3257.png)
[線分 :SVGコードゴルフ - jsdo.it](http://jsdo.it/butchi/oi7v)

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

#### 代替記述

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

```svg:line_by_line.svg
<svg><line x2=89 y2=0 stroke=red /></svg>
```

```svg:line_by_path.svg
<svg><path d=M0,0H89 stroke=red /></svg>
```


### 放物線

![parabola.png](https://qiita-image-store.s3.amazonaws.com/0/6117/36ce45a2-3cd4-f8a1-7a9e-e03174dcacb9.png)
[放物線: SVGコードゴルフ - jsdo.it](http://jsdo.it/butchi/Ma4S)

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

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


## 正多角形（近似）

### 正3角形

![triangle_approximate.png](https://qiita-image-store.s3.amazonaws.com/0/6117/3384f8c9-92eb-e08a-c131-8cad280d8d98.png)
[正3角形（近似） :SVGコードゴルフ - jsdo.it](http://jsdo.it/butchi/y3pa)

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


### 正4角形（正方形）

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

### 正5角形

![pentagon_approximate.png](https://qiita-image-store.s3.amazonaws.com/0/6117/4cebc910-ed0f-7101-0fa1-6c132e4cce4f.png)
[正5角形（近似） :SVGコードゴルフ - jsdo.it](http://jsdo.it/butchi/W1jL)

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

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

## 正多角形（厳密）

### 正3角形

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

![triangle_exact.png](https://qiita-image-store.s3.amazonaws.com/0/6117/3bbbbf87-5ece-b99d-bbb0-d79e3f96b48e.png)
[正3角形（厳密） :SVGコードゴルフ - jsdo.it](http://jsdo.it/butchi/eqB7)

```svg: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](http://www.w3.org/TR/SVG-Transforms/)

[Coordinate Systems, Transformations and Units — SVG 2](http://www.w3.org/TR/SVG2/coords.html)

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

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

### 正4角形（正方形）

![square.png](https://qiita-image-store.s3.amazonaws.com/0/6117/c0db8ed6-e513-adfe-857b-598ac75f3dc9.png)
[正方形: SVGコードゴルフ - jsdo.it](http://jsdo.it/butchi/klTb)

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

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

#### 代替記述

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

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

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

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


### 正5角形

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

### 正6角形

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

### 正7角形

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


## 最後に

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