Skip to content

Commit

Permalink
LOD検索は冒頭50MBだけ見れば十分であることを発見、その検証方法を残す
Browse files Browse the repository at this point in the history
  • Loading branch information
linoal committed Dec 4, 2023
1 parent b2e223d commit 9cb3089
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 3 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
*.a filter=lfs diff=lfs merge=lfs -text
*.lib filter=lfs diff=lfs merge=lfs -text
*.dll filter=lfs diff=lfs merge=lfs -text
data/日本語パステスト/udx/bldg/52385618_bldg_6697_op.gml filter=lfs diff=lfs merge=lfs -text
Git LFS file not shown
23 changes: 22 additions & 1 deletion include/plateau/dataset/lod_searcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,34 @@ namespace plateau::dataset {

/**
* \brief GMLファイルに含まれるLOD番号を検索します。
* ファイルの中身を文字列検索し、":lod(番号)" にヒットした番号をフラグ形式で返します。
* ファイルの中身を文字列検索し、":lod(番号)" にヒットした番号のうち高いものを返します。
*
* 用途:
* PLATEAUデータのインポートにおける範囲選択画面で、GMLファイルについて利用可能なLODを検索します。
* 範囲選択画面では多くのGMLファイルを検索対象とするので、高速である必要があります。
*
* 検証方法:
* このクラスに変更を加えたとき、多くのGMLファイルに関して結果が変わらないかどうかを検証する方法を残しました。
* 詳しくはtest_lod_searcher.cpp の DisplayLodsRecursive という名前のテストのコメントを参照してください。
*/
class LIBPLATEAU_EXPORT LodSearcher {

public:
/// ファイル中に含まれる最大LODを返します。
/// 引数 specification_max_lod は仕様上とりうるLODの最大値であり、そのLODが見つかった場合は探索を終了してその値を返します。
static int searchMaxLodInFile(const std::filesystem::path& file_path, int specification_max_lod);
static int searchMaxLodInIstream(std::istream& ifs, int specification_max_lod);

private:

/**
* GMLファイルの冒頭の何メガバイトを検索対象とするかの値です。その値以降は検索しません。
* サイズを制限しないと、範囲選択画面で重いGMLファイルのアイコンを1つ表示するのに長々と待たされることになります。
* 制限が50MBであれば、2023年の東京、沼津、新潟の全データにおいて、全文を読むのと結果が変わらないことを検証済みです。
* しかし、今後のあらゆるデータで大丈夫であるという保証はなく、今後に調整が必要になるかもしれません。
*/
static constexpr long max_gml_read_size = 50 /*メガバイト*/* 1000000;
// サイズ制限を無くしたい場合は下のコメントアウトを外してください
// static constexpr long max_gml_read_size = LONG_MAX;
};
}
9 changes: 7 additions & 2 deletions src/dataset/lod_searcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ int LodSearcher::searchMaxLodInFile(const fs::path& file_path, int specification
int LodSearcher::searchMaxLodInIstream(std::istream& ifs, int specification_max_lod) {
// 注意:
// この関数は実行速度にこだわる必要があるため、 std::string よりも原始的な C言語の機能を積極的に利用しています。
// 用途はPLATEAUデータのインポートにおける範囲選択画面で、GMLファイルについて利用可能なLODを検索します。
// 範囲選択画面では多くのGMLファイルを検索対象とするので、高速である必要があります。

// 文字列検索で ":lod" にヒットした直後の数値をLODとします。
const static auto lod_pattern = u8":lod";
Expand All @@ -56,6 +54,7 @@ int LodSearcher::searchMaxLodInIstream(std::istream& ifs, int specification_max_
char chunk[chunk_mem_size];
const char* const chunk_const = chunk;
int found_max_lod = -1;
long total_read_size = 0;

do {
ifs.read(chunk, chunk_read_size);
Expand Down Expand Up @@ -83,6 +82,12 @@ int LodSearcher::searchMaxLodInIstream(std::istream& ifs, int specification_max_
auto next_pos = std::min(found_ptr + lod_pattern_size, chunk_last);
found_ptr = strstr(next_pos, lod_pattern);
}

// ここまで読めば十分という値に達したとき
total_read_size += read_size;
if(total_read_size > max_gml_read_size) {
break;
}
} while (!ifs.eof());


Expand Down
35 changes: 35 additions & 0 deletions test/test_lod_searcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@
#include <plateau/dataset/lod_searcher.h>
#include <fstream>
#include "plateau/dataset/city_model_package.h"
#include <filesystem>
#include <chrono>

namespace plateau::dataset {
namespace fs = std::filesystem;
namespace chrono = std::chrono;

class LodSearcherTest : public ::testing::Test {
protected:
void SetUp() override {
Expand Down Expand Up @@ -37,5 +42,35 @@ namespace plateau::dataset {
TEST_F(LodSearcherTest, MultipleLods) { // NOLINT
ASSERT_EQ(getMaxLod(":lod2:lod3"), 3);
}

TEST_F(LodSearcherTest, SearchInFile) { // NOLINT
const auto start_time = chrono::system_clock::now();
const int max_lod = LodSearcher::searchMaxLodInFile(fs::u8path(u8"../data/日本語パステスト/udx/bldg/52385618_bldg_6697_op.gml"), CityModelPackageInfo::getPredefined(PredefinedCityModelPackage::Building).maxLOD());
const auto end_time = chrono::system_clock::now();
ASSERT_EQ(max_lod, 3);
double elapsed = chrono::duration_cast<chrono::milliseconds>(end_time - start_time).count();
std::cout << "time: " << elapsed << " ms" << std::endl;
}


/// 注意:下のコメントアウト部分は削除しないでください。

/// 今後、LODSearcher に変更を加えたとき、結果が変わらないかどうかを検証する手段として下のコードをコメントアウトして残しておきます。
/// 実行方法:
/// コメントアウトを外し、パスをテストしたいフォルダパスに変更してテスト実行します。
/// するとGMLファイル名とLODが出力されるので、変更前後でそのdiffをとって出力が同じであることを検証できます。
// TEST_F(LodSearcherTest, DisplayLodsRecursive) { // NOLINT
// // 下のパスを、ご自分のPCでテストしたいフォルダのパスに変更してください。
// const auto src_dir = fs::u8path(u8"F:\\Desktop\\plateauData\\15100_niigata-shi_2022_citygml_1_op\\udx");
//
// std::cout << "==== LOD Search Result ====" << std::endl;
// for(const auto& entry : fs::recursive_directory_iterator(src_dir) ) {
// if(entry.is_directory()) continue;
// if(entry.path().extension() != ".gml") continue;
// int lod = LodSearcher::searchMaxLodInFile(entry.path(), 999);
// std::cout << entry.path().filename() << ": " << lod << std::endl;
// }
// std::cout << "==== LOD Search End ====" << std::endl;
// }
}

0 comments on commit 9cb3089

Please sign in to comment.