Glowforgeの3Dレーザープリンターは木、革、アクリルなどから美しい製品を作り出します。Coregraphicsと他のiOS APIを利用することで、アプリのユーザーはGlowforgeに送ることができるベクターグラフィックを作成したり、操作したりすることができます。このトークではこれらの機能をSwiftを用いてどのように構築したか、そしてSwiftを用いることで私達のソリューションがどのようにより堅牢でエレガントで安全になったかを説明します。


ビルドをするとき、レーザープリンターを立ち上げる
Glouforgeは3Dレーザープリンター。iPhoneケースや額縁などがつくれる

写真からこんなふうに作れます

ベクタ絵も利用できます
これはコースター用


Web向けにはいろいろツールがあると思います。

SVGで画像を表示することがあると思いますが、それを超えると複雑な事が必要。
Glowforgeで私はその部分を担当しています。


Traceがお気に入りです。写真から、Traceを使って
この写真のなかで穴を開けて裏の素材をみせる


どうやるのでしょう。アプリで縁取りする


ピクセルを特定してボーダーをマーキング、ベジエパスで縁取りしていく。
Flood Fillingアルゴリズムを使っている。
たとえば

中心をタップすると白のピクセルを選択してくれる


Lという文字の縁取りができる。通常はピクセルは2Dになっていると思いますが、2DのArrayのピクセルは余り使わないので1DのArrayにする


2Dポイントにアクセスできなくなるので対応する

4*4だとします

Pixcelを行として特定する。2*4、そして+1
タッチするとIndexは9,これが1DArray中の位置。

SVGはこんな感じ。Groupタグが重要

6つ個々のViewになる。独立してインタラクション可能


穴とか、黒の領域があるので、プリントできる場所に持って活かせることができる


ベジエパスを描画してboundingをとってframeをつかって描画

それぞれOriginが定義されている。これに基づいてPNGを描画できる。Transformが重要、丸の真ん中に配置させることができる


Drag Groupで独立して扱えるように
Drag Groupを表示する際はViewに入れる

LayerをVeiwに追加していく

LayerをPathから追加していく。
ただ予想外のことが
ずれてしまった

先程、猫の目の中をタップしてふちどりました。ぴったり領域にハマっていたが、ここではハマっていない
なぜか

Layer Frameがあって、もともとはこうなっていた。この位置というのは、もともとのSVGファイルのための場所だった。

目の中にうまくハマるポジションに移動させる。Origin Point - 1という形で計算します、それを使ってトランスレーションを活用してTransformをかける
うまくはまりました

イメージの話です

プロパティとしてこれらがあります。表示にはImageViewを使います


Viewが手に入ったらDragGroupViewを適用
でもどうでしょう

かなり丸からずれてしまっています。
Transformのプロパティはこのように定義されています

これが理由です

15度右に回転させます、そううるとこういう形で出てくるのが期待されるが、SVGの中ではOriginの周りで回転するので、違いはかなり大きくなります。
これをどう修正したら良いでしょう

iOSでは中心、SVGではOrigin.回転軸を中心に移動して、PointをOriginに戻してやる
このExtensionを作りました


Viewの中のTransformationはこのような形になります
コースターはこのような見た目になりました。

安全性を重視しています。レーザーを扱っているので。

祖父からもらった素材があったが、2回も壊すことは出来ない。大切に扱わなくてはいけない。
アプリは、バグがあったら修正してもう一度再起動すればいいが素材の場合層は行かない。
ValueTypeをつかい、不要な、もしくは予期せぬ変化が起きないようにした。
Abstranctions、独立して使えるようにそれぞれテストしていくことが重要、Transformationは独立して起きる。
Testing テストされていないコードは不完全なコードです、非常に重要であると考えています。ユーザーの貴重な素材を破壊したくないので色々なテストを、独立して行い、統合のためのテストも行っている。

Glowforgeにおいてコードをテストする際に、いろいろなものを作ってビルドを確認するが、楽しい作業であると同時にストレスを溜めるものでもある。そのためにいろいろな素材を集めてやらなくてはならない。
なぜImageがPathの外にあるのかということを検索しても無い。
今日そういった違いをお見せすることができていれば幸いです。
