翼コレクション第18弾零戦飛行隊/現用艦船キットコレクションVol.1 その2

前回、開封して中身の確認だけしていた「零戦飛行隊」と「現用艦船キットコレクション」を作りました。

エフトイズ「現用艦船キットコレクション Vol.1 海上自衛隊護衛艦」

まずは護衛艦「しらね」からです。こちらはガム1粒入りの正真正銘の食玩です。パーツ数もそんなになく30分もかからずに完成できました。

DSC_0004

接着剤を使わずともちゃんと組めるよう、パーツを穴にしっかりと差し込む方式(?)になっています。細かなパーツが後で外れるのが嫌だったので、自分は接着剤で固定しながら組みました。

DSC_0014

完成するとなかなかカッコいいです!

船体色は素のプラスチックの色ではなく、ちゃんとツヤ消しグレイで塗装されているので質感もなかなかいいです。また、自分レベルではどうしても汚なくなってしまいそうな白いラインもパキッと決まっていて、精巧さをアップさせている気がします。

CIWSなどの小さいパーツの塗装が若干弱い気がしますが、こういう部分こそ自分でも塗れるので、ディティールアップしがいがあるモデルだと思いました。(ただしスケールは1/1250) フルハルな艦は、1/2000戦艦ミズーリに続いて2隻目ですが、今回は立派なラダーやプロペラ、シャフトまでついているモデルで満足しています。

ちなみに、船首が右にくるように船台に固定しているのは、ちょっとしたこだわりです。

童友社「翼コレクション第18弾 日本海軍零式艦上戦闘機21型/22型/52型 零戦飛行隊」

1/700スケールを除いて、軍用機を作るのは通算3機目です。中学か高校の頃に二式水戦とSu-34を作った以来でちょっとだけテンションが上がります。

こっちは途中経過の写真を撮る間もなく夢中になって作ってしまいました。

DSC_0025

写真ではあんまり分かりづらいですが、塗装のディティールがかなり細かいです。主翼の「ノルナ」「オスナ」の表記まで小さいながら再現されています。

DSC_0020

出撃を待機している様子にしたかったので、人形はあえてコクピットに載せませんでした。ちなみに、主翼に接着しているわけではありません(笑)。

このシリーズ、予想以上の出来が気にいってしまって、また西海模型さんに足を伸ばしたのですが、既に売り切れてしまっていました。もしかしたら自分が買ったコレが最後の一つだったかもしれません。残念。

翼コレクション第18弾零戦飛行隊/現用艦船キットコレクションVol.1

ここのところ忙しかったのであまりプラモデルに手を出せてなかったんですが、今日はまた、仕事帰りに西海模型さんに行ってきました。2回に1回の来店の確率で「店内の客は米兵のみ!」という感じになっています。外国人にも人気のお店のようです。

ちなみに今日の四ヶ町アーケードはインド兵だらけでした。玉屋の前を突っ切っただけですが、100人以上見たと思います。というのも、インド海軍のシヴァリック級「シヴァリック」、ディーパック級「シャクティ」、ラジプット級「ランヴィジェ」の駆逐艦やフリゲート艦など3隻が佐世保に寄港しているらしく、ちょうど店舗に設置されているニュースでもその日米印合同演習の話題をやっていました。

さて、宮崎駿監督の最後の長編アニメ「風立ちぬ」の影響もあって、九試単戦、九六式艦戦などのプラモもいいなあと思って眺めていると、童友社の「翼コレクション第18弾 日本海軍零式艦上戦闘機21型/22型/52型 零戦飛行隊」を見つけました。 実は、西海模型さんの店舗の一番奥に置いてあるのは前から知っていたんですが、中身に何が入っているか分からない食玩はあまり手を出せずにいたんです。あ、これはお菓子なんかが入ってないから食玩ではないのかな…。

また、ちゃんとした1/48や1/72スケールの戦闘機のプラモデルも、前々から興味があったんですが手持ちの塗料は艦船カラーばかり。一つでも買うと初期投資が多そうだなぁと及び腰になっていました。 今回、「風立ちぬ」の影響で弟が1/48スケールの零戦を買っているのを見てやっぱり欲しくなり「零戦飛行隊」だったら塗装済みみたいだし648円だし、きっと許されるよね!というダメな言い訳をしつつ手にとってしまいました。

「中に何が入っているか分からない(かつ塗装済み)」のを買うので気が大きくなったのか、直前まで買うつもりがなかったエフトイズの「現用艦船キットコレクション Vol.1 海上自衛隊護衛艦」も買ってしまいました。だってレジ横に540円で積んであるんだもの。買っちゃうよ、そりゃあー。

ちなみに、なぜかアオシマの1/2000ドイツ戦艦テルピッツタミヤの1/700日本海軍小艦艇セット、タミヤの呉色も手に持ってましたなぜか。そしてなぜか買いましたなぜか。

douyusha-zerofighter-and-ftoys-jmsdf-aegis-01

まず「現用艦船キットコレクション」を開封。

douyusha-zerofighter-and-ftoys-jmsdf-aegis-02

中学生の頃、祖父に連れられて五島列島沖であった観艦式に行ったことがあり、そこで見た護衛艦「こんごう」を期待してましたが、しらねでした。ちょっと残念と思いつつ、現用艦船モデルは初なので少しテンションも上がります。ちなみに、こっちにはガムが1粒ついているので食玩です。写真の左上の見切れている白いのです。

次に「零戦飛行隊」。

douyusha-zerofighter-and-ftoys-jmsdf-aegis-03

こちらは狙っていた二二型でした。開封してみると意外と大きい! 艦船に付属している1/700艦載機・水上機などを除くと、軍用機は高校以来なのでスケール感があまりないんですが、1/72くらいのサイズなんじゃないかな? 塗装もしっかりしていて、700円弱とは思えない満足感です。色も渋い!

2014/08/03 追記 1/100スケールのようです。

そういえば、食玩ではなくプラモデルの話なんですが、軍用機のモデルって価格帯が1000円〜1500円でもしっかりしたものが買えるようですね。艦船でその価格帯だとちっさい駆逐艦や軽巡クラスです。パーツ数や金型の複雑さに依存してるんでしょうか、それとも軍用機の方が人気で量産の結果、価格が低いんでしょうか。あ、元となる軍用機の種類が艦船より少ないっていうのもあるのかもしれませんね。(艦船の場合、ラインナップを多くしなければならない為、需要総数が同じでもモデルが細分化してしまって、その分量産化が難しいのでは?という意味で)

さて、パーツを見てて思ったんですが、まず塗装しないので接着剤をつけるのに注意しなければいけないな、という点。いつもは主要パーツを接着した後に塗装して接着剤の跡を隠蔽しているので大丈夫ですが今回はいつも以上にはみ出し注意です。

次に、枠のプラ棒とくっついた状態で塗装がされているので切断面に色がついていないんじゃないかな、という点。ガンプラのように色が練り込んであるプラではなく明らかに吹いています。また、塗装済みなので切断面のヤスリがけもあまり派手にできそうにありません。

当たり前と言えば当たり前ですが、あらためてそういう視点から見ていろいろと思うところがありました。さてどう作って行こうかな。

オマケ

kazetachinu

「風立ちぬ」のヒロイン・菜穂子がかわいいです。病弱で健気で気丈でちょっぴりお茶目で美人っていう黄金比は、普通の70過ぎのお爺ちゃんでは描けませんよね!

siren のロゴを作ってみました

私個人がオープンソースで開発をしている三次元ベースの簡易 CAD システム「siren」のロゴを作成してみました。

今、自分が勤めている会社は海に関する仕事がメインで、マシンのホスト名やシステムの開発コード名に、海に関する用語をつけるのが慣例となっています。この簡易三次元 CAD は、会社の業務としてではなく、あくまでも個人的に開発しているものなんですが、その慣例に倣うかたちで「siren(セイレーン)」と名付けました。セイレーンは、ギリシャ神話に登場する海の怪物のひとつで、岩礁から美しい歌声で歌い、その声で船員たちを惑わし、航海中の船を遭難させたり難破させたりする怪物です。上半身は女性、下半身は鳥という奇妙な形をしているそうで、時代が下るにつれ、人魚の姿をしているとされたようです。そして、大きな音を出すサイレンはこのセイレーンが語源らしいです。

siren_logo_simple

ロゴについて

セイレーンとサイレンを組み合わせて描いてみました。途中から気付いたんですが、鮮かな色の影絵調+黒い文字にアンダーラインってものすごくFFのロゴっぽいですね。もうちょっと動的な水飛沫みたいなのを追加しようかとも思ったのですが、さらに天野喜孝風になるとアレなのでやめておきました。ちなみに、セイレーンのロゴについて調べているとスターバックスのマークもセイレーンがモデルらしいです。

当初はセイレーンだけだったんですが、siren の開発を手伝ってくれている弟に見せたところ「サイレンにしようぜ」といっていたので、試しにサイレンを立ててみたら、「セイレーンがサイレンをつかっている」という図らずしも良い具合なミスマッチ感が生まれました。

フォントなどのライセンスまわりがクリアになったら、そのうちクリエイティブコモンにしようと思っています。まだソースデータは公開していません。

読みについて

公式では siren を「セイレーン」と呼び、カタカナ表記もそうするように統一しています。ただし、読み(発音)については自由してもらって構いません、というのが公式のスタンスです。開発サイドではもっぱら「サイレン」と呼んでいます。日常的にセイレーンと呼ぶのは、自分で名付けておきながら、なんだか恥かしい感じがするのと、呼びやすさの意味からです。また、「シレン」と呼ぶ人もいました。通じさえすればいいので、どれも間違いではありません。 今のところユーザーはかなり少ないと思うし、あまり気にする人はいないかなー。

タミヤ 1/700 軽巡 矢矧&フジミ 1/700 空母 海鷹 その2

前回、はじめてちゃんとしたマスキングを行なって矢矧の塗装を行いました。今日は乾燥したようなのでテープを剥がしていきたいと思います。

ijn-lightcruiser-yahagi-and-aircraftcarrier-kaiyou-part2-01

船体は既に軍艦色(佐世保海軍工廠色)で塗装しており、その上から1度目のリノリウム色の塗装、筆塗りに失敗したので塗装を一旦落として2度目のスプレーによるリノリウム色の塗装、さらにマスキングをして上部構造物を軍艦色で塗装した状態です。下地がリノリウム色であるせいか軍艦色での隠蔽があまり上手くいかず、一度乾燥した後にもう一度吹いています。ちょっと塗装を乗せすぎな感じが…。

それでも、ワクワクしながらテープを剥がすと

ijn-lightcruiser-yahagi-and-aircraftcarrier-kaiyou-part2-02

こんな感じになりました!なかなか良い感じ!

ijn-lightcruiser-yahagi-and-aircraftcarrier-kaiyou-part2-03

近寄って見てみると、軍艦色がテープの隙間から漏れている箇所がちらほら。このくらい狭い範囲なら、筆塗りで補修することができるでしょう。あと、最初に筆塗りして落としたリノリウム色の塗装の後が少し残ってますね。ここは見なかったことにしよう…。

ijn-lightcruiser-yahagi-and-aircraftcarrier-kaiyou-part2-04

魚雷運搬軌道はマスキングをどうやってしようかよく分からず、リノリウム色のまんまです。ガチの人(?)はモールド自体を平らに削ってしまい、真鍮線で作り直したり、軌道エッチングパーツを立てたりしてるようですが、ううむ。今の自分のスキルではフラグだらけなので、それは次の機会かな。

矢矧の乾燥具合に満足したので、次は海鷹です。

ijn-lightcruiser-yahagi-and-aircraftcarrier-kaiyou-part2-05

艦橋の窓枠エッチングパーツをはじめ、構造物はほとんど乗せてしまいました。説明書の手順どおりではないです。塗装の順番を試行錯誤しながら組む練習と思っていろいろとチャレンジしているんですが、はたして上手くいってるのかわかりません。

ijn-lightcruiser-yahagi-and-aircraftcarrier-kaiyou-part2-06

ミッドウェー海戦で空母4隻を失ったのを契機に、大阪商船の貨客船「あるぜんちな丸」を三菱重工長崎造船所で空母に改装した艦ですので、何も考えずに佐世保海軍工廠色を吹いています。

ijn-lightcruiser-yahagi-and-aircraftcarrier-kaiyou-part2-07

ウォーターラインモデルなので、通常はあまり下から覗き込むことはありませんが、下からもちゃんと吹きました。空母は平板状の構造物だらけですので、いろいろな角度から吹かなければならないようです。こういう時、どうしても塗料の量が多くなりそうなのでエアブラシで噴霧量を調整できたら便利そうですねー。

次回は、空母の顔とも言える飛行甲板に取りかかりたいと思います。上手く行くといいな。

OpenCASCADE で曲面を作成する

今回はいよいよ曲面を作成していきたいと思います。

平面までなら、なんとか独自に三次元幾何ライブラリーをこしらえて扱うことができるかもしれませんが、自由曲面を扱うシステムを組もうとすると、とても独自開発ではやっていけません。そんな時、OCCが力を発揮するわけです。

また、OCCではトポロジカルな扱いをする上で、平面と曲面の明確な差はあまりありません。 もちろん、作成時に必要となる要素は平面の方がより限定的ですが、トポロジーを考えた場合、平面も曲面の一部という考え方のほうがより自然です。

OCC上でトポロジカルな面(平面も曲面も)を扱うには、前回の平面の作成の際に出てきた面クラス TopoDS_Face を用います。

通過点を指定してベジエ曲面を作成する

uv方向にマス目状に並べた通過点を指定することで、曲面を作成します。一番、直感的で簡単な曲面の生成方法ですが、これは座標値の羅列から uv 曲線群を定義して面を生成しているので、内部的にはパラメトリックな曲面の式で構成されています。

コード

TColgp_Array2OfPnt poles(0, 3, 0, 3);
poles.SetValue(0, 0, gp_Pnt( 0,  0, 20));
poles.SetValue(0, 1, gp_Pnt( 0, 10, 20));
poles.SetValue(0, 2, gp_Pnt( 0, 20, 20));
poles.SetValue(0, 3, gp_Pnt( 0, 30, 20));
poles.SetValue(1, 0, gp_Pnt(10,  0, 10));
poles.SetValue(1, 1, gp_Pnt(10, 10, 10));
poles.SetValue(1, 2, gp_Pnt(10, 20,  5));
poles.SetValue(1, 3, gp_Pnt(10, 30,  0));
poles.SetValue(2, 0, gp_Pnt(20,  0,  0));
poles.SetValue(2, 1, gp_Pnt(20, 10,  5));
poles.SetValue(2, 2, gp_Pnt(20, 20, 10));
poles.SetValue(2, 3, gp_Pnt(20, 30, 10));
poles.SetValue(3, 0, gp_Pnt(30,  0, 20));
poles.SetValue(3, 1, gp_Pnt(30, 10, 20));
poles.SetValue(3, 2, gp_Pnt(30, 20, 20));
poles.SetValue(3, 3, gp_Pnt(30, 30, 20));

Handle(Geom_BezierSurface) s = new Geom_BezierSurface(poles);
TopoDS_Face f = BRepBuilderAPI_MakeFace(s, 1.0e-7);

TColgp_Array2OfPnt クラスは、gp_Pnt を2次元配列として保持するためのコレクションクラスです。 このコードを実行すると、次のような曲面が生成されます。

また、Geom_BezierSurface クラスのコンストラクタには、各通過点のウェイトを設定することも出来、次のようにコーディングすることができます。

// poles はあるものとする ...

// ウェイトの設定
TColStd_Array2OfReal weights(0, 3, 0, 3);
weights.SetValue(0, 0, 1.0);
weights.SetValue(0, 1, 1.0);
// ...

Handle(Geom_BezierSurface) s = new Geom_BezierSurface(poles, weights);
TopoDS_Face f = BRepBuilderAPI_MakeFace(s, 1.0e-7);

poles の u, v の各店に対応したウェイトを TColStd_Array2OfReal クラスで設定していき、コンストラクタに渡してあげます。

NURBS 曲面を作成する

ワイヤーをスイープ(掃引)して曲面を作成する

複数のワイヤーをロフトして曲面を作成する

OpenCASCADE で平面を作成する

前回の曲線に引き続き、今度は平面を作成していきたいと思います。

前提

平面を決定するための要素は

  • 任意の3点を通る
  • 任意の1点と法線ベクトル

などのいずれかの条件が必要です。 さらに、有限平面を幾何的に決定するには、

  • 外形
  • uv方向の範囲

などの条件が必要となります。

一方無限平面は、画面に表示したり、重心位置や面積を計算したり、交線を発生させたり、さまざまな幾何的処理を行う際に不都合が多いのは確かです。また、コンピュータのリソースも有限です。

OCCでは、「無限平面」をジオメトリックに、式や値の集合として保持することは可能ですが、トポロジカルなシェイプ(形状)として保持することはありません。これは次のような見方ができるかもしれません。

  1. 直線 y = ax + b の式 ← ジオメトリーレベル、範囲は無限
  2. 1 の条件 かつ 0 <= x <= 10 ← トポロジーレベル、範囲は有限

トポロジーレベルでの条件(?)は、範囲を設定することだけではなく、行列を用いたトランスフォーメーションなどもそれに当たります。式以外でその形状を決定づける全ての要因がトポロジーであると言えます。

この部分の解釈は、私自身、幾何数学があまり得意ではないので上手く説明ができませんし、何か勘違いをしている部分もあるかもしれませんが、ジオペトリーとトポロジーの概念を詳しく説明したサイトはインターネット上にたくさんありますし、OCCでのコーディングを深めていく上で、雰囲気を感じとっていただければ…ということでお茶を濁します。すいません。

以後、このブログで直線、曲線、平面、曲面といった単語が出てきたら、すべて「有限~」であると思ってください。あんまり出てこないとは思いますが、有限か無限かが重要なポイントでは、明示的に述べたいと思います。

矩形平面を作成する

さて、実際にモノを作ります。ここで矩形平面と呼んでいる平面は、任意の三次元座標を基準にし、uv方向に大きさを持つ矩形上の平面のことです。下図のようなものです。

ここで平面を決定づける要素は

  • 基準点 pos[x, y, z]
  • 法線ベクトル norm[x, y, z]
  • v ベクトル vdir[x, y, z]
  • u 方向の範囲 umin, umax
  • v 方向の範囲 vmin, vmax

です。u ベクトルはありませんが、法線ベクトルと v 方向を示すベクトルの二つがあれば、この二つの外積から u 方向は決定されます。

コード

Standard_Real umin = -10, umax = 10;
Standard_Real vmin = -10, vmax = 10;

gp_Pnt pos(0, 0, 0);
gp_Dir norm(0, 0, 1);
gp_Dir vdir(0, 1, 0);
gp_Ax3 ax(pos, norm, vdir);
gp_Pln pln(ax);

TopoDS_Face f = BRepBuilderAPI_MakeFace(pln, umin, umax, vmin, vmax);

上で示した要素を定義して、BRepBuilderAPI_MakeFace クラスで平面を作成しているだけですので、あまり説明をすることはないと思います。

今回、初めて登場した gp_Dir は、名前の通り方向(Direction)を示す単位ベクトルです。この型を用いて API を呼び出したりする際、その方向だけが用いられ、大きさは無視されます。なので、

gp_Dir dir(1, 1, 0); // XY方向にナナメ

という指定の仕方をしても、用いられる際には正規化されていますので大丈夫です。

gp_Ax3 は、軸クラスです。gp_Ax3 のほか、gp_Ax1 と gp_Ax2 も存在します。

  • gp_Ax1 … 位置(gp_Pnt)と方向(gp_Dir)を持つ
  • gp_Ax2 … 位置(gp_Pnt)と方向(gp_Dir)とv方向(gp_Dir)を持つ
  • gp_Ax3 … Ax2 の要素に加え、右手系・左手系の設定を持つ

軸をカメラに例えると、Ax1 でカメラの位置と視線方向が決定でき、Ax2 では視線方向を軸とした視野の回転を制限することができるわけです。(決定要因が視線方向だけだと、視野における上がどちらの方向か定まりませんもんね)

さらに gp_Pln は、Ax3 の情報を持った「無限」平面です。持っている情報は Ax3 のそれと変わりませんので、意味論としての入れ物として解釈していいと思います。

あとは、BRepBuilderAPI を使ってトポロジカルな面 TopoDS_Face を作成しています。

1点だけ補足を述べておきますと、上記の例の pos は、あくまでもベースとなる無限平面を定義するものですので、uv 方向の範囲内(有限平面内)に存在している必要はありません。つまり、例えば原点(0, 0, 0)に位置定義をしておき、u が 100~200 の範囲、v が 50~80 の範囲、という定義も問題なく成立するわけです。

任意の外形を持つ平面を作成する

さて、次は任意の外形を持つ平面を作成します。図で示すと、次のような形状を作成します。

前項では、uv 方向の範囲を指定して平面を作成しましたが、この項からは「合わせ技」が登場します。具体的に述べますと、外形を一旦、ワイヤーというシェイプとして生成しておき、そのワイヤーを用いて平面を作成するわけです。

コード

百聞は一見にしかず。実際にコードを追っていきましょう。

BRepBuilderAPI_MakePolygon mp;
mp.Add(gp_Pnt(0, 0, 0));
mp.Add(gp_Pnt(10, 0, 0));
mp.Add(gp_Pnt(10, 5, 0));
mp.Add(gp_Pnt(20, 5, 0));
mp.Add(gp_Pnt(20, 15, 0));
mp.Add(gp_Pnt(15, 12, 0));
mp.Add(gp_Pnt(5, 12, 0));
mp.Add(gp_Pnt(3, 10, 0));
mp.Add(gp_Pnt(0, 0, 0));
mp.Build();

if (mp.IsDone()) {
    TopoDS_Wire w = mp.Wire();
    BRepBuilderAPI_MakeFace mf(w, Standard_True);
    mf.Build();
    if (mf.IsDone()) {
        TopoDS_Face f = mf.Face();
        return mrb_fixnum_value(::set(f, self));
    }
}

以前のポリラインを作成する記事で紹介したように、BRepBuilderAPI_MakePolygon クラスを使って、ポリラインを作成し、TopoDS_Wire として受け取っています。このワイヤーを用い BRepBuilderAPI_MakeFace クラスで平面を作成しています。

この MakeFace クラスは、前項と同じものですが、コンストラクタがオーバーロードされており、いくつもの方法で面を作ることが可能となっています。これは MakeFace に限らず、MakeEdge などのクラスも同様です。

MakePolygon クラスは、Wire() だけでなく Edge() や Shape() でも作成した曲線を返すことができますが、ここでは明示的に Wire として受け取っています。Wire を端的に表現すると「1個以上の Edge からなる連続した曲線群」で、連続性が保証されていることが重要なポイントです。単に「複数の Edge」で良ければ、Edge の配列かなにかで十分ですが、複数の Edge をひとつの Wire として表現するということは、同時にそれらの Edge が連続してつながっている状態であるということを表します。

閉じた領域である有限平面の外形となるには、外形を構成している Edge がバラバラに存在しているのではなく、ひと筆書きで連続していることが条件となるため、MakeFace の引数には Wire が用いられるわけです。

さらに条件をつけ加えると、その Wire は始終点がくっついて輪状になっている必要があります。外形線なのに、どこかが途切れていたりしたら、その平面の範囲を決定できませんよね。

BRepBuilderAPI_MakeFace クラスのコンストラクタの第2引数が Standard_True になっていますが、これは平面であることを強制するためのフラグです。 前項では gp_Pln クラスを用いて、作りたい面が乗っているベースとなる無限平面を明示的に指定していました。今回の Wire から平面を生成する方法では、そのような明示的な指定はありません。そのため、平面であることを強制するフラグが存在するのです。(このフラグを False にすると、曲面として面を張ります)

また当たり前ですが、平面を作成する場合、ポリラインの各通過点は同一平面上になければなりません。

オマケ: OCCにおける数値型について

OCCでは移植性向上のため、整数値、浮動小数点数、真偽値などの値を次のように定義しています。

typedef int           Standard_Integer;
typedef double        Standard_Real;
typedef bool          Standard_Boolean;
typedef float         Standard_ShortReal;
typedef char          Standard_Character;
typedef short         Standard_ExtCharacter;
typedef unsigned char Standard_Byte;
typedef void*         Standard_Address;
typedef size_t        Standard_Size;
typedef std::time_t   Standard_Time;
typedef const char*   Standard_CString;
typedef const short*  Standard_ExtString;

詳しい内容は、Standard_TypeDef.hxx に記載されています。このブログでも、これらの定義に則って表記しています。 複数のプラットフォームへの移植を考えてなくても、OCCを使ったコードではできるだけ上記の型名を用いておいた方がいいでしょう。

OpenCASCADE で NURBS 曲線を作成する

前回の点、線分、ポリライン作成に続いて、今回は曲線を作成したいと思います。

通過点を指定して曲線を作る

曲線の場合、座標値の集合である線分やポリラインと違い曲線を定義する式を組み立て(ジオメトリーレベル)、そこからトポロジーレベルのシェイプを生成する必要があります。

コード

Standard_Integer nb_pts = 4; // 点数

// 点配列クラスに4点設定
Handle(TColgp_HArray1OfPnt) pary = new TColgp_HArray1OfPnt(0, nb_pts - 1);
pary->SetValue(0, gp_Pnt(0, 0, 0));
pary->SetValue(1, gp_Pnt(10, 0, 0));
pary->SetValue(2, gp_Pnt(10, 10, 0));
pary->SetValue(3, gp_Pnt(20, 20, 0));

Standard_Real tol = 1.0e-7; // トレランス(幾何誤差の許容値)
GeomAPI_Interpolate intp(pary, Standard_False, tol);

intp.Perform();
Handle(Geom_BSplineCurve) hgeom_bspc = intp.Curve();
TopoDS_Edge e = BRepBuilderAPI_MakeEdge(hgeom_bspc);

新しいクラスがいくつか出てきました。順を追って見てみましょう。

まず、Handle(TColgp_HArray1OfPnt) ですが、これは名前のとおり、gp_Pnt クラスの1次元配列コレクション TColgp_HArray1OfPnt の Handle 型です。 詳しい Handle の解説は別記事でしたいと思いますが、この型で定義されたオブジェクトは、new でインスタンスを作っても OCC 内に実装された独自のガベージコレクションが自動的に管理をしてくれるので、解放の必要がないオブジェクトになります。 使い方は普通のポインタ同様、アロー演算子でメソッドを呼び出します。

SetValue() でインデックスと点座標値を渡していきます。インデックスは1から開始されるので、注意してください。

次の GeomAPI_Interpolate は、通過点からBスプライン曲線を作成するためのクラスです。コンストラクタの第2引数を Standard_True にすると、曲線の始終点を曲線的に連結して輪状の曲線を作成します。

Perform() メソッドで計算を行い、Curve() メソッドで、ジオメトリーレベルの曲線シェイプ Geom_BSplineCurve の Handle 型を取得することができます。

さらに、BRepBuilderAPI_MakeEdge に渡すことにより、最終的に扱う TopoDS_Edge を受け取ることができます。

NURBS 曲線の要素から NURBS 曲線を作る

前提

このブログをご覧の方はご存じの方が大半だと思いますが、NURBS 曲線の定義は次の 3 つの要素から成ります。

  1. 次数
  2. 制御点列
  3. ノットベクトル列

制御点は x, y, z 座標値のほか、ウェイト w を持ちます。また、ノットベクトルの数は次の式により決定されます。

ノット数 = (制御点数) + (次数 + 1)

サンプル用の要素

  1. 次数: 2
  2. 制御点列: [100, 0, 0, 1], [70, -10, 10, 1], [30, 40, 10, 1.2], [0, 0, 0, 1]
  3. ノットベクトル列: [0, 0, 0, 1, 2, 2, 2]

これらの要素を用い、OCC 上のトポロジカルなシェイプを作成します。

コード

TColgp_Array1OfPnt poles(0, 3);
poles.SetValue(0, gp_Pnt(100,  0,  0));
poles.SetValue(1, gp_Pnt( 70,-10, 10));
poles.SetValue(2, gp_Pnt( 30, 40, 10));
poles.SetValue(3, gp_Pnt(  0,  0,  0));

TColStd_Array1OfReal weights(0, 3);
weights.SetValue(0, 1.0);
weights.SetValue(1, 1.0);
weights.SetValue(2, 1.2);
weights.SetValue(3, 1.0);

TColStd_Array1OfReal knots(0, 2);
knots.SetValue(0, 0.0);
knots.SetValue(1, 1.0);
knots.SetValue(2, 2.0);

TColStd_Array1OfInteger mults(0, 2);
mults.SetValue(0, 3);
mults.SetValue(1, 1);
mults.SetValue(2, 3);

Handle(Geom_BSplineCurve) hgeom_bscurve = new Geom_BSplineCurve(
    poles, weights, knots, mults, 2, Standard_False);

TopoDS_Edge e = BRepBuilderAPI_MakeEdge(hgeom_bscurve);

上から、poles(制御点)、weights(制御点に対応するウエイト)、knots(ノットベクトル列)、mults(ノットベクトルの多重度)を設定し、Geom_BSplineCurve クラスのコンストラクタに渡しています。

ノットベクトルの多重度とはノットベクトルの各要素が「いくつ」続いているかを示すもので、この例では、

[0, 0, 0, 1, 2, 2, 2]

というノットベクトル列に対して、0 が 3 個、1 が 1 個、2 が 3 個と読み変え、

knots = [0, 1, 2]
mults = [3, 1, 3]

という引数を導き出すことができます。これは、例えば 0 が 100 個並ぶような巨大なノットベクトル列も

knots = [0]
mults = [100]

のように、シンプルに「圧縮」して表記できる利点があるためです。

この NURBS 曲線を表示してみると、次のようになりました。

B-Spline curve

オマケ: ライブラリはどれ?

OCCには65個もの共有ライブラリが存在しており、自分が使いたいクラスがどのライブラリで定義されているのか、迷うことがあります。

OCCを使ったプログラミングで最低限必要なライブラリは、TKernel.so です。TKernel は間接的に tbb などのライブラリを参照しています。

さらに、自分が使いたいクラスのライブラリを調べるには、クラス・リファレンスの情報を参考にすればいいと思います。

例えば、BRepBuilderAPI_MakeEdge クラスを使いたい場合、クラス・リファレンスのページを参照すると、次のようになっていると思います。

ここで、赤枠で示された Toolkit の名前がそのままライブラリ名になっています。この例では、BRepBuilderAPI_MakeEdge は TKBRep と TKTopAlgo が必要ということになります。

この情報を基に

g++ -lTKernel -lTKBRep -lTKTopAlgo -L/usr/lib/opencas -I/usr/include/opencascade source.cpp

という具合にリンクしてあげると良いと思います。

ちなみに Microsoft Windows のダイナミックリンクライブラリの場合も、同様に調べることができます。

OpenCASCADE で点、線分、ポリラインを作成する。

OpenCASCADE関連の日本語情報がほとんどありませんので、Tipsというか、使い方というか、自分用のメモ的なものを小出しにしてまとめていこうと思います。

OCCで形状を作成する場合、特殊なものでなければ BRepBuilderAPI を用います。点、線分、ポリラインも例に漏れずこれを使います。

点を作る

OCCの点は、扱うレベルによっていくつか言い方が変わってきます。
ここではトポロジーレベル(TopoDS)の点(Vertex)を作成します。

gp_Pnt p(10, 20, 0);
TopoDS_Vertex v = BRepBuilderAPI_MakeVertex(p);

簡単ですね!

上の例では、座標値 [10, 20, 0] の位置に存在する点を作成しました。
gp_Pnt は、これも点と言えば点なのですが、主に X, Y, Z の座標値を格納したり、引数に渡す時の入れ物としての「点」です。
一方、TopoDS_Vertex は、幾何として三次元空間上に存在する「点」です。

なんだか良く分からない説明ですが、gp_Pnt をその人のプロフィール、TopoDS_Vertex がその人自身、みたいな感じで見てもらったら結構です。(かえって分かりづらいかな…)

通常は上の例で問題がないんですが、もう少しだけ「ちゃんと」記述すると、次のようにも書けます。

gp_Pnt p(10, 20, 0);
BRepBuilderAPI_MakeVertex mv(p);
TopoDS_Vertex v = mv.Vertex(); // Vertex として受け取る場合
TopoDS_Shape  s = mv.Shape();  // Shape として受け取る場合

BRepBuilderAPI_Make~系のクラスは、作る目的の型に特殊化してくれるメソッドと、抽象的な TopoDS_Shape 型で返してくれる Shape() が大体備わっています。用途に応じて使い分けができます。

線分を作成する

OCCにおける線という概念も、点と同様に扱うレベルによって言い方が変わってきます。ここでも、まずはトポロジーレベルでの線分を作成してみましょう。

gp_Pnt start_point(0, 0, 0);
gp_Pnt terminal_point(10, 20, 0);
TopoDS_Edge e = BRepBuilderAPI_MakeEdge(start_point, terminal_point);

gp_Pnt 型で始終点を定義して、それを引数に BRepBuilderAPI_MakeEdge() で線分を作成しています。これも Vertex 同様に MakeEdge のオブジェクトを作り

gp_Pnt start_point(0, 0, 0);
gp_Pnt terminal_point(10, 20, 0);
BRepBuilderAPI_MakeEdge me(start_point, terminal_point);
if (me.IsDone()) {
    TopoDS_Edge e = me.Edge();   // Edge として受け取る場合
    TopoDS_Shape s = me.Shape(); // Shape として受け取る場合
}

という風に書く事もできます。Vertex と一つ違うのは、IsDone() メソッドで判定している点です。
Vertex の場合は、点の作成に失敗することがありませんが、線分の場合は例えば始終点が同一点であった場合など、線分として成立しない引数が渡される可能性があります。
そこで、作成が上手くいったかどうかを IsDone() で判定しているわけです。
MakeEdge に限らず、引数によっては成立しない形状を作成する際には、いきなり Shape() を取得するのではなく IsDone() でチェックすることを心掛けましょう。

ポリラインを作成する

ポリラインは BRepBuilderAPI_MakePolygon を使って作成します。トポロジーレベルでの幾何の型は TopoDS_Edge または TopoDS_Wire になります。
作成した形状によって Edge / Wire にいずれかになるわけではなく、次のように用途によって受け取ることができます。

BRepBuilderAPI_MakePolygon mp;

mp.Add(gp_Pnt(0, 0, 0));
mp.Add(gp_Pnt(10, 0, 0));
mp.Add(gp_Pnt(10, 10, 0));
mp.Add(gp_Pnt(20, 10, 0));

mp.Build();

if (mp.IsDone()) {
    TopoDS_Edge e = mp.Edge();    // Edge として
    TopoDS_Wire w = mp.Wire();    // Wire として
    TOpoDS_Shape e = mp.Shape();  // Shape として
}

ポリラインの通過点を順番に Add() していき、最後に Build() します。
点や線分や座標値を1つ、または2つ指定された瞬間にその形状が確定しますがポリラインの場合は複数の通過点によって構成されていますので、明示的に Build() を呼ばないといけません。

オマケ1: TopoDS_Shape からダウンキャストする

発生したシェイプは、とりあえず TopoDS_Shape で受け取っておいて、必要な時にダウンキャストして利用することがよくあります。

キャストと言えば、一般的にはポインタの型変換ですがOCCでは実体アドレスから特殊化する方法があります。(OCCにおけるポインタ隠蔽の仕組みについては別の機会に書きます)

TopoDS_Shape s = ...
TopAbs_ShapeEnum type = s.ShapeType()

if (type == TopAbs_Vertex) {
    TopoDS_Vertex v = TopoDS::Vertex(s);
    ...
}
else if (type == TopAbs_Edge) {
    TopoDS_Edge e = TopoDS::Edge(s);
    ...
}
else if (type == TopAbs_Wire) {
    TopoDS_Wire w = TopoDS::Wire(s);
    ...
}
...

何らかの処理によって発生した TopoDS_Shape 型の s を、その ShapeType を見てそれぞれの型に「ダウンキャスト」しています。
上の TopoDS::Vertex, Edge, Wire のほか、Face, Shell, Solid, CompSolid, Compound, Shape もそれぞれの型に対応して使うことができます。

また、これらの TopoDS_* 型は、すべて TopoDS_Shape の派生クラスになっているので、

TopoDS_Shape s = some_builder_instance.Edge();

と、親の型で受け取っても、必要に応じてダウンキャストできるので問題はありません。
これらの機能により、トポロジーレベルのオブジェクトは柔軟に扱うことができます。

オマケ2: ヘッダーファイルは?

OCCは大抵の場合、使いたいクラスの型名がそのままヘッダーファイル名になっています。
その為、「gp_Pnt」や「BRepBuilderAPI_MakeEdge」を使いたい場合は、

#include <gp_Pnt.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>

のように、拡張子「hxx」をつけて #include してあげればOKです。
もちろん、INCLUDE に OCC の inc ディレクトリが指定しておかなければなりません。

タミヤ 1/700 軽巡 矢矧&フジミ 1/700 空母 海鷹

本日、6月29日は佐世保大空襲が行なわれた日です。昭和20年の半ば、弱りきった日本にトドメを刺すべく日本各地で米軍による空襲がくりかえされていました。全国でも有数の軍港である佐世保もまた例外ではなく、3月に敵偵察機が来て、4月と5月のボーイング B29の空襲で100名ほどの市民が殺害され、6月29日の大空襲では1200名以上が犠牲になったそうです。 市内に子供のころから住んでいると、平和教育や親戚、親しい方などから、当時の空襲を体験したお年寄のお話を聞く機会が何度もありましたが、その時は成すすべもなかったようです。弓張岳に設置された高角砲台から応射していたとのことですが、高高度爆撃機 B29 まではまるで届かなかったようです。また、佐世保には鎮守府がある上に各地に軍関連施設があり、佐世保基地のほか、大村基地にも佐世保海軍航空隊が配備されていましたが、度重なる空襲で大村基地は壊滅。大村海軍航空隊も前月の5月5日に解隊されており、迎撃能力はほとんどない状態でした。佐世保市街に古い木造建築物がまったく残っていないのはこのためです。戦後は区画整備がなされ、特に中心地はかなり道路が変わっているようです。

まあ、戦争と割り切ってしまえば仕方のないことですが、続く8月9日の長崎市への原爆投下までを含めて考えると、ほとんど「なぶり殺し」という言葉の方が合っている気もします。日本も、もちろん朝鮮半島や大陸、東南亜諸国で似たような事はやっていますが、米国だけはやられる立場になったことがないことが考えさせられるところです。

さて、タミヤ ウォーターラインシリーズ 1/700 の軽巡洋艦「矢矧」上甲板を筆塗りを盛大に失敗して、軽い現実逃避で他のモノを色々作っていました。

前回の水上機の色を塗って乾燥している間、作るものが無くなったので、勇気を出して矢矧の塗り直しをやろうと決意しました。

矢矧の上甲板を再塗装

こんなに広い面を筆塗りするのは初めてだったんですが、やっぱりヒドいことになりました。

写真で見ていても泣きたくなるような筆ムラです。塗っている途中からこういう状態だったので少し不安でしたが「乾燥したら色が馴染むのかなぁ」とにわかに期待していました。

塗料をもっと薄めて、何度も重ね塗りをしたり、練習を積み重ねれば、まだマシになるのか、それともこういう広い面はエアブラシやスプレーじゃないとムリなのか…、今後の研究課題です。

このリノリウム甲板を塗ろうとした際にラッカースプレーがあればそれを使っていたんでしょうが、なかったので物は試しと筆塗りをしてみたのが裏目に出たパターンですねー。

1/2000 戦艦「ミズーリ」を購入した時、ラッカースプレーも一緒に買ってきてました。準備は整っているので、筆で塗った塗料を落としていきます。

溶剤で落とした状態です。上手くいくかどうか分からず、慎重になりすぎて落としていたのでちょっと残りがありますが…。船側や上甲板の一部は、前回の矢矧の記事で紹介したとおり、既に軍艦色が塗装されているのでゴシゴシと落としていくのも少し億劫になってました。まあ、同じ色で再塗装するわけなので、このくらいで大丈夫だろうと言い聞かせながら、スプレーでいざ再塗装!

海鷹の組み立て開始

矢矧の上甲板が復活するのを信じ、乾燥させている間にフジミの 1/700 航空母艦「海鷹」の組み立てに入りたいと思います。

説明書では、部分部分のパーツをまず組んで、それを船体に載せて行く手順で組み立てていくよう指示がありましたが、今回のケースでは塗装を行いたいので、

  1. 一番大きい船体を組む
  2. 次に大きい前端・後端部の甲板を取り付け
  3. 左右に付き出た甲板の取り付け
  4. その上の構造物・支柱を取り付け
  5. 軍艦色塗装
  6. 軍艦色以外のパーツ(カッターなど)を別に塗装して取り付け
  7. 飛行甲板を塗装して取り付け

という手順でやっていこうと思います。実際の船の建造もそうですが、大きな構造物から小さな構造物を取り付けていくのが主です。支柱付きの付き出た甲板を作っておいて、それを船体に取り付けさせる説明書になんだか違和感がありました。んー、文字で書いても意味が分からないか。まあ、それはそれで。

さて、この海鷹の船体はセンターラインで右舷と左舷が分かれています。両舷ともプラスチックの板なので、手で持ってもぺろんぺろんになるくらい安定していません。船体内部に接合を安定させるための補助的な骨とか入ってたら良いんですが、そういうのも見当たりません。

駆逐艦では不安定な接着面の接合っていうのはありませんでしたが、前回のミズーリでマスキングテープで仮止めしておいてから接着する方法を学びました。つまり、以前ようにそのままなんとか接合しようとするような私ではないのだよ…!

ということで、テープまみれにしてから、裏から接着剤を流し込む方法で組み立てを開始しました。「抑えておく」というツールに、最初の頃は洗濯バサミを多様していましたが、力が強すぎたり、口が小さかったり、あまり使い勝手が良くありません。テープなら微妙な抑え具合も可能なので、特に板を直角に接合しなければならないようなところの「抑え」にちょうど良い具合です。

海鷹のブリッジは、船首側の飛行甲板の下にあります。あんまり見えないところですが、ブリッジの窓の部分は最初から同梱されているエッチングパーツを取り付けるようです。

7番の窓枠を箱状に組み立ててから接着するんですが、まだ勇気がなくて放置してあります。窓枠も精密なのは嬉しい気持ちもあり、だったらもうちょっとよく見えるアンテナ支柱をエッチングパーツにしてくれとも思いつつ。

矢矧マスキング&再塗装

そんな事をやっていると、塗装した矢矧が乾燥していました。

うっわ!何これ!コイツ…思った以上にキレイになったぞ!

霧状にして塗料を飛ばすだけでこんなに違うのかってくらいムラもなくフラットになりました。これまで、一度に広い面積が塗れるモンだーと考えていたスプレーの新たな利点を実感した瞬間でした。特に同じ面を筆塗り・スプレーを見比べてみるので、めちゃくちゃ違うっていうことが私にも理解できたわけです。

テンションが上がったので、当初サボってやっていなかった(ちゃんとした)マスキングを施しました。

リノリウム甲板色で塗装しちゃっていた軍艦色の部分を露出するかたちで、マスキングテープをペタペタしています。結構地味な作業で、軽く1時間は超えたと思います。しかし、多分こういう作業が塗装が終わった時にしっかりと違いが出てくるはずだよな〜と思って頑張ってペタペタ。

ワイヤーを巻いてる装置や弾薬箱といったものは、もっと上級者の人はモールドを削ぎ落としてエッチングパーツと置き換える、といったこともするらしいです。この手間や塗装後の塗り分け具合を考えれば、その方法のほうが確かにキレイな仕上がりなんだろうなあ。ただ、自分はそういうパーツを持っていないので、モールドの隙間まで丹念にマスキングしていきます…。初めてこの精度でのマスキングをしたわりには、我ながら丁寧にできたと思います。

あとは軍艦色で再々塗装して、待つのみ!乾燥後のテープを剥す瞬間が待ち遠しいですね。

待っている間に、海鷹の手順3だった「左右に付き出た甲板の取り付け」を進めておきます。この甲板の上に機銃やカッター、アンテナ支柱などの小物がのってきます。

矢矧、乾燥が楽しみだなあ。

静岡模型教材共同組合 1/700 水上機(二式水戦、零式水偵、強風、晴嵐)

静岡模型教材共同組合は、タミヤ、アオシマ、ハセガワの3社からなるウォーターラインシリーズを出しているメーカーの業界団体です。1992年までフジミも加盟していました。 ウォーターラインシリーズの1000円以上する 1/700 スケール駆逐艦には、各社レーベル共通のウォーターライン小型艦兵装セットが付属しており、その中に水上機も4機含まれています。

付属しているのは、

  • 二式水上戦闘機
  • 零式小型水上偵察機
  • 水上戦闘機 強風
  • 特殊攻撃機 晴嵐

です。

二式水戦は、「ジパング」の初めの頃、父島近海で海鳥と戦闘した戦闘機です。強風は紫電・紫電改のベースになった戦闘機で、Wikipedia の記事には、佐世保海軍航空隊所属の強風の写真が掲載されています。二式水戦も佐世保航空隊に常駐していた戦闘隊の主力だったようです。また、晴嵐は、2012年まで世界最大だった伊四〇〇号型潜水艦に搭載されるべく開発された攻撃機です。すべて水上機なので、フロートがついています。いわゆる「ゲタ履き」と呼ばれる飛行機です。

一番最初に作った「吹雪」の時にこの4機の組立に挑戦しましたが、結果は惨敗。まともにゲタを履かせられたのは1機のみでした。

接着剤の使い方・着け方が全然分かってなかった上に、組み立て前に塗装してしまった事が大きな敗因だったと思います。今回、リノリウム甲板の塗りがヒドい事になっている矢矧の状態からの現実逃避に引き続き、「三日月」についていたこれらの水上機作成にリベンジしたいと思います。(「」にはこのパーツは付属していませんでした。)

基本的な事で笑われるかもしれませんが…、前回の失敗の経験から、次の点に注意して組み立てました。

  1. 接着剤は本当に微量で良い。つまようじの先くらいの量で十分。
  2. 機体を固定する。
  3. 塗装前に組む。

これだけの事なんですが、ピンセットで慎重にフロートを取り付ける作業は、なんとか無事に4機ともクリアすることができました。

完全に乾燥するのを待って、次は塗装に入りたいと思います。