OS X をアップデートするたびに Windows から Mac が見えなくなる現象

自分用メモです。

以下、SMBを使用する場合。

システム環境設定 → ネットワーク → 詳細 → WINS
で、共有名、ワークグループ名が OS X をアップデートするたびに消えるので、設定し直す。

Canvas3D によるルービックキューブ、そして日本の教育について

Canvas3D によるルービックキューブのその2です。
前回は話を簡単にするために、「クリックされた面さえ分かれば回転させるのは容易」と書きましたが、実際は少し問題がありました。
と、言うのも、ドラッグされた方向(2次元)と、3次元の各軸とのなす角を知る必要があるからです。

cube2.png図をご覧下さい。細い矢印がX軸、太い矢印がドラッグ方向です。キューブの中心に原点があります。X軸は(3次元の)単位ベクトルで表すと(1,0,0)です。これを2次元に投射すると、カメラの位置によって様々な値を取り得るのですが、今回はその計算は省略して、とりあえず、図のように下向き45°で表示されているとしましょう。この場合、1/sqrt(2) = 0.707 ですから、X軸のベクトルは2次元で表すと(0.707, -0.707)です。
ドラッグ方向のベクトルは、開始点を (x1, y1)、終了点を(x2, y2)とすると、( x2 – x1, y2 – y1 )ですね。ここでは仮に(5,5)としておきましょう。

さて、この二つのベクトルのなす角を知るには「内積」を求めるのが一般的です。まずは、ドラッグ方向を単位ベクトルにしておきましょう。

a = sqrt( 5*5 + 5*5 )
= 7.07

xn = x / a
= 0.707
yn = y / a
= 0.707

ですから、(0.707, 0.707)ですね。

ベクトル A( xa, ya ) と B( xb, yb )のなす角は、

acos(〈A,B〉/ ||A||・||B||)

で求められます。acos はアークコサイン、逆余弦です。〈A,B〉が内積。
||A|| と ||B|| は、A と B のノルム、即ちベクトルの大きさであり、この場合はあらかじめ単位ベクトルに直しておきましたから必要ありません。

〈A,B〉 = xa * xb + ya * yb
= 0.707 * 0.707 + 0.707 * (-0.707)
= 0

この内積は二つのベクトルが平行なときに1、直交するときに0になりますので、この場合、ドラッグ方向はX軸に対して垂直、即ちX軸を中心に回転させようとしている、とめでたく判定できたわけです。
仮に内積が1に近い値ならば、X軸に対して水平、即ちZ軸を中心に回転させようとしているとわかります。

日本の教育

前回、この部分の説明を軽く流したのは、「内積」なんて高校で習うんだし、いちいち説明しなくても良いだろう、と思ったからです。
でも、よく考えてみると、こんなの忘れてますよね。実際私もこの間まで忘れてました。

なぜ忘れるのかというと、二つのベクトルのなす角を知ったからといって嬉しくも何ともないからです。「ふーん」としか思わない。

ですが、自分で3Dゲームを作ろうとすれば、嫌でも覚えざるを得ないし、たぶん、一生忘れません。

ですから、高校生にも、プログラミングさせたら良いのです。「数学なんて、何の役に立つの?」という子供の素朴な疑問に対する答えは、現代に於いて、「プログラミングに必要」というのが最も説得力があります。

日本の教育は詰め込み型だと批判されています。それに対して、詰め込みのどこが悪い? という再批判もあります。いずれにしろ最低限のことは詰め込まなければならないでしょう。かけ算九九を無理やり覚えさせるのはかわいそうなどといった議論は取り上げるまでもありません。
しかし、教育というものはある程度まで進むと、本人の自主性がなければ効果が上がらなくなります。殆どの人がベクトルの内積を忘れてしまうのも、何の役に立つか分からないからです。

資源の乏しい我が国に於いては、ITは今後最も有望な産業です。我が国を支える人材を育成するためにも、教育にプログラミングを取り入れるのは重要です。
ただ、先生方は苦労するかもしれません。歳を取ってからプログラミングをマスターするのは容易ではないからです。しかし、やって出来ないということはないはずです。聖職に身を捧げたならば、そのくらいの努力はして貰わなければなりません。

Canvas 3D によるルービックキューブ

Canvas 3D というライブラリがあります。JavaScript からグラフィックボードの機能を使えてしまうという恐ろしい代物です。これは面白い! ということで、早速使ってみました。

まだ、デザイン等が未完成ですが、一応プレイできます。ただ、残念ながら IE や Opera には未対応です。今のところ、Google ChromeFirefox でしか表示できません。

2015年5月16日追記: 現在ではIE 11 でもプレイできます。

cube1.png

※ 「ルービックキューブ」は株式会社メガハウスの登録商標です。

今回、幾つか気がついたことを備忘も兼ねて書き記します。

まず、Canvas 3Dでは Collada 形式の3Dモデルを標準としています。例えば、Shade では、10.5 から Collada 形式の出力に対応しましたが、残念ながら私が使っているのは 8.5 で、度重なるアップグレードの奨めもずっとスルーしてきたので、もはやアップグレードパス(2世代前までに限定)がない状態です。
そこで、Metasequoia を使ってモデリング(と言っても、単なる立方体)し、Vixar Motion で読み込んでから、最後に Collada で出力しました。
迂遠且つ若干の制限事項(リンクされた図形が表示されないなど)もありますが、まず Shade で obj 形式で出力し、それをメタセコで読み込み mqo で出力、そして Vixar Motion で Collada へ、というやり方も可能です。
尚、Canvas 3D では、バージョン2.2から立方体などのプリミティブ図形を内部で生成できるようになっています。従って、Collada の必要はなかったとも言えますが、テクスチャ貼りの自由度などの点で、やはり外部ツールでモデリングしてインポートする方が便利です。

クリックされた面の判定

20111001130822.pngこのようなゲーム的なプログラムでは、インタラクティブ性が肝要です。問題はクリックされた面をどうやって判定するかです。
実はC++によるルービックキューブの制作記事を公開されている方がいらっしゃって、大いに参考にさせていただいたのですが、この方の場合、全て自前で描画しているために、非常に高い技術が必要となるかわりに、クリックされた面を知るのは比較的簡単なようなのですね。一方、私の場合、表示はライブラリ任せなので、クリックされた場所がどの面にあたるのかを知る一般的な方法がありません。
仕方がないので、図のようにオブジェクトを(実際には非表示で)配置して、「このオブジェクトがクリックされたらこの面」という具合に判定することにしました。「え? クリックされたか知る方法はないんじゃなかったの?」と思われるかもしれませんが、違うのです。方法がないのはクリックされた「面」を知ることであって、どのオブジェクトがクリックされたかを知る API はちゃんとあります。面が分からなければ、ユーザーがどの軸に対してどの向きに回転させようとしているのか分からないので、この点は重要です。
(実はCanvas 3Dでは、最近の仕様変更で非表示のオブジェクトをクリック判定しないようになり、上記の判定法は不可能になりました。各小立方体をさらに面に小分けするなど、対応法は幾つか考えられますが、今回はライブラリのコードをハックして無理やり判定するようにしてしまいました。あまり良い方法ではありません)

6面完成しているかの判定

さて、面の問題が解決すれば、ドラッグによる回転は容易に実装できます。最後に残された問題は、6面完成しているかどうかの判定です。
「各小立方体が最初の位置に戻っていれば6面完成」ではありません。実は完成形には24のパターンがあり、その全てについて判定する必要があります。
サイコロで考えると分かりやすいです。今、1が上を向いています。つまり1の目が出ています。この状態で、4つの側面のどれが正面を向くかで4つのパターンがあることが分かると思います。全ての面について同じことが言えますので、6 * 4 = 24 パターンというわけです。
まあ、理屈は簡単なのですが、実際の判定には全てのパターンの回転行列を求める必要があります。手計算ではとてもやってられないので、Ruby の行列演算を使いました。例えば、次のような感じです。

require 'matrix'
y = -Math::PI/2
z = Math::PI
cos_y = Math.cos(y)
sin_y = Math.sin(y)
cos_z = Math.cos(z)
sin_z = Math.sin(z)
m1 = Matrix[[cos_y,0,sin_y,0],[0,1,0,0],[-sin_y,0,cos_y,0],[0,0,0,1]]
m2 = Matrix[[cos_z,-sin_z,0,0],[sin_z,cos_z,0,0],[0,0,1,0],[0,0,0,1]]
p m2 * m1

Y軸を中心に-90度、Z軸を中心に180度回転させる場合の回転行列を求めています。cos(-90)は 0、sin(-90) は-1、cos(180)は-1、sin(180)は0、と言う風に、0 や 1 が並びますから、そんなに難しい計算ではありませんが、手計算で24パターンもやるのは上述の通りかなり大変です。

こうやって求めた回転行列を使った、六面完成チェック関数が以下です。

function check(){
	var ok;
	var pos;
	var mat = [];
	mat[0] =   [1 ,0 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,0 ,1];
	mat[1] =   [1 ,0 ,0 ,0 ,0 ,0 ,1 ,0 ,0,-1 ,0 ,0 ,0 ,0 ,0 ,1];
	mat[2] =   [1 ,0 ,0 ,0 ,0,-1 ,0 ,0 ,0 ,0,-1 ,0 ,0 ,0 ,0 ,1];
	mat[3] =   [1 ,0 ,0 ,0 ,0 ,0,-1 ,0 ,0 ,1 ,0 ,0 ,0 ,0 ,0 ,1];
	mat[4] =   [0,-1 ,0 ,0 ,1 ,0 ,0 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,0 ,1];
	mat[5] =   [0,-1 ,0 ,0 ,0 ,0,-1 ,0 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,1];
	mat[6] =   [0 ,1 ,0 ,0 ,1 ,0 ,0 ,0 ,0 ,0,-1 ,0 ,0 ,0 ,0 ,1];
	mat[7] =   [0 ,0 ,1 ,0 ,1 ,0 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,0 ,0 ,1];
	mat[8] =   [0 ,1 ,0 ,0,-1 ,0 ,0 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,0 ,1];
	mat[9] =   [0 ,0 ,1 ,0,-1 ,0 ,0 ,0 ,0,-1 ,0 ,0 ,0 ,0 ,0 ,1];
	mat[10] =  [0,-1 ,0 ,0,-1 ,0 ,0 ,0 ,0 ,0,-1 ,0 ,0 ,0 ,0 ,1];
	mat[11] =  [0 ,0,-1 ,0,-1 ,0 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,0 ,0 ,1];
	mat[12] = [-1 ,0 ,0 ,0 ,0,-1 ,0 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,0 ,1];
	mat[13] = [-1 ,0 ,0 ,0 ,0 ,0,-1 ,0 ,0,-1 ,0 ,0 ,0 ,0 ,0 ,1];
	mat[14] = [-1 ,0 ,0 ,0 ,0 ,1 ,0 ,0 ,0 ,0,-1 ,0 ,0 ,0 ,0 ,1];
	mat[15] = [-1 ,0 ,0 ,0 ,0 ,0 ,1 ,0 ,0 ,1 ,0 ,0 ,0 ,0 ,0 ,1];
	mat[16] =  [0 ,0,-1 ,0 ,0 ,1 ,0 ,0 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,1];
	mat[17] =  [0 ,1 ,0 ,0 ,0 ,0 ,1 ,0 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,1];
	mat[18] =  [0 ,0,-1 ,0 ,1 ,0 ,0 ,0 ,0,-1 ,0 ,0 ,0 ,0 ,0 ,1];
	mat[19] =  [0 ,0 ,1 ,0 ,0,-1 ,0 ,0 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,1];
	mat[20] =  [0 ,0 ,1 ,0 ,0 ,1 ,0 ,0,-1 ,0 ,0 ,0 ,0 ,0 ,0 ,1];
	mat[21] =  [0,-1 ,0 ,0 ,0 ,0 ,1 ,0,-1 ,0 ,0 ,0 ,0 ,0 ,0 ,1];
	mat[22] =  [0 ,0,-1 ,0 ,0,-1 ,0 ,0,-1 ,0 ,0 ,0 ,0 ,0 ,0 ,1];
	mat[23] =  [0 ,1 ,0 ,0 ,0 ,0,-1 ,0,-1 ,0 ,0 ,0 ,0 ,0 ,0 ,1];
	
	for( var m=0; m<24; m++ ){
		ok = true;
		loop:for( var i=0; i<3; i++ ){
			for( var j=0; j<3; j++ ){
				for( var k=0; k<3; k++ ){
					pos = c3dl.multiplyMatrixByVector( mat[m], things[i][j][k].getPosition() );
					
					if( pos[0] != (i-1)*20 || pos[1] != (j-1)*20 || pos[2] != (k-1)*20 ){
						ok = false;
						break loop;
					}
				}
			}
		}
		if( ok ){
			break;
		}
	}
	return ok;
}

0 と 1 がこれでもかと並んでますね(笑)
ちなみに、mat[0]はなにも回転しない場合で、本来必要ありませんが、美観のために入れてあります(笑)
ご覧のように Canvas 3D にも行列演算を行ってくれるユーティリティー(c3dl.multiplyMatrixByVector())があります。こちらは、Rubyと少し使い方が違って、要素数16の配列を渡すと、4行4列の行列として扱ってくれます。

WebGLは普及するか

Canvas 3Dは WebGLという技術を使用しており、この WebGL は、ネイティブアプリには劣るものの、グラフィックボードの機能を利用した、かなり本格的な3D表現が可能です。
今回使ってみた感触では、少なくともメタセコで作ったモデルを表示するまでは非常に簡単でした。「これならいくらでもゲーム作れるじゃん!」と、思わずドメインまで取ってしまいました( webglgame.jp )。
ところが、Microsoft は、自社の DirectX を推進する目的もあってか WebGL に反対していて、現在はもちろん、将来にわたって IE でのサポートは絶望的なようです。
折角の有望な技術が、最大シェアのブラウザでサポートされないばかりに廃れてしまうとしたら惜しいことです。幸い(?)、Google Chrome などのより先進的なブラウザに乗り換える人が増えていますので、この流れが加速することを祈るばかりです。
Opera や Safari でも、もうじき対応するとのことです。

関連記事:Canvas3D によるルービックキューブ、そして日本の教育について

ペンタブの幾何学

百聞は一見に如かず。次のダイアログをご覧下さい。

pen_tab.jpg

複数のモニタを使っている場合、殆どのペンタブレットで、全画面を移動できるようにするか、または一つのモニタの中だけに制限するか選べます。通常は後者を選びます。さもないと、移動できる領域が大変な横長になってしまい、手元の縦横比と画面上の縦横比が異なってしまうからです。仮に全画面を移動でき、且つ縦横比を固定するように設定すると、今度はペンタブ上の利用可能な領域が極端に少なくなってしまいます。

というわけで、領域はプライマリモニタ、縦横比は固定で使うのが常道なのですが、どういうわけか、今朝、全画面且つ縦横比は固定しないという設定(デフォルト)に戻ってしまっていました。

さて、その状態(モニタは二つ、いずれもアスペクト比は16:9、ペンタブは4:3)に於いて、右上から左下へ、45°の角度でペンタブ上に斜線を引くと、画面上では何度になるでしょう?

全画面のアスペクト比は 32:9、ペンタブは4:3、つまり 12:9 ですから、画面の方が 32 / 12 = 2.666…倍、横長です。

まず距離ですが、手元でルート2移動する間に、画面上では

sqrt( 2.666^2 + 1^2 ) = 2.847

移動しますから、

2.847 / 1.414 = 2.013

元より2倍強、長くなってしまいます。

そして、角度は

acos( 1 / 2.847 ) = 69.436 (度)

ですね。

まぁ、どうでもいいようなことですね(笑)

ところで、この記事を書いていて 16:9 のペンタブが欲しくなりました。が、近頃散財続きなので今の 4:3 のやつで我慢しようかと思います。

モニタのキャリブレーション

モニタを買いました。三菱RDT233WLXです。ついこの間にもiiyamaの27インチを買ったばかりですが、そちらはテレビ用に回し、今までデスクトップでセカンダリモニタとして使っていた三菱RDT178Sを退役させて、プライマリだったBenQをセカンダリに、新しく買った三菱をプライマリにしました。

001.jpg

KVM で Mac と切り替えて使っています。

002.jpg

そして、散財ついでに i1Display 2 を導入しました。

003.jpg

センサーを設置しているところです。マウスをぶら下げて遊んでいるわけではありません(笑)

残念ながら、この製品、28,000円と安物のモニタが買えてしまう値段の割には、ドライバが未署名でWindows7で使えない、設定アプリの表示が時々おかしくなる、といった難点があります。

もっとも、WindowsXP や Mac が使える環境なら特に問題ありませんし、Windows7であっても、起動時にF8を押して「詳細ブートオプション」を表示し、「ドライバー署名の強制を無効にする」を選択することで、一応使えます。

気に入ったのは、素早く客観的で正確なモニタ調整ができることです。それこそが存在意義ですから当然と言えば当然ですけどね。

モニタを設定する際に試行錯誤で延々とやるくらいなら、こういった製品を使って時間の節約をするのも良いのではないかと思います。タイムイズマネーです。

文字列反転日本語対応

先日の文字列をインプレイスで反転させるコードは、ASCII文字専用でした。
軽量言語では str.reverse() みたいな感じで多バイト文字でも簡単に反転できますが、C/C++ でやるとなると、かなり難しいです(私にとっては)。

まず、文字コードの判定から始まって、1バイト文字と多バイト文字の混在にも配慮しないといけないし、Shift_JISなどは2バイト目に’5C’が来るいわゆるダメ文字もあったりして、非常に厄介です。

まあ、しかし頭の体操には丁度よいのではないかということで、ぼちぼち書いてみたのが以下のコードです。

#include <stdlib.h>

char * revStr( char * str ){
	int len = strlen( str );
	char *buf;
	buf = (char *)malloc(sizeof(str));
	int j = 0;

	for( int i = len-1; i >= 0; i-- ){
		if (str[i]>=(char)0x00 && str[i]<(char)0x7F) {
			buf[j] = str[i];
			j += 1;
		}else if(str[i]>=(char)0xC2 && str[i]<=(char)0xDF){
			buf[j] = str[i];
			buf[j+1] = str[i+1];
			j += 2;
		}else if(str[i]>=(char)0xE0 && str[i]<=(char)0xEF){
			buf[j]= str[i];
			buf[j+1] = str[i+1];
			buf[j+2] = str[i+2];
			j += 3;
		}else if(str[i]>=(char)0xF0 && str[i]<=(char)0xF4){
			buf[j]= str[i];
			buf[j+1] = str[i+1];
			buf[j+2] = str[i+2];
			buf[j+3] = str[i+3];
			j += 4;
		}
	}
	buf[j] = '';
	return buf;
}

int main () {
	char *str = revStr("グンミーチャ デー リブラ!");

	printf("%s", str);
	free(str);

	return 0;
}

文字コードはUTF-8に決め打ちです。と言うのも、UTF-8は先頭が0x00…0x7Fだったら1バイト、0xC2…0xDFなら2バイトというふうに確定できるので、扱いやすいのです。そのかわり、仮名・漢字は1文字で3バイト、一部の記号は4バイトだったりします。

インプレイスを維持するのはさすがに無理でした。普通にバッファを確保しています。

次に Objective-C というか、Cocoa フレームワークを使ってみました。若干非効率になってしまってますが、バイト数だのに煩わされなくていいのでラクですね。

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
	NSMutableString *str = [NSMutableString stringWithString:@"まにわしらさぎ"];
	NSString *tmp;
	int len = [str length];

	for( int i = 0; i < len/2; i++ ){
		tmp = [str substringWithRange:NSMakeRange(i,1)];
		[str replaceCharactersInRange:NSMakeRange(i,1) withString:[str substringWithRange:NSMakeRange(len-i-1,1)]];
		[str replaceCharactersInRange:NSMakeRange(len-i-1,1) withString:tmp];
	}

	NSLog(@"%@", str);
	[pool drain];

	return 0;
}

スキルと才能、どっちが大事?

高名なプログラマ Joel Spolsky 氏は、経営する会社の面接試験に於いて、受験者に簡単なコードを書かせるそうです。その一つが「文字列をインプレイスで反転させる」というものです。
氏曰く、ほとんどの受験者が文字列のバッファをもう一つ割り当てて、そこに反転した文字を埋めていくのだそうです。しかし、それでは不合格です。インプレイスじゃないとダメなんです。
と、いうわけで、私も挑戦してみました。

int main () {
    char str[] = "the quick brown fox jumps over the lazy dog";
    int len = strlen( str );
    for( int i = 0; i < len/2; i++ ){
        str[len] = str[i];
        str[i] = str[len-i-1];
        str[len-i-1] = str[len];
    }
    str[len] = '\0';

    printf( "%s", str );

    return 0;
}

いかがでしょう。

実行結果は

god yzal eht revo spmuj xof nworb kciuq eht

となります。
とりあえずこれで正解のはずですが、もっとエレガントな書き方を思いつかれた方はぜひご教示ください。

印象深いのは、Spolsky 氏が「求めているのは才能に溢れた人物であり、特定のスキルを持った技術者ではない」と述べていることです。日本ではその特定のスキル、殊に資格が重視されるのと好対照ですね。
かつて日本企業のお偉いさん達は口をそろえて「我社の財産は人材です」と言っていたものです(そして、甲陽軍鑑を引用して「人は石垣、人は城!」と得意気に付け加えていたものです)。
それが今では「才能? そんなわけのわからんものより具体的なスキルだ」などとおっしゃる。人材派遣が流行るのも道理です。
その考えも分からないことはありません。即戦力はどこの現場でも欲しい。しかし、それだけではあまりに近視眼的と言わざるを得ません。

十分に賢く、物事を成し遂げるタイプの人を雇えば、どんなスキルであれすぐに身につけてくれる筈です。たまたま今特定のスキルを持っている人よりずっと頼もしいではありませんか。
将来を見据えて人材の採用、育成を行うことが、結局は企業が生き残るための一番の方法です。

成功を恐れる人々

弱虫は、幸福をさえおそれるものです。綿で怪我をするんです。
太宰治『人間失格』

 

オリコンがスマートフォン向けの音楽配信サービスを「強化」し、一曲の中心価格は450円とのことです。

450円!

いくらなんでも高すぎですよね。Apple が105円でやっていることをオリコンが450円でやって、通用するとは思えません。

結局、彼らには勝つ気がないということでしょう。失敗ではなく成功を恐れるというのは、個人においても組織においてもしばしば見られる心理です。Apple に対抗して100円前後にしてしまうと、既存の販路からやいのやいの言われてしまうので、ここは無難に450円、というわけです。

音楽業界も斜陽になってきたとはいえ、まだまだオリコンは大会社、下手なことをして火傷するよりは、安全圏でぼちぼちやっていこうという発想が透けて見えるような価格です。

しかしながら、傍から見れば、これが退嬰の道であることは明らかです。Apple に比して弱者であるオリコンが競争に勝つためには、少なくとも一点において Apple を凌駕していなければなりません(ランチェスターの法則)。価格で勝つのが無理ならば他の訴求点でも構わないので、とにかく「これだけは負けない」というのが何か無いといけない。それが見えてこないのです。

音楽業界に限らず、今、日本企業に元気がありません。円高、不況と逆風は強いですが、多くの消費者は本当は日本企業の製品・サービスを使いたいはずです。日本企業にお勤めの皆さん、どうか、勝つことを恐れず、惜しみなく勝って下さい。

外資系にお勤めの方は、たまには負けてみると視野が広がりますよ(笑)

小倉城

仕事で小倉には良く行くのですが、小倉城に寄ったのは10年ぶりです。JR小倉駅から徒歩15分くらいの、ごく近いところにあります。

小倉城

この前の萩などと違って、ここは観光地というよりは市民の憩いの場なので、カメラを持つ人も少なく、何となく撮影していて気恥ずかしかったです。

猫がいました。

猫