screenをtscreenからtmuxへ乗り換えた

普段、端末経由で作業をする際、GNU Screen ライクな tscreen を使っていました。tscreen は Screen 系の中ではマイナーな類のもので、Debian の公式リポジトリにも入っていません。自前でソースコードを取ってきてビルドして使っていました。 というのも、自分が Screen を使い始めた当初は今のようにあまり選択肢がなくて、GNU Screen 以外と言えば数えるほどもなかった気がします。

tscreen を使い始めた大きな(覚えている)理由としては、本家ではできなかった画面の縦分割をサポートしていた事でしょうか。本家のキーとも互換性が高かったのも理由の一つだったと思います。

tscreen を常駐させ、中でIRCメーラー、作業環境一式を立ち上げていましたが、cgdb などのターミナル制御をガリガリやっている一部のソフトとの相性が悪かった為、今さらながら tmux に乗り替えることにしました。

tscreen と比べて気付いたこと

画面ロック

tscreen ではスクリーンセイバーとして bsdgames の worms を表示させていました。tmux でも同じように画面ロック機能を用いて、任意のコマンドを実行できましたが、実装に差があるようです。

  • tscreen 画面ロック中もキー入力は tscreen がしっかり管理しており、任意のキーを押すだけで画面ロックが解除される。

  • ** tmux** 画面ロック中のキー入力は、スクリーンセイバーとして実行されたコマンドに移ってしまい、そのコマンドを終了させない限り、tmux はキー入力を感知しない。

worms は C-c で終了しない限り終了しないコマンドです。tscreen では任意のキーを押せば、tscreen が責任をもって worms を殺してくれますが、tmux では自分で殺す必要があるようです。 セキュリティロックさせる意味では、tmux のようにキー入力を完全に画面ロックコマンドに任せてしまう方が良い気がしますが、単にスクリーンセイバーとして使いたいだけだったら、画面ロックコマンドの使い勝手に依存しない tscreen の方が利便性は高いです。 どちらも一長一短なので、まあいいんじゃないかな、と思います。

Unicode 文字の扱い

IRC では UTF-8 のチャンネルに入っていて、最近 Twitter などで良く見る Unicode 文字を駆使したキモい顔文字なんかも表示できるようになっています。 tscreen では、意図的かどうか分かりませんが、とにかく表示しようとしてレイアウト(特に文字幅)が崩れる事がありました。tmux では、文字幅の扱いに不安がありそうな文字は全て半角の「?」で表示されているようで、レイアウトの崩れが少なくなっています。レイアウトが崩れても表示させたいもの、レイアウトが崩れてまで表示させたくないもの、いろいろあるかもしれませんが、Emacs でミニバッファを開きまくっている自分としては、tmux のほうが合っている気がしました。

# 多分、意図的にやっているわけじゃないんだろうな。curses 依存のような。
# ついでに言うと、未だに ISO-2022-JP のチャンネルで CP932 依存の半角カナを垂れ流す奴ら滅びろ。
# 往々にしてそういう発言は読めなくても困ることがないけれど。

ちなみに、tmux のほうが崩れない「気がする」程度で、崩れるタイミングではやっぱり崩れます。ただ、本来の目的であった cgdb がちゃんと表示できているから及第点は超えていますね。

ウィンドウとペインの概念

本家 GNU Screen から tmux へ乗り換えた人のブログ記事でもよく目につきますが、tscreen もウィンドウとペインの概念がなく、単にウィンドウだけです。 最初は戸惑いましたが、これも慣れれば大丈夫そうです。

デザイン比較

ガリガリとカスタマイズをした tscreen と、ほとんどまっさらな設定の tmux を比べるのはちょっとナンセンスですが、なかなかダサくなってしまいました。(tmux はこれから手を入れて行こうと思います。)

tscreen

tscreen

tmux

tmux

緑一色っておま…!

tmux のペインには、tscreen のウィンドウのタイトルバーみたいなものがないので、視覚的にどのペインがアクティブになっているか分かりづらいです。あくまでもデフォルト設定なので、カスタマイズする方法はあると思いますが。ちなみに、tscreen ではアクティブウィンドウのタイトルバーを赤く、ノンアクティブを薄い緑色で表現しています。tmux 側に立って言うと、タイトルバーがない分 1 行だけ広く使えるメリットもありますね。

tmux が使っている色が緑一色というのは、「ひょっとしてANSI 256 colorをサポートしていない端末向け…」と思ったりもしますが、このご時世、あんまりメリットがない気がします。ステータスバーのアクティブウィンドウ表示も「*」で表現していますが、背景色を変えたほうがよっぽど分かりやすいです。 かと言って、画面ダンプのモノクロ印字に耐えられるほどカラー表示にレイアウトが依存していないわけでもなさそうなので、今どき「4ビットカラー対応だぜ」っていうのもなんだか。

「最初からやっといてくれる」の感覚が、もうちょっとおせっかい気味でも良い気がしました。結局、RC ファイルをいじるなら量が減ろうが増えようが、普段使いにはあんまり関係なくなります。

その他 tmux の良いところ

他の方もたくさん書いていますが、軽い気がしたり、レイアウトがそこまで崩れなかったり、そんなに設定しなくてもそこそこ使えたり、とメリットもたくさんありそうです。

下のステータスバーには、ログイン名、ホスト名、カレントパスが常に表示されているので、bash のプロンプトは「$」だけにしても良さそうですね。tscreen でも設定をガリガリ書けば出来そうですが、地味に便利です。

時刻表示は、まあ当たり前として…あとはやはり慣れでしょうかね。

tscreen では日頃の惰性から C-a をコマンドキーにしていたのですが、bash や emacs で行頭に移動したい場合や、vim で数値をインクリメントしたい場合 C-a a とタイプしなければならず、少し手間でした。コマンドキーを変更すれば良かったんですが、慣れもあってついつい使い続けていました。 tmux のデフォルトは C-b なので、vim のバックスクロールにぶち当たりはしますが、こちらに「慣れ」を変更してもいいかもしれません。ちなみに ratpoison ではコマンドキーは C-t でした。

総評

ダサさは自分で改善できるので良いとして、全体的なメリットを考えても乗り換える理由には充分だと感じました。tscreen は、公式サイトも消えてしまっているようで、多分メンテナンスも行なわれていないと思います。代わって tmux は、今もっともナウい Screen 系ソフトらしいので、ユーザ数や開発頻度、これからの改善にも期待が持てます。

さっさと調教して慣れていきたいと思います。

オマケ

全く需要がないと思いますが、これまで使っていた tscreenrc を貼っておきます。

[perl] startup_message off autodetach on

backtick 0 5 5 sh /home/dyama/bin/stat

shelltitle “$ |shell”

caption always “%{= mW} %n %{-}%?%F%{= rW}%:%{= Gk}%? %t %=” defhstatus “%n:%t” hardstatus alwayslastline “%{= bW}%-w%{= Wk}%n:%t%{-}%+w%= $USER %0`(%m/%d %02c)”

msgwait 10

defscrollback 2000

bind r eval ‘echo “Resize Window”‘ ‘command -c resize’ bind -c resize ^] command bind -c resize j eval ‘resize +1’ ‘command -c resize’ bind -c resize k eval ‘resize -1’ ‘command -c resize’

defutf8 on encoding utf-8 utf-8 defencoding utf-8

cjkwidth on

defkanji utf-7

color

defbce “on”

do not use ‘screen-bce’

term rxvt-256color termcapinfo rxvt-256color ‘Co#256:AB=\E[48;5;%dm:AF=\E[38;5;%dm:hs:ts=\E]0;:fs=\007:ds=\E]0;\007’

idle 1800 blankerprg /home/dyama/bin/worms2

↑たしか /usr/games/worms に上手く引数を渡せなかったので

シェルスクリプトを指定しています。

[/perl]

オックスフォード白熱教室

小学生の頃に家族旅行でイギリスに行った時、母の友人がいるオックスフォード大学を訪ずれました。今でこそ世界有数の大学という事を知っていますが、子供だったので、広大な緑地帯で放し飼いされていたクジャクを追い回した記憶しかありません。
今日、仕事から帰ってきて夕食に一人鍋をしていると、テレビで「NHK オックスフォード白熱教室 第4回 数学が教える“知の限界”」が放送されていました。同大学マーカス・デュ・ソートイ教授によるカオス理論を中心にした、とっても分かりやすい内容の講義(もちろん、日本語吹き替え)で、いくつも興味深い内容のお話をやっていました。かなり一般的に楽しめる事を意識した講義だとは思いますが、難しい数式どころか、黒板すら使わずに話していて、数学が分からない自分にでも理解ができるものでした。残念ながら途中からしか見れなかったので、再放送などがあれば最初から見直してみたいと思います。

レミングの集団自殺

ある海外のドキュメンタリー番組で、レミングというネズミの一種が、4年に1度、崖から海へと一斉に飛び降りて自殺するという事が紹介されました。結局、後から番組関係者の証言によりヤラセであった事が分かったのですが、レミングの個体数が周期的に増減しているのは事実らしいです。
講義では、レミングの世代ごとの個体数をある式で表して、数学的な予測が可能な範囲と予測ができない範囲、つまりカオス状態に突入するところを分かりやすく説明しています。
ある世代の個体数を [math]N_{1}[/math] とした場合、次世代の個体数 [math]N_{2}[/math] は、次のように定義されるらしいです。

[math]N_{2} = ( N_{1} \cdot PN_{1} ) – \frac{ N_{1} \cdot PN_{1} }{T}[/math]
※ただし、[math]N_{2} \geqq 0[/math]

[math]\frac{ N_{1} \cdot PN_{1} }{T}[/math] の項が減少個体数を表し、[math]T[/math] の値が小さくなるにつれ総個体数は少なくなります。また [math]P[/math] は、ある世代と次世代に生まれた個体の総数の増加率を示す係数です。
[math]T[/math], [math]P[/math] をそれぞれ、[math]T = 10[/math], [math]P = 2[/math] とした場合、最初の世代 [math]N_{1}[/math] の値が [math]0 < N_{1} < T[/math] の時、世代を重ねるごとに収束して [math]N_{2} \fallingdotseq 5[/math] という結果に安定するらしいです。

分かりづらいので、最初の個体数が 2、 3、 8、 10 だった場合のグラフを書いてみました。

Screenshot_from_2013-10-26 11:16:45

2、3、8 のいずれの場合も、最終的には 5 に収束して安定期に入ります。8 の場合、一度減った個体数が徐々に増えていくことが分かります。[math]T[/math] と同じ値の 10 は、増えることなく絶滅してしまいました。10 以上のどのような実数を与えても絶滅します。この式での最初の世代の上限は [math]N < T_{(10)}[/math] のようです。

次に、係数を [math]P = 2.5[/math] にして、最初の個体数を 2、3、9.9 だった場合のグラフを書きました。

Screenshot_from_2013-10-26 11:40:30

2 は 2 世代後には 6 に収束します。 3 は、6 の周辺に辿りついたあと増えたり減ったりしながら、やがて振れ幅が小さくなって 6 になります。9.9 の場合は、1 世代後に極端に値が減りますが、その後は徐々に回復していき、やがて 6 に収束しました。9.9 の場合の 1 世代後以降の折れ線は、[math]N = 0.1[/math] の時と同じものになります。同様に 9.5 の場合の 1 世代以降の折れ線は、0.5 の時と同じものになります。[math]T = N_{(9.5)} + N_{(0.5)}[/math] のようです。

さて、最終的に収束する値以上の値については、[math]T[/math] を超えない限り、1 世代以降でそれ以外の値と同じ折れ線になることが分かったので、2 と 3 の場合について、[math]P[/math] の値を変えて遊んでみましょう。
次のグラフは[math]P = 3[/math]の場合です。

Screenshot_from_2013-10-26 11:55:55

半ば予想どおりですが、今度は振れ幅がかなりゆっくりと小さくなっていっているようです。1 世代おきの増減が顕著に見ることができました。ここで、[math]P[/math] の値をどんどん上げることにより、振れ幅の衰退がどんどん小さくなっていき、限りなく周期的に増減をくりかえすグラフになるのかも!という期待が出てきます。
次に[math]P = 3.5[/math]の場合です。

Screenshot_from_2013-10-26 12:04:57

いきなり期待が裏切られました。3 の場合、最初の頃の振れ幅よりも途中から大きくなっています。
さらに[math]P = 3.7[/math]の場合、

Screenshot_from_2013-10-26 12:08:37

かろうじて 1 世代おきに増減をくりかえしているものの、振れ幅の大きさがめちゃくちゃになりました。
そして[math]P = 4[/math]、

Screenshot_from_2013-10-26 12:11:15

1 世代おきにくりかえしていた増減すらなくなり、完全に予測できないグラフとなりました。

番組では、4 年に一度、周期的に個体数を極端に減らすレミング題材にして、このようなグラフを紹介していました。[math]P[/math] と最初の個体数によって、レミングの個体数に似たグラフを表現できるということです。さらに、上で試してみたとおり、この式では [math]P[/math] が 3.5 から周期性が失なわれ始め、4 になると予測不可能なめちゃくちゃな状態、つまり「カオス状態」に突入することも紹介していました。

このレミングの話の前に、重力がお互いに影響し合う惑星の軌道や、複数の磁石を用いた振り子、二重振り子の話がありました。そこで、ささいな初期状態の変化が結果的には、予測不可能なカオス状態へ突入しかねないバタフライ効果についても触れていました。

余談ですが、番組では 4 までしか触れていなかったので、「[math]P[/math] の値を上げれば上げるほど、折れ線はどんどんカオス状態になっていくんだろうなあ」という淡い期待をしてしまいましたが、実際には…

Screenshot_from_2013-10-26 12:22:56

[math]P = 5[/math]の場合、2 が 8 に収束するわ、3 が [math]T[/math] を超えていないにも関わらず、絶滅してしまうわ、グラフの折れ線的にはグラフの後の世代を予測できる非カオス状態になりましたが、これまでの考え自体を否定する結果となりました。

そもそも、そういう挙動をする式だと言ってしまえばそれまでですが、初期状態の小さな変化によって、結果が予測不可能なものになる分かりやすい例えだったと思います。

mrubyがやってきた!

OpenCASCADE の勉強のために、仕事とは関係ないところで、自分なりの簡易三次元 CAD ビューアを作成しています。
形状をパラメトリックに定義したり、対話的に制御したり、一連の処理をモジュール化する上で必要になってくるのがマクロ環境。マクロと言ってしまうと、使い勝手の悪いバッチ処理的なイメージがそこはかとなくありますが、強力なインタプリタ環境を組み込みたいと思いました。

アプリケーションを組む上でもトライアンドエラーのデバッグ効率は上がりますし、CAD ソフトにおける純粋な三次元幾何演算をハード的な部分であるとすれば、「ある決まった工業製品の組み立てモデルをシミュレーションする」といったより論理的な、ソフト的な役割のライブラリ化にも役立つと思っています。

さて、OpenCASCADE にはこのブログでも何回か書いたとおり、DRAW TEST HARNESS というコマンド・ドリヴンな対話型デバッグシェルが含まれています。単機能評価だけで言うと、Tk による最低限の UI とシェルっていう組み合わせは別に捨てたもんじゃないのですが、ユーザに提供するマクロ環境として Tcl/tk を選択するのはいささか時代遅れな感じは否めません。シェルスクリプトや Perl、AWK に馴染みのある人ならば、あんまり気にせずに使い込なせると思うんですが、本質とは違うところでの労力を強いるのは極力避けたいところでもあります。

対話的にも動作することができ、モジュール化しても軽快に動いてくれるインタプリタ環境を探していました。
最低限、

  • 基本的な計算(四則演算、数学関数の呼び出し)
  • 変数の保持と解釈
  • 条件式、繰り返し構文

を備えているものだったら何でも良いと思っていました。ほぼ全ての言語にあるようなものばかりですね。もちろん、書き易さやメンテナンスのやり易さも条件のひとつです。

さて、最初に思いついたのは Python です。Python のコーディングは、私自身、累計でも1万行も書いていないと思いますが、欧米製の大手 CAD ソフトでは Python をマクロ環境として組み込むものが増えてきているようです。フランスのパリに Open CASADE の勉強会に行った時に開発メンバーが見せてくれたデモでも、OpenCASCADE の C++ コードを Python から呼んでいたようです。また、2011年から OpenCASCADE のコミュニティ・エディションをメンテナンスしている Thomas Paviot 氏も PythonOCC という Python ラッパーのプロジェクトを立ち上げています。

大手 CAD や OpenCASCADE との連結でも実績のある Python ですが、組み込み関連の情報を漁っていると、 mruby というものを見つけました。

mruby とは、Ruby の開発者 Matz 氏が最近精力的に開発を進めている組み込み向けの Ruby 実装らしいです。本家 CRuby に比べて依存関係が少なく、小さな端末でも動きやすいよう設計されているようで、Vim 関連の記事でよく参考にさせていただいている mattn 氏頻繁にコミットされている事がブログからも伺えます。

私はガチガチの関数手続き型の頭と、シェルスクリプトのようなゆるゆるのシェル展開ありきの頭の2ビットでコーディングをしていたので、Ruby のような「ちょうど良い」言語には向いていないんだろうなーと食わず嫌いをしていて手をつけなかったような気がします。いや、嫌っていたワケではないのですが、あれ楽しい!これ楽しい!と目移りしている間に、いつの間にか、ちゃんとやってみる機会を逃したというのが正しいかもしれません。少なくとも、ちゃんとやりたい言語の一つであった事は間違いありません。

# 余談ですが、Lisp もちゃんと時間をとってやりたいです。Emacs の設定ファイルのために elisp をごちょごちょ書いたような記憶しかありせん。
# オライリーの「初めての Ruby(オーム社刊、Yasugi 著、2008年)」で紹介されている Ruby の系図に、Ruby が Lisp の考え方も引き継いでいるような図があったので楽しみ。

これは好機とばかりに、mruby を試してみることにしました。

Hello, mruby!

mruby を make するのは簡単でした。他所でも紹介されているように、git で clone して make するだけです。Ruby の環境をまともに触るのも初めてでしたので、初めて知ることがたくさんありました。

まず、Makefile は存在しているのですが、Makefile の中で呼ばれているのは ruby minirake というコマンド。make から minirake が呼ばれて、最終的に gcc がコンパイルする形になってます。コンパイルの動作を処理している minirake は全て Ruby で実装してあり、Ruby 初心者が最初に見た時は「?」マークの連続でした。(でも、それほど時間をかけずに読んでいけました。Ruby すごい!)

頭に mini と付いているのは、きっと mruby のための小さな仕組みであり、本家 CRuby では Rake という Ruby のための Make 環境があるんだろうな、とも理解できました。

Ruby には gem というモジュール管理機構があるようです。Perl で言う CPAN のようなものだと思いますが、rake ファイルにターゲットを追記しておくだけで新しい gem を作ることができました。本家 Perl と軽量目的の mruby を比べるとアレかもしれませんが、分かりやすさ・透明性と簡単さは驚きです。(これなら自分もできるかも!と思わせてくれるのにはテンションが上がります)

さてはて、自分のアプリケーションに組み込む場合は Windows 環境で動かさなければならないので、Windows 環境、とりわけ Visual Studio でビルドできるかというのは大きな問題でした。そして、結果から言うと杞憂でした。
Windows では TortoiseGit と MSYSGIT を使っていますので、Windows に Ruby を入れて PATH を通したあと、MSYS 環境に clone して make するだけでした。途中、bison がないぞって怒られたので、bison.exe を入れたらすんなりと mruby.exe(インタプリタ本体)、mirb.exe(mruby.exeに対話シェル機能を入れたもの)、mrbc.exe(Rubyコードをバイトコードにコンパイルするやつ) が出来てしまいました。これらバイナリは libmruby.a をスタティックリンクしているようで、スタンドアロンで動作可能っていう嬉しさ。さすが組み込み向けです。

コーディングをほとんどしていないのに、こんな側面から mruby がどんどん好きになってしまいます。

Visual Studio で

自分のアプリケーションを Windows 以外のプラットフォームでも提供するんだったら、Qt なんかでチャキっと組んだ方がいいと思うんですが、私は Qt を使ったことがありません。Qt はすごくやりたいのですが、それはまた別の機会として、当面の目標である Windows でそこそこ動くものを作らねばなりません。

そういう理由で、ユーザ・フロントエンドを C#、OpenCASCADE や mruby のラッパー DLL を C++/CLI で実装しよう(※)と思いました。ラッパー DLL も C++/CLI 依存の部分とネイティブ C++ 準拠の部分を分けてコーディングする事により、最悪、別のプラットフォームになった場合、ネイティブ C++ の部分だけ抜き出してビルドし直せばいいと思いました。MFC を使った COM 実装に比べれば、C++/CLI の制約なんて目をつぶる事ができそうですし、そんな高度な事もする予定がないので、当面はこれで問題がないはずです。

※Microsoft の公式推薦の C++/CLI 入門書籍でも、「C++マネージド拡張の失敗という前例もあるし、特に理由がなければ C++/CLI なんて使うな」と前書きに書いてありましたね。あれは声出して笑いました。

さて、さっそく MSYS環境で make した mruby.dll を Visual Studio で作成した C++/CLI の wmruby.exe (デバッグの為、とりあえずEXEを作成)からリンクしてみて実行しました。コンパイル、リンクとも正常に完了しているものの、実行時には 0xc0000007b というエラーが出て、実行できません。調べてみると、どうもバイナリイメージが CIL とネイティブの間で上手く取りつげていないようです。

ここは mruby ではなく、MSYS と、Windows の目紛しく仕組みが変わるバイナリの取り扱いの不一致だろうって事で、あまり深く調べずに考え方を変えました。

mruby.dll を make するために rake ファイルを読み漁ってた時に vs2010 や vs2012 といった、いかにも Visual Studio で mruby をビルドするオプションっぽいのを発見していました。

openssl とか、gem が他のオープンソースライブラリを使う時、Visual Studio ではなく MSYS 環境のほうが色々と苦労が少なそうだなーと思っていたので、あえて MSYS で libmruby.a を make していましたが、そこが問題になりそうだったら選択肢がありません。

vs2010 を使って、ビルドし直してみると、Visual Studio によって libmruby.a ではなく libmruby.lib が生成されました。加えて、MSYS でビルドしていた自前の mruby.dll も Visual Studio で C++/CLI として libmruby.lib にリンクして再ビルドすると、拍子抜けするほど上手く行きました。

libmruby.lib さえビルドできてしまったら、あとはこっちのもんですね!

IIJ 版

これまで触っていた本家の mruby では、require やシェルコマンド実行のクオートなど、Kernel でサポートしているものもほとんどありませんでした。開発途上という側面と、最低限のものを提供するというスタンスがあると思われます。

本家 mruby のほか、IIJ さんも精力的に mruby の開発に手を出しているようで、本家から folk したリポジトリになっています。mattn 氏のブログを拝読していたら、先程述べた require やクオート、正規表現など「モバイル端末などの局所的な組み込みには要らなかもしれない!でもPCで実行する対話的アプリのモジュールなら要るよね!」的な機能を IIJ 版にどんどん追加されていっている様子が伺えました。記事にもありましたが、CRuby にも遜色がないほどの基本機能を提供できるようになっているようです。本当に凄いし、夢が広がります!

という事で早速、IIJ 版を clone して make してみました。linux では何ごともなくすんなり。
./mirb して

[ruby]
ls.each_line do |item|
puts item
end
[/ruby]

すると、ちゃんと実行できました。楽しい。

さて、Windows 環境ではどうかと言うと、ソケットを扱ってそうな gem があったり、コードを見てみると Windows 向けのコーディングがされていなかったりと、半ば予想はしていましたが、Visual Studio でビルドしようとしても失敗しました。当たり前だよネ。

Visual Studio っていう巨大なイレギュラー環境が立ちふさがって、作業がストップしてしまいましたが、丹念に乗り越えなければならない道だろうなぁと思います。今はビルド方法をまとめるくらいしか能力がないですが、Ruby をガリガリ使えるようになって、実装の事も理解できるようになったら issue 飛ばしたり、コーディング面でも協力できるようになれればなあ、と思いました。

OpenCASCADE の Draw Test Harness を活用する その3

前回までの記事では、OpenCASCADE の Draw Test Harness を利用し、独自コマンドを組み込むところまでを紹介しました。今回は、実例を用いながらコーディングしていきたいと思います。

目的

任意の半径を持つ球体を 1/8 にした形状を作成し、その容積を印字したいと思います。

想定しているコマンドの書式は次のとおり。

[bash]
sphere1p8 result_name radius_of_sphere
[/bash]

アプローチとしては、まず原点(0, 0, 0)に半径 r の sphere を作り、同じ位置に大きさ(r, r, r) の box を作成し、二つをコモン演算します。その結果に対して容積を取得しようと思います。

ソースコード

まず、前回のサンプルコードをベースに、プリミティブ、ソリッド、プロパティを扱うためのヘッダを追加してあげます。次に、hello() 関数を sphere1p8() 関数に書き換え、コマンド定義も変更してやります。

[cpp]

include <iostream>

include "/opt/occ660/ros/config.h"

include <Draw.hxx>

include <Draw_Interpretor.hxx>

include <DBRep.hxx>

/* コマンドで利用するヘッダ */

include <TopoDS_Solid.hxx>

include <BRepPrimAPI_MakeBox.hxx>

include <BRepPrimAPI_MakeSphere.hxx>

include <BRepAlgoAPI_Common.hxx>

include <BRepGProp.hxx>

include <GProp_GProps.hxx>

include <Standard_PrimitiveTypes.hxx>

/* 1/8球を作成し、ボリュームを印字する */
static int sphere1p8(Draw_Interpretor& di, Standard_Integer argc, const char** argv)
{
if (argc != 3)
return 1;

// 半径
double r = atof(argv[2]);

// 球と箱を作る
BRepPrimAPI_MakeSphere sphere(gp_Pnt(0, 0, 0), r);
BRepPrimAPI_MakeBox box(gp_Pnt(0, 0, 0), r, r, r);

// ブール演算
BRepAlgoAPI_Common bo(box.Solid(), sphere.Solid());
bo.SetOperation(BOPAlgo_COMMON); // 6.6.0 から BOP_* が BOPAlgo_* になってる
bo.Build();

if (bo.ErrorStatus())
    return bo.ErrorStatus();

// 結果を取り出して、登録
TopoDS_Shape shape = bo.Shape();
DBRep::Set(argv[1], shape);

// 容積を印字
GProp_GProps gpr;
BRepGProp::VolumeProperties(shape, gpr);
std::cout &lt;&lt; std::endl &lt;&lt; &quot;Volume: &quot; &lt;&lt; gpr.Mass() &lt;&lt; std::endl;

return 0;

}

void Draw_InitAppli(Draw_Interpretor& di)
{
Draw::Commands(di);
di.Add("sphere1p8", "sphere1p8 result r", FILE, sphere1p8);
}

include <Draw_Main.hxx>

DRAW_MAIN
[/cpp]

sphere1p8() 内の処理は、コメントを参考にすれば説明は不要だと思います。1点だけ、補足をしておきますと、40行目の DBRep::Set() 関数で DBRep という Draw の幾何オブジェクト管理構造にオブジェクトを登録しています。この DBRep に登録する事により、AXO ビューアにオブジェクトが表示されることになります。また、Draw インタプリタ上からオブジェクトの名前をキーにして扱うことも出来るようになります。

Draw 内だけで使われるもので、有用な関数を次に示します。

  • Draw_Interpretor::Eval … 関数内から Draw コマンドを実行する
    例)

    di.Eval("pload ALL; axo");
  • Draw_Interpretor::EvalFile … 関数内からファイルパスを指定し、Tcl スクリプトファイルを実行する
    例)

    di.EvalFile("script.tcl");
  • DBRep::Set … オブジェクト名をキーにして、オブジェクトを管理構造に追加する
    例)

    DBRep::Set(objname, myObject);
  • DBRep::Get … オブジェクト名をキーにして、オブジェクトを管理構造から取得する
    例)

    TopoDS_Shape myObject = DBRep::Get(objname);

上記の例のように Eval() の文字列はコマンド単位ではなく、一連のスクリプトの内容として食わせることが可能です。(コマンドはセミコロン区切りで1行に連結できます。)
また、DBRep はオブジェクトを静的に管理しているようなので、static 呼び出しで使います。 コマンドの引数として指定されたオブジェクト名で、オブジェクトを取得・設定する際に利用します。
これだけ知っていれば充分ですが、さらに詳しい情報は、Draw_InterpretorDBRep のリファレンスを参考にしてください。

ビルドと実行

前回のサンプルファイルの時から、利用しているライブラリファイルが増えましたので、ビルドコマンドライン、とりわけ Makefile も書き換える必要があります。

[cpp]
g++ -I/usr/local/inc -lTKernel -lTKDraw -lTKMath -lTKBRep -lTKTopAlgo -lTKPrim -lTKBO -lTKG2d drawtest.cpp
[/cpp]

沢山増えましたね。リンカエラーで「クラス○○の参照が見つかりません!」と怒られた場合は、クラスのリファレンスマニュアルを参照すると、ライブラリ名を特定することができます。例えば、Draw_interpretor クラスの参照エラーとなった場合、リファレンスページの画面上部に「Open CASCADE Technology > Module Draw > Toolkit TKDraw > Package Draw」と表示されています。この Toolkit の部分がライブラリ名になるので、この場合ですと「TKDraw」というライブラリをリンクしてあげればいい事になります。
OpenCASCADE ライブラリは、ほとんどに接頭辞 TK が付いていますが、Toolkit の略です。Tcl/Tk の Tk とおんなじですね。

ビルドが成功したら、実行バイナリを起動して、pload ALL、axo の順にタイプします。その後、追加したコマンド sphere1p8 obj 10.2、 fit コマンドを実行すると、次のようになりました。

dth_volume_sample容積は、約 555 らしいです。ちゃんと動いている模様。

あとは、コンパイラに -g して GDB などに投げて、ガリガリとトライ&エラーが楽しめます。

OpenCASCADE の Draw Test Harness を活用する その2

前回の記事で、OpenCASCADE に同梱されているコマンド駆動型の効率的なデバッグ環境 Draw Test Harness の使い方を紹介しました。今回は、いよいよデバッグ&プレビュー環境として活躍させるための、独自コマンドを追加する方法を書きたいと思います。

Draw Test Harness に独自コマンドを追加する

Draw Test Harness の環境に自前のコマンド(コード)を追加する方法は簡単です。どちらかと言うと、自分のデバッグしたいコードを取り出して、Tcl ないし Draw インタプリタを組み込むイメージです。何はともあれ、まずはコードを見てみましょう。

[cpp]
// File: drawtest.cpp

include <iostream>

// このプログラムを Draw インタプリタプログラムにするために必要なヘッダ

include "/opt/occ660/ros/config.h"

include <Draw.hxx>

include <Draw_Interpretor.hxx>

include <DBRep.hxx>

static int hello(Draw_Interpretor& di, // 1. コマンド実装部
Standard_Integer argc, const char** argv) //
{ //
std::cout << "hello, draw!" << std::endl; //
return 0; //
} //

void Draw_InitAppli(Draw_Interpretor& di) // 2. コマンド定義部
{ //
Draw::Commands(di); //
di.Add("hello", "print hello string for test", //
FILE, hello, "Test command"); //
} //

include <Draw_Main.hxx> // 3. アプリケーション

DRAW_MAIN // 実行部

[/cpp]

こちらの手順で OpenCASCADE を導入した場合を前提にして書いていますが、5行目の CASROOT ディレクトリ(ros ディレクトリ)の直下にある config.h のパス文字列を、お使いの環境での config.h のパスに変更するだけで正常に動くと思います。

このプログラムは、1. コマンド実装部、2. コマンド定義部、3. アプリケーション実行部に分かれています。一つ一つはすごく簡単なので、ちゃっちゃか解説しちゃいましょう。

1. コマンド実装部

この関数がコマンドの実際の処理となります。上のサンプルでは、文字列を標準出力に印字する hello() 関数として実装しています。Draw インタプリタとコマンドの実行引数を取る静的関数であれば、名前は何でも構いません。複数のコマンドを実装したい場合は、コマンド毎に、コマンド用インタフェイスを持つ関数を追加してあげます。

[cpp]
/* コマンド用インタフェイス */
static int // 戻り値: コマンド正常終了時は0。
funcname (
Draw_Interpretor&, // Draw インタプリタのアドレス
Standard_Integer, // コマンドの引数数
const char** // コマンドの引数文字列
)
[/cpp]

2. コマンド定義部

Draw_InitAppli() はアプリケーションが初期化される際に一度だけ自動的に呼ばれる関数です。ここで、Draw::Commands() を呼び出した後、Draw_Interpretor::Add() 関数を使って、上記で追加した関数とコマンドの関連付けを Draw インタプリタに宣言します。

[cpp]
Draw_Interpretor::Add(
const Standard_CString Command, // コマンド名
const Standard_CString Help, // コマンドのヘルプ文字列
const Standard_CString Filename, // コマンドの関数がコーディングされているファイルパス
const Draw_CommandFunction Function, // コマンドの関数ポインタ
const Standard_CString Group=&quot;User Commands&quot; // コマンドのグループ文字列
)
[/cpp]

コマンド名と関数さえしっかり定義できていれば、あとは適当で構いません。ヘルプ文字列は、Draw インタプリタで help commandname を実行した際に、表示されるテキストを指定します。普通はコマンドの使い方を書いておくためのものです。

3. アプリケーション実行部

DRAW_MAIN 定数により、アプリケーションに必要な main() 関数や Draw インタプリタのその他の機能の呼び出しなど、面倒なコーディングはプリプロセッサが全部やってくれます。最後にこの2行を書いておけば、とりあえずOK。

ビルドと実行

ビルドは次のとおりです。TKDraw ライブラリを忘れずにリンクしましょう。

[bash]
g++ -lTKernel -I/usr/local/inc -lTKDraw drawtest.cpp
[/bash]

ここで生成された a.out を実行し、「hello」とタイプすると、hello() 内で定義したコードが実行されます。※ a.out を実行した際に「the CASROOT variable is mandatory to Run OpenCascade」というメッセージが表示されたら、環境変数 CASROOT が上手く定義されていません。

「hello, draw!」と印字されれば成功です。「exit」 とタイプして終了させましょう。

今回のサンプルでは、hello() 関数内で OpenCASCADE を用いた処理は一切行なっていなかった為、a.out の実行直後に hello コマンドを実行しても大丈夫でしたが、今後、OpenCASCADE を用いた処理を書くようになれば、必ず「pload ALL」を実行しなければなりません。

次回は、もう少し意味のあるデバッグコマンドを実装しながら、コマンド内でよく使うであろう機能を紹介したいと思います。

onnanoko

本日のまとめ

  1. Draw,Draw_Interpretor,DBRep ヘッダを読み込み、Draw_InitAppli() と DRAW_MAIN を持つソースコードを準備する。
  2. コマンド用インタフェイスを持った関数を作り、Draw_InitAppli() 内で、コマンドと関連付けする。
  3. コンパイルし、libTKDraw にリンクして、実行する。

OpenCASCADE の Draw Test Harness を活用する その1

OpenCASCADE には、コマンド駆動型の効率的なデバッグ環境 Draw Test Harness というものが付属しています。 OpenCASCADE のコードを、単機能ごとに評価できるツールとして開発には外せないものであり、非常に有用なものです。快適なデバッグするのには、グラフィカルなユーザインタフェイスやイベント、コマンド実行の仕組み、簡単な繰りかえし処理や変数、数式の解釈など、かなり高次元なフレームワークを構築しないと、難しいものがあります。その「本質以外の部分」を担ってくれるのが Draw Test Harness です。

Draw Test Harness の簡単な説明

Draw Test Harness は Tcl 言語のインタプリタを内包しており、Tcl 言語のモジュールとして OpenCASCADE を利用された様々なコマンドを実行することができます。また、Viewer や簡単なマウス処理も提供されているので、対話的にコマンドを実行し、結果を三次元ビューで確認することができます。

Tcl 言語をご存知ない方にとっては、「今から新しい言語を覚えるのか…」と逃げ腰になる必要はありません。確かに Tcl はレトロな言語なのですが、インタプリタとしては使い古されており、あまり高度なことをしようとしない限り、充分に、クイックリーに動いてくれる環境です。基本的には、デバッグを自動化してくれるマクロという位置付けですので、バッチファイルやシェルスクリプトを書いたことがある方ならば、充分に使いこなせると思います。基本はコマンドの羅列です。

Draw Test Harness では GUI のメニューも提供されていますが、こちらは Tcl 言語の相棒といっても過言ではない GUI フレームワーク Tk で実装されています。こちらに関しては、Tk を用いて GUI を構築しようとしない限り、まったく知識は要りません。

Draw Test Harness を実行する

前項の手順で OpenCASCADE をインストールし、ros ディレクトリを指す環境変数 CASROOT が定義された状態を前提としています。X サーバが動いている端末または、Xを飛ばしたクライアント上から、次のコマンドをタイプします。

[bash] DRAWEXE [/bash]

GUIのメニューが表示され、端末には「Draw[n]>」というプロンプトが表示されたと思います。これが Tcl コンソールです。プロンプトに続けて、

[bash] pload ALL axo box b 10 10 10 fit [/bash]

とタイプしていくと、平行投影ビューにボックスが表示され、ビューにフィットすると思います。dth

1行目の「pload ALL」は、モジュールファイルを全て読み込むコマンドです。このコマンドを最初に実行しておかないと、Tcl コンソールから OpenCASCADE モジュールをコールすることができません。(ちなみに、OpenCASCADE モジュールは、環境変数 CASROOT で定義された ros ディレクトリからパスを追っていき読み込んでいます。) 2行目の「axo」で平行投影ビューを表示して、3行目の「box b 10 10 10」で「(原点位置に)大きさ10,10,10のbというboxを作る」というコマンドです。最後の「fit」コマンドで、平行投影ビューいっぱいにboxの表示をフィットさせています。

最後に、「exit」とタイプすると Tcl コンソールが終了します。

このような具合で、コマンドを対話的にタイプしていって IGES を読み込んだり、オブジェクトの容積を出したりすることができるツールが Draw Test Harness です。 Tcl コンソール自体がインタプリタになっているので、上でタイプしたコマンドをテキストファイル box.tcl に保存しておき、

[bash] DRAWEXE < box.tcl [/bash]

することにより、一連の作業を自動的に処理させることもできます。 次の Tcl スクリプトは、ボックスと平面の交線(エッジを含むコンパウンド)を水平レベルごとに取得し、表示するサンプルです。

[perl]

!/usr/bin/env tclsh

pload ALL

ビューの作成

axo

ボックスの作成

box b 10 10 12 fit

ボックスを傾ける

trotate b 0 0 0 1 0 0 14 trotate b 0 0 0 0 1 0 -21 fit

水平面で交線を求める

for {set i 1} {$i <= 14} {incr i} { plane p$i 0 0 $i 0 0 1 psection c$i b p$i unset p$i } [/perl]

簡単な制御構文を用いています。私自信、Tcl 言語はそれほど書いたことあるわけではないのですが、以前のブログ記事を見てみるとこんなモノも書いていたようです。全然覚えてないな・・・。

Windows 環境では、CASROOT ディレクトリ(ros)直下にある draw.bat をダブルクリックすると、Tcl コンソールが開きます。

Draw Test Harness を使った応用

Draw Test Harness には、OpenCASCADE モジュールとして提供されているコマンドが数百種類もあります。ここでは、一つ一つに関しての説明は省きますが、これらのコマンドを組み合わせることで、ちょっとした非対話的な CAD ないし、三次元データコンバータくらいなら書けてしまいます。また、DRAWEXE の標準入出力をつないだアプリケーションを書けば、コマンド駆動型、かつしっかりとしたGUIを積んだアプリケーションを書けないことはありません。ちょっとした IGES ファイルの形状のチェックや、形状を反転・拡大縮小したい場合などにも力を発揮します。

また、提供されているコマンドの実装はソースコードレベルで公開されていますので、例えば、三次元オブジェクトの重心位置を取得するコードを書きたい場合、Draw コマンド vprops の実装を調べれば良いわけです。Draw インタプリタ内で「getsourcefile vprops」とタイプすると、ソースコードのファイル名を教えてくれます。そのファイル名を基に $CASROOT/ros/src から目的のソースコードを探し出すことができます。Draw コマンドは、基本的には単機能ごとに機能を提供しているものなので、Draw コマンドの実装方法が「最強のサンプル集」となることでしょう。

さらに、Draw Test Harness では、既存のコマンドに加え、ユーザが C++ を用いてコーディングした OpenCASCADE のコードも簡単に呼び出すことができます。OpenCASCADE を使う、つまり C++ で OpenCASCADE を使う場合、Draw Test Harness は最強のデバッグビューアとなるのです。

次回は、Draw Test Harness に自分で書いた OpenCASCADE コードを独自のコマンドとして登録し、実行してみます。

onnanoko本日のまとめ

  • Draw Test Harness は、コマンド駆動型の強力な OpenCASCADE インタプリタ。
  • 面倒な GUI 周りが最初から準備されているので、三次元幾何演算のトライアンドエラー、プレビューがかんたんにできる。
  • 対話的に利用するもよし、数百種類あるコマンドを組み合わせてバッチ処理をさせてもよし。
  • それぞれのコマンドは、source commandname によって C++ のソースコードを参照できる。

OpenCASCADE における幾何オブジェクトの管理

OpenCASCADE で、幾何オブジェクトを管理するにはいくつも方法があるようですが、付属のコマンド実行環境 Draw Test Harness では、幾何オブジェクトに対して文字列の名前を与え、それで管理できる仕組みを提供しています。
具体的には、Standard_CString 文字列をキーとする AIS コンテキストに登録された Shape との関連付けマップ構造を持っているようです。Draw Test Harness 上でコーディングする際、次のようなコードをしょっちゅう書きます。

[cpp]
{
// …

// オブジェクトを取得
TopoDS_Shape S = DBRep::Get(shapename);

// ...

// オブジェクトを追加
TopoDS_Shape SS = ...
DBRep::Set(SS, shapename2);

}
[/cpp]

DBRep クラス
のソースを追ってみると、名前文字列とインデックスキーの関連付けに Tcl のマップが利用されており、その後で Draw クラスの Set(), Get() がコールされており、Draw クラス内で Draw_VMap 型のマップが宣言されていました。さらに、Draw_VMap は TCollection_BasicMap クラスの派生クラスとなっており、このコレクション・マップを利用すれば幾何オブジェクトを管理することができるようです。

誘惑に負けて std::map を使いそうになってしまいますが、特にプログラミング上の制約の多い Windows で幾何オブジェクトを取り扱うには、TCollection_BasicMap を利用するのが無難なようです。

OpenCASCADE 6.6.0 をビルドする。

OpenCASCADE 6.6.0 がリリースされて数ヶ月経ちますが、ようやく自宅の環境でもビルドする暇が出来たので手順を書いておきたいと思います。
手順と言っても、ソースコードを落としてきて make するだけなので、すごく簡単です。

OpenCASCADE 6.6.0 のビルド

うちの環境は相変わらず Debian 7.0 の x86 環境ですので、その環境を前提として書いています。
まず、公式サイトのダウンロードページより、6.6.0 の樽玉を落としてきます。ここでは、/tmp/occ640 を作業ディレクトリにしますので、そこに落とします。ダウンロードの際は、公式サイトにユーザ登録する必要があります。

ダウンロード後、次のコマンドを実行します。

[bash]
cd /tmp/occ640
tar zxvf OpenCASCADE660.tgz
cd ros
./build_configure

configure が生成される

./configure –enable-data –enable-algo –enable-vis –enable-caf –enable-dxe –enable-draw \
–with-tbb-include=/usr/include/tbb –with-tbb-library=/usr/lib –with-freeimage=/usr/include \
–with-gl2ps=/usr/include
[/bash]

configure にビルドするコンポーネントと OpenCASCADE が利用しているライブラリのパスを指定しています。何も指定しなくても最低限の構成でビルドすることは出来ますが、最低限の構成だと IGES の読み書きすらまともにできないので、全ビルドするように指定しています。

./configure を実行する際、ログの最後のほうに出てくるレポートを参考にしてください。

[bash]

3rdparty mandatory products

freetype : yes
tcltk : yes

3rdparty optional products

gl2ps : yes
freeimage : yes
tbb includes : yes
tbb libraries : yes
qt : no (–with-qt=DIR option was not defined)

Component Build


FoundationClasses yes
ModelingData yes
ModelingAlgorithms yes
Visualization yes
ApplicationFramework yes
DataExchange yes
Draw yes
[/bash]

私の場合、サンプルとして付属する Qt プロジェクトでのみ利用されている「qt」の部分以外は、全て有効にしました。freetype、tcktk が欠落していると、Component の Visualization 以下のビルドができません。tbb は Intel の CPU で効率的にマルチスレッドを実現するためのライブラリです。

参考までに、私の Debian では次のパッケージをインストールしました。

[bash]
sudo aptitude install libxmu-dev libfreetype6-dev
sudo aptitude install tcl-dev tk-dev
sudo aptitude install libgl2ps-dev libfreeimage-dev libtbb-dev
[/bash]

それぞれの開発パッケージに含まれるヘッダファイル、ライブラリファイルは、sudo dpkg -L パッケージ名 で確認することができます。これを基に、configure オプションの –with-tbb-include= といったオプションを指定します。
どの Component が必要か取捨選択できるようになるまでは、とりあえず全部動くようにしておくのが無難でしょう。上の configure のレポートのようになったら、後は make するだけです。

[bash]
make
[/bash]

ちなみに、最後の make は非常に時間がかかります。私の環境(core i5/x86、SSD、シングルスレッドビルド)で、396分かかりました。

ビルド後のチェック

ビルドが完了したら、そのまま sudo make install してもいいのですが、コワイのでまずちゃんと使えるかチェックします。

正常にビルドができていれば、共有ライブラリは ros/adm/lin/amk//.libs/lib.so に生成されているはずです。また、ヘッダファイルは ros/inc に格納されているので、次のようにオプションを指定すれば、OpenCASCADE を利用したアプリケーションのビルドをすることが出来ます。

[bash]
cd ros
mkdir mysrc
cd mysrc
vim test.cpp
cat test.cpp

include <stdio.h>

include "Standard_Boolean.hxx"

// サンプルプログラム
int main()
{
Standard_Boolean n = Standard_True;
printf("%d\n", n);
return 0;
}
g++ -lTKernel -I/tmp/occ660/ros/inc -L/tmp/occ660/ros/adm/lin/amk//.libs test.cpp
LD_LIBRARY_PATH=/tmp/occ660/adm/lin/amk/
/.libs ./a.out
1
[/bash]

OpenCASCADE で利用される基本型 Standard_Boolean を用いたサンプルプログラムをビルドし、実行した模様です。最終行のように「1」が表示されれば、OpenCASCADE が利用できるようになっています。

インストール

正常に使えている事が確認できたら、次のコマンドでインストールします。

[bash]
make install
[/bash]

これでライブラリは /usr/local/lib、ヘッダファイルは /usr/local/inc に格納されます。また、DRAWEXE といった実行ファイルが /usr/local/bin に設置されます。

最後に、OpenCASCADE のサンプルプロジェクトなどで ros ディレクトリ以下のファイルを利用しますので、作業ディレクトリを

[bash]
mv /tmp/occ660 /opt/
[/bash]

しておき、$HOME/.profile に $CASROOT=/opt/occ660/ors を追記しておきます。

Windows でのビルド

Windows における OpenCASCADE は、標準ビルド環境が Microsoft Visual Studio のソリューションファイルとして提供されている為、前項のような開発者の環境に合わせた条件付きコンパイルがやりづらくなっています。基本的な手順は、6.5.4 の手順と変わりません。

Tiarra やめました。

長らく利用していた IRC プロキシソフト Tiarra の利用をやめました。理由は次のとおりです。

  • tscreen(GNU Screenみたいなの)上の riece で IRC には常駐しているので、端末ログインすればどこからでも繋がる。
    • 携帯電話なんかの専用クライアントから接続できる手軽さはあるけれど、果たしてサーバソフトを常駐させるまで使うかっていうと、そうでもなかった。
    • 携帯電話なんかの専用クライアントから接続する場合は、大人しく別USERとしてログインすればいい気がしてた。
  • 頼んでもない大量の WHO リストが1,2分おきに tiarra サーバから出力されるようになって、チャットどころじゃなくなる。
    • サーバメッセージをメインログじゃなくてチャンネルログに流して、かつアクティブを持っていっちゃうようなクライアント側にも問題があるはずなんだけど、なんだか気持ち悪い。XChatやLimechatで接続すると、WHOリストは「プロトコルログ」のような生ログ表示以外には表示されないので、特に問題ない。
    • tiarra を経由しなかったら、riece でも WHOリストの大量取得現象は見られなかったから、IRCサーバ側にリクエストを投げているのは tiarra のはず。ここ1年くらいで、現象が起きる日と起きないがある。設定はいじってないし、なんだろうな。
    • 次の理由により、詳しく調べる前にtiarraの利用をやめることにしました。
  • かなり高度かつ柔軟な設定が出来るわりに、得られる効果がほとんどない。
    • tiarra のメリットと言えば、同一ホストからのセッション数を減らすことができる点。
    • それ以外だと、メイン宛のPRIVMSGを外部から読める、チャンネルの入退室を最小限にできる、常駐ロガーとして活躍…くらいか。
      • 常駐ロガーという意味では、自分のように既にクライアントソフトが常駐しているユーザにとってまるで意味がないもの。
    • デメリット
      • 設定が高度な分、煩雑でもあり、接続ができなくなったり、DCCのルーティング設定で問題があった場合など、問題を複雑化してしまいそう。
      • 複数サーバーに対し、それぞれ違う nick でログインしている/したいのに、そこらへんの設定が考慮されずに設計されていそう。
      • 設定自体、ちょっとWindows寄り。起動スクリプトを書いてcronなどに登録したり、ユーザごとの設定ファイルに対応させたり、いろいろ改造して使ってました。

お世話になっていたのは確かなのですが、IRC を便利に手間なく使うための Tiarra を本気で改良するのも本末転倒になってしまいそうで、結果的に利用をやめてしまいました。

当初、自分が Tiarra を導入した頃はガラケーでしたので、CGI/HTMLベースのIRCクライアントと一緒に使う際に威力を発揮していたんですが、今じゃスマホからSSHで端末を開いて、screen セッション上で動いている riece on emacs を表示して、普通にチャットができますもんね。

なんだかマイナス意見ばかりになってしまいましたが(利用をやめた理由だから当たり前ですが…)、オープンソースでこれだけのものを作って公開してくださった方には感謝しています。

 

tr1の正規表現ライブラリを使う

Microsoft Visual Studio 2008 の SP1 からは C++ Technical Report 1 (TR1)をサポートしているので、Boost やPCRE などのライブラリを用いずに正規表現を扱うことができます。

[cpp]

include <iostream>

include <string>

include <regex>

// usage: a.exe pattern replace-to

using namespace std;

int main(int c, char** v)
{
if (c != 3) return 1;

tr1::regex ex(v[1]); // 正規表現オブジェクト
char buf[256]; // 読み取り用のバッファ

while (cin.getline(buf, sizeof(buf)))
cout << tr1::regex_replace(string(buf), ex, string(v[2])) << endl;

return 0;
}
[/cpp]

Boost のコードと比べれば、名前空間が boost から tr1 に変わったこと、regex ヘッダが標準パスに入ったこと、regex_replace() の第3引数が char* から std::string に変わったことくらいでしょうか。Boost からの移植ですので、互換性があって当然ですね。

C++11 では、名前空間がさらに tr1 から std に移されているようです。TR1 は C++ の言語自体の規格ではないものの、拡張ライブラリの標準規格ですので、名前空間などの移り変わりに注意しておけば、今後も安心して使っていけると思われます。