相关文章推荐
解决Cesium Terrain Builder 在Windows下编译不成功问题

解决Cesium Terrain Builder 在Windows下编译不成功问题

由于最近公司需要制作离线GIS数据转换工具。故要放弃Cesiumlab工具。

首先,参考下面CTB在windows下安装指南。可以编译Windows版本的CTB。

但实际过程里面发现不少小坑,导致编译不成功。群里有许多小伙伴也遇到类似问题。以此我描述以上链接为基础在编译会遇到的问题进行解决,并结合可以生成Layer.json文件,不压缩.terrain文件也可查看地形数据。

一、解决编译问题。

1.解决问题。lib\gdal_i.lib : warning LNK4272: 库计算机类型“x64”与目标计算机类型“x86”冲突。

红线内一定选择x64,不然在编译时出链接错误。

2.解决问题。Unable to open EPSG support file gcs.csv。

需要设置环境变量:

如果设置之后还是出现“Unable to open EPSG support file gcs.csv”问题。则在cmd输入set gdal_data查看路径是否正确、有没有带其它符号(我遇到过最后带一个;(分号),反复出现,导到不能正常运行)。

3.解决问题。不能使用中文目录问题。

在GDALAllRegister();下一行加入CPLSetConfigOption("GDAL_FILENAME_IS_UTF8", "NO");

二、生成Layer.json。首先打ctb-tile.cpp文件。

1.在main()函数中加入:

command.option("-l", "--layer", "only output the layer.json metadata file", TerrainBuild::setMetadata);

2.添加函数

static void
        setMetadata(command_t *command) {
        static_cast<TerrainBuild *>(Command::self(command))->metadata = true;
    }

3.添加成员变量,并在构造函数初始化

bool metadata;

4.添加函数

static void
buildMetadata(const RasterTiler &tiler, TerrainBuild *command, TerrainMetadata *metadata) {
    const string dirname = string(command->outputDir) + osDirSep;
    i_zoom startZoom = (command->startZoom < 0) ? tiler.maxZoomLevel() : command->startZoom,
        endZoom = (command->endZoom < 0) ? 0 : command->endZoom;
    const std::string filename = concat(dirname, "layer.json");
    RasterIterator iter(tiler, startZoom, endZoom);
    int currentIndex = incrementMetaDatainIterator(iter, 0);
    setIteratorSize(iter);
    while (!iter.exhausted()) {
        const TileCoordinate *coordinate = iter.GridIterator::operator*();
        if (metadata) metadata->add(tiler.grid(), coordinate);
        currentIndex = incrementMetaDatainIterator(iter, currentIndex);
        showProgress(currentIndex, filename);
}

5.修改runTiler函数

static int
runTiler(const char *inputFilename, TerrainBuild *command, Grid *grid, TerrainMetadata *metadata) {
    GDALDataset  *poDataset = (GDALDataset *)GDALOpen(inputFilename, GA_ReadOnly);
    if (poDataset == NULL) {
        cerr << "Error: could not open GDAL dataset" << endl;
        return 1;
    // Metadata of only this thread, it will be joined to global later
    TerrainMetadata *threadMetadata = metadata ? new TerrainMetadata() : NULL;
    // Choose serializer of tiles (Directory of files, MBTiles store...)
    CTBFileTileSerializer serializer(string(command->outputDir) + osDirSep, command->resume);
    try {
        serializer.startSerialization();
        if (command->metadata) {
            const RasterTiler tiler(poDataset, *grid, command->tilerOptions);
            buildMetadata(tiler, command, threadMetadata);
        if (strcmp(command->outputFormat, "Terrain") == 0) {
            const TerrainTiler tiler(poDataset, *grid);
            buildTerrain(serializer, tiler, command, threadMetadata);
        else if (strcmp(command->outputFormat, "Mesh") == 0) {
            const MeshTiler tiler(poDataset, *grid, command->tilerOptions, command->meshQualityFactor);
            buildMesh(serializer, tiler, command, threadMetadata, command->vertexNormals);
        else {                    // it's a GDAL format
            const RasterTiler tiler(poDataset, *grid, command->tilerOptions);
            buildGDAL(serializer, tiler, command, threadMetadata);
    catch (CTBException &e) {
        cerr << "Error: " << e.what() << endl;
    serializer.endSerialization();
    GDALClose(poDataset);
    // Pass metadata to global instance.
    if (threadMetadata) {
        static std::mutex mutex;
        std::lock_guard<std::mutex> lock(mutex);
        metadata->add(*threadMetadata);
        delete threadMetadata;
    return 0;
}

以上五步可以解决生成数据,没有layer.json的问题。

三、由于ctb生成的文件是经过gzip压缩过的,需要在docker环境下搭建terrain-server很是麻烦。所以使ctb生成文件直接发布使用更为方便。

1.在main()函数下添加

command.option("-G", "--gzip", "use zib compress file(defalut uncompress)", TerrainBuild::setGzib);

2.添加函数

static void setGzib(command_t * command) {
        static_cast<TerrainBuild *>(Command::self(command))->gzib = true;
    }

3.添加成员,并在构造函数内初始化

bool gzib;

4.修改buildMesh函数内方法

static void
buildMesh(MeshSerializer &serializer, const MeshTiler &tiler, TerrainBuild *command, TerrainMetadata *metadata, bool writeVertexNormals = false) {
    i_zoom startZoom = (command->startZoom < 0) ? tiler.maxZoomLevel() : command->startZoom,
        endZoom = (command->endZoom < 0) ? 0 : command->endZoom;
    // DEBUG Chunker:
#if 0
    const string dirname = string(command->outputDir) + osDirSep;
    TileCoordinate coordinate(13, 8102, 6047);
    MeshTile *tile = tiler.createMesh(tiler.dataset(), coordinate);
    const string txtname = CTBFileTileSerializer::getTileFilename(&coordinate, dirname, "wkt");
    const Mesh &mesh = tile->getMesh();
    mesh.writeWktFile(txtname.c_str());
    CRSBounds bounds = tiler.grid().tileBounds(coordinate);
    double x = bounds.getMinX() + 0.5 * (bounds.getMaxX() - bounds.getMinX());
    double y = bounds.getMinY() + 0.5 * (bounds.getMaxY() - bounds.getMinY());
    CRSPoint point(x, y);
    TileCoordinate c = tiler.grid().crsToTile(point, coordinate.zoom);
    const string filename = CTBFileTileSerializer::getTileFilename(&coordinate, dirname, "terrain");
    tile->writeFile(filename.c_str(), writeVertexNormals);
    delete tile;
    return;
#endif
    MeshIterator iter(tiler, startZoom, endZoom);
    int currentIndex = incrementMeshIterator(iter, 0);
    setIteratorSize(iter);
    GDALDatasetReaderWithOverviews reader(tiler);
    while (!iter.exhausted()) {
        const TileCoordinate *coordinate = iter.GridIterator::operator*();
        if (metadata) metadata->add(tiler.grid(), coordinate);
        if (serializer.mustSerializeCoordinate(coordinate)) {
            MeshTile *tile = iter.operator*(&reader);
            if (serializer.mustSerializeCoordinate(coordinate)) {
                 MeshTile *tile = iter.operator*(&reader);
                 serializer.serializeTile(tile, writeVertexNormals, command->gzib);
                 delete tile;
 
推荐文章