lasファイルを書き込むのはなかなか大変です。
ヘッダにデータ点群の情報をいろいろと書き込む必要があるためですが、
その情報の中に点数、範囲などがあるため、
例えばXYZのテキストファイルをlasファイルにしようとしたりする場合、
情報収集のために1回スキャンし、
ヘッダを書き込んだ後で2回目のスキャンで点群をlasファイルに書き込まなければいけないようです。
実際、付属のtxt2lasのソースコードを見るとそうしているようです。
というのも、LASWriter
クラスのコンストラクタがLASHeader
オブジェクトを要求するためです。
何とかヘッダを楽チンに作りたいところです。
入力元がlasファイルなら、入力lasファイルのヘッダをコピーし、
必要なところだけを修正して書き出したりすればいいはずです。
スキャン2回というのも大変です。
それでなくてもLASファイルは大容量になりやすいので、2回もスキャンしていては処理時間が膨大になってしまいます。
ところがスキャン1回にする方法もどうやらあるようです(少々インチキくさい)。
仮ヘッダをとりあえず書き込んでおいて、点群書き込みと情報収集を同時に行い、
最後に再びヘッダを書き込むという方法です。
なお、可変ヘッダはまた別のようです。
本当にできるでしょうか
以下の例では、入力LASファイルから何らかの条件で点を抽出して出力LASファイルに書き込む例です。
変数reader
に入力LASファイルのLASReader
オブジェクトが、
変数header_in
には入力LASファイルのLASHeader
オブジェクトがそれぞれ入っているとします。
std::ofstream ofs; int nPoints = 0; double dMinX, dMinY, dMinZ; double dMaxX, dMaxY, dMaxZ; dMinX = dMinY = dMinZ = DBL_MAX; dMaxX = dMaxY = dMaxZ = -1*DBL_MAX; int aRecCount[5] = { 0, 0, 0, 0, 0 }; if ( !liblas::Create( ofs, argv[2] ) ) { exit( 1 ); } // 仮ヘッダの作成 liblas::LASHeader header_out; // この時点でわかる情報を設定する header_out.SetDataFormatId( header_in.GetDataFormatId() ); header_out.SetScale( header_in.GetScaleX(), header_in.GetScaleY(), header_in.GetScaleZ() ); header_out.SetOffset( header_in.GetOffsetX(), header_in.GetOffsetY(), header_in.GetOffsetZ() ); // 仮ヘッダを使ってLASWriterオブジェクトを作成 liblas::LASWriter writer( ofs, header_out ); // スキャン開始 while ( reader.ReadNextPoint() ) { liblas::LASPoint const &p = reader.GetPoint(); if ( /* 何か条件*/ ) { writer.WritePoint( p ); nPoints++; if ( p.GetX() < dMinX ) dMinX = p.GetX(); if ( p.GetY() < dMinY ) dMinY = p.GetY(); if ( p.GetZ() < dMinZ ) dMinZ = p.GetZ(); if ( p.GetX() > dMaxX ) dMaxX = p.GetX(); if ( p.GetY() > dMaxY ) dMaxY = p.GetY(); if ( p.GetZ() > dMaxZ ) dMaxZ = p.GetZ(); aRecCount[p.GetReturnNumber()]++; } } // 残りの情報をヘッダに設定 header_out.SetMin( dMinX, dMinY, dMinZ ); header_out.SetMax( dMaxX, dMaxY, dMaxZ ); header_out.SetPointRecordsCount( nPoints ); header_out.SetPointRecordsByReturnCount( 0, aRecCount[0] ); header_out.SetPointRecordsByReturnCount( 1, aRecCount[1] ); header_out.SetPointRecordsByReturnCount( 2, aRecCount[2] ); header_out.SetPointRecordsByReturnCount( 3, aRecCount[3] ); header_out.SetPointRecordsByReturnCount( 4, aRecCount[4] ); // 完成ヘッダを再度書き込み writer.WriteHeader( header_out );
何か条件のところに、例えば1st returnだったらなどの条件を入れたりするといいでしょう。
ためしに実行してみるとどうやらちゃんとできているようです。