Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
1
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

POV-Rayでの外部ファイルの読み込み

はじめに

これは POV-Rayによる数学お絵かき入門 Advent Calendar 2017 の13日目の記事です.

povrayでは外部ファイルを読み込むためのコマンドが用意されています.
これによって他の言語で計算した結果を取り込んでPOV-Rayで可視化させる事が可能になります.
この具体例は第15回で見る予定です.

公式ドキュメントでは以下に相当しますが, 具体例に乏しいので今回に限ってはあまり参考にならないかもしれません.
http://www.povray.org/documentation/3.7.0/r3_3.html#r3_3_2_3

使い方

他の殆どのプログラミング言語のそれとは異なり, POV-Rayでは特定の形式のテキストファイルしか扱えません.
換言すれば, あまり自由度は高くないです.

読み込み可能な形式

次に外部ファイルに必要な要件を箇条書きで示します.

  • ファイルはテキストファイルでカンマ,区切りされている必要があります.
  • 各要素は 数値 / ベクトル / 文字列 の何れかである必要があります.
  • カンマ前後に改行やスペースなどの空白文字が含まれていても構いません.
  • ただし次のような通常のcsvファイルは正常に読み込めません. これは行末にカンマが入っていないためです.
2,<4,0,0>,"hoge"
3,<8,0,0>,"fuga"
5,<0,1,1>,"piyo"
  • 行末がカンマで終わるような形式であればこれは可能です.
2,<4,0,0>,"hoge",
3,<8,0,0>,"fuga",
5,<0,1,1>,"piyo"
  • 拡張子は任意です.

構文

以下で#fopen, #read, definedの使い方を説明します.

ファイルを開く

ファイルを開くには次のように#fopenを使います.
ここでFILE_HANDLE_IDENTIFIERにはファイルを扱うための識別子が, FILE_NAMEにはファイル名が入ります.

#fopen FILE_HANDLE_IDENTIFIER FILE_NAME read

最後のreadはファイルを読むための宣言です.

要素を読み込む

ファイルの要素を読み込むためには次のように#readを使います.
ここでFILE_HANDLE_IDENTIFIERは先程宣言したファイル識別子で, DATA_IDENTIFIERには要素の読み込み先となる識別子が入ります.

#read(FILE_HANDLE_IDENTIFIER, DATA_IDENTIFIER1, ... , DATA_IDENTIFIERn)

POV-Rayでは最初の#readでファイルの先頭の要素が読み込まれ, 続いて読み込まれる度に要素の読み込み位置が一つずつ下がっていきます.

つまり, 最初に#fopenでファイルを開いた後は#readを繰り返せば順々に要素が読み込まれていきます.

関数definedについて

さて, POV-Rayには識別子が定義されているかを調べるための関数definedが用意されています.
このdefinedは識別子が宣言されていればtrueを, 宣言されていなければfalseを返します.
(第四回に見たように, POV-Rayでは真偽値は数値で表現されていたのでした)
ファイル識別子にこの関数を使えば, 読み込む要素が残っている場合にtrueを, 残っていない場合にfalseを返します.
これの有用性は後述の具体例で見ます.

ファイルを閉じる

レンダリング処理が終われば(正確には構文解析が終われば)ファイルは自動的に閉じられます.
#fcloseでファイルを閉じることも可能ですが, 基本的には使う必要はありません.

具体例

最初の例

次のコードを最初の例とします.

hoge.txt
2,<4,0,0>,"hoge",
3,<8,0,0>,"fuga",
5,<0,1,1>,"piyo"
#fopen fuga "hoge.txt" read
#read(fuga,val1,vec1,str1)
#read(fuga,val2,vec2,str2)
#read(fuga,val3,vec3,str3)

この宣言によってval1, val2, val3にそれぞれ2, 3, 5が入ります.
ベクトル, 文字列についても同様です.

点列の描画

外部ファイルに書かれた複数の座標から, それらを中心とする複数の球面を描くには次のようにします.

hoge.txt
<1,0,0>,<2,0,0>,<3,0,0>,<4,0,0>,<5,0,0>,
<0,1,0>,<0,2,0>,<0,3,0>,<0,4,0>,<0,5,0>,
<0,0,1>,<0,0,2>,<0,0,3>,<0,0,4>,<0,0,5>
#fopen fuga "hoge.txt" read
#while(defined(fuga))
    #read(fuga,vec)
    sphere{vec,0.1 pigment{rgb<1,0,0>}}
#end

このように, definedを使うことで, 座標の書かれたテキストファイルから点列を描くことが出来ます.

これを応用すれば次のアニメーションを描くことが出来ます.

これはLorentzアトラクターのアニメーションで, 色々の初期条件からアトラクターに近づく様子を表しています.

注意点など

配列

#readで読み込む際に配列の要素に書き込む, つまり次のように書くことは出来ません.

#read(fuga,ary[1])

配列に入れたい状況では, 次のように一時変数を利用します.

#read(fuga,tmp)
#declare ary[1]=tmp;

書き込み

書き込みのための#writeも用意されていますが, あまり使わないため今回は省略しました.
詳しくは上記の公式ドキュメントを参照して下さい.
(ひょっとすると改めて書くかもしれません)

ファイル読み込み vs インクルードファイル

筆者の場合はファイル読み込みの使用頻度が低く毎度のように構文を忘れるので, インクルードファイル(第19回予定)を直接他のプログラミング言語から出力する方が使い易く感じる事もあります.

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
1
Help us understand the problem. What are the problem?