33#include < plateau/texture/texture_image_base.h>
44#include < plateau/texture/texture_packer.h>
55#include < cassert>
6+ #include < cmath>
67
78namespace 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