入力ソースを設定するコマンドを作った
Mac OS Xの入力ソース(ことえりやGoogle日本語入力など)をCUIで設定(有効/無効/選択)できるコマンドを作った→https://github.com/minoki/InputSourceSelector
入力ソースをいじるには、Mac OS X 10.5以降であればCarbonのText Input Source Servicesを叩けばいい。入力ソースのID(例:com.apple.inputmethod.Kotoeri.Roman)から入力ソースを取得するにはTISCreateInputSourceListを呼び出す。この関数は名前の通り入力リストのリストを返すが、第一引数にプロパティリストを渡す事で入力ソースを絞り込む事ができる。帰ってきたCFArrayRefから入力ソース(TISInputSourceRef型)を取得しTISEnableInputSourceやTISSelectInputSourceを呼び出せば、それぞれ入力ソースを有効化、選択できる。
プログラム中でTISCreateInputSourceListから帰ってきた入力ソースの配列を走査するのにFast Enumerationを使っているが、TISInputSourceRef型はObjective-Cのid型と互換性がないため、ループを
for (TISInputSourceRef inputSource in inputSources) {
...
}
と書くことはできない。しかし、__attribute__((NSObject))を使えばid互換の型として扱ってくれるようだ。
for (TISInputSourceRef __attribute__((NSObject)) inputSource in inputSources) {
...
}
さて、このコマンドの使い方だが、
$ InputSourceSelector list
と打てば入力ソースのIDと名前の一覧が表示される。list-enabledとすれば現在有効になっている入力ソース飲みが表示される。これで調べたIDに対して
$ InputSourceSelector enable (調べたID)
と打てばその入力ソースが有効化される(右上のメニューの入力ソース一覧に現れる)。また、
$ InputSourceSelector select (調べたID)
と打てばその入力ソースが現在の入力ソースとして選択される。
Asymptoteで立体の輪郭を描く(2)
前回、Asymptoteを使用して球を描いた。その時の図をよく見ると、点 \((0,0,1)\) が球の輪郭に接しているのが分かる。視点がXY平面の上側にあることを考えると、これはおかしいのではないか。実際、次のようにコードを変更して再描画すると、描かれる輪郭と球の輪郭が一致しないことが分かる:
// 球(回転体)の輪郭を描く
// longitudinalbackpenは球の下半分のペンを指定するようだ
draw(s,m=11,longitudinalbackpen=currentpen+solid);
ソースコードの該当部分はbase/solids.asyの280行目以降で定義されているrevolution.longitudinal()なのでこれを修正すればいいのだが、そんな面倒なことをしなくても立体の輪郭の描画にrevolution.silhouette()を用いれば良い。
// 球(回転体)の輪郭を描く
// longitudinalbackpenは球の下半分のペンを指定するようだ
draw(s.silhouette());
draw(s,m=11,longitudinalpen=nullpen,longitudinalbackpen=nullpen);
ただしこの場合
warning [2Dsilhouette]: silhouette routine is intended only for 2d projections
という警告が出る。本来はやはり前回のようにdraw()を使って描画するべきなのだろう。しかし、なぜsilhouette()は問題ないのにlongitudinal()はバグ持ちなのだろうか。もしかして、これは意図した動作だったりするのだろうか。謎だ。
Asymptoteで立体の輪郭を描く
最近、Asymptoteをいじっている。奥村先生の美文書作成入門で紹介されていたので試したところ、なかなか良さそうだったからだ。しかし、どうにもドキュメントが足りない。付属のドキュメントを読めば簡単な図は描けるようになるが、もっとやり込もうとするとリファレンスマニュアルが欲しくなる。ソースコードは割ときれいでコメントもついているのでそれを読めばいいのだが。
今回はこんな図を描いてみた:
import three;
import solids;
size(500);
currentprojection=orthographic(5,4,2,center=true);
currentpen=black+2.0;
// 中心O,半径1の球
revolution s = sphere(O,1);
// 球(回転体)の輪郭を描く
// longitudinalbackpenは球の下半分のペンを指定するようだ
draw(s,m=1,longitudinalbackpen=currentpen+solid);
// x,y,z軸を描く
draw(O--2X,Arrow3);
draw(O--1.8Y,Arrow3);
draw(O--1.3Z,Arrow3);
label("$x$",1.6X,NW,currentpen+fontsize(30pt));
label("$y$",1.3Y,S,currentpen+fontsize(30pt));
label("$z$",1.1Z,NE,currentpen+fontsize(30pt));
real phi = pi/3, theta = pi/4;
triple H = (cos(phi),sin(phi),0);
triple P = expi(pi/2-theta,phi);//(cos(phi)*cos(theta),sin(phi)*cos(theta),sin(theta));
// 原点Oから点H,Pに直線を引く
draw(O--H);
draw(O--P);
label("$P$",P,NE,fontsize(20pt));
label("$H$",H,S,fontsize(20pt));
/*
dot(X);
dot(Y);
dot(Z);
dot(P);
*/
draw(arc(O,H,Z));
draw(arc(O,0.3X,0.3H));
draw(arc(O,0.3P,0.3H));
label("$\varphi$",0.3*(cos(phi/2),sin(phi/2),0),S,fontsize(20pt));
label("$\theta$",0.3*expi(pi/2-theta/2,phi),E,fontsize(20pt));
球を描くのに使っているrevolution(回転体)という型はsolidsモジュール(ソースコードのbase/solids.asy)で定義されている。次に呼び出しているdraw関数のオーバーロードもそこで定義されていて、コメントとシグニチャを示すと
// Draw on picture pic the skeleton of the surface of revolution r.
// Draw the front portion of each of the m transverse slices with pen p and
// the back portion with pen backpen. Rotational arcs are based on
// n-point approximations to the unit circle.
void draw(picture pic=currentpicture, revolution r, int m=0, int n=nslice,
pen frontpen=currentpen, pen backpen=frontpen,
pen longitudinalpen=frontpen, pen longitudinalbackpen=backpen,
light light=currentlight, string name="",
render render=defaultrender, projection P=currentprojection)
となる。
expi関数はC++で実装されているようで、triple.hのtripleクラス内で
// Returns a unit triple in the direction (theta,phi), in radians.
friend triple expi(double theta, double phi)
{
double sintheta=sin(theta);
return triple(sintheta*cos(phi),sintheta*sin(phi),cos(theta));
}
と定義されている。
去年の反省・今年の抱負
新年になりました。本年も当ブログをよろしくお願い致します。といっても、昨年は12本しか記事を書いていませんが…(←一昨年のちょうど半分)
去年やったこと:
- 大学に入った
無事、志望する大学に合格した。 - のに伴い東京に引っ越した
- 競技プログラミングに興味を持った
大学でプログラミングコンテストに挑戦する授業を取ったのと、Google Code Jam Japanに参加した(結果はいまいち)。今年はICPCやその他のプログラミングコンテストに参加するかもしれない。 - LATEX使い始めた
本を買って本格的に勉強することにした。
去年できなかったこと:
- wxWidgetsのInput Method対応
やろうやろうと思いながら結局まだできていない。時間が取れない、実装が(今の自分にとって)難しいというのもあるが、英語で自分の意図を伝えることの難しさも感じた。
大学に入って以降は、ソフトウエア開発に使える時間がなかなか確保できなかった。時間の捻出方法を工夫しないといけない。勉強に充てる時間、サークルの活動に充てる時間、ソフトウエア開発に充てる時間のバランスを取らないといけない。
今年やりたいこと:
- wxWidgetsのInput Method対応
- Mac向けのアプリを作って出す
実は今、必要性に駆られてとあるアプリケーションを作っている。公開できるだけの完成度に達すれば、Mac App Storeで出すかもしれない。といっても、かなりニッチな用途なので、必要とする人は少ないだろう。 - スマートフォン向けのアプリを作って出す
ネタがあれば出したい。
Google Code Jam Japan予選
Google Code Jam Japanの予選に参加した。
のんびり昼食をとっていたら13時を過ぎていた。とりあえずAから取りかかることにする。問題を読んで把握。制約を見るとLargeの場合が1≤M≤109とか書いてあったので、まともに配列を作っていては時間が足りないと判断(実際どうなんだろうか)。求めたいのは1枚のカードだけだったので、そのカードだけに注目して考えることにした。取りかかってから15分程度でクリア。
次にBを見る。面倒そう。貪欲法でいけるかと思ったが、満足度がコーヒーごとに違うのに気づいて考え直す。Smallの規模なら全探索で大丈夫そうなので、とりあえず全探索する。30分程でSmallをクリア。
BのLargeは後回しにして、Cに取り組む。Smallは全探索で行けそう。10分足らずでSmallをクリア。
CのLargeについて考える。1018は64ビット整数で表現できるようだ。一定のビットパターンをビットがなるべく多く立つような組み合わせで分割するには、と考えて解いた。考え過ぎだった面もあるようだが…30分ちょいでクリア。
BのLargeは、満足度も考えて貪欲法をしたら通った。最終日から逆に考えて、その日飲めるコーヒーのうちもっとも満足度の高いものを飲む。
結果は、54点で上位50位以内に入った。ただ、予選だからといって1問しか解かなかった人やのんびり時間をかけて解いた人がいるかもしれないので、決勝ではどうなるか分からない。
