diff --git a/.gitignore b/.gitignore index ccde4ca..b3fcc4e 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,5 @@ build vsxmake* app vcpkg_installed -build \ No newline at end of file +build +binary \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 7422c5d..05a9475 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required (VERSION 3.10) -project(Cesium3DTilesConverter VERSION 3.0.0) +project(Cesium3DTilesConverter VERSION 3.1.0) set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) diff --git a/README.md b/README.md index 5559ec4..6c516f1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # About Project -基于C++17、Qt5的3DTiles转换工具。 +基于C++17、Qt5的3DTiles转换工具, 全网支持唯一根节点合并的开源工具 # 简介 @@ -23,16 +23,17 @@ Converter -f [OPTIONS] ```sh # from osgb dataset -Converter -f OSGB -i -o +Converter -f OSGB -m true -i -o ``` ## 参数说明 ``` Options: - -?, -h, --help displays help on commandline options. - -f, --format OSGB or Vector(required), OSGB 为倾斜摄影格式数据, Vector为GDAL支持的面(Polygon)数据 - -i, --input 输入数据的目录,OSGB数据截止到 `/Data` 目录的上一级,GDAL参考GDAL数据格式。 - -o, --ouput 输出目录。OSGB转换的3DTiles输出的数据文件位于 /Data`目录, GDAL转换的3DTiles输出的数据文件位于/Tile目录,tileset.json位于根目录。 + -?, -h, --help displays help on commandline options. + -f, --format OSGB or Vector(required), OSGB 为倾斜摄影格式数据, Vector为GDAL支持的面(Polygon)数据 + -m, --merge 根节点合并开关选项 + -i, --input 输入数据的目录,OSGB数据截止到 `/Data` 目录的上一级,GDAL参考GDAL数据格式。 + -o, --ouput 输出目录。OSGB转换的3DTiles输出的数据文件位于 /Data`目录, GDAL转换的3DTiles输出的数据文件位于/Tile目录,tileset.json位于根目录。 ``` # 数据要求及说明 @@ -68,7 +69,7 @@ Options: # TODO 1. 目前只迁移了OSGB的转换转换工作,后面进行GDAL转换代码迁移 -2. 根节点合并 +2. 初步实现了根节点合并,目前只做到了Vertex简化,后面加入纹理简化 # Reference 1. 3dtiles specification [https://github.com/CesiumGS/3d-tiles](https://github.com/CesiumGS/3d-tiles) \ No newline at end of file diff --git a/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014.osgb b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014.osgb new file mode 100644 index 0000000..8f1b5cd Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L15_0u.osgb b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L15_0u.osgb new file mode 100644 index 0000000..7674026 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L15_0u.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L16_0uu.osgb b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L16_0uu.osgb new file mode 100644 index 0000000..77b0d06 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L16_0uu.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L17_0uuu.osgb b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L17_0uuu.osgb new file mode 100644 index 0000000..a63823a Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L17_0uuu.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L18_0uuuu.osgb b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L18_0uuuu.osgb new file mode 100644 index 0000000..c766c29 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L18_0uuuu.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L19_0uuuu0.osgb b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L19_0uuuu0.osgb new file mode 100644 index 0000000..77551b8 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L19_0uuuu0.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L19_0uuuu1.osgb b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L19_0uuuu1.osgb new file mode 100644 index 0000000..a319e67 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L19_0uuuu1.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L19_0uuuu2.osgb b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L19_0uuuu2.osgb new file mode 100644 index 0000000..de270f9 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L19_0uuuu2.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L19_0uuuu3.osgb b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L19_0uuuu3.osgb new file mode 100644 index 0000000..8eecd5a Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L19_0uuuu3.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L19_0uuuu4.osgb b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L19_0uuuu4.osgb new file mode 100644 index 0000000..4388c8e Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L19_0uuuu4.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L19_0uuuu5.osgb b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L19_0uuuu5.osgb new file mode 100644 index 0000000..2462b4f Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L19_0uuuu5.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L19_0uuuu6.osgb b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L19_0uuuu6.osgb new file mode 100644 index 0000000..1941a20 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L19_0uuuu6.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L19_0uuuu7.osgb b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L19_0uuuu7.osgb new file mode 100644 index 0000000..96a5ee1 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+014/Tile_+000_+014_L19_0uuuu7.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015.osgb b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015.osgb new file mode 100644 index 0000000..f7b368b Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L15_0u.osgb b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L15_0u.osgb new file mode 100644 index 0000000..feebded Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L15_0u.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L16_0uu.osgb b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L16_0uu.osgb new file mode 100644 index 0000000..2b9532e Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L16_0uu.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L17_0uuu.osgb b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L17_0uuu.osgb new file mode 100644 index 0000000..8b0cf99 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L17_0uuu.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L18_0uuuu.osgb b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L18_0uuuu.osgb new file mode 100644 index 0000000..f453de1 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L18_0uuuu.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L19_0uuuu0.osgb b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L19_0uuuu0.osgb new file mode 100644 index 0000000..2d9c4e3 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L19_0uuuu0.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L19_0uuuu1.osgb b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L19_0uuuu1.osgb new file mode 100644 index 0000000..552bd48 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L19_0uuuu1.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L19_0uuuu2.osgb b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L19_0uuuu2.osgb new file mode 100644 index 0000000..f2b9159 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L19_0uuuu2.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L19_0uuuu3.osgb b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L19_0uuuu3.osgb new file mode 100644 index 0000000..8ec5ebb Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L19_0uuuu3.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L19_0uuuu4.osgb b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L19_0uuuu4.osgb new file mode 100644 index 0000000..6a4e25e Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L19_0uuuu4.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L19_0uuuu5.osgb b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L19_0uuuu5.osgb new file mode 100644 index 0000000..517ac70 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L19_0uuuu5.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L19_0uuuu6.osgb b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L19_0uuuu6.osgb new file mode 100644 index 0000000..ea46cf0 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L19_0uuuu6.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L19_0uuuu7.osgb b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L19_0uuuu7.osgb new file mode 100644 index 0000000..5a70615 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+015/Tile_+000_+015_L19_0uuuu7.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016.osgb b/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016.osgb new file mode 100644 index 0000000..5688d4c Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016_L15_0u.osgb b/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016_L15_0u.osgb new file mode 100644 index 0000000..07a24c1 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016_L15_0u.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016_L16_0uu.osgb b/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016_L16_0uu.osgb new file mode 100644 index 0000000..5566683 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016_L16_0uu.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016_L17_0uuu.osgb b/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016_L17_0uuu.osgb new file mode 100644 index 0000000..3dbd9da Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016_L17_0uuu.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016_L18_0uuuu.osgb b/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016_L18_0uuuu.osgb new file mode 100644 index 0000000..039e11b Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016_L18_0uuuu.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016_L19_0uuuu0.osgb b/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016_L19_0uuuu0.osgb new file mode 100644 index 0000000..abaf5b5 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016_L19_0uuuu0.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016_L19_0uuuu1.osgb b/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016_L19_0uuuu1.osgb new file mode 100644 index 0000000..17658a7 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016_L19_0uuuu1.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016_L19_0uuuu2.osgb b/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016_L19_0uuuu2.osgb new file mode 100644 index 0000000..880f678 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016_L19_0uuuu2.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016_L19_0uuuu3.osgb b/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016_L19_0uuuu3.osgb new file mode 100644 index 0000000..a5c1cd1 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+016/Tile_+000_+016_L19_0uuuu3.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017.osgb b/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017.osgb new file mode 100644 index 0000000..697d089 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017_L15_0u.osgb b/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017_L15_0u.osgb new file mode 100644 index 0000000..00afcd1 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017_L15_0u.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017_L16_0uu.osgb b/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017_L16_0uu.osgb new file mode 100644 index 0000000..7688167 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017_L16_0uu.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017_L17_0uuu.osgb b/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017_L17_0uuu.osgb new file mode 100644 index 0000000..b03123b Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017_L17_0uuu.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017_L18_0uuuu.osgb b/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017_L18_0uuuu.osgb new file mode 100644 index 0000000..cf3a031 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017_L18_0uuuu.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017_L19_0uuuu0.osgb b/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017_L19_0uuuu0.osgb new file mode 100644 index 0000000..3e149bb Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017_L19_0uuuu0.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017_L19_0uuuu1.osgb b/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017_L19_0uuuu1.osgb new file mode 100644 index 0000000..404adb2 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017_L19_0uuuu1.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017_L19_0uuuu2.osgb b/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017_L19_0uuuu2.osgb new file mode 100644 index 0000000..d762459 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017_L19_0uuuu2.osgb differ diff --git a/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017_L19_0uuuu3.osgb b/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017_L19_0uuuu3.osgb new file mode 100644 index 0000000..8fd7140 Binary files /dev/null and b/data/Production_5/Data/Tile_+000_+017/Tile_+000_+017_L19_0uuuu3.osgb differ diff --git a/data/Production_5/metadata.xml b/data/Production_5/metadata.xml index 283fae2..81d2ff8 100644 --- a/data/Production_5/metadata.xml +++ b/data/Production_5/metadata.xml @@ -1,7 +1,7 @@ - PROJCS["ZS7CCGCS2000 / 3-degree Gauss-Kruger CM 113.22E", + PROJCS["LOCAL0 / 3-degree Gauss-Kruger CM 113.36E", GEOGCS["China Geodetic Coordinate System 2000", DATUM["China_2000", SPHEROID["CGCS2000",6378137,298.257222101, @@ -14,7 +14,7 @@ AUTHORITY["EPSG","4490"]], PROJECTION["Transverse_Mercator"], PARAMETER["latitude_of_origin",0], - PARAMETER["central_meridian",113.366666666666666666666667], + PARAMETER["central_meridian",113.37], PARAMETER["scale_factor",1], PARAMETER["false_easting",500000], PARAMETER["false_northing",90], diff --git a/include/CesiumGLTF/CesiumB3DM.h b/include/CesiumGLTF/CesiumB3DM.h index 2503b0a..53dbee4 100644 --- a/include/CesiumGLTF/CesiumB3DM.h +++ b/include/CesiumGLTF/CesiumB3DM.h @@ -17,7 +17,7 @@ namespace scially { osg::Vec3d center; QList meshes; private: - void toB3DM(const QByteArray& glb, QByteArray& buffer) const; + QByteArray toB3DM(const QByteArray& glb) const; }; } diff --git a/include/Commons/OSGSimplify.h b/include/Commons/OSGSimplify.h new file mode 100644 index 0000000..91e6bed --- /dev/null +++ b/include/Commons/OSGSimplify.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +namespace scially { + class OSGSimplify { + public: + OSGSimplify(osg::Node& node) : mNode(node), mSNode(new osg::Group) { + + } + + bool simplify(double ratio); + + osg::ref_ptr node() { + return mSNode; + } + + private: + osg::ref_ptr mSNode; + osg::Node& mNode; + }; +} diff --git a/include/Commons/TileStorage.h b/include/Commons/TileStorage.h index 8c7d7c7..450c064 100644 --- a/include/Commons/TileStorage.h +++ b/include/Commons/TileStorage.h @@ -15,10 +15,10 @@ namespace scially { static TileStorage::Ptr create(const QUrl& path); virtual bool init() { return true; } - virtual bool saveJson(const QString& file, const QJsonObject& content) = 0; - virtual bool saveFile(const QString& file, const QByteArray& content) = 0; + virtual bool saveJson(const QString& file, const QJsonObject& content) const = 0; + virtual bool saveFile(const QString& file, const QByteArray& content) const = 0; - virtual bool exists(const QString& file) { + virtual bool exists(const QString& file) const{ return false; } }; diff --git a/include/Commons/TileStorageDisk.h b/include/Commons/TileStorageDisk.h index e6d0550..62cf4e9 100644 --- a/include/Commons/TileStorageDisk.h +++ b/include/Commons/TileStorageDisk.h @@ -9,13 +9,13 @@ namespace scially { TileStorageDisk(const QString& folder) : mFolder(folder) {} - virtual bool saveJson(const QString& file, const QJsonObject& content) override; - virtual bool saveFile(const QString& file, const QByteArray& content) override; + virtual bool saveJson(const QString& file, const QJsonObject& content) const override; + virtual bool saveFile(const QString& file, const QByteArray& content) const override; - virtual bool exists(const QString& file) override; + virtual bool exists(const QString& file) const override; private: - QString cleanPath(const QString& path); - bool ensurePath(const QString& path); + QString cleanPath(const QString& path) const; + bool ensurePath(const QString& path) const; QString mFolder; }; diff --git a/include/Commons/Version.h b/include/Commons/Version.h index 4bac47a..7886122 100644 --- a/include/Commons/Version.h +++ b/include/Commons/Version.h @@ -1,8 +1,8 @@ #pragma once #define SCIALLY_PROJECT_VERSION_MAJOR 3 -#define SCIALLY_PROJECT_VERSION_MINOR 0 +#define SCIALLY_PROJECT_VERSION_MINOR 1 #define SCIALLY_PROJECT_VERSION_PATCH 0 -constexpr const char* SCIALLY_PROJECT_VERSION = "3.0.0"; +constexpr const char* SCIALLY_PROJECT_VERSION = "3.1.0"; constexpr const char* SCIALLY_PROJECT_NAME = "Cesium3DTilesConverter"; diff --git a/include/ConvertApp/CLIParse.h b/include/ConvertApp/CLIParse.h index a2b96d8..ac8ae78 100644 --- a/include/ConvertApp/CLIParse.h +++ b/include/ConvertApp/CLIParse.h @@ -17,6 +17,7 @@ namespace scially { Format format; QString input; QString output; + bool mergeTop = false; CLIParse() { mParser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions); @@ -31,6 +32,10 @@ namespace scially { QStringList() << "f" << "format", "OSGB or Vector(required)", "format" }, + { + QStringList() << "m" << "merge", + "OSGB Top Merge", "top merge", "false" + }, { QStringList() << "i" << "input", "data input(required)", "input" @@ -70,6 +75,9 @@ namespace scially { private: bool parseOSGB() { + if (mParser.isSet("merge")) { + mergeTop = mParser.value("merge") == "true"; + } return parseIO(); } diff --git a/include/OSGConvert/OSGFolder.h b/include/OSGConvert/OSGFolder.h index 25ff4e6..a41fb5c 100644 --- a/include/OSGConvert/OSGFolder.h +++ b/include/OSGConvert/OSGFolder.h @@ -14,13 +14,16 @@ namespace scially { public: bool load(const OSGConvertOption& options); bool toB3DMPerTile(const OSGConvertOption& options); + bool mergeTile() const; + bool mergeTop(const OSGConvertOption& options) const; + QList tiles() const; private: bool loadMetaData(const QString& input); - bool mergeTile() const; + BaseTile toBaseTile() const; - QList mTiles; + QList mTiles; SpatialReference::Ptr mInSRS; SpatialReferenceMatrix mOutSRS; SpatialTransform::Ptr mSTS; diff --git a/include/OSGConvert/OSGIndex.h b/include/OSGConvert/OSGIndex.h index db46f7f..cc467b8 100644 --- a/include/OSGConvert/OSGIndex.h +++ b/include/OSGConvert/OSGIndex.h @@ -25,14 +25,13 @@ namespace scially { double geometricError = 0; osg::BoundingBoxd boundingBox; QList nodes; - - TileNode() {} - + TileNode(const QString& tileName, const QString& fileName) : mTileName(tileName) , mFileName(fileName) { } + virtual ~TileNode() {} QString relativePath(const QString& suffix) const noexcept { return mTileName + "/" + fileName(suffix); @@ -46,7 +45,9 @@ namespace scially { RootTile toRootTile(bool withChilden) const; - private: + protected: + TileNode() {} + QString mTileName; QString mFileName; }; diff --git a/include/OSGConvert/OSGLodVisitor.h b/include/OSGConvert/OSGLodVisitor.h index 9771d7c..5e81412 100644 --- a/include/OSGConvert/OSGLodVisitor.h +++ b/include/OSGConvert/OSGLodVisitor.h @@ -1,8 +1,9 @@ #pragma once #include -#include #include +#include + #include #include diff --git a/include/OSGConvert/OSGMergeTopIndex.h b/include/OSGConvert/OSGMergeTopIndex.h new file mode 100644 index 0000000..5e8b6d3 --- /dev/null +++ b/include/OSGConvert/OSGMergeTopIndex.h @@ -0,0 +1,110 @@ +#include +#include +#include + +#include +#include + +#include + +#include +#include + +namespace scially { + // pyramid + // t z = 1 + // t t z = 2 + //t t t t z = 3 + // TODO: + // rebuild: + // MergeTileNode -> TileNode -> VirtualNode OSGTileOSGFolder) + class MergeTileNode : public QEnableSharedFromThis { + public: + using Ptr = QSharedPointer; + friend class MergeTileNodeBuilder; + + MergeTileNode(OSGTile::Ptr osgTile); + MergeTileNode(int32_t x, int32_t y, int32_t z); + virtual ~MergeTileNode() {} + + bool parentIndex(uint32_t z, int32_t& x, int32_t& y) const; + + const int32_t& xIndex() const { return mXIndex; } + const int32_t& yIndex() const { return mYIndex; } + const int32_t& zIndex() const { return mZIndex; } + const QString& tileName() const { return mTileName; } + const QString& fileName() const { return mFileName; } + const double& geometricError() const { return mGeometricError; } + const osg::BoundingBoxd& boundingBox() const { return mBoundingBox; } + const QList& nodes() const { return mNodes; } + + int32_t& xIndex() { return mXIndex; } + int32_t& yIndex() { return mYIndex; } + int32_t& zIndex() { return mZIndex; } + double& geometricError() { return mGeometricError; } + osg::BoundingBoxd& boundingBox() { return mBoundingBox; } + QList& nodes() { return mNodes; } + + QString relativePath(const QString& suffix) const { + return QString("top/top_%1_%2_%3%4") + .arg(zIndex()) + .arg(xIndex()) + .arg(yIndex()) + .arg(suffix); + } + + // convert to b3dm + MergeTileNode::Ptr toB3DM( + const SpatialTransform& transform, + const TileStorage& storage, + double splitPixel); + + RootTile toRootTile() const; + + bool operator== (const MergeTileNode& node); + + private: + osg::ref_ptr mOSGNode; + QList mNodes; + + OSGTile::Ptr mOSGTile; + + osg::BoundingBoxd mBoundingBox; + double mGeometricError = 0; + int32_t mXIndex; + int32_t mYIndex; + int32_t mZIndex; + QString mTileName; + QString mFileName; + }; + + class MergeTileNodeBuilder { + public: + static QList + BuildPyramidIndex( + const QList& nodes, + int32_t maxZ); + + // read and simplyf all z level osg node + static void + GenerateOSGNodeInPyramid( + const QList& topNodes, + int32_t maxZ); + + // convert to b3dm + static QList MergeOSGToB3DM( + const QList& topNodes, + const SpatialTransform& transform, + TileStorage& storage, + double splitPixel); + + private: + // read and simplyf osg node + static void + GenerateOSGNodeInPyramidFromBottomToUp( + const QList& nodes, + uint32_t maxZ, + uint32_t z); + }; + +} \ No newline at end of file diff --git a/include/OSGConvert/OSGParseVisitor.h b/include/OSGConvert/OSGParseVisitor.h index 5ff650b..3d11798 100644 --- a/include/OSGConvert/OSGParseVisitor.h +++ b/include/OSGConvert/OSGParseVisitor.h @@ -19,6 +19,10 @@ namespace scially { const osg::Vec3d& tileCenter, const SpatialTransform& transform); + QList OSGBtoCesiumMesh( + osg::Node& osgNode, + const osg::Vec3d& tileCenter, + const SpatialTransform& transform); class OSGParseVisitor: public osg::NodeVisitor { public: diff --git a/include/OSGConvert/OSGTile.h b/include/OSGConvert/OSGTile.h index 33676bc..f87cf06 100644 --- a/include/OSGConvert/OSGTile.h +++ b/include/OSGConvert/OSGTile.h @@ -9,14 +9,20 @@ #include #include #include +#include #include #include #include namespace scially { - class OSGTile { + + class OSGTile: public QEnableSharedFromThis { public: + using Ptr = QSharedPointer; + friend class OSGFolder; + friend class MergeTileNode; + OSGTile(const QString& tileFolder , double minGeometricError , uint32_t splitPixel = 512 @@ -28,6 +34,8 @@ namespace scially { { } + virtual ~OSGTile() {} + bool init(); bool toB3DM( @@ -36,22 +44,24 @@ namespace scially { bool saveJson(const SpatialReference& srs, TileStorage& storage) const; - const TileNode::Ptr b3dms() const { return mB3DMIndexNode; } osg::BoundingBoxd boungdingBox() const { return mBoundingBox; } QString tileName() const { return mTileName; } + int32_t xIndex() const { return mXIndex; } + int32_t yIndex() const { return mYIndex; } + int32_t zIndex() const { return mZIndex; } QString rootTileFilePath() const { return mTileFolder + "/" + mTileName + ".osgb"; } - protected: + private: bool loadRoot(); bool buildIndex(); - private: + protected: QString mTileFolder; QString mTileName; QString mFileName; int32_t mXIndex = -1; int32_t mYIndex = -1; - int32_t mZIndex = -1; + int32_t mZIndex = 1; osg::BoundingBoxd mBoundingBox; diff --git a/include/OSGConvert/OSGTileMerge.h b/include/OSGConvert/OSGTileMerge.h deleted file mode 100644 index 5559bb2..0000000 --- a/include/OSGConvert/OSGTileMerge.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -namespace sically { - // TODO: simplify and merge top -} \ No newline at end of file diff --git a/src/CesiumGLTF/CesiumB3DM.cpp b/src/CesiumGLTF/CesiumB3DM.cpp index a12fb37..27df7cd 100644 --- a/src/CesiumGLTF/CesiumB3DM.cpp +++ b/src/CesiumGLTF/CesiumB3DM.cpp @@ -312,11 +312,12 @@ namespace scially { return false; } - toB3DM(gltfBuffer, buffer); + buffer = toB3DM(gltfBuffer); return true; } - void CesiumB3DM::toB3DM(const QByteArray& glb, QByteArray& buffer) const{ + QByteArray CesiumB3DM::toB3DM(const QByteArray& glb) const{ + QByteArray buffer; QDataStream dataStream(&buffer, QIODevice::WriteOnly); dataStream.setByteOrder(QDataStream::LittleEndian); @@ -369,5 +370,6 @@ namespace scially { dataStream.writeRawData(featureTableJsonByte.data(), featureTableJsonByte.size()); dataStream.writeRawData(glb.data(), glb.size()); + return buffer; } } diff --git a/src/Commons/OSGSimplify.cpp b/src/Commons/OSGSimplify.cpp new file mode 100644 index 0000000..66a7578 --- /dev/null +++ b/src/Commons/OSGSimplify.cpp @@ -0,0 +1,85 @@ +#include + +#include +#include +#include +#include +#include +#include + +namespace scially { + class RemovePagedLod : public osg::NodeVisitor { + public: + RemovePagedLod(osg::ref_ptr node) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) { + this->node = node; + } + + virtual void apply(osg::Node& node) override { + traverse(node); + } + + virtual void apply(osg::PagedLOD& node) override { + apply(static_cast(node)); + } + + virtual void apply(osg::Geode& geode) override { + node->addChild(&geode); + } + + osg::ref_ptr node; + }; + + + class OSGImageVisitor : public osg::NodeVisitor { + public: + OSGImageVisitor(double ratio) + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + , ratio(ratio){ + + } + + virtual void apply(osg::Node& node) override { + traverse(node); + } + + + virtual void apply(osg::Geode& geode) override { + for (size_t i = 0; i < geode.getNumDrawables(); i++) { + osg::StateSet* ss = geode.getDrawable(i)->getStateSet(); + if (ss == nullptr) + continue; + + auto tt = dynamic_cast(ss->getTextureAttribute(0, osg::StateAttribute::TEXTURE)); + + if (tt == nullptr) + continue; + + osg::Image* img = tt->getImage(0); + + if (img == nullptr) + continue; + + img->scaleImage(img->s() * ratio, img->t() * ratio, img->r() * ratio); + } + + } + + + double ratio; + }; + + bool OSGSimplify::simplify(double ratio) { + RemovePagedLod rpl(mSNode); + mNode.accept(rpl); + mSNode = rpl.node; + + if (mSNode == nullptr || mSNode->getNumChildren() == 0) + return false; + + osgUtil::Simplifier simp(ratio); + mSNode->accept(simp); + + OSGImageVisitor oiv(ratio); + mSNode->accept(oiv); + } +} diff --git a/src/Commons/TileStorageDisk.cpp b/src/Commons/TileStorageDisk.cpp index b2601a7..b308d1a 100644 --- a/src/Commons/TileStorageDisk.cpp +++ b/src/Commons/TileStorageDisk.cpp @@ -6,7 +6,7 @@ #include namespace scially { - bool TileStorageDisk::saveJson(const QString& file, const QJsonObject& content) { + bool TileStorageDisk::saveJson(const QString& file, const QJsonObject& content) const { QJsonDocument doc(content); #if NDEBUG QByteArray json = doc.toJson(QJsonDocument::Compact); @@ -16,7 +16,7 @@ namespace scially { return saveFile(file, json); } - bool TileStorageDisk::saveFile(const QString& file, const QByteArray& content) { + bool TileStorageDisk::saveFile(const QString& file, const QByteArray& content) const { QString outPath = cleanPath(file); ensurePath(outPath); @@ -30,11 +30,11 @@ namespace scially { return r > 0; } - bool TileStorageDisk::exists(const QString& file) { + bool TileStorageDisk::exists(const QString& file) const { return QDir(cleanPath(file)).exists(); } - QString TileStorageDisk::cleanPath(const QString& path){ + QString TileStorageDisk::cleanPath(const QString& path) const { QString outPath; if (QDir::isAbsolutePath(path)) { outPath = path; @@ -46,7 +46,7 @@ namespace scially { return outPath; } - bool TileStorageDisk::ensurePath(const QString& path){ + bool TileStorageDisk::ensurePath(const QString& path) const{ auto parentPath = QDir::cleanPath(QDir(path).filePath(QStringLiteral(".."))); return QDir().mkpath(parentPath); } diff --git a/src/ConvertApp/ConvertApp.cpp b/src/ConvertApp/ConvertApp.cpp index 3902dd7..fdc434b 100644 --- a/src/ConvertApp/ConvertApp.cpp +++ b/src/ConvertApp/ConvertApp.cpp @@ -34,6 +34,11 @@ int main(int argc, char** argv) { if(!dataFolder.toB3DMPerTile(options)) return -1; + + if (parser.mergeTop) { + if (!dataFolder.mergeTop(options)) + return -1; + } } qInfo() << "finish convert in" << beginTime.secsTo(QTime::currentTime()) << "s"; diff --git a/src/OSGConvert/OSGFolder.cpp b/src/OSGConvert/OSGFolder.cpp index edd5407..ae7e929 100644 --- a/src/OSGConvert/OSGFolder.cpp +++ b/src/OSGConvert/OSGFolder.cpp @@ -1,14 +1,20 @@ -#include #include #include +#include +#include + +#include +#include #include +#include #include +#include #include #include -#include -#include -#include + +#include +#include namespace scially { bool OSGFolder::load(const OSGConvertOption& options) { @@ -27,18 +33,20 @@ namespace scially { osg::BoundingBoxd osgBound; for (const auto& tileFolder : tileFolders) { - OSGTile tile( + OSGTile::Ptr tile{ + new OSGTile( tileFolder.absoluteFilePath(), options.MinGeometricError, options.SplitPixel, - options.skipPerTile); + options.skipPerTile) + }; - if (!tile.init()) { + if (!tile->init()) { qWarning() << "load" << tileFolder.fileName() << "failed"; continue; } mTiles.append(tile); - osgBound.expandBy(tile.boungdingBox()); + osgBound.expandBy(tile->boungdingBox()); } if (mTiles.isEmpty()) @@ -60,12 +68,12 @@ namespace scially { QList> workFutures; QList tree; - for (OSGTile& tile : mTiles) { - QFuture f = QtConcurrent::run(&threadPool, [this, &tile, &tree]() { - qInfo() << tile.tileName() << "tile start convert to b3dm"; + foreach (auto tile, mTiles) { + QFuture f = QtConcurrent::run(&threadPool, [this, tile, &tree]() { + qInfo() << tile->tileName() << "tile start convert to b3dm"; - if (tile.toB3DM(*mSTS, *mStorage)) { - return tile.saveJson(mOutSRS, *mStorage); + if (tile->toB3DM(*mSTS, *mStorage)) { + return tile->saveJson(mOutSRS, *mStorage); } else { return false; @@ -93,8 +101,8 @@ namespace scially { osg::BoundingBoxd mergeBoundingBox; RootTile root; - foreach(const OSGTile & tile, mTiles) { - auto b3dmIndex = tile.b3dms(); + foreach(auto tile, mTiles) { + auto b3dmIndex = tile->mB3DMIndexNode; if (b3dmIndex == nullptr) continue; @@ -114,6 +122,71 @@ namespace scially { return b; } + bool OSGFolder::mergeTop(const OSGConvertOption& options) const { + int32_t minx = std::numeric_limits::max(); + int32_t miny = std::numeric_limits::max(); + + int32_t maxx = std::numeric_limits::min(); + int32_t maxy = std::numeric_limits::min(); + + QList nodes; + + for(const auto& tile: mTiles) { + if (!tile->mB3DMIndexNode) + continue; + + MergeTileNode::Ptr node{ new MergeTileNode(tile) }; + nodes.push_back(node); + + minx = std::min(minx, node->xIndex()); + miny = std::min(miny, node->yIndex()); + + maxx = std::max(maxx, node->xIndex()); + maxy = std::max(maxy, node->yIndex()); + } + + int32_t maxIndex = std::max({ maxx - minx, maxy - miny}); + + if (maxIndex <= 0) { + return false; + } + + int32_t maxZ = static_cast(std::log2(maxIndex) + 1) + 1; // z start from 1 + + // buiding pyramid index + QList topNodes = MergeTileNodeBuilder::BuildPyramidIndex(nodes, maxZ); + + // constrution + MergeTileNodeBuilder::GenerateOSGNodeInPyramid(topNodes, maxZ); + auto mergeB3dmTiles = MergeTileNodeBuilder::MergeOSGToB3DM(topNodes, *mSTS, *mStorage, options.SplitPixel); + + if (mergeB3dmTiles.isEmpty()) { + return false; + } + + osg::BoundingBoxd mergeBoundingBox; + RootTile root; + + for(const auto& tile: mergeB3dmTiles) { + mergeBoundingBox.expandBy(tile->boundingBox()); + RootTile r = tile->toRootTile(); + root.children.append(r); + } + + root.boundingVolume.box = osgBoundingToCesiumBoundBox(mergeBoundingBox); + root.geometricError = osgBoundingSize(mergeBoundingBox); + root.refine = "REPLACE"; + root.transform = osgMatrixToCesiumTransform(mOutSRS.originENU()); + + BaseTile b; + b.root = root; + b.geometricError = root.geometricError; + + BaseTileReadWriter brw; + const QJsonObject obj = brw.writeToJson(b); + return mStorage->saveJson("tileset.json", obj); + } + bool OSGFolder::loadMetaData(const QString& input) { QFile metaDataFile(input); if (!metaDataFile.exists()) { @@ -156,4 +229,14 @@ namespace scially { return mInSRS != nullptr; } + + QList OSGFolder::tiles() const { + QList validTile; + std::copy_if(mTiles.begin(), mTiles.end(), + std::back_inserter(validTile), + [](const OSGTile::Ptr& p) { + return p->mB3DMIndexNode != nullptr; + }); + return validTile; + } } diff --git a/src/OSGConvert/OSGMergeTopIndex.cpp b/src/OSGConvert/OSGMergeTopIndex.cpp new file mode 100644 index 0000000..266a2b0 --- /dev/null +++ b/src/OSGConvert/OSGMergeTopIndex.cpp @@ -0,0 +1,297 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +namespace scially { + + MergeTileNode::MergeTileNode(OSGTile::Ptr osgTile): mOSGTile(osgTile) { + Q_ASSERT(osgTile != nullptr); + + mXIndex = osgTile->xIndex(); + mYIndex = osgTile->yIndex(); + mZIndex = osgTile->zIndex(); + + mFileName = QString("Top_%1").arg(mZIndex); + mTileName = QString("Top_%1_%2").arg(mXIndex).arg(mYIndex); + + if (mOSGTile) { + mBoundingBox = mOSGTile->mB3DMIndexNode->boundingBox; + mGeometricError = mOSGTile->mB3DMIndexNode->geometricError; + } + } + + MergeTileNode::MergeTileNode(int32_t x, int32_t y, int32_t z) + :mXIndex(x), mYIndex(y), mZIndex(z){ + mFileName = QString("Top_%1").arg(mZIndex); + mTileName = QString("%1_%2").arg(mXIndex).arg(mYIndex); + } + + bool MergeTileNode::operator== (const MergeTileNode& node) { + return mXIndex == node.mXIndex + && mYIndex == node.mYIndex + && mZIndex == node.mZIndex; + } + + + bool MergeTileNode::parentIndex(uint32_t z, int32_t& x, int32_t& y) const { + if (z >= mZIndex) { + qWarning() << "try to new level zoom"; + return false; + } + + x = mXIndex >> (mZIndex - z); + y = mYIndex >> (mZIndex - z); + + return true; + } + + MergeTileNode::Ptr MergeTileNode::toB3DM( + const SpatialTransform& transform, + const TileStorage& storage, + double splitPixel) { + + if (mOSGTile != nullptr) { + MergeTileNode::Ptr leafNode{ + new MergeTileNode(mOSGTile) + }; + + return leafNode; + } + + osg::Vec3d tileCenter = transform.transform(mBoundingBox.center()); + + CesiumB3DM::Ptr b3dm{ new CesiumB3DM }; + b3dm->center = tileCenter; + + double maxGeometricError = 0; + + auto meshes = OSGBtoCesiumMesh( + *mOSGNode, + tileCenter, + transform); + + b3dm->meshes.append(meshes); + maxGeometricError = std::max(maxGeometricError, geometricError()); + + if (b3dm->meshes.isEmpty()) { + return nullptr; + } + + QString outFileName = relativePath(".b3dm"); + + QByteArray b3dmBuffer; + if (!b3dm->toGltfBinaryWithNoPack(b3dmBuffer)) { + qCritical() << "fialed convert meshes to b3dm buffer"; + return nullptr; + } + + if (!storage.saveFile(outFileName, b3dmBuffer)) { + return nullptr; + } + + MergeTileNode::Ptr b3dmTree{ + new MergeTileNode(mXIndex, mYIndex, mZIndex) + }; + + b3dmTree->mGeometricError = maxGeometricError; + for (const auto& mesh : b3dm->meshes) { + b3dmTree->mBoundingBox.expandBy(mesh.boundingBox()); + } + + // Attention! + b3dmTree->mBoundingBox.xMin() += tileCenter.x(); + b3dmTree->mBoundingBox.yMin() += tileCenter.y(); + b3dmTree->mBoundingBox.zMin() += tileCenter.z(); + b3dmTree->mBoundingBox.xMax() += tileCenter.x(); + b3dmTree->mBoundingBox.yMax() += tileCenter.y(); + b3dmTree->mBoundingBox.zMax() += tileCenter.z(); + + for (const auto& childNode : mNodes) { + MergeTileNode::Ptr node = childNode->toB3DM( + transform, + storage, + splitPixel + ); + + if (node) { + b3dmTree->mNodes.append(node); + } + } + + return b3dmTree; + } + + RootTile MergeTileNode::toRootTile() const { + RootTile root; + root.geometricError = mGeometricError * 16; + root.refine = "REPLACE"; + root.boundingVolume.box = osgBoundingToCesiumBoundBox(mBoundingBox); + + // child node to 3dtiles content + for(const auto& node: mNodes) { + RootTile r = node->toRootTile(); + root.children.append(r); + } + + root.content.emplace(); + // per tile tieset.json + if (mOSGTile) { + root.content.value().uri = mOSGTile->mOSGIndexNode->relativePath(".json"); + } + else { + root.content.value().uri = relativePath(".b3dm"); + } + + return root; + } + + QList MergeTileNodeBuilder::BuildPyramidIndex(const QList& nodes, int32_t maxZ) { + QQueue nodeQueue; + QList topNodes; + + QMap, MergeTileNode::Ptr> buildCache; + + for (auto node : nodes) { + node->zIndex() = maxZ; + nodeQueue.enqueue(node); + } + + for (int32_t i = maxZ; i > 0; --i) { + size_t s = nodeQueue.size(); + for (size_t j = 0; j < s; ++j) { + auto n = nodeQueue.dequeue(); + + int32_t x, y; + if (!n->parentIndex(i - 1, x, y)) { + continue; + } + + auto parent = buildCache.value(std::make_tuple( x, y, i - 1 ), nullptr); + + if (parent == nullptr) { + parent = MergeTileNode::Ptr::create(x, y, i - 1); + nodeQueue.enqueue(parent); + buildCache[std::make_tuple(x, y, i - 1)] = parent; + + if (i == 2) { + topNodes.append(parent); + } + } + + parent->mNodes.append(n); + } + } + + return topNodes; + } + + void MergeTileNodeBuilder::GenerateOSGNodeInPyramid(const QList& topNodes, int32_t maxZ) { + + if (maxZ == 1) { + return; + } + + GenerateOSGNodeInPyramidFromBottomToUp(topNodes, maxZ, 1); + } + + // pyramid and update bound + // t z = 1 1 / pyramid = ratio + // t t z = 2 1 / pyramid * 2 = ratio + //t t t t z = 3 1 / pyramid * 3 = ratio ( ratio = 1 ) + void MergeTileNodeBuilder::GenerateOSGNodeInPyramidFromBottomToUp( + const QList& nodes, + uint32_t maxZ, + uint32_t z) { + if (z == 0) + return; + + if (z == maxZ) { + for(const auto& node: nodes) { + QString osgPath = node->mOSGTile->rootTileFilePath(); + auto osgNode = osgDB::readRefNodeFile(osgPath.toStdString()); + + if (osgNode) { + node->mOSGNode = osgNode; + } + else { + qWarning() << "read" << node->mOSGTile->rootTileFilePath() << "failed"; + } + } + }else { + for(const auto& node: nodes) { + GenerateOSGNodeInPyramidFromBottomToUp(node->mNodes, maxZ, z + 1); + + osg::ref_ptr group = new osg::Group; + + double maxGeometricError = 0; + osg::BoundingBoxd box; + for(const auto& n: node->mNodes) { + if (n->mOSGNode) { + group->addChild(n->mOSGNode); + } + maxGeometricError = std::max(maxGeometricError, n->mGeometricError); + box.expandBy(n->mBoundingBox); + } + + // simplify + OSGSimplify simp(*group); + simp.simplify(1.0 / maxZ); + + node->mOSGNode = group; + node->mGeometricError = maxGeometricError * 2; + node->mBoundingBox = box; + } + } + } + + QList MergeTileNodeBuilder::MergeOSGToB3DM( + const QList& topNodes, + const SpatialTransform& transform, + TileStorage& storage, + double splitPixel) { + + QList b3dms; + for (const auto& node : topNodes) { + auto r = node->toB3DM(transform, storage, splitPixel); + if (r) { + b3dms.append(r); + } + } + return b3dms; + } +} + +//else if(z == maxZ - 1) { +// foreach(auto node, nodes) { +// osg::ref_ptr group = new osg::Group; + +// foreach(auto n, node->nodes) { +// auto dyn = n.dynamicCast(); +// Q_ASSERT(dyn); + +// if (dyn->mOSGNode) { +// group->addChild(dyn->mOSGNode); +// } +// } + +// // simplify +// OSGSimplify simp(*group); +// simp.simplify(1.0 / maxZ); + +// node->mOSGNode = group; +// } +//} \ No newline at end of file diff --git a/src/OSGConvert/OSGParseVisitor.cpp b/src/OSGConvert/OSGParseVisitor.cpp index 744a091..a6b34ae 100644 --- a/src/OSGConvert/OSGParseVisitor.cpp +++ b/src/OSGConvert/OSGParseVisitor.cpp @@ -224,4 +224,14 @@ namespace scially { model->accept(loader); return loader.meshes; } + + QList OSGBtoCesiumMesh( + osg::Node& osgNode, + const osg::Vec3d& tileCenter, + const SpatialTransform& transform) { + + OSGParseVisitor loader(tileCenter, &transform); + osgNode.accept(loader); + return loader.meshes; + } } diff --git a/src/OSGConvert/OSGTile.cpp b/src/OSGConvert/OSGTile.cpp index d928feb..736d4bf 100644 --- a/src/OSGConvert/OSGTile.cpp +++ b/src/OSGConvert/OSGTile.cpp @@ -26,9 +26,7 @@ namespace scially { if (split.length() >= 3) { mYIndex = split[2].toInt(); } - if (split.length() >= 4) { - mZIndex = split[3].toInt(); - } + return loadRoot(); } diff --git a/src/OSGConvert/OSGTileMerge.cpp b/src/OSGConvert/OSGTileMerge.cpp deleted file mode 100644 index 02809bd..0000000 --- a/src/OSGConvert/OSGTileMerge.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include - -namespace scially { - -} \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 934ba02..4e91eb8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -2,8 +2,8 @@ include(QtRuntimeLibraryFunction) set(TESTS - TestOSGFolder.cpp TestOSGLodVisitor.cpp + TestOSGMergTopIndex.cpp TestOSGParseVisitor.cpp) foreach(TESTSRC ${TESTS}) diff --git a/tests/TestOSGFolder.cpp b/tests/TestOSGFolder.cpp deleted file mode 100644 index 8bce512..0000000 --- a/tests/TestOSGFolder.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include "TestTemplate.h" - -#include -#include - -namespace scially { - class TestOSGFolder : public QObject { - Q_OBJECT - private slots: - void initTestCase() { - options.thread = 1; - options.output = "file:./"; - options.input = "./data/Production_5"; - Q_ASSERT(folder.load(options)); - } - - void testToB3DM() { - Q_ASSERT(folder.toB3DMPerTile(options)); - } - - private: - OSGConvertOption options; - OSGFolder folder; - }; -} - -TESTTEMPLAGE_MAIN(scially::TestOSGFolder) -#include "TestOSGFolder.moc" \ No newline at end of file diff --git a/tests/TestOSGLodVisitor.cpp b/tests/TestOSGLodVisitor.cpp index 3a11f58..74db170 100644 --- a/tests/TestOSGLodVisitor.cpp +++ b/tests/TestOSGLodVisitor.cpp @@ -11,14 +11,14 @@ namespace scially { private slots: void initTestCase(){ node = osgDB::readRefNodeFile("data/Production_5/Data/Tile_+000_+012/Tile_+000_+012.osgb"); - Q_ASSERT(node != nullptr); + QVERIFY(node != nullptr); } void testCase1() { OSGLodVisitor visitor; node->accept(visitor); - Q_ASSERT(visitor.vertexCount > 0); - Q_ASSERT(visitor.children.size() > 0); + QVERIFY(visitor.vertexCount > 0); + QVERIFY(visitor.children.size() > 0); } private: diff --git a/tests/TestOSGMergTopIndex.cpp b/tests/TestOSGMergTopIndex.cpp new file mode 100644 index 0000000..d1fe64e --- /dev/null +++ b/tests/TestOSGMergTopIndex.cpp @@ -0,0 +1,54 @@ +#include +#include + +#include "TestTemplate.h" + +namespace scially { + class TestOSGMergTopIndex : public QObject { + Q_OBJECT + private slots: + void initTestCase() { + options.thread = 1; + options.output = "file:./"; + options.input = "./data/Production_5"; + QVERIFY(folder.load(options)); + + for (int32_t i = 0; i < 5; i++) { + for (int32_t j = 0; j < 5; j++) { + MergeTileNode::Ptr node{ + new MergeTileNode(i, j, 2) + }; + fakeNodes.append(node); + } + } + } + + void testBuildPyramidIndex() { + auto topNodes = MergeTileNodeBuilder::BuildPyramidIndex(fakeNodes, 2); + for(const auto & node: topNodes) { + qDebug() << node->xIndex() << node->yIndex() << node->zIndex(); + } + QVERIFY(topNodes.size() == (5 / 2 + 1) * (5 / 2 + 1 )); + } + + void testToB3DM() { + QBENCHMARK{ + QVERIFY(folder.toB3DMPerTile(options)); + } + } + + void testMergeTop() { + QBENCHMARK{ + QVERIFY(folder.mergeTop(options)); + } + } + + private: + QList fakeNodes; + OSGConvertOption options; + OSGFolder folder; + }; +} + +TESTTEMPLAGE_MAIN(scially::TestOSGMergTopIndex) +#include "TestOSGMergTopIndex.moc" \ No newline at end of file diff --git a/tests/TestOSGParseVisitor.cpp b/tests/TestOSGParseVisitor.cpp index 58654c5..2c2199b 100644 --- a/tests/TestOSGParseVisitor.cpp +++ b/tests/TestOSGParseVisitor.cpp @@ -10,13 +10,13 @@ namespace scially { private slots: void initTestCase() { node = osgDB::readRefNodeFile("data/Production_5/Data/Tile_+000_+012/Tile_+000_+012.osgb"); - Q_ASSERT(node != nullptr); + QVERIFY(node != nullptr); } void testCase1() { OSGParseVisitor visitor(osg::Vec3(0, 0, 0), nullptr); node->accept(visitor); - Q_ASSERT(visitor.meshes.size() > 0); + QVERIFY(visitor.meshes.size() > 0); } private: diff --git a/tests/TestTemplate.h b/tests/TestTemplate.h index 2e11467..03f3a3c 100644 --- a/tests/TestTemplate.h +++ b/tests/TestTemplate.h @@ -3,6 +3,7 @@ #include #include +#include #define TESTTEMPLAGE_MAIN(TestObject) \ int main(int argc, char *argv[]) \