Skip to content

Commit

Permalink
Refactoring of code to easily write new output formats
Browse files Browse the repository at this point in the history
It simplifies the code to write new output formats as MBTiles... Defines
an set abstract classes anyone can override to implement its own logic
when serializing.
  • Loading branch information
ahuarte47 committed May 11, 2018
1 parent c448bc5 commit 9a21915
Show file tree
Hide file tree
Showing 16 changed files with 770 additions and 169 deletions.
10 changes: 10 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ add_library(ctb SHARED
GDALTile.cpp
GDALTiler.cpp
GDALDatasetReader.cpp
CTBFileTileSerializer.cpp
CTBFileOutputStream.cpp
CTBZOutputStream.cpp
TerrainTiler.cpp
TerrainTile.cpp
MeshTiler.cpp
Expand All @@ -35,22 +38,29 @@ set(HEADERS
BoundingSphere.hpp
Coordinate.hpp
Coordinate3D.hpp
GDALSerializer.hpp
GDALTile.hpp
GDALTiler.hpp
GDALDatasetReader.hpp
CTBFileTileSerializer.hpp
CTBFileOutputStream.hpp
CTBOutputStream.hpp
CTBZOutputStream.hpp
GlobalGeodetic.hpp
GlobalMercator.hpp
Grid.hpp
GridIterator.hpp
HeightFieldChunker.hpp
Mesh.hpp
MeshIterator.hpp
MeshSerializer.hpp
MeshTile.hpp
MeshTiler.hpp
RasterIterator.hpp
RasterTiler.hpp
CTBException.hpp
TerrainIterator.hpp
TerrainSerializer.hpp
TerrainTile.hpp
TerrainTiler.hpp
Tile.hpp
Expand Down
43 changes: 43 additions & 0 deletions src/CTBFileOutputStream.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*******************************************************************************
* Copyright 2018 GeoData <[email protected]>
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*******************************************************************************/

/**
* @file CTBFileOutputStream.cpp
* @brief This defines the `CTBFileOutputStream` class
*/

#include "CTBFileOutputStream.hpp"

using namespace ctb;

/**
* @details
* Writes a sequence of memory pointed by ptr into the FILE*.
*/
uint32_t
ctb::CTBFileOutputStream::write(const void *ptr, uint32_t size) {
return (uint32_t)fwrite(ptr, size, 1, fp);
}

/**
* @details
* Writes a sequence of memory pointed by ptr into the ostream.
*/
uint32_t
ctb::CTBStdOutputStream::write(const void *ptr, uint32_t size) {
mstream.write((const char *)ptr, size);
return size;
}
60 changes: 60 additions & 0 deletions src/CTBFileOutputStream.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#ifndef CTBFILEOUTPUTSTREAM_HPP
#define CTBFILEOUTPUTSTREAM_HPP

/*******************************************************************************
* Copyright 2018 GeoData <[email protected]>
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*******************************************************************************/

/**
* @file CTBFileOutputStream.hpp
* @brief This declares and defines the `CTBFileOutputStream` and `CTBStdOutputStream` classes
*/

#include <stdio.h>
#include <ostream>
#include "CTBOutputStream.hpp"

namespace ctb {
class CTBFileOutputStream;
class CTBStdOutputStream;
}

/// Implements CTBOutputStream for `FILE*` objects
class CTB_DLL ctb::CTBFileOutputStream : public ctb::CTBOutputStream {
public:
CTBFileOutputStream(FILE *fptr): fp(fptr) {}

/// Writes a sequence of memory pointed by ptr into the stream
virtual uint32_t write(const void *ptr, uint32_t size);

protected:
/// The underlying FILE*
FILE *fp;
};

/// Implements CTBOutputStream for `std::ostream` objects
class CTB_DLL ctb::CTBStdOutputStream : public ctb::CTBOutputStream {
public:
CTBStdOutputStream(std::ostream &stream): mstream(stream) {}

/// Writes a sequence of memory pointed by ptr into the stream
virtual uint32_t write(const void *ptr, uint32_t size);

protected:
/// The underlying std::ostream
std::ostream &mstream;
};

#endif /* CTBFILEOUTPUTSTREAM_HPP */
169 changes: 169 additions & 0 deletions src/CTBFileTileSerializer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/*******************************************************************************
* Copyright 2018 GeoData <[email protected]>
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*******************************************************************************/

/**
* @file CTBFileTileSerializer.cpp
* @brief This defines the `CTBFileTileSerializer` class
*/

#include <stdio.h>
#include <string.h>
#include <mutex>

#include "../deps/concat.hpp"
#include "cpl_vsi.h"
#include "CTBException.hpp"
#include "CTBFileTileSerializer.hpp"

#include "CTBFileOutputStream.hpp"
#include "CTBZOutputStream.hpp"

using namespace std;
using namespace ctb;

#ifdef _WIN32
static const char *osDirSep = "\\";
#else
static const char *osDirSep = "/";
#endif


/// Create a filename for a tile coordinate
std::string
ctb::CTBFileTileSerializer::getTileFilename(const TileCoordinate *coord, const string dirname, const char *extension) {
static mutex mutex;
VSIStatBufL stat;
string filename = concat(dirname, coord->zoom, osDirSep, coord->x);

lock_guard<std::mutex> lock(mutex);

// Check whether the `{zoom}/{x}` directory exists or not
if (VSIStatExL(filename.c_str(), &stat, VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG)) {
filename = concat(dirname, coord->zoom);

// Check whether the `{zoom}` directory exists or not
if (VSIStatExL(filename.c_str(), &stat, VSI_STAT_EXISTS_FLAG | VSI_STAT_NATURE_FLAG)) {
// Create the `{zoom}` directory
if (VSIMkdir(filename.c_str(), 0755))
throw CTBException("Could not create the zoom level directory");

} else if (!VSI_ISDIR(stat.st_mode)) {
throw CTBException("Zoom level file path is not a directory");
}

// Create the `{zoom}/{x}` directory
filename += concat(osDirSep, coord->x);
if (VSIMkdir(filename.c_str(), 0755))
throw CTBException("Could not create the x level directory");

} else if (!VSI_ISDIR(stat.st_mode)) {
throw CTBException("X level file path is not a directory");
}

// Create the filename itself, adding the extension if required
filename += concat(osDirSep, coord->y);
if (extension != NULL) {
filename += ".";
filename += extension;
}

return filename;
}

/// Check if file exists
static bool
fileExists(const std::string& filename) {
VSIStatBufL statbuf;
return VSIStatExL(filename.c_str(), &statbuf, VSI_STAT_EXISTS_FLAG) == 0;
}


/**
* @details
* Returns if the specified Tile Coordinate should be serialized
*/
bool ctb::CTBFileTileSerializer::mustSerializeCoordinate(const ctb::TileCoordinate *coordinate) {
if (!mresume)
return true;

const string filename = getTileFilename(coordinate, moutputDir, "terrain");
return !fileExists(filename);
}

/**
* @details
* Serialize a GDALTile to the Directory store
*/
bool
ctb::CTBFileTileSerializer::serializeTile(const ctb::GDALTile *tile, GDALDriver *driver, const char *extension, CPLStringList &creationOptions) {
const TileCoordinate *coordinate = tile;
const string filename = getTileFilename(coordinate, moutputDir, extension);
const string temp_filename = concat(filename, ".tmp");

GDALDataset *poDstDS;
poDstDS = driver->CreateCopy(temp_filename.c_str(), tile->dataset, FALSE, creationOptions, NULL, NULL);

// Close the datasets, flushing data to destination
if (poDstDS == NULL) {
throw CTBException("Could not create GDAL tile");
}
GDALClose(poDstDS);

if (VSIRename(temp_filename.c_str(), filename.c_str()) != 0) {
throw new CTBException("Could not rename temporary file");
}
return true;
}

/**
* @details
* Serialize a TerrainTile to the Directory store
*/
bool
ctb::CTBFileTileSerializer::serializeTile(const ctb::TerrainTile *tile) {
const TileCoordinate *coordinate = tile;
const string filename = getTileFilename(tile, moutputDir, "terrain");
const string temp_filename = concat(filename, ".tmp");

CTBZFileOutputStream ostream(temp_filename.c_str());
tile->writeFile(ostream);
ostream.close();

if (VSIRename(temp_filename.c_str(), filename.c_str()) != 0) {
throw new CTBException("Could not rename temporary file");
}
return true;
}

/**
* @details
* Serialize a MeshTile to the Directory store
*/
bool
ctb::CTBFileTileSerializer::serializeTile(const ctb::MeshTile *tile, bool writeVertexNormals) {
const TileCoordinate *coordinate = tile;
const string filename = getTileFilename(coordinate, moutputDir, "terrain");
const string temp_filename = concat(filename, ".tmp");

CTBZFileOutputStream ostream(temp_filename.c_str());
tile->writeFile(ostream, writeVertexNormals);
ostream.close();

if (VSIRename(temp_filename.c_str(), filename.c_str()) != 0) {
throw new CTBException("Could not rename temporary file");
}
return true;
}
74 changes: 74 additions & 0 deletions src/CTBFileTileSerializer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#ifndef CTBFILETILESERIALIZER_HPP
#define CTBFILETILESERIALIZER_HPP

/*******************************************************************************
* Copyright 2018 GeoData <[email protected]>
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*******************************************************************************/

/**
* @file CTBFileTileSerializer.hpp
* @brief This declares and defines the `CTBFileTileSerializer` class
*/

#include <string>

#include "TileCoordinate.hpp"
#include "GDALSerializer.hpp"
#include "TerrainSerializer.hpp"
#include "MeshSerializer.hpp"

namespace ctb {
class CTBFileTileSerializer;
}

/// Implements a serializer of `Tile`s based in a directory of files
class CTB_DLL ctb::CTBFileTileSerializer :
public ctb::GDALSerializer,
public ctb::TerrainSerializer,
public ctb::MeshSerializer {
public:
CTBFileTileSerializer(const std::string &outputDir, bool resume):
moutputDir(outputDir),
mresume(resume) {}

/// Start a new serialization task
virtual void startSerialization() {};

/// Returns if the specified Tile Coordinate should be serialized
virtual bool mustSerializeCoordinate(const ctb::TileCoordinate *coordinate);

/// Serialize a GDALTile to the store
virtual bool serializeTile(const ctb::GDALTile *tile, GDALDriver *driver, const char *extension, const CPLStringList &creationOptions);
/// Serialize a TerrainTile to the store
virtual bool serializeTile(const ctb::TerrainTile *tile);
/// Serialize a MeshTile to the store
virtual bool serializeTile(const ctb::MeshTile *tile, bool writeVertexNormals = false);

/// Serialization finished, releases any resources loaded
virtual void endSerialization() {};


/// Create a filename for a tile coordinate
static std::string
getTileFilename(const TileCoordinate *coord, const std::string dirname, const char *extension);

protected:
/// The target directory where serializing
std::string moutputDir;
/// Do not overwrite existing files
bool mresume;
};

#endif /* CTBFILETILESERIALIZER_HPP */
Loading

0 comments on commit 9a21915

Please sign in to comment.