[GIS] ラスタ→STLを目指せ #2 右ネジ規則を確保する

id:yellow_7320130415 の続き。今回は「右ネジ」規則を確保する方法です。

STLは前述の通り「右ネジ」にしないといけませんが、場合によってはポイント順序を逆にしなければなりません。

外から見れば「左回り」

法線ベクトルは物体内側から物体外側に出て、右ネジになるので、外から表面を見た場合は「左回り」です。

ラスタだと逆になる

ラスタファイルの場合、左上から右下に向かう、左手系になることが多いです。

右手系だと(0,0)->(1,0)->(1,1)->(0,1)->(0,0)は左回りですが、

左手系だと(0,0)->(1,0)->(1,1)->(0,1)->(0,0)を右手系に変換したあとは、右回りです。


座標変換のパラメータ

ところで、GDALでは座標変換のパラメータを取得することができます。

double trans[6];

GDALGetGeoTransform(dataset, trans)

パラメータは次のように使います。

/* col, row はラスタのピクセル位置 */
x = trans[0] + trans[1] * col + trans[2] * row;
y = trans[3] + trans[4] * col + trans[5] * row;

このx,yは、普通は右手系になります*1

右手系・左手系の違いは行列式(たぶん)

だいたいY方向で逆転してX方向はそのまま、というのが多いんですが、TIFFなんかで回転が入ってきたりするとそのままでは対応できないので、行列式の方がいいと思う。

trans[1]*trans[5]-trans[2]*trans[4]

これが正なら右手系なのでポイントの順序はそのまま、負なら左手系なのでポイントの順序を入れ替え、とします。

*1:左手系を貫く空間参照系は知らないだけかも知れないので「普通は」としました

ラスタ→STLを目指せ #1 3点からSTLを書き出す

ここでいうSTLはStandard Triangulated Languageです。
ラスタの特定のバンドの値を高さ方向にとってSTLにしてしまおう、というもの。普通はラスタと言ってもDEMです。

STLの仕様は http://ja.wikipedia.org/wiki/Standard_Triangulated_Language 参照。

今回は、"facet"ブロックをひとつ出力してみましょう。

ふとどうすればいいのか分からないのが法線ベクトル。
三角形が仕様通り右ネジにそろっているとします。

右ネジにそろっているなら法線ベクトルは計算できます。たとえば http://zahyou.6.ql.bz/3db/gai.htm 参照。

/*
 * p = { x1, y1, z1, x2, y2, z2, x3, y3, z3};
 * で
 * (x1,y1,z1), (x2,y2,z2), (x3,y3,z3) が左回りになっているとします。
 */
void print_triangle(FILE *fp, double *p) {
  double v1x, v1y, v1z, v2x, v2y, v2z;
  double nx, ny, nz, an;
  int n;
  v1x = p[3] - p[0];
  v1y = p[4] - p[1];
  v1z = p[5] - p[2];
  v2x = p[6] - p[0];
  v2y = p[7] - p[1];
  v2z = p[8] - p[2];
  /* nx,ny,nzが法線ベクトル */
  nx = v1y*v2z - v1z*v2y;
  ny = v1z*v2x - v1x*v2z;
  nz = v1x*v2y - v1y*v2x;
  /* 正規化 (%eならいらないかも知れない) */
  an = sqrt(nx*nx+ny*ny+nz*nz);
  fprintf(fp,"facet normal %.14e %.14e %.14e\nouter loop\n", nx/an, ny/an, nz/an);
  for( n = 0; n < 3; n++ ) {
    fprintf(fp,"  vertex %.14e %.14e %.14e\n", p[0],p[1],p[2]);
    p += 3;
  }
  fprintf(fp,"endloop\nendfacet\n");
}

基盤地図情報対応 GDAL のビルドで若干つまづく

いまさら感もあるけど、基盤地図情報(JPGIS)対応GDAL。以下「mext_gdal」とします。mextと付いているのは文科省さんの事業の中で開発されたためです。

GDALは、GISの各種フォーマットの相互変換や加工等に活躍してくれるライブラリ+ユーティリティ。基盤地図情報国土地理院が発行する使用条件が緩い地図データ。

GDALは基盤地図情報を読めないのですが、mext_gdalは基盤地図情報に対応してくれたというもの。ありがたや。

ダウンロードは http://www.osgeo.jp/foss4g-mext/ から。

ちょっと思うことがあって、mext_gdalをビルドしなおそうとしたところ、いくつかひっかかったところがあったので、ここに残しておきます。

GDAL 1.9.0 ベースに由来する問題

基盤地図情報対応GDALはGDAL 1.9.0をベースにしています。現在のGDAL 1.9.2では解消されている問題が1.9.0ベースでは残っている、ということがあります。

2つあります。

iconvを呼ぶ箇所のキャスト

gcc 4.4以降では、const型修飾子を厳密にとる模様。
http://d.hatena.ne.jp/tmatsuu/20090717/ あたり参照。

iconvを呼ぶ箇所でコンパイルエラーが発生します。最新のGDALではこの問題は解消されています。

Giflibの破棄された関数

PrintGifError()は現在のGiflibでは破棄されていて、この関数を呼ぼうとしてくれます。

Giflibのソースがバンドルされているので、/usr/local/下に新しいgiflibがある場合はこれを抜いて(そうしないと新しいgiflibを使おうとする)、gifをinternal指定してやるといけるはずです。「はず」としているのは、1.9.0をコンパイルしたときにやったことがあるのですが、記憶の彼方なのです。

ただ、今回は、既に Giflibを外部から使っている GDAL 1.9.2 を入れていて、ややこしくなるのを避けるため、基盤地図情報から他のフォーマットに変換した後はGDAL 1.9.2を使うこととし、mext_gdalはgif非対応としました。

GDAL 1.9.2との同居の問題

mext_gdalを実行するときには LD_LIBRARY_PATH と PATH を mext_gdal にあわせてやる必要があります。いつものことです。

前日の年月日を得る

当日の年月日は、localtimeとtimeを使えば、すぐに解決。

my @arr = localtime(time);
my $y = $arr[5] + 1900;
my $m = $arr[4] + 1;
my $d = $arr[3];
printf "%d %d %d\n", $y, $m, $d;

前日というのは実にやっかいで、前述の$dから引き算をすると、2013年4月0日とかになってしまう。

そこでいろいろ考えてみたが以下略

timeの返り値から1日分の秒数を引けば解決。

my @arr = localtime(time-24*60*60);
my $y = $arr[5] + 1900;
my $m = $arr[4] + 1;
my $d = $arr[3];
printf "%d %d %d\n", $y, $m, $d;

portsの更新はportsnap

はじめに

タイトルと末尾がメインで、中の方は飛ばしちゃって良いと思います。

packages/portsをはじめから入れなおそうとするから

FreeBSDでは各種ソフトウェアは packages (バイナリ) または ports (ソースからコンパイル) で入れるのが多いです。

今回は、ソフトウェアの一部削除とアップデートとを一緒にしようと思い、クリーンインストールはやめたかったので、packages/portsで入れているものをドカッと変えようと思った次第。こういうことを考えるとロクなことがない。

が、後悔先に立たず。もう、pkg_delete -a で packages/ports を全削除しちゃったもんね。そのうえ /usr/local/* と /var/db/pkg を削除する念の入れようでした。この時点で、/usr/bin に入ってる基本コマンド以外はすべて消えました。Apache HTTPD も当然、PostgreSQL も当然、xterm だって消しちゃってる状態。すっからかんです。

いつも通り cvsup を入れる

いちからportsのビルドを行う前に、cvsup-withou-guiをインストール、cvsup ports-supfile を実行。これで、portsを最新の状態にできます。そのあとは、/usr/ports/(カテゴリ)/(ソフトウェア名) に移動して、makeすると、なんかソースコードを引っ張ってきて、パッチもあててくれて、コンパイルしてくれます。時間はかかるけど、portsコンパイル失敗は全く無い。

cvsup実行中に、なんか警告が一杯出てきていたのですが、警告だからまあいいや、無視。
で、xorgあたりをmakeしようとすると、途中でエラー。

…よく分からん。

確かにクラック事件で閉鎖、その後9.1はリリースされたもののpackage(コンパイル済のもの)の配布が停止、といった踏んだりな状態です。portsが残ってるので踏まれるまでで蹴られてはないんです。しかし、portsコンパイルが失敗するとなると、これは踏まれて蹴られて顔に落書きされるレベルの失望感。

いったいどうなってしまったんだよ…。

ただ、ここでも前述の警告が出てるのに気づき、さすがにこの警告に何かあるんだろうと思って読む…。

cvsup オワタ(AA略

2月末をもって本当にportscvs配布が終わってた。

なんだと俺に断わりもなく…いやさんざんコンソールにwiki見れやこら、と警告出しててそれを見落とす私が悪いんですすみませんー。

subversionがどうとか書いてた

しかし泣いていてもはじまらない、対応方法はいったい何だいと探すと、どうもsubversionを使うと良いらしい。
ふむ、まだ古いportsは残っているからsubversionをとにかくコンパイルして入れてやれば…。

ということで、make config-recursive で、先にコンフィギュアを実行する。途中、apacheも入れるぜ、aprも入れるぜ、とかなんとか言われて、いやものごとには順序が云々と口答えしたくはなったものの、結局…いえなんでもありません…すみません…と言いながらコンパイルしていこうとする。

…はい失敗。

subversionコンパイルできない。

本格的にオワ(略

これはあれか、羽田の国内線ターミナル北側あたりを見て「787墓場www」とか思ったからか、このまえつくばに行って某氏に挨拶しなかったからか、3Dプリンタの造形台にさっそく窪みをつくってしまったからか…?

いや、まだあるぞ、subversionのバイナリを引っ張ってきて入れるんだ。

よし、googleさんgoogleさん、"subversion freebsd package"あたりで何か教えて…。

http://www.freebsd.org/doc/ja/books/handbook/ports-using.html

portsnapを使えば解決

……それだけ?
…本当にそれだけ?
それだけでいいの?

さて本題

古いportsは消してしまった方が良いから、まずは/usr/portsを完全に消して、portsnapで引っ張ってきました。

# \rm -rf /usr/ports
# portsnap fetch
# portsnap extract

…うわ、本当だ、解決したわ。

アップデートは次の通り。

# portsnap fetch
# portsnap update

まとめ

  • cvsupオワタ
  • portsnap使え

Windows 7でThumbs.dbを作らないようにする

標記の通り。

まず、Googleさんに聞いたところ http://www26.atwiki.jp/kmgr/pages/60.html に行き当たりました。

グループポリシで設定を変えると良いようです。

ただ、設定の説明を見てもいまひとつピンとこないので、もうちょっと調べてみる。

Windows 7等では、基本的にはAppDataの下にキャッシュが置かれ、各フォルダに Thumbs.db を作らないはず。

だけれども、ネットワークフォルダに対しては、何かの拍子に作られるらしいです。

このへんは http://www.atmarkit.co.jp/fwin2k/win2ktips/706thumbsdb/thumbsdb.html 等参照。

まとめると、次のようになります。

  • 「ファイル名を指定して実行」から gpedit.msc (ローカルグループポリシーエディタ) を起動
  • 左のペインで 「ユーザの構成」/「管理用テンプレート」/「Windows コンポーネント」/「エクスプローラー」 をひらく
  • 「縮小表示の画像のキャッシュをオフにする」を有効にすると、Thumbs.dbもAppData下のキャッシュも作らなくなる
  • 「非表示のthumbs.db ファイルで縮小表示のキャッシュを無効にする」を有効にすると、Thumbs.dbは作られなくなり、AppData下のキャッシュは作られる

3次元プリンタがやってきた

3D Touchがやってきた

3次元プリンタ 3D Touch がやってきました。「カッコいい箱を作る」というミッションのためです。見た目重要ですからね。

粘土細工で見本を作るよりもきれいに、しかもパソコンで編集したものを、短時間で作成できます(作成にかかる時間は1日ぐらい見ないといけませんが)。試しに3次元プリンタで形を実際に作って、実際の使用を前提に触って確認することができるようになるのは非常に便利です。粘土細工をすることになるなら手先不器用だしあきらめよう、と思っていたことができるようになったのです。いい世の中だ。

はじめから問題があった

イントルーダ1つのものが来たのですが、「箱を作る」ミッションでは、はっきり言ってアウト。

プラスチック等を溶かして下から上に乗せていくので、箱の上面は土台の無い状態で無理やり材を乗せないといけない。網目状に頑張ってくれるんだけど、片っ端から下に落ちていく。なんとかのこった網目の上に網目を乗せて、外側はどうにかなるけど、内側は相当残念なことになります。

サポート材を入れて土台を作るとうまくいくんですが、これが常に要ることに気づいたのは、実際に残念なブツを作ってしまってからです。後悔先に立たず。

イントルーダ追加できますか?と販社さんに聞いたところ、可能だそうなんですが、その販社さんさえ「やりたくない」レベルの難易度だそうですorz

水平大事、とても大事

造型台が傾いていると、プリンタは傾きを感知しないまま動作するので、形がおかしくなるばかりか、空洞に充填する網目をバリバリやぶってささくれ立たせ、仕上がりを見た人の心までささくれ立たせてくれます。水平大事。

ヘッダを可動域の境界を左回りなり右回りなりに回して、ホットエンドと造型台との間がどこも同じ隙間になればOK、なんですが、3点でしか支えてないので、微妙な調整がいる。日本語マニュアルには「(隙間を)よく見て下さい」とあるんだけど、目で見ても分かりにくい。調整仕切れてない状態で、ある隅からギリギリで回すと、造型台の傾きによっては造型台をひっかく場合があり、結構がっかりします。

販社さんによると、最終のギリギリを攻める際には、アルミのような、ホットエンドを傷つけないような柔らかく軽い素材を置くんだそうです。

また、造型台の水平調整の後に行う、Zオフセットの調整は、造型台とホットエンドの間に紙を入れて台を上げて、紙を引っこ抜くのに手ごたえがあるところでオフセットをセーブすると良いんだそうです。

ABSのラフトはひどい

3D Touch (正確に言うと Axon2(後述)の吐くコマンドに基づき) ブツを作り出す前にブツの下に土台メッシュを作ります。ラフトというんだそうです。

このラフト、ABS材だと反ります。

プリンタ側は土台が反ってしまったかどうかとか知る由もありませんので、反ってしまってもかまわず動作するので、直方体を作ろうとしても、下面がゆがみます。しかも上面はきれいに作られるため、悲しさは倍増です。

なお、プラスチック材はまだ試してません。

付属ソフトは必ずラフトを出す

付属ソフト Axon2 は、STLを読んで、リビルドして、プリンタ用コマンドを生成するものです。

少なくとも使用している版ではラフトはデフォルトで出ます。これを消すフィルタがあります http://www.bitsfrombytes.com/jpy/forum/post/axon-2-no-raft-option 等参照。
"de-raft"で確かにラフト生成の部分は消えているっぽいですが、3D Touchが食ってくれないの…。特にかっこいい箱を作るミッションなら、ラフトなしで行けたほうが良いかも知れない。

STLエディタとしてのBlender

Axon2はSTLを食ってくれます。となると、オープンソースBlenderでモデルを作れる、ということになります。
本来、Blenderは3次元CG用ソフトなんですけどね…。

慣れるまでなかなか難しいのですが、ベジエで底面の境界線を作って、メッシュにコンバートして、extrudeして、ベベルして、remeshして、Modifier->Booleanで他のソリッドからの引き算というかたちで一部を削り取って、STLとしてエクスポートして、プリントアウトすることはできました。