diff --git a/CMakeLists.txt b/CMakeLists.txt index f62d574..5290237 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,10 @@ cmake_minimum_required (VERSION 3.8) -project(Cesium3DTilesConverter VERSION 3.0.0) +project(Cesium3DTilesConverter VERSION 2.1.0) + +configure_file ( + "${PROJECT_SOURCE_DIR}/include/Config.h.in" + "${PROJECT_SOURCE_DIR}/include/Config.h" +) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") set(CMAKE_CXX_STANDARD 17) diff --git a/README.md b/README.md index 973873f..9aae00c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # About Project + 基于C++17、Qt5的3DTiles 转换工具集。 # 简介 @@ -17,20 +18,20 @@ ## 命令行格式 ```sh -Converter.exe --format [OPTIONS] +Converter -f [OPTIONS] ``` ## 示例命令 ```sh # from osgb dataset -Converter -f OSGB --yUpAxis +Converter -f OSGB --yUpAxis -# from single shp file -Converter -f GDAL --field height +# from shp file +Converter -f GDAL --field height # from gdb file -Converter -f GDAL --field height --layer +Converter -f GDAL --field height --layer ``` ## 参数说明 @@ -52,8 +53,9 @@ Options: -H, --height height offset(default value 0), OSGB高度偏移字段 - 输入数据的目录,OSGB数据截止到 `/Data` 目录的上一级,GDAL参考GDAL数据格式。 - 输出目录。OSGB转换的3DTiles输出的数据文件位于 /Data`目录, GDAL转换的3DTiles输出的数据文件位于/Tile目录,tileset.json位于根目录。 + 输入数据的目录,OSGB数据截止到 `/Data` 目录的上一级,GDAL参考GDAL数据格式。 + + 输出目录。OSGB转换的3DTiles输出的数据文件位于 /Data`目录, GDAL转换的3DTiles输出的数据文件位于/Tile目录,tileset.json位于根目录。 ``` # 数据要求及说明 diff --git a/include/Config.h b/include/Config.h new file mode 100644 index 0000000..e1c84ee --- /dev/null +++ b/include/Config.h @@ -0,0 +1,8 @@ +#pragma once + +#define PROJECT_VERSION_MAJOR 2 +#define PROJECT_VERSION_MINOR 1 +#define PROJECT_VERSION_PATCH 0 + +#define PROJECT_VERSION "2.1.0" +#define PROJECT_NAME "Cesium3DTilesConverter" diff --git a/include/Config.h.in b/include/Config.h.in new file mode 100644 index 0000000..4fc73a0 --- /dev/null +++ b/include/Config.h.in @@ -0,0 +1,8 @@ +#pragma once + +#define PROJECT_VERSION_MAJOR @Cesium3DTilesConverter_VERSION_MAJOR@ +#define PROJECT_VERSION_MINOR @Cesium3DTilesConverter_VERSION_MINOR@ +#define PROJECT_VERSION_PATCH @Cesium3DTilesConverter_VERSION_PATCH@ + +#cmakedefine PROJECT_VERSION "${Cesium3DTilesConverter_VERSION}" +#cmakedefine PROJECT_NAME "${PROJECT_NAME}" \ No newline at end of file diff --git a/include/CoordinateConvert.h b/include/CoordinateConvert.h index 33b65de..31a5a02 100644 --- a/include/CoordinateConvert.h +++ b/include/CoordinateConvert.h @@ -1,7 +1,7 @@ #pragma once #include -#include + #include namespace scially { diff --git a/include/GDALWrapper.h b/include/GDALWrapper.h index 8682cd4..c6f533e 100644 --- a/include/GDALWrapper.h +++ b/include/GDALWrapper.h @@ -1,11 +1,10 @@ #pragma once -#include - #include -#include #include +#include +#include #include namespace scially { @@ -29,53 +28,103 @@ namespace scially { std::string projData; }; + class OGRException : QException { + public: + OGRException(const QString& err) : err_(err) {} + OGRException(OGRErr err) { + switch (err) { + case OGRERR_NOT_ENOUGH_DATA: + err_ = "[gdal/ogr] not enough data"; + break; + case OGRERR_NOT_ENOUGH_MEMORY: + err_ = "[gdal/ogr] not enough memory"; + break; + case OGRERR_UNSUPPORTED_GEOMETRY_TYPE: + err_ = "[gdal/ogr] unsupported geometry type"; + break; + case OGRERR_UNSUPPORTED_OPERATION: + err_ = "[gdal/ogr] unsupported operation"; + break; + case OGRERR_CORRUPT_DATA: + err_ = "[gdal/ogr] corrupt data"; + break; + case OGRERR_FAILURE: + err_ = "[gdal/ogr] failure"; + break; + case OGRERR_UNSUPPORTED_SRS: + err_ = "[gdal/ogr] unsupported srs"; + break; + case OGRERR_INVALID_HANDLE: + err_ = "[gdal/ogr] invalid handle"; + break; + case OGRERR_NON_EXISTING_FEATURE: + err_ = "[gdal/ogr] non existing feataure"; + break; + default: + err_ = "[gdal/ogr] unkonwn error"; + } + } + virtual void raise() const override { + throw* this; + } + virtual OGRException* clone() const override { + return new OGRException(*this); + } + + QString error() const noexcept { + return err_; + } + + private: + QString err_; + }; class OGRFeatureWrapper; class OGRLayerWrapper; class GDALDatasetWrapper; - class OGRFeatureWrapper { public: friend class OGRLayerWrapper; + OGRFeatureWrapper() = default; OGRGeometry* GetGeometryRef() { - return feature->GetGeometryRef(); + return feature_->GetGeometryRef(); } double GetFieldAsDouble(GIntBig fid) { - return feature->GetFieldAsDouble(fid); + return feature_->GetFieldAsDouble(fid); } bool isValid() const { - return feature != nullptr; + return feature_ != nullptr; } GIntBig GetFID() { - return feature->GetFID(); + return feature_->GetFID(); } private: explicit OGRFeatureWrapper(OGRFeature* f) { - feature = QSharedPointer(f, &OGRFeature::DestroyFeature); + feature_.reset(f); } - QSharedPointer feature; + QSharedPointer feature_; }; - class OGRLayerWrapper { public: friend class GDALDatasetWrapper; - + + OGRLayerWrapper() = default; OGRFeatureWrapper GetNextFeature() { - OGRFeature* feature = layer->GetNextFeature(); + OGRFeature* feature = layer_->GetNextFeature(); return OGRFeatureWrapper(feature); } OGREnvelope GetExtent(int bForce = 1) { OGREnvelope envelope; - OGRErr err = layer->GetExtent(&envelope, bForce); + OGRErr err = layer_->GetExtent(&envelope, bForce); if (err != OGRERR_NONE) throw OGRException(err); @@ -83,10 +132,7 @@ namespace scially { } OGRFeatureWrapper GetFeature(GIntBig fid) { - OGRFeature* feature = layer->GetFeature(fid); - if (feature == nullptr) { - throw OGRException(QString("No feature ") + fid + "in Layer"); - } + OGRFeature* feature = layer_->GetFeature(fid); return OGRFeatureWrapper(feature); } @@ -95,48 +141,45 @@ namespace scially { } void ResetReading() { - layer->ResetReading(); + layer_->ResetReading(); } OGRSpatialReference* GetSpatialRef() { - return layer->GetSpatialRef(); + return layer_->GetSpatialRef(); } OGRFeatureDefn* GetLayerDefn() { - return layer->GetLayerDefn(); + return layer_->GetLayerDefn(); } private: - explicit OGRLayerWrapper(OGRLayer* layer) : layer(layer) {} - OGRLayer* layer; // will auto dispose when ds close. + explicit OGRLayerWrapper(OGRLayer* layer) : layer_(layer) {} + OGRLayer* layer_; // will auto dispose when ds close. }; class GDALDatasetWrapper { public: friend class OGRLayerWrapper; - static inline GDALDatasetWrapper open(const char* pszFilename, - unsigned int nOpenFlags, - const char* const* papszAllowedDrivers = nullptr, - const char* const* papszOpenOptions = nullptr, - const char* const* papszSiblingFiles = nullptr) { - GDALDataset* dataset = (GDALDataset*)GDALOpenEx(pszFilename, + GDALDatasetWrapper() = default; + + bool open(const QString &fileName, unsigned int nOpenFlags) { + GDALDataset* dataset = (GDALDataset*)GDALOpenEx(fileName.toStdString().c_str(), nOpenFlags, - papszAllowedDrivers, - papszOpenOptions, - papszSiblingFiles); - if (dataset == nullptr) - throw OGRException(QString("Can't open dataset %1").arg(pszFilename)); - - return GDALDatasetWrapper(dataset); + nullptr, + nullptr, + nullptr); + ds_.reset(dataset); + return ds_ != nullptr; } OGRLayerWrapper GetLayer(int iLayer) { - OGRLayer* layer = ds->GetLayer(iLayer); + OGRLayer* layer = ds_->GetLayer(iLayer); return OGRLayerWrapper(layer); } - OGRLayerWrapper GetLayerByName(const char* nLayer) { - OGRLayer* layer = ds->GetLayerByName(nLayer); + OGRLayerWrapper GetLayerByName(const QString& nLayer) { + OGRLayer* layer = ds_->GetLayerByName(nLayer.toStdString().c_str()); + return OGRLayerWrapper(layer); } bool isValid() const { @@ -145,15 +188,17 @@ namespace scially { private: struct GDALDatasetDeleteWrapper { - void operator() (GDALDataset* dataset) { + void operator()(GDALDataset* dataset) { if (dataset != nullptr) GDALClose(dataset); } }; - // dataset 将被 GDALDatasetWrapper 接管 - explicit GDALDatasetWrapper(GDALDataset* dataset) { - ds = QSharedPointer(dataset, GDALDatasetDeleteWrapper()); + + GDALDatasetWrapper(GDALDataset* dataset) { + Q_ASSERT(dataset != nullptr); + ds_.reset(dataset, GDALDatasetDeleteWrapper()); } - QSharedPointer ds; + + QSharedPointer ds_; }; } diff --git a/include/OGRException.h b/include/OGRException.h deleted file mode 100644 index c269da2..0000000 --- a/include/OGRException.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace scially { - class OGRException : QException { - public: - OGRException(const QString& err) : error(err) {} - OGRException(OGRErr err) { - switch (err) { - case OGRERR_NOT_ENOUGH_DATA: - error = "Not enough data"; - break; - case OGRERR_NOT_ENOUGH_MEMORY: - error = "Not enough memory"; - break; - case OGRERR_UNSUPPORTED_GEOMETRY_TYPE: - error = "Unsupported geometry type"; - break; - case OGRERR_UNSUPPORTED_OPERATION: - error = "Unsupported operation"; - break; - case OGRERR_CORRUPT_DATA: - error = "Corrupt data"; - break; - case OGRERR_FAILURE: - error = "Failure"; - break; - case OGRERR_UNSUPPORTED_SRS: - error = "Unsupported srs"; - break; - case OGRERR_INVALID_HANDLE: - error = "Invalid handle"; - break; - case OGRERR_NON_EXISTING_FEATURE: - error = "Non existing feataure"; - break; - default: - error = "Unkonwn error"; - } - } - - virtual const char* what() const noexcept override { - return error.toStdString().data(); - } - private: - QString error; - }; -} diff --git a/include/QuadTree.h b/include/QuadTree.h index dbd9e0f..f069b76 100644 --- a/include/QuadTree.h +++ b/include/QuadTree.h @@ -1,11 +1,11 @@ #pragma once #include - #include #include #include +#include namespace scially { @@ -13,51 +13,44 @@ namespace scially { public: QuadTree() = default; QuadTree(double minX, double maxX, double minY, double maxY); - QuadTree(const OGREnvelope &e): envelope(e) {} - - bool add(int id, const OGREnvelope& box); - - void setNo(int r, int c, int l){ - row = r; - col = c; - level = l; + QuadTree(OGREnvelope e): envelope_(e) {} + + bool add(int id, OGREnvelope box) noexcept; + void setNo(int r, int c, int l) noexcept { + row_ = r; + col_ = c; + level_ = l; } - void setEnvelope(const OGREnvelope &e){ - envelope.MinX = e.MinX; - envelope.MaxX = e.MaxX; - envelope.MinY = e.MinY; - envelope.MaxY = e.MaxY; + void setEnvelope(OGREnvelope e) noexcept { + envelope_.MinX = e.MinX; + envelope_.MaxX = e.MaxX; + envelope_.MinY = e.MinY; + envelope_.MaxY = e.MaxY; } void traverse(std::function f){ - if(!geoms.isEmpty()) + if(!geoms_.isEmpty()) f(this); - for(auto iter = nodes.begin(); iter != nodes.end(); iter++){ + for(auto iter = nodes_.begin(); iter != nodes_.end(); iter++){ (*iter)->traverse(f); } } - int geomsSize() const { return geoms.size(); } - int getGeomFID(int i) const { return geoms.at(i); } - int getRow() const { return row; } - int getCol() const { return col; } - int getLevel() const { return level; } - virtual ~QuadTree() { - for(auto iter = nodes.begin(); iter != nodes.end(); iter++){ - if(*iter != nullptr) - delete *iter; - } - } - + int geomSize() const noexcept{ return geoms_.size(); } + int geomFID(int i) const noexcept { return geoms_.at(i); } + int row() const noexcept { return row_; } + int col() const noexcept { return col_; } + int level() const noexcept { return level_; } + private: - void split(); - - OGREnvelope envelope; - QVector nodes; - int row = 0; - int col = 0; - int level = 0; - QVector geoms; + void split() noexcept; + + OGREnvelope envelope_; + QVector> nodes_; + int row_ = 0; + int col_ = 0; + int level_ = 0; + QVector geoms_; }; -} +} \ No newline at end of file diff --git a/include/ShpConvert.h b/include/ShpConvert.h index f33a978..6b05c79 100644 --- a/include/ShpConvert.h +++ b/include/ShpConvert.h @@ -13,14 +13,21 @@ namespace scially { class ShpConvert { public: ShpConvert(const QString &fileName, const QString &layerName, const QString &heightField) - :fileName(fileName), layerName(layerName), heightField(heightField) + :fileName_(fileName), layerName_(layerName), heightField_(heightField) {} - void convertTiles(const QString& output); - + bool convertTiles(const QString& output); + bool initQuadTree(QuadTree& root); private: - QString fileName; - QString layerName; - QString heightField; + bool getAllFeatures(); + + OGRLayerWrapper layer_; + OGREnvelope extent_; + QMap iFeature_; + GDALDatasetWrapper ds_; + + QString fileName_; + QString layerName_; + QString heightField_; }; } diff --git a/src/Conveter.cpp b/src/Conveter.cpp index e2412ea..5cf6485 100644 --- a/src/Conveter.cpp +++ b/src/Conveter.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -8,8 +9,10 @@ int main(int argc, char** argv){ QCoreApplication app(argc, argv); - scially::GDALDriverWrapper init; + app.setApplicationVersion(PROJECT_VERSION); + app.setApplicationName(PROJECT_NAME); + scially::GDALDriverWrapper init; scially::CommandLineParse cmd; try { cmd.parse(); diff --git a/src/CoordinateConvert.cpp b/src/CoordinateConvert.cpp index fca564b..fa8d629 100644 --- a/src/CoordinateConvert.cpp +++ b/src/CoordinateConvert.cpp @@ -1,5 +1,4 @@ #include -#include namespace scially { void CoordinateConvert::setSourceSrs(const QString& srs, SrsType t) { @@ -48,4 +47,4 @@ namespace scially { return OGRCoordinateTransformationPtr(transform); } -} +} \ No newline at end of file diff --git a/src/QuadTree.cpp b/src/QuadTree.cpp index 93d5cc5..95a31ed 100644 --- a/src/QuadTree.cpp +++ b/src/QuadTree.cpp @@ -4,77 +4,77 @@ namespace scially { QuadTree::QuadTree(double minX, double maxX, double minY, double maxY) { - envelope.MinX = minX; - envelope.MaxX = maxX; - envelope.MinY = minY; - envelope.MaxY = maxY; + envelope_.MinX = minX; + envelope_.MaxX = maxX; + envelope_.MinY = minY; + envelope_.MaxY = maxY; } - bool QuadTree::add(int id, const OGREnvelope& box) { - if (!envelope.Intersects(box)) { - return false; - } - if (envelope.MaxX - envelope.MinX <= METERIC) { - geoms.append(id); - return true; - } + bool QuadTree::add(int id, OGREnvelope box) noexcept { + if (!envelope_.Intersects(box)) { + return false; + } + if (envelope_.MaxX - envelope_.MinX <= METERIC) { + geoms_.append(id); + return true; + } - if (envelope.Intersects(box)) { - if (nodes.isEmpty()) { - split(); - } - for (int i = 0; i < 4; i++) { - //when box is added to a node, stop the loop - if(nodes[i]->add(id, box)){ - return true; - } - } - } - return false; + if (envelope_.Intersects(box)) { + if (nodes_.isEmpty()) { + split(); + } + for (int i = 0; i < 4; i++) { + //when box is added to a node, stop the loop + if(nodes_[i]->add(id, box)){ + return true; + } + } + } + return false; } - void QuadTree::split() { - double cX = (envelope.MinX + envelope.MaxX) / 2.0; - double cY = (envelope.MinY + envelope.MaxY) / 2.0; - nodes.resize(4); + void QuadTree::split() noexcept { + double cX = (envelope_.MinX + envelope_.MaxX) / 2.0; + double cY = (envelope_.MinY + envelope_.MaxY) / 2.0; + nodes_.resize(4); for (int i = 0; i < 4; i++) { OGREnvelope box; switch (i) { case 0: - box.MinX = envelope.MinX; + box.MinX = envelope_.MinX; box.MaxX = cX; - box.MinY = envelope.MinY; + box.MinY = envelope_.MinY; box.MaxY = cY; - nodes[i] = new QuadTree(box); - nodes[i]->setNo(row * 2, col * 2, level + 1); + nodes_[i].reset(new QuadTree(box)); + nodes_[i]->setNo(row_ * 2, col_ * 2, level_ + 1); break; case 1: box.MinX = cX; - box.MaxX = envelope.MaxX; - box.MinY = envelope.MinY; + box.MaxX = envelope_.MaxX; + box.MinY = envelope_.MinY; box.MaxY = cY; - nodes[i] = new QuadTree(box); - nodes[i]->setNo(row * 2 + 1, col * 2, level + 1); + nodes_[i].reset(new QuadTree(box)); + nodes_[i]->setNo(row_ * 2 + 1, col_ * 2, level_ + 1); break; case 2: box.MinX = cX; - box.MaxX = envelope.MaxX; + box.MaxX = envelope_.MaxX; box.MinY = cY; - box.MaxY = envelope.MaxY; + box.MaxY = envelope_.MaxY; - nodes[i] = new QuadTree(box); - nodes[i]->setNo(row * 2 + 1, col * 2 + 1, level + 1); + nodes_[i].reset(new QuadTree(box)); + nodes_[i]->setNo(row_ * 2 + 1, col_ * 2 + 1, level_ + 1); break; case 3: - box.MinX = envelope.MinX; + box.MinX = envelope_.MinX; box.MaxX = cX; box.MinY = cY; - box.MaxY = envelope.MaxY; + box.MaxY = envelope_.MaxY; - nodes[i] = new QuadTree(box); - nodes[i]->setNo(row * 2, col * 2 + 1, level + 1); + nodes_[i].reset(new QuadTree(box)); + nodes_[i]->setNo(row_ * 2, col_ * 2 + 1, level_ + 1); break; } } diff --git a/src/ShpConvert.cpp b/src/ShpConvert.cpp index f8ca3bf..505f5b3 100644 --- a/src/ShpConvert.cpp +++ b/src/ShpConvert.cpp @@ -6,75 +6,95 @@ #include namespace scially { + bool ShpConvert::getAllFeatures() { + OGRSpatialReference wgsSRS; + wgsSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER); + wgsSRS.importFromEPSG(4326); - void ShpConvert::convertTiles(const QString& output) { - QuadTree tree; - GDALDatasetWrapper ds = GDALDatasetWrapper::open(fileName.toStdString().data(), 1); - OGRLayerWrapper layer = ds.GetLayerByName(layerName.toStdString().data()); - - layer.ResetReading(); - tree.setEnvelope(layer.GetExtent()); - - OGRFeatureWrapper feature = layer.GetNextFeature(); - OGREnvelope layerEnvelope = layer.GetExtent(); + if (!ds_.open(fileName_, 1)) { + qCritical() << "can't open" << fileName_; + return false; + } + layer_ = ds_.GetLayerByName(layerName_); + if (!layer_.isValid()) { + qCritical() << "can't load layer" << layerName_ << "in" << fileName_; + return false; + } + layer_.ResetReading(); + OGRFeatureWrapper feature = layer_.GetNextFeature(); while (feature.isValid()) { - OGREnvelope envelope; OGRGeometry* geometry = feature.GetGeometryRef(); - if (geometry == nullptr) - continue; + OGRErr err = geometry->transformTo(&wgsSRS); + if (err != OGRERR_NONE) { + qCritical() << "can't transform geometry to WGS84"; + return false; + } + + OGREnvelope extent; + geometry->getEnvelope(&extent); + if (!extent_.IsInit()) { + extent_ = extent; + } + else { + extent_.Merge(extent); + } + iFeature_[feature.GetFID()] = feature; + feature = layer_.GetNextFeature(); + } + return true; + } + + bool ShpConvert::initQuadTree(QuadTree& tree) { + if (!getAllFeatures()) { + return false; + } + + tree.setEnvelope(extent_); - geometry->getEnvelope(&envelope); - - tree.add(feature.GetFID(), envelope); - feature = layer.GetNextFeature(); + QMap::iterator iter = iFeature_.begin(); + while (iter != iFeature_.end()) { + OGREnvelope extent; + auto geometry = iter.value().GetGeometryRef(); + geometry->getEnvelope(&extent); + tree.add(iter.key(), extent); + ++iter; } + return true; + } - int heightIndex = layer.GetLayerDefn()->GetFieldIndex(heightField.toStdString().data()); + bool ShpConvert::convertTiles(const QString& output) { + QuadTree tree; + if (!initQuadTree(tree)) { + return false; + } + + int heightIndex = layer_.GetLayerDefn()->GetFieldIndex(heightField_.toStdString().data()); if (heightIndex == -1) { - qCritical() << heightField << "not found in layer"; - return; + qCritical() << heightField_ << "not found in layer" << layerName_; + return false; } BaseTile tile; double layerMaxHeight = 0; - tree.traverse([&layer, &output, &tile, &layerMaxHeight, heightIndex](QuadTree* root) { - OGREnvelope nodeBox; - - // Calc All Geometry Envelope - { - for (int i = 0; i < root->geomsSize(); i++) { - int fid = root->getGeomFID(i); - OGRFeatureWrapper feature = layer.GetFeature(fid); - OGRGeometry* geometry = feature.GetGeometryRef(); - OGREnvelope envelope; - geometry->getEnvelope(&envelope); - if (nodeBox.IsInit()) { - nodeBox.Merge(envelope); - } - else { - nodeBox = envelope; - } - } - } - + tree.traverse([this, &output, &tile, &layerMaxHeight, heightIndex](QuadTree* root) { // Build 3D Model per geometry - double centerX = (nodeBox.MinX + nodeBox.MaxX) / 2; - double centerY = (nodeBox.MinY + nodeBox.MaxY) / 2; - double boxWidth = (nodeBox.MaxX - nodeBox.MinX); - double boxHeight = (nodeBox.MaxY - nodeBox.MinY); + double centerX = (extent_.MinX + extent_.MaxX) / 2; + double centerY = (extent_.MinY + extent_.MaxY) / 2; + double boxWidth = (extent_.MaxX - extent_.MinX); + double boxHeight = (extent_.MaxY - extent_.MinY); double maxHeight = 0; QDir outputLocation = QString("%1/tile/%2/%3"). arg(output). - arg(root->getLevel()). - arg(root->getRow()); + arg(root->level()). + arg(root->row()); if (!outputLocation.exists()) outputLocation.mkpath("."); GeometryMesh meshes; - for (int i = 0; i < root->geomsSize(); i++) { - int fid = root->getGeomFID(i); - OGRFeatureWrapper feature = layer.GetFeature(fid); + for (int i = 0; i < root->geomSize(); i++) { + int fid = root->geomFID(i); + OGRFeatureWrapper feature = iFeature_[fid]; OGRGeometry* geometry = feature.GetGeometryRef(); double height = feature.GetFieldAsDouble(heightIndex); maxHeight = std::max(height, maxHeight); @@ -98,31 +118,31 @@ namespace scially { QByteArray b3dmBuffer = meshes.toB3DM(true); QFile b3dmFile = QString("%1/tile/%2/%3/%4.b3dm"). arg(output). - arg(root->getLevel()). - arg(root->getRow()). - arg(root->getCol()); + arg(root->level()). + arg(root->row()). + arg(root->col()); if (!b3dmFile.open(QIODevice::WriteOnly)){ - qCritical() << "can't write file:" << b3dmFile.fileName(); + qCritical() << "can't write file" << b3dmFile.fileName(); return; } int writeBytes = b3dmFile.write(b3dmBuffer); if (writeBytes <= 0){ - qCritical() << "can't write file:" << b3dmFile.fileName(); + qCritical() << "can't write file" << b3dmFile.fileName(); return; } RootTile child; child.boundingVolume = BoundingVolumeRegion::fromCenterXY( centerX, centerY, - nodeBox.MaxX - nodeBox.MinX, nodeBox.MaxY - nodeBox.MinY, + boxWidth, boxHeight, 0, maxHeight); child.transform = Transform::fromXYZ(centerX, centerY, 0); child.content.emplace(); child.content->uri = QString("./tile/%1/%2/%3.b3dm") - .arg(root->getLevel()) - .arg(root->getRow()) - .arg(root->getCol()); + .arg(root->level()) + .arg(root->row()) + .arg(root->col()); tile.root.children.append(child); }); @@ -131,10 +151,10 @@ namespace scially { tile.geometricError = 200; tile.root.geometricError = 200; BoundingVolumeRegion rootBounding; - rootBounding.west = osg::DegreesToRadians(layerEnvelope.MinX); - rootBounding.east = osg::DegreesToRadians(layerEnvelope.MaxX); - rootBounding.south = osg::DegreesToRadians(layerEnvelope.MinY); - rootBounding.north = osg::DegreesToRadians(layerEnvelope.MaxY); + rootBounding.west = osg::DegreesToRadians(extent_.MinX); + rootBounding.east = osg::DegreesToRadians(extent_.MaxX); + rootBounding.south = osg::DegreesToRadians(extent_.MinY); + rootBounding.north = osg::DegreesToRadians(extent_.MaxY); rootBounding.minHeight = 0; rootBounding.maxHeight = layerMaxHeight; tile.root.boundingVolume = rootBounding; @@ -142,12 +162,13 @@ namespace scially { QFile tileFile(output + "/tileset.json"); if (!tileFile.open(QIODevice::WriteOnly)){ qCritical() << "can't write file:" << tileFile.fileName(); - return; + return false; } int writeBytes = tileFile.write(tileBuffer); if (writeBytes <= 0){ qCritical() << "can't write file:" << tileFile.fileName(); - return; + return false; } - } + return true; + } }