佐世保海軍工廠で建造された艦船一覧

艦船模型を作る上で購入の参考にしようと,佐世保海軍工廠で建造された艦船をまとめてみました

艦名 艦種 備考
千歳 航空母艦 空母への改装。
明石 工作艦
武蔵 戦艦 建造は三菱長崎造船所、艤装が佐世保。
赤城 航空母艦 全通式飛行甲板への近代化改装。
加賀 航空母艦 全通式飛行甲板への近代化改装。
最上 航空巡洋艦 航空巡洋艦への改装。
龍田 軽巡洋艦
球磨 軽巡洋艦
北上 軽巡洋艦
長良 軽巡洋艦
由良 軽巡洋艦
夕張 軽巡洋艦
阿賀野 軽巡洋艦
矢矧 軽巡洋艦
酒匂 軽巡洋艦
睦月 駆逐艦
三日月 駆逐艦
駆逐艦
駆逐艦
初春 駆逐艦
若葉 駆逐艦
白露 駆逐艦
夕立 駆逐艦
朝潮 駆逐艦
雪風 駆逐艦
磯風 駆逐艦
伊401 潜水空母

アオシマ 1/2000 空母エンタープライズ

以前、アオシマ1/700雪風のオマケで買ってきたアオシマの 1/2000 空母「エンタープライズ」を作ります。いつものように、西海模型さんで300円で売っていました。値段も手頃ですし、空いた時間にサクサク作れるから面白いですね。

このエンタープライズはCV-6のヨークタウン級2番艦で、太平洋戦争で日本とやりあったり、日本本土空襲を行なった方です。1968年に佐世保に入港した原子力空母エンタープライズ(CVN-65)とは別です。

さて、「俺様海軍工廠」にとっては初の正規空母の建造です。 がんばっていきましょうー!

DSC_0033

DSC_0034

このシリーズは裏面が組み立て説明書になっているので、購入前に大体の難易度が分かって嬉しいです。前回作成した零戦二二式や護衛艦しらねよりも簡単そうですね!

DSC_0036

パーツ全部はこのような感じ。同シリーズの戦艦ミズーリ作った時にも書きましたが、こいつも船体が分かれています。さらに喫水よりも上の船体も両舷がバラバラです。少ない接点で固定するのは難易度が高いので、気合いを入れていかねば…。

DSC_0039

そう思って意気込んで船体を組むと、喫水より上の船体は組み立て用の補強パーツが入っており、難なく組み立てることができました。右舷・左舷にそれぞれ空いた穴に補強用に独立したパーツをはめ込んで接着できます。これなら楽チン。

さらに、ちゃっちゃか飛行甲板と上部構造物を載せたら一通り完成!

DSC_0041

はやっ。

削り出しと接着を含めて、10分くらいしかかかっていないと思います。さて、組み終わったら次は塗装です。写真でも見てわかるように、未塗装の状態だと安いプラスチック感がすごいです。ちょうど、タミヤの呉カラーを買ってきて使っていなかったので、色の確認ついでに吹いてみたいと思います!

DSC_0042

塗装後です。マスキングをする前に撮影すれば良かったんですが、写真が抜けていましたね。分かりづらいですが、色はよく使っているMr.Colorの佐世保カラーよりもかなり明るめな風合いで、護衛艦しらねの船体色に近い感じがします。これなら、出身地別に船体色を変えた駆逐艦を並べると色のメリハリが出て楽しそうです。

さて、このマスキングは何かというと、飛行甲板のラインを引く練習台です。空母といえば、フジミの1/700海鷹が飛行甲板の設置を前に作業がストップしていますが、初めての空母だったので「飛行甲板の塗装はどうしようかな〜」と考えながら止まっていたのです。

今回、良い機会なのでエンタープライズさんにはライン引きの練習台になってもらいましょう。

DSC_0044

あまり溶かしすぎないようにした白を筆でぶりぶり塗ります。乾燥を待ってからテープを剥がすと

DSC_0048

なかなか良い感じにラインが引けました! マイナーな軽空母はデカールなどもあんまりないですし、この方法で自力で線を引けばいいみたいです。

そしてどうやら、線を一本引いたところで満足しちゃった模様。手を加えたくなったら、完成後でも気軽に加えられるところも、低価格モデルの良いところです。

DSC_0050

戦艦ミズーリに比べ、ディティールがすっきりとしています。空母なので当たり前ですが、細部の表現が難しい 1/2000 スケールのモデルだとなおさらモノ足りない感じもしますね(笑)

DSC_0053

細かなところに色をつけ、船体を結合、船台に乗せれば完成です! 接着剤と塗料の乾燥時間まで含めて、1時間半で完成しました。上手い人ならもっと早いのかな。 艦載機は申し訳程度に2機付いていましたが、ずらーっと甲板に並べるか、何も載せないのが好きなので、今回は出番ナシです。

前回のしらね、零戦二二式と一緒にディスプレイするとこんな感じです。

DSC_0059

百均に売ってあるディスプレイケースは、1/700 ウォーターラインシリーズの駆逐艦にはピッタリで、重ねて置くこともできて重宝してます。

零戦は1/100、しらねは1/1250、エンタープライズは1/2000とスケールがバラバラですが、しらねとエンタープライズは図らずしもいい感じにまとまっています。

翼コレクション第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 ディレクトリが指定しておかなければなりません。