3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

バイナリフォーマットstlファイルをC++で読み込む

Last updated at Posted at 2021-07-10

はじめに

 流体解析みたいな数値シミュレーションコードを書いていると、境界条件としてstlファイル等のCADデータを使いたくなります。でも「C++ stlファイル 読み込み」とか検索しても、Standard Template Libraryを使ったファイルの読み込み方の記事ばかり出てくるんですよね...
 後輩に聞いたら「stlファイルのバイナリ形式は構造が単純なので意外と簡単に読み込める」と言っていたので、試しにやってみたら本当にすんなりできました。

概要

 本記事ではバイナリフォーマットのstlファイルをC++で読み込みます。アスキーフォーマットをご使用の場合はバイナリに変換する必要があります。バイナリstlファイルの構造は

HIRAMINE.com
Wikipedia

を参考にさせていただきました。

バイナリフォーマットstlファイルの構造

 バイナリフォーマットのstlファイルでは、まず任意の文字列(char[]型 80バイト)があって、次にポリゴン数(unsigned int型 4バイト)、そこから各ポリゴンのデータが続きます。各ポリゴンのデータは法線ベクトル(float型 4バイト×3成分)、頂点座標3つ(float型 4バイト×3成分×3点)の順で保存されています。

バイト数 データ型 内容
80 char[] ヘッダー(任意の文字列)
4 unsigned int ポリゴン数
4 float ポリゴン1つ目の法線ベクトルx方向
4 float ポリゴン1つ目の法線ベクトルy方向
4 float ポリゴン1つ目の法線ベクトルz方向
4 float ポリゴン1つ目の頂点1つ目のx座標
4 float ポリゴン1つ目の頂点1つ目のy座標
4 float ポリゴン1つ目の頂点1つ目のz座標
4 float ポリゴン1つ目の頂点2つ目のx座標
4 float ポリゴン1つ目の頂点2つ目のy座標
4 float ポリゴン1つ目の頂点2つ目のz座標
4 float ポリゴン1つ目の頂点3つ目のx座標
4 float ポリゴン1つ目の頂点3つ目のy座標
4 float ポリゴン1つ目の頂点3つ目のz座標
2 -- 未使用データ
4 float ポリゴン2つ目の法線ベクトルx方向
... ... ...

ソースコード全容

 先にソースコードの全容を示します。コードを簡単にするために、座標構造体のcoordとポリゴン構造体のpolygonを定義しました。

#include <iostream>
#include <fstream>
#include <vector>
using namespace std;

// 座標
struct coord{
    float x,y,z;
};

// ポリゴン
struct polygon{
    // 頂点座標
	coord v0,v1,v2;    
    // 法線ベクトル
	coord normal;
    // セット
	void set(coord v0_, coord v1_, coord v2_, coord normal_){
		v0 = v0_ ;
		v1 = v1_ ;
		v2 = v2_ ;
		normal = normal_;
	}    
};

int main(){

	// ファイルオープン
	ifstream fin( "StanfordBunny.stl", ios::in | ios::binary );
	if(!fin){
		cout << "file is not found." << endl;
		return 0;
	}

	// ポリゴン数の読み込み
	unsigned int num_polygons;
	fin.seekg(80,ios_base::beg);
	fin.read((char*) &num_polygons, sizeof(unsigned int) );

	// 各ポリゴンの法線と座標の読み込み
	vector<polygon> poly(num_polygons);
	for(int i=0; i<num_polygons; i++){
		coord vbuff[3];
		coord nbuff;
		fin.read((char*) &nbuff.x, sizeof(float));
		fin.read((char*) &nbuff.y, sizeof(float));
		fin.read((char*) &nbuff.z, sizeof(float));
		for(int j=0; j<3; j++){
			fin.read((char*) &vbuff[j].x, sizeof(float));
			fin.read((char*) &vbuff[j].y, sizeof(float));
			fin.read((char*) &vbuff[j].z, sizeof(float));
		}
		poly[i].set(vbuff[0],vbuff[1],vbuff[2],nbuff);
		fin.seekg(2,ios_base::cur);
	}
    
    // ファイルのクローズ
	fin.close();
	
}

解説

 各部分について簡単に解説します。

ファイルオープン

 ifstreamを使ってstlファイルをバイナリで読み込みます。

// ファイルオープン
ifstream fin( "StanfordBunny.stl", ios::in | ios::binary );
if(!fin){
    cout << "file is not found." << endl;
    return 0;
}

ポリゴン数の読み込み

 ポリゴン数はファイルの開始位置から80バイト(ヘッダー分)後方に書かれているので、finの読み込み位置を80バイトシークさせます。読み込みは通常のバイナリファイルの場合と同様です。

// ポリゴン数の読み込み
unsigned int num_polygons;
fin.seekg(80,ios_base::beg);
fin.read((char*) &num_polygons, sizeof(unsigned int) );

各ポリゴンの法線と座標の読み込み

 あらかじめ定義しておいたpolygon構造体のvectorをポリゴン数だけ確保し、順々にデータを格納していきます。読み込みに際して、データを一時的に保存するバッファーをcoord構造体で定義しておきます。ポリゴン数読み込みが完了した段階でfinは1つ目のポリゴンのデータ開始位置を見ているので、そのまま読み込みを始めます。法線と頂点3つを読み込み終わったら次のポリゴンの読み込みに進みますが、その前に未使用データの2バイト分finの位置を進めておきます。

// 各ポリゴンの法線と座標の読み込み
vector<polygon> poly(num_polygons);
for(int i=0; i<num_polygons; i++){
    coord vbuff[3];
    coord nbuff;
    fin.read((char*) &nbuff.x, sizeof(float));
    fin.read((char*) &nbuff.y, sizeof(float));
    fin.read((char*) &nbuff.z, sizeof(float));
    for(int j=0; j<3; j++){
        fin.read((char*) &vbuff[j].x, sizeof(float));
        fin.read((char*) &vbuff[j].y, sizeof(float));
        fin.read((char*) &vbuff[j].z, sizeof(float));
    }
    poly[i].set(vbuff[0],vbuff[1],vbuff[2],nbuff);
    fin.seekg(2,ios_base::cur);
}

まとめ

 C++でバイナリフォーマットのsrlファイルを読み込む方法を紹介しました。ファイルのバイナリ入出力を使ったことがある方であればそんなに難しくないと思います。ご参考になれば幸いです!

3
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?