Skip to content

Commit dbd1d75

Browse files
committed
1 parent b7c9a1b commit dbd1d75

1 file changed

Lines changed: 25 additions & 33 deletions

File tree

‎src/polygon_mesh/map_attacher.cpp‎

Lines changed: 25 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <plateau/texture/texture_image_base.h>
44
#include <plateau/texture/texture_packer.h>
55
#include <cassert>
6+
#include <cmath>
67

78
namespace plateau::polygonMesh {
89
namespace fs = std::filesystem;
@@ -11,38 +12,34 @@ namespace plateau::polygonMesh {
1112
namespace {
1213

1314

14-
/// 地図タイルを貼り付ける準備として、メッシュにUVを設定します。
15-
/// まず、UVを0を最小、1を最大と仮定して計算します。
16-
/// 頂点の高さは考慮しません。
17-
/// 次に、UVの最小から最大の範囲について、(0,0)から(1,1)の範囲を変換してuv_minからuv_maxの範囲に投影します。
18-
void setUVForMap(Mesh& mesh, const TVec3d bounding_box_min_arg, const TVec3d bounding_box_max_arg, const GeoReference& geo_ref, const TVec2f uv_min, const TVec2f uv_max) { // NOLINT(performance-unnecessary-value-param)
15+
/// ウェブメルカトルの南北成分です。緯度が高いほど大きくなります。
16+
/// 地理院タイルの Y 計算(TileProjection)と同じ投影です。
17+
double webMercatorY(const double latitude_deg) {
18+
constexpr double deg_to_rad = 0.017453292519943295;
19+
const double lat_rad = latitude_deg * deg_to_rad;
20+
return std::asinh(std::tan(lat_rad));
21+
}
22+
23+
/// 結合した地図タイル画像へ、頂点ごとのUVを設定します。
24+
/// 画像の西端が U=0、東端が U=1、南端が V=0、北端が V=1 です。
25+
/// 経度はタイル上で線形、緯度はウェブメルカトルです。
26+
/// メッシュの外接矩形で線形補間すると、3次メッシュ境界の同じ頂点が隣のメッシュと別の画素を指します。
27+
void setUVForMap(Mesh& mesh, const GeoReference& geo_ref, const Extent& image_extent) {
1928
const auto& vertices = mesh.getVertices();
2029
const auto vertices_count = vertices.size();
2130
auto uv = std::vector<TVec2f>();
2231
uv.reserve(vertices_count);
23-
auto min = geo_ref.convertAxisToENU(bounding_box_min_arg);
24-
auto max = geo_ref.convertAxisToENU(bounding_box_max_arg);
2532

26-
// 座標変換後に大小関係逆転することがあるため修正
27-
const auto tmp = min;
28-
min.x = std::min(tmp.x, max.x);
29-
min.y = std::min(tmp.y, max.y);
30-
min.z = std::min(tmp.z, max.z);
31-
max.x = std::max(tmp.x, max.x);
32-
max.y = std::max(tmp.y, max.y);
33-
max.z = std::max(tmp.z, max.z);
34-
35-
const auto diff = max - min;
36-
const auto size2d = TVec2d(diff.x, diff.y);
37-
// const auto size_longer = std::max(size2d.x, size2d.y); // 縦と横のうち長い方の長さを採用します。非正方形の地形でテクスチャが引き伸ばされることを防ぎます。
33+
const auto longitude_min = image_extent.min.longitude;
34+
const auto longitude_span = image_extent.max.longitude - longitude_min;
35+
const auto mercator_south = webMercatorY(image_extent.min.latitude);
36+
const auto mercator_span = webMercatorY(image_extent.max.latitude) - mercator_south;
37+
3838
for(int i=0; i<vertices_count; i++) {
39-
const auto v_with_src_axis = vertices.at(i);
40-
const auto v = GeoReference::convertAxisToENU(geo_ref.getCoordinateSystem(), v_with_src_axis);
41-
const auto uv_x_norm = (float)((v.x - min.x) / size2d.x);
42-
const auto uv_y_norm = (float)((v.y - min.y) / size2d.y);
43-
const auto uv_norm = TVec2f(uv_x_norm, uv_y_norm);
44-
const auto uv_corrected = uv_min + uv_norm * (uv_max - uv_min);
45-
uv.push_back(uv_corrected);
39+
const auto geo = geo_ref.unproject(vertices.at(i));
40+
const auto uv_x = static_cast<float>((geo.longitude - longitude_min) / longitude_span);
41+
const auto uv_y = static_cast<float>((webMercatorY(geo.latitude) - mercator_south) / mercator_span);
42+
uv.push_back(TVec2f(uv_x, uv_y));
4643
}
4744
mesh.setUV1(std::move(uv));
4845
}
@@ -148,13 +145,8 @@ namespace plateau::polygonMesh {
148145
}
149146
packer.flush();
150147

151-
// 緯度経度を計算します。
152-
const auto image_extent = tiles.extent();
153-
const auto mesh_uv_min = image_extent.uvAt(extent.min);
154-
const auto mesh_uv_max = image_extent.uvAt(extent.max);
155-
156-
// UVを貼ります。
157-
setUVForMap(*mesh, min, max, geo_reference, mesh_uv_min, mesh_uv_max);
148+
// 結合画像の範囲へ、頂点ごとにUVを貼ります。
149+
setUVForMap(*mesh, geo_reference, tiles.extent());
158150

159151
// テクスチャを結合後の地図タイルにします。
160152
for(auto& sub_mesh : mesh->getSubMeshes()) {

0 commit comments

Comments
 (0)