12「結び目」の図を簡単に描きたいJavaScriptNode.jsSVG「結び目」についてこの記事でいう「結び目」というのは、一つの閉じた円環がどのように絡まっているかを分類したものです。参照:結び目理論(Wikipedia)「結び目」に関する文書などを書く際に、簡単に結び目の画像を描くことが出来ないかと考えて、調査してみたことと合わせて記事を書いてみたいと思います。今回の記事は、計算によって曲線を生成する、ということに着目したもので、「結び目理論」とは本質的に関係がありません。「交叉」している部分以外は、各グラフィックツールで閉曲線を描くことになるので省略します。「交叉」している部分の描き方は様々な方法があると思いますが、今回は以下のようなやり方で表現しています。曲線を上手に描くのが難しい多くのグラフィックツールでは曲線を描く場合に、「ベジェ曲線」を使用して編集します。多数の点を滑らかに通過するような曲線を手作業で描くのは、ツールに慣れていないとなかなか骨が折れる作業です。前述した「交叉する部分」の編集は単純ながら、グラフィックツールを使って手作業で行うのはなかなか面倒です。結び目が複雑になってくると、この交叉する箇所が多くなり編集時間や間違いの可能性が増えることが予想されます。自動的に描くために今回は、指定した点を通り、SVGを使って滑らかな曲線を表現する調整を計算により求め、また、交叉する部分のSVG編集を同時に行う、ということを目標とします。入力は、グラフィックツール(Inkscapeを使用)により作成したSVGとして、下記のようなSVG画像を出力します。基本の3次Bezier曲線SVGでサポートされている曲線で、簡単な計算式によって様々な形の弧からなる曲線を描くことができます。1)このベジェ曲線の複数の弧を使って、指定した点を通る曲線を生成します。Catmull-Rom曲線Bezier曲線を使って、指定した点を滑らかにつなぐには上記の$P_1$、$P_2$を別途計算することが必要になります。今回はCatmull-Rom曲線というものを利用して、Bezier曲線を生成しました。(Wikipedia)この曲線はBezier同様に簡単な式で表現できる上に、3次Bezier曲線と相互に変換することが可能です。入力として与えられた点を通るCatmull-Rom曲線をBezier曲線に変換することで、SVGの基本機能のみで描画することが可能になります。求める変換式は、下のようになります。作業、および計算処理の流れ直線で概形を描く(手作業)最初に入力するSVGファイルを作成します。このファイルを作る際に、下記の制限を設定しています。制限1:2つの線分が交叉する場合は端点以外の場所で交叉する制限2:全体として1個の閉じた曲線を構成する作成した曲線(線分で構成された閉曲線)をSVGファイルとして保存し、プログラムの入力とします。SVGファイルを読み込み、path要素内のd属性を見つける以下、node.jsを使用して作成したものについて説明します。上記のSVGドキュメント内に存在するpath要素のd属性を読み込みます。ここでは、jsdomを利用してSVGをDOMとして扱っています。.getAttribute("d");path要素のd属性を解析して頂点を求めるpath要素のd属性には、SVGの描画命令文が格納されています。命令文を解析して座標を計算し、頂点として必要なものを抽出します。描画命令文の例)今回は、MoveTo命令とLineTo命令のみを読み取れば良いので、ごく簡単な解析で済ませています。(以下略、必要であれば後述のソースコードを参照してください)交叉する弧を見つける全ての2つの線分の組み合わせについて、「交叉するか否か」を判断し、その情報から配列を生成します。後の工程で曲線の弧が「上を通る」か「下を通る」かを切り替える場所となります。「入力の線分が交叉するなら、生成するCatmull-Rom曲線の弧が交叉する」、また「線分が交叉しないなら、弧は交叉しない」という前提です(その前提が成立するように入力用SVGファイルを作成する必要があります)。false;}Catmull-Rom曲線をSVGのBezierで描く前述の変換式を使って、Catmull-Rom曲線を生成するBezire曲線の各点を求めます。bezierNode;}交叉部分を作る生成されたCatumull-Rom曲線(SVG内ではBezier曲線で表現)の弧で交叉する部分を作ります。g要素をレイヤーとして用いることによって、基本的には手作業で作成したのと同じ表現方法です。出力jsdomのDOMを利用して全体をSVGドキュメントとして完成し、最終的にテキストとして出力して終了です。document.body.innerHTML;}完成したもの以上を、コマンドラインから使用できるプログラムとして作成したものをGitHub上にまとめました。output.svg生成したSVGドキュメントは標準出力に表示されます。今のところ、Inkscapeで作成したSVGでのみ動作を確認しています。今回の記事の内容のデモンストレーションが目的であって、あまり汎用的なツールとなることを目的とはしておりません。動作不良などは悪しからずご了承ください。(8の字結び)まとめ今回の調査の元々のきっかけは、様々なデータを可視化する際に、matplotlibやd3.jsを使ってカスタマイズした図を作るよりも、SVGなどの基本的な機能で描画したほうが手っ取り早く、見やすいものができるのではないか、という考えからSVGの基本機能を調査してみよう、というものでした。簡素ではあるけれども、「特殊な用途のための図」にぴったりのものがない場合に、ひとつの選択肢として考慮してみるのも良いと思います。用いたアルゴリズム構築事業を推進し、企業のAI活用を支援しているベンチャー企業です。2つの事業に関する先進技術の研究・開発も行っています。upLoginユーザーは見つかりませんでした。