From 96d455adeaf041e8c9498552df48b4fb99d0b963 Mon Sep 17 00:00:00 2001 From: Linoal <1321932+linoal@users.noreply.github.com> Date: Mon, 7 Apr 2025 16:21:43 +0900 Subject: [PATCH 01/19] =?UTF-8?q?MeshCode=E3=82=92=E8=A6=AA=E3=82=AF?= =?UTF-8?q?=E3=83=A9=E3=82=B9GridCode=E3=81=AB=E7=A7=BB=E8=A1=8C=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gitignore cmakelists.txt gitignore clangd grid_code.h standard map grid GridCode::create grid実装中 同上 ビルド通る C++テスト通る fix c wrapper gmlfile::gridCode 同上 以降途中 移行中 --- .clangd | 7 ++ .gitignore | 5 +- .idea/vcs.xml | 2 - CMakeLists.txt | 5 +- include/plateau/dataset/gml_file.h | 5 +- include/plateau/dataset/grid_code.h | 62 ++++++++++ include/plateau/dataset/i_dataset_accessor.h | 4 +- include/plateau/dataset/invalid_grid_code.h | 47 ++++++++ include/plateau/dataset/mesh_code.h | 11 +- include/plateau/dataset/standard_map_grid.h | 48 ++++++++ include/plateau/network/client.h | 2 +- src/c_wrapper/CMakeLists.txt | 2 +- src/c_wrapper/gml_file_c.cpp | 6 +- src/c_wrapper/grid_code_c.cpp | 48 ++++++++ src/c_wrapper/i_dataset_accessor_c.cpp | 9 +- src/c_wrapper/mesh_code_c.cpp | 34 ------ src/c_wrapper/vector_c.cpp | 51 ++++---- src/dataset/CMakeLists.txt | 5 +- src/dataset/gml_file.cpp | 12 +- src/dataset/grid_code.cpp | 44 +++++++ src/dataset/local_dataset_accessor.cpp | 37 +++--- src/dataset/local_dataset_accessor.h | 6 +- src/dataset/mesh_code.cpp | 19 ++- src/dataset/server_dataset_accessor.cpp | 22 ++-- src/dataset/server_dataset_accessor.h | 4 +- src/dataset/standard_map_grid.cpp | 54 +++++++++ src/network/client.cpp | 2 +- src/plateau/dataset/standard_map_grid.cpp | 53 +++++++++ test/test_dataset.cpp | 4 +- test/test_dataset_source.cpp | 10 +- .../Dataset/DatasetAccessorTest.cs | 10 +- .../Dataset/DatasetSourceTest.cs | 2 +- .../CSharpPLATEAU/Dataset/DatasetAccessor.cs | 6 +- .../CSharpPLATEAU/Dataset/GridCode.cs | 112 ++++++++++++++++++ .../CSharpPLATEAU/Dataset/MeshCode.cs | 58 +-------- ...torMeshCode.cs => NativeVectorGridCode.cs} | 29 ++--- .../CSharpPLATEAU/Native/PInvokeDisposable.cs | 5 +- 37 files changed, 634 insertions(+), 208 deletions(-) create mode 100644 .clangd create mode 100644 include/plateau/dataset/grid_code.h create mode 100644 include/plateau/dataset/invalid_grid_code.h create mode 100644 include/plateau/dataset/standard_map_grid.h create mode 100644 src/c_wrapper/grid_code_c.cpp delete mode 100644 src/c_wrapper/mesh_code_c.cpp create mode 100644 src/dataset/grid_code.cpp create mode 100644 src/dataset/standard_map_grid.cpp create mode 100644 src/plateau/dataset/standard_map_grid.cpp create mode 100644 wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/GridCode.cs rename wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/{NativeVectorMeshCode.cs => NativeVectorGridCode.cs} (64%) diff --git a/.clangd b/.clangd new file mode 100644 index 00000000..1085221b --- /dev/null +++ b/.clangd @@ -0,0 +1,7 @@ +CompileFlags: + If: + PathMatch: [.*] + Condition: "system(windows)" + CompilationDatabase: out/build/x64-Debug-Unity + Remove: [-fPIC] + Add: [--target=x86_64-pc-windows-msvc] diff --git a/.gitignore b/.gitignore index eacfc354..512bf824 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ - # fbx_sdk は再配布禁止のため、ご自分で用意していただく形になります。 /3rdparty/fbx_sdk/ @@ -22,8 +21,10 @@ _deps obj bin -# Visual Studio +# Editor settings .vs +.vscode +.idea # Resharper User config *.DotSettings.user diff --git a/.idea/vcs.xml b/.idea/vcs.xml index be1ca900..57d9b2b4 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -15,8 +15,6 @@ - - diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c5141f4..030d9926 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,7 @@ # .soファイルが存在しても、 .so が依存する .so ファイルが存在しない場合に DllNotFoundException になります。 # 次のコマンドで .so がどのようなライブラリに依存するか調べると良いです。 # objdump -x libplateau.so | grep NEEDED -# ldd ./libplateau.so | grep "not found” +# ldd ./libplateau.so | grep "not found" cmake_minimum_required(VERSION 3.8) @@ -79,6 +79,9 @@ if(WIN32) # CMake文法上の WIN32 add_definitions(-D WIN32) # C言語の #define キーワードとしての WIN32 endif() +# clangdで静的解析するための情報を出力 +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + # libjpeg-turboが複数architecture向けビルドをサポートしていないため限定 # https://github.com/libjpeg-turbo/libjpeg-turbo/blob/main/CMakeLists.txt#L101 set(COUNT 1) diff --git a/include/plateau/dataset/gml_file.h b/include/plateau/dataset/gml_file.h index dbf83846..abdf5cd9 100644 --- a/include/plateau/dataset/gml_file.h +++ b/include/plateau/dataset/gml_file.h @@ -20,7 +20,8 @@ namespace plateau::dataset { const std::string& getPath() const; void setPath(const std::string& path); - MeshCode getMeshCode() const; + std::shared_ptr getGridCode() const; + GridCode* getGridCodeRaw() const; // 寿命管理をDLL利用者に任せる用です const std::string& getFeatureType() const; PredefinedCityModelPackage getPackage() const; std::string getAppearanceDirectoryPath() const; @@ -61,7 +62,7 @@ namespace plateau::dataset { private: std::string path_; - std::string code_; + std::shared_ptr grid_code_; std::string feature_type_; bool is_valid_; bool is_local_; diff --git a/include/plateau/dataset/grid_code.h b/include/plateau/dataset/grid_code.h new file mode 100644 index 00000000..c83a0ba2 --- /dev/null +++ b/include/plateau/dataset/grid_code.h @@ -0,0 +1,62 @@ +#pragma once + +#include +#include +#include +#include "plateau/geometry/geo_coordinate.h" + +namespace plateau::dataset { + /** + * \brief 地図の区画を表すコードの基底クラスです。 + * + * メッシュコードや国土基本図図郭など、地図の区画を表現するコードシステムの共通機能を提供します。 + */ + class LIBPLATEAU_EXPORT GridCode { + public: + virtual ~GridCode() = default; + + /** + * \brief コードを文字列として取得します。 + */ + virtual std::string get() const = 0; + + /** + * \brief コードが表す緯度経度範囲を取得します。 + */ + virtual geometry::Extent getExtent() const = 0; + + /** + * \brief このコードが他のコードに内包されるかどうかを計算します。 + */ + virtual bool isWithin(const GridCode& other) const = 0; + + /** + * \brief コードが適切な値かどうかを返します。 + */ + virtual bool isValid() const = 0; + + /** + * \brief 与えられたコードから適切なGridCodeの派生クラスのインスタンスを作成します。 + * \param code コード文字列 + * \return コードの形式に応じてMeshCodeまたはStandardMapGridのインスタンスを返します。 + * \throw std::invalid_argument コードの形式が不正な場合 + */ + static std::shared_ptr create(const std::string& code); + + /** + * \brief 与えられたコードから適切なGridCodeの派生クラスのインスタンスを作成します。 + * \param code コード文字列 + * \return コードの形式に応じてMeshCodeまたはStandardMapGridのインスタンスを返します。生ポインタで返されます。 + * \throw std::invalid_argument コードの形式が不正な場合 + */ + static GridCode* createRaw(const std::string& code); + + }; + + struct GridCodeComparator { + bool operator()(const std::shared_ptr& lhs, const std::shared_ptr& rhs) const { + if(lhs == nullptr || rhs == nullptr) return false; + return lhs->get() < rhs->get(); + } + }; +} diff --git a/include/plateau/dataset/i_dataset_accessor.h b/include/plateau/dataset/i_dataset_accessor.h index f46387bb..aa904a33 100644 --- a/include/plateau/dataset/i_dataset_accessor.h +++ b/include/plateau/dataset/i_dataset_accessor.h @@ -3,6 +3,8 @@ #include #include #include +#include +#include namespace plateau::geometry { class GeoReference; @@ -129,7 +131,7 @@ namespace plateau::dataset { /** * \brief 都市モデルデータが存在する地域メッシュのリストを取得します。 */ - virtual std::set& getMeshCodes() = 0; + virtual std::set, GridCodeComparator>& getGridCodes() = 0; virtual TVec3d calculateCenterPoint(const plateau::geometry::GeoReference& geo_reference) = 0; diff --git a/include/plateau/dataset/invalid_grid_code.h b/include/plateau/dataset/invalid_grid_code.h new file mode 100644 index 00000000..82245876 --- /dev/null +++ b/include/plateau/dataset/invalid_grid_code.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include "plateau/dataset/grid_code.h" +#include "plateau/geometry/geo_coordinate.h" + +namespace plateau::dataset { + /** + * \brief 無効なグリッドコードを表すクラスです。 + * + * GridCodeの派生クラスとして、無効なグリッドコードを表現します。 + * このクラスのインスタンスは常に無効(isValid() == false)です。 + */ + class LIBPLATEAU_EXPORT InvalidGridCode : public GridCode { + public: + InvalidGridCode() = default; + + /** + * \brief 無効なグリッドコードを文字列として取得します。 + * \return 常に空文字列を返します。 + */ + std::string get() const override { return ""; } + + /** + * \brief 無効なグリッドコードの緯度経度範囲を取得します。 + * \return 原点(0,0,0)を中心とする無効な範囲を返します。 + */ + geometry::Extent getExtent() const override { + return geometry::Extent( + geometry::GeoCoordinate(0, 0, 0), + geometry::GeoCoordinate(0, 0, 0) + ); + } + + /** + * \brief このコードが他のコードに内包されるかどうかを計算します。 + * \return 常にfalseを返します。 + */ + bool isWithin(const GridCode& other) const override { return false; } + + /** + * \brief コードが適切な値かどうかを返します。 + * \return 常にfalseを返します。 + */ + bool isValid() const override { return false; } + }; +} \ No newline at end of file diff --git a/include/plateau/dataset/mesh_code.h b/include/plateau/dataset/mesh_code.h index 743d5e96..e6feb1e3 100644 --- a/include/plateau/dataset/mesh_code.h +++ b/include/plateau/dataset/mesh_code.h @@ -5,6 +5,7 @@ #include #include "plateau/geometry/geo_coordinate.h" +#include "plateau/dataset/grid_code.h" namespace plateau::dataset { /** @@ -12,7 +13,7 @@ namespace plateau::dataset { * * 2~5次メッシュの緯度経度範囲の取得、緯度経度範囲を内包する3次メッシュの取得を行う機能を提供しています。 */ - class LIBPLATEAU_EXPORT MeshCode { + class LIBPLATEAU_EXPORT MeshCode : public GridCode { public: explicit MeshCode(const std::string& code); MeshCode() = default; @@ -20,7 +21,7 @@ namespace plateau::dataset { /** * \brief メッシュコードを文字列として取得します。 */ - std::string get() const; + std::string get() const override; /** * \brief メッシュコードの次数を取得します。 @@ -30,7 +31,7 @@ namespace plateau::dataset { /** * \brief メッシュコードの緯度経度範囲を取得します。 */ - geometry::Extent getExtent() const; + geometry::Extent getExtent() const override; /** * \brief 座標点を含む3次メッシュを取得します。 @@ -50,7 +51,7 @@ namespace plateau::dataset { /** * \brief 地域メッシュが内包されるかどうかを計算します。 */ - bool isWithin(const MeshCode& other) const; + bool isWithin(const GridCode& other) const override; /** * \brief 地域メッシュを2次メッシュとして取得します。 @@ -65,7 +66,7 @@ namespace plateau::dataset { /** * \brief メッシュコードが適切な値かどうかを返します。 */ - bool isValid() const; + bool isValid() const override; bool operator==(const MeshCode& other) const; diff --git a/include/plateau/dataset/standard_map_grid.h b/include/plateau/dataset/standard_map_grid.h new file mode 100644 index 00000000..859a5802 --- /dev/null +++ b/include/plateau/dataset/standard_map_grid.h @@ -0,0 +1,48 @@ +#pragma once + +#include + +#include +#include "plateau/geometry/geo_coordinate.h" +#include "plateau/dataset/grid_code.h" + +namespace plateau::dataset { + /** + * \brief 国土基本図図郭を表します。 + * + * 国土基本図の図郭コードを扱い、緯度経度範囲の取得などの機能を提供します。 + */ + class LIBPLATEAU_EXPORT StandardMapGrid : public GridCode { + public: + explicit StandardMapGrid(const std::string& code); + StandardMapGrid() = default; + + /** + * \brief 図郭コードを文字列として取得します。 + */ + std::string get() const override; + + /** + * \brief 図郭の緯度経度範囲を取得します。 + */ + geometry::Extent getExtent() const override; + + /** + * \brief 図郭が他の図郭に内包されるかどうかを計算します。 + */ + bool isWithin(const GridCode& other) const override; + + /** + * \brief 図郭コードが適切な値かどうかを返します。 + */ + bool isValid() const override; + + bool operator==(const StandardMapGrid& other) const; + bool operator<(StandardMapGrid& other) const; + bool operator<(const StandardMapGrid& other) const; + + private: + std::string code_; // 図郭コード + bool is_valid_; // コードが有効かどうか + }; +} \ No newline at end of file diff --git a/include/plateau/network/client.h b/include/plateau/network/client.h index e59f1682..cf535a4c 100644 --- a/include/plateau/network/client.h +++ b/include/plateau/network/client.h @@ -19,7 +19,7 @@ namespace plateau::network { * データセットに含まれるファイルです。 */ struct DatasetFileItem { - std::string mesh_code; + std::string grid_code; std::string url; int max_lod = 0; }; diff --git a/src/c_wrapper/CMakeLists.txt b/src/c_wrapper/CMakeLists.txt index e1b3fe51..d95d1ca0 100644 --- a/src/c_wrapper/CMakeLists.txt +++ b/src/c_wrapper/CMakeLists.txt @@ -32,7 +32,7 @@ add_library(c_wrapper OBJECT "node_c.cpp" "geometry_utils_c.cpp" "geo_reference_c.cpp" - "mesh_code_c.cpp" + "grid_code_c.cpp" "gml_file_c.cpp" "city_model_package_info_c.cpp" "mesh_extract_options_c.cpp" diff --git a/src/c_wrapper/gml_file_c.cpp b/src/c_wrapper/gml_file_c.cpp index 62922437..bb896570 100644 --- a/src/c_wrapper/gml_file_c.cpp +++ b/src/c_wrapper/gml_file_c.cpp @@ -43,10 +43,10 @@ extern "C" { GmlFile, handle->getFeatureType()) - DLL_VALUE_FUNC(plateau_gml_file_get_mesh_code, + DLL_PTR_FUNC(plateau_gml_file_get_grid_code, GmlFile, - MeshCode, - handle->getMeshCode()) + GridCode, + handle->getGridCodeRaw()) LIBPLATEAU_C_EXPORT APIResult LIBPLATEAU_C_API plateau_gml_file_fetch( const GmlFile* const gml_file_info, diff --git a/src/c_wrapper/grid_code_c.cpp b/src/c_wrapper/grid_code_c.cpp new file mode 100644 index 00000000..6733a3cf --- /dev/null +++ b/src/c_wrapper/grid_code_c.cpp @@ -0,0 +1,48 @@ +#include "libplateau_c.h" +#include +#include + +using namespace libplateau; +using namespace plateau::dataset; +using namespace plateau::geometry; + +extern "C" { + + + LIBPLATEAU_C_EXPORT APIResult LIBPLATEAU_C_API plateau_grid_code_parse( + const char* code, + GridCode** out_grid_code + ) { + *out_grid_code = GridCode::createRaw(code); + return APIResult::Success; + } + + LIBPLATEAU_C_EXPORT APIResult LIBPLATEAU_C_API plateau_mesh_code_get_extent( + const GridCode* grid_code, Extent* extent + ) { + API_TRY{ + if (grid_code == nullptr) return APIResult::ErrorInvalidArgument; + *extent = grid_code->getExtent(); + return APIResult::Success; + } + API_CATCH; + return APIResult::ErrorUnknown; + } + + DLL_2_ARG_FUNC(plateau_grid_code_is_valid, + const GridCode* grid_code, + bool* out_is_valid, + if (grid_code == nullptr) { *out_is_valid = false; return APIResult::ErrorInvalidArgument; } + *out_is_valid = grid_code->isValid()) + + DLL_STRING_VALUE_FUNC(plateau_grid_code_get_string_code, + GridCode, + handle->get()) + + LIBPLATEAU_C_EXPORT APIResult LIBPLATEAU_C_API plateau_grid_code_delete( + GridCode* grid_code + ) { + delete grid_code; + return APIResult::Success; + } +} diff --git a/src/c_wrapper/i_dataset_accessor_c.cpp b/src/c_wrapper/i_dataset_accessor_c.cpp index 07fb3ebd..9c831ba3 100644 --- a/src/c_wrapper/i_dataset_accessor_c.cpp +++ b/src/c_wrapper/i_dataset_accessor_c.cpp @@ -17,12 +17,13 @@ extern "C" { LIBPLATEAU_C_EXPORT APIResult LIBPLATEAU_C_API plateau_i_dataset_accessor_get_mesh_codes( IDatasetAccessor* const dataset_accessor, - std::vector* const out_mesh_codes + std::vector* const out_grid_codes ) { API_TRY{ - const auto& mesh_codes = dataset_accessor->getMeshCodes(); - for (const auto& mesh_code : mesh_codes) - out_mesh_codes->push_back(mesh_code); + const auto& grid_codes = dataset_accessor->getGridCodes(); + for (const auto& grid_code : grid_codes) { + out_grid_codes->push_back(grid_code->get()); + } return APIResult::Success; } API_CATCH; return APIResult::ErrorUnknown; diff --git a/src/c_wrapper/mesh_code_c.cpp b/src/c_wrapper/mesh_code_c.cpp deleted file mode 100644 index 767a6ce7..00000000 --- a/src/c_wrapper/mesh_code_c.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "libplateau_c.h" - -#include - -using namespace libplateau; -using namespace plateau::dataset; -using namespace plateau::geometry; - -extern "C" { - - // MeshCode は構造体としてポインタではない実体をやりとり可能です。 - - LIBPLATEAU_C_EXPORT MeshCode LIBPLATEAU_C_API plateau_mesh_code_parse( - const char* code - ) { - return MeshCode(code); - } - - LIBPLATEAU_C_EXPORT APIResult LIBPLATEAU_C_API plateau_mesh_code_get_extent( - const MeshCode mesh_code, Extent* extent - ) { - API_TRY{ - *extent = mesh_code.getExtent(); - return APIResult::Success; - } - API_CATCH; - return APIResult::ErrorUnknown; - } - - DLL_2_ARG_FUNC(plateau_mesh_code_is_valid, - MeshCode mesh_code, - bool* out_is_valid, - *out_is_valid = mesh_code.isValid()) -} diff --git a/src/c_wrapper/vector_c.cpp b/src/c_wrapper/vector_c.cpp index 7b9db428..2d53e64b 100644 --- a/src/c_wrapper/vector_c.cpp +++ b/src/c_wrapper/vector_c.cpp @@ -30,7 +30,15 @@ extern "C"{ * その実体が P/Invoke で直接に値渡しできる(簡単な構造体など)場合は 4 を利用、 * できない場合は 3 を利用することを想定しています。 */ -#define PLATEAU_VECTOR(FUNC_NAME, VECTOR_ELEMENT_TYPE) \ +#define PLATEAU_VECTOR_GET_BY_PTR(FUNC_NAME, VECTOR_ELEMENT_TYPE) \ + PLATEAU_VECTOR_BASE(FUNC_NAME, VECTOR_ELEMENT_TYPE) \ + GET_BY_PTR(FUNC_NAME, VECTOR_ELEMENT_TYPE) + +#define PLATEAU_VECTOR_GET_BY_VALUE(FUNC_NAME, VECTOR_ELEMENT_TYPE) \ + PLATEAU_VECTOR_BASE(FUNC_NAME, VECTOR_ELEMENT_TYPE) \ + GET_BY_VALUE(FUNC_NAME, VECTOR_ELEMENT_TYPE) + +#define PLATEAU_VECTOR_BASE(FUNC_NAME, VECTOR_ELEMENT_TYPE) \ LIBPLATEAU_C_EXPORT APIResult LIBPLATEAU_API plateau_create_vector_ ## FUNC_NAME ( \ std::vector< VECTOR_ELEMENT_TYPE >** out_vector_ptr){ \ *out_vector_ptr = new std::vector< VECTOR_ELEMENT_TYPE >(); \ @@ -44,18 +52,6 @@ LIBPLATEAU_C_EXPORT APIResult LIBPLATEAU_API plateau_create_vector_ ## FUNC_NAME return APIResult::Success; \ } \ \ - DLL_PTR_FUNC_WITH_INDEX_CHECK (plateau_vector_ ## FUNC_NAME ## _get_pointer, \ - std::vector< VECTOR_ELEMENT_TYPE >, \ - VECTOR_ELEMENT_TYPE, \ - &(handle->at(index)), \ - index >= handle->size()) \ - \ - DLL_VALUE_FUNC_WITH_INDEX_CHECK (plateau_vector_ ## FUNC_NAME ## _get_value, \ - std::vector< VECTOR_ELEMENT_TYPE >, \ - VECTOR_ELEMENT_TYPE, \ - handle->at(index), \ - index >= handle->size()) \ - \ DLL_VALUE_FUNC (plateau_vector_ ## FUNC_NAME ## _count, \ std::vector< VECTOR_ELEMENT_TYPE >, \ int, \ @@ -71,12 +67,27 @@ LIBPLATEAU_C_EXPORT APIResult LIBPLATEAU_API plateau_create_vector_ ## FUNC_NAME VECTOR_ELEMENT_TYPE* element_ptr, /*NOLINT*/ \ vector->push_back(*element_ptr)) - PLATEAU_VECTOR(gml_file, GmlFile) - PLATEAU_VECTOR(mesh_code, MeshCode) - PLATEAU_VECTOR(dataset_metadata_group, DatasetMetadataGroup) - PLATEAU_VECTOR(dataset_metadata, DatasetMetadata) - PLATEAU_VECTOR(string, std::string) - PLATEAU_VECTOR(city_object_index, CityObjectIndex) - PLATEAU_VECTOR(extent, Extent) + +#define GET_BY_PTR(FUNC_NAME, VECTOR_ELEMENT_TYPE) \ + DLL_PTR_FUNC_WITH_INDEX_CHECK (plateau_vector_ ## FUNC_NAME ## _get_pointer, \ + std::vector< VECTOR_ELEMENT_TYPE >, \ + VECTOR_ELEMENT_TYPE, \ + &(handle->at(index)), \ + index >= handle->size()) + +#define GET_BY_VALUE(FUNC_NAME, VECTOR_ELEMENT_TYPE) \ + DLL_VALUE_FUNC_WITH_INDEX_CHECK (plateau_vector_ ## FUNC_NAME ## _get_value, \ + std::vector< VECTOR_ELEMENT_TYPE >, \ + VECTOR_ELEMENT_TYPE, \ + handle->at(index), \ + index >= handle->size()) + + PLATEAU_VECTOR_GET_BY_PTR(gml_file, GmlFile) + PLATEAU_VECTOR_GET_BY_VALUE(grid_code, GridCode*) // TODO クリーンアップ + PLATEAU_VECTOR_GET_BY_PTR(dataset_metadata_group, DatasetMetadataGroup) + PLATEAU_VECTOR_GET_BY_PTR(dataset_metadata, DatasetMetadata) + PLATEAU_VECTOR_GET_BY_PTR(string, std::string) + PLATEAU_VECTOR_GET_BY_VALUE(city_object_index, CityObjectIndex) + PLATEAU_VECTOR_GET_BY_VALUE(extent, Extent) } diff --git a/src/dataset/CMakeLists.txt b/src/dataset/CMakeLists.txt index 51b299ab..f56838dc 100644 --- a/src/dataset/CMakeLists.txt +++ b/src/dataset/CMakeLists.txt @@ -4,4 +4,7 @@ target_sources(plateau PRIVATE "server_dataset_accessor.cpp" "mesh_code.cpp" "lod_searcher.cpp" - "dataset_source.cpp") + "dataset_source.cpp" + "grid_code.cpp" + "standard_map_grid.cpp" +) diff --git a/src/dataset/gml_file.cpp b/src/dataset/gml_file.cpp index 26c238b7..80a251e7 100644 --- a/src/dataset/gml_file.cpp +++ b/src/dataset/gml_file.cpp @@ -47,8 +47,12 @@ namespace plateau::dataset { applyPath(); } - MeshCode GmlFile::getMeshCode() const { - return MeshCode(code_); + std::shared_ptr GmlFile::getGridCode() const { + return grid_code_; + } + + GridCode* GmlFile::getGridCodeRaw() const { + return GridCode::createRaw(grid_code_->get()); } const std::string& GmlFile::getFeatureType() const { @@ -87,7 +91,7 @@ namespace plateau::dataset { } bool GmlFile::isValid() const { - return is_valid_ && getMeshCode().isValid(); + return is_valid_ && getGridCode()->isValid(); } bool GmlFile::isMaxLodCalculated() const { @@ -111,7 +115,7 @@ namespace plateau::dataset { current += character; } try { - code_ = filename_parts.empty() ? "" : filename_parts.at(0); + grid_code_ = GridCode::create(filename_parts.empty() ? "" : filename_parts.at(0)); feature_type_ = filename_parts.size() <= 1 ? "" : filename_parts.at(1); is_valid_ = true; } diff --git a/src/dataset/grid_code.cpp b/src/dataset/grid_code.cpp new file mode 100644 index 00000000..18e2df74 --- /dev/null +++ b/src/dataset/grid_code.cpp @@ -0,0 +1,44 @@ +#include "plateau/dataset/grid_code.h" +#include "plateau/dataset/mesh_code.h" +#include "plateau/dataset/standard_map_grid.h" +#include "plateau/dataset/invalid_grid_code.h" +#include +#include + +namespace plateau::dataset { + + GridCode* GridCode::createRaw(const std::string& code) { + if (code.empty()) { + return new InvalidGridCode(); + } + + bool has_digit = false; + bool has_upper = false; + + // コードの文字を検査 + for (char c : code) { + if (std::isdigit(c)) has_digit = true; + if (std::isupper(c)) has_upper = true; + } + + try { + // 数字のみの場合はメッシュコード + if (has_digit && !has_upper) { + return new MeshCode(code); + } + // 数字と大文字アルファベットの場合は国土基本図図郭 + else if (has_digit && has_upper) { + return new StandardMapGrid(code); + } + } catch (const std::invalid_argument&) { + return new InvalidGridCode(); + } + + return new InvalidGridCode(); + } + + std::shared_ptr GridCode::create(const std::string& code) { + return std::shared_ptr(createRaw(code)); + } + +} \ No newline at end of file diff --git a/src/dataset/local_dataset_accessor.cpp b/src/dataset/local_dataset_accessor.cpp index a560c610..1a6d4078 100644 --- a/src/dataset/local_dataset_accessor.cpp +++ b/src/dataset/local_dataset_accessor.cpp @@ -6,6 +6,7 @@ #include #include "local_dataset_accessor.h" +#include "plateau/dataset/grid_code.h" namespace plateau::dataset { namespace fs = std::filesystem; @@ -152,12 +153,12 @@ namespace plateau::dataset { auto& gml_files = collection.files_.at(package); findGMLsBFS(entry.path(), gml_files); for (const auto& gml_file: gml_files) { - auto mesh_code = gml_file.getMeshCode(); + auto grid_code = gml_file.getGridCode(); if (!gml_file.isValid()) continue; - if (collection.files_by_code_.count(mesh_code.get()) == 0) { - collection.files_by_code_.emplace(mesh_code.get(), std::vector()); + if (collection.files_by_code_.count(grid_code->get()) == 0) { + collection.files_by_code_.emplace(grid_code->get(), std::vector()); } - collection.files_by_code_[mesh_code.get()].push_back(gml_file); + collection.files_by_code_[grid_code->get()].push_back(gml_file); } } } @@ -175,7 +176,7 @@ namespace plateau::dataset { out_collection_ptr->setUdxPath(udx_path_); for (const auto& [code, files] : files_by_code_) { - if (extent_filter.intersects2D(MeshCode(code).getExtent())) { + if (extent_filter.intersects2D(GridCode::create(code)->getExtent())) { for (const auto& file : files) { out_collection_ptr->addFile(UdxSubFolder::getPackage(file.getFeatureType()), file); } @@ -285,13 +286,13 @@ namespace plateau::dataset { double lat_sum = 0; double lon_sum = 0; double height_sum = 0; - for (const auto& mesh_code : mesh_codes_) { - const auto& center = mesh_code.getExtent().centerPoint(); + for (const auto& grid_code : grid_codes_) { + const auto& center = grid_code->getExtent().centerPoint(); lat_sum += center.latitude; lon_sum += center.longitude; height_sum += center.height; } - auto num = (double)mesh_codes_.size(); + auto num = (double)grid_codes_.size(); geometry::GeoCoordinate geo_average = geometry::GeoCoordinate(lat_sum / num, lon_sum / num, height_sum / num); auto euclid_average = geo_reference.project(geo_average); return euclid_average; @@ -301,17 +302,17 @@ namespace plateau::dataset { return fs::relative(fs::u8path(path).make_preferred(), fs::u8path(udx_path_)).make_preferred().string(); } - std::set& LocalDatasetAccessor::getMeshCodes() { - if (mesh_codes_.empty()) { + std::set, GridCodeComparator>& LocalDatasetAccessor::getGridCodes() { + if (grid_codes_.empty()) { for (const auto& [_, files]: files_) { for (const auto& file: files) { - auto mesh_code = file.getMeshCode(); - if (!mesh_code.isValid()) continue; - mesh_codes_.insert(file.getMeshCode()); + auto grid_code = file.getGridCode(); + if (!grid_code->isValid()) continue; + grid_codes_.insert(GridCode::create(file.getGridCode()->get())); } } } - return mesh_codes_; + return grid_codes_; } void LocalDatasetAccessor::addFile(PredefinedCityModelPackage sub_folder, const GmlFile& gml_file_info) { @@ -320,11 +321,11 @@ namespace plateau::dataset { } files_.at(sub_folder).push_back(gml_file_info); - const auto mesh_code = gml_file_info.getMeshCode().get(); - if (files_by_code_.count(mesh_code) == 0) { - files_by_code_.emplace(mesh_code, std::vector()); + const auto grid_code = gml_file_info.getGridCode()->get(); + if (files_by_code_.count(grid_code) == 0) { + files_by_code_.emplace(grid_code, std::vector()); } - files_by_code_[mesh_code].push_back(gml_file_info); + files_by_code_[grid_code].push_back(gml_file_info); } void LocalDatasetAccessor::setUdxPath(std::string udx_path) { diff --git a/src/dataset/local_dataset_accessor.h b/src/dataset/local_dataset_accessor.h index d817319e..d5021c7d 100644 --- a/src/dataset/local_dataset_accessor.h +++ b/src/dataset/local_dataset_accessor.h @@ -66,9 +66,9 @@ namespace plateau::dataset { int getGmlFileCount(PredefinedCityModelPackage package); /** - * \brief 都市モデルデータが存在する地域メッシュのリストを取得します。 + * \brief 都市モデルデータが存在するGridCodeのリストを取得します。 */ - std::set& getMeshCodes() override; + std::set, GridCodeComparator>& getGridCodes() override; std::string getRelativePath(const std::string& path) const; std::string getU8RelativePath(const std::string& path) const; @@ -84,7 +84,7 @@ namespace plateau::dataset { private: std::string udx_path_; std::map> files_; - std::set mesh_codes_; + std::set, GridCodeComparator> grid_codes_; std::map> files_by_code_; void addFile(PredefinedCityModelPackage sub_folder, const GmlFile& gml_file_info); void setUdxPath(std::string udx_path); diff --git a/src/dataset/mesh_code.cpp b/src/dataset/mesh_code.cpp index d7842cd5..725d0beb 100644 --- a/src/dataset/mesh_code.cpp +++ b/src/dataset/mesh_code.cpp @@ -234,11 +234,17 @@ namespace plateau::dataset { return result; } - bool MeshCode::isWithin(const MeshCode& other) const { - if (get() == other.get()) + bool MeshCode::isWithin(const GridCode& other) const { + // 型チェック + const auto* other_mesh = dynamic_cast(&other); + if (other_mesh == nullptr) { + return false; // 異なる型の場合は内包関係にないとみなす + } + + if (get() == other_mesh->get()) return true; - return get().substr(0, 6) == other.get(); + return get().substr(0, 6) == other_mesh->get(); } MeshCode MeshCode::asSecond() const { @@ -298,13 +304,6 @@ namespace plateau::dataset { return get() == other.get(); } - bool MeshCode::operator<(MeshCode& other) const { - return std::stoi(get()) < std::stoi(other.get()); - } - - bool MeshCode::operator<(const MeshCode& other) const { - return std::stoi(get()) < std::stoi(other.get()); - } void MeshCode::nextCol(MeshCode& mesh_code) { if (mesh_code.third_col_ < third_division_count - 1) { diff --git a/src/dataset/server_dataset_accessor.cpp b/src/dataset/server_dataset_accessor.cpp index b96f3823..59fd2158 100644 --- a/src/dataset/server_dataset_accessor.cpp +++ b/src/dataset/server_dataset_accessor.cpp @@ -15,18 +15,20 @@ namespace plateau::dataset { void ServerDatasetAccessor::loadFromServer() { // データセット情報を再取得します。 dataset_files_ = client_.getFiles(dataset_id_); - mesh_codes_.clear(); + grid_codes_.clear(); } - std::set& ServerDatasetAccessor::getMeshCodes() { - if (mesh_codes_.empty()) { + std::set, GridCodeComparator>& ServerDatasetAccessor::getGridCodes() { + if (grid_codes_.empty()) { for (const auto& [_, files] : dataset_files_) { for (const auto& file : files) { - mesh_codes_.insert(MeshCode(file.mesh_code)); + auto grid_code = GridCode::create(file.grid_code); + if(!grid_code->isValid()) continue; + grid_codes_.insert(std::move(grid_code)); } } } - return mesh_codes_; + return grid_codes_; } std::shared_ptr> ServerDatasetAccessor::getGmlFiles( @@ -57,13 +59,13 @@ namespace plateau::dataset { double lat_sum = 0; double lon_sum = 0; double height_sum = 0; - for (const auto& mesh_code : getMeshCodes()) { - const auto& center = mesh_code.getExtent().centerPoint(); + for (const auto& grid_code : getGridCodes()) { + const auto& center = grid_code->getExtent().centerPoint(); lat_sum += center.latitude; lon_sum += center.longitude; height_sum += center.height; } - auto num = (double)getMeshCodes().size(); + auto num = (double)getGridCodes().size(); geometry::GeoCoordinate geo_average = geometry::GeoCoordinate(lat_sum / num, lon_sum / num, height_sum / num); auto euclid_average = geo_reference.project(geo_average); return euclid_average; @@ -97,7 +99,7 @@ namespace plateau::dataset { for (const auto& [package, files] : dataset_files_) { for (const auto& file : files) { - auto extent = MeshCode(file.mesh_code).getExtent(); + auto extent = GridCode::create(file.grid_code)->getExtent(); if (extent_filter.intersects2D(extent)) { out_collection_ptr->addFile(package, file); } @@ -126,7 +128,7 @@ namespace plateau::dataset { // ファイルごとに mesh_codes_str_set に含まれるなら追加していきます。 for (const auto& [sub_folder, files] : dataset_files_) { for (const auto& file : files) { - if (mesh_codes_str_set.find(file.mesh_code) != mesh_codes_str_set.end()) { + if (mesh_codes_str_set.find(file.grid_code) != mesh_codes_str_set.end()) { out_collection_ptr->addFile(sub_folder, file); } } diff --git a/src/dataset/server_dataset_accessor.h b/src/dataset/server_dataset_accessor.h index 15d257fd..ceebf94b 100644 --- a/src/dataset/server_dataset_accessor.h +++ b/src/dataset/server_dataset_accessor.h @@ -18,7 +18,7 @@ namespace plateau::dataset { void loadFromServer(); - std::set& getMeshCodes() override; + std::set, GridCodeComparator>& getGridCodes() override; std::shared_ptr> getGmlFiles(const PredefinedCityModelPackage package) override; void getGmlFiles(const PredefinedCityModelPackage package_flags, std::vector& out_gml_files) override; @@ -43,7 +43,7 @@ namespace plateau::dataset { network::Client client_; std::string dataset_id_; network::DatasetFiles dataset_files_; - std::set mesh_codes_; + std::set, GridCodeComparator> grid_codes_; void addFile(const std::string& sub_folder, const network::DatasetFileItem& gml_file_info); }; diff --git a/src/dataset/standard_map_grid.cpp b/src/dataset/standard_map_grid.cpp new file mode 100644 index 00000000..7c1c3f1e --- /dev/null +++ b/src/dataset/standard_map_grid.cpp @@ -0,0 +1,54 @@ +#include "plateau/dataset/standard_map_grid.h" +#include "plateau/geometry/geo_coordinate.h" +#include +#include + +namespace plateau::dataset { + + StandardMapGrid::StandardMapGrid(const std::string& code) : code_(code), is_valid_(false) { + // コードの形式を検証 + // TODO + is_valid_ = true; + } + + std::string StandardMapGrid::get() const { + return code_; + } + + geometry::Extent StandardMapGrid::getExtent() const { + if (!isValid()) { + throw std::runtime_error("Invalid standard map grid code."); + } + + // TODO: 図郭コードから緯度経度範囲を計算する実装を追加 + // この実装は図郭コードの仕様に基づいて行う必要があります + return geometry::Extent(geometry::GeoCoordinate(0, 0, 0), geometry::GeoCoordinate(0, 0, 0)); + } + + bool StandardMapGrid::isWithin(const GridCode& other) const { + if (!isValid()) return false; + + // 同じ型の場合のみ比較 + const auto* other_grid = dynamic_cast(&other); + if (other_grid == nullptr) return false; + + // TODO: 図郭の包含関係を判定する実装を追加 + return false; + } + + bool StandardMapGrid::isValid() const { + return is_valid_; + } + + bool StandardMapGrid::operator==(const StandardMapGrid& other) const { + return code_ == other.code_; + } + + bool StandardMapGrid::operator<(StandardMapGrid& other) const { + return code_ < other.code_; + } + + bool StandardMapGrid::operator<(const StandardMapGrid& other) const { + return code_ < other.code_; + } +} \ No newline at end of file diff --git a/src/network/client.cpp b/src/network/client.cpp index 54d6ef4f..95a9945b 100644 --- a/src/network/client.cpp +++ b/src/network/client.cpp @@ -115,7 +115,7 @@ namespace plateau::network { for (const auto& file_item: file_items) { // 各ファイルについて DatasetFileItem dataset_file; dataset_file.max_lod = file_item.at("maxLod").get(); - dataset_file.mesh_code = file_item.at("code"); + dataset_file.grid_code = file_item.at("code"); dataset_file.url = file_item.at("url"); dataset_files.at(key).push_back(dataset_file); diff --git a/src/plateau/dataset/standard_map_grid.cpp b/src/plateau/dataset/standard_map_grid.cpp new file mode 100644 index 00000000..50d6d306 --- /dev/null +++ b/src/plateau/dataset/standard_map_grid.cpp @@ -0,0 +1,53 @@ +#include "plateau/dataset/standard_map_grid.h" +#include "plateau/geometry/geo_coordinate.h" +#include + +namespace plateau::dataset { + + StandardMapGrid::StandardMapGrid(const std::string& code) : code_(code), is_valid_(false) { + // コードの形式を検証 + // TODO + is_valid_ = true; + } + + std::string StandardMapGrid::get() const { + return code_; + } + + geometry::Extent StandardMapGrid::getExtent() const { + if (!isValid()) { + throw std::runtime_error("Invalid standard map grid code."); + } + + // TODO: 図郭コードから緯度経度範囲を計算する実装を追加 + // この実装は図郭コードの仕様に基づいて行う必要があります + return geometry::Extent(geometry::GeoCoordinate(0, 0, 0), geometry::GeoCoordinate(0, 0, 0)); + } + + bool StandardMapGrid::isWithin(const GridCode& other) const { + if (!isValid()) return false; + + // 同じ型の場合のみ比較 + const auto* other_grid = dynamic_cast(&other); + if (other_grid == nullptr) return false; + + // TODO: 図郭の包含関係を判定する実装を追加 + return false; + } + + bool StandardMapGrid::isValid() const { + return is_valid_; + } + + bool StandardMapGrid::operator==(const StandardMapGrid& other) const { + return code_ == other.code_; + } + + bool StandardMapGrid::operator<(StandardMapGrid& other) const { + return code_ < other.code_; + } + + bool StandardMapGrid::operator<(const StandardMapGrid& other) const { + return code_ < other.code_; + } +} \ No newline at end of file diff --git a/test/test_dataset.cpp b/test/test_dataset.cpp index 8663dd70..0816f6c5 100644 --- a/test/test_dataset.cpp +++ b/test/test_dataset.cpp @@ -73,8 +73,8 @@ TEST_F(DatasetTest,DISABLED_getGmlsServer) { // NOLINT } TEST_F(DatasetTest, getAllMeshCodes) { // NOLINT - const auto& mesh_codes = local_dataset_accessor->getMeshCodes(); - ASSERT_TRUE(mesh_codes.size() > 0); + const auto& grid_codes = local_dataset_accessor->getGridCodes(); + ASSERT_TRUE(grid_codes.size() > 0); } namespace { diff --git a/test/test_dataset_source.cpp b/test/test_dataset_source.cpp index 13065cc0..0dd8ede9 100644 --- a/test/test_dataset_source.cpp +++ b/test/test_dataset_source.cpp @@ -18,16 +18,16 @@ namespace plateau::dataset { std::make_shared( std::move(DatasetSource::createLocal(u8"../data/日本語パステスト"))); auto accessor = source->getAccessor(); - auto mesh_code_str = accessor->getMeshCodes().begin()->get(); - ASSERT_EQ(mesh_code_str, "533925"); + auto grid_code_str = accessor->getGridCodes().begin()->get()->get(); + ASSERT_EQ(grid_code_str, "533925"); } TEST_F(DatasetSourceTest, DISABLED_get_accessor_of_server_source_returns_server_accessor) { // NOLINT auto source = DatasetSource::createServer(std::string("23ku"), network::Client::createClientForMockServer()); auto accessor = source.getAccessor(); - auto mesh_code_str = accessor->getMeshCodes().begin()->get(); - ASSERT_EQ(mesh_code_str, "533926"); + auto grid_code_str = accessor->getGridCodes().begin()->get()->get(); + ASSERT_EQ(grid_code_str, "533926"); auto gml_files = accessor->getGmlFiles(PredefinedCityModelPackage::Building); - ASSERT_EQ(gml_files->at(0).getMeshCode().get(), "53392642"); + ASSERT_EQ(gml_files->at(0).getGridCode()->get(), "53392642"); } } diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetAccessorTest.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetAccessorTest.cs index 9523495b..4932c43d 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetAccessorTest.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetAccessorTest.cs @@ -21,8 +21,8 @@ public void GetMeshCodesLocal() { using var source = DatasetSource.Create(new DatasetSourceConfigLocal(TestDataPathLocal)); using var accessor = source.Accessor; - Assert.IsTrue(accessor.MeshCodes.Length > 0, "メッシュコードが存在します。"); - Console.WriteLine(accessor.MeshCodes.At(0).ToString()); + Assert.IsTrue(accessor.GridCodes.Length > 0, "メッシュコードが存在します。"); + Console.WriteLine(accessor.GridCodes.At(0).ToString()); } [Ignore, TestMethod] @@ -30,7 +30,7 @@ public void GetMeshCodeServer() { using var source = DatasetSource.CreateForMockServer(TestDatasetIdServer); using var accessor = source.Accessor; - var meshCodes = accessor.MeshCodes; + var meshCodes = accessor.GridCodes; Assert.AreEqual(3, meshCodes.Length); Assert.AreEqual("53392642", meshCodes.At(1).ToString()); } @@ -100,7 +100,7 @@ public void MaxLodLocal() { using var datasetSource = DatasetSource.Create(new DatasetSourceConfigLocal(TestDataPathLocal)); var accessor = datasetSource.Accessor; - var meshCodes = accessor.MeshCodes; + var meshCodes = accessor.GridCodes; Assert.IsTrue(meshCodes.Length > 0, "メッシュコードが存在します。"); int maxLod = accessor.GetGmlFiles(PredefinedCityModelPackage.Building).At(0).GetMaxLod(); Assert.AreEqual(2, maxLod); @@ -153,7 +153,7 @@ public void GetGmlFiles() private static void TestCenterPoint(DatasetSource source) { using var collection = source.Accessor; - var meshCodes = collection.MeshCodes.ToArray(); + var meshCodes = collection.GridCodes.ToArray(); Assert.IsTrue(meshCodes.Length > 0); PlateauVector3d center; diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetSourceTest.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetSourceTest.cs index d5ef8ef8..5450ee55 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetSourceTest.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetSourceTest.cs @@ -20,7 +20,7 @@ public void Accessor_From_Server_Works() { using var source = DatasetSource.CreateForMockServer("23ku"); using var accessor = source.Accessor; - Assert.AreEqual("53392642", accessor.MeshCodes.At(1).ToString()); + Assert.AreEqual("53392642", accessor.GridCodes.At(1).ToString()); var gmls = accessor.GetGmlFiles(PredefinedCityModelPackage.Building); Assert.AreEqual( NetworkConfig.MockServerUrl + "/13100_tokyo23-ku_2020_citygml_3_2_op/udx/bldg/53392642_bldg_6697_2_op.gml", diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/DatasetAccessor.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/DatasetAccessor.cs index 981c497e..7624e59f 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/DatasetAccessor.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/DatasetAccessor.cs @@ -41,11 +41,11 @@ public NativeVectorGmlFile GetAllGmlFiles() return GetGmlFiles((PredefinedCityModelPackage)allPackages); } - public NativeVectorMeshCode MeshCodes + public NativeVectorGridCode GridCodes { get { - var meshCodes = NativeVectorMeshCode.Create(); + var meshCodes = NativeVectorGridCode.Create(); var result = NativeMethods.plateau_i_dataset_accessor_get_mesh_codes( Handle, meshCodes.Handle); DLLUtil.CheckDllError(result); @@ -76,7 +76,7 @@ public PlateauVector3d CalculateCenterPoint(GeoReference geoReference) public DatasetAccessor FilterByMeshCodes(IEnumerable meshCodes) { - var nativeMeshCodes = NativeVectorMeshCode.Create(); + var nativeMeshCodes = NativeVectorGridCode.Create(); foreach (var meshCode in meshCodes) { nativeMeshCodes.Add(meshCode); diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/GridCode.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/GridCode.cs new file mode 100644 index 00000000..dfc23671 --- /dev/null +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/GridCode.cs @@ -0,0 +1,112 @@ +using System; +using System.Runtime.InteropServices; +using PLATEAU.Interop; +using PLATEAU.Native; + +namespace PLATEAU.Dataset +{ + /// + /// メッシュコードと国土基本図の図郭のC++上の親クラスです。 + /// + public class GridCode : PInvokeDisposable + { + internal GridCode(IntPtr handle, bool autoDispose = true) : base(handle, autoDispose) + { + } + + public static GridCode Parse(string code) + { + var result = NativeMethods.plateau_grid_code_parse(code, out var gridCodePtr); + DLLUtil.CheckDllError(result); + return new GridCode(gridCodePtr); + } + + public GridCode Copy() + { + return Parse(StringCode); + } + + public Extent Extent + { + get + { + ThrowIfInvalid(); + Extent value = new Extent(); + APIResult result = NativeMethods.plateau_grid_code_get_extent(Handle, ref value); + DLLUtil.CheckDllError(result); + return value; + } + } + + public string StringCode + { + get + { + ThrowIfInvalid(); + return DLLUtil.GetNativeStringByValue( + Handle, + NativeMethods.plateau_grid_code_get_string_code_size, + NativeMethods.plateau_grid_code_get_string_code + ); + } + } + + public bool IsValid + { + get + { + var result = NativeMethods.plateau_grid_code_is_valid(Handle, out bool resultIsValid); + DLLUtil.CheckDllError(result); + return resultIsValid; + } + } + + private void ThrowIfInvalid() + { + if (IsValid) return; + throw new Exception("Invalid GridCode."); + } + + protected override void DisposeNative() + { + var result = NativeMethods.plateau_grid_code_delete(Handle); + DLLUtil.CheckDllError(result); + } + + private static class NativeMethods + { + [DllImport(DLLUtil.DllName)] + internal static extern APIResult plateau_grid_code_parse( + [In] string code, + out IntPtr gridCodePtr + ); + + [DllImport(DLLUtil.DllName)] + internal static extern APIResult plateau_grid_code_get_extent( + [In] IntPtr gridCode, + [In, Out] ref Extent outExtent); + + [DllImport(DLLUtil.DllName)] + internal static extern APIResult plateau_grid_code_delete( + [In] IntPtr gridCodePtr + ); + + [DllImport(DLLUtil.DllName)] + internal static extern APIResult plateau_grid_code_is_valid( + [In] IntPtr gridCodePtr, + [MarshalAs(UnmanagedType.U1)] out bool outIsValid); + + [DllImport(DLLUtil.DllName)] + internal static extern APIResult plateau_grid_code_get_string_code_size( + [In] IntPtr gridCodePtr, + out int strSize + ); + + [DllImport(DLLUtil.DllName)] + internal static extern APIResult plateau_grid_code_get_string_code( + [In] IntPtr gridCodePtr, + [In, Out] IntPtr outStringCode + ); + } + } +} diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/MeshCode.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/MeshCode.cs index 610b4093..03e2acfd 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/MeshCode.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/MeshCode.cs @@ -21,32 +21,8 @@ public struct MeshCode public readonly int Level; [MarshalAs(UnmanagedType.U1)] private readonly bool isValid; - public bool IsValid - { - get - { - var result = NativeMethods.plateau_mesh_code_is_valid(this, out bool resultIsValid); - DLLUtil.CheckDllError(result); - return resultIsValid; - } - } - - public Extent Extent - { - get - { - ThrowIfInvalid(); - Extent value = new Extent(); - APIResult result = NativeMethods.plateau_mesh_code_get_extent(this, ref value); - DLLUtil.CheckDllError(result); - return value; - } - } - - public static MeshCode Parse(string code) - { - return NativeMethods.plateau_mesh_code_parse(code); - } + + private static bool getHalfMeshNumber(out int num, int row, int col) @@ -65,7 +41,7 @@ private static bool getHalfMeshNumber(out int num, int row, int col) public override string ToString() { - ThrowIfInvalid(); + // ThrowIfInvalid(); string secondString = Level2(); if (this.Level == 2) return secondString; @@ -86,37 +62,15 @@ public override string ToString() public string Level2() { - ThrowIfInvalid(); + // ThrowIfInvalid(); return $"{this.FirstRow | 00}{this.FirstCol | 00}{this.SecondRow | 0}{this.SecondCol | 0}"; } public string Level3() { - ThrowIfInvalid(); + // ThrowIfInvalid(); return $"{Level2()}{this.ThirdRow | 0}{this.ThirdCol | 0}"; } - - private void ThrowIfInvalid() - { - if (IsValid) return; - throw new Exception("Invalid MeshCode. ( MeshCode.Invalid == true)"); - } - - private static class NativeMethods - { - [DllImport(DLLUtil.DllName)] - internal static extern MeshCode plateau_mesh_code_parse( - [In] string code); - - [DllImport(DLLUtil.DllName)] - internal static extern APIResult plateau_mesh_code_get_extent( - [In] MeshCode meshCode, - [In, Out] ref Extent outExtent); - - [DllImport(DLLUtil.DllName)] - internal static extern APIResult plateau_mesh_code_is_valid( - [In] MeshCode meshCode, - [MarshalAs(UnmanagedType.U1)] out bool outIsValid); - } + } } diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/NativeVectorMeshCode.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/NativeVectorGridCode.cs similarity index 64% rename from wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/NativeVectorMeshCode.cs rename to wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/NativeVectorGridCode.cs index 62af5c2f..ac9a19d9 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/NativeVectorMeshCode.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/NativeVectorGridCode.cs @@ -5,25 +5,26 @@ namespace PLATEAU.Native { - public class NativeVectorMeshCode : NativeVectorDisposableBase + public class NativeVectorGridCode : NativeVectorDisposableBase { - private NativeVectorMeshCode(IntPtr ptr) : base(ptr) + private NativeVectorGridCode(IntPtr ptr) : base(ptr) { } - public static NativeVectorMeshCode Create() + public static NativeVectorGridCode Create() { var result = NativeMethods.plateau_create_vector_mesh_code(out var ptr); DLLUtil.CheckDllError(result); - return new NativeVectorMeshCode(ptr); + return new NativeVectorGridCode(ptr); } - public override MeshCode At(int index) + public override GridCode At(int index) { ThrowIfDisposed(); - var meshCode = DLLUtil.GetNativeValue(Handle, index, - NativeMethods.plateau_vector_mesh_code_get_value); - return meshCode; + var gridCodePtr = DLLUtil.GetNativeValue(Handle, index, + NativeMethods.plateau_vector_grid_code_get_value); + var gridCode = new GridCode(gridCodePtr, false); + return gridCode.Copy(); // 寿命管理のためコピーを渡します。元データはvector廃棄時に消します。 } public override int Length @@ -32,7 +33,7 @@ public override int Length { ThrowIfDisposed(); int count = DLLUtil.GetNativeValue(Handle, - NativeMethods.plateau_vector_mesh_code_count); + NativeMethods.plateau_vector_grid_code_count); return count; } } @@ -62,20 +63,20 @@ internal static extern APIResult plateau_delete_vector_mesh_code( [In] IntPtr vectorPtr); [DllImport(DLLUtil.DllName)] - internal static extern APIResult plateau_vector_mesh_code_get_value( + internal static extern APIResult plateau_vector_grid_code_get_value( [In] IntPtr vectorPtr, - out MeshCode outMeshCode, + out IntPtr outGridCodePtr, int index); [DllImport(DLLUtil.DllName)] - internal static extern APIResult plateau_vector_mesh_code_count( + internal static extern APIResult plateau_vector_grid_code_count( [In] IntPtr handle, out int outCount); [DllImport(DLLUtil.DllName)] - internal static extern APIResult plateau_vector_mesh_code_push_back_value( + internal static extern APIResult grid_code_push_back_value( [In] IntPtr handle, - [In] MeshCode meshCode); + [In] IntPtr gridCodePtr); } } } diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/PInvokeDisposable.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/PInvokeDisposable.cs index 22e9ff98..cc6ae1fc 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/PInvokeDisposable.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/PInvokeDisposable.cs @@ -12,16 +12,19 @@ public abstract class PInvokeDisposable : IDisposable { public IntPtr Handle { get; } private bool isDisposed; + private bool autoDispose; protected abstract void DisposeNative(); - protected PInvokeDisposable(IntPtr handle) + protected PInvokeDisposable(IntPtr handle, bool autoDispose = true) { Handle = handle; + this.autoDispose = autoDispose; } public void Dispose() { + if (!this.autoDispose) return; if (this.isDisposed) return; DisposeNative(); GC.SuppressFinalize(this); From df78fcf20185a29fb7b178b701e2215de67cb64f Mon Sep 17 00:00:00 2001 From: Linoal <1321932+linoal@users.noreply.github.com> Date: Tue, 8 Apr 2025 14:22:38 +0900 Subject: [PATCH 02/19] =?UTF-8?q?=E5=90=8C=E4=B8=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/c_wrapper/i_dataset_accessor_c.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/c_wrapper/i_dataset_accessor_c.cpp b/src/c_wrapper/i_dataset_accessor_c.cpp index 9c831ba3..04ae138a 100644 --- a/src/c_wrapper/i_dataset_accessor_c.cpp +++ b/src/c_wrapper/i_dataset_accessor_c.cpp @@ -1,5 +1,7 @@ #include "libplateau_c.h" #include +#include +#include extern "C" { using namespace plateau::dataset; From 8572c2eb563fc2182e8a3453b90baa9a3c55c0c7 Mon Sep 17 00:00:00 2001 From: Linoal <1321932+linoal@users.noreply.github.com> Date: Tue, 8 Apr 2025 15:12:27 +0900 Subject: [PATCH 03/19] =?UTF-8?q?GmlFile=E3=82=84DatasetAccessor=E3=82=92M?= =?UTF-8?q?eshCode=E3=81=8B=E3=82=89GridCode=E3=81=AB=E7=A7=BB=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit filter移行中 filter_by_grid_coords 移行中 C#テストが通る --- include/plateau/dataset/grid_code.h | 16 ++++++++ include/plateau/dataset/i_dataset_accessor.h | 9 +++-- include/plateau/dataset/invalid_grid_code.h | 11 ++++++ include/plateau/dataset/mesh_code.h | 11 ++++-- include/plateau/dataset/standard_map_grid.h | 15 +++++++ src/c_wrapper/grid_code_c.cpp | 2 +- src/c_wrapper/i_dataset_accessor_c.cpp | 12 +++--- src/c_wrapper/vector_c.cpp | 18 +++++++++ src/dataset/local_dataset_accessor.cpp | 22 +++++++---- src/dataset/local_dataset_accessor.h | 4 +- src/dataset/mesh_code.cpp | 15 ++++--- src/dataset/server_dataset_accessor.cpp | 25 ++++++++---- src/dataset/server_dataset_accessor.h | 4 +- src/dataset/standard_map_grid.cpp | 15 +++++++ test/test_dataset.cpp | 10 ++--- test/test_server_dataset_accessor.cpp | 2 +- .../Dataset/DatasetAccessorTest.cs | 8 ++-- .../Dataset/DatasetSourceTest.cs | 2 +- .../CSharpPLATEAU.Test/Dataset/GmlFileTest.cs | 6 +-- .../Dataset/MeshCodeTest.cs | 2 +- .../GeometryModel/MeshExtractorTests.cs | 2 +- .../CSharpPLATEAU/Dataset/DatasetAccessor.cs | 12 +++--- .../CSharpPLATEAU/Dataset/GmlFile.cs | 19 ++++----- .../CSharpPLATEAU/Dataset/GridCode.cs | 16 +++++--- .../Native/NativeVectorGridCode.cs | 39 +++++++++++++------ .../CSharpPLATEAU/Native/PInvokeDisposable.cs | 5 +++ 26 files changed, 215 insertions(+), 87 deletions(-) diff --git a/include/plateau/dataset/grid_code.h b/include/plateau/dataset/grid_code.h index c83a0ba2..79ebdc51 100644 --- a/include/plateau/dataset/grid_code.h +++ b/include/plateau/dataset/grid_code.h @@ -35,6 +35,22 @@ namespace plateau::dataset { */ virtual bool isValid() const = 0; + /** + * \brief 1段階上のレベルのグリッドコードに変換します。 + */ + virtual std::shared_ptr upper() = 0; + + /** + * \brief コードのレベル(詳細度)を取得します。 + */ + virtual int getLevel() const = 0; + + /** + * \brief コードのレベル(詳細度)が、PLATEAUの仕様上考えられる中でもっとも大きいものであるときにtrueを返します。 + * @return + */ + virtual bool isLargestLevel() const = 0; + /** * \brief 与えられたコードから適切なGridCodeの派生クラスのインスタンスを作成します。 * \param code コード文字列 diff --git a/include/plateau/dataset/i_dataset_accessor.h b/include/plateau/dataset/i_dataset_accessor.h index aa904a33..d780a3e5 100644 --- a/include/plateau/dataset/i_dataset_accessor.h +++ b/include/plateau/dataset/i_dataset_accessor.h @@ -116,17 +116,18 @@ namespace plateau::dataset { /** * \brief メッシュコードで都市モデルデータをフィルタリングします。 - * \param mesh_codes 欲しい地域IDのvector + * \param grid_codes 欲しい地域IDのvector * \param collection フィルタリングされた都市モデルデータの格納先 */ - virtual void filterByMeshCodes(const std::vector& mesh_codes, IDatasetAccessor& collection) const = 0; + virtual void filterByGridCodes(const std::vector& grid_codes, IDatasetAccessor& collection) const = 0; /** * \brief メッシュコードで都市モデルデータをフィルタリングします。 - * \param mesh_codes 欲しい地域IDのvector + * \param grid_codes 欲しい地域IDのvector * \return フィルタリングされた都市モデルデータ */ - virtual std::shared_ptr filterByMeshCodes(const std::vector& mesh_codes) const = 0; + virtual std::shared_ptr filterByGridCodes( + const std::vector>& grid_codes) const = 0; /** * \brief 都市モデルデータが存在する地域メッシュのリストを取得します。 diff --git a/include/plateau/dataset/invalid_grid_code.h b/include/plateau/dataset/invalid_grid_code.h index 82245876..b3bc4800 100644 --- a/include/plateau/dataset/invalid_grid_code.h +++ b/include/plateau/dataset/invalid_grid_code.h @@ -43,5 +43,16 @@ namespace plateau::dataset { * \return 常にfalseを返します。 */ bool isValid() const override { return false; } + + /** + * \brief 1段階上のレベルのグリッドコードに変換します。 + * \return 無効なグリッドコードを返します。 + */ + std::shared_ptr upper() override { + return std::make_shared(); + } + + int getLevel() const override { return -1; } + bool isLargestLevel() const override { return true; } }; } \ No newline at end of file diff --git a/include/plateau/dataset/mesh_code.h b/include/plateau/dataset/mesh_code.h index e6feb1e3..6720d56b 100644 --- a/include/plateau/dataset/mesh_code.h +++ b/include/plateau/dataset/mesh_code.h @@ -61,18 +61,21 @@ namespace plateau::dataset { /** * \brief レベル2以上の範囲で1段階上のレベルの地域メッシュに変換します。 */ - MeshCode& upper(); + std::shared_ptr upper() override; /** * \brief メッシュコードが適切な値かどうかを返します。 */ bool isValid() const override; + /** + * \brief コードのレベル(詳細度)が、PLATEAUの仕様上考えられる中でもっとも大きいものであるときにtrueを返します。 + */ + bool isLargestLevel() const override; + bool operator==(const MeshCode& other) const; - //! setに入れるために演算子オーバーロードします。 - bool operator<(MeshCode& other) const; - bool operator<(const MeshCode& other) const; + private: int first_row_; diff --git a/include/plateau/dataset/standard_map_grid.h b/include/plateau/dataset/standard_map_grid.h index 859a5802..5ea397ea 100644 --- a/include/plateau/dataset/standard_map_grid.h +++ b/include/plateau/dataset/standard_map_grid.h @@ -37,6 +37,21 @@ namespace plateau::dataset { */ bool isValid() const override; + /** + * \brief 1段階上のレベルのグリッドコードに変換します。 + */ + std::shared_ptr upper() override; + + /** + * \brief コードのレベル(詳細度)を取得します。 + */ + int getLevel() const override; + + /** + * \brief コードのレベル(詳細度)が、PLATEAUの仕様上考えられる中でもっとも大きいものであるときにtrueを返します。 + */ + bool isLargestLevel() const override; + bool operator==(const StandardMapGrid& other) const; bool operator<(StandardMapGrid& other) const; bool operator<(const StandardMapGrid& other) const; diff --git a/src/c_wrapper/grid_code_c.cpp b/src/c_wrapper/grid_code_c.cpp index 6733a3cf..a5d3f950 100644 --- a/src/c_wrapper/grid_code_c.cpp +++ b/src/c_wrapper/grid_code_c.cpp @@ -17,7 +17,7 @@ extern "C" { return APIResult::Success; } - LIBPLATEAU_C_EXPORT APIResult LIBPLATEAU_C_API plateau_mesh_code_get_extent( + LIBPLATEAU_C_EXPORT APIResult LIBPLATEAU_C_API plateau_grid_code_get_extent( const GridCode* grid_code, Extent* extent ) { API_TRY{ diff --git a/src/c_wrapper/i_dataset_accessor_c.cpp b/src/c_wrapper/i_dataset_accessor_c.cpp index 04ae138a..440c3318 100644 --- a/src/c_wrapper/i_dataset_accessor_c.cpp +++ b/src/c_wrapper/i_dataset_accessor_c.cpp @@ -17,14 +17,14 @@ extern "C" { std::vector* out_gml_files, accessor->getGmlFiles(package, *out_gml_files)) - LIBPLATEAU_C_EXPORT APIResult LIBPLATEAU_C_API plateau_i_dataset_accessor_get_mesh_codes( + LIBPLATEAU_C_EXPORT APIResult LIBPLATEAU_C_API plateau_i_dataset_accessor_get_grid_codes( IDatasetAccessor* const dataset_accessor, - std::vector* const out_grid_codes + std::vector* const out_grid_codes ) { API_TRY{ const auto& grid_codes = dataset_accessor->getGridCodes(); for (const auto& grid_code : grid_codes) { - out_grid_codes->push_back(grid_code->get()); + out_grid_codes->push_back(GridCode::createRaw(grid_code->get())); // GridCode::createRawを使用 } return APIResult::Success; } API_CATCH; @@ -42,12 +42,12 @@ extern "C" { TVec3d* const out_center_point, *out_center_point = accessor->calculateCenterPoint(*geo_reference)) - DLL_3_ARG_FUNC(plateau_i_dataset_accessor_filter_by_mesh_codes, + DLL_3_ARG_FUNC(plateau_i_dataset_accessor_filter_by_grid_codes, const IDatasetAccessor* const accessor, - const std::vector* mesh_codes, + const std::vector* grid_codes, IDatasetAccessor** out_dataset_accessor_ptr, auto filtered = accessor->create(); - accessor->filterByMeshCodes(*mesh_codes, *filtered); + accessor->filterByGridCodes(*grid_codes, *filtered); *out_dataset_accessor_ptr = filtered; ) diff --git a/src/c_wrapper/vector_c.cpp b/src/c_wrapper/vector_c.cpp index 2d53e64b..ce1b6300 100644 --- a/src/c_wrapper/vector_c.cpp +++ b/src/c_wrapper/vector_c.cpp @@ -82,8 +82,26 @@ LIBPLATEAU_C_EXPORT APIResult LIBPLATEAU_API plateau_create_vector_ ## FUNC_NAME handle->at(index), \ index >= handle->size()) +/** + * vector<ポインタ型> の要素をdeleteしてからvectorをクリアするための関数を生成するマクロです。 + * これはvectorがポインタを含む場合(例:vector)に使用します。 + * 生成される関数は plateau_cleanup_vector_FUNC_NAME という名前になります。 + */ +#define CLEANUP(FUNC_NAME, VECTOR_ELEMENT_TYPE) \ + LIBPLATEAU_C_EXPORT APIResult LIBPLATEAU_C_API plateau_cleanup_vector_ ## FUNC_NAME ( \ + std::vector< VECTOR_ELEMENT_TYPE >* vector_ptr \ + ){ \ + if (vector_ptr == nullptr) return APIResult::ErrorInvalidArgument; \ + for (auto* element : *vector_ptr) { \ + delete element; \ + } \ + vector_ptr->clear(); \ + return APIResult::Success; \ + } + PLATEAU_VECTOR_GET_BY_PTR(gml_file, GmlFile) PLATEAU_VECTOR_GET_BY_VALUE(grid_code, GridCode*) // TODO クリーンアップ + CLEANUP(grid_code, GridCode*) PLATEAU_VECTOR_GET_BY_PTR(dataset_metadata_group, DatasetMetadataGroup) PLATEAU_VECTOR_GET_BY_PTR(dataset_metadata, DatasetMetadata) PLATEAU_VECTOR_GET_BY_PTR(string, std::string) diff --git a/src/dataset/local_dataset_accessor.cpp b/src/dataset/local_dataset_accessor.cpp index 1a6d4078..5c41e4d7 100644 --- a/src/dataset/local_dataset_accessor.cpp +++ b/src/dataset/local_dataset_accessor.cpp @@ -184,7 +184,7 @@ namespace plateau::dataset { } } - void LocalDatasetAccessor::filterByMeshCodes(const std::vector& mesh_codes, + void LocalDatasetAccessor::filterByGridCodes(const std::vector& grid_codes, IDatasetAccessor& collection) const { const auto out_collection_ptr = dynamic_cast(&collection); if (out_collection_ptr == nullptr) @@ -194,13 +194,16 @@ namespace plateau::dataset { out_collection_ptr->setUdxPath(udx_path_); // 検索用に、引数の mesh_codes を文字列のセットにします。 auto mesh_codes_str_set = std::set(); - for (auto mesh_code : mesh_codes) { + for (auto grid_code : grid_codes) { // 各地域メッシュについて上位の地域メッシュも含め登録する。 // 重複する地域メッシュはinsert関数で弾かれる。 - for (; mesh_code.getLevel() >= 2; mesh_code = mesh_code.upper()) { - if (!mesh_code.isValid()) + auto next_grid_code = GridCode::create(grid_code->get()); + for (; !next_grid_code->isLargestLevel(); ) { + if (!grid_code->isValid()) break; - mesh_codes_str_set.insert(mesh_code.get()); + mesh_codes_str_set.insert(grid_code->get()); + + next_grid_code = next_grid_code->upper(); } } // ファイルごとに mesh_codes_str_set に含まれるなら追加していきます。 @@ -214,9 +217,14 @@ namespace plateau::dataset { } std::shared_ptr - LocalDatasetAccessor::filterByMeshCodes(const std::vector& mesh_codes) const { + LocalDatasetAccessor::filterByGridCodes(const std::vector>& grid_codes) const { auto result = std::make_shared(); - filterByMeshCodes(mesh_codes, *result); + std::vector raw_grid_codes; + raw_grid_codes.reserve(grid_codes.size()); + for(const auto grid_code : grid_codes) { + raw_grid_codes.push_back(grid_code.get()); + } + filterByGridCodes(raw_grid_codes, *result); return result; } diff --git a/src/dataset/local_dataset_accessor.h b/src/dataset/local_dataset_accessor.h index d5021c7d..6f20a03e 100644 --- a/src/dataset/local_dataset_accessor.h +++ b/src/dataset/local_dataset_accessor.h @@ -34,8 +34,8 @@ namespace plateau::dataset { std::shared_ptr filter(const geometry::Extent& extent) const override; void filter(const geometry::Extent& extent, IDatasetAccessor& collection) const override; - void filterByMeshCodes(const std::vector& mesh_codes, IDatasetAccessor& collection) const override; - std::shared_ptr filterByMeshCodes(const std::vector& mesh_codes) const override; + void filterByGridCodes(const std::vector& grid_codes, IDatasetAccessor& collection) const override; + std::shared_ptr filterByGridCodes(const std::vector>& grid_codes) const override; /** * \brief 存在する都市モデルパッケージをマスクとして取得します。 diff --git a/src/dataset/mesh_code.cpp b/src/dataset/mesh_code.cpp index 725d0beb..5e1e68d6 100644 --- a/src/dataset/mesh_code.cpp +++ b/src/dataset/mesh_code.cpp @@ -253,13 +253,14 @@ namespace plateau::dataset { return result; } - MeshCode& MeshCode::upper() { + std::shared_ptr MeshCode::upper() { // レベル2以上の範囲で1段階上のレベルの地域メッシュに変換 - level_ = std::max(1, level_ - 1); - if (level_ < 2) - is_valid_ = false; + auto new_mesh_code = std::make_shared(*this); + new_mesh_code->level_ = std::max(1, level_ - 1); + if (new_mesh_code->level_ < 2) + new_mesh_code->is_valid_ = false; - return *this; + return new_mesh_code; } std::string MeshCode::get() const { @@ -300,6 +301,10 @@ namespace plateau::dataset { return is_valid_; } + bool MeshCode::isLargestLevel() const { + return getLevel() == 2; + } + bool MeshCode::operator==(const MeshCode& other) const { return get() == other.get(); } diff --git a/src/dataset/server_dataset_accessor.cpp b/src/dataset/server_dataset_accessor.cpp index 59fd2158..1cbb3fb2 100644 --- a/src/dataset/server_dataset_accessor.cpp +++ b/src/dataset/server_dataset_accessor.cpp @@ -107,21 +107,25 @@ namespace plateau::dataset { } } - void ServerDatasetAccessor::filterByMeshCodes(const std::vector& mesh_codes, - IDatasetAccessor& collection) const { + void ServerDatasetAccessor::filterByGridCodes(const std::vector& grid_codes, + IDatasetAccessor& collection) const { const auto out_collection_ptr = dynamic_cast(&collection); if (out_collection_ptr == nullptr) return; // 検索用に、引数の mesh_codes を文字列のセットにします。 + // TODO ここの処理はlocal_dataset_accessor.cppと重複する auto mesh_codes_str_set = std::set(); - for (auto mesh_code : mesh_codes) { + for (auto grid_code : grid_codes) { // 各地域メッシュについて上位の地域メッシュも含め登録する。 // 重複する地域メッシュはinsert関数で弾かれる。 - for (; mesh_code.getLevel() >= 2; mesh_code = mesh_code.upper()) { - if (!mesh_code.isValid()) + auto next_grid_code = GridCode::create(grid_code->get()); + for (; !next_grid_code->isLargestLevel(); ) { + if (!grid_code->isValid()) break; - mesh_codes_str_set.insert(mesh_code.get()); + mesh_codes_str_set.insert(grid_code->get()); + + next_grid_code = next_grid_code->upper(); } } @@ -136,9 +140,14 @@ namespace plateau::dataset { } std::shared_ptr - ServerDatasetAccessor::filterByMeshCodes(const std::vector& mesh_codes) const { + ServerDatasetAccessor::filterByGridCodes(const std::vector>& grid_codes) const { auto result = std::make_shared(dataset_id_, client_); - filterByMeshCodes(mesh_codes, *result); + std::vector raw_grid_codes; + raw_grid_codes.reserve(grid_codes.size()); + for(const auto grid_code : grid_codes) { + raw_grid_codes.push_back(grid_code.get()); + } + filterByGridCodes(raw_grid_codes, *result); return result; } } diff --git a/src/dataset/server_dataset_accessor.h b/src/dataset/server_dataset_accessor.h index ceebf94b..660cd3a7 100644 --- a/src/dataset/server_dataset_accessor.h +++ b/src/dataset/server_dataset_accessor.h @@ -33,8 +33,8 @@ namespace plateau::dataset { void filter(const geometry::Extent& extent, IDatasetAccessor& collection) const override; std::shared_ptr filter(const geometry::Extent& extent) const override; - void filterByMeshCodes(const std::vector& mesh_codes, IDatasetAccessor& collection) const override; - std::shared_ptr filterByMeshCodes(const std::vector& mesh_codes) const override; + void filterByGridCodes(const std::vector& grid_codes, IDatasetAccessor& collection) const override; + std::shared_ptr filterByGridCodes(const std::vector>& grid_codes) const override; ServerDatasetAccessor* create() const override { return new ServerDatasetAccessor(dataset_id_, client_); } ServerDatasetAccessor* clone() const override { return new ServerDatasetAccessor(*this); } diff --git a/src/dataset/standard_map_grid.cpp b/src/dataset/standard_map_grid.cpp index 7c1c3f1e..cbc68a07 100644 --- a/src/dataset/standard_map_grid.cpp +++ b/src/dataset/standard_map_grid.cpp @@ -40,6 +40,21 @@ namespace plateau::dataset { return is_valid_; } + std::shared_ptr StandardMapGrid::upper() { + // 仮実装: 自分自身のコピーを返す + return std::make_shared(code_); + } + + int StandardMapGrid::getLevel() const { + // 仮実装: 常に1を返す + return 1; + } + + bool StandardMapGrid::isLargestLevel() const { + // 仮実装: 常にtrueを返す + return true; + } + bool StandardMapGrid::operator==(const StandardMapGrid& other) const { return code_ == other.code_; } diff --git a/test/test_dataset.cpp b/test/test_dataset.cpp index 0816f6c5..672bacdd 100644 --- a/test/test_dataset.cpp +++ b/test/test_dataset.cpp @@ -177,22 +177,22 @@ TEST_F(DatasetTest, DISABLED_fetch_server_generates_files) { // NOLINT fs::remove_all(temp_test_dir); } -namespace { // テスト filterByMeshCodes で使う無名名前空間の関数です。 +namespace { // テスト filterByGridCodes で使う無名名前空間の関数です。 bool doResultOfFilterByMeshCodesContainsMeshCode(const std::string& mesh_code_str, const IDatasetAccessor& udx_file_collection, const PredefinedCityModelPackage sub_folder) { - auto mesh_code = std::vector{ MeshCode(mesh_code_str) }; - auto filtered_collection = udx_file_collection.filterByMeshCodes(mesh_code); + auto grid_code = std::vector>{GridCode::create(mesh_code_str) }; + auto filtered_collection = udx_file_collection.filterByGridCodes(grid_code); auto gml_vector = filtered_collection->getGmlFiles(sub_folder); bool contains_mesh_code = false; for (const auto& building_gml : *gml_vector) { - if (building_gml.getPath().find(mesh_code[0].get()) != std::string::npos) { + if (building_gml.getPath().find(grid_code[0]->get()) != std::string::npos) { contains_mesh_code = true; } } return contains_mesh_code; } -} // テスト filterByMeshCodes で使う無名名前空間の関数です。 +} // テスト filterByGridCodes で使う無名名前空間の関数です。 TEST_F(DatasetTest, filter_by_mesh_codes) { // NOLINT ASSERT_TRUE(doResultOfFilterByMeshCodesContainsMeshCode("53392642", *local_dataset_accessor, diff --git a/test/test_server_dataset_accessor.cpp b/test/test_server_dataset_accessor.cpp index 0a2df4d3..f2e3cec7 100644 --- a/test/test_server_dataset_accessor.cpp +++ b/test/test_server_dataset_accessor.cpp @@ -27,7 +27,7 @@ namespace plateau::dataset { TEST_F(ServerDatasetAccessorTest, DISABLED_getmaxLod) { // NOLINT const auto dataset_source = DatasetSource::createServer("23ku", network::Client::createClientForMockServer()); const auto accessor = dataset_source.getAccessor(); - const auto filter_by_mesh_codes = accessor->filterByMeshCodes({MeshCode("53392670")}); + const auto filter_by_mesh_codes = accessor->filterByGridCodes({GridCode::create("53392670")}); const auto gml_files = filter_by_mesh_codes->getGmlFiles(PredefinedCityModelPackage::Building); auto first_gml = gml_files->at(0); int max_lod = first_gml.getMaxLod(); diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetAccessorTest.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetAccessorTest.cs index 4932c43d..35146669 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetAccessorTest.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetAccessorTest.cs @@ -42,7 +42,7 @@ public void GetGmlFilesLocal() using var accessor = datasetSource.Accessor; var gmls = accessor.GetGmlFiles(PredefinedCityModelPackage.Building); Assert.AreEqual(1, gmls.Length); - Assert.AreEqual("53392642", gmls.At(0).MeshCode.ToString()); + Assert.AreEqual("53392642", gmls.At(0).GridCode.ToString()); Assert.AreEqual( Path.GetFullPath("data/日本語パステスト/udx/bldg/53392642_bldg_6697_op2.gml"), Path.GetFullPath(gmls.At(0).Path) @@ -146,7 +146,7 @@ public void GetGmlFiles() Assert.IsTrue(gmlFiles.Length > 0); var firstGml = gmlFiles.At(0); Assert.AreEqual(PredefinedCityModelPackage.Building, firstGml.Package); - Assert.AreEqual("53392642", firstGml.MeshCode.ToString()); + Assert.AreEqual("53392642", firstGml.GridCode.ToString()); } @@ -172,12 +172,12 @@ private static void TestCenterPoint(DatasetSource source) private static bool DoResultOfFilterByMeshCodesContainsMeshCode(DatasetAccessor accessor, string meshCodeStr) { - using var filtered = accessor.FilterByMeshCodes(new[] { MeshCode.Parse(meshCodeStr) }); + using var filtered = accessor.FilterByGridCoords(new[] { GridCode.Create(meshCodeStr) }); var filteredGMLArray = filtered.GetGmlFiles(PredefinedCityModelPackage.Building); bool contains = false; foreach (var gml in filteredGMLArray) { - var meshCode = gml.MeshCode; + var meshCode = gml.GridCode; if (meshCode.ToString() == meshCodeStr) { contains = true; diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetSourceTest.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetSourceTest.cs index 5450ee55..b546d3ab 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetSourceTest.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetSourceTest.cs @@ -12,7 +12,7 @@ public void Get_Accessor_From_Local_DataSource_Returns_Accessor() { using var source = DatasetSource.Create(new DatasetSourceConfigLocal("data/日本語パステスト")); using var accessor = source.Accessor; - Assert.AreEqual(accessor.GetGmlFiles(PredefinedCityModelPackage.Building).At(0).MeshCode.ToString(), "53392642"); + Assert.AreEqual(accessor.GetGmlFiles(PredefinedCityModelPackage.Building).At(0).GridCode.ToString(), "53392642"); } [Ignore, TestMethod] diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/GmlFileTest.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/GmlFileTest.cs index 50cd69e0..11f72245 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/GmlFileTest.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/GmlFileTest.cs @@ -32,7 +32,7 @@ public void TestMeshCode() { string path = "data/udx/bldg/53392642_bldg_6697_op2.gml"; var info = GmlFile.Create(path); - Assert.AreEqual("53392642", info.MeshCode.ToString()); + Assert.AreEqual("53392642", info.GridCode.ToString()); info.Dispose(); } @@ -76,7 +76,7 @@ public void GetMaxLodLocal() { using var source = DatasetSource.Create(new DatasetSourceConfigLocal("data/日本語パステスト")); using var accessor = source.Accessor; - using var filtered = accessor.FilterByMeshCodes(new [] { MeshCode.Parse("53392642") }); + using var filtered = accessor.FilterByGridCoords(new [] { GridCode.Create("53392642") }); var gmls = filtered.GetGmlFiles(PredefinedCityModelPackage.Building); Assert.AreEqual(1, gmls.Length); Assert.AreEqual(2, gmls.At(0).GetMaxLod()); @@ -87,7 +87,7 @@ public void GetMaxLodServer() { using var source = DatasetSource.CreateForMockServer("23ku"); using var accessor = source.Accessor; - using var filtered = accessor.FilterByMeshCodes(new[] { MeshCode.Parse("53392642") }); + using var filtered = accessor.FilterByGridCoords(new[] { GridCode.Create("53392642") }); var gmls = filtered.GetGmlFiles(PredefinedCityModelPackage.Building); Assert.AreEqual(1, gmls.Length); Assert.AreEqual(1, gmls.At(0).GetMaxLod()); diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/MeshCodeTest.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/MeshCodeTest.cs index fd172668..ae968c89 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/MeshCodeTest.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/MeshCodeTest.cs @@ -10,7 +10,7 @@ public class MeshCodeTest [TestMethod] public void Get_Extent_Calculates_Returns_Proper_Coordinate() { - var extent = MeshCode.Parse("53394525").Extent; + var extent = GridCode.Create("53394525").Extent; var expected = new GeoCoordinate(35.68731814, 139.68926804, 0); AssertGE(extent.Max.Latitude, expected.Latitude); diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/GeometryModel/MeshExtractorTests.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/GeometryModel/MeshExtractorTests.cs index e2cc6abd..e69a4588 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/GeometryModel/MeshExtractorTests.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/GeometryModel/MeshExtractorTests.cs @@ -79,7 +79,7 @@ public void ExtractInExtentsReturnsAllNodesIfItIsCalledWithSufficientExtents() for (int j = 1; j <= 4; ++j) { var meshCodeStr = thirdMeshCodeStr + $"{i}{j}"; - extents.Add(MeshCode.Parse(meshCodeStr).Extent); + extents.Add(GridCode.Create(meshCodeStr).Extent); } } diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/DatasetAccessor.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/DatasetAccessor.cs index 7624e59f..b2d663e3 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/DatasetAccessor.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/DatasetAccessor.cs @@ -46,7 +46,7 @@ public NativeVectorGridCode GridCodes get { var meshCodes = NativeVectorGridCode.Create(); - var result = NativeMethods.plateau_i_dataset_accessor_get_mesh_codes( + var result = NativeMethods.plateau_i_dataset_accessor_get_grid_codes( Handle, meshCodes.Handle); DLLUtil.CheckDllError(result); return meshCodes; @@ -74,15 +74,15 @@ public PlateauVector3d CalculateCenterPoint(GeoReference geoReference) return centerPoint; } - public DatasetAccessor FilterByMeshCodes(IEnumerable meshCodes) + public DatasetAccessor FilterByGridCoords(IEnumerable gridCodes) { var nativeMeshCodes = NativeVectorGridCode.Create(); - foreach (var meshCode in meshCodes) + foreach (var meshCode in gridCodes) { nativeMeshCodes.Add(meshCode); } - var result = NativeMethods.plateau_i_dataset_accessor_filter_by_mesh_codes( + var result = NativeMethods.plateau_i_dataset_accessor_filter_by_grid_codes( Handle, nativeMeshCodes.Handle, out var filteredPtr); DLLUtil.CheckDllError(result); nativeMeshCodes.Dispose(); @@ -121,7 +121,7 @@ internal static extern APIResult plateau_i_dataset_accessor_get_gml_files( [In] IntPtr refVectorGmlFilePtr); [DllImport(DLLUtil.DllName)] - internal static extern APIResult plateau_i_dataset_accessor_get_mesh_codes( + internal static extern APIResult plateau_i_dataset_accessor_get_grid_codes( [In] IntPtr accessorPtr, [In,Out] IntPtr refVectorMeshCodePtr); @@ -137,7 +137,7 @@ internal static extern APIResult plateau_i_dataset_accessor_calculate_center_poi out PlateauVector3d outCenterPoint); [DllImport(DLLUtil.DllName)] - internal static extern APIResult plateau_i_dataset_accessor_filter_by_mesh_codes( + internal static extern APIResult plateau_i_dataset_accessor_filter_by_grid_codes( [In] IntPtr accessorPtr, [In] IntPtr nativeVectorMeshCodePtr, out IntPtr outFilteredAccessorPtr); diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/GmlFile.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/GmlFile.cs index f3faab17..07ee7cfb 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/GmlFile.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/GmlFile.cs @@ -78,18 +78,19 @@ public PredefinedCityModelPackage Package { } /// - /// GMLファイルのメッシュコードを返します。 - /// ただし、誤った形式のGMLファイル名である等の理由でメッシュコードを読み取れなかった場合は - /// 戻り値の meshCode.IsValid が false になります。 + /// GMLファイルのGridCodeを返します。 + /// ただし、誤った形式のGMLファイル名である等の理由でGridCodeを読み取れなかった場合は + /// 戻り値の isValid が false になります。 /// - public MeshCode MeshCode + public GridCode GridCode { get { ThrowIfDisposed(); - var meshCode = DLLUtil.GetNativeValue(Handle, - NativeMethods.plateau_gml_file_get_mesh_code); - return meshCode; + var gridCodePtr = DLLUtil.GetNativeValue(Handle, + NativeMethods.plateau_gml_file_get_grid_code); + var copied = GridCode.CopyFrom(gridCodePtr); + return copied; } } @@ -208,9 +209,9 @@ internal static extern APIResult plateau_gml_file_get_feature_type_str( out int strLength); [DllImport(DLLUtil.DllName)] - internal static extern APIResult plateau_gml_file_get_mesh_code( + internal static extern APIResult plateau_gml_file_get_grid_code( [In] IntPtr gmlFilePtr, - out MeshCode outMeshCode); + out IntPtr outGridCodePtr); [DllImport(DLLUtil.DllName, CharSet = CharSet.Ansi)] internal static extern APIResult plateau_gml_file_fetch( diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/GridCode.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/GridCode.cs index dfc23671..201de568 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/GridCode.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/GridCode.cs @@ -10,20 +10,21 @@ namespace PLATEAU.Dataset /// public class GridCode : PInvokeDisposable { - internal GridCode(IntPtr handle, bool autoDispose = true) : base(handle, autoDispose) + private GridCode(IntPtr handle, bool autoDispose = true) : base(handle, autoDispose) { } - public static GridCode Parse(string code) + public static GridCode Create(string code) { var result = NativeMethods.plateau_grid_code_parse(code, out var gridCodePtr); DLLUtil.CheckDllError(result); return new GridCode(gridCodePtr); } - - public GridCode Copy() + + public static GridCode CopyFrom(IntPtr otherGridCodePtr) { - return Parse(StringCode); + var other = new GridCode(otherGridCodePtr, false); + return Create(other.StringCode); } public Extent Extent @@ -50,6 +51,11 @@ public string StringCode ); } } + + public override string ToString() + { + return StringCode; + } public bool IsValid { diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/NativeVectorGridCode.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/NativeVectorGridCode.cs index ac9a19d9..f1014bff 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/NativeVectorGridCode.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/NativeVectorGridCode.cs @@ -10,10 +10,9 @@ public class NativeVectorGridCode : NativeVectorDisposableBase private NativeVectorGridCode(IntPtr ptr) : base(ptr) { } - public static NativeVectorGridCode Create() { - var result = NativeMethods.plateau_create_vector_mesh_code(out var ptr); + var result = NativeMethods.plateau_create_vector_grid_code(out var ptr); DLLUtil.CheckDllError(result); return new NativeVectorGridCode(ptr); } @@ -23,8 +22,7 @@ public override GridCode At(int index) ThrowIfDisposed(); var gridCodePtr = DLLUtil.GetNativeValue(Handle, index, NativeMethods.plateau_vector_grid_code_get_value); - var gridCode = new GridCode(gridCodePtr, false); - return gridCode.Copy(); // 寿命管理のためコピーを渡します。元データはvector廃棄時に消します。 + return GridCode.CopyFrom(gridCodePtr); // 寿命管理のためコピーを渡します。元データはvector廃棄時に消します。 } public override int Length @@ -38,28 +36,41 @@ public override int Length } } - public void Add(MeshCode meshCode) + public void Add(GridCode gridCode) { - var result = NativeMethods.plateau_vector_mesh_code_push_back_value( - Handle, meshCode); + gridCode.PreventAutoDispose(); + var result = NativeMethods.plateau_vector_grid_code_push_back_value( + Handle, gridCode.Handle); DLLUtil.CheckDllError(result); } - protected override void DisposeNative() { - var result = NativeMethods.plateau_delete_vector_mesh_code(Handle); + // ベクター内の各GridCodeを削除してからベクターを解放 + CleanupElements(); + var result = NativeMethods.plateau_delete_vector_grid_code(Handle); + DLLUtil.CheckDllError(result); + } + + /// + /// ベクター内の各GridCodeオブジェクトを削除します。 + /// ベクター自体は削除しません。 + /// + public void CleanupElements() + { + ThrowIfDisposed(); + var result = NativeMethods.plateau_cleanup_vector_grid_code(Handle); DLLUtil.CheckDllError(result); } private static class NativeMethods { [DllImport(DLLUtil.DllName)] - internal static extern APIResult plateau_create_vector_mesh_code( + internal static extern APIResult plateau_create_vector_grid_code( out IntPtr outVectorPtr); [DllImport(DLLUtil.DllName)] - internal static extern APIResult plateau_delete_vector_mesh_code( + internal static extern APIResult plateau_delete_vector_grid_code( [In] IntPtr vectorPtr); [DllImport(DLLUtil.DllName)] @@ -74,9 +85,13 @@ internal static extern APIResult plateau_vector_grid_code_count( out int outCount); [DllImport(DLLUtil.DllName)] - internal static extern APIResult grid_code_push_back_value( + internal static extern APIResult plateau_vector_grid_code_push_back_value( [In] IntPtr handle, [In] IntPtr gridCodePtr); + + [DllImport(DLLUtil.DllName)] + internal static extern APIResult plateau_cleanup_vector_grid_code( + [In] IntPtr handle); } } } diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/PInvokeDisposable.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/PInvokeDisposable.cs index cc6ae1fc..ef2efc27 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/PInvokeDisposable.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/PInvokeDisposable.cs @@ -30,6 +30,11 @@ public void Dispose() GC.SuppressFinalize(this); this.isDisposed = true; } + + public void PreventAutoDispose() + { + this.autoDispose = false; + } protected void ThrowIfDisposed() { From 1870eec76ad256032efb80d6b2b5d6ea4d88a7d1 Mon Sep 17 00:00:00 2001 From: Linoal <1321932+linoal@users.noreply.github.com> Date: Mon, 14 Apr 2025 18:14:59 +0900 Subject: [PATCH 04/19] =?UTF-8?q?gridCode=E7=A7=BB=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/plateau/dataset/grid_code.h | 18 ++++- include/plateau/dataset/invalid_grid_code.h | 8 ++- include/plateau/dataset/mesh_code.h | 31 +++++---- include/plateau/dataset/standard_map_grid.h | 5 +- src/c_wrapper/grid_code_c.cpp | 32 +++++++++ src/dataset/mesh_code.cpp | 19 +++++- src/dataset/standard_map_grid.cpp | 19 +++++- src/plateau/dataset/grid_code.cpp | 62 ++++++++++++++++++ .../CSharpPLATEAU/Dataset/GridCode.cs | 65 +++++++++++++++++++ 9 files changed, 238 insertions(+), 21 deletions(-) create mode 100644 src/plateau/dataset/grid_code.cpp diff --git a/include/plateau/dataset/grid_code.h b/include/plateau/dataset/grid_code.h index 79ebdc51..18f90df1 100644 --- a/include/plateau/dataset/grid_code.h +++ b/include/plateau/dataset/grid_code.h @@ -6,6 +6,9 @@ #include "plateau/geometry/geo_coordinate.h" namespace plateau::dataset { + class StandardMapGrid; + class MeshCode; + /** * \brief 地図の区画を表すコードの基底クラスです。 * @@ -38,7 +41,8 @@ namespace plateau::dataset { /** * \brief 1段階上のレベルのグリッドコードに変換します。 */ - virtual std::shared_ptr upper() = 0; + virtual std::shared_ptr upper() const = 0; + virtual GridCode* upperRaw() const = 0; /** * \brief コードのレベル(詳細度)を取得します。 @@ -51,6 +55,18 @@ namespace plateau::dataset { */ virtual bool isLargestLevel() const = 0; + /** + * \brief コードのレベル(詳細度)が、PLATEAUの典型的な建物のGMLファイルのレベルよりも小さい場合にtrueを返します。 + */ + virtual bool isSmallerThanNormalGml() const = 0; + + /** + * \brief コードのレベル(詳細度)が、PLATEAUの典型的な建物のGMLファイルのレベルである場合にtrueを返します。 + */ + virtual bool isNormalGmlLevel() const = 0; + + bool isMeshCode() const; + /** * \brief 与えられたコードから適切なGridCodeの派生クラスのインスタンスを作成します。 * \param code コード文字列 diff --git a/include/plateau/dataset/invalid_grid_code.h b/include/plateau/dataset/invalid_grid_code.h index b3bc4800..320a59c9 100644 --- a/include/plateau/dataset/invalid_grid_code.h +++ b/include/plateau/dataset/invalid_grid_code.h @@ -48,11 +48,17 @@ namespace plateau::dataset { * \brief 1段階上のレベルのグリッドコードに変換します。 * \return 無効なグリッドコードを返します。 */ - std::shared_ptr upper() override { + std::shared_ptr upper() const override { return std::make_shared(); } + GridCode* upperRaw() const override { + return new InvalidGridCode(); + } + int getLevel() const override { return -1; } bool isLargestLevel() const override { return true; } + bool isSmallerThanNormalGml() const override { return false; } + bool isNormalGmlLevel() const override { return true; } }; } \ No newline at end of file diff --git a/include/plateau/dataset/mesh_code.h b/include/plateau/dataset/mesh_code.h index 6720d56b..d52b6588 100644 --- a/include/plateau/dataset/mesh_code.h +++ b/include/plateau/dataset/mesh_code.h @@ -13,7 +13,7 @@ namespace plateau::dataset { * * 2~5次メッシュの緯度経度範囲の取得、緯度経度範囲を内包する3次メッシュの取得を行う機能を提供しています。 */ - class LIBPLATEAU_EXPORT MeshCode : public GridCode { +class LIBPLATEAU_EXPORT MeshCode : public plateau::dataset::GridCode { public: explicit MeshCode(const std::string& code); MeshCode() = default; @@ -61,7 +61,8 @@ namespace plateau::dataset { /** * \brief レベル2以上の範囲で1段階上のレベルの地域メッシュに変換します。 */ - std::shared_ptr upper() override; + std::shared_ptr upper() const override; + GridCode* upperRaw() const override; /** * \brief メッシュコードが適切な値かどうかを返します。 @@ -72,24 +73,26 @@ namespace plateau::dataset { * \brief コードのレベル(詳細度)が、PLATEAUの仕様上考えられる中でもっとも大きいものであるときにtrueを返します。 */ bool isLargestLevel() const override; + bool isSmallerThanNormalGml() const override; + bool isNormalGmlLevel() const override; bool operator==(const MeshCode& other) const; private: - int first_row_; - int first_col_; - int second_row_; - int second_col_; - int third_row_; - int third_col_; - int fourth_row_; - int fourth_col_; - int fifth_row_; - int fifth_col_; - int level_; - bool is_valid_; + int first_row_ = 0; + int first_col_ = 0; + int second_row_ = 0; + int second_col_ = 0; + int third_row_ = 0; + int third_col_ = 0; + int fourth_row_ = 0; + int fourth_col_ = 0; + int fifth_row_ = 0; + int fifth_col_ = 0; + int level_ = 0; + bool is_valid_ = false; static void nextRow(MeshCode& mesh_code); static void nextCol(MeshCode& mesh_code); diff --git a/include/plateau/dataset/standard_map_grid.h b/include/plateau/dataset/standard_map_grid.h index 5ea397ea..bb82daf7 100644 --- a/include/plateau/dataset/standard_map_grid.h +++ b/include/plateau/dataset/standard_map_grid.h @@ -40,7 +40,8 @@ namespace plateau::dataset { /** * \brief 1段階上のレベルのグリッドコードに変換します。 */ - std::shared_ptr upper() override; + std::shared_ptr upper() const override; + GridCode* upperRaw() const override; /** * \brief コードのレベル(詳細度)を取得します。 @@ -51,6 +52,8 @@ namespace plateau::dataset { * \brief コードのレベル(詳細度)が、PLATEAUの仕様上考えられる中でもっとも大きいものであるときにtrueを返します。 */ bool isLargestLevel() const override; + bool isSmallerThanNormalGml() const override; + bool isNormalGmlLevel() const override; bool operator==(const StandardMapGrid& other) const; bool operator<(StandardMapGrid& other) const; diff --git a/src/c_wrapper/grid_code_c.cpp b/src/c_wrapper/grid_code_c.cpp index a5d3f950..c425ba42 100644 --- a/src/c_wrapper/grid_code_c.cpp +++ b/src/c_wrapper/grid_code_c.cpp @@ -39,10 +39,42 @@ extern "C" { GridCode, handle->get()) + DLL_2_ARG_FUNC(plateau_grid_code_is_largest_level, + const GridCode* grid_code, + bool* out_is_largest_level, + if (grid_code == nullptr) { *out_is_largest_level = false; return APIResult::ErrorInvalidArgument; } + *out_is_largest_level = grid_code->isLargestLevel() + ) + + DLL_2_ARG_FUNC(plateau_grid_code_is_smaller_than_normal_gml, + const GridCode* grid_code, + bool* out_is_smaller_than_normal_gml, + if (grid_code == nullptr) { *out_is_smaller_than_normal_gml = false; return APIResult::ErrorInvalidArgument; } + *out_is_smaller_than_normal_gml = grid_code->isSmallerThanNormalGml()) + + DLL_2_ARG_FUNC(plateau_grid_code_is_normal_gml_level, + const GridCode* grid_code, + bool* out_is_normal_gml_level, + if (grid_code == nullptr) { *out_is_normal_gml_level = false; return APIResult::ErrorInvalidArgument; } + *out_is_normal_gml_level = grid_code->isNormalGmlLevel()) + LIBPLATEAU_C_EXPORT APIResult LIBPLATEAU_C_API plateau_grid_code_delete( GridCode* grid_code ) { delete grid_code; return APIResult::Success; } + + LIBPLATEAU_C_EXPORT APIResult LIBPLATEAU_C_API plateau_grid_code_upper( + const GridCode* grid_code, + GridCode** out_upper_grid_code + ) { + API_TRY{ + if (grid_code == nullptr) return APIResult::ErrorInvalidArgument; + *out_upper_grid_code = grid_code->upperRaw(); + return APIResult::Success; + } + API_CATCH; + return APIResult::ErrorUnknown; + } } diff --git a/src/dataset/mesh_code.cpp b/src/dataset/mesh_code.cpp index 5e1e68d6..f23b2225 100644 --- a/src/dataset/mesh_code.cpp +++ b/src/dataset/mesh_code.cpp @@ -253,9 +253,15 @@ namespace plateau::dataset { return result; } - std::shared_ptr MeshCode::upper() { + std::shared_ptr MeshCode::upper() const { // レベル2以上の範囲で1段階上のレベルの地域メッシュに変換 - auto new_mesh_code = std::make_shared(*this); + auto new_mesh_code = std::shared_ptr(upperRaw()); + return new_mesh_code; + } + + GridCode* MeshCode::upperRaw() const { || + // レベル2以上の範囲で1段階上のレベルの地域メッシュに変換 + auto new_mesh_code = new MeshCode(*this); new_mesh_code->level_ = std::max(1, level_ - 1); if (new_mesh_code->level_ < 2) new_mesh_code->is_valid_ = false; @@ -305,11 +311,20 @@ namespace plateau::dataset { return getLevel() == 2; } + bool MeshCode::isSmallerThanNormalGml() const { + return getLevel() >= 4; + } + + bool MeshCode::isNormalGmlLevel() const { + return getLevel() == 3; + } + bool MeshCode::operator==(const MeshCode& other) const { return get() == other.get(); } + void MeshCode::nextCol(MeshCode& mesh_code) { if (mesh_code.third_col_ < third_division_count - 1) { mesh_code.third_col_ += 1; diff --git a/src/dataset/standard_map_grid.cpp b/src/dataset/standard_map_grid.cpp index cbc68a07..2f6cfe7c 100644 --- a/src/dataset/standard_map_grid.cpp +++ b/src/dataset/standard_map_grid.cpp @@ -40,9 +40,14 @@ namespace plateau::dataset { return is_valid_; } - std::shared_ptr StandardMapGrid::upper() { + std::shared_ptr StandardMapGrid::upper() const { // 仮実装: 自分自身のコピーを返す - return std::make_shared(code_); + return std::shared_ptr(upperRaw()); + } + + GridCode* StandardMapGrid::upperRaw() const { + // 仮実装: 自分自身のコピーを返す + return new StandardMapGrid(code_); } int StandardMapGrid::getLevel() const { @@ -55,6 +60,16 @@ namespace plateau::dataset { return true; } + bool StandardMapGrid::isSmallerThanNormalGml() const { + // 仮実装 + return false; + } + + bool StandardMapGrid::isNormalGmlLevel() const { + // 仮実装: 常にtrueを返す + return true; + } + bool StandardMapGrid::operator==(const StandardMapGrid& other) const { return code_ == other.code_; } diff --git a/src/plateau/dataset/grid_code.cpp b/src/plateau/dataset/grid_code.cpp new file mode 100644 index 00000000..3f6bec16 --- /dev/null +++ b/src/plateau/dataset/grid_code.cpp @@ -0,0 +1,62 @@ +#include "plateau/dataset/grid_code.h" +#include "plateau/dataset/mesh_code.h" +#include "plateau/dataset/standard_map_grid.h" +#include + +namespace plateau::dataset { + +bool GridCode::isMeshCode() const { + return dynamic_cast(this) != nullptr; +} + +std::shared_ptr GridCode::create(const std::string& code) { + // Try creating as MeshCode + try { + auto meshCode = std::make_shared(code); + if (meshCode->isValid()) { + return meshCode; + } + } catch (const std::invalid_argument&) { + // Ignore and try StandardMapGrid + } + + // Try creating as StandardMapGrid + try { + auto standardMapGrid = std::make_shared(code); + if (standardMapGrid->isValid()) { + return standardMapGrid; + } + } catch (const std::invalid_argument&) { + // Ignore + } + + throw std::invalid_argument("Invalid code format: " + code); +} + +GridCode* GridCode::createRaw(const std::string& code) { + // Try creating as MeshCode + try { + auto* meshCode = new MeshCode(code); + if (meshCode->isValid()) { + return meshCode; + } + delete meshCode; + } catch (const std::invalid_argument&) { + // Ignore and try StandardMapGrid + } + + // Try creating as StandardMapGrid + try { + auto* standardMapGrid = new StandardMapGrid(code); + if (standardMapGrid->isValid()) { + return standardMapGrid; + } + delete standardMapGrid; + } catch (const std::invalid_argument&) { + // Ignore + } + + throw std::invalid_argument("Invalid code format: " + code); +} + +} \ No newline at end of file diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/GridCode.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/GridCode.cs index 201de568..98b71d86 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/GridCode.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/GridCode.cs @@ -57,6 +57,47 @@ public override string ToString() return StringCode; } + public bool IsLargestLevel + { + get + { + var result = NativeMethods.plateau_grid_code_is_largest_level(Handle, out bool isLargestLevel); + DLLUtil.CheckDllError(result); + return isLargestLevel; + } + } + + public bool IsSmallerThanNormalGml + { + get + { + var result = NativeMethods.plateau_grid_code_is_smaller_than_normal_gml(Handle, out bool isSmallerThanNormalGml); + DLLUtil.CheckDllError(result); + return isSmallerThanNormalGml; + } + } + + public bool IsNormalGmlLevel + { + get + { + var result = NativeMethods.plateau_grid_code_is_normal_gml_level(Handle, out bool isNormalGmlLevel); + DLLUtil.CheckDllError(result); + return isNormalGmlLevel; + } + } + + /// + /// 1段階上のレベルのグリッドコードに変換します。 + /// + /// 1段階上のレベルのグリッドコードオブジェクト + public GridCode Upper() + { + var result = NativeMethods.plateau_grid_code_upper(Handle, out var upperGridCodePtr); + DLLUtil.CheckDllError(result); + return new GridCode(upperGridCodePtr); + } + public bool IsValid { get @@ -108,6 +149,30 @@ internal static extern APIResult plateau_grid_code_get_string_code_size( out int strSize ); + [DllImport(DLLUtil.DllName)] + internal static extern APIResult plateau_grid_code_is_largest_level( + [In] IntPtr gridCodePtr, + [MarshalAs(UnmanagedType.U1)] out bool outIsLargestLevel + ); + + [DllImport(DLLUtil.DllName)] + internal static extern APIResult plateau_grid_code_is_smaller_than_normal_gml( + [In] IntPtr gridCodePtr, + [MarshalAs(UnmanagedType.U1)] out bool isSmallerThanNormalGml + ); + + [DllImport(DLLUtil.DllName)] + internal static extern APIResult plateau_grid_code_is_normal_gml_level( + [In] IntPtr gridCodePtr, + [MarshalAs(UnmanagedType.U1)] out bool isNormalGmlLevel + ); + + [DllImport(DLLUtil.DllName)] + internal static extern APIResult plateau_grid_code_upper( + [In] IntPtr gridCodePtr, + out IntPtr outUpperGridCodePtr + ); + [DllImport(DLLUtil.DllName)] internal static extern APIResult plateau_grid_code_get_string_code( [In] IntPtr gridCodePtr, From bd84e7ef967176e6e8126b36b3abfe8df2a7921b Mon Sep 17 00:00:00 2001 From: Linoal <1321932+linoal@users.noreply.github.com> Date: Tue, 15 Apr 2025 13:19:43 +0900 Subject: [PATCH 05/19] =?UTF-8?q?GridCode=E7=A7=BB=E8=A1=8C2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/c_wrapper/vector_c.cpp | 2 +- src/dataset/local_dataset_accessor.cpp | 2 +- src/dataset/mesh_code.cpp | 2 +- src/dataset/server_dataset_accessor.cpp | 2 +- .../csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/GridCode.cs | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/c_wrapper/vector_c.cpp b/src/c_wrapper/vector_c.cpp index ce1b6300..ad7e983b 100644 --- a/src/c_wrapper/vector_c.cpp +++ b/src/c_wrapper/vector_c.cpp @@ -100,7 +100,7 @@ LIBPLATEAU_C_EXPORT APIResult LIBPLATEAU_API plateau_create_vector_ ## FUNC_NAME } PLATEAU_VECTOR_GET_BY_PTR(gml_file, GmlFile) - PLATEAU_VECTOR_GET_BY_VALUE(grid_code, GridCode*) // TODO クリーンアップ + PLATEAU_VECTOR_GET_BY_VALUE(grid_code, GridCode*) CLEANUP(grid_code, GridCode*) PLATEAU_VECTOR_GET_BY_PTR(dataset_metadata_group, DatasetMetadataGroup) PLATEAU_VECTOR_GET_BY_PTR(dataset_metadata, DatasetMetadata) diff --git a/src/dataset/local_dataset_accessor.cpp b/src/dataset/local_dataset_accessor.cpp index 5c41e4d7..240afb00 100644 --- a/src/dataset/local_dataset_accessor.cpp +++ b/src/dataset/local_dataset_accessor.cpp @@ -201,7 +201,7 @@ namespace plateau::dataset { for (; !next_grid_code->isLargestLevel(); ) { if (!grid_code->isValid()) break; - mesh_codes_str_set.insert(grid_code->get()); + mesh_codes_str_set.insert(next_grid_code->get()); next_grid_code = next_grid_code->upper(); } diff --git a/src/dataset/mesh_code.cpp b/src/dataset/mesh_code.cpp index f23b2225..909f42e7 100644 --- a/src/dataset/mesh_code.cpp +++ b/src/dataset/mesh_code.cpp @@ -259,7 +259,7 @@ namespace plateau::dataset { return new_mesh_code; } - GridCode* MeshCode::upperRaw() const { || + GridCode* MeshCode::upperRaw() const { // レベル2以上の範囲で1段階上のレベルの地域メッシュに変換 auto new_mesh_code = new MeshCode(*this); new_mesh_code->level_ = std::max(1, level_ - 1); diff --git a/src/dataset/server_dataset_accessor.cpp b/src/dataset/server_dataset_accessor.cpp index 1cbb3fb2..a674fa17 100644 --- a/src/dataset/server_dataset_accessor.cpp +++ b/src/dataset/server_dataset_accessor.cpp @@ -123,7 +123,7 @@ namespace plateau::dataset { for (; !next_grid_code->isLargestLevel(); ) { if (!grid_code->isValid()) break; - mesh_codes_str_set.insert(grid_code->get()); + mesh_codes_str_set.insert(next_grid_code->get()); next_grid_code = next_grid_code->upper(); } diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/GridCode.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/GridCode.cs index 98b71d86..48f9aa18 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/GridCode.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/GridCode.cs @@ -14,11 +14,11 @@ private GridCode(IntPtr handle, bool autoDispose = true) : base(handle, autoDisp { } - public static GridCode Create(string code) + public static GridCode Create(string code, bool autoDispose = true) { var result = NativeMethods.plateau_grid_code_parse(code, out var gridCodePtr); DLLUtil.CheckDllError(result); - return new GridCode(gridCodePtr); + return new GridCode(gridCodePtr, autoDispose); } public static GridCode CopyFrom(IntPtr otherGridCodePtr) From 18250a5b6cb7c010099a33435aeacd36442f3882 Mon Sep 17 00:00:00 2001 From: Linoal <1321932+linoal@users.noreply.github.com> Date: Tue, 15 Apr 2025 16:22:35 +0900 Subject: [PATCH 06/19] =?UTF-8?q?=E3=82=B3=E3=83=BC=E3=83=89=E6=95=B4?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 共通部分まとめ 不要なのを削除中 警告対処中 警告対処中 不要なもの削除 コード整理 --- include/plateau/dataset/gml_file.h | 1 - include/plateau/dataset/grid_code.h | 1 - include/plateau/dataset/i_dataset_accessor.h | 10 +-- include/plateau/dataset/invalid_grid_code.h | 4 +- include/plateau/dataset/mesh_code.h | 2 +- include/plateau/dataset/standard_map_grid.h | 4 +- include/plateau/network/client.h | 5 +- src/c_wrapper/i_dataset_accessor_c.cpp | 1 - src/dataset/CMakeLists.txt | 1 + src/dataset/gml_file.cpp | 1 - src/dataset/grid_code_utils.cpp | 31 ++++++++++ src/dataset/grid_code_utils.h | 17 +++++ src/dataset/local_dataset_accessor.cpp | 23 +++---- src/dataset/mesh_code.cpp | 4 +- src/dataset/server_dataset_accessor.cpp | 23 ++----- src/dataset/server_dataset_accessor.h | 4 +- src/dataset/standard_map_grid.cpp | 6 +- src/plateau/dataset/grid_code.cpp | 62 ------------------- src/plateau/dataset/standard_map_grid.cpp | 53 ---------------- test/test_mesh_extractor.cpp | 4 +- .../Native/NativeVectorGridCode.cs | 4 ++ 21 files changed, 89 insertions(+), 172 deletions(-) create mode 100644 src/dataset/grid_code_utils.cpp create mode 100644 src/dataset/grid_code_utils.h delete mode 100644 src/plateau/dataset/grid_code.cpp delete mode 100644 src/plateau/dataset/standard_map_grid.cpp diff --git a/include/plateau/dataset/gml_file.h b/include/plateau/dataset/gml_file.h index abdf5cd9..b5e611d8 100644 --- a/include/plateau/dataset/gml_file.h +++ b/include/plateau/dataset/gml_file.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include #include "plateau/network/client.h" diff --git a/include/plateau/dataset/grid_code.h b/include/plateau/dataset/grid_code.h index 18f90df1..7ec84348 100644 --- a/include/plateau/dataset/grid_code.h +++ b/include/plateau/dataset/grid_code.h @@ -65,7 +65,6 @@ namespace plateau::dataset { */ virtual bool isNormalGmlLevel() const = 0; - bool isMeshCode() const; /** * \brief 与えられたコードから適切なGridCodeの派生クラスのインスタンスを作成します。 diff --git a/include/plateau/dataset/i_dataset_accessor.h b/include/plateau/dataset/i_dataset_accessor.h index d780a3e5..85c2bd43 100644 --- a/include/plateau/dataset/i_dataset_accessor.h +++ b/include/plateau/dataset/i_dataset_accessor.h @@ -16,7 +16,7 @@ namespace plateau::dataset { */ class LIBPLATEAU_EXPORT UdxSubFolder { public: - UdxSubFolder(std::string name) + explicit UdxSubFolder(std::string name) : name_(std::move(name)) { } @@ -27,11 +27,11 @@ namespace plateau::dataset { return name_; } - operator std::string& () { + explicit operator std::string& () { return name_; } - operator std::string() const { + explicit operator std::string() const { return name_; } @@ -95,9 +95,9 @@ namespace plateau::dataset { * \brief GMLファイル群のうち、範囲が extent の内部であり、パッケージ種が package であるものを vector で返します。 * なお、 package はフラグの集合と見なされるので、複数のビットを立てることで複数の指定が可能です。 */ - virtual std::shared_ptr> getGmlFiles(const PredefinedCityModelPackage package) = 0; + virtual std::shared_ptr> getGmlFiles(PredefinedCityModelPackage package) = 0; - virtual void getGmlFiles(const PredefinedCityModelPackage package, + virtual void getGmlFiles(PredefinedCityModelPackage package, std::vector& out_vector) = 0; /** diff --git a/include/plateau/dataset/invalid_grid_code.h b/include/plateau/dataset/invalid_grid_code.h index 320a59c9..ac657279 100644 --- a/include/plateau/dataset/invalid_grid_code.h +++ b/include/plateau/dataset/invalid_grid_code.h @@ -26,10 +26,10 @@ namespace plateau::dataset { * \return 原点(0,0,0)を中心とする無効な範囲を返します。 */ geometry::Extent getExtent() const override { - return geometry::Extent( + return { geometry::GeoCoordinate(0, 0, 0), geometry::GeoCoordinate(0, 0, 0) - ); + }; } /** diff --git a/include/plateau/dataset/mesh_code.h b/include/plateau/dataset/mesh_code.h index d52b6588..84fb49ce 100644 --- a/include/plateau/dataset/mesh_code.h +++ b/include/plateau/dataset/mesh_code.h @@ -26,7 +26,7 @@ class LIBPLATEAU_EXPORT MeshCode : public plateau::dataset::GridCode { /** * \brief メッシュコードの次数を取得します。 */ - int getLevel() const; + int getLevel() const override; /** * \brief メッシュコードの緯度経度範囲を取得します。 diff --git a/include/plateau/dataset/standard_map_grid.h b/include/plateau/dataset/standard_map_grid.h index bb82daf7..6e25be27 100644 --- a/include/plateau/dataset/standard_map_grid.h +++ b/include/plateau/dataset/standard_map_grid.h @@ -14,7 +14,7 @@ namespace plateau::dataset { */ class LIBPLATEAU_EXPORT StandardMapGrid : public GridCode { public: - explicit StandardMapGrid(const std::string& code); + explicit StandardMapGrid(std::string code); StandardMapGrid() = default; /** @@ -61,6 +61,6 @@ namespace plateau::dataset { private: std::string code_; // 図郭コード - bool is_valid_; // コードが有効かどうか + bool is_valid_ = false; // コードが有効かどうか }; } \ No newline at end of file diff --git a/include/plateau/network/client.h b/include/plateau/network/client.h index cf535a4c..ad5b6010 100644 --- a/include/plateau/network/client.h +++ b/include/plateau/network/client.h @@ -1,7 +1,10 @@ #pragma once #include #include -#include +#include +#include +#include +#include "libplateau_api.h" namespace plateau::network { diff --git a/src/c_wrapper/i_dataset_accessor_c.cpp b/src/c_wrapper/i_dataset_accessor_c.cpp index 440c3318..cb8b169a 100644 --- a/src/c_wrapper/i_dataset_accessor_c.cpp +++ b/src/c_wrapper/i_dataset_accessor_c.cpp @@ -1,7 +1,6 @@ #include "libplateau_c.h" #include #include -#include extern "C" { using namespace plateau::dataset; diff --git a/src/dataset/CMakeLists.txt b/src/dataset/CMakeLists.txt index f56838dc..5805bcbe 100644 --- a/src/dataset/CMakeLists.txt +++ b/src/dataset/CMakeLists.txt @@ -6,5 +6,6 @@ target_sources(plateau PRIVATE "lod_searcher.cpp" "dataset_source.cpp" "grid_code.cpp" + "grid_code_utils.cpp" "standard_map_grid.cpp" ) diff --git a/src/dataset/gml_file.cpp b/src/dataset/gml_file.cpp index 80a251e7..da9ee717 100644 --- a/src/dataset/gml_file.cpp +++ b/src/dataset/gml_file.cpp @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/src/dataset/grid_code_utils.cpp b/src/dataset/grid_code_utils.cpp new file mode 100644 index 00000000..f01f900a --- /dev/null +++ b/src/dataset/grid_code_utils.cpp @@ -0,0 +1,31 @@ +#include "grid_code_utils.h" + +namespace plateau::dataset::utils { + + std::set createExpandedGridCodeSet(const std::vector& grid_codes) { + std::set grid_codes_str_set; + for (const auto& grid_code_ptr: grid_codes) { + if (!grid_code_ptr || !grid_code_ptr->isValid()) { + continue; // 不正なポインタやコードはスキップ + } + + // createは毎回新しいインスタンスを生成するため、ループの外で取得する + std::shared_ptr current_code = GridCode::create(grid_code_ptr->get()); + if (!current_code || !current_code->isValid()) { + continue; + } + + // 現在のコードとその上位コードをセットに追加 + while (true) { + if (!current_code->isValid()) break; + grid_codes_str_set.insert(current_code->get()); + if (current_code->isLargestLevel()) break; // 最上位なら終了 + current_code = current_code->upper(); + if (!current_code) break; + } + } + return grid_codes_str_set; + } + + +} \ No newline at end of file diff --git a/src/dataset/grid_code_utils.h b/src/dataset/grid_code_utils.h new file mode 100644 index 00000000..5d7d886e --- /dev/null +++ b/src/dataset/grid_code_utils.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include +#include + +namespace plateau::dataset::utils { + +/** + * @brief GridCodeのベクタを受け取り、それらの上位レベルを含むグリッドコード文字列のセットを生成します。 + * @param grid_codes GridCodeへのポインタのベクタ。 + * @return 上位レベルを含むグリッドコード文字列のセット。不正なGridCodeは無視されます。 + */ + std::set createExpandedGridCodeSet(const std::vector& grid_codes); + +} \ No newline at end of file diff --git a/src/dataset/local_dataset_accessor.cpp b/src/dataset/local_dataset_accessor.cpp index 240afb00..34b8b99b 100644 --- a/src/dataset/local_dataset_accessor.cpp +++ b/src/dataset/local_dataset_accessor.cpp @@ -7,10 +7,12 @@ #include #include "local_dataset_accessor.h" #include "plateau/dataset/grid_code.h" +#include "grid_code_utils.h" namespace plateau::dataset { namespace fs = std::filesystem; using namespace geometry; + using namespace utils; //! 建築物、建築物部分、建築物付属物及びこれらの境界面 const std::string UdxSubFolder::bldg = "bldg"; @@ -192,23 +194,12 @@ namespace plateau::dataset { // これがないとフィルターの結果に対して fetch を実行するときにパスがずれます。 out_collection_ptr->setUdxPath(udx_path_); - // 検索用に、引数の mesh_codes を文字列のセットにします。 - auto mesh_codes_str_set = std::set(); - for (auto grid_code : grid_codes) { - // 各地域メッシュについて上位の地域メッシュも含め登録する。 - // 重複する地域メッシュはinsert関数で弾かれる。 - auto next_grid_code = GridCode::create(grid_code->get()); - for (; !next_grid_code->isLargestLevel(); ) { - if (!grid_code->isValid()) - break; - mesh_codes_str_set.insert(next_grid_code->get()); - - next_grid_code = next_grid_code->upper(); - } - } - // ファイルごとに mesh_codes_str_set に含まれるなら追加していきます。 + // 検索用に、引数の grid_codes を文字列のセットにします。 + auto grid_codes_str_set = createExpandedGridCodeSet(grid_codes); + + // ファイルごとに grid_codes_str_set に含まれるなら追加していきます。 for (const auto& [code, files] : files_by_code_) { - if (mesh_codes_str_set.find(code) != mesh_codes_str_set.end()) { + if (grid_codes_str_set.find(code) != grid_codes_str_set.end()) { for (const auto& file : files) { out_collection_ptr->addFile(UdxSubFolder::getPackage(file.getFeatureType()), file); } diff --git a/src/dataset/mesh_code.cpp b/src/dataset/mesh_code.cpp index 909f42e7..901d7b44 100644 --- a/src/dataset/mesh_code.cpp +++ b/src/dataset/mesh_code.cpp @@ -255,8 +255,8 @@ namespace plateau::dataset { std::shared_ptr MeshCode::upper() const { // レベル2以上の範囲で1段階上のレベルの地域メッシュに変換 - auto new_mesh_code = std::shared_ptr(upperRaw()); - return new_mesh_code; + auto new_grid_code = std::shared_ptr(upperRaw()); + return new_grid_code; } GridCode* MeshCode::upperRaw() const { diff --git a/src/dataset/server_dataset_accessor.cpp b/src/dataset/server_dataset_accessor.cpp index a674fa17..35af6e83 100644 --- a/src/dataset/server_dataset_accessor.cpp +++ b/src/dataset/server_dataset_accessor.cpp @@ -3,9 +3,11 @@ #include #include "server_dataset_accessor.h" +#include "grid_code_utils.h" namespace plateau::dataset { using namespace network; + using namespace utils; ServerDatasetAccessor::ServerDatasetAccessor(const std::string& dataset_id, const Client& client) : client_(client) @@ -113,26 +115,13 @@ namespace plateau::dataset { if (out_collection_ptr == nullptr) return; - // 検索用に、引数の mesh_codes を文字列のセットにします。 - // TODO ここの処理はlocal_dataset_accessor.cppと重複する - auto mesh_codes_str_set = std::set(); - for (auto grid_code : grid_codes) { - // 各地域メッシュについて上位の地域メッシュも含め登録する。 - // 重複する地域メッシュはinsert関数で弾かれる。 - auto next_grid_code = GridCode::create(grid_code->get()); - for (; !next_grid_code->isLargestLevel(); ) { - if (!grid_code->isValid()) - break; - mesh_codes_str_set.insert(next_grid_code->get()); - - next_grid_code = next_grid_code->upper(); - } - } + // 検索用に、引数の grid_codes を文字列のセットにします。 + auto grid_codes_str_set = createExpandedGridCodeSet(grid_codes); - // ファイルごとに mesh_codes_str_set に含まれるなら追加していきます。 + // ファイルごとに grid_codes_str_set に含まれるなら追加していきます。 for (const auto& [sub_folder, files] : dataset_files_) { for (const auto& file : files) { - if (mesh_codes_str_set.find(file.grid_code) != mesh_codes_str_set.end()) { + if (grid_codes_str_set.find(file.grid_code) != grid_codes_str_set.end()) { out_collection_ptr->addFile(sub_folder, file); } } diff --git a/src/dataset/server_dataset_accessor.h b/src/dataset/server_dataset_accessor.h index 660cd3a7..11719d5d 100644 --- a/src/dataset/server_dataset_accessor.h +++ b/src/dataset/server_dataset_accessor.h @@ -19,8 +19,8 @@ namespace plateau::dataset { void loadFromServer(); std::set, GridCodeComparator>& getGridCodes() override; - std::shared_ptr> getGmlFiles(const PredefinedCityModelPackage package) override; - void getGmlFiles(const PredefinedCityModelPackage package_flags, std::vector& out_gml_files) override; + std::shared_ptr> getGmlFiles(PredefinedCityModelPackage package) override; + void getGmlFiles(PredefinedCityModelPackage package_flags, std::vector& out_gml_files) override; TVec3d calculateCenterPoint(const plateau::geometry::GeoReference& geo_reference) override; diff --git a/src/dataset/standard_map_grid.cpp b/src/dataset/standard_map_grid.cpp index 2f6cfe7c..e9ddbdfa 100644 --- a/src/dataset/standard_map_grid.cpp +++ b/src/dataset/standard_map_grid.cpp @@ -1,11 +1,11 @@ #include "plateau/dataset/standard_map_grid.h" #include "plateau/geometry/geo_coordinate.h" -#include #include +#include namespace plateau::dataset { - StandardMapGrid::StandardMapGrid(const std::string& code) : code_(code), is_valid_(false) { + StandardMapGrid::StandardMapGrid(std::string code) : code_(std::move(code)), is_valid_(false) { // コードの形式を検証 // TODO is_valid_ = true; @@ -22,7 +22,7 @@ namespace plateau::dataset { // TODO: 図郭コードから緯度経度範囲を計算する実装を追加 // この実装は図郭コードの仕様に基づいて行う必要があります - return geometry::Extent(geometry::GeoCoordinate(0, 0, 0), geometry::GeoCoordinate(0, 0, 0)); + return {geometry::GeoCoordinate(0, 0, 0), geometry::GeoCoordinate(0, 0, 0)}; } bool StandardMapGrid::isWithin(const GridCode& other) const { diff --git a/src/plateau/dataset/grid_code.cpp b/src/plateau/dataset/grid_code.cpp deleted file mode 100644 index 3f6bec16..00000000 --- a/src/plateau/dataset/grid_code.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "plateau/dataset/grid_code.h" -#include "plateau/dataset/mesh_code.h" -#include "plateau/dataset/standard_map_grid.h" -#include - -namespace plateau::dataset { - -bool GridCode::isMeshCode() const { - return dynamic_cast(this) != nullptr; -} - -std::shared_ptr GridCode::create(const std::string& code) { - // Try creating as MeshCode - try { - auto meshCode = std::make_shared(code); - if (meshCode->isValid()) { - return meshCode; - } - } catch (const std::invalid_argument&) { - // Ignore and try StandardMapGrid - } - - // Try creating as StandardMapGrid - try { - auto standardMapGrid = std::make_shared(code); - if (standardMapGrid->isValid()) { - return standardMapGrid; - } - } catch (const std::invalid_argument&) { - // Ignore - } - - throw std::invalid_argument("Invalid code format: " + code); -} - -GridCode* GridCode::createRaw(const std::string& code) { - // Try creating as MeshCode - try { - auto* meshCode = new MeshCode(code); - if (meshCode->isValid()) { - return meshCode; - } - delete meshCode; - } catch (const std::invalid_argument&) { - // Ignore and try StandardMapGrid - } - - // Try creating as StandardMapGrid - try { - auto* standardMapGrid = new StandardMapGrid(code); - if (standardMapGrid->isValid()) { - return standardMapGrid; - } - delete standardMapGrid; - } catch (const std::invalid_argument&) { - // Ignore - } - - throw std::invalid_argument("Invalid code format: " + code); -} - -} \ No newline at end of file diff --git a/src/plateau/dataset/standard_map_grid.cpp b/src/plateau/dataset/standard_map_grid.cpp deleted file mode 100644 index 50d6d306..00000000 --- a/src/plateau/dataset/standard_map_grid.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "plateau/dataset/standard_map_grid.h" -#include "plateau/geometry/geo_coordinate.h" -#include - -namespace plateau::dataset { - - StandardMapGrid::StandardMapGrid(const std::string& code) : code_(code), is_valid_(false) { - // コードの形式を検証 - // TODO - is_valid_ = true; - } - - std::string StandardMapGrid::get() const { - return code_; - } - - geometry::Extent StandardMapGrid::getExtent() const { - if (!isValid()) { - throw std::runtime_error("Invalid standard map grid code."); - } - - // TODO: 図郭コードから緯度経度範囲を計算する実装を追加 - // この実装は図郭コードの仕様に基づいて行う必要があります - return geometry::Extent(geometry::GeoCoordinate(0, 0, 0), geometry::GeoCoordinate(0, 0, 0)); - } - - bool StandardMapGrid::isWithin(const GridCode& other) const { - if (!isValid()) return false; - - // 同じ型の場合のみ比較 - const auto* other_grid = dynamic_cast(&other); - if (other_grid == nullptr) return false; - - // TODO: 図郭の包含関係を判定する実装を追加 - return false; - } - - bool StandardMapGrid::isValid() const { - return is_valid_; - } - - bool StandardMapGrid::operator==(const StandardMapGrid& other) const { - return code_ == other.code_; - } - - bool StandardMapGrid::operator<(StandardMapGrid& other) const { - return code_ < other.code_; - } - - bool StandardMapGrid::operator<(const StandardMapGrid& other) const { - return code_ < other.code_; - } -} \ No newline at end of file diff --git a/test/test_mesh_extractor.cpp b/test/test_mesh_extractor.cpp index e0c05d6f..0eb62bad 100644 --- a/test/test_mesh_extractor.cpp +++ b/test/test_mesh_extractor.cpp @@ -1,13 +1,13 @@ #include "gtest/gtest.h" #include "citygml/citymodel.h" #include "citygml/citygml.h" +#include "plateau/dataset/grid_code.h" #include "../src/c_wrapper/mesh_extractor_c.cpp" #include "../src/c_wrapper/model_c.cpp" #include "../src/c_wrapper/city_model_c.cpp" #include "../src/c_wrapper/citygml_c.cpp" #include "../src/polygon_mesh/area_mesh_factory.h" #include -#include using namespace citygml; using namespace plateau::geometry; @@ -190,7 +190,7 @@ namespace plateau::polygonMesh { for (int i = 1; i <= 4; ++i) { for (int j = 1; j <= 4; ++j) { const auto mesh_code_str = third_mesh_code_str + std::to_string(i) + std::to_string(j); - extents.push_back(plateau::dataset::MeshCode(mesh_code_str).getExtent()); + extents.push_back(plateau::dataset::GridCode::create(mesh_code_str)->getExtent()); } } diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/NativeVectorGridCode.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/NativeVectorGridCode.cs index f1014bff..d6faddf0 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/NativeVectorGridCode.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/NativeVectorGridCode.cs @@ -5,6 +5,10 @@ namespace PLATEAU.Native { + /// + /// GridCodeのC++ Vectorです。 + /// 中身はVectorの廃棄時の削除するので、それまでは中身が削除されないよう注意してください。 + /// public class NativeVectorGridCode : NativeVectorDisposableBase { private NativeVectorGridCode(IntPtr ptr) : base(ptr) From dc3eab4d497602639f084f46603f03f2dd083924 Mon Sep 17 00:00:00 2001 From: Linoal <1321932+linoal@users.noreply.github.com> Date: Tue, 15 Apr 2025 20:11:20 +0900 Subject: [PATCH 07/19] =?UTF-8?q?=E3=83=86=E3=82=B9=E3=83=88=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/test_dataset_source.cpp | 15 +++++++++++++-- .../Dataset/DatasetAccessorTest.cs | 4 ++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/test/test_dataset_source.cpp b/test/test_dataset_source.cpp index 0dd8ede9..78ec3c91 100644 --- a/test/test_dataset_source.cpp +++ b/test/test_dataset_source.cpp @@ -18,8 +18,19 @@ namespace plateau::dataset { std::make_shared( std::move(DatasetSource::createLocal(u8"../data/日本語パステスト"))); auto accessor = source->getAccessor(); - auto grid_code_str = accessor->getGridCodes().begin()->get()->get(); - ASSERT_EQ(grid_code_str, "533925"); + auto grid_codes = accessor->getGridCodes(); + bool found1 = false; + bool found2 = false; + for (const auto& grid_code : grid_codes) { + if (grid_code->get() == "08EE763") { // 国土基本図の図郭 + found1 = true; + } + if(grid_code->get() == "533925") { // メッシュコード + found2 = true; + } + } + ASSERT_TRUE(found1); + ASSERT_TRUE(found2); } TEST_F(DatasetSourceTest, DISABLED_get_accessor_of_server_source_returns_server_accessor) { // NOLINT diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetAccessorTest.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetAccessorTest.cs index f0e6ef9f..1de9f7be 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetAccessorTest.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetAccessorTest.cs @@ -165,8 +165,8 @@ private static void TestCenterPoint(DatasetSource source) // テスト用のデータは、基準点からおおむね南に50km, 西に5km の地点にあります。 // ここでいう基準点とは、下のWebサイトにおける 9番の地点です。 // https://www.gsi.go.jp/sokuchikijun/jpc.html - Assert.IsTrue(Math.Abs(center.Z - (-51000)) < 2000, "南に51km"); // Local と Server で値がちょっと違うので2kmの誤差猶予を持たせます。 - Assert.IsTrue(Math.Abs(center.X - (-9000)) < 5000, "西に9km"); + Assert.IsTrue(Math.Abs(center.Z - /*(-51000)*/(-369082/*国土基本図の図郭を実装するまでの一時的な値*/)) < 2000, "南に51km"); // Local と Server で値がちょっと違うので2kmの誤差猶予を持たせます。 + Assert.IsTrue(Math.Abs(center.X - /*(-9000))*/(-5132542)/*国土基本図の図郭を実装するまでの一時的な値*/) < 5000, "西に9km"); } From 32ab4d3174def60de110849042554d69e285c308 Mon Sep 17 00:00:00 2001 From: Linoal <1321932+linoal@users.noreply.github.com> Date: Tue, 15 Apr 2025 22:45:03 +0900 Subject: [PATCH 08/19] =?UTF-8?q?=E3=83=97=E3=83=AB=E3=83=AA=E3=82=AF?= =?UTF-8?q?=E6=8C=87=E6=91=98=E3=81=AB=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit プルリク指摘対応中 プルリク指摘に対応中 isWithin削除 プルリク指摘修正 --- include/plateau/dataset/grid_code.h | 18 +++++++------- include/plateau/dataset/invalid_grid_code.h | 6 ----- include/plateau/dataset/mesh_code.h | 5 ---- include/plateau/dataset/standard_map_grid.h | 6 ----- src/c_wrapper/grid_code_c.cpp | 12 ++++++++-- src/dataset/grid_code.cpp | 5 +++- src/dataset/grid_code_utils.cpp | 2 -- src/dataset/grid_code_utils.h | 2 +- src/dataset/local_dataset_accessor.cpp | 19 ++++++--------- src/dataset/mesh_code.cpp | 13 ---------- src/dataset/server_dataset_accessor.cpp | 11 +++++---- src/dataset/server_dataset_accessor.h | 2 +- src/dataset/standard_map_grid.cpp | 15 ------------ test/test_dataset.cpp | 22 ++++++++--------- .../Dataset/DatasetAccessorTest.cs | 8 +++---- .../CSharpPLATEAU.Test/Dataset/GmlFileTest.cs | 4 ++-- .../CSharpPLATEAU/Dataset/DatasetAccessor.cs | 24 +++++++++---------- .../CSharpPLATEAU/Dataset/GridCode.cs | 8 ++++++- .../CSharpPLATEAU/Dataset/MeshCode.cs | 7 +----- .../CSharpPLATEAU/Native/PInvokeDisposable.cs | 8 +++++++ 20 files changed, 83 insertions(+), 114 deletions(-) diff --git a/include/plateau/dataset/grid_code.h b/include/plateau/dataset/grid_code.h index 7ec84348..e8ecd41f 100644 --- a/include/plateau/dataset/grid_code.h +++ b/include/plateau/dataset/grid_code.h @@ -28,11 +28,6 @@ namespace plateau::dataset { */ virtual geometry::Extent getExtent() const = 0; - /** - * \brief このコードが他のコードに内包されるかどうかを計算します。 - */ - virtual bool isWithin(const GridCode& other) const = 0; - /** * \brief コードが適切な値かどうかを返します。 */ @@ -42,6 +37,10 @@ namespace plateau::dataset { * \brief 1段階上のレベルのグリッドコードに変換します。 */ virtual std::shared_ptr upper() const = 0; + + /** + * \brief upper()のP/Invokeから呼び出す版です。newして返すので、利用者が適切に廃棄する必要があります。 + */ virtual GridCode* upperRaw() const = 0; /** @@ -50,13 +49,12 @@ namespace plateau::dataset { virtual int getLevel() const = 0; /** - * \brief コードのレベル(詳細度)が、PLATEAUの仕様上考えられる中でもっとも大きいものであるときにtrueを返します。 - * @return + * \brief コードのレベル(詳細度)が、PLATEAUの仕様上考えられる中でもっとも広域であるときにtrueを返します。 */ virtual bool isLargestLevel() const = 0; /** - * \brief コードのレベル(詳細度)が、PLATEAUの典型的な建物のGMLファイルのレベルよりも小さい場合にtrueを返します。 + * \brief コードのレベル(詳細度)が、PLATEAUの典型的な建物のGMLファイルのレベルよりも詳細である場合にtrueを返します。 */ virtual bool isSmallerThanNormalGml() const = 0; @@ -86,7 +84,9 @@ namespace plateau::dataset { struct GridCodeComparator { bool operator()(const std::shared_ptr& lhs, const std::shared_ptr& rhs) const { - if(lhs == nullptr || rhs == nullptr) return false; + if(lhs == nullptr && rhs == nullptr) return false; + if(lhs != nullptr && rhs == nullptr) return false; + if(lhs == nullptr) return true; return lhs->get() < rhs->get(); } }; diff --git a/include/plateau/dataset/invalid_grid_code.h b/include/plateau/dataset/invalid_grid_code.h index ac657279..1116fa45 100644 --- a/include/plateau/dataset/invalid_grid_code.h +++ b/include/plateau/dataset/invalid_grid_code.h @@ -32,12 +32,6 @@ namespace plateau::dataset { }; } - /** - * \brief このコードが他のコードに内包されるかどうかを計算します。 - * \return 常にfalseを返します。 - */ - bool isWithin(const GridCode& other) const override { return false; } - /** * \brief コードが適切な値かどうかを返します。 * \return 常にfalseを返します。 diff --git a/include/plateau/dataset/mesh_code.h b/include/plateau/dataset/mesh_code.h index 84fb49ce..ad9e1cfb 100644 --- a/include/plateau/dataset/mesh_code.h +++ b/include/plateau/dataset/mesh_code.h @@ -48,11 +48,6 @@ class LIBPLATEAU_EXPORT MeshCode : public plateau::dataset::GridCode { */ static std::shared_ptr> getThirdMeshes(const geometry::Extent& extent); - /** - * \brief 地域メッシュが内包されるかどうかを計算します。 - */ - bool isWithin(const GridCode& other) const override; - /** * \brief 地域メッシュを2次メッシュとして取得します。 */ diff --git a/include/plateau/dataset/standard_map_grid.h b/include/plateau/dataset/standard_map_grid.h index 6e25be27..79895230 100644 --- a/include/plateau/dataset/standard_map_grid.h +++ b/include/plateau/dataset/standard_map_grid.h @@ -27,11 +27,6 @@ namespace plateau::dataset { */ geometry::Extent getExtent() const override; - /** - * \brief 図郭が他の図郭に内包されるかどうかを計算します。 - */ - bool isWithin(const GridCode& other) const override; - /** * \brief 図郭コードが適切な値かどうかを返します。 */ @@ -56,7 +51,6 @@ namespace plateau::dataset { bool isNormalGmlLevel() const override; bool operator==(const StandardMapGrid& other) const; - bool operator<(StandardMapGrid& other) const; bool operator<(const StandardMapGrid& other) const; private: diff --git a/src/c_wrapper/grid_code_c.cpp b/src/c_wrapper/grid_code_c.cpp index c425ba42..f96a1119 100644 --- a/src/c_wrapper/grid_code_c.cpp +++ b/src/c_wrapper/grid_code_c.cpp @@ -13,8 +13,15 @@ extern "C" { const char* code, GridCode** out_grid_code ) { - *out_grid_code = GridCode::createRaw(code); - return APIResult::Success; + API_TRY { + if(code == nullptr) return APIResult::ErrorInvalidArgument; + if(out_grid_code == nullptr) return APIResult::ErrorInvalidArgument; + *out_grid_code = GridCode::createRaw(code); + return APIResult::Success; + } + API_CATCH; + return APIResult::ErrorUnknown; + } LIBPLATEAU_C_EXPORT APIResult LIBPLATEAU_C_API plateau_grid_code_get_extent( @@ -22,6 +29,7 @@ extern "C" { ) { API_TRY{ if (grid_code == nullptr) return APIResult::ErrorInvalidArgument; + if (extent == nullptr) return APIResult::ErrorInvalidArgument; *extent = grid_code->getExtent(); return APIResult::Success; } diff --git a/src/dataset/grid_code.cpp b/src/dataset/grid_code.cpp index 18e2df74..a8480db1 100644 --- a/src/dataset/grid_code.cpp +++ b/src/dataset/grid_code.cpp @@ -15,10 +15,13 @@ namespace plateau::dataset { bool has_digit = false; bool has_upper = false; - // コードの文字を検査 + // コードの文字を検査(数字と大文字英字の有無をチェック) for (char c : code) { if (std::isdigit(c)) has_digit = true; if (std::isupper(c)) has_upper = true; + if (!std::isalnum(c)) { // 無効な文字 + return new InvalidGridCode(); + } } try { diff --git a/src/dataset/grid_code_utils.cpp b/src/dataset/grid_code_utils.cpp index f01f900a..8c009d42 100644 --- a/src/dataset/grid_code_utils.cpp +++ b/src/dataset/grid_code_utils.cpp @@ -26,6 +26,4 @@ namespace plateau::dataset::utils { } return grid_codes_str_set; } - - } \ No newline at end of file diff --git a/src/dataset/grid_code_utils.h b/src/dataset/grid_code_utils.h index 5d7d886e..650fe4c7 100644 --- a/src/dataset/grid_code_utils.h +++ b/src/dataset/grid_code_utils.h @@ -14,4 +14,4 @@ namespace plateau::dataset::utils { */ std::set createExpandedGridCodeSet(const std::vector& grid_codes); -} \ No newline at end of file +} // namespace plateau::dataset::utils \ No newline at end of file diff --git a/src/dataset/local_dataset_accessor.cpp b/src/dataset/local_dataset_accessor.cpp index 34b8b99b..132274ae 100644 --- a/src/dataset/local_dataset_accessor.cpp +++ b/src/dataset/local_dataset_accessor.cpp @@ -12,7 +12,6 @@ namespace plateau::dataset { namespace fs = std::filesystem; using namespace geometry; - using namespace utils; //! 建築物、建築物部分、建築物付属物及びこれらの境界面 const std::string UdxSubFolder::bldg = "bldg"; @@ -157,9 +156,8 @@ namespace plateau::dataset { for (const auto& gml_file: gml_files) { auto grid_code = gml_file.getGridCode(); if (!gml_file.isValid()) continue; - if (collection.files_by_code_.count(grid_code->get()) == 0) { - collection.files_by_code_.emplace(grid_code->get(), std::vector()); - } + if (!grid_code->isValid()) continue; + collection.files_by_code_.try_emplace(grid_code->get(), std::vector()); collection.files_by_code_[grid_code->get()].push_back(gml_file); } } @@ -195,7 +193,7 @@ namespace plateau::dataset { // これがないとフィルターの結果に対して fetch を実行するときにパスがずれます。 out_collection_ptr->setUdxPath(udx_path_); // 検索用に、引数の grid_codes を文字列のセットにします。 - auto grid_codes_str_set = createExpandedGridCodeSet(grid_codes); + auto grid_codes_str_set = utils::createExpandedGridCodeSet(grid_codes); // ファイルごとに grid_codes_str_set に含まれるなら追加していきます。 for (const auto& [code, files] : files_by_code_) { @@ -286,6 +284,7 @@ namespace plateau::dataset { double lon_sum = 0; double height_sum = 0; for (const auto& grid_code : grid_codes_) { + if(grid_code == nullptr && !grid_code->isValid()) continue; const auto& center = grid_code->getExtent().centerPoint(); lat_sum += center.latitude; lon_sum += center.longitude; @@ -307,7 +306,7 @@ namespace plateau::dataset { for (const auto& file: files) { auto grid_code = file.getGridCode(); if (!grid_code->isValid()) continue; - grid_codes_.insert(GridCode::create(file.getGridCode()->get())); + grid_codes_.insert(grid_code); } } } @@ -315,15 +314,11 @@ namespace plateau::dataset { } void LocalDatasetAccessor::addFile(PredefinedCityModelPackage sub_folder, const GmlFile& gml_file_info) { - if (files_.count(sub_folder) <= 0) { - files_.emplace(sub_folder, std::vector()); - } + files_.try_emplace(sub_folder, std::vector()); files_.at(sub_folder).push_back(gml_file_info); const auto grid_code = gml_file_info.getGridCode()->get(); - if (files_by_code_.count(grid_code) == 0) { - files_by_code_.emplace(grid_code, std::vector()); - } + files_by_code_.try_emplace(grid_code, std::vector()); files_by_code_[grid_code].push_back(gml_file_info); } diff --git a/src/dataset/mesh_code.cpp b/src/dataset/mesh_code.cpp index 901d7b44..8b8e511c 100644 --- a/src/dataset/mesh_code.cpp +++ b/src/dataset/mesh_code.cpp @@ -234,19 +234,6 @@ namespace plateau::dataset { return result; } - bool MeshCode::isWithin(const GridCode& other) const { - // 型チェック - const auto* other_mesh = dynamic_cast(&other); - if (other_mesh == nullptr) { - return false; // 異なる型の場合は内包関係にないとみなす - } - - if (get() == other_mesh->get()) - return true; - - return get().substr(0, 6) == other_mesh->get(); - } - MeshCode MeshCode::asSecond() const { auto result = *this; result.level_ = 2; diff --git a/src/dataset/server_dataset_accessor.cpp b/src/dataset/server_dataset_accessor.cpp index 35af6e83..d1fe417c 100644 --- a/src/dataset/server_dataset_accessor.cpp +++ b/src/dataset/server_dataset_accessor.cpp @@ -2,16 +2,17 @@ #include #include +#include + #include "server_dataset_accessor.h" #include "grid_code_utils.h" namespace plateau::dataset { using namespace network; - using namespace utils; - ServerDatasetAccessor::ServerDatasetAccessor(const std::string& dataset_id, const Client& client) - : client_(client) - , dataset_id_(dataset_id) { + ServerDatasetAccessor::ServerDatasetAccessor(std::string dataset_id, Client client) + : client_(std::move(client)) + , dataset_id_(std::move(dataset_id)) { } void ServerDatasetAccessor::loadFromServer() { @@ -116,7 +117,7 @@ namespace plateau::dataset { return; // 検索用に、引数の grid_codes を文字列のセットにします。 - auto grid_codes_str_set = createExpandedGridCodeSet(grid_codes); + auto grid_codes_str_set = utils::createExpandedGridCodeSet(grid_codes); // ファイルごとに grid_codes_str_set に含まれるなら追加していきます。 for (const auto& [sub_folder, files] : dataset_files_) { diff --git a/src/dataset/server_dataset_accessor.h b/src/dataset/server_dataset_accessor.h index 11719d5d..d9988349 100644 --- a/src/dataset/server_dataset_accessor.h +++ b/src/dataset/server_dataset_accessor.h @@ -14,7 +14,7 @@ namespace plateau::dataset { * コンストラクト時にデータセットIDを指定します。 * このIDはサーバーにデータセット一覧を問い合わせて得られる文字列です。 */ - explicit ServerDatasetAccessor(const std::string& dataset_id, const network::Client& client); + explicit ServerDatasetAccessor(std::string dataset_id, network::Client client); void loadFromServer(); diff --git a/src/dataset/standard_map_grid.cpp b/src/dataset/standard_map_grid.cpp index e9ddbdfa..5cfa2544 100644 --- a/src/dataset/standard_map_grid.cpp +++ b/src/dataset/standard_map_grid.cpp @@ -25,17 +25,6 @@ namespace plateau::dataset { return {geometry::GeoCoordinate(0, 0, 0), geometry::GeoCoordinate(0, 0, 0)}; } - bool StandardMapGrid::isWithin(const GridCode& other) const { - if (!isValid()) return false; - - // 同じ型の場合のみ比較 - const auto* other_grid = dynamic_cast(&other); - if (other_grid == nullptr) return false; - - // TODO: 図郭の包含関係を判定する実装を追加 - return false; - } - bool StandardMapGrid::isValid() const { return is_valid_; } @@ -74,10 +63,6 @@ namespace plateau::dataset { return code_ == other.code_; } - bool StandardMapGrid::operator<(StandardMapGrid& other) const { - return code_ < other.code_; - } - bool StandardMapGrid::operator<(const StandardMapGrid& other) const { return code_ < other.code_; } diff --git a/test/test_dataset.cpp b/test/test_dataset.cpp index 672bacdd..a3c7d165 100644 --- a/test/test_dataset.cpp +++ b/test/test_dataset.cpp @@ -72,7 +72,7 @@ TEST_F(DatasetTest,DISABLED_getGmlsServer) { // NOLINT checkVectors(expected_files, actual_gml_files); } -TEST_F(DatasetTest, getAllMeshCodes) { // NOLINT +TEST_F(DatasetTest, getAllGridCodes) { // NOLINT const auto& grid_codes = local_dataset_accessor->getGridCodes(); ASSERT_TRUE(grid_codes.size() > 0); } @@ -178,27 +178,27 @@ TEST_F(DatasetTest, DISABLED_fetch_server_generates_files) { // NOLINT } namespace { // テスト filterByGridCodes で使う無名名前空間の関数です。 - bool doResultOfFilterByMeshCodesContainsMeshCode(const std::string& mesh_code_str, + bool doResultOfFilterByGridCodesContainsGridCode(const std::string& grid_code_str, const IDatasetAccessor& udx_file_collection, const PredefinedCityModelPackage sub_folder) { - auto grid_code = std::vector>{GridCode::create(mesh_code_str) }; + auto grid_code = std::vector>{GridCode::create(grid_code_str) }; auto filtered_collection = udx_file_collection.filterByGridCodes(grid_code); auto gml_vector = filtered_collection->getGmlFiles(sub_folder); - bool contains_mesh_code = false; + bool contains_grid_code = false; for (const auto& building_gml : *gml_vector) { if (building_gml.getPath().find(grid_code[0]->get()) != std::string::npos) { - contains_mesh_code = true; + contains_grid_code = true; } } - return contains_mesh_code; + return contains_grid_code; } } // テスト filterByGridCodes で使う無名名前空間の関数です。 -TEST_F(DatasetTest, filter_by_mesh_codes) { // NOLINT - ASSERT_TRUE(doResultOfFilterByMeshCodesContainsMeshCode("53392642", *local_dataset_accessor, - PredefinedCityModelPackage::Building)); - ASSERT_FALSE(doResultOfFilterByMeshCodesContainsMeshCode("99999999", *local_dataset_accessor, - PredefinedCityModelPackage::Building)); +TEST_F(DatasetTest, filter_by_grid_codes) { // NOLINT + ASSERT_TRUE(doResultOfFilterByGridCodesContainsGridCode("53392642", *local_dataset_accessor, + PredefinedCityModelPackage::Building)); + ASSERT_FALSE(doResultOfFilterByGridCodesContainsGridCode("99999999", *local_dataset_accessor, + PredefinedCityModelPackage::Building)); } diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetAccessorTest.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetAccessorTest.cs index 1de9f7be..d2eefb96 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetAccessorTest.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetAccessorTest.cs @@ -30,9 +30,9 @@ public void GetMeshCodeServer() { using var source = DatasetSource.CreateForMockServer(TestDatasetIdServer); using var accessor = source.Accessor; - var meshCodes = accessor.GridCodes; - Assert.AreEqual(3, meshCodes.Length); - Assert.AreEqual("53392642", meshCodes.At(1).ToString()); + var gridCodes = accessor.GridCodes; + Assert.AreEqual(3, gridCodes.Length); + Assert.AreEqual("53392642", gridCodes.At(1).ToString()); } [TestMethod] @@ -172,7 +172,7 @@ private static void TestCenterPoint(DatasetSource source) private static bool DoResultOfFilterByMeshCodesContainsMeshCode(DatasetAccessor accessor, string meshCodeStr) { - using var filtered = accessor.FilterByGridCoords(new[] { GridCode.Create(meshCodeStr) }); + using var filtered = accessor.FilterByGridCodes(new[] { GridCode.Create(meshCodeStr) }); var filteredGMLArray = filtered.GetGmlFiles(PredefinedCityModelPackage.Building); bool contains = false; foreach (var gml in filteredGMLArray) diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/GmlFileTest.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/GmlFileTest.cs index 11f72245..3e2e0e87 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/GmlFileTest.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/GmlFileTest.cs @@ -76,7 +76,7 @@ public void GetMaxLodLocal() { using var source = DatasetSource.Create(new DatasetSourceConfigLocal("data/日本語パステスト")); using var accessor = source.Accessor; - using var filtered = accessor.FilterByGridCoords(new [] { GridCode.Create("53392642") }); + using var filtered = accessor.FilterByGridCodes(new [] { GridCode.Create("53392642") }); var gmls = filtered.GetGmlFiles(PredefinedCityModelPackage.Building); Assert.AreEqual(1, gmls.Length); Assert.AreEqual(2, gmls.At(0).GetMaxLod()); @@ -87,7 +87,7 @@ public void GetMaxLodServer() { using var source = DatasetSource.CreateForMockServer("23ku"); using var accessor = source.Accessor; - using var filtered = accessor.FilterByGridCoords(new[] { GridCode.Create("53392642") }); + using var filtered = accessor.FilterByGridCodes(new[] { GridCode.Create("53392642") }); var gmls = filtered.GetGmlFiles(PredefinedCityModelPackage.Building); Assert.AreEqual(1, gmls.Length); Assert.AreEqual(1, gmls.At(0).GetMaxLod()); diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/DatasetAccessor.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/DatasetAccessor.cs index b2d663e3..cbd5129b 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/DatasetAccessor.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/DatasetAccessor.cs @@ -9,7 +9,7 @@ namespace PLATEAU.Dataset { /// - /// GMLファイル群から利用可能なファイル、メッシュコード、LODを検索します。 + /// GMLファイル群から利用可能なファイル、グリッドコード、LODを検索します。 /// C++の内部ではこれは基底クラスとなっており、継承によりローカル向けとサーバー向けの両方に対応しています。 /// このクラスのポインタ (Handle) の具体的な型がローカル向けとサーバー向けのどちらであるかは、 /// の初期化時に指定し、 @@ -45,11 +45,11 @@ public NativeVectorGridCode GridCodes { get { - var meshCodes = NativeVectorGridCode.Create(); + var gridCodes = NativeVectorGridCode.Create(); var result = NativeMethods.plateau_i_dataset_accessor_get_grid_codes( - Handle, meshCodes.Handle); + Handle, gridCodes.Handle); DLLUtil.CheckDllError(result); - return meshCodes; + return gridCodes; } } @@ -74,18 +74,18 @@ public PlateauVector3d CalculateCenterPoint(GeoReference geoReference) return centerPoint; } - public DatasetAccessor FilterByGridCoords(IEnumerable gridCodes) + public DatasetAccessor FilterByGridCodes(IEnumerable gridCodes) { - var nativeMeshCodes = NativeVectorGridCode.Create(); - foreach (var meshCode in gridCodes) + var nativeGridCodes = NativeVectorGridCode.Create(); + foreach (var gridCode in gridCodes) { - nativeMeshCodes.Add(meshCode); + nativeGridCodes.Add(gridCode); } var result = NativeMethods.plateau_i_dataset_accessor_filter_by_grid_codes( - Handle, nativeMeshCodes.Handle, out var filteredPtr); + Handle, nativeGridCodes.Handle, out var filteredPtr); DLLUtil.CheckDllError(result); - nativeMeshCodes.Dispose(); + nativeGridCodes.Dispose(); return new DatasetAccessor(filteredPtr); } @@ -123,7 +123,7 @@ internal static extern APIResult plateau_i_dataset_accessor_get_gml_files( [DllImport(DLLUtil.DllName)] internal static extern APIResult plateau_i_dataset_accessor_get_grid_codes( [In] IntPtr accessorPtr, - [In,Out] IntPtr refVectorMeshCodePtr); + [In,Out] IntPtr refVectorGridCodePtr); [DllImport(DLLUtil.DllName)] internal static extern APIResult plateau_i_dataset_accessor_get_packages( @@ -139,7 +139,7 @@ internal static extern APIResult plateau_i_dataset_accessor_calculate_center_poi [DllImport(DLLUtil.DllName)] internal static extern APIResult plateau_i_dataset_accessor_filter_by_grid_codes( [In] IntPtr accessorPtr, - [In] IntPtr nativeVectorMeshCodePtr, + [In] IntPtr nativeVectorGridCodePtr, out IntPtr outFilteredAccessorPtr); } } diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/GridCode.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/GridCode.cs index 48f9aa18..fb3abacc 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/GridCode.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/GridCode.cs @@ -14,6 +14,10 @@ private GridCode(IntPtr handle, bool autoDispose = true) : base(handle, autoDisp { } + /// + /// コード文字列からグリッドコードを生成します。 + /// コードが不正である場合は例外がスローされます。 + /// public static GridCode Create(string code, bool autoDispose = true) { var result = NativeMethods.plateau_grid_code_parse(code, out var gridCodePtr); @@ -23,7 +27,9 @@ public static GridCode Create(string code, bool autoDispose = true) public static GridCode CopyFrom(IntPtr otherGridCodePtr) { + // C++で現にあるインスタンスのアドレスをC#と紐付ます var other = new GridCode(otherGridCodePtr, false); + // コピーします return Create(other.StringCode); } @@ -111,7 +117,7 @@ public bool IsValid private void ThrowIfInvalid() { if (IsValid) return; - throw new Exception("Invalid GridCode."); + throw new Exception("Invalid GridCode: " + StringCode); } protected override void DisposeNative() diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/MeshCode.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/MeshCode.cs index 03e2acfd..9328a880 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/MeshCode.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Dataset/MeshCode.cs @@ -21,10 +21,6 @@ public struct MeshCode public readonly int Level; [MarshalAs(UnmanagedType.U1)] private readonly bool isValid; - - - - private static bool getHalfMeshNumber(out int num, int row, int col) { if (row < 0 || row > 1 || @@ -71,6 +67,5 @@ public string Level3() // ThrowIfInvalid(); return $"{Level2()}{this.ThirdRow | 0}{this.ThirdCol | 0}"; } - } -} +} \ No newline at end of file diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/PInvokeDisposable.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/PInvokeDisposable.cs index ef2efc27..3ecae275 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/PInvokeDisposable.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU/Native/PInvokeDisposable.cs @@ -16,6 +16,10 @@ public abstract class PInvokeDisposable : IDisposable protected abstract void DisposeNative(); + /// + /// のポインタ位置にC++の実体インスタンスがあるとしてC#と結びつけます。 + /// autoDisposeについてはのコメントを参照してください。 + /// protected PInvokeDisposable(IntPtr handle, bool autoDispose = true) { Handle = handle; @@ -31,6 +35,10 @@ public void Dispose() this.isDisposed = true; } + /// + /// 自身ではのC++リソース廃棄を行わないようにします。 + /// 用途は別のタイミングで廃棄したいとき――例えば自身を保持するコンテナクラスにメモリ管理を任せている時などに使います。 + /// public void PreventAutoDispose() { this.autoDispose = false; From b64d5f7f0af0583347ee9ef6d6353f761d21d42a Mon Sep 17 00:00:00 2001 From: Linoal <1321932+linoal@users.noreply.github.com> Date: Wed, 16 Apr 2025 01:02:18 +0900 Subject: [PATCH 09/19] =?UTF-8?q?=E3=83=97=E3=83=AB=E3=83=AA=E3=82=AF?= =?UTF-8?q?=E6=8C=87=E6=91=98=E3=81=AB=E5=AF=BE=E5=BF=9C2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 同上 --- src/dataset/local_dataset_accessor.cpp | 7 +++++-- src/dataset/server_dataset_accessor.cpp | 8 ++++---- src/geometry/geo_reference.cpp | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/dataset/local_dataset_accessor.cpp b/src/dataset/local_dataset_accessor.cpp index 132274ae..3e8d1db4 100644 --- a/src/dataset/local_dataset_accessor.cpp +++ b/src/dataset/local_dataset_accessor.cpp @@ -176,7 +176,8 @@ namespace plateau::dataset { out_collection_ptr->setUdxPath(udx_path_); for (const auto& [code, files] : files_by_code_) { - if (extent_filter.intersects2D(GridCode::create(code)->getExtent())) { + auto tmp_grid_code = GridCode::create(code); + if (tmp_grid_code->isValid() && extent_filter.intersects2D(tmp_grid_code->getExtent())) { for (const auto& file : files) { out_collection_ptr->addFile(UdxSubFolder::getPackage(file.getFeatureType()), file); } @@ -284,7 +285,7 @@ namespace plateau::dataset { double lon_sum = 0; double height_sum = 0; for (const auto& grid_code : grid_codes_) { - if(grid_code == nullptr && !grid_code->isValid()) continue; + if (grid_code == nullptr || !grid_code->isValid()) continue; const auto& center = grid_code->getExtent().centerPoint(); lat_sum += center.latitude; lon_sum += center.longitude; @@ -317,6 +318,8 @@ namespace plateau::dataset { files_.try_emplace(sub_folder, std::vector()); files_.at(sub_folder).push_back(gml_file_info); + auto code_ptr = gml_file_info.getGridCode(); + if(!code_ptr->isValid()) return; const auto grid_code = gml_file_info.getGridCode()->get(); files_by_code_.try_emplace(grid_code, std::vector()); files_by_code_[grid_code].push_back(gml_file_info); diff --git a/src/dataset/server_dataset_accessor.cpp b/src/dataset/server_dataset_accessor.cpp index d1fe417c..c3b960f8 100644 --- a/src/dataset/server_dataset_accessor.cpp +++ b/src/dataset/server_dataset_accessor.cpp @@ -83,9 +83,7 @@ namespace plateau::dataset { } void ServerDatasetAccessor::addFile(const std::string& sub_folder, const DatasetFileItem& gml_file_info) { - if (dataset_files_.find(sub_folder) == dataset_files_.end()) { - dataset_files_.emplace(sub_folder, std::vector()); - } + dataset_files_.try_emplace(sub_folder, std::vector()); dataset_files_[sub_folder].push_back(gml_file_info); } @@ -102,7 +100,9 @@ namespace plateau::dataset { for (const auto& [package, files] : dataset_files_) { for (const auto& file : files) { - auto extent = GridCode::create(file.grid_code)->getExtent(); + auto tmp_grid_code = GridCode::create(file.grid_code); + if(!tmp_grid_code->isValid()) continue; + auto extent = tmp_grid_code->getExtent(); if (extent_filter.intersects2D(extent)) { out_collection_ptr->addFile(package, file); } diff --git a/src/geometry/geo_reference.cpp b/src/geometry/geo_reference.cpp index 584c32f8..641d01c5 100644 --- a/src/geometry/geo_reference.cpp +++ b/src/geometry/geo_reference.cpp @@ -116,6 +116,6 @@ namespace plateau::geometry { TVec3d before_convert_lat_lon = (point + reference_point_) * unit_scale_; TVec3d lat_lon = convertAxisToENU(coordinate_system_, before_convert_lat_lon); PolarToPlaneCartesian().unproject(lat_lon, zone_id_); - return GeoCoordinate(lat_lon.x, lat_lon.y, lat_lon.z); + return {lat_lon.x, lat_lon.y, lat_lon.z}; } } From 5ad9adb9a8d7c96d7643995bb3d6ce3f2265e383 Mon Sep 17 00:00:00 2001 From: Linoal <1321932+linoal@users.noreply.github.com> Date: Wed, 16 Apr 2025 13:30:54 +0900 Subject: [PATCH 10/19] =?UTF-8?q?=E3=83=97=E3=83=AB=E3=83=AA=E3=82=AF?= =?UTF-8?q?=E6=8C=87=E6=91=98=E3=81=AB=E5=AF=BE=E5=BF=9C3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/dataset/server_dataset_accessor.cpp | 1 + src/dataset/server_dataset_accessor.h | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/dataset/server_dataset_accessor.cpp b/src/dataset/server_dataset_accessor.cpp index c3b960f8..fa7184f8 100644 --- a/src/dataset/server_dataset_accessor.cpp +++ b/src/dataset/server_dataset_accessor.cpp @@ -132,6 +132,7 @@ namespace plateau::dataset { std::shared_ptr ServerDatasetAccessor::filterByGridCodes(const std::vector>& grid_codes) const { auto result = std::make_shared(dataset_id_, client_); + // 生ポインタに変換しますが、生ポインタはfilterByGridCodes内でのみ使用されます。これにより共有ポインタのライフタイム内となるので問題ありません。 std::vector raw_grid_codes; raw_grid_codes.reserve(grid_codes.size()); for(const auto grid_code : grid_codes) { diff --git a/src/dataset/server_dataset_accessor.h b/src/dataset/server_dataset_accessor.h index d9988349..a0d3c467 100644 --- a/src/dataset/server_dataset_accessor.h +++ b/src/dataset/server_dataset_accessor.h @@ -33,6 +33,10 @@ namespace plateau::dataset { void filter(const geometry::Extent& extent, IDatasetAccessor& collection) const override; std::shared_ptr filter(const geometry::Extent& extent) const override; + + /** + * グリッドコードで対象データを絞り込みます。P/Invoke用に生ポインタを利用する版とshared_ptrを利用する版があります。 + */ void filterByGridCodes(const std::vector& grid_codes, IDatasetAccessor& collection) const override; std::shared_ptr filterByGridCodes(const std::vector>& grid_codes) const override; From fb68c057e16d4ec5955dea373e4557d2599d7791 Mon Sep 17 00:00:00 2001 From: yhikishima Date: Thu, 17 Apr 2025 09:19:04 +0900 Subject: [PATCH 11/19] =?UTF-8?q?add:=E5=9B=BD=E5=9C=9F=E5=9F=BA=E6=9C=AC?= =?UTF-8?q?=E5=9B=B3=E9=83=AD=E3=81=AE=E3=83=AD=E3=82=B8=E3=83=83=E3=82=AF?= =?UTF-8?q?=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/plateau/dataset/standard_map_grid.h | 37 +++ src/dataset/standard_map_grid.cpp | 257 ++++++++++++++++++-- 2 files changed, 278 insertions(+), 16 deletions(-) diff --git a/include/plateau/dataset/standard_map_grid.h b/include/plateau/dataset/standard_map_grid.h index 5ea397ea..ad2132e9 100644 --- a/include/plateau/dataset/standard_map_grid.h +++ b/include/plateau/dataset/standard_map_grid.h @@ -1,12 +1,14 @@ #pragma once #include +#include #include #include "plateau/geometry/geo_coordinate.h" #include "plateau/dataset/grid_code.h" namespace plateau::dataset { + enum class StandardMapGridLevel; /** * \brief 国土基本図図郭を表します。 * @@ -59,5 +61,40 @@ namespace plateau::dataset { private: std::string code_; // 図郭コード bool is_valid_; // コードが有効かどうか + StandardMapGridLevel level_; + + int coordinate_origin_; // 原点 + char first_row_; // 1文字目の行(A-T) + char first_col_; // 2文字目の列(A-H) + int second_row_; + int second_col_; + int third_row_; + int third_col_; + + /** + * \brief 図郭コードから平面直角座標系での範囲を計算します。 + * \return 平面直角座標系での範囲(min, max) + */ + std::pair calculateGridExtent() const; + + /** + * サブグリッドの範囲を計算します。 + * @param min_x 最小X座標(入出力) + * @param min_y 最小Y座標(入出力) + * @param max_x 最大X座標(出力) + * @param max_y 最大Y座標(出力) + * @param row_index 行インデックス + * @param col_index 列インデックス + * @param cell_width セルの幅 + * @param cell_height セルの高さ + * @param is_x_right X方向の向き(右方向ならtrue) + * @param is_y_upper Y方向の向き(上方向ならtrue) + */ + void calculateSubGridExtent( + double& min_x, double& min_y, + double& max_x, double& max_y, + int row_index, int col_index, + double cell_width, double cell_height, + bool is_x_right, bool is_y_upper) const; }; } \ No newline at end of file diff --git a/src/dataset/standard_map_grid.cpp b/src/dataset/standard_map_grid.cpp index cbc68a07..f73cd768 100644 --- a/src/dataset/standard_map_grid.cpp +++ b/src/dataset/standard_map_grid.cpp @@ -1,28 +1,247 @@ #include "plateau/dataset/standard_map_grid.h" + +#include + #include "plateau/geometry/geo_coordinate.h" #include #include +#include +#include namespace plateau::dataset { - StandardMapGrid::StandardMapGrid(const std::string& code) : code_(code), is_valid_(false) { - // コードの形式を検証 - // TODO - is_valid_ = true; + enum class StandardMapGridLevel + { + Invalid = -1, + Level50000 = 0, + Level5000 = 1, + Level2500 = 2, + Level1000 = 3, + Level500 = 4, + }; + + namespace { + constexpr int level5000_division_count = 10; + constexpr int level2500_division_count = 2; + constexpr int level1000_division_count = 5; + constexpr int level500_division_count = 10; + + // 1セルのサイズ + constexpr double level50000_cell_width = 40000.0; // 40km + constexpr double level50000_cell_height = 30000.0; // 30km + constexpr int level50000_row_count = 20; // 縦方向の分割数 + + constexpr double level5000_cell_height = level50000_cell_height / level5000_division_count; // 3km + constexpr double level5000_cell_width = level50000_cell_width / level5000_division_count; // 4km + + constexpr double level2500_cell_height = level5000_cell_height / level2500_division_count; // 1.5km + constexpr double level2500_cell_width = level5000_cell_width / level2500_division_count; // 2km + + constexpr double level1000_cell_height = level5000_cell_height / level1000_division_count; // 600m + constexpr double level1000_cell_width = level5000_cell_width / level1000_division_count; // 800m + + constexpr double level500_cell_height = level5000_cell_height / level500_division_count; // 300m + constexpr double level500_cell_width = level5000_cell_width / level500_division_count; // 400m + + // 原点から端までのセル数 + constexpr double row_half_count = 10.0; + constexpr double col_half_count = 4.0; + } + + /** + * 図郭コードの文字列からレベル(詳細度)を返します。 + */ + StandardMapGridLevel parseLevel(const std::string& code) { + + if (code.size() == 4) { + return StandardMapGridLevel::Level50000; + } + if (code.size() == 6) { + return StandardMapGridLevel::Level5000; + } + if (code.size() == 7) { + return StandardMapGridLevel::Level2500; + } + if (code.size() == 8) { + // 末尾がアルファベットであれば1000 + if (std::isalpha(code.back())) { + return StandardMapGridLevel::Level1000; + } + // 末尾が数字であれば500 + else { + return StandardMapGridLevel::Level500; + } + } + + // サポート対象外 + return StandardMapGridLevel::Invalid; + } + + StandardMapGrid::StandardMapGrid(const std::string& code) : code_(code), is_valid_(true) { + // 図郭コードの文字列が数字とアルファベットからなることをチェックします。 + if (!std::all_of(code_.begin(), code_.end(), [](char c) + { + return std::isalnum(c); + })) { + is_valid_ = false; + return; + } + + // 図郭コードのレベル(詳細度)をチェックします。 + level_ = parseLevel(code); + if (level_ == StandardMapGridLevel::Invalid) { + is_valid_ = false; + return; + } + + // 原点設定 + coordinate_origin_ = std::stoi(code.substr(0, 2)); + + // 図郭コードの行番号、列番号を取得します。 + first_row_ = code[2]; // 1文字目は行 + first_col_ = code[3]; // 2文字目は列 + if (level_ == StandardMapGridLevel::Level50000) { + return; + } + + second_row_ = std::stoi(code.substr(4, 1)); + second_col_ = std::stoi(code.substr(5, 1)); + + if (level_ == StandardMapGridLevel::Level5000) { + return; + } + + if (level_ == StandardMapGridLevel::Level2500) { + // 2×2分割のインデックスを計算 + int third = std::stoi(code.substr(6, 1)); // 1-4 + third_row_ = (third - 1) / 2; // 0 or 1 + third_col_ = (third - 1) % 2; // 0 or 1 + return; + } + + if (level_ == StandardMapGridLevel::Level1000) { + third_row_ = std::stoi(code.substr(6, 1)); // 0-4 + third_col_ = code.substr(7, 1)[0] - 'A'; // 0-4 (A-E) + return; + } + + // Level500 + third_row_ = std::stoi(code.substr(6, 1)); // 0-9 + third_col_ = std::stoi(code.substr(7, 1)); // 0-9 } std::string StandardMapGrid::get() const { return code_; } + std::pair StandardMapGrid::calculateGridExtent() const { + double min_x = 0.0, min_y = 0.0; + double max_x = 0.0, max_y = 0.0; + + // 親セルの位置に基づいて方向フラグを設定(スコープ外でも使用するため、ここで定義) + bool is_x_right = false; + bool is_y_upper = false; + + // Level50000の計算 + { + // 南北方向(行)のインデックス計算 + // A行から数えて何番目かを計算(0始まり) + int row_index = first_row_ - 'A'; + + // 東西方向(列)のインデックス計算 + // A列から数えて何番目かを計算(0始まり) + int col_index = first_col_ - 'A'; + + // 基準点からの距離を計算 + // 列(X座標): 原点から左右対称(左が負、右が正) + min_x = (col_index - col_half_count) * level50000_cell_width; + max_x = min_x + level50000_cell_width; + + // 行(Y座標): 原点から上下対称(上が正、下が負) + min_y = (row_half_count - row_index) * level50000_cell_height; + max_y = min_y + level50000_cell_height; + + // 親セルの位置に基づいて方向フラグを設定 + is_x_right = col_index >= col_half_count; // E列より右側 + is_y_upper = row_index <= row_half_count; // 中央より上側 + } + + if (level_ == StandardMapGridLevel::Level50000) { + return {TVec3d(min_x, min_y, 0), TVec3d(max_x, max_y, 0)}; + } + + // Level5000の計算 + calculateSubGridExtent( + min_x, min_y, max_x, max_y, + second_row_, second_col_, + level5000_cell_width, level5000_cell_height, + is_x_right, is_y_upper); + + if (level_ == StandardMapGridLevel::Level5000) { + return {TVec3d(min_x, min_y, 0), TVec3d(max_x, max_y, 0)}; + } + + if (level_ == StandardMapGridLevel::Level2500) { + calculateSubGridExtent( + min_x, min_y, max_x, max_y, + third_row_, third_col_, + level2500_cell_width, level2500_cell_height, + is_x_right, is_y_upper); + return {TVec3d(min_x, min_y, 0), TVec3d(max_x, max_y, 0)}; + } else if (level_ == StandardMapGridLevel::Level1000) { + calculateSubGridExtent( + min_x, min_y, max_x, max_y, + third_row_, third_col_, + level1000_cell_width, level1000_cell_height, + is_x_right, is_y_upper); + return {TVec3d(min_x, min_y, 0), TVec3d(max_x, max_y, 0)}; + } else { // Level500 + calculateSubGridExtent( + min_x, min_y, max_x, max_y, + third_row_, third_col_, + level500_cell_width, level500_cell_height, + is_x_right, is_y_upper); + return {TVec3d(min_x, min_y, 0), TVec3d(max_x, max_y, 0)}; + } + } + + void StandardMapGrid::calculateSubGridExtent( + double& min_x, double& min_y, + double& max_x, double& max_y, + int row_index, int col_index, + double cell_width, double cell_height, + bool is_x_right, bool is_y_upper) const { + + // X座標の計算 + // is_x_rightがtrueの場合、親セルの左端から右方向に移動 + // is_x_rightがfalseの場合、親セルの左端から左方向に移動 + min_x = min_x + (is_x_right ? col_index * cell_width : -col_index * cell_width); + max_x = min_x + cell_width; + + // Y座標の計算 + // is_y_upperがtrueの場合、親セルの下端から上方向に移動 + // is_y_upperがfalseの場合、親セルの下端から下方向に移動 + min_y = min_y + (is_y_upper ? row_index * cell_height : -row_index * cell_height); + max_y = min_y + cell_height; + } + geometry::Extent StandardMapGrid::getExtent() const { if (!isValid()) { throw std::runtime_error("Invalid standard map grid code."); } + + const auto [planeMin, planeMax] = calculateGridExtent(); + + // GeoReferenceを取得 + plateau::polygonMesh::MeshExtractOptions options; + options.coordinate_zone_id = coordinate_origin_; + const auto geo_reference = geometry::GeoReference(options.coordinate_zone_id, options.reference_point, options.unit_scale, options.mesh_axes); + + // 平面直角座標系から緯度経度に変換 + const auto min_coordinate = geo_reference.unproject(planeMin); + const auto max_coordinate = geo_reference.unproject(planeMax); - // TODO: 図郭コードから緯度経度範囲を計算する実装を追加 - // この実装は図郭コードの仕様に基づいて行う必要があります - return geometry::Extent(geometry::GeoCoordinate(0, 0, 0), geometry::GeoCoordinate(0, 0, 0)); + return geometry::Extent(min_coordinate, max_coordinate); } bool StandardMapGrid::isWithin(const GridCode& other) const { @@ -31,9 +250,14 @@ namespace plateau::dataset { // 同じ型の場合のみ比較 const auto* other_grid = dynamic_cast(&other); if (other_grid == nullptr) return false; - - // TODO: 図郭の包含関係を判定する実装を追加 - return false; + + if (code_ == other_grid->code_) { + return true; + } + + // Level50000の場合は先頭4文字、Level50000以外の場合は先頭6文字で比較 + const size_t compare_length = (level_ == StandardMapGridLevel::Level50000) ? 4 : 6; + return code_.substr(0, compare_length) == other_grid->code_.substr(0, compare_length); } bool StandardMapGrid::isValid() const { @@ -41,18 +265,19 @@ namespace plateau::dataset { } std::shared_ptr StandardMapGrid::upper() { - // 仮実装: 自分自身のコピーを返す - return std::make_shared(code_); + // 1段階上のレベルの図郭コードに変換 + auto new_code = std::make_shared(code_); + new_code->level_ = static_cast(static_cast(level_) - 1); + new_code->is_valid_ = new_code->level_ >= StandardMapGridLevel::Level50000; + return new_code; } int StandardMapGrid::getLevel() const { - // 仮実装: 常に1を返す - return 1; + return (int)level_; } bool StandardMapGrid::isLargestLevel() const { - // 仮実装: 常にtrueを返す - return true; + return level_ == StandardMapGridLevel::Level50000; } bool StandardMapGrid::operator==(const StandardMapGrid& other) const { From e6da4442f9a7c071dd314bd0dbe6b90549798b8b Mon Sep 17 00:00:00 2001 From: yhikishima Date: Thu, 17 Apr 2025 09:19:40 +0900 Subject: [PATCH 12/19] =?UTF-8?q?add:=E5=9B=BD=E5=9C=9F=E5=9F=BA=E6=9C=AC?= =?UTF-8?q?=E5=9B=B3=E9=83=AD=E3=81=AE=E3=83=86=E3=82=B9=E3=83=88=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/CMakeLists.txt | 3 +- test/test_standard_map_grid.cpp | 124 ++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 test/test_standard_map_grid.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3efef245..efa34669 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -48,7 +48,8 @@ add_executable(plateau_test "test_texture_image_base.cpp" "test_map_zoom_level_searcher.cpp" "test_height_map_aligner.cpp" - "test_heightmap_mesh_generator.cpp") + "test_heightmap_mesh_generator.cpp" + "test_standard_map_grid.cpp") add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/test_granularity_convert") diff --git a/test/test_standard_map_grid.cpp b/test/test_standard_map_grid.cpp new file mode 100644 index 00000000..d21552be --- /dev/null +++ b/test/test_standard_map_grid.cpp @@ -0,0 +1,124 @@ +#include + +#include + +#include +#include + +using namespace citygml; +using namespace plateau::dataset; +using namespace plateau::geometry; + +TEST(StandardMapGrid, Level5000_WithinBounds) { + const auto extent = StandardMapGrid("08EE54").getExtent(); // Level5000 + const auto expected = GeoCoordinate(37.4689, 138.7113, 0); + + std::stringstream ss; + ss << "Extent bounds: (" << extent.min.latitude << ", " << extent.min.longitude << ") - (" + << extent.max.latitude << ", " << extent.max.longitude << ")\n" + << "Expected point: (" << expected.latitude << ", " << expected.longitude << ")"; + SCOPED_TRACE(ss.str()); + ASSERT_TRUE( + extent.max.latitude >= expected.latitude && + extent.max.longitude >= expected.longitude && + extent.min.latitude <= expected.latitude && + extent.min.longitude <= expected.longitude + ); +} + +TEST(StandardMapGrid, Level5000_OutOfBounds) { + const auto extent = StandardMapGrid("08EE54").getExtent(); // Level5000 + const auto nonexpected = GeoCoordinate(37.4659, 138.7283, 0); + + std::stringstream ss; + ss << "Extent bounds: (" << extent.min.latitude << ", " << extent.min.longitude << ") - (" + << extent.max.latitude << ", " << extent.max.longitude << ")\n" + << "Non-expected point: (" << nonexpected.latitude << ", " << nonexpected.longitude << ")"; + SCOPED_TRACE(ss.str()); + ASSERT_FALSE( + extent.max.latitude >= nonexpected.latitude && + extent.max.longitude >= nonexpected.longitude && + extent.min.latitude <= nonexpected.latitude && + extent.min.longitude <= nonexpected.longitude + ); +} + +TEST(StandardMapGrid, Level2500_WithinBounds) { + const auto extent = StandardMapGrid("08EE554").getExtent(); // Level2500 + const auto expected = GeoCoordinate(37.4661, 138.7678, 0); + + std::stringstream ss; + ss << "Extent bounds: (" << extent.min.latitude << ", " << extent.min.longitude << ") - (" + << extent.max.latitude << ", " << extent.max.longitude << ")\n" + << "Expected point: (" << expected.latitude << ", " << expected.longitude << ")"; + SCOPED_TRACE(ss.str()); + ASSERT_TRUE( + extent.max.latitude >= expected.latitude && + extent.max.longitude >= expected.longitude && + extent.min.latitude <= expected.latitude && + extent.min.longitude <= expected.longitude + ); +} + +TEST(StandardMapGrid, Level2500_OutOfBounds) { + const auto extent = StandardMapGrid("08EE554").getExtent(); // Level2500 + const auto nonexpected = GeoCoordinate(37.4631, 138.7848, 0); + + std::stringstream ss; + ss << "Extent bounds: (" << extent.min.latitude << ", " << extent.min.longitude << ") - (" + << extent.max.latitude << ", " << extent.max.longitude << ")\n" + << "Non-expected point: (" << nonexpected.latitude << ", " << nonexpected.longitude << ")"; + SCOPED_TRACE(ss.str()); + ASSERT_FALSE( + extent.max.latitude >= nonexpected.latitude && + extent.max.longitude >= nonexpected.longitude && + extent.min.latitude <= nonexpected.latitude && + extent.min.longitude <= nonexpected.longitude + ); +} + +TEST(StandardMapGrid, isWithinTest) { + // Level50000とLevel5000の包含関係 + const auto grid50000 = StandardMapGrid("09AE"); + const auto grid5000 = StandardMapGrid("09AE09"); + const auto grid2500 = StandardMapGrid("09AE091"); + const auto grid1000 = StandardMapGrid("09AE091A"); + const auto grid500 = StandardMapGrid("09AE0911"); + + // 同じコードは包含関係にある + ASSERT_TRUE(grid50000.isWithin(grid50000)); + ASSERT_TRUE(grid5000.isWithin(grid5000)); + + // Level50000は下位レベルを包含する + ASSERT_TRUE(grid50000.isWithin(grid5000)); + ASSERT_TRUE(grid50000.isWithin(grid2500)); + ASSERT_TRUE(grid50000.isWithin(grid1000)); + ASSERT_TRUE(grid50000.isWithin(grid500)); + + // Level5000は下位レベルを包含する + ASSERT_TRUE(grid5000.isWithin(grid2500)); + ASSERT_TRUE(grid5000.isWithin(grid1000)); + ASSERT_TRUE(grid5000.isWithin(grid500)); + + // 下位レベルは上位レベルを包含しない + ASSERT_FALSE(grid5000.isWithin(grid50000)); + ASSERT_FALSE(grid2500.isWithin(grid50000)); + ASSERT_FALSE(grid2500.isWithin(grid5000)); +} + +TEST(StandardMapGrid, invalidGridCode) { + // 無効な図郭コードのテスト + ASSERT_FALSE(StandardMapGrid("invalid").isValid()); + ASSERT_FALSE(StandardMapGrid("09").isValid()); // 短すぎる + ASSERT_FALSE(StandardMapGrid("09AE09-1-1").isValid()); // 長すぎる + ASSERT_FALSE(StandardMapGrid("09ZZ09").isValid()); // 無効な文字 +} + +TEST(StandardMapGrid, levelCheck) { + // 各レベルの判定テスト + ASSERT_EQ(StandardMapGrid("09AE").getLevel(), 0); // Level50000 + ASSERT_EQ(StandardMapGrid("09AE09").getLevel(), 1); // Level5000 + ASSERT_EQ(StandardMapGrid("09AE091").getLevel(), 2); // Level2500 + ASSERT_EQ(StandardMapGrid("09AE091A").getLevel(), 3); // Level1000 + ASSERT_EQ(StandardMapGrid("09AE0911").getLevel(), 4); // Level500 +} \ No newline at end of file From a5354b72d40edfed35360b1e05aee99dc32b6e4a Mon Sep 17 00:00:00 2001 From: yhikishima Date: Thu, 17 Apr 2025 13:22:20 +0900 Subject: [PATCH 13/19] =?UTF-8?q?add:=E3=83=86=E3=82=B9=E3=83=88=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/plateau/dataset/standard_map_grid.h | 2 +- src/dataset/standard_map_grid.cpp | 40 ++++-------- test/test_standard_map_grid.cpp | 67 ++++++++++++--------- 3 files changed, 51 insertions(+), 58 deletions(-) diff --git a/include/plateau/dataset/standard_map_grid.h b/include/plateau/dataset/standard_map_grid.h index 9b595bca..b205699b 100644 --- a/include/plateau/dataset/standard_map_grid.h +++ b/include/plateau/dataset/standard_map_grid.h @@ -56,7 +56,7 @@ namespace plateau::dataset { private: std::string code_; // 図郭コード - bool is_valid_ = false; // コードが有効かどうか + bool is_valid_ = true; // コードが有効かどうか StandardMapGridLevel level_; int coordinate_origin_; // 原点 diff --git a/src/dataset/standard_map_grid.cpp b/src/dataset/standard_map_grid.cpp index 282a4372..38e1a67c 100644 --- a/src/dataset/standard_map_grid.cpp +++ b/src/dataset/standard_map_grid.cpp @@ -3,6 +3,7 @@ #include "plateau/geometry/geo_coordinate.h" #include #include +#include #include namespace plateau::dataset { @@ -74,7 +75,7 @@ namespace plateau::dataset { return StandardMapGridLevel::Invalid; } - StandardMapGrid::StandardMapGrid(std::string code) : code_(std::move(code), is_valid_(true)) { + StandardMapGrid::StandardMapGrid(std::string code) : code_(std::move(code)) { // 図郭コードの文字列が数字とアルファベットからなることをチェックします。 if (!std::all_of(code_.begin(), code_.end(), [](char c) { @@ -241,37 +242,22 @@ namespace plateau::dataset { return geometry::Extent(min_coordinate, max_coordinate); } - bool StandardMapGrid::isWithin(const GridCode& other) const { - if (!isValid()) return false; - - // 同じ型の場合のみ比較 - const auto* other_grid = dynamic_cast(&other); - if (other_grid == nullptr) return false; - - if (code_ == other_grid->code_) { - return true; - } - - // Level50000の場合は先頭4文字、Level50000以外の場合は先頭6文字で比較 - const size_t compare_length = (level_ == StandardMapGridLevel::Level50000) ? 4 : 6; - return code_.substr(0, compare_length) == other_grid->code_.substr(0, compare_length); - } - bool StandardMapGrid::isValid() const { return is_valid_; } - std::shared_ptr StandardMapGrid::upper() { + std::shared_ptr StandardMapGrid::upper() const { // 1段階上のレベルの図郭コードに変換 - auto new_code = std::make_shared(code_); - new_code->level_ = static_cast(static_cast(level_) - 1); - new_code->is_valid_ = new_code->level_ >= StandardMapGridLevel::Level50000; - return new_code; + auto new_grid_code = std::shared_ptr(upperRaw()); + return new_grid_code; } GridCode* StandardMapGrid::upperRaw() const { - // 仮実装: 自分自身のコピーを返す - return new StandardMapGrid(code_); + // 1段階上のレベルの図郭コードに変換 + auto new_code = new StandardMapGrid(code_); + new_code->level_ = static_cast(static_cast(level_) - 1); + new_code->is_valid_ = new_code->level_ >= StandardMapGridLevel::Level50000; + return new_code; } int StandardMapGrid::getLevel() const { @@ -283,13 +269,11 @@ namespace plateau::dataset { } bool StandardMapGrid::isSmallerThanNormalGml() const { - // 仮実装 - return false; + return level_ < StandardMapGridLevel::Level2500; } bool StandardMapGrid::isNormalGmlLevel() const { - // 仮実装: 常にtrueを返す - return true; + return level_ == StandardMapGridLevel::Level2500; } bool StandardMapGrid::operator==(const StandardMapGrid& other) const { diff --git a/test/test_standard_map_grid.cpp b/test/test_standard_map_grid.cpp index d21552be..7fe30e2d 100644 --- a/test/test_standard_map_grid.cpp +++ b/test/test_standard_map_grid.cpp @@ -77,35 +77,6 @@ TEST(StandardMapGrid, Level2500_OutOfBounds) { ); } -TEST(StandardMapGrid, isWithinTest) { - // Level50000とLevel5000の包含関係 - const auto grid50000 = StandardMapGrid("09AE"); - const auto grid5000 = StandardMapGrid("09AE09"); - const auto grid2500 = StandardMapGrid("09AE091"); - const auto grid1000 = StandardMapGrid("09AE091A"); - const auto grid500 = StandardMapGrid("09AE0911"); - - // 同じコードは包含関係にある - ASSERT_TRUE(grid50000.isWithin(grid50000)); - ASSERT_TRUE(grid5000.isWithin(grid5000)); - - // Level50000は下位レベルを包含する - ASSERT_TRUE(grid50000.isWithin(grid5000)); - ASSERT_TRUE(grid50000.isWithin(grid2500)); - ASSERT_TRUE(grid50000.isWithin(grid1000)); - ASSERT_TRUE(grid50000.isWithin(grid500)); - - // Level5000は下位レベルを包含する - ASSERT_TRUE(grid5000.isWithin(grid2500)); - ASSERT_TRUE(grid5000.isWithin(grid1000)); - ASSERT_TRUE(grid5000.isWithin(grid500)); - - // 下位レベルは上位レベルを包含しない - ASSERT_FALSE(grid5000.isWithin(grid50000)); - ASSERT_FALSE(grid2500.isWithin(grid50000)); - ASSERT_FALSE(grid2500.isWithin(grid5000)); -} - TEST(StandardMapGrid, invalidGridCode) { // 無効な図郭コードのテスト ASSERT_FALSE(StandardMapGrid("invalid").isValid()); @@ -121,4 +92,42 @@ TEST(StandardMapGrid, levelCheck) { ASSERT_EQ(StandardMapGrid("09AE091").getLevel(), 2); // Level2500 ASSERT_EQ(StandardMapGrid("09AE091A").getLevel(), 3); // Level1000 ASSERT_EQ(StandardMapGrid("09AE0911").getLevel(), 4); // Level500 +} + +TEST(StandardMapGrid, upperMethodTest) { + // Level500からLevel50000までの変換をテスト + auto grid = StandardMapGrid("09AE0911"); // Level500 + ASSERT_EQ(grid.upper()->get(), "09AE091"); // Level1000 + + grid = StandardMapGrid("09AE091A"); // Level1000 + ASSERT_EQ(grid.upper()->get(), "09AE091"); // Level2500 + + grid = StandardMapGrid("09AE091"); // Level2500 + ASSERT_EQ(grid.upper()->get(), "09AE09"); // Level5000 + + grid = StandardMapGrid("09AE09"); // Level5000 + ASSERT_EQ(grid.upper()->get(), "09AE"); // Level50000 + + // Level50000からの変換は無効になるはず + grid = StandardMapGrid("09AE"); // Level50000 + auto upper_grid = grid.upper(); + ASSERT_FALSE(upper_grid->isValid()); +} + +TEST(StandardMapGrid, levelCheckMethods) { + // isLargestLevelのテスト + ASSERT_TRUE(StandardMapGrid("09AE").isLargestLevel()); // Level50000 + ASSERT_FALSE(StandardMapGrid("09AE09").isLargestLevel()); // Level5000 + + // isSmallerThanNormalGmlのテスト + ASSERT_TRUE(StandardMapGrid("09AE").isSmallerThanNormalGml()); // Level50000 + ASSERT_TRUE(StandardMapGrid("09AE09").isSmallerThanNormalGml()); // Level5000 + ASSERT_FALSE(StandardMapGrid("09AE091").isSmallerThanNormalGml()); // Level2500 + ASSERT_FALSE(StandardMapGrid("09AE091A").isSmallerThanNormalGml()); // Level1000 + + // isNormalGmlLevelのテスト + ASSERT_FALSE(StandardMapGrid("09AE").isNormalGmlLevel()); // Level50000 + ASSERT_FALSE(StandardMapGrid("09AE09").isNormalGmlLevel()); // Level5000 + ASSERT_TRUE(StandardMapGrid("09AE091").isNormalGmlLevel()); // Level2500 + ASSERT_FALSE(StandardMapGrid("09AE091A").isNormalGmlLevel()); // Level1000 } \ No newline at end of file From 562d020e023d49c9139a76f19fbd8df41779fca3 Mon Sep 17 00:00:00 2001 From: yhikishima Date: Mon, 21 Apr 2025 11:18:38 +0900 Subject: [PATCH 14/19] =?UTF-8?q?fix:=E5=9B=BD=E5=9C=9F=E5=9B=B3=E9=83=AD?= =?UTF-8?q?=E3=81=AE=E7=AF=84=E5=9B=B2=E3=81=AE=E3=83=AD=E3=82=B8=E3=83=83?= =?UTF-8?q?=E3=82=AF=E4=BF=AE=E6=AD=A3=E3=81=A8=E3=83=86=E3=82=B9=E3=83=88?= =?UTF-8?q?=E3=82=92=E9=80=9A=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/plateau/dataset/standard_map_grid.h | 42 +-- src/dataset/standard_map_grid.cpp | 354 +++++++++++--------- test/test_standard_map_grid.cpp | 250 ++++++++++++-- 3 files changed, 436 insertions(+), 210 deletions(-) diff --git a/include/plateau/dataset/standard_map_grid.h b/include/plateau/dataset/standard_map_grid.h index b205699b..26bfa997 100644 --- a/include/plateau/dataset/standard_map_grid.h +++ b/include/plateau/dataset/standard_map_grid.h @@ -54,43 +54,23 @@ namespace plateau::dataset { bool operator==(const StandardMapGrid& other) const; bool operator<(const StandardMapGrid& other) const; + /** + * \brief 図郭コードから平面直角座標系での範囲を計算します。 + * \return 平面直角座標系での範囲(min, max) + */ + std::pair calculateGridExtent() const; + private: std::string code_; // 図郭コード bool is_valid_ = true; // コードが有効かどうか StandardMapGridLevel level_; int coordinate_origin_; // 原点 - char first_row_; // 1文字目の行(A-T) - char first_col_; // 2文字目の列(A-H) + char first_row_; // 1文字目はrow座標(東西, A-H) + char first_column_; // 2文字目はcolumn座標(南北, A-T) int second_row_; - int second_col_; + int second_column_; int third_row_; - int third_col_; - - /** - * \brief 図郭コードから平面直角座標系での範囲を計算します。 - * \return 平面直角座標系での範囲(min, max) - */ - std::pair calculateGridExtent() const; - - /** - * サブグリッドの範囲を計算します。 - * @param min_x 最小X座標(入出力) - * @param min_y 最小Y座標(入出力) - * @param max_x 最大X座標(出力) - * @param max_y 最大Y座標(出力) - * @param row_index 行インデックス - * @param col_index 列インデックス - * @param cell_width セルの幅 - * @param cell_height セルの高さ - * @param is_x_right X方向の向き(右方向ならtrue) - * @param is_y_upper Y方向の向き(上方向ならtrue) - */ - void calculateSubGridExtent( - double& min_x, double& min_y, - double& max_x, double& max_y, - int row_index, int col_index, - double cell_width, double cell_height, - bool is_x_right, bool is_y_upper) const; + int third_column_; }; -} \ No newline at end of file +} diff --git a/src/dataset/standard_map_grid.cpp b/src/dataset/standard_map_grid.cpp index 38e1a67c..dfdb5bf8 100644 --- a/src/dataset/standard_map_grid.cpp +++ b/src/dataset/standard_map_grid.cpp @@ -5,6 +5,7 @@ #include #include #include +#include namespace plateau::dataset { @@ -25,107 +26,169 @@ namespace plateau::dataset { constexpr int level500_division_count = 10; // 1セルのサイズ - constexpr double level50000_cell_width = 40000.0; // 40km - constexpr double level50000_cell_height = 30000.0; // 30km - constexpr int level50000_row_count = 20; // 縦方向の分割数 + constexpr double level50000_cell_column = 30000.0; // 南北30km + constexpr double level50000_cell_row = 40000.0; // 東西40km - constexpr double level5000_cell_height = level50000_cell_height / level5000_division_count; // 3km - constexpr double level5000_cell_width = level50000_cell_width / level5000_division_count; // 4km + constexpr double level5000_cell_column = level50000_cell_column / level5000_division_count; // 南北4km + constexpr double level5000_cell_row = level50000_cell_row / level5000_division_count; // 東西3km - constexpr double level2500_cell_height = level5000_cell_height / level2500_division_count; // 1.5km - constexpr double level2500_cell_width = level5000_cell_width / level2500_division_count; // 2km + constexpr double level2500_cell_column = level5000_cell_column / level2500_division_count; // 南北2km + constexpr double level2500_cell_row = level5000_cell_row / level2500_division_count; // 東西1.5km - constexpr double level1000_cell_height = level5000_cell_height / level1000_division_count; // 600m - constexpr double level1000_cell_width = level5000_cell_width / level1000_division_count; // 800m + constexpr double level1000_cell_column = level5000_cell_column / level1000_division_count; // 南北800m + constexpr double level1000_cell_row = level5000_cell_row / level1000_division_count; // 東西600m - constexpr double level500_cell_height = level5000_cell_height / level500_division_count; // 300m - constexpr double level500_cell_width = level5000_cell_width / level500_division_count; // 400m + constexpr double level500_cell_column = level5000_cell_column / level500_division_count; // 南北400m + constexpr double level500_cell_row = level5000_cell_row / level500_division_count; // 東西300m - // 原点から端までのセル数 - constexpr double row_half_count = 10.0; - constexpr double col_half_count = 4.0; - } - - /** - * 図郭コードの文字列からレベル(詳細度)を返します。 - */ - StandardMapGridLevel parseLevel(const std::string& code) { + /** + * 図郭コードの文字列からレベル(詳細度)を返します。 + */ + StandardMapGridLevel parseLevel(const std::string& code) { + if (code.size() == 4) { + return StandardMapGridLevel::Level50000; + } + if (code.size() == 6) { + return StandardMapGridLevel::Level5000; + } + if (code.size() == 7) { + return StandardMapGridLevel::Level2500; + } + if (code.size() == 8) { + // 末尾がアルファベットであれば1000 + if (std::isalpha(code.back())) { + return StandardMapGridLevel::Level1000; + } + // 末尾が数字であれば500 + else { + return StandardMapGridLevel::Level500; + } + } - if (code.size() == 4) { - return StandardMapGridLevel::Level50000; + // サポート対象外 + return StandardMapGridLevel::Invalid; } - if (code.size() == 6) { - return StandardMapGridLevel::Level5000; + + /** + * 計算された平面直角座標をTVec3dのペアに変換します。 + */ + std::pair createExtentPair( + double min_column, double min_row, + double max_column, double max_row) { + // column: 南北方向(緯度):Y軸 + // row: 東西方向(経度):X軸 + return {TVec3d(min_row, 0, min_column), TVec3d(max_row, 0, max_column)}; } - if (code.size() == 7) { - return StandardMapGridLevel::Level2500; + + void calculateSubGridExtent( + double& min_column, double& min_row, + double& max_column, double& max_row, + int column_index, int row_index, + double cell_column, double cell_row) { + + // column座標(南北)の計算 + min_column = min_column + (column_index * cell_column); + max_column = min_column + cell_column; + + // row座標(東西)の計算 + min_row = min_row + (row_index * cell_row); + max_row = min_row + cell_row; } - if (code.size() == 8) { - // 末尾がアルファベットであれば1000 - if (std::isalpha(code.back())) { - return StandardMapGridLevel::Level1000; + } + + StandardMapGrid::StandardMapGrid(std::string code) : code_(std::move(code)) { + try { + // 図郭コードの文字列が数字とアルファベットからなることをチェックします。 + if (!std::all_of(code_.begin(), code_.end(), [](char c) + { + return std::isalnum(c); + })) { + is_valid_ = false; + return; } - // 末尾が数字であれば500 - else { - return StandardMapGridLevel::Level500; + + // 図郭コードのレベル(詳細度)をチェックします。 + level_ = parseLevel(code_); + if (level_ == StandardMapGridLevel::Invalid) { + is_valid_ = false; + return; } - } - // サポート対象外 - return StandardMapGridLevel::Invalid; - } + // 原点設定 + coordinate_origin_ = std::stoi(code_.substr(0, 2)); - StandardMapGrid::StandardMapGrid(std::string code) : code_(std::move(code)) { - // 図郭コードの文字列が数字とアルファベットからなることをチェックします。 - if (!std::all_of(code_.begin(), code_.end(), [](char c) - { - return std::isalnum(c); - })) { - is_valid_ = false; - return; - } + // 図郭コードのcolumn, row座標を取得します。 + first_column_ = code_[2]; // 1文字目はcolumn座標(南北) + first_row_ = code_[3]; // 2文字目はrow座標(東西) - // 図郭コードのレベル(詳細度)をチェックします。 - level_ = parseLevel(code); - if (level_ == StandardMapGridLevel::Invalid) { - is_valid_ = false; - return; - } + // 文字の範囲チェック + if (first_column_ < 'A' || first_column_ > 'T' || + first_row_ < 'A' || first_row_ > 'H') { + is_valid_ = false; + return; + } - // 原点設定 - coordinate_origin_ = std::stoi(code.substr(0, 2)); + if (level_ == StandardMapGridLevel::Level50000) { + return; + } - // 図郭コードの行番号、列番号を取得します。 - first_row_ = code[2]; // 1文字目は行 - first_col_ = code[3]; // 2文字目は列 - if (level_ == StandardMapGridLevel::Level50000) { - return; - } + // 基点は左下(90) + second_column_ = 9 - std::stoi(code_.substr(4, 1)); + second_row_ = std::stoi(code_.substr(5, 1)); - second_row_ = std::stoi(code.substr(4, 1)); - second_col_ = std::stoi(code.substr(5, 1)); + if (level_ == StandardMapGridLevel::Level5000) { + return; + } - if (level_ == StandardMapGridLevel::Level5000) { - return; - } + if (level_ == StandardMapGridLevel::Level2500) { + // 基点は左下 + int third = std::stoi(code_.substr(6, 1)); // 1-4 + switch (third) { + case 1: // 左上 + third_column_ = 1; + third_row_ = 0; + break; + case 2: // 右上 + third_column_ = 1; + third_row_ = 1; + break; + case 3: // 左下 + third_column_ = 0; + third_row_ = 0; + break; + case 4: // 右下 + third_column_ = 0; + third_row_ = 1; + break; + default: + is_valid_ = false; + break; + } + return; + } - if (level_ == StandardMapGridLevel::Level2500) { - // 2×2分割のインデックスを計算 - int third = std::stoi(code.substr(6, 1)); // 1-4 - third_row_ = (third - 1) / 2; // 0 or 1 - third_col_ = (third - 1) % 2; // 0 or 1 - return; - } + if (level_ == StandardMapGridLevel::Level1000) { + // 基点は左下(4A) + third_column_ = 4 - std::stoi(code_.substr(6, 1)); // 0-4 + third_row_ = code_.substr(7, 1)[0] - 'A'; // 0-4 (A-E) + + // Level1000の範囲チェック + if (third_column_ < 0 || third_column_ > 4 || + third_row_ < 0 || third_row_ > 4) { + is_valid_ = false; + } + return; + } - if (level_ == StandardMapGridLevel::Level1000) { - third_row_ = std::stoi(code.substr(6, 1)); // 0-4 - third_col_ = code.substr(7, 1)[0] - 'A'; // 0-4 (A-E) - return; - } + // Level500 + // 基点は左下(9A) + third_column_ = 9 - std::stoi(code_.substr(6, 1)); // 0-9 + third_row_ = std::stoi(code_.substr(7, 1)); // 0-9 - // Level500 - third_row_ = std::stoi(code.substr(6, 1)); // 0-9 - third_col_ = std::stoi(code.substr(7, 1)); // 0-9 + } catch (const std::exception& e) { + is_valid_ = false; + std::cerr << "Failed to parse grid code " << code_ << ": " << e.what() << std::endl; + } } std::string StandardMapGrid::get() const { @@ -133,96 +196,61 @@ namespace plateau::dataset { } std::pair StandardMapGrid::calculateGridExtent() const { - double min_x = 0.0, min_y = 0.0; - double max_x = 0.0, max_y = 0.0; + // 東西方向のインデックスを計算(東がプラス、西がマイナス) + int row_index = first_row_ - 'E'; - // 親セルの位置に基づいて方向フラグを設定(スコープ外でも使用するため、ここで定義) - bool is_x_right = false; - bool is_y_upper = false; + // 南北方向のインデックスを計算(北がプラス、南がマイナス) + int column_index = 'J' - first_column_; // Level50000の計算 - { - // 南北方向(行)のインデックス計算 - // A行から数えて何番目かを計算(0始まり) - int row_index = first_row_ - 'A'; - - // 東西方向(列)のインデックス計算 - // A列から数えて何番目かを計算(0始まり) - int col_index = first_col_ - 'A'; - - // 基準点からの距離を計算 - // 列(X座標): 原点から左右対称(左が負、右が正) - min_x = (col_index - col_half_count) * level50000_cell_width; - max_x = min_x + level50000_cell_width; - - // 行(Y座標): 原点から上下対称(上が正、下が負) - min_y = (row_half_count - row_index) * level50000_cell_height; - max_y = min_y + level50000_cell_height; - - // 親セルの位置に基づいて方向フラグを設定 - is_x_right = col_index >= col_half_count; // E列より右側 - is_y_upper = row_index <= row_half_count; // 中央より上側 - } + // column座標(南北)の計算 + double min_column = column_index * level50000_cell_column; + double max_column = min_column + level50000_cell_column; + + // row座標(東西)の計算 + double min_row = row_index * level50000_cell_row; + double max_row = min_row + level50000_cell_row; if (level_ == StandardMapGridLevel::Level50000) { - return {TVec3d(min_x, min_y, 0), TVec3d(max_x, max_y, 0)}; + return createExtentPair(min_column, min_row, max_column, max_row); } // Level5000の計算 calculateSubGridExtent( - min_x, min_y, max_x, max_y, - second_row_, second_col_, - level5000_cell_width, level5000_cell_height, - is_x_right, is_y_upper); + min_column, min_row, max_column, max_row, + second_column_, second_row_, + level5000_cell_column, level5000_cell_row); if (level_ == StandardMapGridLevel::Level5000) { - return {TVec3d(min_x, min_y, 0), TVec3d(max_x, max_y, 0)}; + return createExtentPair(min_column, min_row, max_column, max_row); } if (level_ == StandardMapGridLevel::Level2500) { + calculateSubGridExtent( - min_x, min_y, max_x, max_y, - third_row_, third_col_, - level2500_cell_width, level2500_cell_height, - is_x_right, is_y_upper); - return {TVec3d(min_x, min_y, 0), TVec3d(max_x, max_y, 0)}; + min_column, min_row, max_column, max_row, + third_column_, third_row_, + level2500_cell_column, level2500_cell_row); + return createExtentPair(min_column, min_row, max_column, max_row); + } else if (level_ == StandardMapGridLevel::Level1000) { + calculateSubGridExtent( - min_x, min_y, max_x, max_y, - third_row_, third_col_, - level1000_cell_width, level1000_cell_height, - is_x_right, is_y_upper); - return {TVec3d(min_x, min_y, 0), TVec3d(max_x, max_y, 0)}; + min_column, min_row, max_column, max_row, + third_column_, third_row_, + level1000_cell_column, level1000_cell_row); + return createExtentPair(min_column, min_row, max_column, max_row); + } else { // Level500 + calculateSubGridExtent( - min_x, min_y, max_x, max_y, - third_row_, third_col_, - level500_cell_width, level500_cell_height, - is_x_right, is_y_upper); - return {TVec3d(min_x, min_y, 0), TVec3d(max_x, max_y, 0)}; + min_column, min_row, max_column, max_row, + third_column_, third_row_, + level500_cell_column, level500_cell_row); + return createExtentPair(min_column, min_row, max_column, max_row); } } - void StandardMapGrid::calculateSubGridExtent( - double& min_x, double& min_y, - double& max_x, double& max_y, - int row_index, int col_index, - double cell_width, double cell_height, - bool is_x_right, bool is_y_upper) const { - - // X座標の計算 - // is_x_rightがtrueの場合、親セルの左端から右方向に移動 - // is_x_rightがfalseの場合、親セルの左端から左方向に移動 - min_x = min_x + (is_x_right ? col_index * cell_width : -col_index * cell_width); - max_x = min_x + cell_width; - - // Y座標の計算 - // is_y_upperがtrueの場合、親セルの下端から上方向に移動 - // is_y_upperがfalseの場合、親セルの下端から下方向に移動 - min_y = min_y + (is_y_upper ? row_index * cell_height : -row_index * cell_height); - max_y = min_y + cell_height; - } - geometry::Extent StandardMapGrid::getExtent() const { if (!isValid()) { throw std::runtime_error("Invalid standard map grid code."); @@ -253,11 +281,31 @@ namespace plateau::dataset { } GridCode* StandardMapGrid::upperRaw() const { - // 1段階上のレベルの図郭コードに変換 - auto new_code = new StandardMapGrid(code_); - new_code->level_ = static_cast(static_cast(level_) - 1); - new_code->is_valid_ = new_code->level_ >= StandardMapGridLevel::Level50000; - return new_code; + auto* new_grid = new StandardMapGrid(code_); + + switch (level_) { + case StandardMapGridLevel::Level500: + case StandardMapGridLevel::Level1000: + case StandardMapGridLevel::Level2500: + // 6桁のLevel5000コードにする(末尾を削除) + new_grid->code_ = code_.substr(0, 6); + new_grid->level_ = StandardMapGridLevel::Level5000; + break; + + case StandardMapGridLevel::Level5000: + // 4桁のLevel50000コードにする(末尾を削除) + new_grid->code_ = code_.substr(0, 4); + new_grid->level_ = StandardMapGridLevel::Level50000; + break; + + case StandardMapGridLevel::Level50000: + default: + // 不正なレベルの場合も無効にする + new_grid->is_valid_ = false; + break; + } + + return new_grid; } int StandardMapGrid::getLevel() const { diff --git a/test/test_standard_map_grid.cpp b/test/test_standard_map_grid.cpp index 7fe30e2d..22fcad43 100644 --- a/test/test_standard_map_grid.cpp +++ b/test/test_standard_map_grid.cpp @@ -9,9 +9,15 @@ using namespace citygml; using namespace plateau::dataset; using namespace plateau::geometry; -TEST(StandardMapGrid, Level5000_WithinBounds) { - const auto extent = StandardMapGrid("08EE54").getExtent(); // Level5000 - const auto expected = GeoCoordinate(37.4689, 138.7113, 0); +TEST(StandardMapGrid, Level50000_WithinBounds) { + const auto extent = StandardMapGrid("08JE").getExtent(); + const auto expected = GeoCoordinate(36.0935, 138.8013, 0); + + const auto extent2 = StandardMapGrid("08KD").getExtent(); + const auto expected2 = GeoCoordinate(35.7532, 138.0981, 0); + + const auto extent3 = StandardMapGrid("08KC").getExtent(); + const auto expected3 = GeoCoordinate(35.7978, 137.8043, 0); std::stringstream ss; ss << "Extent bounds: (" << extent.min.latitude << ", " << extent.min.longitude << ") - (" @@ -24,28 +30,52 @@ TEST(StandardMapGrid, Level5000_WithinBounds) { extent.min.latitude <= expected.latitude && extent.min.longitude <= expected.longitude ); + + std::stringstream ss2; + ss2 << "Extent2 bounds: (" << extent2.min.latitude << ", " << extent2.min.longitude << ") - (" + << extent2.max.latitude << ", " << extent2.max.longitude << ")\n" + << "Expected point2: (" << expected2.latitude << ", " << expected2.longitude << ")"; + SCOPED_TRACE(ss2.str()); + ASSERT_TRUE( + extent2.max.latitude >= expected2.latitude && + extent2.max.longitude >= expected2.longitude && + extent2.min.latitude <= expected2.latitude && + extent2.min.longitude <= expected2.longitude + ); + + std::stringstream ss3; + ss3 << "Extent3 bounds: (" << extent3.min.latitude << ", " << extent3.min.longitude << ") - (" + << extent3.max.latitude << ", " << extent3.max.longitude << ")\n" + << "Expected point3: (" << expected3.latitude << ", " << expected3.longitude << ")"; + SCOPED_TRACE(ss3.str()); + ASSERT_TRUE( + extent3.max.latitude >= expected3.latitude && + extent3.max.longitude >= expected3.longitude && + extent3.min.latitude <= expected3.latitude && + extent3.min.longitude <= expected3.longitude + ); } -TEST(StandardMapGrid, Level5000_OutOfBounds) { - const auto extent = StandardMapGrid("08EE54").getExtent(); // Level5000 - const auto nonexpected = GeoCoordinate(37.4659, 138.7283, 0); +TEST(StandardMapGrid, Level5000_WithinBounds) { + const auto extent = StandardMapGrid("08JE54").getExtent(); // Level5000 + const auto expected = GeoCoordinate(36.1125, 138.6911, 0); std::stringstream ss; ss << "Extent bounds: (" << extent.min.latitude << ", " << extent.min.longitude << ") - (" << extent.max.latitude << ", " << extent.max.longitude << ")\n" - << "Non-expected point: (" << nonexpected.latitude << ", " << nonexpected.longitude << ")"; + << "Expected point: (" << expected.latitude << ", " << expected.longitude << ")"; SCOPED_TRACE(ss.str()); - ASSERT_FALSE( - extent.max.latitude >= nonexpected.latitude && - extent.max.longitude >= nonexpected.longitude && - extent.min.latitude <= nonexpected.latitude && - extent.min.longitude <= nonexpected.longitude + ASSERT_TRUE( + extent.max.latitude >= expected.latitude && + extent.max.longitude >= expected.longitude && + extent.min.latitude <= expected.latitude && + extent.min.longitude <= expected.longitude ); } TEST(StandardMapGrid, Level2500_WithinBounds) { const auto extent = StandardMapGrid("08EE554").getExtent(); // Level2500 - const auto expected = GeoCoordinate(37.4661, 138.7678, 0); + const auto expected = GeoCoordinate(37.4669, 138.7544, 0); std::stringstream ss; ss << "Extent bounds: (" << extent.min.latitude << ", " << extent.min.longitude << ") - (" @@ -60,20 +90,20 @@ TEST(StandardMapGrid, Level2500_WithinBounds) { ); } -TEST(StandardMapGrid, Level2500_OutOfBounds) { - const auto extent = StandardMapGrid("08EE554").getExtent(); // Level2500 - const auto nonexpected = GeoCoordinate(37.4631, 138.7848, 0); +TEST(StandardMapGrid, Level1000_WithinBounds) { + const auto extent = StandardMapGrid("08JE640E").getExtent(); // Level2500 + const auto expected = GeoCoordinate(36.1053, 138.7151, 0); std::stringstream ss; ss << "Extent bounds: (" << extent.min.latitude << ", " << extent.min.longitude << ") - (" << extent.max.latitude << ", " << extent.max.longitude << ")\n" - << "Non-expected point: (" << nonexpected.latitude << ", " << nonexpected.longitude << ")"; + << "Expected point: (" << expected.latitude << ", " << expected.longitude << ")"; SCOPED_TRACE(ss.str()); - ASSERT_FALSE( - extent.max.latitude >= nonexpected.latitude && - extent.max.longitude >= nonexpected.longitude && - extent.min.latitude <= nonexpected.latitude && - extent.min.longitude <= nonexpected.longitude + ASSERT_TRUE( + extent.max.latitude >= expected.latitude && + extent.max.longitude >= expected.longitude && + extent.min.latitude <= expected.latitude && + extent.min.longitude <= expected.longitude ); } @@ -81,7 +111,7 @@ TEST(StandardMapGrid, invalidGridCode) { // 無効な図郭コードのテスト ASSERT_FALSE(StandardMapGrid("invalid").isValid()); ASSERT_FALSE(StandardMapGrid("09").isValid()); // 短すぎる - ASSERT_FALSE(StandardMapGrid("09AE09-1-1").isValid()); // 長すぎる + ASSERT_FALSE(StandardMapGrid("09AE09111").isValid()); // 長すぎる ASSERT_FALSE(StandardMapGrid("09ZZ09").isValid()); // 無効な文字 } @@ -97,10 +127,10 @@ TEST(StandardMapGrid, levelCheck) { TEST(StandardMapGrid, upperMethodTest) { // Level500からLevel50000までの変換をテスト auto grid = StandardMapGrid("09AE0911"); // Level500 - ASSERT_EQ(grid.upper()->get(), "09AE091"); // Level1000 + ASSERT_EQ(grid.upper()->get(), "09AE09"); // Level5000 grid = StandardMapGrid("09AE091A"); // Level1000 - ASSERT_EQ(grid.upper()->get(), "09AE091"); // Level2500 + ASSERT_EQ(grid.upper()->get(), "09AE09"); // Level5000 grid = StandardMapGrid("09AE091"); // Level2500 ASSERT_EQ(grid.upper()->get(), "09AE09"); // Level5000 @@ -130,4 +160,172 @@ TEST(StandardMapGrid, levelCheckMethods) { ASSERT_FALSE(StandardMapGrid("09AE09").isNormalGmlLevel()); // Level5000 ASSERT_TRUE(StandardMapGrid("09AE091").isNormalGmlLevel()); // Level2500 ASSERT_FALSE(StandardMapGrid("09AE091A").isNormalGmlLevel()); // Level1000 -} \ No newline at end of file +} + +TEST(StandardMapGrid, calculateGridExtent_Level50000) { + // 基準点のテスト + { + const auto grid = StandardMapGrid("08JE"); + const auto [min, max] = grid.calculateGridExtent(); + + EXPECT_DOUBLE_EQ(min.x, 0); + EXPECT_DOUBLE_EQ(min.z, 0); + EXPECT_DOUBLE_EQ(max.x, 40000); + EXPECT_DOUBLE_EQ(max.z, 30000); + + std::cout << "Grid 08JE: " + << "(" << min.x << ", " << min.z << ") - (" + << max.x << ", " << max.z << ")" << std::endl; + } + + { + const auto grid = StandardMapGrid("08NA"); // N(南), A(東西) + const auto [min, max] = grid.calculateGridExtent(); + + EXPECT_DOUBLE_EQ(min.x, -160000); + EXPECT_DOUBLE_EQ(min.z, -120000); + EXPECT_DOUBLE_EQ(max.x, -120000); + EXPECT_DOUBLE_EQ(max.z, -90000); + + std::cout << "Grid 08NA: " + << "(" << min.x << ", " << min.z << ") - (" + << max.x << ", " << max.z << ")" << std::endl; + } + + { + const auto grid = StandardMapGrid("08FA"); // F(北), A(東西) + const auto [min, max] = grid.calculateGridExtent(); + + EXPECT_DOUBLE_EQ(min.x, -160000); + EXPECT_DOUBLE_EQ(min.z, 120000); + EXPECT_DOUBLE_EQ(max.x, -120000); + EXPECT_DOUBLE_EQ(max.z, 150000); + + std::cout << "Grid 08FA: " + << "(" << min.x << ", " << min.z << ") - (" + << max.x << ", " << max.z << ")" << std::endl; + } +} + +TEST(StandardMapGrid, calculateGridExtent_Level5000) { + // Level5000表面直角座標計算テスト + { + const auto grid = StandardMapGrid("08JE54"); // Level5000 + const auto [min, max] = grid.calculateGridExtent(); + + EXPECT_DOUBLE_EQ(min.x, 16000.0); + EXPECT_DOUBLE_EQ(min.z, 12000.0); + EXPECT_DOUBLE_EQ(max.x, 20000.0); + EXPECT_DOUBLE_EQ(max.z, 15000.0); + + std::cout << "\n08JE54:" << std::endl + << "(" << min.x << ", " << min.z << ") - (" << max.x << ", " << max.z << ")" << std::endl; + } + + // Level5000表面直角座標計算テスト(別のケース) + { + const auto grid = StandardMapGrid("08NA54"); // Level5000 + const auto [min, max] = grid.calculateGridExtent(); + + + EXPECT_DOUBLE_EQ(min.x, -144000.0); + EXPECT_DOUBLE_EQ(min.z, -108000.0); + EXPECT_DOUBLE_EQ(max.x, -140000.0); + EXPECT_DOUBLE_EQ(max.z, -105000.0); + + std::cout << "\n08NA54: " + << "(" << min.x << ", " << min.z << ") - (" + << max.x << ", " << max.z << ")" << std::endl; + } +} + +TEST(StandardMapGrid, calculateGridExtent_Level2500) { + { + const auto grid = StandardMapGrid("08JE541"); + const auto [min, max] = grid.calculateGridExtent(); + + EXPECT_DOUBLE_EQ(min.x, 16000.0); + EXPECT_DOUBLE_EQ(min.z, 13500.0); + EXPECT_DOUBLE_EQ(max.x, 18000.0); + EXPECT_DOUBLE_EQ(max.z, 15000.0); + + std::cout << "\n08JE54:" << std::endl + << "(" << min.x << ", " << min.z << ") - (" << max.x << ", " << max.z << ")" << std::endl; + } + + { + const auto grid = StandardMapGrid("08NA542"); + const auto [min, max] = grid.calculateGridExtent(); + + + EXPECT_DOUBLE_EQ(min.x, -142000.0); + EXPECT_DOUBLE_EQ(min.z, -106500.0); + EXPECT_DOUBLE_EQ(max.x, -140000.0); + EXPECT_DOUBLE_EQ(max.z, -105000.0); + + std::cout << "\n08NA54: " + << "(" << min.x << ", " << min.z << ") - (" + << max.x << ", " << max.z << ")" << std::endl; + } +} + +TEST(StandardMapGrid, calculateGridExtent_Level1000) { + { + const auto grid = StandardMapGrid("08JE640E"); + const auto [min, max] = grid.calculateGridExtent(); + + EXPECT_DOUBLE_EQ(min.x, 19200.0); + EXPECT_DOUBLE_EQ(min.z, 11400.0); + EXPECT_DOUBLE_EQ(max.x, 20000.0); + EXPECT_DOUBLE_EQ(max.z, 12000.0); + + std::cout << "\n08JE54:" << std::endl + << "(" << min.x << ", " << min.z << ") - (" << max.x << ", " << max.z << ")" << std::endl; + } + + { + const auto grid = StandardMapGrid("08NA542B"); + const auto [min, max] = grid.calculateGridExtent(); + + + EXPECT_DOUBLE_EQ(min.x, -143200.0); + EXPECT_DOUBLE_EQ(min.z, -106800.0); + EXPECT_DOUBLE_EQ(max.x, -142400.0); + EXPECT_DOUBLE_EQ(max.z, -106200.0); + + std::cout << "\n08NA54: " + << "(" << min.x << ", " << min.z << ") - (" + << max.x << ", " << max.z << ")" << std::endl; + } +} + + +TEST(StandardMapGrid, calculateGridExtent_Level500) { + { + const auto grid = StandardMapGrid("08JE6421"); + const auto [min, max] = grid.calculateGridExtent(); + + EXPECT_DOUBLE_EQ(min.x, 16400.0); + EXPECT_DOUBLE_EQ(min.z, 11100.0); + EXPECT_DOUBLE_EQ(max.x, 16800.0); + EXPECT_DOUBLE_EQ(max.z, 11400.0); + + std::cout << "\n08JE54:" << std::endl + << "(" << min.x << ", " << min.z << ") - (" << max.x << ", " << max.z << ")" << std::endl; + } + + { + const auto grid = StandardMapGrid("08NA5476"); + const auto [min, max] = grid.calculateGridExtent(); + + + EXPECT_DOUBLE_EQ(min.x, -141600.0); + EXPECT_DOUBLE_EQ(min.z, -107400.0); + EXPECT_DOUBLE_EQ(max.x, -141200.0); + EXPECT_DOUBLE_EQ(max.z, -107100.0); + + std::cout << "\n08NA54: " + << "(" << min.x << ", " << min.z << ") - (" + << max.x << ", " << max.z << ")" << std::endl; + } +} \ No newline at end of file From c440dc32dc9a657cf5b3b607c4b9a7d8ac159c1a Mon Sep 17 00:00:00 2001 From: yhikishima Date: Tue, 22 Apr 2025 07:30:15 +0900 Subject: [PATCH 15/19] =?UTF-8?q?fix:=E3=82=B3=E3=83=B3=E3=82=B9=E3=83=88?= =?UTF-8?q?=E3=83=A9=E3=82=AF=E3=82=BF=E3=81=A7valid=E3=81=AE=E3=83=95?= =?UTF-8?q?=E3=83=A9=E3=82=B0=E5=88=9D=E6=9C=9F=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/plateau/dataset/standard_map_grid.h | 4 ++-- src/dataset/standard_map_grid.cpp | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/plateau/dataset/standard_map_grid.h b/include/plateau/dataset/standard_map_grid.h index 26bfa997..11657736 100644 --- a/include/plateau/dataset/standard_map_grid.h +++ b/include/plateau/dataset/standard_map_grid.h @@ -15,7 +15,7 @@ namespace plateau::dataset { */ class LIBPLATEAU_EXPORT StandardMapGrid : public GridCode { public: - explicit StandardMapGrid(std::string code); + explicit StandardMapGrid(std::string code, bool is_valid); StandardMapGrid() = default; /** @@ -62,7 +62,7 @@ namespace plateau::dataset { private: std::string code_; // 図郭コード - bool is_valid_ = true; // コードが有効かどうか + bool is_valid_ = false; // コードが有効かどうか StandardMapGridLevel level_; int coordinate_origin_; // 原点 diff --git a/src/dataset/standard_map_grid.cpp b/src/dataset/standard_map_grid.cpp index dfdb5bf8..05ee3c6d 100644 --- a/src/dataset/standard_map_grid.cpp +++ b/src/dataset/standard_map_grid.cpp @@ -96,7 +96,8 @@ namespace plateau::dataset { } } - StandardMapGrid::StandardMapGrid(std::string code) : code_(std::move(code)) { + StandardMapGrid::StandardMapGrid(std::string code, bool is_valid = true) : + code_(std::move(code)), is_valid_(is_valid) { try { // 図郭コードの文字列が数字とアルファベットからなることをチェックします。 if (!std::all_of(code_.begin(), code_.end(), [](char c) From 00dd41b0fc17cbc95f46f69b27af068a65c373c1 Mon Sep 17 00:00:00 2001 From: yhikishima Date: Tue, 22 Apr 2025 07:32:19 +0900 Subject: [PATCH 16/19] =?UTF-8?q?fix:test=E3=81=AEcmakelist=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c98a391f..4ca91885 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -30,7 +30,6 @@ add_executable(plateau_test "test_mesh_extractor.cpp" "test_grid_merger.cpp" "test_mesh_code.cpp" - "test_dataset.cpp" "test_vector_tile.cpp" "test_obj_writer.cpp" "test_gltf_writer.cpp" From c5e8545c31a624a6ae4b6fe7cc2e4499b8fc2edc Mon Sep 17 00:00:00 2001 From: yhikishima Date: Tue, 22 Apr 2025 08:21:17 +0900 Subject: [PATCH 17/19] =?UTF-8?q?fix:=E3=82=B3=E3=83=BC=E3=83=89=E3=83=AC?= =?UTF-8?q?=E3=83=93=E3=83=A5=E3=83=BC=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/plateau/dataset/standard_map_grid.h | 14 +++- src/dataset/standard_map_grid.cpp | 48 +++-------- test/test_standard_map_grid.cpp | 93 ++++++++++----------- 3 files changed, 68 insertions(+), 87 deletions(-) diff --git a/include/plateau/dataset/standard_map_grid.h b/include/plateau/dataset/standard_map_grid.h index 11657736..a6ec0228 100644 --- a/include/plateau/dataset/standard_map_grid.h +++ b/include/plateau/dataset/standard_map_grid.h @@ -7,7 +7,17 @@ #include "plateau/dataset/grid_code.h" namespace plateau::dataset { - enum class StandardMapGridLevel; + + enum class StandardMapGridLevel + { + Invalid = -1, + Level50000 = 0, + Level5000 = 1, + Level2500 = 2, + Level1000 = 3, + Level500 = 4, + }; + /** * \brief 国土基本図図郭を表します。 * @@ -15,7 +25,7 @@ namespace plateau::dataset { */ class LIBPLATEAU_EXPORT StandardMapGrid : public GridCode { public: - explicit StandardMapGrid(std::string code, bool is_valid); + explicit StandardMapGrid(std::string code); StandardMapGrid() = default; /** diff --git a/src/dataset/standard_map_grid.cpp b/src/dataset/standard_map_grid.cpp index 05ee3c6d..bb0e15d0 100644 --- a/src/dataset/standard_map_grid.cpp +++ b/src/dataset/standard_map_grid.cpp @@ -9,16 +9,6 @@ namespace plateau::dataset { - enum class StandardMapGridLevel - { - Invalid = -1, - Level50000 = 0, - Level5000 = 1, - Level2500 = 2, - Level1000 = 3, - Level500 = 4, - }; - namespace { constexpr int level5000_division_count = 10; constexpr int level2500_division_count = 2; @@ -96,13 +86,14 @@ namespace plateau::dataset { } } - StandardMapGrid::StandardMapGrid(std::string code, bool is_valid = true) : - code_(std::move(code)), is_valid_(is_valid) { + StandardMapGrid::StandardMapGrid(std::string code) : code_(std::move(code)) { try { + is_valid_ = true; + // 図郭コードの文字列が数字とアルファベットからなることをチェックします。 if (!std::all_of(code_.begin(), code_.end(), [](char c) { - return std::isalnum(c); + return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z'); })) { is_valid_ = false; return; @@ -282,31 +273,16 @@ namespace plateau::dataset { } GridCode* StandardMapGrid::upperRaw() const { - auto* new_grid = new StandardMapGrid(code_); - - switch (level_) { - case StandardMapGridLevel::Level500: - case StandardMapGridLevel::Level1000: - case StandardMapGridLevel::Level2500: - // 6桁のLevel5000コードにする(末尾を削除) - new_grid->code_ = code_.substr(0, 6); - new_grid->level_ = StandardMapGridLevel::Level5000; - break; - - case StandardMapGridLevel::Level5000: - // 4桁のLevel50000コードにする(末尾を削除) - new_grid->code_ = code_.substr(0, 4); - new_grid->level_ = StandardMapGridLevel::Level50000; - break; - - case StandardMapGridLevel::Level50000: - default: - // 不正なレベルの場合も無効にする - new_grid->is_valid_ = false; - break; + if (level_ == StandardMapGridLevel::Level50000) { + auto* new_grid = new StandardMapGrid(code_); + new_grid->is_valid_ = false; + return new_grid; } - return new_grid; + const std::string upper_code = level_ > StandardMapGridLevel::Level5000 + ? code_.substr(0, 6) + : code_.substr(0, 4); + return new StandardMapGrid(upper_code); } int StandardMapGrid::getLevel() const { diff --git a/test/test_standard_map_grid.cpp b/test/test_standard_map_grid.cpp index 22fcad43..f2ed922a 100644 --- a/test/test_standard_map_grid.cpp +++ b/test/test_standard_map_grid.cpp @@ -168,10 +168,10 @@ TEST(StandardMapGrid, calculateGridExtent_Level50000) { const auto grid = StandardMapGrid("08JE"); const auto [min, max] = grid.calculateGridExtent(); - EXPECT_DOUBLE_EQ(min.x, 0); - EXPECT_DOUBLE_EQ(min.z, 0); - EXPECT_DOUBLE_EQ(max.x, 40000); - EXPECT_DOUBLE_EQ(max.z, 30000); + EXPECT_NEAR(min.x, 0, 0.1); + EXPECT_NEAR(min.z, 0, 0.1); + EXPECT_NEAR(max.x, 40000, 0.1); + EXPECT_NEAR(max.z, 30000, 0.1); std::cout << "Grid 08JE: " << "(" << min.x << ", " << min.z << ") - (" @@ -182,10 +182,10 @@ TEST(StandardMapGrid, calculateGridExtent_Level50000) { const auto grid = StandardMapGrid("08NA"); // N(南), A(東西) const auto [min, max] = grid.calculateGridExtent(); - EXPECT_DOUBLE_EQ(min.x, -160000); - EXPECT_DOUBLE_EQ(min.z, -120000); - EXPECT_DOUBLE_EQ(max.x, -120000); - EXPECT_DOUBLE_EQ(max.z, -90000); + EXPECT_NEAR(min.x, -160000, 0.1); + EXPECT_NEAR(min.z, -120000, 0.1); + EXPECT_NEAR(max.x, -120000, 0.1); + EXPECT_NEAR(max.z, -90000, 0.1); std::cout << "Grid 08NA: " << "(" << min.x << ", " << min.z << ") - (" @@ -196,10 +196,10 @@ TEST(StandardMapGrid, calculateGridExtent_Level50000) { const auto grid = StandardMapGrid("08FA"); // F(北), A(東西) const auto [min, max] = grid.calculateGridExtent(); - EXPECT_DOUBLE_EQ(min.x, -160000); - EXPECT_DOUBLE_EQ(min.z, 120000); - EXPECT_DOUBLE_EQ(max.x, -120000); - EXPECT_DOUBLE_EQ(max.z, 150000); + EXPECT_NEAR(min.x, -160000, 0.1); + EXPECT_NEAR(min.z, 120000, 0.1); + EXPECT_NEAR(max.x, -120000, 0.1); + EXPECT_NEAR(max.z, 150000, 0.1); std::cout << "Grid 08FA: " << "(" << min.x << ", " << min.z << ") - (" @@ -213,10 +213,10 @@ TEST(StandardMapGrid, calculateGridExtent_Level5000) { const auto grid = StandardMapGrid("08JE54"); // Level5000 const auto [min, max] = grid.calculateGridExtent(); - EXPECT_DOUBLE_EQ(min.x, 16000.0); - EXPECT_DOUBLE_EQ(min.z, 12000.0); - EXPECT_DOUBLE_EQ(max.x, 20000.0); - EXPECT_DOUBLE_EQ(max.z, 15000.0); + EXPECT_NEAR(min.x, 16000.0, 0.1); + EXPECT_NEAR(min.z, 12000.0, 0.1); + EXPECT_NEAR(max.x, 20000.0, 0.1); + EXPECT_NEAR(max.z, 15000.0, 0.1); std::cout << "\n08JE54:" << std::endl << "(" << min.x << ", " << min.z << ") - (" << max.x << ", " << max.z << ")" << std::endl; @@ -227,11 +227,10 @@ TEST(StandardMapGrid, calculateGridExtent_Level5000) { const auto grid = StandardMapGrid("08NA54"); // Level5000 const auto [min, max] = grid.calculateGridExtent(); - - EXPECT_DOUBLE_EQ(min.x, -144000.0); - EXPECT_DOUBLE_EQ(min.z, -108000.0); - EXPECT_DOUBLE_EQ(max.x, -140000.0); - EXPECT_DOUBLE_EQ(max.z, -105000.0); + EXPECT_NEAR(min.x, -144000.0, 0.1); + EXPECT_NEAR(min.z, -108000.0, 0.1); + EXPECT_NEAR(max.x, -140000.0, 0.1); + EXPECT_NEAR(max.z, -105000.0, 0.1); std::cout << "\n08NA54: " << "(" << min.x << ", " << min.z << ") - (" @@ -244,10 +243,10 @@ TEST(StandardMapGrid, calculateGridExtent_Level2500) { const auto grid = StandardMapGrid("08JE541"); const auto [min, max] = grid.calculateGridExtent(); - EXPECT_DOUBLE_EQ(min.x, 16000.0); - EXPECT_DOUBLE_EQ(min.z, 13500.0); - EXPECT_DOUBLE_EQ(max.x, 18000.0); - EXPECT_DOUBLE_EQ(max.z, 15000.0); + EXPECT_NEAR(min.x, 16000.0, 0.1); + EXPECT_NEAR(min.z, 13500.0, 0.1); + EXPECT_NEAR(max.x, 18000.0, 0.1); + EXPECT_NEAR(max.z, 15000.0, 0.1); std::cout << "\n08JE54:" << std::endl << "(" << min.x << ", " << min.z << ") - (" << max.x << ", " << max.z << ")" << std::endl; @@ -257,11 +256,10 @@ TEST(StandardMapGrid, calculateGridExtent_Level2500) { const auto grid = StandardMapGrid("08NA542"); const auto [min, max] = grid.calculateGridExtent(); - - EXPECT_DOUBLE_EQ(min.x, -142000.0); - EXPECT_DOUBLE_EQ(min.z, -106500.0); - EXPECT_DOUBLE_EQ(max.x, -140000.0); - EXPECT_DOUBLE_EQ(max.z, -105000.0); + EXPECT_NEAR(min.x, -142000.0, 0.1); + EXPECT_NEAR(min.z, -106500.0, 0.1); + EXPECT_NEAR(max.x, -140000.0, 0.1); + EXPECT_NEAR(max.z, -105000.0, 0.1); std::cout << "\n08NA54: " << "(" << min.x << ", " << min.z << ") - (" @@ -274,10 +272,10 @@ TEST(StandardMapGrid, calculateGridExtent_Level1000) { const auto grid = StandardMapGrid("08JE640E"); const auto [min, max] = grid.calculateGridExtent(); - EXPECT_DOUBLE_EQ(min.x, 19200.0); - EXPECT_DOUBLE_EQ(min.z, 11400.0); - EXPECT_DOUBLE_EQ(max.x, 20000.0); - EXPECT_DOUBLE_EQ(max.z, 12000.0); + EXPECT_NEAR(min.x, 19200.0, 0.1); + EXPECT_NEAR(min.z, 11400.0, 0.1); + EXPECT_NEAR(max.x, 20000.0, 0.1); + EXPECT_NEAR(max.z, 12000.0, 0.1); std::cout << "\n08JE54:" << std::endl << "(" << min.x << ", " << min.z << ") - (" << max.x << ", " << max.z << ")" << std::endl; @@ -287,11 +285,10 @@ TEST(StandardMapGrid, calculateGridExtent_Level1000) { const auto grid = StandardMapGrid("08NA542B"); const auto [min, max] = grid.calculateGridExtent(); - - EXPECT_DOUBLE_EQ(min.x, -143200.0); - EXPECT_DOUBLE_EQ(min.z, -106800.0); - EXPECT_DOUBLE_EQ(max.x, -142400.0); - EXPECT_DOUBLE_EQ(max.z, -106200.0); + EXPECT_NEAR(min.x, -143200.0, 0.1); + EXPECT_NEAR(min.z, -106800.0, 0.1); + EXPECT_NEAR(max.x, -142400.0, 0.1); + EXPECT_NEAR(max.z, -106200.0, 0.1); std::cout << "\n08NA54: " << "(" << min.x << ", " << min.z << ") - (" @@ -299,16 +296,15 @@ TEST(StandardMapGrid, calculateGridExtent_Level1000) { } } - TEST(StandardMapGrid, calculateGridExtent_Level500) { { const auto grid = StandardMapGrid("08JE6421"); const auto [min, max] = grid.calculateGridExtent(); - EXPECT_DOUBLE_EQ(min.x, 16400.0); - EXPECT_DOUBLE_EQ(min.z, 11100.0); - EXPECT_DOUBLE_EQ(max.x, 16800.0); - EXPECT_DOUBLE_EQ(max.z, 11400.0); + EXPECT_NEAR(min.x, 16400.0, 0.1); + EXPECT_NEAR(min.z, 11100.0, 0.1); + EXPECT_NEAR(max.x, 16800.0, 0.1); + EXPECT_NEAR(max.z, 11400.0, 0.1); std::cout << "\n08JE54:" << std::endl << "(" << min.x << ", " << min.z << ") - (" << max.x << ", " << max.z << ")" << std::endl; @@ -318,11 +314,10 @@ TEST(StandardMapGrid, calculateGridExtent_Level500) { const auto grid = StandardMapGrid("08NA5476"); const auto [min, max] = grid.calculateGridExtent(); - - EXPECT_DOUBLE_EQ(min.x, -141600.0); - EXPECT_DOUBLE_EQ(min.z, -107400.0); - EXPECT_DOUBLE_EQ(max.x, -141200.0); - EXPECT_DOUBLE_EQ(max.z, -107100.0); + EXPECT_NEAR(min.x, -141600.0, 0.1); + EXPECT_NEAR(min.z, -107400.0, 0.1); + EXPECT_NEAR(max.x, -141200.0, 0.1); + EXPECT_NEAR(max.z, -107100.0, 0.1); std::cout << "\n08NA54: " << "(" << min.x << ", " << min.z << ") - (" From 2804e866bb6c0bc9a506b3f38bd82e47ee740a59 Mon Sep 17 00:00:00 2001 From: yhikishima Date: Tue, 22 Apr 2025 08:27:02 +0900 Subject: [PATCH 18/19] =?UTF-8?q?fix:=E3=82=B3=E3=83=A1=E3=83=B3=E3=83=88?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/test_standard_map_grid.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_standard_map_grid.cpp b/test/test_standard_map_grid.cpp index f2ed922a..9bf9fd42 100644 --- a/test/test_standard_map_grid.cpp +++ b/test/test_standard_map_grid.cpp @@ -74,7 +74,7 @@ TEST(StandardMapGrid, Level5000_WithinBounds) { } TEST(StandardMapGrid, Level2500_WithinBounds) { - const auto extent = StandardMapGrid("08EE554").getExtent(); // Level2500 + const auto extent = StandardMapGrid("08EE554").getExtent(); const auto expected = GeoCoordinate(37.4669, 138.7544, 0); std::stringstream ss; @@ -91,7 +91,7 @@ TEST(StandardMapGrid, Level2500_WithinBounds) { } TEST(StandardMapGrid, Level1000_WithinBounds) { - const auto extent = StandardMapGrid("08JE640E").getExtent(); // Level2500 + const auto extent = StandardMapGrid("08JE640E").getExtent(); const auto expected = GeoCoordinate(36.1053, 138.7151, 0); std::stringstream ss; From a967910020a464e24bb6ceacfe09d66316739303 Mon Sep 17 00:00:00 2001 From: yhikishima Date: Tue, 22 Apr 2025 16:33:28 +0900 Subject: [PATCH 19/19] =?UTF-8?q?fix:c#=E3=81=AE=E3=83=86=E3=82=B9?= =?UTF-8?q?=E3=83=88=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CSharpPLATEAU.Test/Dataset/DatasetAccessorTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetAccessorTest.cs b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetAccessorTest.cs index d2eefb96..6765f875 100644 --- a/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetAccessorTest.cs +++ b/wrappers/csharp/LibPLATEAU.NET/CSharpPLATEAU.Test/Dataset/DatasetAccessorTest.cs @@ -165,8 +165,8 @@ private static void TestCenterPoint(DatasetSource source) // テスト用のデータは、基準点からおおむね南に50km, 西に5km の地点にあります。 // ここでいう基準点とは、下のWebサイトにおける 9番の地点です。 // https://www.gsi.go.jp/sokuchikijun/jpc.html - Assert.IsTrue(Math.Abs(center.Z - /*(-51000)*/(-369082/*国土基本図の図郭を実装するまでの一時的な値*/)) < 2000, "南に51km"); // Local と Server で値がちょっと違うので2kmの誤差猶予を持たせます。 - Assert.IsTrue(Math.Abs(center.X - /*(-9000))*/(-5132542)/*国土基本図の図郭を実装するまでの一時的な値*/) < 5000, "西に9km"); + Assert.IsTrue(Math.Abs(center.Z - 18000) < 2000, "北に18km"); // Local と Server で値がちょっと違うので2kmの誤差猶予を持たせます。 + Assert.IsTrue(Math.Abs(center.X - (-37000)) < 5000, "西に37km"); }